Commit 68075b0a authored by sigurds@chromium.org's avatar sigurds@chromium.org

Reland "Add handling for argument adaptor frames to inlining."

Original: https://codereview.chromium.org/573703002/

Reland Fixes:
- Add deopt framestate to CollectStackTrace runtime call

R=mstarzinger@chromium.org

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

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24023 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 892e6621
...@@ -224,7 +224,7 @@ Node* AstGraphBuilder::Environment::Checkpoint( ...@@ -224,7 +224,7 @@ Node* AstGraphBuilder::Environment::Checkpoint(
UpdateStateValues(&stack_node_, parameters_count() + locals_count(), UpdateStateValues(&stack_node_, parameters_count() + locals_count(),
stack_height()); stack_height());
const Operator* op = common()->FrameState(ast_id, combine); const Operator* op = common()->FrameState(JS_FRAME, ast_id, combine);
return graph()->NewNode(op, parameters_node_, locals_node_, stack_node_, return graph()->NewNode(op, parameters_node_, locals_node_, stack_node_,
GetContext(), GetContext(),
...@@ -2020,12 +2020,10 @@ Node* AstGraphBuilder::BuildBinaryOp(Node* left, Node* right, Token::Value op) { ...@@ -2020,12 +2020,10 @@ Node* AstGraphBuilder::BuildBinaryOp(Node* left, Node* right, Token::Value op) {
void AstGraphBuilder::PrepareFrameState(Node* node, BailoutId ast_id, void AstGraphBuilder::PrepareFrameState(Node* node, BailoutId ast_id,
OutputFrameStateCombine combine) { OutputFrameStateCombine combine) {
if (OperatorProperties::HasFrameStateInput(node->op())) { if (OperatorProperties::HasFrameStateInput(node->op())) {
int frame_state_index = NodeProperties::GetFrameStateIndex(node); DCHECK(NodeProperties::GetFrameStateInput(node)->opcode() ==
IrOpcode::kDead);
DCHECK(node->InputAt(frame_state_index)->op()->opcode() == IrOpcode::kDead); NodeProperties::ReplaceFrameStateInput(
node, environment()->Checkpoint(ast_id, combine));
Node* frame_state_node = environment()->Checkpoint(ast_id, combine);
node->ReplaceInput(frame_state_index, frame_state_node);
} }
} }
......
...@@ -246,7 +246,7 @@ void CodeGenerator::AddSafepointAndDeopt(Instruction* instr) { ...@@ -246,7 +246,7 @@ void CodeGenerator::AddSafepointAndDeopt(Instruction* instr) {
// (just after the code address). // (just after the code address).
InstructionOperandConverter converter(this, instr); InstructionOperandConverter converter(this, instr);
// Deoptimization info starts at argument 1 // Deoptimization info starts at argument 1
int frame_state_offset = 1; size_t frame_state_offset = 1;
FrameStateDescriptor* descriptor = FrameStateDescriptor* descriptor =
GetFrameStateDescriptor(instr, frame_state_offset); GetFrameStateDescriptor(instr, frame_state_offset);
int pc_offset = masm()->pc_offset(); int pc_offset = masm()->pc_offset();
...@@ -266,7 +266,7 @@ void CodeGenerator::AddSafepointAndDeopt(Instruction* instr) { ...@@ -266,7 +266,7 @@ void CodeGenerator::AddSafepointAndDeopt(Instruction* instr) {
// Make sure all the values live in stack slots or they are immediates. // Make sure all the values live in stack slots or they are immediates.
// (The values should not live in register because registers are clobbered // (The values should not live in register because registers are clobbered
// by calls.) // by calls.)
for (int i = 0; i < descriptor->size(); i++) { for (size_t i = 0; i < descriptor->size(); i++) {
InstructionOperand* op = instr->InputAt(frame_state_offset + 1 + i); InstructionOperand* op = instr->InputAt(frame_state_offset + 1 + i);
CHECK(op->IsStackSlot() || op->IsImmediate()); CHECK(op->IsStackSlot() || op->IsImmediate());
} }
...@@ -287,40 +287,48 @@ int CodeGenerator::DefineDeoptimizationLiteral(Handle<Object> literal) { ...@@ -287,40 +287,48 @@ int CodeGenerator::DefineDeoptimizationLiteral(Handle<Object> literal) {
FrameStateDescriptor* CodeGenerator::GetFrameStateDescriptor( FrameStateDescriptor* CodeGenerator::GetFrameStateDescriptor(
Instruction* instr, int frame_state_offset) { Instruction* instr, size_t frame_state_offset) {
InstructionOperandConverter i(this, instr); InstructionOperandConverter i(this, instr);
InstructionSequence::StateId state_id = InstructionSequence::StateId state_id = InstructionSequence::StateId::FromInt(
InstructionSequence::StateId::FromInt(i.InputInt32(frame_state_offset)); i.InputInt32(static_cast<int>(frame_state_offset)));
return code()->GetFrameStateDescriptor(state_id); return code()->GetFrameStateDescriptor(state_id);
} }
void CodeGenerator::BuildTranslationForFrameStateDescriptor( void CodeGenerator::BuildTranslationForFrameStateDescriptor(
FrameStateDescriptor* descriptor, Instruction* instr, FrameStateDescriptor* descriptor, Instruction* instr,
Translation* translation, int frame_state_offset, Translation* translation, size_t frame_state_offset,
OutputFrameStateCombine state_combine) { OutputFrameStateCombine state_combine) {
// Outer-most state must be added to translation first. // Outer-most state must be added to translation first.
if (descriptor->outer_state() != NULL) { if (descriptor->outer_state() != NULL) {
BuildTranslationForFrameStateDescriptor( BuildTranslationForFrameStateDescriptor(descriptor->outer_state(), instr,
descriptor->outer_state(), instr, translation, translation, frame_state_offset,
frame_state_offset + descriptor->size(), kIgnoreOutput); kIgnoreOutput);
} }
int height = descriptor->size() - descriptor->parameters_count(); int id = Translation::kSelfLiteralId;
switch (state_combine) { if (!descriptor->jsfunction().is_null()) {
case kPushOutput: id = DefineDeoptimizationLiteral(
height++; Handle<Object>::cast(descriptor->jsfunction().ToHandleChecked()));
}
switch (descriptor->type()) {
case JS_FRAME:
translation->BeginJSFrame(
descriptor->bailout_id(), id,
static_cast<unsigned int>(descriptor->GetHeight(state_combine)));
break; break;
case kIgnoreOutput: case ARGUMENTS_ADAPTOR:
translation->BeginArgumentsAdaptorFrame(
id, static_cast<unsigned int>(descriptor->parameters_count()));
break; break;
} }
translation->BeginJSFrame(descriptor->bailout_id(), frame_state_offset += descriptor->outer_state()->GetTotalSize();
Translation::kSelfLiteralId, height); for (size_t i = 0; i < descriptor->size(); i++) {
AddTranslationForOperand(
for (int i = 0; i < descriptor->size(); i++) { translation, instr,
AddTranslationForOperand(translation, instr, instr->InputAt(static_cast<int>(frame_state_offset + i)));
instr->InputAt(i + frame_state_offset));
} }
switch (state_combine) { switch (state_combine) {
...@@ -335,14 +343,15 @@ void CodeGenerator::BuildTranslationForFrameStateDescriptor( ...@@ -335,14 +343,15 @@ void CodeGenerator::BuildTranslationForFrameStateDescriptor(
int CodeGenerator::BuildTranslation(Instruction* instr, int pc_offset, int CodeGenerator::BuildTranslation(Instruction* instr, int pc_offset,
int frame_state_offset, size_t frame_state_offset,
OutputFrameStateCombine state_combine) { OutputFrameStateCombine state_combine) {
FrameStateDescriptor* descriptor = FrameStateDescriptor* descriptor =
GetFrameStateDescriptor(instr, frame_state_offset); GetFrameStateDescriptor(instr, frame_state_offset);
frame_state_offset++; frame_state_offset++;
int frame_count = descriptor->GetFrameCount(); Translation translation(
Translation translation(&translations_, frame_count, frame_count, zone()); &translations_, static_cast<int>(descriptor->GetFrameCount()),
static_cast<int>(descriptor->GetJSFrameCount()), zone());
BuildTranslationForFrameStateDescriptor(descriptor, instr, &translation, BuildTranslationForFrameStateDescriptor(descriptor, instr, &translation,
frame_state_offset, state_combine); frame_state_offset, state_combine);
......
...@@ -87,13 +87,13 @@ class CodeGenerator FINAL : public GapResolver::Assembler { ...@@ -87,13 +87,13 @@ class CodeGenerator FINAL : public GapResolver::Assembler {
void PopulateDeoptimizationData(Handle<Code> code); void PopulateDeoptimizationData(Handle<Code> code);
int DefineDeoptimizationLiteral(Handle<Object> literal); int DefineDeoptimizationLiteral(Handle<Object> literal);
FrameStateDescriptor* GetFrameStateDescriptor(Instruction* instr, FrameStateDescriptor* GetFrameStateDescriptor(Instruction* instr,
int frame_state_offset); size_t frame_state_offset);
int BuildTranslation(Instruction* instr, int pc_offset, int BuildTranslation(Instruction* instr, int pc_offset,
int frame_state_offset, size_t frame_state_offset,
OutputFrameStateCombine state_combine); OutputFrameStateCombine state_combine);
void BuildTranslationForFrameStateDescriptor( void BuildTranslationForFrameStateDescriptor(
FrameStateDescriptor* descriptor, Instruction* instr, FrameStateDescriptor* descriptor, Instruction* instr,
Translation* translation, int frame_state_offset, Translation* translation, size_t frame_state_offset,
OutputFrameStateCombine state_combine); OutputFrameStateCombine state_combine);
void AddTranslationForOperand(Translation* translation, Instruction* instr, void AddTranslationForOperand(Translation* translation, Instruction* instr,
InstructionOperand* op); InstructionOperand* op);
......
...@@ -206,10 +206,11 @@ const Operator* CommonOperatorBuilder::StateValues(int arguments) { ...@@ -206,10 +206,11 @@ const Operator* CommonOperatorBuilder::StateValues(int arguments) {
const Operator* CommonOperatorBuilder::FrameState( const Operator* CommonOperatorBuilder::FrameState(
BailoutId bailout_id, OutputFrameStateCombine combine) { FrameStateType type, BailoutId bailout_id,
OutputFrameStateCombine state_combine, MaybeHandle<JSFunction> jsfunction) {
return new (zone()) Operator1<FrameStateCallInfo>( return new (zone()) Operator1<FrameStateCallInfo>(
IrOpcode::kFrameState, Operator::kPure, 4, 1, "FrameState", IrOpcode::kFrameState, Operator::kPure, 4, 1, "FrameState",
FrameStateCallInfo(bailout_id, combine)); FrameStateCallInfo(type, bailout_id, state_combine, jsfunction));
} }
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#define V8_COMPILER_COMMON_OPERATOR_H_ #define V8_COMPILER_COMMON_OPERATOR_H_
#include "src/compiler/machine-type.h" #include "src/compiler/machine-type.h"
#include "src/unique.h"
namespace v8 { namespace v8 {
namespace internal { namespace internal {
...@@ -13,9 +14,6 @@ namespace internal { ...@@ -13,9 +14,6 @@ namespace internal {
// Forward declarations. // Forward declarations.
class ExternalReference; class ExternalReference;
class OStream; class OStream;
template <typename>
class Unique;
class Zone;
namespace compiler { namespace compiler {
...@@ -34,18 +32,34 @@ enum OutputFrameStateCombine { ...@@ -34,18 +32,34 @@ enum OutputFrameStateCombine {
}; };
// The type of stack frame that a FrameState node represents.
enum FrameStateType {
JS_FRAME, // Represents an unoptimized JavaScriptFrame.
ARGUMENTS_ADAPTOR // Represents an ArgumentsAdaptorFrame.
};
class FrameStateCallInfo FINAL { class FrameStateCallInfo FINAL {
public: public:
FrameStateCallInfo(BailoutId bailout_id, FrameStateCallInfo(
OutputFrameStateCombine state_combine) FrameStateType type, BailoutId bailout_id,
: bailout_id_(bailout_id), frame_state_combine_(state_combine) {} OutputFrameStateCombine state_combine,
MaybeHandle<JSFunction> jsfunction = MaybeHandle<JSFunction>())
: type_(type),
bailout_id_(bailout_id),
frame_state_combine_(state_combine),
jsfunction_(jsfunction) {}
FrameStateType type() const { return type_; }
BailoutId bailout_id() const { return bailout_id_; } BailoutId bailout_id() const { return bailout_id_; }
OutputFrameStateCombine state_combine() const { return frame_state_combine_; } OutputFrameStateCombine state_combine() const { return frame_state_combine_; }
MaybeHandle<JSFunction> jsfunction() const { return jsfunction_; }
private: private:
FrameStateType type_;
BailoutId bailout_id_; BailoutId bailout_id_;
OutputFrameStateCombine frame_state_combine_; OutputFrameStateCombine frame_state_combine_;
MaybeHandle<JSFunction> jsfunction_;
}; };
...@@ -81,8 +95,10 @@ class CommonOperatorBuilder FINAL { ...@@ -81,8 +95,10 @@ class CommonOperatorBuilder FINAL {
const Operator* ValueEffect(int arguments); const Operator* ValueEffect(int arguments);
const Operator* Finish(int arguments); const Operator* Finish(int arguments);
const Operator* StateValues(int arguments); const Operator* StateValues(int arguments);
const Operator* FrameState(BailoutId bailout_id, const Operator* FrameState(
OutputFrameStateCombine combine); FrameStateType type, BailoutId bailout_id,
OutputFrameStateCombine state_combine,
MaybeHandle<JSFunction> jsfunction = MaybeHandle<JSFunction>());
const Operator* Call(const CallDescriptor* descriptor); const Operator* Call(const CallDescriptor* descriptor);
const Operator* Projection(size_t index); const Operator* Projection(size_t index);
......
...@@ -348,7 +348,7 @@ struct CallBuffer { ...@@ -348,7 +348,7 @@ struct CallBuffer {
size_t frame_state_value_count() const { size_t frame_state_value_count() const {
return (frame_state_descriptor == NULL) return (frame_state_descriptor == NULL)
? 0 ? 0
: (frame_state_descriptor->total_size() + : (frame_state_descriptor->GetTotalSize() +
1); // Include deopt id. 1); // Include deopt id.
} }
}; };
......
...@@ -303,9 +303,9 @@ TARGET_TEST_F(InstructionSelectorTest, CallJSFunctionWithDeopt) { ...@@ -303,9 +303,9 @@ TARGET_TEST_F(InstructionSelectorTest, CallJSFunctionWithDeopt) {
Node* stack = m.NewNode(m.common()->StateValues(0)); Node* stack = m.NewNode(m.common()->StateValues(0));
Node* context_dummy = m.Int32Constant(0); Node* context_dummy = m.Int32Constant(0);
Node* state_node = Node* state_node = m.NewNode(
m.NewNode(m.common()->FrameState(bailout_id, kPushOutput), parameters, m.common()->FrameState(JS_FRAME, bailout_id, kPushOutput), parameters,
locals, stack, context_dummy, m.UndefinedConstant()); locals, stack, context_dummy, m.UndefinedConstant());
Node* call = m.CallJS0(function_node, receiver, context, state_node); Node* call = m.CallJS0(function_node, receiver, context, state_node);
m.Return(call); m.Return(call);
...@@ -344,8 +344,8 @@ TARGET_TEST_F(InstructionSelectorTest, CallFunctionStubWithDeopt) { ...@@ -344,8 +344,8 @@ TARGET_TEST_F(InstructionSelectorTest, CallFunctionStubWithDeopt) {
Node* context_sentinel = m.Int32Constant(0); Node* context_sentinel = m.Int32Constant(0);
Node* frame_state_before = m.NewNode( Node* frame_state_before = m.NewNode(
m.common()->FrameState(bailout_id_before, kPushOutput), parameters, m.common()->FrameState(JS_FRAME, bailout_id_before, kPushOutput),
locals, stack, context_sentinel, m.UndefinedConstant()); parameters, locals, stack, context_sentinel, m.UndefinedConstant());
// Build the call. // Build the call.
Node* call = m.CallFunctionStub0(function_node, receiver, context, Node* call = m.CallFunctionStub0(function_node, receiver, context,
...@@ -383,9 +383,9 @@ TARGET_TEST_F(InstructionSelectorTest, CallFunctionStubWithDeopt) { ...@@ -383,9 +383,9 @@ TARGET_TEST_F(InstructionSelectorTest, CallFunctionStubWithDeopt) {
s.GetFrameStateDescriptor(deopt_id_before); s.GetFrameStateDescriptor(deopt_id_before);
EXPECT_EQ(bailout_id_before, desc_before->bailout_id()); EXPECT_EQ(bailout_id_before, desc_before->bailout_id());
EXPECT_EQ(kPushOutput, desc_before->state_combine()); EXPECT_EQ(kPushOutput, desc_before->state_combine());
EXPECT_EQ(1, desc_before->parameters_count()); EXPECT_EQ(1u, desc_before->parameters_count());
EXPECT_EQ(1, desc_before->locals_count()); EXPECT_EQ(1u, desc_before->locals_count());
EXPECT_EQ(1, desc_before->stack_count()); EXPECT_EQ(1u, desc_before->stack_count());
EXPECT_EQ(43, s.ToInt32(call_instr->InputAt(2))); EXPECT_EQ(43, s.ToInt32(call_instr->InputAt(2)));
EXPECT_EQ(0, s.ToInt32(call_instr->InputAt(3))); EXPECT_EQ(0, s.ToInt32(call_instr->InputAt(3)));
EXPECT_EQ(44, s.ToInt32(call_instr->InputAt(4))); EXPECT_EQ(44, s.ToInt32(call_instr->InputAt(4)));
...@@ -419,18 +419,18 @@ TARGET_TEST_F(InstructionSelectorTest, ...@@ -419,18 +419,18 @@ TARGET_TEST_F(InstructionSelectorTest,
Node* parameters = m.NewNode(m.common()->StateValues(1), m.Int32Constant(63)); Node* parameters = m.NewNode(m.common()->StateValues(1), m.Int32Constant(63));
Node* locals = m.NewNode(m.common()->StateValues(1), m.Int32Constant(64)); Node* locals = m.NewNode(m.common()->StateValues(1), m.Int32Constant(64));
Node* stack = m.NewNode(m.common()->StateValues(1), m.Int32Constant(65)); Node* stack = m.NewNode(m.common()->StateValues(1), m.Int32Constant(65));
Node* frame_state_parent = Node* frame_state_parent = m.NewNode(
m.NewNode(m.common()->FrameState(bailout_id_parent, kIgnoreOutput), m.common()->FrameState(JS_FRAME, bailout_id_parent, kIgnoreOutput),
parameters, locals, stack, context, m.UndefinedConstant()); parameters, locals, stack, context, m.UndefinedConstant());
Node* context2 = m.Int32Constant(46); Node* context2 = m.Int32Constant(46);
Node* parameters2 = Node* parameters2 =
m.NewNode(m.common()->StateValues(1), m.Int32Constant(43)); m.NewNode(m.common()->StateValues(1), m.Int32Constant(43));
Node* locals2 = m.NewNode(m.common()->StateValues(1), m.Int32Constant(44)); Node* locals2 = m.NewNode(m.common()->StateValues(1), m.Int32Constant(44));
Node* stack2 = m.NewNode(m.common()->StateValues(1), m.Int32Constant(45)); Node* stack2 = m.NewNode(m.common()->StateValues(1), m.Int32Constant(45));
Node* frame_state_before = Node* frame_state_before = m.NewNode(
m.NewNode(m.common()->FrameState(bailout_id_before, kPushOutput), m.common()->FrameState(JS_FRAME, bailout_id_before, kPushOutput),
parameters2, locals2, stack2, context2, frame_state_parent); parameters2, locals2, stack2, context2, frame_state_parent);
// Build the call. // Build the call.
Node* call = m.CallFunctionStub0(function_node, receiver, context2, Node* call = m.CallFunctionStub0(function_node, receiver, context2,
...@@ -467,9 +467,9 @@ TARGET_TEST_F(InstructionSelectorTest, ...@@ -467,9 +467,9 @@ TARGET_TEST_F(InstructionSelectorTest,
FrameStateDescriptor* desc_before = FrameStateDescriptor* desc_before =
s.GetFrameStateDescriptor(deopt_id_before); s.GetFrameStateDescriptor(deopt_id_before);
EXPECT_EQ(bailout_id_before, desc_before->bailout_id()); EXPECT_EQ(bailout_id_before, desc_before->bailout_id());
EXPECT_EQ(1, desc_before->parameters_count()); EXPECT_EQ(1u, desc_before->parameters_count());
EXPECT_EQ(1, desc_before->locals_count()); EXPECT_EQ(1u, desc_before->locals_count());
EXPECT_EQ(1, desc_before->stack_count()); EXPECT_EQ(1u, desc_before->stack_count());
EXPECT_EQ(63, s.ToInt32(call_instr->InputAt(2))); EXPECT_EQ(63, s.ToInt32(call_instr->InputAt(2)));
// Context: // Context:
EXPECT_EQ(66, s.ToInt32(call_instr->InputAt(3))); EXPECT_EQ(66, s.ToInt32(call_instr->InputAt(3)));
......
...@@ -1037,14 +1037,16 @@ void InstructionSelector::AddFrameStateInputs( ...@@ -1037,14 +1037,16 @@ void InstructionSelector::AddFrameStateInputs(
DCHECK_EQ(descriptor->stack_count(), stack->InputCount()); DCHECK_EQ(descriptor->stack_count(), stack->InputCount());
OperandGenerator g(this); OperandGenerator g(this);
for (int i = 0; i < descriptor->parameters_count(); i++) { for (int i = 0; i < static_cast<int>(descriptor->parameters_count()); i++) {
inputs->push_back(UseOrImmediate(&g, parameters->InputAt(i))); inputs->push_back(UseOrImmediate(&g, parameters->InputAt(i)));
} }
inputs->push_back(UseOrImmediate(&g, context)); if (descriptor->HasContext()) {
for (int i = 0; i < descriptor->locals_count(); i++) { inputs->push_back(UseOrImmediate(&g, context));
}
for (int i = 0; i < static_cast<int>(descriptor->locals_count()); i++) {
inputs->push_back(UseOrImmediate(&g, locals->InputAt(i))); inputs->push_back(UseOrImmediate(&g, locals->InputAt(i)));
} }
for (int i = 0; i < descriptor->stack_count(); i++) { for (int i = 0; i < static_cast<int>(descriptor->stack_count()); i++) {
inputs->push_back(UseOrImmediate(&g, stack->InputAt(i))); inputs->push_back(UseOrImmediate(&g, stack->InputAt(i)));
} }
} }
......
...@@ -702,55 +702,84 @@ class Constant FINAL { ...@@ -702,55 +702,84 @@ class Constant FINAL {
class FrameStateDescriptor : public ZoneObject { class FrameStateDescriptor : public ZoneObject {
public: public:
FrameStateDescriptor(const FrameStateCallInfo& state_info, FrameStateDescriptor(const FrameStateCallInfo& state_info,
int parameters_count, int locals_count, int stack_count, size_t parameters_count, size_t locals_count,
size_t stack_count,
FrameStateDescriptor* outer_state = NULL) FrameStateDescriptor* outer_state = NULL)
: bailout_id_(state_info.bailout_id()), : type_(state_info.type()),
bailout_id_(state_info.bailout_id()),
frame_state_combine_(state_info.state_combine()), frame_state_combine_(state_info.state_combine()),
parameters_count_(parameters_count), parameters_count_(parameters_count),
locals_count_(locals_count), locals_count_(locals_count),
stack_count_(stack_count), stack_count_(stack_count),
outer_state_(outer_state) {} outer_state_(outer_state),
jsfunction_(state_info.jsfunction()) {}
FrameStateType type() const { return type_; }
BailoutId bailout_id() const { return bailout_id_; } BailoutId bailout_id() const { return bailout_id_; }
OutputFrameStateCombine state_combine() const { return frame_state_combine_; } OutputFrameStateCombine state_combine() const { return frame_state_combine_; }
int parameters_count() { return parameters_count_; } size_t parameters_count() const { return parameters_count_; }
int locals_count() { return locals_count_; } size_t locals_count() const { return locals_count_; }
int stack_count() { return stack_count_; } size_t stack_count() const { return stack_count_; }
FrameStateDescriptor* outer_state() { return outer_state_; } FrameStateDescriptor* outer_state() const { return outer_state_; }
void set_outer_state(FrameStateDescriptor* outer_state) { MaybeHandle<JSFunction> jsfunction() const { return jsfunction_; }
outer_state_ = outer_state;
}
int size() { size_t size() const {
return parameters_count_ + locals_count_ + stack_count_ + return parameters_count_ + locals_count_ + stack_count_ +
1; // Includes context. (HasContext() ? 1 : 0);
} }
int total_size() { size_t GetTotalSize() const {
int total_size = 0; size_t total_size = 0;
for (FrameStateDescriptor* iter = this; iter != NULL; for (const FrameStateDescriptor* iter = this; iter != NULL;
iter = iter->outer_state_) { iter = iter->outer_state_) {
total_size += iter->size(); total_size += iter->size();
} }
return total_size; return total_size;
} }
int GetFrameCount() { size_t GetHeight(OutputFrameStateCombine override) const {
int count = 0; size_t height = size() - parameters_count();
for (FrameStateDescriptor* iter = this; iter != NULL; switch (override) {
case kPushOutput:
++height;
break;
case kIgnoreOutput:
break;
}
return height;
}
size_t GetFrameCount() const {
size_t count = 0;
for (const FrameStateDescriptor* iter = this; iter != NULL;
iter = iter->outer_state_) { iter = iter->outer_state_) {
++count; ++count;
} }
return count; return count;
} }
size_t GetJSFrameCount() const {
size_t count = 0;
for (const FrameStateDescriptor* iter = this; iter != NULL;
iter = iter->outer_state_) {
if (iter->type_ == JS_FRAME) {
++count;
}
}
return count;
}
bool HasContext() const { return type_ == JS_FRAME; }
private: private:
FrameStateType type_;
BailoutId bailout_id_; BailoutId bailout_id_;
OutputFrameStateCombine frame_state_combine_; OutputFrameStateCombine frame_state_combine_;
int parameters_count_; size_t parameters_count_;
int locals_count_; size_t locals_count_;
int stack_count_; size_t stack_count_;
FrameStateDescriptor* outer_state_; FrameStateDescriptor* outer_state_;
MaybeHandle<JSFunction> jsfunction_;
}; };
OStream& operator<<(OStream& os, const Constant& constant); OStream& operator<<(OStream& os, const Constant& constant);
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include "src/compiler/node-properties-inl.h" #include "src/compiler/node-properties-inl.h"
#include "src/compiler/simplified-operator.h" #include "src/compiler/simplified-operator.h"
#include "src/compiler/typer.h" #include "src/compiler/typer.h"
#include "src/full-codegen.h"
#include "src/parser.h" #include "src/parser.h"
#include "src/rewriter.h" #include "src/rewriter.h"
#include "src/scopes.h" #include "src/scopes.h"
...@@ -54,7 +55,6 @@ void JSInliner::Inline() { ...@@ -54,7 +55,6 @@ void JSInliner::Inline() {
// test cases, where similar code is currently duplicated). // test cases, where similar code is currently duplicated).
static void Parse(Handle<JSFunction> function, CompilationInfoWithZone* info) { static void Parse(Handle<JSFunction> function, CompilationInfoWithZone* info) {
CHECK(Parser::Parse(info)); CHECK(Parser::Parse(info));
info->SetOptimizing(BailoutId::None(), Handle<Code>(function->code()));
CHECK(Rewriter::Rewrite(info)); CHECK(Rewriter::Rewrite(info));
CHECK(Scope::Analyze(info)); CHECK(Scope::Analyze(info));
CHECK_NE(NULL, info->scope()); CHECK_NE(NULL, info->scope());
...@@ -90,6 +90,16 @@ class Inlinee { ...@@ -90,6 +90,16 @@ class Inlinee {
DCHECK_EQ(IrOpcode::kReturn, unique_return->opcode()); DCHECK_EQ(IrOpcode::kReturn, unique_return->opcode());
return unique_return; return unique_return;
} }
// Counts JSFunction, Receiver, arguments, context but not effect, control.
size_t total_parameters() { return start_->op()->OutputCount(); }
// Counts only formal parameters.
size_t formal_parameters() {
DCHECK_GE(total_parameters(), 3);
return total_parameters() - 3;
}
// Inline this graph at {call}, use {jsgraph} and its zone to create // Inline this graph at {call}, use {jsgraph} and its zone to create
// any new nodes. // any new nodes.
void InlineAtCall(JSGraph* jsgraph, Node* call); void InlineAtCall(JSGraph* jsgraph, Node* call);
...@@ -196,7 +206,7 @@ class CopyVisitor : public NullNodeVisitor { ...@@ -196,7 +206,7 @@ class CopyVisitor : public NullNodeVisitor {
private: private:
void ReplaceSentinels() { void ReplaceSentinels() {
for (int id = 0; id < source_graph_->NodeCount(); ++id) { for (NodeId id = 0; id < source_graph_->NodeCount(); ++id) {
Node* sentinel = sentinels_[id]; Node* sentinel = sentinels_[id];
if (sentinel == NULL) continue; if (sentinel == NULL) continue;
Node* copy = copies_[id]; Node* copy = copies_[id];
...@@ -235,11 +245,8 @@ void Inlinee::InlineAtCall(JSGraph* jsgraph, Node* call) { ...@@ -235,11 +245,8 @@ void Inlinee::InlineAtCall(JSGraph* jsgraph, Node* call) {
NodeProperties::GetValueInput(call, 0), NodeProperties::GetValueInput(call, 0),
NodeProperties::GetEffectInput(call)); NodeProperties::GetEffectInput(call));
// {inlinee_inputs} counts JSFunction, Receiver, arguments, context,
// but not effect, control.
int inlinee_inputs = start_->op()->OutputCount();
// Context is last argument. // Context is last argument.
int inlinee_context_index = inlinee_inputs - 1; int inlinee_context_index = static_cast<int>(total_parameters()) - 1;
// {inliner_inputs} counts JSFunction, Receiver, arguments, but not // {inliner_inputs} counts JSFunction, Receiver, arguments, but not
// context, effect, control. // context, effect, control.
int inliner_inputs = OperatorProperties::GetValueInputCount(call->op()); int inliner_inputs = OperatorProperties::GetValueInputCount(call->op());
...@@ -299,10 +306,74 @@ void Inlinee::InlineAtCall(JSGraph* jsgraph, Node* call) { ...@@ -299,10 +306,74 @@ void Inlinee::InlineAtCall(JSGraph* jsgraph, Node* call) {
} }
void JSInliner::TryInlineCall(Node* call) { // TODO(turbofan) Provide such accessors for every node, possibly even
DCHECK_EQ(IrOpcode::kJSCallFunction, call->opcode()); // generate them.
class JSCallFunctionAccessor {
public:
explicit JSCallFunctionAccessor(Node* call) : call_(call) {
DCHECK_EQ(IrOpcode::kJSCallFunction, call->opcode());
}
Node* jsfunction() { return call_->InputAt(0); }
Node* receiver() { return call_->InputAt(1); }
Node* formal_argument(size_t index) {
DCHECK(index < formal_arguments());
return call_->InputAt(static_cast<int>(2 + index));
}
size_t formal_arguments() {
// {value_inputs} includes jsfunction and receiver.
size_t value_inputs = OperatorProperties::GetValueInputCount(call_->op());
DCHECK_GE(call_->InputCount(), 2);
return value_inputs - 2;
}
Node* frame_state() { return NodeProperties::GetFrameStateInput(call_); }
private:
Node* call_;
};
void JSInliner::AddClosureToFrameState(Node* frame_state,
Handle<JSFunction> jsfunction) {
FrameStateCallInfo call_info = OpParameter<FrameStateCallInfo>(frame_state);
const Operator* op = jsgraph_->common()->FrameState(
FrameStateType::JS_FRAME, call_info.bailout_id(),
call_info.state_combine(), jsfunction);
frame_state->set_op(op);
}
Node* JSInliner::CreateArgumentsAdaptorFrameState(JSCallFunctionAccessor* call,
Handle<JSFunction> jsfunction,
Zone* temp_zone) {
const Operator* op =
jsgraph_->common()->FrameState(FrameStateType::ARGUMENTS_ADAPTOR,
BailoutId(-1), kIgnoreOutput, jsfunction);
const Operator* op0 = jsgraph_->common()->StateValues(0);
Node* node0 = jsgraph_->graph()->NewNode(op0);
NodeVector params(temp_zone);
params.push_back(call->receiver());
for (size_t argument = 0; argument != call->formal_arguments(); ++argument) {
params.push_back(call->formal_argument(argument));
}
const Operator* op_param =
jsgraph_->common()->StateValues(static_cast<int>(params.size()));
Node* params_node = jsgraph_->graph()->NewNode(
op_param, static_cast<int>(params.size()), &params.front());
return jsgraph_->graph()->NewNode(op, params_node, node0, node0,
jsgraph_->UndefinedConstant(),
call->frame_state());
}
HeapObjectMatcher<JSFunction> match(call->InputAt(0)); void JSInliner::TryInlineCall(Node* call_node) {
JSCallFunctionAccessor call(call_node);
HeapObjectMatcher<JSFunction> match(call.jsfunction());
if (!match.HasValue()) { if (!match.HasValue()) {
return; return;
} }
...@@ -322,6 +393,18 @@ void JSInliner::TryInlineCall(Node* call) { ...@@ -322,6 +393,18 @@ void JSInliner::TryInlineCall(Node* call) {
CompilationInfoWithZone info(function); CompilationInfoWithZone info(function);
Parse(function, &info); Parse(function, &info);
if (!function->shared()->has_deoptimization_support()) {
// TODO(turbofan) In the future, unoptimized code with deopt support could
// be generated lazily once deopt is triggered.
info.EnableDeoptimizationSupport();
if (!FullCodeGenerator::MakeCode(&info)) {
DCHECK(false);
return;
}
function->shared()->EnableDeoptimizationSupport(*info.code());
function->shared()->set_feedback_vector(*info.feedback_vector());
}
if (info.scope()->arguments() != NULL) { if (info.scope()->arguments() != NULL) {
// For now do not inline functions that use their arguments array. // For now do not inline functions that use their arguments array.
SmartArrayPointer<char> name = function->shared()->DebugName()->ToCString(); SmartArrayPointer<char> name = function->shared()->DebugName()->ToCString();
...@@ -353,7 +436,24 @@ void JSInliner::TryInlineCall(Node* call) { ...@@ -353,7 +436,24 @@ void JSInliner::TryInlineCall(Node* call) {
visitor.CopyGraph(); visitor.CopyGraph();
Inlinee inlinee(visitor.GetCopy(graph.start()), visitor.GetCopy(graph.end())); Inlinee inlinee(visitor.GetCopy(graph.start()), visitor.GetCopy(graph.end()));
inlinee.InlineAtCall(jsgraph_, call);
Node* outer_frame_state = call.frame_state();
// Insert argument adaptor frame if required.
if (call.formal_arguments() != inlinee.formal_parameters()) {
outer_frame_state =
CreateArgumentsAdaptorFrameState(&call, function, info.zone());
}
for (NodeVectorConstIter it = visitor.copies().begin();
it != visitor.copies().end(); ++it) {
Node* node = *it;
if (node != NULL && node->opcode() == IrOpcode::kFrameState) {
AddClosureToFrameState(node, function);
NodeProperties::ReplaceFrameStateInput(node, outer_frame_state);
}
}
inlinee.InlineAtCall(jsgraph_, call_node);
} }
} }
} }
......
...@@ -12,6 +12,8 @@ namespace v8 { ...@@ -12,6 +12,8 @@ namespace v8 {
namespace internal { namespace internal {
namespace compiler { namespace compiler {
class JSCallFunctionAccessor;
class JSInliner { class JSInliner {
public: public:
JSInliner(CompilationInfo* info, JSGraph* jsgraph) JSInliner(CompilationInfo* info, JSGraph* jsgraph)
...@@ -25,6 +27,10 @@ class JSInliner { ...@@ -25,6 +27,10 @@ class JSInliner {
CompilationInfo* info_; CompilationInfo* info_;
JSGraph* jsgraph_; JSGraph* jsgraph_;
Node* CreateArgumentsAdaptorFrameState(JSCallFunctionAccessor* call,
Handle<JSFunction> jsfunction,
Zone* temp_zone);
void AddClosureToFrameState(Node* frame_state, Handle<JSFunction> jsfunction);
static void UnifyReturn(Graph* graph); static void UnifyReturn(Graph* graph);
}; };
} }
......
...@@ -123,6 +123,9 @@ bool Linkage::NeedsFrameState(Runtime::FunctionId function) { ...@@ -123,6 +123,9 @@ bool Linkage::NeedsFrameState(Runtime::FunctionId function) {
case Runtime::kPrepareStep: case Runtime::kPrepareStep:
case Runtime::kSetScriptBreakPoint: case Runtime::kSetScriptBreakPoint:
case Runtime::kStackGuard: case Runtime::kStackGuard:
case Runtime::kCheckExecutionState:
case Runtime::kDebugEvaluate:
case Runtime::kCollectStackTrace:
return true; return true;
default: default:
return false; return false;
......
...@@ -162,6 +162,12 @@ inline void NodeProperties::ReplaceEffectInput(Node* node, Node* effect, ...@@ -162,6 +162,12 @@ inline void NodeProperties::ReplaceEffectInput(Node* node, Node* effect,
return node->ReplaceInput(FirstEffectIndex(node) + index, effect); return node->ReplaceInput(FirstEffectIndex(node) + index, effect);
} }
inline void NodeProperties::ReplaceFrameStateInput(Node* node,
Node* frame_state) {
DCHECK(OperatorProperties::HasFrameStateInput(node->op()));
node->ReplaceInput(FirstFrameStateIndex(node), frame_state);
}
inline void NodeProperties::RemoveNonValueInputs(Node* node) { inline void NodeProperties::RemoveNonValueInputs(Node* node) {
node->TrimInputCount(OperatorProperties::GetValueInputCount(node->op())); node->TrimInputCount(OperatorProperties::GetValueInputCount(node->op()));
} }
......
...@@ -35,6 +35,7 @@ class NodeProperties { ...@@ -35,6 +35,7 @@ class NodeProperties {
static inline void ReplaceControlInput(Node* node, Node* control); static inline void ReplaceControlInput(Node* node, Node* control);
static inline void ReplaceEffectInput(Node* node, Node* effect, static inline void ReplaceEffectInput(Node* node, Node* effect,
int index = 0); int index = 0);
static inline void ReplaceFrameStateInput(Node* node, Node* frame_state);
static inline void RemoveNonValueInputs(Node* node); static inline void RemoveNonValueInputs(Node* node);
static inline void ReplaceWithValue(Node* node, Node* value, static inline void ReplaceWithValue(Node* node, Node* value,
Node* effect = NULL); Node* effect = NULL);
......
...@@ -71,6 +71,7 @@ typedef NodeSet::reverse_iterator NodeSetRIter; ...@@ -71,6 +71,7 @@ typedef NodeSet::reverse_iterator NodeSetRIter;
typedef ZoneVector<Node*> NodeVector; typedef ZoneVector<Node*> NodeVector;
typedef NodeVector::iterator NodeVectorIter; typedef NodeVector::iterator NodeVectorIter;
typedef NodeVector::const_iterator NodeVectorConstIter;
typedef NodeVector::reverse_iterator NodeVectorRIter; typedef NodeVector::reverse_iterator NodeVectorRIter;
typedef ZoneVector<NodeVector> NodeVectorVector; typedef ZoneVector<NodeVector> NodeVectorVector;
......
...@@ -932,9 +932,9 @@ void OptimizedFrame::Summarize(List<FrameSummary>* frames) { ...@@ -932,9 +932,9 @@ void OptimizedFrame::Summarize(List<FrameSummary>* frames) {
DCHECK(frames->length() == 0); DCHECK(frames->length() == 0);
DCHECK(is_optimized()); DCHECK(is_optimized());
// Delegate to JS frame in absence of inlining. // Delegate to JS frame in absence of turbofan deoptimization.
// TODO(turbofan): Revisit once we support inlining. // TODO(turbofan): Revisit once we support deoptimization across the board.
if (LookupCode()->is_turbofanned()) { if (LookupCode()->is_turbofanned() && !FLAG_turbo_deoptimization) {
return JavaScriptFrame::Summarize(frames); return JavaScriptFrame::Summarize(frames);
} }
...@@ -1059,9 +1059,9 @@ DeoptimizationInputData* OptimizedFrame::GetDeoptimizationData( ...@@ -1059,9 +1059,9 @@ DeoptimizationInputData* OptimizedFrame::GetDeoptimizationData(
int OptimizedFrame::GetInlineCount() { int OptimizedFrame::GetInlineCount() {
DCHECK(is_optimized()); DCHECK(is_optimized());
// Delegate to JS frame in absence of inlining. // Delegate to JS frame in absence of turbofan deoptimization.
// TODO(turbofan): Revisit once we support inlining. // TODO(turbofan): Revisit once we support deoptimization across the board.
if (LookupCode()->is_turbofanned()) { if (LookupCode()->is_turbofanned() && !FLAG_turbo_deoptimization) {
return JavaScriptFrame::GetInlineCount(); return JavaScriptFrame::GetInlineCount();
} }
...@@ -1083,9 +1083,9 @@ void OptimizedFrame::GetFunctions(List<JSFunction*>* functions) { ...@@ -1083,9 +1083,9 @@ void OptimizedFrame::GetFunctions(List<JSFunction*>* functions) {
DCHECK(functions->length() == 0); DCHECK(functions->length() == 0);
DCHECK(is_optimized()); DCHECK(is_optimized());
// Delegate to JS frame in absence of inlining. // Delegate to JS frame in absence of turbofan deoptimization.
// TODO(turbofan): Revisit once we support inlining. // TODO(turbofan): Revisit once we support deoptimization across the board.
if (LookupCode()->is_turbofanned()) { if (LookupCode()->is_turbofanned() && !FLAG_turbo_deoptimization) {
return JavaScriptFrame::GetFunctions(functions); return JavaScriptFrame::GetFunctions(functions);
} }
......
...@@ -80,17 +80,16 @@ ...@@ -80,17 +80,16 @@
############################################################################## ##############################################################################
# TurboFan compiler failures. # TurboFan compiler failures.
# Scheduler cannot handle free-floating loops yet
'test-run-inlining/InlineLoop': [SKIP],
# TODO(dcarney): C calls are broken all over the place. # TODO(dcarney): C calls are broken all over the place.
'test-run-machops/RunCall*': [SKIP], 'test-run-machops/RunCall*': [SKIP],
'test-run-machops/RunLoadImmIndex': [SKIP], 'test-run-machops/RunLoadImmIndex': [SKIP],
'test-run-machops/RunSpillLotsOfThingsWithCall': [SKIP], 'test-run-machops/RunSpillLotsOfThingsWithCall': [SKIP],
# TODO(sigurds): The schedule is borked with multiple inlinees. # TODO(sigurds): The schedule is borked with multiple inlinees,
# and cannot handle free-floating loops yet
'test-run-inlining/InlineTwiceDependentDiamond': [SKIP], 'test-run-inlining/InlineTwiceDependentDiamond': [SKIP],
'test-run-inlining/InlineTwiceDependentDiamondDifferent': [SKIP], 'test-run-inlining/InlineTwiceDependentDiamondDifferent': [SKIP],
'test-run-inlining/InlineLoop': [SKIP],
# Some tests are just too slow to run for now. # Some tests are just too slow to run for now.
'test-api/Threading*': [PASS, NO_VARIANTS], 'test-api/Threading*': [PASS, NO_VARIANTS],
......
...@@ -148,9 +148,9 @@ class TrivialDeoptCodegenTester : public DeoptCodegenTester { ...@@ -148,9 +148,9 @@ class TrivialDeoptCodegenTester : public DeoptCodegenTester {
Node* locals = m.NewNode(common.StateValues(0)); Node* locals = m.NewNode(common.StateValues(0));
Node* stack = m.NewNode(common.StateValues(0)); Node* stack = m.NewNode(common.StateValues(0));
Node* state_node = Node* state_node = m.NewNode(
m.NewNode(common.FrameState(bailout_id, kIgnoreOutput), parameters, common.FrameState(JS_FRAME, bailout_id, kIgnoreOutput), parameters,
locals, stack, caller_context_node, m.UndefinedConstant()); locals, stack, caller_context_node, m.UndefinedConstant());
Handle<Context> context(deopt_function->context(), CcTest::i_isolate()); Handle<Context> context(deopt_function->context(), CcTest::i_isolate());
Unique<Object> context_constant = Unique<Object> context_constant =
...@@ -262,9 +262,9 @@ class TrivialRuntimeDeoptCodegenTester : public DeoptCodegenTester { ...@@ -262,9 +262,9 @@ class TrivialRuntimeDeoptCodegenTester : public DeoptCodegenTester {
Node* locals = m.NewNode(common.StateValues(0)); Node* locals = m.NewNode(common.StateValues(0));
Node* stack = m.NewNode(common.StateValues(0)); Node* stack = m.NewNode(common.StateValues(0));
Node* state_node = Node* state_node = m.NewNode(
m.NewNode(common.FrameState(bailout_id, kIgnoreOutput), parameters, common.FrameState(JS_FRAME, bailout_id, kIgnoreOutput), parameters,
locals, stack, context_node, m.UndefinedConstant()); locals, stack, context_node, m.UndefinedConstant());
m.CallRuntime1(Runtime::kDeoptimizeFunction, this_fun_node, context_node, m.CallRuntime1(Runtime::kDeoptimizeFunction, this_fun_node, context_node,
state_node); state_node);
......
...@@ -60,7 +60,7 @@ class JSTypedLoweringTester : public HandleAndZoneScope { ...@@ -60,7 +60,7 @@ class JSTypedLoweringTester : public HandleAndZoneScope {
Node* stack = graph.NewNode(common.StateValues(0)); Node* stack = graph.NewNode(common.StateValues(0));
Node* state_node = Node* state_node =
graph.NewNode(common.FrameState(BailoutId(0), kIgnoreOutput), graph.NewNode(common.FrameState(JS_FRAME, BailoutId(0), kIgnoreOutput),
parameters, locals, stack, context, UndefinedConstant()); parameters, locals, stack, context, UndefinedConstant());
return state_node; return state_node;
......
This diff is collapsed.
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