From 9b158fa79a510bd1fee2f663163d9116879cb33a Mon Sep 17 00:00:00 2001 From: dslomov Date: Wed, 11 Feb 2015 09:22:50 -0800 Subject: [PATCH] new classes: implement default constructors. R=arv@chromium.org,rossberg@chromium.org BUG=v8:3834 LOG=N Review URL: https://codereview.chromium.org/917753002 Cr-Commit-Position: refs/heads/master@{#26594} --- src/arm/full-codegen-arm.cc | 65 ++++++++++++++++-- src/arm64/full-codegen-arm64.cc | 61 +++++++++++++++-- src/full-codegen.h | 2 +- src/globals.h | 7 +- src/hydrogen.cc | 6 ++ src/ia32/full-codegen-ia32.cc | 56 +++++++++++++-- src/parser.cc | 71 ++++++++++++-------- src/parser.h | 2 + src/runtime/runtime-classes.cc | 8 +++ src/runtime/runtime.h | 1 + src/x64/code-stubs-x64.cc | 2 +- src/x64/full-codegen-x64.cc | 60 +++++++++++++++-- test/mjsunit/harmony/classes-experimental.js | 60 ++++++++++++++++- 13 files changed, 349 insertions(+), 52 deletions(-) diff --git a/src/arm/full-codegen-arm.cc b/src/arm/full-codegen-arm.cc index 679327e4e7..c9a5648aa1 100644 --- a/src/arm/full-codegen-arm.cc +++ b/src/arm/full-codegen-arm.cc @@ -3066,8 +3066,7 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) { } -void FullCodeGenerator::EmitLoadSuperConstructor(SuperReference* super_ref) { - DCHECK(super_ref != NULL); +void FullCodeGenerator::EmitLoadSuperConstructor() { __ ldr(r0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); __ Push(r0); __ CallRuntime(Runtime::kGetPrototype, 1); @@ -3193,9 +3192,9 @@ void FullCodeGenerator::VisitCall(Call* expr) { if (FLAG_experimental_classes) { EmitSuperConstructorCall(expr); } else { - SuperReference* super_ref = callee->AsSuperReference(); - EmitLoadSuperConstructor(super_ref); + EmitLoadSuperConstructor(); __ Push(result_register()); + SuperReference* super_ref = callee->AsSuperReference(); VisitForStackValue(super_ref->this_var()); EmitCall(expr, CallICState::METHOD); } @@ -3268,10 +3267,10 @@ void FullCodeGenerator::EmitSuperConstructorCall(Call* expr) { GetVar(result_register(), new_target_var); __ Push(result_register()); - SuperReference* super_ref = expr->expression()->AsSuperReference(); - EmitLoadSuperConstructor(super_ref); + EmitLoadSuperConstructor(); __ push(result_register()); + SuperReference* super_ref = expr->expression()->AsSuperReference(); Variable* this_var = super_ref->this_var()->var(); GetVar(r0, this_var); @@ -4177,6 +4176,60 @@ void FullCodeGenerator::EmitCallFunction(CallRuntime* expr) { } +void FullCodeGenerator::EmitDefaultConstructorCallSuper(CallRuntime* expr) { + Variable* new_target_var = scope()->DeclarationScope()->new_target_var(); + GetVar(result_register(), new_target_var); + __ Push(result_register()); + + EmitLoadSuperConstructor(); + __ Push(result_register()); + + // Check if the calling frame is an arguments adaptor frame. + Label adaptor_frame, args_set_up, runtime; + __ ldr(r2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset)); + __ ldr(r3, MemOperand(r2, StandardFrameConstants::kContextOffset)); + __ cmp(r3, Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); + __ b(eq, &adaptor_frame); + // default constructor has no arguments, so no adaptor frame means no args. + __ mov(r0, Operand::Zero()); + __ b(&args_set_up); + + // Copy arguments from adaptor frame. + { + __ bind(&adaptor_frame); + __ ldr(r1, MemOperand(r2, ArgumentsAdaptorFrameConstants::kLengthOffset)); + __ SmiUntag(r1, r1); + + // Subtract 1 from arguments count, for new.target. + __ sub(r1, r1, Operand(1)); + __ mov(r0, r1); + + // Get arguments pointer in r2. + __ add(r2, r2, Operand(r1, LSL, kPointerSizeLog2)); + __ add(r2, r2, Operand(StandardFrameConstants::kCallerSPOffset)); + Label loop; + __ bind(&loop); + // Pre-decrement r2 with kPointerSize on each iteration. + // Pre-decrement in order to skip receiver. + __ ldr(r3, MemOperand(r2, kPointerSize, NegPreIndex)); + __ Push(r3); + __ sub(r1, r1, Operand(1)); + __ cmp(r1, Operand::Zero()); + __ b(ne, &loop); + } + + __ bind(&args_set_up); + __ ldr(r1, MemOperand(sp, r0, LSL, kPointerSizeLog2)); + + CallConstructStub stub(isolate(), SUPER_CONSTRUCTOR_CALL); + __ Call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL); + + __ Drop(1); + + context()->Plug(result_register()); +} + + void FullCodeGenerator::EmitRegExpConstructResult(CallRuntime* expr) { RegExpConstructResultStub stub(isolate()); ZoneList* args = expr->arguments(); diff --git a/src/arm64/full-codegen-arm64.cc b/src/arm64/full-codegen-arm64.cc index 18605df670..c1615c985c 100644 --- a/src/arm64/full-codegen-arm64.cc +++ b/src/arm64/full-codegen-arm64.cc @@ -2754,8 +2754,7 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) { } -void FullCodeGenerator::EmitLoadSuperConstructor(SuperReference* super_ref) { - DCHECK(super_ref != NULL); +void FullCodeGenerator::EmitLoadSuperConstructor() { __ ldr(x0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); __ Push(x0); __ CallRuntime(Runtime::kGetPrototype, 1); @@ -2883,7 +2882,7 @@ void FullCodeGenerator::VisitCall(Call* expr) { EmitSuperConstructorCall(expr); } else { SuperReference* super_ref = callee->AsSuperReference(); - EmitLoadSuperConstructor(super_ref); + EmitLoadSuperConstructor(); __ Push(result_register()); VisitForStackValue(super_ref->this_var()); EmitCall(expr, CallICState::METHOD); @@ -2958,7 +2957,7 @@ void FullCodeGenerator::EmitSuperConstructorCall(Call* expr) { __ Push(result_register()); SuperReference* super_ref = expr->expression()->AsSuperReference(); - EmitLoadSuperConstructor(super_ref); + EmitLoadSuperConstructor(); __ push(result_register()); Variable* this_var = super_ref->this_var()->var(); @@ -3884,6 +3883,60 @@ void FullCodeGenerator::EmitCallFunction(CallRuntime* expr) { } +void FullCodeGenerator::EmitDefaultConstructorCallSuper(CallRuntime* expr) { + Variable* new_target_var = scope()->DeclarationScope()->new_target_var(); + GetVar(result_register(), new_target_var); + __ Push(result_register()); + + EmitLoadSuperConstructor(); + __ Push(result_register()); + + // Check if the calling frame is an arguments adaptor frame. + Label adaptor_frame, args_set_up, runtime; + Register caller_fp = x11; + __ Ldr(x11, MemOperand(fp, StandardFrameConstants::kCallerFPOffset)); + __ Ldr(x12, MemOperand(x11, StandardFrameConstants::kContextOffset)); + __ Cmp(x12, Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)); + __ B(eq, &adaptor_frame); + // default constructor has no arguments, so no adaptor frame means no args. + __ Mov(x0, Operand(0)); + __ B(&args_set_up); + + // Copy arguments from adaptor frame. + { + __ bind(&adaptor_frame); + __ Ldr(x1, MemOperand(x11, ArgumentsAdaptorFrameConstants::kLengthOffset)); + __ SmiUntag(x1, x1); + + // Subtract 1 from arguments count, for new.target. + __ Sub(x1, x1, Operand(1)); + __ Mov(x0, x1); + + // Get arguments pointer in x11. + __ Add(x11, x11, Operand(x1, LSL, kPointerSizeLog2)); + __ Add(x11, x11, StandardFrameConstants::kCallerSPOffset); + Label loop; + __ bind(&loop); + // Pre-decrement x11 with kPointerSize on each iteration. + // Pre-decrement in order to skip receiver. + __ Ldr(x10, MemOperand(x11, -kPointerSize, PreIndex)); + __ Push(x10); + __ Sub(x1, x1, Operand(1)); + __ Cbnz(x1, &loop); + } + + __ bind(&args_set_up); + __ Peek(x1, Operand(x0, LSL, kPointerSizeLog2)); + + CallConstructStub stub(isolate(), SUPER_CONSTRUCTOR_CALL); + __ Call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL); + + __ Drop(1); + + context()->Plug(result_register()); +} + + void FullCodeGenerator::EmitRegExpConstructResult(CallRuntime* expr) { RegExpConstructResultStub stub(isolate()); ZoneList* args = expr->arguments(); diff --git a/src/full-codegen.h b/src/full-codegen.h index 9a2e7460fc..b3c816b0f3 100644 --- a/src/full-codegen.h +++ b/src/full-codegen.h @@ -647,7 +647,7 @@ class FullCodeGenerator: public AstVisitor { // |offset| is the offset in the stack where the home object can be found. void EmitSetHomeObjectIfNeeded(Expression* initializer, int offset); - void EmitLoadSuperConstructor(SuperReference* expr); + void EmitLoadSuperConstructor(); void CallIC(Handle code, TypeFeedbackId id = TypeFeedbackId::None()); diff --git a/src/globals.h b/src/globals.h index bb9a417867..0edd643796 100644 --- a/src/globals.h +++ b/src/globals.h @@ -823,7 +823,9 @@ enum FunctionKind { kAccessorFunction = 1 << 3, kDefaultConstructor = 1 << 4, kSubclassConstructor = 1 << 5, - kBaseConstructor = 1 << 6 + kBaseConstructor = 1 << 6, + kDefaultBaseConstructor = kDefaultConstructor | kBaseConstructor, + kDefaultSubclassConstructor = kDefaultConstructor | kSubclassConstructor, }; @@ -834,7 +836,8 @@ inline bool IsValidFunctionKind(FunctionKind kind) { kind == FunctionKind::kConciseMethod || kind == FunctionKind::kConciseGeneratorMethod || kind == FunctionKind::kAccessorFunction || - kind == FunctionKind::kDefaultConstructor || + kind == FunctionKind::kDefaultBaseConstructor || + kind == FunctionKind::kDefaultSubclassConstructor || kind == FunctionKind::kBaseConstructor || kind == FunctionKind::kSubclassConstructor; } diff --git a/src/hydrogen.cc b/src/hydrogen.cc index 7d154642ce..7e5880a0ad 100644 --- a/src/hydrogen.cc +++ b/src/hydrogen.cc @@ -12109,6 +12109,12 @@ void HOptimizedGraphBuilder::GenerateCallFunction(CallRuntime* call) { } +void HOptimizedGraphBuilder::GenerateDefaultConstructorCallSuper( + CallRuntime* call) { + return Bailout(kSuperReference); +} + + // Fast call to math functions. void HOptimizedGraphBuilder::GenerateMathPow(CallRuntime* call) { DCHECK_EQ(2, call->arguments()->length()); diff --git a/src/ia32/full-codegen-ia32.cc b/src/ia32/full-codegen-ia32.cc index 6ee5d959af..4b603ddabc 100644 --- a/src/ia32/full-codegen-ia32.cc +++ b/src/ia32/full-codegen-ia32.cc @@ -2956,8 +2956,7 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) { } -void FullCodeGenerator::EmitLoadSuperConstructor(SuperReference* super_ref) { - DCHECK(super_ref != NULL); +void FullCodeGenerator::EmitLoadSuperConstructor() { __ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); __ CallRuntime(Runtime::kGetPrototype, 1); } @@ -3075,7 +3074,7 @@ void FullCodeGenerator::VisitCall(Call* expr) { EmitSuperConstructorCall(expr); } else { SuperReference* super_ref = callee->AsSuperReference(); - EmitLoadSuperConstructor(super_ref); + EmitLoadSuperConstructor(); __ push(result_register()); VisitForStackValue(super_ref->this_var()); EmitCall(expr, CallICState::METHOD); @@ -3148,7 +3147,7 @@ void FullCodeGenerator::EmitSuperConstructorCall(Call* expr) { __ push(eax); SuperReference* super_ref = expr->expression()->AsSuperReference(); - EmitLoadSuperConstructor(super_ref); + EmitLoadSuperConstructor(); __ push(result_register()); Variable* this_var = super_ref->this_var()->var(); @@ -4071,6 +4070,55 @@ void FullCodeGenerator::EmitCallFunction(CallRuntime* expr) { } +void FullCodeGenerator::EmitDefaultConstructorCallSuper(CallRuntime* expr) { + Variable* new_target_var = scope()->DeclarationScope()->new_target_var(); + GetVar(eax, new_target_var); + __ push(eax); + + EmitLoadSuperConstructor(); + __ push(result_register()); + + // Check if the calling frame is an arguments adaptor frame. + Label adaptor_frame, args_set_up, runtime; + __ mov(edx, Operand(ebp, StandardFrameConstants::kCallerFPOffset)); + __ mov(ecx, Operand(edx, StandardFrameConstants::kContextOffset)); + __ cmp(ecx, Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); + __ j(equal, &adaptor_frame); + // default constructor has no arguments, so no adaptor frame means no args. + __ mov(eax, Immediate(0)); + __ jmp(&args_set_up); + + // Copy arguments from adaptor frame. + { + __ bind(&adaptor_frame); + __ mov(ecx, Operand(edx, ArgumentsAdaptorFrameConstants::kLengthOffset)); + __ SmiUntag(ecx); + + // Subtract 1 from arguments count, for new.target. + __ sub(ecx, Immediate(1)); + __ mov(eax, ecx); + __ lea(edx, Operand(edx, ecx, times_pointer_size, + StandardFrameConstants::kCallerSPOffset)); + Label loop; + __ bind(&loop); + __ push(Operand(edx, -1 * kPointerSize)); + __ sub(edx, Immediate(kPointerSize)); + __ dec(ecx); + __ j(not_zero, &loop); + } + + __ bind(&args_set_up); + __ mov(edi, Operand(esp, eax, times_pointer_size, 0)); + + CallConstructStub stub(isolate(), SUPER_CONSTRUCTOR_CALL); + __ call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL); + + __ Drop(1); + + context()->Plug(eax); +} + + void FullCodeGenerator::EmitRegExpConstructResult(CallRuntime* expr) { // Load the arguments on the stack and call the stub. RegExpConstructResultStub stub(isolate()); diff --git a/src/parser.cc b/src/parser.cc index 15ed6ded0e..6db0053a69 100644 --- a/src/parser.cc +++ b/src/parser.cc @@ -271,8 +271,11 @@ FunctionLiteral* Parser::DefaultConstructor(bool call_super, Scope* scope, int parameter_count = 0; const AstRawString* name = ast_value_factory()->empty_string(); - Scope* function_scope = - NewScope(scope, FUNCTION_SCOPE, FunctionKind::kDefaultConstructor); + + FunctionKind kind = call_super && !FLAG_experimental_classes + ? FunctionKind::kDefaultBaseConstructor + : FunctionKind::kDefaultSubclassConstructor; + Scope* function_scope = NewScope(scope, FUNCTION_SCOPE, kind); function_scope->SetLanguageMode( static_cast(scope->language_mode() | STRICT_BIT)); // Set start and end position to the same value @@ -283,17 +286,26 @@ FunctionLiteral* Parser::DefaultConstructor(bool call_super, Scope* scope, { AstNodeFactory function_factory(ast_value_factory()); FunctionState function_state(&function_state_, &scope_, function_scope, - kDefaultConstructor, &function_factory); + kind, &function_factory); - body = new (zone()) ZoneList(1, zone()); + body = new (zone()) ZoneList(call_super ? 2 : 1, zone()); + AddAssertIsConstruct(body, pos); if (call_super) { ZoneList* args = new (zone()) ZoneList(0, zone()); - CallRuntime* call = factory()->NewCallRuntime( - ast_value_factory()->empty_string(), - Runtime::FunctionForId(Runtime::kDefaultConstructorSuperCall), args, - pos); - body->Add(factory()->NewExpressionStatement(call, pos), zone()); + if (FLAG_experimental_classes) { + CallRuntime* call = factory()->NewCallRuntime( + ast_value_factory()->empty_string(), + Runtime::FunctionForId(Runtime::kInlineDefaultConstructorCallSuper), + args, pos); + body->Add(factory()->NewReturnStatement(call, pos), zone()); + } else { + CallRuntime* call = factory()->NewCallRuntime( + ast_value_factory()->empty_string(), + Runtime::FunctionForId(Runtime::kDefaultConstructorSuperCall), args, + pos); + body->Add(factory()->NewExpressionStatement(call, pos), zone()); + } function_scope->RecordSuperConstructorCallUsage(); } @@ -307,8 +319,7 @@ FunctionLiteral* Parser::DefaultConstructor(bool call_super, Scope* scope, materialized_literal_count, expected_property_count, handler_count, parameter_count, FunctionLiteral::kNoDuplicateParameters, FunctionLiteral::ANONYMOUS_EXPRESSION, FunctionLiteral::kIsFunction, - FunctionLiteral::kNotParenthesized, FunctionKind::kDefaultConstructor, - pos); + FunctionLiteral::kNotParenthesized, kind, pos); return function_literal; } @@ -3894,6 +3905,26 @@ void Parser::SkipLazyFunctionBody(const AstRawString* function_name, } +void Parser::AddAssertIsConstruct(ZoneList* body, int pos) { + if (!FLAG_experimental_classes) return; + + ZoneList* arguments = + new (zone()) ZoneList(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()); +} + + ZoneList* Parser::ParseEagerFunctionBody( const AstRawString* function_name, int pos, Variable* fvar, Token::Value fvar_init_op, FunctionKind kind, bool* ok) { @@ -3916,22 +3947,8 @@ ZoneList* Parser::ParseEagerFunctionBody( // For concise constructors, check that they are constructed, // not called. - if (FLAG_experimental_classes && i::IsConstructor(kind)) { - ZoneList* arguments = - new (zone()) ZoneList(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()); + if (i::IsConstructor(kind)) { + AddAssertIsConstruct(body, pos); } // For generators, allocate and yield an iterator on function entry. diff --git a/src/parser.h b/src/parser.h index 19036e7739..a91f62ad50 100644 --- a/src/parser.h +++ b/src/parser.h @@ -840,6 +840,8 @@ class Parser : public ParserBase { BreakableStatement* LookupBreakTarget(const AstRawString* label, bool* ok); IterationStatement* LookupContinueTarget(const AstRawString* label, bool* ok); + void AddAssertIsConstruct(ZoneList* body, int pos); + // Factory methods. FunctionLiteral* DefaultConstructor(bool call_super, Scope* scope, int pos, int end_pos); diff --git a/src/runtime/runtime-classes.cc b/src/runtime/runtime-classes.cc index 077c3d5abe..ea641d3faf 100644 --- a/src/runtime/runtime-classes.cc +++ b/src/runtime/runtime-classes.cc @@ -414,7 +414,15 @@ RUNTIME_FUNCTION(Runtime_StoreKeyedToSuper_Sloppy) { } +RUNTIME_FUNCTION(RuntimeReference_DefaultConstructorCallSuper) { + UNREACHABLE(); + return nullptr; +} + + +// TODO(dslomov): deprecated, will remove when experimenal classes is default. RUNTIME_FUNCTION(Runtime_DefaultConstructorSuperCall) { + CHECK(!FLAG_experimental_classes); HandleScope scope(isolate); DCHECK(args.length() == 0); diff --git a/src/runtime/runtime.h b/src/runtime/runtime.h index a73fb24504..56aa905821 100644 --- a/src/runtime/runtime.h +++ b/src/runtime/runtime.h @@ -654,6 +654,7 @@ namespace internal { F(IsJSProxy, 1, 1) \ F(IsConstructCall, 0, 1) \ F(CallFunction, -1 /* receiver + n args + function */, 1) \ + F(DefaultConstructorCallSuper, 0, 1) \ F(ArgumentsLength, 0, 1) \ F(Arguments, 1, 1) \ F(ValueOf, 1, 1) \ diff --git a/src/x64/code-stubs-x64.cc b/src/x64/code-stubs-x64.cc index e56fc4a570..1413eff5cb 100644 --- a/src/x64/code-stubs-x64.cc +++ b/src/x64/code-stubs-x64.cc @@ -936,7 +936,7 @@ void ArgumentsAccessStub::GenerateNewStrict(MacroAssembler* masm) { if (has_new_target()) { // Subtract 1 from smi-tagged arguments count. __ SmiToInteger32(rcx, rcx); - __ decp(rcx); + __ decl(rcx); __ Integer32ToSmi(rcx, rcx); } __ movp(args.GetArgumentOperand(2), rcx); diff --git a/src/x64/full-codegen-x64.cc b/src/x64/full-codegen-x64.cc index 8fe07975c2..33521c6f17 100644 --- a/src/x64/full-codegen-x64.cc +++ b/src/x64/full-codegen-x64.cc @@ -2962,8 +2962,7 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) { } -void FullCodeGenerator::EmitLoadSuperConstructor(SuperReference* super_ref) { - DCHECK(super_ref != NULL); +void FullCodeGenerator::EmitLoadSuperConstructor() { __ Push(Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); __ CallRuntime(Runtime::kGetPrototype, 1); } @@ -3080,9 +3079,9 @@ void FullCodeGenerator::VisitCall(Call* expr) { if (FLAG_experimental_classes) { EmitSuperConstructorCall(expr); } else { - SuperReference* super_ref = callee->AsSuperReference(); - EmitLoadSuperConstructor(super_ref); + EmitLoadSuperConstructor(); __ Push(result_register()); + SuperReference* super_ref = callee->AsSuperReference(); VisitForStackValue(super_ref->this_var()); EmitCall(expr, CallICState::METHOD); } @@ -3153,10 +3152,10 @@ void FullCodeGenerator::EmitSuperConstructorCall(Call* expr) { GetVar(result_register(), new_target_var); __ Push(result_register()); - SuperReference* super_ref = expr->expression()->AsSuperReference(); - EmitLoadSuperConstructor(super_ref); + EmitLoadSuperConstructor(); __ Push(result_register()); + SuperReference* super_ref = expr->expression()->AsSuperReference(); Variable* this_var = super_ref->this_var()->var(); GetVar(rax, this_var); @@ -4071,6 +4070,55 @@ void FullCodeGenerator::EmitCallFunction(CallRuntime* expr) { } +void FullCodeGenerator::EmitDefaultConstructorCallSuper(CallRuntime* expr) { + Variable* new_target_var = scope()->DeclarationScope()->new_target_var(); + GetVar(result_register(), new_target_var); + __ Push(result_register()); + + EmitLoadSuperConstructor(); + __ Push(result_register()); + + // Check if the calling frame is an arguments adaptor frame. + Label adaptor_frame, args_set_up, runtime; + __ movp(rdx, Operand(rbp, StandardFrameConstants::kCallerFPOffset)); + __ movp(rcx, Operand(rdx, StandardFrameConstants::kContextOffset)); + __ Cmp(rcx, Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)); + __ j(equal, &adaptor_frame); + // default constructor has no arguments, so no adaptor frame means no args. + __ movp(rax, Immediate(0)); + __ jmp(&args_set_up); + + // Copy arguments from adaptor frame. + { + __ bind(&adaptor_frame); + __ movp(rcx, Operand(rdx, ArgumentsAdaptorFrameConstants::kLengthOffset)); + __ SmiToInteger64(rcx, rcx); + + // Subtract 1 from arguments count, for new.target. + __ subp(rcx, Immediate(1)); + __ movp(rax, rcx); + __ leap(rdx, Operand(rdx, rcx, times_pointer_size, + StandardFrameConstants::kCallerSPOffset)); + Label loop; + __ bind(&loop); + __ Push(Operand(rdx, -1 * kPointerSize)); + __ subp(rdx, Immediate(kPointerSize)); + __ decp(rcx); + __ j(not_zero, &loop); + } + + __ bind(&args_set_up); + __ movp(rdi, Operand(rsp, rax, times_pointer_size, 0)); + + CallConstructStub stub(isolate(), SUPER_CONSTRUCTOR_CALL); + __ call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL); + + __ Drop(1); + + context()->Plug(result_register()); +} + + void FullCodeGenerator::EmitRegExpConstructResult(CallRuntime* expr) { RegExpConstructResultStub stub(isolate()); ZoneList* args = expr->arguments(); diff --git a/test/mjsunit/harmony/classes-experimental.js b/test/mjsunit/harmony/classes-experimental.js index 36c4dd8246..c37dee2b00 100644 --- a/test/mjsunit/harmony/classes-experimental.js +++ b/test/mjsunit/harmony/classes-experimental.js @@ -172,7 +172,7 @@ assertEquals(10, eua.byteLength); assertEquals(0xFF, eua[0]); assertEquals(0xFA, eua[1]); - assertTrue(eua.__proto__ === ExtendedUint8Array.prototype); + assertSame(ExtendedUint8Array.prototype, eua.__proto__); assertEquals("[object Uint8Array]", Object.prototype.toString.call(eua)); }()); @@ -225,3 +225,61 @@ assertSame(8, s2.y); assertSame(Subclass.prototype, s.__proto__); }()); + + +(function TestDefaultConstructor() { + class Base1 { } + assertThrows(function() { Base1(); }, TypeError); + + class Subclass1 extends Base1 { } + + assertThrows(function() { Subclass1(); }, TypeError); + + let s1 = new Subclass1(); + assertSame(s1.__proto__, Subclass1.prototype); + + class Base2 { + constructor(x, y) { + this.x = x; + this.y = y; + } + } + + class Subclass2 extends Base2 {}; + + let s2 = new Subclass2(1, 2); + + assertSame(s2.__proto__, Subclass2.prototype); + assertSame(1, s2.x); + assertSame(2, s2.y); + + let f = Subclass2.bind({}, 3, 4); + let s2prime = new f(); + assertSame(s2prime.__proto__, Subclass2.prototype); + assertSame(3, s2prime.x); + assertSame(4, s2prime.y); + + let obj = {}; + class Base3 { + constructor() { + return obj; + } + } + + class Subclass3 extends Base3 {}; + + let s3 = new Subclass3(); + assertSame(obj, s3); + + class ExtendedUint8Array extends Uint8Array { } + + var eua = new ExtendedUint8Array(10); + assertEquals(10, eua.length); + assertEquals(10, eua.byteLength); + eua[0] = 0xFF; + eua[1] = 0xFFA; + assertEquals(0xFF, eua[0]); + assertEquals(0xFA, eua[1]); + assertSame(ExtendedUint8Array.prototype, eua.__proto__); + assertEquals("[object Uint8Array]", Object.prototype.toString.call(eua)); +}());