• 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 "js_proxy.h"
17 #include "ecmascript/ecma_macros.h"
18 #include "ecmascript/global_env.h"
19 #include "ecmascript/internal_call_params.h"
20 #include "ecmascript/js_array.h"
21 #include "ecmascript/js_handle.h"
22 #include "ecmascript/object_factory.h"
23 
24 namespace panda::ecmascript {
25 // ES6 9.5.15 ProxyCreate(target, handler)
ProxyCreate(JSThread * thread,const JSHandle<JSTaggedValue> & target,const JSHandle<JSTaggedValue> & handler)26 JSHandle<JSProxy> JSProxy::ProxyCreate(JSThread *thread, const JSHandle<JSTaggedValue> &target,
27                                        const JSHandle<JSTaggedValue> &handler)
28 {
29     // 1. If Type(target) is not Object, throw a TypeError exception.
30     if (!target->IsECMAObject()) {
31         THROW_TYPE_ERROR_AND_RETURN(thread, "ProxyCreate: target is not Object",
32                                     JSHandle<JSProxy>(thread, JSTaggedValue::Exception()));
33     }
34 
35     // 2. If Type(handler) is not Object, throw a TypeError exception.
36     if (!handler->IsECMAObject()) {
37         THROW_TYPE_ERROR_AND_RETURN(thread, "ProxyCreate: handler is not Object",
38                                     JSHandle<JSProxy>(thread, JSTaggedValue::Exception()));
39     }
40     // 3. Let P be ! MakeBasicObject(« [[ProxyHandler]], [[ProxyTarget]] »).
41     // 6. If IsCallable(target) is true, then P.[[Call]] as specified in 9.5.12.
42 
43     // 8. Set the [[ProxyTarget]] internal slot of P to target.
44     // 9. Set the [[ProxyHandler]] internal slot of P to handler.
45     return thread->GetEcmaVM()->GetFactory()->NewJSProxy(target, handler);
46 }
47 
48 // ES6 9.5.1 [[GetPrototypeOf]] ( )
GetPrototype(JSThread * thread,const JSHandle<JSProxy> & proxy)49 JSTaggedValue JSProxy::GetPrototype(JSThread *thread, const JSHandle<JSProxy> &proxy)
50 {
51     // 1. Let handler be the value of the [[ProxyHandler]] internal slot of O.
52     JSHandle<JSTaggedValue> handler(thread, proxy->GetHandler());
53     // 2. If handler is null, throw a TypeError exception.
54     if (handler->IsNull()) {
55         THROW_TYPE_ERROR_AND_RETURN(thread, "JSProxy::GetPrototype: handler is null", JSTaggedValue::Exception());
56     }
57     // 3. Assert: Type(handler) is Object.
58     ASSERT(handler->IsECMAObject());
59     // 4. Let target be the value of the [[ProxyTarget]] internal slot of O.
60     JSHandle<JSTaggedValue> targetHandle(thread, proxy->GetTarget());
61     // 5. Let trap be GetMethod(handler, "getPrototypeOf").
62     JSHandle<JSTaggedValue> name(thread->GlobalConstants()->GetHandledGetPrototypeOfString());
63     JSHandle<JSTaggedValue> trap = JSObject::GetMethod(thread, handler, name);
64     // 6. ReturnIfAbrupt(trap).
65     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
66 
67     // 7. If trap is undefined, then Return target.[[GetPrototypeOf]]().
68     if (trap->IsUndefined()) {
69         return JSHandle<JSObject>(targetHandle)->GetPrototype(thread);
70     }
71     // 8. Let handlerProto be Call(trap, handler, «target»).
72     InternalCallParams *arguments = thread->GetInternalCallParams();
73     arguments->MakeArgv(targetHandle);
74     JSTaggedValue handlerProto = JSFunction::Call(thread, trap, handler, 1, arguments->GetArgv());
75 
76     // 9. ReturnIfAbrupt(handlerProto).
77     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
78     // 10. If Type(handlerProto) is neither Object nor Null, throw a TypeError exception.
79     if (!handlerProto.IsECMAObject() && !handlerProto.IsNull()) {
80         THROW_TYPE_ERROR_AND_RETURN(thread, "JSProxy::GetPrototype: Type(handlerProto) is neither Object nor Null",
81                                     JSTaggedValue::Exception());
82     }
83     // 11. Let extensibleTarget be IsExtensible(target).
84     // 12. ReturnIfAbrupt(extensibleTarget).
85     // 13. If extensibleTarget is true, return handlerProto.
86     if (targetHandle->IsExtensible(thread)) {
87         return handlerProto;
88     }
89     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
90 
91     // 14. Let targetProto be target.[[GetPrototypeOf]]().
92     JSTaggedValue targetProto = JSHandle<JSObject>(targetHandle)->GetPrototype(thread);
93     // 15. ReturnIfAbrupt(targetProto).
94     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
95     // 16. If SameValue(handlerProto, targetProto) is false, throw a TypeError exception.
96     if (!JSTaggedValue::SameValue(handlerProto, targetProto)) {
97         THROW_TYPE_ERROR_AND_RETURN(thread, "JSProxy::GetPrototype: SameValue(handlerProto, targetProto) is false",
98                                     JSTaggedValue::Exception());
99     }
100     // 17. Return handlerProto.
101     return handlerProto;
102 }
103 
104 // ES6 9.5.2 [[SetPrototypeOf]] (V)
SetPrototype(JSThread * thread,const JSHandle<JSProxy> & proxy,const JSHandle<JSTaggedValue> & proto)105 bool JSProxy::SetPrototype(JSThread *thread, const JSHandle<JSProxy> &proxy, const JSHandle<JSTaggedValue> &proto)
106 {
107     // 1. Assert: Either Type(V) is Object or Type(V) is Null.
108     ASSERT(proto->IsECMAObject() || proto->IsNull());
109     // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
110     JSTaggedValue handler = proxy->GetHandler();
111     // 3. If handler is null, throw a TypeError exception.
112     if (handler.IsNull()) {
113         THROW_TYPE_ERROR_AND_RETURN(thread, "JSProxy::SetPrototype: handler is null", false);
114     }
115     // 4. Assert: Type(handler) is Object.
116     ASSERT(handler.IsECMAObject());
117     // 5. Let target be the value of the [[ProxyTarget]] internal slot of O.
118     JSHandle<JSTaggedValue> targetHandle(thread, proxy->GetTarget());
119     // 6. Let trap be GetMethod(handler, "setPrototypeOf").
120     JSHandle<JSTaggedValue> name = thread->GlobalConstants()->GetHandledSetPrototypeOfString();
121     JSHandle<JSTaggedValue> trap(JSObject::GetMethod(thread, JSHandle<JSTaggedValue>(thread, handler), name));
122     // 7. ReturnIfAbrupt(trap).
123     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
124 
125     // 7. If trap is undefined, then Return target.[[SetPrototypeOf]](V).
126     if (trap->IsUndefined()) {
127         return JSTaggedValue::SetPrototype(thread, targetHandle, proto);
128     };
129     JSHandle<JSTaggedValue> handlerTag(thread, proxy->GetHandler());
130     InternalCallParams *arguments = thread->GetInternalCallParams();
131     arguments->MakeArgv(targetHandle, proto);
132     JSTaggedValue trapResult =
133         JSFunction::Call(thread, trap, handlerTag, 2, arguments->GetArgv());  // 2: target and proto
134 
135     // 9. Let booleanTrapResult be ToBoolean(Call(trap, handler, «target, V»)).
136     // If booleanTrapResult is false, return false
137     bool booleanTrapResult = trapResult.ToBoolean();
138     if (!booleanTrapResult) {
139         return false;
140     }
141     // 10. ReturnIfAbrupt(booleanTrapResult).
142     // 11. Let extensibleTarget be IsExtensible(target).
143     // 12. ReturnIfAbrupt(extensibleTarget).
144     // 13. If extensibleTarget is true, return booleanTrapResult
145     if (targetHandle->IsExtensible(thread)) {
146         return booleanTrapResult;
147     }
148     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
149 
150     // 14. Let targetProto be target.[[GetPrototypeOf]]().
151     JSTaggedValue targetProto = JSHandle<JSObject>(targetHandle)->GetPrototype(thread);
152     // 15. ReturnIfAbrupt(targetProto).
153     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
154 
155     // 16. If booleanTrapResult is true and SameValue(V, targetProto) is false, throw a TypeError exception.
156     if (booleanTrapResult && !JSTaggedValue::SameValue(proto.GetTaggedValue(), targetProto)) {
157         THROW_TYPE_ERROR_AND_RETURN(thread, "JSProxy::SetPrototype: TypeError of targetProto and Result", false);
158     }
159     // 17. Return handlerProto.
160     return booleanTrapResult;
161 }
162 
163 // ES6 9.5.3 [[IsExtensible]] ( )
IsExtensible(JSThread * thread,const JSHandle<JSProxy> & proxy)164 bool JSProxy::IsExtensible(JSThread *thread, const JSHandle<JSProxy> &proxy)
165 {
166     // 1. Let handler be the value of the [[ProxyHandler]] internal slot of O.
167     JSTaggedValue handler = proxy->GetHandler();
168     // 2. If handler is null, throw a TypeError exception.
169     if (handler.IsNull()) {
170         THROW_TYPE_ERROR_AND_RETURN(thread, "JSProxy::IsExtensible: handler is null", false);
171     }
172     // 3. Assert: Type(handler) is Object.
173     ASSERT(handler.IsECMAObject());
174     // 4. Let target be the value of the [[ProxyTarget]] internal slot of O.
175     JSHandle<JSTaggedValue> targetHandle(thread, proxy->GetTarget());
176     // 5. Let trap be GetMethod(handler, "isExtensible").
177     JSHandle<JSTaggedValue> name = thread->GlobalConstants()->GetHandledIsExtensibleString();
178     JSHandle<JSTaggedValue> trap(JSObject::GetMethod(thread, JSHandle<JSTaggedValue>(thread, handler), name));
179     // 6. ReturnIfAbrupt(trap).
180     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
181 
182     // 7. If trap is undefined, then Return target.[[IsExtensible]]().
183     if (trap->IsUndefined()) {
184         return targetHandle->IsExtensible(thread);
185     }
186     // 8. Let booleanTrapResult be ToBoolean(Call(trap, handler, «target»)).
187     JSHandle<JSTaggedValue> newTgt(thread, JSTaggedValue::Undefined());
188     JSHandle<JSTaggedValue> handlerTag(thread, proxy->GetHandler());
189     InternalCallParams *arguments = thread->GetInternalCallParams();
190     arguments->MakeArgv(targetHandle);
191     JSTaggedValue trapResult = JSFunction::Call(thread, trap, handlerTag, 1, arguments->GetArgv());
192 
193     bool booleanTrapResult = trapResult.ToBoolean();
194     // 9. ReturnIfAbrupt(booleanTrapResult).
195     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
196 
197     // 10. Let targetResult be target.[[IsExtensible]]().
198     // 11. ReturnIfAbrupt(targetResult).
199     // 12. If SameValue(booleanTrapResult, targetResult) is false, throw a TypeError exception.
200     // 13. Return booleanTrapResult.
201     if (targetHandle->IsExtensible(thread) != booleanTrapResult) {
202         THROW_TYPE_ERROR_AND_RETURN(thread, "JSProxy::IsExtensible: TypeError of targetResult", false);
203     }
204 
205     return booleanTrapResult;
206 }
207 
208 // ES6 9.5.4 [[PreventExtensions]] ( )
PreventExtensions(JSThread * thread,const JSHandle<JSProxy> & proxy)209 bool JSProxy::PreventExtensions(JSThread *thread, const JSHandle<JSProxy> &proxy)
210 {
211     // 1. Let handler be the value of the [[ProxyHandler]] internal slot of O.
212     // 2. If handler is null, throw a TypeError exception.
213     // 3. Assert: Type(handler) is Object.
214     // 4. Let target be the value of the [[ProxyTarget]] internal slot of O.
215     // 5. Let trap be GetMethod(handler, "preventExtensions").
216     // 6. ReturnIfAbrupt(trap).
217     // 7. If trap is undefined, then
218     // a. Return target.[[PreventExtensions]]().
219     // 8. Let booleanTrapResult be ToBoolean(Call(trap, handler, «target»)).
220     // 9. ReturnIfAbrupt(booleanTrapResult).
221     JSTaggedValue handler = proxy->GetHandler();
222     if (handler.IsNull()) {
223         THROW_TYPE_ERROR_AND_RETURN(thread, "JSProxy::PreventExtensions: handler is null", false);
224     }
225     ASSERT(handler.IsECMAObject());
226     JSHandle<JSTaggedValue> targetHandle(thread, proxy->GetTarget());
227     JSHandle<JSTaggedValue> name = thread->GlobalConstants()->GetHandledPreventExtensionsString();
228     JSHandle<JSTaggedValue> trap(JSObject::GetMethod(thread, JSHandle<JSTaggedValue>(thread, handler), name));
229     // 6. ReturnIfAbrupt(trap).
230     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
231 
232     if (trap->IsUndefined()) {
233         return JSTaggedValue::PreventExtensions(thread, targetHandle);
234     }
235     JSHandle<JSTaggedValue> handlerTag(thread, proxy->GetHandler());
236     InternalCallParams *arguments = thread->GetInternalCallParams();
237     arguments->MakeArgv(targetHandle);
238     JSTaggedValue trapResult = JSFunction::Call(thread, trap, handlerTag, 1, arguments->GetArgv());
239 
240     bool booleanTrapResult = trapResult.ToBoolean();
241     // 9. ReturnIfAbrupt(booleanTrapResult).
242     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
243     // 10. If booleanTrapResult is true, then
244     // a. Let targetIsExtensible be target.[[IsExtensible]]().
245     // b. ReturnIfAbrupt(targetIsExtensible).
246     // c. If targetIsExtensible is true, throw a TypeError exception.
247     if (booleanTrapResult && targetHandle->IsExtensible(thread)) {
248         THROW_TYPE_ERROR_AND_RETURN(thread, "JSProxy::PreventExtensions: targetIsExtensible is true", false);
249     }
250     // 11. Return booleanTrapResult.
251     return booleanTrapResult;
252 }
253 
254 // ES6 9.5.5 [[GetOwnProperty]] (P)
GetOwnProperty(JSThread * thread,const JSHandle<JSProxy> & proxy,const JSHandle<JSTaggedValue> & key,PropertyDescriptor & desc)255 bool JSProxy::GetOwnProperty(JSThread *thread, const JSHandle<JSProxy> &proxy, const JSHandle<JSTaggedValue> &key,
256                              PropertyDescriptor &desc)
257 {
258     // 1. Assert: IsPropertyKey(P) is true.
259     ASSERT(JSTaggedValue::IsPropertyKey(key));
260     // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
261     // 3. If handler is null, throw a TypeError exception.
262     // 4. Assert: Type(handler) is Object.
263     // 5. Let target be the value of the [[ProxyTarget]] internal slot of O.
264     // 6. Let trap be GetMethod(handler, "getOwnPropertyDescriptor").
265     // 7. ReturnIfAbrupt(trap).
266     // 8. If trap is undefined, then
267     // a. Return target.[[GetOwnProperty]](P).
268     // 9. Let trapResultObj be Call(trap, handler, «target, P»).
269     // 10. ReturnIfAbrupt(trapResultObj).
270     // 11. If Type(trapResultObj) is neither Object nor Undefined, throw a TypeError exception
271     JSTaggedValue handler = proxy->GetHandler();
272     if (handler.IsNull()) {
273         THROW_TYPE_ERROR_AND_RETURN(thread, "JSProxy::GetOwnProperty: handler is null", false);
274     }
275     ASSERT(handler.IsECMAObject());
276     JSHandle<JSTaggedValue> targetHandle(thread, proxy->GetTarget());
277     JSHandle<JSTaggedValue> name = thread->GlobalConstants()->GetHandledGetOwnPropertyDescriptorString();
278     JSHandle<JSTaggedValue> trap(JSObject::GetMethod(thread, JSHandle<JSTaggedValue>(thread, handler), name));
279     // 7. ReturnIfAbrupt(trap).
280     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
281 
282     if (trap->IsUndefined()) {
283         return JSTaggedValue::GetOwnProperty(thread, targetHandle, key, desc);
284     }
285     JSHandle<JSTaggedValue> handlerTag(thread, proxy->GetHandler());
286     InternalCallParams *arguments = thread->GetInternalCallParams();
287     arguments->MakeArgv(targetHandle, key);
288     JSTaggedValue trapResultObj =
289         JSFunction::Call(thread, trap, handlerTag, 2, arguments->GetArgv());  // 2: target and key
290 
291     JSHandle<JSTaggedValue> resultHandle(thread, trapResultObj);
292 
293     // 11. If Type(trapResultObj) is neither Object nor Undefined, throw a TypeError exception.
294     if (!trapResultObj.IsECMAObject() && !trapResultObj.IsUndefined()) {
295         THROW_TYPE_ERROR_AND_RETURN(thread, "JSProxy::GetOwnProperty: TypeError of trapResultObj", false);
296     }
297     // 12. Let targetDesc be target.[[GetOwnProperty]](P).
298     PropertyDescriptor targetDesc(thread);
299     bool found = JSTaggedValue::GetOwnProperty(thread, targetHandle, key, targetDesc);
300     // 13. ReturnIfAbrupt(targetDesc).
301     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
302 
303     // 14. If trapResultObj is undefined, then
304     if (resultHandle->IsUndefined()) {
305         // a. If targetDesc is undefined, return undefined.
306         if (!found) {
307             return false;
308         }
309         // b. If targetDesc.[[Configurable]] is false, throw a TypeError exception.
310         if (!targetDesc.IsConfigurable()) {
311             THROW_TYPE_ERROR_AND_RETURN(thread, "JSProxy::GetOwnProperty: targetDesc.[[Configurable]] is false", false);
312         }
313         // c. Let extensibleTarget be IsExtensible(target).
314         // d. ReturnIfAbrupt(extensibleTarget).
315         // e. Assert: Type(extensibleTarget) is Boolean.
316         // f. If extensibleTarget is false, throw a TypeError exception.
317         if (!targetHandle->IsExtensible(thread)) {
318             THROW_TYPE_ERROR_AND_RETURN(thread, "JSProxy::GetOwnProperty: extensibleTarget is false", false);
319         }
320         // g. Return undefined.
321         return false;
322     }
323     // 15. Let extensibleTarget be IsExtensible(target).
324     // 16. ReturnIfAbrupt(extensibleTarget).
325     // 17. Let resultDesc be ToPropertyDescriptor(trapResultObj).
326     PropertyDescriptor &resultDesc = desc;
327     JSObject::ToPropertyDescriptor(thread, resultHandle, resultDesc);
328     // 18. ReturnIfAbrupt(resultDesc)
329     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
330     // 19. Call CompletePropertyDescriptor(resultDesc).
331     PropertyDescriptor::CompletePropertyDescriptor(thread, resultDesc);
332     // 20. Let valid be IsCompatiblePropertyDescriptor (extensibleTarget, resultDesc, targetDesc).
333     bool valid = JSObject::IsCompatiblePropertyDescriptor(targetHandle->IsExtensible(thread), resultDesc, targetDesc);
334     if (!valid) {
335         THROW_TYPE_ERROR_AND_RETURN(thread, "JSProxy::GetOwnProperty: TypeError of valid", false);
336     }
337     // 22. If resultDesc.[[Configurable]] is false, then
338     if (!resultDesc.IsConfigurable()) {
339         // a. If targetDesc is undefined or targetDesc.[[Configurable]] is true, then
340         if (!found || targetDesc.IsConfigurable()) {
341             THROW_TYPE_ERROR_AND_RETURN(thread, "JSProxy::GetOwnProperty: TypeError of targetDesc configurable", false);
342         }
343         // b. If resultDesc has a [[Writable]] field and resultDesc.[[Writable]] is false, then
344         //    If targetDesc.[[Writable]] is true, throw a TypeError exception.
345         if (resultDesc.HasWritable() && !resultDesc.IsWritable() && targetDesc.IsWritable()) {
346             THROW_TYPE_ERROR_AND_RETURN(thread, "JSProxy::GetOwnProperty: TypeError of targetDesc writable", false);
347         }
348         // b. If resultDesc has a [[Writable]] field and resultDesc.[[Writable]] is false, then
349         //    If targetDesc.[[Writable]] is true, throw a TypeError exception.
350         if (resultDesc.HasWritable() && !resultDesc.IsWritable() && targetDesc.IsWritable()) {
351             THROW_TYPE_ERROR_AND_RETURN(thread, "", false);
352         }
353     }
354     // 23. Return resultDesc.
355     return true;
356 }
357 
358 // ES6 9.5.6 [[DefineOwnProperty]] (P, Desc)
DefineOwnProperty(JSThread * thread,const JSHandle<JSProxy> & proxy,const JSHandle<JSTaggedValue> & key,const PropertyDescriptor & desc)359 bool JSProxy::DefineOwnProperty(JSThread *thread, const JSHandle<JSProxy> &proxy, const JSHandle<JSTaggedValue> &key,
360                                 const PropertyDescriptor &desc)
361 {
362     // step 1 ~ 10 are almost same as GetOwnProperty
363     ASSERT(JSTaggedValue::IsPropertyKey(key));
364     JSTaggedValue handler = proxy->GetHandler();
365     if (handler.IsNull()) {
366         THROW_TYPE_ERROR_AND_RETURN(thread, "JSProxy::DefineOwnProperty: handler is Null", false);
367     }
368     ASSERT(handler.IsECMAObject());
369     JSHandle<JSTaggedValue> targetHandle(thread, proxy->GetTarget());
370     JSHandle<JSTaggedValue> name = thread->GlobalConstants()->GetHandledDefinePropertyString();
371     JSHandle<JSTaggedValue> trap(JSObject::GetMethod(thread, JSHandle<JSTaggedValue>(thread, handler), name));
372     // 7. ReturnIfAbrupt(trap).
373     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
374     if (trap->IsUndefined()) {
375         return JSTaggedValue::DefineOwnProperty(thread, targetHandle, key, desc);
376     }
377 
378     // 9. Let descObj be FromPropertyDescriptor(Desc).
379     JSHandle<JSTaggedValue> descObj = JSObject::FromPropertyDescriptor(thread, desc);
380     JSHandle<JSTaggedValue> handlerTag(thread, proxy->GetHandler());
381     InternalCallParams *arguments = thread->GetInternalCallParams();
382     arguments->MakeArgv(targetHandle, key, descObj);
383     JSTaggedValue trapResult =
384         JSFunction::Call(thread, trap, handlerTag, 3, arguments->GetArgv());  // 3: target, key and desc
385 
386     bool booleanTrapResult = trapResult.ToBoolean();
387     // 11. ReturnIfAbrupt(booleanTrapResult).
388     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
389     if (!booleanTrapResult) {
390         return false;
391     }
392     // 13. Let targetDesc be target.[[GetOwnProperty]](P).
393     PropertyDescriptor targetDesc(thread);
394     bool found = JSTaggedValue::GetOwnProperty(thread, targetHandle, key, targetDesc);
395     // 14. ReturnIfAbrupt(targetDesc).
396     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
397 
398     // 15. Let extensibleTarget be IsExtensible(target).
399     // 16. ReturnIfAbrupt(extensibleTarget).
400     // 17. If Desc has a [[Configurable]] field and if Desc.[[Configurable]] is false, then Let settingConfigFalse be
401     // true.
402     // 18. Else let settingConfigFalse be false.
403     bool settingConfigFalse = false;
404     if (desc.HasConfigurable() && !desc.IsConfigurable()) {
405         settingConfigFalse = true;
406     }
407     // 19. If targetDesc is undefined, then
408     if (!found) {
409         // a. If extensibleTarget is false, throw a TypeError exception.
410         if (!targetHandle->IsExtensible(thread)) {
411             THROW_TYPE_ERROR_AND_RETURN(thread, "JSProxy::DefineOwnProperty: extensibleTarget is false", false);
412         }
413         // b. If settingConfigFalse is true, throw a TypeError exception.
414         if (settingConfigFalse) {
415             THROW_TYPE_ERROR_AND_RETURN(thread, "JSProxy::DefineOwnProperty: settingConfigFalse is true", false);
416         }
417     } else {
418         // a. If IsCompatiblePropertyDescriptor(extensibleTarget, Desc , targetDesc) is false, throw a TypeError
419         // exception.
420         if (!JSObject::IsCompatiblePropertyDescriptor(targetHandle->IsExtensible(thread), desc, targetDesc)) {
421             THROW_TYPE_ERROR_AND_RETURN(thread, "JSProxy::DefineOwnProperty: CompatiblePropertyDescriptor err", false);
422         }
423         // b. If settingConfigFalse is true and targetDesc.[[Configurable]] is true, throw a TypeError exception.
424         if (settingConfigFalse && targetDesc.IsConfigurable()) {
425             THROW_TYPE_ERROR_AND_RETURN(thread, "JSProxy::DefineOwnProperty: TypeError of settingConfigFalse", false);
426         }
427         // c. If IsDataDescriptor(targetDesc) is true, targetDesc.[[Configurable]] is false, and targetDesc.[[Writable]]
428         // is true, then If Desc has a [[Writable]] field and Desc.[[Writable]] is false, throw a TypeError exception.
429         if (targetDesc.IsDataDescriptor() && !targetDesc.IsConfigurable() && targetDesc.IsWritable() &&
430             desc.HasWritable() && !desc.IsWritable()) {
431             THROW_TYPE_ERROR_AND_RETURN(thread, "JSProxy::DefineOwnProperty: TypeError of DataDescriptor", false);
432         }
433         // c. If IsDataDescriptor(targetDesc) is true, targetDesc.[[Configurable]] is false, and targetDesc.[[Writable]]
434         // is true, then If Desc has a [[Writable]] field and Desc.[[Writable]] is false, throw a TypeError exception.
435         if (targetDesc.IsDataDescriptor() && !targetDesc.IsConfigurable() && targetDesc.IsWritable() &&
436             desc.HasWritable() && !desc.IsWritable()) {
437             THROW_TYPE_ERROR_AND_RETURN(thread, "", false);
438         }
439     }
440     // 21. Return true.
441     return true;
442 }
443 
444 // ES6 9.5.7 [[HasProperty]] (P)
HasProperty(JSThread * thread,const JSHandle<JSProxy> & proxy,const JSHandle<JSTaggedValue> & key)445 bool JSProxy::HasProperty(JSThread *thread, const JSHandle<JSProxy> &proxy, const JSHandle<JSTaggedValue> &key)
446 {
447     // step 1 ~ 10 are almost same as GetOwnProperty
448     ASSERT(JSTaggedValue::IsPropertyKey(key));
449     JSTaggedValue handler = proxy->GetHandler();
450     if (handler.IsNull()) {
451         THROW_TYPE_ERROR_AND_RETURN(thread, "JSProxy::HasProperty: handler is Null", false);
452     }
453     ASSERT(handler.IsECMAObject());
454     JSHandle<JSTaggedValue> targetHandle(thread, proxy->GetTarget());
455     JSHandle<JSTaggedValue> name = thread->GlobalConstants()->GetHandledHasString();
456     JSHandle<JSTaggedValue> trap(JSObject::GetMethod(thread, JSHandle<JSTaggedValue>(thread, handler), name));
457     // 7. ReturnIfAbrupt(trap).
458     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
459     if (trap->IsUndefined()) {
460         return JSTaggedValue::HasProperty(thread, targetHandle, key);
461     }
462 
463     // 9. Let booleanTrapResult be ToBoolean(Call(trap, handler, «target, P»)).
464     JSHandle<JSTaggedValue> handlerTag(thread, proxy->GetHandler());
465 
466     InternalCallParams *arguments = thread->GetInternalCallParams();
467     arguments->MakeArgv(targetHandle, key);
468     JSTaggedValue trapResult =
469         JSFunction::Call(thread, trap, handlerTag, 2, arguments->GetArgv());  // 2: target and key
470 
471     bool booleanTrapResult = trapResult.ToBoolean();
472     // 10. ReturnIfAbrupt(booleanTrapResult).
473     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
474 
475     // 11. If booleanTrapResult is false, then
476     if (!booleanTrapResult) {
477         // a. Let targetDesc be target.[[GetOwnProperty]](P).
478         PropertyDescriptor targetDesc(thread);
479         bool found = JSTaggedValue::GetOwnProperty(thread, targetHandle, key, targetDesc);
480         // b. ReturnIfAbrupt(targetDesc).
481         RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
482         // c. If targetDesc is not undefined, then
483         if (found) {
484             // i. If targetDesc.[[Configurable]] is false, throw a TypeError exception.
485             if (!targetDesc.IsConfigurable()) {
486                 THROW_TYPE_ERROR_AND_RETURN(thread, "JSProxy::HasProperty: TypeError of targetDesc", false);
487             }
488             // ii. Let extensibleTarget be IsExtensible(target).
489             // iii. ReturnIfAbrupt(extensibleTarget).
490             // iv. If extensibleTarget is false, throw a TypeError exception.
491             if (!targetHandle->IsExtensible(thread)) {
492                 THROW_TYPE_ERROR_AND_RETURN(thread, "JSProxy::HasProperty: extensibleTarget is false", false);
493             }
494         }
495     }
496     return booleanTrapResult;
497 }
498 
499 // ES6 9.5.8 [[Get]] (P, Receiver)
GetProperty(JSThread * thread,const JSHandle<JSProxy> & proxy,const JSHandle<JSTaggedValue> & key,const JSHandle<JSTaggedValue> & receiver)500 OperationResult JSProxy::GetProperty(JSThread *thread, const JSHandle<JSProxy> &proxy,
501                                      const JSHandle<JSTaggedValue> &key, const JSHandle<JSTaggedValue> &receiver)
502 {
503     // step 1 ~ 10 are almost same as GetOwnProperty
504     ASSERT(JSTaggedValue::IsPropertyKey(key));
505     JSTaggedValue handler = proxy->GetHandler();
506     JSHandle<JSTaggedValue> exceptionHandle(thread, JSTaggedValue::Exception());
507     if (handler.IsNull()) {
508         THROW_TYPE_ERROR_AND_RETURN(thread, "JSProxy::GetProperty: handler is Null",
509                                     OperationResult(thread, exceptionHandle.GetTaggedValue(), PropertyMetaData(false)));
510     }
511     ASSERT(handler.IsECMAObject());
512     JSHandle<JSTaggedValue> targetHandle(thread, proxy->GetTarget());
513     JSHandle<JSTaggedValue> name = thread->GlobalConstants()->GetHandledGetString();
514     JSHandle<JSTaggedValue> trap(JSObject::GetMethod(thread, JSHandle<JSTaggedValue>(thread, handler), name));
515     // 7. ReturnIfAbrupt(trap).
516     RETURN_VALUE_IF_ABRUPT_COMPLETION(
517         thread, OperationResult(thread, exceptionHandle.GetTaggedValue(), PropertyMetaData(false)));
518 
519     if (trap->IsUndefined()) {
520         return JSTaggedValue::GetProperty(thread, targetHandle, key, receiver);
521     }
522     // 9. Let trapResult be Call(trap, handler, «target, P, Receiver»).
523     JSHandle<JSTaggedValue> handlerTag(thread, proxy->GetHandler());
524     InternalCallParams *arguments = thread->GetInternalCallParams();
525     arguments->MakeArgv(targetHandle, key, receiver);
526     JSTaggedValue trapResult =
527         JSFunction::Call(thread, trap, handlerTag, 3, arguments->GetArgv());  // 3: «target, P, Receiver»
528     JSHandle<JSTaggedValue> resultHandle(thread, trapResult);
529 
530     // 10. ReturnIfAbrupt(trapResult).
531     RETURN_VALUE_IF_ABRUPT_COMPLETION(
532         thread, OperationResult(thread, exceptionHandle.GetTaggedValue(), PropertyMetaData(false)));
533 
534     // 11. Let targetDesc be target.[[GetOwnProperty]](P).
535     PropertyDescriptor targetDesc(thread);
536     bool found = JSTaggedValue::GetOwnProperty(thread, targetHandle, key, targetDesc);
537     // 12. ReturnIfAbrupt(targetDesc).
538     RETURN_VALUE_IF_ABRUPT_COMPLETION(
539         thread, OperationResult(thread, exceptionHandle.GetTaggedValue(), PropertyMetaData(false)));
540 
541     // 13. If targetDesc is not undefined, then
542     if (found) {
543         // a. If IsDataDescriptor(targetDesc) and targetDesc.[[Configurable]] is false and targetDesc.[[Writable]] is
544         // false, then
545         if (targetDesc.IsDataDescriptor() && !targetDesc.IsConfigurable() && !targetDesc.IsWritable()) {
546             // i. If SameValue(trapResult, targetDesc.[[Value]]) is false, throw a TypeError exception.
547             if (!JSTaggedValue::SameValue(resultHandle.GetTaggedValue(), targetDesc.GetValue().GetTaggedValue())) {
548                 THROW_TYPE_ERROR_AND_RETURN(
549                     thread, "JSProxy::GetProperty: TypeError of trapResult",
550                     OperationResult(thread, exceptionHandle.GetTaggedValue(), PropertyMetaData(false)));
551             }
552         }
553         // b. If IsAccessorDescriptor(targetDesc) and targetDesc.[[Configurable]] is false and targetDesc.[[Get]] is
554         // undefined, then
555         if (targetDesc.IsAccessorDescriptor() && !targetDesc.IsConfigurable() &&
556             targetDesc.GetGetter()->IsUndefined()) {
557             // i. If trapResult is not undefined, throw a TypeError exception.
558             if (!resultHandle.GetTaggedValue().IsUndefined()) {
559                 THROW_TYPE_ERROR_AND_RETURN(
560                     thread, "JSProxy::GetProperty: trapResult is not undefined",
561                     OperationResult(thread, exceptionHandle.GetTaggedValue(), PropertyMetaData(false)));
562             }
563         }
564     }
565     // 14. Return trapResult.
566     return OperationResult(thread, resultHandle.GetTaggedValue(), PropertyMetaData(true));
567 }
568 
569 // ES6 9.5.9 [[Set]] ( P, V, Receiver)
SetProperty(JSThread * thread,const JSHandle<JSProxy> & proxy,const JSHandle<JSTaggedValue> & key,const JSHandle<JSTaggedValue> & value,const JSHandle<JSTaggedValue> & receiver,bool mayThrow)570 bool JSProxy::SetProperty(JSThread *thread, const JSHandle<JSProxy> &proxy, const JSHandle<JSTaggedValue> &key,
571                           const JSHandle<JSTaggedValue> &value, const JSHandle<JSTaggedValue> &receiver, bool mayThrow)
572 {
573     // step 1 ~ 10 are almost same as GetOwnProperty
574     ASSERT(JSTaggedValue::IsPropertyKey(key));
575     JSTaggedValue handler = proxy->GetHandler();
576     if (handler.IsNull()) {
577         THROW_TYPE_ERROR_AND_RETURN(thread, "JSProxy::SetProperty: handler is Null", false);
578     }
579     ASSERT(handler.IsECMAObject());
580     JSHandle<JSTaggedValue> targetHandle(thread, proxy->GetTarget());
581     JSHandle<JSTaggedValue> name = thread->GlobalConstants()->GetHandledSetString();
582     JSHandle<JSTaggedValue> trap(JSObject::GetMethod(thread, JSHandle<JSTaggedValue>(thread, handler), name));
583     // 7. ReturnIfAbrupt(trap).
584     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
585     if (trap->IsUndefined()) {
586         return JSTaggedValue::SetProperty(thread, targetHandle, key, value, receiver, mayThrow);
587     }
588 
589     // 9. Let booleanTrapResult be ToBoolean(Call(trap, handler, «target, P, V, Receiver»))
590     JSHandle<JSTaggedValue> handlerTag(thread, proxy->GetHandler());
591     InternalCallParams *arguments = thread->GetInternalCallParams();
592     arguments->MakeArgv(targetHandle, key, value, receiver);
593     JSTaggedValue trapResult =
594         JSFunction::Call(thread, trap, handlerTag, 4, arguments->GetArgv());  // 4: «target, P, V, Receiver»
595 
596     bool booleanTrapResult = trapResult.ToBoolean();
597     // 11. ReturnIfAbrupt(booleanTrapResult).
598     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
599     if (!booleanTrapResult) {
600         return false;
601     }
602     // 13. Let targetDesc be target.[[GetOwnProperty]](P).
603     PropertyDescriptor targetDesc(thread);
604     bool found = JSTaggedValue::GetOwnProperty(thread, targetHandle, key, targetDesc);
605     // 14. If targetDesc is not undefined, then
606     if (found) {
607         // a. If IsDataDescriptor(targetDesc) and targetDesc.[[Configurable]] is false and targetDesc.[[Writable]] is
608         // false, then
609         if (targetDesc.IsDataDescriptor() && !targetDesc.IsConfigurable() && !targetDesc.IsWritable()) {
610             // i. If SameValue(trapResult, targetDesc.[[Value]]) is false, throw a TypeError exception.
611             if (!JSTaggedValue::SameValue(value, targetDesc.GetValue())) {
612                 THROW_TYPE_ERROR_AND_RETURN(thread, "JSProxy::SetProperty: TypeError of trapResult", false);
613             }
614         }
615         // b. If IsAccessorDescriptor(targetDesc) and targetDesc.[[Configurable]] is false, then
616         // i. If targetDesc.[[Set]] is undefined, throw a TypeError exception.
617         if (targetDesc.IsAccessorDescriptor() && !targetDesc.IsConfigurable() &&
618             targetDesc.GetSetter()->IsUndefined()) {
619             THROW_TYPE_ERROR_AND_RETURN(thread, "JSProxy::SetProperty: TypeError of AccessorDescriptor", false);
620         }
621     }
622     return true;
623 }
624 
625 // ES6 9.5.10 [[Delete]] (P)
DeleteProperty(JSThread * thread,const JSHandle<JSProxy> & proxy,const JSHandle<JSTaggedValue> & key)626 bool JSProxy::DeleteProperty(JSThread *thread, const JSHandle<JSProxy> &proxy, const JSHandle<JSTaggedValue> &key)
627 {
628     // step 1 ~ 13 are almost same as GetOwnProperty
629     ASSERT(JSTaggedValue::IsPropertyKey(key));
630     JSTaggedValue handler = proxy->GetHandler();
631     if (handler.IsNull()) {
632         THROW_TYPE_ERROR_AND_RETURN(thread, "JSProxy::DeleteProperty: handler is Null", false);
633     }
634     ASSERT(handler.IsECMAObject());
635     JSHandle<JSTaggedValue> targetHandle(thread, proxy->GetTarget());
636     JSHandle<JSTaggedValue> name = thread->GlobalConstants()->GetHandledDeletePropertyString();
637     JSHandle<JSTaggedValue> trap(JSObject::GetMethod(thread, JSHandle<JSTaggedValue>(thread, handler), name));
638     // 7. ReturnIfAbrupt(trap).
639     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
640     if (trap->IsUndefined()) {
641         return JSTaggedValue::DeleteProperty(thread, targetHandle, key);
642     }
643 
644     // 9. Let booleanTrapResult be ToBoolean(Call(trap, handler, «target, P»)).
645     JSHandle<JSTaggedValue> newTgt(thread, JSTaggedValue::Undefined());
646     JSHandle<JSTaggedValue> handlerTag(thread, proxy->GetHandler());
647     InternalCallParams *arguments = thread->GetInternalCallParams();
648     arguments->MakeArgv(targetHandle, key);
649     JSTaggedValue trapResult =
650         JSFunction::Call(thread, trap, handlerTag, 2, arguments->GetArgv());  // 2: target and key
651 
652     bool booleanTrapResult = trapResult.ToBoolean();
653     // 11. ReturnIfAbrupt(booleanTrapResult).
654     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
655     if (!booleanTrapResult) {
656         return false;
657     }
658     // 13. Let targetDesc be target.[[GetOwnProperty]](P).
659     PropertyDescriptor targetDesc(thread);
660     bool found = JSTaggedValue::GetOwnProperty(thread, targetHandle, key, targetDesc);
661     // 14. If targetDesc is undefined, return true.
662     if (!found) {
663         return true;
664     }
665     // 15. If targetDesc.[[Configurable]] is false, throw a TypeError exception.
666     if (!targetDesc.IsConfigurable()) {
667         THROW_TYPE_ERROR_AND_RETURN(thread, "JSProxy::DeleteProperty: targetDesc is not Configurable", false);
668     }
669     if (!targetHandle->IsExtensible(thread)) {
670         THROW_TYPE_ERROR_AND_RETURN(thread, "JSProxy::DeleteProperty: targetHandle is not Extensible", false);
671     }
672     if (!targetHandle->IsExtensible(thread)) {
673         THROW_TYPE_ERROR_AND_RETURN(thread, "", false);
674     }
675     // 16. Return true.
676     return true;
677 }
678 
679 // ES6 9.5.12 [[OwnPropertyKeys]] ()
OwnPropertyKeys(JSThread * thread,const JSHandle<JSProxy> & proxy)680 JSHandle<TaggedArray> JSProxy::OwnPropertyKeys(JSThread *thread, const JSHandle<JSProxy> &proxy)
681 {
682     // step 1 ~ 4 get ProxyHandler and ProxyTarget
683     JSTaggedValue handler = proxy->GetHandler();
684     if (handler.IsNull()) {
685         THROW_TYPE_ERROR_AND_RETURN(thread, "OwnPropertyKeys: handler is null",
686                                     JSHandle<TaggedArray>(thread, JSTaggedValue::Exception()));
687     }
688 
689     ASSERT(handler.IsECMAObject());
690     JSHandle<JSTaggedValue> targetHandle(thread, proxy->GetTarget());
691 
692     // 5.Let trap be GetMethod(handler, "ownKeys").
693     JSHandle<JSTaggedValue> key = thread->GlobalConstants()->GetHandledOwnKeysString();
694     JSHandle<JSTaggedValue> handlerHandle(thread, handler);
695     JSHandle<JSTaggedValue> trap(JSObject::GetMethod(thread, handlerHandle, key));
696 
697     // 6.ReturnIfAbrupt(trap).
698     RETURN_HANDLE_IF_ABRUPT_COMPLETION(TaggedArray, thread);
699 
700     // 7.If trap is undefined, then
701     //    a.Return target.[[OwnPropertyKeys]]().
702     if (trap->IsUndefined()) {
703         return JSTaggedValue::GetOwnPropertyKeys(thread, targetHandle);
704     }
705 
706     // 8.Let trapResultArray be Call(trap, handler, «target»).
707     JSHandle<JSFunction> tagFunc(targetHandle);
708     InternalCallParams *arguments = thread->GetInternalCallParams();
709     arguments->MakeArgv(targetHandle);
710     JSTaggedValue res = JSFunction::Call(thread, trap, handlerHandle, 1, arguments->GetArgv());
711     JSHandle<JSTaggedValue> trap_res_arr(thread, res);
712 
713     // 9.Let trapResult be CreateListFromArrayLike(trapResultArray, «String, Symbol»).
714     // 10.ReturnIfAbrupt(trapResult)
715     // If trapResult contains any duplicate entries, throw a TypeError exception.
716     JSHandle<TaggedArray> trapRes(
717         JSObject::CreateListFromArrayLike<ElementTypes::STRING_AND_SYMBOL>(thread, trap_res_arr));
718     RETURN_HANDLE_IF_ABRUPT_COMPLETION(TaggedArray, thread);
719 
720     if (trapRes->HasDuplicateEntry()) {
721         THROW_TYPE_ERROR_AND_RETURN(thread, "OwnPropertyKeys: contains duplicate entries",
722                                     JSHandle<TaggedArray>(thread, JSTaggedValue::Exception()));
723     }
724 
725     // 11.Let extensibleTarget be IsExtensible(target).
726     bool extensibleTarget = targetHandle->IsExtensible(thread);
727 
728     // 12.ReturnIfAbrupt(extensibleTarget).
729     RETURN_HANDLE_IF_ABRUPT_COMPLETION(TaggedArray, thread);
730 
731     // 13.Let targetKeys be target.[[OwnPropertyKeys]]().
732     JSHandle<TaggedArray> targetKeys = JSTaggedValue::GetOwnPropertyKeys(thread, targetHandle);
733 
734     // 14.ReturnIfAbrupt(targetKeys).
735     RETURN_HANDLE_IF_ABRUPT_COMPLETION(TaggedArray, thread);
736 
737     // 15.Assert: targetKeys is a List containing only String and Symbol values.
738     // 16.Let targetConfigurableKeys be an empty List.
739     // 17.Let targetNonconfigurableKeys be an empty List.
740     // 18.Repeat, for each element key of targetKeys,
741     //     a.Let desc be target.[[GetOwnProperty]](key).
742     //     b.ReturnIfAbrupt(desc).
743     //     c.If desc is not undefined and desc.[[Configurable]] is false, then
744     //        i.Append key as an element of targetNonconfigurableKeys.
745     //     d.Else,
746     //        i.Append key as an element of targetConfigurableKeys.
747     uint32_t length = targetKeys->GetLength();
748     JSHandle<TaggedArray> tgtCfigKeys = thread->GetEcmaVM()->GetFactory()->NewTaggedArray(length);
749     JSHandle<TaggedArray> tgtNoCfigKeys = thread->GetEcmaVM()->GetFactory()->NewTaggedArray(length);
750 
751     uint32_t cfigLength = 0;
752     uint32_t noCfigLength = 0;
753     for (uint32_t i = 0; i < length; i++) {
754         JSHandle<JSTaggedValue> targetKey(thread, targetKeys->Get(i));
755         ASSERT(targetKey->IsStringOrSymbol());
756 
757         PropertyDescriptor desc(thread);
758         JSTaggedValue::GetOwnProperty(thread, targetHandle, targetKey, desc);
759         RETURN_HANDLE_IF_ABRUPT_COMPLETION(TaggedArray, thread);
760 
761         if (!desc.IsEmpty() && !desc.IsConfigurable()) {
762             tgtNoCfigKeys->Set(thread, noCfigLength, targetKey);
763             noCfigLength++;
764         } else {
765             tgtCfigKeys->Set(thread, cfigLength, targetKey);
766             cfigLength++;
767         }
768     }
769 
770     // 19.If extensibleTarget is true and targetNonconfigurableKeys is empty, then
771     //     a.Return trapResult.
772     if (extensibleTarget && (cfigLength == 0)) {
773         return trapRes;
774     }
775 
776     // 20.Let uncheckedResultKeys be a new List which is a copy of trapResult.
777     JSHandle<TaggedArray> uncheckFesKeys =
778         thread->GetEcmaVM()->GetFactory()->CopyArray(trapRes, trapRes->GetLength(), trapRes->GetLength());
779     uint32_t uncheckLength = uncheckFesKeys->GetLength();
780 
781     // 21.Repeat, for each key that is an element of targetNonconfigurableKeys,
782     //     a.If key is not an element of uncheckedResultKeys, throw a TypeError exception.
783     //     b.Remove key from uncheckedResultKeys
784     for (uint32_t i = 0; i < noCfigLength; i++) {
785         uint32_t idx = uncheckFesKeys->GetIdx(tgtNoCfigKeys->Get(i));
786         if (idx == TaggedArray::MAX_ARRAY_INDEX) {
787             THROW_TYPE_ERROR_AND_RETURN(thread, "OwnPropertyKeys: key is not an element of uncheckedResultKeys",
788                                         JSHandle<TaggedArray>(thread, JSTaggedValue::Exception()));
789         }
790         uncheckFesKeys->Set(thread, idx, JSTaggedValue::Hole());
791         uncheckLength--;
792     }
793 
794     // 22.If extensibleTarget is true, return trapResult.
795     if (extensibleTarget) {
796         return trapRes;
797     }
798 
799     // 23.Repeat, for each key that is an element of targetConfigurableKeys,
800     //     a.If key is not an element of uncheckedResultKeys, throw a TypeError exception.
801     //     b.Remove key from uncheckedResultKeys
802     for (uint32_t i = 0; i < cfigLength; i++) {
803         uint32_t idx = uncheckFesKeys->GetIdx(tgtCfigKeys->Get(i));
804         if (idx == TaggedArray::MAX_ARRAY_INDEX) {
805             THROW_TYPE_ERROR_AND_RETURN(thread, "OwnPropertyKeys: key is not an element of uncheckedResultKeys",
806                                         JSHandle<TaggedArray>(thread, JSTaggedValue::Exception()));
807         }
808         uncheckFesKeys->Set(thread, idx, JSTaggedValue::Hole());
809         uncheckLength--;
810     }
811 
812     // 24.If uncheckedResultKeys is not empty, throw a TypeError exception.
813     if (uncheckLength != 0) {
814         THROW_TYPE_ERROR_AND_RETURN(thread, "OwnPropertyKeys: uncheckedResultKeys is not empty",
815                                     JSHandle<TaggedArray>(thread, JSTaggedValue::Exception()));
816     }
817 
818     // 25.Return trapResult.
819     return trapRes;
820 }
821 
822 // ES6 9.5.13 [[Call]] (thisArgument, argumentsList)
CallInternal(JSThread * thread,const JSHandle<JSProxy> & proxy,const JSHandle<JSTaggedValue> & thisArg,uint32_t argc,const JSTaggedType argv[])823 JSTaggedValue JSProxy::CallInternal(JSThread *thread, const JSHandle<JSProxy> &proxy,
824                                     const JSHandle<JSTaggedValue> &thisArg, uint32_t argc,
825                                     const JSTaggedType argv[])
826 {
827     // step 1 ~ 4 get ProxyHandler and ProxyTarget
828     JSHandle<JSTaggedValue> handler(thread, proxy->GetHandler());
829     if (handler->IsNull()) {
830         THROW_TYPE_ERROR_AND_RETURN(thread, "Call: handler is null", JSTaggedValue::Exception());
831     }
832     ASSERT(handler->IsECMAObject());
833     JSHandle<JSTaggedValue> target(thread, proxy->GetTarget());
834 
835     // 5.Let trap be GetMethod(handler, "apply").
836     JSHandle<JSTaggedValue> key(thread->GlobalConstants()->GetHandledApplyString());
837     JSHandle<JSTaggedValue> method = JSObject::GetMethod(thread, handler, key);
838 
839     // 6.ReturnIfAbrupt(trap).
840     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
841     // 7.If trap is undefined, then
842     //   a.Return Call(target, thisArgument, argumentsList).
843     if (method->IsUndefined()) {
844         return JSFunction::Call(thread, target, thisArg, argc, argv);
845     }
846     // 8.Let argArray be CreateArrayFromList(argumentsList).
847     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
848     JSHandle<TaggedArray> taggedArray = factory->NewTaggedArray(argc);
849     for (uint32_t index = 0; index < argc; ++index) {
850         taggedArray->Set(thread, index, JSTaggedValue(argv[index]));
851     }
852     JSHandle<JSArray> arrHandle = JSArray::CreateArrayFromList(thread, taggedArray);
853 
854     // 9.Return Call(trap, handler, «target, thisArgument, argArray»).
855     InternalCallParams *proxyArgv = thread->GetInternalCallParams();
856     proxyArgv->MakeArgv(target, thisArg, arrHandle);
857     return JSFunction::Call(thread, method, handler, 3, proxyArgv->GetArgv());  // 3: «target, thisArgument, argArray»
858 }
859 
860 // ES6 9.5.14 [[Construct]] ( argumentsList, newTarget)
ConstructInternal(JSThread * thread,const JSHandle<JSProxy> & proxy,uint32_t argc,const JSTaggedType argv[],const JSHandle<JSTaggedValue> & newTarget)861 JSTaggedValue JSProxy::ConstructInternal(JSThread *thread, const JSHandle<JSProxy> &proxy, uint32_t argc,
862                                          const JSTaggedType argv[], const JSHandle<JSTaggedValue> &newTarget)
863 {
864     // step 1 ~ 4 get ProxyHandler and ProxyTarget
865     JSHandle<JSTaggedValue> handler(thread, proxy->GetHandler());
866     if (handler->IsNull()) {
867         THROW_TYPE_ERROR_AND_RETURN(thread, "Constructor: handler is null", JSTaggedValue::Exception());
868     }
869     ASSERT(handler->IsECMAObject());
870     JSHandle<JSTaggedValue> target(thread, proxy->GetTarget());
871 
872     // 5.Let trap be GetMethod(handler, "construct").
873     JSHandle<JSTaggedValue> key(thread->GlobalConstants()->GetHandledProxyConstructString());
874     JSHandle<JSTaggedValue> method = JSObject::GetMethod(thread, handler, key);
875 
876     // 6.ReturnIfAbrupt(trap).
877     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
878     // 7.If trap is undefined, then
879     //   a.Assert: target has a [[Construct]] internal method.
880     //   b.Return Construct(target, argumentsList, newTarget).
881     if (method->IsUndefined()) {
882         ASSERT(target->IsConstructor());
883         return JSFunction::Construct(thread, target, argc, argv, newTarget);
884     }
885 
886     // 8.Let argArray be CreateArrayFromList(argumentsList).
887     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
888     JSHandle<TaggedArray> taggedArray = factory->NewTaggedArray(argc);
889     for (uint32_t index = 0; index < argc; ++index) {
890         taggedArray->Set(thread, index, JSTaggedValue(argv[index]));
891     }
892     JSHandle<JSArray> arrHandle = JSArray::CreateArrayFromList(thread, taggedArray);
893 
894     // step 8 ~ 9 Call(trap, handler, «target, argArray, newTarget »).
895     InternalCallParams *arguments = thread->GetInternalCallParams();
896     arguments->MakeArgv(target, arrHandle, newTarget);
897     JSTaggedValue newObj =
898         JSFunction::Call(thread, method, handler, 3, arguments->GetArgv());  // 3: «target, argArray, newTarget »
899     // 10.ReturnIfAbrupt(newObj).
900     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
901     // 11.If Type(newObj) is not Object, throw a TypeError exception.
902     if (!newObj.IsObject()) {
903         THROW_TYPE_ERROR_AND_RETURN(thread, "new object is not object", JSTaggedValue::Exception());
904     }
905     // 12.Return newObj.
906     return newObj;
907 }
908 
IsArray(JSThread * thread) const909 bool JSProxy::IsArray(JSThread *thread) const
910 {
911     if (GetHandler().IsNull()) {
912         THROW_TYPE_ERROR_AND_RETURN(thread, "", false);
913     }
914     return GetTarget().IsArray(thread);
915 }
916 
GetSourceTarget(JSThread * thread) const917 JSHandle<JSTaggedValue> JSProxy::GetSourceTarget(JSThread *thread) const
918 {
919     JSMutableHandle<JSProxy> proxy(thread, JSTaggedValue(this));
920     JSMutableHandle<JSTaggedValue> target(thread, proxy->GetTarget());
921     while (target->IsJSProxy()) {
922         proxy.Update(target.GetTaggedValue());
923         target.Update(proxy->GetTarget());
924     }
925     return target;
926 }
927 }  // namespace panda::ecmascript
928