Index: src/code-stub-assembler.cc |
diff --git a/src/code-stub-assembler.cc b/src/code-stub-assembler.cc |
index 520789cc16fab43bbf3813aed52e9abc0a45c19e..e131048f761fa86af28857596600410ff3cadbb0 100644 |
--- a/src/code-stub-assembler.cc |
+++ b/src/code-stub-assembler.cc |
@@ -2911,6 +2911,10 @@ Node* CodeStubAssembler::IsCallableMap(Node* map) { |
Int32Constant(0)); |
} |
+Node* CodeStubAssembler::IsCallable(Node* object) { |
+ return IsCallableMap(LoadMap(object)); |
+} |
+ |
Node* CodeStubAssembler::IsConstructorMap(Node* map) { |
CSA_ASSERT(this, IsMap(map)); |
return Word32NotEqual( |
@@ -7962,33 +7966,90 @@ Node* CodeStubAssembler::GetSuperConstructor(Node* active_function, |
Node* CodeStubAssembler::InstanceOf(Node* object, Node* callable, |
Node* context) { |
- Label return_runtime(this, Label::kDeferred), end(this); |
- Variable result(this, MachineRepresentation::kTagged); |
+ Variable var_result(this, MachineRepresentation::kTagged); |
+ Label if_notcallable(this, Label::kDeferred), |
+ if_notreceiver(this, Label::kDeferred), if_otherhandler(this), |
+ if_nohandler(this, Label::kDeferred), return_true(this), |
+ return_false(this), return_result(this, &var_result); |
+ |
+ // Ensure that the {callable} is actually a JSReceiver. |
+ GotoIf(TaggedIsSmi(callable), &if_notreceiver); |
+ GotoUnless(IsJSReceiver(callable), &if_notreceiver); |
+ |
+ // Load the @@hasInstance property from {callable}. |
+ Node* inst_of_handler = CallStub(CodeFactory::GetProperty(isolate()), context, |
+ callable, HasInstanceSymbolConstant()); |
+ |
+ // Optimize for the likely case where {inst_of_handler} is the builtin |
+ // Function.prototype[@@hasInstance] method, and emit a direct call in |
+ // that case without any additional checking. |
+ Node* native_context = LoadNativeContext(context); |
+ Node* function_has_instance = |
+ LoadContextElement(native_context, Context::FUNCTION_HAS_INSTANCE_INDEX); |
+ GotoUnless(WordEqual(inst_of_handler, function_has_instance), |
+ &if_otherhandler); |
+ { |
+ // Call to Function.prototype[@@hasInstance] directly. |
+ Callable builtin(isolate()->builtins()->FunctionPrototypeHasInstance(), |
+ CallTrampolineDescriptor(isolate())); |
+ Node* result = CallJS(builtin, context, inst_of_handler, callable, object); |
+ var_result.Bind(result); |
+ Goto(&return_result); |
+ } |
- // Check if no one installed @@hasInstance somewhere. |
- GotoUnless( |
- WordEqual(LoadObjectField(LoadRoot(Heap::kHasInstanceProtectorRootIndex), |
- PropertyCell::kValueOffset), |
- SmiConstant(Smi::FromInt(Isolate::kProtectorValid))), |
- &return_runtime); |
+ Bind(&if_otherhandler); |
+ { |
+ // Check if there's actually an {inst_of_handler}. |
+ GotoIf(IsNull(inst_of_handler), &if_nohandler); |
+ GotoIf(IsUndefined(inst_of_handler), &if_nohandler); |
- // Check if {callable} is a valid receiver. |
- GotoIf(TaggedIsSmi(callable), &return_runtime); |
- GotoUnless(IsCallableMap(LoadMap(callable)), &return_runtime); |
+ // Call the {inst_of_handler} for {callable} and {object}. |
+ Node* result = CallJS( |
+ CodeFactory::Call(isolate(), ConvertReceiverMode::kNotNullOrUndefined), |
+ context, inst_of_handler, callable, object); |
- // Use the inline OrdinaryHasInstance directly. |
- result.Bind(OrdinaryHasInstance(context, callable, object)); |
- Goto(&end); |
+ // Convert the {result} to a Boolean. |
+ BranchIfToBooleanIsTrue(result, &return_true, &return_false); |
+ } |
- // TODO(bmeurer): Use GetPropertyStub here once available. |
- Bind(&return_runtime); |
+ Bind(&if_nohandler); |
{ |
- result.Bind(CallRuntime(Runtime::kInstanceOf, context, object, callable)); |
- Goto(&end); |
+ // Ensure that the {callable} is actually Callable. |
+ GotoUnless(IsCallable(callable), &if_notcallable); |
+ |
+ // Use the OrdinaryHasInstance algorithm. |
+ Node* result = CallStub(CodeFactory::OrdinaryHasInstance(isolate()), |
+ context, callable, object); |
+ var_result.Bind(result); |
+ Goto(&return_result); |
} |
- Bind(&end); |
- return result.value(); |
+ Bind(&if_notcallable); |
+ { |
+ Node* result = |
+ CallRuntime(Runtime::kThrowNonCallableInInstanceOfCheck, context); |
+ var_result.Bind(result); |
+ Goto(&return_result); |
+ } |
+ |
+ Bind(&if_notreceiver); |
+ { |
+ Node* result = |
+ CallRuntime(Runtime::kThrowNonObjectInInstanceOfCheck, context); |
+ var_result.Bind(result); |
+ Goto(&return_result); |
+ } |
+ |
+ Bind(&return_true); |
+ var_result.Bind(TrueConstant()); |
+ Goto(&return_result); |
+ |
+ Bind(&return_false); |
+ var_result.Bind(FalseConstant()); |
+ Goto(&return_result); |
+ |
+ Bind(&return_result); |
+ return var_result.value(); |
} |
Node* CodeStubAssembler::NumberInc(Node* value) { |