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