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