• 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(thread, moduleRequest.GetTaggedValue());
84     ReplaceModuleThroughFeature(thread, moduleRequestName);
85 
86     CString baseFilename{};
87     StageOfHotReload stageOfHotReload = thread->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->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->GetModuleManager();
129     CString moduleRequestStr = ModulePathHelper::Utf8ConvertToString(thread, 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     JSHandle<JSTaggedValue> module = thread->GetModuleManager()->TryGetImportedModule(recordName);
165     if (!module->IsUndefined()) {
166         return module;
167     }
168 
169     ASSERT(jsPandaFile->IsModule(recordInfo));
170     JSHandle<JSTaggedValue> moduleRecord =
171         SharedModuleHelper::ParseSharedModule(thread, jsPandaFile, recordName, fileName, recordInfo);
172     JSHandle<SourceTextModule>::Cast(moduleRecord)->SetEcmaModuleRecordNameString(recordName);
173     sharedModuleManager->AddToResolvedModulesAndCreateSharedModuleMutex(
174         thread, recordName, moduleRecord.GetTaggedValue());
175     return moduleRecord;
176 }
177 
HostResolveImportedModuleForHotReload(JSThread * thread,const CString & moduleFileName,const CString & recordName,const ExecuteTypes & executeType)178 JSHandle<JSTaggedValue> ModuleResolver::HostResolveImportedModuleForHotReload(JSThread *thread,
179                                                                               const CString &moduleFileName,
180                                                                               const CString &recordName,
181                                                                               const ExecuteTypes &executeType)
182 {
183     std::shared_ptr<JSPandaFile> jsPandaFile = JSPandaFileManager::GetInstance()->LoadJSPandaFile(
184         thread, moduleFileName, recordName, false, executeType);
185     RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
186     if (jsPandaFile == nullptr) { // LCOV_EXCL_BR_LINE
187         LOG_FULL(FATAL) << "Load current file's panda file failed. Current file is " << moduleFileName;
188     }
189 
190     JSRecordInfo *recordInfo = jsPandaFile->CheckAndGetRecordInfo(recordName);
191     if (recordInfo == nullptr) {
192         CString msg = "cannot find record '" + recordName + "',please check the request path.'" + moduleFileName + "'.";
193         THROW_NEW_ERROR_AND_RETURN_HANDLE(thread, ErrorType::REFERENCE_ERROR, JSTaggedValue, msg.c_str());
194     }
195 
196     JSHandle<JSTaggedValue> moduleRecord =
197         ResolveModuleWithMerge(thread, jsPandaFile.get(), recordName, recordInfo, executeType);
198     RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
199     ModuleManager *moduleManager = thread->GetModuleManager();
200     moduleManager->UpdateResolveImportedModule(recordName, moduleRecord.GetTaggedValue());
201     return moduleRecord;
202 }
203 
HostResolveImportedModuleWithMerge(JSThread * thread,const CString & moduleFileName,const CString & recordName,const JSPandaFile * jsPandaFile,const ExecuteTypes & executeType)204 JSHandle<JSTaggedValue> ModuleResolver::HostResolveImportedModuleWithMerge(JSThread *thread,
205                                                                            const CString &moduleFileName,
206                                                                            const CString &recordName,
207                                                                            const JSPandaFile *jsPandaFile,
208                                                                            const ExecuteTypes &executeType)
209 {
210     if (jsPandaFile == nullptr) {
211         std::shared_ptr<JSPandaFile> file = JSPandaFileManager::GetInstance()->LoadJSPandaFile(
212             thread, moduleFileName, recordName, false, executeType);
213         RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
214         if (file == nullptr) {
215             CString msg = "Load file with filename '" + moduleFileName + "' failed, recordName '" + recordName + "'";
216             THROW_NEW_ERROR_AND_RETURN_HANDLE(thread, ErrorType::REFERENCE_ERROR, JSTaggedValue, msg.c_str());
217         }
218         jsPandaFile = file.get();
219     }
220     JSRecordInfo *recordInfo = jsPandaFile->CheckAndGetRecordInfo(recordName);
221     if (recordInfo == nullptr) {
222         CString msg = "cannot find record '" + recordName + "',please check the request path.'" + moduleFileName + "'.";
223         THROW_NEW_ERROR_AND_RETURN_HANDLE(thread, ErrorType::REFERENCE_ERROR, JSTaggedValue, msg.c_str());
224     }
225 
226     if (jsPandaFile->IsSharedModule(recordInfo)) {
227         return ResolveSharedImportedModuleWithMerge(thread, moduleFileName, recordName, jsPandaFile, recordInfo);
228     }
229     ModuleManager *moduleManager = thread->GetModuleManager();
230     JSHandle<JSTaggedValue> module = moduleManager->TryGetImportedModule(recordName);
231     if (!module->IsUndefined()) {
232         return module;
233     }
234     JSHandle<JSTaggedValue> moduleRecord =
235         ResolveModuleWithMerge(thread, jsPandaFile, recordName, recordInfo, executeType);
236     RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
237     moduleManager->AddResolveImportedModule(recordName, moduleRecord.GetTaggedValue());
238     return moduleRecord;
239 }
HostResolveImportedModuleBundlePackBuffer(JSThread * thread,const CString & referencingModule,const JSPandaFile * jsPandaFile,const ExecuteTypes & executeType)240 JSHandle<JSTaggedValue> ModuleResolver::HostResolveImportedModuleBundlePackBuffer(JSThread *thread,
241                                                                                   const CString &referencingModule,
242                                                                                   const JSPandaFile *jsPandaFile,
243                                                                                   const ExecuteTypes &executeType)
244 {
245     ModuleManager *moduleManager = thread->GetModuleManager();
246     JSHandle<JSTaggedValue> module = moduleManager->TryGetImportedModule(referencingModule);
247     if (!module->IsUndefined()) {
248         return module;
249     }
250     return ResolveModuleBundlePack(thread, jsPandaFile, executeType);
251 }
HostResolveImportedModuleBundlePack(JSThread * thread,const CString & referencingModule,const ExecuteTypes & executeType)252 JSHandle<JSTaggedValue> ModuleResolver::HostResolveImportedModuleBundlePack(JSThread *thread,
253                                                                             const CString &referencingModule,
254                                                                             const ExecuteTypes &executeType)
255 {
256     ModuleManager *moduleManager = thread->GetModuleManager();
257     // Can not use jsPandaFile from js_pandafile_executor, need to construct with JSPandaFile::ENTRY_MAIN_FUNCTION
258     std::shared_ptr<JSPandaFile> jsPandaFile =
259         JSPandaFileManager::GetInstance()->LoadJSPandaFile(
260             thread, referencingModule, JSPandaFile::ENTRY_MAIN_FUNCTION, false, executeType);
261     RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
262     if (jsPandaFile == nullptr) { // LCOV_EXCL_BR_LINE
263         LOG_FULL(FATAL) << "Load current file's panda file failed. Current file is " << referencingModule;
264     }
265 
266     [[maybe_unused]] JSRecordInfo *recordInfo = jsPandaFile->CheckAndGetRecordInfo(referencingModule);
267     ASSERT(recordInfo != nullptr && !jsPandaFile->IsSharedModule(recordInfo));
268 
269     CString moduleFileName = referencingModule;
270     if (moduleManager->IsVMBundlePack()) {
271         if (!AOTFileManager::GetAbsolutePath(referencingModule, moduleFileName)) {
272             CString msg = "Parse absolute " + referencingModule + " path failed";
273             THROW_NEW_ERROR_AND_RETURN_HANDLE(thread, ErrorType::REFERENCE_ERROR, JSTaggedValue, msg.c_str());
274         }
275     }
276     JSHandle<JSTaggedValue> module = moduleManager->TryGetImportedModule(moduleFileName);
277     if (!module->IsUndefined()) {
278         return module;
279     }
280     std::shared_ptr<JSPandaFile> pandaFile = JSPandaFileManager::GetInstance()->LoadJSPandaFile(
281         thread, moduleFileName, JSPandaFile::ENTRY_MAIN_FUNCTION, false, executeType);
282     RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
283     if (pandaFile == nullptr) { // LCOV_EXCL_BR_LINE
284         LOG_FULL(FATAL) << "Load current file's panda file failed. Current file is " << referencingModule;
285     }
286 
287     return ResolveModuleBundlePack(thread, pandaFile.get(), executeType);
288 }
289 
ResolveModuleBundlePack(JSThread * thread,const JSPandaFile * jsPandaFile,const ExecuteTypes & executeType)290 JSHandle<JSTaggedValue> ModuleResolver::ResolveModuleBundlePack(JSThread *thread,
291                                                                 const JSPandaFile *jsPandaFile,
292                                                                 const ExecuteTypes &executeType)
293 {
294     CString moduleFileName = jsPandaFile->GetJSPandaFileDesc();
295     JSHandle<JSTaggedValue> moduleRecord = thread->GlobalConstants()->GetHandledUndefined();
296     JSRecordInfo recordInfo = const_cast<JSPandaFile *>(jsPandaFile)->FindRecordInfo(JSPandaFile::ENTRY_FUNCTION_NAME);
297     if (jsPandaFile->IsModule(&recordInfo)) {
298         moduleRecord =
299             ModuleDataExtractor::ParseModule(thread, jsPandaFile, moduleFileName, moduleFileName, &recordInfo);
300     } else {
301         ASSERT(jsPandaFile->IsCjs(&recordInfo));
302         moduleRecord = ModuleDataExtractor::ParseCjsModule(thread, jsPandaFile);
303     }
304     // json file can not be compiled into isolate abc.
305     ASSERT(!jsPandaFile->IsJson(&recordInfo));
306     ModuleDeregister::InitForDeregisterModule(moduleRecord, executeType);
307     ModuleManager *moduleManager = thread->GetModuleManager();
308     moduleManager->AddResolveImportedModule(moduleFileName, moduleRecord.GetTaggedValue());
309     return moduleRecord;
310 }
311 
ResolveNativeModule(JSThread * thread,const CString & moduleRequest,const CString & baseFileName,ModuleTypes moduleType)312 JSHandle<JSTaggedValue> ModuleResolver::ResolveNativeModule(JSThread *thread,
313                                                             const CString &moduleRequest,
314                                                             const CString &baseFileName,
315                                                             ModuleTypes moduleType)
316 {
317     JSHandle<JSTaggedValue> moduleRecord =
318         ModuleDataExtractor::ParseNativeModule(thread, moduleRequest, baseFileName, moduleType);
319     ModuleManager *moduleManager = thread->GetModuleManager();
320     moduleManager->AddResolveImportedModule(moduleRequest, moduleRecord.GetTaggedValue());
321     return moduleRecord;
322 }
323 
ResolveModuleWithMerge(JSThread * thread,const JSPandaFile * jsPandaFile,const CString & recordName,JSRecordInfo * recordInfo,const ExecuteTypes & executeType)324 JSHandle<JSTaggedValue> ModuleResolver::ResolveModuleWithMerge(JSThread *thread,
325                                                                const JSPandaFile *jsPandaFile,
326                                                                const CString &recordName,
327                                                                JSRecordInfo *recordInfo,
328                                                                const ExecuteTypes &executeType)
329 {
330     CString moduleFileName = jsPandaFile->GetJSPandaFileDesc();
331     JSHandle<JSTaggedValue> moduleRecord = thread->GlobalConstants()->GetHandledUndefined();
332     if (jsPandaFile->IsModule(recordInfo)) {
333         RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
334         moduleRecord = ModuleDataExtractor::ParseModule(thread, jsPandaFile, recordName, moduleFileName, recordInfo);
335     } else if (jsPandaFile->IsJson(recordInfo)) {
336         moduleRecord = ModuleDataExtractor::ParseJsonModule(thread, jsPandaFile, moduleFileName, recordName);
337     } else {
338         ASSERT(jsPandaFile->IsCjs(recordInfo));
339         RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
340         moduleRecord = ModuleDataExtractor::ParseCjsModule(thread, jsPandaFile);
341     }
342 
343     JSHandle<SourceTextModule>::Cast(moduleRecord)->SetEcmaModuleRecordNameString(recordName);
344     ModuleDeregister::InitForDeregisterModule(moduleRecord, executeType);
345     return moduleRecord;
346 }
347 } // namespace panda::ecmascript