1 /*
2 * Copyright (c) 2023 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/checkpoint/thread_state_transition.h"
16 #include "ecmascript/module/js_module_deregister.h"
17
18 #include "ecmascript/jspandafile/js_pandafile_executor.h"
19 #include "ecmascript/module/js_module_manager.h"
20 #include "ecmascript/module/module_path_helper.h"
21
22 namespace panda::ecmascript {
23 using PathHelper = base::PathHelper;
24
FreeModuleRecord(void * env,void * pointer,void * hint)25 void ModuleDeregister::FreeModuleRecord([[maybe_unused]] void *env, void *pointer, void *hint)
26 {
27 if (pointer == nullptr) { // LCOV_EXCL_BR_LINE
28 LOG_FULL(FATAL) << "Lacking deregister module's name.";
29 return;
30 }
31 auto thread = reinterpret_cast<JSThread* >(hint);
32 ThreadManagedScope managedScope(thread);
33 [[maybe_unused]] EcmaHandleScope scope(thread);
34
35 // pointer is module's name, which will be deregistered.
36 JSTaggedValue moduleVal =
37 thread->GetCurrentEcmaContext()->GetModuleManager()->HostGetImportedModule(pointer);
38 if (moduleVal.IsUndefined()) {
39 return;
40 }
41 JSHandle<SourceTextModule> module(thread, SourceTextModule::Cast(moduleVal.GetTaggedObject()));
42 LoadingTypes type = module->GetLoadingTypes();
43 CString recordNameStr = SourceTextModule::GetModuleName(module.GetTaggedValue());
44 if (type != LoadingTypes::DYNAMITC_MODULE) {
45 LOG_FULL(INFO) << "free stable module's ModuleNameSpace" << recordNameStr;
46 }
47 NativeAreaAllocator* allocator = thread->GetEcmaVM()->GetNativeAreaAllocator();
48 allocator->FreeBuffer(pointer);
49 if (type == LoadingTypes::DYNAMITC_MODULE) {
50 std::set<CString> decreaseModule = {recordNameStr};
51 DecreaseRegisterCounts(thread, module, decreaseModule);
52 uint16_t counts = module->GetRegisterCounts();
53 if (counts == 0) {
54 thread->GetEcmaVM()->RemoveFromDeregisterModuleList(recordNameStr);
55 }
56 LOG_FULL(INFO) << "try to remove module " << recordNameStr << ", register counts is " << counts;
57 }
58 }
59
ReviseLoadedModuleCount(JSThread * thread,const CString & moduleName)60 void ModuleDeregister::ReviseLoadedModuleCount(JSThread *thread, const CString &moduleName)
61 {
62 EcmaVM *vm = thread->GetEcmaVM();
63 ModuleManager *moduleManager = thread->GetCurrentEcmaContext()->GetModuleManager();
64 if (!moduleManager->IsLocalModuleLoaded(moduleName)) {
65 return;
66 }
67 JSHandle<SourceTextModule> module = moduleManager->HostGetImportedModule(moduleName);
68
69 LoadingTypes type = module->GetLoadingTypes();
70 // do not change stable module's RegisterCounts.
71 if (type == LoadingTypes::STABLE_MODULE) {
72 return;
73 }
74 if (!vm->ContainInDeregisterModuleList(moduleName)) {
75 std::set<CString> increaseModule = {moduleName};
76 IncreaseRegisterCounts(thread, module, increaseModule);
77 }
78 }
79
RemoveModule(JSThread * thread,JSHandle<SourceTextModule> module)80 void ModuleDeregister::RemoveModule(JSThread *thread, JSHandle<SourceTextModule> module)
81 {
82 CString recordName = SourceTextModule::GetModuleName(module.GetTaggedValue());
83 ModuleManager *moduleManager = thread->GetCurrentEcmaContext()->GetModuleManager();
84 if (!thread->GetEcmaVM()->IsWorkerThread() &&
85 (module->GetTypes() == ModuleTypes::APP_MODULE || module->GetTypes() == ModuleTypes::OHOS_MODULE)) {
86 if (TryToRemoveSO(thread, module)) {
87 LOG_FULL(INFO) << "Remove native module " << recordName << " successfully.";
88 } else {
89 LOG_FULL(INFO) << "Remove native module " << recordName << " failed.";
90 }
91 }
92 moduleManager->RemoveModuleFromCache(recordName);
93 }
94
IncreaseRegisterCounts(JSThread * thread,JSHandle<SourceTextModule> module,std::set<CString> & increaseModule)95 void ModuleDeregister::IncreaseRegisterCounts(JSThread *thread, JSHandle<SourceTextModule> module,
96 std::set<CString> &increaseModule)
97 {
98 if (!module->GetRequestedModules().IsUndefined()) {
99 JSHandle<TaggedArray> requestedModules(thread, module->GetRequestedModules());
100 size_t requestedModulesLen = requestedModules->GetLength();
101 JSMutableHandle<JSTaggedValue> required(thread, thread->GlobalConstants()->GetUndefined());
102 for (size_t idx = 0; idx < requestedModulesLen; idx++) {
103 required.Update(requestedModules->Get(idx));
104 JSMutableHandle<SourceTextModule> requiredModule(thread, thread->GlobalConstants()->GetUndefined());
105 const CString moduleRecordName = module->GetEcmaModuleRecordNameString();
106 CString moduleName;
107 if (moduleRecordName.empty()) {
108 JSHandle<JSTaggedValue> requiredVal =
109 SourceTextModule::HostResolveImportedModule(thread, module, required);
110 RETURN_IF_ABRUPT_COMPLETION(thread);
111 requiredModule.Update(JSHandle<SourceTextModule>::Cast(requiredVal));
112 moduleName = requiredModule->GetEcmaModuleFilenameString();
113 } else {
114 JSHandle<JSTaggedValue> requiredVal =
115 SourceTextModule::HostResolveImportedModuleWithMerge(thread, module, required);
116 RETURN_IF_ABRUPT_COMPLETION(thread);
117 requiredModule.Update(JSHandle<SourceTextModule>::Cast(requiredVal));
118 moduleName = requiredModule->GetEcmaModuleRecordNameString();
119 }
120 if (increaseModule.find(moduleName) != increaseModule.end()) {
121 LOG_FULL(DEBUG) << "Find module cyclical loading, stop increasing.";
122 requiredModule->SetLoadingTypes(LoadingTypes::STABLE_MODULE);
123 return;
124 }
125 increaseModule.emplace(moduleName);
126 LoadingTypes type = requiredModule->GetLoadingTypes();
127 if (type == LoadingTypes::DYNAMITC_MODULE) {
128 IncreaseRegisterCounts(thread, requiredModule, increaseModule);
129 }
130 }
131 }
132
133 if (module->GetLoadingTypes() == LoadingTypes::STABLE_MODULE) {
134 return;
135 }
136 uint16_t registerNum = module->GetRegisterCounts();
137 if (registerNum == UINT16_MAX) {
138 module->SetLoadingTypes(LoadingTypes::STABLE_MODULE);
139 return;
140 }
141 module->SetRegisterCounts(registerNum + 1);
142 }
143
DecreaseRegisterCounts(JSThread * thread,JSHandle<SourceTextModule> module,std::set<CString> & decreaseModule)144 void ModuleDeregister::DecreaseRegisterCounts(JSThread *thread, JSHandle<SourceTextModule> module,
145 std::set<CString> &decreaseModule)
146 {
147 if (!module->GetRequestedModules().IsUndefined()) {
148 JSHandle<TaggedArray> requestedModules(thread, module->GetRequestedModules());
149 size_t requestedModulesLen = requestedModules->GetLength();
150 JSMutableHandle<JSTaggedValue> required(thread, thread->GlobalConstants()->GetUndefined());
151 for (size_t idx = 0; idx < requestedModulesLen; idx++) {
152 required.Update(requestedModules->Get(idx));
153 JSMutableHandle<SourceTextModule> requiredModule(thread, thread->GlobalConstants()->GetUndefined());
154 const CString moduleRecordName = module->GetEcmaModuleRecordNameString();
155 CString moduleName;
156 if (moduleRecordName.empty()) {
157 JSHandle<JSTaggedValue> requiredVal =
158 SourceTextModule::HostResolveImportedModule(thread, module, required);
159 RETURN_IF_ABRUPT_COMPLETION(thread);
160 requiredModule.Update(JSHandle<SourceTextModule>::Cast(requiredVal));
161 moduleName = requiredModule->GetEcmaModuleFilenameString();
162 } else {
163 JSHandle<JSTaggedValue> requiredVal =
164 SourceTextModule::HostResolveImportedModuleWithMerge(thread, module, required);
165 RETURN_IF_ABRUPT_COMPLETION(thread);
166 requiredModule.Update(JSHandle<SourceTextModule>::Cast(requiredVal));
167 moduleName = requiredModule->GetEcmaModuleRecordNameString();
168 }
169 if (decreaseModule.find(moduleName) != decreaseModule.end()) {
170 LOG_FULL(DEBUG) << "Find module cyclical loading, stop increasing.";
171 requiredModule->SetLoadingTypes(LoadingTypes::STABLE_MODULE);
172 return;
173 }
174 decreaseModule.emplace(moduleName);
175 LoadingTypes type = requiredModule->GetLoadingTypes();
176 if (type == LoadingTypes::DYNAMITC_MODULE) {
177 DecreaseRegisterCounts(thread, requiredModule, decreaseModule);
178 }
179 }
180 }
181
182 if (module->GetLoadingTypes() != LoadingTypes::DYNAMITC_MODULE) {
183 return;
184 }
185 uint16_t num = module->GetRegisterCounts();
186 if (num == 0) { // LCOV_EXCL_BR_LINE
187 LOG_FULL(FATAL) << "moduleNameSpace can not be uninstalled";
188 }
189
190 uint16_t registerNum = num - 1;
191 if (registerNum == 0) {
192 LOG_FULL(INFO) << "try to remove module " << SourceTextModule::GetModuleName(module.GetTaggedValue());
193 RemoveModule(thread, module);
194 }
195 module->SetRegisterCounts(registerNum);
196 }
197 } // namespace panda::ecmascript
198