Line data Source code
1 : // Copyright 2016 the V8 project authors. All rights reserved.
2 : // Use of this source code is governed by a BSD-style license that can be
3 : // found in the LICENSE file.
4 :
5 : #include "src/builtins/builtins-proxy-gen.h"
6 : #include "src/builtins/builtins-utils-gen.h"
7 : #include "src/builtins/builtins-utils.h"
8 : #include "src/builtins/builtins.h"
9 :
10 : #include "src/counters.h"
11 : #include "src/objects-inl.h"
12 :
13 : namespace v8 {
14 : namespace internal {
15 :
16 112 : void ProxiesCodeStubAssembler::GotoIfRevokedProxy(Node* object,
17 : Label* if_proxy_revoked) {
18 224 : Label proxy_not_revoked(this);
19 224 : GotoIfNot(IsJSProxy(object), &proxy_not_revoked);
20 224 : Branch(IsJSReceiver(CAST(LoadObjectField(object, JSProxy::kHandlerOffset))),
21 112 : &proxy_not_revoked, if_proxy_revoked);
22 112 : BIND(&proxy_not_revoked);
23 112 : }
24 :
25 112 : Node* ProxiesCodeStubAssembler::AllocateProxy(Node* target, Node* handler,
26 : Node* context) {
27 224 : VARIABLE(map, MachineRepresentation::kTagged);
28 :
29 112 : Label callable_target(this), constructor_target(this), none_target(this),
30 112 : create_proxy(this);
31 :
32 224 : Node* nativeContext = LoadNativeContext(context);
33 :
34 224 : Branch(IsCallable(target), &callable_target, &none_target);
35 :
36 112 : BIND(&callable_target);
37 : {
38 : // Every object that is a constructor is implicitly callable
39 : // so it's okay to nest this check here
40 224 : GotoIf(IsConstructor(target), &constructor_target);
41 : map.Bind(
42 224 : LoadContextElement(nativeContext, Context::PROXY_CALLABLE_MAP_INDEX));
43 112 : Goto(&create_proxy);
44 : }
45 112 : BIND(&constructor_target);
46 : {
47 224 : map.Bind(LoadContextElement(nativeContext,
48 224 : Context::PROXY_CONSTRUCTOR_MAP_INDEX));
49 112 : Goto(&create_proxy);
50 : }
51 112 : BIND(&none_target);
52 : {
53 224 : map.Bind(LoadContextElement(nativeContext, Context::PROXY_MAP_INDEX));
54 112 : Goto(&create_proxy);
55 : }
56 :
57 112 : BIND(&create_proxy);
58 224 : Node* proxy = Allocate(JSProxy::kSize);
59 112 : StoreMapNoWriteBarrier(proxy, map.value());
60 : StoreObjectFieldRoot(proxy, JSProxy::kPropertiesOrHashOffset,
61 112 : RootIndex::kEmptyPropertyDictionary);
62 112 : StoreObjectFieldNoWriteBarrier(proxy, JSProxy::kTargetOffset, target);
63 112 : StoreObjectFieldNoWriteBarrier(proxy, JSProxy::kHandlerOffset, handler);
64 :
65 112 : return proxy;
66 : }
67 :
68 112 : Node* ProxiesCodeStubAssembler::AllocateJSArrayForCodeStubArguments(
69 : Node* context, CodeStubArguments& args, Node* argc, ParameterMode mode) {
70 112 : Comment("AllocateJSArrayForCodeStubArguments");
71 :
72 112 : Label if_empty_array(this), allocate_js_array(this);
73 : // Do not use AllocateJSArray since {elements} might end up in LOS.
74 224 : VARIABLE(elements, MachineRepresentation::kTagged);
75 :
76 224 : TNode<Smi> length = ParameterToTagged(argc, mode);
77 224 : GotoIf(SmiEqual(length, SmiConstant(0)), &if_empty_array);
78 : {
79 112 : Label if_large_object(this, Label::kDeferred);
80 224 : Node* allocated_elements = AllocateFixedArray(PACKED_ELEMENTS, argc, mode,
81 112 : kAllowLargeObjectAllocation);
82 112 : elements.Bind(allocated_elements);
83 :
84 112 : TVARIABLE(IntPtrT, offset,
85 : IntPtrConstant(FixedArrayBase::kHeaderSize - kHeapObjectTag));
86 224 : VariableList list({&offset}, zone());
87 :
88 224 : GotoIf(SmiGreaterThan(length, SmiConstant(FixedArray::kMaxRegularLength)),
89 112 : &if_large_object);
90 336 : args.ForEach(list, [=, &offset](Node* arg) {
91 224 : StoreNoWriteBarrier(MachineRepresentation::kTagged, allocated_elements,
92 336 : offset.value(), arg);
93 224 : Increment(&offset, kTaggedSize);
94 224 : });
95 112 : Goto(&allocate_js_array);
96 :
97 112 : BIND(&if_large_object);
98 : {
99 336 : args.ForEach(list, [=, &offset](Node* arg) {
100 224 : Store(allocated_elements, offset.value(), arg);
101 224 : Increment(&offset, kTaggedSize);
102 224 : });
103 112 : Goto(&allocate_js_array);
104 : }
105 : }
106 :
107 112 : BIND(&if_empty_array);
108 : {
109 224 : elements.Bind(EmptyFixedArrayConstant());
110 112 : Goto(&allocate_js_array);
111 : }
112 :
113 112 : BIND(&allocate_js_array);
114 : // Allocate the result JSArray.
115 224 : Node* native_context = LoadNativeContext(context);
116 : TNode<Map> array_map =
117 112 : LoadJSArrayElementsMap(PACKED_ELEMENTS, native_context);
118 : TNode<JSArray> array =
119 112 : AllocateJSArray(array_map, CAST(elements.value()), length);
120 :
121 112 : return array;
122 : }
123 :
124 56 : Node* ProxiesCodeStubAssembler::CreateProxyRevokeFunctionContext(
125 : Node* proxy, Node* native_context) {
126 112 : Node* const context = Allocate(FixedArray::SizeFor(kProxyContextLength));
127 56 : StoreMapNoWriteBarrier(context, RootIndex::kFunctionContextMap);
128 56 : InitializeFunctionContext(native_context, context, kProxyContextLength);
129 56 : StoreContextElementNoWriteBarrier(context, kProxySlot, proxy);
130 56 : return context;
131 : }
132 :
133 56 : Node* ProxiesCodeStubAssembler::AllocateProxyRevokeFunction(Node* proxy,
134 : Node* context) {
135 112 : Node* const native_context = LoadNativeContext(context);
136 :
137 : Node* const proxy_context =
138 56 : CreateProxyRevokeFunctionContext(proxy, native_context);
139 112 : Node* const revoke_map = LoadContextElement(
140 56 : native_context, Context::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX);
141 : Node* const revoke_info =
142 112 : LoadContextElement(native_context, Context::PROXY_REVOKE_SHARED_FUN);
143 :
144 : return AllocateFunctionWithMapAndContext(revoke_map, revoke_info,
145 56 : proxy_context);
146 : }
147 :
148 : // ES #sec-proxy-constructor
149 280 : TF_BUILTIN(ProxyConstructor, ProxiesCodeStubAssembler) {
150 : Node* context = Parameter(Descriptor::kContext);
151 :
152 : // 1. If NewTarget is undefined, throw a TypeError exception.
153 : Node* new_target = Parameter(Descriptor::kJSNewTarget);
154 56 : Label throwtypeerror(this, Label::kDeferred), createproxy(this);
155 112 : Branch(IsUndefined(new_target), &throwtypeerror, &createproxy);
156 :
157 56 : BIND(&throwtypeerror);
158 : {
159 56 : ThrowTypeError(context, MessageTemplate::kConstructorNotFunction, "Proxy");
160 : }
161 :
162 : // 2. Return ? ProxyCreate(target, handler).
163 56 : BIND(&createproxy);
164 : {
165 : // https://tc39.github.io/ecma262/#sec-proxycreate
166 : Node* target = Parameter(Descriptor::kTarget);
167 : Node* handler = Parameter(Descriptor::kHandler);
168 :
169 : // 1. If Type(target) is not Object, throw a TypeError exception.
170 : // 2. If target is a Proxy exotic object and target.[[ProxyHandler]] is
171 : // null, throw a TypeError exception.
172 : // 3. If Type(handler) is not Object, throw a TypeError exception.
173 : // 4. If handler is a Proxy exotic object and handler.[[ProxyHandler]]
174 : // is null, throw a TypeError exception.
175 56 : Label throw_proxy_non_object(this, Label::kDeferred),
176 56 : throw_proxy_handler_or_target_revoked(this, Label::kDeferred),
177 56 : return_create_proxy(this);
178 :
179 112 : GotoIf(TaggedIsSmi(target), &throw_proxy_non_object);
180 112 : GotoIfNot(IsJSReceiver(target), &throw_proxy_non_object);
181 56 : GotoIfRevokedProxy(target, &throw_proxy_handler_or_target_revoked);
182 :
183 112 : GotoIf(TaggedIsSmi(handler), &throw_proxy_non_object);
184 112 : GotoIfNot(IsJSReceiver(handler), &throw_proxy_non_object);
185 56 : GotoIfRevokedProxy(handler, &throw_proxy_handler_or_target_revoked);
186 :
187 : // 5. Let P be a newly created object.
188 : // 6. Set P's essential internal methods (except for [[Call]] and
189 : // [[Construct]]) to the definitions specified in 9.5.
190 : // 7. If IsCallable(target) is true, then
191 : // a. Set P.[[Call]] as specified in 9.5.12.
192 : // b. If IsConstructor(target) is true, then
193 : // 1. Set P.[[Construct]] as specified in 9.5.13.
194 : // 8. Set P.[[ProxyTarget]] to target.
195 : // 9. Set P.[[ProxyHandler]] to handler.
196 : // 10. Return P.
197 112 : Return(AllocateProxy(target, handler, context));
198 :
199 56 : BIND(&throw_proxy_non_object);
200 56 : ThrowTypeError(context, MessageTemplate::kProxyNonObject);
201 :
202 56 : BIND(&throw_proxy_handler_or_target_revoked);
203 56 : ThrowTypeError(context, MessageTemplate::kProxyHandlerOrTargetRevoked);
204 : }
205 56 : }
206 :
207 280 : TF_BUILTIN(CallProxy, ProxiesCodeStubAssembler) {
208 : Node* argc = Parameter(Descriptor::kActualArgumentsCount);
209 112 : Node* argc_ptr = ChangeInt32ToIntPtr(argc);
210 : Node* proxy = Parameter(Descriptor::kFunction);
211 : Node* context = Parameter(Descriptor::kContext);
212 :
213 : CSA_ASSERT(this, IsJSProxy(proxy));
214 : CSA_ASSERT(this, IsCallable(proxy));
215 :
216 56 : PerformStackCheck(CAST(context));
217 :
218 56 : Label throw_proxy_handler_revoked(this, Label::kDeferred),
219 56 : trap_undefined(this);
220 :
221 : // 1. Let handler be the value of the [[ProxyHandler]] internal slot of O.
222 : Node* handler = LoadObjectField(proxy, JSProxy::kHandlerOffset);
223 :
224 : // 2. If handler is null, throw a TypeError exception.
225 : CSA_ASSERT(this, IsNullOrJSReceiver(handler));
226 112 : GotoIfNot(IsJSReceiver(handler), &throw_proxy_handler_revoked);
227 :
228 : // 3. Assert: Type(handler) is Object.
229 : CSA_ASSERT(this, IsJSReceiver(handler));
230 :
231 : // 4. Let target be the value of the [[ProxyTarget]] internal slot of O.
232 : Node* target = LoadObjectField(proxy, JSProxy::kTargetOffset);
233 :
234 : // 5. Let trap be ? GetMethod(handler, "apply").
235 : // 6. If trap is undefined, then
236 56 : Handle<Name> trap_name = factory()->apply_string();
237 56 : Node* trap = GetMethod(context, handler, trap_name, &trap_undefined);
238 :
239 : CodeStubArguments args(this, argc_ptr);
240 112 : Node* receiver = args.GetReceiver();
241 :
242 : // 7. Let argArray be CreateArrayFromList(argumentsList).
243 56 : Node* array = AllocateJSArrayForCodeStubArguments(context, args, argc_ptr,
244 56 : INTPTR_PARAMETERS);
245 :
246 : // 8. Return Call(trap, handler, «target, thisArgument, argArray»).
247 112 : Node* result = CallJS(CodeFactory::Call(isolate()), context, trap, handler,
248 56 : target, receiver, array);
249 56 : args.PopAndReturn(result);
250 :
251 56 : BIND(&trap_undefined);
252 : {
253 : // 6.a. Return Call(target, thisArgument, argumentsList).
254 112 : TailCallStub(CodeFactory::Call(isolate()), context, target, argc);
255 : }
256 :
257 56 : BIND(&throw_proxy_handler_revoked);
258 56 : { ThrowTypeError(context, MessageTemplate::kProxyRevoked, "apply"); }
259 56 : }
260 :
261 280 : TF_BUILTIN(ConstructProxy, ProxiesCodeStubAssembler) {
262 : Node* argc = Parameter(Descriptor::kActualArgumentsCount);
263 112 : Node* argc_ptr = ChangeInt32ToIntPtr(argc);
264 : Node* proxy = Parameter(Descriptor::kTarget);
265 : Node* new_target = Parameter(Descriptor::kNewTarget);
266 : Node* context = Parameter(Descriptor::kContext);
267 :
268 : CSA_ASSERT(this, IsJSProxy(proxy));
269 : CSA_ASSERT(this, IsCallable(proxy));
270 :
271 56 : Label throw_proxy_handler_revoked(this, Label::kDeferred),
272 56 : trap_undefined(this), not_an_object(this, Label::kDeferred);
273 :
274 : // 1. Let handler be the value of the [[ProxyHandler]] internal slot of O.
275 56 : Node* handler = LoadObjectField(proxy, JSProxy::kHandlerOffset);
276 :
277 : // 2. If handler is null, throw a TypeError exception.
278 : CSA_ASSERT(this, IsNullOrJSReceiver(handler));
279 112 : GotoIfNot(IsJSReceiver(handler), &throw_proxy_handler_revoked);
280 :
281 : // 3. Assert: Type(handler) is Object.
282 : CSA_ASSERT(this, IsJSReceiver(handler));
283 :
284 : // 4. Let target be the value of the [[ProxyTarget]] internal slot of O.
285 : Node* target = LoadObjectField(proxy, JSProxy::kTargetOffset);
286 :
287 : // 5. Let trap be ? GetMethod(handler, "construct").
288 : // 6. If trap is undefined, then
289 56 : Handle<Name> trap_name = factory()->construct_string();
290 56 : Node* trap = GetMethod(context, handler, trap_name, &trap_undefined);
291 :
292 : CodeStubArguments args(this, argc_ptr);
293 :
294 : // 7. Let argArray be CreateArrayFromList(argumentsList).
295 56 : Node* array = AllocateJSArrayForCodeStubArguments(context, args, argc_ptr,
296 56 : INTPTR_PARAMETERS);
297 :
298 : // 8. Let newObj be ? Call(trap, handler, « target, argArray, newTarget »).
299 112 : Node* new_obj = CallJS(CodeFactory::Call(isolate()), context, trap, handler,
300 56 : target, array, new_target);
301 :
302 : // 9. If Type(newObj) is not Object, throw a TypeError exception.
303 112 : GotoIf(TaggedIsSmi(new_obj), ¬_an_object);
304 112 : GotoIfNot(IsJSReceiver(new_obj), ¬_an_object);
305 :
306 : // 10. Return newObj.
307 56 : args.PopAndReturn(new_obj);
308 :
309 56 : BIND(¬_an_object);
310 : {
311 56 : ThrowTypeError(context, MessageTemplate::kProxyConstructNonObject, new_obj);
312 : }
313 :
314 56 : BIND(&trap_undefined);
315 : {
316 : // 6.a. Assert: target has a [[Construct]] internal method.
317 : CSA_ASSERT(this, IsConstructor(target));
318 :
319 : // 6.b. Return ? Construct(target, argumentsList, newTarget).
320 112 : TailCallStub(CodeFactory::Construct(isolate()), context, target, new_target,
321 56 : argc);
322 : }
323 :
324 56 : BIND(&throw_proxy_handler_revoked);
325 56 : { ThrowTypeError(context, MessageTemplate::kProxyRevoked, "construct"); }
326 56 : }
327 :
328 224 : TF_BUILTIN(ProxyHasProperty, ProxiesCodeStubAssembler) {
329 : Node* context = Parameter(Descriptor::kContext);
330 : Node* proxy = Parameter(Descriptor::kProxy);
331 : Node* name = Parameter(Descriptor::kName);
332 :
333 : CSA_ASSERT(this, IsJSProxy(proxy));
334 :
335 56 : PerformStackCheck(CAST(context));
336 :
337 : // 1. Assert: IsPropertyKey(P) is true.
338 : CSA_ASSERT(this, IsName(name));
339 : CSA_ASSERT(this, Word32Equal(IsPrivateSymbol(name), Int32Constant(0)));
340 :
341 56 : Label throw_proxy_handler_revoked(this, Label::kDeferred),
342 56 : trap_undefined(this),
343 56 : if_try_get_own_property_bailout(this, Label::kDeferred),
344 56 : trap_not_callable(this, Label::kDeferred), return_true(this),
345 56 : return_false(this), check_target_desc(this);
346 :
347 : // 2. Let handler be O.[[ProxyHandler]].
348 : Node* handler = LoadObjectField(proxy, JSProxy::kHandlerOffset);
349 :
350 : // 3. If handler is null, throw a TypeError exception.
351 : // 4. Assert: Type(handler) is Object.
352 112 : GotoIfNot(IsJSReceiver(handler), &throw_proxy_handler_revoked);
353 :
354 : // 5. Let target be O.[[ProxyTarget]].
355 : Node* target = LoadObjectField(proxy, JSProxy::kTargetOffset);
356 :
357 : // 6. Let trap be ? GetMethod(handler, "has").
358 : // 7. If trap is undefined, then (see 7.a below).
359 56 : Handle<Name> trap_name = factory()->has_string();
360 56 : Node* trap = GetMethod(context, handler, trap_name, &trap_undefined);
361 :
362 112 : GotoIf(TaggedIsSmi(trap), &trap_not_callable);
363 112 : GotoIfNot(IsCallable(trap), &trap_not_callable);
364 :
365 : // 8. Let booleanTrapResult be ToBoolean(? Call(trap, handler, « target, P
366 : // »)).
367 112 : BranchIfToBooleanIsTrue(CallJS(CodeFactory::Call(isolate()), context, trap,
368 : handler, target, name),
369 56 : &return_true, &check_target_desc);
370 :
371 56 : BIND(&check_target_desc);
372 : {
373 : // 9. If booleanTrapResult is false, then (see 9.a. in CheckHasTrapResult).
374 56 : CheckHasTrapResult(context, target, proxy, name, &return_false,
375 56 : &if_try_get_own_property_bailout);
376 : }
377 :
378 56 : BIND(&if_try_get_own_property_bailout);
379 : {
380 : CallRuntime(Runtime::kCheckProxyHasTrap, context, name, target);
381 112 : Return(FalseConstant());
382 : }
383 :
384 56 : BIND(&trap_undefined);
385 : {
386 : // 7.a. Return ? target.[[HasProperty]](P).
387 56 : TailCallBuiltin(Builtins::kHasProperty, context, target, name);
388 : }
389 :
390 56 : BIND(&return_false);
391 112 : Return(FalseConstant());
392 :
393 56 : BIND(&return_true);
394 112 : Return(TrueConstant());
395 :
396 56 : BIND(&throw_proxy_handler_revoked);
397 56 : ThrowTypeError(context, MessageTemplate::kProxyRevoked, "has");
398 :
399 56 : BIND(&trap_not_callable);
400 : ThrowTypeError(context, MessageTemplate::kPropertyNotFunction, trap,
401 112 : StringConstant("has"), proxy);
402 56 : }
403 :
404 224 : TF_BUILTIN(ProxyGetProperty, ProxiesCodeStubAssembler) {
405 : Node* context = Parameter(Descriptor::kContext);
406 : Node* proxy = Parameter(Descriptor::kProxy);
407 : Node* name = Parameter(Descriptor::kName);
408 : Node* receiver = Parameter(Descriptor::kReceiverValue);
409 : Node* on_non_existent = Parameter(Descriptor::kOnNonExistent);
410 :
411 : CSA_ASSERT(this, IsJSProxy(proxy));
412 :
413 : // 1. Assert: IsPropertyKey(P) is true.
414 : CSA_ASSERT(this, TaggedIsNotSmi(name));
415 : CSA_ASSERT(this, IsName(name));
416 : CSA_ASSERT(this, Word32Equal(IsPrivateSymbol(name), Int32Constant(0)));
417 :
418 56 : Label throw_proxy_handler_revoked(this, Label::kDeferred),
419 56 : trap_undefined(this);
420 :
421 : // 2. Let handler be O.[[ProxyHandler]].
422 56 : Node* handler = LoadObjectField(proxy, JSProxy::kHandlerOffset);
423 :
424 : // 3. If handler is null, throw a TypeError exception.
425 112 : GotoIf(IsNull(handler), &throw_proxy_handler_revoked);
426 :
427 : // 4. Assert: Type(handler) is Object.
428 : CSA_ASSERT(this, IsJSReceiver(handler));
429 :
430 : // 5. Let target be O.[[ProxyTarget]].
431 : Node* target = LoadObjectField(proxy, JSProxy::kTargetOffset);
432 :
433 : // 6. Let trap be ? GetMethod(handler, "get").
434 : // 7. If trap is undefined, then (see 7.a below).
435 56 : Handle<Name> trap_name = factory()->get_string();
436 56 : Node* trap = GetMethod(context, handler, trap_name, &trap_undefined);
437 :
438 : // 8. Let trapResult be ? Call(trap, handler, « target, P, Receiver »).
439 : Node* trap_result = CallJS(
440 112 : CodeFactory::Call(isolate(), ConvertReceiverMode::kNotNullOrUndefined),
441 56 : context, trap, handler, target, name, receiver);
442 :
443 : // 9. Let targetDesc be ? target.[[GetOwnProperty]](P).
444 56 : Label return_result(this);
445 56 : CheckGetSetTrapResult(context, target, proxy, name, trap_result,
446 56 : &return_result, JSProxy::kGet);
447 :
448 56 : BIND(&return_result);
449 : {
450 : // 11. Return trapResult.
451 56 : Return(trap_result);
452 : }
453 :
454 56 : BIND(&trap_undefined);
455 : {
456 : // 7.a. Return ? target.[[Get]](P, Receiver).
457 : // TODO(mslekova): Introduce GetPropertyWithReceiver stub
458 56 : Return(CallRuntime(Runtime::kGetPropertyWithReceiver, context, target, name,
459 56 : receiver, on_non_existent));
460 : }
461 :
462 56 : BIND(&throw_proxy_handler_revoked);
463 56 : ThrowTypeError(context, MessageTemplate::kProxyRevoked, "get");
464 56 : }
465 :
466 224 : TF_BUILTIN(ProxySetProperty, ProxiesCodeStubAssembler) {
467 : Node* context = Parameter(Descriptor::kContext);
468 : Node* proxy = Parameter(Descriptor::kProxy);
469 : Node* name = Parameter(Descriptor::kName);
470 : Node* value = Parameter(Descriptor::kValue);
471 : Node* receiver = Parameter(Descriptor::kReceiverValue);
472 :
473 : CSA_ASSERT(this, IsJSProxy(proxy));
474 :
475 : // 1. Assert: IsPropertyKey(P) is true.
476 : CSA_ASSERT(this, TaggedIsNotSmi(name));
477 : CSA_ASSERT(this, IsName(name));
478 :
479 56 : Label throw_proxy_handler_revoked(this, Label::kDeferred),
480 56 : trap_undefined(this), failure(this, Label::kDeferred),
481 56 : continue_checks(this), success(this),
482 56 : private_symbol(this, Label::kDeferred);
483 :
484 112 : GotoIf(IsPrivateSymbol(name), &private_symbol);
485 :
486 : // 2. Let handler be O.[[ProxyHandler]].
487 : Node* handler = LoadObjectField(proxy, JSProxy::kHandlerOffset);
488 :
489 : // 3. If handler is null, throw a TypeError exception.
490 112 : GotoIfNot(IsJSReceiver(handler), &throw_proxy_handler_revoked);
491 :
492 : // 4. Assert: Type(handler) is Object.
493 : CSA_ASSERT(this, IsJSReceiver(handler));
494 :
495 : // 5. Let target be O.[[ProxyTarget]].
496 : Node* target = LoadObjectField(proxy, JSProxy::kTargetOffset);
497 :
498 : // 6. Let trap be ? GetMethod(handler, "set").
499 : // 7. If trap is undefined, then (see 7.a below).
500 56 : Handle<Name> set_string = factory()->set_string();
501 56 : Node* trap = GetMethod(context, handler, set_string, &trap_undefined);
502 :
503 : // 8. Let booleanTrapResult be ToBoolean(? Call(trap, handler,
504 : // « target, P, V, Receiver »)).
505 : // 9. If booleanTrapResult is false, return false.
506 56 : BranchIfToBooleanIsTrue(
507 112 : CallJS(CodeFactory::Call(isolate(),
508 : ConvertReceiverMode::kNotNullOrUndefined),
509 : context, trap, handler, target, name, value, receiver),
510 56 : &continue_checks, &failure);
511 :
512 56 : BIND(&continue_checks);
513 : {
514 : // 9. Let targetDesc be ? target.[[GetOwnProperty]](P).
515 56 : Label return_result(this);
516 56 : CheckGetSetTrapResult(context, target, proxy, name, value, &success,
517 56 : JSProxy::kSet);
518 : }
519 :
520 56 : BIND(&failure);
521 : {
522 : CallRuntime(Runtime::kThrowTypeErrorIfStrict, context,
523 : SmiConstant(MessageTemplate::kProxyTrapReturnedFalsishFor),
524 : HeapConstant(set_string), name);
525 56 : Goto(&success);
526 : }
527 :
528 : // 12. Return true.
529 56 : BIND(&success);
530 56 : Return(value);
531 :
532 56 : BIND(&private_symbol);
533 : {
534 56 : Label failure(this);
535 :
536 : CallRuntime(Runtime::kThrowTypeErrorIfStrict, context,
537 : SmiConstant(MessageTemplate::kProxyPrivate));
538 112 : Return(UndefinedConstant());
539 : }
540 :
541 56 : BIND(&trap_undefined);
542 : {
543 : // 7.a. Return ? target.[[Set]](P, V, Receiver).
544 : CallRuntime(Runtime::kSetPropertyWithReceiver, context, target, name, value,
545 : receiver);
546 56 : Return(value);
547 : }
548 :
549 56 : BIND(&throw_proxy_handler_revoked);
550 56 : ThrowTypeError(context, MessageTemplate::kProxyRevoked, "set");
551 56 : }
552 :
553 112 : void ProxiesCodeStubAssembler::CheckGetSetTrapResult(
554 : Node* context, Node* target, Node* proxy, Node* name, Node* trap_result,
555 : Label* check_passed, JSProxy::AccessKind access_kind) {
556 224 : Node* map = LoadMap(target);
557 224 : VARIABLE(var_value, MachineRepresentation::kTagged);
558 224 : VARIABLE(var_details, MachineRepresentation::kWord32);
559 224 : VARIABLE(var_raw_value, MachineRepresentation::kTagged);
560 :
561 112 : Label if_found_value(this), check_in_runtime(this, Label::kDeferred);
562 :
563 224 : GotoIfNot(IsUniqueNameNoIndex(CAST(name)), &check_in_runtime);
564 224 : Node* instance_type = LoadInstanceType(target);
565 : TryGetOwnProperty(context, target, target, map, instance_type, name,
566 : &if_found_value, &var_value, &var_details, &var_raw_value,
567 112 : check_passed, &check_in_runtime, kReturnAccessorPair);
568 :
569 112 : BIND(&if_found_value);
570 : {
571 112 : Label throw_non_configurable_data(this, Label::kDeferred),
572 112 : throw_non_configurable_accessor(this, Label::kDeferred),
573 112 : check_accessor(this), check_data(this);
574 :
575 : // If targetDesc is not undefined and targetDesc.[[Configurable]] is
576 : // false, then:
577 224 : GotoIfNot(IsSetWord32(var_details.value(),
578 224 : PropertyDetails::kAttributesDontDeleteMask),
579 112 : check_passed);
580 :
581 : // If IsDataDescriptor(targetDesc) is true and
582 : // targetDesc.[[Writable]] is false, then:
583 112 : BranchIfAccessorPair(var_raw_value.value(), &check_accessor, &check_data);
584 :
585 112 : BIND(&check_data);
586 : {
587 224 : Node* read_only = IsSetWord32(var_details.value(),
588 224 : PropertyDetails::kAttributesReadOnlyMask);
589 112 : GotoIfNot(read_only, check_passed);
590 :
591 : // If SameValue(trapResult, targetDesc.[[Value]]) is false,
592 : // throw a TypeError exception.
593 112 : BranchIfSameValue(trap_result, var_value.value(), check_passed,
594 112 : &throw_non_configurable_data);
595 : }
596 :
597 112 : BIND(&check_accessor);
598 : {
599 112 : Node* accessor_pair = var_raw_value.value();
600 :
601 112 : if (access_kind == JSProxy::kGet) {
602 56 : Label continue_check(this, Label::kDeferred);
603 : // 10.b. If IsAccessorDescriptor(targetDesc) is true and
604 : // targetDesc.[[Get]] is undefined, then:
605 : Node* getter =
606 : LoadObjectField(accessor_pair, AccessorPair::kGetterOffset);
607 : // Here we check for null as well because if the getter was never
608 : // defined it's set as null.
609 112 : GotoIf(IsUndefined(getter), &continue_check);
610 112 : GotoIf(IsNull(getter), &continue_check);
611 56 : Goto(check_passed);
612 :
613 : // 10.b.i. If trapResult is not undefined, throw a TypeError exception.
614 56 : BIND(&continue_check);
615 112 : GotoIfNot(IsUndefined(trap_result), &throw_non_configurable_accessor);
616 : } else {
617 : // 11.b.i. If targetDesc.[[Set]] is undefined, throw a TypeError
618 : // exception.
619 : Node* setter =
620 : LoadObjectField(accessor_pair, AccessorPair::kSetterOffset);
621 112 : GotoIf(IsUndefined(setter), &throw_non_configurable_accessor);
622 112 : GotoIf(IsNull(setter), &throw_non_configurable_accessor);
623 : }
624 112 : Goto(check_passed);
625 : }
626 :
627 112 : BIND(&check_in_runtime);
628 : {
629 : CallRuntime(Runtime::kCheckProxyGetSetTrapResult, context, name, target,
630 : trap_result, SmiConstant(access_kind));
631 112 : Return(trap_result);
632 : }
633 :
634 112 : BIND(&throw_non_configurable_data);
635 : {
636 112 : if (access_kind == JSProxy::kGet) {
637 56 : ThrowTypeError(context, MessageTemplate::kProxyGetNonConfigurableData,
638 56 : name, var_value.value(), trap_result);
639 : } else {
640 56 : ThrowTypeError(context, MessageTemplate::kProxySetFrozenData, name);
641 : }
642 : }
643 :
644 112 : BIND(&throw_non_configurable_accessor);
645 : {
646 112 : if (access_kind == JSProxy::kGet) {
647 : ThrowTypeError(context,
648 : MessageTemplate::kProxyGetNonConfigurableAccessor, name,
649 56 : trap_result);
650 : } else {
651 56 : ThrowTypeError(context, MessageTemplate::kProxySetFrozenAccessor, name);
652 : }
653 : }
654 : }
655 112 : }
656 :
657 56 : void ProxiesCodeStubAssembler::CheckHasTrapResult(Node* context, Node* target,
658 : Node* proxy, Node* name,
659 : Label* check_passed,
660 : Label* if_bailout) {
661 112 : Node* target_map = LoadMap(target);
662 112 : VARIABLE(var_value, MachineRepresentation::kTagged);
663 112 : VARIABLE(var_details, MachineRepresentation::kWord32);
664 112 : VARIABLE(var_raw_value, MachineRepresentation::kTagged);
665 :
666 56 : Label if_found_value(this, Label::kDeferred),
667 56 : throw_non_configurable(this, Label::kDeferred),
668 56 : throw_non_extensible(this, Label::kDeferred);
669 :
670 : // 9.a. Let targetDesc be ? target.[[GetOwnProperty]](P).
671 112 : GotoIfNot(IsUniqueNameNoIndex(CAST(name)), if_bailout);
672 112 : Node* instance_type = LoadInstanceType(target);
673 : TryGetOwnProperty(context, target, target, target_map, instance_type, name,
674 : &if_found_value, &var_value, &var_details, &var_raw_value,
675 56 : check_passed, if_bailout, kReturnAccessorPair);
676 :
677 : // 9.b. If targetDesc is not undefined, then (see 9.b.i. below).
678 56 : BIND(&if_found_value);
679 : {
680 : // 9.b.i. If targetDesc.[[Configurable]] is false, throw a TypeError
681 : // exception.
682 112 : Node* non_configurable = IsSetWord32(
683 112 : var_details.value(), PropertyDetails::kAttributesDontDeleteMask);
684 56 : GotoIf(non_configurable, &throw_non_configurable);
685 :
686 : // 9.b.ii. Let extensibleTarget be ? IsExtensible(target).
687 112 : Node* target_extensible = IsExtensibleMap(target_map);
688 :
689 : // 9.b.iii. If extensibleTarget is false, throw a TypeError exception.
690 56 : GotoIfNot(target_extensible, &throw_non_extensible);
691 56 : Goto(check_passed);
692 : }
693 :
694 56 : BIND(&throw_non_configurable);
695 56 : { ThrowTypeError(context, MessageTemplate::kProxyHasNonConfigurable, name); }
696 :
697 56 : BIND(&throw_non_extensible);
698 56 : { ThrowTypeError(context, MessageTemplate::kProxyHasNonExtensible, name); }
699 56 : }
700 :
701 : } // namespace internal
702 59456 : } // namespace v8
|