• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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/js_module_namespace.h"
17 
18 #include "ecmascript/global_env.h"
19 #include "ecmascript/js_array.h"
20 #include "ecmascript/module/js_module_record.h"
21 #include "ecmascript/module/js_module_source_text.h"
22 #include "ecmascript/base/string_helper.h"
23 
24 namespace panda::ecmascript {
ModuleNamespaceCreate(JSThread * thread,const JSHandle<JSTaggedValue> & module,const JSHandle<TaggedArray> & exports)25 JSHandle<ModuleNamespace> ModuleNamespace::ModuleNamespaceCreate(JSThread *thread,
26                                                                  const JSHandle<JSTaggedValue> &module,
27                                                                  const JSHandle<TaggedArray> &exports)
28 {
29     auto globalConst = thread->GlobalConstants();
30     // 1. Assert: module is a Module Record.
31     ASSERT(module->IsModuleRecord());
32     // 2. Assert: module.[[Namespace]] is undefined.
33     JSHandle<ModuleRecord> moduleRecord = JSHandle<ModuleRecord>::Cast(module);
34     ASSERT(ModuleRecord::GetNamespace(moduleRecord.GetTaggedValue()).IsUndefined());
35     // 3. Assert: exports is a List of String values.
36     // 4. Let M be a newly created object.
37     // 5. Set M's essential internal methods to the definitions specified in 9.4.6.
38     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
39     JSHandle<ModuleNamespace> mNp = factory->NewModuleNamespace();
40     // 6. Set M.[[Module]] to module.
41     mNp->SetModule(thread, module);
42     // 7. Let sortedExports be a new List containing the same values as the list exports where the values
43     // are ordered as if an Array of the same values had been sorted using
44     // Array.prototype.sort using undefined as comparefn.
45     JSHandle<JSArray> exportsArray = JSArray::CreateArrayFromList(thread, exports);
46     JSHandle<JSObject> sortedExports = JSHandle<JSObject>::Cast(exportsArray);
47     JSHandle<JSTaggedValue> fn = globalConst->GetHandledUndefined();
48     JSArray::Sort(thread, sortedExports, fn);
49     // 8. Set M.[[Exports]] to sortedExports.
50     mNp->SetExports(thread, sortedExports);
51     // 9. Create own properties of M corresponding to the definitions in 26.3.
52 
53     JSHandle<JSTaggedValue> toStringTag = thread->GetEcmaVM()->GetGlobalEnv()->GetToStringTagSymbol();
54     JSHandle<JSTaggedValue> moduleString = globalConst->GetHandledModuleString();
55     PropertyDescriptor des(thread, moduleString, false, false, false);
56     JSHandle<JSObject> mNpObj = JSHandle<JSObject>::Cast(mNp);
57     JSObject::DefineOwnProperty(thread, mNpObj, toStringTag, des);
58     // 10. Set module.[[Namespace]] to M.
59     ModuleRecord::SetNamespace(thread, moduleRecord.GetTaggedValue(), mNp.GetTaggedValue());
60     mNp->GetJSHClass()->SetExtensible(false);
61     return mNp;
62 }
63 
GetProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key)64 OperationResult ModuleNamespace::GetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
65                                              const JSHandle<JSTaggedValue> &key)
66 {
67     // 1. Assert: IsPropertyKey(P) is true.
68     ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
69     // 2. If Type(P) is Symbol, then
70     //   a. Return ? OrdinaryGet(O, P, Receiver).
71     if (key->IsSymbol()) {
72         return JSObject::GetProperty(thread, obj, key);
73     }
74     JSHandle<ModuleNamespace> moduleNamespace = JSHandle<ModuleNamespace>::Cast(obj);
75     // 3. Let exports be O.[[Exports]].
76     JSHandle<JSTaggedValue> exports(thread, moduleNamespace->GetExports());
77     // 4. If P is not an element of exports, return undefined.
78     if (exports->IsUndefined()) {
79         return OperationResult(thread, thread->GlobalConstants()->GetUndefined(), PropertyMetaData(false));
80     }
81     if (!JSArray::IncludeInSortedValue(thread, exports, key)) {
82         return OperationResult(thread, thread->GlobalConstants()->GetUndefined(), PropertyMetaData(false));
83     }
84     // 5. Let m be O.[[Module]].
85     JSHandle<SourceTextModule> mm(thread, moduleNamespace->GetModule());
86     // 6. Let binding be ! m.ResolveExport(P, « »).
87     CVector<std::pair<JSHandle<SourceTextModule>, JSHandle<JSTaggedValue>>> resolveSet;
88     JSHandle<JSTaggedValue> binding = SourceTextModule::ResolveExport(thread, mm, key, resolveSet);
89     // 7. Assert: binding is a ResolvedBinding Record.
90     // Adapter new module
91     ASSERT(binding->IsResolvedBinding() || binding->IsResolvedIndexBinding());
92     JSTaggedValue result;
93     // 8. Let targetModule be binding.[[Module]].
94     if (binding->IsResolvedBinding()) {
95         JSHandle<ResolvedBinding> resolvedBind = JSHandle<ResolvedBinding>::Cast(binding);
96         JSTaggedValue targetModule = resolvedBind->GetModule();
97         // 9. Assert: targetModule is not undefined.
98         ASSERT(!targetModule.IsUndefined());
99         result = SourceTextModule::Cast(targetModule.GetTaggedObject())->
100                                         GetModuleValue(thread, resolvedBind->GetBindingName(), true);
101     } else {
102         JSHandle<ResolvedIndexBinding> resolvedBind = JSHandle<ResolvedIndexBinding>::Cast(binding);
103         JSTaggedValue targetModule = resolvedBind->GetModule();
104         // 9. Assert: targetModule is not undefined.
105         ASSERT(!targetModule.IsUndefined());
106         result = SourceTextModule::Cast(targetModule.GetTaggedObject())->
107                                         GetModuleValue(thread, resolvedBind->GetIndex(), true);
108     }
109     return OperationResult(thread, result, PropertyMetaData(true));
110 }
111 
OwnPropertyKeys(JSThread * thread,const JSHandle<JSTaggedValue> & obj)112 JSHandle<TaggedArray> ModuleNamespace::OwnPropertyKeys(JSThread *thread, const JSHandle<JSTaggedValue> &obj)
113 {
114     ASSERT(obj->IsModuleNamespace());
115     // 1. Let exports be a copy of O.[[Exports]].
116     JSHandle<ModuleNamespace> moduleNamespace = JSHandle<ModuleNamespace>::Cast(obj);
117     JSHandle<JSTaggedValue> exports(thread, moduleNamespace->GetExports());
118     JSHandle<TaggedArray> exportsArray = JSArray::ToTaggedArray(thread, exports);
119     if (!moduleNamespace->ValidateKeysAvailable(thread, exportsArray)) {
120         return exportsArray;
121     }
122 
123     // 2. Let symbolKeys be ! OrdinaryOwnPropertyKeys(O).
124     JSHandle<TaggedArray> symbolKeys = JSObject::GetOwnPropertyKeys(thread, JSHandle<JSObject>(obj));
125     // 3. Append all the entries of symbolKeys to the end of exports.
126     JSHandle<TaggedArray> result = TaggedArray::Append(thread, exportsArray, symbolKeys);
127     // 4. Return exports.
128     return result;
129 }
130 
PreventExtensions()131 bool ModuleNamespace::PreventExtensions()
132 {
133     return true;
134 }
135 
DefineOwnProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key,PropertyDescriptor desc)136 bool ModuleNamespace::DefineOwnProperty(JSThread *thread,
137                                         const JSHandle<JSTaggedValue> &obj,
138                                         const JSHandle<JSTaggedValue> &key,
139                                         PropertyDescriptor desc)
140 {
141     ASSERT(obj->IsModuleNamespace());
142     // 1. If Type(P) is Symbol, return ! OrdinaryDefineOwnProperty(O, P, Desc).
143     if (key->IsSymbol()) {
144         bool res = JSObject::OrdinaryDefineOwnProperty(thread, JSHandle<JSObject>(obj), key, desc);
145         return res;
146     }
147 
148     // 2. Let current be ? O.[[GetOwnProperty]](P).
149     PropertyDescriptor current(thread);
150     // 3. If current is undefined, return false.
151     if (!GetOwnProperty(thread, obj, key, current)) {
152         return false;
153     }
154     // 4. If Desc has a [[Configurable]] field and Desc.[[Configurable]] is true, return false.
155     // 5. If Desc has an [[Enumerable]] field and Desc.[[Enumerable]] is false, return false.
156     // 6. If IsAccessorDescriptor(Desc) is true, return false.
157     // 7. If Desc has a [[Writable]] field and Desc.[[Writable]] is false, return false.
158     if (desc.IsAccessorDescriptor()) {
159         return false;
160     }
161     if (desc.HasConfigurable() && desc.IsConfigurable()) {
162         return false;
163     }
164     if (desc.HasEnumerable() && !desc.IsEnumerable()) {
165         return false;
166     }
167     if (desc.HasWritable() && !desc.IsWritable()) {
168         return false;
169     }
170 
171     // 8. If Desc has a [[Value]] field, return SameValue(Desc.[[Value]], current.[[Value]]).
172     if (desc.HasValue()) {
173         JSHandle<JSTaggedValue> descValue = desc.GetValue();
174         JSHandle<JSTaggedValue> currentValue = current.GetValue();
175         return JSTaggedValue::SameValue(descValue, currentValue);
176     }
177 
178     // 9. Return true.
179     return true;
180 }
181 
HasProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key)182 bool ModuleNamespace::HasProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
183                                   const JSHandle<JSTaggedValue> &key)
184 {
185     ASSERT(obj->IsModuleNamespace());
186     // 1. If Type(P) is Symbol, return OrdinaryHasProperty(O, P).
187     if (key->IsSymbol()) {
188         return JSObject::HasProperty(thread, JSHandle<JSObject>(obj), key);
189     }
190     // 2. Let exports be O.[[Exports]].
191     JSHandle<ModuleNamespace> moduleNamespace = JSHandle<ModuleNamespace>::Cast(obj);
192     JSHandle<JSTaggedValue> exports(thread, moduleNamespace->GetExports());
193     // 3. If P is an element of exports, return true.
194     if (exports->IsUndefined()) {
195         return false;
196     }
197     if (JSArray::IncludeInSortedValue(thread, exports, key)) {
198         return true;
199     }
200     // 4. Return false.
201     return false;
202 }
203 
SetPrototype(const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & proto)204 bool ModuleNamespace::SetPrototype([[maybe_unused]]const JSHandle<JSTaggedValue> &obj,
205                                    const JSHandle<JSTaggedValue> &proto)
206 {
207     ASSERT(obj->IsModuleNamespace());
208     // 1. Assert: Either Type(V) is Object or Type(V) is Null.
209     ASSERT(proto->IsECMAObject() || proto->IsNull());
210     return proto->IsNull();
211 }
212 
GetOwnProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key,PropertyDescriptor & desc)213 bool ModuleNamespace::GetOwnProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
214                                      const JSHandle<JSTaggedValue> &key, PropertyDescriptor &desc)
215 {
216     // 1. If Type(P) is Symbol, return OrdinaryGetOwnProperty(O, P).
217     if (key->IsSymbol()) {
218         return JSObject::GetOwnProperty(thread, JSHandle<JSObject>(obj), key, desc);
219     }
220     // 2. Let exports be O.[[Exports]].
221     JSHandle<ModuleNamespace> moduleNamespace = JSHandle<ModuleNamespace>::Cast(obj);
222     JSHandle<JSTaggedValue> exports(thread, moduleNamespace->GetExports());
223     // 3. If P is not an element of exports, return undefined.
224     if (exports->IsUndefined()) {
225         return false;
226     }
227     if (!JSArray::IncludeInSortedValue(thread, exports, key)) {
228         return false;
229     }
230     // 4. Let value be ? O.[[Get]](P, O).
231     JSHandle<JSTaggedValue> value = ModuleNamespace::GetProperty(thread, obj, key).GetValue();
232     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
233     // 5. Return PropertyDescriptor {
234     //    [[Value]]: value, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: false }.
235     desc.SetValue(value);
236     desc.SetEnumerable(true);
237     desc.SetWritable(true);
238     desc.SetConfigurable(false);
239     return true;
240 }
241 
SetProperty(JSThread * thread,bool mayThrow)242 bool ModuleNamespace::SetProperty(JSThread *thread, bool mayThrow)
243 {
244     if (mayThrow) {
245         THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot assign to read only property of Object Module", false);
246     }
247     return false;
248 }
249 
DeleteProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key)250 bool ModuleNamespace::DeleteProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
251                                      const JSHandle<JSTaggedValue> &key)
252 {
253     ASSERT(obj->IsModuleNamespace());
254     // 1. Assert: IsPropertyKey(P) is true.
255     ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
256     // 2. If Type(P) is Symbol, then
257     //    Return ? OrdinaryDelete(O, P).
258     if (key->IsSymbol()) {
259         return JSObject::DeleteProperty(thread, JSHandle<JSObject>(obj), key);
260     }
261     // 3. Let exports be O.[[Exports]].
262     JSHandle<ModuleNamespace> moduleNamespace = JSHandle<ModuleNamespace>::Cast(obj);
263     JSHandle<JSTaggedValue> exports(thread, moduleNamespace->GetExports());
264     // 4. If P is an element of exports, return false.
265     if (exports->IsUndefined()) {
266         return true;
267     }
268     if (JSArray::IncludeInSortedValue(thread, exports, key)) {
269         return false;
270     }
271     return true;
272 }
273 
ValidateKeysAvailable(JSThread * thread,const JSHandle<TaggedArray> & exports)274 bool ModuleNamespace::ValidateKeysAvailable(JSThread *thread, const JSHandle<TaggedArray> &exports)
275 {
276     JSHandle<ModuleNamespace> moduleNamespace(thread, this);
277     JSHandle<SourceTextModule> mm(thread, moduleNamespace->GetModule());
278     uint32_t exportsLength = exports->GetLength();
279     for (uint32_t idx = 0; idx < exportsLength; idx++) {
280         JSHandle<JSTaggedValue> key(thread, exports->Get(idx));
281         CVector<std::pair<JSHandle<SourceTextModule>, JSHandle<JSTaggedValue>>> resolveSet;
282         JSHandle<JSTaggedValue> binding = SourceTextModule::ResolveExport(thread, mm, key, resolveSet);
283         // Adapter new module
284         ASSERT(binding->IsResolvedBinding() || binding->IsResolvedIndexBinding());
285         JSTaggedValue targetModule = JSTaggedValue::Undefined();
286         if (binding->IsResolvedBinding()) {
287             targetModule = JSHandle<ResolvedBinding>::Cast(binding)->GetModule();
288         } else if (binding->IsResolvedIndexBinding()) {
289             targetModule = JSHandle<ResolvedIndexBinding>::Cast(binding)->GetModule();
290         }
291         ASSERT(!targetModule.IsUndefined());
292         JSTaggedValue dictionary = SourceTextModule::Cast(targetModule.GetTaggedObject())->GetNameDictionary();
293         if (dictionary.IsUndefined()) {
294             THROW_REFERENCE_ERROR_AND_RETURN(thread, "module environment is undefined", false);
295         }
296     }
297     return true;
298 }
299 }  // namespace panda::ecmascript
300