From 68075b0a0516bae4525daebd9bc258679a6c1cad Mon Sep 17 00:00:00 2001 From: "sigurds@chromium.org" Date: Thu, 18 Sep 2014 08:56:52 +0000 Subject: [PATCH] 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 --- src/compiler/ast-graph-builder.cc | 12 +- src/compiler/code-generator.cc | 55 ++++---- src/compiler/code-generator.h | 6 +- src/compiler/common-operator.cc | 5 +- src/compiler/common-operator.h | 34 +++-- src/compiler/instruction-selector-impl.h | 2 +- src/compiler/instruction-selector-unittest.cc | 34 ++--- src/compiler/instruction-selector.cc | 10 +- src/compiler/instruction.h | 71 +++++++--- src/compiler/js-inlining.cc | 120 +++++++++++++++-- src/compiler/js-inlining.h | 6 + src/compiler/linkage.cc | 3 + src/compiler/node-properties-inl.h | 6 + src/compiler/node-properties.h | 1 + src/compiler/node.h | 1 + src/frames.cc | 18 +-- test/cctest/cctest.status | 7 +- test/cctest/compiler/test-codegen-deopt.cc | 12 +- test/cctest/compiler/test-js-typed-lowering.cc | 2 +- test/cctest/compiler/test-run-inlining.cc | 172 +++++++++++++++++++------ 20 files changed, 421 insertions(+), 156 deletions(-) diff --git a/src/compiler/ast-graph-builder.cc b/src/compiler/ast-graph-builder.cc index 5c61471..0364078 100644 --- a/src/compiler/ast-graph-builder.cc +++ b/src/compiler/ast-graph-builder.cc @@ -224,7 +224,7 @@ Node* AstGraphBuilder::Environment::Checkpoint( UpdateStateValues(&stack_node_, parameters_count() + locals_count(), 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_, GetContext(), @@ -2020,12 +2020,10 @@ Node* AstGraphBuilder::BuildBinaryOp(Node* left, Node* right, Token::Value op) { void AstGraphBuilder::PrepareFrameState(Node* node, BailoutId ast_id, OutputFrameStateCombine combine) { if (OperatorProperties::HasFrameStateInput(node->op())) { - int frame_state_index = NodeProperties::GetFrameStateIndex(node); - - DCHECK(node->InputAt(frame_state_index)->op()->opcode() == IrOpcode::kDead); - - Node* frame_state_node = environment()->Checkpoint(ast_id, combine); - node->ReplaceInput(frame_state_index, frame_state_node); + DCHECK(NodeProperties::GetFrameStateInput(node)->opcode() == + IrOpcode::kDead); + NodeProperties::ReplaceFrameStateInput( + node, environment()->Checkpoint(ast_id, combine)); } } diff --git a/src/compiler/code-generator.cc b/src/compiler/code-generator.cc index 574d1ae..ae0e102 100644 --- a/src/compiler/code-generator.cc +++ b/src/compiler/code-generator.cc @@ -246,7 +246,7 @@ void CodeGenerator::AddSafepointAndDeopt(Instruction* instr) { // (just after the code address). InstructionOperandConverter converter(this, instr); // Deoptimization info starts at argument 1 - int frame_state_offset = 1; + size_t frame_state_offset = 1; FrameStateDescriptor* descriptor = GetFrameStateDescriptor(instr, frame_state_offset); int pc_offset = masm()->pc_offset(); @@ -266,7 +266,7 @@ void CodeGenerator::AddSafepointAndDeopt(Instruction* instr) { // Make sure all the values live in stack slots or they are immediates. // (The values should not live in register because registers are clobbered // 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); CHECK(op->IsStackSlot() || op->IsImmediate()); } @@ -287,40 +287,48 @@ int CodeGenerator::DefineDeoptimizationLiteral(Handle literal) { FrameStateDescriptor* CodeGenerator::GetFrameStateDescriptor( - Instruction* instr, int frame_state_offset) { + Instruction* instr, size_t frame_state_offset) { InstructionOperandConverter i(this, instr); - InstructionSequence::StateId state_id = - InstructionSequence::StateId::FromInt(i.InputInt32(frame_state_offset)); + InstructionSequence::StateId state_id = InstructionSequence::StateId::FromInt( + i.InputInt32(static_cast(frame_state_offset))); return code()->GetFrameStateDescriptor(state_id); } void CodeGenerator::BuildTranslationForFrameStateDescriptor( FrameStateDescriptor* descriptor, Instruction* instr, - Translation* translation, int frame_state_offset, + Translation* translation, size_t frame_state_offset, OutputFrameStateCombine state_combine) { // Outer-most state must be added to translation first. if (descriptor->outer_state() != NULL) { - BuildTranslationForFrameStateDescriptor( - descriptor->outer_state(), instr, translation, - frame_state_offset + descriptor->size(), kIgnoreOutput); + BuildTranslationForFrameStateDescriptor(descriptor->outer_state(), instr, + translation, frame_state_offset, + kIgnoreOutput); } - int height = descriptor->size() - descriptor->parameters_count(); - switch (state_combine) { - case kPushOutput: - height++; + int id = Translation::kSelfLiteralId; + if (!descriptor->jsfunction().is_null()) { + id = DefineDeoptimizationLiteral( + Handle::cast(descriptor->jsfunction().ToHandleChecked())); + } + + switch (descriptor->type()) { + case JS_FRAME: + translation->BeginJSFrame( + descriptor->bailout_id(), id, + static_cast(descriptor->GetHeight(state_combine))); break; - case kIgnoreOutput: + case ARGUMENTS_ADAPTOR: + translation->BeginArgumentsAdaptorFrame( + id, static_cast(descriptor->parameters_count())); break; } - translation->BeginJSFrame(descriptor->bailout_id(), - Translation::kSelfLiteralId, height); - - for (int i = 0; i < descriptor->size(); i++) { - AddTranslationForOperand(translation, instr, - instr->InputAt(i + frame_state_offset)); + frame_state_offset += descriptor->outer_state()->GetTotalSize(); + for (size_t i = 0; i < descriptor->size(); i++) { + AddTranslationForOperand( + translation, instr, + instr->InputAt(static_cast(frame_state_offset + i))); } switch (state_combine) { @@ -335,14 +343,15 @@ void CodeGenerator::BuildTranslationForFrameStateDescriptor( int CodeGenerator::BuildTranslation(Instruction* instr, int pc_offset, - int frame_state_offset, + size_t frame_state_offset, OutputFrameStateCombine state_combine) { FrameStateDescriptor* descriptor = GetFrameStateDescriptor(instr, frame_state_offset); frame_state_offset++; - int frame_count = descriptor->GetFrameCount(); - Translation translation(&translations_, frame_count, frame_count, zone()); + Translation translation( + &translations_, static_cast(descriptor->GetFrameCount()), + static_cast(descriptor->GetJSFrameCount()), zone()); BuildTranslationForFrameStateDescriptor(descriptor, instr, &translation, frame_state_offset, state_combine); diff --git a/src/compiler/code-generator.h b/src/compiler/code-generator.h index 78ac990..dfc98cd 100644 --- a/src/compiler/code-generator.h +++ b/src/compiler/code-generator.h @@ -87,13 +87,13 @@ class CodeGenerator FINAL : public GapResolver::Assembler { void PopulateDeoptimizationData(Handle code); int DefineDeoptimizationLiteral(Handle literal); FrameStateDescriptor* GetFrameStateDescriptor(Instruction* instr, - int frame_state_offset); + size_t frame_state_offset); int BuildTranslation(Instruction* instr, int pc_offset, - int frame_state_offset, + size_t frame_state_offset, OutputFrameStateCombine state_combine); void BuildTranslationForFrameStateDescriptor( FrameStateDescriptor* descriptor, Instruction* instr, - Translation* translation, int frame_state_offset, + Translation* translation, size_t frame_state_offset, OutputFrameStateCombine state_combine); void AddTranslationForOperand(Translation* translation, Instruction* instr, InstructionOperand* op); diff --git a/src/compiler/common-operator.cc b/src/compiler/common-operator.cc index e104b96..9034843 100644 --- a/src/compiler/common-operator.cc +++ b/src/compiler/common-operator.cc @@ -206,10 +206,11 @@ const Operator* CommonOperatorBuilder::StateValues(int arguments) { const Operator* CommonOperatorBuilder::FrameState( - BailoutId bailout_id, OutputFrameStateCombine combine) { + FrameStateType type, BailoutId bailout_id, + OutputFrameStateCombine state_combine, MaybeHandle jsfunction) { return new (zone()) Operator1( IrOpcode::kFrameState, Operator::kPure, 4, 1, "FrameState", - FrameStateCallInfo(bailout_id, combine)); + FrameStateCallInfo(type, bailout_id, state_combine, jsfunction)); } diff --git a/src/compiler/common-operator.h b/src/compiler/common-operator.h index 137155e..52c0af2 100644 --- a/src/compiler/common-operator.h +++ b/src/compiler/common-operator.h @@ -6,6 +6,7 @@ #define V8_COMPILER_COMMON_OPERATOR_H_ #include "src/compiler/machine-type.h" +#include "src/unique.h" namespace v8 { namespace internal { @@ -13,9 +14,6 @@ namespace internal { // Forward declarations. class ExternalReference; class OStream; -template -class Unique; -class Zone; namespace compiler { @@ -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 { public: - FrameStateCallInfo(BailoutId bailout_id, - OutputFrameStateCombine state_combine) - : bailout_id_(bailout_id), frame_state_combine_(state_combine) {} - + FrameStateCallInfo( + FrameStateType type, BailoutId bailout_id, + OutputFrameStateCombine state_combine, + MaybeHandle jsfunction = MaybeHandle()) + : 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_; } OutputFrameStateCombine state_combine() const { return frame_state_combine_; } + MaybeHandle jsfunction() const { return jsfunction_; } private: + FrameStateType type_; BailoutId bailout_id_; OutputFrameStateCombine frame_state_combine_; + MaybeHandle jsfunction_; }; @@ -81,8 +95,10 @@ class CommonOperatorBuilder FINAL { const Operator* ValueEffect(int arguments); const Operator* Finish(int arguments); const Operator* StateValues(int arguments); - const Operator* FrameState(BailoutId bailout_id, - OutputFrameStateCombine combine); + const Operator* FrameState( + FrameStateType type, BailoutId bailout_id, + OutputFrameStateCombine state_combine, + MaybeHandle jsfunction = MaybeHandle()); const Operator* Call(const CallDescriptor* descriptor); const Operator* Projection(size_t index); diff --git a/src/compiler/instruction-selector-impl.h b/src/compiler/instruction-selector-impl.h index 6f3a6df..d00109e 100644 --- a/src/compiler/instruction-selector-impl.h +++ b/src/compiler/instruction-selector-impl.h @@ -348,7 +348,7 @@ struct CallBuffer { size_t frame_state_value_count() const { return (frame_state_descriptor == NULL) ? 0 - : (frame_state_descriptor->total_size() + + : (frame_state_descriptor->GetTotalSize() + 1); // Include deopt id. } }; diff --git a/src/compiler/instruction-selector-unittest.cc b/src/compiler/instruction-selector-unittest.cc index f987e0f..aa70735 100644 --- a/src/compiler/instruction-selector-unittest.cc +++ b/src/compiler/instruction-selector-unittest.cc @@ -303,9 +303,9 @@ TARGET_TEST_F(InstructionSelectorTest, CallJSFunctionWithDeopt) { Node* stack = m.NewNode(m.common()->StateValues(0)); Node* context_dummy = m.Int32Constant(0); - Node* state_node = - m.NewNode(m.common()->FrameState(bailout_id, kPushOutput), parameters, - locals, stack, context_dummy, m.UndefinedConstant()); + Node* state_node = m.NewNode( + m.common()->FrameState(JS_FRAME, bailout_id, kPushOutput), parameters, + locals, stack, context_dummy, m.UndefinedConstant()); Node* call = m.CallJS0(function_node, receiver, context, state_node); m.Return(call); @@ -344,8 +344,8 @@ TARGET_TEST_F(InstructionSelectorTest, CallFunctionStubWithDeopt) { Node* context_sentinel = m.Int32Constant(0); Node* frame_state_before = m.NewNode( - m.common()->FrameState(bailout_id_before, kPushOutput), parameters, - locals, stack, context_sentinel, m.UndefinedConstant()); + m.common()->FrameState(JS_FRAME, bailout_id_before, kPushOutput), + parameters, locals, stack, context_sentinel, m.UndefinedConstant()); // Build the call. Node* call = m.CallFunctionStub0(function_node, receiver, context, @@ -383,9 +383,9 @@ TARGET_TEST_F(InstructionSelectorTest, CallFunctionStubWithDeopt) { s.GetFrameStateDescriptor(deopt_id_before); EXPECT_EQ(bailout_id_before, desc_before->bailout_id()); EXPECT_EQ(kPushOutput, desc_before->state_combine()); - EXPECT_EQ(1, desc_before->parameters_count()); - EXPECT_EQ(1, desc_before->locals_count()); - EXPECT_EQ(1, desc_before->stack_count()); + 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))); EXPECT_EQ(44, s.ToInt32(call_instr->InputAt(4))); @@ -419,18 +419,18 @@ TARGET_TEST_F(InstructionSelectorTest, Node* parameters = m.NewNode(m.common()->StateValues(1), m.Int32Constant(63)); Node* locals = m.NewNode(m.common()->StateValues(1), m.Int32Constant(64)); Node* stack = m.NewNode(m.common()->StateValues(1), m.Int32Constant(65)); - Node* frame_state_parent = - m.NewNode(m.common()->FrameState(bailout_id_parent, kIgnoreOutput), - parameters, locals, stack, context, m.UndefinedConstant()); + Node* frame_state_parent = m.NewNode( + m.common()->FrameState(JS_FRAME, bailout_id_parent, kIgnoreOutput), + parameters, locals, stack, context, m.UndefinedConstant()); Node* context2 = m.Int32Constant(46); Node* parameters2 = m.NewNode(m.common()->StateValues(1), m.Int32Constant(43)); Node* locals2 = m.NewNode(m.common()->StateValues(1), m.Int32Constant(44)); Node* stack2 = m.NewNode(m.common()->StateValues(1), m.Int32Constant(45)); - Node* frame_state_before = - m.NewNode(m.common()->FrameState(bailout_id_before, kPushOutput), - parameters2, locals2, stack2, context2, frame_state_parent); + Node* frame_state_before = m.NewNode( + m.common()->FrameState(JS_FRAME, bailout_id_before, kPushOutput), + parameters2, locals2, stack2, context2, frame_state_parent); // Build the call. Node* call = m.CallFunctionStub0(function_node, receiver, context2, @@ -467,9 +467,9 @@ TARGET_TEST_F(InstructionSelectorTest, FrameStateDescriptor* desc_before = s.GetFrameStateDescriptor(deopt_id_before); EXPECT_EQ(bailout_id_before, desc_before->bailout_id()); - EXPECT_EQ(1, desc_before->parameters_count()); - EXPECT_EQ(1, desc_before->locals_count()); - EXPECT_EQ(1, desc_before->stack_count()); + EXPECT_EQ(1u, desc_before->parameters_count()); + EXPECT_EQ(1u, desc_before->locals_count()); + EXPECT_EQ(1u, desc_before->stack_count()); EXPECT_EQ(63, s.ToInt32(call_instr->InputAt(2))); // Context: EXPECT_EQ(66, s.ToInt32(call_instr->InputAt(3))); diff --git a/src/compiler/instruction-selector.cc b/src/compiler/instruction-selector.cc index dec46b6..6bc41f4 100644 --- a/src/compiler/instruction-selector.cc +++ b/src/compiler/instruction-selector.cc @@ -1037,14 +1037,16 @@ void InstructionSelector::AddFrameStateInputs( DCHECK_EQ(descriptor->stack_count(), stack->InputCount()); OperandGenerator g(this); - for (int i = 0; i < descriptor->parameters_count(); i++) { + for (int i = 0; i < static_cast(descriptor->parameters_count()); i++) { inputs->push_back(UseOrImmediate(&g, parameters->InputAt(i))); } - inputs->push_back(UseOrImmediate(&g, context)); - for (int i = 0; i < descriptor->locals_count(); i++) { + if (descriptor->HasContext()) { + inputs->push_back(UseOrImmediate(&g, context)); + } + for (int i = 0; i < static_cast(descriptor->locals_count()); 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(descriptor->stack_count()); i++) { inputs->push_back(UseOrImmediate(&g, stack->InputAt(i))); } } diff --git a/src/compiler/instruction.h b/src/compiler/instruction.h index e2399b6..6d00784 100644 --- a/src/compiler/instruction.h +++ b/src/compiler/instruction.h @@ -702,55 +702,84 @@ class Constant FINAL { class FrameStateDescriptor : public ZoneObject { public: 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) - : bailout_id_(state_info.bailout_id()), + : type_(state_info.type()), + bailout_id_(state_info.bailout_id()), frame_state_combine_(state_info.state_combine()), parameters_count_(parameters_count), locals_count_(locals_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_; } OutputFrameStateCombine state_combine() const { return frame_state_combine_; } - int parameters_count() { return parameters_count_; } - int locals_count() { return locals_count_; } - int stack_count() { return stack_count_; } - FrameStateDescriptor* outer_state() { return outer_state_; } - void set_outer_state(FrameStateDescriptor* outer_state) { - outer_state_ = outer_state; - } + size_t parameters_count() const { return parameters_count_; } + 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() const { return jsfunction_; } - int size() { + size_t size() const { return parameters_count_ + locals_count_ + stack_count_ + - 1; // Includes context. + (HasContext() ? 1 : 0); } - int total_size() { - int total_size = 0; - for (FrameStateDescriptor* iter = this; iter != NULL; + size_t GetTotalSize() const { + size_t total_size = 0; + for (const FrameStateDescriptor* iter = this; iter != NULL; iter = iter->outer_state_) { total_size += iter->size(); } return total_size; } - int GetFrameCount() { - int count = 0; - for (FrameStateDescriptor* iter = this; iter != NULL; + size_t GetHeight(OutputFrameStateCombine override) const { + size_t height = size() - parameters_count(); + 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_) { ++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: + FrameStateType type_; BailoutId bailout_id_; OutputFrameStateCombine frame_state_combine_; - int parameters_count_; - int locals_count_; - int stack_count_; + size_t parameters_count_; + size_t locals_count_; + size_t stack_count_; FrameStateDescriptor* outer_state_; + MaybeHandle jsfunction_; }; OStream& operator<<(OStream& os, const Constant& constant); diff --git a/src/compiler/js-inlining.cc b/src/compiler/js-inlining.cc index b908ae8..4166ace 100644 --- a/src/compiler/js-inlining.cc +++ b/src/compiler/js-inlining.cc @@ -15,6 +15,7 @@ #include "src/compiler/node-properties-inl.h" #include "src/compiler/simplified-operator.h" #include "src/compiler/typer.h" +#include "src/full-codegen.h" #include "src/parser.h" #include "src/rewriter.h" #include "src/scopes.h" @@ -54,7 +55,6 @@ void JSInliner::Inline() { // test cases, where similar code is currently duplicated). static void Parse(Handle function, CompilationInfoWithZone* info) { CHECK(Parser::Parse(info)); - info->SetOptimizing(BailoutId::None(), Handle(function->code())); CHECK(Rewriter::Rewrite(info)); CHECK(Scope::Analyze(info)); CHECK_NE(NULL, info->scope()); @@ -90,6 +90,16 @@ class Inlinee { DCHECK_EQ(IrOpcode::kReturn, unique_return->opcode()); 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 // any new nodes. void InlineAtCall(JSGraph* jsgraph, Node* call); @@ -196,7 +206,7 @@ class CopyVisitor : public NullNodeVisitor { private: void ReplaceSentinels() { - for (int id = 0; id < source_graph_->NodeCount(); ++id) { + for (NodeId id = 0; id < source_graph_->NodeCount(); ++id) { Node* sentinel = sentinels_[id]; if (sentinel == NULL) continue; Node* copy = copies_[id]; @@ -235,11 +245,8 @@ void Inlinee::InlineAtCall(JSGraph* jsgraph, Node* call) { NodeProperties::GetValueInput(call, 0), NodeProperties::GetEffectInput(call)); - // {inlinee_inputs} counts JSFunction, Receiver, arguments, context, - // but not effect, control. - int inlinee_inputs = start_->op()->OutputCount(); // Context is last argument. - int inlinee_context_index = inlinee_inputs - 1; + int inlinee_context_index = static_cast(total_parameters()) - 1; // {inliner_inputs} counts JSFunction, Receiver, arguments, but not // context, effect, control. int inliner_inputs = OperatorProperties::GetValueInputCount(call->op()); @@ -299,10 +306,74 @@ void Inlinee::InlineAtCall(JSGraph* jsgraph, Node* call) { } -void JSInliner::TryInlineCall(Node* call) { - DCHECK_EQ(IrOpcode::kJSCallFunction, call->opcode()); +// TODO(turbofan) Provide such accessors for every node, possibly even +// 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(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) { + FrameStateCallInfo call_info = OpParameter(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, + 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(params.size())); + Node* params_node = jsgraph_->graph()->NewNode( + op_param, static_cast(params.size()), ¶ms.front()); + return jsgraph_->graph()->NewNode(op, params_node, node0, node0, + jsgraph_->UndefinedConstant(), + call->frame_state()); +} + - HeapObjectMatcher match(call->InputAt(0)); +void JSInliner::TryInlineCall(Node* call_node) { + JSCallFunctionAccessor call(call_node); + + HeapObjectMatcher match(call.jsfunction()); if (!match.HasValue()) { return; } @@ -322,6 +393,18 @@ void JSInliner::TryInlineCall(Node* call) { CompilationInfoWithZone info(function); 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) { // For now do not inline functions that use their arguments array. SmartArrayPointer name = function->shared()->DebugName()->ToCString(); @@ -353,7 +436,24 @@ void JSInliner::TryInlineCall(Node* call) { visitor.CopyGraph(); 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); } } } diff --git a/src/compiler/js-inlining.h b/src/compiler/js-inlining.h index a434571..f135170 100644 --- a/src/compiler/js-inlining.h +++ b/src/compiler/js-inlining.h @@ -12,6 +12,8 @@ namespace v8 { namespace internal { namespace compiler { +class JSCallFunctionAccessor; + class JSInliner { public: JSInliner(CompilationInfo* info, JSGraph* jsgraph) @@ -25,6 +27,10 @@ class JSInliner { CompilationInfo* info_; JSGraph* jsgraph_; + Node* CreateArgumentsAdaptorFrameState(JSCallFunctionAccessor* call, + Handle jsfunction, + Zone* temp_zone); + void AddClosureToFrameState(Node* frame_state, Handle jsfunction); static void UnifyReturn(Graph* graph); }; } diff --git a/src/compiler/linkage.cc b/src/compiler/linkage.cc index e459b1e..465a667 100644 --- a/src/compiler/linkage.cc +++ b/src/compiler/linkage.cc @@ -123,6 +123,9 @@ bool Linkage::NeedsFrameState(Runtime::FunctionId function) { case Runtime::kPrepareStep: case Runtime::kSetScriptBreakPoint: case Runtime::kStackGuard: + case Runtime::kCheckExecutionState: + case Runtime::kDebugEvaluate: + case Runtime::kCollectStackTrace: return true; default: return false; diff --git a/src/compiler/node-properties-inl.h b/src/compiler/node-properties-inl.h index bc52dfd..3f6d531 100644 --- a/src/compiler/node-properties-inl.h +++ b/src/compiler/node-properties-inl.h @@ -162,6 +162,12 @@ inline void NodeProperties::ReplaceEffectInput(Node* node, Node* 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) { node->TrimInputCount(OperatorProperties::GetValueInputCount(node->op())); } diff --git a/src/compiler/node-properties.h b/src/compiler/node-properties.h index 6bc9856..94bd731 100644 --- a/src/compiler/node-properties.h +++ b/src/compiler/node-properties.h @@ -35,6 +35,7 @@ class NodeProperties { static inline void ReplaceControlInput(Node* node, Node* control); static inline void ReplaceEffectInput(Node* node, Node* effect, int index = 0); + static inline void ReplaceFrameStateInput(Node* node, Node* frame_state); static inline void RemoveNonValueInputs(Node* node); static inline void ReplaceWithValue(Node* node, Node* value, Node* effect = NULL); diff --git a/src/compiler/node.h b/src/compiler/node.h index 73787f0..c3f5a53 100644 --- a/src/compiler/node.h +++ b/src/compiler/node.h @@ -71,6 +71,7 @@ typedef NodeSet::reverse_iterator NodeSetRIter; typedef ZoneVector NodeVector; typedef NodeVector::iterator NodeVectorIter; +typedef NodeVector::const_iterator NodeVectorConstIter; typedef NodeVector::reverse_iterator NodeVectorRIter; typedef ZoneVector NodeVectorVector; diff --git a/src/frames.cc b/src/frames.cc index 01c0a49..f116fd2 100644 --- a/src/frames.cc +++ b/src/frames.cc @@ -932,9 +932,9 @@ void OptimizedFrame::Summarize(List* frames) { DCHECK(frames->length() == 0); DCHECK(is_optimized()); - // Delegate to JS frame in absence of inlining. - // TODO(turbofan): Revisit once we support inlining. - if (LookupCode()->is_turbofanned()) { + // Delegate to JS frame in absence of turbofan deoptimization. + // TODO(turbofan): Revisit once we support deoptimization across the board. + if (LookupCode()->is_turbofanned() && !FLAG_turbo_deoptimization) { return JavaScriptFrame::Summarize(frames); } @@ -1059,9 +1059,9 @@ DeoptimizationInputData* OptimizedFrame::GetDeoptimizationData( int OptimizedFrame::GetInlineCount() { DCHECK(is_optimized()); - // Delegate to JS frame in absence of inlining. - // TODO(turbofan): Revisit once we support inlining. - if (LookupCode()->is_turbofanned()) { + // Delegate to JS frame in absence of turbofan deoptimization. + // TODO(turbofan): Revisit once we support deoptimization across the board. + if (LookupCode()->is_turbofanned() && !FLAG_turbo_deoptimization) { return JavaScriptFrame::GetInlineCount(); } @@ -1083,9 +1083,9 @@ void OptimizedFrame::GetFunctions(List* functions) { DCHECK(functions->length() == 0); DCHECK(is_optimized()); - // Delegate to JS frame in absence of inlining. - // TODO(turbofan): Revisit once we support inlining. - if (LookupCode()->is_turbofanned()) { + // Delegate to JS frame in absence of turbofan deoptimization. + // TODO(turbofan): Revisit once we support deoptimization across the board. + if (LookupCode()->is_turbofanned() && !FLAG_turbo_deoptimization) { return JavaScriptFrame::GetFunctions(functions); } diff --git a/test/cctest/cctest.status b/test/cctest/cctest.status index 86bc794..44ad3ae 100644 --- a/test/cctest/cctest.status +++ b/test/cctest/cctest.status @@ -80,17 +80,16 @@ ############################################################################## # 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. 'test-run-machops/RunCall*': [SKIP], 'test-run-machops/RunLoadImmIndex': [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/InlineTwiceDependentDiamondDifferent': [SKIP], + 'test-run-inlining/InlineLoop': [SKIP], # Some tests are just too slow to run for now. 'test-api/Threading*': [PASS, NO_VARIANTS], diff --git a/test/cctest/compiler/test-codegen-deopt.cc b/test/cctest/compiler/test-codegen-deopt.cc index fb036a0..5b6c358 100644 --- a/test/cctest/compiler/test-codegen-deopt.cc +++ b/test/cctest/compiler/test-codegen-deopt.cc @@ -148,9 +148,9 @@ class TrivialDeoptCodegenTester : public DeoptCodegenTester { Node* locals = m.NewNode(common.StateValues(0)); Node* stack = m.NewNode(common.StateValues(0)); - Node* state_node = - m.NewNode(common.FrameState(bailout_id, kIgnoreOutput), parameters, - locals, stack, caller_context_node, m.UndefinedConstant()); + Node* state_node = m.NewNode( + common.FrameState(JS_FRAME, bailout_id, kIgnoreOutput), parameters, + locals, stack, caller_context_node, m.UndefinedConstant()); Handle context(deopt_function->context(), CcTest::i_isolate()); Unique context_constant = @@ -262,9 +262,9 @@ class TrivialRuntimeDeoptCodegenTester : public DeoptCodegenTester { Node* locals = m.NewNode(common.StateValues(0)); Node* stack = m.NewNode(common.StateValues(0)); - Node* state_node = - m.NewNode(common.FrameState(bailout_id, kIgnoreOutput), parameters, - locals, stack, context_node, m.UndefinedConstant()); + Node* state_node = m.NewNode( + common.FrameState(JS_FRAME, bailout_id, kIgnoreOutput), parameters, + locals, stack, context_node, m.UndefinedConstant()); m.CallRuntime1(Runtime::kDeoptimizeFunction, this_fun_node, context_node, state_node); diff --git a/test/cctest/compiler/test-js-typed-lowering.cc b/test/cctest/compiler/test-js-typed-lowering.cc index 26ca766..afb9ed5 100644 --- a/test/cctest/compiler/test-js-typed-lowering.cc +++ b/test/cctest/compiler/test-js-typed-lowering.cc @@ -60,7 +60,7 @@ class JSTypedLoweringTester : public HandleAndZoneScope { Node* stack = graph.NewNode(common.StateValues(0)); Node* state_node = - graph.NewNode(common.FrameState(BailoutId(0), kIgnoreOutput), + graph.NewNode(common.FrameState(JS_FRAME, BailoutId(0), kIgnoreOutput), parameters, locals, stack, context, UndefinedConstant()); return state_node; diff --git a/test/cctest/compiler/test-run-inlining.cc b/test/cctest/compiler/test-run-inlining.cc index 1e52b35..ad82fec 100644 --- a/test/cctest/compiler/test-run-inlining.cc +++ b/test/cctest/compiler/test-run-inlining.cc @@ -11,49 +11,70 @@ using namespace v8::internal; using namespace v8::internal::compiler; -// TODO(sigurds) At the moment we do not write optimization frames when -// inlining, thus the reported stack depth changes depending on inlining. -// AssertStackDepth checks the stack depth actually changes as a simple way -// to ensure that inlining actually occurs. -// Once inlining creates optimization frames, all these unit tests need to -// check that the optimization frame is there. - - -static void AssertStackDepth(const v8::FunctionCallbackInfo& args) { - v8::HandleScope scope(args.GetIsolate()); - v8::Handle stackTrace = v8::StackTrace::CurrentStackTrace( - args.GetIsolate(), 10, v8::StackTrace::kDetailed); - CHECK_EQ(args[0]->ToInt32()->Value(), stackTrace->GetFrameCount()); +// Helper to determine inline count via JavaScriptFrame::GetInlineCount. +// Note that a count of 1 indicates that no inlining has occured. +static void AssertInlineCount(const v8::FunctionCallbackInfo& args) { + StackTraceFrameIterator it(CcTest::i_isolate()); + int frames_seen = 0; + JavaScriptFrame* topmost = it.frame(); + while (!it.done()) { + JavaScriptFrame* frame = it.frame(); + PrintF("%d %s, inline count: %d\n", frames_seen, + frame->function()->shared()->DebugName()->ToCString().get(), + frame->GetInlineCount()); + frames_seen++; + it.Advance(); + } + CHECK_EQ(args[0]->ToInt32()->Value(), topmost->GetInlineCount()); } -static void InstallAssertStackDepthHelper(v8::Isolate* isolate) { +static void InstallAssertInlineCountHelper(v8::Isolate* isolate) { v8::Local context = isolate->GetCurrentContext(); v8::Local t = - v8::FunctionTemplate::New(isolate, AssertStackDepth); - context->Global()->Set(v8_str("AssertStackDepth"), t->GetFunction()); + v8::FunctionTemplate::New(isolate, AssertInlineCount); + context->Global()->Set(v8_str("AssertInlineCount"), t->GetFunction()); } TEST(SimpleInlining) { + FLAG_turbo_deoptimization = true; FunctionTester T( "(function(){" - "function foo(s) { AssertStackDepth(1); return s; };" + "function foo(s) { AssertInlineCount(2); return s; };" "function bar(s, t) { return foo(s); };" "return bar;})();", CompilationInfo::kInliningEnabled | CompilationInfo::kContextSpecializing | CompilationInfo::kTypingEnabled); - InstallAssertStackDepthHelper(CcTest::isolate()); + InstallAssertInlineCountHelper(CcTest::isolate()); + T.CheckCall(T.Val(1), T.Val(1), T.Val(2)); +} + + +TEST(SimpleInliningDeopt) { + FLAG_turbo_deoptimization = true; + FunctionTester T( + "(function(){" + "function foo(s) { %DeoptimizeFunction(bar); return " + "s; };" + "function bar(s, t) { return foo(s); };" + "return bar;})();", + CompilationInfo::kInliningEnabled | + CompilationInfo::kContextSpecializing | + CompilationInfo::kTypingEnabled); + + InstallAssertInlineCountHelper(CcTest::isolate()); T.CheckCall(T.Val(1), T.Val(1), T.Val(2)); } TEST(SimpleInliningContext) { + FLAG_turbo_deoptimization = true; FunctionTester T( "(function () {" - "function foo(s) { AssertStackDepth(1); var x = 12; return s + x; };" + "function foo(s) { AssertInlineCount(2); var x = 12; return s + x; };" "function bar(s, t) { return foo(s); };" "return bar;" "})();", @@ -61,12 +82,33 @@ TEST(SimpleInliningContext) { CompilationInfo::kContextSpecializing | CompilationInfo::kTypingEnabled); - InstallAssertStackDepthHelper(CcTest::isolate()); + InstallAssertInlineCountHelper(CcTest::isolate()); + T.CheckCall(T.Val(13), T.Val(1), T.Val(2)); +} + + +TEST(SimpleInliningContextDeopt) { + FLAG_turbo_deoptimization = true; + FunctionTester T( + "(function () {" + "function foo(s) { " + " AssertInlineCount(2); %DeoptimizeFunction(bar); var x = 12;" + " return s + x;" + "};" + "function bar(s, t) { return foo(s); };" + "return bar;" + "})();", + CompilationInfo::kInliningEnabled | + CompilationInfo::kContextSpecializing | + CompilationInfo::kTypingEnabled); + + InstallAssertInlineCountHelper(CcTest::isolate()); T.CheckCall(T.Val(13), T.Val(1), T.Val(2)); } TEST(CaptureContext) { + FLAG_turbo_deoptimization = true; FunctionTester T( "var f = (function () {" "var x = 42;" @@ -78,7 +120,7 @@ TEST(CaptureContext) { CompilationInfo::kContextSpecializing | CompilationInfo::kTypingEnabled); - InstallAssertStackDepthHelper(CcTest::isolate()); + InstallAssertInlineCountHelper(CcTest::isolate()); T.CheckCall(T.Val(42 + 12), T.Val(12), T.undefined()); } @@ -86,42 +128,65 @@ TEST(CaptureContext) { // TODO(sigurds) For now we do not inline any native functions. If we do at // some point, change this test. TEST(DontInlineEval) { + FLAG_turbo_deoptimization = true; FunctionTester T( "var x = 42;" "(function () {" - "function bar(s, t) { return eval(\"AssertStackDepth(2); x\") };" + "function bar(s, t) { return eval(\"AssertInlineCount(1); x\") };" "return bar;" "})();", CompilationInfo::kInliningEnabled | CompilationInfo::kContextSpecializing | CompilationInfo::kTypingEnabled); - InstallAssertStackDepthHelper(CcTest::isolate()); + InstallAssertInlineCountHelper(CcTest::isolate()); T.CheckCall(T.Val(42), T.Val("x"), T.undefined()); } TEST(InlineOmitArguments) { + FLAG_turbo_deoptimization = true; FunctionTester T( "(function () {" "var x = 42;" - "function bar(s, t, u, v) { AssertStackDepth(1); return x + s; };" + "function bar(s, t, u, v) { AssertInlineCount(2); return x + s; };" "return (function (s,t) { return bar(s); });" "})();", CompilationInfo::kInliningEnabled | CompilationInfo::kContextSpecializing | CompilationInfo::kTypingEnabled); - InstallAssertStackDepthHelper(CcTest::isolate()); + InstallAssertInlineCountHelper(CcTest::isolate()); T.CheckCall(T.Val(42 + 12), T.Val(12), T.undefined()); } +TEST(InlineOmitArgumentsDeopt) { + FLAG_turbo_deoptimization = true; + FunctionTester T( + "(function () {" + "function foo(s,t,u,v) { AssertInlineCount(2); %DeoptimizeFunction(bar); " + "return baz(); };" + "function bar() { return foo(11); };" + "function baz() { return foo.arguments.length == 1 && " + " foo.arguments[0] == 11 ; }" + "return bar;" + "})();", + CompilationInfo::kInliningEnabled | + CompilationInfo::kContextSpecializing | + CompilationInfo::kTypingEnabled); + + InstallAssertInlineCountHelper(CcTest::isolate()); + T.CheckCall(T.true_value(), T.Val(12), T.Val(14)); +} + + TEST(InlineSurplusArguments) { + FLAG_turbo_deoptimization = true; FunctionTester T( "(function () {" "var x = 42;" - "function foo(s) { AssertStackDepth(1); return x + s; };" + "function foo(s) { AssertInlineCount(2); return x + s; };" "function bar(s,t) { return foo(s,t,13); };" "return bar;" "})();", @@ -129,32 +194,56 @@ TEST(InlineSurplusArguments) { CompilationInfo::kContextSpecializing | CompilationInfo::kTypingEnabled); - InstallAssertStackDepthHelper(CcTest::isolate()); + InstallAssertInlineCountHelper(CcTest::isolate()); T.CheckCall(T.Val(42 + 12), T.Val(12), T.undefined()); } +TEST(InlineSurplusArgumentsDeopt) { + FLAG_turbo_deoptimization = true; + FunctionTester T( + "(function () {" + "function foo(s) { AssertInlineCount(2); %DeoptimizeFunction(bar); " + "return baz(); };" + "function bar() { return foo(13, 14, 15); };" + "function baz() { return foo.arguments.length == 3 && " + " foo.arguments[0] == 13 && " + " foo.arguments[1] == 14 && " + " foo.arguments[2] == 15; }" + "return bar;" + "})();", + CompilationInfo::kInliningEnabled | + CompilationInfo::kContextSpecializing | + CompilationInfo::kTypingEnabled); + + InstallAssertInlineCountHelper(CcTest::isolate()); + T.CheckCall(T.true_value(), T.Val(12), T.Val(14)); +} + + TEST(InlineTwice) { + FLAG_turbo_deoptimization = true; FunctionTester T( "(function () {" "var x = 42;" - "function bar(s) { AssertStackDepth(1); return x + s; };" + "function bar(s) { AssertInlineCount(2); return x + s; };" "return (function (s,t) { return bar(s) + bar(t); });" "})();", CompilationInfo::kInliningEnabled | CompilationInfo::kContextSpecializing | CompilationInfo::kTypingEnabled); - InstallAssertStackDepthHelper(CcTest::isolate()); + InstallAssertInlineCountHelper(CcTest::isolate()); T.CheckCall(T.Val(2 * 42 + 12 + 4), T.Val(12), T.Val(4)); } TEST(InlineTwiceDependent) { + FLAG_turbo_deoptimization = true; FunctionTester T( "(function () {" "var x = 42;" - "function foo(s) { AssertStackDepth(1); return x + s; };" + "function foo(s) { AssertInlineCount(2); return x + s; };" "function bar(s,t) { return foo(foo(s)); };" "return bar;" "})();", @@ -162,16 +251,17 @@ TEST(InlineTwiceDependent) { CompilationInfo::kContextSpecializing | CompilationInfo::kTypingEnabled); - InstallAssertStackDepthHelper(CcTest::isolate()); + InstallAssertInlineCountHelper(CcTest::isolate()); T.CheckCall(T.Val(42 + 42 + 12), T.Val(12), T.Val(4)); } TEST(InlineTwiceDependentDiamond) { + FLAG_turbo_deoptimization = true; FunctionTester T( "(function () {" "var x = 41;" - "function foo(s) { AssertStackDepth(1); if (s % 2 == 0) {" + "function foo(s) { AssertInlineCount(2); if (s % 2 == 0) {" " return x - s } else { return x + s; } };" "function bar(s,t) { return foo(foo(s)); };" "return bar;" @@ -180,16 +270,17 @@ TEST(InlineTwiceDependentDiamond) { CompilationInfo::kContextSpecializing | CompilationInfo::kTypingEnabled); - InstallAssertStackDepthHelper(CcTest::isolate()); + InstallAssertInlineCountHelper(CcTest::isolate()); T.CheckCall(T.Val(-11), T.Val(11), T.Val(4)); } TEST(InlineTwiceDependentDiamondDifferent) { + FLAG_turbo_deoptimization = true; FunctionTester T( "(function () {" "var x = 41;" - "function foo(s,t) { AssertStackDepth(1); if (s % 2 == 0) {" + "function foo(s,t) { AssertInlineCount(2); if (s % 2 == 0) {" " return x - s * t } else { return x + s * t; } };" "function bar(s,t) { return foo(foo(s, 3), 5); };" "return bar;" @@ -198,16 +289,17 @@ TEST(InlineTwiceDependentDiamondDifferent) { CompilationInfo::kContextSpecializing | CompilationInfo::kTypingEnabled); - InstallAssertStackDepthHelper(CcTest::isolate()); + InstallAssertInlineCountHelper(CcTest::isolate()); T.CheckCall(T.Val(-329), T.Val(11), T.Val(4)); } TEST(InlineLoop) { + FLAG_turbo_deoptimization = true; FunctionTester T( "(function () {" "var x = 41;" - "function foo(s) { AssertStackDepth(1); while (s > 0) {" + "function foo(s) { AssertInlineCount(2); while (s > 0) {" " s = s - 1; }; return s; };" "function bar(s,t) { return foo(foo(s)); };" "return bar;" @@ -216,12 +308,13 @@ TEST(InlineLoop) { CompilationInfo::kContextSpecializing | CompilationInfo::kTypingEnabled); - InstallAssertStackDepthHelper(CcTest::isolate()); + InstallAssertInlineCountHelper(CcTest::isolate()); T.CheckCall(T.Val(0.0), T.Val(11), T.Val(4)); } TEST(InlineStrictIntoNonStrict) { + FLAG_turbo_deoptimization = true; FunctionTester T( "(function () {" "var x = Object.create({}, { y: { value:42, writable:false } });" @@ -234,12 +327,13 @@ TEST(InlineStrictIntoNonStrict) { CompilationInfo::kContextSpecializing | CompilationInfo::kTypingEnabled); - InstallAssertStackDepthHelper(CcTest::isolate()); + InstallAssertInlineCountHelper(CcTest::isolate()); T.CheckThrows(T.undefined(), T.undefined()); } TEST(InlineNonStrictIntoStrict) { + FLAG_turbo_deoptimization = true; FunctionTester T( "(function () {" "var x = Object.create({}, { y: { value:42, writable:false } });" @@ -251,7 +345,7 @@ TEST(InlineNonStrictIntoStrict) { CompilationInfo::kContextSpecializing | CompilationInfo::kTypingEnabled); - InstallAssertStackDepthHelper(CcTest::isolate()); + InstallAssertInlineCountHelper(CcTest::isolate()); T.CheckCall(T.Val(42), T.undefined(), T.undefined()); } -- 2.7.4