Commit 0ba88594 authored by Igor Sheludko's avatar Igor Sheludko Committed by V8 LUCI CQ

[ic] Make DefineOwnIC throw if the private symbol already exists

Drive-by:
* don't create proto handlers for DefineOwnIC and StoreOwnIC,
* make sure that none of the DefineOwnIC and StoreOwnIC handlers are
  leaked into StoreIC's megamorphic stub cache.

Bug: v8:9888, chromium:1259950
Change-Id: I9db538e6ed14bc578aa80df037ffebd9e8c3c649
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3250641
Commit-Queue: Igor Sheludko <ishell@chromium.org>
Reviewed-by: 's avatarShu-yu Guo <syg@chromium.org>
Cr-Commit-Position: refs/heads/main@{#77632}
parent 43253f7a
...@@ -714,6 +714,8 @@ void Symbol::SymbolPrint(std::ostream& os) { ...@@ -714,6 +714,8 @@ void Symbol::SymbolPrint(std::ostream& os) {
os << " (" << PrivateSymbolToName() << ")"; os << " (" << PrivateSymbolToName() << ")";
} }
os << "\n - private: " << is_private(); os << "\n - private: " << is_private();
os << "\n - private_name: " << is_private_name();
os << "\n - private_brand: " << is_private_brand();
os << "\n"; os << "\n";
} }
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include "src/ic/stub-cache.h" #include "src/ic/stub-cache.h"
#include "src/logging/counters.h" #include "src/logging/counters.h"
#include "src/objects/cell.h" #include "src/objects/cell.h"
#include "src/objects/feedback-vector.h"
#include "src/objects/foreign.h" #include "src/objects/foreign.h"
#include "src/objects/heap-number.h" #include "src/objects/heap-number.h"
#include "src/objects/megadom-handler.h" #include "src/objects/megadom-handler.h"
...@@ -1223,6 +1224,10 @@ void AccessorAssembler::HandleStoreICHandlerCase( ...@@ -1223,6 +1224,10 @@ void AccessorAssembler::HandleStoreICHandlerCase(
properties, CAST(p->name()), &dictionary_found, &var_name_index, miss); properties, CAST(p->name()), &dictionary_found, &var_name_index, miss);
BIND(&dictionary_found); BIND(&dictionary_found);
{ {
if (p->IsDefineOwn()) {
// Take slow path to throw if a private name already exists.
GotoIf(IsPrivateSymbol(CAST(p->name())), &if_slow);
}
Label if_constant(this), done(this); Label if_constant(this), done(this);
TNode<Uint32T> details = TNode<Uint32T> details =
LoadDetailsByKeyIndex(properties, var_name_index.value()); LoadDetailsByKeyIndex(properties, var_name_index.value());
...@@ -1340,6 +1345,9 @@ void AccessorAssembler::HandleStoreICHandlerCase( ...@@ -1340,6 +1345,9 @@ void AccessorAssembler::HandleStoreICHandlerCase(
{ {
TNode<PropertyCell> property_cell = CAST(map_or_property_cell); TNode<PropertyCell> property_cell = CAST(map_or_property_cell);
ExitPoint direct_exit(this); ExitPoint direct_exit(this);
// StoreGlobalIC_PropertyCellCase doesn't properly handle private names
// but they are not expected here anyway.
CSA_DCHECK(this, BoolConstant(!p->IsDefineOwn()));
StoreGlobalIC_PropertyCellCase(property_cell, p->value(), &direct_exit, StoreGlobalIC_PropertyCellCase(property_cell, p->value(), &direct_exit,
miss); miss);
} }
...@@ -1347,7 +1355,9 @@ void AccessorAssembler::HandleStoreICHandlerCase( ...@@ -1347,7 +1355,9 @@ void AccessorAssembler::HandleStoreICHandlerCase(
{ {
TNode<Map> map = CAST(map_or_property_cell); TNode<Map> map = CAST(map_or_property_cell);
HandleStoreICTransitionMapHandlerCase(p, map, miss, HandleStoreICTransitionMapHandlerCase(p, map, miss,
kCheckPrototypeValidity); p->IsAnyStoreOwn()
? kDontCheckPrototypeValidity
: kCheckPrototypeValidity);
Return(p->value()); Return(p->value());
} }
} }
...@@ -1771,6 +1781,11 @@ void AccessorAssembler::HandleStoreICProtoHandler( ...@@ -1771,6 +1781,11 @@ void AccessorAssembler::HandleStoreICProtoHandler(
if (ic_mode == ICMode::kGlobalIC) { if (ic_mode == ICMode::kGlobalIC) {
TailCallRuntime(Runtime::kStoreGlobalIC_Slow, p->context(), p->value(), TailCallRuntime(Runtime::kStoreGlobalIC_Slow, p->context(), p->value(),
p->slot(), p->vector(), p->receiver(), p->name()); p->slot(), p->vector(), p->receiver(), p->name());
} else if (p->IsAnyStoreOwn()) {
// DefineOwnIC and StoreOwnIC shouldn't be using slow proto handlers,
// otherwise proper slow function must be called.
CSA_DCHECK(this, BoolConstant(!p->IsAnyStoreOwn()));
Unreachable();
} else { } else {
TailCallRuntime(Runtime::kKeyedStoreIC_Slow, p->context(), p->value(), TailCallRuntime(Runtime::kKeyedStoreIC_Slow, p->context(), p->value(),
p->receiver(), p->name()); p->receiver(), p->name());
...@@ -1850,6 +1865,9 @@ void AccessorAssembler::HandleStoreICProtoHandler( ...@@ -1850,6 +1865,9 @@ void AccessorAssembler::HandleStoreICProtoHandler(
BIND(&if_store_global_proxy); BIND(&if_store_global_proxy);
{ {
ExitPoint direct_exit(this); ExitPoint direct_exit(this);
// StoreGlobalIC_PropertyCellCase doesn't properly handle private names
// but they are not expected here anyway.
CSA_DCHECK(this, BoolConstant(!p->IsDefineOwn()));
StoreGlobalIC_PropertyCellCase(CAST(holder), p->value(), &direct_exit, StoreGlobalIC_PropertyCellCase(CAST(holder), p->value(), &direct_exit,
miss); miss);
} }
......
...@@ -229,6 +229,7 @@ class V8_EXPORT_PRIVATE AccessorAssembler : public CodeStubAssembler { ...@@ -229,6 +229,7 @@ class V8_EXPORT_PRIVATE AccessorAssembler : public CodeStubAssembler {
bool IsStoreOwn() const { return mode_ == StoreICMode::kStoreOwn; } bool IsStoreOwn() const { return mode_ == StoreICMode::kStoreOwn; }
bool IsDefineOwn() const { return mode_ == StoreICMode::kDefineOwn; } bool IsDefineOwn() const { return mode_ == StoreICMode::kDefineOwn; }
bool IsAnyStoreOwn() const { return IsStoreOwn() || IsDefineOwn(); }
private: private:
TNode<Context> context_; TNode<Context> context_;
...@@ -247,6 +248,7 @@ class V8_EXPORT_PRIVATE AccessorAssembler : public CodeStubAssembler { ...@@ -247,6 +248,7 @@ class V8_EXPORT_PRIVATE AccessorAssembler : public CodeStubAssembler {
const StoreICParameters* p, TNode<MaybeObject> handler, Label* miss, const StoreICParameters* p, TNode<MaybeObject> handler, Label* miss,
ICMode ic_mode, ElementSupport support_elements = kOnlyProperties); ICMode ic_mode, ElementSupport support_elements = kOnlyProperties);
enum StoreTransitionMapFlags { enum StoreTransitionMapFlags {
kDontCheckPrototypeValidity = 0,
kCheckPrototypeValidity = 1 << 0, kCheckPrototypeValidity = 1 << 0,
kValidateTransitionHandler = 1 << 1, kValidateTransitionHandler = 1 << 1,
kStoreTransitionMapFlagsMask = kStoreTransitionMapFlagsMask =
......
...@@ -219,6 +219,40 @@ Handle<Object> StoreHandler::StoreElementTransition( ...@@ -219,6 +219,40 @@ Handle<Object> StoreHandler::StoreElementTransition(
return handler; return handler;
} }
// static
MaybeObjectHandle StoreHandler::StoreOwnTransition(Isolate* isolate,
Handle<Map> transition_map) {
bool is_dictionary_map = transition_map->is_dictionary_map();
#ifdef DEBUG
if (!is_dictionary_map) {
InternalIndex descriptor = transition_map->LastAdded();
Handle<DescriptorArray> descriptors(
transition_map->instance_descriptors(isolate), isolate);
PropertyDetails details = descriptors->GetDetails(descriptor);
if (descriptors->GetKey(descriptor).IsPrivate()) {
DCHECK_EQ(DONT_ENUM, details.attributes());
} else {
DCHECK_EQ(NONE, details.attributes());
}
Representation representation = details.representation();
DCHECK(!representation.IsNone());
}
#endif
// Declarative handlers don't support access checks.
DCHECK(!transition_map->is_access_check_needed());
// StoreOwnTransition does not involve any prototype checks.
if (is_dictionary_map) {
DCHECK(!transition_map->IsJSGlobalObjectMap());
int config = KindBits::encode(Kind::kNormal);
return MaybeObjectHandle(Smi::FromInt(config), isolate);
} else {
return MaybeObjectHandle::Weak(transition_map);
}
}
// static
MaybeObjectHandle StoreHandler::StoreTransition(Isolate* isolate, MaybeObjectHandle StoreHandler::StoreTransition(Isolate* isolate,
Handle<Map> transition_map) { Handle<Map> transition_map) {
bool is_dictionary_map = transition_map->is_dictionary_map(); bool is_dictionary_map = transition_map->is_dictionary_map();
...@@ -227,6 +261,8 @@ MaybeObjectHandle StoreHandler::StoreTransition(Isolate* isolate, ...@@ -227,6 +261,8 @@ MaybeObjectHandle StoreHandler::StoreTransition(Isolate* isolate,
InternalIndex descriptor = transition_map->LastAdded(); InternalIndex descriptor = transition_map->LastAdded();
Handle<DescriptorArray> descriptors( Handle<DescriptorArray> descriptors(
transition_map->instance_descriptors(isolate), isolate); transition_map->instance_descriptors(isolate), isolate);
// Private fields must be added via StoreOwnTransition handler.
DCHECK(!descriptors->GetKey(descriptor).IsPrivateName());
PropertyDetails details = descriptors->GetDetails(descriptor); PropertyDetails details = descriptors->GetDetails(descriptor);
if (descriptors->GetKey(descriptor).IsPrivate()) { if (descriptors->GetKey(descriptor).IsPrivate()) {
DCHECK_EQ(DONT_ENUM, details.attributes()); DCHECK_EQ(DONT_ENUM, details.attributes());
......
...@@ -301,6 +301,11 @@ class StoreHandler final : public DataHandler { ...@@ -301,6 +301,11 @@ class StoreHandler final : public DataHandler {
PropertyConstness constness, PropertyConstness constness,
Representation representation); Representation representation);
// Create a store transition handler which doesn't check prototype chain.
static MaybeObjectHandle StoreOwnTransition(Isolate* isolate,
Handle<Map> transition_map);
// Create a store transition handler with prototype chain validity cell check.
static MaybeObjectHandle StoreTransition(Isolate* isolate, static MaybeObjectHandle StoreTransition(Isolate* isolate,
Handle<Map> transition_map); Handle<Map> transition_map);
......
...@@ -114,13 +114,12 @@ void IC::TraceIC(const char* type, Handle<Object> name, State old_state, ...@@ -114,13 +114,12 @@ void IC::TraceIC(const char* type, Handle<Object> name, State old_state,
} else if (IsKeyedLoadIC()) { } else if (IsKeyedLoadIC()) {
KeyedAccessLoadMode mode = nexus()->GetKeyedAccessLoadMode(); KeyedAccessLoadMode mode = nexus()->GetKeyedAccessLoadMode();
modifier = GetModifier(mode); modifier = GetModifier(mode);
} else if (IsKeyedStoreIC() || IsStoreInArrayLiteralICKind(kind()) || } else if (IsKeyedStoreIC() || IsStoreInArrayLiteralIC() || IsDefineOwnIC()) {
IsDefineOwnIC()) {
KeyedAccessStoreMode mode = nexus()->GetKeyedAccessStoreMode(); KeyedAccessStoreMode mode = nexus()->GetKeyedAccessStoreMode();
modifier = GetModifier(mode); modifier = GetModifier(mode);
} }
bool keyed_prefix = is_keyed() && !IsStoreInArrayLiteralICKind(kind()); bool keyed_prefix = is_keyed() && !IsStoreInArrayLiteralIC();
if (!(TracingFlags::ic_stats.load(std::memory_order_relaxed) & if (!(TracingFlags::ic_stats.load(std::memory_order_relaxed) &
v8::tracing::TracingCategoryObserver::ENABLED_BY_TRACING)) { v8::tracing::TracingCategoryObserver::ENABLED_BY_TRACING)) {
...@@ -831,7 +830,10 @@ void LoadIC::UpdateCaches(LookupIterator* lookup) { ...@@ -831,7 +830,10 @@ void LoadIC::UpdateCaches(LookupIterator* lookup) {
} }
StubCache* IC::stub_cache() { StubCache* IC::stub_cache() {
// HasICs and each of the store own ICs require its own stub cache.
// Until we create them, don't allow accessing the load/store stub caches.
DCHECK(!IsAnyHas()); DCHECK(!IsAnyHas());
DCHECK(!is_any_store_own());
if (IsAnyLoad()) { if (IsAnyLoad()) {
return isolate()->load_stub_cache(); return isolate()->load_stub_cache();
} else { } else {
...@@ -842,7 +844,7 @@ StubCache* IC::stub_cache() { ...@@ -842,7 +844,7 @@ StubCache* IC::stub_cache() {
void IC::UpdateMegamorphicCache(Handle<Map> map, Handle<Name> name, void IC::UpdateMegamorphicCache(Handle<Map> map, Handle<Name> name,
const MaybeObjectHandle& handler) { const MaybeObjectHandle& handler) {
if (!IsAnyHas()) { if (!IsAnyHas() && !is_any_store_own()) {
stub_cache()->Set(*name, *map, *handler); stub_cache()->Set(*name, *map, *handler);
} }
} }
...@@ -1833,6 +1835,13 @@ MaybeObjectHandle StoreIC::ComputeHandler(LookupIterator* lookup) { ...@@ -1833,6 +1835,13 @@ MaybeObjectHandle StoreIC::ComputeHandler(LookupIterator* lookup) {
#endif #endif
return StoreHandler::StoreGlobal(lookup->transition_cell()); return StoreHandler::StoreGlobal(lookup->transition_cell());
} }
if (IsDefineOwnIC()) {
// Private field can't be deleted from this global object and can't
// be overwritten, so install slow handler in order to make store IC
// throw if a private name already exists.
TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
return MaybeObjectHandle(StoreHandler::StoreSlow(isolate()));
}
Handle<Smi> smi_handler = StoreHandler::StoreGlobalProxy(isolate()); Handle<Smi> smi_handler = StoreHandler::StoreGlobalProxy(isolate());
Handle<Object> handler = StoreHandler::StoreThroughPrototype( Handle<Object> handler = StoreHandler::StoreThroughPrototype(
...@@ -1845,7 +1854,10 @@ MaybeObjectHandle StoreIC::ComputeHandler(LookupIterator* lookup) { ...@@ -1845,7 +1854,10 @@ MaybeObjectHandle StoreIC::ComputeHandler(LookupIterator* lookup) {
!lookup_start_object_map()->is_dictionary_map()); !lookup_start_object_map()->is_dictionary_map());
DCHECK(lookup->IsCacheableTransition()); DCHECK(lookup->IsCacheableTransition());
if (IsAnyStoreOwn()) {
return StoreHandler::StoreOwnTransition(isolate(),
lookup->transition_map());
}
return StoreHandler::StoreTransition(isolate(), lookup->transition_map()); return StoreHandler::StoreTransition(isolate(), lookup->transition_map());
} }
...@@ -2072,7 +2084,7 @@ void KeyedStoreIC::UpdateStoreElement(Handle<Map> receiver_map, ...@@ -2072,7 +2084,7 @@ void KeyedStoreIC::UpdateStoreElement(Handle<Map> receiver_map,
for (const MapAndHandler& map_and_handler : target_maps_and_handlers) { for (const MapAndHandler& map_and_handler : target_maps_and_handlers) {
Handle<Map> map = map_and_handler.first; Handle<Map> map = map_and_handler.first;
if (!map.is_null() && map->instance_type() == JS_PRIMITIVE_WRAPPER_TYPE) { if (!map.is_null() && map->instance_type() == JS_PRIMITIVE_WRAPPER_TYPE) {
DCHECK(!IsStoreInArrayLiteralICKind(kind())); DCHECK(!IsStoreInArrayLiteralIC());
set_slow_stub_reason("JSPrimitiveWrapper"); set_slow_stub_reason("JSPrimitiveWrapper");
return; return;
} }
...@@ -2163,13 +2175,13 @@ void KeyedStoreIC::UpdateStoreElement(Handle<Map> receiver_map, ...@@ -2163,13 +2175,13 @@ void KeyedStoreIC::UpdateStoreElement(Handle<Map> receiver_map,
return; return;
} else if (map->has_typed_array_or_rab_gsab_typed_array_elements()) { } else if (map->has_typed_array_or_rab_gsab_typed_array_elements()) {
DCHECK(!IsStoreInArrayLiteralICKind(kind())); DCHECK(!IsStoreInArrayLiteralIC());
external_arrays++; external_arrays++;
} }
} }
if (external_arrays != 0 && if (external_arrays != 0 &&
external_arrays != target_maps_and_handlers.size()) { external_arrays != target_maps_and_handlers.size()) {
DCHECK(!IsStoreInArrayLiteralICKind(kind())); DCHECK(!IsStoreInArrayLiteralIC());
set_slow_stub_reason( set_slow_stub_reason(
"unsupported combination of external and normal arrays"); "unsupported combination of external and normal arrays");
return; return;
...@@ -2197,7 +2209,7 @@ Handle<Object> KeyedStoreIC::StoreElementHandler( ...@@ -2197,7 +2209,7 @@ Handle<Object> KeyedStoreIC::StoreElementHandler(
DCHECK_IMPLIES( DCHECK_IMPLIES(
!receiver_map->has_dictionary_elements() && !receiver_map->has_dictionary_elements() &&
receiver_map->MayHaveReadOnlyElementsInPrototypeChain(isolate()), receiver_map->MayHaveReadOnlyElementsInPrototypeChain(isolate()),
IsStoreInArrayLiteralICKind(kind())); IsStoreInArrayLiteralIC());
if (receiver_map->IsJSProxyMap()) { if (receiver_map->IsJSProxyMap()) {
return StoreHandler::StoreProxy(isolate()); return StoreHandler::StoreProxy(isolate());
...@@ -2218,7 +2230,7 @@ Handle<Object> KeyedStoreIC::StoreElementHandler( ...@@ -2218,7 +2230,7 @@ Handle<Object> KeyedStoreIC::StoreElementHandler(
if (receiver_map->has_typed_array_or_rab_gsab_typed_array_elements()) { if (receiver_map->has_typed_array_or_rab_gsab_typed_array_elements()) {
return code; return code;
} }
} else if (IsStoreInArrayLiteralICKind(kind())) { } else if (IsStoreInArrayLiteralIC()) {
// TODO(jgruber): Update counter name. // TODO(jgruber): Update counter name.
TRACE_HANDLER_STATS(isolate(), StoreInArrayLiteralIC_SlowStub); TRACE_HANDLER_STATS(isolate(), StoreInArrayLiteralIC_SlowStub);
return StoreHandler::StoreSlow(isolate(), store_mode); return StoreHandler::StoreSlow(isolate(), store_mode);
...@@ -2230,7 +2242,7 @@ Handle<Object> KeyedStoreIC::StoreElementHandler( ...@@ -2230,7 +2242,7 @@ Handle<Object> KeyedStoreIC::StoreElementHandler(
code = StoreHandler::StoreSlow(isolate(), store_mode); code = StoreHandler::StoreSlow(isolate(), store_mode);
} }
if (IsStoreInArrayLiteralICKind(kind())) return code; if (is_any_store_own() || IsStoreInArrayLiteralIC()) return code;
Handle<Object> validity_cell; Handle<Object> validity_cell;
if (!prev_validity_cell.ToHandle(&validity_cell)) { if (!prev_validity_cell.ToHandle(&validity_cell)) {
validity_cell = validity_cell =
......
...@@ -122,13 +122,17 @@ class IC { ...@@ -122,13 +122,17 @@ class IC {
bool IsStoreIC() const { return IsStoreICKind(kind_); } bool IsStoreIC() const { return IsStoreICKind(kind_); }
bool IsStoreOwnIC() const { return IsStoreOwnICKind(kind_); } bool IsStoreOwnIC() const { return IsStoreOwnICKind(kind_); }
bool IsDefineOwnIC() const { return IsDefineOwnICKind(kind_); } bool IsDefineOwnIC() const { return IsDefineOwnICKind(kind_); }
bool IsStoreInArrayLiteralIC() const {
return IsStoreInArrayLiteralICKind(kind_);
}
bool IsKeyedStoreIC() const { return IsKeyedStoreICKind(kind_); } bool IsKeyedStoreIC() const { return IsKeyedStoreICKind(kind_); }
bool IsKeyedHasIC() const { return IsKeyedHasICKind(kind_); } bool IsKeyedHasIC() const { return IsKeyedHasICKind(kind_); }
bool IsKeyedDefineOwnIC() const { return IsKeyedDefineOwnICKind(kind_); }
bool is_keyed() const { bool is_keyed() const {
return IsKeyedLoadIC() || IsKeyedStoreIC() || return IsKeyedLoadIC() || IsKeyedStoreIC() || IsStoreInArrayLiteralIC() ||
IsStoreInArrayLiteralICKind(kind_) || IsKeyedHasIC() || IsKeyedHasIC() || IsKeyedDefineOwnIC();
IsKeyedDefineOwnICKind(kind_);
} }
bool is_any_store_own() const { return IsStoreOwnIC() || IsDefineOwnIC(); }
bool ShouldRecomputeHandler(Handle<String> name); bool ShouldRecomputeHandler(Handle<String> name);
Handle<Map> lookup_start_object_map() { return lookup_start_object_map_; } Handle<Map> lookup_start_object_map() { return lookup_start_object_map_; }
......
...@@ -154,8 +154,13 @@ class KeyedStoreGenericAssembler : public AccessorAssembler { ...@@ -154,8 +154,13 @@ class KeyedStoreGenericAssembler : public AccessorAssembler {
bool ShouldCallSetter() const { return IsKeyedStore() || IsKeyedStoreOwn(); } bool ShouldCallSetter() const { return IsKeyedStore() || IsKeyedStoreOwn(); }
bool ShouldCheckPrototypeValidity() const { bool ShouldCheckPrototypeValidity() const {
// We don't do this for "in-literal" stores, because it is impossible for // We don't do this for "in-literal" stores, because it is impossible for
// the target object to be a "prototype" // the target object to be a "prototype".
return !IsStoreInLiteral() && !IsKeyedStoreOwn(); // We don't need the prototype validity check for "own" stores, because
// we don't care about the prototype chain.
// Thus, we need the prototype check only for ordinary stores.
DCHECK_IMPLIES(!IsKeyedStore(), IsStoreInLiteral() || IsKeyedStoreOwn() ||
IsKeyedDefineOwn());
return IsKeyedStore();
} }
}; };
...@@ -813,7 +818,7 @@ void KeyedStoreGenericAssembler::EmitGenericPropertyStore( ...@@ -813,7 +818,7 @@ void KeyedStoreGenericAssembler::EmitGenericPropertyStore(
BIND(&descriptor_found); BIND(&descriptor_found);
{ {
if (IsKeyedDefineOwn()) { if (IsKeyedDefineOwn()) {
// Take slow path to throw if a private name already exists // Take slow path to throw if a private name already exists.
GotoIf(IsPrivateSymbol(name), slow); GotoIf(IsPrivateSymbol(name), slow);
} }
TNode<IntPtrT> name_index = var_name_index.value(); TNode<IntPtrT> name_index = var_name_index.value();
...@@ -875,6 +880,7 @@ void KeyedStoreGenericAssembler::EmitGenericPropertyStore( ...@@ -875,6 +880,7 @@ void KeyedStoreGenericAssembler::EmitGenericPropertyStore(
{ {
Label check_const(this), overwrite(this), done(this); Label check_const(this), overwrite(this), done(this);
if (IsKeyedDefineOwn()) { if (IsKeyedDefineOwn()) {
// Take slow path to throw if a private name already exists.
GotoIf(IsPrivateSymbol(name), slow); GotoIf(IsPrivateSymbol(name), slow);
} }
TNode<Uint32T> details = TNode<Uint32T> details =
...@@ -1071,6 +1077,7 @@ void KeyedStoreGenericAssembler::KeyedStoreGeneric( ...@@ -1071,6 +1077,7 @@ void KeyedStoreGenericAssembler::KeyedStoreGeneric(
BIND(&slow); BIND(&slow);
{ {
if (IsKeyedStore() || IsKeyedStoreOwn()) { if (IsKeyedStore() || IsKeyedStoreOwn()) {
CSA_DCHECK(this, BoolConstant(!IsKeyedStoreOwn()));
Comment("KeyedStoreGeneric_slow"); Comment("KeyedStoreGeneric_slow");
TailCallRuntime(Runtime::kSetKeyedProperty, context, receiver, key, TailCallRuntime(Runtime::kSetKeyedProperty, context, receiver, key,
value); value);
......
// Copyright 2021 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 test(obj) {
class Base {
constructor() {
return obj;
}
}
class C extends Base {
#x = 1;
}
let c = new C();
c = new C();
}
assertThrows(
() => test(globalThis),
TypeError, "Cannot initialize #x twice on the same object");
assertThrows(
() => test(Object.create(null)),
TypeError, "Cannot initialize #x twice on the same object");
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