• 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/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