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