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/checkpoint/thread_state_transition.h"
18 #include "ecmascript/jspandafile/js_pandafile_executor.h"
19 #include "ecmascript/module/module_path_helper.h"
20 #include "ecmascript/module/module_resolver.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
42 NativeAreaAllocator* allocator = thread->GetEcmaVM()->GetNativeAreaAllocator();
43 allocator->FreeBuffer(pointer);
44
45 JSHandle<SourceTextModule> module(thread, SourceTextModule::Cast(moduleVal.GetTaggedObject()));
46 LoadingTypes type = module->GetLoadingTypes();
47 CString recordNameStr = SourceTextModule::GetModuleName(module.GetTaggedValue());
48 if (type != LoadingTypes::DYNAMITC_MODULE) {
49 LOG_FULL(INFO) << "free stable module's ModuleNameSpace" << recordNameStr;
50 return;
51 }
52
53 std::set<CString> decreaseModule = {recordNameStr};
54 DecreaseRegisterCounts(thread, module, decreaseModule);
55 uint16_t counts = module->GetRegisterCounts();
56 if (counts == 0) {
57 thread->GetEcmaVM()->RemoveFromDeregisterModuleList(recordNameStr);
58 }
59 LOG_FULL(INFO) << "try to remove module " << recordNameStr << ", register counts is " << counts;
60 }
61
ReviseLoadedModuleCount(JSThread * thread,const CString & moduleName)62 void ModuleDeregister::ReviseLoadedModuleCount(JSThread *thread, const CString &moduleName)
63 {
64 EcmaVM *vm = thread->GetEcmaVM();
65 ModuleManager *moduleManager = thread->GetCurrentEcmaContext()->GetModuleManager();
66 if (!moduleManager->IsLocalModuleLoaded(moduleName)) {
67 return;
68 }
69 JSHandle<SourceTextModule> module = moduleManager->HostGetImportedModule(moduleName);
70
71 LoadingTypes type = module->GetLoadingTypes();
72 // do not change stable module's RegisterCounts.
73 if (type == LoadingTypes::STABLE_MODULE) {
74 return;
75 }
76 if (!vm->ContainInDeregisterModuleList(moduleName)) {
77 std::set<CString> increaseModule = {moduleName};
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 CString recordName = SourceTextModule::GetModuleName(module.GetTaggedValue());
85 ModuleManager *moduleManager = thread->GetCurrentEcmaContext()->GetModuleManager();
86 if (!thread->GetEcmaVM()->IsWorkerThread() &&
87 (module->GetTypes() == ModuleTypes::APP_MODULE || module->GetTypes() == ModuleTypes::OHOS_MODULE)) {
88 if (TryToRemoveSO(thread, module)) {
89 LOG_FULL(INFO) << "Remove native module " << recordName << " successfully.";
90 } else {
91 LOG_FULL(INFO) << "Remove native module " << recordName << " failed.";
92 }
93 }
94 moduleManager->RemoveModuleFromCache(recordName);
95 }
96
IncreaseRegisterCounts(JSThread * thread,JSHandle<SourceTextModule> module,std::set<CString> & increaseModule)97 void ModuleDeregister::IncreaseRegisterCounts(JSThread *thread, JSHandle<SourceTextModule> module,
98 std::set<CString> &increaseModule)
99 {
100 if (!module->GetRequestedModules().IsUndefined()) {
101 JSHandle<TaggedArray> requestedModules(thread, module->GetRequestedModules());
102 size_t requestedModulesLen = requestedModules->GetLength();
103 for (size_t idx = 0; idx < requestedModulesLen; idx++) {
104 JSHandle<SourceTextModule> requiredModule = JSHandle<SourceTextModule>::Cast(
105 SourceTextModule::GetRequestedModule(thread, module, requestedModules, idx));
106 RETURN_IF_ABRUPT_COMPLETION(thread);
107 const CString moduleRecordName = module->GetEcmaModuleRecordNameString();
108 CString moduleName =
109 moduleRecordName.empty() ? requiredModule->GetEcmaModuleFilenameString() : moduleRecordName;
110 if (increaseModule.find(moduleName) != increaseModule.end()) {
111 LOG_FULL(DEBUG) << "Find module cyclical loading, stop increasing.";
112 requiredModule->SetLoadingTypes(LoadingTypes::STABLE_MODULE);
113 return;
114 }
115 increaseModule.emplace(moduleName);
116 LoadingTypes type = requiredModule->GetLoadingTypes();
117 if (type == LoadingTypes::DYNAMITC_MODULE) {
118 IncreaseRegisterCounts(thread, requiredModule, increaseModule);
119 }
120 }
121 }
122
123 if (module->GetLoadingTypes() == LoadingTypes::STABLE_MODULE) {
124 return;
125 }
126 uint16_t registerNum = module->GetRegisterCounts();
127 if (registerNum == UINT16_MAX) {
128 module->SetLoadingTypes(LoadingTypes::STABLE_MODULE);
129 return;
130 }
131 module->SetRegisterCounts(registerNum + 1);
132 }
133
DecreaseRegisterCounts(JSThread * thread,JSHandle<SourceTextModule> module,std::set<CString> & decreaseModule)134 void ModuleDeregister::DecreaseRegisterCounts(JSThread *thread, JSHandle<SourceTextModule> module,
135 std::set<CString> &decreaseModule)
136 {
137 if (!module->GetRequestedModules().IsUndefined()) {
138 JSHandle<TaggedArray> requestedModules(thread, module->GetRequestedModules());
139 size_t requestedModulesLen = requestedModules->GetLength();
140 for (size_t idx = 0; idx < requestedModulesLen; idx++) {
141 JSHandle<SourceTextModule> requiredModule = JSHandle<SourceTextModule>::Cast(
142 SourceTextModule::GetRequestedModule(thread, module, requestedModules, idx));
143 RETURN_IF_ABRUPT_COMPLETION(thread);
144 const CString moduleRecordName = module->GetEcmaModuleRecordNameString();
145 CString moduleName =
146 moduleRecordName.empty() ? requiredModule->GetEcmaModuleFilenameString() : moduleRecordName;
147 if (decreaseModule.find(moduleName) != decreaseModule.end()) {
148 LOG_FULL(DEBUG) << "Find module cyclical loading, stop increasing.";
149 requiredModule->SetLoadingTypes(LoadingTypes::STABLE_MODULE);
150 return;
151 }
152 decreaseModule.emplace(moduleName);
153 LoadingTypes type = requiredModule->GetLoadingTypes();
154 if (type == LoadingTypes::DYNAMITC_MODULE) {
155 DecreaseRegisterCounts(thread, requiredModule, decreaseModule);
156 }
157 }
158 }
159
160 if (module->GetLoadingTypes() != LoadingTypes::DYNAMITC_MODULE) {
161 return;
162 }
163 uint16_t num = module->GetRegisterCounts();
164 if (num == 0) { // LCOV_EXCL_BR_LINE
165 LOG_FULL(FATAL) << "moduleNameSpace can not be uninstalled";
166 }
167
168 uint16_t registerNum = num - 1;
169 if (registerNum == 0) {
170 LOG_FULL(INFO) << "try to remove module " << SourceTextModule::GetModuleName(module.GetTaggedValue());
171 RemoveModule(thread, module);
172 }
173 module->SetRegisterCounts(registerNum);
174 }
175 } // namespace panda::ecmascript
176