[es6] Fix prototype chain walk for instanceof.
When walking up the prototype chain during OrdinaryHasInstance, we first check if the current prototype equals the expected one, and only afterwards check the current prototype against null. That's obviously wrong if we check something like Proxy, whose prototype is null. R=yangguo@chromium.org BUG=v8:5085 Review-Url: https://codereview.chromium.org/2041103007 Cr-Commit-Position: refs/heads/master@{#36840}
This commit is contained in:
parent
f2312019af
commit
eb1c9e2723
@ -1956,8 +1956,8 @@ Node* CodeStubAssembler::OrdinaryHasInstance(Node* context, Node* callable,
|
||||
|
||||
// Check the current {object} prototype.
|
||||
Node* object_prototype = LoadMapPrototype(object_map);
|
||||
GotoIf(WordEqual(object_prototype, callable_prototype), &return_true);
|
||||
GotoIf(WordEqual(object_prototype, NullConstant()), &return_false);
|
||||
GotoIf(WordEqual(object_prototype, callable_prototype), &return_true);
|
||||
|
||||
// Continue with the prototype.
|
||||
var_object_map.Bind(LoadMap(object_prototype));
|
||||
|
@ -1267,6 +1267,17 @@ Reduction JSTypedLowering::ReduceJSInstanceOf(Node* node) {
|
||||
simplified()->LoadField(AccessBuilder::ForMapPrototype()),
|
||||
loop_object_map, loop_effect, control);
|
||||
|
||||
// If not, check if object prototype is the null prototype.
|
||||
Node* null_proto =
|
||||
graph()->NewNode(simplified()->ReferenceEqual(r.right_type()),
|
||||
object_prototype, jsgraph()->NullConstant());
|
||||
Node* branch_null_proto = graph()->NewNode(
|
||||
common()->Branch(BranchHint::kFalse), null_proto, control);
|
||||
Node* if_null_proto = graph()->NewNode(common()->IfTrue(), branch_null_proto);
|
||||
Node* e_null_proto = effect;
|
||||
|
||||
control = graph()->NewNode(common()->IfFalse(), branch_null_proto);
|
||||
|
||||
// Check if object prototype is equal to function prototype.
|
||||
Node* eq_proto =
|
||||
graph()->NewNode(simplified()->ReferenceEqual(r.right_type()),
|
||||
@ -1278,16 +1289,6 @@ Reduction JSTypedLowering::ReduceJSInstanceOf(Node* node) {
|
||||
|
||||
control = graph()->NewNode(common()->IfFalse(), branch_eq_proto);
|
||||
|
||||
// If not, check if object prototype is the null prototype.
|
||||
Node* null_proto =
|
||||
graph()->NewNode(simplified()->ReferenceEqual(r.right_type()),
|
||||
object_prototype, jsgraph()->NullConstant());
|
||||
Node* branch_null_proto = graph()->NewNode(
|
||||
common()->Branch(BranchHint::kFalse), null_proto, control);
|
||||
Node* if_null_proto = graph()->NewNode(common()->IfTrue(), branch_null_proto);
|
||||
Node* e_null_proto = effect;
|
||||
|
||||
control = graph()->NewNode(common()->IfFalse(), branch_null_proto);
|
||||
Node* load_object_map = effect =
|
||||
graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
|
||||
object_prototype, effect, control);
|
||||
|
@ -2525,10 +2525,10 @@ void LCodeGen::DoHasInPrototypeChainAndBranch(
|
||||
DeoptimizeIf(eq, instr, Deoptimizer::kProxy);
|
||||
|
||||
__ ldr(object_prototype, FieldMemOperand(object_map, Map::kPrototypeOffset));
|
||||
__ cmp(object_prototype, prototype);
|
||||
EmitTrueBranch(instr, eq);
|
||||
__ CompareRoot(object_prototype, Heap::kNullValueRootIndex);
|
||||
EmitFalseBranch(instr, eq);
|
||||
__ cmp(object_prototype, prototype);
|
||||
EmitTrueBranch(instr, eq);
|
||||
__ ldr(object_map, FieldMemOperand(object_prototype, HeapObject::kMapOffset));
|
||||
__ b(&loop);
|
||||
}
|
||||
|
@ -2832,10 +2832,10 @@ void LCodeGen::DoHasInPrototypeChainAndBranch(
|
||||
DeoptimizeIf(eq, instr, Deoptimizer::kProxy);
|
||||
|
||||
__ Ldr(object_prototype, FieldMemOperand(object_map, Map::kPrototypeOffset));
|
||||
__ Cmp(object_prototype, prototype);
|
||||
__ B(eq, instr->TrueLabel(chunk_));
|
||||
__ CompareRoot(object_prototype, Heap::kNullValueRootIndex);
|
||||
__ B(eq, instr->FalseLabel(chunk_));
|
||||
__ Cmp(object_prototype, prototype);
|
||||
__ B(eq, instr->TrueLabel(chunk_));
|
||||
__ Ldr(object_map, FieldMemOperand(object_prototype, HeapObject::kMapOffset));
|
||||
__ B(&loop);
|
||||
}
|
||||
|
@ -2316,10 +2316,10 @@ void LCodeGen::DoHasInPrototypeChainAndBranch(
|
||||
DeoptimizeIf(equal, instr, Deoptimizer::kProxy);
|
||||
|
||||
__ mov(object_prototype, FieldOperand(object_map, Map::kPrototypeOffset));
|
||||
__ cmp(object_prototype, prototype);
|
||||
EmitTrueBranch(instr, equal);
|
||||
__ cmp(object_prototype, factory()->null_value());
|
||||
EmitFalseBranch(instr, equal);
|
||||
__ cmp(object_prototype, prototype);
|
||||
EmitTrueBranch(instr, equal);
|
||||
__ mov(object_map, FieldOperand(object_prototype, HeapObject::kMapOffset));
|
||||
__ jmp(&loop);
|
||||
}
|
||||
|
@ -2415,9 +2415,9 @@ void LCodeGen::DoHasInPrototypeChainAndBranch(
|
||||
Operand(JS_PROXY_TYPE));
|
||||
|
||||
__ lw(object_prototype, FieldMemOperand(object_map, Map::kPrototypeOffset));
|
||||
EmitTrueBranch(instr, eq, object_prototype, Operand(prototype));
|
||||
__ LoadRoot(at, Heap::kNullValueRootIndex);
|
||||
EmitFalseBranch(instr, eq, object_prototype, Operand(at));
|
||||
EmitTrueBranch(instr, eq, object_prototype, Operand(prototype));
|
||||
__ Branch(USE_DELAY_SLOT, &loop);
|
||||
__ lw(object_map, FieldMemOperand(object_prototype, HeapObject::kMapOffset));
|
||||
}
|
||||
|
@ -2535,9 +2535,9 @@ void LCodeGen::DoHasInPrototypeChainAndBranch(
|
||||
Operand(JS_PROXY_TYPE));
|
||||
|
||||
__ ld(object_prototype, FieldMemOperand(object_map, Map::kPrototypeOffset));
|
||||
EmitTrueBranch(instr, eq, object_prototype, Operand(prototype));
|
||||
__ LoadRoot(at, Heap::kNullValueRootIndex);
|
||||
EmitFalseBranch(instr, eq, object_prototype, Operand(at));
|
||||
EmitTrueBranch(instr, eq, object_prototype, Operand(prototype));
|
||||
__ Branch(&loop, USE_DELAY_SLOT);
|
||||
__ ld(object_map, FieldMemOperand(object_prototype,
|
||||
HeapObject::kMapOffset)); // In delay slot.
|
||||
|
@ -2589,10 +2589,10 @@ void LCodeGen::DoHasInPrototypeChainAndBranch(
|
||||
DeoptimizeIf(eq, instr, Deoptimizer::kProxy);
|
||||
__ LoadP(object_prototype,
|
||||
FieldMemOperand(object_map, Map::kPrototypeOffset));
|
||||
__ cmp(object_prototype, prototype);
|
||||
EmitTrueBranch(instr, eq);
|
||||
__ CompareRoot(object_prototype, Heap::kNullValueRootIndex);
|
||||
EmitFalseBranch(instr, eq);
|
||||
__ cmp(object_prototype, prototype);
|
||||
EmitTrueBranch(instr, eq);
|
||||
__ LoadP(object_map,
|
||||
FieldMemOperand(object_prototype, HeapObject::kMapOffset));
|
||||
__ b(&loop);
|
||||
|
@ -2567,10 +2567,10 @@ void LCodeGen::DoHasInPrototypeChainAndBranch(
|
||||
DeoptimizeIf(eq, instr, Deoptimizer::kProxy);
|
||||
__ LoadP(object_prototype,
|
||||
FieldMemOperand(object_map, Map::kPrototypeOffset));
|
||||
__ CmpP(object_prototype, prototype);
|
||||
EmitTrueBranch(instr, eq);
|
||||
__ CompareRoot(object_prototype, Heap::kNullValueRootIndex);
|
||||
EmitFalseBranch(instr, eq);
|
||||
__ CmpP(object_prototype, prototype);
|
||||
EmitTrueBranch(instr, eq);
|
||||
__ LoadP(object_map,
|
||||
FieldMemOperand(object_prototype, HeapObject::kMapOffset));
|
||||
__ b(&loop);
|
||||
|
@ -2456,7 +2456,6 @@ void LCodeGen::DoHasInPrototypeChainAndBranch(
|
||||
Label loop;
|
||||
__ bind(&loop);
|
||||
|
||||
|
||||
// Deoptimize if the object needs to be access checked.
|
||||
__ testb(FieldOperand(object_map, Map::kBitFieldOffset),
|
||||
Immediate(1 << Map::kIsAccessCheckNeeded));
|
||||
@ -2466,10 +2465,10 @@ void LCodeGen::DoHasInPrototypeChainAndBranch(
|
||||
DeoptimizeIf(equal, instr, Deoptimizer::kProxy);
|
||||
|
||||
__ movp(object_prototype, FieldOperand(object_map, Map::kPrototypeOffset));
|
||||
__ cmpp(object_prototype, prototype);
|
||||
EmitTrueBranch(instr, equal);
|
||||
__ CompareRoot(object_prototype, Heap::kNullValueRootIndex);
|
||||
EmitFalseBranch(instr, equal);
|
||||
__ cmpp(object_prototype, prototype);
|
||||
EmitTrueBranch(instr, equal);
|
||||
__ movp(object_map, FieldOperand(object_prototype, HeapObject::kMapOffset));
|
||||
__ jmp(&loop);
|
||||
}
|
||||
|
@ -2602,10 +2602,10 @@ void LCodeGen::DoHasInPrototypeChainAndBranch(
|
||||
DeoptimizeIf(equal, instr, Deoptimizer::kProxy);
|
||||
|
||||
__ mov(object_prototype, FieldOperand(object_map, Map::kPrototypeOffset));
|
||||
__ cmp(object_prototype, prototype);
|
||||
EmitTrueBranch(instr, equal);
|
||||
__ cmp(object_prototype, factory()->null_value());
|
||||
EmitFalseBranch(instr, equal);
|
||||
__ cmp(object_prototype, prototype);
|
||||
EmitTrueBranch(instr, equal);
|
||||
__ mov(object_map, FieldOperand(object_prototype, HeapObject::kMapOffset));
|
||||
__ jmp(&loop);
|
||||
}
|
||||
|
14
test/mjsunit/regress/regress-5085.js
Normal file
14
test/mjsunit/regress/regress-5085.js
Normal file
@ -0,0 +1,14 @@
|
||||
// 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.
|
||||
|
||||
// Flags: --allow-natives-syntax
|
||||
|
||||
function foo(x) {
|
||||
return x instanceof Proxy;
|
||||
}
|
||||
|
||||
assertFalse(foo({}));
|
||||
assertFalse(foo({}));
|
||||
%OptimizeFunctionOnNextCall(foo);
|
||||
assertFalse(foo({}));
|
Loading…
Reference in New Issue
Block a user