Commit e2f0bca7 authored by mstarzinger's avatar mstarzinger Committed by Commit bot

[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.

R=arv@chromium.org

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

Cr-Commit-Position: refs/heads/master@{#29500}
parent dd7962bf
...@@ -566,12 +566,11 @@ void AstGraphBuilder::CreateGraphBody(bool stack_check) { ...@@ -566,12 +566,11 @@ void AstGraphBuilder::CreateGraphBody(bool stack_check) {
Variable* rest_parameter = scope->rest_parameter(&rest_index); Variable* rest_parameter = scope->rest_parameter(&rest_index);
BuildRestArgumentsArray(rest_parameter, rest_index); BuildRestArgumentsArray(rest_parameter, rest_index);
// Build .this_function var if it is used. // Build assignment to {.this_function} variable if it is used.
BuildThisFunctionVar(scope->this_function_var()); BuildThisFunctionVariable(scope->this_function_var());
if (scope->new_target_var() != nullptr) { // Build assignment to {new.target} variable if it is used.
SetStackOverflow(); BuildNewTargetVariable(scope->new_target_var());
}
// Emit tracing call if requested to do so. // Emit tracing call if requested to do so.
if (FLAG_trace) { if (FLAG_trace) {
...@@ -3146,10 +3145,8 @@ Node* AstGraphBuilder::BuildArgumentsObject(Variable* arguments) { ...@@ -3146,10 +3145,8 @@ Node* AstGraphBuilder::BuildArgumentsObject(Variable* arguments) {
DCHECK(arguments->IsContextSlot() || arguments->IsStackAllocated()); DCHECK(arguments->IsContextSlot() || arguments->IsStackAllocated());
// This should never lazy deopt, so it is fine to send invalid bailout id. // This should never lazy deopt, so it is fine to send invalid bailout id.
FrameStateBeforeAndAfter states(this, BailoutId::None()); FrameStateBeforeAndAfter states(this, BailoutId::None());
VectorSlotPair feedback; BuildVariableAssignment(arguments, object, Token::ASSIGN, VectorSlotPair(),
BuildVariableAssignment(arguments, object, Token::ASSIGN, feedback,
BailoutId::None(), states); BailoutId::None(), states);
return object; return object;
} }
...@@ -3162,30 +3159,46 @@ Node* AstGraphBuilder::BuildRestArgumentsArray(Variable* rest, int index) { ...@@ -3162,30 +3159,46 @@ Node* AstGraphBuilder::BuildRestArgumentsArray(Variable* rest, int index) {
Node* object = NewNode(op, jsgraph()->SmiConstant(index), Node* object = NewNode(op, jsgraph()->SmiConstant(index),
jsgraph()->SmiConstant(language_mode())); jsgraph()->SmiConstant(language_mode()));
// Assign the object to the rest array // Assign the object to the rest parameter variable.
DCHECK(rest->IsContextSlot() || rest->IsStackAllocated()); DCHECK(rest->IsContextSlot() || rest->IsStackAllocated());
// This should never lazy deopt, so it is fine to send invalid bailout id. // This should never lazy deopt, so it is fine to send invalid bailout id.
FrameStateBeforeAndAfter states(this, BailoutId::None()); FrameStateBeforeAndAfter states(this, BailoutId::None());
VectorSlotPair feedback; BuildVariableAssignment(rest, object, Token::ASSIGN, VectorSlotPair(),
BuildVariableAssignment(rest, object, Token::ASSIGN, feedback,
BailoutId::None(), states); BailoutId::None(), states);
return object; return object;
} }
Node* AstGraphBuilder::BuildThisFunctionVar(Variable* this_function_var) { Node* AstGraphBuilder::BuildThisFunctionVariable(Variable* this_function_var) {
if (this_function_var == nullptr) return nullptr; if (this_function_var == nullptr) return nullptr;
// Retrieve the closure we were called with.
Node* this_function = GetFunctionClosure(); Node* this_function = GetFunctionClosure();
// Assign the object to the {.this_function} variable.
FrameStateBeforeAndAfter states(this, BailoutId::None()); FrameStateBeforeAndAfter states(this, BailoutId::None());
VectorSlotPair feedback;
BuildVariableAssignment(this_function_var, this_function, Token::INIT_CONST, BuildVariableAssignment(this_function_var, this_function, Token::INIT_CONST,
feedback, BailoutId::None(), states); VectorSlotPair(), BailoutId::None(), states);
return this_function; 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* AstGraphBuilder::BuildHoleCheckSilent(Node* value, Node* for_hole,
Node* not_hole) { Node* not_hole) {
Node* the_hole = jsgraph()->TheHoleConstant(); Node* the_hole = jsgraph()->TheHoleConstant();
......
...@@ -265,8 +265,11 @@ class AstGraphBuilder : public AstVisitor { ...@@ -265,8 +265,11 @@ class AstGraphBuilder : public AstVisitor {
// Builder to create an array of rest parameters if used // Builder to create an array of rest parameters if used
Node* BuildRestArgumentsArray(Variable* rest, int index); Node* BuildRestArgumentsArray(Variable* rest, int index);
// Builder that assigns to the .this_function internal variable if needed. // Builder that assigns to the {.this_function} internal variable if needed.
Node* BuildThisFunctionVar(Variable* this_function_var); 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. // Builders for variable load and assignment.
Node* BuildVariableAssignment(Variable* variable, Node* value, Node* BuildVariableAssignment(Variable* variable, Node* value,
......
...@@ -175,6 +175,7 @@ int Linkage::FrameStateInputCount(Runtime::FunctionId function) { ...@@ -175,6 +175,7 @@ int Linkage::FrameStateInputCount(Runtime::FunctionId function) {
case Runtime::kDefineSetterPropertyUnchecked: // TODO(jarin): Is it safe? case Runtime::kDefineSetterPropertyUnchecked: // TODO(jarin): Is it safe?
case Runtime::kForInDone: case Runtime::kForInDone:
case Runtime::kForInStep: case Runtime::kForInStep:
case Runtime::kGetOriginalConstructor:
case Runtime::kNewArguments: case Runtime::kNewArguments:
case Runtime::kNewClosure: case Runtime::kNewClosure:
case Runtime::kNewFunctionContext: case Runtime::kNewFunctionContext:
......
...@@ -730,6 +730,17 @@ bool JavaScriptFrame::IsConstructor() const { ...@@ -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 { int JavaScriptFrame::GetArgumentsLength() const {
// If there is an arguments adaptor frame get the arguments length from it. // If there is an arguments adaptor frame get the arguments length from it.
if (has_adapted_arguments()) { if (has_adapted_arguments()) {
......
...@@ -533,6 +533,10 @@ class JavaScriptFrame: public StandardFrame { ...@@ -533,6 +533,10 @@ class JavaScriptFrame: public StandardFrame {
// Check if this frame is a constructor frame invoked through 'new'. // Check if this frame is a constructor frame invoked through 'new'.
bool IsConstructor() const; 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 // Check if this frame has "adapted" arguments in the sense that the
// actual passed arguments are available in an arguments adaptor // actual passed arguments are available in an arguments adaptor
// frame below it on the stack. // frame below it on the stack.
......
...@@ -604,6 +604,16 @@ RUNTIME_FUNCTION(Runtime_GetConstructorDelegate) { ...@@ -604,6 +604,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) { RUNTIME_FUNCTION(Runtime_CallFunction) {
SealHandleScope shs(isolate); SealHandleScope shs(isolate);
return __RT_impl_Runtime_Call(args, isolate); return __RT_impl_Runtime_Call(args, isolate);
......
...@@ -239,6 +239,7 @@ namespace internal { ...@@ -239,6 +239,7 @@ namespace internal {
F(Apply, 5, 1) \ F(Apply, 5, 1) \
F(GetFunctionDelegate, 1, 1) \ F(GetFunctionDelegate, 1, 1) \
F(GetConstructorDelegate, 1, 1) \ F(GetConstructorDelegate, 1, 1) \
F(GetOriginalConstructor, 0, 1) \
F(CallFunction, -1 /* receiver + n args + function */, 1) \ F(CallFunction, -1 /* receiver + n args + function */, 1) \
F(IsConstructCall, 0, 1) \ F(IsConstructCall, 0, 1) \
F(IsFunction, 1, 1) F(IsFunction, 1, 1)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment