LCOV - code coverage report
Current view: top level - src/builtins - builtins-proxy-gen.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 302 302 100.0 %
Date: 2019-01-20 Functions: 27 27 100.0 %

          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         224 : void ProxiesCodeStubAssembler::GotoIfRevokedProxy(Node* object,
      17             :                                                   Label* if_proxy_revoked) {
      18         224 :   Label proxy_not_revoked(this);
      19         448 :   GotoIfNot(IsJSProxy(object), &proxy_not_revoked);
      20             :   Branch(IsJSReceiver(CAST(LoadObjectField(object, JSProxy::kHandlerOffset))),
      21         448 :          &proxy_not_revoked, if_proxy_revoked);
      22         224 :   BIND(&proxy_not_revoked);
      23         224 : }
      24             : 
      25         112 : Node* ProxiesCodeStubAssembler::AllocateProxy(Node* target, Node* handler,
      26             :                                               Node* context) {
      27         112 :   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             :     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             :     Label if_large_object(this, Label::kDeferred);
      80             :     Node* allocated_elements = AllocateFixedArray(PACKED_ELEMENTS, argc, mode,
      81         224 :                                                   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         112 :     GotoIf(SmiGreaterThan(length, SmiConstant(FixedArray::kMaxRegularLength)),
      89         224 :            &if_large_object);
      90         112 :     args.ForEach(list, [=, &offset](Node* arg) {
      91             :       StoreNoWriteBarrier(MachineRepresentation::kTagged, allocated_elements,
      92         224 :                           offset.value(), arg);
      93         112 :       Increment(&offset, kTaggedSize);
      94         336 :     });
      95         112 :     Goto(&allocate_js_array);
      96             : 
      97         112 :     BIND(&if_large_object);
      98             :     {
      99         112 :       args.ForEach(list, [=, &offset](Node* arg) {
     100         224 :         Store(allocated_elements, offset.value(), arg);
     101         112 :         Increment(&offset, kTaggedSize);
     102         336 :       });
     103         112 :       Goto(&allocate_js_array);
     104         112 :     }
     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 :       AllocateUninitializedJSArrayWithoutElements(array_map, length);
     120             :   StoreObjectFieldNoWriteBarrier(array, JSObject::kElementsOffset,
     121         112 :                                  elements.value());
     122             : 
     123         112 :   return array;
     124             : }
     125             : 
     126          56 : Node* ProxiesCodeStubAssembler::CreateProxyRevokeFunctionContext(
     127             :     Node* proxy, Node* native_context) {
     128         112 :   Node* const context = Allocate(FixedArray::SizeFor(kProxyContextLength));
     129          56 :   StoreMapNoWriteBarrier(context, RootIndex::kFunctionContextMap);
     130          56 :   InitializeFunctionContext(native_context, context, kProxyContextLength);
     131          56 :   StoreContextElementNoWriteBarrier(context, kProxySlot, proxy);
     132          56 :   return context;
     133             : }
     134             : 
     135          56 : Node* ProxiesCodeStubAssembler::AllocateProxyRevokeFunction(Node* proxy,
     136             :                                                             Node* context) {
     137         112 :   Node* const native_context = LoadNativeContext(context);
     138             : 
     139             :   Node* const proxy_context =
     140          56 :       CreateProxyRevokeFunctionContext(proxy, native_context);
     141             :   Node* const revoke_map = LoadContextElement(
     142         112 :       native_context, Context::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX);
     143             :   Node* const revoke_info =
     144         112 :       LoadContextElement(native_context, Context::PROXY_REVOKE_SHARED_FUN);
     145             : 
     146             :   return AllocateFunctionWithMapAndContext(revoke_map, revoke_info,
     147          56 :                                            proxy_context);
     148             : }
     149             : 
     150             : // ES #sec-proxy-constructor
     151         280 : 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          56 :   Label throwtypeerror(this, Label::kDeferred), createproxy(this);
     157         112 :   Branch(IsUndefined(new_target), &throwtypeerror, &createproxy);
     158             : 
     159          56 :   BIND(&throwtypeerror);
     160             :   {
     161          56 :     ThrowTypeError(context, MessageTemplate::kConstructorNotFunction, "Proxy");
     162             :   }
     163             : 
     164             :   // 2. Return ? ProxyCreate(target, handler).
     165          56 :   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          56 :         throw_proxy_handler_or_target_revoked(this, Label::kDeferred),
     179          56 :         return_create_proxy(this);
     180             : 
     181         112 :     GotoIf(TaggedIsSmi(target), &throw_proxy_non_object);
     182         112 :     GotoIfNot(IsJSReceiver(target), &throw_proxy_non_object);
     183          56 :     GotoIfRevokedProxy(target, &throw_proxy_handler_or_target_revoked);
     184             : 
     185         112 :     GotoIf(TaggedIsSmi(handler), &throw_proxy_non_object);
     186         112 :     GotoIfNot(IsJSReceiver(handler), &throw_proxy_non_object);
     187          56 :     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         112 :     Return(AllocateProxy(target, handler, context));
     200             : 
     201          56 :     BIND(&throw_proxy_non_object);
     202          56 :     ThrowTypeError(context, MessageTemplate::kProxyNonObject);
     203             : 
     204          56 :     BIND(&throw_proxy_handler_or_target_revoked);
     205         112 :     ThrowTypeError(context, MessageTemplate::kProxyHandlerOrTargetRevoked);
     206          56 :   }
     207          56 : }
     208             : 
     209         224 : 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         112 :   Node* const native_context = LoadNativeContext(context);
     214             : 
     215             :   Label throw_proxy_non_object(this, Label::kDeferred),
     216          56 :       throw_proxy_handler_or_target_revoked(this, Label::kDeferred),
     217          56 :       return_create_proxy(this);
     218             : 
     219         112 :   GotoIf(TaggedIsSmi(target), &throw_proxy_non_object);
     220         112 :   GotoIfNot(IsJSReceiver(target), &throw_proxy_non_object);
     221          56 :   GotoIfRevokedProxy(target, &throw_proxy_handler_or_target_revoked);
     222             : 
     223         112 :   GotoIf(TaggedIsSmi(handler), &throw_proxy_non_object);
     224         112 :   GotoIfNot(IsJSReceiver(handler), &throw_proxy_non_object);
     225          56 :   GotoIfRevokedProxy(handler, &throw_proxy_handler_or_target_revoked);
     226             : 
     227          56 :   Node* const proxy = AllocateProxy(target, handler, context);
     228          56 :   Node* const revoke = AllocateProxyRevokeFunction(proxy, context);
     229             : 
     230         112 :   Node* const result = Allocate(JSProxyRevocableResult::kSize);
     231             :   Node* const result_map = LoadContextElement(
     232         112 :       native_context, Context::PROXY_REVOCABLE_RESULT_MAP_INDEX);
     233          56 :   StoreMapNoWriteBarrier(result, result_map);
     234             :   StoreObjectFieldRoot(result, JSProxyRevocableResult::kPropertiesOrHashOffset,
     235          56 :                        RootIndex::kEmptyFixedArray);
     236             :   StoreObjectFieldRoot(result, JSProxyRevocableResult::kElementsOffset,
     237          56 :                        RootIndex::kEmptyFixedArray);
     238             :   StoreObjectFieldNoWriteBarrier(result, JSProxyRevocableResult::kProxyOffset,
     239          56 :                                  proxy);
     240             :   StoreObjectFieldNoWriteBarrier(result, JSProxyRevocableResult::kRevokeOffset,
     241          56 :                                  revoke);
     242          56 :   Return(result);
     243             : 
     244          56 :   BIND(&throw_proxy_non_object);
     245          56 :   ThrowTypeError(context, MessageTemplate::kProxyNonObject);
     246             : 
     247          56 :   BIND(&throw_proxy_handler_or_target_revoked);
     248         112 :   ThrowTypeError(context, MessageTemplate::kProxyHandlerOrTargetRevoked);
     249          56 : }
     250             : 
     251             : // Proxy Revocation Functions
     252             : // https://tc39.github.io/ecma262/#sec-proxy-revocation-functions
     253         224 : TF_BUILTIN(ProxyRevoke, ProxiesCodeStubAssembler) {
     254             :   Node* const context = Parameter(Descriptor::kContext);
     255             : 
     256             :   // 1. Let p be F.[[RevocableProxy]].
     257         112 :   Node* const proxy_slot = IntPtrConstant(kProxySlot);
     258         112 :   Node* const proxy = LoadContextElement(context, proxy_slot);
     259             : 
     260             :   Label revoke_called(this);
     261             : 
     262             :   // 2. If p is null, ...
     263         112 :   GotoIf(IsNull(proxy), &revoke_called);
     264             : 
     265             :   // 3. Set F.[[RevocableProxy]] to null.
     266         112 :   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         112 :   StoreObjectField(proxy, JSProxy::kTargetOffset, NullConstant());
     273             : 
     274             :   // 6. Set p.[[ProxyHandler]] to null.
     275         112 :   StoreObjectField(proxy, JSProxy::kHandlerOffset, NullConstant());
     276             : 
     277             :   // 7. Return undefined.
     278         112 :   Return(UndefinedConstant());
     279             : 
     280          56 :   BIND(&revoke_called);
     281             :   // 2. ... return undefined.
     282         112 :   Return(UndefinedConstant());
     283          56 : }
     284             : 
     285         280 : TF_BUILTIN(CallProxy, ProxiesCodeStubAssembler) {
     286             :   Node* argc = Parameter(Descriptor::kActualArgumentsCount);
     287         112 :   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          56 :   PerformStackCheck(CAST(context));
     295             : 
     296             :   Label throw_proxy_handler_revoked(this, Label::kDeferred),
     297          56 :       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         112 :   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          56 :   Handle<Name> trap_name = factory()->apply_string();
     315          56 :   Node* trap = GetMethod(context, handler, trap_name, &trap_undefined);
     316             : 
     317             :   CodeStubArguments args(this, argc_ptr);
     318         112 :   Node* receiver = args.GetReceiver();
     319             : 
     320             :   // 7. Let argArray be CreateArrayFromList(argumentsList).
     321             :   Node* array = AllocateJSArrayForCodeStubArguments(context, args, argc_ptr,
     322          56 :                                                     INTPTR_PARAMETERS);
     323             : 
     324             :   // 8. Return Call(trap, handler, «target, thisArgument, argArray»).
     325             :   Node* result = CallJS(CodeFactory::Call(isolate()), context, trap, handler,
     326         112 :                         target, receiver, array);
     327          56 :   args.PopAndReturn(result);
     328             : 
     329          56 :   BIND(&trap_undefined);
     330             :   {
     331             :     // 6.a. Return Call(target, thisArgument, argumentsList).
     332         112 :     TailCallStub(CodeFactory::Call(isolate()), context, target, argc);
     333             :   }
     334             : 
     335          56 :   BIND(&throw_proxy_handler_revoked);
     336         112 :   { ThrowTypeError(context, MessageTemplate::kProxyRevoked, "apply"); }
     337          56 : }
     338             : 
     339         280 : TF_BUILTIN(ConstructProxy, ProxiesCodeStubAssembler) {
     340             :   Node* argc = Parameter(Descriptor::kActualArgumentsCount);
     341         112 :   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          56 :       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          56 :   Node* handler = LoadObjectField(proxy, JSProxy::kHandlerOffset);
     354             : 
     355             :   // 2. If handler is null, throw a TypeError exception.
     356             :   CSA_ASSERT(this, IsNullOrJSReceiver(handler));
     357         112 :   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          56 :   Handle<Name> trap_name = factory()->construct_string();
     368          56 :   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          56 :                                                     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         112 :                          target, array, new_target);
     379             : 
     380             :   // 9. If Type(newObj) is not Object, throw a TypeError exception.
     381         112 :   GotoIf(TaggedIsSmi(new_obj), &not_an_object);
     382         112 :   GotoIfNot(IsJSReceiver(new_obj), &not_an_object);
     383             : 
     384             :   // 10. Return newObj.
     385          56 :   args.PopAndReturn(new_obj);
     386             : 
     387          56 :   BIND(&not_an_object);
     388             :   {
     389          56 :     ThrowTypeError(context, MessageTemplate::kProxyConstructNonObject, new_obj);
     390             :   }
     391             : 
     392          56 :   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         112 :                  argc);
     400             :   }
     401             : 
     402          56 :   BIND(&throw_proxy_handler_revoked);
     403         112 :   { ThrowTypeError(context, MessageTemplate::kProxyRevoked, "construct"); }
     404          56 : }
     405             : 
     406         224 : 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          56 :   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          56 :       trap_undefined(this),
     421          56 :       if_try_get_own_property_bailout(this, Label::kDeferred),
     422          56 :       trap_not_callable(this, Label::kDeferred), return_true(this),
     423          56 :       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         112 :   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          56 :   Handle<Name> trap_name = factory()->has_string();
     438          56 :   Node* trap = GetMethod(context, handler, trap_name, &trap_undefined);
     439             : 
     440         112 :   GotoIf(TaggedIsSmi(trap), &trap_not_callable);
     441         112 :   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         112 :                           &return_true, &check_target_desc);
     448             : 
     449          56 :   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          56 :                        &if_try_get_own_property_bailout);
     454             :   }
     455             : 
     456          56 :   BIND(&if_try_get_own_property_bailout);
     457             :   {
     458             :     CallRuntime(Runtime::kCheckProxyHasTrap, context, name, target);
     459         112 :     Return(FalseConstant());
     460             :   }
     461             : 
     462          56 :   BIND(&trap_undefined);
     463             :   {
     464             :     // 7.a. Return ? target.[[HasProperty]](P).
     465          56 :     TailCallBuiltin(Builtins::kHasProperty, context, target, name);
     466             :   }
     467             : 
     468          56 :   BIND(&return_false);
     469         112 :   Return(FalseConstant());
     470             : 
     471          56 :   BIND(&return_true);
     472         112 :   Return(TrueConstant());
     473             : 
     474          56 :   BIND(&throw_proxy_handler_revoked);
     475          56 :   ThrowTypeError(context, MessageTemplate::kProxyRevoked, "has");
     476             : 
     477          56 :   BIND(&trap_not_callable);
     478             :   ThrowTypeError(context, MessageTemplate::kPropertyNotFunction, trap,
     479         168 :                  StringConstant("has"), proxy);
     480          56 : }
     481             : 
     482         224 : 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          56 :       trap_undefined(this);
     498             : 
     499             :   // 2. Let handler be O.[[ProxyHandler]].
     500          56 :   Node* handler = LoadObjectField(proxy, JSProxy::kHandlerOffset);
     501             : 
     502             :   // 3. If handler is null, throw a TypeError exception.
     503         112 :   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          56 :   Handle<Name> trap_name = factory()->get_string();
     514          56 :   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         112 :       context, trap, handler, target, name, receiver);
     520             : 
     521             :   // 9. Let targetDesc be ? target.[[GetOwnProperty]](P).
     522          56 :   Label return_result(this);
     523             :   CheckGetSetTrapResult(context, target, proxy, name, trap_result,
     524          56 :                         &return_result, JSProxy::kGet);
     525             : 
     526          56 :   BIND(&return_result);
     527             :   {
     528             :     // 11. Return trapResult.
     529          56 :     Return(trap_result);
     530             :   }
     531             : 
     532          56 :   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          56 :                        receiver, on_non_existent));
     538             :   }
     539             : 
     540          56 :   BIND(&throw_proxy_handler_revoked);
     541         112 :   ThrowTypeError(context, MessageTemplate::kProxyRevoked, "get");
     542          56 : }
     543             : 
     544         224 : 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          56 :       trap_undefined(this), failure(this, Label::kDeferred),
     560          56 :       continue_checks(this), success(this),
     561          56 :       private_symbol(this, Label::kDeferred);
     562             : 
     563         112 :   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         112 :   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          56 :   Handle<Name> set_string = factory()->set_string();
     580          56 :   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         112 :       &continue_checks, &failure);
     590             : 
     591          56 :   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          56 :                           JSProxy::kSet);
     597             :   }
     598             : 
     599          56 :   BIND(&failure);
     600             :   {
     601             :     Label if_throw(this, Label::kDeferred);
     602             :     Branch(SmiEqual(language_mode, SmiConstant(LanguageMode::kStrict)),
     603         112 :            &if_throw, &success);
     604             : 
     605          56 :     BIND(&if_throw);
     606             :     ThrowTypeError(context, MessageTemplate::kProxyTrapReturnedFalsishFor,
     607          56 :                    HeapConstant(set_string), name);
     608             :   }
     609             : 
     610             :   // 12. Return true.
     611          56 :   BIND(&success);
     612          56 :   Return(value);
     613             : 
     614          56 :   BIND(&private_symbol);
     615             :   {
     616          56 :     Label failure(this), throw_error(this, Label::kDeferred);
     617             : 
     618             :     Branch(SmiEqual(language_mode, SmiConstant(LanguageMode::kStrict)),
     619         112 :            &throw_error, &failure);
     620             : 
     621          56 :     BIND(&failure);
     622         112 :     Return(UndefinedConstant());
     623             : 
     624          56 :     BIND(&throw_error);
     625         112 :     ThrowTypeError(context, MessageTemplate::kProxyPrivate);
     626             :   }
     627             : 
     628          56 :   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          56 :     Return(value);
     634             :   }
     635             : 
     636          56 :   BIND(&throw_proxy_handler_revoked);
     637         112 :   ThrowTypeError(context, MessageTemplate::kProxyRevoked, "set");
     638          56 : }
     639             : 
     640         112 : void ProxiesCodeStubAssembler::CheckGetSetTrapResult(
     641             :     Node* context, Node* target, Node* proxy, Node* name, Node* trap_result,
     642             :     Label* check_passed, JSProxy::AccessKind access_kind) {
     643         224 :   Node* map = LoadMap(target);
     644         112 :   VARIABLE(var_value, MachineRepresentation::kTagged);
     645         224 :   VARIABLE(var_details, MachineRepresentation::kWord32);
     646         224 :   VARIABLE(var_raw_value, MachineRepresentation::kTagged);
     647             : 
     648         112 :   Label if_found_value(this), check_in_runtime(this, Label::kDeferred);
     649             : 
     650         224 :   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         112 :                     check_passed, &check_in_runtime, kReturnAccessorPair);
     654             : 
     655         112 :   BIND(&if_found_value);
     656             :   {
     657             :     Label throw_non_configurable_data(this, Label::kDeferred),
     658         112 :         throw_non_configurable_accessor(this, Label::kDeferred),
     659         112 :         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         224 :                           PropertyDetails::kAttributesDontDeleteMask),
     665         224 :               check_passed);
     666             : 
     667             :     // If IsDataDescriptor(targetDesc) is true and
     668             :     // targetDesc.[[Writable]] is false, then:
     669         112 :     BranchIfAccessorPair(var_raw_value.value(), &check_accessor, &check_data);
     670             : 
     671         112 :     BIND(&check_data);
     672             :     {
     673             :       Node* read_only = IsSetWord32(var_details.value(),
     674         336 :                                     PropertyDetails::kAttributesReadOnlyMask);
     675         112 :       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         112 :                         &throw_non_configurable_data);
     681             :     }
     682             : 
     683         112 :     BIND(&check_accessor);
     684             :     {
     685         112 :       Node* accessor_pair = var_raw_value.value();
     686             : 
     687         112 :       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         112 :         GotoIf(IsUndefined(getter), &continue_check);
     696         112 :         GotoIf(IsNull(getter), &continue_check);
     697          56 :         Goto(check_passed);
     698             : 
     699             :         // 10.b.i. If trapResult is not undefined, throw a TypeError exception.
     700          56 :         BIND(&continue_check);
     701         112 :         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         112 :         GotoIf(IsUndefined(setter), &throw_non_configurable_accessor);
     708         112 :         GotoIf(IsNull(setter), &throw_non_configurable_accessor);
     709             :       }
     710         112 :       Goto(check_passed);
     711             :     }
     712             : 
     713         112 :     BIND(&check_in_runtime);
     714             :     {
     715             :       CallRuntime(Runtime::kCheckProxyGetSetTrapResult, context, name, target,
     716             :                   trap_result, SmiConstant(access_kind));
     717         112 :       Return(trap_result);
     718             :     }
     719             : 
     720         112 :     BIND(&throw_non_configurable_data);
     721             :     {
     722         112 :       if (access_kind == JSProxy::kGet) {
     723             :         ThrowTypeError(context, MessageTemplate::kProxyGetNonConfigurableData,
     724          56 :                        name, var_value.value(), trap_result);
     725             :       } else {
     726          56 :         ThrowTypeError(context, MessageTemplate::kProxySetFrozenData, name);
     727             :       }
     728             :     }
     729             : 
     730         112 :     BIND(&throw_non_configurable_accessor);
     731             :     {
     732         112 :       if (access_kind == JSProxy::kGet) {
     733             :         ThrowTypeError(context,
     734             :                        MessageTemplate::kProxyGetNonConfigurableAccessor, name,
     735          56 :                        trap_result);
     736             :       } else {
     737          56 :         ThrowTypeError(context, MessageTemplate::kProxySetFrozenAccessor, name);
     738             :       }
     739         112 :     }
     740         112 :   }
     741         112 : }
     742             : 
     743          56 : void ProxiesCodeStubAssembler::CheckHasTrapResult(Node* context, Node* target,
     744             :                                                   Node* proxy, Node* name,
     745             :                                                   Label* check_passed,
     746             :                                                   Label* if_bailout) {
     747         112 :   Node* target_map = LoadMap(target);
     748          56 :   VARIABLE(var_value, MachineRepresentation::kTagged);
     749         112 :   VARIABLE(var_details, MachineRepresentation::kWord32);
     750         112 :   VARIABLE(var_raw_value, MachineRepresentation::kTagged);
     751             : 
     752          56 :   Label if_found_value(this, Label::kDeferred),
     753          56 :       throw_non_configurable(this, Label::kDeferred),
     754          56 :       throw_non_extensible(this, Label::kDeferred);
     755             : 
     756             :   // 9.a. Let targetDesc be ? target.[[GetOwnProperty]](P).
     757         112 :   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          56 :                     check_passed, if_bailout, kReturnAccessorPair);
     761             : 
     762             :   // 9.b. If targetDesc is not undefined, then (see 9.b.i. below).
     763          56 :   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         168 :         var_details.value(), PropertyDetails::kAttributesDontDeleteMask);
     769          56 :     GotoIf(non_configurable, &throw_non_configurable);
     770             : 
     771             :     // 9.b.ii. Let extensibleTarget be ? IsExtensible(target).
     772         112 :     Node* target_extensible = IsExtensibleMap(target_map);
     773             : 
     774             :     // 9.b.iii. If extensibleTarget is false, throw a TypeError exception.
     775          56 :     GotoIfNot(target_extensible, &throw_non_extensible);
     776          56 :     Goto(check_passed);
     777             :   }
     778             : 
     779          56 :   BIND(&throw_non_configurable);
     780          56 :   { ThrowTypeError(context, MessageTemplate::kProxyHasNonConfigurable, name); }
     781             : 
     782          56 :   BIND(&throw_non_extensible);
     783         112 :   { ThrowTypeError(context, MessageTemplate::kProxyHasNonExtensible, name); }
     784          56 : }
     785             : 
     786             : }  // namespace internal
     787       94089 : }  // namespace v8

Generated by: LCOV version 1.10