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