• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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