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