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