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()).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