[turbofan] Build graphs for super constructor calls.
authormstarzinger <mstarzinger@chromium.org>
Tue, 14 Jul 2015 11:40:15 +0000 (04:40 -0700)
committerCommit bot <commit-bot@chromium.org>
Tue, 14 Jul 2015 11:40:31 +0000 (11:40 +0000)
This adapts JSCallConstruct nodes to represent both, ordinary 'new'
constructor calls as well as 'super' constructor calls. Note that we
still bailout for super calls for now.

R=bmeurer@chromium.org

Review URL: https://codereview.chromium.org/1234023003

Cr-Commit-Position: refs/heads/master@{#29647}

src/compiler/ast-graph-builder.cc
src/compiler/ast-graph-builder.h
src/compiler/js-generic-lowering.cc

index fab743781cca1bb0a83a80dcea1daa15d159d54e..f442017cd86b8fcdc4b463ea5e38ea242183dcc3 100644 (file)
@@ -2428,11 +2428,7 @@ void AstGraphBuilder::VisitCall(Call* expr) {
       break;
     }
     case Call::SUPER_CALL:
-      // TODO(dslomov): Implement super calls.
-      callee_value = jsgraph()->UndefinedConstant();
-      receiver_value = jsgraph()->UndefinedConstant();
-      SetStackOverflow();
-      break;
+      return VisitCallSuper(expr);
     case Call::POSSIBLY_EVAL_CALL:
       possibly_eval = true;
       if (callee->AsVariableProxy()->var()->IsLookupSlot()) {
@@ -2499,6 +2495,45 @@ void AstGraphBuilder::VisitCall(Call* expr) {
 }
 
 
+void AstGraphBuilder::VisitCallSuper(Call* expr) {
+  SuperCallReference* super = expr->expression()->AsSuperCallReference();
+  DCHECK_NOT_NULL(super);
+
+  // Prepare the callee to the super call. The super constructor is stored as
+  // the prototype of the constructor we are currently executing.
+  VisitForValue(super->this_function_var());
+  Node* this_function = environment()->Pop();
+  const Operator* op = javascript()->CallRuntime(Runtime::kGetPrototype, 1);
+  Node* super_function = NewNode(op, this_function);
+  // TODO(mstarzinger): This probably needs a proper bailout id.
+  PrepareFrameState(super_function, BailoutId::None());
+  environment()->Push(super_function);
+
+  // Evaluate all arguments to the super call.
+  ZoneList<Expression*>* args = expr->arguments();
+  VisitForValues(args);
+
+  // Original receiver is loaded from the {new.target} variable.
+  VisitForValue(super->new_target_var());
+
+  // Create node to perform the super call.
+  const Operator* call = javascript()->CallConstruct(args->length() + 2);
+  Node* value = ProcessArguments(call, args->length() + 2);
+  PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
+
+  // TODO(mstarzinger): It sure would be nice if this were desugared. Also we
+  // are still missing the hole-check in the assignment below, fix that.
+  FrameStateBeforeAndAfter states(this, BailoutId::None());
+  BuildVariableAssignment(super->this_var()->var(), value, Token::INIT_CONST,
+                          VectorSlotPair(), BailoutId::None(), states);
+
+  // TODO(mstarzinger): Remove bailout once lowering is correct.
+  SetStackOverflow();
+
+  ast_context()->ProduceValue(value);
+}
+
+
 void AstGraphBuilder::VisitCallNew(CallNew* expr) {
   VisitForValue(expr->expression());
 
@@ -2506,9 +2541,12 @@ void AstGraphBuilder::VisitCallNew(CallNew* expr) {
   ZoneList<Expression*>* args = expr->arguments();
   VisitForValues(args);
 
+  // Original receiver is the same as the callee.
+  environment()->Push(environment()->Peek(args->length()));
+
   // Create node to perform the construct call.
-  const Operator* call = javascript()->CallConstruct(args->length() + 1);
-  Node* value = ProcessArguments(call, args->length() + 1);
+  const Operator* call = javascript()->CallConstruct(args->length() + 2);
+  Node* value = ProcessArguments(call, args->length() + 2);
   PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
   ast_context()->ProduceValue(value);
 }
index 7957c0dc863a8fd9ad4e190a03f4d29bb7d2bbfe..201a20a18afec5c011bb5abbabcef55e1354d4d6 100644 (file)
@@ -387,6 +387,9 @@ class AstGraphBuilder : public AstVisitor {
   // Common for all IterationStatement bodies.
   void VisitIterationBody(IterationStatement* stmt, LoopBuilder* loop);
 
+  // Dispatched from VisitCall.
+  void VisitCallSuper(Call* expr);
+
   // Dispatched from VisitCallRuntime.
   void VisitCallJSRuntime(CallRuntime* expr);
 
index 81db1527a33400176cd0d6a88050ba281cd30a2b..4915b75d06f4d93e009472dcf84c66974e6d9541 100644 (file)
@@ -541,12 +541,16 @@ void JSGenericLowering::LowerJSCallConstruct(Node* node) {
   CallInterfaceDescriptor d = stub.GetCallInterfaceDescriptor();
   CallDescriptor::Flags flags = AdjustFrameStatesForCall(node);
   CallDescriptor* desc =
-      Linkage::GetStubCallDescriptor(isolate(), zone(), d, arity, flags);
+      Linkage::GetStubCallDescriptor(isolate(), zone(), d, arity - 1, flags);
   Node* stub_code = jsgraph()->HeapConstant(stub.GetCode());
-  Node* construct = NodeProperties::GetValueInput(node, 0);
+  Node* actual_construct = NodeProperties::GetValueInput(node, 0);
+  Node* original_construct = NodeProperties::GetValueInput(node, arity - 1);
+  node->RemoveInput(arity - 1);  // Drop original constructor.
   node->InsertInput(zone(), 0, stub_code);
-  node->InsertInput(zone(), 1, jsgraph()->Int32Constant(arity - 1));
-  node->InsertInput(zone(), 2, construct);
+  node->InsertInput(zone(), 1, jsgraph()->Int32Constant(arity - 2));
+  node->InsertInput(zone(), 2, actual_construct);
+  // TODO(mstarzinger): Pass original constructor in register.
+  CHECK_EQ(actual_construct, original_construct);
   node->InsertInput(zone(), 3, jsgraph()->UndefinedConstant());
   node->set_op(common()->Call(desc));
 }