1 /*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "ecmascript/module/module_tools.h"
17
18 #include "ecmascript/ecma_context.h"
19 #include "ecmascript/global_env.h"
20 #include "ecmascript/jspandafile/js_pandafile_executor.h"
21 #include "ecmascript/module/js_module_manager.h"
22 #include "ecmascript/module/js_shared_module.h"
23 #include "ecmascript/module/module_logger.h"
24 #include "ecmascript/module/module_manager_helper.h"
25 #include "ecmascript/module/module_path_helper.h"
26 #include "ecmascript/require/js_cjs_module.h"
27
28
29 namespace panda::ecmascript {
30
GetModuleValueFromIndexBindingForLog(JSThread * thread,JSHandle<SourceTextModule> module,JSTaggedValue resolvedBinding,int32_t index)31 JSTaggedValue ModuleTools::GetModuleValueFromIndexBindingForLog(
32 JSThread *thread, JSHandle<SourceTextModule> module, JSTaggedValue resolvedBinding, int32_t index)
33 {
34 JSHandle<ResolvedRecordIndexBinding> binding(thread, resolvedBinding);
35 JSHandle<SourceTextModule> resolvedModule =
36 ModuleManagerHelper::GetResolvedRecordIndexBindingModule(thread, module, binding);
37 ModuleLogger *moduleLogger =
38 thread->GetCurrentEcmaContext()->GetModuleLogger();
39 moduleLogger->InsertModuleLoadInfo(module, resolvedModule, index);
40 return ModuleManagerHelper::GetModuleValue(thread, resolvedModule, binding->GetIndex());
41 }
42
43 // use for moduleLogger is not nullptr
GetModuleValueFromRecordBindingForLog(JSThread * thread,JSHandle<SourceTextModule> module,JSTaggedValue resolvedBinding,int32_t index)44 JSTaggedValue ModuleTools::GetModuleValueFromRecordBindingForLog(
45 JSThread *thread, JSHandle<SourceTextModule> module, JSTaggedValue resolvedBinding, int32_t index)
46 {
47 JSHandle<ResolvedRecordBinding> binding(thread, resolvedBinding);
48 JSHandle<SourceTextModule> resolvedModule =
49 ModuleManagerHelper::GetResolvedRecordBindingModule(thread, module, binding);
50 ModuleLogger *moduleLogger =
51 thread->GetCurrentEcmaContext()->GetModuleLogger();
52 moduleLogger->InsertModuleLoadInfo(module, resolvedModule, index);
53 return ModuleManagerHelper::GetModuleValue(thread, resolvedModule, binding->GetBindingName());
54 }
55
56 // use for moduleLogger is not nullptr
ProcessModuleLoadInfo(JSThread * thread,JSHandle<SourceTextModule> currentModule,JSTaggedValue resolvedBinding,int32_t index)57 JSTaggedValue ModuleTools::ProcessModuleLoadInfo(JSThread *thread, JSHandle<SourceTextModule> currentModule,
58 JSTaggedValue resolvedBinding, int32_t index)
59 {
60 ModuleLogger *moduleLogger = thread->GetCurrentEcmaContext()->GetModuleLogger();
61 JSMutableHandle<JSTaggedValue> res(thread, thread->GlobalConstants()->GetUndefined());
62 if (resolvedBinding.IsResolvedIndexBinding()) {
63 ResolvedIndexBinding *binding = ResolvedIndexBinding::Cast(resolvedBinding.GetTaggedObject());
64 JSTaggedValue resolvedModule = binding->GetModule();
65 JSHandle<SourceTextModule> module(thread, resolvedModule);
66 ASSERT(resolvedModule.IsSourceTextModule());
67
68 // Support for only modifying var value of HotReload.
69 // Cause patchFile exclude the record of importing modifying var. Can't reresolve moduleRecord.
70 EcmaContext *context = thread->GetCurrentEcmaContext();
71 if (context->GetStageOfHotReload() == StageOfHotReload::LOAD_END_EXECUTE_PATCHMAIN) {
72 const JSHandle<JSTaggedValue> resolvedModuleOfHotReload =
73 context->FindPatchModule(module->GetEcmaModuleRecordNameString());
74 if (!resolvedModuleOfHotReload->IsHole()) {
75 resolvedModule = resolvedModuleOfHotReload.GetTaggedValue();
76 JSHandle<SourceTextModule> moduleOfHotReload(thread, resolvedModule);
77 moduleLogger->InsertModuleLoadInfo(currentModule, module, index);
78 return ModuleManagerHelper::GetModuleValue(thread, moduleOfHotReload, binding->GetIndex());
79 }
80 }
81 moduleLogger->InsertModuleLoadInfo(currentModule, module, index);
82 return ModuleManagerHelper::GetModuleValue(thread, module, binding->GetIndex());
83 }
84 if (resolvedBinding.IsResolvedBinding()) {
85 ResolvedBinding *binding = ResolvedBinding::Cast(resolvedBinding.GetTaggedObject());
86 JSTaggedValue resolvedModule = binding->GetModule();
87 JSHandle<SourceTextModule> module(thread, resolvedModule);
88 if (SourceTextModule::IsNativeModule(module->GetTypes())) {
89 moduleLogger->InsertModuleLoadInfo(currentModule, module, index);
90 return ModuleManagerHelper::UpdateBindingAndGetModuleValue(
91 thread, currentModule, module, index, binding->GetBindingName());
92 }
93 if (module->GetTypes() == ModuleTypes::CJS_MODULE) {
94 moduleLogger->InsertModuleLoadInfo(currentModule, module, index);
95 return ModuleManagerHelper::UpdateBindingAndGetModuleValue(
96 thread, currentModule, module, index, binding->GetBindingName());
97 }
98 }
99 if (resolvedBinding.IsResolvedRecordIndexBinding()) {
100 return GetModuleValueFromIndexBindingForLog(thread, currentModule, resolvedBinding, index);
101 }
102 if (resolvedBinding.IsResolvedRecordBinding()) { // LCOV_EXCL_BR_LINE
103 return GetModuleValueFromRecordBindingForLog(thread, currentModule, resolvedBinding, index);
104 }
105 LOG_ECMA(FATAL) << "Get module value failed, mistaken ResolvedBinding";
106 UNREACHABLE();
107 }
108
ProcessModuleNameSpaceLoadInfo(JSThread * thread,JSHandle<SourceTextModule> currentModule,JSHandle<SourceTextModule> requiredModule)109 JSTaggedValue ModuleTools::ProcessModuleNameSpaceLoadInfo(
110 JSThread *thread, JSHandle<SourceTextModule> currentModule, JSHandle<SourceTextModule> requiredModule)
111 {
112 ModuleTypes moduleType = requiredModule->GetTypes();
113 ModuleLogger *moduleLogger = thread->GetCurrentEcmaContext()->GetModuleLogger();
114 // if requiredModule is Native module
115 if (SourceTextModule::IsNativeModule(moduleType)) {
116 moduleLogger->InsertModuleLoadInfo(currentModule, requiredModule, -1);
117 return SourceTextModule::Cast(requiredModule.GetTaggedValue())->GetModuleValue(thread, 0, false);
118 }
119 // if requiredModule is CommonJS
120 if (moduleType == ModuleTypes::CJS_MODULE) {
121 moduleLogger->InsertModuleLoadInfo(currentModule, requiredModule, -1);
122 CString cjsModuleName = SourceTextModule::GetModuleName(requiredModule.GetTaggedValue());
123 JSHandle<JSTaggedValue> moduleNameHandle(thread->GetEcmaVM()->GetFactory()->NewFromUtf8(cjsModuleName));
124 return CjsModule::SearchFromModuleCache(thread, moduleNameHandle).GetTaggedValue();
125 }
126 // if requiredModule is ESM
127 moduleLogger->InsertModuleLoadInfo(currentModule, requiredModule, -1);
128 JSHandle<JSTaggedValue> moduleNamespace = SourceTextModule::GetModuleNamespace(thread, requiredModule);
129 ASSERT(moduleNamespace->IsModuleNamespace());
130 return moduleNamespace.GetTaggedValue();
131 }
132
GetLazyModuleValueFromIndexBindingForLog(JSThread * thread,JSHandle<SourceTextModule> module,JSTaggedValue resolvedBinding,int32_t index)133 JSTaggedValue ModuleTools::GetLazyModuleValueFromIndexBindingForLog(
134 JSThread *thread, JSHandle<SourceTextModule> module, JSTaggedValue resolvedBinding, int32_t index)
135 {
136 JSHandle<ResolvedRecordIndexBinding> binding(thread, resolvedBinding);
137 JSHandle<JSTaggedValue> recordName(thread, binding->GetModuleRecord());
138 ASSERT(recordName->IsString());
139 // moduleRecord is string, find at current vm
140 ModuleManager *moduleManager = thread->GetCurrentEcmaContext()->GetModuleManager();
141 CString recordNameStr = ModulePathHelper::Utf8ConvertToString(recordName.GetTaggedValue());
142 JSHandle<SourceTextModule> resolvedModule;
143 if (moduleManager->IsLocalModuleLoaded(recordNameStr)) {
144 resolvedModule = moduleManager->HostGetImportedModule(recordNameStr);
145 if (!moduleManager->IsEvaluatedModule(recordNameStr)) {
146 SourceTextModule::Evaluate(thread, resolvedModule, nullptr);
147 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception());
148 }
149 } else {
150 auto isMergedAbc = !module->GetEcmaModuleRecordNameString().empty();
151 CString fileName = ModulePathHelper::Utf8ConvertToString(binding->GetAbcFileName());
152 if (!JSPandaFileExecutor::LazyExecuteModule(thread,
153 recordNameStr, fileName, isMergedAbc)) { // LCOV_EXCL_BR_LINE
154 LOG_ECMA(FATAL) << "LazyExecuteModule failed";
155 }
156 resolvedModule = moduleManager->HostGetImportedModule(recordNameStr);
157 }
158 ModuleLogger *moduleLogger =
159 thread->GetCurrentEcmaContext()->GetModuleLogger();
160 moduleLogger->InsertModuleLoadInfo(module, resolvedModule, index);
161 return ModuleManagerHelper::GetModuleValue(thread, resolvedModule, binding->GetIndex());
162 }
163
164 // use for moduleLogger is not nullptr
GetLazyModuleValueFromRecordBindingForLog(JSThread * thread,JSHandle<SourceTextModule> module,JSTaggedValue resolvedBinding,int32_t index)165 JSTaggedValue ModuleTools::GetLazyModuleValueFromRecordBindingForLog(
166 JSThread *thread, JSHandle<SourceTextModule> module, JSTaggedValue resolvedBinding, int32_t index)
167 {
168 JSHandle<ResolvedRecordBinding> binding(thread, resolvedBinding);
169 JSHandle<JSTaggedValue> recordName(thread, binding->GetModuleRecord());
170 ASSERT(recordName->IsString());
171 // moduleRecord is string, find at current vm
172 ModuleManager *moduleManager = thread->GetCurrentEcmaContext()->GetModuleManager();
173 CString recordNameStr = ModulePathHelper::Utf8ConvertToString(recordName.GetTaggedValue());
174 JSHandle<SourceTextModule> resolvedModule;
175 if (moduleManager->IsLocalModuleLoaded(recordNameStr)) {
176 resolvedModule = moduleManager->HostGetImportedModule(recordNameStr);
177 if (!moduleManager->IsEvaluatedModule(recordNameStr)) {
178 SourceTextModule::Evaluate(thread, resolvedModule, nullptr);
179 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception());
180 }
181 } else {
182 auto isMergedAbc = !module->GetEcmaModuleRecordNameString().empty();
183 CString fileName = module->GetEcmaModuleFilenameString();
184 if (!JSPandaFileExecutor::LazyExecuteModule(thread,
185 recordNameStr, fileName, isMergedAbc)) { // LCOV_EXCL_BR_LINE
186 LOG_ECMA(FATAL) << "LazyExecuteModule failed";
187 }
188 resolvedModule = moduleManager->HostGetImportedModule(recordNameStr);
189 }
190 ModuleLogger *moduleLogger =
191 thread->GetCurrentEcmaContext()->GetModuleLogger();
192 moduleLogger->InsertModuleLoadInfo(module, resolvedModule, index);
193 return ModuleManagerHelper::GetModuleValue(thread, resolvedModule, binding->GetBindingName());
194 }
195
196 // use for moduleLogger is not nullptr
ProcessLazyModuleLoadInfo(JSThread * thread,JSHandle<SourceTextModule> currentModule,JSTaggedValue resolvedBinding,int32_t index)197 JSTaggedValue ModuleTools::ProcessLazyModuleLoadInfo(JSThread *thread, JSHandle<SourceTextModule> currentModule,
198 JSTaggedValue resolvedBinding, int32_t index)
199 {
200 ModuleLogger *moduleLogger = thread->GetCurrentEcmaContext()->GetModuleLogger();
201 JSMutableHandle<JSTaggedValue> res(thread, thread->GlobalConstants()->GetUndefined());
202 if (resolvedBinding.IsResolvedIndexBinding()) {
203 JSHandle<ResolvedIndexBinding> binding(thread, resolvedBinding);
204 JSTaggedValue resolvedModule = binding->GetModule();
205 JSMutableHandle<SourceTextModule> module(thread, resolvedModule);
206 ASSERT(resolvedModule.IsSourceTextModule());
207 // Support for only modifying var value of HotReload.
208 // Cause patchFile exclude the record of importing modifying var. Can't reresolve moduleRecord.
209 EcmaContext *context = thread->GetCurrentEcmaContext();
210 if (context->GetStageOfHotReload() == StageOfHotReload::LOAD_END_EXECUTE_PATCHMAIN) {
211 const JSHandle<JSTaggedValue> resolvedModuleOfHotReload =
212 context->FindPatchModule(module->GetEcmaModuleRecordNameString());
213 if (!resolvedModuleOfHotReload->IsHole()) {
214 resolvedModule = resolvedModuleOfHotReload.GetTaggedValue();
215 module.Update(resolvedModule);
216 }
217 }
218 if (module->GetStatus() < ModuleStatus::EVALUATED) {
219 SourceTextModule::Evaluate(thread, module, nullptr, 0, ExecuteTypes::LAZY);
220 }
221 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception());
222 moduleLogger->InsertModuleLoadInfo(currentModule, module, index);
223 return ModuleManagerHelper::GetModuleValue(thread, module, binding->GetIndex());
224 }
225 if (resolvedBinding.IsResolvedBinding()) {
226 JSHandle<ResolvedBinding> binding(thread, resolvedBinding);
227 JSTaggedValue resolvedModule = binding->GetModule();
228 JSHandle<SourceTextModule> module(thread, resolvedModule);
229 ModuleTypes moduleType = module->GetTypes();
230 if (SourceTextModule::IsNativeModule(moduleType)) {
231 SourceTextModule::EvaluateNativeModule(thread, module, moduleType);
232 moduleLogger->InsertModuleLoadInfo(currentModule, module, index);
233 return ModuleManagerHelper::UpdateBindingAndGetModuleValue(
234 thread, currentModule, module, index, binding->GetBindingName());
235 }
236 if (SourceTextModule::IsCjsModule(moduleType)) {
237 ModuleStatus status = module->GetStatus();
238 if (status < ModuleStatus::EVALUATED) {
239 SourceTextModule::ModuleExecution(thread, module, nullptr, 0);
240 SourceTextModule::RecordEvaluatedOrError(thread, module);
241 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception());
242 }
243 moduleLogger->InsertModuleLoadInfo(currentModule, module, index);
244 return ModuleManagerHelper::UpdateBindingAndGetModuleValue(
245 thread, currentModule, module, index, binding->GetBindingName());
246 }
247 }
248 if (resolvedBinding.IsResolvedRecordIndexBinding()) {
249 return GetLazyModuleValueFromIndexBindingForLog(thread, currentModule, resolvedBinding, index);
250 }
251 if (resolvedBinding.IsResolvedRecordBinding()) { // LCOV_EXCL_BR_LINE
252 return GetLazyModuleValueFromRecordBindingForLog(thread, currentModule, resolvedBinding, index);
253 }
254 LOG_ECMA(FATAL) << "Get module value failed, mistaken ResolvedBinding";
255 UNREACHABLE();
256 }
257 } // namespace panda::ecmascript
258