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