• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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 #include "ecmascript/module/js_module_manager.h"
16 
17 #include "ecmascript/aot_file_manager.h"
18 #include "ecmascript/base/path_helper.h"
19 #include "ecmascript/builtins/builtins_json.h"
20 #include "ecmascript/global_env.h"
21 #include "ecmascript/interpreter/frame_handler.h"
22 #include "ecmascript/interpreter/fast_runtime_stub-inl.h"
23 #include "ecmascript/jspandafile/module_data_extractor.h"
24 #include "ecmascript/jspandafile/js_pandafile.h"
25 #include "ecmascript/jspandafile/js_pandafile_executor.h"
26 #include "ecmascript/jspandafile/js_pandafile_manager.h"
27 #include "ecmascript/js_array.h"
28 #include "ecmascript/linked_hash_table.h"
29 #include "ecmascript/module/js_module_source_text.h"
30 #include "ecmascript/tagged_dictionary.h"
31 #include "ecmascript/require/js_cjs_module.h"
32 
33 #ifdef PANDA_TARGET_WINDOWS
34 #include <algorithm>
35 #endif
36 
37 namespace panda::ecmascript {
38 using BuiltinsJson = builtins::BuiltinsJson;
39 using PathHelper = base::PathHelper;
40 
41 namespace {
42 constexpr size_t NATIVE_PREFIX_SIZE = 8;
43 constexpr size_t OHOS_PREFIX_SIZE = 6;
44 constexpr size_t APP_PREFIX_SIZE = 5;
45 
46 constexpr char REQUIRE_NAITVE_MODULE_PREFIX[] = "@native:";
47 constexpr char REQUIRE_NAPI_OHOS_PREFIX[] = "@ohos:";
48 constexpr char REQUIRE_NAPI_APP_PREFIX[] = "@app:";
49 }
50 
ModuleManager(EcmaVM * vm)51 ModuleManager::ModuleManager(EcmaVM *vm) : vm_(vm)
52 {
53     resolvedModules_ = NameDictionary::Create(vm_->GetJSThread(), DEAULT_DICTIONART_CAPACITY).GetTaggedValue();
54 }
55 
GetCurrentModule()56 JSTaggedValue ModuleManager::GetCurrentModule()
57 {
58     FrameHandler frameHandler(vm_->GetJSThread());
59     JSTaggedValue currentFunc = frameHandler.GetFunction();
60     return JSFunction::Cast(currentFunc.GetTaggedObject())->GetModule();
61 }
62 
GetModuleValueInner(int32_t index)63 JSTaggedValue ModuleManager::GetModuleValueInner(int32_t index)
64 {
65     JSTaggedValue currentModule = GetCurrentModule();
66     if (currentModule.IsUndefined()) {
67         LOG_FULL(FATAL) << "GetModuleValueInner currentModule failed";
68     }
69     return SourceTextModule::Cast(currentModule.GetTaggedObject())->GetModuleValue(vm_->GetJSThread(), index, false);
70 }
71 
GetModuleValueInner(int32_t index,JSTaggedValue jsFunc)72 JSTaggedValue ModuleManager::GetModuleValueInner(int32_t index, JSTaggedValue jsFunc)
73 {
74     JSTaggedValue currentModule = JSFunction::Cast(jsFunc.GetTaggedObject())->GetModule();
75     if (currentModule.IsUndefined()) {
76         LOG_FULL(FATAL) << "GetModuleValueInner currentModule failed";
77     }
78     return SourceTextModule::Cast(currentModule.GetTaggedObject())->GetModuleValue(vm_->GetJSThread(), index, false);
79 }
80 
GetModuleValueOutter(int32_t index)81 JSTaggedValue ModuleManager::GetModuleValueOutter(int32_t index)
82 {
83     JSTaggedValue currentModule = GetCurrentModule();
84     return GetModuleValueOutterInternal(index, currentModule);
85 }
86 
GetModuleName(JSTaggedValue currentModule)87 JSTaggedValue ModuleManager::GetModuleName(JSTaggedValue currentModule)
88 {
89     SourceTextModule *module = SourceTextModule::Cast(currentModule.GetTaggedObject());
90     JSTaggedValue recordName = module->GetEcmaModuleRecordName();
91     if (recordName.IsUndefined()) {
92         return module->GetEcmaModuleFilename();
93     } else {
94         return recordName;
95     }
96 }
97 
GetModuleValueOutter(int32_t index,JSTaggedValue jsFunc)98 JSTaggedValue ModuleManager::GetModuleValueOutter(int32_t index, JSTaggedValue jsFunc)
99 {
100     JSTaggedValue currentModule = JSFunction::Cast(jsFunc.GetTaggedObject())->GetModule();
101     return GetModuleValueOutterInternal(index, currentModule);
102 }
103 
GetModuleValueOutterInternal(int32_t index,JSTaggedValue currentModule)104 JSTaggedValue ModuleManager::GetModuleValueOutterInternal(int32_t index, JSTaggedValue currentModule)
105 {
106     JSThread *thread = vm_->GetJSThread();
107     if (currentModule.IsUndefined()) {
108         LOG_FULL(FATAL) << "GetModuleValueOutter currentModule failed";
109         UNREACHABLE();
110     }
111     JSTaggedValue moduleEnvironment = SourceTextModule::Cast(currentModule.GetTaggedObject())->GetEnvironment();
112     if (moduleEnvironment.IsUndefined()) {
113         return thread->GlobalConstants()->GetUndefined();
114     }
115     ASSERT(moduleEnvironment.IsTaggedArray());
116     JSTaggedValue resolvedBinding = TaggedArray::Cast(moduleEnvironment.GetTaggedObject())->Get(index);
117     if (resolvedBinding.IsResolvedIndexBinding()) {
118         ResolvedIndexBinding *binding = ResolvedIndexBinding::Cast(resolvedBinding.GetTaggedObject());
119         JSTaggedValue resolvedModule = binding->GetModule();
120         ASSERT(resolvedModule.IsSourceTextModule());
121         SourceTextModule *module = SourceTextModule::Cast(resolvedModule.GetTaggedObject());
122 
123         ModuleTypes moduleType = module->GetTypes();
124         if (IsNativeModule(moduleType)) {
125             return GetNativeModuleValue(thread, currentModule, resolvedModule, binding);
126         }
127         if (module->GetTypes() == ModuleTypes::CJS_MODULE) {
128             return GetCJSModuleValue(thread, currentModule, resolvedModule, binding);
129         }
130         return SourceTextModule::Cast(
131             resolvedModule.GetTaggedObject())->GetModuleValue(thread, binding->GetIndex(), false);
132     }
133     ResolvedBinding *binding = ResolvedBinding::Cast(resolvedBinding.GetTaggedObject());
134     JSTaggedValue resolvedModule = binding->GetModule();
135     SourceTextModule *module = SourceTextModule::Cast(resolvedModule.GetTaggedObject());
136     if (module->GetTypes() == ModuleTypes::CJS_MODULE) {
137         JSHandle<JSTaggedValue> cjsModuleName(thread, GetModuleName(JSTaggedValue(module)));
138         return CjsModule::SearchFromModuleCache(thread, cjsModuleName).GetTaggedValue();
139     }
140     LOG_ECMA(FATAL) << "Get module value failed, mistaken ResolvedBinding";
141     UNREACHABLE();
142 }
143 
GetNativeModuleValue(JSThread * thread,JSTaggedValue currentModule,JSTaggedValue resolvedModule,ResolvedIndexBinding * binding)144 JSTaggedValue ModuleManager::GetNativeModuleValue(JSThread *thread, JSTaggedValue currentModule,
145     JSTaggedValue resolvedModule, ResolvedIndexBinding *binding)
146 {
147     JSHandle<JSTaggedValue> nativeModuleName(thread, GetModuleName(resolvedModule));
148     JSHandle<JSTaggedValue> nativeExports = JSHandle<JSTaggedValue>(thread,
149         SourceTextModule::Cast(resolvedModule.GetTaggedObject())->GetModuleValue(thread, 0, false));
150     if (!nativeExports->IsJSObject()) {
151         JSHandle<JSTaggedValue> curModuleName(thread, SourceTextModule::Cast(
152             currentModule.GetTaggedObject())->GetEcmaModuleFilename());
153         LOG_FULL(WARN) << "GetNativeModuleValue: currentModule " + ConvertToString(curModuleName.GetTaggedValue()) +
154             ", find requireModule " + ConvertToString(nativeModuleName.GetTaggedValue()) + " failed";
155         return nativeExports.GetTaggedValue();
156     }
157     return GetValueFromExportObject(nativeExports, binding->GetIndex());
158 }
159 
GetCJSModuleValue(JSThread * thread,JSTaggedValue currentModule,JSTaggedValue resolvedModule,ResolvedIndexBinding * binding)160 JSTaggedValue ModuleManager::GetCJSModuleValue(JSThread *thread, JSTaggedValue currentModule,
161     JSTaggedValue resolvedModule, ResolvedIndexBinding *binding)
162 {
163     JSHandle<JSTaggedValue> cjsModuleName(thread, GetModuleName(resolvedModule));
164     JSHandle<JSTaggedValue> cjsExports = CjsModule::SearchFromModuleCache(thread, cjsModuleName);
165     // if cjsModule is not JSObject, means cjs uses default exports.
166     if (!cjsExports->IsJSObject()) {
167         if (cjsExports->IsHole()) {
168             ObjectFactory *factory = vm_->GetFactory();
169             JSHandle<JSTaggedValue> curModuleName(thread, SourceTextModule::Cast(
170                 currentModule.GetTaggedObject())->GetEcmaModuleFilename());
171             CString errorMsg = "GetCJSModuleValue: currentModule" + ConvertToString(curModuleName.GetTaggedValue()) +
172                                 "find requireModule" + ConvertToString(cjsModuleName.GetTaggedValue()) + "failed";
173             JSHandle<JSObject> syntaxError =
174                 factory->GetJSError(base::ErrorType::SYNTAX_ERROR, errorMsg.c_str());
175             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, syntaxError.GetTaggedValue(), JSTaggedValue::Exception());
176         }
177         return cjsExports.GetTaggedValue();
178     }
179     return GetValueFromExportObject(cjsExports, binding->GetIndex());
180 }
181 
GetValueFromExportObject(JSHandle<JSTaggedValue> & exportObject,int32_t index)182 JSTaggedValue ModuleManager::GetValueFromExportObject(JSHandle<JSTaggedValue> &exportObject, int32_t index)
183 {
184     if (index == SourceTextModule::UNDEFINED_INDEX) {
185         return exportObject.GetTaggedValue();
186     }
187     JSObject *obj = JSObject::Cast(exportObject.GetTaggedValue());
188     JSHClass *jsHclass = obj->GetJSHClass();
189     LayoutInfo *layoutInfo = LayoutInfo::Cast(jsHclass->GetLayout().GetTaggedObject());
190     PropertyAttributes attr = layoutInfo->GetAttr(index);
191     JSTaggedValue value = obj->GetProperty(jsHclass, attr);
192     if (UNLIKELY(value.IsAccessor())) {
193         return FastRuntimeStub::CallGetter(vm_->GetJSThread(), JSTaggedValue(obj), JSTaggedValue(obj), value);
194     }
195     ASSERT(!value.IsAccessor());
196     return value;
197 }
198 
StoreModuleValue(int32_t index,JSTaggedValue value)199 void ModuleManager::StoreModuleValue(int32_t index, JSTaggedValue value)
200 {
201     JSThread *thread = vm_->GetJSThread();
202     JSHandle<SourceTextModule> currentModule(thread, GetCurrentModule());
203     StoreModuleValueInternal(currentModule, index, value);
204 }
205 
StoreModuleValue(int32_t index,JSTaggedValue value,JSTaggedValue jsFunc)206 void ModuleManager::StoreModuleValue(int32_t index, JSTaggedValue value, JSTaggedValue jsFunc)
207 {
208     JSThread *thread = vm_->GetJSThread();
209     JSHandle<SourceTextModule> currentModule(thread, JSFunction::Cast(jsFunc.GetTaggedObject())->GetModule());
210     StoreModuleValueInternal(currentModule, index, value);
211 }
212 
StoreModuleValueInternal(JSHandle<SourceTextModule> & currentModule,int32_t index,JSTaggedValue value)213 void ModuleManager::StoreModuleValueInternal(JSHandle<SourceTextModule> &currentModule,
214                                              int32_t index, JSTaggedValue value)
215 {
216     if (currentModule.GetTaggedValue().IsUndefined()) {
217         LOG_FULL(FATAL) << "StoreModuleValue currentModule failed";
218         UNREACHABLE();
219     }
220     JSThread *thread = vm_->GetJSThread();
221     JSHandle<JSTaggedValue> valueHandle(thread, value);
222     currentModule->StoreModuleValue(thread, index, valueHandle);
223 }
224 
GetModuleValueInner(JSTaggedValue key)225 JSTaggedValue ModuleManager::GetModuleValueInner(JSTaggedValue key)
226 {
227     JSTaggedValue currentModule = GetCurrentModule();
228     if (currentModule.IsUndefined()) {
229         LOG_FULL(FATAL) << "GetModuleValueInner currentModule failed";
230         UNREACHABLE();
231     }
232     return SourceTextModule::Cast(currentModule.GetTaggedObject())->GetModuleValue(vm_->GetJSThread(), key, false);
233 }
234 
GetModuleValueInner(JSTaggedValue key,JSTaggedValue jsFunc)235 JSTaggedValue ModuleManager::GetModuleValueInner(JSTaggedValue key, JSTaggedValue jsFunc)
236 {
237     JSTaggedValue currentModule = JSFunction::Cast(jsFunc.GetTaggedObject())->GetModule();
238     if (currentModule.IsUndefined()) {
239         LOG_FULL(FATAL) << "GetModuleValueInner currentModule failed";
240         UNREACHABLE();
241     }
242     return SourceTextModule::Cast(currentModule.GetTaggedObject())->GetModuleValue(vm_->GetJSThread(), key, false);
243 }
244 
GetModuleValueOutter(JSTaggedValue key)245 JSTaggedValue ModuleManager::GetModuleValueOutter(JSTaggedValue key)
246 {
247     JSTaggedValue currentModule = GetCurrentModule();
248     return GetModuleValueOutterInternal(key, currentModule);
249 }
250 
GetModuleValueOutter(JSTaggedValue key,JSTaggedValue jsFunc)251 JSTaggedValue ModuleManager::GetModuleValueOutter(JSTaggedValue key, JSTaggedValue jsFunc)
252 {
253     JSTaggedValue currentModule = JSFunction::Cast(jsFunc.GetTaggedObject())->GetModule();
254     return GetModuleValueOutterInternal(key, currentModule);
255 }
256 
GetModuleValueOutterInternal(JSTaggedValue key,JSTaggedValue currentModule)257 JSTaggedValue ModuleManager::GetModuleValueOutterInternal(JSTaggedValue key, JSTaggedValue currentModule)
258 {
259     JSThread *thread = vm_->GetJSThread();
260     if (currentModule.IsUndefined()) {
261         LOG_FULL(FATAL) << "GetModuleValueOutter currentModule failed";
262         UNREACHABLE();
263     }
264     JSTaggedValue moduleEnvironment = SourceTextModule::Cast(currentModule.GetTaggedObject())->GetEnvironment();
265     if (moduleEnvironment.IsUndefined()) {
266         return thread->GlobalConstants()->GetUndefined();
267     }
268     int entry = NameDictionary::Cast(moduleEnvironment.GetTaggedObject())->FindEntry(key);
269     if (entry == -1) {
270         return thread->GlobalConstants()->GetUndefined();
271     }
272     JSTaggedValue resolvedBinding = NameDictionary::Cast(moduleEnvironment.GetTaggedObject())->GetValue(entry);
273     ASSERT(resolvedBinding.IsResolvedBinding());
274     ResolvedBinding *binding = ResolvedBinding::Cast(resolvedBinding.GetTaggedObject());
275     JSTaggedValue resolvedModule = binding->GetModule();
276     ASSERT(resolvedModule.IsSourceTextModule());
277     SourceTextModule *module = SourceTextModule::Cast(resolvedModule.GetTaggedObject());
278     if (module->GetTypes() == ModuleTypes::CJS_MODULE) {
279         JSHandle<JSTaggedValue> cjsModuleName(thread, GetModuleName(JSTaggedValue(module)));
280         return CjsModule::SearchFromModuleCache(thread, cjsModuleName).GetTaggedValue();
281     }
282     return SourceTextModule::Cast(resolvedModule.GetTaggedObject())->GetModuleValue(thread,
283                                                                                     binding->GetBindingName(), false);
284 }
285 
StoreModuleValue(JSTaggedValue key,JSTaggedValue value)286 void ModuleManager::StoreModuleValue(JSTaggedValue key, JSTaggedValue value)
287 {
288     JSThread *thread = vm_->GetJSThread();
289     JSHandle<SourceTextModule> currentModule(thread, GetCurrentModule());
290     StoreModuleValueInternal(currentModule, key, value);
291 }
292 
StoreModuleValue(JSTaggedValue key,JSTaggedValue value,JSTaggedValue jsFunc)293 void ModuleManager::StoreModuleValue(JSTaggedValue key, JSTaggedValue value, JSTaggedValue jsFunc)
294 {
295     JSThread *thread = vm_->GetJSThread();
296     JSHandle<SourceTextModule> currentModule(thread, JSFunction::Cast(jsFunc.GetTaggedObject())->GetModule());
297     StoreModuleValueInternal(currentModule, key, value);
298 }
299 
StoreModuleValueInternal(JSHandle<SourceTextModule> & currentModule,JSTaggedValue key,JSTaggedValue value)300 void ModuleManager::StoreModuleValueInternal(JSHandle<SourceTextModule> &currentModule,
301                                              JSTaggedValue key, JSTaggedValue value)
302 {
303     if (currentModule.GetTaggedValue().IsUndefined()) {
304         LOG_FULL(FATAL) << "StoreModuleValue currentModule failed";
305         UNREACHABLE();
306     }
307     JSThread *thread = vm_->GetJSThread();
308     JSHandle<JSTaggedValue> keyHandle(thread, key);
309     JSHandle<JSTaggedValue> valueHandle(thread, value);
310     currentModule->StoreModuleValue(thread, keyHandle, valueHandle);
311 }
312 
HostGetImportedModule(const CString & referencingModule)313 JSHandle<SourceTextModule> ModuleManager::HostGetImportedModule(const CString &referencingModule)
314 {
315     ObjectFactory *factory = vm_->GetFactory();
316     JSHandle<EcmaString> referencingHandle = factory->NewFromUtf8(referencingModule);
317     return HostGetImportedModule(referencingHandle.GetTaggedValue());
318 }
319 
HostGetImportedModule(JSTaggedValue referencing)320 JSHandle<SourceTextModule> ModuleManager::HostGetImportedModule(JSTaggedValue referencing)
321 {
322     NameDictionary *dict = NameDictionary::Cast(resolvedModules_.GetTaggedObject());
323     int entry = dict->FindEntry(referencing);
324     LOG_ECMA_IF(entry == -1, FATAL) << "Can not get module: "
325                                     << ConvertToString(referencing);
326     JSTaggedValue result = dict->GetValue(entry);
327     return JSHandle<SourceTextModule>(vm_->GetJSThread(), result);
328 }
329 
IsImportedModuleLoaded(JSTaggedValue referencing)330 bool ModuleManager::IsImportedModuleLoaded(JSTaggedValue referencing)
331 {
332     int entry = NameDictionary::Cast(resolvedModules_.GetTaggedObject())->FindEntry(referencing);
333     return (entry != -1);
334 }
335 
HostResolveImportedModuleWithMerge(const CString & moduleFileName,const CString & recordName)336 JSHandle<JSTaggedValue> ModuleManager::HostResolveImportedModuleWithMerge(const CString &moduleFileName,
337                                                                           const CString &recordName)
338 {
339     JSThread *thread = vm_->GetJSThread();
340     ObjectFactory *factory = vm_->GetFactory();
341 
342     JSHandle<EcmaString> recordNameHandle = factory->NewFromUtf8(recordName);
343     NameDictionary *dict = NameDictionary::Cast(resolvedModules_.GetTaggedObject());
344     int entry = dict->FindEntry(recordNameHandle.GetTaggedValue());
345     if (entry != -1) {
346         return JSHandle<JSTaggedValue>(thread, dict->GetValue(entry));
347     }
348     const JSPandaFile *jsPandaFile =
349         JSPandaFileManager::GetInstance()->LoadJSPandaFile(thread, moduleFileName, recordName.c_str());
350     if (jsPandaFile == nullptr) {
351         CString msg = "Load file with filename '" + moduleFileName + "' failed, recordName '" + recordName + "'";
352         THROW_NEW_ERROR_AND_RETURN_HANDLE(thread, ErrorType::REFERENCE_ERROR, JSTaggedValue, msg.c_str());
353     }
354 
355     JSHandle<JSTaggedValue> moduleRecord = ResolveModuleWithMerge(thread, jsPandaFile, recordName);
356     RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
357     JSHandle<NameDictionary> handleDict(thread, resolvedModules_);
358     resolvedModules_ = NameDictionary::Put(thread, handleDict,JSHandle<JSTaggedValue>(recordNameHandle),
359         JSHandle<JSTaggedValue>(moduleRecord), PropertyAttributes::Default()).GetTaggedValue();
360 
361     return moduleRecord;
362 }
363 
HostResolveImportedModule(const CString & referencingModule)364 JSHandle<JSTaggedValue> ModuleManager::HostResolveImportedModule(const CString &referencingModule)
365 {
366     JSThread *thread = vm_->GetJSThread();
367     ObjectFactory *factory = vm_->GetFactory();
368 
369     JSHandle<EcmaString> referencingHandle = factory->NewFromUtf8(referencingModule);
370     CString moduleFileName = referencingModule;
371     if (vm_->IsBundlePack()) {
372         if (AOTFileManager::GetAbsolutePath(referencingModule, moduleFileName)) {
373             referencingHandle = factory->NewFromUtf8(moduleFileName);
374         } else {
375             CString msg = "Parse absolute " + referencingModule + " path failed";
376             THROW_NEW_ERROR_AND_RETURN_HANDLE(thread, ErrorType::REFERENCE_ERROR, JSTaggedValue, msg.c_str());
377         }
378     }
379 
380     NameDictionary *dict = NameDictionary::Cast(resolvedModules_.GetTaggedObject());
381     int entry = dict->FindEntry(referencingHandle.GetTaggedValue());
382     if (entry != -1) {
383         return JSHandle<JSTaggedValue>(thread, dict->GetValue(entry));
384     }
385 
386     const JSPandaFile *jsPandaFile =
387         JSPandaFileManager::GetInstance()->LoadJSPandaFile(thread, moduleFileName, JSPandaFile::ENTRY_MAIN_FUNCTION);
388     if (jsPandaFile == nullptr) {
389         CString msg = "Load file with filename '" + moduleFileName + "' failed";
390         THROW_NEW_ERROR_AND_RETURN_HANDLE(thread, ErrorType::REFERENCE_ERROR, JSTaggedValue, msg.c_str());
391     }
392 
393     return ResolveModule(thread, jsPandaFile);
394 }
395 
HostResolveImportedModule(const void * buffer,size_t size,const CString & filename)396 JSHandle<JSTaggedValue> ModuleManager::HostResolveImportedModule(const void *buffer, size_t size,
397                                                                  const CString &filename)
398 {
399     JSThread *thread = vm_->GetJSThread();
400     ObjectFactory *factory = vm_->GetFactory();
401 
402     JSHandle<EcmaString> referencingHandle = factory->NewFromUtf8(filename);
403     NameDictionary *dict = NameDictionary::Cast(resolvedModules_.GetTaggedObject());
404     int entry = dict->FindEntry(referencingHandle.GetTaggedValue());
405     if (entry != -1) {
406         return JSHandle<JSTaggedValue>(thread, dict->GetValue(entry));
407     }
408 
409     const JSPandaFile *jsPandaFile =
410         JSPandaFileManager::GetInstance()->LoadJSPandaFile(thread, filename,
411                                                            JSPandaFile::ENTRY_MAIN_FUNCTION, buffer, size);
412     if (jsPandaFile == nullptr) {
413         CString msg = "Load file with filename '" + filename + "' failed";
414         THROW_NEW_ERROR_AND_RETURN_HANDLE(thread, ErrorType::REFERENCE_ERROR, JSTaggedValue, msg.c_str());
415     }
416 
417     return ResolveModule(thread, jsPandaFile);
418 }
419 
ResolveModule(JSThread * thread,const JSPandaFile * jsPandaFile)420 JSHandle<JSTaggedValue> ModuleManager::ResolveModule(JSThread *thread, const JSPandaFile *jsPandaFile)
421 {
422     ObjectFactory *factory = vm_->GetFactory();
423     CString moduleFileName = jsPandaFile->GetJSPandaFileDesc();
424     JSHandle<JSTaggedValue> moduleRecord = thread->GlobalConstants()->GetHandledUndefined();
425     if (jsPandaFile->IsModule(thread)) {
426         moduleRecord = ModuleDataExtractor::ParseModule(thread, jsPandaFile, moduleFileName, moduleFileName);
427     } else if (jsPandaFile->IsJson(thread)) {
428         moduleRecord = ModuleDataExtractor::ParseJsonModule(thread, jsPandaFile, moduleFileName);
429     } else {
430         ASSERT(jsPandaFile->IsCjs(thread));
431         moduleRecord = ModuleDataExtractor::ParseCjsModule(thread, jsPandaFile);
432     }
433 
434     JSHandle<NameDictionary> dict(thread, resolvedModules_);
435     JSHandle<JSTaggedValue> referencingHandle = JSHandle<JSTaggedValue>::Cast(factory->NewFromUtf8(moduleFileName));
436     resolvedModules_ =
437         NameDictionary::Put(thread, dict, referencingHandle, moduleRecord, PropertyAttributes::Default())
438         .GetTaggedValue();
439     return moduleRecord;
440 }
441 
ResolveNativeModule(const CString & moduleRequestName,ModuleTypes moduleType)442 JSHandle<SourceTextModule> ModuleManager::ResolveNativeModule(const CString &moduleRequestName, ModuleTypes moduleType)
443 {
444     ObjectFactory *factory = vm_->GetFactory();
445     JSThread *thread = vm_->GetJSThread();
446 
447     JSHandle<JSTaggedValue> referencingModule(factory->NewFromUtf8(moduleRequestName));
448     JSHandle<JSTaggedValue> moduleRecord = ModuleDataExtractor::ParseNativeModule(thread,
449         moduleRequestName, moduleType);
450     JSHandle<NameDictionary> dict(thread, resolvedModules_);
451     resolvedModules_ = NameDictionary::Put(thread, dict, referencingModule, moduleRecord,
452         PropertyAttributes::Default()).GetTaggedValue();
453     return JSHandle<SourceTextModule>::Cast(moduleRecord);
454 }
455 
ResolveModuleWithMerge(JSThread * thread,const JSPandaFile * jsPandaFile,const CString & recordName)456 JSHandle<JSTaggedValue> ModuleManager::ResolveModuleWithMerge(JSThread *thread, const JSPandaFile *jsPandaFile,
457                                                               const CString &recordName)
458 {
459     ObjectFactory *factory = vm_->GetFactory();
460     CString moduleFileName = jsPandaFile->GetJSPandaFileDesc();
461     JSHandle<JSTaggedValue> moduleRecord = thread->GlobalConstants()->GetHandledUndefined();
462     if (jsPandaFile->IsModule(thread, recordName)) {
463         RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
464         moduleRecord = ModuleDataExtractor::ParseModule(thread, jsPandaFile, recordName, moduleFileName);
465     } else if (jsPandaFile->IsJson(thread, recordName)) {
466         moduleRecord = ModuleDataExtractor::ParseJsonModule(thread, jsPandaFile, moduleFileName, recordName);
467     } else {
468         ASSERT(jsPandaFile->IsCjs(thread, recordName));
469         RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
470         moduleRecord = ModuleDataExtractor::ParseCjsModule(thread, jsPandaFile);
471     }
472 
473     JSHandle<JSTaggedValue> recordNameHandle = JSHandle<JSTaggedValue>::Cast(factory->NewFromUtf8(recordName));
474     JSHandle<SourceTextModule>::Cast(moduleRecord)->SetEcmaModuleRecordName(thread, recordNameHandle);
475     return moduleRecord;
476 }
477 
AddResolveImportedModule(const JSPandaFile * jsPandaFile,const CString & referencingModule)478 void ModuleManager::AddResolveImportedModule(const JSPandaFile *jsPandaFile, const CString &referencingModule)
479 {
480     JSThread *thread = vm_->GetJSThread();
481     JSHandle<JSTaggedValue> moduleRecord =
482         ModuleDataExtractor::ParseModule(thread, jsPandaFile, referencingModule, referencingModule);
483     AddResolveImportedModule(referencingModule, moduleRecord);
484 }
485 
AddResolveImportedModule(const CString & referencingModule,JSHandle<JSTaggedValue> moduleRecord)486 void ModuleManager::AddResolveImportedModule(const CString &referencingModule, JSHandle<JSTaggedValue> moduleRecord)
487 {
488     JSThread *thread = vm_->GetJSThread();
489     ObjectFactory *factory = vm_->GetFactory();
490     JSHandle<JSTaggedValue> referencingHandle(factory->NewFromUtf8(referencingModule));
491     JSHandle<NameDictionary> dict(thread, resolvedModules_);
492     resolvedModules_ =
493         NameDictionary::Put(thread, dict, referencingHandle, moduleRecord, PropertyAttributes::Default())
494         .GetTaggedValue();
495 }
496 
GetModuleNamespace(int32_t index)497 JSTaggedValue ModuleManager::GetModuleNamespace(int32_t index)
498 {
499     JSTaggedValue currentModule = GetCurrentModule();
500     return GetModuleNamespaceInternal(index, currentModule);
501 }
502 
GetModuleNamespace(int32_t index,JSTaggedValue currentFunc)503 JSTaggedValue ModuleManager::GetModuleNamespace(int32_t index, JSTaggedValue currentFunc)
504 {
505     JSTaggedValue currentModule = JSFunction::Cast(currentFunc.GetTaggedObject())->GetModule();
506     return GetModuleNamespaceInternal(index, currentModule);
507 }
508 
GetModuleNamespaceInternal(int32_t index,JSTaggedValue currentModule)509 JSTaggedValue ModuleManager::GetModuleNamespaceInternal(int32_t index, JSTaggedValue currentModule)
510 {
511     if (currentModule.IsUndefined()) {
512         LOG_FULL(FATAL) << "GetModuleNamespace currentModule failed";
513         UNREACHABLE();
514     }
515     JSThread *thread = vm_->GetJSThread();
516     SourceTextModule *module = SourceTextModule::Cast(currentModule.GetTaggedObject());
517     JSTaggedValue requestedModule = module->GetRequestedModules();
518     JSTaggedValue moduleName = TaggedArray::Cast(requestedModule.GetTaggedObject())->Get(index);
519     JSTaggedValue moduleRecordName = module->GetEcmaModuleRecordName();
520     JSHandle<JSTaggedValue> requiredModule;
521     if (moduleRecordName.IsUndefined()) {
522         requiredModule = SourceTextModule::HostResolveImportedModule(thread,
523             JSHandle<SourceTextModule>(thread, module), JSHandle<JSTaggedValue>(thread, moduleName));
524     } else {
525         ASSERT(moduleRecordName.IsString());
526         requiredModule = SourceTextModule::HostResolveImportedModuleWithMerge(thread,
527             JSHandle<SourceTextModule>(thread, module), JSHandle<JSTaggedValue>(thread, moduleName));
528     }
529     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception());
530     JSHandle<SourceTextModule> requiredModuleST = JSHandle<SourceTextModule>::Cast(requiredModule);
531     ModuleTypes moduleType = requiredModuleST->GetTypes();
532     // if requiredModuleST is Native module
533     if (ModuleManager::IsNativeModule(moduleType)) {
534         return SourceTextModule::Cast(requiredModuleST.GetTaggedValue())->GetModuleValue(thread, 0, false);
535     }
536     // if requiredModuleST is CommonJS
537     if (moduleType == ModuleTypes::CJS_MODULE) {
538         JSHandle<JSTaggedValue> cjsModuleName(thread, GetModuleName(requiredModuleST.GetTaggedValue()));
539         return CjsModule::SearchFromModuleCache(thread, cjsModuleName).GetTaggedValue();
540     }
541 
542     // if requiredModuleST is ESM
543     JSHandle<JSTaggedValue> moduleNamespace = SourceTextModule::GetModuleNamespace(thread, requiredModuleST);
544     ASSERT(moduleNamespace->IsModuleNamespace());
545     return moduleNamespace.GetTaggedValue();
546 }
547 
GetModuleNamespace(JSTaggedValue localName)548 JSTaggedValue ModuleManager::GetModuleNamespace(JSTaggedValue localName)
549 {
550     JSTaggedValue currentModule = GetCurrentModule();
551     return GetModuleNamespaceInternal(localName, currentModule);
552 }
553 
GetModuleNamespace(JSTaggedValue localName,JSTaggedValue currentFunc)554 JSTaggedValue ModuleManager::GetModuleNamespace(JSTaggedValue localName, JSTaggedValue currentFunc)
555 {
556     JSTaggedValue currentModule = JSFunction::Cast(currentFunc.GetTaggedObject())->GetModule();
557     return GetModuleNamespaceInternal(localName, currentModule);
558 }
559 
GetModuleNamespaceInternal(JSTaggedValue localName,JSTaggedValue currentModule)560 JSTaggedValue ModuleManager::GetModuleNamespaceInternal(JSTaggedValue localName, JSTaggedValue currentModule)
561 {
562     if (currentModule.IsUndefined()) {
563         LOG_FULL(FATAL) << "GetModuleNamespace currentModule failed";
564         UNREACHABLE();
565     }
566     JSTaggedValue moduleEnvironment = SourceTextModule::Cast(currentModule.GetTaggedObject())->GetEnvironment();
567     if (moduleEnvironment.IsUndefined()) {
568         return vm_->GetJSThread()->GlobalConstants()->GetUndefined();
569     }
570     int entry = NameDictionary::Cast(moduleEnvironment.GetTaggedObject())->FindEntry(localName);
571     if (entry == -1) {
572         return vm_->GetJSThread()->GlobalConstants()->GetUndefined();
573     }
574     JSTaggedValue moduleNamespace = NameDictionary::Cast(moduleEnvironment.GetTaggedObject())->GetValue(entry);
575     ASSERT(moduleNamespace.IsModuleNamespace());
576     return moduleNamespace;
577 }
578 
Iterate(const RootVisitor & v)579 void ModuleManager::Iterate(const RootVisitor &v)
580 {
581     v(Root::ROOT_VM, ObjectSlot(reinterpret_cast<uintptr_t>(&resolvedModules_)));
582 }
583 
GetRecordName(JSTaggedValue module)584 CString ModuleManager::GetRecordName(JSTaggedValue module)
585 {
586     CString entry = "";
587     if (module.IsString()) {
588         entry = ConvertToString(module);
589     }
590     if (module.IsSourceTextModule()) {
591         SourceTextModule *sourceTextModule = SourceTextModule::Cast(module.GetTaggedObject());
592         if (sourceTextModule->GetEcmaModuleRecordName().IsString()) {
593             entry = ConvertToString(sourceTextModule->GetEcmaModuleRecordName());
594         }
595     }
596     return entry;
597 }
598 
GetExportObjectIndex(EcmaVM * vm,JSHandle<SourceTextModule> ecmaModule,const std::string & key)599 int ModuleManager::GetExportObjectIndex(EcmaVM *vm, JSHandle<SourceTextModule> ecmaModule,
600                                         const std::string &key)
601 {
602     JSThread *thread = vm->GetJSThread();
603     JSHandle<TaggedArray> localExportEntries = JSHandle<TaggedArray>(thread, ecmaModule->GetLocalExportEntries());
604     size_t exportEntriesLen = localExportEntries->GetLength();
605     // 0: There's only one export value "default"
606     int index = 0;
607     JSMutableHandle<LocalExportEntry> ee(thread, thread->GlobalConstants()->GetUndefined());
608     if (exportEntriesLen > 1) { // 1:  The number of export objects exceeds 1
609         for (size_t idx = 0; idx < exportEntriesLen; idx++) {
610             ee.Update(localExportEntries->Get(idx));
611             if (EcmaStringAccessor(ee->GetExportName()).ToStdString() == key) {
612                 ASSERT(idx <= static_cast<size_t>(INT_MAX));
613                 index = static_cast<int>(ee->GetLocalIndex());
614                 break;
615             }
616         }
617     }
618     return index;
619 }
620 
JsonParse(JSThread * thread,const JSPandaFile * jsPandaFile,CString entryPoint)621 JSTaggedValue ModuleManager::JsonParse(JSThread *thread, const JSPandaFile *jsPandaFile, CString entryPoint)
622 {
623     JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
624     EcmaRuntimeCallInfo *info =
625         EcmaInterpreter::NewRuntimeCallInfo(
626             thread, undefined, undefined, undefined, 1); // 1 : argument numbers
627     CString value = jsPandaFile->GetJsonStringId(thread, entryPoint);
628     JSHandle<JSTaggedValue> arg0(thread->GetEcmaVM()->GetFactory()->NewFromASCII(value));
629     info->SetCallArg(arg0.GetTaggedValue());
630     return BuiltinsJson::Parse(info);
631 }
632 
CheckNativeModule(const CString & moduleRequestName)633 std::pair<bool, ModuleTypes> ModuleManager::CheckNativeModule(const CString &moduleRequestName)
634 {
635     if (moduleRequestName.compare(0, OHOS_PREFIX_SIZE, REQUIRE_NAPI_OHOS_PREFIX) == 0) {
636         return {true, ModuleTypes::OHOS_MODULE};
637     } else if (moduleRequestName.compare(0, APP_PREFIX_SIZE, REQUIRE_NAPI_APP_PREFIX) == 0) {
638         return {true, ModuleTypes::APP_MODULE};
639     } else if (moduleRequestName.compare(0, NATIVE_PREFIX_SIZE, REQUIRE_NAITVE_MODULE_PREFIX) == 0) {
640         return {true, ModuleTypes::NATIVE_MODULE};
641     } else {
642         return {false, ModuleTypes::UNKNOWN};
643     }
644 }
645 
GetStrippedModuleName(const CString & moduleRequestName)646 CString ModuleManager::GetStrippedModuleName(const CString &moduleRequestName)
647 {
648     size_t pos = 0;
649     if (moduleRequestName.compare(0, OHOS_PREFIX_SIZE, REQUIRE_NAPI_OHOS_PREFIX) == 0) {
650         pos = OHOS_PREFIX_SIZE;
651     } else if (moduleRequestName.compare(0, APP_PREFIX_SIZE, REQUIRE_NAPI_APP_PREFIX) == 0) {
652         pos = APP_PREFIX_SIZE;
653     } else if (moduleRequestName.compare(0, NATIVE_PREFIX_SIZE, REQUIRE_NAITVE_MODULE_PREFIX) == 0) {
654         pos = NATIVE_PREFIX_SIZE;
655     } else {
656         LOG_FULL(FATAL) << "Unknown format " << moduleRequestName;
657         UNREACHABLE();
658     }
659     return moduleRequestName.substr(pos);
660 }
661 
GetRequireNativeModuleFunc(EcmaVM * vm,ModuleTypes moduleType)662 Local<JSValueRef> ModuleManager::GetRequireNativeModuleFunc(EcmaVM *vm, ModuleTypes moduleType)
663 {
664     Local<ObjectRef> globalObject = JSNApi::GetGlobalObject(vm);
665     auto globalConstants = vm->GetJSThread()->GlobalConstants();
666     auto funcName = (moduleType == ModuleTypes::NATIVE_MODULE) ?
667         globalConstants->GetHandledRequireNativeModuleString() :
668         globalConstants->GetHandledRequireNapiString();
669     return globalObject->Get(vm, JSNApiHelper::ToLocal<StringRef>(funcName));
670 }
671 
LoadNativeModule(JSThread * thread,JSHandle<SourceTextModule> & requiredModule,const JSHandle<JSTaggedValue> & moduleRequest,ModuleTypes moduleType)672 bool ModuleManager::LoadNativeModule(JSThread *thread, JSHandle<SourceTextModule> &requiredModule,
673     const JSHandle<JSTaggedValue> &moduleRequest, ModuleTypes moduleType)
674 {
675     EcmaVM *vm = thread->GetEcmaVM();
676     LocalScope scope(vm);
677 
678     CString moduleRequestName = ConvertToString(EcmaString::Cast(moduleRequest->GetTaggedObject()));
679     CString moduleName = GetStrippedModuleName(moduleRequestName);
680     std::vector<Local<JSValueRef>> arguments;
681     LOG_FULL(DEBUG) << "Request module is " << moduleRequestName;
682 
683     arguments.emplace_back(StringRef::NewFromUtf8(vm, moduleName.c_str()));
684     if (moduleType == ModuleTypes::APP_MODULE) {
685         size_t pos = moduleName.find_last_of('/');
686         if (pos == CString::npos) {
687             LOG_FULL(FATAL) << "Invalid native module " << moduleName;
688             UNREACHABLE();
689         }
690         CString soName = moduleName.substr(pos + 1);
691         CString path = moduleName.substr(0, pos);
692         // use module name as so name
693         arguments[0] = StringRef::NewFromUtf8(vm, soName.c_str());
694         arguments.emplace_back(BooleanRef::New(vm, true));
695         arguments.emplace_back(StringRef::NewFromUtf8(vm, path.c_str()));
696     }
697 
698     auto maybeFuncRef = GetRequireNativeModuleFunc(vm, moduleType);
699     // some function(s) may not registered in global object for non-main thread
700     if (!maybeFuncRef->IsFunction()) {
701         LOG_FULL(WARN) << "Not found require func";
702         return false;
703     }
704 
705     Local<FunctionRef> funcRef = maybeFuncRef;
706     auto exportObject = funcRef->Call(vm, JSValueRef::Undefined(vm), arguments.data(), arguments.size());
707     if (UNLIKELY(thread->HasPendingException())) {
708         thread->ClearException();
709         LOG_FULL(ERROR) << "LoadNativeModule has exception";
710         return false;
711     }
712     requiredModule->StoreModuleValue(thread, 0, JSNApiHelper::ToJSHandle(exportObject));
713     return true;
714 }
715 } // namespace panda::ecmascript
716