Reviewers: arv,

Description:
[turbofan] Port initialization of new.target variable.

This implements the proper initialization of the new.target internal
variable in the AstGraphBuilder. For now this uses a runtime call that
cannot handle inlined frames correctly.

[email protected]

Please review this at https://codereview.chromium.org/1212813008/

Base URL: https://chromium.googlesource.com/v8/v8.git@master

Affected files (+60, -17 lines):
  M src/compiler/ast-graph-builder.h
  M src/compiler/ast-graph-builder.cc
  M src/compiler/linkage.cc
  M src/frames.h
  M src/frames.cc
  M src/runtime/runtime.h
  M src/runtime/runtime-function.cc


Index: src/compiler/ast-graph-builder.cc
diff --git a/src/compiler/ast-graph-builder.cc b/src/compiler/ast-graph-builder.cc index 31cd3fd2d68240571428a7eea72abff45ccfb54a..e802cd8399682122e6fbd1bfc64749f036551bbc 100644
--- a/src/compiler/ast-graph-builder.cc
+++ b/src/compiler/ast-graph-builder.cc
@@ -566,12 +566,11 @@ void AstGraphBuilder::CreateGraphBody(bool stack_check) {
   Variable* rest_parameter = scope->rest_parameter(&rest_index);
   BuildRestArgumentsArray(rest_parameter, rest_index);

-  // Build .this_function var if it is used.
-  BuildThisFunctionVar(scope->this_function_var());
+  // Build assignment to {.this_function} variable if it is used.
+  BuildThisFunctionVariable(scope->this_function_var());

-  if (scope->new_target_var() != nullptr) {
-    SetStackOverflow();
-  }
+  // Build assignment to {new.target} variable if it is used.
+  BuildNewTargetVariable(scope->new_target_var());

   // Emit tracing call if requested to do so.
   if (FLAG_trace) {
@@ -3144,10 +3143,8 @@ Node* AstGraphBuilder::BuildArgumentsObject(Variable* arguments) {
   DCHECK(arguments->IsContextSlot() || arguments->IsStackAllocated());
// This should never lazy deopt, so it is fine to send invalid bailout id.
   FrameStateBeforeAndAfter states(this, BailoutId::None());
-  VectorSlotPair feedback;
-  BuildVariableAssignment(arguments, object, Token::ASSIGN, feedback,
+ BuildVariableAssignment(arguments, object, Token::ASSIGN, VectorSlotPair(),
                           BailoutId::None(), states);
-
   return object;
 }

@@ -3160,30 +3157,46 @@ Node* AstGraphBuilder::BuildRestArgumentsArray(Variable* rest, int index) {
   Node* object = NewNode(op, jsgraph()->SmiConstant(index),
                          jsgraph()->SmiConstant(language_mode()));

-  // Assign the object to the rest array
+  // Assign the object to the rest parameter variable.
   DCHECK(rest->IsContextSlot() || rest->IsStackAllocated());
// This should never lazy deopt, so it is fine to send invalid bailout id.
   FrameStateBeforeAndAfter states(this, BailoutId::None());
-  VectorSlotPair feedback;
-  BuildVariableAssignment(rest, object, Token::ASSIGN, feedback,
+  BuildVariableAssignment(rest, object, Token::ASSIGN, VectorSlotPair(),
                           BailoutId::None(), states);
-
   return object;
 }


-Node* AstGraphBuilder::BuildThisFunctionVar(Variable* this_function_var) {
+Node* AstGraphBuilder::BuildThisFunctionVariable(Variable* this_function_var) {
   if (this_function_var == nullptr) return nullptr;

+  // Retrieve the closure we were called with.
   Node* this_function = GetFunctionClosure();
+
+  // Assign the object to the {.this_function} variable.
   FrameStateBeforeAndAfter states(this, BailoutId::None());
-  VectorSlotPair feedback;
BuildVariableAssignment(this_function_var, this_function, Token::INIT_CONST,
-                          feedback, BailoutId::None(), states);
+                          VectorSlotPair(), BailoutId::None(), states);
   return this_function;
 }


+Node* AstGraphBuilder::BuildNewTargetVariable(Variable* new_target_var) {
+  if (new_target_var == nullptr) return nullptr;
+
+ // Retrieve the original constructor in case we are called as a constructor.
+  const Operator* op =
+      javascript()->CallRuntime(Runtime::kGetOriginalConstructor, 0);
+  Node* object = NewNode(op);
+
+  // Assign the object to the {new.target} variable.
+  FrameStateBeforeAndAfter states(this, BailoutId::None());
+  BuildVariableAssignment(new_target_var, object, Token::INIT_CONST,
+                          VectorSlotPair(), BailoutId::None(), states);
+  return object;
+}
+
+
 Node* AstGraphBuilder::BuildHoleCheckSilent(Node* value, Node* for_hole,
                                             Node* not_hole) {
   Node* the_hole = jsgraph()->TheHoleConstant();
Index: src/compiler/ast-graph-builder.h
diff --git a/src/compiler/ast-graph-builder.h b/src/compiler/ast-graph-builder.h index 17190bc8b7adad0612335c14cb2895fa654a5d4f..b2c6f4355d26fa75953ab61c6b46d1abe70bc7a3 100644
--- a/src/compiler/ast-graph-builder.h
+++ b/src/compiler/ast-graph-builder.h
@@ -265,8 +265,11 @@ class AstGraphBuilder : public AstVisitor {
   // Builder to create an array of rest parameters if used
   Node* BuildRestArgumentsArray(Variable* rest, int index);

- // Builder that assigns to the .this_function internal variable if needed.
-  Node* BuildThisFunctionVar(Variable* this_function_var);
+ // Builder that assigns to the {.this_function} internal variable if needed.
+  Node* BuildThisFunctionVariable(Variable* this_function_var);
+
+  // Builder that assigns to the {new.target} internal variable if needed.
+  Node* BuildNewTargetVariable(Variable* new_target_var);

   // Builders for variable load and assignment.
   Node* BuildVariableAssignment(Variable* variable, Node* value,
Index: src/compiler/linkage.cc
diff --git a/src/compiler/linkage.cc b/src/compiler/linkage.cc
index 93bf21a84291918f40b2d63b65f6a52f9aa6e083..6ef014246d95f74dba60a5d0bb079b6a9defdfd8 100644
--- a/src/compiler/linkage.cc
+++ b/src/compiler/linkage.cc
@@ -175,6 +175,7 @@ int Linkage::FrameStateInputCount(Runtime::FunctionId function) { case Runtime::kDefineSetterPropertyUnchecked: // TODO(jarin): Is it safe?
     case Runtime::kForInDone:
     case Runtime::kForInStep:
+    case Runtime::kGetOriginalConstructor:
     case Runtime::kNewArguments:
     case Runtime::kNewClosure:
     case Runtime::kNewFunctionContext:
Index: src/frames.cc
diff --git a/src/frames.cc b/src/frames.cc
index cde6f21f74813ddb7f90612293bcc057225929ae..5aefe066f5ba7cfb9f871718525fad9858a88a8d 100644
--- a/src/frames.cc
+++ b/src/frames.cc
@@ -730,6 +730,17 @@ bool JavaScriptFrame::IsConstructor() const {
 }


+Object* JavaScriptFrame::GetOriginalConstructor() const {
+  Address fp = caller_fp();
+  if (has_adapted_arguments()) {
+    // Skip the arguments adaptor frame and look at the real caller.
+    fp = Memory::Address_at(fp + StandardFrameConstants::kCallerFPOffset);
+  }
+  DCHECK(IsConstructFrame(fp));
+  return GetExpression(fp, 2);
+}
+
+
 int JavaScriptFrame::GetArgumentsLength() const {
// If there is an arguments adaptor frame get the arguments length from it.
   if (has_adapted_arguments()) {
Index: src/frames.h
diff --git a/src/frames.h b/src/frames.h
index 562445a2f1b115f71ed3ea17f97f0452f90afa03..ca3aba441a284240d44d0ac4796675ab3b257124 100644
--- a/src/frames.h
+++ b/src/frames.h
@@ -533,6 +533,10 @@ class JavaScriptFrame: public StandardFrame {
   // Check if this frame is a constructor frame invoked through 'new'.
   bool IsConstructor() const;

+ // Returns the original constructor function that was used in the constructor + // call to this frame. Note that this is only valid on constructor frames.
+  Object* GetOriginalConstructor() const;
+
   // Check if this frame has "adapted" arguments in the sense that the
   // actual passed arguments are available in an arguments adaptor
   // frame below it on the stack.
Index: src/runtime/runtime-function.cc
diff --git a/src/runtime/runtime-function.cc b/src/runtime/runtime-function.cc index d644d37e42b2fff45685eb2c7604c5c68c801a3d..43c9ab4e04f079ebf90eea22f5ee6661eeff3852 100644
--- a/src/runtime/runtime-function.cc
+++ b/src/runtime/runtime-function.cc
@@ -601,6 +601,16 @@ RUNTIME_FUNCTION(Runtime_GetConstructorDelegate) {
 }


+RUNTIME_FUNCTION(Runtime_GetOriginalConstructor) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 0);
+  JavaScriptFrameIterator it(isolate);
+  JavaScriptFrame* frame = it.frame();
+  return frame->IsConstructor() ? frame->GetOriginalConstructor()
+                                : isolate->heap()->undefined_value();
+}
+
+
 RUNTIME_FUNCTION(Runtime_CallFunction) {
   SealHandleScope shs(isolate);
   return __RT_impl_Runtime_Call(args, isolate);
Index: src/runtime/runtime.h
diff --git a/src/runtime/runtime.h b/src/runtime/runtime.h
index 37d98603ba21d4b3186a4bc0ab6ed4e6983e74a2..da1ae40ba068cb4c58e7a9ac5595f3dfc2f4e995 100644
--- a/src/runtime/runtime.h
+++ b/src/runtime/runtime.h
@@ -239,6 +239,7 @@ namespace internal {
   F(Apply, 5, 1)                                            \
   F(GetFunctionDelegate, 1, 1)                              \
   F(GetConstructorDelegate, 1, 1)                           \
+  F(GetOriginalConstructor, 0, 1)                           \
   F(CallFunction, -1 /* receiver + n args + function */, 1) \
   F(IsConstructCall, 0, 1)                                  \
   F(IsFunction, 1, 1)


--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
--- You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to