| Index: src/code-stub-assembler.cc
|
| diff --git a/src/code-stub-assembler.cc b/src/code-stub-assembler.cc
|
| index 000c064a7057d072cca4c9c14fb0b2223f1cdc17..50fcfa19bdd12373b984b31841a36642b8cba7c0 100644
|
| --- a/src/code-stub-assembler.cc
|
| +++ b/src/code-stub-assembler.cc
|
| @@ -1,7 +1,10 @@
|
| // Copyright 2016 the V8 project authors. All rights reserved.
|
| // Use of this source code is governed by a BSD-style license that can be
|
| // found in the LICENSE file.
|
| +
|
| #include "src/code-stub-assembler.h"
|
| +
|
| +#include "src/builtins/builtins-descriptors.h"
|
| #include "src/code-factory.h"
|
| #include "src/frames-inl.h"
|
| #include "src/frames.h"
|
| @@ -5997,60 +6000,78 @@ void CodeStubAssembler::TryPrototypeChainLookup(
|
| Node* CodeStubAssembler::OrdinaryHasInstance(Node* context, Node* callable,
|
| Node* object) {
|
| VARIABLE(var_result, MachineRepresentation::kTagged);
|
| - Label return_false(this), return_true(this),
|
| + Label return_false(this, Label::kDeferred), return_true(this),
|
| + return_instanceof(this, Label::kDeferred),
|
| return_runtime(this, Label::kDeferred), return_result(this);
|
|
|
| - // Goto runtime if {object} is a Smi.
|
| - GotoIf(TaggedIsSmi(object), &return_runtime);
|
| -
|
| - // Load map of {object}.
|
| - Node* object_map = LoadMap(object);
|
| -
|
| - // Goto runtime if {callable} is a Smi.
|
| - GotoIf(TaggedIsSmi(callable), &return_runtime);
|
| -
|
| - // Load map of {callable}.
|
| + // Return false if {callable} is not Callable.
|
| + GotoIf(TaggedIsSmi(callable), &return_false);
|
| Node* callable_map = LoadMap(callable);
|
| + GotoIfNot(IsCallableMap(callable_map), &return_false);
|
|
|
| - // Goto runtime if {callable} is not a JSFunction.
|
| + // If {callable} is a JSBoundFunction, call the instanceof operator
|
| + // recursively with the bound target function.
|
| Node* callable_instance_type = LoadMapInstanceType(callable_map);
|
| - GotoIfNot(
|
| - Word32Equal(callable_instance_type, Int32Constant(JS_FUNCTION_TYPE)),
|
| - &return_runtime);
|
| + GotoIf(InstanceTypeEqual(callable_instance_type, JS_BOUND_FUNCTION_TYPE),
|
| + &return_instanceof);
|
|
|
| - // Goto runtime if {callable} is not a constructor or has
|
| - // a non-instance "prototype".
|
| + // Return false if {object} is not a JSReceiver.
|
| + GotoIf(TaggedIsSmi(object), &return_false);
|
| + Node* object_map = LoadMap(object);
|
| + GotoIfNot(IsJSReceiverMap(object_map), &return_false);
|
| +
|
| + // Load the "prototype" from the {callable}. We have a fast-path here for
|
| + // JSFunction objects that are marked as constructors and have an instance
|
| + // "prototype".
|
| + VARIABLE(var_callable_prototype, MachineRepresentation::kTagged);
|
| + Label fast_callable_prototype(this),
|
| + slow_callable_prototype(this, Label::kDeferred),
|
| + done_callable_prototype(this);
|
| + GotoIfNot(IsJSFunctionInstanceType(callable_instance_type),
|
| + &slow_callable_prototype);
|
| Node* callable_bitfield = LoadMapBitField(callable_map);
|
| - GotoIfNot(
|
| + Branch(
|
| Word32Equal(Word32And(callable_bitfield,
|
| Int32Constant((1 << Map::kHasNonInstancePrototype) |
|
| (1 << Map::kIsConstructor))),
|
| Int32Constant(1 << Map::kIsConstructor)),
|
| - &return_runtime);
|
| -
|
| - // Get the "prototype" (or initial map) of the {callable}.
|
| - Node* callable_prototype =
|
| - LoadObjectField(callable, JSFunction::kPrototypeOrInitialMapOffset);
|
| - {
|
| - Label callable_prototype_valid(this);
|
| - VARIABLE(var_callable_prototype, MachineRepresentation::kTagged,
|
| - callable_prototype);
|
| -
|
| - // Resolve the "prototype" if the {callable} has an initial map. Afterwards
|
| - // the {callable_prototype} will be either the JSReceiver prototype object
|
| - // or the hole value, which means that no instances of the {callable} were
|
| - // created so far and hence we should return false.
|
| - Node* callable_prototype_instance_type =
|
| - LoadInstanceType(callable_prototype);
|
| - GotoIfNot(
|
| - Word32Equal(callable_prototype_instance_type, Int32Constant(MAP_TYPE)),
|
| - &callable_prototype_valid);
|
| + &fast_callable_prototype, &slow_callable_prototype);
|
| + BIND(&fast_callable_prototype);
|
| + {
|
| + // Get the "prototype" (or initial map) of the {callable}.
|
| + Node* callable_prototype =
|
| + LoadObjectField(callable, JSFunction::kPrototypeOrInitialMapOffset);
|
| + var_callable_prototype.Bind(callable_prototype);
|
| +
|
| + // Resolve the "prototype" if the {callable} has an initial map.
|
| + // Afterwards the {callable_prototype} will be either the JSReceiver
|
| + // prototype object or the hole value, which means that no instances of
|
| + // the {callable} were created so far and hence we should return false.
|
| + GotoIfNot(IsMap(callable_prototype), &done_callable_prototype);
|
| var_callable_prototype.Bind(
|
| LoadObjectField(callable_prototype, Map::kPrototypeOffset));
|
| - Goto(&callable_prototype_valid);
|
| - BIND(&callable_prototype_valid);
|
| - callable_prototype = var_callable_prototype.value();
|
| + Goto(&done_callable_prototype);
|
| + }
|
| + BIND(&slow_callable_prototype);
|
| + {
|
| + // Generic "prototype" lookup on the {callable}, including check
|
| + // that the resulting prototype is a proper JSReceiver.
|
| + Label callable_prototype_not_receiver(this, Label::kDeferred);
|
| + Node* callable_prototype =
|
| + GetProperty(context, callable, PrototypeStringConstant());
|
| + GotoIf(TaggedIsSmi(callable_prototype), &callable_prototype_not_receiver);
|
| + var_callable_prototype.Bind(callable_prototype);
|
| + Branch(IsJSReceiver(callable_prototype), &done_callable_prototype,
|
| + &callable_prototype_not_receiver);
|
| + BIND(&callable_prototype_not_receiver);
|
| + {
|
| + CallRuntime(Runtime::kThrowInstanceofNonobjectProto, context,
|
| + callable_prototype);
|
| + Unreachable();
|
| + }
|
| }
|
| + BIND(&done_callable_prototype);
|
| + Node* callable_prototype = var_callable_prototype.value();
|
|
|
| // Loop through the prototype chain looking for the {callable} prototype.
|
| VARIABLE(var_object_map, MachineRepresentation::kTagged, object_map);
|
| @@ -6058,9 +6079,8 @@ Node* CodeStubAssembler::OrdinaryHasInstance(Node* context, Node* callable,
|
| Goto(&loop);
|
| BIND(&loop);
|
| {
|
| - Node* object_map = var_object_map.value();
|
| -
|
| // Check if the current {object} needs to be access checked.
|
| + Node* object_map = var_object_map.value();
|
| Node* object_bitfield = LoadMapBitField(object_map);
|
| GotoIfNot(
|
| Word32Equal(Word32And(object_bitfield,
|
| @@ -6070,7 +6090,7 @@ Node* CodeStubAssembler::OrdinaryHasInstance(Node* context, Node* callable,
|
|
|
| // Check if the current {object} is a proxy.
|
| Node* object_instance_type = LoadMapInstanceType(object_map);
|
| - GotoIf(Word32Equal(object_instance_type, Int32Constant(JS_PROXY_TYPE)),
|
| + GotoIf(InstanceTypeEqual(object_instance_type, JS_PROXY_TYPE),
|
| &return_runtime);
|
|
|
| // Check the current {object} prototype.
|
| @@ -6094,8 +6114,21 @@ Node* CodeStubAssembler::OrdinaryHasInstance(Node* context, Node* callable,
|
| BIND(&return_runtime);
|
| {
|
| // Fallback to the runtime implementation.
|
| - var_result.Bind(
|
| - CallRuntime(Runtime::kOrdinaryHasInstance, context, callable, object));
|
| + var_result.Bind(CallRuntime(Runtime::kHasInPrototypeChain, context, object,
|
| + callable_prototype));
|
| + }
|
| + Goto(&return_result);
|
| +
|
| + BIND(&return_instanceof);
|
| + {
|
| + // Use the InstanceOf algorithm on the [[BoundTargetFunction]].
|
| + ExternalReference ref(Builtins::kInstanceOf, isolate());
|
| + Node* code = Load(MachineType::AnyTagged(), ExternalConstant(ref));
|
| + Node* bound_target_function =
|
| + LoadObjectField(callable, JSBoundFunction::kBoundTargetFunctionOffset);
|
| + Node* result = CallStub(Builtin_InstanceOf_InterfaceDescriptor(isolate()),
|
| + code, context, object, bound_target_function);
|
| + var_result.Bind(result);
|
| }
|
| Goto(&return_result);
|
|
|
| @@ -8758,8 +8791,8 @@ Node* CodeStubAssembler::InstanceOf(Node* object, Node* callable,
|
| GotoIfNot(IsCallable(callable), &if_notcallable);
|
|
|
| // Use the OrdinaryHasInstance algorithm.
|
| - Node* result = CallStub(CodeFactory::OrdinaryHasInstance(isolate()),
|
| - context, callable, object);
|
| + Node* result =
|
| + CallBuiltin(Builtins::kOrdinaryHasInstance, context, callable, object);
|
| var_result.Bind(result);
|
| Goto(&return_result);
|
| }
|
|
|