}
+void Builtins::Generate_JSConstructStubForDerived(MacroAssembler* masm) {
+ // ----------- S t a t e -------------
+ // -- r0 : number of arguments
+ // -- r1 : constructor function
+ // -- r2 : allocation site or undefined
+ // -- r3 : original constructor
+ // -- lr : return address
+ // -- sp[...]: constructor arguments
+ // -----------------------------------
+
+ // TODO(dslomov): support pretenuring
+ CHECK(!FLAG_pretenuring_call_new);
+
+ {
+ FrameScope frame_scope(masm, StackFrame::CONSTRUCT);
+
+ __ mov(r4, r0);
+ __ SmiTag(r4);
+ __ push(r4); // Smi-tagged arguments count.
+
+ // receiver is the hole.
+ __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
+ __ push(ip);
+
+ // Set up pointer to last argument.
+ __ add(r2, fp, Operand(StandardFrameConstants::kCallerSPOffset));
+
+ // Copy arguments and receiver to the expression stack.
+ // r0: number of arguments
+ // r1: constructor function
+ // r2: address of last argument (caller sp)
+ // r4: number of arguments (smi-tagged)
+ // sp[0]: receiver
+ // sp[1]: number of arguments (smi-tagged)
+ Label loop, entry;
+ __ b(&entry);
+ __ bind(&loop);
+ __ ldr(ip, MemOperand(r2, r4, LSL, kPointerSizeLog2 - 1));
+ __ push(ip);
+ __ bind(&entry);
+ __ sub(r4, r4, Operand(2), SetCC);
+ __ b(ge, &loop);
+
+ // Call the function.
+ // r0: number of arguments
+ // r1: constructor function
+ ParameterCount actual(r0);
+ __ InvokeFunction(r1, actual, CALL_FUNCTION, NullCallWrapper());
+
+ // Restore context from the frame.
+ // r0: result
+ // sp[0]: number of arguments (smi-tagged)
+ __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
+ __ ldr(r1, MemOperand(sp, 0));
+
+ // Leave construct frame.
+ }
+
+ __ add(sp, sp, Operand(r1, LSL, kPointerSizeLog2 - 1));
+ __ add(sp, sp, Operand(kPointerSize));
+ __ Jump(lr);
+}
+
+
static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm,
bool is_construct) {
// Called from Generate_JS_Entry
bool skip_init_check;
if (var->scope()->DeclarationScope() != scope()->DeclarationScope()) {
skip_init_check = false;
+ } else if (var->is_this()) {
+ CHECK((info_->shared_info()->kind() & kSubclassConstructor) != 0);
+ // TODO(dslomov): implement 'this' hole check elimination.
+ skip_init_check = false;
} else {
// Check that we always have valid source position.
DCHECK(var->initializer_position() != RelocInfo::kNoPosition);
EmitLoadSuperConstructor(super_ref);
__ push(result_register());
+ Variable* this_var = super_ref->this_var()->var();
+
+ GetVar(r0, this_var);
+ __ CompareRoot(r0, Heap::kTheHoleValueRootIndex);
+ Label uninitialized_this;
+ __ b(eq, &uninitialized_this);
+ __ mov(r0, Operand(this_var->name()));
+ __ Push(r0);
+ __ CallRuntime(Runtime::kThrowReferenceError, 1);
+ __ bind(&uninitialized_this);
+
// Push the arguments ("left-to-right") on the stack.
ZoneList<Expression*>* args = expr->arguments();
int arg_count = args->length();
RecordJSReturnSite(expr);
- // TODO(dslomov): implement TDZ for `this`.
- EmitVariableAssignment(super_ref->this_var()->var(), Token::ASSIGN);
+ EmitVariableAssignment(this_var, Token::INIT_CONST);
context()->Plug(r0);
}
}
+void Builtins::Generate_JSConstructStubForDerived(MacroAssembler* masm) {
+ // ----------- S t a t e -------------
+ // -- x0 : number of arguments
+ // -- x1 : constructor function
+ // -- x2 : allocation site or undefined
+ // -- x3 : original constructor
+ // -- lr : return address
+ // -- sp[...]: constructor arguments
+ // -----------------------------------
+ ASM_LOCATION("Builtins::Generate_JSConstructStubForDerived");
+
+ // TODO(dslomov): support pretenuring
+ CHECK(!FLAG_pretenuring_call_new);
+
+ {
+ FrameScope frame_scope(masm, StackFrame::CONSTRUCT);
+ __ Mov(x4, x0);
+ __ SmiTag(x4);
+ __ LoadRoot(x10, Heap::kTheHoleValueRootIndex);
+ __ Push(x4, x10);
+ // sp[0]: number of arguments
+ // sp[1]: receiver (the hole)
+
+
+ // Set up pointer to last argument.
+ __ Add(x2, fp, StandardFrameConstants::kCallerSPOffset);
+
+ // Copy arguments and receiver to the expression stack.
+ // Copy 2 values every loop to use ldp/stp.
+ // x0: number of arguments
+ // x1: constructor function
+ // x2: address of last argument (caller sp)
+ // jssp[0]: receiver
+ // jssp[1]: number of arguments (smi-tagged)
+ // Compute the start address of the copy in x4.
+ __ Add(x4, x2, Operand(x0, LSL, kPointerSizeLog2));
+ Label loop, entry, done_copying_arguments;
+ __ B(&entry);
+ __ Bind(&loop);
+ __ Ldp(x10, x11, MemOperand(x4, -2 * kPointerSize, PreIndex));
+ __ Push(x11, x10);
+ __ Bind(&entry);
+ __ Cmp(x4, x2);
+ __ B(gt, &loop);
+ // Because we copied values 2 by 2 we may have copied one extra value.
+ // Drop it if that is the case.
+ __ B(eq, &done_copying_arguments);
+ __ Drop(1);
+ __ Bind(&done_copying_arguments);
+
+ // Call the function.
+ // x0: number of arguments
+ // x1: constructor function
+ ParameterCount actual(x0);
+ __ InvokeFunction(x1, actual, CALL_FUNCTION, NullCallWrapper());
+
+
+ // Restore the context from the frame.
+ // x0: result
+ // jssp[0]: number of arguments (smi-tagged)
+ __ Ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
+
+ // Load number of arguments (smi).
+ __ Peek(x1, 0);
+
+ // Leave construct frame
+ }
+
+ __ DropBySMI(x1);
+ __ Drop(1);
+ __ Ret();
+}
+
+
// Input:
// x0: code entry.
// x1: function.
bool skip_init_check;
if (var->scope()->DeclarationScope() != scope()->DeclarationScope()) {
skip_init_check = false;
+ } else if (var->is_this()) {
+ CHECK((info_->shared_info()->kind() & kSubclassConstructor) != 0);
+ // TODO(dslomov): implement 'this' hole check elimination.
+ skip_init_check = false;
} else {
// Check that we always have valid source position.
DCHECK(var->initializer_position() != RelocInfo::kNoPosition);
EmitLoadSuperConstructor(super_ref);
__ push(result_register());
+ Variable* this_var = super_ref->this_var()->var();
+
+ GetVar(x0, this_var);
+ Label uninitialized_this;
+ __ JumpIfRoot(x0, Heap::kTheHoleValueRootIndex, &uninitialized_this);
+ __ Mov(x0, Operand(this_var->name()));
+ __ Push(x0);
+ __ CallRuntime(Runtime::kThrowReferenceError, 1);
+ __ bind(&uninitialized_this);
+
// Push the arguments ("left-to-right") on the stack.
ZoneList<Expression*>* args = expr->arguments();
int arg_count = args->length();
RecordJSReturnSite(expr);
- // TODO(dslomov): implement TDZ for `this`.
- EmitVariableAssignment(super_ref->this_var()->var(), Token::ASSIGN);
+ EmitVariableAssignment(this_var, Token::INIT_CONST);
context()->Plug(x0);
}
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, 4> {};
+ class FunctionKindBits : public BitField<FunctionKind, 6, 5> {};
};
V(ArgumentsAdaptorTrampoline, BUILTIN, UNINITIALIZED, kNoExtraICState) \
V(InOptimizationQueue, BUILTIN, UNINITIALIZED, kNoExtraICState) \
V(JSConstructStubGeneric, BUILTIN, UNINITIALIZED, kNoExtraICState) \
+ V(JSConstructStubForDerived, BUILTIN, UNINITIALIZED, kNoExtraICState) \
V(JSConstructStubApi, BUILTIN, UNINITIALIZED, kNoExtraICState) \
V(JSEntryTrampoline, BUILTIN, UNINITIALIZED, kNoExtraICState) \
V(JSConstructEntryTrampoline, BUILTIN, UNINITIALIZED, kNoExtraICState) \
static void Generate_CompileOptimized(MacroAssembler* masm);
static void Generate_CompileOptimizedConcurrent(MacroAssembler* masm);
static void Generate_JSConstructStubGeneric(MacroAssembler* masm);
+ static void Generate_JSConstructStubForDerived(MacroAssembler* masm);
static void Generate_JSConstructStubApi(MacroAssembler* masm);
static void Generate_JSEntryTrampoline(MacroAssembler* masm);
static void Generate_JSConstructEntryTrampoline(MacroAssembler* masm);
kGeneratorFunction = 2,
kConciseMethod = 4,
kConciseGeneratorMethod = kGeneratorFunction | kConciseMethod,
- kDefaultConstructor = 8
+ kDefaultConstructor = 8,
+ kSubclassConstructor = 16
};
kind == FunctionKind::kGeneratorFunction ||
kind == FunctionKind::kConciseMethod ||
kind == FunctionKind::kConciseGeneratorMethod ||
- kind == FunctionKind::kDefaultConstructor;
+ kind == FunctionKind::kDefaultConstructor ||
+ kind == FunctionKind::kSubclassConstructor;
}
return kind & FunctionKind::kDefaultConstructor;
}
-
+inline bool IsSubclassConstructor(FunctionKind kind) {
+ DCHECK(IsValidFunctionKind(kind));
+ return kind & FunctionKind::kSubclassConstructor;
+}
} } // namespace v8::internal
namespace i = v8::internal;
}
+void Builtins::Generate_JSConstructStubForDerived(MacroAssembler* masm) {
+ // ----------- S t a t e -------------
+ // -- eax: number of arguments
+ // -- edi: constructor function
+ // -- ebx: allocation site or undefined
+ // -- edx: original constructor
+ // -----------------------------------
+
+ // TODO(dslomov): support pretenuring
+ CHECK(!FLAG_pretenuring_call_new);
+
+ {
+ FrameScope frame_scope(masm, StackFrame::CONSTRUCT);
+
+ // Preserve actual arguments count.
+ __ SmiTag(eax);
+ __ push(eax);
+ __ SmiUntag(eax);
+
+ // receiver is the hole.
+ __ push(Immediate(masm->isolate()->factory()->the_hole_value()));
+
+ // Set up pointer to last argument.
+ __ lea(ebx, Operand(ebp, StandardFrameConstants::kCallerSPOffset));
+
+ // Copy arguments and receiver to the expression stack.
+ Label loop, entry;
+ __ mov(ecx, eax);
+ __ jmp(&entry);
+ __ bind(&loop);
+ __ push(Operand(ebx, ecx, times_4, 0));
+ __ bind(&entry);
+ __ dec(ecx);
+ __ j(greater_equal, &loop);
+
+ ParameterCount actual(eax);
+ __ InvokeFunction(edi, actual, CALL_FUNCTION, NullCallWrapper());
+
+ // Restore context from the frame.
+ __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
+
+ __ mov(ebx, Operand(esp, 0));
+ }
+
+ __ pop(ecx); // Return address.
+ __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize));
+ __ push(ecx);
+ __ ret(0);
+}
+
+
static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm,
bool is_construct) {
ProfileEntryHookStub::MaybeCallEntryHook(masm);
bool skip_init_check;
if (var->scope()->DeclarationScope() != scope()->DeclarationScope()) {
skip_init_check = false;
+ } else if (var->is_this()) {
+ CHECK((info_->shared_info()->kind() & kSubclassConstructor) != 0);
+ // TODO(dslomov): implement 'this' hole check elimination.
+ skip_init_check = false;
} else {
// Check that we always have valid source position.
DCHECK(var->initializer_position() != RelocInfo::kNoPosition);
EmitLoadSuperConstructor(super_ref);
__ push(result_register());
+ Variable* this_var = super_ref->this_var()->var();
+ GetVar(eax, this_var);
+ __ cmp(eax, isolate()->factory()->the_hole_value());
+ Label uninitialized_this;
+ __ j(equal, &uninitialized_this);
+ __ push(Immediate(this_var->name()));
+ __ CallRuntime(Runtime::kThrowReferenceError, 1);
+ __ bind(&uninitialized_this);
+
// Push the arguments ("left-to-right") on the stack.
ZoneList<Expression*>* args = expr->arguments();
int arg_count = args->length();
RecordJSReturnSite(expr);
- // TODO(dslomov): implement TDZ for `this`.
- EmitVariableAssignment(super_ref->this_var()->var(), Token::ASSIGN);
+ EmitVariableAssignment(this_var, Token::INIT_CONST);
context()->Plug(eax);
}
kIsGenerator,
kIsConciseMethod,
kIsDefaultConstructor,
+ kIsSubclassConstructor,
kIsAsmFunction,
kDeserialized,
kCompilerHintsCount // Pseudo entry
};
- class FunctionKindBits : public BitField<FunctionKind, kIsArrow, 4> {};
+ class FunctionKindBits : public BitField<FunctionKind, kIsArrow, 5> {};
class DeoptCountBits : public BitField<int, 0, 4> {};
class OptReenableTriesBits : public BitField<int, 4, 18> {};
}
-Scope* Parser::NewScope(Scope* parent, ScopeType scope_type) {
+Scope* Parser::NewScope(Scope* parent, ScopeType scope_type,
+ FunctionKind kind) {
DCHECK(ast_value_factory());
DCHECK(scope_type != MODULE_SCOPE || allow_harmony_modules());
+ DCHECK((scope_type == FUNCTION_SCOPE && IsValidFunctionKind(kind)) ||
+ kind == kNormalFunction);
Scope* result = new (zone())
Scope(isolate(), zone(), parent, scope_type, ast_value_factory());
- result->Initialize();
+ bool uninitialized_this =
+ FLAG_experimental_classes && IsSubclassConstructor(kind);
+ result->Initialize(uninitialized_this);
return result;
}
int parameter_count = 0;
const AstRawString* name = ast_value_factory()->empty_string();
- Scope* function_scope = NewScope(scope, FUNCTION_SCOPE);
+ Scope* function_scope =
+ NewScope(scope, FUNCTION_SCOPE, FunctionKind::kDefaultConstructor);
function_scope->SetStrictMode(STRICT);
// Set start and end position to the same value
function_scope->set_start_position(pos);
Scope* original_declaration_scope = original_scope_->DeclarationScope();
Scope* scope =
function_type == FunctionLiteral::DECLARATION &&
- (!allow_harmony_scoping() || strict_mode() == SLOPPY) &&
- (original_scope_ == original_declaration_scope ||
- declaration_scope != original_declaration_scope)
- ? NewScope(declaration_scope, FUNCTION_SCOPE)
- : NewScope(scope_, FUNCTION_SCOPE);
+ (!allow_harmony_scoping() || strict_mode() == SLOPPY) &&
+ (original_scope_ == original_declaration_scope ||
+ declaration_scope != original_declaration_scope)
+ ? NewScope(declaration_scope, FUNCTION_SCOPE, kind)
+ : NewScope(scope_, FUNCTION_SCOPE, kind);
ZoneList<Statement*>* body = NULL;
int materialized_literal_count = -1;
int expected_property_count = -1;
bool has_seen_constructor = false;
Expect(Token::LBRACE, CHECK_OK);
+ const bool has_extends = extends != nullptr;
while (peek() != Token::RBRACE) {
if (Check(Token::SEMICOLON)) continue;
if (fni_ != NULL) fni_->Enter();
bool is_computed_name = false; // Classes do not care about computed
// property names here.
ObjectLiteral::Property* property = ParsePropertyDefinition(
- &checker, in_class, is_static, &is_computed_name, &has_seen_constructor,
- CHECK_OK);
+ &checker, in_class, has_extends, is_static, &is_computed_name,
+ &has_seen_constructor, CHECK_OK);
if (has_seen_constructor && constructor == NULL) {
constructor = GetPropertyValue(property)->AsFunctionLiteral();
ZoneList<v8::internal::Statement*>* NewStatementList(int size, Zone* zone) {
return new(zone) ZoneList<v8::internal::Statement*>(size, zone);
}
- V8_INLINE Scope* NewScope(Scope* parent_scope, ScopeType scope_type);
+ V8_INLINE Scope* NewScope(Scope* parent_scope, ScopeType scope_type,
+ FunctionKind kind = kNormalFunction);
// Utility functions
int DeclareArrowParametersFromExpression(Expression* expression, Scope* scope,
// Factory methods.
- Scope* NewScope(Scope* parent, ScopeType type);
+ Scope* NewScope(Scope* parent, ScopeType type,
+ FunctionKind kind = kNormalFunction);
FunctionLiteral* DefaultConstructor(bool call_super, Scope* scope, int pos,
int end_pos);
}
-Scope* ParserTraits::NewScope(Scope* parent_scope, ScopeType scope_type) {
- return parser_->NewScope(parent_scope, scope_type);
+Scope* ParserTraits::NewScope(Scope* parent_scope, ScopeType scope_type,
+ FunctionKind kind) {
+ return parser_->NewScope(parent_scope, scope_type, kind);
}
scope_->SetStrictMode(STRICT);
scope_->SetScopeName(name);
- if (Check(Token::EXTENDS)) {
+ bool has_extends = Check(Token::EXTENDS);
+ if (has_extends) {
ParseLeftHandSideExpression(CHECK_OK);
}
const bool is_static = false;
bool is_computed_name = false; // Classes do not care about computed
// property names here.
- ParsePropertyDefinition(&checker, in_class, is_static, &is_computed_name,
- &has_seen_constructor, CHECK_OK);
+ ParsePropertyDefinition(&checker, in_class, has_extends, is_static,
+ &is_computed_name, &has_seen_constructor, CHECK_OK);
}
Expect(Token::RBRACE, CHECK_OK);
bool* ok);
ExpressionT ParseObjectLiteral(bool* ok);
ObjectLiteralPropertyT ParsePropertyDefinition(
- ObjectLiteralCheckerBase* checker, bool in_class, bool is_static,
- bool* is_computed_name, bool* has_seen_constructor, bool* ok);
+ ObjectLiteralCheckerBase* checker, bool in_class, bool has_extends,
+ bool is_static, bool* is_computed_name, bool* has_seen_constructor,
+ bool* ok);
typename Traits::Type::ExpressionList ParseArguments(bool* ok);
ExpressionT ParseAssignmentExpression(bool accept_IN, bool* ok);
ExpressionT ParseYieldExpression(bool* ok);
const char* type, Handle<Object> arg, int pos) {
return PreParserExpression::Default();
}
- PreParserScope NewScope(PreParserScope* outer_scope, ScopeType scope_type) {
+ PreParserScope NewScope(PreParserScope* outer_scope, ScopeType scope_type,
+ FunctionKind kind = kNormalFunction) {
return PreParserScope(outer_scope, scope_type);
}
template <class Traits>
typename ParserBase<Traits>::ObjectLiteralPropertyT
ParserBase<Traits>::ParsePropertyDefinition(ObjectLiteralCheckerBase* checker,
- bool in_class, bool is_static,
+ bool in_class, bool has_extends,
+ bool is_static,
bool* is_computed_name,
bool* has_seen_constructor,
bool* ok) {
if (in_class && !is_static && this->IsConstructor(name)) {
*has_seen_constructor = true;
- kind = FunctionKind::kNormalFunction;
+ kind = has_extends ? FunctionKind::kSubclassConstructor
+ : FunctionKind::kNormalFunction;
}
value = this->ParseFunctionLiteral(
} else if (in_class && name_is_static && !is_static) {
// static MethodDefinition
- return ParsePropertyDefinition(checker, true, true, is_computed_name,
- nullptr, ok);
-
+ return ParsePropertyDefinition(checker, true, has_extends, true,
+ is_computed_name, nullptr, ok);
} else if (is_get || is_set) {
// Accessor
name = this->EmptyIdentifier();
const bool in_class = false;
const bool is_static = false;
+ const bool has_extends = false;
bool is_computed_name = false;
ObjectLiteralPropertyT property = this->ParsePropertyDefinition(
- &checker, in_class, is_static, &is_computed_name, nullptr, CHECK_OK);
+ &checker, in_class, has_extends, is_static, &is_computed_name, NULL,
+ CHECK_OK);
if (is_computed_name) {
has_computed_names = true;
: isolate->factory()->empty_string();
constructor->shared()->set_name(*name_string);
+ if (FLAG_experimental_classes) {
+ if (!super_class->IsTheHole() && !super_class->IsNull()) {
+ Handle<Code> stub(isolate->builtins()->JSConstructStubForDerived());
+ constructor->shared()->set_construct_stub(*stub);
+ }
+ }
+
JSFunction::SetPrototype(constructor, prototype);
PropertyAttributes attribs =
static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE | READ_ONLY);
}
-void Scope::Initialize() {
+void Scope::Initialize(bool uninitialized_this) {
DCHECK(!already_resolved());
// Add this scope as a new inner scope of the outer scope.
// such parameter is 'this' which is passed on the stack when
// invoking scripts
if (is_declaration_scope()) {
- Variable* var =
- variables_.Declare(this,
- ast_value_factory_->this_string(),
- VAR,
- false,
- Variable::THIS,
- kCreatedInitialized);
+ DCHECK(!uninitialized_this || is_function_scope());
+ DCHECK(FLAG_experimental_classes || !uninitialized_this);
+ Variable* var = variables_.Declare(
+ this, ast_value_factory_->this_string(),
+ uninitialized_this ? CONST : VAR, false, Variable::THIS,
+ uninitialized_this ? kNeedsInitialization : kCreatedInitialized);
var->AllocateTo(Variable::PARAMETER, -1);
receiver_ = var;
} else {
scope_name_ = scope_name;
}
- void Initialize();
+ void Initialize(bool uninitialized_this = false);
// Checks if the block scope is redundant, i.e. it does not contain any
// block scoped declarations. In that case it is removed from the scope
}
+void Builtins::Generate_JSConstructStubForDerived(MacroAssembler* masm) {
+ // ----------- S t a t e -------------
+ // -- rax: number of arguments
+ // -- rdi: constructor function
+ // -- rbx: allocation site or undefined
+ // -- rdx: original constructor
+ // -----------------------------------
+ // TODO(dslomov): support pretenuring
+ CHECK(!FLAG_pretenuring_call_new);
+
+ {
+ FrameScope frame_scope(masm, StackFrame::CONSTRUCT);
+
+ // Store a smi-tagged arguments count on the stack.
+ __ Integer32ToSmi(rax, rax);
+ __ Push(rax);
+ __ SmiToInteger32(rax, rax);
+
+ // receiver is the hole.
+ __ Push(masm->isolate()->factory()->the_hole_value());
+
+ // Set up pointer to last argument.
+ __ leap(rbx, Operand(rbp, StandardFrameConstants::kCallerSPOffset));
+
+ // Copy arguments and receiver to the expression stack.
+ Label loop, entry;
+ __ movp(rcx, rax);
+ __ jmp(&entry);
+ __ bind(&loop);
+ __ Push(Operand(rbx, rcx, times_pointer_size, 0));
+ __ bind(&entry);
+ __ decp(rcx);
+ __ j(greater_equal, &loop);
+
+ // Call the function.
+ ParameterCount actual(rax);
+ __ InvokeFunction(rdi, actual, CALL_FUNCTION, NullCallWrapper());
+
+ // Restore context from the frame.
+ __ movp(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
+
+ __ movp(rbx, Operand(rsp, 0)); // Get arguments count.
+ } // Leave construct frame.
+
+ // Remove caller arguments from the stack and return.
+ __ PopReturnAddressTo(rcx);
+ SmiIndex index = masm->SmiToIndex(rbx, rbx, kPointerSizeLog2);
+ __ leap(rsp, Operand(rsp, index.reg, index.scale, 1 * kPointerSize));
+ __ PushReturnAddressFrom(rcx);
+ __ ret(0);
+}
+
+
static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm,
bool is_construct) {
ProfileEntryHookStub::MaybeCallEntryHook(masm);
bool skip_init_check;
if (var->scope()->DeclarationScope() != scope()->DeclarationScope()) {
skip_init_check = false;
+ } else if (var->is_this()) {
+ CHECK((info_->shared_info()->kind() & kSubclassConstructor) != 0);
+ // TODO(dslomov): implement 'this' hole check elimination.
+ skip_init_check = false;
} else {
// Check that we always have valid source position.
DCHECK(var->initializer_position() != RelocInfo::kNoPosition);
EmitLoadSuperConstructor(super_ref);
__ Push(result_register());
+ Variable* this_var = super_ref->this_var()->var();
+
+ GetVar(rax, this_var);
+ __ CompareRoot(rax, Heap::kTheHoleValueRootIndex);
+ Label uninitialized_this;
+ __ j(equal, &uninitialized_this);
+ __ Push(this_var->name());
+ __ CallRuntime(Runtime::kThrowReferenceError, 1);
+ __ bind(&uninitialized_this);
+
+
// Push the arguments ("left-to-right") on the stack.
ZoneList<Expression*>* args = expr->arguments();
int arg_count = args->length();
RecordJSReturnSite(expr);
- // TODO(dslomov): implement TDZ for `this`.
- EmitVariableAssignment(super_ref->this_var()->var(), Token::ASSIGN);
+ EmitVariableAssignment(this_var, Token::INIT_CONST);
context()->Plug(rax);
}
'use strict';
class Base {
- constructor() {
+ constructor(a, b) {
let o = new Object();
- o.prp = 1;
+ o.prp = a + b;
return o;
}
}
class Subclass extends Base {
- constructor() {
+ constructor(a, b) {
+ var exn;
try {
this.prp1 = 3;
} catch (e) {
- // TODO(dslomov): actually test the exception once TDZ is implemented.
+ exn = e;
}
- super();
- assertSame(1, this.prp);
+ assertTrue(exn instanceof ReferenceError);
+ super(a, b);
+ assertSame(a + b, this.prp);
assertSame(undefined, this.prp1);
assertFalse(this.hasOwnProperty("prp1"));
return this;
}
}
-let s = new Subclass();
+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() {
+ super(1,2);
+
+ let called = false;
+ function tmp() { called = true; return 3; }
+ var exn = null;
+ try {
+ super(tmp(),4);
+ } catch(e) { exn = e; }
+ assertTrue(exn !== null);
+ assertFalse(called);
+ }
+}
+
+new Subclass2();