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