• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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());
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());
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());
69     if (SourceTextModule::IsSharedModule((resolvedModule))) {
70         JSHandle<JSTaggedValue> bindingName(thread, resolvedBinding->GetBindingName());
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());
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(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(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