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
This commit is contained in:
parent
9261c44fd4
commit
45d8e74cd6
@ -1332,9 +1332,7 @@ void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> 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 {
|
||||
|
@ -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 {
|
||||
|
@ -1318,9 +1318,7 @@ void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> 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 {
|
||||
|
@ -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 {
|
||||
|
31
src/ast.h
31
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:
|
||||
@ -2492,8 +2494,7 @@ class FunctionLiteral FINAL : public Expression {
|
||||
class HasDuplicateParameters : public BitField<ParameterFlag, 3, 1> {};
|
||||
class IsFunction : public BitField<IsFunctionFlag, 4, 1> {};
|
||||
class IsParenthesized : public BitField<IsParenthesizedFlag, 5, 1> {};
|
||||
class IsGenerator : public BitField<bool, 6, 1> {};
|
||||
class IsArrow : public BitField<bool, 7, 1> {};
|
||||
class FunctionKindBits : public BitField<FunctionKind, 6, 3> {};
|
||||
};
|
||||
|
||||
|
||||
@ -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,
|
||||
|
@ -1343,7 +1343,7 @@ HValue* CodeStubGraphBuilder<FastNewClosureStub>::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.
|
||||
|
@ -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<StrictMode, 0, 1> {};
|
||||
class IsGeneratorBits : public BitField<bool, 1, 1> {};
|
||||
class FunctionKindBits : public BitField<FunctionKind, 1, 3> {};
|
||||
|
||||
DEFINE_CALL_INTERFACE_DESCRIPTOR(FastNewClosure);
|
||||
DEFINE_HYDROGEN_CODE_STUB(FastNewClosure, HydrogenCodeStub);
|
||||
|
@ -654,8 +654,7 @@ static void SetFunctionInfo(Handle<SharedFunctionInfo> 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<SharedFunctionInfo> 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<SharedFunctionInfo> Compiler::BuildFunctionInfo(
|
||||
|
||||
// Create a shared function info object.
|
||||
Handle<SharedFunctionInfo> 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);
|
||||
|
@ -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;
|
||||
|
@ -1237,6 +1237,9 @@ void Factory::InitializeFunction(Handle<JSFunction> 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<JSFunction> Factory::NewFunctionFromSharedFunctionInfo(
|
||||
Handle<SharedFunctionInfo> info,
|
||||
Handle<Context> 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(Map::cast(context->native_context()->get(map_index)));
|
||||
Handle<JSFunction> result = NewFunction(map, info, context, pretenure);
|
||||
|
||||
@ -1904,13 +1906,14 @@ Handle<FixedArray> Factory::NewTypeFeedbackVector(int slot_count) {
|
||||
|
||||
|
||||
Handle<SharedFunctionInfo> Factory::NewSharedFunctionInfo(
|
||||
Handle<String> name, int number_of_literals, bool is_generator,
|
||||
bool is_arrow, Handle<Code> code, Handle<ScopeInfo> scope_info,
|
||||
Handle<String> name, int number_of_literals, FunctionKind kind,
|
||||
Handle<Code> code, Handle<ScopeInfo> scope_info,
|
||||
Handle<FixedArray> feedback_vector) {
|
||||
DCHECK(IsValidFunctionKind(kind));
|
||||
Handle<SharedFunctionInfo> 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<SharedFunctionInfo> 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);
|
||||
}
|
||||
|
@ -598,8 +598,8 @@ class Factory FINAL {
|
||||
|
||||
// Allocates a new SharedFunctionInfo object.
|
||||
Handle<SharedFunctionInfo> NewSharedFunctionInfo(
|
||||
Handle<String> name, int number_of_literals, bool is_generator,
|
||||
bool is_arrow, Handle<Code> code, Handle<ScopeInfo> scope_info,
|
||||
Handle<String> name, int number_of_literals, FunctionKind kind,
|
||||
Handle<Code> code, Handle<ScopeInfo> scope_info,
|
||||
Handle<FixedArray> feedback_vector);
|
||||
Handle<SharedFunctionInfo> NewSharedFunctionInfo(Handle<String> name,
|
||||
MaybeHandle<Code> code);
|
||||
|
@ -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)
|
||||
|
@ -1547,11 +1547,9 @@ void FullCodeGenerator::VisitNativeFunctionLiteral(
|
||||
const int literals = fun->NumberOfLiterals();
|
||||
Handle<Code> code = Handle<Code>(fun->shared()->code());
|
||||
Handle<Code> construct_stub = Handle<Code>(fun->shared()->construct_stub());
|
||||
bool is_generator = false;
|
||||
bool is_arrow = false;
|
||||
Handle<SharedFunctionInfo> shared =
|
||||
isolate()->factory()->NewSharedFunctionInfo(
|
||||
name, literals, is_generator, is_arrow, code,
|
||||
name, literals, FunctionKind::kNormalFunction, code,
|
||||
Handle<ScopeInfo>(fun->shared()->scope_info()),
|
||||
Handle<FixedArray>(fun->shared()->feedback_vector()));
|
||||
shared->set_construct_stub(*construct_stub);
|
||||
|
@ -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;
|
||||
|
@ -7481,18 +7481,20 @@ class HFunctionLiteral FINAL : public HTemplateInstruction<1> {
|
||||
Handle<SharedFunctionInfo> 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<SharedFunctionInfo> shared,
|
||||
HFunctionLiteral(HValue* context, Handle<SharedFunctionInfo> 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<SharedFunctionInfo> shared_info_;
|
||||
FunctionKind kind_;
|
||||
bool pretenure_ : 1;
|
||||
bool has_no_literals_ : 1;
|
||||
bool is_generator_ : 1;
|
||||
StrictMode strict_mode_;
|
||||
};
|
||||
|
||||
|
@ -1254,9 +1254,7 @@ void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> 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 {
|
||||
|
@ -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 {
|
||||
|
@ -1319,9 +1319,7 @@ void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> 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 {
|
||||
|
@ -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 {
|
||||
|
@ -1314,9 +1314,7 @@ void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> 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 {
|
||||
|
@ -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 {
|
||||
|
@ -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)
|
||||
|
@ -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,11 +7321,14 @@ class SharedFunctionInfo: public HeapObject {
|
||||
kIsFunction,
|
||||
kDontCache,
|
||||
kDontFlush,
|
||||
kIsGenerator,
|
||||
kIsArrow,
|
||||
kIsGenerator,
|
||||
kIsConciseMethod,
|
||||
kCompilerHintsCount // Pseudo entry
|
||||
};
|
||||
|
||||
class FunctionKindBits : public BitField<FunctionKind, kIsArrow, 3> {};
|
||||
|
||||
class DeoptCountBits : public BitField<int, 0, 4> {};
|
||||
class OptReenableTriesBits : public BitField<int, 4, 18> {};
|
||||
class ICAgeBits : public BitField<int, 22, 8> {};
|
||||
|
@ -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(),
|
||||
|
24
src/parser.h
24
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<ParserTraits> {
|
||||
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);
|
||||
|
@ -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;
|
||||
|
174
src/preparser.h
174
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<PreParserTraits> {
|
||||
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<Traits>::ExpressionT ParserBase<Traits>::ParseArrayLiteral(
|
||||
|
||||
|
||||
template <class Traits>
|
||||
typename ParserBase<Traits>::ObjectLiteralPropertyT ParserBase<
|
||||
Traits>::ParsePropertyDefinition(ObjectLiteralChecker* checker, bool* ok) {
|
||||
LiteralT key = this->EmptyLiteral();
|
||||
typename ParserBase<Traits>::IdentifierT ParserBase<Traits>::ParsePropertyName(
|
||||
bool* is_getter, bool* is_setter, bool* ok) {
|
||||
Token::Value next = peek();
|
||||
int next_pos = peek_position();
|
||||
|
||||
switch (next) {
|
||||
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: {
|
||||
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;
|
||||
return this->GetSymbol(scanner_);
|
||||
case Token::NUMBER:
|
||||
Consume(Token::NUMBER);
|
||||
name = this->GetNumberAsSymbol(scanner_);
|
||||
break;
|
||||
return this->GetNumberAsSymbol(scanner_);
|
||||
default:
|
||||
name = ParseIdentifierName(
|
||||
CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
|
||||
return ParseIdentifierNameOrGetOrSet(is_getter, is_setter,
|
||||
CHECK_OK_CUSTOM(EmptyIdentifier));
|
||||
}
|
||||
// Validate the property.
|
||||
PropertyKind type = is_getter ? kGetterProperty : kSetterProperty;
|
||||
checker->CheckProperty(next, type,
|
||||
}
|
||||
|
||||
|
||||
template <class Traits>
|
||||
typename ParserBase<Traits>::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));
|
||||
typename Traits::Type::FunctionLiteral value =
|
||||
this->ParseFunctionLiteral(
|
||||
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
|
||||
false, // not a generator
|
||||
RelocInfo::kNoPosition, FunctionLiteral::ANONYMOUS_EXPRESSION,
|
||||
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);
|
||||
}
|
||||
// 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);
|
||||
}
|
||||
} else {
|
||||
Token::Value next = Next();
|
||||
ReportUnexpectedToken(next);
|
||||
*ok = false;
|
||||
return this->EmptyObjectLiteralProperty();
|
||||
}
|
||||
|
||||
// Validate the property
|
||||
checker->CheckProperty(next, kValueProperty,
|
||||
CHECK_OK_CUSTOM(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,13 +2428,11 @@ ParserBase<Traits>::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,
|
||||
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();
|
||||
@ -2596,7 +2594,7 @@ typename ParserBase<Traits>::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);
|
||||
|
@ -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> context(isolate->context());
|
||||
PretenureFlag pretenure_flag = NOT_TENURED;
|
||||
return *isolate->factory()->NewFunctionFromSharedFunctionInfo(
|
||||
shared, context, pretenure_flag);
|
||||
return *isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context,
|
||||
pretenure_flag);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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) \
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -1288,9 +1288,7 @@ void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> 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 {
|
||||
|
@ -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 {
|
||||
|
@ -1251,9 +1251,7 @@ void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> 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 {
|
||||
|
@ -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 {
|
||||
|
@ -1217,7 +1217,8 @@ enum ParserFlag {
|
||||
kAllowGenerators,
|
||||
kAllowHarmonyNumericLiterals,
|
||||
kAllowArrowFunctions,
|
||||
kAllowClasses
|
||||
kAllowClasses,
|
||||
kAllowHarmonyObjectLiterals
|
||||
};
|
||||
|
||||
|
||||
@ -1237,6 +1238,8 @@ void SetParserFlags(i::ParserBase<Traits>* 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,
|
||||
static const ParserFlag flags1[] = {
|
||||
kAllowLazy, kAllowHarmonyScoping,
|
||||
kAllowModules, kAllowGenerators,
|
||||
kAllowArrowFunctions};
|
||||
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));
|
||||
}
|
||||
|
123
test/mjsunit/harmony/object-literals-method.js
Normal file
123
test/mjsunit/harmony/object-literals-method.js
Normal file
@ -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'));
|
||||
})();
|
5
test/mjsunit/runtime-gen/functionisconcisemethod.js
Normal file
5
test/mjsunit/runtime-gen/functionisconcisemethod.js
Normal file
@ -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);
|
Loading…
Reference in New Issue
Block a user