Commit afd5ff55 authored by henrique.ferreiro's avatar henrique.ferreiro Committed by Commit bot

Install the 'name' property in classes at runtime

This allows to detect a static property also named 'name', and also makes sure 'name' is added last, to be standards-compliant.

BUG=v8:4199

Review-Url: https://codereview.chromium.org/2423053002
Cr-Commit-Position: refs/heads/master@{#41546}
parent dfc0bb63
......@@ -304,6 +304,7 @@ class AstValue : public ZoneObject {
F(get_space, "get ") \
F(length, "length") \
F(let, "let") \
F(name, "name") \
F(native, "native") \
F(new_target, ".new.target") \
F(next, "next") \
......
......@@ -2787,6 +2787,12 @@ class ClassLiteral final : public Expression {
ZoneList<Property*>* properties() const { return properties_; }
int start_position() const { return 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 {
return HasStaticComputedNames::decode(bit_field_);
}
VariableProxy* static_initializer_proxy() const {
return static_initializer_proxy_;
......@@ -2813,14 +2819,18 @@ class ClassLiteral final : public Expression {
ClassLiteral(VariableProxy* class_variable_proxy, Expression* extends,
FunctionLiteral* constructor, ZoneList<Property*>* properties,
int start_position, int end_position)
int start_position, int end_position,
bool has_name_static_property, bool has_static_computed_names)
: Expression(start_position, kClassLiteral),
end_position_(end_position),
class_variable_proxy_(class_variable_proxy),
extends_(extends),
constructor_(constructor),
properties_(properties),
static_initializer_proxy_(nullptr) {}
static_initializer_proxy_(nullptr) {
bit_field_ |= HasNameStaticProperty::encode(has_name_static_property) |
HasStaticComputedNames::encode(has_static_computed_names);
}
int end_position_;
FeedbackVectorSlot prototype_slot_;
......@@ -2830,6 +2840,11 @@ class ClassLiteral final : public Expression {
FunctionLiteral* constructor_;
ZoneList<Property*>* properties_;
VariableProxy* static_initializer_proxy_;
class HasNameStaticProperty
: public BitField<bool, Expression::kNextBitFieldIndex, 1> {};
class HasStaticComputedNames
: public BitField<bool, HasNameStaticProperty::kNext, 1> {};
};
......@@ -3463,9 +3478,12 @@ class AstNodeFactory final BASE_EMBEDDED {
ClassLiteral* NewClassLiteral(VariableProxy* proxy, Expression* extends,
FunctionLiteral* constructor,
ZoneList<ClassLiteral::Property*>* properties,
int start_position, int end_position) {
return new (zone_) ClassLiteral(proxy, extends, constructor, properties,
start_position, end_position);
int start_position, int end_position,
bool has_name_static_property,
bool has_static_computed_names) {
return new (zone_) ClassLiteral(
proxy, extends, constructor, properties, start_position, end_position,
has_name_static_property, has_static_computed_names);
}
NativeFunctionLiteral* NewNativeFunctionLiteral(const AstRawString* name,
......
......@@ -293,6 +293,7 @@ class Genesis BASE_EMBEDDED {
// prototype, maps.
Handle<Map> sloppy_function_map_writable_prototype_;
Handle<Map> strict_function_map_writable_prototype_;
Handle<Map> class_function_map_;
Handle<JSFunction> strict_poison_function_;
Handle<JSFunction> restricted_function_properties_thrower_;
......@@ -684,6 +685,10 @@ void Genesis::CreateStrictModeFunctionMaps(Handle<JSFunction> empty) {
strict_function_map_writable_prototype_ = factory()->CreateStrictFunctionMap(
FUNCTION_WITH_WRITEABLE_PROTOTYPE, empty);
// Allocate map for classes
class_function_map_ = factory()->CreateClassFunctionMap(empty);
native_context()->set_class_function_map(*class_function_map_);
// Now that the strict mode function map is available, set up the
// restricted "arguments" and "caller" getters.
AddRestrictedFunctionProperties(empty);
......@@ -1267,6 +1272,7 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
sloppy_function_map_writable_prototype_->SetConstructor(*function_fun);
strict_function_map_writable_prototype_->SetConstructor(*function_fun);
class_function_map_->SetConstructor(*function_fun);
}
{ // --- A r r a y ---
......
......@@ -2525,7 +2525,7 @@ compiler::Node* FastNewClosureStub::Generate(CodeStubAssembler* assembler,
assembler->Bind(&if_class_constructor);
{
map_index.Bind(
assembler->IntPtrConstant(Context::STRICT_FUNCTION_MAP_INDEX));
assembler->IntPtrConstant(Context::CLASS_FUNCTION_MAP_INDEX));
assembler->Goto(&load_map);
}
......
......@@ -322,6 +322,7 @@ enum ContextLookupFlags {
V(STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX, Map, \
strict_function_without_prototype_map) \
V(STRICT_GENERATOR_FUNCTION_MAP_INDEX, Map, strict_generator_function_map) \
V(CLASS_FUNCTION_MAP_INDEX, Map, class_function_map) \
V(STRING_FUNCTION_INDEX, JSFunction, string_function) \
V(STRING_FUNCTION_PROTOTYPE_MAP_INDEX, Map, string_function_prototype_map) \
V(STRING_ITERATOR_MAP_INDEX, Map, string_iterator_map) \
......@@ -623,8 +624,10 @@ class Context: public FixedArray {
}
if (IsClassConstructor(kind)) {
// Use strict function map (no own "caller" / "arguments")
return STRICT_FUNCTION_MAP_INDEX;
// Like the strict function map, but with no 'name' accessor. 'name'
// needs to be the last property and it is added during instantiation,
// in case a static property with the same name exists"
return CLASS_FUNCTION_MAP_INDEX;
}
if (IsArrowFunction(kind) || IsConciseMethod(kind) ||
......
......@@ -2727,6 +2727,42 @@ void Factory::SetStrictFunctionInstanceDescriptor(Handle<Map> map,
}
}
Handle<Map> Factory::CreateClassFunctionMap(Handle<JSFunction> empty_function) {
Handle<Map> map = NewMap(JS_FUNCTION_TYPE, JSFunction::kSize);
SetClassFunctionInstanceDescriptor(map);
map->set_is_constructor(true);
map->set_is_callable();
Map::SetPrototype(map, empty_function);
return map;
}
void Factory::SetClassFunctionInstanceDescriptor(Handle<Map> map) {
Map::EnsureDescriptorSlack(map, 2);
PropertyAttributes rw_attribs =
static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
PropertyAttributes roc_attribs =
static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY);
STATIC_ASSERT(JSFunction::kLengthDescriptorIndex == 0);
{ // Add length.
Handle<AccessorInfo> length =
Accessors::FunctionLengthInfo(isolate(), roc_attribs);
AccessorConstantDescriptor d(handle(Name::cast(length->name())), length,
roc_attribs);
map->AppendDescriptor(&d);
}
{
// Add prototype.
Handle<AccessorInfo> prototype =
Accessors::FunctionPrototypeInfo(isolate(), rw_attribs);
AccessorConstantDescriptor d(Handle<Name>(Name::cast(prototype->name())),
prototype, rw_attribs);
map->AppendDescriptor(&d);
}
}
Handle<JSFixedArrayIterator> Factory::NewJSFixedArrayIterator(
Handle<FixedArray> array) {
// Create the "next" function (must be unique per iterator object).
......
......@@ -722,6 +722,8 @@ class V8_EXPORT_PRIVATE Factory final {
Handle<Map> CreateStrictFunctionMap(FunctionMode function_mode,
Handle<JSFunction> empty_function);
Handle<Map> CreateClassFunctionMap(Handle<JSFunction> empty_function);
// Allocates a new JSMessageObject object.
Handle<JSMessageObject> NewJSMessageObject(MessageTemplate::Template message,
Handle<Object> argument,
......@@ -803,6 +805,8 @@ class V8_EXPORT_PRIVATE Factory final {
void SetStrictFunctionInstanceDescriptor(Handle<Map> map,
FunctionMode function_mode);
void SetClassFunctionInstanceDescriptor(Handle<Map> map);
};
} // namespace internal
......
......@@ -1415,6 +1415,7 @@ void BytecodeGenerator::VisitClassLiteral(ClassLiteral* expr) {
.StoreAccumulatorInRegister(prototype);
VisitClassLiteralProperties(expr, literal, prototype);
BuildClassLiteralNameProperty(expr, literal);
builder()->CallRuntime(Runtime::kToFastProperties, literal);
// Assign to class variable.
if (expr->class_variable_proxy() != nullptr) {
......@@ -1513,6 +1514,18 @@ void BytecodeGenerator::VisitClassLiteralProperties(ClassLiteral* expr,
}
}
void BytecodeGenerator::BuildClassLiteralNameProperty(ClassLiteral* expr,
Register literal) {
if (!expr->has_name_static_property() &&
!expr->constructor()->raw_name()->IsEmpty()) {
Runtime::FunctionId runtime_id =
expr->has_static_computed_names()
? Runtime::kInstallClassNameAccessorWithCheck
: Runtime::kInstallClassNameAccessor;
builder()->CallRuntime(runtime_id, literal);
}
}
void BytecodeGenerator::VisitNativeFunctionLiteral(
NativeFunctionLiteral* expr) {
size_t entry = builder()->AllocateConstantPoolEntry();
......
......@@ -132,6 +132,7 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
void VisitClassLiteralForRuntimeDefinition(ClassLiteral* expr);
void VisitClassLiteralProperties(ClassLiteral* expr, Register literal,
Register prototype);
void BuildClassLiteralNameProperty(ClassLiteral* expr, Register literal);
void VisitThisFunctionVariable(Variable* variable);
void VisitNewTargetVariable(Variable* variable);
void VisitBlockDeclarationsAndStatements(Block* stmt);
......
......@@ -677,7 +677,9 @@ class ParserBase {
instance_field_initializers(parser->impl()->NewExpressionList(0)),
constructor(parser->impl()->EmptyFunctionLiteral()),
has_seen_constructor(false),
static_initializer_var(nullptr) {}
static_initializer_var(nullptr),
has_name_static_property(false),
has_static_computed_names(false) {}
VariableProxy* proxy;
ExpressionT extends;
typename Types::ClassPropertyList properties;
......@@ -685,6 +687,8 @@ class ParserBase {
FunctionLiteralT constructor;
bool has_seen_constructor;
Variable* static_initializer_var;
bool has_name_static_property;
bool has_static_computed_names;
};
DeclarationScope* NewScriptScope() const {
......@@ -1168,7 +1172,7 @@ class ParserBase {
ClassLiteralPropertyT ParseClassPropertyDefinition(
ClassLiteralChecker* checker, bool has_extends, bool* is_computed_name,
bool* has_seen_constructor, ClassLiteralProperty::Kind* property_kind,
bool* is_static, bool* ok);
bool* is_static, bool* has_name_static_property, bool* ok);
FunctionLiteralT ParseClassFieldForInitializer(bool has_initializer,
bool* ok);
ObjectLiteralPropertyT ParseObjectPropertyDefinition(
......@@ -2141,8 +2145,9 @@ typename ParserBase<Impl>::ClassLiteralPropertyT
ParserBase<Impl>::ParseClassPropertyDefinition(
ClassLiteralChecker* checker, bool has_extends, bool* is_computed_name,
bool* has_seen_constructor, ClassLiteralProperty::Kind* property_kind,
bool* is_static, bool* ok) {
DCHECK(has_seen_constructor != nullptr);
bool* is_static, bool* has_name_static_property, bool* ok) {
DCHECK_NOT_NULL(has_seen_constructor);
DCHECK_NOT_NULL(has_name_static_property);
bool is_get = false;
bool is_set = false;
bool is_generator = false;
......@@ -2177,6 +2182,10 @@ ParserBase<Impl>::ParseClassPropertyDefinition(
is_computed_name, CHECK_OK_CUSTOM(EmptyClassLiteralProperty));
}
if (!*has_name_static_property && is_static && impl()->IsName(name)) {
*has_name_static_property = true;
}
switch (kind) {
case PropertyKind::kClassField:
case PropertyKind::kNotSet: // This case is a name followed by a name or
......@@ -4144,7 +4153,12 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseClassLiteral(
bool is_constructor = !class_info.has_seen_constructor;
ClassLiteralPropertyT property = ParseClassPropertyDefinition(
&checker, has_extends, &is_computed_name,
&class_info.has_seen_constructor, &property_kind, &is_static, CHECK_OK);
&class_info.has_seen_constructor, &property_kind, &is_static,
&class_info.has_name_static_property, CHECK_OK);
if (!class_info.has_static_computed_names && is_static &&
is_computed_name) {
class_info.has_static_computed_names = true;
}
is_constructor &= class_info.has_seen_constructor;
impl()->RewriteNonPattern(CHECK_OK);
impl()->AccumulateFormalParameterContainmentErrors();
......
......@@ -3568,6 +3568,8 @@ void Parser::DeclareClassProperty(const AstRawString* class_name,
// - static_initializer_var
// - instance_field_initializers
// - properties
// - has_name_static_property
// - has_static_computed_names
Expression* Parser::RewriteClassLiteral(const AstRawString* name,
ClassInfo* class_info, int pos,
bool* ok) {
......@@ -3602,7 +3604,9 @@ Expression* Parser::RewriteClassLiteral(const AstRawString* name,
ClassLiteral* class_literal = factory()->NewClassLiteral(
class_info->proxy, class_info->extends, class_info->constructor,
class_info->properties, pos, end_pos);
class_info->properties, pos, end_pos,
class_info->has_name_static_property,
class_info->has_static_computed_names);
if (class_info->static_initializer_var != nullptr) {
class_literal->set_static_initializer_proxy(
......
......@@ -722,6 +722,10 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
return identifier == ast_value_factory()->constructor_string();
}
V8_INLINE bool IsName(const AstRawString* identifier) const {
return identifier == ast_value_factory()->name_string();
}
V8_INLINE static bool IsBoilerplateProperty(
ObjectLiteral::Property* property) {
return ObjectLiteral::IsBoilerplateProperty(property);
......
......@@ -67,6 +67,8 @@ PreParserIdentifier GetSymbolHelper(Scanner* scanner) {
return PreParserIdentifier::Prototype();
if (scanner->LiteralMatches("constructor", 11))
return PreParserIdentifier::Constructor();
if (scanner->LiteralMatches("name", 4))
return PreParserIdentifier::Name();
return PreParserIdentifier::Default();
}
}
......
......@@ -68,6 +68,9 @@ class PreParserIdentifier {
static PreParserIdentifier Async() {
return PreParserIdentifier(kAsyncIdentifier);
}
static PreParserIdentifier Name() {
return PreParserIdentifier(kNameIdentifier);
}
bool IsEmpty() const { return type_ == kEmptyIdentifier; }
bool IsEval() const { return type_ == kEvalIdentifier; }
bool IsArguments() const { return type_ == kArgumentsIdentifier; }
......@@ -80,6 +83,7 @@ class PreParserIdentifier {
bool IsConstructor() const { return type_ == kConstructorIdentifier; }
bool IsEnum() const { return type_ == kEnumIdentifier; }
bool IsAwait() const { return type_ == kAwaitIdentifier; }
bool IsName() const { return type_ == kNameIdentifier; }
// Allow identifier->name()[->length()] to work. The preparser
// does not need the actual positions/lengths of the identifiers.
......@@ -105,7 +109,8 @@ class PreParserIdentifier {
kConstructorIdentifier,
kEnumIdentifier,
kAwaitIdentifier,
kAsyncIdentifier
kAsyncIdentifier,
kNameIdentifier
};
explicit PreParserIdentifier(Type type) : type_(type), string_(nullptr) {}
......@@ -1152,6 +1157,10 @@ class PreParser : public ParserBase<PreParser> {
return identifier.IsConstructor();
}
V8_INLINE bool IsName(PreParserIdentifier identifier) const {
return identifier.IsName();
}
V8_INLINE static bool IsBoilerplateProperty(PreParserExpression property) {
// PreParser doesn't count boilerplate properties.
return false;
......
......@@ -7,6 +7,7 @@
#include <stdlib.h>
#include <limits>
#include "src/accessors.h"
#include "src/arguments.h"
#include "src/debug/debug.h"
#include "src/frames-inl.h"
......@@ -170,6 +171,42 @@ RUNTIME_FUNCTION(Runtime_DefineClass) {
end_position));
}
namespace {
void InstallClassNameAccessor(Isolate* isolate, Handle<JSObject> object) {
PropertyAttributes attrs =
static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY);
// Cannot fail since this should only be called when creating an object
// literal.
CHECK(!JSObject::SetAccessor(
object, Accessors::FunctionNameInfo(object->GetIsolate(), attrs))
.is_null());
}
} // anonymous namespace
RUNTIME_FUNCTION(Runtime_InstallClassNameAccessor) {
HandleScope scope(isolate);
DCHECK(args.length() == 1);
CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
InstallClassNameAccessor(isolate, object);
return *object;
}
RUNTIME_FUNCTION(Runtime_InstallClassNameAccessorWithCheck) {
HandleScope scope(isolate);
DCHECK(args.length() == 1);
CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
// If a property named "name" is already defined, exit.
Handle<Name> key = isolate->factory()->name_string();
if (JSObject::HasRealNamedProperty(object, key).FromMaybe(false)) {
return *object;
}
// Define the "name" accessor.
InstallClassNameAccessor(isolate, object);
return *object;
}
namespace {
enum class SuperMode { kLoad, kStore };
......
......@@ -74,21 +74,23 @@ namespace internal {
F(AtomicsWake, 3, 1) \
F(AtomicsNumWaitersForTesting, 2, 1)
#define FOR_EACH_INTRINSIC_CLASSES(F) \
F(ThrowNonMethodError, 0, 1) \
F(ThrowUnsupportedSuperError, 0, 1) \
F(ThrowConstructorNonCallableError, 1, 1) \
F(ThrowArrayNotSubclassableError, 0, 1) \
F(ThrowStaticPrototypeError, 0, 1) \
F(HomeObjectSymbol, 0, 1) \
F(DefineClass, 4, 1) \
F(LoadFromSuper, 3, 1) \
F(LoadKeyedFromSuper, 3, 1) \
F(StoreToSuper_Strict, 4, 1) \
F(StoreToSuper_Sloppy, 4, 1) \
F(StoreKeyedToSuper_Strict, 4, 1) \
F(StoreKeyedToSuper_Sloppy, 4, 1) \
F(GetSuperConstructor, 1, 1) \
#define FOR_EACH_INTRINSIC_CLASSES(F) \
F(ThrowNonMethodError, 0, 1) \
F(ThrowUnsupportedSuperError, 0, 1) \
F(ThrowConstructorNonCallableError, 1, 1) \
F(ThrowArrayNotSubclassableError, 0, 1) \
F(ThrowStaticPrototypeError, 0, 1) \
F(HomeObjectSymbol, 0, 1) \
F(DefineClass, 4, 1) \
F(InstallClassNameAccessor, 1, 1) \
F(InstallClassNameAccessorWithCheck, 1, 1) \
F(LoadFromSuper, 3, 1) \
F(LoadKeyedFromSuper, 3, 1) \
F(StoreToSuper_Strict, 4, 1) \
F(StoreToSuper_Sloppy, 4, 1) \
F(StoreKeyedToSuper_Strict, 4, 1) \
F(StoreKeyedToSuper_Sloppy, 4, 1) \
F(GetSuperConstructor, 1, 1) \
F(NewWithSpread, -1, 1)
#define FOR_EACH_INTRINSIC_COLLECTIONS(F) \
......
......@@ -79,7 +79,7 @@ bytecodes: [
B(Star), R(0),
B(CreateArrayLiteral), U8(0), U8(0), U8(9),
B(Star), R(1),
B(CallJSRuntime), U8(154), R(0), U8(2),
B(CallJSRuntime), U8(155), R(0), U8(2),
/* 44 S> */ B(Return),
]
constant pool: [
......
......@@ -14,7 +14,7 @@ snippet: "
"
frame size: 9
parameter count: 1
bytecode array length: 70
bytecode array length: 75
bytecodes: [
B(LdaTheHole),
B(Star), R(2),
......@@ -41,6 +41,7 @@ bytecodes: [
B(Star), R(8),
B(LdaZero),
B(StaDataPropertyInLiteral), R(4), R(6), R(7), R(8),
B(CallRuntime), U16(Runtime::kInstallClassNameAccessor), R(3), U8(1),
B(CallRuntime), U16(Runtime::kToFastProperties), R(3), U8(1),
B(Star), R(0),
B(Star), R(1),
......@@ -66,7 +67,7 @@ snippet: "
"
frame size: 9
parameter count: 1
bytecode array length: 70
bytecode array length: 75
bytecodes: [
B(LdaTheHole),
B(Star), R(2),
......@@ -93,6 +94,7 @@ bytecodes: [
B(Star), R(8),
B(LdaZero),
B(StaDataPropertyInLiteral), R(4), R(6), R(7), R(8),
B(CallRuntime), U16(Runtime::kInstallClassNameAccessor), R(3), U8(1),
B(CallRuntime), U16(Runtime::kToFastProperties), R(3), U8(1),
B(Star), R(0),
B(Star), R(1),
......@@ -120,7 +122,7 @@ snippet: "
"
frame size: 10
parameter count: 1
bytecode array length: 114
bytecode array length: 119
bytecodes: [
B(CreateFunctionContext), U8(2),
B(PushContext), R(3),
......@@ -164,6 +166,7 @@ bytecodes: [
B(Star), R(8),
B(LdaSmi), U8(1),
B(StaDataPropertyInLiteral), R(6), R(7), R(8), R(9),
B(CallRuntime), U16(Runtime::kInstallClassNameAccessorWithCheck), R(4), U8(1),
B(CallRuntime), U16(Runtime::kToFastProperties), R(4), U8(1),
B(Star), R(0),
B(Star), R(1),
......@@ -190,7 +193,7 @@ snippet: "
"
frame size: 8
parameter count: 1
bytecode array length: 61
bytecode array length: 66
bytecodes: [
B(CreateFunctionContext), U8(1),
B(PushContext), R(3),
......@@ -213,6 +216,7 @@ bytecodes: [
B(Star), R(4),
B(LdaNamedProperty), R(4), U8(1), U8(2),
B(Star), R(5),
B(CallRuntime), U16(Runtime::kInstallClassNameAccessor), R(4), U8(1),
B(CallRuntime), U16(Runtime::kToFastProperties), R(4), U8(1),
B(Star), R(0),
B(Star), R(1),
......@@ -228,3 +232,68 @@ constant pool: [
handlers: [
]
---
snippet: "
(class {})
class E { static name () {}}
"
frame size: 10
parameter count: 1
bytecode array length: 104
bytecodes: [
B(LdaTheHole),
B(Star), R(3),
/* 30 E> */ B(StackCheck),
/* 35 S> */ B(LdaTheHole),
B(Star), R(4),
B(CreateClosure), U8(0), U8(2),
B(Star), R(5),
B(LdaSmi), U8(35),
B(Star), R(6),
B(LdaSmi), U8(43),
B(Star), R(7),
B(CallRuntime), U16(Runtime::kDefineClass), R(4), U8(4),
B(Star), R(4),
B(LdaNamedProperty), R(4), U8(1), U8(2),
B(Star), R(5),
B(CallRuntime), U16(Runtime::kToFastProperties), R(4), U8(1),
B(Star), R(1),
B(LdaTheHole),
B(Star), R(0),
/* 45 S> */ B(LdaTheHole),
B(Star), R(4),
B(CreateClosure), U8(2), U8(2),
B(Star), R(5),
B(LdaSmi), U8(45),
B(Star), R(6),
B(LdaSmi), U8(73),
B(Star), R(7),
B(CallRuntime), U16(Runtime::kDefineClass), R(4), U8(4),
B(Star), R(4),
B(LdaNamedProperty), R(4), U8(1), U8(4),
B(Star), R(5),
B(LdaConstant), U8(3),
B(ToName), R(7),
B(CreateClosure), U8(4), U8(2),
B(Star), R(8),
B(LdaSmi), U8(2),
B(Star), R(9),
B(LdaZero),
B(StaDataPropertyInLiteral), R(4), R(7), R(8), R(9),
B(CallRuntime), U16(Runtime::kToFastProperties), R(4), U8(1),
B(Star), R(0),
B(Star), R(2),
B(Star), R(3),
B(LdaUndefined),
/* 74 S> */ B(Return),
]
constant pool: [
SHARED_FUNCTION_INFO_TYPE,
ONE_BYTE_INTERNALIZED_STRING_TYPE ["prototype"],
SHARED_FUNCTION_INFO_TYPE,
ONE_BYTE_INTERNALIZED_STRING_TYPE ["name"],
SHARED_FUNCTION_INFO_TYPE,
]
handlers: [
]
......@@ -603,7 +603,7 @@ snippet: "
"
frame size: 8
parameter count: 2
bytecode array length: 170
bytecode array length: 175
bytecodes: [
B(Ldar), R(new_target),
B(JumpIfUndefined), U8(21),
......@@ -672,6 +672,7 @@ bytecodes: [
B(Star), R(2),
B(LdaNamedProperty), R(2), U8(2), U8(2),
B(Star), R(3),
B(CallRuntime), U16(Runtime::kInstallClassNameAccessor), R(2), U8(1),
B(CallRuntime), U16(Runtime::kToFastProperties), R(2), U8(1),
B(StaCurrentContextSlot), U8(6),
B(LdaCurrentContextSlot), U8(6),
......
......@@ -126,14 +126,14 @@ bytecodes: [
B(LdaUndefined),
B(Star), R(11),
B(Mov), R(2), R(12),
/* 152 E> */ B(CallJSRuntime), U8(154), R(11), U8(2),
/* 152 E> */ B(CallJSRuntime), U8(155), R(11), U8(2),
B(Star), R(9),
B(CreateArrayLiteral), U8(1), U8(1), U8(9),
B(Star), R(10),
B(CallJSRuntime), U8(153), R(7), U8(4),
B(CallJSRuntime), U8(154), R(7), U8(4),
B(Star), R(5),
B(Mov), R(0), R(6),
/* 140 E> */ B(CallJSRuntime), U8(150), R(3), U8(4),
/* 140 E> */ B(CallJSRuntime), U8(151), R(3), U8(4),
B(Star), R(3),
B(Ldar), R(this),
B(JumpIfNotHole), U8(4),
......
......@@ -2142,6 +2142,9 @@ TEST(ClassDeclarations) {
"var count = 0;\n"
"class C { constructor() { count++; }}\n"
"return new C();\n",
"(class {})\n"
"class E { static name () {}}\n",
};
CHECK(CompareTexts(BuildActual(printer, snippets),
......
......@@ -81,7 +81,7 @@ function ID(x) {
// TODO(arv): It is not clear that we are adding the "standard" properties
// in the right order. As far as I can tell the spec adds them in alphabetical
// order.
assertArrayEquals(['length', 'name', 'prototype', 'a', 'b', 'c', 'd'],
assertArrayEquals(['length', 'prototype', 'a', 'b', 'c', 'd', 'name'],
Object.getOwnPropertyNames(C));
})();
......@@ -99,7 +99,7 @@ function ID(x) {
assertEquals('D', C[2]());
// Array indexes first.
assertArrayEquals([], Object.keys(C));
assertArrayEquals(['1', '2', 'length', 'name', 'prototype', 'a', 'c'],
assertArrayEquals(['1', '2', 'length', 'prototype', 'a', 'c', 'name'],
Object.getOwnPropertyNames(C));
})();
......@@ -118,7 +118,7 @@ function ID(x) {
assertEquals('C', C.c());
assertEquals('D', C[sym2]());
assertArrayEquals([], Object.keys(C));
assertArrayEquals(['length', 'name', 'prototype', 'a', 'c'],
assertArrayEquals(['length', 'prototype', 'a', 'c', 'name'],
Object.getOwnPropertyNames(C));
assertArrayEquals([sym1, sym2], Object.getOwnPropertySymbols(C));
})();
......
......@@ -373,3 +373,16 @@
assertEquals('function () {}', obj.h.toString());
assertEquals('() => {}', obj.i.toString());
})();
(function testClassNameOrder() {
assertEquals(['length', 'prototype'], Object.getOwnPropertyNames(class {}));
class A { }
assertEquals(['length', 'prototype', 'name'], Object.getOwnPropertyNames(A));
class B { static foo() { } }
assertEquals(['length', 'prototype', 'foo', 'name'], Object.getOwnPropertyNames(B));
class C { static name() { } static foo() { } }
assertEquals(['length', 'prototype', 'name', 'foo'], Object.getOwnPropertyNames(C));
})();
......@@ -37,12 +37,6 @@
###################### MISSING ES6 FEATURES #######################
# The order of adding the name property is wrong
# https://code.google.com/p/v8/issues/detail?id=4199
'language/computed-property-names/class/static/method-number': [FAIL, FAIL_SLOPPY],
'language/computed-property-names/class/static/method-symbol': [FAIL, FAIL_SLOPPY],
'language/computed-property-names/class/static/method-string': [FAIL, FAIL_SLOPPY],
# https://code.google.com/p/v8/issues/detail?id=4248
'language/expressions/compound-assignment/S11.13.2_A5.*': [FAIL],
'language/expressions/compound-assignment/S11.13.2_A6.*': [FAIL],
......@@ -79,7 +73,6 @@
'built-ins/Proxy/revocable/revocation-function-name': [FAIL],
'language/expressions/assignment/fn-name-lhs-cover': [FAIL],
'language/expressions/assignment/fn-name-lhs-member': [FAIL],
'language/expressions/class/name': [FAIL],
'language/expressions/function/name': [FAIL],
'language/expressions/generators/name': [FAIL],
'intl402/NumberFormat/prototype/format/format-function-name': [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