1 /*
2 * Copyright (c) 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 #include "ecmascript/global_env.h"
16 #include "ecmascript/module/js_shared_module.h"
17 #include "ecmascript/module/module_data_extractor.h"
18 #include "ecmascript/shared_objects/js_shared_array.h"
19
20 namespace panda::ecmascript {
GenerateSendableFuncModule(JSThread * thread,const JSHandle<JSTaggedValue> & module)21 JSHandle<JSTaggedValue> SendableClassModule::GenerateSendableFuncModule(JSThread *thread,
22 const JSHandle<JSTaggedValue> &module)
23 {
24 // esm -> SourceTextModule; cjs or script -> string of recordName
25 if (!module->IsSourceTextModule()) {
26 ASSERT(module->IsString());
27 return module;
28 }
29 JSHandle<SourceTextModule> currentModule = JSHandle<SourceTextModule>::Cast(module);
30 // Only clone module in isolate-heap.
31 if (SourceTextModule::IsModuleInSharedHeap(currentModule)) {
32 return module;
33 }
34 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
35 JSHandle<SourceTextModule> sModule = factory->NewSSourceTextModule();
36 JSHandle<JSTaggedValue> currentEnvironment(thread, currentModule->GetEnvironment(thread));
37 JSHandle<TaggedArray> sendableEnvironment = SendableClassModule::CloneModuleEnvironment(thread,
38 currentEnvironment);
39 sModule->SetSharedType(SharedTypes::SENDABLE_FUNCTION_MODULE);
40 sModule->SetEnvironment(thread, sendableEnvironment);
41 sModule->SetEcmaModuleFilenameString(currentModule->GetEcmaModuleFilenameString());
42 sModule->SetEcmaModuleRecordNameString(currentModule->GetEcmaModuleRecordNameString());
43 sModule->SetSendableEnv(thread, JSTaggedValue::Undefined());
44 return JSHandle<JSTaggedValue>(sModule);
45 }
46
CloneRecordIndexBinding(JSThread * thread,JSTaggedValue indexBinding)47 JSHandle<JSTaggedValue> SendableClassModule::CloneRecordIndexBinding(JSThread *thread, JSTaggedValue indexBinding)
48 {
49 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
50 JSHandle<ResolvedIndexBinding> binding(thread, indexBinding);
51 JSHandle<SourceTextModule> resolvedModule(thread, binding->GetModule(thread));
52 if (SourceTextModule::IsSharedModule((resolvedModule))) {
53 return JSHandle<JSTaggedValue>::Cast(
54 factory->NewSResolvedIndexBindingRecord(resolvedModule, binding->GetIndex()));
55 }
56
57 CString moduleName = SourceTextModule::GetModuleName(resolvedModule.GetTaggedValue());
58 JSHandle<EcmaString> record = thread->GetEcmaVM()->GetFactory()->NewFromUtf8(moduleName);
59 JSHandle<EcmaString> fileName = factory->NewFromUtf8(resolvedModule->GetEcmaModuleFilenameString());
60 int32_t index = binding->GetIndex();
61 return JSHandle<JSTaggedValue>::Cast(factory->NewSResolvedRecordIndexBindingRecord(record, fileName, index));
62 }
63
CloneRecordNameBinding(JSThread * thread,JSTaggedValue binding)64 JSHandle<JSTaggedValue> SendableClassModule::CloneRecordNameBinding(JSThread *thread, JSTaggedValue binding)
65 {
66 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
67 ResolvedBinding *resolvedBinding = ResolvedBinding::Cast(binding.GetTaggedObject());
68 JSHandle<SourceTextModule> resolvedModule(thread, resolvedBinding->GetModule(thread));
69 if (SourceTextModule::IsSharedModule((resolvedModule))) {
70 JSHandle<JSTaggedValue> bindingName(thread, resolvedBinding->GetBindingName(thread));
71 return JSHandle<JSTaggedValue>::Cast(
72 factory->NewSResolvedBindingRecord(resolvedModule, bindingName));
73 }
74
75 CString moduleName = SourceTextModule::GetModuleName(resolvedModule.GetTaggedValue());
76 JSHandle<EcmaString> record = thread->GetEcmaVM()->GetFactory()->NewFromUtf8(moduleName);
77 JSHandle<JSTaggedValue> bindingName(thread, resolvedBinding->GetBindingName(thread));
78 return JSHandle<JSTaggedValue>::Cast(factory->NewSResolvedRecordBindingRecord(record, bindingName));
79 }
80
CloneModuleEnvironment(JSThread * thread,const JSHandle<JSTaggedValue> & moduleEnvironment)81 JSHandle<TaggedArray> SendableClassModule::CloneModuleEnvironment(JSThread *thread,
82 const JSHandle<JSTaggedValue> &moduleEnvironment)
83 {
84 if (moduleEnvironment->IsUndefined()) {
85 return JSHandle<TaggedArray>(moduleEnvironment);
86 }
87 JSHandle<TaggedArray> currentEnvironment(moduleEnvironment);
88 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
89 int enumKeys = static_cast<int>(currentEnvironment->GetLength());
90 JSHandle<TaggedArray> sendableEnvironment = factory->NewSDictionaryArray(enumKeys);
91 for (int idx = 0; idx < enumKeys; idx++) {
92 JSTaggedValue key = currentEnvironment->Get(thread, idx);
93 if (key.IsRecord()) {
94 JSType type = key.GetTaggedObject()->GetClass()->GetObjectType();
95 switch (type) {
96 case JSType::RESOLVEDBINDING_RECORD: {
97 JSHandle<JSTaggedValue> recordBinding = SendableClassModule::CloneRecordNameBinding(thread, key);
98 sendableEnvironment->Set(thread, idx, recordBinding);
99 break;
100 }
101 case JSType::RESOLVEDINDEXBINDING_RECORD: {
102 JSHandle<JSTaggedValue> recordBinding = SendableClassModule::CloneRecordIndexBinding(thread, key);
103 sendableEnvironment->Set(thread, idx, recordBinding);
104 break;
105 }
106 case JSType::RESOLVEDRECORDINDEXBINDING_RECORD:
107 break;
108 case JSType::RESOLVEDRECORDBINDING_RECORD:
109 break;
110 default:
111 LOG_FULL(FATAL) << "UNREACHABLE";
112 }
113 }
114 continue;
115 }
116 return sendableEnvironment;
117 }
118
CloneEnvForSModule(JSThread * thread,const JSHandle<SourceTextModule> & module,JSHandle<TaggedArray> & envRec)119 JSHandle<TaggedArray> JSSharedModule::CloneEnvForSModule(JSThread *thread, const JSHandle<SourceTextModule> &module,
120 JSHandle<TaggedArray> &envRec)
121 {
122 if (!SourceTextModule::IsSharedModule(module)) {
123 return envRec;
124 }
125 return SendableClassModule::CloneModuleEnvironment(thread, JSHandle<JSTaggedValue>(envRec));
126 }
127
ParseSharedModule(JSThread * thread,const JSPandaFile * jsPandaFile,const CString & descriptor,const CString & moduleFilename,JSRecordInfo * recordInfo)128 JSHandle<JSTaggedValue> SharedModuleHelper::ParseSharedModule(JSThread *thread, const JSPandaFile *jsPandaFile,
129 const CString &descriptor, const CString &moduleFilename,
130 JSRecordInfo *recordInfo)
131 {
132 int moduleIdx = jsPandaFile->GetModuleRecordIdx(descriptor);
133 ASSERT(jsPandaFile->IsNewVersion() && (moduleIdx != -1)); // new pandafile version use new literal offset mechanism
134 panda_file::File::EntityId moduleId = panda_file::File::EntityId(static_cast<uint32_t>(moduleIdx));
135
136 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
137 JSHandle<SourceTextModule> moduleRecord = factory->NewSSourceTextModule();
138 moduleRecord->SetSharedType(SharedTypes::SHARED_MODULE);
139 ModuleDataExtractor::ExtractModuleDatas(thread, jsPandaFile, moduleId, moduleRecord, recordInfo);
140
141 bool hasTLA = jsPandaFile->GetHasTopLevelAwait(descriptor);
142 moduleRecord->SetHasTLA(hasTLA);
143 moduleRecord->SetEcmaModuleFilenameString(moduleFilename);
144 moduleRecord->SetStatus(ModuleStatus::UNINSTANTIATED);
145 moduleRecord->SetTypes(ModuleTypes::ECMA_MODULE);
146 moduleRecord->SetIsNewBcVersion(true);
147 return JSHandle<JSTaggedValue>::Cast(moduleRecord);
148 }
149
GenerateSharedExports(JSThread * thread,const JSHandle<TaggedArray> & oldExports)150 JSHandle<TaggedArray> JSSharedModule::GenerateSharedExports(JSThread *thread, const JSHandle<TaggedArray> &oldExports)
151 {
152 uint32_t newLength = oldExports->GetLength();
153 if (newLength == 0) {
154 LOG_FULL(INFO) << "Empty exports in moduleNamespace";
155 }
156 JSHandle<TaggedArray> newArray = thread->GetEcmaVM()->GetFactory()->NewSTaggedArray(newLength);
157 for (uint32_t i = 0; i < newLength; i++) {
158 JSTaggedValue value = oldExports->Get(thread, i);
159 ASSERT(value.IsString());
160 newArray->Set(thread, i, value);
161 }
162 return newArray;
163 }
164
CreateSharedSortedExports(JSThread * thread,const JSHandle<TaggedArray> & oldExports)165 JSHandle<JSTaggedValue> JSSharedModule::CreateSharedSortedExports(JSThread *thread,
166 const JSHandle<TaggedArray> &oldExports)
167 {
168 auto globalConst = thread->GlobalConstants();
169 JSHandle<TaggedArray> exports = GenerateSharedExports(thread, oldExports);
170 // 7. Let sortedExports be a new List containing the same values as the list exports where the values
171 // are ordered as if an Array of the same values had been sorted using
172 // Array.prototype.sort using undefined as comparefn.
173 JSHandle<JSSharedArray> exportsArray = JSSharedArray::CreateArrayFromList(thread, exports);
174 JSHandle<JSTaggedValue> sortedExports = JSHandle<JSTaggedValue>::Cast(exportsArray);
175 JSHandle<JSTaggedValue> fn = globalConst->GetHandledUndefined();
176 JSSharedArray::Sort(thread, sortedExports, fn);
177 return sortedExports;
178 }
179
SModuleNamespaceCreate(JSThread * thread,const JSHandle<JSTaggedValue> & module,const JSHandle<TaggedArray> & exports)180 JSHandle<ModuleNamespace> JSSharedModule::SModuleNamespaceCreate(JSThread *thread,
181 const JSHandle<JSTaggedValue> &module,
182 const JSHandle<TaggedArray> &exports)
183 {
184 auto globalConst = thread->GlobalConstants();
185 // 2. Assert: module.[[Namespace]] is undefined.
186 // 3. Assert: exports is a List of String values.
187 // 4. Let M be a newly created object.
188 // 5. Set M's essential internal methods to the definitions specified in 9.4.6.
189 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
190 JSHandle<ModuleNamespace> mNp = factory->NewSModuleNamespace();
191 // 6. Set M.[[Module]] to module.
192 mNp->SetModule(thread, module);
193 JSHandle<JSTaggedValue> sortedExports = JSSharedModule::CreateSharedSortedExports(thread, exports);
194
195 // 8. Set M.[[Exports]] to sortedExports.
196 mNp->SetExports(thread, sortedExports);
197 // 9. Create own properties of M corresponding to the definitions in 26.3.
198
199 JSHandle<JSTaggedValue> toStringTag = thread->GetEcmaVM()->GetGlobalEnv()->GetToStringTagSymbol();
200 JSHandle<JSTaggedValue> moduleString = globalConst->GetHandledModuleString();
201 PropertyDescriptor des(thread, moduleString, false, false, false);
202 JSHandle<JSObject> mNpObj = JSHandle<JSObject>::Cast(mNp);
203 JSObject::DefineOwnProperty(thread, mNpObj, toStringTag, des);
204 JSHandle<ModuleRecord> moduleRecord = JSHandle<ModuleRecord>::Cast(module);
205 SourceTextModule::Cast(moduleRecord.GetTaggedValue().GetTaggedObject())->SetNamespace(thread,
206 mNp.GetTaggedValue());
207 // 10. Set module.[[Namespace]] to M.
208 mNp->GetJSHClass()->SetExtensible(false);
209 return mNp;
210 }
211 } // namespace panda::ecmascript
212