1 /*
2 * Copyright (c) 2021 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
16 #include "ecmascript/ecma_module.h"
17 #include "ecmascript/ecma_vm.h"
18 #include "ecmascript/global_env.h"
19 #include "ecmascript/js_thread.h"
20 #include "ecmascript/object_factory.h"
21 #include "ecmascript/tagged_array.h"
22 #include "ecmascript/tagged_dictionary.h"
23
24 namespace panda::ecmascript {
GetItem(const JSThread * thread,JSHandle<JSTaggedValue> itemName)25 JSHandle<JSTaggedValue> EcmaModule::GetItem(const JSThread *thread, JSHandle<JSTaggedValue> itemName)
26 {
27 JSHandle<NameDictionary> moduleItems(thread, NameDictionary::Cast(GetNameDictionary().GetTaggedObject()));
28 int entry = moduleItems->FindEntry(itemName.GetTaggedValue());
29 if (entry != -1) {
30 return JSHandle<JSTaggedValue>(thread, moduleItems->GetValue(entry));
31 }
32
33 return JSHandle<JSTaggedValue>(thread, JSTaggedValue::Undefined());
34 }
35
AddItem(const JSThread * thread,JSHandle<EcmaModule> module,JSHandle<JSTaggedValue> itemName,JSHandle<JSTaggedValue> itemValue)36 void EcmaModule::AddItem(const JSThread *thread, JSHandle<EcmaModule> module, JSHandle<JSTaggedValue> itemName,
37 JSHandle<JSTaggedValue> itemValue)
38 {
39 JSMutableHandle<JSTaggedValue> data(thread, module->GetNameDictionary());
40 if (data->IsUndefined()) {
41 data.Update(NameDictionary::Create(thread, DEAULT_DICTIONART_CAPACITY));
42 }
43 JSHandle<NameDictionary> dataDict = JSHandle<NameDictionary>::Cast(data);
44 JSHandle<NameDictionary> newDict =
45 NameDictionary::Put(thread, dataDict, itemName, itemValue, PropertyAttributes::Default());
46 module->SetNameDictionary(thread, newDict);
47 }
48
RemoveItem(const JSThread * thread,JSHandle<EcmaModule> module,JSHandle<JSTaggedValue> itemName)49 void EcmaModule::RemoveItem(const JSThread *thread, JSHandle<EcmaModule> module, JSHandle<JSTaggedValue> itemName)
50 {
51 JSHandle<JSTaggedValue> data(thread, module->GetNameDictionary());
52 if (data->IsUndefined()) {
53 return;
54 }
55 JSHandle<NameDictionary> moduleItems(data);
56 int entry = moduleItems->FindEntry(itemName.GetTaggedValue());
57 if (entry != -1) {
58 JSHandle<NameDictionary> newDict = NameDictionary::Remove(thread, moduleItems, entry);
59 module->SetNameDictionary(thread, newDict);
60 }
61 }
62
CopyModuleInternal(const JSThread * thread,JSHandle<EcmaModule> dstModule,JSHandle<EcmaModule> srcModule)63 void EcmaModule::CopyModuleInternal(const JSThread *thread, JSHandle<EcmaModule> dstModule,
64 JSHandle<EcmaModule> srcModule)
65 {
66 JSHandle<NameDictionary> moduleItems(thread,
67 NameDictionary::Cast(srcModule->GetNameDictionary().GetTaggedObject()));
68 uint32_t numAllKeys = moduleItems->EntriesCount();
69 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
70 JSHandle<TaggedArray> allKeys = factory->NewTaggedArray(numAllKeys);
71 moduleItems->GetAllKeys(thread, 0, allKeys.GetObject<TaggedArray>());
72
73 JSMutableHandle<JSTaggedValue> itemName(thread, JSTaggedValue::Undefined());
74 JSMutableHandle<JSTaggedValue> itemValue(thread, JSTaggedValue::Undefined());
75 unsigned int capcity = allKeys->GetLength();
76 for (unsigned int i = 0; i < capcity; i++) {
77 int entry = moduleItems->FindEntry(allKeys->Get(i));
78 if (entry != -1) {
79 itemName.Update(allKeys->Get(i));
80 itemValue.Update(moduleItems->GetValue(entry));
81 EcmaModule::AddItem(thread, dstModule, itemName, itemValue);
82 }
83 }
84 }
85
DebugPrint(const JSThread * thread,const CString & caller)86 void EcmaModule::DebugPrint(const JSThread *thread, const CString &caller)
87 {
88 JSHandle<NameDictionary> moduleItems(thread, NameDictionary::Cast(GetNameDictionary().GetTaggedObject()));
89 uint32_t numAllKeys = moduleItems->EntriesCount();
90 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
91 JSHandle<TaggedArray> allKeys = factory->NewTaggedArray(numAllKeys);
92 moduleItems->GetAllKeys(thread, 0, allKeys.GetObject<TaggedArray>());
93
94 unsigned int capcity = allKeys->GetLength();
95 for (unsigned int i = 0; i < capcity; i++) {
96 int entry = moduleItems->FindEntry(allKeys->Get(i));
97 if (entry != -1) {
98 std::cout << "[" << caller << "]" << std::endl
99 << "--itemName: " << ConvertToString(EcmaString::Cast(allKeys->Get(i).GetTaggedObject()))
100 << std::endl
101 << "--itemValue(ObjRef): 0x" << std::hex << moduleItems->GetValue(entry).GetRawData()
102 << std::endl;
103 }
104 }
105 }
106
ModuleManager(EcmaVM * vm)107 ModuleManager::ModuleManager(EcmaVM *vm) : vm_(vm)
108 {
109 ecmaModules_ = NameDictionary::Create(vm_->GetJSThread(), DEAULT_DICTIONART_CAPACITY).GetTaggedValue();
110 }
111
112 // class ModuleManager
AddModule(JSHandle<JSTaggedValue> moduleName,JSHandle<JSTaggedValue> module)113 void ModuleManager::AddModule(JSHandle<JSTaggedValue> moduleName, JSHandle<JSTaggedValue> module)
114 {
115 JSThread *thread = vm_->GetJSThread();
116 [[maybe_unused]] EcmaHandleScope scope(thread);
117 JSHandle<NameDictionary> dict(thread, ecmaModules_);
118 ecmaModules_ =
119 NameDictionary::Put(thread, dict, moduleName, module, PropertyAttributes::Default()).GetTaggedValue();
120 }
121
RemoveModule(JSHandle<JSTaggedValue> moduleName)122 void ModuleManager::RemoveModule(JSHandle<JSTaggedValue> moduleName)
123 {
124 JSThread *thread = vm_->GetJSThread();
125 [[maybe_unused]] EcmaHandleScope scope(thread);
126 JSHandle<NameDictionary> moduleItems(thread, ecmaModules_);
127 int entry = moduleItems->FindEntry(moduleName.GetTaggedValue());
128 if (entry != -1) {
129 ecmaModules_ = NameDictionary::Remove(thread, moduleItems, entry).GetTaggedValue();
130 }
131 }
132
GetModule(const JSThread * thread,JSHandle<JSTaggedValue> moduleName)133 JSHandle<JSTaggedValue> ModuleManager::GetModule(const JSThread *thread,
134 [[maybe_unused]] JSHandle<JSTaggedValue> moduleName)
135 {
136 int entry = NameDictionary::Cast(ecmaModules_.GetTaggedObject())->FindEntry(moduleName.GetTaggedValue());
137 if (entry != -1) {
138 return JSHandle<JSTaggedValue>(thread, NameDictionary::Cast(ecmaModules_.GetTaggedObject())->GetValue(entry));
139 }
140 return thread->GlobalConstants()->GetHandledUndefined();
141 }
142
GenerateAmiPath(const CString & currentPathFile,const CString & relativeFile)143 CString ModuleManager::GenerateAmiPath(const CString ¤tPathFile, const CString &relativeFile)
144 {
145 if (relativeFile.find("./") != 0 && relativeFile.find("../") != 0) { // not start with "./" or "../"
146 return relativeFile; // not relative
147 }
148
149 auto slashPos = currentPathFile.find_last_of('/');
150 if (slashPos == CString::npos) {
151 return relativeFile; // no need to process
152 }
153
154 auto dotPos = relativeFile.find_last_of(".");
155 if (dotPos == CString::npos) {
156 dotPos = 0;
157 }
158
159 CString fullPath;
160 fullPath.append(currentPathFile.substr(0, slashPos + 1)); // 1: with "/"
161 fullPath.append(relativeFile.substr(0, dotPos));
162 fullPath.append(".abc"); // ".js" -> ".abc"
163 return fullPath;
164 }
165
GetCurrentExportModuleName()166 const CString &ModuleManager::GetCurrentExportModuleName()
167 {
168 return moduleNames_.back();
169 }
170
SetCurrentExportModuleName(const std::string_view & moduleFile)171 void ModuleManager::SetCurrentExportModuleName(const std::string_view &moduleFile)
172 {
173 moduleNames_.emplace_back(CString(moduleFile)); // xx/xx/x.abc
174 }
175
RestoreCurrentExportModuleName()176 void ModuleManager::RestoreCurrentExportModuleName()
177 {
178 auto s = moduleNames_.size();
179 if (s > 0) {
180 moduleNames_.resize(s - 1);
181 return;
182 }
183 UNREACHABLE();
184 }
185
GetPrevExportModuleName()186 const CString &ModuleManager::GetPrevExportModuleName()
187 {
188 static const int MINIMUM_COUNT = 2;
189 auto count = moduleNames_.size();
190 ASSERT(count >= MINIMUM_COUNT);
191 return moduleNames_[count - MINIMUM_COUNT];
192 }
193
AddModuleItem(const JSThread * thread,JSHandle<JSTaggedValue> itemName,JSHandle<JSTaggedValue> value)194 void ModuleManager::AddModuleItem(const JSThread *thread, JSHandle<JSTaggedValue> itemName,
195 JSHandle<JSTaggedValue> value)
196 {
197 CString name_str = GetCurrentExportModuleName();
198 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
199
200 JSHandle<EcmaString> moduleName = factory->NewFromString(name_str);
201
202 JSHandle<JSTaggedValue> module = GetModule(thread, JSHandle<JSTaggedValue>::Cast(moduleName));
203 if (module->IsUndefined()) {
204 JSHandle<EcmaModule> emptyModule = factory->NewEmptyEcmaModule();
205 EcmaModule::AddItem(thread, emptyModule, itemName, value);
206
207 AddModule(JSHandle<JSTaggedValue>::Cast(moduleName), JSHandle<JSTaggedValue>::Cast(emptyModule));
208 } else {
209 EcmaModule::AddItem(thread, JSHandle<EcmaModule>(module), itemName, value);
210 }
211 }
212
GetModuleItem(const JSThread * thread,JSHandle<JSTaggedValue> module,JSHandle<JSTaggedValue> itemName)213 JSHandle<JSTaggedValue> ModuleManager::GetModuleItem(const JSThread *thread, JSHandle<JSTaggedValue> module,
214 JSHandle<JSTaggedValue> itemName)
215 {
216 return EcmaModule::Cast(module->GetTaggedObject())->GetItem(thread, itemName); // Assume the module is exist
217 }
218
CopyModule(const JSThread * thread,JSHandle<JSTaggedValue> src)219 void ModuleManager::CopyModule(const JSThread *thread, JSHandle<JSTaggedValue> src)
220 {
221 ASSERT(src->IsHeapObject());
222 JSHandle<EcmaModule> srcModule = JSHandle<EcmaModule>::Cast(src);
223 CString name_str = GetCurrentExportModuleName(); // Assume the srcModule exist when dstModule Execute
224
225 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
226 JSHandle<EcmaString> moduleName = factory->NewFromString(name_str);
227
228 JSHandle<JSTaggedValue> dstModule = GetModule(thread, JSHandle<JSTaggedValue>::Cast(moduleName));
229
230 if (dstModule->IsUndefined()) {
231 JSHandle<EcmaModule> emptyModule = factory->NewEmptyEcmaModule();
232 EcmaModule::CopyModuleInternal(thread, emptyModule, srcModule);
233
234 AddModule(JSHandle<JSTaggedValue>::Cast(moduleName), JSHandle<JSTaggedValue>::Cast(emptyModule));
235 } else {
236 EcmaModule::CopyModuleInternal(thread, JSHandle<EcmaModule>(dstModule), srcModule);
237 }
238 }
239
DebugPrint(const JSThread * thread,const CString & caller)240 void ModuleManager::DebugPrint([[maybe_unused]] const JSThread *thread, [[maybe_unused]] const CString &caller)
241 {
242 std::cout << "ModuleStack:";
243 for_each(moduleNames_.cbegin(),
244 moduleNames_.cend(),
245 [](const CString& s)->void {
246 std::cout << s << " ";
247 });
248 std::cout << "\n";
249 }
250 } // namespace panda::ecmascript
251