F(use_asm, "use asm") \
F(use_strong, "use strong") \
F(use_strict, "use strict") \
- F(value, "value")
+ F(value, "value") \
+ F(is_construct_call, "_IsConstructCall")
#define OTHER_CONSTANTS(F) \
F(true_value) \
class HasDuplicateParameters : public BitField<ParameterFlag, 3, 1> {};
class IsFunction : public BitField<IsFunctionFlag, 4, 1> {};
class IsParenthesized : public BitField<IsParenthesizedFlag, 5, 1> {};
- class FunctionKindBits : public BitField<FunctionKind, 6, 6> {};
+ class FunctionKindBits : public BitField<FunctionKind, 6, 7> {};
};
private:
STATIC_ASSERT(LANGUAGE_END == 3);
class LanguageModeBits : public BitField<LanguageMode, 0, 2> {};
- class FunctionKindBits : public BitField<FunctionKind, 2, 6> {};
+ class FunctionKindBits : public BitField<FunctionKind, 2, 7> {};
DEFINE_CALL_INTERFACE_DESCRIPTOR(FastNewClosure);
DEFINE_HYDROGEN_CODE_STUB(FastNewClosure, HydrogenCodeStub);
case Runtime::kStringMatch:
case Runtime::kStringReplaceGlobalRegExpWithString:
case Runtime::kThrowConstAssignError:
+ case Runtime::kThrowConstructorNonCallableError:
case Runtime::kThrowNonMethodError:
case Runtime::kThrowNotDateError:
case Runtime::kThrowReferenceError:
kConciseGeneratorMethod = kGeneratorFunction | kConciseMethod,
kAccessorFunction = 1 << 3,
kDefaultConstructor = 1 << 4,
- kSubclassConstructor = 1 << 5
+ kSubclassConstructor = 1 << 5,
+ kBaseConstructor = 1 << 6,
};
kind == FunctionKind::kConciseGeneratorMethod ||
kind == FunctionKind::kAccessorFunction ||
kind == FunctionKind::kDefaultConstructor ||
+ kind == FunctionKind::kBaseConstructor ||
kind == FunctionKind::kSubclassConstructor;
}
}
+inline bool IsBaseConstructor(FunctionKind kind) {
+ DCHECK(IsValidFunctionKind(kind));
+ return kind & FunctionKind::kBaseConstructor;
+}
+
+
inline bool IsSubclassConstructor(FunctionKind kind) {
DCHECK(IsValidFunctionKind(kind));
return kind & FunctionKind::kSubclassConstructor;
}
+
+
+inline bool IsConstructor(FunctionKind kind) {
+ DCHECK(IsValidFunctionKind(kind));
+ return kind &
+ (FunctionKind::kBaseConstructor | FunctionKind::kSubclassConstructor |
+ FunctionKind::kDefaultConstructor);
+}
} } // namespace v8::internal
namespace i = v8::internal;
sloppy_lexical: ["Block-scoped declarations (let, const, function, class) not yet supported outside strict mode"],
super_constructor_call: ["A 'super' constructor call may only appear as the first statement of a function, and its arguments may not access 'this'. Other forms are not yet supported."],
duplicate_proto: ["Duplicate __proto__ fields are not allowed in object literals"],
- param_after_rest: ["Rest parameter must be last formal parameter"]
+ param_after_rest: ["Rest parameter must be last formal parameter"],
+ constructor_noncallable: ["Class constructors cannot be invoked without 'new'"]
};
kIsConciseMethod,
kIsAccessorFunction,
kIsDefaultConstructor,
+ kIsBaseConstructor,
kIsSubclassConstructor,
kIsAsmFunction,
kDeserialized,
// Add hints for other modes when they're added.
STATIC_ASSERT(LANGUAGE_END == 3);
- class FunctionKindBits : public BitField<FunctionKind, kIsArrow, 6> {};
+ class FunctionKindBits : public BitField<FunctionKind, kIsArrow, 7> {};
class DeoptCountBits : public BitField<int, 0, 4> {};
class OptReenableTriesBits : public BitField<int, 4, 18> {};
{
AstNodeFactory function_factory(ast_value_factory());
FunctionState function_state(&function_state_, &scope_, function_scope,
- &function_factory);
+ kDefaultConstructor, &function_factory);
body = new (zone()) ZoneList<Statement*>(1, zone());
if (call_super) {
// Enters 'scope'.
AstNodeFactory function_factory(ast_value_factory());
FunctionState function_state(&function_state_, &scope_, *scope,
- &function_factory);
+ kNormalFunction, &function_factory);
scope_->SetLanguageMode(info->language_mode());
ZoneList<Statement*>* body = new(zone()) ZoneList<Statement*>(16, zone());
original_scope_ = scope;
AstNodeFactory function_factory(ast_value_factory());
FunctionState function_state(&function_state_, &scope_, scope,
- &function_factory);
+ shared_info->kind(), &function_factory);
DCHECK(is_sloppy(scope->language_mode()) ||
is_strict(info()->language_mode()));
DCHECK(info()->language_mode() == shared_info->language_mode());
tok == Token::SEMICOLON ||
tok == Token::RBRACE ||
tok == Token::EOS) {
- return_value = GetLiteralUndefined(position());
+ if (FLAG_experimental_classes &&
+ IsSubclassConstructor(function_state_->kind())) {
+ return_value = ThisExpression(scope_, factory(), loc.beg_pos);
+ } else {
+ return_value = GetLiteralUndefined(position());
+ }
} else {
return_value = ParseExpression(true, CHECK_OK);
}
ExpectSemicolon(CHECK_OK);
+
if (is_generator()) {
Expression* generator = factory()->NewVariableProxy(
function_state_->generator_object_variable());
// Parse function body.
{
AstNodeFactory function_factory(ast_value_factory());
- FunctionState function_state(&function_state_, &scope_, scope,
+ FunctionState function_state(&function_state_, &scope_, scope, kind,
&function_factory);
scope_->SetScopeName(function_name);
&expected_property_count, CHECK_OK);
} else {
body = ParseEagerFunctionBody(function_name, pos, fvar, fvar_init_op,
- is_generator, CHECK_OK);
+ kind, CHECK_OK);
materialized_literal_count = function_state.materialized_literal_count();
expected_property_count = function_state.expected_property_count();
handler_count = function_state.handler_count();
ZoneList<Statement*>* Parser::ParseEagerFunctionBody(
const AstRawString* function_name, int pos, Variable* fvar,
- Token::Value fvar_init_op, bool is_generator, bool* ok) {
+ Token::Value fvar_init_op, FunctionKind kind, bool* ok) {
// Everything inside an eagerly parsed function will be parsed eagerly
// (see comment above).
ParsingModeScope parsing_mode(this, PARSE_EAGERLY);
RelocInfo::kNoPosition), zone());
}
+
+ // For concise constructors, check that they are constructed,
+ // not called.
+ if (FLAG_experimental_classes && i::IsConstructor(kind)) {
+ ZoneList<Expression*>* arguments =
+ new (zone()) ZoneList<Expression*>(0, zone());
+ CallRuntime* construct_check = factory()->NewCallRuntime(
+ ast_value_factory()->is_construct_call_string(),
+ Runtime::FunctionForId(Runtime::kInlineIsConstructCall), arguments,
+ pos);
+ CallRuntime* non_callable_error = factory()->NewCallRuntime(
+ ast_value_factory()->empty_string(),
+ Runtime::FunctionForId(Runtime::kThrowConstructorNonCallableError),
+ arguments, pos);
+ IfStatement* if_statement = factory()->NewIfStatement(
+ factory()->NewUnaryOperation(Token::NOT, construct_check, pos),
+ factory()->NewReturnStatement(non_callable_error, pos),
+ factory()->NewEmptyStatement(pos), pos);
+ body->Add(if_statement, zone());
+ }
+
// For generators, allocate and yield an iterator on function entry.
- if (is_generator) {
+ if (IsGeneratorFunction(kind)) {
ZoneList<Expression*>* arguments =
new(zone()) ZoneList<Expression*>(0, zone());
CallRuntime* allocation = factory()->NewCallRuntime(
ParseStatementList(body, Token::RBRACE, false, NULL, CHECK_OK);
- if (is_generator) {
+ if (IsGeneratorFunction(kind)) {
VariableProxy* get_proxy = factory()->NewVariableProxy(
function_state_->generator_object_variable());
Expression* undefined =
yield, RelocInfo::kNoPosition), zone());
}
+ if (FLAG_experimental_classes && IsSubclassConstructor(kind)) {
+ body->Add(
+ factory()->NewReturnStatement(
+ this->ThisExpression(scope_, factory(), RelocInfo::kNoPosition),
+ RelocInfo::kNoPosition),
+ zone());
+ }
+
Expect(Token::RBRACE, CHECK_OK);
scope_->set_end_position(scanner()->location().end_pos);
reusable_preparser_->set_allow_strong_mode(allow_strong_mode());
}
PreParser::PreParseResult result = reusable_preparser_->PreParseLazyFunction(
- language_mode(), is_generator(), logger);
+ language_mode(), function_state_->kind(), logger);
if (pre_parse_timer_ != NULL) {
pre_parse_timer_->Stop();
}
int* expected_property_count, bool* ok);
V8_INLINE ZoneList<Statement*>* ParseEagerFunctionBody(
const AstRawString* name, int pos, Variable* fvar,
- Token::Value fvar_init_op, bool is_generator, bool* ok);
+ Token::Value fvar_init_op, FunctionKind kind, bool* ok);
ClassLiteral* ParseClassLiteral(const AstRawString* name,
Scanner::Location class_name_location,
// Consumes the ending }.
ZoneList<Statement*>* ParseEagerFunctionBody(
const AstRawString* function_name, int pos, Variable* fvar,
- Token::Value fvar_init_op, bool is_generator, bool* ok);
+ Token::Value fvar_init_op, FunctionKind kind, bool* ok);
void ThrowPendingError();
ZoneList<Statement*>* ParserTraits::ParseEagerFunctionBody(
const AstRawString* name, int pos, Variable* fvar,
- Token::Value fvar_init_op, bool is_generator, bool* ok) {
- return parser_->ParseEagerFunctionBody(name, pos, fvar, fvar_init_op,
- is_generator, ok);
+ Token::Value fvar_init_op, FunctionKind kind, bool* ok) {
+ return parser_->ParseEagerFunctionBody(name, pos, fvar, fvar_init_op, kind,
+ ok);
}
void ParserTraits::CheckConflictingVarDeclarations(v8::internal::Scope* scope,
PreParser::PreParseResult PreParser::PreParseLazyFunction(
- LanguageMode language_mode, bool is_generator, ParserRecorder* log) {
+ LanguageMode language_mode, FunctionKind kind, ParserRecorder* log) {
log_ = log;
// Lazy functions always have trivial outer scopes (no with/catch scopes).
PreParserScope top_scope(scope_, SCRIPT_SCOPE);
PreParserFactory top_factory(NULL);
- FunctionState top_state(&function_state_, &scope_, &top_scope, &top_factory);
+ FunctionState top_state(&function_state_, &scope_, &top_scope,
+ kNormalFunction, &top_factory);
scope_->SetLanguageMode(language_mode);
PreParserScope function_scope(scope_, FUNCTION_SCOPE);
PreParserFactory function_factory(NULL);
- FunctionState function_state(&function_state_, &scope_, &function_scope,
+ FunctionState function_state(&function_state_, &scope_, &function_scope, kind,
&function_factory);
- function_state.set_is_generator(is_generator);
DCHECK_EQ(Token::LBRACE, scanner()->current_token());
bool ok = true;
int start_position = peek_position();
ScopeType outer_scope_type = scope_->type();
PreParserScope function_scope(scope_, FUNCTION_SCOPE);
PreParserFactory factory(NULL);
- FunctionState function_state(&function_state_, &scope_, &function_scope,
+ FunctionState function_state(&function_state_, &scope_, &function_scope, kind,
&factory);
- function_state.set_is_generator(IsGeneratorFunction(kind));
// FormalParameterList ::
// '(' (Identifier)*[','] ')'
Expect(Token::LPAREN, CHECK_OK);
public:
FunctionState(FunctionState** function_state_stack,
typename Traits::Type::Scope** scope_stack,
- typename Traits::Type::Scope* scope,
+ typename Traits::Type::Scope* scope, FunctionKind kind,
typename Traits::Type::Factory* factory);
~FunctionState();
void AddProperty() { expected_property_count_++; }
int expected_property_count() { return expected_property_count_; }
- void set_is_generator(bool is_generator) { is_generator_ = is_generator; }
- bool is_generator() const { return is_generator_; }
+ bool is_generator() const { return IsGeneratorFunction(kind_); }
+
+ FunctionKind kind() const { return kind_; }
void set_generator_object_variable(
typename Traits::Type::GeneratorVariable* variable) {
DCHECK(variable != NULL);
- DCHECK(!is_generator());
+ DCHECK(is_generator());
generator_object_variable_ = variable;
- is_generator_ = true;
}
typename Traits::Type::GeneratorVariable* generator_object_variable()
const {
// Properties count estimation.
int expected_property_count_;
- // Whether the function is a generator.
- bool is_generator_;
+ FunctionKind kind_;
// For generators, this variable may hold the generator object. It variable
// is used by yield expressions and return statements. It is not necessary
// for generator functions to have this variable set.
Variable* generator_object_variable_;
+
FunctionState** function_state_stack_;
FunctionState* outer_function_state_;
typename Traits::Type::Scope** scope_stack_;
}
V8_INLINE PreParserStatementList
- ParseEagerFunctionBody(PreParserIdentifier function_name, int pos,
- Variable* fvar, Token::Value fvar_init_op,
- bool is_generator, bool* ok);
+ ParseEagerFunctionBody(PreParserIdentifier function_name, int pos,
+ Variable* fvar, Token::Value fvar_init_op,
+ FunctionKind kind, bool* ok);
// Utility functions
int DeclareArrowParametersFromExpression(PreParserExpression expression,
PreParseResult PreParseProgram(int* materialized_literals = 0) {
PreParserScope scope(scope_, SCRIPT_SCOPE);
PreParserFactory factory(NULL);
- FunctionState top_scope(&function_state_, &scope_, &scope, &factory);
+ FunctionState top_scope(&function_state_, &scope_, &scope, kNormalFunction,
+ &factory);
bool ok = true;
int start_position = scanner()->peek_location().beg_pos;
ParseSourceElements(Token::EOS, &ok);
// At return, unless an error occurred, the scanner is positioned before the
// the final '}'.
PreParseResult PreParseLazyFunction(LanguageMode language_mode,
- bool is_generator, ParserRecorder* log);
+ FunctionKind kind, ParserRecorder* log);
private:
friend class PreParserTraits;
int* materialized_literal_count,
int* expected_property_count, bool* ok);
V8_INLINE PreParserStatementList
- ParseEagerFunctionBody(PreParserIdentifier function_name, int pos,
- Variable* fvar, Token::Value fvar_init_op,
- bool is_generator, bool* ok);
+ ParseEagerFunctionBody(PreParserIdentifier function_name, int pos,
+ Variable* fvar, Token::Value fvar_init_op,
+ FunctionKind kind, bool* ok);
Expression ParseFunctionLiteral(
Identifier name, Scanner::Location function_name_location,
PreParserStatementList PreParser::ParseEagerFunctionBody(
PreParserIdentifier function_name, int pos, Variable* fvar,
- Token::Value fvar_init_op, bool is_generator, bool* ok) {
+ Token::Value fvar_init_op, FunctionKind kind, bool* ok) {
ParsingModeScope parsing_mode(this, PARSE_EAGERLY);
ParseSourceElements(Token::RBRACE, ok);
PreParserStatementList PreParserTraits::ParseEagerFunctionBody(
PreParserIdentifier function_name, int pos, Variable* fvar,
- Token::Value fvar_init_op, bool is_generator, bool* ok) {
+ Token::Value fvar_init_op, FunctionKind kind, bool* ok) {
return pre_parser_->ParseEagerFunctionBody(function_name, pos, fvar,
- fvar_init_op, is_generator, ok);
+ fvar_init_op, kind, ok);
}
ParserBase<Traits>::FunctionState::FunctionState(
FunctionState** function_state_stack,
typename Traits::Type::Scope** scope_stack,
- typename Traits::Type::Scope* scope,
+ typename Traits::Type::Scope* scope, FunctionKind kind,
typename Traits::Type::Factory* factory)
: next_materialized_literal_index_(JSFunction::kLiteralsPrefixSize),
next_handler_index_(0),
expected_property_count_(0),
- is_generator_(false),
+ kind_(kind),
generator_object_variable_(NULL),
function_state_stack_(function_state_stack),
outer_function_state_(*function_state_stack),
if (in_class && !is_static && this->IsConstructor(name)) {
*has_seen_constructor = true;
kind = has_extends ? FunctionKind::kSubclassConstructor
- : FunctionKind::kNormalFunction;
+ : FunctionKind::kBaseConstructor;
}
value = this->ParseFunctionLiteral(
typename Traits::Type::Factory function_factory(this->ast_value_factory());
FunctionState function_state(&function_state_, &scope_,
Traits::Type::ptr_to_scope(scope),
- &function_factory);
+ kArrowFunction, &function_factory);
Scanner::Location dupe_error_loc = Scanner::Location::invalid();
num_parameters = Traits::DeclareArrowParametersFromExpression(
params_ast, scope_, &dupe_error_loc, ok);
} else {
body = this->ParseEagerFunctionBody(
this->EmptyIdentifier(), RelocInfo::kNoPosition, NULL,
- Token::INIT_VAR, false, // Not a generator.
- CHECK_OK);
+ Token::INIT_VAR, kArrowFunction, CHECK_OK);
materialized_literal_count =
function_state.materialized_literal_count();
expected_property_count = function_state.expected_property_count();
}
+RUNTIME_FUNCTION(Runtime_ThrowConstructorNonCallableError) {
+ HandleScope scope(isolate);
+ DCHECK(args.length() == 0);
+ THROW_NEW_ERROR_RETURN_FAILURE(
+ isolate,
+ NewTypeError("constructor_noncallable", HandleVector<Object>(NULL, 0)));
+}
+
+
RUNTIME_FUNCTION(Runtime_ToMethod) {
HandleScope scope(isolate);
DCHECK(args.length() == 2);
/* Classes support */ \
F(ToMethod, 2, 1) \
F(HomeObjectSymbol, 0, 1) \
+ F(DefaultConstructorSuperCall, 0, 1) \
F(DefineClass, 6, 1) \
F(DefineClassMethod, 3, 1) \
F(ClassGetSourceCode, 1, 1) \
- F(ThrowNonMethodError, 0, 1) \
- F(ThrowUnsupportedSuperError, 0, 1) \
F(LoadFromSuper, 3, 1) \
F(LoadKeyedFromSuper, 3, 1) \
+ F(ThrowConstructorNonCallableError, 0, 1) \
+ F(ThrowNonMethodError, 0, 1) \
+ F(ThrowUnsupportedSuperError, 0, 1) \
F(StoreToSuper_Strict, 4, 1) \
F(StoreToSuper_Sloppy, 4, 1) \
F(StoreKeyedToSuper_Strict, 4, 1) \
- F(StoreKeyedToSuper_Sloppy, 4, 1) \
- F(DefaultConstructorSuperCall, 0, 1)
+ F(StoreKeyedToSuper_Sloppy, 4, 1)
#define RUNTIME_FUNCTION_LIST_ALWAYS_2(F) \
let b = new Base(1, 2);
assertSame(3, b.prp);
+
let s = new Subclass(2, -1);
assertSame(1, s.prp);
assertSame(undefined, s.prp1);
assertFalse(s.hasOwnProperty("prp1"));
class Subclass2 extends Base {
- constructor() {
+ constructor(x) {
super(1,2);
+ if (x < 0) return;
+
let called = false;
function tmp() { called = true; return 3; }
var exn = null;
}
}
-new Subclass2();
+var s2 = new Subclass2(1);
+assertSame(3, s2.prp);
+
+var s3 = new Subclass2(-1);
+assertSame(3, s3.prp);
+
+assertThrows(function() { Subclass.call(new Object(), 1, 2); }, TypeError);
+assertThrows(function() { Base.call(new Object(), 1, 2); }, TypeError);