Commit b9076b49 authored by Georg Neis's avatar Georg Neis Committed by Commit Bot

[csa] Fix instanceof for LHS with proxy in prototype chain

If the LHS has a proxy in its prototype chain (or is itself one), then
the LHS's [prototype_or_initial_map] being the hole does not necessarily
imply that the result is false.

This CL also adds support for --force-slow-path, which would have been
useful in finding this bug earlier.

Bug: v8:9036
Change-Id: I6f5134d6ce18f9f14549ced3d33527f54ce9bcb2
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1539497
Auto-Submit: Georg Neis <neis@chromium.org>
Reviewed-by: 's avatarBenedikt Meurer <bmeurer@chromium.org>
Commit-Queue: Georg Neis <neis@chromium.org>
Cr-Commit-Position: refs/heads/master@{#60476}
parent 227f8e99
......@@ -9923,6 +9923,8 @@ Node* CodeStubAssembler::OrdinaryHasInstance(Node* context, Node* callable,
VARIABLE(var_result, MachineRepresentation::kTagged);
Label return_runtime(this, Label::kDeferred), return_result(this);
GotoIfForceSlowPath(&return_runtime);
// Goto runtime if {object} is a Smi.
GotoIf(TaggedIsSmi(object), &return_runtime);
......@@ -9944,26 +9946,28 @@ Node* CodeStubAssembler::OrdinaryHasInstance(Node* context, Node* callable,
Node* callable_prototype =
LoadObjectField(callable, JSFunction::kPrototypeOrInitialMapOffset);
{
Label callable_prototype_valid(this);
Label no_initial_map(this), walk_prototype_chain(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(InstanceTypeEqual(callable_prototype_instance_type, MAP_TYPE),
&callable_prototype_valid);
// Resolve the "prototype" if the {callable} has an initial map.
GotoIfNot(IsMap(callable_prototype), &no_initial_map);
var_callable_prototype.Bind(
LoadObjectField(callable_prototype, Map::kPrototypeOffset));
Goto(&callable_prototype_valid);
BIND(&callable_prototype_valid);
Goto(&walk_prototype_chain);
BIND(&no_initial_map);
// {callable_prototype} is the hole if the "prototype" property hasn't been
// requested so far.
Branch(WordEqual(callable_prototype, TheHoleConstant()), &return_runtime,
&walk_prototype_chain);
BIND(&walk_prototype_chain);
callable_prototype = var_callable_prototype.value();
}
// Loop through the prototype chain looking for the {callable} prototype.
CSA_ASSERT(this, IsJSReceiver(callable_prototype));
var_result.Bind(HasInPrototypeChain(context, object, callable_prototype));
Goto(&return_result);
......
// Copyright 2019 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.
function C() {};
const p = new Proxy({}, { getPrototypeOf() { return C.prototype } });
assertTrue(p instanceof C);
assertTrue(p instanceof C);
// Copyright 2019 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.
function C() {};
const p = new Proxy({}, { getPrototypeOf() { return C.prototype } });
assertTrue(C[Symbol.hasInstance](p));
assertTrue(C[Symbol.hasInstance](p));
// Copyright 2019 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.
function C() {};
const p = new Proxy({}, { getPrototypeOf() { return C.prototype } });
const o = Object.create(p);
assertTrue(o instanceof C);
assertTrue(o instanceof C);
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