• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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