Commit d47a4063 authored by mvstanton's avatar mvstanton Committed by Commit bot

ES6: Object.setPrototypeOf(func, null) breaks instanceof

The way desugared instanceof called OrdinaryHasInstance if the lookup of
@@hasInstance failed was incorrect.

BUG=v8:4774
LOG=N

Review URL: https://codereview.chromium.org/1812793002

Cr-Commit-Position: refs/heads/master@{#34855}
parent 122862f6
...@@ -6103,7 +6103,8 @@ Expression* ParserTraits::RewriteYieldStar( ...@@ -6103,7 +6103,8 @@ Expression* ParserTraits::RewriteYieldStar(
// if (!IS_CALLABLE(C)) { // if (!IS_CALLABLE(C)) {
// throw MakeTypeError(kCalledNonCallableInstanceOf); // throw MakeTypeError(kCalledNonCallableInstanceOf);
// } // }
// handler_result = %ordinary_has_instance(C, O); // handler_result = %_GetOrdinaryHasInstance()
// handler_result = %_Call(handler_result, C, O);
// } else { // } else {
// handler_result = !!(%_Call(handler_result, C, O)); // handler_result = !!(%_Call(handler_result, C, O));
// } // }
...@@ -6148,7 +6149,7 @@ Expression* ParserTraits::RewriteInstanceof(Expression* lhs, Expression* rhs, ...@@ -6148,7 +6149,7 @@ Expression* ParserTraits::RewriteInstanceof(Expression* lhs, Expression* rhs,
factory->NewCallRuntime(Runtime::kInlineIsJSReceiver, args, nopos); factory->NewCallRuntime(Runtime::kInlineIsJSReceiver, args, nopos);
Expression* call = Expression* call =
NewThrowTypeError(MessageTemplate::kNonObjectInInstanceOfCheck, NewThrowTypeError(MessageTemplate::kNonObjectInInstanceOfCheck,
avfactory->empty_string(), nopos); avfactory->empty_string(), pos);
Statement* throw_call = factory->NewExpressionStatement(call, nopos); Statement* throw_call = factory->NewExpressionStatement(call, nopos);
validate_C = validate_C =
...@@ -6176,7 +6177,8 @@ Expression* ParserTraits::RewriteInstanceof(Expression* lhs, Expression* rhs, ...@@ -6176,7 +6177,8 @@ Expression* ParserTraits::RewriteInstanceof(Expression* lhs, Expression* rhs,
// if (!IS_CALLABLE(C)) { // if (!IS_CALLABLE(C)) {
// throw MakeTypeError(kCalledNonCallableInstanceOf); // throw MakeTypeError(kCalledNonCallableInstanceOf);
// } // }
// result = %ordinary_has_instance(C, O); // handler_result = %_GetOrdinaryHasInstance()
// handler_result = %_Call(handler_result, C, O);
// } else { // } else {
// handler_result = !!%_Call(handler_result, C, O); // handler_result = !!%_Call(handler_result, C, O);
// } // }
...@@ -6186,17 +6188,29 @@ Expression* ParserTraits::RewriteInstanceof(Expression* lhs, Expression* rhs, ...@@ -6186,17 +6188,29 @@ Expression* ParserTraits::RewriteInstanceof(Expression* lhs, Expression* rhs,
Token::EQ_STRICT, factory->NewVariableProxy(var_handler_result), Token::EQ_STRICT, factory->NewVariableProxy(var_handler_result),
factory->NewUndefinedLiteral(nopos), nopos); factory->NewUndefinedLiteral(nopos), nopos);
Block* then_side = factory->NewBlock(nullptr, 2, false, nopos); Block* then_side = factory->NewBlock(nullptr, 3, false, nopos);
{ {
Expression* throw_expr = Expression* throw_expr =
NewThrowTypeError(MessageTemplate::kCalledNonCallableInstanceOf, NewThrowTypeError(MessageTemplate::kCalledNonCallableInstanceOf,
avfactory->empty_string(), nopos); avfactory->empty_string(), pos);
Statement* validate_C = CheckCallable(var_C, throw_expr); Statement* validate_C = CheckCallable(var_C, throw_expr);
ZoneList<Expression*>* args = new (zone) ZoneList<Expression*>(2, zone);
ZoneList<Expression*>* empty_args =
new (zone) ZoneList<Expression*>(0, zone);
Expression* ordinary_has_instance = factory->NewCallRuntime(
Runtime::kInlineGetOrdinaryHasInstance, empty_args, pos);
Expression* handler_proxy = factory->NewVariableProxy(var_handler_result);
Expression* assignment_handler = factory->NewAssignment(
Token::ASSIGN, handler_proxy, ordinary_has_instance, nopos);
Statement* assignment_get_handler =
factory->NewExpressionStatement(assignment_handler, nopos);
ZoneList<Expression*>* args = new (zone) ZoneList<Expression*>(3, zone);
args->Add(factory->NewVariableProxy(var_handler_result), zone);
args->Add(factory->NewVariableProxy(var_C), zone); args->Add(factory->NewVariableProxy(var_C), zone);
args->Add(factory->NewVariableProxy(var_O), zone); args->Add(factory->NewVariableProxy(var_O), zone);
CallRuntime* call = factory->NewCallRuntime( Expression* call =
Context::ORDINARY_HAS_INSTANCE_INDEX, args, pos); factory->NewCallRuntime(Runtime::kInlineCall, args, pos);
Expression* result_proxy = factory->NewVariableProxy(var_handler_result); Expression* result_proxy = factory->NewVariableProxy(var_handler_result);
Expression* assignment = Expression* assignment =
factory->NewAssignment(Token::ASSIGN, result_proxy, call, nopos); factory->NewAssignment(Token::ASSIGN, result_proxy, call, nopos);
...@@ -6204,6 +6218,7 @@ Expression* ParserTraits::RewriteInstanceof(Expression* lhs, Expression* rhs, ...@@ -6204,6 +6218,7 @@ Expression* ParserTraits::RewriteInstanceof(Expression* lhs, Expression* rhs,
factory->NewExpressionStatement(assignment, nopos); factory->NewExpressionStatement(assignment, nopos);
then_side->statements()->Add(validate_C, zone); then_side->statements()->Add(validate_C, zone);
then_side->statements()->Add(assignment_get_handler, zone);
then_side->statements()->Add(assignment_return, zone); then_side->statements()->Add(assignment_return, zone);
} }
......
...@@ -468,6 +468,12 @@ RUNTIME_FUNCTION(Runtime_IncrementUseCounter) { ...@@ -468,6 +468,12 @@ RUNTIME_FUNCTION(Runtime_IncrementUseCounter) {
return isolate->heap()->undefined_value(); return isolate->heap()->undefined_value();
} }
RUNTIME_FUNCTION(Runtime_GetOrdinaryHasInstance) {
HandleScope scope(isolate);
DCHECK_EQ(0, args.length());
return isolate->native_context()->ordinary_has_instance();
}
RUNTIME_FUNCTION(Runtime_GetAndResetRuntimeCallStats) { RUNTIME_FUNCTION(Runtime_GetAndResetRuntimeCallStats) {
HandleScope scope(isolate); HandleScope scope(isolate);
......
...@@ -276,7 +276,6 @@ namespace internal { ...@@ -276,7 +276,6 @@ namespace internal {
#define FOR_EACH_INTRINSIC_I18N(F) #define FOR_EACH_INTRINSIC_I18N(F)
#endif #endif
#define FOR_EACH_INTRINSIC_INTERNAL(F) \ #define FOR_EACH_INTRINSIC_INTERNAL(F) \
F(CheckIsBootstrapping, 0, 1) \ F(CheckIsBootstrapping, 0, 1) \
F(ExportFromRuntime, 1, 1) \ F(ExportFromRuntime, 1, 1) \
...@@ -321,9 +320,9 @@ namespace internal { ...@@ -321,9 +320,9 @@ namespace internal {
F(ThrowCalledNonCallable, 1, 1) \ F(ThrowCalledNonCallable, 1, 1) \
F(CreateListFromArrayLike, 1, 1) \ F(CreateListFromArrayLike, 1, 1) \
F(IncrementUseCounter, 1, 1) \ F(IncrementUseCounter, 1, 1) \
F(GetOrdinaryHasInstance, 0, 1) \
F(GetAndResetRuntimeCallStats, 0, 1) F(GetAndResetRuntimeCallStats, 0, 1)
#define FOR_EACH_INTRINSIC_JSON(F) \ #define FOR_EACH_INTRINSIC_JSON(F) \
F(QuoteJSONString, 1, 1) \ F(QuoteJSONString, 1, 1) \
F(BasicJSONStringify, 1, 1) \ F(BasicJSONStringify, 1, 1) \
......
...@@ -560,6 +560,11 @@ TEST(CallRuntime) { ...@@ -560,6 +560,11 @@ TEST(CallRuntime) {
} }
TEST(IfConditions) { TEST(IfConditions) {
if (FLAG_harmony_instanceof) {
// TODO(mvstanton): when ES6 instanceof ships, regenerate the bytecode
// expectations and remove this flag check.
return;
}
InitializedIgnitionHandleScope scope; InitializedIgnitionHandleScope scope;
BytecodeExpectationsPrinter printer(CcTest::isolate(), BytecodeExpectationsPrinter printer(CcTest::isolate(),
ConstantPoolType::kNumber); ConstantPoolType::kNumber);
......
...@@ -1725,10 +1725,14 @@ TEST(NeStrict) { ...@@ -1725,10 +1725,14 @@ TEST(NeStrict) {
TEST(InstanceOf) { TEST(InstanceOf) {
const char* errorMsg = FLAG_harmony_instanceof
? "asm: line 0: do-expression encountered\n"
: "asm: line 39: illegal comparison operator\n";
CHECK_FUNC_ERROR( CHECK_FUNC_ERROR(
"function bar() { return (0 instanceof 0)|0; }\n" "function bar() { return (0 instanceof 0)|0; }\n"
"function foo() { bar(); }", "function foo() { bar(); }",
"asm: line 39: illegal comparison operator\n"); errorMsg);
} }
......
...@@ -317,6 +317,9 @@ function instanceof_check2(type) { ...@@ -317,6 +317,9 @@ function instanceof_check2(type) {
} }
var realmBArray = Realm.eval(realmB, "Array"); var realmBArray = Realm.eval(realmB, "Array");
// Two calls with Array because ES6 instanceof desugars into a load of Array,
// and load has a premonomorphic state.
instanceof_check(Array);
instanceof_check(Array); instanceof_check(Array);
instanceof_check(realmBArray); instanceof_check(realmBArray);
...@@ -327,6 +330,10 @@ instanceof_check(realmBArray); ...@@ -327,6 +330,10 @@ instanceof_check(realmBArray);
// It'll go (uninit->realmBArray) then (realmBArray->megamorphic). Recognize // It'll go (uninit->realmBArray) then (realmBArray->megamorphic). Recognize
// that state "Array" implies an AllocationSite is present, and code is // that state "Array" implies an AllocationSite is present, and code is
// configured to use it. // configured to use it.
// Two calls with realmBArray because ES6 instanceof desugars into a load of
// realmBArray, and load has a premonomorphic state.
instanceof_check2(realmBArray);
instanceof_check2(realmBArray); instanceof_check2(realmBArray);
instanceof_check2(Array); instanceof_check2(Array);
......
...@@ -1018,7 +1018,19 @@ TestHasOwnThrow({ ...@@ -1018,7 +1018,19 @@ TestHasOwnThrow({
var o4 = Object.create(o2) var o4 = Object.create(o2)
var o5 = Object.create(o3) var o5 = Object.create(o3)
function handler(o) { return {get: function() { return o } } } function handler(o) {
return {
get: function(r, p) {
// We want to test prototype lookup, so ensure the proxy
// offers OrdinaryHasInstance behavior.
if (p === Symbol.hasInstance) {
return undefined;
}
return o;
}
}
}
var f0 = new Proxy(function() {}, handler(o0)) var f0 = new Proxy(function() {}, handler(o0))
var f1 = new Proxy(function() {}, handler(o1)) var f1 = new Proxy(function() {}, handler(o1))
var f2 = new Proxy(function() {}, handler(o2)) var f2 = new Proxy(function() {}, handler(o2))
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment