[turbofan] Pass closure as node to FrameState.

First step towards support for inlining based on SharedFunctionInfo
instead of JSFunction.

R=jarin@chromium.org

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

Cr-Commit-Position: refs/heads/master@{#28419}
This commit is contained in:
bmeurer 2015-05-15 05:17:15 -07:00 committed by Commit bot
parent 3c1487db60
commit 1643671f1b
16 changed files with 139 additions and 137 deletions

View File

@ -814,6 +814,7 @@ Node* AstGraphBuilder::Environment::Checkpoint(
Node* result = graph()->NewNode(op, parameters_node_, locals_node_,
stack_node_, builder()->current_context(),
builder()->GetFunctionClosure(),
builder()->jsgraph()->UndefinedConstant());
if (FLAG_analyze_environment_liveness) {
liveness_block()->Checkpoint(result);

View File

@ -426,17 +426,20 @@ FrameStateDescriptor* CodeGenerator::GetFrameStateDescriptor(
return code()->GetFrameStateDescriptor(state_id);
}
struct OperandAndType {
OperandAndType(InstructionOperand* operand, MachineType type)
: operand_(operand), type_(type) {}
InstructionOperand* operand_;
MachineType type_;
namespace {
struct OperandAndType {
InstructionOperand* const operand;
MachineType const type;
};
static OperandAndType TypedOperandForFrameState(
FrameStateDescriptor* descriptor, Instruction* instr,
size_t frame_state_offset, size_t index, OutputFrameStateCombine combine) {
OperandAndType TypedOperandForFrameState(FrameStateDescriptor* descriptor,
Instruction* instr,
size_t frame_state_offset,
size_t index,
OutputFrameStateCombine combine) {
DCHECK(index < descriptor->GetSize(combine));
switch (combine.kind()) {
case OutputFrameStateCombine::kPushOutput: {
@ -445,8 +448,7 @@ static OperandAndType TypedOperandForFrameState(
descriptor->GetSize(OutputFrameStateCombine::Ignore());
// If the index is past the existing stack items, return the output.
if (index >= size_without_output) {
return OperandAndType(instr->OutputAt(index - size_without_output),
kMachAnyTagged);
return {instr->OutputAt(index - size_without_output), kMachAnyTagged};
}
break;
}
@ -455,31 +457,35 @@ static OperandAndType TypedOperandForFrameState(
descriptor->GetSize(combine) - 1 - combine.GetOffsetToPokeAt();
if (index >= index_from_top &&
index < index_from_top + instr->OutputCount()) {
return OperandAndType(instr->OutputAt(index - index_from_top),
kMachAnyTagged);
return {instr->OutputAt(index - index_from_top), kMachAnyTagged};
}
break;
}
return OperandAndType(instr->InputAt(frame_state_offset + index),
descriptor->GetType(index));
return {instr->InputAt(frame_state_offset + index),
descriptor->GetType(index)};
}
} // namespace
void CodeGenerator::BuildTranslationForFrameStateDescriptor(
FrameStateDescriptor* descriptor, Instruction* instr,
Translation* translation, size_t frame_state_offset,
OutputFrameStateCombine state_combine) {
// Outer-most state must be added to translation first.
if (descriptor->outer_state() != NULL) {
if (descriptor->outer_state() != nullptr) {
BuildTranslationForFrameStateDescriptor(descriptor->outer_state(), instr,
translation, frame_state_offset,
OutputFrameStateCombine::Ignore());
}
frame_state_offset += descriptor->outer_state()->GetTotalSize();
// TODO(bmeurer): Fix this special case here.
int id = Translation::kSelfLiteralId;
if (!descriptor->jsfunction().is_null()) {
id = DefineDeoptimizationLiteral(
Handle<Object>::cast(descriptor->jsfunction().ToHandleChecked()));
if (descriptor->outer_state() != nullptr) {
InstructionOperandConverter converter(this, instr);
Handle<HeapObject> function(converter.InputHeapObject(frame_state_offset));
id = DefineDeoptimizationLiteral(function);
}
switch (descriptor->type()) {
@ -487,7 +493,7 @@ void CodeGenerator::BuildTranslationForFrameStateDescriptor(
translation->BeginJSFrame(
descriptor->bailout_id(), id,
static_cast<unsigned int>(descriptor->GetSize(state_combine) -
descriptor->parameters_count()));
(1 + descriptor->parameters_count())));
break;
case ARGUMENTS_ADAPTOR:
translation->BeginArgumentsAdaptorFrame(
@ -495,11 +501,10 @@ void CodeGenerator::BuildTranslationForFrameStateDescriptor(
break;
}
frame_state_offset += descriptor->outer_state()->GetTotalSize();
for (size_t i = 0; i < descriptor->GetSize(state_combine); i++) {
for (size_t i = 1; i < descriptor->GetSize(state_combine); i++) {
OperandAndType op = TypedOperandForFrameState(
descriptor, instr, frame_state_offset, i, state_combine);
AddTranslationForOperand(translation, instr, op.operand_, op.type_);
AddTranslationForOperand(translation, instr, op.operand, op.type);
}
}

View File

@ -609,12 +609,12 @@ const Operator* CommonOperatorBuilder::TypedStateValues(
const Operator* CommonOperatorBuilder::FrameState(
FrameStateType type, BailoutId bailout_id,
OutputFrameStateCombine state_combine, MaybeHandle<JSFunction> jsfunction) {
return new (zone()) Operator1<FrameStateCallInfo>( // --
IrOpcode::kFrameState, Operator::kPure, // opcode
"FrameState", // name
4, 0, 0, 1, 0, 0, // counts
FrameStateCallInfo(type, bailout_id, state_combine, jsfunction));
OutputFrameStateCombine state_combine) {
return new (zone()) Operator1<FrameStateCallInfo>( // --
IrOpcode::kFrameState, Operator::kPure, // opcode
"FrameState", // name
5, 0, 0, 1, 0, 0, // counts
FrameStateCallInfo(type, bailout_id, state_combine)); // parameter
}

View File

@ -128,10 +128,8 @@ class CommonOperatorBuilder final : public ZoneObject {
const Operator* Finish(int arguments);
const Operator* StateValues(int arguments);
const Operator* TypedStateValues(const ZoneVector<MachineType>* types);
const Operator* FrameState(
FrameStateType type, BailoutId bailout_id,
OutputFrameStateCombine state_combine,
MaybeHandle<JSFunction> jsfunction = MaybeHandle<JSFunction>());
const Operator* FrameState(FrameStateType type, BailoutId bailout_id,
OutputFrameStateCombine state_combine);
const Operator* Call(const CallDescriptor* descriptor);
const Operator* TailCall(const CallDescriptor* descriptor);
const Operator* Projection(size_t index);

View File

@ -48,6 +48,7 @@ std::ostream& operator<<(std::ostream& os, FrameStateCallInfo const& info) {
return os << info.type() << ", " << info.bailout_id() << ", "
<< info.state_combine();
}
}
}
}
} // namespace compiler
} // namespace internal
} // namespace v8

View File

@ -5,8 +5,6 @@
#ifndef V8_COMPILER_FRAME_STATES_H_
#define V8_COMPILER_FRAME_STATES_H_
#include "src/handles-inl.h" // TODO(everyone): Fix our inl.h crap
#include "src/objects-inl.h" // TODO(everyone): Fix our inl.h crap
#include "src/utils.h"
namespace v8 {
@ -80,25 +78,20 @@ enum FrameStateType {
class FrameStateCallInfo final {
public:
FrameStateCallInfo(
FrameStateType type, BailoutId bailout_id,
OutputFrameStateCombine state_combine,
MaybeHandle<JSFunction> jsfunction = MaybeHandle<JSFunction>())
FrameStateCallInfo(FrameStateType type, BailoutId bailout_id,
OutputFrameStateCombine state_combine)
: type_(type),
bailout_id_(bailout_id),
frame_state_combine_(state_combine),
jsfunction_(jsfunction) {}
frame_state_combine_(state_combine) {}
FrameStateType type() const { return type_; }
BailoutId bailout_id() const { return bailout_id_; }
OutputFrameStateCombine state_combine() const { return frame_state_combine_; }
MaybeHandle<JSFunction> jsfunction() const { return jsfunction_; }
private:
FrameStateType type_;
BailoutId bailout_id_;
OutputFrameStateCombine frame_state_combine_;
MaybeHandle<JSFunction> jsfunction_;
FrameStateType const type_;
BailoutId const bailout_id_;
OutputFrameStateCombine const frame_state_combine_;
};
bool operator==(FrameStateCallInfo const&, FrameStateCallInfo const&);

View File

@ -1028,7 +1028,7 @@ void InstructionSelector::VisitThrow(Node* value) {
FrameStateDescriptor* InstructionSelector::GetFrameStateDescriptor(
Node* state) {
DCHECK(state->opcode() == IrOpcode::kFrameState);
DCHECK_EQ(5, state->InputCount());
DCHECK_EQ(6, state->InputCount());
DCHECK_EQ(IrOpcode::kTypedStateValues, state->InputAt(0)->opcode());
DCHECK_EQ(IrOpcode::kTypedStateValues, state->InputAt(1)->opcode());
DCHECK_EQ(IrOpcode::kTypedStateValues, state->InputAt(2)->opcode());
@ -1040,13 +1040,14 @@ FrameStateDescriptor* InstructionSelector::GetFrameStateDescriptor(
int stack = static_cast<int>(StateValuesAccess(state->InputAt(2)).size());
FrameStateDescriptor* outer_state = NULL;
Node* outer_node = state->InputAt(4);
Node* outer_node = state->InputAt(5);
if (outer_node->opcode() == IrOpcode::kFrameState) {
outer_state = GetFrameStateDescriptor(outer_node);
}
return new (instruction_zone()) FrameStateDescriptor(
instruction_zone(), state_info, parameters, locals, stack, outer_state);
instruction_zone(), state_info.type(), state_info.bailout_id(),
state_info.state_combine(), parameters, locals, stack, outer_state);
}
@ -1068,14 +1069,15 @@ void InstructionSelector::AddFrameStateInputs(
FrameStateDescriptor* descriptor) {
DCHECK_EQ(IrOpcode::kFrameState, state->op()->opcode());
if (descriptor->outer_state() != NULL) {
AddFrameStateInputs(state->InputAt(4), inputs, descriptor->outer_state());
if (descriptor->outer_state()) {
AddFrameStateInputs(state->InputAt(5), inputs, descriptor->outer_state());
}
Node* parameters = state->InputAt(0);
Node* locals = state->InputAt(1);
Node* stack = state->InputAt(2);
Node* context = state->InputAt(3);
Node* function = state->InputAt(4);
DCHECK_EQ(IrOpcode::kTypedStateValues, parameters->op()->opcode());
DCHECK_EQ(IrOpcode::kTypedStateValues, locals->op()->opcode());
@ -1091,6 +1093,8 @@ void InstructionSelector::AddFrameStateInputs(
OperandGenerator g(this);
size_t value_index = 0;
inputs->push_back(SlotOrImmediate(&g, function));
descriptor->SetType(value_index++, kMachAnyTagged);
for (StateValuesAccess::TypedNode input_node :
StateValuesAccess(parameters)) {
inputs->push_back(SlotOrImmediate(&g, input_node.node));

View File

@ -662,22 +662,23 @@ void InstructionSequence::SetSourcePosition(const Instruction* instr,
FrameStateDescriptor::FrameStateDescriptor(
Zone* zone, const FrameStateCallInfo& state_info, size_t parameters_count,
Zone* zone, FrameStateType type, BailoutId bailout_id,
OutputFrameStateCombine state_combine, size_t parameters_count,
size_t locals_count, size_t stack_count, FrameStateDescriptor* outer_state)
: type_(state_info.type()),
bailout_id_(state_info.bailout_id()),
frame_state_combine_(state_info.state_combine()),
: type_(type),
bailout_id_(bailout_id),
frame_state_combine_(state_combine),
parameters_count_(parameters_count),
locals_count_(locals_count),
stack_count_(stack_count),
types_(zone),
outer_state_(outer_state),
jsfunction_(state_info.jsfunction()) {
outer_state_(outer_state) {
types_.resize(GetSize(), kMachNone);
}
size_t FrameStateDescriptor::GetSize(OutputFrameStateCombine combine) const {
size_t size = parameters_count() + locals_count() + stack_count() +
size_t size = 1 + parameters_count() + locals_count() + stack_count() +
(HasContext() ? 1 : 0);
switch (combine.kind()) {
case OutputFrameStateCombine::kPushOutput:

View File

@ -862,10 +862,11 @@ class Constant final {
class FrameStateDescriptor : public ZoneObject {
public:
FrameStateDescriptor(Zone* zone, const FrameStateCallInfo& state_info,
FrameStateDescriptor(Zone* zone, FrameStateType type, BailoutId bailout_id,
OutputFrameStateCombine state_combine,
size_t parameters_count, size_t locals_count,
size_t stack_count,
FrameStateDescriptor* outer_state = NULL);
FrameStateDescriptor* outer_state = nullptr);
FrameStateType type() const { return type_; }
BailoutId bailout_id() const { return bailout_id_; }
@ -874,7 +875,6 @@ class FrameStateDescriptor : public ZoneObject {
size_t locals_count() const { return locals_count_; }
size_t stack_count() const { return stack_count_; }
FrameStateDescriptor* outer_state() const { return outer_state_; }
MaybeHandle<JSFunction> jsfunction() const { return jsfunction_; }
bool HasContext() const { return type_ == JS_FRAME; }
size_t GetSize(OutputFrameStateCombine combine =
@ -895,7 +895,6 @@ class FrameStateDescriptor : public ZoneObject {
size_t stack_count_;
ZoneVector<MachineType> types_;
FrameStateDescriptor* outer_state_;
MaybeHandle<JSFunction> jsfunction_;
};
std::ostream& operator<<(std::ostream& os, const Constant& constant);

View File

@ -191,7 +191,7 @@ Node* JSGraph::EmptyFrameState() {
common()->FrameState(JS_FRAME, BailoutId::None(),
OutputFrameStateCombine::Ignore()),
state_values, state_values, state_values, NoContextConstant(),
UndefinedConstant());
UndefinedConstant(), UndefinedConstant());
cached_nodes_[kEmptyFrameState] = empty_frame_state;
}
return empty_frame_state;

View File

@ -264,22 +264,11 @@ Reduction JSInliner::InlineCall(Node* call, Inlinee& inlinee) {
}
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),
OutputFrameStateCombine::Ignore(), jsfunction);
OutputFrameStateCombine::Ignore());
const Operator* op0 = jsgraph_->common()->StateValues(0);
Node* node0 = jsgraph_->graph()->NewNode(op0);
NodeVector params(temp_zone);
@ -293,7 +282,7 @@ Node* JSInliner::CreateArgumentsAdaptorFrameState(JSCallFunctionAccessor* call,
op_param, static_cast<int>(params.size()), &params.front());
return jsgraph_->graph()->NewNode(op, params_node, node0, node0,
jsgraph_->UndefinedConstant(),
call->frame_state());
call->jsfunction(), call->frame_state());
}
@ -359,14 +348,12 @@ Reduction JSInliner::Reduce(Node* node) {
call.formal_arguments() < inlinee.formal_parameters()) {
return NoChange();
}
outer_frame_state =
CreateArgumentsAdaptorFrameState(&call, function, info.zone());
outer_frame_state = CreateArgumentsAdaptorFrameState(&call, info.zone());
}
for (Node* node : visitor.copies()) {
if (node && node->opcode() == IrOpcode::kFrameState) {
DCHECK_EQ(1, OperatorProperties::GetFrameStateInputCount(node->op()));
AddClosureToFrameState(node, function);
NodeProperties::ReplaceFrameStateInput(node, 0, outer_frame_state);
}
}

View File

@ -36,9 +36,7 @@ class JSInliner final : public AdvancedReducer {
JSGraph* jsgraph_;
Node* CreateArgumentsAdaptorFrameState(JSCallFunctionAccessor* call,
Handle<JSFunction> jsfunction,
Zone* temp_zone);
void AddClosureToFrameState(Node* frame_state, Handle<JSFunction> jsfunction);
Reduction InlineCall(Node* call, Inlinee& inlinee);
};

View File

@ -289,7 +289,8 @@ class JSBinopReduction final {
return graph()->NewNode(op, frame_state->InputAt(0),
frame_state->InputAt(1), frame_state->InputAt(2),
frame_state->InputAt(3), frame_state->InputAt(4));
frame_state->InputAt(3), frame_state->InputAt(4),
frame_state->InputAt(5));
}
Node* CreateFrameStateForRightInput(Node* frame_state, Node* converted_left) {
@ -326,7 +327,8 @@ class JSBinopReduction final {
return graph()->NewNode(op, frame_state->InputAt(0),
frame_state->InputAt(1), new_stack,
frame_state->InputAt(3), frame_state->InputAt(4));
frame_state->InputAt(3), frame_state->InputAt(4),
frame_state->InputAt(5));
}
Node* ConvertPlainPrimitiveToNumber(Node* node) {

View File

@ -421,6 +421,10 @@ void Verifier::Visitor::Check(Node* node) {
}
case IrOpcode::kFrameState:
// TODO(jarin): what are the constraints on these?
CHECK_EQ(5, value_count);
CHECK_EQ(0, control_count);
CHECK_EQ(0, effect_count);
CHECK_EQ(6, input_count);
break;
case IrOpcode::kStateValues:
case IrOpcode::kTypedStateValues:

View File

@ -129,10 +129,11 @@ class TrivialDeoptCodegenTester : public DeoptCodegenTester {
Node* locals = m.NewNode(common.TypedStateValues(&empty_types));
Node* stack = m.NewNode(common.TypedStateValues(&empty_types));
Node* state_node = m.NewNode(
common.FrameState(JS_FRAME, bailout_id,
OutputFrameStateCombine::Ignore()),
parameters, locals, stack, caller_context_node, m.UndefinedConstant());
Node* state_node =
m.NewNode(common.FrameState(JS_FRAME, bailout_id,
OutputFrameStateCombine::Ignore()),
parameters, locals, stack, caller_context_node,
deopt_fun_node, m.UndefinedConstant());
Handle<Context> context(deopt_function->context(), CcTest::i_isolate());
Unique<Context> context_constant =
@ -245,10 +246,11 @@ class TrivialRuntimeDeoptCodegenTester : public DeoptCodegenTester {
Node* locals = m.NewNode(common.TypedStateValues(&empty_types));
Node* stack = m.NewNode(common.TypedStateValues(&empty_types));
Node* state_node = m.NewNode(
common.FrameState(JS_FRAME, bailout_id,
OutputFrameStateCombine::Ignore()),
parameters, locals, stack, context_node, m.UndefinedConstant());
Node* state_node =
m.NewNode(common.FrameState(JS_FRAME, bailout_id,
OutputFrameStateCombine::Ignore()),
parameters, locals, stack, context_node, this_fun_node,
m.UndefinedConstant());
m.CallRuntime1(Runtime::kDeoptimizeFunction, this_fun_node, context_node,
state_node);

View File

@ -362,10 +362,11 @@ TARGET_TEST_F(InstructionSelectorTest, CallJSFunctionWithDeopt) {
Node* stack = m.NewNode(m.common()->TypedStateValues(&empty_types));
Node* context_dummy = m.Int32Constant(0);
Node* state_node = m.NewNode(
m.common()->FrameState(JS_FRAME, bailout_id,
OutputFrameStateCombine::Push()),
parameters, locals, stack, context_dummy, m.UndefinedConstant());
Node* state_node =
m.NewNode(m.common()->FrameState(JS_FRAME, bailout_id,
OutputFrameStateCombine::Push()),
parameters, locals, stack, context_dummy, function_node,
m.UndefinedConstant());
Node* call = m.CallJS0(function_node, receiver, context, state_node);
m.Return(call);
@ -410,10 +411,11 @@ TARGET_TEST_F(InstructionSelectorTest, CallFunctionStubWithDeopt) {
m.UndefinedConstant());
Node* context_sentinel = m.Int32Constant(0);
Node* frame_state_before = m.NewNode(
m.common()->FrameState(JS_FRAME, bailout_id_before,
OutputFrameStateCombine::Push()),
parameters, locals, stack, context_sentinel, m.UndefinedConstant());
Node* frame_state_before =
m.NewNode(m.common()->FrameState(JS_FRAME, bailout_id_before,
OutputFrameStateCombine::Push()),
parameters, locals, stack, context_sentinel, function_node,
m.UndefinedConstant());
// Build the call.
Node* call = m.CallFunctionStub0(function_node, receiver, context,
@ -437,7 +439,7 @@ TARGET_TEST_F(InstructionSelectorTest, CallFunctionStubWithDeopt) {
size_t num_operands =
1 + // Code object.
1 +
4 + // Frame state deopt id + one input for each value in frame state.
5 + // Frame state deopt id + one input for each value in frame state.
1 + // Function.
1; // Context.
ASSERT_EQ(num_operands, call_instr->InputCount());
@ -455,21 +457,23 @@ TARGET_TEST_F(InstructionSelectorTest, CallFunctionStubWithDeopt) {
EXPECT_EQ(1u, desc_before->parameters_count());
EXPECT_EQ(1u, desc_before->locals_count());
EXPECT_EQ(1u, desc_before->stack_count());
EXPECT_EQ(43, s.ToInt32(call_instr->InputAt(2)));
EXPECT_EQ(0, s.ToInt32(call_instr->InputAt(3))); // This should be a context.
EXPECT_EQ(43, s.ToInt32(call_instr->InputAt(3)));
EXPECT_EQ(0, s.ToInt32(call_instr->InputAt(4))); // This should be a context.
// We inserted 0 here.
EXPECT_EQ(0.5, s.ToFloat64(call_instr->InputAt(4)));
EXPECT_TRUE(s.ToHeapObject(call_instr->InputAt(5))->IsUndefined());
EXPECT_EQ(kMachInt32, desc_before->GetType(0));
EXPECT_EQ(kMachAnyTagged, desc_before->GetType(1)); // context is always
EXPECT_EQ(0.5, s.ToFloat64(call_instr->InputAt(5)));
EXPECT_TRUE(s.ToHeapObject(call_instr->InputAt(6))->IsUndefined());
EXPECT_EQ(kMachAnyTagged, desc_before->GetType(0)); // function is always
// tagged/any.
EXPECT_EQ(kMachFloat64, desc_before->GetType(2));
EXPECT_EQ(kMachAnyTagged, desc_before->GetType(3));
EXPECT_EQ(kMachInt32, desc_before->GetType(1));
EXPECT_EQ(kMachAnyTagged, desc_before->GetType(2)); // context is always
// tagged/any.
EXPECT_EQ(kMachFloat64, desc_before->GetType(3));
EXPECT_EQ(kMachAnyTagged, desc_before->GetType(4));
// Function.
EXPECT_EQ(s.ToVreg(function_node), s.ToVreg(call_instr->InputAt(6)));
EXPECT_EQ(s.ToVreg(function_node), s.ToVreg(call_instr->InputAt(7)));
// Context.
EXPECT_EQ(s.ToVreg(context), s.ToVreg(call_instr->InputAt(7)));
EXPECT_EQ(s.ToVreg(context), s.ToVreg(call_instr->InputAt(8)));
EXPECT_EQ(kArchRet, s[index++]->arch_opcode());
@ -501,10 +505,10 @@ TARGET_TEST_F(InstructionSelectorTest,
m.NewNode(m.common()->TypedStateValues(&int32_type), m.Int32Constant(64));
Node* stack =
m.NewNode(m.common()->TypedStateValues(&int32_type), m.Int32Constant(65));
Node* frame_state_parent =
m.NewNode(m.common()->FrameState(JS_FRAME, bailout_id_parent,
OutputFrameStateCombine::Ignore()),
parameters, locals, stack, context, m.UndefinedConstant());
Node* frame_state_parent = m.NewNode(
m.common()->FrameState(JS_FRAME, bailout_id_parent,
OutputFrameStateCombine::Ignore()),
parameters, locals, stack, context, function_node, m.UndefinedConstant());
Node* context2 = m.Int32Constant(46);
Node* parameters2 =
@ -516,7 +520,8 @@ TARGET_TEST_F(InstructionSelectorTest,
Node* frame_state_before =
m.NewNode(m.common()->FrameState(JS_FRAME, bailout_id_before,
OutputFrameStateCombine::Push()),
parameters2, locals2, stack2, context2, frame_state_parent);
parameters2, locals2, stack2, context2, function_node,
frame_state_parent);
// Build the call.
Node* call = m.CallFunctionStub0(function_node, receiver, context2,
@ -540,8 +545,8 @@ TARGET_TEST_F(InstructionSelectorTest,
size_t num_operands =
1 + // Code object.
1 + // Frame state deopt id
5 + // One input for each value in frame state + context.
4 + // One input for each value in the parent frame state + context.
6 + // One input for each value in frame state + context.
5 + // One input for each value in the parent frame state + context.
1 + // Function.
1; // Context.
EXPECT_EQ(num_operands, call_instr->InputCount());
@ -558,34 +563,36 @@ TARGET_TEST_F(InstructionSelectorTest,
EXPECT_EQ(1u, desc_before_outer->locals_count());
EXPECT_EQ(1u, desc_before_outer->stack_count());
// Values from parent environment.
EXPECT_EQ(63, s.ToInt32(call_instr->InputAt(2)));
EXPECT_EQ(kMachInt32, desc_before_outer->GetType(0));
EXPECT_EQ(kMachAnyTagged, desc_before->GetType(0));
EXPECT_EQ(63, s.ToInt32(call_instr->InputAt(3)));
EXPECT_EQ(kMachInt32, desc_before_outer->GetType(1));
// Context:
EXPECT_EQ(66, s.ToInt32(call_instr->InputAt(3)));
EXPECT_EQ(kMachAnyTagged, desc_before_outer->GetType(1));
EXPECT_EQ(64, s.ToInt32(call_instr->InputAt(4)));
EXPECT_EQ(kMachInt32, desc_before_outer->GetType(2));
EXPECT_EQ(65, s.ToInt32(call_instr->InputAt(5)));
EXPECT_EQ(66, s.ToInt32(call_instr->InputAt(4)));
EXPECT_EQ(kMachAnyTagged, desc_before_outer->GetType(2));
EXPECT_EQ(64, s.ToInt32(call_instr->InputAt(5)));
EXPECT_EQ(kMachInt32, desc_before_outer->GetType(3));
EXPECT_EQ(65, s.ToInt32(call_instr->InputAt(6)));
EXPECT_EQ(kMachInt32, desc_before_outer->GetType(4));
// Values from the nested frame.
EXPECT_EQ(1u, desc_before->parameters_count());
EXPECT_EQ(1u, desc_before->locals_count());
EXPECT_EQ(2u, desc_before->stack_count());
EXPECT_EQ(43, s.ToInt32(call_instr->InputAt(6)));
EXPECT_EQ(kMachInt32, desc_before->GetType(0));
EXPECT_EQ(46, s.ToInt32(call_instr->InputAt(7)));
EXPECT_EQ(kMachAnyTagged, desc_before->GetType(1));
EXPECT_EQ(0.25, s.ToFloat64(call_instr->InputAt(8)));
EXPECT_EQ(kMachFloat64, desc_before->GetType(2));
EXPECT_EQ(44, s.ToInt32(call_instr->InputAt(9)));
EXPECT_EQ(kMachInt32, desc_before->GetType(3));
EXPECT_EQ(45, s.ToInt32(call_instr->InputAt(10)));
EXPECT_EQ(kMachAnyTagged, desc_before->GetType(0));
EXPECT_EQ(43, s.ToInt32(call_instr->InputAt(8)));
EXPECT_EQ(kMachInt32, desc_before->GetType(1));
EXPECT_EQ(46, s.ToInt32(call_instr->InputAt(9)));
EXPECT_EQ(kMachAnyTagged, desc_before->GetType(2));
EXPECT_EQ(0.25, s.ToFloat64(call_instr->InputAt(10)));
EXPECT_EQ(kMachFloat64, desc_before->GetType(3));
EXPECT_EQ(44, s.ToInt32(call_instr->InputAt(11)));
EXPECT_EQ(kMachInt32, desc_before->GetType(4));
EXPECT_EQ(45, s.ToInt32(call_instr->InputAt(12)));
EXPECT_EQ(kMachInt32, desc_before->GetType(5));
// Function.
EXPECT_EQ(s.ToVreg(function_node), s.ToVreg(call_instr->InputAt(11)));
EXPECT_EQ(s.ToVreg(function_node), s.ToVreg(call_instr->InputAt(13)));
// Context.
EXPECT_EQ(s.ToVreg(context2), s.ToVreg(call_instr->InputAt(12)));
EXPECT_EQ(s.ToVreg(context2), s.ToVreg(call_instr->InputAt(14)));
// Continuation.
EXPECT_EQ(kArchRet, s[index++]->arch_opcode());