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