Commit 224b659c authored by Timothy Gu's avatar Timothy Gu Committed by V8 LUCI CQ

Install class "name" accessor before methods

https://github.com/tc39/ecma262/pull/1490 changed the spec so that the
"name" property of a class should be installed after "length" but before
"prototype". This CL adapts accordingly.

After this change, there is now no need for the separate code path to
set the "name" accessor at runtime. Delete the relevant runtime code as
well.

Bug: v8:8771
Change-Id: I8f809b45bf209c899cf5df76d0ebf6d9a45a6d4e
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2974772
Commit-Queue: Timothy Gu <timothygu@chromium.org>
Reviewed-by: 's avatarMarja Hölttä <marja@chromium.org>
Cr-Commit-Position: refs/heads/master@{#75340}
parent 250a6480
...@@ -2453,9 +2453,6 @@ class ClassLiteral final : public Expression { ...@@ -2453,9 +2453,6 @@ class ClassLiteral final : public Expression {
ZonePtrList<Property>* private_members() const { return private_members_; } ZonePtrList<Property>* private_members() const { return private_members_; }
int start_position() const { return position(); } int start_position() const { return position(); }
int end_position() const { return end_position_; } int end_position() const { return end_position_; }
bool has_name_static_property() const {
return HasNameStaticProperty::decode(bit_field_);
}
bool has_static_computed_names() const { bool has_static_computed_names() const {
return HasStaticComputedNames::decode(bit_field_); return HasStaticComputedNames::decode(bit_field_);
} }
...@@ -2491,9 +2488,9 @@ class ClassLiteral final : public Expression { ...@@ -2491,9 +2488,9 @@ class ClassLiteral final : public Expression {
FunctionLiteral* static_initializer, FunctionLiteral* static_initializer,
FunctionLiteral* instance_members_initializer_function, FunctionLiteral* instance_members_initializer_function,
int start_position, int end_position, int start_position, int end_position,
bool has_name_static_property, bool has_static_computed_names, bool has_static_computed_names, bool is_anonymous,
bool is_anonymous, bool has_private_methods, bool has_private_methods, Variable* home_object,
Variable* home_object, Variable* static_home_object) Variable* static_home_object)
: Expression(start_position, kClassLiteral), : Expression(start_position, kClassLiteral),
end_position_(end_position), end_position_(end_position),
scope_(scope), scope_(scope),
...@@ -2506,8 +2503,7 @@ class ClassLiteral final : public Expression { ...@@ -2506,8 +2503,7 @@ class ClassLiteral final : public Expression {
instance_members_initializer_function), instance_members_initializer_function),
home_object_(home_object), home_object_(home_object),
static_home_object_(static_home_object) { static_home_object_(static_home_object) {
bit_field_ |= HasNameStaticProperty::encode(has_name_static_property) | bit_field_ |= HasStaticComputedNames::encode(has_static_computed_names) |
HasStaticComputedNames::encode(has_static_computed_names) |
IsAnonymousExpression::encode(is_anonymous) | IsAnonymousExpression::encode(is_anonymous) |
HasPrivateMethods::encode(has_private_methods); HasPrivateMethods::encode(has_private_methods);
} }
...@@ -2520,8 +2516,7 @@ class ClassLiteral final : public Expression { ...@@ -2520,8 +2516,7 @@ class ClassLiteral final : public Expression {
ZonePtrList<Property>* private_members_; ZonePtrList<Property>* private_members_;
FunctionLiteral* static_initializer_; FunctionLiteral* static_initializer_;
FunctionLiteral* instance_members_initializer_function_; FunctionLiteral* instance_members_initializer_function_;
using HasNameStaticProperty = Expression::NextBitField<bool, 1>; using HasStaticComputedNames = Expression::NextBitField<bool, 1>;
using HasStaticComputedNames = HasNameStaticProperty::Next<bool, 1>;
using IsAnonymousExpression = HasStaticComputedNames::Next<bool, 1>; using IsAnonymousExpression = HasStaticComputedNames::Next<bool, 1>;
using HasPrivateMethods = IsAnonymousExpression::Next<bool, 1>; using HasPrivateMethods = IsAnonymousExpression::Next<bool, 1>;
Variable* home_object_; Variable* home_object_;
...@@ -3251,16 +3246,14 @@ class AstNodeFactory final { ...@@ -3251,16 +3246,14 @@ class AstNodeFactory final {
ZonePtrList<ClassLiteral::Property>* private_members, ZonePtrList<ClassLiteral::Property>* private_members,
FunctionLiteral* static_initializer, FunctionLiteral* static_initializer,
FunctionLiteral* instance_members_initializer_function, FunctionLiteral* instance_members_initializer_function,
int start_position, int end_position, bool has_name_static_property, int start_position, int end_position, bool has_static_computed_names,
bool has_static_computed_names, bool is_anonymous, bool is_anonymous, bool has_private_methods, Variable* home_object,
bool has_private_methods, Variable* home_object,
Variable* static_home_object) { Variable* static_home_object) {
return zone_->New<ClassLiteral>( return zone_->New<ClassLiteral>(
scope, extends, constructor, public_members, private_members, scope, extends, constructor, public_members, private_members,
static_initializer, instance_members_initializer_function, static_initializer, instance_members_initializer_function,
start_position, end_position, has_name_static_property, start_position, end_position, has_static_computed_names, is_anonymous,
has_static_computed_names, is_anonymous, has_private_methods, has_private_methods, home_object, static_home_object);
home_object, static_home_object);
} }
NativeFunctionLiteral* NewNativeFunctionLiteral(const AstRawString* name, NativeFunctionLiteral* NewNativeFunctionLiteral(const AstRawString* name,
......
...@@ -276,10 +276,13 @@ void AddToDictionaryTemplate(IsolateT* isolate, Handle<Dictionary> dictionary, ...@@ -276,10 +276,13 @@ void AddToDictionaryTemplate(IsolateT* isolate, Handle<Dictionary> dictionary,
existing_value.IsAccessorInfo()); existing_value.IsAccessorInfo());
DCHECK_IMPLIES(!existing_value.IsSmi(), DCHECK_IMPLIES(!existing_value.IsSmi(),
AccessorInfo::cast(existing_value).name() == AccessorInfo::cast(existing_value).name() ==
*isolate->factory()->length_string()); *isolate->factory()->length_string() ||
AccessorInfo::cast(existing_value).name() ==
*isolate->factory()->name_string());
if (!existing_value.IsSmi() || Smi::ToInt(existing_value) < key_index) { if (!existing_value.IsSmi() || Smi::ToInt(existing_value) < key_index) {
// Overwrite existing value because it was defined before the computed // Overwrite existing value because it was defined before the computed
// one (AccessorInfo "length" property is always defined before). // one (AccessorInfo "length" and "name" properties are always defined
// before).
PropertyDetails details( PropertyDetails details(
kData, DONT_ENUM, PropertyDetails::kConstIfDictConstnessTracking, kData, DONT_ENUM, PropertyDetails::kConstIfDictConstnessTracking,
enum_order_existing); enum_order_existing);
...@@ -625,6 +628,14 @@ Handle<ClassBoilerplate> ClassBoilerplate::BuildClassBoilerplate( ...@@ -625,6 +628,14 @@ Handle<ClassBoilerplate> ClassBoilerplate::BuildClassBoilerplate(
static_desc.AddConstant(isolate, factory->length_string(), static_desc.AddConstant(isolate, factory->length_string(),
factory->function_length_accessor(), attribs); factory->function_length_accessor(), attribs);
} }
{
// Add name_accessor.
// All classes, even anonymous ones, have a name accessor.
PropertyAttributes attribs =
static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY);
static_desc.AddConstant(isolate, factory->name_string(),
factory->function_name_accessor(), attribs);
}
{ {
// Add prototype_accessor. // Add prototype_accessor.
PropertyAttributes attribs = PropertyAttributes attribs =
...@@ -698,18 +709,6 @@ Handle<ClassBoilerplate> ClassBoilerplate::BuildClassBoilerplate( ...@@ -698,18 +709,6 @@ Handle<ClassBoilerplate> ClassBoilerplate::BuildClassBoilerplate(
} }
} }
// All classes, even anonymous ones, have a name accessor. If static_desc is
// in dictionary mode, the name accessor is installed at runtime in
// DefineClass.
if (!expr->has_name_static_property() &&
!static_desc.HasDictionaryProperties()) {
// Set class name accessor if the "name" method was not added yet.
PropertyAttributes attribs =
static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY);
static_desc.AddConstant(isolate, factory->name_string(),
factory->function_name_accessor(), attribs);
}
static_desc.Finalize(isolate); static_desc.Finalize(isolate);
instance_desc.Finalize(isolate); instance_desc.Finalize(isolate);
......
...@@ -595,7 +595,6 @@ class ParserBase { ...@@ -595,7 +595,6 @@ class ParserBase {
instance_fields(parser->impl()->NewClassPropertyList(4)), instance_fields(parser->impl()->NewClassPropertyList(4)),
constructor(parser->impl()->NullExpression()), constructor(parser->impl()->NullExpression()),
has_seen_constructor(false), has_seen_constructor(false),
has_name_static_property(false),
has_static_computed_names(false), has_static_computed_names(false),
has_static_elements(false), has_static_elements(false),
has_static_private_methods(false), has_static_private_methods(false),
...@@ -615,7 +614,6 @@ class ParserBase { ...@@ -615,7 +614,6 @@ class ParserBase {
FunctionLiteralT constructor; FunctionLiteralT constructor;
bool has_seen_constructor; bool has_seen_constructor;
bool has_name_static_property;
bool has_static_computed_names; bool has_static_computed_names;
bool has_static_elements; bool has_static_elements;
bool has_static_private_methods; bool has_static_private_methods;
...@@ -2316,11 +2314,6 @@ ParserBase<Impl>::ParseClassPropertyDefinition(ClassInfo* class_info, ...@@ -2316,11 +2314,6 @@ ParserBase<Impl>::ParseClassPropertyDefinition(ClassInfo* class_info,
name_expression = ParseProperty(prop_info); name_expression = ParseProperty(prop_info);
} }
if (!class_info->has_name_static_property && prop_info->is_static &&
impl()->IsName(prop_info->name)) {
class_info->has_name_static_property = true;
}
switch (prop_info->kind) { switch (prop_info->kind) {
case ParsePropertyKind::kAssign: case ParsePropertyKind::kAssign:
case ParsePropertyKind::kClassField: case ParsePropertyKind::kClassField:
......
...@@ -3132,7 +3132,6 @@ FunctionLiteral* Parser::CreateInitializerFunction( ...@@ -3132,7 +3132,6 @@ FunctionLiteral* Parser::CreateInitializerFunction(
// - proxy // - proxy
// - extends // - extends
// - properties // - properties
// - has_name_static_property
// - has_static_computed_names // - has_static_computed_names
Expression* Parser::RewriteClassLiteral(ClassScope* block_scope, Expression* Parser::RewriteClassLiteral(ClassScope* block_scope,
const AstRawString* name, const AstRawString* name,
...@@ -3183,7 +3182,6 @@ Expression* Parser::RewriteClassLiteral(ClassScope* block_scope, ...@@ -3183,7 +3182,6 @@ Expression* Parser::RewriteClassLiteral(ClassScope* block_scope,
block_scope, class_info->extends, class_info->constructor, block_scope, class_info->extends, class_info->constructor,
class_info->public_members, class_info->private_members, class_info->public_members, class_info->private_members,
static_initializer, instance_members_initializer_function, pos, end_pos, static_initializer, instance_members_initializer_function, pos, end_pos,
class_info->has_name_static_property,
class_info->has_static_computed_names, class_info->is_anonymous, class_info->has_static_computed_names, class_info->is_anonymous,
class_info->has_private_methods, class_info->home_object_variable, class_info->has_private_methods, class_info->home_object_variable,
class_info->static_home_object_variable); class_info->static_home_object_variable);
......
...@@ -202,19 +202,12 @@ Handle<Dictionary> ShallowCopyDictionaryTemplate( ...@@ -202,19 +202,12 @@ Handle<Dictionary> ShallowCopyDictionaryTemplate(
template <typename Dictionary> template <typename Dictionary>
bool SubstituteValues(Isolate* isolate, Handle<Dictionary> dictionary, bool SubstituteValues(Isolate* isolate, Handle<Dictionary> dictionary,
RuntimeArguments& args, RuntimeArguments& args) {
bool* install_name_accessor = nullptr) {
Handle<Name> name_string = isolate->factory()->name_string();
// Replace all indices with proper methods. // Replace all indices with proper methods.
ReadOnlyRoots roots(isolate); ReadOnlyRoots roots(isolate);
for (InternalIndex i : dictionary->IterateEntries()) { for (InternalIndex i : dictionary->IterateEntries()) {
Object maybe_key = dictionary->KeyAt(i); Object maybe_key = dictionary->KeyAt(i);
if (!Dictionary::IsKey(roots, maybe_key)) continue; if (!Dictionary::IsKey(roots, maybe_key)) continue;
if (install_name_accessor && *install_name_accessor &&
(maybe_key == *name_string)) {
*install_name_accessor = false;
}
Handle<Object> key(maybe_key, isolate); Handle<Object> key(maybe_key, isolate);
Handle<Object> value(dictionary->ValueAt(i), isolate); Handle<Object> value(dictionary->ValueAt(i), isolate);
if (value->IsAccessorPair()) { if (value->IsAccessorPair()) {
...@@ -400,7 +393,7 @@ bool AddDescriptorsByTemplate( ...@@ -400,7 +393,7 @@ bool AddDescriptorsByTemplate(
Handle<Dictionary> properties_dictionary_template, Handle<Dictionary> properties_dictionary_template,
Handle<NumberDictionary> elements_dictionary_template, Handle<NumberDictionary> elements_dictionary_template,
Handle<FixedArray> computed_properties, Handle<JSObject> receiver, Handle<FixedArray> computed_properties, Handle<JSObject> receiver,
bool install_name_accessor, RuntimeArguments& args) { RuntimeArguments& args) {
int computed_properties_length = computed_properties->length(); int computed_properties_length = computed_properties->length();
// Shallow-copy properties template. // Shallow-copy properties template.
...@@ -438,20 +431,9 @@ bool AddDescriptorsByTemplate( ...@@ -438,20 +431,9 @@ bool AddDescriptorsByTemplate(
} }
// Replace all indices with proper methods. // Replace all indices with proper methods.
if (!SubstituteValues<Dictionary>(isolate, properties_dictionary, args, if (!SubstituteValues<Dictionary>(isolate, properties_dictionary, args)) {
&install_name_accessor)) {
return false; return false;
} }
if (install_name_accessor) {
PropertyAttributes attribs =
static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY);
PropertyDetails details(kAccessor, attribs,
PropertyDetails::kConstIfDictConstnessTracking);
Handle<Dictionary> dict = ToHandle(Dictionary::Add(
isolate, properties_dictionary, isolate->factory()->name_string(),
isolate->factory()->function_name_accessor(), details));
CHECK_EQ(*dict, *properties_dictionary);
}
UpdateProtectors(isolate, receiver, properties_dictionary); UpdateProtectors(isolate, receiver, properties_dictionary);
...@@ -520,23 +502,18 @@ bool InitClassPrototype(Isolate* isolate, ...@@ -520,23 +502,18 @@ bool InitClassPrototype(Isolate* isolate,
map->set_may_have_interesting_symbols(true); map->set_may_have_interesting_symbols(true);
map->set_construction_counter(Map::kNoSlackTracking); map->set_construction_counter(Map::kNoSlackTracking);
// Class prototypes do not have a name accessor.
const bool install_name_accessor = false;
if (V8_ENABLE_SWISS_NAME_DICTIONARY_BOOL) { if (V8_ENABLE_SWISS_NAME_DICTIONARY_BOOL) {
Handle<SwissNameDictionary> properties_dictionary_template = Handle<SwissNameDictionary> properties_dictionary_template =
Handle<SwissNameDictionary>::cast(properties_template); Handle<SwissNameDictionary>::cast(properties_template);
return AddDescriptorsByTemplate( return AddDescriptorsByTemplate(
isolate, map, properties_dictionary_template, isolate, map, properties_dictionary_template,
elements_dictionary_template, computed_properties, prototype, elements_dictionary_template, computed_properties, prototype, args);
install_name_accessor, args);
} else { } else {
Handle<NameDictionary> properties_dictionary_template = Handle<NameDictionary> properties_dictionary_template =
Handle<NameDictionary>::cast(properties_template); Handle<NameDictionary>::cast(properties_template);
return AddDescriptorsByTemplate( return AddDescriptorsByTemplate(
isolate, map, properties_dictionary_template, isolate, map, properties_dictionary_template,
elements_dictionary_template, computed_properties, prototype, elements_dictionary_template, computed_properties, prototype, args);
install_name_accessor, args);
} }
} }
} }
...@@ -582,24 +559,19 @@ bool InitClassConstructor(Isolate* isolate, ...@@ -582,24 +559,19 @@ bool InitClassConstructor(Isolate* isolate,
map->set_may_have_interesting_symbols(true); map->set_may_have_interesting_symbols(true);
map->set_construction_counter(Map::kNoSlackTracking); map->set_construction_counter(Map::kNoSlackTracking);
// All class constructors have a name accessor.
const bool install_name_accessor = true;
if (V8_ENABLE_SWISS_NAME_DICTIONARY_BOOL) { if (V8_ENABLE_SWISS_NAME_DICTIONARY_BOOL) {
Handle<SwissNameDictionary> properties_dictionary_template = Handle<SwissNameDictionary> properties_dictionary_template =
Handle<SwissNameDictionary>::cast(properties_template); Handle<SwissNameDictionary>::cast(properties_template);
return AddDescriptorsByTemplate( return AddDescriptorsByTemplate(
isolate, map, properties_dictionary_template, isolate, map, properties_dictionary_template,
elements_dictionary_template, computed_properties, constructor, elements_dictionary_template, computed_properties, constructor, args);
install_name_accessor, args);
} else { } else {
Handle<NameDictionary> properties_dictionary_template = Handle<NameDictionary> properties_dictionary_template =
Handle<NameDictionary>::cast(properties_template); Handle<NameDictionary>::cast(properties_template);
return AddDescriptorsByTemplate( return AddDescriptorsByTemplate(
isolate, map, properties_dictionary_template, isolate, map, properties_dictionary_template,
elements_dictionary_template, computed_properties, constructor, elements_dictionary_template, computed_properties, constructor, args);
install_name_accessor, args);
} }
} }
} }
......
...@@ -78,10 +78,7 @@ function ID(x) { ...@@ -78,10 +78,7 @@ function ID(x) {
assertEquals('C', C.c()); assertEquals('C', C.c());
assertEquals('D', C.d()); assertEquals('D', C.d());
assertArrayEquals([], Object.keys(C)); assertArrayEquals([], Object.keys(C));
// TODO(arv): It is not clear that we are adding the "standard" properties assertArrayEquals(['length', 'name', 'prototype', 'a', 'b', 'c', 'd'],
// in the right order. As far as I can tell the spec adds them in alphabetical
// order.
assertArrayEquals(['length', 'prototype', 'a', 'b', 'c', 'd', 'name'],
Object.getOwnPropertyNames(C)); Object.getOwnPropertyNames(C));
})(); })();
...@@ -99,7 +96,7 @@ function ID(x) { ...@@ -99,7 +96,7 @@ function ID(x) {
assertEquals('D', C[2]()); assertEquals('D', C[2]());
// Array indexes first. // Array indexes first.
assertArrayEquals([], Object.keys(C)); assertArrayEquals([], Object.keys(C));
assertArrayEquals(['1', '2', 'length', 'prototype', 'a', 'c', 'name'], assertArrayEquals(['1', '2', 'length', 'name', 'prototype', 'a', 'c'],
Object.getOwnPropertyNames(C)); Object.getOwnPropertyNames(C));
})(); })();
...@@ -118,7 +115,7 @@ function ID(x) { ...@@ -118,7 +115,7 @@ function ID(x) {
assertEquals('C', C.c()); assertEquals('C', C.c());
assertEquals('D', C[sym2]()); assertEquals('D', C[sym2]());
assertArrayEquals([], Object.keys(C)); assertArrayEquals([], Object.keys(C));
assertArrayEquals(['length', 'prototype', 'a', 'c', 'name'], assertArrayEquals(['length', 'name', 'prototype', 'a', 'c'],
Object.getOwnPropertyNames(C)); Object.getOwnPropertyNames(C));
assertArrayEquals([sym1, sym2], Object.getOwnPropertySymbols(C)); assertArrayEquals([sym1, sym2], Object.getOwnPropertySymbols(C));
})(); })();
......
...@@ -394,25 +394,25 @@ ...@@ -394,25 +394,25 @@
})(); })();
(function testClassNameOrder() { (function testClassNameOrder() {
assertEquals(['length', 'prototype', 'name'], Object.getOwnPropertyNames(class {})); assertEquals(['length', 'name', 'prototype'], Object.getOwnPropertyNames(class {}));
var tmp = {'': class {}}; var tmp = {'': class {}};
var Tmp = tmp['']; var Tmp = tmp[''];
assertEquals(['length', 'prototype', 'name'], Object.getOwnPropertyNames(Tmp)); assertEquals(['length', 'name', 'prototype'], Object.getOwnPropertyNames(Tmp));
var name = () => ''; var name = () => '';
var tmp = {[name()]: class {}}; var tmp = {[name()]: class {}};
var Tmp = tmp[name()]; var Tmp = tmp[name()];
assertEquals(['length', 'prototype', 'name'], Object.getOwnPropertyNames(Tmp)); assertEquals(['length', 'name', 'prototype'], Object.getOwnPropertyNames(Tmp));
class A { } class A { }
assertEquals(['length', 'prototype', 'name'], Object.getOwnPropertyNames(A)); assertEquals(['length', 'name', 'prototype'], Object.getOwnPropertyNames(A));
class B { static foo() { } } class B { static foo() { } }
assertEquals(['length', 'prototype', 'foo', 'name'], Object.getOwnPropertyNames(B)); assertEquals(['length', 'name', 'prototype', 'foo'], Object.getOwnPropertyNames(B));
class C { static name() { } static foo() { } } class C { static name() { } static foo() { } }
assertEquals(['length', 'prototype', 'name', 'foo'], Object.getOwnPropertyNames(C)); assertEquals(['length', 'name', 'prototype', 'foo'], Object.getOwnPropertyNames(C));
})(); })();
(function testStaticName() { (function testStaticName() {
......
...@@ -71,11 +71,6 @@ ...@@ -71,11 +71,6 @@
# https://code.google.com/p/v8/issues/detail?id=10958 # https://code.google.com/p/v8/issues/detail?id=10958
'language/module-code/eval-gtbndng-indirect-faux-assertion': [FAIL], 'language/module-code/eval-gtbndng-indirect-faux-assertion': [FAIL],
# https://code.google.com/p/v8/issues/detail?id=8771
'language/computed-property-names/class/static/method-number': [FAIL],
'language/computed-property-names/class/static/method-string': [FAIL],
'language/computed-property-names/class/static/method-symbol': [FAIL],
# https://bugs.chromium.org/p/v8/issues/detail?id=4895 # https://bugs.chromium.org/p/v8/issues/detail?id=4895
# Some TypedArray methods throw due to the same bug, from Get # Some TypedArray methods throw due to the same bug, from Get
'built-ins/TypedArray/prototype/every/callbackfn-detachbuffer': [FAIL], 'built-ins/TypedArray/prototype/every/callbackfn-detachbuffer': [FAIL],
......
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