1 /*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "ecmascript/module/module_resolver.h"
17
18 #include "ecmascript/jspandafile/js_pandafile_manager.h"
19 #include "ecmascript/module/js_shared_module_manager.h"
20 #include "ecmascript/module/module_path_helper.h"
21 #include "ecmascript/module/js_module_deregister.h"
22 #include "ecmascript/module/module_data_extractor.h"
23 #include "ecmascript/object_fast_operator-inl.h"
24 #include "ecmascript/patch/quick_fix_manager.h"
25 #include "ecmascript/platform/module.h"
26
27 namespace panda::ecmascript {
HostResolveImportedModule(JSThread * thread,const JSHandle<SourceTextModule> & module,const JSHandle<JSTaggedValue> & moduleRequest,const ExecuteTypes & executeType)28 JSHandle<JSTaggedValue> ModuleResolver::HostResolveImportedModule(JSThread *thread,
29 const JSHandle<SourceTextModule> &module,
30 const JSHandle<JSTaggedValue> &moduleRequest,
31 const ExecuteTypes &executeType)
32 {
33 return module->GetEcmaModuleRecordNameString().empty() ?
34 HostResolveImportedModuleBundlePack(thread, module, moduleRequest, executeType) :
35 HostResolveImportedModuleWithMerge(thread, module, moduleRequest, executeType);
36 }
37
HostResolveImportedModule(JSThread * thread,const CString & fileName,const CString & recordName,const JSPandaFile * jsPandaFile,const ExecuteTypes & executeType)38 JSHandle<JSTaggedValue> ModuleResolver::HostResolveImportedModule(JSThread* thread,
39 const CString& fileName,
40 const CString& recordName,
41 const JSPandaFile* jsPandaFile,
42 const ExecuteTypes &executeType)
43 {
44 if (jsPandaFile == nullptr) {
45 std::shared_ptr<JSPandaFile> file =
46 JSPandaFileManager::GetInstance()->LoadJSPandaFile(thread, fileName, recordName, false, executeType);
47 RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
48 if (file == nullptr) {
49 CString msg = "Load file with filename '" + fileName + "' failed, recordName '" + recordName + "'";
50 THROW_NEW_ERROR_AND_RETURN_HANDLE(thread, ErrorType::REFERENCE_ERROR, JSTaggedValue, msg.c_str());
51 }
52 jsPandaFile = file.get();
53 }
54 return jsPandaFile->IsBundlePack() ?
55 HostResolveImportedModuleBundlePack(thread, fileName, executeType) :
56 HostResolveImportedModuleWithMerge(thread, fileName, recordName, jsPandaFile, executeType);
57 }
58
HostResolveImportedModule(JSThread * thread,const CString & fileName,const CString & recordName,const void * buffer,size_t size,const ExecuteTypes & executeType)59 JSHandle<JSTaggedValue> ModuleResolver::HostResolveImportedModule(JSThread* thread,
60 const CString& fileName,
61 const CString& recordName,
62 const void* buffer,
63 size_t size,
64 const ExecuteTypes &executeType)
65 {
66 std::shared_ptr<JSPandaFile> jsPandaFile =
67 JSPandaFileManager::GetInstance()->LoadJSPandaFile(thread, fileName, recordName, buffer, size);
68 RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
69 if (jsPandaFile == nullptr) {
70 CString msg = "Load file with filename '" + fileName + "' failed, recordName '" + recordName + "'";
71 THROW_NEW_ERROR_AND_RETURN_HANDLE(thread, ErrorType::REFERENCE_ERROR, JSTaggedValue, msg.c_str());
72 }
73 return jsPandaFile->IsBundlePack() ?
74 HostResolveImportedModuleBundlePackBuffer(thread, fileName, jsPandaFile.get(), executeType) :
75 HostResolveImportedModuleWithMerge(thread, fileName, recordName, jsPandaFile.get(), executeType);
76 }
77
HostResolveImportedModuleWithMerge(JSThread * thread,const JSHandle<SourceTextModule> & module,const JSHandle<JSTaggedValue> & moduleRequest,const ExecuteTypes & executeType)78 JSHandle<JSTaggedValue> ModuleResolver::HostResolveImportedModuleWithMerge(JSThread *thread,
79 const JSHandle<SourceTextModule> &module,
80 const JSHandle<JSTaggedValue> &moduleRequest,
81 const ExecuteTypes &executeType)
82 {
83 CString moduleRequestName = ModulePathHelper::Utf8ConvertToString(moduleRequest.GetTaggedValue());
84 ReplaceModuleThroughFeature(thread, moduleRequestName);
85
86 CString baseFilename{};
87 StageOfHotReload stageOfHotReload = thread->GetCurrentEcmaContext()->GetStageOfHotReload();
88 if (stageOfHotReload == StageOfHotReload::BEGIN_EXECUTE_PATCHMAIN ||
89 stageOfHotReload == StageOfHotReload::LOAD_END_EXECUTE_PATCHMAIN) {
90 baseFilename = thread->GetEcmaVM()->GetQuickFixManager()->GetBaseFileName(module);
91 } else {
92 baseFilename = module->GetEcmaModuleFilenameString();
93 }
94
95 auto moduleManager = thread->GetCurrentEcmaContext()->GetModuleManager();
96 if (SourceTextModule::IsNativeModule(moduleRequestName)) {
97 JSHandle<JSTaggedValue> cachedModule = moduleManager->TryGetImportedModule(moduleRequestName);
98 if (!cachedModule->IsUndefined()) {
99 return cachedModule;
100 }
101 return ResolveNativeModule(thread, moduleRequestName, baseFilename,
102 SourceTextModule::GetNativeModuleType(moduleRequestName));
103 }
104 CString recordName = module->GetEcmaModuleRecordNameString();
105 std::shared_ptr<JSPandaFile> pandaFile =
106 JSPandaFileManager::GetInstance()->LoadJSPandaFile(thread, baseFilename, recordName, false, executeType);
107 RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
108 if (pandaFile == nullptr) { // LCOV_EXCL_BR_LINE
109 LOG_FULL(FATAL) << "Load current file's panda file failed. Current file is " << baseFilename;
110 }
111
112 CString entryPoint =
113 ModulePathHelper::ConcatFileNameWithMerge(thread, pandaFile.get(), baseFilename, recordName, moduleRequestName);
114 RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
115
116 JSHandle<JSTaggedValue> handle = CheckEntryPointPreview(thread, entryPoint);
117 if (handle != thread->GlobalConstants()->GetHandledNull()) {
118 return handle;
119 }
120 return HostResolveImportedModuleWithMerge(thread, baseFilename, entryPoint, nullptr, executeType);
121 }
122
HostResolveImportedModuleBundlePack(JSThread * thread,const JSHandle<SourceTextModule> & module,const JSHandle<JSTaggedValue> & moduleRequest,const ExecuteTypes & executeType)123 JSHandle<JSTaggedValue> ModuleResolver::HostResolveImportedModuleBundlePack(JSThread *thread,
124 const JSHandle<SourceTextModule> &module,
125 const JSHandle<JSTaggedValue> &moduleRequest,
126 const ExecuteTypes &executeType)
127 {
128 auto moduleManager = thread->GetCurrentEcmaContext()->GetModuleManager();
129 CString moduleRequestStr = ModulePathHelper::Utf8ConvertToString(moduleRequest.GetTaggedValue());
130 if (moduleManager->IsLocalModuleLoaded(moduleRequestStr)) {
131 return JSHandle<JSTaggedValue>(moduleManager->HostGetImportedModule(moduleRequestStr));
132 }
133
134 CString dirname = base::PathHelper::ResolveDirPath(module->GetEcmaModuleFilenameString());
135 CString moduleFilename = ResolveFilenameFromNative(thread, dirname, moduleRequestStr);
136 RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
137 return HostResolveImportedModuleBundlePack(thread, moduleFilename, executeType);
138 }
ReplaceModuleThroughFeature(JSThread * thread,CString & requestName)139 void ModuleResolver::ReplaceModuleThroughFeature(JSThread *thread, CString &requestName)
140 {
141 const auto vm = thread->GetEcmaVM();
142 // check if module need to be mock
143 if (vm->IsMockModule(requestName)) {
144 requestName = vm->GetMockModule(requestName);
145 }
146
147 // Load the replaced module, hms -> system hsp
148 if (vm->IsHmsModule(requestName)) {
149 requestName = vm->GetHmsModule(requestName);
150 }
151 }
152
ResolveSharedImportedModuleWithMerge(JSThread * thread,const CString & fileName,const CString & recordName,const JSPandaFile * jsPandaFile,JSRecordInfo * recordInfo)153 JSHandle<JSTaggedValue> ModuleResolver::ResolveSharedImportedModuleWithMerge(JSThread *thread,
154 const CString &fileName,
155 const CString &recordName,
156 const JSPandaFile *jsPandaFile,
157 [[maybe_unused]] JSRecordInfo *recordInfo)
158 {
159 auto sharedModuleManager = SharedModuleManager::GetInstance();
160 if (sharedModuleManager->SearchInSModuleManager(thread, recordName)) {
161 return JSHandle<JSTaggedValue>(sharedModuleManager->GetSModule(thread, recordName));
162 }
163 // before resolving module completely, shared-module put into isolate -thread resolvedModules_ temporarily.
164 ModuleManager *moduleManager = thread->GetCurrentEcmaContext()->GetModuleManager();
165 JSHandle<JSTaggedValue> module = moduleManager->TryGetImportedModule(recordName);
166 if (!module->IsUndefined()) {
167 return module;
168 }
169
170 ASSERT(jsPandaFile->IsModule(recordInfo));
171 JSHandle<JSTaggedValue> moduleRecord =
172 SharedModuleHelper::ParseSharedModule(thread, jsPandaFile, recordName, fileName, recordInfo);
173 JSHandle<SourceTextModule>::Cast(moduleRecord)->SetEcmaModuleRecordNameString(recordName);
174 moduleManager->AddResolveImportedModule(recordName, moduleRecord.GetTaggedValue());
175 moduleManager->AddToInstantiatingSModuleList(recordName);
176 return moduleRecord;
177 }
178
HostResolveImportedModuleForHotReload(JSThread * thread,const CString & moduleFileName,const CString & recordName,const ExecuteTypes & executeType)179 JSHandle<JSTaggedValue> ModuleResolver::HostResolveImportedModuleForHotReload(JSThread *thread,
180 const CString &moduleFileName,
181 const CString &recordName,
182 const ExecuteTypes &executeType)
183 {
184 std::shared_ptr<JSPandaFile> jsPandaFile =
185 JSPandaFileManager::GetInstance()->LoadJSPandaFile(thread, moduleFileName, recordName, false, executeType);
186 RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
187 if (jsPandaFile == nullptr) { // LCOV_EXCL_BR_LINE
188 LOG_FULL(FATAL) << "Load current file's panda file failed. Current file is " << moduleFileName;
189 }
190
191 JSRecordInfo *recordInfo = jsPandaFile->CheckAndGetRecordInfo(recordName);
192 if (recordInfo == nullptr) {
193 CString msg = "cannot find record '" + recordName + "',please check the request path.'" + moduleFileName + "'.";
194 THROW_NEW_ERROR_AND_RETURN_HANDLE(thread, ErrorType::REFERENCE_ERROR, JSTaggedValue, msg.c_str());
195 }
196
197 JSHandle<JSTaggedValue> moduleRecord =
198 ResolveModuleWithMerge(thread, jsPandaFile.get(), recordName, recordInfo, executeType);
199 RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
200 ModuleManager *moduleManager = thread->GetCurrentEcmaContext()->GetModuleManager();
201 moduleManager->UpdateResolveImportedModule(recordName, moduleRecord.GetTaggedValue());
202 return moduleRecord;
203 }
204
HostResolveImportedModuleWithMerge(JSThread * thread,const CString & moduleFileName,const CString & recordName,const JSPandaFile * jsPandaFile,const ExecuteTypes & executeType)205 JSHandle<JSTaggedValue> ModuleResolver::HostResolveImportedModuleWithMerge(JSThread *thread,
206 const CString &moduleFileName,
207 const CString &recordName,
208 const JSPandaFile *jsPandaFile,
209 const ExecuteTypes &executeType)
210 {
211 if (jsPandaFile == nullptr) {
212 std::shared_ptr<JSPandaFile> file =
213 JSPandaFileManager::GetInstance()->LoadJSPandaFile(thread, moduleFileName, recordName, false, executeType);
214 RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
215 if (file == nullptr) {
216 CString msg = "Load file with filename '" + moduleFileName + "' failed, recordName '" + recordName + "'";
217 THROW_NEW_ERROR_AND_RETURN_HANDLE(thread, ErrorType::REFERENCE_ERROR, JSTaggedValue, msg.c_str());
218 }
219 jsPandaFile = file.get();
220 }
221 JSRecordInfo *recordInfo = jsPandaFile->CheckAndGetRecordInfo(recordName);
222 if (recordInfo == nullptr) {
223 CString msg = "cannot find record '" + recordName + "',please check the request path.'" + moduleFileName + "'.";
224 THROW_NEW_ERROR_AND_RETURN_HANDLE(thread, ErrorType::REFERENCE_ERROR, JSTaggedValue, msg.c_str());
225 }
226
227 if (jsPandaFile->IsSharedModule(recordInfo)) {
228 return ResolveSharedImportedModuleWithMerge(thread, moduleFileName, recordName, jsPandaFile, recordInfo);
229 }
230 ModuleManager *moduleManager = thread->GetCurrentEcmaContext()->GetModuleManager();
231 JSHandle<JSTaggedValue> module = moduleManager->TryGetImportedModule(recordName);
232 if (!module->IsUndefined()) {
233 return module;
234 }
235 JSHandle<JSTaggedValue> moduleRecord =
236 ResolveModuleWithMerge(thread, jsPandaFile, recordName, recordInfo, executeType);
237 RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
238 moduleManager->AddResolveImportedModule(recordName, moduleRecord.GetTaggedValue());
239 return moduleRecord;
240 }
HostResolveImportedModuleBundlePackBuffer(JSThread * thread,const CString & referencingModule,const JSPandaFile * jsPandaFile,const ExecuteTypes & executeType)241 JSHandle<JSTaggedValue> ModuleResolver::HostResolveImportedModuleBundlePackBuffer(JSThread *thread,
242 const CString &referencingModule,
243 const JSPandaFile *jsPandaFile,
244 const ExecuteTypes &executeType)
245 {
246 ModuleManager *moduleManager = thread->GetCurrentEcmaContext()->GetModuleManager();
247 JSHandle<JSTaggedValue> module = moduleManager->TryGetImportedModule(referencingModule);
248 if (!module->IsUndefined()) {
249 return module;
250 }
251 return ResolveModuleBundlePack(thread, jsPandaFile, executeType);
252 }
HostResolveImportedModuleBundlePack(JSThread * thread,const CString & referencingModule,const ExecuteTypes & executeType)253 JSHandle<JSTaggedValue> ModuleResolver::HostResolveImportedModuleBundlePack(JSThread *thread,
254 const CString &referencingModule,
255 const ExecuteTypes &executeType)
256 {
257 ModuleManager *moduleManager = thread->GetCurrentEcmaContext()->GetModuleManager();
258 // Can not use jsPandaFile from js_pandafile_executor, need to construct with JSPandaFile::ENTRY_MAIN_FUNCTION
259 std::shared_ptr<JSPandaFile> jsPandaFile =
260 JSPandaFileManager::GetInstance()->LoadJSPandaFile(
261 thread, referencingModule, JSPandaFile::ENTRY_MAIN_FUNCTION, false, executeType);
262 RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
263 if (jsPandaFile == nullptr) { // LCOV_EXCL_BR_LINE
264 LOG_FULL(FATAL) << "Load current file's panda file failed. Current file is " << referencingModule;
265 }
266
267 [[maybe_unused]] JSRecordInfo *recordInfo = jsPandaFile->CheckAndGetRecordInfo(referencingModule);
268 ASSERT(recordInfo != nullptr && !jsPandaFile->IsSharedModule(recordInfo));
269
270 CString moduleFileName = referencingModule;
271 if (moduleManager->IsVMBundlePack()) {
272 if (!AOTFileManager::GetAbsolutePath(referencingModule, moduleFileName)) {
273 CString msg = "Parse absolute " + referencingModule + " path failed";
274 THROW_NEW_ERROR_AND_RETURN_HANDLE(thread, ErrorType::REFERENCE_ERROR, JSTaggedValue, msg.c_str());
275 }
276 }
277 JSHandle<JSTaggedValue> module = moduleManager->TryGetImportedModule(moduleFileName);
278 if (!module->IsUndefined()) {
279 return module;
280 }
281 std::shared_ptr<JSPandaFile> pandaFile = JSPandaFileManager::GetInstance()->LoadJSPandaFile(
282 thread, moduleFileName, JSPandaFile::ENTRY_MAIN_FUNCTION, false, executeType);
283 RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
284 if (pandaFile == nullptr) { // LCOV_EXCL_BR_LINE
285 LOG_FULL(FATAL) << "Load current file's panda file failed. Current file is " << referencingModule;
286 }
287
288 return ResolveModuleBundlePack(thread, pandaFile.get(), executeType);
289 }
290
ResolveModuleBundlePack(JSThread * thread,const JSPandaFile * jsPandaFile,const ExecuteTypes & executeType)291 JSHandle<JSTaggedValue> ModuleResolver::ResolveModuleBundlePack(JSThread *thread,
292 const JSPandaFile *jsPandaFile,
293 const ExecuteTypes &executeType)
294 {
295 CString moduleFileName = jsPandaFile->GetJSPandaFileDesc();
296 JSHandle<JSTaggedValue> moduleRecord = thread->GlobalConstants()->GetHandledUndefined();
297 JSRecordInfo recordInfo = const_cast<JSPandaFile *>(jsPandaFile)->FindRecordInfo(JSPandaFile::ENTRY_FUNCTION_NAME);
298 if (jsPandaFile->IsModule(&recordInfo)) {
299 moduleRecord =
300 ModuleDataExtractor::ParseModule(thread, jsPandaFile, moduleFileName, moduleFileName, &recordInfo);
301 } else {
302 ASSERT(jsPandaFile->IsCjs(&recordInfo));
303 moduleRecord = ModuleDataExtractor::ParseCjsModule(thread, jsPandaFile);
304 }
305 // json file can not be compiled into isolate abc.
306 ASSERT(!jsPandaFile->IsJson(&recordInfo));
307 ModuleDeregister::InitForDeregisterModule(moduleRecord, executeType);
308 ModuleManager *moduleManager = thread->GetCurrentEcmaContext()->GetModuleManager();
309 moduleManager->AddResolveImportedModule(moduleFileName, moduleRecord.GetTaggedValue());
310 return moduleRecord;
311 }
312
ResolveNativeModule(JSThread * thread,const CString & moduleRequest,const CString & baseFileName,ModuleTypes moduleType)313 JSHandle<JSTaggedValue> ModuleResolver::ResolveNativeModule(JSThread *thread,
314 const CString &moduleRequest,
315 const CString &baseFileName,
316 ModuleTypes moduleType)
317 {
318 JSHandle<JSTaggedValue> moduleRecord =
319 ModuleDataExtractor::ParseNativeModule(thread, moduleRequest, baseFileName, moduleType);
320 ModuleManager *moduleManager = thread->GetCurrentEcmaContext()->GetModuleManager();
321 moduleManager->AddResolveImportedModule(moduleRequest, moduleRecord.GetTaggedValue());
322 return moduleRecord;
323 }
324
ResolveModuleWithMerge(JSThread * thread,const JSPandaFile * jsPandaFile,const CString & recordName,JSRecordInfo * recordInfo,const ExecuteTypes & executeType)325 JSHandle<JSTaggedValue> ModuleResolver::ResolveModuleWithMerge(JSThread *thread,
326 const JSPandaFile *jsPandaFile,
327 const CString &recordName,
328 JSRecordInfo *recordInfo,
329 const ExecuteTypes &executeType)
330 {
331 CString moduleFileName = jsPandaFile->GetJSPandaFileDesc();
332 JSHandle<JSTaggedValue> moduleRecord = thread->GlobalConstants()->GetHandledUndefined();
333 if (jsPandaFile->IsModule(recordInfo)) {
334 RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
335 moduleRecord = ModuleDataExtractor::ParseModule(thread, jsPandaFile, recordName, moduleFileName, recordInfo);
336 } else if (jsPandaFile->IsJson(recordInfo)) {
337 moduleRecord = ModuleDataExtractor::ParseJsonModule(thread, jsPandaFile, moduleFileName, recordName);
338 } else {
339 ASSERT(jsPandaFile->IsCjs(recordInfo));
340 RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
341 moduleRecord = ModuleDataExtractor::ParseCjsModule(thread, jsPandaFile);
342 }
343
344 JSHandle<SourceTextModule>::Cast(moduleRecord)->SetEcmaModuleRecordNameString(recordName);
345 ModuleDeregister::InitForDeregisterModule(moduleRecord, executeType);
346 return moduleRecord;
347 }
348 } // namespace panda::ecmascript