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