• 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;
69     bool isShared = SourceTextModule::IsSharedModule(moduleRecord);
70     if (isShared) {
71         moduleRequestArray = factory->NewSTaggedArray(len, JSTaggedValue::Hole(), MemSpaceType::SHARED_OLD_SPACE);
72         requestModuleArray = factory->NewSTaggedArray(len, JSTaggedValue::Hole(), MemSpaceType::SHARED_OLD_SPACE);
73     } else {
74         moduleRequestArray = factory->NewTaggedArray(len);
75         requestModuleArray = factory->NewTaggedArray(len);
76     }
77 
78     for (size_t idx = 0; idx < len; idx++) {
79         StringData sd = jsPandaFile->GetStringData(panda_file::File::EntityId(moduleRequests[idx]));
80         JSTaggedValue value(factory->GetRawStringFromStringTable(sd));
81         moduleRequestArray->Set(thread, idx, value);
82     }
83     if (len > 0) {
84         moduleRecord->SetModuleRequests(thread, moduleRequestArray);
85         // For .[RequestedModules], will later replace by sourceTextModule/recordName
86         moduleRecord->SetRequestedModules(thread, requestModuleArray);
87     }
88 
89     uint32_t lazyImportIdx = recordInfo->lazyImportIdx;
90     if (lazyImportIdx != 0) {
91         bool *lazyImportFlags =
92             ModuleLazyImportFlagAccessor(jsPandaFile, panda_file::File::EntityId(lazyImportIdx));
93         moduleRecord->SetLazyImportArray(lazyImportFlags); // set module Lazy Import flag
94     }
95     // note the order can't change
96     mda.EnumerateImportEntry(thread, moduleRecord);
97     mda.EnumerateLocalExportEntry(thread, moduleRecord);
98     mda.EnumerateIndirectExportEntry(thread, moduleRecord);
99     mda.EnumerateStarExportEntry(thread, moduleRecord);
100 }
101 
ParseCjsModule(JSThread * thread,const JSPandaFile * jsPandaFile)102 JSHandle<JSTaggedValue> ModuleDataExtractor::ParseCjsModule(JSThread *thread, const JSPandaFile *jsPandaFile)
103 {
104     const CString &descriptor = jsPandaFile->GetJSPandaFileDesc();
105     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
106     JSHandle<SourceTextModule> moduleRecord = factory->NewSourceTextModule();
107 
108     moduleRecord->SetEcmaModuleFilenameString(descriptor);
109 
110     JSHandle<JSTaggedValue> defaultName = thread->GlobalConstants()->GetHandledDefaultString();
111     JSHandle<LocalExportEntry> localExportEntry = factory->NewLocalExportEntry(defaultName,
112         defaultName, LocalExportEntry::LOCAL_DEFAULT_INDEX, SharedTypes::UNSENDABLE_MODULE);
113     SourceTextModule::AddLocalExportEntry(thread, moduleRecord, localExportEntry, 0, 1); // 1 means len
114     moduleRecord->SetStatus(ModuleStatus::UNINSTANTIATED);
115     moduleRecord->SetTypes(ModuleTypes::CJS_MODULE);
116     moduleRecord->SetIsNewBcVersion(jsPandaFile->IsNewVersion());
117 
118     return JSHandle<JSTaggedValue>::Cast(moduleRecord);
119 }
120 
ParseJsonModule(JSThread * thread,const JSPandaFile * jsPandaFile,const CString & moduleFilename,const CString & recordName)121 JSHandle<JSTaggedValue> ModuleDataExtractor::ParseJsonModule(JSThread *thread, const JSPandaFile *jsPandaFile,
122                                                              const CString &moduleFilename, const CString &recordName)
123 {
124     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
125     JSHandle<SourceTextModule> moduleRecord = factory->NewSourceTextModule();
126 
127     JSHandle<JSTaggedValue> defaultName = thread->GlobalConstants()->GetHandledDefaultString();
128     JSHandle<LocalExportEntry> localExportEntry = factory->NewLocalExportEntry(defaultName,
129         defaultName, LocalExportEntry::LOCAL_DEFAULT_INDEX, SharedTypes::UNSENDABLE_MODULE);
130     SourceTextModule::AddLocalExportEntry(thread, moduleRecord, localExportEntry, 0, 1); // 1 means len
131     JSTaggedValue jsonData = JsonParse(thread, jsPandaFile, recordName);
132     RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
133     SourceTextModule::StoreModuleValue(thread, moduleRecord, 0, JSHandle<JSTaggedValue>(thread, jsonData)); // index = 0
134 
135     moduleRecord->SetEcmaModuleFilenameString(moduleFilename);
136 
137     moduleRecord->SetStatus(ModuleStatus::EVALUATED);
138     moduleRecord->SetTypes(ModuleTypes::JSON_MODULE);
139     moduleRecord->SetIsNewBcVersion(jsPandaFile->IsNewVersion());
140 
141     return JSHandle<JSTaggedValue>::Cast(moduleRecord);
142 }
143 
ParseNativeModule(JSThread * thread,const CString & moduleRequestName,const CString & baseFileName,ModuleTypes moduleType)144 JSHandle<JSTaggedValue> ModuleDataExtractor::ParseNativeModule(JSThread *thread, const CString &moduleRequestName,
145                                                                const CString &baseFileName, ModuleTypes moduleType)
146 {
147     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
148     JSHandle<SourceTextModule> moduleRecord = factory->NewSourceTextModule();
149 
150     // set moduleRecordName as non-undefined to distinguish between merge and non-merge mode
151     moduleRecord->SetEcmaModuleRecordNameString(moduleRequestName);
152     moduleRecord->SetEcmaModuleFilenameString(baseFileName);
153     JSHandle<JSTaggedValue> defaultName = thread->GlobalConstants()->GetHandledDefaultString();
154     JSHandle<LocalExportEntry> localExportEntry = factory->NewLocalExportEntry(defaultName,
155         defaultName, LocalExportEntry::LOCAL_DEFAULT_INDEX, SharedTypes::UNSENDABLE_MODULE);
156     SourceTextModule::AddLocalExportEntry(thread, moduleRecord, localExportEntry, 0, 1);
157     moduleRecord->SetTypes(moduleType);
158     moduleRecord->SetIsNewBcVersion(true);
159     moduleRecord->SetStatus(ModuleStatus::INSTANTIATED);
160     SourceTextModule::StoreModuleValue(thread, moduleRecord, 0, thread->GlobalConstants()->GetHandledUndefined());
161 
162     return JSHandle<JSTaggedValue>::Cast(moduleRecord);
163 }
164 
JsonParse(JSThread * thread,const JSPandaFile * jsPandaFile,CString entryPoint)165 JSTaggedValue ModuleDataExtractor::JsonParse(JSThread *thread, const JSPandaFile *jsPandaFile, CString entryPoint)
166 {
167     JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
168     EcmaRuntimeCallInfo *info =
169         EcmaInterpreter::NewRuntimeCallInfo(
170             thread, undefined, undefined, undefined, 1); // 1 : argument numbers
171     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
172     JSRecordInfo *recordInfo = jsPandaFile->CheckAndGetRecordInfo(entryPoint);
173     ASSERT(recordInfo != nullptr);
174     StringData sd = jsPandaFile->GetStringData(EntityId(recordInfo->jsonStringId));
175     JSTaggedValue value(thread->GetEcmaVM()->GetFactory()->GetRawStringFromStringTable(sd));
176     info->SetCallArg(value);
177     return BuiltinsJson::Parse(info);
178 }
179 
ModuleLazyImportFlagAccessor(const JSPandaFile * pandaFile,EntityId lazyImportFlagId)180 bool* ModuleDataExtractor::ModuleLazyImportFlagAccessor(const JSPandaFile *pandaFile, EntityId lazyImportFlagId)
181 {
182     auto &pf = *pandaFile->GetPandaFile();
183     auto sp = pf.GetSpanFromId(lazyImportFlagId);
184 
185     uint32_t numLazyImportFlags = panda_file::helpers::Read<panda_file::ID_SIZE>(&sp);
186     bool *lazyImportArray = new bool[numLazyImportFlags]();
187     for (size_t idx = 0; idx < numLazyImportFlags; idx++) {
188         uint32_t value = static_cast<uint32_t>(panda_file::helpers::Read<sizeof(uint8_t)>(&sp));
189         lazyImportArray[idx] = value > 0 ? 1 : 0;
190     }
191     return lazyImportArray;
192 }
193 }  // namespace panda::ecmascript
194