• 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 #include "ecmascript/module/js_shared_module_manager.h"
16 
17 #include "ecmascript/jspandafile/js_pandafile_executor.h"
18 #include "ecmascript/jspandafile/js_pandafile_manager.h"
19 #include "ecmascript/module/module_manager_helper.h"
20 #include "ecmascript/module/module_path_helper.h"
21 #include "ecmascript/runtime_lock.h"
22 
23 namespace panda::ecmascript {
24 using StringHelper = base::StringHelper;
25 using JSPandaFile = ecmascript::JSPandaFile;
26 using JSRecordInfo = ecmascript::JSPandaFile::JSRecordInfo;
27 
GetInstance()28 SharedModuleManager* SharedModuleManager::GetInstance()
29 {
30     static SharedModuleManager* instance = new SharedModuleManager();
31     return instance;
32 }
33 
Iterate(const RootVisitor & v)34 void SharedModuleManager::Iterate(const RootVisitor &v)
35 {
36     for (auto &it : resolvedSharedModules_) {
37         ObjectSlot slot(reinterpret_cast<uintptr_t>(&it.second));
38         v(Root::ROOT_VM, slot);
39         ASSERT(slot.GetTaggedValue() == it.second);
40     }
41 }
42 
GetSendableModuleValue(JSThread * thread,int32_t index,JSTaggedValue jsFunc)43 JSTaggedValue SharedModuleManager::GetSendableModuleValue(JSThread *thread, int32_t index, JSTaggedValue jsFunc)
44 {
45     JSTaggedValue currentModule = JSFunction::Cast(jsFunc.GetTaggedObject())->GetModule();
46     return GetSendableModuleValueImpl(thread, index, currentModule);
47 }
48 
GetSendableModuleValueImpl(JSThread * thread,int32_t index,JSTaggedValue currentModule) const49 JSTaggedValue SharedModuleManager::GetSendableModuleValueImpl(
50     JSThread *thread, int32_t index, JSTaggedValue currentModule) const
51 {
52     if (currentModule.IsUndefined()) { // LCOV_EXCL_BR_LINE
53         LOG_FULL(FATAL) << "GetModuleValueOutter currentModule failed";
54         UNREACHABLE();
55     }
56 
57     JSHandle<SourceTextModule> module(thread, currentModule.GetTaggedObject());
58     JSTaggedValue moduleEnvironment = module->GetEnvironment();
59     if (moduleEnvironment.IsUndefined()) {
60         return thread->GlobalConstants()->GetUndefined();
61     }
62     ASSERT(moduleEnvironment.IsTaggedArray());
63     JSTaggedValue resolvedBinding = TaggedArray::Cast(moduleEnvironment.GetTaggedObject())->Get(index);
64     if (resolvedBinding.IsResolvedRecordIndexBinding()) {
65         return ModuleManagerHelper::GetModuleValueFromIndexBinding(thread, module, resolvedBinding);
66     } else if (resolvedBinding.IsResolvedIndexBinding()) {
67         ResolvedIndexBinding *binding = ResolvedIndexBinding::Cast(resolvedBinding.GetTaggedObject());
68         JSHandle<SourceTextModule> resolvedModule(thread, binding->GetModule().GetTaggedObject());
69         return ModuleManagerHelper::GetModuleValue(thread, resolvedModule, binding->GetIndex());
70     } else if (resolvedBinding.IsResolvedRecordBinding()) {
71         return ModuleManagerHelper::GetModuleValueFromRecordBinding(thread, module, resolvedBinding);
72     }
73     LOG_ECMA(FATAL) << "Unexpect binding";
74     UNREACHABLE();
75 }
76 
GetLazySendableModuleValue(JSThread * thread,int32_t index,JSTaggedValue jsFunc)77 JSTaggedValue SharedModuleManager::GetLazySendableModuleValue(JSThread *thread, int32_t index, JSTaggedValue jsFunc)
78 {
79     JSTaggedValue currentModule = JSFunction::Cast(jsFunc.GetTaggedObject())->GetModule();
80     return GetLazySendableModuleValueImpl(thread, index, currentModule);
81 }
82 
GetLazySendableModuleValueImpl(JSThread * thread,int32_t index,JSTaggedValue currentModule) const83 JSTaggedValue SharedModuleManager::GetLazySendableModuleValueImpl(
84     JSThread *thread, int32_t index, JSTaggedValue currentModule) const
85 {
86     if (currentModule.IsUndefined()) { // LCOV_EXCL_BR_LINE
87         LOG_FULL(FATAL) << "GetModuleValueOutter currentModule failed";
88         UNREACHABLE();
89     }
90 
91     JSHandle<SourceTextModule> module(thread, currentModule.GetTaggedObject());
92     JSTaggedValue moduleEnvironment = module->GetEnvironment();
93     if (moduleEnvironment.IsUndefined()) {
94         return thread->GlobalConstants()->GetUndefined();
95     }
96     ASSERT(moduleEnvironment.IsTaggedArray());
97     JSTaggedValue resolvedBinding = TaggedArray::Cast(moduleEnvironment.GetTaggedObject())->Get(index);
98     if (resolvedBinding.IsResolvedRecordIndexBinding()) {
99         return ModuleManagerHelper::GetLazyModuleValueFromIndexBinding(thread, module, resolvedBinding);
100     } else if (resolvedBinding.IsResolvedIndexBinding()) {
101         ResolvedIndexBinding *binding = ResolvedIndexBinding::Cast(resolvedBinding.GetTaggedObject());
102         JSHandle<SourceTextModule> resolvedModule(thread, binding->GetModule().GetTaggedObject());
103         SourceTextModule::Evaluate(thread, resolvedModule, nullptr);
104         RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception());
105         return ModuleManagerHelper::GetModuleValue(thread, resolvedModule, binding->GetIndex());
106     } else if (resolvedBinding.IsResolvedRecordBinding()) {
107         return ModuleManagerHelper::GetLazyModuleValueFromRecordBinding(thread, module, resolvedBinding);
108     }
109     LOG_ECMA(FATAL) << "Unexpect binding";
110     UNREACHABLE();
111 }
112 
ResolveImportedModule(JSThread * thread,const CString & fileName,bool executeFromJob)113 JSHandle<JSTaggedValue> SharedModuleManager::ResolveImportedModule(JSThread *thread, const CString &fileName,
114                                                                    bool executeFromJob)
115 {
116     std::shared_ptr<JSPandaFile> jsPandaFile =
117         JSPandaFileManager::GetInstance()->LoadJSPandaFile(thread, fileName, JSPandaFile::ENTRY_MAIN_FUNCTION);
118     if (jsPandaFile == nullptr) { // LCOV_EXCL_BR_LINE
119         LOG_FULL(FATAL) << "Load current file's panda file failed. Current file is " << fileName;
120     }
121     JSRecordInfo *recordInfo = nullptr;
122     [[maybe_unused]] bool hasRecord = jsPandaFile->CheckAndGetRecordInfo(fileName, &recordInfo);
123     ASSERT(hasRecord && !jsPandaFile->IsSharedModule(recordInfo));
124     // loading unshared module though current context's module manager
125     ModuleManager *moduleManager = thread->GetCurrentEcmaContext()->GetModuleManager();
126     return moduleManager->HostResolveImportedModule(fileName, executeFromJob);
127 }
128 
ResolveImportedModuleWithMerge(JSThread * thread,const CString & fileName,const CString & recordName,bool executeFromJob)129 JSHandle<JSTaggedValue> SharedModuleManager::ResolveImportedModuleWithMerge(JSThread *thread,
130     const CString &fileName, const CString &recordName, bool executeFromJob)
131 {
132     std::shared_ptr<JSPandaFile> jsPandaFile =
133         JSPandaFileManager::GetInstance()->LoadJSPandaFile(thread, fileName, recordName, false);
134     RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
135     if (jsPandaFile == nullptr) {
136         CString msg = "Load file with filename '" + fileName + "' failed, recordName '" + recordName + "'";
137         THROW_NEW_ERROR_AND_RETURN_HANDLE(thread, ErrorType::REFERENCE_ERROR, JSTaggedValue, msg.c_str());
138     }
139     JSRecordInfo *recordInfo = nullptr;
140     bool hasRecord = jsPandaFile->CheckAndGetRecordInfo(recordName, &recordInfo);
141     if (!hasRecord) {
142         CString msg = "cannot find record '" + recordName + "', please check the request path.'"
143                       + fileName + "'.";
144         THROW_NEW_ERROR_AND_RETURN_HANDLE(thread, ErrorType::REFERENCE_ERROR, JSTaggedValue, msg.c_str());
145     }
146 
147     if (jsPandaFile->IsSharedModule(recordInfo)) {
148         return ResolveSharedImportedModuleWithMerge(thread, fileName, recordName, jsPandaFile.get(),
149                                                     recordInfo);
150     }
151     // loading unshared module though current context's module manager
152     ModuleManager *moduleManager = thread->GetCurrentEcmaContext()->GetModuleManager();
153     return moduleManager->HostResolveImportedModuleWithMerge(fileName, recordName, executeFromJob);
154 }
155 
ResolveSharedImportedModuleWithMerge(JSThread * thread,const CString & fileName,const CString & recordName,const JSPandaFile * jsPandaFile,JSRecordInfo * recordInfo)156 JSHandle<JSTaggedValue> SharedModuleManager::ResolveSharedImportedModuleWithMerge(JSThread *thread,
157     const CString &fileName, const CString &recordName, const JSPandaFile *jsPandaFile,
158     [[maybe_unused]] JSRecordInfo *recordInfo)
159 {
160     if (SearchInSModuleManager(thread, recordName)) {
161         return JSHandle<JSTaggedValue>(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 = SharedModuleHelper::ParseSharedModule(thread, jsPandaFile, recordName,
172                                                                                  fileName, recordInfo);
173     JSHandle<SourceTextModule>::Cast(moduleRecord)->SetEcmaModuleRecordNameString(recordName);
174     moduleManager->AddResolveImportedModule(recordName, moduleRecord.GetTaggedValue());
175     moduleManager->AddToInstantiatingSModuleList(recordName);
176     return moduleRecord;
177 }
178 
SearchInSModuleManagerUnsafe(const CString & recordName)179 bool SharedModuleManager::SearchInSModuleManagerUnsafe(const CString &recordName)
180 {
181     auto entry = resolvedSharedModules_.find(recordName);
182     if (entry != resolvedSharedModules_.end()) {
183         return true;
184     }
185     return false;
186 }
187 
GetSModuleUnsafe(JSThread * thread,const CString & recordName)188 JSHandle<SourceTextModule> SharedModuleManager::GetSModuleUnsafe(JSThread *thread, const CString &recordName)
189 {
190     auto entry = resolvedSharedModules_.find(recordName);
191     if (entry == resolvedSharedModules_.end()) {
192         return JSHandle<SourceTextModule>::Cast(thread->GlobalConstants()->GetHandledUndefined());
193     }
194     JSHandle<JSTaggedValue> module(thread, entry->second);
195     return JSHandle<SourceTextModule>::Cast(module);
196 }
197 
GetSModule(JSThread * thread,const CString & recordName)198 JSHandle<SourceTextModule> SharedModuleManager::GetSModule(JSThread *thread, const CString &recordName)
199 {
200     RuntimeLockHolder locker(thread, mutex_);
201     return GetSModuleUnsafe(thread, recordName);
202 }
203 
SearchInSModuleManager(JSThread * thread,const CString & recordName)204 bool SharedModuleManager::SearchInSModuleManager(JSThread *thread, const CString &recordName)
205 {
206     RuntimeLockHolder locker(thread, mutex_);
207     return SearchInSModuleManagerUnsafe(recordName);
208 }
InsertInSModuleManager(JSThread * thread,const CString & recordName,JSHandle<SourceTextModule> & moduleRecord)209 void SharedModuleManager::InsertInSModuleManager(JSThread *thread, const CString &recordName,
210     JSHandle<SourceTextModule> &moduleRecord)
211 {
212     RuntimeLockHolder locker(thread, mutex_);
213     JSHandle<JSTaggedValue> module = JSHandle<JSTaggedValue>::Cast(moduleRecord);
214     if (!SearchInSModuleManagerUnsafe(recordName)) {
215         AddResolveImportedSModule(recordName, module.GetTaggedValue());
216         StateVisit stateVisit;
217         sharedModuleMutex_.emplace(recordName, std::move(stateVisit));
218     }
219 }
220 
TransferSModule(JSThread * thread)221 void SharedModuleManager::TransferSModule(JSThread *thread)
222 {
223     ModuleManager *moduleManager = thread->GetCurrentEcmaContext()->GetModuleManager();
224     CVector<CString> instantiatingSModuleList = moduleManager->GetInstantiatingSModuleList();
225     for (auto s:instantiatingSModuleList) {
226         JSHandle<SourceTextModule> module = moduleManager->HostGetImportedModule(s);
227         ASSERT(module->GetSharedType() == SharedTypes::SHARED_MODULE);
228         InsertInSModuleManager(thread, s, module);
229         moduleManager->RemoveModuleNameFromList(s);
230     }
231     moduleManager->ClearInstantiatingSModuleList();
232 }
233 
findModuleMutexWithLock(JSThread * thread,const JSHandle<SourceTextModule> & module)234 StateVisit &SharedModuleManager::findModuleMutexWithLock(JSThread *thread, const JSHandle<SourceTextModule> &module)
235 {
236     RuntimeLockHolder locker(thread, mutex_);
237     CString moduleName = SourceTextModule::GetModuleName(module.GetTaggedValue());
238     auto it = sharedModuleMutex_.find(moduleName);
239     if (it == sharedModuleMutex_.end()) { // LCOV_EXCL_BR_LINE
240         LOG_ECMA(FATAL) << " Get shared module mutex failed";
241     }
242     return it->second;
243 }
244 
IsInstaniatedSModule(JSThread * thread,const JSHandle<SourceTextModule> & module)245 bool SharedModuleManager::IsInstaniatedSModule(JSThread *thread, const JSHandle<SourceTextModule> &module)
246 {
247     RuntimeLockHolder locker(thread, mutex_);
248     return (module->GetStatus() >= ModuleStatus::INSTANTIATED);
249 }
250 
GenerateFuncModule(JSThread * thread,const JSPandaFile * jsPandaFile,const CString & entryPoint,ClassKind classKind)251 JSHandle<JSTaggedValue> SharedModuleManager::GenerateFuncModule(JSThread *thread, const JSPandaFile *jsPandaFile,
252                                                                 const CString &entryPoint, ClassKind classKind)
253 {
254     CString recordName = jsPandaFile->GetRecordName(entryPoint);
255     auto vm = thread->GetEcmaVM();
256     JSRecordInfo *recordInfo = nullptr;
257     [[maybe_unused]] bool hasRecord = jsPandaFile->CheckAndGetRecordInfo(recordName, &recordInfo);
258     ASSERT(hasRecord);
259     if (jsPandaFile->IsModule(recordInfo)) {
260         JSHandle<SourceTextModule> module;
261         if (jsPandaFile->IsSharedModule(recordInfo)) {
262             return JSHandle<JSTaggedValue>(GetSModule(thread, entryPoint));
263         } else {
264             ModuleManager *moduleManager = thread->GetCurrentEcmaContext()->GetModuleManager();
265             module = moduleManager->HostGetImportedModule(recordName);
266         }
267 
268         if (classKind == ClassKind::NON_SENDABLE) {
269             return JSHandle<JSTaggedValue>(module);
270         } else {
271             // Clone isolate module at shared-heap to mark sendable class.
272             return SendableClassModule::GenerateSendableFuncModule(thread, JSHandle<JSTaggedValue>(module));
273         }
274     }
275     return JSHandle<JSTaggedValue>(vm->GetFactory()->NewFromUtf8(recordName));
276 }
277 
SModuleNamespaceCreate(JSThread * thread,const JSHandle<JSTaggedValue> & module,const JSHandle<TaggedArray> & exports)278 JSHandle<ModuleNamespace> SharedModuleManager::SModuleNamespaceCreate(JSThread *thread,
279     const JSHandle<JSTaggedValue> &module, const JSHandle<TaggedArray> &exports)
280 {
281     RuntimeLockHolder locker(thread, mutex_);
282     return JSSharedModule::SModuleNamespaceCreate(thread, module, exports);
283 }
284 
SharedNativeObjDestory()285 void SharedModuleManager::SharedNativeObjDestory()
286 {
287     for (auto it = resolvedSharedModules_.begin(); it != resolvedSharedModules_.end(); it++) {
288         CString key = it->first;
289         ASSERT(!key.empty());
290         JSTaggedValue module = it->second;
291         SourceTextModule::Cast(module)->DestoryLazyImportArray();
292         SourceTextModule::Cast(module)->DestoryEcmaModuleFilenameString();
293         SourceTextModule::Cast(module)->DestoryEcmaModuleRecordNameString();
294     }
295 }
296 } // namespace panda::ecmascript
297