Commit 0461a2ac authored by Sathya Gunasekaran's avatar Sathya Gunasekaran Committed by Commit Bot

[ic] Fix private field lookup in generic case

Previously, we didn't have access checks for the megamorphic case cause
we'd never get to this IC state for a receiver that doesn't hold the
right private field. But now with lazy feedback allocation we share
the megamorphic case code paths for the uninitialized loads as well,
which exposes our bug.

Bug: chromium:982702
Change-Id: I419406bcfc52575260a85d05520c1662735e15f8
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1697256Reviewed-by: 's avatarMythri Alle <mythria@chromium.org>
Reviewed-by: 's avatarGeorg Neis <neis@chromium.org>
Reviewed-by: 's avatarToon Verwaest <verwaest@chromium.org>
Commit-Queue: Sathya Gunasekaran <gsathya@chromium.org>
Cr-Commit-Position: refs/heads/master@{#62668}
parent b0abfb4f
......@@ -6596,6 +6596,11 @@ TNode<BoolT> CodeStubAssembler::IsPrivateSymbol(
[=] { return Int32FalseConstant(); });
}
TNode<BoolT> CodeStubAssembler::IsPrivateName(SloppyTNode<Symbol> symbol) {
TNode<Uint32T> flags = LoadObjectField<Uint32T>(symbol, Symbol::kFlagsOffset);
return IsSetWord32<Symbol::IsPrivateNameBit>(flags);
}
TNode<BoolT> CodeStubAssembler::IsNativeContext(
SloppyTNode<HeapObject> object) {
return WordEqual(LoadMap(object), LoadRoot(RootIndex::kNativeContextMap));
......
......@@ -2275,6 +2275,7 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
TNode<BoolT> IsOneByteStringInstanceType(SloppyTNode<Int32T> instance_type);
TNode<BoolT> IsPrimitiveInstanceType(SloppyTNode<Int32T> instance_type);
TNode<BoolT> IsPrivateSymbol(SloppyTNode<HeapObject> object);
TNode<BoolT> IsPrivateName(SloppyTNode<Symbol> symbol);
TNode<BoolT> IsPromiseCapability(SloppyTNode<HeapObject> object);
TNode<BoolT> IsPropertyArray(SloppyTNode<HeapObject> object);
TNode<BoolT> IsPropertyCell(SloppyTNode<HeapObject> object);
......
......@@ -2283,14 +2283,14 @@ void AccessorAssembler::GenericPropertyLoad(Node* receiver, Node* receiver_map,
{
VARIABLE(var_holder_map, MachineRepresentation::kTagged);
VARIABLE(var_holder_instance_type, MachineRepresentation::kWord32);
Label return_undefined(this);
Label return_undefined(this), is_private_symbol(this);
Variable* merged_variables[] = {&var_holder_map, &var_holder_instance_type};
Label loop(this, arraysize(merged_variables), merged_variables);
var_holder_map.Bind(receiver_map);
var_holder_instance_type.Bind(instance_type);
// Private symbols must not be looked up on the prototype chain.
GotoIf(IsPrivateSymbol(p->name()), &return_undefined);
GotoIf(IsPrivateSymbol(p->name()), &is_private_symbol);
Goto(&loop);
BIND(&loop);
{
......@@ -2321,6 +2321,16 @@ void AccessorAssembler::GenericPropertyLoad(Node* receiver, Node* receiver_map,
Return(var_value.value());
}
BIND(&is_private_symbol);
{
CSA_ASSERT(this, IsPrivateSymbol(p->name()));
// For private names that don't exist on the receiver, we bail
// to the runtime to throw. For private symbols, we just return
// undefined.
Branch(IsPrivateName(p->name()), slow, &return_undefined);
}
BIND(&return_undefined);
Return(UndefinedConstant());
}
......
......@@ -868,11 +868,19 @@ void KeyedStoreGenericAssembler::EmitGenericPropertyStore(
BIND(&not_found);
{
CheckForAssociatedProtector(p->name(), slow);
Label extensible(this);
Label extensible(this), is_private_symbol(this);
Node* bitfield3 = LoadMapBitField3(receiver_map);
GotoIf(IsPrivateSymbol(p->name()), &extensible);
GotoIf(IsPrivateSymbol(p->name()), &is_private_symbol);
Branch(IsSetWord32<Map::IsExtensibleBit>(bitfield3), &extensible, slow);
BIND(&is_private_symbol);
{
CSA_ASSERT(this, IsPrivateSymbol(p->name()));
// For private names, we miss to the runtime which will throw.
// For private symbols, we extend and store an own property.
Branch(IsPrivateName(p->name()), slow, &extensible);
}
BIND(&extensible);
if (ShouldCheckPrototype()) {
DCHECK(ShouldCallSetter());
......
// 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.
class A {
static #foo = 3;
constructor() {
print(A.prototype.#foo);
}
}
assertThrows(() => new A(), TypeError);
class B {
static #foo = 3;
constructor() {
B.prototype.#foo = 2;
}
}
assertThrows(() => new B(), TypeError);
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