• 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/builtins/builtins_reflect.h"
17 
18 #include "ecmascript/interpreter/interpreter.h"
19 #include "ecmascript/js_tagged_value-inl.h"
20 
21 namespace panda::ecmascript::builtins {
22 // ecma 26.1.1 Reflect.apply (target, thisArgument, argumentsList)
ReflectApply(EcmaRuntimeCallInfo * argv)23 JSTaggedValue BuiltinsReflect::ReflectApply(EcmaRuntimeCallInfo *argv)
24 {
25     ASSERT(argv);
26     BUILTINS_API_TRACE(argv->GetThread(), Reflect, Apply);
27     JSThread *thread = argv->GetThread();
28     [[maybe_unused]] EcmaHandleScope handleScope(thread);
29     // 1. If IsCallable(target) is false, throw a TypeError exception.
30     JSHandle<JSTaggedValue> target = GetCallArg(argv, 0);
31     if (!target->IsCallable()) {
32         THROW_TYPE_ERROR_AND_RETURN(thread, "Reflect.apply target is not callable", JSTaggedValue::Exception());
33     }
34     // 2. Let args be ? CreateListFromArrayLike(argumentsList).
35     JSHandle<JSTaggedValue> thisArgument = GetCallArg(argv, 1);
36     JSHandle<JSTaggedValue> argumentsList = GetCallArg(argv, BuiltinsBase::ArgsPosition::THIRD);
37     JSHandle<JSTaggedValue> argOrAbrupt = JSObject::CreateListFromArrayLike(thread, argumentsList);
38     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
39     JSHandle<TaggedArray> args = JSHandle<TaggedArray>::Cast(argOrAbrupt);
40 
41     // 3. Perform PrepareForTailCall().
42     // 4. Return ? Call(target, thisArgument, args).
43     const uint32_t argsLength = args->GetLength();
44     JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
45     EcmaRuntimeCallInfo *info =
46         EcmaInterpreter::NewRuntimeCallInfo(thread, target, thisArgument, undefined, argsLength);
47     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
48     info->SetCallArg(argsLength, args);
49     return JSFunction::Call(info);
50 }
51 
52 // ecma 26.1.2 Reflect.construct (target, argumentsList [ , newTarget])
ReflectConstruct(EcmaRuntimeCallInfo * argv)53 JSTaggedValue BuiltinsReflect::ReflectConstruct(EcmaRuntimeCallInfo *argv)
54 {
55     ASSERT(argv);
56     BUILTINS_API_TRACE(argv->GetThread(), Reflect, Constructor);
57     JSThread *thread = argv->GetThread();
58     [[maybe_unused]] EcmaHandleScope handleScope(thread);
59     // 1. If IsConstructor(target) is false, throw a TypeError exception.
60     JSHandle<JSTaggedValue> target = GetCallArg(argv, 0);
61     if (!target->IsConstructor()) {
62         THROW_TYPE_ERROR_AND_RETURN(thread, "Reflect.construct target is not constructor", JSTaggedValue::Exception());
63     }
64     // 2. If newTarget is not present, set newTarget to target.
65     JSHandle<JSTaggedValue> newTarget =
66         argv->GetArgsNumber() > 2 ? GetCallArg(argv, BuiltinsBase::ArgsPosition::THIRD) : target;  // 2: num args
67     // 3. Else if IsConstructor(newTarget) is false, throw a TypeError exception.
68     if (!newTarget->IsConstructor()) {
69         THROW_TYPE_ERROR_AND_RETURN(thread, "Reflect.construct newTarget is present, but not constructor",
70                                     JSTaggedValue::Exception());
71     }
72     // 4. Let args be ? CreateListFromArrayLike(argumentsList).
73     JSHandle<JSTaggedValue> argumentsList = GetCallArg(argv, 1);
74     JSHandle<JSTaggedValue> argOrAbrupt = JSObject::CreateListFromArrayLike(thread, argumentsList);
75     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
76     JSHandle<TaggedArray> args = JSHandle<TaggedArray>::Cast(argOrAbrupt);
77     // 5. Return ? Construct(target, args, newTarget).
78     const uint32_t argsLength = args->GetLength();
79     JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
80     EcmaRuntimeCallInfo *info = EcmaInterpreter::NewRuntimeCallInfo(thread, target, undefined, newTarget, argsLength);
81     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
82     info->SetCallArg(argsLength, args);
83     return JSFunction::Construct(info);
84 }
85 
86 // ecma 26.1.3 Reflect.defineProperty (target, propertyKey, attributes)
ReflectDefineProperty(EcmaRuntimeCallInfo * argv)87 JSTaggedValue BuiltinsReflect::ReflectDefineProperty(EcmaRuntimeCallInfo *argv)
88 {
89     ASSERT(argv);
90     BUILTINS_API_TRACE(argv->GetThread(), Reflect, DefineProperty);
91     JSThread *thread = argv->GetThread();
92     [[maybe_unused]] EcmaHandleScope handleScope(thread);
93     // 1. If Type(target) is not Object, throw a TypeError exception.
94     JSHandle<JSTaggedValue> target = GetCallArg(argv, 0);
95     if (!target->IsECMAObject()) {
96         THROW_TYPE_ERROR_AND_RETURN(thread, "Reflect.defineProperty target is not object", JSTaggedValue::Exception());
97     }
98     // 2. Let key be ? ToPropertyKey(propertyKey).
99     JSHandle<JSTaggedValue> key = JSTaggedValue::ToPropertyKey(thread, GetCallArg(argv, 1));
100     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
101     // 3. Let desc be ? ToPropertyDescriptor(attributes).
102     JSHandle<JSTaggedValue> attributes = GetCallArg(argv, BuiltinsBase::ArgsPosition::THIRD);
103     PropertyDescriptor desc(thread);
104     JSObject::ToPropertyDescriptor(thread, attributes, desc);
105     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
106     // 4. Return ? target.[[DefineOwnProperty]](key, desc).
107     return GetTaggedBoolean(JSTaggedValue::DefineOwnProperty(thread, target, key, desc));
108 }
109 
110 // ecma 21.1.4 Reflect.deleteProperty (target, propertyKey)
ReflectDeleteProperty(EcmaRuntimeCallInfo * argv)111 JSTaggedValue BuiltinsReflect::ReflectDeleteProperty(EcmaRuntimeCallInfo *argv)
112 {
113     ASSERT(argv);
114     BUILTINS_API_TRACE(argv->GetThread(), Reflect, DeleteProperty);
115     JSThread *thread = argv->GetThread();
116     [[maybe_unused]] EcmaHandleScope handleScope(thread);
117     // 1. If Type(target) is not Object, throw a TypeError exception.
118     JSHandle<JSTaggedValue> target = GetCallArg(argv, 0);
119     if (!target->IsECMAObject()) {
120         THROW_TYPE_ERROR_AND_RETURN(thread, "Reflect.deleteProperty target is not object", JSTaggedValue::Exception());
121     }
122     // 2. Let key be ? ToPropertyKey(propertyKey).
123     JSHandle<JSTaggedValue> key = JSTaggedValue::ToPropertyKey(thread, GetCallArg(argv, 1));
124     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
125     // 3. Return ? target.[[Delete]](key).
126     return GetTaggedBoolean(JSTaggedValue::DeleteProperty(thread, target, key));
127 }
128 
129 // ecma 26.1.5 Reflect.get (target, propertyKey [ , receiver])
ReflectGet(EcmaRuntimeCallInfo * argv)130 JSTaggedValue BuiltinsReflect::ReflectGet(EcmaRuntimeCallInfo *argv)
131 {
132     ASSERT(argv);
133     BUILTINS_API_TRACE(argv->GetThread(), Reflect, Get);
134     JSThread *thread = argv->GetThread();
135     [[maybe_unused]] EcmaHandleScope handleScope(thread);
136     // 1. If Type(target) is not Object, throw a TypeError exception.
137     JSHandle<JSTaggedValue> val = GetCallArg(argv, 0);
138     if (!val->IsECMAObject()) {
139         THROW_TYPE_ERROR_AND_RETURN(thread, "Reflect.get target is not object", JSTaggedValue::Exception());
140     }
141     JSHandle<JSObject> target = JSHandle<JSObject>::Cast(val);
142     // 2. Let key be ? ToPropertyKey(propertyKey).
143     JSHandle<JSTaggedValue> key = JSTaggedValue::ToPropertyKey(thread, GetCallArg(argv, 1));
144     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
145     // 3. If receiver is not present, then
146     //     a. Set receiver to target.
147     // 4. Return ? target.[[Get]](key, receiver).
148     if (argv->GetArgsNumber() == 2) {  // 2: 2 means that there are 2 args in total
149         return JSObject::GetProperty(thread, target, key).GetValue().GetTaggedValue();
150     }
151     JSHandle<JSTaggedValue> receiver = GetCallArg(argv, BuiltinsBase::ArgsPosition::THIRD);
152     return JSObject::GetProperty(thread, val, key, receiver).GetValue().GetTaggedValue();
153 }
154 
155 // ecma 26.1.6 Reflect.getOwnPropertyDescriptor ( target, propertyKey )
ReflectGetOwnPropertyDescriptor(EcmaRuntimeCallInfo * argv)156 JSTaggedValue BuiltinsReflect::ReflectGetOwnPropertyDescriptor(EcmaRuntimeCallInfo *argv)
157 {
158     ASSERT(argv);
159     BUILTINS_API_TRACE(argv->GetThread(), Reflect, GetOwnPropertyDescriptor);
160     JSThread *thread = argv->GetThread();
161     [[maybe_unused]] EcmaHandleScope handleScope(thread);
162     // 1. If Type(target) is not Object, throw a TypeError exception.
163     JSHandle<JSTaggedValue> target = GetCallArg(argv, 0);
164     if (!target->IsECMAObject()) {
165         THROW_TYPE_ERROR_AND_RETURN(thread, "Reflect.getOwnPropertyDescriptor target is not object",
166                                     JSTaggedValue::Exception());
167     }
168     // 2. Let key be ? ToPropertyKey(propertyKey).
169     JSHandle<JSTaggedValue> key = JSTaggedValue::ToPropertyKey(thread, GetCallArg(argv, 1));
170     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
171     // 3. Let desc be ? target.[[GetOwnProperty]](key).
172     PropertyDescriptor desc(thread);
173     if (!JSTaggedValue::GetOwnProperty(thread, target, key, desc)) {
174         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
175     }
176     // 4. Return FromPropertyDescriptor(desc).
177     JSHandle<JSTaggedValue> res = JSObject::FromPropertyDescriptor(thread, desc);
178     return res.GetTaggedValue();
179 }
180 
181 // ecma 21.1.7 Reflect.getPrototypeOf (target)
ReflectGetPrototypeOf(EcmaRuntimeCallInfo * argv)182 JSTaggedValue BuiltinsReflect::ReflectGetPrototypeOf(EcmaRuntimeCallInfo *argv)
183 {
184     ASSERT(argv);
185     BUILTINS_API_TRACE(argv->GetThread(), Reflect, GetPrototypeOf);
186     JSThread *thread = argv->GetThread();
187     [[maybe_unused]] EcmaHandleScope handleScope(thread);
188     // 1. If Type(target) is not Object, throw a TypeError exception.
189     JSHandle<JSTaggedValue> val = GetCallArg(argv, 0);
190     if (!val->IsECMAObject()) {
191         THROW_TYPE_ERROR_AND_RETURN(thread, "Reflect.getPrototypeOf target is not object", JSTaggedValue::Exception());
192     }
193     // 2. Return ? target.[[GetPrototypeOf]]().
194     return JSTaggedValue::GetPrototype(thread, val);
195 }
196 
197 // ecma 26.1.8 Reflect.has (target, propertyKey)
ReflectHas(EcmaRuntimeCallInfo * argv)198 JSTaggedValue BuiltinsReflect::ReflectHas(EcmaRuntimeCallInfo *argv)
199 {
200     ASSERT(argv);
201     BUILTINS_API_TRACE(argv->GetThread(), Reflect, Has);
202     JSThread *thread = argv->GetThread();
203     [[maybe_unused]] EcmaHandleScope handleScope(thread);
204     // 1. If Type(target) is not Object, throw a TypeError exception.
205     JSHandle<JSTaggedValue> target = GetCallArg(argv, 0);
206     if (!target->IsECMAObject()) {
207         THROW_TYPE_ERROR_AND_RETURN(thread, "Reflect.has target is not object", JSTaggedValue::Exception());
208     }
209     // 2. Let key be ? ToPropertyKey(propertyKey).
210     JSHandle<JSTaggedValue> key = JSTaggedValue::ToPropertyKey(thread, GetCallArg(argv, 1));
211     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
212     // 3. Return ? target.[[HasProperty]](key).
213     return GetTaggedBoolean(JSTaggedValue::HasProperty(thread, target, key));
214 }
215 
216 // ecma 26.1.9  Reflect.isExtensible (target)
ReflectIsExtensible(EcmaRuntimeCallInfo * argv)217 JSTaggedValue BuiltinsReflect::ReflectIsExtensible(EcmaRuntimeCallInfo *argv)
218 {
219     ASSERT(argv);
220     JSThread *thread = argv->GetThread();
221     [[maybe_unused]] EcmaHandleScope handleScope(thread);
222     // 1. If Type(target) is not Object, throw a TypeError exception.
223     JSHandle<JSTaggedValue> target = GetCallArg(argv, 0);
224     if (!target->IsECMAObject()) {
225         THROW_TYPE_ERROR_AND_RETURN(thread, "Reflect.isExtensible target is not object", JSTaggedValue::Exception());
226     }
227     // 2. Return ? target.[[IsExtensible]]().
228     return GetTaggedBoolean(target->IsExtensible(thread));
229 }
230 
231 // ecma 26.1.10 Reflect.ownKeys (target)
ReflectOwnKeys(EcmaRuntimeCallInfo * argv)232 JSTaggedValue BuiltinsReflect::ReflectOwnKeys(EcmaRuntimeCallInfo *argv)
233 {
234     ASSERT(argv);
235     BUILTINS_API_TRACE(argv->GetThread(), Reflect, OwnKeys);
236     JSThread *thread = argv->GetThread();
237     [[maybe_unused]] EcmaHandleScope handleScope(thread);
238     // 1. If Type(target) is not Object, throw a TypeError exception.
239     JSHandle<JSTaggedValue> target = GetCallArg(argv, 0);
240     if (!target->IsECMAObject()) {
241         THROW_TYPE_ERROR_AND_RETURN(thread, "Reflect.ownKeys target is not object", JSTaggedValue::Exception());
242     }
243     // 2. Let keys be ? target.[[OwnPropertyKeys]]().
244     JSHandle<TaggedArray> keys = JSTaggedValue::GetOwnPropertyKeys(thread, target);
245     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
246     // 3. Return CreateArrayFromList(keys).
247     JSHandle<JSArray> result = JSArray::CreateArrayFromList(thread, keys);
248     return result.GetTaggedValue();
249 }
250 
251 // ecma 26.1.11 Reflect.preventExtensions (target)
ReflectPreventExtensions(EcmaRuntimeCallInfo * argv)252 JSTaggedValue BuiltinsReflect::ReflectPreventExtensions(EcmaRuntimeCallInfo *argv)
253 {
254     ASSERT(argv);
255     BUILTINS_API_TRACE(argv->GetThread(), Reflect, PreventExtensions);
256     JSThread *thread = argv->GetThread();
257     [[maybe_unused]] EcmaHandleScope handleScope(thread);
258     // 1. If Type(target) is not Object, throw a TypeError exception.
259     JSHandle<JSTaggedValue> target = GetCallArg(argv, 0);
260     if (!target->IsECMAObject()) {
261         THROW_TYPE_ERROR_AND_RETURN(thread, "Reflect.preventExtensions target is not object",
262                                     JSTaggedValue::Exception());
263     }
264     // 2. Return ? target.[[PreventExtensions]]().
265     return GetTaggedBoolean(JSTaggedValue::PreventExtensions(thread, target));
266 }
267 
268 // ecma 26.1.12 Reflect.set (target, propertyKey, V [ , receiver])
ReflectSet(EcmaRuntimeCallInfo * argv)269 JSTaggedValue BuiltinsReflect::ReflectSet(EcmaRuntimeCallInfo *argv)
270 {
271     ASSERT(argv);
272     BUILTINS_API_TRACE(argv->GetThread(), Reflect, Set);
273     JSThread *thread = argv->GetThread();
274     [[maybe_unused]] EcmaHandleScope handleScope(thread);
275     // 1. If Type(target) is not Object, throw a TypeError exception.
276     JSHandle<JSTaggedValue> targetVal = GetCallArg(argv, 0);
277     if (!targetVal->IsECMAObject()) {
278         THROW_TYPE_ERROR_AND_RETURN(thread, "Reflect.get target is not object", JSTaggedValue::Exception());
279     }
280     // 2. Let key be ? ToPropertyKey(propertyKey).
281     JSHandle<JSTaggedValue> key = JSTaggedValue::ToPropertyKey(thread, GetCallArg(argv, 1));
282     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
283     JSHandle<JSTaggedValue> value = GetCallArg(argv, BuiltinsBase::ArgsPosition::THIRD);
284     // 3. If receiver is not present, then
285     //     a. Set receiver to target.
286     // 4. Return ? target.[[Set]](key, receiver).
287     if (argv->GetArgsNumber() == 3) {  // 3: 3 means that there are three args in total
288         return GetTaggedBoolean(JSTaggedValue::SetProperty(thread, targetVal, key, value));
289     }
290     JSHandle<JSTaggedValue> receiver = GetCallArg(argv, 3);  // 3: 3 means the third arg
291     return GetTaggedBoolean(JSTaggedValue::SetProperty(thread, targetVal, key, value, receiver));
292 }
293 
294 // ecma 26.1.13  Reflect.setPrototypeOf (target, proto)
ReflectSetPrototypeOf(EcmaRuntimeCallInfo * argv)295 JSTaggedValue BuiltinsReflect::ReflectSetPrototypeOf(EcmaRuntimeCallInfo *argv)
296 {
297     ASSERT(argv);
298     BUILTINS_API_TRACE(argv->GetThread(), Reflect, SetPrototypeOf);
299     JSThread *thread = argv->GetThread();
300     [[maybe_unused]] EcmaHandleScope handleScope(thread);
301     // 1. If Type(target) is not Object, throw a TypeError exception.
302     JSHandle<JSTaggedValue> target = GetCallArg(argv, 0);
303     if (!target->IsECMAObject()) {
304         THROW_TYPE_ERROR_AND_RETURN(thread, "Reflect.setPrototypeOf target is not object", JSTaggedValue::Exception());
305     }
306     // 2. If Type(proto) is not Object and proto is not null, throw a TypeError exception.
307     JSHandle<JSTaggedValue> proto = GetCallArg(argv, 1);
308     if (!proto->IsECMAObject() && !proto->IsNull()) {
309         THROW_TYPE_ERROR_AND_RETURN(thread, "SetPrototypeOf: proto is neither Object nor Null",
310                                     JSTaggedValue::Exception());
311     }
312     // 3. Return ? target.[[SetPrototypeOf]](proto).
313     return GetTaggedBoolean(JSTaggedValue::SetPrototype(thread, target, proto));
314 }
315 }  // namespace panda::ecmascript::builtins
316