1 /*
2  * Copyright (c) 2022 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/jspandafile/accessor/module_data_accessor.h"
17 #include "ecmascript/global_env_constants-inl.h"
18 #include "ecmascript/jspandafile/js_pandafile_manager.h"
19 #include "ecmascript/shared_objects/js_shared_array.h"
20 
21 namespace panda::ecmascript {
ModuleDataAccessor(const JSPandaFile *pandaFile, EntityId moduleDataId)22 ModuleDataAccessor::ModuleDataAccessor(const JSPandaFile *pandaFile, EntityId moduleDataId)
23     : pandaFile_(pandaFile), moduleDataId_(moduleDataId)
24 {
25     auto &pf = *pandaFile_->GetPandaFile();
26     auto sp = pf.GetSpanFromId(moduleDataId);
27 
28     auto moduleSp = sp.SubSpan(panda_file::ID_SIZE); // skip literalnum
29 
30     numModuleRequests_ = panda_file::helpers::Read<panda_file::ID_SIZE>(&moduleSp);
31 
32     for (size_t idx = 0; idx < numModuleRequests_; idx++) {
33         auto value = static_cast<uint32_t>(panda_file::helpers::Read<sizeof(uint32_t)>(&moduleSp));
34         moduleRequests_.emplace_back(value);
35     }
36 
37     entryDataSp_ = moduleSp;
38 }
39 
CreatEntries(JSThread *thread, uint32_t regularImportNum, SharedTypes sharedType)40 JSHandle<TaggedArray> ModuleDataAccessor::CreatEntries(JSThread *thread, uint32_t regularImportNum,
41                                                        SharedTypes sharedType)
42 {
43     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
44     JSHandle<TaggedArray> regularImportEntries;
45     if (sharedType == SharedTypes::SHARED_MODULE) {
46         regularImportEntries = factory->NewSTaggedArray(regularImportNum, JSTaggedValue::Hole(),
47             MemSpaceType::SHARED_OLD_SPACE);
48     } else {
49         regularImportEntries = factory->NewTaggedArray(regularImportNum);
50     }
51     return regularImportEntries;
52 }
53 
EnumerateImportEntry(JSThread *thread, const JSHandle<TaggedArray> &requestModuleArray, JSHandle<SourceTextModule> &moduleRecord)54 void ModuleDataAccessor::EnumerateImportEntry(JSThread *thread,
55                                               const JSHandle<TaggedArray> &requestModuleArray,
56                                               JSHandle<SourceTextModule> &moduleRecord)
57 {
58     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
59     auto globalConstants = thread->GlobalConstants();
60     auto sp = entryDataSp_;
61     SharedTypes sharedType = moduleRecord->GetSharedType();
62     auto regularImportNum = panda_file::helpers::Read<panda_file::ID_SIZE>(&sp);
63     JSHandle<TaggedArray> regularImportEntries = CreatEntries(thread, regularImportNum, sharedType);
64 
65     JSMutableHandle<JSTaggedValue> importName(thread, globalConstants->GetUndefined());
66     JSMutableHandle<JSTaggedValue> localName(thread, globalConstants->GetUndefined());
67     JSMutableHandle<JSTaggedValue> moduleRequest(thread, globalConstants->GetUndefined());
68 
69     for (size_t idx = 0; idx < regularImportNum; idx++) {
70         ReadRegularImportEntry(&sp, factory, requestModuleArray, importName, localName, moduleRequest);
71         JSHandle<ImportEntry> importEntry = factory->NewImportEntry(moduleRequest, importName, localName,
72                                                                     sharedType);
73         regularImportEntries->Set(thread, idx, importEntry);
74     }
75 
76     auto namespaceImportNum = panda_file::helpers::Read<panda_file::ID_SIZE>(&sp);
77     auto totalSize = regularImportNum + namespaceImportNum;
78     if (totalSize == 0) {
79         entryDataSp_ = sp;
80         return;
81     }
82     JSHandle<TaggedArray> importEntries;
83     if (sharedType == SharedTypes::SHARED_MODULE) {
84         importEntries = JSSharedArray::SetCapacity(thread, regularImportEntries, totalSize);
85     } else {
86         importEntries = TaggedArray::SetCapacity(thread, regularImportEntries, totalSize);
87     }
88 
89     importName.Update(globalConstants->GetHandledStarString());
90 
91     for (size_t idx = regularImportNum; idx < totalSize; idx++) {
92         ReadNamespaceImportEntry(&sp, factory, requestModuleArray, localName, moduleRequest);
93         JSHandle<ImportEntry> importEntry = factory->NewImportEntry(moduleRequest, importName, localName,
94                                                                     sharedType);
95         importEntries->Set(thread, idx, importEntry);
96     }
97     entryDataSp_ = sp;
98     moduleRecord->SetImportEntries(thread, importEntries);
99 }
100 
ReadRegularImportEntry(Span<const uint8_t> *sp, ObjectFactory *factory, const JSHandle<TaggedArray> &requestModuleArray, JSMutableHandle<JSTaggedValue> &importName, JSMutableHandle<JSTaggedValue> &localName, JSMutableHandle<JSTaggedValue> &moduleRequest)101 void ModuleDataAccessor::ReadRegularImportEntry(Span<const uint8_t> *sp, ObjectFactory *factory,
102                                                 const JSHandle<TaggedArray> &requestModuleArray,
103                                                 JSMutableHandle<JSTaggedValue> &importName,
104                                                 JSMutableHandle<JSTaggedValue> &localName,
105                                                 JSMutableHandle<JSTaggedValue> &moduleRequest)
106 {
107     size_t requestArraySize = requestModuleArray->GetLength();
108 
109     auto localNameOffset = static_cast<uint32_t>(panda_file::helpers::Read<sizeof(uint32_t)>(sp));
110     auto importNameOffset = static_cast<uint32_t>(panda_file::helpers::Read<sizeof(uint32_t)>(sp));
111     auto moduleRequestIdx = static_cast<uint32_t>(panda_file::helpers::Read<sizeof(uint16_t)>(sp));
112     auto sd = pandaFile_->GetStringData(panda_file::File::EntityId(localNameOffset));
113     localName.Update(JSTaggedValue(factory->GetRawStringFromStringTable(sd)));
114 
115     sd = pandaFile_->GetStringData(panda_file::File::EntityId(importNameOffset));
116     importName.Update(JSTaggedValue(factory->GetRawStringFromStringTable(sd)));
117 
118     if (requestArraySize != 0) {
119         moduleRequest.Update(requestModuleArray->Get(moduleRequestIdx));
120     }
121 }
122 
ReadNamespaceImportEntry(Span<const uint8_t> *sp, ObjectFactory *factory, const JSHandle<TaggedArray> &requestModuleArray, JSMutableHandle<JSTaggedValue> &localName, JSMutableHandle<JSTaggedValue> &moduleRequest)123 void ModuleDataAccessor::ReadNamespaceImportEntry(Span<const uint8_t> *sp, ObjectFactory *factory,
124                                                   const JSHandle<TaggedArray> &requestModuleArray,
125                                                   JSMutableHandle<JSTaggedValue> &localName,
126                                                   JSMutableHandle<JSTaggedValue> &moduleRequest)
127 {
128     size_t requestArraySize = requestModuleArray->GetLength();
129 
130     auto localNameOffset = static_cast<uint32_t>(panda_file::helpers::Read<sizeof(uint32_t)>(sp));
131     auto moduleRequestIdx = static_cast<uint32_t>(panda_file::helpers::Read<sizeof(uint16_t)>(sp));
132     auto sd = pandaFile_->GetStringData(panda_file::File::EntityId(localNameOffset));
133     localName.Update(JSTaggedValue(factory->GetRawStringFromStringTable(sd)));
134 
135     if (requestArraySize != 0) {
136         moduleRequest.Update(requestModuleArray->Get(moduleRequestIdx));
137     }
138 }
139 
EnumerateLocalExportEntry(JSThread *thread, JSHandle<SourceTextModule> &moduleRecord)140 void ModuleDataAccessor::EnumerateLocalExportEntry(JSThread *thread, JSHandle<SourceTextModule> &moduleRecord)
141 {
142     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
143     auto sp = entryDataSp_;
144     auto localExportNum = panda_file::helpers::Read<panda_file::ID_SIZE>(&sp);
145     if (localExportNum == 0) {
146         entryDataSp_ = sp;
147         return;
148     }
149     SharedTypes sharedType = moduleRecord->GetSharedType();
150     JSHandle<TaggedArray> localExportEntries = CreatEntries(thread, localExportNum, sharedType);
151 
152     uint32_t localIndex = -1;
153     JSMutableHandle<JSTaggedValue> distinctLocalName(thread, JSTaggedValue::Undefined());
154     for (size_t idx = 0; idx < localExportNum; idx++) {
155         auto localNameOffset = static_cast<uint32_t>(panda_file::helpers::Read<sizeof(uint32_t)>(&sp));
156         auto exportNameOffset = static_cast<uint32_t>(panda_file::helpers::Read<sizeof(uint32_t)>(&sp));
157         auto sd = pandaFile_->GetStringData(panda_file::File::EntityId(localNameOffset));
158         JSHandle<JSTaggedValue> localName(thread, factory->GetRawStringFromStringTable(sd));
159 
160         sd = pandaFile_->GetStringData(panda_file::File::EntityId(exportNameOffset));
161         JSHandle<JSTaggedValue> exportName(thread, factory->GetRawStringFromStringTable(sd));
162 
163         if (!JSTaggedValue::StrictEqual(thread, distinctLocalName, localName)) {
164             distinctLocalName.Update(localName);
165             localIndex++;
166         }
167         JSHandle<LocalExportEntry> localExportEntry = factory->NewLocalExportEntry(exportName, localName, localIndex,
168                                                                                    sharedType);
169         localExportEntries->Set(thread, idx, localExportEntry);
170     }
171     entryDataSp_ = sp;
172     moduleRecord->SetLocalExportEntries(thread, localExportEntries);
173 }
174 
EnumerateIndirectExportEntry(JSThread *thread, const JSHandle<TaggedArray> &requestModuleArray, JSHandle<SourceTextModule> &moduleRecord)175 void ModuleDataAccessor::EnumerateIndirectExportEntry(JSThread *thread, const JSHandle<TaggedArray> &requestModuleArray,
176                                                       JSHandle<SourceTextModule> &moduleRecord)
177 {
178     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
179     auto globalConstants = thread->GlobalConstants();
180     auto sp = entryDataSp_;
181     size_t requestArraySize = requestModuleArray->GetLength();
182 
183     auto indirectExportNum = panda_file::helpers::Read<panda_file::ID_SIZE>(&sp);
184     if (indirectExportNum == 0) {
185         entryDataSp_ = sp;
186         return;
187     }
188 
189     SharedTypes sharedType = moduleRecord->GetSharedType();
190     JSHandle<TaggedArray> indirectExportEntries = CreatEntries(thread, indirectExportNum, sharedType);
191     JSMutableHandle<JSTaggedValue> moduleRequest(thread, globalConstants->GetUndefined());
192     for (size_t idx = 0; idx < indirectExportNum; idx++) {
193         auto exportNameOffset = static_cast<uint32_t>(panda_file::helpers::Read<sizeof(uint32_t)>(&sp));
194         auto importNameOffset = static_cast<uint32_t>(panda_file::helpers::Read<sizeof(uint32_t)>(&sp));
195         auto moduleRequestIdx = static_cast<uint32_t>(panda_file::helpers::Read<sizeof(uint16_t)>(&sp));
196         auto sd = pandaFile_->GetStringData(panda_file::File::EntityId(exportNameOffset));
197         JSHandle<JSTaggedValue> exportName(thread, factory->GetRawStringFromStringTable(sd));
198 
199         sd = pandaFile_->GetStringData(panda_file::File::EntityId(importNameOffset));
200         JSHandle<JSTaggedValue> importName(thread, factory->GetRawStringFromStringTable(sd));
201 
202         if (requestArraySize != 0) {
203             moduleRequest.Update(requestModuleArray->Get(moduleRequestIdx));
204         }
205         JSHandle<IndirectExportEntry> indirectExportEntry = factory->NewIndirectExportEntry(exportName,
206             moduleRequest, importName, sharedType);
207         indirectExportEntries->Set(thread, idx, indirectExportEntry);
208     }
209     entryDataSp_ = sp;
210     moduleRecord->SetIndirectExportEntries(thread, indirectExportEntries);
211 }
212 
EnumerateStarExportEntry(JSThread *thread, const JSHandle<TaggedArray> &requestModuleArray, JSHandle<SourceTextModule> &moduleRecord)213 void ModuleDataAccessor::EnumerateStarExportEntry(JSThread *thread, const JSHandle<TaggedArray> &requestModuleArray,
214                                                   JSHandle<SourceTextModule> &moduleRecord)
215 {
216     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
217     auto globalConstants = thread->GlobalConstants();
218     auto sp = entryDataSp_;
219     size_t requestArraySize = requestModuleArray->GetLength();
220 
221     auto starExportNum = panda_file::helpers::Read<panda_file::ID_SIZE>(&sp);
222     if (starExportNum == 0) {
223         entryDataSp_ = sp;
224         return;
225     }
226 
227     SharedTypes sharedType = moduleRecord->GetSharedType();
228     JSHandle<TaggedArray> starExportEntries = CreatEntries(thread, starExportNum, sharedType);
229     JSMutableHandle<JSTaggedValue> moduleRequest(thread, globalConstants->GetUndefined());
230     for (size_t idx = 0; idx < starExportNum; idx++) {
231         auto moduleRequestIdx = static_cast<uint32_t>(panda_file::helpers::Read<sizeof(uint16_t)>(&sp));
232         if (requestArraySize != 0) {
233             moduleRequest.Update(requestModuleArray->Get(moduleRequestIdx));
234         }
235 
236         JSHandle<StarExportEntry> starExportEntry = factory->NewStarExportEntry(moduleRequest, sharedType);
237         starExportEntries->Set(thread, idx, starExportEntry.GetTaggedValue());
238     }
239     entryDataSp_ = sp;
240     moduleRecord->SetStarExportEntries(thread, starExportEntries);
241 }
242 }  // namespace panda::ecmascript
243