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> ¤tModule,
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> ¤tModule,
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())
360 .GetTaggedValue();
361
362 return moduleRecord;
363 }
364
HostResolveImportedModule(const CString & referencingModule)365 JSHandle<JSTaggedValue> ModuleManager::HostResolveImportedModule(const CString &referencingModule)
366 {
367 JSThread *thread = vm_->GetJSThread();
368 ObjectFactory *factory = vm_->GetFactory();
369
370 JSHandle<EcmaString> referencingHandle = factory->NewFromUtf8(referencingModule);
371 CString moduleFileName = referencingModule;
372 if (vm_->IsBundlePack()) {
373 if (AOTFileManager::GetAbsolutePath(referencingModule, moduleFileName)) {
374 referencingHandle = factory->NewFromUtf8(moduleFileName);
375 } else {
376 CString msg = "Parse absolute " + referencingModule + " path failed";
377 THROW_NEW_ERROR_AND_RETURN_HANDLE(thread, ErrorType::REFERENCE_ERROR, JSTaggedValue, msg.c_str());
378 }
379 }
380
381 NameDictionary *dict = NameDictionary::Cast(resolvedModules_.GetTaggedObject());
382 int entry = dict->FindEntry(referencingHandle.GetTaggedValue());
383 if (entry != -1) {
384 return JSHandle<JSTaggedValue>(thread, dict->GetValue(entry));
385 }
386
387 const JSPandaFile *jsPandaFile =
388 JSPandaFileManager::GetInstance()->LoadJSPandaFile(thread, moduleFileName, JSPandaFile::ENTRY_MAIN_FUNCTION);
389 if (jsPandaFile == nullptr) {
390 CString msg = "Load file with filename '" + moduleFileName + "' failed";
391 THROW_NEW_ERROR_AND_RETURN_HANDLE(thread, ErrorType::REFERENCE_ERROR, JSTaggedValue, msg.c_str());
392 }
393
394 return ResolveModule(thread, jsPandaFile);
395 }
396
HostResolveImportedModule(const void * buffer,size_t size,const CString & filename)397 JSHandle<JSTaggedValue> ModuleManager::HostResolveImportedModule(const void *buffer, size_t size,
398 const CString &filename)
399 {
400 JSThread *thread = vm_->GetJSThread();
401 ObjectFactory *factory = vm_->GetFactory();
402
403 JSHandle<EcmaString> referencingHandle = factory->NewFromUtf8(filename);
404 NameDictionary *dict = NameDictionary::Cast(resolvedModules_.GetTaggedObject());
405 int entry = dict->FindEntry(referencingHandle.GetTaggedValue());
406 if (entry != -1) {
407 return JSHandle<JSTaggedValue>(thread, dict->GetValue(entry));
408 }
409
410 const JSPandaFile *jsPandaFile =
411 JSPandaFileManager::GetInstance()->LoadJSPandaFile(thread, filename,
412 JSPandaFile::ENTRY_MAIN_FUNCTION, buffer, size);
413 if (jsPandaFile == nullptr) {
414 CString msg = "Load file with filename '" + filename + "' failed";
415 THROW_NEW_ERROR_AND_RETURN_HANDLE(thread, ErrorType::REFERENCE_ERROR, JSTaggedValue, msg.c_str());
416 }
417
418 return ResolveModule(thread, jsPandaFile);
419 }
420
ResolveModule(JSThread * thread,const JSPandaFile * jsPandaFile)421 JSHandle<JSTaggedValue> ModuleManager::ResolveModule(JSThread *thread, const JSPandaFile *jsPandaFile)
422 {
423 ObjectFactory *factory = vm_->GetFactory();
424 CString moduleFileName = jsPandaFile->GetJSPandaFileDesc();
425 JSHandle<JSTaggedValue> moduleRecord = thread->GlobalConstants()->GetHandledUndefined();
426 if (jsPandaFile->IsModule(thread)) {
427 moduleRecord = ModuleDataExtractor::ParseModule(thread, jsPandaFile, moduleFileName, moduleFileName);
428 } else if (jsPandaFile->IsJson(thread)) {
429 moduleRecord = ModuleDataExtractor::ParseJsonModule(thread, jsPandaFile, moduleFileName);
430 } else {
431 ASSERT(jsPandaFile->IsCjs(thread));
432 moduleRecord = ModuleDataExtractor::ParseCjsModule(thread, jsPandaFile);
433 }
434
435 JSHandle<NameDictionary> dict(thread, resolvedModules_);
436 JSHandle<JSTaggedValue> referencingHandle = JSHandle<JSTaggedValue>::Cast(factory->NewFromUtf8(moduleFileName));
437 resolvedModules_ =
438 NameDictionary::Put(thread, dict, referencingHandle, moduleRecord, PropertyAttributes::Default())
439 .GetTaggedValue();
440 return moduleRecord;
441 }
442
ResolveNativeModule(const CString & moduleRequestName,ModuleTypes moduleType)443 JSHandle<SourceTextModule> ModuleManager::ResolveNativeModule(const CString &moduleRequestName, ModuleTypes moduleType)
444 {
445 ObjectFactory *factory = vm_->GetFactory();
446 JSThread *thread = vm_->GetJSThread();
447
448 JSHandle<JSTaggedValue> referencingModule(factory->NewFromUtf8(moduleRequestName));
449 JSHandle<JSTaggedValue> moduleRecord = ModuleDataExtractor::ParseNativeModule(thread,
450 moduleRequestName, moduleType);
451 JSHandle<NameDictionary> dict(thread, resolvedModules_);
452 resolvedModules_ = NameDictionary::Put(thread, dict, referencingModule, moduleRecord,
453 PropertyAttributes::Default()).GetTaggedValue();
454 return JSHandle<SourceTextModule>::Cast(moduleRecord);
455 }
456
ResolveModuleWithMerge(JSThread * thread,const JSPandaFile * jsPandaFile,const CString & recordName)457 JSHandle<JSTaggedValue> ModuleManager::ResolveModuleWithMerge(JSThread *thread, const JSPandaFile *jsPandaFile,
458 const CString &recordName)
459 {
460 ObjectFactory *factory = vm_->GetFactory();
461 CString moduleFileName = jsPandaFile->GetJSPandaFileDesc();
462 JSHandle<JSTaggedValue> moduleRecord = thread->GlobalConstants()->GetHandledUndefined();
463 if (jsPandaFile->IsModule(thread, recordName)) {
464 RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
465 moduleRecord = ModuleDataExtractor::ParseModule(thread, jsPandaFile, recordName, moduleFileName);
466 } else if (jsPandaFile->IsJson(thread, recordName)) {
467 moduleRecord = ModuleDataExtractor::ParseJsonModule(thread, jsPandaFile, moduleFileName, recordName);
468 } else {
469 ASSERT(jsPandaFile->IsCjs(thread, recordName));
470 RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
471 moduleRecord = ModuleDataExtractor::ParseCjsModule(thread, jsPandaFile);
472 }
473
474 JSHandle<JSTaggedValue> recordNameHandle = JSHandle<JSTaggedValue>::Cast(factory->NewFromUtf8(recordName));
475 JSHandle<SourceTextModule>::Cast(moduleRecord)->SetEcmaModuleRecordName(thread, recordNameHandle);
476 return moduleRecord;
477 }
478
AddResolveImportedModule(const JSPandaFile * jsPandaFile,const CString & referencingModule)479 void ModuleManager::AddResolveImportedModule(const JSPandaFile *jsPandaFile, const CString &referencingModule)
480 {
481 JSThread *thread = vm_->GetJSThread();
482 JSHandle<JSTaggedValue> moduleRecord =
483 ModuleDataExtractor::ParseModule(thread, jsPandaFile, referencingModule, referencingModule);
484 AddResolveImportedModule(referencingModule, moduleRecord);
485 }
486
AddResolveImportedModule(const CString & referencingModule,JSHandle<JSTaggedValue> moduleRecord)487 void ModuleManager::AddResolveImportedModule(const CString &referencingModule, JSHandle<JSTaggedValue> moduleRecord)
488 {
489 JSThread *thread = vm_->GetJSThread();
490 ObjectFactory *factory = vm_->GetFactory();
491 JSHandle<JSTaggedValue> referencingHandle(factory->NewFromUtf8(referencingModule));
492 JSHandle<NameDictionary> dict(thread, resolvedModules_);
493 resolvedModules_ =
494 NameDictionary::Put(thread, dict, referencingHandle, moduleRecord, PropertyAttributes::Default())
495 .GetTaggedValue();
496 }
497
GetModuleNamespace(int32_t index)498 JSTaggedValue ModuleManager::GetModuleNamespace(int32_t index)
499 {
500 JSTaggedValue currentModule = GetCurrentModule();
501 return GetModuleNamespaceInternal(index, currentModule);
502 }
503
GetModuleNamespace(int32_t index,JSTaggedValue currentFunc)504 JSTaggedValue ModuleManager::GetModuleNamespace(int32_t index, JSTaggedValue currentFunc)
505 {
506 JSTaggedValue currentModule = JSFunction::Cast(currentFunc.GetTaggedObject())->GetModule();
507 return GetModuleNamespaceInternal(index, currentModule);
508 }
509
GetModuleNamespaceInternal(int32_t index,JSTaggedValue currentModule)510 JSTaggedValue ModuleManager::GetModuleNamespaceInternal(int32_t index, JSTaggedValue currentModule)
511 {
512 if (currentModule.IsUndefined()) {
513 LOG_FULL(FATAL) << "GetModuleNamespace currentModule failed";
514 UNREACHABLE();
515 }
516 JSThread *thread = vm_->GetJSThread();
517 SourceTextModule *module = SourceTextModule::Cast(currentModule.GetTaggedObject());
518 JSTaggedValue requestedModule = module->GetRequestedModules();
519 JSTaggedValue moduleName = TaggedArray::Cast(requestedModule.GetTaggedObject())->Get(index);
520 JSTaggedValue moduleRecordName = module->GetEcmaModuleRecordName();
521 JSHandle<JSTaggedValue> requiredModule;
522 if (moduleRecordName.IsUndefined()) {
523 requiredModule = SourceTextModule::HostResolveImportedModule(thread,
524 JSHandle<SourceTextModule>(thread, module), JSHandle<JSTaggedValue>(thread, moduleName));
525 } else {
526 ASSERT(moduleRecordName.IsString());
527 requiredModule = SourceTextModule::HostResolveImportedModuleWithMerge(thread,
528 JSHandle<SourceTextModule>(thread, module), JSHandle<JSTaggedValue>(thread, moduleName));
529 }
530 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception());
531 JSHandle<SourceTextModule> requiredModuleST = JSHandle<SourceTextModule>::Cast(requiredModule);
532 ModuleTypes moduleType = requiredModuleST->GetTypes();
533 // if requiredModuleST is Native module
534 if (ModuleManager::IsNativeModule(moduleType)) {
535 return SourceTextModule::Cast(requiredModuleST.GetTaggedValue())->GetModuleValue(thread, 0, false);
536 }
537 // if requiredModuleST is CommonJS
538 if (moduleType == ModuleTypes::CJS_MODULE) {
539 JSHandle<JSTaggedValue> cjsModuleName(thread, GetModuleName(requiredModuleST.GetTaggedValue()));
540 return CjsModule::SearchFromModuleCache(thread, cjsModuleName).GetTaggedValue();
541 }
542
543 // if requiredModuleST is ESM
544 JSHandle<JSTaggedValue> moduleNamespace = SourceTextModule::GetModuleNamespace(thread, requiredModuleST);
545 ASSERT(moduleNamespace->IsModuleNamespace());
546 return moduleNamespace.GetTaggedValue();
547 }
548
GetModuleNamespace(JSTaggedValue localName)549 JSTaggedValue ModuleManager::GetModuleNamespace(JSTaggedValue localName)
550 {
551 JSTaggedValue currentModule = GetCurrentModule();
552 return GetModuleNamespaceInternal(localName, currentModule);
553 }
554
GetModuleNamespace(JSTaggedValue localName,JSTaggedValue currentFunc)555 JSTaggedValue ModuleManager::GetModuleNamespace(JSTaggedValue localName, JSTaggedValue currentFunc)
556 {
557 JSTaggedValue currentModule = JSFunction::Cast(currentFunc.GetTaggedObject())->GetModule();
558 return GetModuleNamespaceInternal(localName, currentModule);
559 }
560
GetModuleNamespaceInternal(JSTaggedValue localName,JSTaggedValue currentModule)561 JSTaggedValue ModuleManager::GetModuleNamespaceInternal(JSTaggedValue localName, JSTaggedValue currentModule)
562 {
563 if (currentModule.IsUndefined()) {
564 LOG_FULL(FATAL) << "GetModuleNamespace currentModule failed";
565 UNREACHABLE();
566 }
567 JSTaggedValue moduleEnvironment = SourceTextModule::Cast(currentModule.GetTaggedObject())->GetEnvironment();
568 if (moduleEnvironment.IsUndefined()) {
569 return vm_->GetJSThread()->GlobalConstants()->GetUndefined();
570 }
571 int entry = NameDictionary::Cast(moduleEnvironment.GetTaggedObject())->FindEntry(localName);
572 if (entry == -1) {
573 return vm_->GetJSThread()->GlobalConstants()->GetUndefined();
574 }
575 JSTaggedValue moduleNamespace = NameDictionary::Cast(moduleEnvironment.GetTaggedObject())->GetValue(entry);
576 ASSERT(moduleNamespace.IsModuleNamespace());
577 return moduleNamespace;
578 }
579
Iterate(const RootVisitor & v)580 void ModuleManager::Iterate(const RootVisitor &v)
581 {
582 v(Root::ROOT_VM, ObjectSlot(reinterpret_cast<uintptr_t>(&resolvedModules_)));
583 }
584
GetRecordName(JSTaggedValue module)585 CString ModuleManager::GetRecordName(JSTaggedValue module)
586 {
587 CString entry = "";
588 if (module.IsString()) {
589 entry = ConvertToString(module);
590 }
591 if (module.IsSourceTextModule()) {
592 SourceTextModule *sourceTextModule = SourceTextModule::Cast(module.GetTaggedObject());
593 if (sourceTextModule->GetEcmaModuleRecordName().IsString()) {
594 entry = ConvertToString(sourceTextModule->GetEcmaModuleRecordName());
595 }
596 }
597 return entry;
598 }
599
GetExportObjectIndex(EcmaVM * vm,JSHandle<SourceTextModule> ecmaModule,const std::string & key)600 int ModuleManager::GetExportObjectIndex(EcmaVM *vm, JSHandle<SourceTextModule> ecmaModule,
601 const std::string &key)
602 {
603 JSThread *thread = vm->GetJSThread();
604 JSHandle<TaggedArray> localExportEntries = JSHandle<TaggedArray>(thread, ecmaModule->GetLocalExportEntries());
605 size_t exportEntriesLen = localExportEntries->GetLength();
606 // 0: There's only one export value "default"
607 int index = 0;
608 JSMutableHandle<LocalExportEntry> ee(thread, thread->GlobalConstants()->GetUndefined());
609 if (exportEntriesLen > 1) { // 1: The number of export objects exceeds 1
610 for (size_t idx = 0; idx < exportEntriesLen; idx++) {
611 ee.Update(localExportEntries->Get(idx));
612 if (EcmaStringAccessor(ee->GetExportName()).ToStdString() == key) {
613 ASSERT(idx <= static_cast<size_t>(INT_MAX));
614 index = static_cast<int>(idx);
615 break;
616 }
617 }
618 }
619 return index;
620 }
621
JsonParse(JSThread * thread,const JSPandaFile * jsPandaFile,CString entryPoint)622 JSTaggedValue ModuleManager::JsonParse(JSThread *thread, const JSPandaFile *jsPandaFile, CString entryPoint)
623 {
624 JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
625 EcmaRuntimeCallInfo *info =
626 EcmaInterpreter::NewRuntimeCallInfo(
627 thread, undefined, undefined, undefined, 1); // 1 : argument numbers
628 CString value = jsPandaFile->GetJsonStringId(thread, entryPoint);
629 JSHandle<JSTaggedValue> arg0(thread->GetEcmaVM()->GetFactory()->NewFromASCII(value));
630 info->SetCallArg(arg0.GetTaggedValue());
631 return BuiltinsJson::Parse(info);
632 }
633
CheckNativeModule(const CString & moduleRequestName)634 std::pair<bool, ModuleTypes> ModuleManager::CheckNativeModule(const CString &moduleRequestName)
635 {
636 if (moduleRequestName.compare(0, OHOS_PREFIX_SIZE, REQUIRE_NAPI_OHOS_PREFIX) == 0) {
637 return {true, ModuleTypes::OHOS_MODULE};
638 } else if (moduleRequestName.compare(0, APP_PREFIX_SIZE, REQUIRE_NAPI_APP_PREFIX) == 0) {
639 return {true, ModuleTypes::APP_MODULE};
640 } else if (moduleRequestName.compare(0, NATIVE_PREFIX_SIZE, REQUIRE_NAITVE_MODULE_PREFIX) == 0) {
641 return {true, ModuleTypes::NATIVE_MODULE};
642 } else {
643 return {false, ModuleTypes::UNKNOWN};
644 }
645 }
646
GetStrippedModuleName(const CString & moduleRequestName)647 CString ModuleManager::GetStrippedModuleName(const CString &moduleRequestName)
648 {
649 size_t pos = 0;
650 if (moduleRequestName.compare(0, OHOS_PREFIX_SIZE, REQUIRE_NAPI_OHOS_PREFIX) == 0) {
651 pos = OHOS_PREFIX_SIZE;
652 } else if (moduleRequestName.compare(0, APP_PREFIX_SIZE, REQUIRE_NAPI_APP_PREFIX) == 0) {
653 pos = APP_PREFIX_SIZE;
654 } else if (moduleRequestName.compare(0, NATIVE_PREFIX_SIZE, REQUIRE_NAITVE_MODULE_PREFIX) == 0) {
655 pos = NATIVE_PREFIX_SIZE;
656 } else {
657 LOG_FULL(FATAL) << "Unknown format " << moduleRequestName;
658 UNREACHABLE();
659 }
660 return moduleRequestName.substr(pos);
661 }
662
GetRequireNativeModuleFunc(EcmaVM * vm,ModuleTypes moduleType)663 Local<JSValueRef> ModuleManager::GetRequireNativeModuleFunc(EcmaVM *vm, ModuleTypes moduleType)
664 {
665 Local<ObjectRef> globalObject = JSNApi::GetGlobalObject(vm);
666 auto globalConstants = vm->GetJSThread()->GlobalConstants();
667 auto funcName = (moduleType == ModuleTypes::NATIVE_MODULE) ?
668 globalConstants->GetHandledRequireNativeModuleString() :
669 globalConstants->GetHandledRequireNapiString();
670 return globalObject->Get(vm, JSNApiHelper::ToLocal<StringRef>(funcName));
671 }
672
LoadNativeModule(JSThread * thread,JSHandle<SourceTextModule> & requiredModule,const JSHandle<JSTaggedValue> & moduleRequest,ModuleTypes moduleType)673 bool ModuleManager::LoadNativeModule(JSThread *thread, JSHandle<SourceTextModule> &requiredModule,
674 const JSHandle<JSTaggedValue> &moduleRequest, ModuleTypes moduleType)
675 {
676 EcmaVM *vm = thread->GetEcmaVM();
677 LocalScope scope(vm);
678
679 CString moduleRequestName = ConvertToString(EcmaString::Cast(moduleRequest->GetTaggedObject()));
680 CString moduleName = GetStrippedModuleName(moduleRequestName);
681 std::vector<Local<JSValueRef>> arguments;
682 LOG_FULL(DEBUG) << "Request module is " << moduleRequestName;
683
684 arguments.emplace_back(StringRef::NewFromUtf8(vm, moduleName.c_str()));
685 if (moduleType == ModuleTypes::APP_MODULE) {
686 size_t pos = moduleName.find_last_of('/');
687 if (pos == CString::npos) {
688 LOG_FULL(FATAL) << "Invalid native module " << moduleName;
689 UNREACHABLE();
690 }
691 CString soName = moduleName.substr(pos + 1);
692 CString path = moduleName.substr(0, pos);
693 // use module name as so name
694 arguments[0] = StringRef::NewFromUtf8(vm, soName.c_str());
695 arguments.emplace_back(BooleanRef::New(vm, true));
696 arguments.emplace_back(StringRef::NewFromUtf8(vm, path.c_str()));
697 }
698
699 auto maybeFuncRef = GetRequireNativeModuleFunc(vm, moduleType);
700 // some function(s) may not registered in global object for non-main thread
701 if (!maybeFuncRef->IsFunction()) {
702 LOG_FULL(WARN) << "Not found require func";
703 return false;
704 }
705
706 Local<FunctionRef> funcRef = maybeFuncRef;
707 auto exportObject = funcRef->Call(vm, JSValueRef::Undefined(vm), arguments.data(), arguments.size());
708 if (UNLIKELY(thread->HasPendingException())) {
709 thread->ClearException();
710 LOG_FULL(ERROR) << "LoadNativeModule has exception";
711 return false;
712 }
713 requiredModule->StoreModuleValue(thread, 0, JSNApiHelper::ToJSHandle(exportObject));
714 return true;
715 }
716 } // namespace panda::ecmascript
717