• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-2024 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/module/module_data_extractor.h"
17 
18 #include "ecmascript/builtins/builtins_json.h"
19 #include "ecmascript/interpreter/interpreter.h"
20 #include "ecmascript/module/accessor/module_data_accessor.h"
21 
22 namespace panda::ecmascript {
23 using StringData = panda_file::StringData;
24 using BuiltinsJson = builtins::BuiltinsJson;
25 using JSRecordInfo = ecmascript::JSPandaFile::JSRecordInfo;
26 
ParseModule(JSThread * thread,const JSPandaFile * jsPandaFile,const CString & descriptor,const CString & moduleFilename,JSRecordInfo * recordInfo)27 JSHandle<JSTaggedValue> ModuleDataExtractor::ParseModule(JSThread *thread, const JSPandaFile *jsPandaFile,
28                                                          const CString &descriptor, const CString &moduleFilename,
29                                                          JSRecordInfo *recordInfo)
30 {
31     int moduleIdx = jsPandaFile->GetModuleRecordIdx(descriptor);
32     ASSERT(moduleIdx != -1);
33     panda_file::File::EntityId moduleId;
34     if (jsPandaFile->IsNewVersion()) {  // new pandafile version use new literal offset mechanism
35         moduleId = panda_file::File::EntityId(static_cast<uint32_t>(moduleIdx));
36     } else {
37         panda_file::LiteralDataAccessor lda = jsPandaFile->GetLiteralDataAccessor();
38         moduleId = lda.GetLiteralArrayId(static_cast<size_t>(moduleIdx));
39     }
40 
41     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
42     JSHandle<SourceTextModule> moduleRecord = factory->NewSourceTextModule();
43     ExtractModuleDatas(thread, jsPandaFile, moduleId, moduleRecord, recordInfo);
44 
45     bool hasTLA = recordInfo->hasTopLevelAwait;
46     moduleRecord->SetHasTLA(hasTLA);
47 
48     moduleRecord->SetEcmaModuleFilenameString(moduleFilename);
49 
50     moduleRecord->SetStatus(ModuleStatus::UNINSTANTIATED);
51     moduleRecord->SetTypes(ModuleTypes::ECMA_MODULE);
52     moduleRecord->SetIsNewBcVersion(jsPandaFile->IsNewVersion());
53 
54     return JSHandle<JSTaggedValue>::Cast(moduleRecord);
55 }
56 
ExtractModuleDatas(JSThread * thread,const JSPandaFile * jsPandaFile,panda_file::File::EntityId moduleId,JSHandle<SourceTextModule> & moduleRecord,JSRecordInfo * recordInfo)57 void ModuleDataExtractor::ExtractModuleDatas(JSThread *thread, const JSPandaFile *jsPandaFile,
58                                              panda_file::File::EntityId moduleId,
59                                              JSHandle<SourceTextModule> &moduleRecord,
60                                              [[maybe_unused]]JSRecordInfo *recordInfo)
61 {
62     [[maybe_unused]] EcmaHandleScope scope(thread);
63     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
64     ModuleDataAccessor mda(jsPandaFile, moduleId);
65     const std::vector<uint32_t> &moduleRequests = mda.getModuleRequests();
66     size_t len = moduleRequests.size();
67     JSHandle<TaggedArray> moduleRequestArray;
68     JSHandle<TaggedArray> requestModuleArray(thread->GlobalConstants()->GetHandledUndefined());
69     bool isShared = SourceTextModule::IsSharedModule(moduleRecord);
70     if (isShared) {
71         moduleRequestArray = factory->NewSTaggedArray(len, JSTaggedValue::Hole(), MemSpaceType::SHARED_OLD_SPACE);
72     } else {
73         moduleRequestArray = factory->NewTaggedArray(len);
74         requestModuleArray = factory->NewTaggedArray(len);
75     }
76 
77     for (size_t idx = 0; idx < len; idx++) {
78         StringData sd = jsPandaFile->GetStringData(panda_file::File::EntityId(moduleRequests[idx]));
79         JSTaggedValue value(factory->GetRawStringFromStringTable(sd));
80         moduleRequestArray->Set(thread, idx, value);
81     }
82     if (len > 0) {
83         moduleRecord->SetModuleRequests(thread, moduleRequestArray);
84         // For .[RequestedModules], normal module will later replace by sourceTextModule
85         moduleRecord->SetRequestedModules(thread, requestModuleArray);
86         if (isShared) {
87             moduleRecord->SetRequestedModules(thread, moduleRequestArray);
88         }
89     }
90 
91     uint32_t lazyImportIdx = recordInfo->lazyImportIdx;
92     if (lazyImportIdx != 0) {
93         bool *lazyImportFlags =
94             ModuleLazyImportFlagAccessor(jsPandaFile, panda_file::File::EntityId(lazyImportIdx));
95         moduleRecord->SetLazyImportArray(lazyImportFlags); // set module Lazy Import flag
96     }
97     // note the order can't change
98     mda.EnumerateImportEntry(thread, moduleRecord);
99     mda.EnumerateLocalExportEntry(thread, moduleRecord);
100     mda.EnumerateIndirectExportEntry(thread, moduleRecord);
101     mda.EnumerateStarExportEntry(thread, moduleRecord);
102 }
103 
ParseCjsModule(JSThread * thread,const JSPandaFile * jsPandaFile)104 JSHandle<JSTaggedValue> ModuleDataExtractor::ParseCjsModule(JSThread *thread, const JSPandaFile *jsPandaFile)
105 {
106     const CString &descriptor = jsPandaFile->GetJSPandaFileDesc();
107     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
108     JSHandle<SourceTextModule> moduleRecord = factory->NewSourceTextModule();
109 
110     moduleRecord->SetEcmaModuleFilenameString(descriptor);
111 
112     JSHandle<JSTaggedValue> defaultName = thread->GlobalConstants()->GetHandledDefaultString();
113     JSHandle<LocalExportEntry> localExportEntry = factory->NewLocalExportEntry(defaultName,
114         defaultName, LocalExportEntry::LOCAL_DEFAULT_INDEX, SharedTypes::UNSENDABLE_MODULE);
115     SourceTextModule::AddLocalExportEntry(thread, moduleRecord, localExportEntry, 0, 1); // 1 means len
116     moduleRecord->SetStatus(ModuleStatus::UNINSTANTIATED);
117     moduleRecord->SetTypes(ModuleTypes::CJS_MODULE);
118     moduleRecord->SetIsNewBcVersion(jsPandaFile->IsNewVersion());
119 
120     return JSHandle<JSTaggedValue>::Cast(moduleRecord);
121 }
122 
ParseJsonModule(JSThread * thread,const JSPandaFile * jsPandaFile,const CString & moduleFilename,const CString & recordName)123 JSHandle<JSTaggedValue> ModuleDataExtractor::ParseJsonModule(JSThread *thread, const JSPandaFile *jsPandaFile,
124                                                              const CString &moduleFilename, const CString &recordName)
125 {
126     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
127     JSHandle<SourceTextModule> moduleRecord = factory->NewSourceTextModule();
128 
129     JSHandle<JSTaggedValue> defaultName = thread->GlobalConstants()->GetHandledDefaultString();
130     JSHandle<LocalExportEntry> localExportEntry = factory->NewLocalExportEntry(defaultName,
131         defaultName, LocalExportEntry::LOCAL_DEFAULT_INDEX, SharedTypes::UNSENDABLE_MODULE);
132     SourceTextModule::AddLocalExportEntry(thread, moduleRecord, localExportEntry, 0, 1); // 1 means len
133     JSTaggedValue jsonData = JsonParse(thread, jsPandaFile, recordName);
134     RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
135     SourceTextModule::StoreModuleValue(thread, moduleRecord, 0, JSHandle<JSTaggedValue>(thread, jsonData)); // index = 0
136 
137     moduleRecord->SetEcmaModuleFilenameString(moduleFilename);
138 
139     moduleRecord->SetStatus(ModuleStatus::UNINSTANTIATED);
140     moduleRecord->SetTypes(ModuleTypes::JSON_MODULE);
141     moduleRecord->SetIsNewBcVersion(jsPandaFile->IsNewVersion());
142 
143     return JSHandle<JSTaggedValue>::Cast(moduleRecord);
144 }
145 
ParseNativeModule(JSThread * thread,const CString & moduleRequestName,const CString & baseFileName,ModuleTypes moduleType)146 JSHandle<JSTaggedValue> ModuleDataExtractor::ParseNativeModule(JSThread *thread, const CString &moduleRequestName,
147                                                                const CString &baseFileName, ModuleTypes moduleType)
148 {
149     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
150     JSHandle<SourceTextModule> moduleRecord = factory->NewSourceTextModule();
151 
152     // set moduleRecordName as non-undefined to distinguish between merge and non-merge mode
153     moduleRecord->SetEcmaModuleRecordNameString(moduleRequestName);
154     moduleRecord->SetEcmaModuleFilenameString(baseFileName);
155     JSHandle<JSTaggedValue> defaultName = thread->GlobalConstants()->GetHandledDefaultString();
156     JSHandle<LocalExportEntry> localExportEntry = factory->NewLocalExportEntry(defaultName,
157         defaultName, LocalExportEntry::LOCAL_DEFAULT_INDEX, SharedTypes::UNSENDABLE_MODULE);
158     SourceTextModule::AddLocalExportEntry(thread, moduleRecord, localExportEntry, 0, 1);
159     moduleRecord->SetTypes(moduleType);
160     moduleRecord->SetIsNewBcVersion(true);
161     moduleRecord->SetStatus(ModuleStatus::INSTANTIATED);
162     SourceTextModule::StoreModuleValue(thread, moduleRecord, 0, thread->GlobalConstants()->GetHandledUndefined());
163 
164     return JSHandle<JSTaggedValue>::Cast(moduleRecord);
165 }
166 
JsonParse(JSThread * thread,const JSPandaFile * jsPandaFile,CString entryPoint)167 JSTaggedValue ModuleDataExtractor::JsonParse(JSThread *thread, const JSPandaFile *jsPandaFile, CString entryPoint)
168 {
169     JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
170     EcmaRuntimeCallInfo *info =
171         EcmaInterpreter::NewRuntimeCallInfo(
172             thread, undefined, undefined, undefined, 1); // 1 : argument numbers
173     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
174     JSRecordInfo *recordInfo = jsPandaFile->CheckAndGetRecordInfo(entryPoint);
175     ASSERT(recordInfo != nullptr);
176     StringData sd = jsPandaFile->GetStringData(EntityId(recordInfo->jsonStringId));
177     JSTaggedValue value(thread->GetEcmaVM()->GetFactory()->GetRawStringFromStringTable(sd));
178     info->SetCallArg(value);
179     return BuiltinsJson::Parse(info);
180 }
181 
ModuleLazyImportFlagAccessor(const JSPandaFile * pandaFile,EntityId lazyImportFlagId)182 bool* ModuleDataExtractor::ModuleLazyImportFlagAccessor(const JSPandaFile *pandaFile, EntityId lazyImportFlagId)
183 {
184     auto &pf = *pandaFile->GetPandaFile();
185     auto sp = pf.GetSpanFromId(lazyImportFlagId);
186 
187     uint32_t numLazyImportFlags = panda_file::helpers::Read<panda_file::ID_SIZE>(&sp);
188     bool *lazyImportArray = new bool[numLazyImportFlags]();
189     for (size_t idx = 0; idx < numLazyImportFlags; idx++) {
190         uint32_t value = static_cast<uint32_t>(panda_file::helpers::Read<sizeof(uint8_t)>(&sp));
191         lazyImportArray[idx] = value > 0 ? 1 : 0;
192     }
193     return lazyImportArray;
194 }
195 }  // namespace panda::ecmascript
196