From b7dc9c580a274c29622a7d7dcaf047a677c2e47d Mon Sep 17 00:00:00 2001 From: jarin Date: Thu, 19 Mar 2015 07:00:28 -0700 Subject: [PATCH] [turbofan] Remember types for deoptimization during simplified lowering. With this change, we remember the types of frame state inputs (in a new operator, called TypedStateValues). Instead of inferring the value types when building translations, we used the recorded types. The original approach was not reliable because the passes after simplified lowering can change node types, and this in turn confuses the translation builder. BUG=chromium:468727 LOG=n R=bmeurer@chromium.org Review URL: https://codereview.chromium.org/1015423002 Cr-Commit-Position: refs/heads/master@{#27310} --- src/compiler/code-generator.cc | 18 +- src/compiler/common-operator.cc | 9 + src/compiler/common-operator.h | 1 + src/compiler/instruction-selector.cc | 172 ++---------------- src/compiler/instruction-selector.h | 1 - src/compiler/liveness-analyzer.cc | 4 +- src/compiler/opcodes.h | 1 + src/compiler/simplified-lowering.cc | 24 ++- src/compiler/state-values-utils.cc | 27 ++- src/compiler/state-values-utils.h | 9 +- src/compiler/typer.cc | 5 + src/compiler/verifier.cc | 1 + test/cctest/compiler/test-codegen-deopt.cc | 20 +- test/mjsunit/compiler/regress-468727.js | 16 ++ .../compiler/instruction-selector-unittest.cc | 46 +++-- .../compiler/liveness-analyzer-unittest.cc | 12 +- .../compiler/state-values-utils-unittest.cc | 14 +- 17 files changed, 172 insertions(+), 208 deletions(-) create mode 100644 test/mjsunit/compiler/regress-468727.js diff --git a/src/compiler/code-generator.cc b/src/compiler/code-generator.cc index e88eafd3e..7e5da3c19 100644 --- a/src/compiler/code-generator.cc +++ b/src/compiler/code-generator.cc @@ -509,8 +509,10 @@ void CodeGenerator::AddTranslationForOperand(Translation* translation, InstructionOperand* op, MachineType type) { if (op->IsStackSlot()) { - if (type == kMachBool || type == kMachInt32 || type == kMachInt8 || - type == kMachInt16) { + // TODO(jarin) kMachBool and kRepBit should materialize true and false + // rather than creating an int value. + if (type == kMachBool || type == kRepBit || type == kMachInt32 || + type == kMachInt8 || type == kMachInt16) { translation->StoreInt32StackSlot(op->index()); } else if (type == kMachUint32 || type == kMachUint16 || type == kMachUint8) { @@ -525,8 +527,10 @@ void CodeGenerator::AddTranslationForOperand(Translation* translation, translation->StoreDoubleStackSlot(op->index()); } else if (op->IsRegister()) { InstructionOperandConverter converter(this, instr); - if (type == kMachBool || type == kMachInt32 || type == kMachInt8 || - type == kMachInt16) { + // TODO(jarin) kMachBool and kRepBit should materialize true and false + // rather than creating an int value. + if (type == kMachBool || type == kRepBit || type == kMachInt32 || + type == kMachInt8 || type == kMachInt16) { translation->StoreInt32Register(converter.ToRegister(op)); } else if (type == kMachUint32 || type == kMachUint16 || type == kMachUint8) { @@ -546,12 +550,14 @@ void CodeGenerator::AddTranslationForOperand(Translation* translation, Handle constant_object; switch (constant.type()) { case Constant::kInt32: - DCHECK(type == kMachInt32 || type == kMachUint32); + DCHECK(type == kMachInt32 || type == kMachUint32 || type == kRepBit); constant_object = isolate()->factory()->NewNumberFromInt(constant.ToInt32()); break; case Constant::kFloat64: - DCHECK(type == kMachFloat64 || type == kMachAnyTagged); + DCHECK(type == kMachFloat64 || type == kMachAnyTagged || + type == kRepTagged || type == (kTypeInt32 | kRepTagged) || + type == (kTypeUint32 | kRepTagged)); constant_object = isolate()->factory()->NewNumber(constant.ToFloat64()); break; case Constant::kHeapObject: diff --git a/src/compiler/common-operator.cc b/src/compiler/common-operator.cc index 9cc30d27b..75f353c7f 100644 --- a/src/compiler/common-operator.cc +++ b/src/compiler/common-operator.cc @@ -604,6 +604,15 @@ const Operator* CommonOperatorBuilder::StateValues(int arguments) { } +const Operator* CommonOperatorBuilder::TypedStateValues( + const ZoneVector* types) { + return new (zone()) Operator1*>( // -- + IrOpcode::kTypedStateValues, Operator::kPure, // opcode + "TypedStateValues", // name + static_cast(types->size()), 0, 0, 1, 0, 0, types); // counts +} + + const Operator* CommonOperatorBuilder::FrameState( FrameStateType type, BailoutId bailout_id, OutputFrameStateCombine state_combine, MaybeHandle jsfunction) { diff --git a/src/compiler/common-operator.h b/src/compiler/common-operator.h index f28ea8b51..23d06eaa9 100644 --- a/src/compiler/common-operator.h +++ b/src/compiler/common-operator.h @@ -205,6 +205,7 @@ class CommonOperatorBuilder FINAL : public ZoneObject { const Operator* ValueEffect(int arguments); const Operator* Finish(int arguments); const Operator* StateValues(int arguments); + const Operator* TypedStateValues(const ZoneVector* types); const Operator* FrameState( FrameStateType type, BailoutId bailout_id, OutputFrameStateCombine state_combine, diff --git a/src/compiler/instruction-selector.cc b/src/compiler/instruction-selector.cc index 11d52cfef..0d0314dda 100644 --- a/src/compiler/instruction-selector.cc +++ b/src/compiler/instruction-selector.cc @@ -574,147 +574,6 @@ void InstructionSelector::VisitControl(BasicBlock* block) { } -MachineType InstructionSelector::GetMachineType(Node* node) { - DCHECK_NOT_NULL(schedule()->block(node)); // should only use scheduled nodes. - switch (node->opcode()) { - case IrOpcode::kStart: - case IrOpcode::kLoop: - case IrOpcode::kEnd: - case IrOpcode::kBranch: - case IrOpcode::kIfTrue: - case IrOpcode::kIfFalse: - case IrOpcode::kSwitch: - case IrOpcode::kIfValue: - case IrOpcode::kIfDefault: - case IrOpcode::kEffectPhi: - case IrOpcode::kEffectSet: - case IrOpcode::kMerge: - // No code needed for these graph artifacts. - return kMachNone; - case IrOpcode::kFinish: - return kMachAnyTagged; - case IrOpcode::kParameter: - return linkage()->GetParameterType(OpParameter(node)); - case IrOpcode::kOsrValue: - return kMachAnyTagged; - case IrOpcode::kPhi: - return OpParameter(node); - case IrOpcode::kProjection: - // TODO(jarin) Really project from outputs. - return kMachAnyTagged; - case IrOpcode::kInt32Constant: - return kMachInt32; - case IrOpcode::kInt64Constant: - return kMachInt64; - case IrOpcode::kExternalConstant: - return kMachPtr; - case IrOpcode::kFloat64Constant: - return kMachFloat64; - case IrOpcode::kHeapConstant: - case IrOpcode::kNumberConstant: - return kMachAnyTagged; - case IrOpcode::kCall: - return kMachAnyTagged; - case IrOpcode::kFrameState: - case IrOpcode::kStateValues: - return kMachNone; - case IrOpcode::kLoad: - return OpParameter(node); - case IrOpcode::kStore: - return kMachNone; - case IrOpcode::kCheckedLoad: - return OpParameter(node); - case IrOpcode::kCheckedStore: - return kMachNone; - case IrOpcode::kWord32And: - case IrOpcode::kWord32Or: - case IrOpcode::kWord32Xor: - case IrOpcode::kWord32Shl: - case IrOpcode::kWord32Shr: - case IrOpcode::kWord32Sar: - case IrOpcode::kWord32Ror: - return kMachInt32; - case IrOpcode::kWord32Equal: - return kMachBool; - case IrOpcode::kWord64And: - case IrOpcode::kWord64Or: - case IrOpcode::kWord64Xor: - case IrOpcode::kWord64Shl: - case IrOpcode::kWord64Shr: - case IrOpcode::kWord64Sar: - case IrOpcode::kWord64Ror: - return kMachInt64; - case IrOpcode::kWord64Equal: - return kMachBool; - case IrOpcode::kInt32Add: - case IrOpcode::kInt32AddWithOverflow: - case IrOpcode::kInt32Sub: - case IrOpcode::kInt32SubWithOverflow: - case IrOpcode::kInt32Mul: - case IrOpcode::kInt32Div: - case IrOpcode::kInt32Mod: - return kMachInt32; - case IrOpcode::kInt32LessThan: - case IrOpcode::kInt32LessThanOrEqual: - case IrOpcode::kUint32LessThan: - case IrOpcode::kUint32LessThanOrEqual: - return kMachBool; - case IrOpcode::kInt64Add: - case IrOpcode::kInt64Sub: - case IrOpcode::kInt64Mul: - case IrOpcode::kInt64Div: - case IrOpcode::kInt64Mod: - return kMachInt64; - case IrOpcode::kInt64LessThan: - case IrOpcode::kInt64LessThanOrEqual: - return kMachBool; - case IrOpcode::kChangeFloat32ToFloat64: - case IrOpcode::kChangeInt32ToFloat64: - case IrOpcode::kChangeUint32ToFloat64: - return kMachFloat64; - case IrOpcode::kChangeFloat64ToInt32: - return kMachInt32; - case IrOpcode::kChangeFloat64ToUint32: - return kMachUint32; - case IrOpcode::kChangeInt32ToInt64: - return kMachInt64; - case IrOpcode::kChangeUint32ToUint64: - return kMachUint64; - case IrOpcode::kTruncateFloat64ToFloat32: - return kMachFloat32; - case IrOpcode::kTruncateFloat64ToInt32: - case IrOpcode::kTruncateInt64ToInt32: - return kMachInt32; - case IrOpcode::kFloat64Add: - case IrOpcode::kFloat64Sub: - case IrOpcode::kFloat64Mul: - case IrOpcode::kFloat64Div: - case IrOpcode::kFloat64Mod: - case IrOpcode::kFloat64Max: - case IrOpcode::kFloat64Min: - case IrOpcode::kFloat64Sqrt: - case IrOpcode::kFloat64RoundDown: - case IrOpcode::kFloat64RoundTruncate: - case IrOpcode::kFloat64RoundTiesAway: - return kMachFloat64; - case IrOpcode::kFloat64Equal: - case IrOpcode::kFloat64LessThan: - case IrOpcode::kFloat64LessThanOrEqual: - return kMachBool; - case IrOpcode::kFloat64ExtractLowWord32: - case IrOpcode::kFloat64ExtractHighWord32: - return kMachInt32; - case IrOpcode::kFloat64InsertLowWord32: - case IrOpcode::kFloat64InsertHighWord32: - return kMachFloat64; - default: - V8_Fatal(__FILE__, __LINE__, "Unexpected operator #%d:%s @ node #%d", - node->opcode(), node->op()->mnemonic(), node->id()); - } - return kMachNone; -} - - void InstructionSelector::VisitNode(Node* node) { DCHECK_NOT_NULL(schedule()->block(node)); // should only use scheduled nodes. SourcePosition source_position = source_positions_->GetSourcePosition(node); @@ -1149,9 +1008,9 @@ FrameStateDescriptor* InstructionSelector::GetFrameStateDescriptor( Node* state) { DCHECK(state->opcode() == IrOpcode::kFrameState); DCHECK_EQ(5, state->InputCount()); - DCHECK_EQ(IrOpcode::kStateValues, state->InputAt(0)->opcode()); - DCHECK_EQ(IrOpcode::kStateValues, state->InputAt(1)->opcode()); - DCHECK_EQ(IrOpcode::kStateValues, state->InputAt(2)->opcode()); + DCHECK_EQ(IrOpcode::kTypedStateValues, state->InputAt(0)->opcode()); + DCHECK_EQ(IrOpcode::kTypedStateValues, state->InputAt(1)->opcode()); + DCHECK_EQ(IrOpcode::kTypedStateValues, state->InputAt(2)->opcode()); FrameStateCallInfo state_info = OpParameter(state); int parameters = @@ -1197,9 +1056,9 @@ void InstructionSelector::AddFrameStateInputs( Node* stack = state->InputAt(2); Node* context = state->InputAt(3); - DCHECK_EQ(IrOpcode::kStateValues, parameters->op()->opcode()); - DCHECK_EQ(IrOpcode::kStateValues, locals->op()->opcode()); - DCHECK_EQ(IrOpcode::kStateValues, stack->op()->opcode()); + DCHECK_EQ(IrOpcode::kTypedStateValues, parameters->op()->opcode()); + DCHECK_EQ(IrOpcode::kTypedStateValues, locals->op()->opcode()); + DCHECK_EQ(IrOpcode::kTypedStateValues, stack->op()->opcode()); DCHECK_EQ(descriptor->parameters_count(), StateValuesAccess(parameters).size()); @@ -1211,21 +1070,22 @@ void InstructionSelector::AddFrameStateInputs( OperandGenerator g(this); size_t value_index = 0; - for (Node* input_node : StateValuesAccess(parameters)) { - inputs->push_back(UseOrImmediate(&g, input_node)); - descriptor->SetType(value_index++, GetMachineType(input_node)); + for (StateValuesAccess::TypedNode input_node : + StateValuesAccess(parameters)) { + inputs->push_back(UseOrImmediate(&g, input_node.node)); + descriptor->SetType(value_index++, input_node.type); } if (descriptor->HasContext()) { inputs->push_back(UseOrImmediate(&g, context)); descriptor->SetType(value_index++, kMachAnyTagged); } - for (Node* input_node : StateValuesAccess(locals)) { - inputs->push_back(UseOrImmediate(&g, input_node)); - descriptor->SetType(value_index++, GetMachineType(input_node)); + for (StateValuesAccess::TypedNode input_node : StateValuesAccess(locals)) { + inputs->push_back(UseOrImmediate(&g, input_node.node)); + descriptor->SetType(value_index++, input_node.type); } - for (Node* input_node : StateValuesAccess(stack)) { - inputs->push_back(UseOrImmediate(&g, input_node)); - descriptor->SetType(value_index++, GetMachineType(input_node)); + for (StateValuesAccess::TypedNode input_node : StateValuesAccess(stack)) { + inputs->push_back(UseOrImmediate(&g, input_node.node)); + descriptor->SetType(value_index++, input_node.type); } DCHECK(value_index == descriptor->GetSize()); } diff --git a/src/compiler/instruction-selector.h b/src/compiler/instruction-selector.h index 92979beb8..937ed4db3 100644 --- a/src/compiler/instruction-selector.h +++ b/src/compiler/instruction-selector.h @@ -173,7 +173,6 @@ class InstructionSelector FINAL { FrameStateDescriptor* GetFrameStateDescriptor(Node* node); void AddFrameStateInputs(Node* state, InstructionOperandVector* inputs, FrameStateDescriptor* descriptor); - MachineType GetMachineType(Node* node); // =========================================================================== // ============= Architecture-specific graph covering methods. =============== diff --git a/src/compiler/liveness-analyzer.cc b/src/compiler/liveness-analyzer.cc index 8aeb8d5cb..301106d1c 100644 --- a/src/compiler/liveness-analyzer.cc +++ b/src/compiler/liveness-analyzer.cc @@ -142,12 +142,12 @@ void NonLiveFrameStateSlotReplacer::ClearNonLiveFrameStateSlots( Node* NonLiveFrameStateSlotReplacer::ClearNonLiveStateValues( Node* values, BitVector* liveness) { DCHECK(inputs_buffer_.empty()); - for (Node* node : StateValuesAccess(values)) { + for (StateValuesAccess::TypedNode node : StateValuesAccess(values)) { // Index of the next variable is its furure index in the inputs buffer, // i.e., the buffer's size. int var = static_cast(inputs_buffer_.size()); bool live = liveness->Contains(var) || permanently_live_.Contains(var); - inputs_buffer_.push_back(live ? node : replacement_node_); + inputs_buffer_.push_back(live ? node.node : replacement_node_); } Node* result = state_values_cache()->GetNodeForValues( inputs_buffer_.empty() ? nullptr : &(inputs_buffer_.front()), diff --git a/src/compiler/opcodes.h b/src/compiler/opcodes.h index 014025029..9114c8d13 100644 --- a/src/compiler/opcodes.h +++ b/src/compiler/opcodes.h @@ -48,6 +48,7 @@ V(Finish) \ V(FrameState) \ V(StateValues) \ + V(TypedStateValues) \ V(Call) \ V(Parameter) \ V(OsrValue) \ diff --git a/src/compiler/simplified-lowering.cc b/src/compiler/simplified-lowering.cc index 19aea9f63..ef65c9bc7 100644 --- a/src/compiler/simplified-lowering.cc +++ b/src/compiler/simplified-lowering.cc @@ -424,6 +424,25 @@ class RepresentationSelector { } } + void VisitStateValues(Node* node) { + if (phase_ == PROPAGATE) { + for (int i = 0; i < node->InputCount(); i++) { + Enqueue(node->InputAt(i), kTypeAny); + } + } else { + Zone* zone = jsgraph_->zone(); + ZoneVector* types = + new (zone->New(sizeof(ZoneVector))) + ZoneVector(node->InputCount(), zone); + for (int i = 0; i < node->InputCount(); i++) { + MachineTypeUnion input_type = GetInfo(node->InputAt(i))->output; + (*types)[i] = static_cast(input_type); + } + node->set_op(jsgraph_->common()->TypedStateValues(types)); + } + SetOutput(node, kMachAnyTagged); + } + const Operator* Int32Op(Node* node) { return changer_->Int32OperatorFor(node->opcode()); } @@ -1021,10 +1040,7 @@ class RepresentationSelector { case IrOpcode::kLoadStackPointer: return VisitLeaf(node, kMachPtr); case IrOpcode::kStateValues: - for (int i = 0; i < node->InputCount(); i++) { - ProcessInput(node, i, kTypeAny); - } - SetOutput(node, kMachAnyTagged); + VisitStateValues(node); break; default: VisitInputs(node); diff --git a/src/compiler/state-values-utils.cc b/src/compiler/state-values-utils.cc index 2d643d78a..2c7d0edd7 100644 --- a/src/compiler/state-values-utils.cc +++ b/src/compiler/state-values-utils.cc @@ -173,6 +173,7 @@ Node* StateValuesCache::GetNodeForValues(Node** values, size_t count) { #if DEBUG for (size_t i = 0; i < count; i++) { DCHECK_NE(values[i]->opcode(), IrOpcode::kStateValues); + DCHECK_NE(values[i]->opcode(), IrOpcode::kTypedStateValues); } #endif if (count == 0) { @@ -190,7 +191,8 @@ Node* StateValuesCache::GetNodeForValues(Node** values, size_t count) { Node* tree = BuildTree(&it, height); // If the 'tree' is a single node, equip it with a StateValues wrapper. - if (tree->opcode() != IrOpcode::kStateValues) { + if (tree->opcode() != IrOpcode::kStateValues && + tree->opcode() != IrOpcode::kTypedStateValues) { tree = GetValuesNodeFromCache(&tree, 1); } @@ -249,7 +251,8 @@ void StateValuesAccess::iterator::Advance() { return; } Top()->index++; - } else if (node->InputAt(index)->opcode() == IrOpcode::kStateValues) { + } else if (node->InputAt(index)->opcode() == IrOpcode::kStateValues || + node->InputAt(index)->opcode() == IrOpcode::kTypedStateValues) { // Nested state, we need to push to the stack. Push(node->InputAt(index)); } else { @@ -265,6 +268,19 @@ Node* StateValuesAccess::iterator::node() { } +MachineType StateValuesAccess::iterator::type() { + Node* state = Top()->node; + if (state->opcode() == IrOpcode::kStateValues) { + return kMachAnyTagged; + } else { + DCHECK_EQ(IrOpcode::kTypedStateValues, state->opcode()); + const ZoneVector* types = + OpParameter*>(state); + return (*types)[Top()->index]; + } +} + + bool StateValuesAccess::iterator::operator!=(iterator& other) { // We only allow comparison with end(). CHECK(other.done()); @@ -278,13 +294,16 @@ StateValuesAccess::iterator& StateValuesAccess::iterator::operator++() { } -Node* StateValuesAccess::iterator::operator*() { return node(); } +StateValuesAccess::TypedNode StateValuesAccess::iterator::operator*() { + return TypedNode(node(), type()); +} size_t StateValuesAccess::size() { size_t count = 0; for (int i = 0; i < node_->InputCount(); i++) { - if (node_->InputAt(i)->opcode() == IrOpcode::kStateValues) { + if (node_->InputAt(i)->opcode() == IrOpcode::kStateValues || + node_->InputAt(i)->opcode() == IrOpcode::kTypedStateValues) { count += StateValuesAccess(node_->InputAt(i)).size(); } else { count++; diff --git a/src/compiler/state-values-utils.h b/src/compiler/state-values-utils.h index ff7e9dd7c..79550bd3f 100644 --- a/src/compiler/state-values-utils.h +++ b/src/compiler/state-values-utils.h @@ -62,12 +62,18 @@ class StateValuesCache { class StateValuesAccess { public: + struct TypedNode { + Node* node; + MachineType type; + TypedNode(Node* node, MachineType type) : node(node), type(type) {} + }; + class iterator { public: // Bare minimum of operators needed for range iteration. bool operator!=(iterator& other); iterator& operator++(); - Node* operator*(); + TypedNode operator*(); private: friend class StateValuesAccess; @@ -76,6 +82,7 @@ class StateValuesAccess { explicit iterator(Node* node); Node* node(); + MachineType type(); bool done(); void Advance(); diff --git a/src/compiler/typer.cc b/src/compiler/typer.cc index a36d6896f..67e2c55b2 100644 --- a/src/compiler/typer.cc +++ b/src/compiler/typer.cc @@ -716,6 +716,11 @@ Bounds Typer::Visitor::TypeStateValues(Node* node) { } +Bounds Typer::Visitor::TypeTypedStateValues(Node* node) { + return Bounds(Type::None(zone()), Type::Internal(zone())); +} + + Bounds Typer::Visitor::TypeCall(Node* node) { return Bounds::Unbounded(zone()); } diff --git a/src/compiler/verifier.cc b/src/compiler/verifier.cc index 534b68441..3cc6424c6 100644 --- a/src/compiler/verifier.cc +++ b/src/compiler/verifier.cc @@ -427,6 +427,7 @@ void Verifier::Visitor::Check(Node* node) { // TODO(jarin): what are the constraints on these? break; case IrOpcode::kStateValues: + case IrOpcode::kTypedStateValues: // TODO(jarin): what are the constraints on these? break; case IrOpcode::kCall: diff --git a/test/cctest/compiler/test-codegen-deopt.cc b/test/cctest/compiler/test-codegen-deopt.cc index 9c12cb2db..0b5930821 100644 --- a/test/cctest/compiler/test-codegen-deopt.cc +++ b/test/cctest/compiler/test-codegen-deopt.cc @@ -46,7 +46,9 @@ class DeoptCodegenTester { function(NewFunction(src)), parse_info(scope->main_zone(), function), info(&parse_info), - bailout_id(-1) { + bailout_id(-1), + tagged_type(1, kMachAnyTagged, zone()), + empty_types(zone()) { CHECK(Parser::ParseStatic(&parse_info)); info.SetOptimizing(BailoutId::None(), Handle(function->code())); CHECK(Compiler::Analyze(&parse_info)); @@ -83,6 +85,8 @@ class DeoptCodegenTester { Handle result_code; TestInstrSeq* code; Graph* graph; + ZoneVector tagged_type; + ZoneVector empty_types; }; @@ -120,9 +124,10 @@ class TrivialDeoptCodegenTester : public DeoptCodegenTester { m.NewNode(common.HeapConstant(caller_context_constant)); bailout_id = GetCallBailoutId(); - Node* parameters = m.NewNode(common.StateValues(1), m.UndefinedConstant()); - Node* locals = m.NewNode(common.StateValues(0)); - Node* stack = m.NewNode(common.StateValues(0)); + Node* parameters = + m.NewNode(common.TypedStateValues(&tagged_type), m.UndefinedConstant()); + 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, @@ -235,9 +240,10 @@ class TrivialRuntimeDeoptCodegenTester : public DeoptCodegenTester { Node* context_node = m.NewNode(common.HeapConstant(context_constant)); bailout_id = GetCallBailoutId(); - Node* parameters = m.NewNode(common.StateValues(1), m.UndefinedConstant()); - Node* locals = m.NewNode(common.StateValues(0)); - Node* stack = m.NewNode(common.StateValues(0)); + Node* parameters = + m.NewNode(common.TypedStateValues(&tagged_type), m.UndefinedConstant()); + 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, diff --git a/test/mjsunit/compiler/regress-468727.js b/test/mjsunit/compiler/regress-468727.js new file mode 100644 index 000000000..a69efe5a5 --- /dev/null +++ b/test/mjsunit/compiler/regress-468727.js @@ -0,0 +1,16 @@ +// Copyright 2015 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --noanalyze-environment-liveness + +function f() { + var __v_7 = -126 - __v_3; + var __v_17 = ((__v_15 & __v_14) != 4) | 16; + if (__v_17) { + var __v_11 = 1 << __v_7; + } + __v_12 >>= __v_3; +} + +assertThrows(f); diff --git a/test/unittests/compiler/instruction-selector-unittest.cc b/test/unittests/compiler/instruction-selector-unittest.cc index 10c457d69..e52580dc6 100644 --- a/test/unittests/compiler/instruction-selector-unittest.cc +++ b/test/unittests/compiler/instruction-selector-unittest.cc @@ -347,9 +347,13 @@ TARGET_TEST_F(InstructionSelectorTest, CallJSFunctionWithDeopt) { Node* receiver = m.Parameter(1); Node* context = m.Parameter(2); - Node* parameters = m.NewNode(m.common()->StateValues(1), m.Int32Constant(1)); - Node* locals = m.NewNode(m.common()->StateValues(0)); - Node* stack = m.NewNode(m.common()->StateValues(0)); + ZoneVector int32_type(1, kMachInt32, zone()); + ZoneVector empty_types(zone()); + + Node* parameters = + m.NewNode(m.common()->TypedStateValues(&int32_type), m.Int32Constant(1)); + Node* locals = m.NewNode(m.common()->TypedStateValues(&empty_types)); + Node* stack = m.NewNode(m.common()->TypedStateValues(&empty_types)); Node* context_dummy = m.Int32Constant(0); Node* state_node = m.NewNode( @@ -387,10 +391,17 @@ TARGET_TEST_F(InstructionSelectorTest, CallFunctionStubWithDeopt) { Node* receiver = m.Parameter(1); Node* context = m.Int32Constant(1); // Context is ignored. + ZoneVector int32_type(1, kMachInt32, zone()); + ZoneVector float64_type(1, kMachFloat64, zone()); + ZoneVector tagged_type(1, kMachAnyTagged, zone()); + // Build frame state for the state before the call. - Node* parameters = m.NewNode(m.common()->StateValues(1), m.Int32Constant(43)); - Node* locals = m.NewNode(m.common()->StateValues(1), m.Float64Constant(0.5)); - Node* stack = m.NewNode(m.common()->StateValues(1), m.UndefinedConstant()); + Node* parameters = + m.NewNode(m.common()->TypedStateValues(&int32_type), m.Int32Constant(43)); + Node* locals = m.NewNode(m.common()->TypedStateValues(&float64_type), + m.Float64Constant(0.5)); + Node* stack = m.NewNode(m.common()->TypedStateValues(&tagged_type), + m.UndefinedConstant()); Node* context_sentinel = m.Int32Constant(0); Node* frame_state_before = m.NewNode( @@ -473,10 +484,17 @@ TARGET_TEST_F(InstructionSelectorTest, Node* receiver = m.Parameter(1); Node* context = m.Int32Constant(66); + ZoneVector int32_type(1, kMachInt32, zone()); + ZoneVector int32x2_type(2, kMachInt32, zone()); + ZoneVector float64_type(1, kMachFloat64, zone()); + // Build frame state for the state before the call. - 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* parameters = + m.NewNode(m.common()->TypedStateValues(&int32_type), m.Int32Constant(63)); + Node* locals = + 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()), @@ -484,11 +502,11 @@ TARGET_TEST_F(InstructionSelectorTest, 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.Float64Constant(0.25)); - Node* stack2 = m.NewNode(m.common()->StateValues(2), m.Int32Constant(44), - m.Int32Constant(45)); + m.NewNode(m.common()->TypedStateValues(&int32_type), m.Int32Constant(43)); + Node* locals2 = m.NewNode(m.common()->TypedStateValues(&float64_type), + m.Float64Constant(0.25)); + Node* stack2 = m.NewNode(m.common()->TypedStateValues(&int32x2_type), + m.Int32Constant(44), m.Int32Constant(45)); Node* frame_state_before = m.NewNode(m.common()->FrameState(JS_FRAME, bailout_id_before, OutputFrameStateCombine::Push()), diff --git a/test/unittests/compiler/liveness-analyzer-unittest.cc b/test/unittests/compiler/liveness-analyzer-unittest.cc index b59c71aeb..f7d0db354 100644 --- a/test/unittests/compiler/liveness-analyzer-unittest.cc +++ b/test/unittests/compiler/liveness-analyzer-unittest.cc @@ -115,15 +115,15 @@ class LivenessAnalysisTest : public GraphTest { return false; } int i = 0; - for (Node* value : locals) { + for (StateValuesAccess::TypedNode value : locals) { if (liveness_[i] == 'L') { StringMatchResultListener value_listener; - if (value == replacement_) { - *listener << "whose local #" << i << " was " << value->opcode() + if (value.node == replacement_) { + *listener << "whose local #" << i << " was " << value.node->opcode() << " but should have been 'undefined'"; return false; } else if (!IsInt32Constant(first_const + i) - .MatchAndExplain(value, &value_listener)) { + .MatchAndExplain(value.node, &value_listener)) { *listener << "whose local #" << i << " does not match"; if (value_listener.str() != "") { *listener << ", " << value_listener.str(); @@ -131,8 +131,8 @@ class LivenessAnalysisTest : public GraphTest { return false; } } else if (liveness_[i] == '.') { - if (value != replacement_) { - *listener << "whose local #" << i << " is " << value + if (value.node != replacement_) { + *listener << "whose local #" << i << " is " << value.node << " but should have been " << replacement_ << " (undefined)"; return false; diff --git a/test/unittests/compiler/state-values-utils-unittest.cc b/test/unittests/compiler/state-values-utils-unittest.cc index 7bcdc5c06..e6f470159 100644 --- a/test/unittests/compiler/state-values-utils-unittest.cc +++ b/test/unittests/compiler/state-values-utils-unittest.cc @@ -32,8 +32,8 @@ TEST_F(StateValuesIteratorTest, SimpleIteration) { } Node* state_values = StateValuesFromVector(&inputs); int i = 0; - for (Node* node : StateValuesAccess(state_values)) { - EXPECT_THAT(node, IsInt32Constant(i)); + for (StateValuesAccess::TypedNode node : StateValuesAccess(state_values)) { + EXPECT_THAT(node.node, IsInt32Constant(i)); i++; } EXPECT_EQ(count, i); @@ -43,7 +43,7 @@ TEST_F(StateValuesIteratorTest, SimpleIteration) { TEST_F(StateValuesIteratorTest, EmptyIteration) { NodeVector inputs(zone()); Node* state_values = StateValuesFromVector(&inputs); - for (Node* node : StateValuesAccess(state_values)) { + for (auto node : StateValuesAccess(state_values)) { USE(node); FAIL(); } @@ -82,8 +82,8 @@ TEST_F(StateValuesIteratorTest, NestedIteration) { } Node* state_values = StateValuesFromVector(&inputs); int i = 0; - for (Node* node : StateValuesAccess(state_values)) { - EXPECT_THAT(node, IsInt32Constant(i)); + for (StateValuesAccess::TypedNode node : StateValuesAccess(state_values)) { + EXPECT_THAT(node.node, IsInt32Constant(i)); i++; } EXPECT_EQ(count, i); @@ -110,8 +110,8 @@ TEST_F(StateValuesIteratorTest, TreeFromVector) { // Check the tree contents with vector. int i = 0; - for (Node* node : StateValuesAccess(values_node)) { - EXPECT_THAT(node, IsInt32Constant(i)); + for (StateValuesAccess::TypedNode node : StateValuesAccess(values_node)) { + EXPECT_THAT(node.node, IsInt32Constant(i)); i++; } EXPECT_EQ(inputs.size(), static_cast(i)); -- 2.34.1