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