new classes: implement default constructors.
authordslomov <dslomov@chromium.org>
Wed, 11 Feb 2015 17:22:50 +0000 (09:22 -0800)
committerCommit bot <commit-bot@chromium.org>
Wed, 11 Feb 2015 17:23:00 +0000 (17:23 +0000)
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}

13 files changed:
src/arm/full-codegen-arm.cc
src/arm64/full-codegen-arm64.cc
src/full-codegen.h
src/globals.h
src/hydrogen.cc
src/ia32/full-codegen-ia32.cc
src/parser.cc
src/parser.h
src/runtime/runtime-classes.cc
src/runtime/runtime.h
src/x64/code-stubs-x64.cc
src/x64/full-codegen-x64.cc
test/mjsunit/harmony/classes-experimental.js

index 679327e..c9a5648 100644 (file)
@@ -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<Expression*>* args = expr->arguments();
index 18605df..c1615c9 100644 (file)
@@ -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<Expression*>* args = expr->arguments();
index 9a2e746..b3c816b 100644 (file)
@@ -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> code,
               TypeFeedbackId id = TypeFeedbackId::None());
index bb9a417..0edd643 100644 (file)
@@ -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;
 }
index 7d15464..7e5880a 100644 (file)
@@ -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());
index 6ee5d95..4b603dd 100644 (file)
@@ -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());
index 15ed6de..6db0053 100644 (file)
@@ -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<LanguageMode>(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<Statement*>(1, zone());
+    body = new (zone()) ZoneList<Statement*>(call_super ? 2 : 1, zone());
+    AddAssertIsConstruct(body, pos);
     if (call_super) {
       ZoneList<Expression*>* args =
           new (zone()) ZoneList<Expression*>(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<Statement*>* body, int pos) {
+  if (!FLAG_experimental_classes) return;
+
+  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());
+}
+
+
 ZoneList<Statement*>* Parser::ParseEagerFunctionBody(
     const AstRawString* function_name, int pos, Variable* fvar,
     Token::Value fvar_init_op, FunctionKind kind, bool* ok) {
@@ -3916,22 +3947,8 @@ ZoneList<Statement*>* Parser::ParseEagerFunctionBody(
 
   // 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());
+  if (i::IsConstructor(kind)) {
+    AddAssertIsConstruct(body, pos);
   }
 
   // For generators, allocate and yield an iterator on function entry.
index 19036e7..a91f62a 100644 (file)
@@ -840,6 +840,8 @@ class Parser : public ParserBase<ParserTraits> {
   BreakableStatement* LookupBreakTarget(const AstRawString* label, bool* ok);
   IterationStatement* LookupContinueTarget(const AstRawString* label, bool* ok);
 
+  void AddAssertIsConstruct(ZoneList<Statement*>* body, int pos);
+
   // Factory methods.
   FunctionLiteral* DefaultConstructor(bool call_super, Scope* scope, int pos,
                                       int end_pos);
index 077c3d5..ea641d3 100644 (file)
@@ -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);
 
index a73fb24..56aa905 100644 (file)
@@ -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)                                          \
index e56fc4a..1413eff 100644 (file)
@@ -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);
index 8fe0797..33521c6 100644 (file)
@@ -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<Expression*>* args = expr->arguments();
index 36c4dd8..c37dee2 100644 (file)
   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));
 }());
 
   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));
+}());