• 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/module/module_manager_helper.h"
19 #include "ecmascript/module/module_path_helper.h"
20 #include "ecmascript/runtime_lock.h"
21 
22 namespace panda::ecmascript {
23 using StringHelper = base::StringHelper;
24 using JSPandaFile = ecmascript::JSPandaFile;
25 using JSRecordInfo = ecmascript::JSPandaFile::JSRecordInfo;
26 
GetInstance()27 SharedModuleManager* SharedModuleManager::GetInstance()
28 {
29     static SharedModuleManager* instance = new SharedModuleManager();
30     return instance;
31 }
32 
Iterate(RootVisitor & v)33 void SharedModuleManager::Iterate(RootVisitor &v)
34 {
35     for (auto &it : resolvedSharedModules_) {
36         ObjectSlot slot(reinterpret_cast<uintptr_t>(&it.second));
37         v.VisitRoot(Root::ROOT_VM, slot);
38         ASSERT(slot.GetTaggedValue() == it.second);
39     }
40 }
41 
GetSendableModuleValueInner(JSThread * thread,int32_t index,JSTaggedValue jsFunc)42 JSTaggedValue SharedModuleManager::GetSendableModuleValueInner(JSThread* thread, int32_t index, JSTaggedValue jsFunc)
43 {
44     ModuleManager* moduleManager = thread->GetCurrentEcmaContext()->GetModuleManager();
45     JSTaggedValue currentModule = JSFunction::Cast(jsFunc.GetTaggedObject())->GetModule();
46     if (currentModule.IsUndefined()) { // LCOV_EXCL_BR_LINE
47         LOG_FULL(FATAL) << "GetSendableModuleValueInner currentModule is undefined";
48     }
49     if (!SourceTextModule::IsSendableFunctionModule(currentModule)) {
50         return SourceTextModule::Cast(currentModule)->GetModuleValue(thread, index, false);
51     }
52     CString referenceName = SourceTextModule::GetModuleName(currentModule);
53     if (moduleManager->IsModuleLoaded(referenceName)) {
54         JSHandle<SourceTextModule> currentModuleHdl = moduleManager->GetImportedModule(referenceName);
55         if (currentModuleHdl->GetStatus() > ModuleStatus::INSTANTIATED) {
56             return currentModuleHdl->GetModuleValue(thread, index, false);
57         }
58     }
59     JSHandle<SourceTextModule> currentModuleHdl(thread, currentModule);
60     auto isMergedAbc = !currentModuleHdl->GetEcmaModuleRecordNameString().empty();
61     CString fileName = currentModuleHdl->GetEcmaModuleFilenameString();
62     if (!JSPandaFileExecutor::LazyExecuteModule(thread, referenceName, fileName, isMergedAbc)) { // LCOV_EXCL_BR_LINE
63         LOG_ECMA(FATAL) << "GetSendableModuleValueInner LazyExecuteModule failed";
64     }
65     ASSERT(moduleManager->IsModuleLoaded(referenceName));
66     return moduleManager->GetImportedModule(referenceName)->GetModuleValue(thread, index, false);
67 }
68 
GetSendableModuleValue(JSThread * thread,int32_t index,JSTaggedValue jsFunc)69 JSTaggedValue SharedModuleManager::GetSendableModuleValue(JSThread *thread, int32_t index, JSTaggedValue jsFunc)
70 {
71     JSTaggedValue currentModule = JSFunction::Cast(jsFunc.GetTaggedObject())->GetModule();
72     return GetSendableModuleValueImpl(thread, index, currentModule);
73 }
74 
GetSendableModuleValueImpl(JSThread * thread,int32_t index,JSTaggedValue currentModule) const75 JSTaggedValue SharedModuleManager::GetSendableModuleValueImpl(
76     JSThread *thread, int32_t index, JSTaggedValue currentModule) const
77 {
78     if (currentModule.IsUndefined()) { // LCOV_EXCL_BR_LINE
79         LOG_FULL(FATAL) << "GetModuleValueOutter currentModule failed";
80         UNREACHABLE();
81     }
82 
83     JSHandle<SourceTextModule> module(thread, currentModule.GetTaggedObject());
84     JSTaggedValue moduleEnvironment = module->GetEnvironment();
85     if (moduleEnvironment.IsUndefined()) {
86         return thread->GlobalConstants()->GetUndefined();
87     }
88     ASSERT(moduleEnvironment.IsTaggedArray());
89     JSTaggedValue resolvedBinding = TaggedArray::Cast(moduleEnvironment.GetTaggedObject())->Get(index);
90     if (resolvedBinding.IsResolvedRecordIndexBinding()) {
91         return ModuleManagerHelper::GetModuleValueFromIndexBinding(thread, module, resolvedBinding);
92     } else if (resolvedBinding.IsResolvedIndexBinding()) {
93         ResolvedIndexBinding *binding = ResolvedIndexBinding::Cast(resolvedBinding.GetTaggedObject());
94         JSHandle<SourceTextModule> resolvedModule(thread, binding->GetModule().GetTaggedObject());
95         return ModuleManagerHelper::GetModuleValue(thread, resolvedModule, binding->GetIndex());
96     } else if (resolvedBinding.IsResolvedRecordBinding()) {
97         return ModuleManagerHelper::GetModuleValueFromRecordBinding(thread, module, resolvedBinding);
98     }
99     LOG_ECMA(FATAL) << "Unexpect binding";
100     UNREACHABLE();
101 }
102 
GetLazySendableModuleValue(JSThread * thread,int32_t index,JSTaggedValue jsFunc)103 JSTaggedValue SharedModuleManager::GetLazySendableModuleValue(JSThread *thread, int32_t index, JSTaggedValue jsFunc)
104 {
105     JSTaggedValue currentModule = JSFunction::Cast(jsFunc.GetTaggedObject())->GetModule();
106     return GetLazySendableModuleValueImpl(thread, index, currentModule);
107 }
108 
GetLazySendableModuleValueImpl(JSThread * thread,int32_t index,JSTaggedValue currentModule) const109 JSTaggedValue SharedModuleManager::GetLazySendableModuleValueImpl(
110     JSThread *thread, int32_t index, JSTaggedValue currentModule) const
111 {
112     if (currentModule.IsUndefined()) { // LCOV_EXCL_BR_LINE
113         LOG_FULL(FATAL) << "GetModuleValueOutter currentModule failed";
114         UNREACHABLE();
115     }
116 
117     JSHandle<SourceTextModule> module(thread, currentModule.GetTaggedObject());
118     JSTaggedValue moduleEnvironment = module->GetEnvironment();
119     if (moduleEnvironment.IsUndefined()) {
120         return thread->GlobalConstants()->GetUndefined();
121     }
122     ASSERT(moduleEnvironment.IsTaggedArray());
123     JSTaggedValue resolvedBinding = TaggedArray::Cast(moduleEnvironment.GetTaggedObject())->Get(index);
124     if (resolvedBinding.IsResolvedRecordIndexBinding()) {
125         return ModuleManagerHelper::GetLazyModuleValueFromIndexBinding(thread, module, resolvedBinding);
126     } else if (resolvedBinding.IsResolvedIndexBinding()) {
127         ResolvedIndexBinding *binding = ResolvedIndexBinding::Cast(resolvedBinding.GetTaggedObject());
128         JSHandle<SourceTextModule> resolvedModule(thread, binding->GetModule().GetTaggedObject());
129         SourceTextModule::Evaluate(thread, resolvedModule, nullptr);
130         RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception());
131         return ModuleManagerHelper::GetModuleValue(thread, resolvedModule, binding->GetIndex());
132     } else if (resolvedBinding.IsResolvedRecordBinding()) {
133         return ModuleManagerHelper::GetLazyModuleValueFromRecordBinding(thread, module, resolvedBinding);
134     }
135     LOG_ECMA(FATAL) << "Unexpect binding";
136     UNREACHABLE();
137 }
138 
SearchInSModuleManagerUnsafe(const CString & recordName)139 bool SharedModuleManager::SearchInSModuleManagerUnsafe(const CString &recordName)
140 {
141     auto entry = resolvedSharedModules_.find(recordName);
142     if (entry != resolvedSharedModules_.end()) {
143         return true;
144     }
145     return false;
146 }
147 
GetSModuleUnsafe(JSThread * thread,const CString & recordName)148 JSHandle<SourceTextModule> SharedModuleManager::GetSModuleUnsafe(JSThread *thread, const CString &recordName)
149 {
150     auto entry = resolvedSharedModules_.find(recordName);
151     if (entry == resolvedSharedModules_.end()) {
152         // LATER DO: cause assert failed
153         return JSHandle<SourceTextModule>::Cast(thread->GlobalConstants()->GetHandledUndefined());
154     }
155     JSHandle<JSTaggedValue> module(thread, entry->second);
156     return JSHandle<SourceTextModule>::Cast(module);
157 }
158 
GetSModule(JSThread * thread,const CString & recordName)159 JSHandle<SourceTextModule> SharedModuleManager::GetSModule(JSThread *thread, const CString &recordName)
160 {
161     RuntimeLockHolder locker(thread, mutex_);
162     return GetSModuleUnsafe(thread, recordName);
163 }
164 
SearchInSModuleManager(JSThread * thread,const CString & recordName)165 bool SharedModuleManager::SearchInSModuleManager(JSThread *thread, const CString &recordName)
166 {
167     RuntimeLockHolder locker(thread, mutex_);
168     return SearchInSModuleManagerUnsafe(recordName);
169 }
InsertInSModuleManager(JSThread * thread,const CString & recordName,JSHandle<SourceTextModule> & moduleRecord)170 void SharedModuleManager::InsertInSModuleManager(JSThread *thread, const CString &recordName,
171     JSHandle<SourceTextModule> &moduleRecord)
172 {
173     RuntimeLockHolder locker(thread, mutex_);
174     JSHandle<JSTaggedValue> module = JSHandle<JSTaggedValue>::Cast(moduleRecord);
175     if (!SearchInSModuleManagerUnsafe(recordName)) {
176         AddResolveImportedSModule(recordName, module.GetTaggedValue());
177         StateVisit stateVisit;
178         sharedModuleMutex_.emplace(recordName, std::move(stateVisit));
179     }
180 }
181 
TransferSModule(JSThread * thread)182 void SharedModuleManager::TransferSModule(JSThread *thread)
183 {
184     ModuleManager *moduleManager = thread->GetCurrentEcmaContext()->GetModuleManager();
185     CVector<CString> instantiatingSModuleList = moduleManager->GetInstantiatingSModuleList();
186     for (auto s:instantiatingSModuleList) {
187         JSHandle<SourceTextModule> module = moduleManager->HostGetImportedModule(s);
188         ASSERT(module->GetSharedType() == SharedTypes::SHARED_MODULE);
189         InsertInSModuleManager(thread, s, module);
190         moduleManager->RemoveModuleNameFromList(s);
191     }
192     moduleManager->ClearInstantiatingSModuleList();
193 }
194 
findModuleMutexWithLock(JSThread * thread,const JSHandle<SourceTextModule> & module)195 StateVisit &SharedModuleManager::findModuleMutexWithLock(JSThread *thread, const JSHandle<SourceTextModule> &module)
196 {
197     RuntimeLockHolder locker(thread, mutex_);
198     CString moduleName = SourceTextModule::GetModuleName(module.GetTaggedValue());
199     auto it = sharedModuleMutex_.find(moduleName);
200     if (it == sharedModuleMutex_.end()) { // LCOV_EXCL_BR_LINE
201         LOG_ECMA(FATAL) << " Get shared module mutex failed";
202     }
203     return it->second;
204 }
205 
IsInstantiatedSModule(JSThread * thread,const JSHandle<SourceTextModule> & module)206 bool SharedModuleManager::IsInstantiatedSModule(JSThread *thread, const JSHandle<SourceTextModule> &module)
207 {
208     RuntimeLockHolder locker(thread, mutex_);
209     return (module->GetStatus() >= ModuleStatus::INSTANTIATED);
210 }
211 
GenerateFuncModule(JSThread * thread,const JSPandaFile * jsPandaFile,const CString & entryPoint,ClassKind classKind)212 JSHandle<JSTaggedValue> SharedModuleManager::GenerateFuncModule(JSThread *thread, const JSPandaFile *jsPandaFile,
213                                                                 const CString &entryPoint, ClassKind classKind)
214 {
215     CString recordName = jsPandaFile->GetRecordName(entryPoint);
216     auto vm = thread->GetEcmaVM();
217     JSRecordInfo *recordInfo = jsPandaFile->CheckAndGetRecordInfo(recordName);
218     ASSERT(recordInfo != nullptr);
219     if (jsPandaFile->IsModule(recordInfo)) {
220         JSHandle<SourceTextModule> module;
221         if (jsPandaFile->IsSharedModule(recordInfo)) {
222             return JSHandle<JSTaggedValue>(GetSModule(thread, entryPoint));
223         } else {
224             ModuleManager *moduleManager = thread->GetCurrentEcmaContext()->GetModuleManager();
225             module = moduleManager->HostGetImportedModule(recordName);
226         }
227 
228         if (classKind == ClassKind::NON_SENDABLE) {
229             return JSHandle<JSTaggedValue>(module);
230         } else {
231             // Clone isolate module at shared-heap to mark sendable class.
232             return SendableClassModule::GenerateSendableFuncModule(thread, JSHandle<JSTaggedValue>(module));
233         }
234     }
235     return JSHandle<JSTaggedValue>(vm->GetFactory()->NewFromUtf8(recordName));
236 }
237 
SModuleNamespaceCreate(JSThread * thread,const JSHandle<JSTaggedValue> & module,const JSHandle<TaggedArray> & exports)238 JSHandle<ModuleNamespace> SharedModuleManager::SModuleNamespaceCreate(JSThread *thread,
239     const JSHandle<JSTaggedValue> &module, const JSHandle<TaggedArray> &exports)
240 {
241     RuntimeLockHolder locker(thread, mutex_);
242     return JSSharedModule::SModuleNamespaceCreate(thread, module, exports);
243 }
244 
SharedNativeObjDestory()245 void SharedModuleManager::SharedNativeObjDestory()
246 {
247     for (auto it = resolvedSharedModules_.begin(); it != resolvedSharedModules_.end(); it++) {
248         CString key = it->first;
249         ASSERT(!key.empty());
250         JSTaggedValue module = it->second;
251         SourceTextModule::Cast(module)->DestoryLazyImportArray();
252         SourceTextModule::Cast(module)->DestoryEcmaModuleFilenameString();
253         SourceTextModule::Cast(module)->DestoryEcmaModuleRecordNameString();
254     }
255 }
256 } // namespace panda::ecmascript
257