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