From 45d8e74cd6c97b96e82ea4086f205974660cd36e Mon Sep 17 00:00:00 2001 From: "arv@chromium.org" Date: Wed, 10 Sep 2014 16:39:42 +0000 Subject: [PATCH] ES6: Add support for method shorthand in object literals This is governed by the harmony-object-literals flag. BUG=v8:3516 LOG=Y R=rossberg@chromium.org Review URL: https://codereview.chromium.org/477263002 git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@23846 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/arm/full-codegen-arm.cc | 4 +- src/arm/lithium-codegen-arm.cc | 5 +- src/arm64/full-codegen-arm64.cc | 4 +- src/arm64/lithium-codegen-arm64.cc | 5 +- src/ast.h | 43 ++--- src/code-stubs-hydrogen.cc | 2 +- src/code-stubs.h | 14 +- src/compiler.cc | 13 +- src/contexts.h | 22 ++- src/factory.cc | 15 +- src/factory.h | 4 +- src/flag-definitions.h | 3 + src/full-codegen.cc | 4 +- src/globals.h | 35 ++++ src/hydrogen-instructions.h | 12 +- src/ia32/full-codegen-ia32.cc | 4 +- src/ia32/lithium-codegen-ia32.cc | 5 +- src/mips/full-codegen-mips.cc | 4 +- src/mips/lithium-codegen-mips.cc | 5 +- src/mips64/full-codegen-mips64.cc | 4 +- src/mips64/lithium-codegen-mips64.cc | 5 +- src/objects-inl.h | 17 +- src/objects.h | 21 ++- src/parser.cc | 63 +++---- src/parser.h | 24 +-- src/preparser.cc | 42 ++--- src/preparser.h | 196 ++++++++++----------- src/runtime.cc | 12 +- src/runtime.h | 1 + src/v8natives.js | 7 +- src/x64/full-codegen-x64.cc | 4 +- src/x64/lithium-codegen-x64.cc | 5 +- src/x87/full-codegen-x87.cc | 4 +- src/x87/lithium-codegen-x87.cc | 5 +- test/cctest/test-parsing.cc | 194 ++++++++++++++++++-- test/mjsunit/harmony/object-literals-method.js | 123 +++++++++++++ .../mjsunit/runtime-gen/functionisconcisemethod.js | 5 + 37 files changed, 633 insertions(+), 302 deletions(-) create mode 100644 test/mjsunit/harmony/object-literals-method.js create mode 100644 test/mjsunit/runtime-gen/functionisconcisemethod.js diff --git a/src/arm/full-codegen-arm.cc b/src/arm/full-codegen-arm.cc index dfd0e61..361f4a8 100644 --- a/src/arm/full-codegen-arm.cc +++ b/src/arm/full-codegen-arm.cc @@ -1332,9 +1332,7 @@ void FullCodeGenerator::EmitNewClosure(Handle info, !pretenure && scope()->is_function_scope() && info->num_literals() == 0) { - FastNewClosureStub stub(isolate(), - info->strict_mode(), - info->is_generator()); + FastNewClosureStub stub(isolate(), info->strict_mode(), info->kind()); __ mov(r2, Operand(info)); __ CallStub(&stub); } else { diff --git a/src/arm/lithium-codegen-arm.cc b/src/arm/lithium-codegen-arm.cc index 37e6d20..377d38b 100644 --- a/src/arm/lithium-codegen-arm.cc +++ b/src/arm/lithium-codegen-arm.cc @@ -5492,9 +5492,8 @@ void LCodeGen::DoFunctionLiteral(LFunctionLiteral* instr) { // space for nested functions that don't need literals cloning. bool pretenure = instr->hydrogen()->pretenure(); if (!pretenure && instr->hydrogen()->has_no_literals()) { - FastNewClosureStub stub(isolate(), - instr->hydrogen()->strict_mode(), - instr->hydrogen()->is_generator()); + FastNewClosureStub stub(isolate(), instr->hydrogen()->strict_mode(), + instr->hydrogen()->kind()); __ mov(r2, Operand(instr->hydrogen()->shared_info())); CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); } else { diff --git a/src/arm64/full-codegen-arm64.cc b/src/arm64/full-codegen-arm64.cc index 198e781..2e576ad 100644 --- a/src/arm64/full-codegen-arm64.cc +++ b/src/arm64/full-codegen-arm64.cc @@ -1318,9 +1318,7 @@ void FullCodeGenerator::EmitNewClosure(Handle info, !pretenure && scope()->is_function_scope() && info->num_literals() == 0) { - FastNewClosureStub stub(isolate(), - info->strict_mode(), - info->is_generator()); + FastNewClosureStub stub(isolate(), info->strict_mode(), info->kind()); __ Mov(x2, Operand(info)); __ CallStub(&stub); } else { diff --git a/src/arm64/lithium-codegen-arm64.cc b/src/arm64/lithium-codegen-arm64.cc index 904eecd..da237a6 100644 --- a/src/arm64/lithium-codegen-arm64.cc +++ b/src/arm64/lithium-codegen-arm64.cc @@ -2864,9 +2864,8 @@ void LCodeGen::DoFunctionLiteral(LFunctionLiteral* instr) { // space for nested functions that don't need literals cloning. bool pretenure = instr->hydrogen()->pretenure(); if (!pretenure && instr->hydrogen()->has_no_literals()) { - FastNewClosureStub stub(isolate(), - instr->hydrogen()->strict_mode(), - instr->hydrogen()->is_generator()); + FastNewClosureStub stub(isolate(), instr->hydrogen()->strict_mode(), + instr->hydrogen()->kind()); __ Mov(x2, Operand(instr->hydrogen()->shared_info())); CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); } else { diff --git a/src/ast.h b/src/ast.h index f8f65f1..c5a924c 100644 --- a/src/ast.h +++ b/src/ast.h @@ -2325,12 +2325,6 @@ class FunctionLiteral FINAL : public Expression { kNotParenthesized }; - enum KindFlag { - kNormalFunction, - kArrowFunction, - kGeneratorFunction - }; - enum ArityRestriction { NORMAL_ARITY, GETTER_ARITY, @@ -2420,8 +2414,16 @@ class FunctionLiteral FINAL : public Expression { bitfield_ = IsParenthesized::update(bitfield_, kIsParenthesized); } - bool is_generator() { return IsGenerator::decode(bitfield_); } - bool is_arrow() { return IsArrow::decode(bitfield_); } + FunctionKind kind() { return FunctionKindBits::decode(bitfield_); } + bool is_arrow() { + return IsArrowFunction(FunctionKindBits::decode(bitfield_)); + } + bool is_generator() { + return IsGeneratorFunction(FunctionKindBits::decode(bitfield_)); + } + bool is_concise_method() { + return IsConciseMethod(FunctionKindBits::decode(bitfield_)); + } int ast_node_count() { return ast_properties_.node_count(); } AstProperties::Flags* flags() { return ast_properties_.flags(); } @@ -2445,7 +2447,7 @@ class FunctionLiteral FINAL : public Expression { int parameter_count, FunctionType function_type, ParameterFlag has_duplicate_parameters, IsFunctionFlag is_function, - IsParenthesizedFlag is_parenthesized, KindFlag kind, + IsParenthesizedFlag is_parenthesized, FunctionKind kind, int position, IdGen* id_gen) : Expression(zone, position, id_gen), raw_name_(name), @@ -2464,8 +2466,8 @@ class FunctionLiteral FINAL : public Expression { HasDuplicateParameters::encode(has_duplicate_parameters) | IsFunction::encode(is_function) | IsParenthesized::encode(is_parenthesized) | - IsGenerator::encode(kind == kGeneratorFunction) | - IsArrow::encode(kind == kArrowFunction); + FunctionKindBits::encode(kind); + DCHECK(IsValidFunctionKind(kind)); } private: @@ -2486,14 +2488,13 @@ class FunctionLiteral FINAL : public Expression { int function_token_position_; unsigned bitfield_; - class IsExpression: public BitField {}; - class IsAnonymous: public BitField {}; - class Pretenure: public BitField {}; - class HasDuplicateParameters: public BitField {}; - class IsFunction: public BitField {}; - class IsParenthesized: public BitField {}; - class IsGenerator : public BitField {}; - class IsArrow : public BitField {}; + class IsExpression : public BitField {}; + class IsAnonymous : public BitField {}; + class Pretenure : public BitField {}; + class HasDuplicateParameters : public BitField {}; + class IsFunction : public BitField {}; + class IsParenthesized : public BitField {}; + class FunctionKindBits : public BitField {}; }; @@ -3439,8 +3440,8 @@ class AstNodeFactory FINAL BASE_EMBEDDED { FunctionLiteral::ParameterFlag has_duplicate_parameters, FunctionLiteral::FunctionType function_type, FunctionLiteral::IsFunctionFlag is_function, - FunctionLiteral::IsParenthesizedFlag is_parenthesized, - FunctionLiteral::KindFlag kind, int position) { + FunctionLiteral::IsParenthesizedFlag is_parenthesized, FunctionKind kind, + int position) { FunctionLiteral* lit = new (zone_) FunctionLiteral( zone_, name, ast_value_factory, scope, body, materialized_literal_count, expected_property_count, handler_count, parameter_count, function_type, diff --git a/src/code-stubs-hydrogen.cc b/src/code-stubs-hydrogen.cc index e3261a3..57bf1e8 100644 --- a/src/code-stubs-hydrogen.cc +++ b/src/code-stubs-hydrogen.cc @@ -1343,7 +1343,7 @@ HValue* CodeStubGraphBuilder::BuildCodeStub() { NOT_TENURED, JS_FUNCTION_TYPE); int map_index = Context::FunctionMapIndex(casted_stub()->strict_mode(), - casted_stub()->is_generator()); + casted_stub()->kind()); // Compute the function map in the current native context and set that // as the map of the allocated object. diff --git a/src/code-stubs.h b/src/code-stubs.h index a5be529..626e14e 100644 --- a/src/code-stubs.h +++ b/src/code-stubs.h @@ -551,21 +551,27 @@ class NumberToStringStub FINAL : public HydrogenCodeStub { class FastNewClosureStub : public HydrogenCodeStub { public: FastNewClosureStub(Isolate* isolate, StrictMode strict_mode, - bool is_generator) + FunctionKind kind) : HydrogenCodeStub(isolate) { + DCHECK(IsValidFunctionKind(kind)); set_sub_minor_key(StrictModeBits::encode(strict_mode) | - IsGeneratorBits::encode(is_generator)); + FunctionKindBits::encode(kind)); } StrictMode strict_mode() const { return StrictModeBits::decode(sub_minor_key()); } - bool is_generator() const { return IsGeneratorBits::decode(sub_minor_key()); } + FunctionKind kind() const { + return FunctionKindBits::decode(sub_minor_key()); + } + bool is_arrow() const { return IsArrowFunction(kind()); } + bool is_generator() const { return IsGeneratorFunction(kind()); } + bool is_concise_method() const { return IsConciseMethod(kind()); } private: class StrictModeBits : public BitField {}; - class IsGeneratorBits : public BitField {}; + class FunctionKindBits : public BitField {}; DEFINE_CALL_INTERFACE_DESCRIPTOR(FastNewClosure); DEFINE_HYDROGEN_CODE_STUB(FastNewClosure, HydrogenCodeStub); diff --git a/src/compiler.cc b/src/compiler.cc index e0c8ae3..162c65b 100644 --- a/src/compiler.cc +++ b/src/compiler.cc @@ -654,8 +654,7 @@ static void SetFunctionInfo(Handle function_info, function_info->set_is_function(lit->is_function()); function_info->set_bailout_reason(lit->dont_optimize_reason()); function_info->set_dont_cache(lit->flags()->Contains(kDontCache)); - function_info->set_is_generator(lit->is_generator()); - function_info->set_is_arrow(lit->is_arrow()); + function_info->set_kind(lit->kind()); } @@ -871,9 +870,8 @@ static Handle CompileToplevel(CompilationInfo* info) { // Allocate function. DCHECK(!info->code().is_null()); result = isolate->factory()->NewSharedFunctionInfo( - lit->name(), lit->materialized_literal_count(), lit->is_generator(), - lit->is_arrow(), info->code(), - ScopeInfo::Create(info->scope(), info->zone()), + lit->name(), lit->materialized_literal_count(), lit->kind(), + info->code(), ScopeInfo::Create(info->scope(), info->zone()), info->feedback_vector()); DCHECK_EQ(RelocInfo::kNoPosition, lit->function_token_position()); @@ -1094,9 +1092,8 @@ Handle Compiler::BuildFunctionInfo( // Create a shared function info object. Handle result = factory->NewSharedFunctionInfo( - literal->name(), literal->materialized_literal_count(), - literal->is_generator(), literal->is_arrow(), info.code(), scope_info, - info.feedback_vector()); + literal->name(), literal->materialized_literal_count(), literal->kind(), + info.code(), scope_info, info.feedback_vector()); SetFunctionInfo(result, literal, false, script); RecordFunctionCompilation(Logger::FUNCTION_TAG, &info, result); result->set_allows_lazy_compilation(allow_lazy); diff --git a/src/contexts.h b/src/contexts.h index e8d2291..ae80021 100644 --- a/src/contexts.h +++ b/src/contexts.h @@ -553,14 +553,20 @@ class Context: public FixedArray { return kHeaderSize + index * kPointerSize - kHeapObjectTag; } - static int FunctionMapIndex(StrictMode strict_mode, bool is_generator) { - return is_generator - ? (strict_mode == SLOPPY - ? SLOPPY_GENERATOR_FUNCTION_MAP_INDEX - : STRICT_GENERATOR_FUNCTION_MAP_INDEX) - : (strict_mode == SLOPPY - ? SLOPPY_FUNCTION_MAP_INDEX - : STRICT_FUNCTION_MAP_INDEX); + static int FunctionMapIndex(StrictMode strict_mode, FunctionKind kind) { + if (IsGeneratorFunction(kind)) { + return strict_mode == SLOPPY ? SLOPPY_GENERATOR_FUNCTION_MAP_INDEX + : STRICT_GENERATOR_FUNCTION_MAP_INDEX; + } + + if (IsConciseMethod(kind)) { + return strict_mode == SLOPPY + ? SLOPPY_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX + : STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX; + } + + return strict_mode == SLOPPY ? SLOPPY_FUNCTION_MAP_INDEX + : STRICT_FUNCTION_MAP_INDEX; } static const int kSize = kHeaderSize + NATIVE_CONTEXT_SLOTS * kPointerSize; diff --git a/src/factory.cc b/src/factory.cc index 6688cc1..f931b7f 100644 --- a/src/factory.cc +++ b/src/factory.cc @@ -1237,6 +1237,9 @@ void Factory::InitializeFunction(Handle function, function->set_prototype_or_initial_map(*the_hole_value()); function->set_literals_or_bindings(*empty_fixed_array()); function->set_next_function_link(*undefined_value()); + + // TODO(arv): This does not look correct. We need to make sure we use + // a Map that has no prototype property. if (info->is_arrow()) function->RemovePrototype(); } @@ -1356,8 +1359,7 @@ Handle Factory::NewFunctionFromSharedFunctionInfo( Handle info, Handle context, PretenureFlag pretenure) { - int map_index = Context::FunctionMapIndex(info->strict_mode(), - info->is_generator()); + int map_index = Context::FunctionMapIndex(info->strict_mode(), info->kind()); Handle map(Map::cast(context->native_context()->get(map_index))); Handle result = NewFunction(map, info, context, pretenure); @@ -1904,13 +1906,14 @@ Handle Factory::NewTypeFeedbackVector(int slot_count) { Handle Factory::NewSharedFunctionInfo( - Handle name, int number_of_literals, bool is_generator, - bool is_arrow, Handle code, Handle scope_info, + Handle name, int number_of_literals, FunctionKind kind, + Handle code, Handle scope_info, Handle feedback_vector) { + DCHECK(IsValidFunctionKind(kind)); Handle shared = NewSharedFunctionInfo(name, code); shared->set_scope_info(*scope_info); shared->set_feedback_vector(*feedback_vector); - shared->set_is_arrow(is_arrow); + shared->set_kind(kind); int literals_array_size = number_of_literals; // If the function contains object, regexp or array literals, // allocate extra space for a literals array prefix containing the @@ -1919,7 +1922,7 @@ Handle Factory::NewSharedFunctionInfo( literals_array_size += JSFunction::kLiteralsPrefixSize; } shared->set_num_literals(literals_array_size); - if (is_generator) { + if (IsGeneratorFunction(kind)) { shared->set_instance_class_name(isolate()->heap()->Generator_string()); shared->DisableOptimization(kGenerator); } diff --git a/src/factory.h b/src/factory.h index 92e6d5c..47b16f5 100644 --- a/src/factory.h +++ b/src/factory.h @@ -598,8 +598,8 @@ class Factory FINAL { // Allocates a new SharedFunctionInfo object. Handle NewSharedFunctionInfo( - Handle name, int number_of_literals, bool is_generator, - bool is_arrow, Handle code, Handle scope_info, + Handle name, int number_of_literals, FunctionKind kind, + Handle code, Handle scope_info, Handle feedback_vector); Handle NewSharedFunctionInfo(Handle name, MaybeHandle code); diff --git a/src/flag-definitions.h b/src/flag-definitions.h index fe5f443..5e85389 100644 --- a/src/flag-definitions.h +++ b/src/flag-definitions.h @@ -161,6 +161,8 @@ DEFINE_BOOL(harmony_strings, false, "enable harmony string") DEFINE_BOOL(harmony_arrays, false, "enable harmony arrays") DEFINE_BOOL(harmony_arrow_functions, false, "enable harmony arrow functions") DEFINE_BOOL(harmony_classes, false, "enable harmony classes") +DEFINE_BOOL(harmony_object_literals, false, + "enable harmony object literal extensions") DEFINE_BOOL(harmony, false, "enable all harmony features (except proxies)") DEFINE_IMPLICATION(harmony, harmony_scoping) @@ -172,6 +174,7 @@ DEFINE_IMPLICATION(harmony, harmony_strings) DEFINE_IMPLICATION(harmony, harmony_arrays) DEFINE_IMPLICATION(harmony, harmony_arrow_functions) DEFINE_IMPLICATION(harmony, harmony_classes) +DEFINE_IMPLICATION(harmony, harmony_object_literals) DEFINE_IMPLICATION(harmony_modules, harmony_scoping) DEFINE_IMPLICATION(harmony, es_staging) diff --git a/src/full-codegen.cc b/src/full-codegen.cc index cfbef49..aee5ca7 100644 --- a/src/full-codegen.cc +++ b/src/full-codegen.cc @@ -1547,11 +1547,9 @@ void FullCodeGenerator::VisitNativeFunctionLiteral( const int literals = fun->NumberOfLiterals(); Handle code = Handle(fun->shared()->code()); Handle construct_stub = Handle(fun->shared()->construct_stub()); - bool is_generator = false; - bool is_arrow = false; Handle shared = isolate()->factory()->NewSharedFunctionInfo( - name, literals, is_generator, is_arrow, code, + name, literals, FunctionKind::kNormalFunction, code, Handle(fun->shared()->scope_info()), Handle(fun->shared()->feedback_vector())); shared->set_construct_stub(*construct_stub); diff --git a/src/globals.h b/src/globals.h index cc31be1..55bb572 100644 --- a/src/globals.h +++ b/src/globals.h @@ -756,6 +756,41 @@ enum MinusZeroMode { FAIL_ON_MINUS_ZERO }; + +enum FunctionKind { + kNormalFunction = 0, + kArrowFunction = 1, + kGeneratorFunction = 2, + kConciseMethod = 4 +}; + + +inline bool IsValidFunctionKind(FunctionKind kind) { + // At the moment these are mutually exclusive but in the future that wont be + // the case since ES6 allows concise generator methods. + return kind == FunctionKind::kNormalFunction || + kind == FunctionKind::kArrowFunction || + kind == FunctionKind::kGeneratorFunction || + kind == FunctionKind::kConciseMethod; +} + + +inline bool IsArrowFunction(FunctionKind kind) { + DCHECK(IsValidFunctionKind(kind)); + return kind & FunctionKind::kArrowFunction; +} + + +inline bool IsGeneratorFunction(FunctionKind kind) { + DCHECK(IsValidFunctionKind(kind)); + return kind & FunctionKind::kGeneratorFunction; +} + + +inline bool IsConciseMethod(FunctionKind kind) { + DCHECK(IsValidFunctionKind(kind)); + return kind & FunctionKind::kConciseMethod; +} } } // namespace v8::internal namespace i = v8::internal; diff --git a/src/hydrogen-instructions.h b/src/hydrogen-instructions.h index 1c32400..bcf5492 100644 --- a/src/hydrogen-instructions.h +++ b/src/hydrogen-instructions.h @@ -7481,18 +7481,20 @@ class HFunctionLiteral FINAL : public HTemplateInstruction<1> { Handle shared_info() const { return shared_info_; } bool pretenure() const { return pretenure_; } bool has_no_literals() const { return has_no_literals_; } - bool is_generator() const { return is_generator_; } + bool is_arrow() const { return IsArrowFunction(kind_); } + bool is_generator() const { return IsGeneratorFunction(kind_); } + bool is_concise_method() const { return IsConciseMethod(kind_); } + FunctionKind kind() const { return kind_; } StrictMode strict_mode() const { return strict_mode_; } private: - HFunctionLiteral(HValue* context, - Handle shared, + HFunctionLiteral(HValue* context, Handle shared, bool pretenure) : HTemplateInstruction<1>(HType::JSObject()), shared_info_(shared), + kind_(shared->kind()), pretenure_(pretenure), has_no_literals_(shared->num_literals() == 0), - is_generator_(shared->is_generator()), strict_mode_(shared->strict_mode()) { SetOperandAt(0, context); set_representation(Representation::Tagged()); @@ -7502,9 +7504,9 @@ class HFunctionLiteral FINAL : public HTemplateInstruction<1> { virtual bool IsDeletable() const OVERRIDE { return true; } Handle shared_info_; + FunctionKind kind_; bool pretenure_ : 1; bool has_no_literals_ : 1; - bool is_generator_ : 1; StrictMode strict_mode_; }; diff --git a/src/ia32/full-codegen-ia32.cc b/src/ia32/full-codegen-ia32.cc index 1990f68..db1430b 100644 --- a/src/ia32/full-codegen-ia32.cc +++ b/src/ia32/full-codegen-ia32.cc @@ -1254,9 +1254,7 @@ void FullCodeGenerator::EmitNewClosure(Handle info, !pretenure && scope()->is_function_scope() && info->num_literals() == 0) { - FastNewClosureStub stub(isolate(), - info->strict_mode(), - info->is_generator()); + FastNewClosureStub stub(isolate(), info->strict_mode(), info->kind()); __ mov(ebx, Immediate(info)); __ CallStub(&stub); } else { diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc index c094596..d9504c7 100644 --- a/src/ia32/lithium-codegen-ia32.cc +++ b/src/ia32/lithium-codegen-ia32.cc @@ -5290,9 +5290,8 @@ void LCodeGen::DoFunctionLiteral(LFunctionLiteral* instr) { // space for nested functions that don't need literals cloning. bool pretenure = instr->hydrogen()->pretenure(); if (!pretenure && instr->hydrogen()->has_no_literals()) { - FastNewClosureStub stub(isolate(), - instr->hydrogen()->strict_mode(), - instr->hydrogen()->is_generator()); + FastNewClosureStub stub(isolate(), instr->hydrogen()->strict_mode(), + instr->hydrogen()->kind()); __ mov(ebx, Immediate(instr->hydrogen()->shared_info())); CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); } else { diff --git a/src/mips/full-codegen-mips.cc b/src/mips/full-codegen-mips.cc index 62205bd..e5ef9ec 100644 --- a/src/mips/full-codegen-mips.cc +++ b/src/mips/full-codegen-mips.cc @@ -1319,9 +1319,7 @@ void FullCodeGenerator::EmitNewClosure(Handle info, !pretenure && scope()->is_function_scope() && info->num_literals() == 0) { - FastNewClosureStub stub(isolate(), - info->strict_mode(), - info->is_generator()); + FastNewClosureStub stub(isolate(), info->strict_mode(), info->kind()); __ li(a2, Operand(info)); __ CallStub(&stub); } else { diff --git a/src/mips/lithium-codegen-mips.cc b/src/mips/lithium-codegen-mips.cc index 978ef73..aca6bb3 100644 --- a/src/mips/lithium-codegen-mips.cc +++ b/src/mips/lithium-codegen-mips.cc @@ -5479,9 +5479,8 @@ void LCodeGen::DoFunctionLiteral(LFunctionLiteral* instr) { // space for nested functions that don't need literals cloning. bool pretenure = instr->hydrogen()->pretenure(); if (!pretenure && instr->hydrogen()->has_no_literals()) { - FastNewClosureStub stub(isolate(), - instr->hydrogen()->strict_mode(), - instr->hydrogen()->is_generator()); + FastNewClosureStub stub(isolate(), instr->hydrogen()->strict_mode(), + instr->hydrogen()->kind()); __ li(a2, Operand(instr->hydrogen()->shared_info())); CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); } else { diff --git a/src/mips64/full-codegen-mips64.cc b/src/mips64/full-codegen-mips64.cc index 4b3a644..5341599 100644 --- a/src/mips64/full-codegen-mips64.cc +++ b/src/mips64/full-codegen-mips64.cc @@ -1314,9 +1314,7 @@ void FullCodeGenerator::EmitNewClosure(Handle info, !pretenure && scope()->is_function_scope() && info->num_literals() == 0) { - FastNewClosureStub stub(isolate(), - info->strict_mode(), - info->is_generator()); + FastNewClosureStub stub(isolate(), info->strict_mode(), info->kind()); __ li(a2, Operand(info)); __ CallStub(&stub); } else { diff --git a/src/mips64/lithium-codegen-mips64.cc b/src/mips64/lithium-codegen-mips64.cc index 8a58d4b..7da40ff 100644 --- a/src/mips64/lithium-codegen-mips64.cc +++ b/src/mips64/lithium-codegen-mips64.cc @@ -5519,9 +5519,8 @@ void LCodeGen::DoFunctionLiteral(LFunctionLiteral* instr) { // space for nested functions that don't need literals cloning. bool pretenure = instr->hydrogen()->pretenure(); if (!pretenure && instr->hydrogen()->has_no_literals()) { - FastNewClosureStub stub(isolate(), - instr->hydrogen()->strict_mode(), - instr->hydrogen()->is_generator()); + FastNewClosureStub stub(isolate(), instr->hydrogen()->strict_mode(), + instr->hydrogen()->kind()); __ li(a2, Operand(instr->hydrogen()->shared_info())); CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); } else { diff --git a/src/objects-inl.h b/src/objects-inl.h index 1fffea2..20a12b6 100644 --- a/src/objects-inl.h +++ b/src/objects-inl.h @@ -5559,6 +5559,19 @@ void SharedFunctionInfo::set_strict_mode(StrictMode strict_mode) { } +FunctionKind SharedFunctionInfo::kind() { + return FunctionKindBits::decode(compiler_hints()); +} + + +void SharedFunctionInfo::set_kind(FunctionKind kind) { + DCHECK(IsValidFunctionKind(kind)); + int hints = compiler_hints(); + hints = FunctionKindBits::update(hints, kind); + set_compiler_hints(hints); +} + + BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, native, kNative) BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, inline_builtin, kInlineBuiltin) @@ -5570,8 +5583,10 @@ BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, is_anonymous, kIsAnonymous) BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, is_function, kIsFunction) BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, dont_cache, kDontCache) BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, dont_flush, kDontFlush) -BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, is_generator, kIsGenerator) BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, is_arrow, kIsArrow) +BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, is_generator, kIsGenerator) +BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, is_concise_method, + kIsConciseMethod) ACCESSORS(CodeCache, default_cache, FixedArray, kDefaultCacheOffset) ACCESSORS(CodeCache, normal_type_cache, Object, kNormalTypeCacheOffset) diff --git a/src/objects.h b/src/objects.h index add8337..32dd94f 100644 --- a/src/objects.h +++ b/src/objects.h @@ -7121,6 +7121,12 @@ class SharedFunctionInfo: public HeapObject { // Indicates that this function is an arrow function. DECL_BOOLEAN_ACCESSORS(is_arrow) + // Indicates that this function is a concise method. + DECL_BOOLEAN_ACCESSORS(is_concise_method) + + inline FunctionKind kind(); + inline void set_kind(FunctionKind kind); + // Indicates whether or not the code in the shared function support // deoptimization. inline bool has_deoptimization_support(); @@ -7315,17 +7321,20 @@ class SharedFunctionInfo: public HeapObject { kIsFunction, kDontCache, kDontFlush, - kIsGenerator, kIsArrow, + kIsGenerator, + kIsConciseMethod, kCompilerHintsCount // Pseudo entry }; - class DeoptCountBits: public BitField {}; - class OptReenableTriesBits: public BitField {}; - class ICAgeBits: public BitField {}; + class FunctionKindBits : public BitField {}; + + class DeoptCountBits : public BitField {}; + class OptReenableTriesBits : public BitField {}; + class ICAgeBits : public BitField {}; - class OptCountBits: public BitField {}; - class DisabledOptimizationReasonBits: public BitField {}; + class OptCountBits : public BitField {}; + class DisabledOptimizationReasonBits : public BitField {}; private: #if V8_HOST_ARCH_32_BIT diff --git a/src/parser.cc b/src/parser.cc index d385efe..b5f9c1b 100644 --- a/src/parser.cc +++ b/src/parser.cc @@ -724,18 +724,13 @@ Expression* ParserTraits::ParseV8Intrinsic(bool* ok) { FunctionLiteral* ParserTraits::ParseFunctionLiteral( - const AstRawString* name, - Scanner::Location function_name_location, - bool name_is_strict_reserved, - bool is_generator, - int function_token_position, - FunctionLiteral::FunctionType type, - FunctionLiteral::ArityRestriction arity_restriction, - bool* ok) { - return parser_->ParseFunctionLiteral(name, function_name_location, - name_is_strict_reserved, is_generator, - function_token_position, type, - arity_restriction, ok); + const AstRawString* name, Scanner::Location function_name_location, + bool name_is_strict_reserved, FunctionKind kind, + int function_token_position, FunctionLiteral::FunctionType type, + FunctionLiteral::ArityRestriction arity_restriction, bool* ok) { + return parser_->ParseFunctionLiteral( + name, function_name_location, name_is_strict_reserved, kind, + function_token_position, type, arity_restriction, ok); } @@ -767,6 +762,7 @@ Parser::Parser(CompilationInfo* info, ParseInfo* parse_info) set_allow_arrow_functions(FLAG_harmony_arrow_functions); set_allow_harmony_numeric_literals(FLAG_harmony_numeric_literals); set_allow_classes(FLAG_harmony_classes); + set_allow_harmony_object_literals(FLAG_harmony_object_literals); for (int feature = 0; feature < v8::Isolate::kUseCounterFeatureCount; ++feature) { use_counts_[feature] = 0; @@ -911,8 +907,7 @@ FunctionLiteral* Parser::DoParseProgram(CompilationInfo* info, function_state.handler_count(), 0, FunctionLiteral::kNoDuplicateParameters, FunctionLiteral::ANONYMOUS_EXPRESSION, FunctionLiteral::kGlobalOrEval, - FunctionLiteral::kNotParenthesized, FunctionLiteral::kNormalFunction, - 0); + FunctionLiteral::kNotParenthesized, FunctionKind::kNormalFunction, 0); result->set_ast_properties(factory()->visitor()->ast_properties()); result->set_dont_optimize_reason( factory()->visitor()->dont_optimize_reason()); @@ -999,18 +994,16 @@ FunctionLiteral* Parser::ParseLazy(Utf16CharacterStream* source) { ? FunctionLiteral::ANONYMOUS_EXPRESSION : FunctionLiteral::NAMED_EXPRESSION) : FunctionLiteral::DECLARATION; - bool is_generator = shared_info->is_generator(); bool ok = true; if (shared_info->is_arrow()) { - DCHECK(!is_generator); Expression* expression = ParseExpression(false, &ok); DCHECK(expression->IsFunctionLiteral()); result = expression->AsFunctionLiteral(); } else { result = ParseFunctionLiteral(raw_name, Scanner::Location::invalid(), false, // Strict mode name already checked. - is_generator, RelocInfo::kNoPosition, + shared_info->kind(), RelocInfo::kNoPosition, function_type, FunctionLiteral::NORMAL_ARITY, &ok); } @@ -1894,14 +1887,12 @@ Statement* Parser::ParseFunctionDeclaration( bool is_strict_reserved = false; const AstRawString* name = ParseIdentifierOrStrictReservedWord( &is_strict_reserved, CHECK_OK); - FunctionLiteral* fun = ParseFunctionLiteral(name, - scanner()->location(), - is_strict_reserved, - is_generator, - pos, - FunctionLiteral::DECLARATION, - FunctionLiteral::NORMAL_ARITY, - CHECK_OK); + FunctionLiteral* fun = + ParseFunctionLiteral(name, scanner()->location(), is_strict_reserved, + is_generator ? FunctionKind::kGeneratorFunction + : FunctionKind::kNormalFunction, + pos, FunctionLiteral::DECLARATION, + FunctionLiteral::NORMAL_ARITY, CHECK_OK); // Even if we're not at the top-level of the global or a function // scope, we treat it as such and introduce the function with its // initial value upon entering the corresponding scope. @@ -3365,14 +3356,10 @@ int ParserTraits::DeclareArrowParametersFromExpression( FunctionLiteral* Parser::ParseFunctionLiteral( - const AstRawString* function_name, - Scanner::Location function_name_location, - bool name_is_strict_reserved, - bool is_generator, - int function_token_pos, + const AstRawString* function_name, Scanner::Location function_name_location, + bool name_is_strict_reserved, FunctionKind kind, int function_token_pos, FunctionLiteral::FunctionType function_type, - FunctionLiteral::ArityRestriction arity_restriction, - bool* ok) { + FunctionLiteral::ArityRestriction arity_restriction, bool* ok) { // Function :: // '(' FormalParameterList? ')' '{' FunctionBody '}' // @@ -3385,6 +3372,8 @@ FunctionLiteral* Parser::ParseFunctionLiteral( int pos = function_token_pos == RelocInfo::kNoPosition ? peek_position() : function_token_pos; + bool is_generator = IsGeneratorFunction(kind); + // Anonymous functions were passed either the empty symbol or a null // handle as the function name. Remember if we were passed a non-empty // handle to decide whether to invoke function name inference. @@ -3593,7 +3582,8 @@ FunctionLiteral* Parser::ParseFunctionLiteral( } // Validate strict mode. - if (strict_mode() == STRICT) { + // Concise methods use StrictFormalParameters. + if (strict_mode() == STRICT || IsConciseMethod(kind)) { CheckStrictFunctionNameAndParameters(function_name, name_is_strict_reserved, function_name_location, @@ -3601,6 +3591,8 @@ FunctionLiteral* Parser::ParseFunctionLiteral( dupe_error_loc, reserved_loc, CHECK_OK); + } + if (strict_mode() == STRICT) { CheckOctalLiteral(scope->start_position(), scope->end_position(), CHECK_OK); @@ -3613,9 +3605,6 @@ FunctionLiteral* Parser::ParseFunctionLiteral( } } - FunctionLiteral::KindFlag kind = is_generator - ? FunctionLiteral::kGeneratorFunction - : FunctionLiteral::kNormalFunction; FunctionLiteral* function_literal = factory()->NewFunctionLiteral( function_name, ast_value_factory_, scope, body, materialized_literal_count, expected_property_count, handler_count, @@ -3775,6 +3764,8 @@ PreParser::PreParseResult Parser::ParseLazyFunctionBodyWithPreParser( reusable_preparser_->set_allow_harmony_numeric_literals( allow_harmony_numeric_literals()); reusable_preparser_->set_allow_classes(allow_classes()); + reusable_preparser_->set_allow_harmony_object_literals( + allow_harmony_object_literals()); } PreParser::PreParseResult result = reusable_preparser_->PreParseLazyFunction(strict_mode(), diff --git a/src/parser.h b/src/parser.h index c975471..a344252 100644 --- a/src/parser.h +++ b/src/parser.h @@ -573,14 +573,10 @@ class ParserTraits { // Temporary glue; these functions will move to ParserBase. Expression* ParseV8Intrinsic(bool* ok); FunctionLiteral* ParseFunctionLiteral( - const AstRawString* name, - Scanner::Location function_name_location, - bool name_is_strict_reserved, - bool is_generator, - int function_token_position, - FunctionLiteral::FunctionType type, - FunctionLiteral::ArityRestriction arity_restriction, - bool* ok); + const AstRawString* name, Scanner::Location function_name_location, + bool name_is_strict_reserved, FunctionKind kind, + int function_token_position, FunctionLiteral::FunctionType type, + FunctionLiteral::ArityRestriction arity_restriction, bool* ok); V8_INLINE void SkipLazyFunctionBody(const AstRawString* name, int* materialized_literal_count, int* expected_property_count, bool* ok); @@ -746,14 +742,10 @@ class Parser : public ParserBase { Statement* body, bool* ok); FunctionLiteral* ParseFunctionLiteral( - const AstRawString* name, - Scanner::Location function_name_location, - bool name_is_strict_reserved, - bool is_generator, - int function_token_position, - FunctionLiteral::FunctionType type, - FunctionLiteral::ArityRestriction arity_restriction, - bool* ok); + const AstRawString* name, Scanner::Location function_name_location, + bool name_is_strict_reserved, FunctionKind kind, + int function_token_position, FunctionLiteral::FunctionType type, + FunctionLiteral::ArityRestriction arity_restriction, bool* ok); // Magical syntax support. Expression* ParseV8Intrinsic(bool* ok); diff --git a/src/preparser.cc b/src/preparser.cc index f100f4a..b658f5c 100644 --- a/src/preparser.cc +++ b/src/preparser.cc @@ -102,16 +102,12 @@ PreParserExpression PreParserTraits::ParseV8Intrinsic(bool* ok) { PreParserExpression PreParserTraits::ParseFunctionLiteral( - PreParserIdentifier name, - Scanner::Location function_name_location, - bool name_is_strict_reserved, - bool is_generator, - int function_token_position, - FunctionLiteral::FunctionType type, - FunctionLiteral::ArityRestriction arity_restriction, - bool* ok) { + PreParserIdentifier name, Scanner::Location function_name_location, + bool name_is_strict_reserved, FunctionKind kind, + int function_token_position, FunctionLiteral::FunctionType type, + FunctionLiteral::ArityRestriction arity_restriction, bool* ok) { return pre_parser_->ParseFunctionLiteral( - name, function_name_location, name_is_strict_reserved, is_generator, + name, function_name_location, name_is_strict_reserved, kind, function_token_position, type, arity_restriction, ok); } @@ -340,14 +336,11 @@ PreParser::Statement PreParser::ParseFunctionDeclaration(bool* ok) { bool is_strict_reserved = false; Identifier name = ParseIdentifierOrStrictReservedWord( &is_strict_reserved, CHECK_OK); - ParseFunctionLiteral(name, - scanner()->location(), - is_strict_reserved, - is_generator, - pos, - FunctionLiteral::DECLARATION, - FunctionLiteral::NORMAL_ARITY, - CHECK_OK); + ParseFunctionLiteral(name, scanner()->location(), is_strict_reserved, + is_generator ? FunctionKind::kGeneratorFunction + : FunctionKind::kNormalFunction, + pos, FunctionLiteral::DECLARATION, + FunctionLiteral::NORMAL_ARITY, CHECK_OK); return Statement::FunctionDeclaration(); } @@ -805,14 +798,10 @@ PreParser::Statement PreParser::ParseDebuggerStatement(bool* ok) { PreParser::Expression PreParser::ParseFunctionLiteral( - Identifier function_name, - Scanner::Location function_name_location, - bool name_is_strict_reserved, - bool is_generator, - int function_token_pos, + Identifier function_name, Scanner::Location function_name_location, + bool name_is_strict_reserved, FunctionKind kind, int function_token_pos, FunctionLiteral::FunctionType function_type, - FunctionLiteral::ArityRestriction arity_restriction, - bool* ok) { + FunctionLiteral::ArityRestriction arity_restriction, bool* ok) { // Function :: // '(' FormalParameterList? ')' '{' FunctionBody '}' @@ -821,7 +810,7 @@ PreParser::Expression PreParser::ParseFunctionLiteral( PreParserScope function_scope(scope_, FUNCTION_SCOPE); FunctionState function_state(&function_state_, &scope_, &function_scope, NULL, this->ast_value_factory()); - function_state.set_is_generator(is_generator); + function_state.set_is_generator(IsGeneratorFunction(kind)); // FormalParameterList :: // '(' (Identifier)*[','] ')' Expect(Token::LPAREN, CHECK_OK); @@ -876,7 +865,8 @@ PreParser::Expression PreParser::ParseFunctionLiteral( // Validate strict mode. We can do this only after parsing the function, // since the function can declare itself strict. - if (strict_mode() == STRICT) { + // Concise methods use StrictFormalParameters. + if (strict_mode() == STRICT || IsConciseMethod(kind)) { if (function_name.IsEvalOrArguments()) { ReportMessageAt(function_name_location, "strict_eval_arguments"); *ok = false; diff --git a/src/preparser.h b/src/preparser.h index 87addfb..15887ba 100644 --- a/src/preparser.h +++ b/src/preparser.h @@ -85,6 +85,7 @@ class ParserBase : public Traits { allow_natives_syntax_(false), allow_generators_(false), allow_arrow_functions_(false), + allow_harmony_object_literals_(false), zone_(zone), ast_node_id_gen_(ast_node_id_gen) {} @@ -100,6 +101,9 @@ class ParserBase : public Traits { return scanner()->HarmonyNumericLiterals(); } bool allow_classes() const { return scanner()->HarmonyClasses(); } + bool allow_harmony_object_literals() const { + return allow_harmony_object_literals_; + } // Setters that determine whether certain syntactical constructs are // allowed to be parsed by this instance of the parser. @@ -114,8 +118,9 @@ class ParserBase : public Traits { void set_allow_harmony_numeric_literals(bool allow) { scanner()->SetHarmonyNumericLiterals(allow); } - void set_allow_classes(bool allow) { - scanner()->SetHarmonyClasses(allow); + void set_allow_classes(bool allow) { scanner()->SetHarmonyClasses(allow); } + void set_allow_harmony_object_literals(bool allow) { + allow_harmony_object_literals_ = allow; } protected: @@ -481,6 +486,7 @@ class ParserBase : public Traits { ExpressionT ParseObjectLiteral(bool* ok); ObjectLiteralPropertyT ParsePropertyDefinition(ObjectLiteralChecker* checker, bool* ok); + IdentifierT ParsePropertyName(bool* is_getter, bool* is_setter, bool* ok); typename Traits::Type::ExpressionList ParseArguments(bool* ok); ExpressionT ParseAssignmentExpression(bool accept_IN, bool* ok); ExpressionT ParseYieldExpression(bool* ok); @@ -579,6 +585,7 @@ class ParserBase : public Traits { bool allow_natives_syntax_; bool allow_generators_; bool allow_arrow_functions_; + bool allow_harmony_object_literals_; typename Traits::Type::Zone* zone_; // Only used by Parser. AstNode::IdGen* ast_node_id_gen_; @@ -1054,8 +1061,8 @@ class PreParserFactory { FunctionLiteral::ParameterFlag has_duplicate_parameters, FunctionLiteral::FunctionType function_type, FunctionLiteral::IsFunctionFlag is_function, - FunctionLiteral::IsParenthesizedFlag is_parenthesized, - FunctionLiteral::KindFlag kind, int position) { + FunctionLiteral::IsParenthesizedFlag is_parenthesized, FunctionKind kind, + int position) { return PreParserExpression::Default(); } @@ -1331,14 +1338,10 @@ class PreParserTraits { // Temporary glue; these functions will move to ParserBase. PreParserExpression ParseV8Intrinsic(bool* ok); PreParserExpression ParseFunctionLiteral( - PreParserIdentifier name, - Scanner::Location function_name_location, - bool name_is_strict_reserved, - bool is_generator, - int function_token_position, - FunctionLiteral::FunctionType type, - FunctionLiteral::ArityRestriction arity_restriction, - bool* ok); + PreParserIdentifier name, Scanner::Location function_name_location, + bool name_is_strict_reserved, FunctionKind kind, + int function_token_position, FunctionLiteral::FunctionType type, + FunctionLiteral::ArityRestriction arity_restriction, bool* ok); private: PreParser* pre_parser_; @@ -1469,14 +1472,10 @@ class PreParser : public ParserBase { bool is_generator, bool* ok); Expression ParseFunctionLiteral( - Identifier name, - Scanner::Location function_name_location, - bool name_is_strict_reserved, - bool is_generator, - int function_token_pos, + Identifier name, Scanner::Location function_name_location, + bool name_is_strict_reserved, FunctionKind kind, int function_token_pos, FunctionLiteral::FunctionType function_type, - FunctionLiteral::ArityRestriction arity_restriction, - bool* ok); + FunctionLiteral::ArityRestriction arity_restriction, bool* ok); void ParseLazyFunctionLiteralBody(bool* ok); bool CheckInOrOf(bool accept_OF); @@ -1852,84 +1851,85 @@ typename ParserBase::ExpressionT ParserBase::ParseArrayLiteral( template -typename ParserBase::ObjectLiteralPropertyT ParserBase< - Traits>::ParsePropertyDefinition(ObjectLiteralChecker* checker, bool* ok) { - LiteralT key = this->EmptyLiteral(); +typename ParserBase::IdentifierT ParserBase::ParsePropertyName( + bool* is_getter, bool* is_setter, bool* ok) { Token::Value next = peek(); - int next_pos = peek_position(); - switch (next) { - case Token::STRING: { + case Token::STRING: Consume(Token::STRING); - IdentifierT string = this->GetSymbol(scanner_); - if (fni_ != NULL) this->PushLiteralName(fni_, string); - uint32_t index; - if (this->IsArrayIndex(string, &index)) { - key = factory()->NewNumberLiteral(index, next_pos); - break; - } - key = factory()->NewStringLiteral(string, next_pos); - break; - } - case Token::NUMBER: { + return this->GetSymbol(scanner_); + case Token::NUMBER: Consume(Token::NUMBER); - key = this->ExpressionFromLiteral(Token::NUMBER, next_pos, scanner_, - factory()); - break; - } - default: { - bool is_getter = false; - bool is_setter = false; - IdentifierT id = ParseIdentifierNameOrGetOrSet( - &is_getter, &is_setter, CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); - if (fni_ != NULL) this->PushLiteralName(fni_, id); - - if ((is_getter || is_setter) && peek() != Token::COLON) { - // Special handling of getter and setter syntax: - // { ... , get foo() { ... }, ... , set foo(v) { ... v ... } , ... } - // We have already read the "get" or "set" keyword. - IdentifierT name = this->EmptyIdentifier(); - switch (peek()) { - case Token::STRING: - Consume(Token::STRING); - name = this->GetSymbol(scanner_); - break; - case Token::NUMBER: - Consume(Token::NUMBER); - name = this->GetNumberAsSymbol(scanner_); - break; - default: - name = ParseIdentifierName( - CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); - } - // Validate the property. - PropertyKind type = is_getter ? kGetterProperty : kSetterProperty; - checker->CheckProperty(next, type, - CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); - typename Traits::Type::FunctionLiteral value = - this->ParseFunctionLiteral( - name, scanner()->location(), - false, // reserved words are allowed here - false, // not a generator - RelocInfo::kNoPosition, FunctionLiteral::ANONYMOUS_EXPRESSION, - is_getter ? FunctionLiteral::GETTER_ARITY - : FunctionLiteral::SETTER_ARITY, - CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); - return factory()->NewObjectLiteralProperty(is_getter, value, next_pos); - } - // Failed to parse as get/set property, so it's just a normal property - // (which might be called "get" or "set" or something else). - key = factory()->NewStringLiteral(id, next_pos); - } + return this->GetNumberAsSymbol(scanner_); + default: + return ParseIdentifierNameOrGetOrSet(is_getter, is_setter, + CHECK_OK_CUSTOM(EmptyIdentifier)); } +} + - // Validate the property - checker->CheckProperty(next, kValueProperty, - CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); +template +typename ParserBase::ObjectLiteralPropertyT ParserBase< + Traits>::ParsePropertyDefinition(ObjectLiteralChecker* checker, bool* ok) { + // TODO(arv): Add support for concise generator methods. + ExpressionT value = this->EmptyExpression(); + bool is_getter = false; + bool is_setter = false; + Token::Value name_token = peek(); + int next_pos = peek_position(); + IdentifierT name = ParsePropertyName( + &is_getter, &is_setter, CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); + if (fni_ != NULL) this->PushLiteralName(fni_, name); + + if (peek() == Token::COLON) { + // PropertyDefinition : PropertyName ':' AssignmentExpression + checker->CheckProperty(name_token, kValueProperty, + CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); + Consume(Token::COLON); + value = this->ParseAssignmentExpression( + true, CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); + + } else if (allow_harmony_object_literals_ && peek() == Token::LPAREN) { + // Concise Method + checker->CheckProperty(name_token, kValueProperty, + CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); + value = this->ParseFunctionLiteral( + name, scanner()->location(), + false, // reserved words are allowed here + FunctionKind::kConciseMethod, RelocInfo::kNoPosition, + FunctionLiteral::ANONYMOUS_EXPRESSION, FunctionLiteral::NORMAL_ARITY, + CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); + + } else if (is_getter || is_setter) { + // Accessor + bool dont_care = false; + name_token = peek(); + name = ParsePropertyName(&dont_care, &dont_care, + CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); + // Validate the property. + checker->CheckProperty(name_token, + is_getter ? kGetterProperty : kSetterProperty, + CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); + typename Traits::Type::FunctionLiteral value = this->ParseFunctionLiteral( + name, scanner()->location(), + false, // reserved words are allowed here + FunctionKind::kNormalFunction, RelocInfo::kNoPosition, + FunctionLiteral::ANONYMOUS_EXPRESSION, + is_getter ? FunctionLiteral::GETTER_ARITY + : FunctionLiteral::SETTER_ARITY, + CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); + return factory()->NewObjectLiteralProperty(is_getter, value, next_pos); + } else { + Token::Value next = Next(); + ReportUnexpectedToken(next); + *ok = false; + return this->EmptyObjectLiteralProperty(); + } - Expect(Token::COLON, CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); - ExpressionT value = this->ParseAssignmentExpression( - true, CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); + uint32_t index; + LiteralT key = this->IsArrayIndex(name, &index) + ? factory()->NewNumberLiteral(index, next_pos) + : factory()->NewStringLiteral(name, next_pos); return factory()->NewObjectLiteralProperty(key, value); } @@ -2428,14 +2428,12 @@ ParserBase::ParseMemberExpression(bool* ok) { function_name_location = scanner()->location(); function_type = FunctionLiteral::NAMED_EXPRESSION; } - result = this->ParseFunctionLiteral(name, - function_name_location, - is_strict_reserved_name, - is_generator, - function_token_position, - function_type, - FunctionLiteral::NORMAL_ARITY, - CHECK_OK); + result = this->ParseFunctionLiteral( + name, function_name_location, is_strict_reserved_name, + is_generator ? FunctionKind::kGeneratorFunction + : FunctionKind::kNormalFunction, + function_token_position, function_type, FunctionLiteral::NORMAL_ARITY, + CHECK_OK); } else if (peek() == Token::SUPER) { int beg_pos = position(); Consume(Token::SUPER); @@ -2596,7 +2594,7 @@ typename ParserBase::ExpressionT ParserBase< materialized_literal_count, expected_property_count, handler_count, num_parameters, FunctionLiteral::kNoDuplicateParameters, FunctionLiteral::ANONYMOUS_EXPRESSION, FunctionLiteral::kIsFunction, - FunctionLiteral::kNotParenthesized, FunctionLiteral::kArrowFunction, + FunctionLiteral::kNotParenthesized, FunctionKind::kArrowFunction, start_pos); function_literal->set_function_token_position(start_pos); diff --git a/src/runtime.cc b/src/runtime.cc index d18c22c..77c7bb9 100644 --- a/src/runtime.cc +++ b/src/runtime.cc @@ -2775,6 +2775,14 @@ RUNTIME_FUNCTION(Runtime_FunctionIsArrow) { } +RUNTIME_FUNCTION(Runtime_FunctionIsConciseMethod) { + SealHandleScope shs(isolate); + DCHECK(args.length() == 1); + CONVERT_ARG_CHECKED(JSFunction, f, 0); + return isolate->heap()->ToBoolean(f->shared()->is_concise_method()); +} + + RUNTIME_FUNCTION(Runtime_FunctionRemovePrototype) { SealHandleScope shs(isolate); DCHECK(args.length() == 1); @@ -8125,8 +8133,8 @@ RUNTIME_FUNCTION(Runtime_NewClosureFromStubFailure) { CONVERT_ARG_HANDLE_CHECKED(SharedFunctionInfo, shared, 0); Handle context(isolate->context()); PretenureFlag pretenure_flag = NOT_TENURED; - return *isolate->factory()->NewFunctionFromSharedFunctionInfo( - shared, context, pretenure_flag); + return *isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context, + pretenure_flag); } diff --git a/src/runtime.h b/src/runtime.h index 6be7515..4f11c2e 100644 --- a/src/runtime.h +++ b/src/runtime.h @@ -197,6 +197,7 @@ namespace internal { F(FunctionMarkNameShouldPrintAsAnonymous, 1, 1) \ F(FunctionIsGenerator, 1, 1) \ F(FunctionIsArrow, 1, 1) \ + F(FunctionIsConciseMethod, 1, 1) \ F(FunctionBindArguments, 4, 1) \ F(BoundFunctionGetBindings, 1, 1) \ F(FunctionRemovePrototype, 1, 1) \ diff --git a/src/v8natives.js b/src/v8natives.js index a522738..405e7d6 100644 --- a/src/v8natives.js +++ b/src/v8natives.js @@ -1757,7 +1757,12 @@ function FunctionSourceString(func) { var name = %FunctionNameShouldPrintAsAnonymous(func) ? 'anonymous' : %FunctionGetName(func); - var head = %FunctionIsGenerator(func) ? 'function* ' : 'function '; + + // TODO(arv): Handle concise generator methods. + + var head = %FunctionIsConciseMethod(func) + ? '' + : %FunctionIsGenerator(func) ? 'function* ' : 'function '; return head + name + source; } diff --git a/src/x64/full-codegen-x64.cc b/src/x64/full-codegen-x64.cc index fd6bcae..5babef0 100644 --- a/src/x64/full-codegen-x64.cc +++ b/src/x64/full-codegen-x64.cc @@ -1288,9 +1288,7 @@ void FullCodeGenerator::EmitNewClosure(Handle info, !pretenure && scope()->is_function_scope() && info->num_literals() == 0) { - FastNewClosureStub stub(isolate(), - info->strict_mode(), - info->is_generator()); + FastNewClosureStub stub(isolate(), info->strict_mode(), info->kind()); __ Move(rbx, info); __ CallStub(&stub); } else { diff --git a/src/x64/lithium-codegen-x64.cc b/src/x64/lithium-codegen-x64.cc index c39833e..c59d9e0 100644 --- a/src/x64/lithium-codegen-x64.cc +++ b/src/x64/lithium-codegen-x64.cc @@ -5457,9 +5457,8 @@ void LCodeGen::DoFunctionLiteral(LFunctionLiteral* instr) { // space for nested functions that don't need literals cloning. bool pretenure = instr->hydrogen()->pretenure(); if (!pretenure && instr->hydrogen()->has_no_literals()) { - FastNewClosureStub stub(isolate(), - instr->hydrogen()->strict_mode(), - instr->hydrogen()->is_generator()); + FastNewClosureStub stub(isolate(), instr->hydrogen()->strict_mode(), + instr->hydrogen()->kind()); __ Move(rbx, instr->hydrogen()->shared_info()); CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); } else { diff --git a/src/x87/full-codegen-x87.cc b/src/x87/full-codegen-x87.cc index a9b2b31..78d2ec0 100644 --- a/src/x87/full-codegen-x87.cc +++ b/src/x87/full-codegen-x87.cc @@ -1251,9 +1251,7 @@ void FullCodeGenerator::EmitNewClosure(Handle info, !pretenure && scope()->is_function_scope() && info->num_literals() == 0) { - FastNewClosureStub stub(isolate(), - info->strict_mode(), - info->is_generator()); + FastNewClosureStub stub(isolate(), info->strict_mode(), info->kind()); __ mov(ebx, Immediate(info)); __ CallStub(&stub); } else { diff --git a/src/x87/lithium-codegen-x87.cc b/src/x87/lithium-codegen-x87.cc index 6a3f991..07c9fb0 100644 --- a/src/x87/lithium-codegen-x87.cc +++ b/src/x87/lithium-codegen-x87.cc @@ -5295,9 +5295,8 @@ void LCodeGen::DoFunctionLiteral(LFunctionLiteral* instr) { // space for nested functions that don't need literals cloning. bool pretenure = instr->hydrogen()->pretenure(); if (!pretenure && instr->hydrogen()->has_no_literals()) { - FastNewClosureStub stub(isolate(), - instr->hydrogen()->strict_mode(), - instr->hydrogen()->is_generator()); + FastNewClosureStub stub(isolate(), instr->hydrogen()->strict_mode(), + instr->hydrogen()->kind()); __ mov(ebx, Immediate(instr->hydrogen()->shared_info())); CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); } else { diff --git a/test/cctest/test-parsing.cc b/test/cctest/test-parsing.cc index f4400a4..fea34a8 100644 --- a/test/cctest/test-parsing.cc +++ b/test/cctest/test-parsing.cc @@ -1217,7 +1217,8 @@ enum ParserFlag { kAllowGenerators, kAllowHarmonyNumericLiterals, kAllowArrowFunctions, - kAllowClasses + kAllowClasses, + kAllowHarmonyObjectLiterals }; @@ -1237,6 +1238,8 @@ void SetParserFlags(i::ParserBase* parser, parser->set_allow_generators(flags.Contains(kAllowGenerators)); parser->set_allow_harmony_numeric_literals( flags.Contains(kAllowHarmonyNumericLiterals)); + parser->set_allow_harmony_object_literals( + flags.Contains(kAllowHarmonyObjectLiterals)); parser->set_allow_arrow_functions(flags.Contains(kAllowArrowFunctions)); parser->set_allow_classes(flags.Contains(kAllowClasses)); } @@ -1446,9 +1449,11 @@ TEST(ParserSync) { CcTest::i_isolate()->stack_guard()->SetStackLimit( i::GetCurrentStackPosition() - 128 * 1024); - static const ParserFlag flags1[] = {kAllowLazy, kAllowHarmonyScoping, - kAllowModules, kAllowGenerators, - kAllowArrowFunctions}; + static const ParserFlag flags1[] = { + kAllowLazy, kAllowHarmonyScoping, + kAllowModules, kAllowGenerators, + kAllowArrowFunctions, kAllowHarmonyNumericLiterals, + kAllowHarmonyObjectLiterals}; for (int i = 0; context_data[i][0] != NULL; ++i) { for (int j = 0; statement_data[j] != NULL; ++j) { for (int k = 0; termination_data[k] != NULL; ++k) { @@ -1523,9 +1528,12 @@ void RunParserSyncTest(const char* context_data[][2], i::GetCurrentStackPosition() - 128 * 1024); static const ParserFlag default_flags[] = { - kAllowLazy, kAllowHarmonyScoping, kAllowModules, - kAllowGenerators, kAllowNativesSyntax, kAllowArrowFunctions, - kAllowClasses}; + kAllowArrowFunctions, kAllowClasses, + kAllowGenerators, kAllowHarmonyNumericLiterals, + kAllowHarmonyObjectLiterals, kAllowHarmonyScoping, + kAllowLazy, kAllowModules, + kAllowNativesSyntax, + }; ParserFlag* generated_flags = NULL; if (flags == NULL) { flags = default_flags; @@ -2520,23 +2528,36 @@ TEST(ErrorsObjectLiteralChecking) { }; const char* statement_data[] = { - ",", "foo: 1, get foo() {}", "foo: 1, set foo(v) {}", - "\"foo\": 1, get \"foo\"() {}", "\"foo\": 1, set \"foo\"(v) {}", - "1: 1, get 1() {}", "1: 1, set 1() {}", + ",", + "foo: 1, get foo() {}", + "foo: 1, set foo(v) {}", + "\"foo\": 1, get \"foo\"() {}", + "\"foo\": 1, set \"foo\"(v) {}", + "1: 1, get 1() {}", + "1: 1, set 1() {}", + "get foo() {}, get foo() {}", + "set foo(_) {}, set foo(_) {}", // It's counter-intuitive, but these collide too (even in classic // mode). Note that we can have "foo" and foo as properties in classic // mode, // but we cannot have "foo" and get foo, or foo and get "foo". - "foo: 1, get \"foo\"() {}", "foo: 1, set \"foo\"(v) {}", - "\"foo\": 1, get foo() {}", "\"foo\": 1, set foo(v) {}", - "1: 1, get \"1\"() {}", "1: 1, set \"1\"() {}", + "foo: 1, get \"foo\"() {}", + "foo: 1, set \"foo\"(v) {}", + "\"foo\": 1, get foo() {}", + "\"foo\": 1, set foo(v) {}", + "1: 1, get \"1\"() {}", + "1: 1, set \"1\"() {}", "\"1\": 1, get 1() {}" "\"1\": 1, set 1(v) {}" // Wrong number of parameters "get bar(x) {}", - "get bar(x, y) {}", "set bar() {}", "set bar(x, y) {}", + "get bar(x, y) {}", + "set bar() {}", + "set bar(x, y) {}", // Parsing FunctionLiteral for getter or setter fails - "get foo( +", "get foo() \"error\"", NULL}; + "get foo( +", + "get foo() \"error\"", + NULL}; RunParserSyncTest(context_data, statement_data, kError); } @@ -2573,6 +2594,8 @@ TEST(NoErrorsObjectLiteralChecking) { "\"foo\": 1, set \"bar\"(v) {}", "1: 1, get 2() {}", "1: 1, set 2(v) {}", + "get: 1, get foo() {}", + "set: 1, set foo(_) {}", // Keywords, future reserved and strict future reserved are also allowed as // property names. "if: 4", @@ -3392,3 +3415,144 @@ TEST(ErrorsSuper) { RunParserSyncTest(context_data, statement_data, kError, NULL, 0, always_flags, arraysize(always_flags)); } + + +TEST(NoErrorsMethodDefinition) { + const char* context_data[][2] = {{"({", "});"}, + {"'use strict'; ({", "});"}, + {NULL, NULL}}; + + const char* object_literal_body_data[] = { + "m() {}", + "m(x) { return x; }", + "m(x, y) {}, n() {}", + "set(x, y) {}", + "get(x, y) {}", + NULL + }; + + static const ParserFlag always_flags[] = {kAllowHarmonyObjectLiterals}; + RunParserSyncTest(context_data, object_literal_body_data, kSuccess, NULL, 0, + always_flags, arraysize(always_flags)); +} + + +TEST(MethodDefinitionNames) { + const char* context_data[][2] = {{"({", "(x, y) {}});"}, + {"'use strict'; ({", "(x, y) {}});"}, + {NULL, NULL}}; + + const char* name_data[] = { + "m", + "'m'", + "\"m\"", + "\"m n\"", + "true", + "false", + "null", + "0", + "1.2", + "1e1", + "1E1", + "1e+1", + "1e-1", + + // Keywords + "async", + "await", + "break", + "case", + "catch", + "class", + "const", + "continue", + "debugger", + "default", + "delete", + "do", + "else", + "enum", + "export", + "extends", + "finally", + "for", + "function", + "if", + "implements", + "import", + "in", + "instanceof", + "interface", + "let", + "new", + "package", + "private", + "protected", + "public", + "return", + "static", + "super", + "switch", + "this", + "throw", + "try", + "typeof", + "var", + "void", + "while", + "with", + "yield", + NULL + }; + + static const ParserFlag always_flags[] = {kAllowHarmonyObjectLiterals}; + RunParserSyncTest(context_data, name_data, kSuccess, NULL, 0, + always_flags, arraysize(always_flags)); +} + + +TEST(MethodDefinitionStrictFormalParamereters) { + const char* context_data[][2] = {{"({method(", "){}});"}, + {"'use strict'; ({method(", "){}});"}, + {NULL, NULL}}; + + const char* params_data[] = { + "x, x", + "x, y, x", + "eval", + "arguments", + "var", + "const", + NULL + }; + + static const ParserFlag always_flags[] = {kAllowHarmonyObjectLiterals}; + RunParserSyncTest(context_data, params_data, kError, NULL, 0, + always_flags, arraysize(always_flags)); +} + + +TEST(MethodDefinitionDuplicateProperty) { + // Duplicate properties are allowed in ES6 but we haven't removed that check + // yet. + const char* context_data[][2] = {{"'use strict'; ({", "});"}, + {NULL, NULL}}; + + const char* params_data[] = { + "x: 1, x() {}", + "x() {}, x: 1", + "x() {}, get x() {}", + "x() {}, set x(_) {}", + "x() {}, x() {}", + "x() {}, y() {}, x() {}", + "x() {}, \"x\"() {}", + "x() {}, 'x'() {}", + "0() {}, '0'() {}", + "1.0() {}, 1: 1", + NULL + }; + + static const ParserFlag always_flags[] = {kAllowHarmonyObjectLiterals}; + RunParserSyncTest(context_data, params_data, kError, NULL, 0, + always_flags, arraysize(always_flags)); +} diff --git a/test/mjsunit/harmony/object-literals-method.js b/test/mjsunit/harmony/object-literals-method.js new file mode 100644 index 0000000..2af0859 --- /dev/null +++ b/test/mjsunit/harmony/object-literals-method.js @@ -0,0 +1,123 @@ +// Copyright 2014 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. + +// Flags: --harmony-object-literals --allow-natives-syntax + + +(function TestDescriptor() { + var object = { + method() { + return 42; + } + }; + assertEquals(42, object.method()); +})(); + + +(function TestDescriptor() { + var object = { + method() { + return 42; + } + }; + + var desc = Object.getOwnPropertyDescriptor(object, 'method'); + assertTrue(desc.enumerable); + assertTrue(desc.configurable); + assertTrue(desc.writable); + assertEquals('function', typeof desc.value); + + assertEquals(42, desc.value()); +})(); + + +(function TestProto() { + var object = { + method() { + return 42; + } + }; + + assertEquals(Function.prototype, Object.getPrototypeOf(object.method)); +})(); + + +(function TestNotConstructable() { + var object = { + method() { + return 42; + } + }; + + assertThrows(function() { + new object.method; + }); +})(); + + +(function TestFunctionName() { + var object = { + method() { + return 42; + }, + 1() {}, + 2.0() {} + }; + var f = object.method; + assertEquals('method', f.name); + var g = object[1]; + assertEquals('1', g.name); + + var h = object[2]; + assertEquals('2', h.name); +})(); + + +(function TestNoBinding() { + var method = 'local'; + var calls = 0; + var object = { + method() { + calls++; + assertEquals('local', method); + } + }; + object.method(); + assertEquals(1, calls); +})(); + + +(function TestNoPrototype() { + var object = { + method() { + return 42; + } + }; + var f = object.method; + assertFalse(f.hasOwnProperty('prototype')); + assertEquals(undefined, f.prototype); + + f.prototype = 42; + assertEquals(42, f.prototype); +})(); + + +(function TestToString() { + var object = { + method() { 42; } + }; + assertEquals('method() { 42; }', object.method.toString()); +})(); + + +(function TestOptimized() { + var object = { + method() { return 42; } + }; + assertEquals(42, object.method()); + assertEquals(42, object.method()); + %OptimizeFunctionOnNextCall(object.method); + assertEquals(42, object.method()); + assertFalse(object.method.hasOwnProperty('prototype')); +})(); diff --git a/test/mjsunit/runtime-gen/functionisconcisemethod.js b/test/mjsunit/runtime-gen/functionisconcisemethod.js new file mode 100644 index 0000000..95bc85b --- /dev/null +++ b/test/mjsunit/runtime-gen/functionisconcisemethod.js @@ -0,0 +1,5 @@ +// Copyright 2014 the V8 project authors. All rights reserved. +// AUTO-GENERATED BY tools/generate-runtime-tests.py, DO NOT MODIFY +// Flags: --allow-natives-syntax --harmony --harmony-proxies +var _f = function() {}; +%FunctionIsConciseMethod(_f); -- 2.7.4