[turbofan] Remember types for deoptimization during simplified lowering.
authorjarin <jarin@chromium.org>
Thu, 19 Mar 2015 14:00:28 +0000 (07:00 -0700)
committerCommit bot <commit-bot@chromium.org>
Thu, 19 Mar 2015 14:00:33 +0000 (14:00 +0000)
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}

17 files changed:
src/compiler/code-generator.cc
src/compiler/common-operator.cc
src/compiler/common-operator.h
src/compiler/instruction-selector.cc
src/compiler/instruction-selector.h
src/compiler/liveness-analyzer.cc
src/compiler/opcodes.h
src/compiler/simplified-lowering.cc
src/compiler/state-values-utils.cc
src/compiler/state-values-utils.h
src/compiler/typer.cc
src/compiler/verifier.cc
test/cctest/compiler/test-codegen-deopt.cc
test/mjsunit/compiler/regress-468727.js [new file with mode: 0644]
test/unittests/compiler/instruction-selector-unittest.cc
test/unittests/compiler/liveness-analyzer-unittest.cc
test/unittests/compiler/state-values-utils-unittest.cc

index e88eafd3eb099ed9e74f23192eab10d5322ab9f7..7e5da3c19330b75bd358930aa821303c625ceebe 100644 (file)
@@ -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<Object> 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:
index 9cc30d27b6f86a350ca25c61eefed06d5ab52896..75f353c7fa2d3ee2aaac54edf5b02ab725abc7aa 100644 (file)
@@ -604,6 +604,15 @@ const Operator* CommonOperatorBuilder::StateValues(int arguments) {
 }
 
 
+const Operator* CommonOperatorBuilder::TypedStateValues(
+    const ZoneVector<MachineType>* types) {
+  return new (zone()) Operator1<const ZoneVector<MachineType>*>(  // --
+      IrOpcode::kTypedStateValues, Operator::kPure,               // opcode
+      "TypedStateValues",                                         // name
+      static_cast<int>(types->size()), 0, 0, 1, 0, 0, types);     // counts
+}
+
+
 const Operator* CommonOperatorBuilder::FrameState(
     FrameStateType type, BailoutId bailout_id,
     OutputFrameStateCombine state_combine, MaybeHandle<JSFunction> jsfunction) {
index f28ea8b51f298b63225339e9ca9cae853499d7ac..23d06eaa9b73760182e7a6664346470174b604ac 100644 (file)
@@ -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<MachineType>* types);
   const Operator* FrameState(
       FrameStateType type, BailoutId bailout_id,
       OutputFrameStateCombine state_combine,
index 11d52cfeffca53ccb79ba09dd5eb30d75f5d431b..0d0314dda328d26c78b9bf3f5cf6fcd2c38d69c2 100644 (file)
@@ -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<int>(node));
-    case IrOpcode::kOsrValue:
-      return kMachAnyTagged;
-    case IrOpcode::kPhi:
-      return OpParameter<MachineType>(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<LoadRepresentation>(node);
-    case IrOpcode::kStore:
-      return kMachNone;
-    case IrOpcode::kCheckedLoad:
-      return OpParameter<MachineType>(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<FrameStateCallInfo>(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());
 }
index 92979beb8e72c8fa5987c16aa0ae0389104c37a1..937ed4db34f2497686e1f12ed1b50f255c85c108 100644 (file)
@@ -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. ===============
index 8aeb8d5cb7923b38a590400cd31354fa4d0667df..301106d1c3a4d5eff4d6553c8cfd7efafe6e6ab4 100644 (file)
@@ -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<int>(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()),
index 0140250295df1fc5d8840e9920aebf94cdf815fa..9114c8d139f90a5810f1fc1d2cf85c7d4f563dcf 100644 (file)
@@ -48,6 +48,7 @@
   V(Finish)              \
   V(FrameState)          \
   V(StateValues)         \
+  V(TypedStateValues)    \
   V(Call)                \
   V(Parameter)           \
   V(OsrValue)            \
index 19aea9f63446a9c3f3ae9d4b3f13679619b8a7ac..ef65c9bc73e2331b40d563142ce2a8fd477992ff 100644 (file)
@@ -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<MachineType>* types =
+          new (zone->New(sizeof(ZoneVector<MachineType>)))
+              ZoneVector<MachineType>(node->InputCount(), zone);
+      for (int i = 0; i < node->InputCount(); i++) {
+        MachineTypeUnion input_type = GetInfo(node->InputAt(i))->output;
+        (*types)[i] = static_cast<MachineType>(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);
index 2d643d78ab429478da472acbb3b77853e8456c2a..2c7d0edd7a0951d51a2148e9f9baa6d62d172d00 100644 (file)
@@ -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<MachineType>* types =
+        OpParameter<const ZoneVector<MachineType>*>(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++;
index ff7e9dd7c5868ae7b312276657fd4e271b2e9635..79550bd3ffbad0270112765c793a7057cfa11d1a 100644 (file)
@@ -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();
 
index a36d6896f1876953c9c8cc5a25fe21c4f8c4baa5..67e2c55b29aa59c5d4c873f8af238e588753e41d 100644 (file)
@@ -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());
 }
index 534b68441494c30a0ad338edef9328576fdbb533..3cc6424c6c25de1e020f94f623109ff885c211df 100644 (file)
@@ -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:
index 9c12cb2dbde299dfb304a135d9cfacec2cd987f3..0b5930821654b5fc064c376b2499e550a43098b4 100644 (file)
@@ -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<Code>(function->code()));
     CHECK(Compiler::Analyze(&parse_info));
@@ -83,6 +85,8 @@ class DeoptCodegenTester {
   Handle<Code> result_code;
   TestInstrSeq* code;
   Graph* graph;
+  ZoneVector<MachineType> tagged_type;
+  ZoneVector<MachineType> 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 (file)
index 0000000..a69efe5
--- /dev/null
@@ -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);
index 10c457d696e90e6747396a5db0c575fa236795e9..e52580dc649b4f08022e1f2d3b2e7b9178736caf 100644 (file)
@@ -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<MachineType> int32_type(1, kMachInt32, zone());
+  ZoneVector<MachineType> 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<MachineType> int32_type(1, kMachInt32, zone());
+  ZoneVector<MachineType> float64_type(1, kMachFloat64, zone());
+  ZoneVector<MachineType> 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<MachineType> int32_type(1, kMachInt32, zone());
+  ZoneVector<MachineType> int32x2_type(2, kMachInt32, zone());
+  ZoneVector<MachineType> 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()),
index b59c71aeb923c23501af86e82597b92c3109f067..f7d0db354d3c5299554e242b77c87e0a3bb55f69 100644 (file)
@@ -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;
index 7bcdc5c068358479c0c82486bb5367fa3b1f13e2..e6f4701598fd11319b20453a5c00f024a494cf90 100644 (file)
@@ -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<size_t>(i));