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