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(
// if (!IS_CALLABLE(C)) {
// throw MakeTypeError(kCalledNonCallableInstanceOf);
// }
// handler_result = %ordinary_has_instance(C, O);
// handler_result = %_GetOrdinaryHasInstance()
// handler_result = %_Call(handler_result, C, O);
// } else {
// handler_result = !!(%_Call(handler_result, C, O));
// }
......@@ -6148,7 +6149,7 @@ Expression* ParserTraits::RewriteInstanceof(Expression* lhs, Expression* rhs,
factory->NewCallRuntime(Runtime::kInlineIsJSReceiver, args, nopos);
Expression* call =
NewThrowTypeError(MessageTemplate::kNonObjectInInstanceOfCheck,
avfactory->empty_string(), nopos);
avfactory->empty_string(), pos);
Statement* throw_call = factory->NewExpressionStatement(call, nopos);
validate_C =
......@@ -6176,7 +6177,8 @@ Expression* ParserTraits::RewriteInstanceof(Expression* lhs, Expression* rhs,
// if (!IS_CALLABLE(C)) {
// throw MakeTypeError(kCalledNonCallableInstanceOf);
// }
// result = %ordinary_has_instance(C, O);
// handler_result = %_GetOrdinaryHasInstance()
// handler_result = %_Call(handler_result, C, O);
// } else {
// handler_result = !!%_Call(handler_result, C, O);
// }
......@@ -6186,17 +6188,29 @@ Expression* ParserTraits::RewriteInstanceof(Expression* lhs, Expression* rhs,
Token::EQ_STRICT, factory->NewVariableProxy(var_handler_result),
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 =
NewThrowTypeError(MessageTemplate::kCalledNonCallableInstanceOf,
avfactory->empty_string(), nopos);
avfactory->empty_string(), pos);
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_O), zone);
CallRuntime* call = factory->NewCallRuntime(
Context::ORDINARY_HAS_INSTANCE_INDEX, args, pos);
Expression* call =
factory->NewCallRuntime(Runtime::kInlineCall, args, pos);
Expression* result_proxy = factory->NewVariableProxy(var_handler_result);
Expression* assignment =
factory->NewAssignment(Token::ASSIGN, result_proxy, call, nopos);
......@@ -6204,6 +6218,7 @@ Expression* ParserTraits::RewriteInstanceof(Expression* lhs, Expression* rhs,
factory->NewExpressionStatement(assignment, nopos);
then_side->statements()->Add(validate_C, zone);
then_side->statements()->Add(assignment_get_handler, zone);
then_side->statements()->Add(assignment_return, zone);
}
......
......@@ -468,6 +468,12 @@ RUNTIME_FUNCTION(Runtime_IncrementUseCounter) {
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) {
HandleScope scope(isolate);
......
......@@ -276,7 +276,6 @@ namespace internal {
#define FOR_EACH_INTRINSIC_I18N(F)
#endif
#define FOR_EACH_INTRINSIC_INTERNAL(F) \
F(CheckIsBootstrapping, 0, 1) \
F(ExportFromRuntime, 1, 1) \
......@@ -321,9 +320,9 @@ namespace internal {
F(ThrowCalledNonCallable, 1, 1) \
F(CreateListFromArrayLike, 1, 1) \
F(IncrementUseCounter, 1, 1) \
F(GetOrdinaryHasInstance, 0, 1) \
F(GetAndResetRuntimeCallStats, 0, 1)
#define FOR_EACH_INTRINSIC_JSON(F) \
F(QuoteJSONString, 1, 1) \
F(BasicJSONStringify, 1, 1) \
......
......@@ -560,6 +560,11 @@ TEST(CallRuntime) {
}
TEST(IfConditions) {
if (FLAG_harmony_instanceof) {
// TODO(mvstanton): when ES6 instanceof ships, regenerate the bytecode
// expectations and remove this flag check.
return;
}
InitializedIgnitionHandleScope scope;
BytecodeExpectationsPrinter printer(CcTest::isolate(),
ConstantPoolType::kNumber);
......
......@@ -1725,10 +1725,14 @@ TEST(NeStrict) {
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(
"function bar() { return (0 instanceof 0)|0; }\n"
"function foo() { bar(); }",
"asm: line 39: illegal comparison operator\n");
errorMsg);
}
......
......@@ -317,6 +317,9 @@ function instanceof_check2(type) {
}
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(realmBArray);
......@@ -327,6 +330,10 @@ instanceof_check(realmBArray);
// It'll go (uninit->realmBArray) then (realmBArray->megamorphic). Recognize
// that state "Array" implies an AllocationSite is present, and code is
// 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(Array);
......
......@@ -1018,7 +1018,19 @@ TestHasOwnThrow({
var o4 = Object.create(o2)
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 f1 = new Proxy(function() {}, handler(o1))
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