Upgrade V8 to version 4.9.385.28
https://chromium.googlesource.com/v8/v8/+/4.9.385.28
FPIIM-449
Change-Id: I4b2e74289d4bf3667f2f3dc8aa2e541f63e26eb4
diff --git a/src/compiler/verifier.cc b/src/compiler/verifier.cc
index 693b414..1a3ef8e 100644
--- a/src/compiler/verifier.cc
+++ b/src/compiler/verifier.cc
@@ -4,23 +4,25 @@
#include "src/compiler/verifier.h"
+#include <algorithm>
#include <deque>
#include <queue>
#include <sstream>
#include <string>
#include "src/bit-vector.h"
-#include "src/compiler/generic-algorithm.h"
-#include "src/compiler/graph-inl.h"
+#include "src/compiler/all-nodes.h"
+#include "src/compiler/common-operator.h"
#include "src/compiler/graph.h"
#include "src/compiler/node.h"
-#include "src/compiler/node-properties-inl.h"
#include "src/compiler/node-properties.h"
#include "src/compiler/opcodes.h"
#include "src/compiler/operator.h"
+#include "src/compiler/operator-properties.h"
#include "src/compiler/schedule.h"
#include "src/compiler/simplified-operator.h"
#include "src/ostreams.h"
+#include "src/types-inl.h"
namespace v8 {
namespace internal {
@@ -28,97 +30,83 @@
static bool IsDefUseChainLinkPresent(Node* def, Node* use) {
- Node::Uses uses = def->uses();
- for (Node::Uses::iterator it = uses.begin(); it != uses.end(); ++it) {
- if (*it == use) return true;
- }
- return false;
+ auto const uses = def->uses();
+ return std::find(uses.begin(), uses.end(), use) != uses.end();
}
static bool IsUseDefChainLinkPresent(Node* def, Node* use) {
- Node::Inputs inputs = use->inputs();
- for (Node::Inputs::iterator it = inputs.begin(); it != inputs.end(); ++it) {
- if (*it == def) return true;
- }
- return false;
+ auto const inputs = use->inputs();
+ return std::find(inputs.begin(), inputs.end(), def) != inputs.end();
}
-class Verifier::Visitor : public NullNodeVisitor {
+class Verifier::Visitor {
public:
Visitor(Zone* z, Typing typed) : zone(z), typing(typed) {}
- // Fulfills the PreNodeCallback interface.
- void Pre(Node* node);
+ void Check(Node* node);
Zone* zone;
Typing typing;
private:
- // TODO(rossberg): Get rid of these once we got rid of NodeProperties.
- Bounds bounds(Node* node) { return NodeProperties::GetBounds(node); }
- Node* ValueInput(Node* node, int i = 0) {
- return NodeProperties::GetValueInput(node, i);
- }
- FieldAccess Field(Node* node) {
- DCHECK(node->opcode() == IrOpcode::kLoadField ||
- node->opcode() == IrOpcode::kStoreField);
- return OpParameter<FieldAccess>(node);
- }
- ElementAccess Element(Node* node) {
- DCHECK(node->opcode() == IrOpcode::kLoadElement ||
- node->opcode() == IrOpcode::kStoreElement);
- return OpParameter<ElementAccess>(node);
- }
void CheckNotTyped(Node* node) {
if (NodeProperties::IsTyped(node)) {
std::ostringstream str;
- str << "TypeError: node #" << node->opcode() << ":"
- << node->op()->mnemonic() << " should never have a type";
- V8_Fatal(__FILE__, __LINE__, str.str().c_str());
+ str << "TypeError: node #" << node->id() << ":" << *node->op()
+ << " should never have a type";
+ FATAL(str.str().c_str());
}
}
void CheckUpperIs(Node* node, Type* type) {
- if (typing == TYPED && !bounds(node).upper->Is(type)) {
+ if (typing == TYPED && !NodeProperties::GetType(node)->Is(type)) {
std::ostringstream str;
- str << "TypeError: node #" << node->opcode() << ":"
- << node->op()->mnemonic() << " upper bound ";
- bounds(node).upper->PrintTo(str);
+ str << "TypeError: node #" << node->id() << ":" << *node->op()
+ << " type ";
+ NodeProperties::GetType(node)->PrintTo(str);
str << " is not ";
type->PrintTo(str);
- V8_Fatal(__FILE__, __LINE__, str.str().c_str());
+ FATAL(str.str().c_str());
}
}
void CheckUpperMaybe(Node* node, Type* type) {
- if (typing == TYPED && !bounds(node).upper->Maybe(type)) {
+ if (typing == TYPED && !NodeProperties::GetType(node)->Maybe(type)) {
std::ostringstream str;
- str << "TypeError: node #" << node->opcode() << ":"
- << node->op()->mnemonic() << " upper bound ";
- bounds(node).upper->PrintTo(str);
+ str << "TypeError: node #" << node->id() << ":" << *node->op()
+ << " type ";
+ NodeProperties::GetType(node)->PrintTo(str);
str << " must intersect ";
type->PrintTo(str);
- V8_Fatal(__FILE__, __LINE__, str.str().c_str());
+ FATAL(str.str().c_str());
}
}
void CheckValueInputIs(Node* node, int i, Type* type) {
- Node* input = ValueInput(node, i);
- if (typing == TYPED && !bounds(input).upper->Is(type)) {
+ Node* input = NodeProperties::GetValueInput(node, i);
+ if (typing == TYPED && !NodeProperties::GetType(input)->Is(type)) {
std::ostringstream str;
- str << "TypeError: node #" << node->opcode() << ":"
- << node->op()->mnemonic() << "(input @" << i << " = "
- << input->opcode() << ":" << input->op()->mnemonic()
- << ") upper bound ";
- bounds(input).upper->PrintTo(str);
+ str << "TypeError: node #" << node->id() << ":" << *node->op()
+ << "(input @" << i << " = " << input->opcode() << ":"
+ << input->op()->mnemonic() << ") type ";
+ NodeProperties::GetType(input)->PrintTo(str);
str << " is not ";
type->PrintTo(str);
- V8_Fatal(__FILE__, __LINE__, str.str().c_str());
+ FATAL(str.str().c_str());
+ }
+ }
+ void CheckOutput(Node* node, Node* use, int count, const char* kind) {
+ if (count <= 0) {
+ std::ostringstream str;
+ str << "GraphError: node #" << node->id() << ":" << *node->op()
+ << " does not produce " << kind << " output used by node #"
+ << use->id() << ":" << *use->op();
+ FATAL(str.str().c_str());
}
}
};
-void Verifier::Visitor::Pre(Node* node) {
+void Verifier::Visitor::Check(Node* node) {
int value_count = node->op()->ValueInputCount();
int context_count = OperatorProperties::GetContextInputCount(node->op());
int frame_state_count =
@@ -132,12 +120,12 @@
CHECK_EQ(input_count, node->InputCount());
// Verify that frame state has been inserted for the nodes that need it.
- if (OperatorProperties::HasFrameStateInput(node->op())) {
- Node* frame_state = NodeProperties::GetFrameStateInput(node);
+ for (int i = 0; i < frame_state_count; i++) {
+ Node* frame_state = NodeProperties::GetFrameStateInput(node, i);
CHECK(frame_state->opcode() == IrOpcode::kFrameState ||
- // kFrameState uses undefined as a sentinel.
+ // kFrameState uses Start as a sentinel.
(node->opcode() == IrOpcode::kFrameState &&
- frame_state->opcode() == IrOpcode::kHeapConstant));
+ frame_state->opcode() == IrOpcode::kStart));
CHECK(IsDefUseChainLinkPresent(frame_state, node));
CHECK(IsUseDefChainLinkPresent(frame_state, node));
}
@@ -145,7 +133,7 @@
// Verify all value inputs actually produce a value.
for (int i = 0; i < value_count; ++i) {
Node* value = NodeProperties::GetValueInput(node, i);
- CHECK(value->op()->ValueOutputCount() > 0);
+ CheckOutput(value, node, value->op()->ValueOutputCount(), "value");
CHECK(IsDefUseChainLinkPresent(value, node));
CHECK(IsUseDefChainLinkPresent(value, node));
}
@@ -153,7 +141,7 @@
// Verify all context inputs are value nodes.
for (int i = 0; i < context_count; ++i) {
Node* context = NodeProperties::GetContextInput(node);
- CHECK(context->op()->ValueOutputCount() > 0);
+ CheckOutput(context, node, context->op()->ValueOutputCount(), "context");
CHECK(IsDefUseChainLinkPresent(context, node));
CHECK(IsUseDefChainLinkPresent(context, node));
}
@@ -161,7 +149,7 @@
// Verify all effect inputs actually have an effect.
for (int i = 0; i < effect_count; ++i) {
Node* effect = NodeProperties::GetEffectInput(node);
- CHECK(effect->op()->EffectOutputCount() > 0);
+ CheckOutput(effect, node, effect->op()->EffectOutputCount(), "effect");
CHECK(IsDefUseChainLinkPresent(effect, node));
CHECK(IsUseDefChainLinkPresent(effect, node));
}
@@ -169,7 +157,7 @@
// Verify all control inputs are control nodes.
for (int i = 0; i < control_count; ++i) {
Node* control = NodeProperties::GetControlInput(node, i);
- CHECK(control->op()->ControlOutputCount() > 0);
+ CheckOutput(control, node, control->op()->ControlOutputCount(), "control");
CHECK(IsDefUseChainLinkPresent(control, node));
CHECK(IsUseDefChainLinkPresent(control, node));
}
@@ -203,17 +191,18 @@
case IrOpcode::kDead:
// Dead is never connected to the graph.
UNREACHABLE();
+ break;
case IrOpcode::kBranch: {
// Branch uses are IfTrue and IfFalse.
- Node::Uses uses = node->uses();
int count_true = 0, count_false = 0;
- for (Node::Uses::iterator it = uses.begin(); it != uses.end(); ++it) {
- CHECK((*it)->opcode() == IrOpcode::kIfTrue ||
- (*it)->opcode() == IrOpcode::kIfFalse);
- if ((*it)->opcode() == IrOpcode::kIfTrue) ++count_true;
- if ((*it)->opcode() == IrOpcode::kIfFalse) ++count_false;
+ for (auto use : node->uses()) {
+ CHECK(use->opcode() == IrOpcode::kIfTrue ||
+ use->opcode() == IrOpcode::kIfFalse);
+ if (use->opcode() == IrOpcode::kIfTrue) ++count_true;
+ if (use->opcode() == IrOpcode::kIfFalse) ++count_false;
}
- CHECK(count_true == 1 && count_false == 1);
+ CHECK_EQ(1, count_true);
+ CHECK_EQ(1, count_false);
// Type is empty.
CheckNotTyped(node);
break;
@@ -225,27 +214,99 @@
// Type is empty.
CheckNotTyped(node);
break;
+ case IrOpcode::kIfSuccess: {
+ // IfSuccess and IfException continuation only on throwing nodes.
+ Node* input = NodeProperties::GetControlInput(node, 0);
+ CHECK(!input->op()->HasProperty(Operator::kNoThrow));
+ // Type is empty.
+ CheckNotTyped(node);
+ break;
+ }
+ case IrOpcode::kIfException: {
+ // IfSuccess and IfException continuation only on throwing nodes.
+ Node* input = NodeProperties::GetControlInput(node, 0);
+ CHECK(!input->op()->HasProperty(Operator::kNoThrow));
+ // Type can be anything.
+ CheckUpperIs(node, Type::Any());
+ break;
+ }
+ case IrOpcode::kSwitch: {
+ // Switch uses are Case and Default.
+ int count_case = 0, count_default = 0;
+ for (auto use : node->uses()) {
+ switch (use->opcode()) {
+ case IrOpcode::kIfValue: {
+ for (auto user : node->uses()) {
+ if (user != use && user->opcode() == IrOpcode::kIfValue) {
+ CHECK_NE(OpParameter<int32_t>(use->op()),
+ OpParameter<int32_t>(user->op()));
+ }
+ }
+ ++count_case;
+ break;
+ }
+ case IrOpcode::kIfDefault: {
+ ++count_default;
+ break;
+ }
+ default: {
+ V8_Fatal(__FILE__, __LINE__, "Switch #%d illegally used by #%d:%s",
+ node->id(), use->id(), use->op()->mnemonic());
+ break;
+ }
+ }
+ }
+ CHECK_EQ(1, count_default);
+ CHECK_EQ(node->op()->ControlOutputCount(), count_case + count_default);
+ // Type is empty.
+ CheckNotTyped(node);
+ break;
+ }
+ case IrOpcode::kIfValue:
+ case IrOpcode::kIfDefault:
+ CHECK_EQ(IrOpcode::kSwitch,
+ NodeProperties::GetControlInput(node)->opcode());
+ // Type is empty.
+ CheckNotTyped(node);
+ break;
case IrOpcode::kLoop:
case IrOpcode::kMerge:
CHECK_EQ(control_count, input_count);
// Type is empty.
CheckNotTyped(node);
break;
+ case IrOpcode::kDeoptimize:
case IrOpcode::kReturn:
- // TODO(rossberg): check successor is End
- // Type is empty.
- CheckNotTyped(node);
- break;
case IrOpcode::kThrow:
- // TODO(rossberg): what are the constraints on these?
+ // Deoptimize, Return and Throw uses are End.
+ for (auto use : node->uses()) {
+ CHECK_EQ(IrOpcode::kEnd, use->opcode());
+ }
// Type is empty.
CheckNotTyped(node);
break;
case IrOpcode::kTerminate:
+ // Terminates take one loop and effect.
+ CHECK_EQ(1, control_count);
+ CHECK_EQ(1, effect_count);
+ CHECK_EQ(2, input_count);
+ CHECK_EQ(IrOpcode::kLoop,
+ NodeProperties::GetControlInput(node)->opcode());
+ // Terminate uses are End.
+ for (auto use : node->uses()) {
+ CHECK_EQ(IrOpcode::kEnd, use->opcode());
+ }
// Type is empty.
CheckNotTyped(node);
+ break;
+ case IrOpcode::kOsrNormalEntry:
+ case IrOpcode::kOsrLoopEntry:
+ // Osr entries take one control and effect.
CHECK_EQ(1, control_count);
- CHECK_EQ(input_count, 1 + effect_count);
+ CHECK_EQ(1, effect_count);
+ CHECK_EQ(2, input_count);
+ // Type is empty.
+ CheckNotTyped(node);
break;
// Common operators
@@ -253,13 +314,13 @@
case IrOpcode::kParameter: {
// Parameters have the start node as inputs.
CHECK_EQ(1, input_count);
- CHECK_EQ(IrOpcode::kStart,
- NodeProperties::GetValueInput(node, 0)->opcode());
// Parameter has an input that produces enough values.
- int index = OpParameter<int>(node);
- Node* input = NodeProperties::GetValueInput(node, 0);
+ int const index = ParameterIndexOf(node->op());
+ Node* const start = NodeProperties::GetValueInput(node, 0);
+ CHECK_EQ(IrOpcode::kStart, start->opcode());
// Currently, parameter indices start at -1 instead of 0.
- CHECK_GT(input->op()->ValueOutputCount(), index + 1);
+ CHECK_LE(-1, index);
+ CHECK_LT(index + 1, start->op()->ValueOutputCount());
// Type can be anything.
CheckUpperIs(node, Type::Any());
break;
@@ -297,9 +358,16 @@
// Type is considered internal.
CheckUpperIs(node, Type::Internal());
break;
+ case IrOpcode::kOsrValue:
+ // OSR values have a value and a control input.
+ CHECK_EQ(1, control_count);
+ CHECK_EQ(1, input_count);
+ // Type is merged from other values in the graph and could be any.
+ CheckUpperIs(node, Type::Any());
+ break;
case IrOpcode::kProjection: {
// Projection has an input that produces enough values.
- int index = static_cast<int>(OpParameter<size_t>(node->op()));
+ int index = static_cast<int>(ProjectionIndexOf(node->op()));
Node* input = NodeProperties::GetValueInput(node, 0);
CHECK_GT(input->op()->ValueOutputCount(), index);
// Type can be anything.
@@ -325,9 +393,7 @@
// TODO(rossberg): for now at least, narrowing does not really hold.
/*
for (int i = 0; i < value_count; ++i) {
- // TODO(rossberg, jarin): Figure out what to do about lower bounds.
- // CHECK(bounds(node).lower->Is(bounds(ValueInput(node, i)).lower));
- CHECK(bounds(ValueInput(node, i)).upper->Is(bounds(node).upper));
+ CHECK(type_of(ValueInput(node, i))->Is(type_of(node)));
}
*/
break;
@@ -341,27 +407,45 @@
CHECK_EQ(input_count, 1 + effect_count);
break;
}
- case IrOpcode::kValueEffect:
+ case IrOpcode::kEffectSet: {
+ CHECK_EQ(0, value_count);
+ CHECK_EQ(0, control_count);
+ CHECK_LT(1, effect_count);
+ break;
+ }
+ case IrOpcode::kGuard:
+ // TODO(bmeurer): what are the constraints on these?
+ break;
+ case IrOpcode::kBeginRegion:
// TODO(rossberg): what are the constraints on these?
break;
- case IrOpcode::kFinish: {
+ case IrOpcode::kFinishRegion: {
// TODO(rossberg): what are the constraints on these?
// Type must be subsumed by input type.
if (typing == TYPED) {
- CHECK(bounds(ValueInput(node)).lower->Is(bounds(node).lower));
- CHECK(bounds(ValueInput(node)).upper->Is(bounds(node).upper));
+ Node* val = NodeProperties::GetValueInput(node, 0);
+ CHECK(NodeProperties::GetType(val)->Is(NodeProperties::GetType(node)));
}
break;
}
case IrOpcode::kFrameState:
// TODO(jarin): what are the constraints on these?
+ CHECK_EQ(5, value_count);
+ CHECK_EQ(0, control_count);
+ CHECK_EQ(0, effect_count);
+ CHECK_EQ(6, input_count);
break;
case IrOpcode::kStateValues:
+ case IrOpcode::kObjectState:
+ case IrOpcode::kTypedStateValues:
// TODO(jarin): what are the constraints on these?
break;
case IrOpcode::kCall:
// TODO(rossberg): what are the constraints on these?
break;
+ case IrOpcode::kTailCall:
+ // TODO(bmeurer): what are the constraints on these?
+ break;
// JavaScript operators
// --------------------
@@ -373,7 +457,6 @@
case IrOpcode::kJSGreaterThan:
case IrOpcode::kJSLessThanOrEqual:
case IrOpcode::kJSGreaterThanOrEqual:
- case IrOpcode::kJSUnaryNot:
// Type is Boolean.
CheckUpperIs(node, Type::Boolean());
break;
@@ -424,13 +507,37 @@
// Type is Object.
CheckUpperIs(node, Type::Object());
break;
+ case IrOpcode::kJSCreateArguments:
+ // Type is OtherObject.
+ CheckUpperIs(node, Type::OtherObject());
+ break;
+ case IrOpcode::kJSCreateArray:
+ // Type is OtherObject.
+ CheckUpperIs(node, Type::OtherObject());
+ break;
+ case IrOpcode::kJSCreateClosure:
+ // Type is Function.
+ CheckUpperIs(node, Type::Function());
+ break;
+ case IrOpcode::kJSCreateIterResultObject:
+ // Type is OtherObject.
+ CheckUpperIs(node, Type::OtherObject());
+ break;
+ case IrOpcode::kJSCreateLiteralArray:
+ case IrOpcode::kJSCreateLiteralObject:
+ case IrOpcode::kJSCreateLiteralRegExp:
+ // Type is OtherObject.
+ CheckUpperIs(node, Type::OtherObject());
+ break;
case IrOpcode::kJSLoadProperty:
case IrOpcode::kJSLoadNamed:
+ case IrOpcode::kJSLoadGlobal:
// Type can be anything.
CheckUpperIs(node, Type::Any());
break;
case IrOpcode::kJSStoreProperty:
case IrOpcode::kJSStoreNamed:
+ case IrOpcode::kJSStoreGlobal:
// Type is empty.
CheckNotTyped(node);
break;
@@ -446,6 +553,7 @@
break;
case IrOpcode::kJSLoadContext:
+ case IrOpcode::kJSLoadDynamic:
// Type can be anything.
CheckUpperIs(node, Type::Any());
break;
@@ -464,28 +572,56 @@
// TODO(rossberg): This should really be Is(Internal), but the typer
// currently can't do backwards propagation.
CheckUpperMaybe(context, Type::Internal());
- if (typing == TYPED) CHECK(bounds(node).upper->IsContext());
+ if (typing == TYPED) CHECK(NodeProperties::GetType(node)->IsContext());
break;
}
case IrOpcode::kJSCallConstruct:
+ case IrOpcode::kJSConvertReceiver:
// Type is Receiver.
CheckUpperIs(node, Type::Receiver());
break;
case IrOpcode::kJSCallFunction:
case IrOpcode::kJSCallRuntime:
case IrOpcode::kJSYield:
- case IrOpcode::kJSDebugger:
// Type can be anything.
CheckUpperIs(node, Type::Any());
break;
+ case IrOpcode::kJSForInPrepare: {
+ // TODO(bmeurer): What are the constraints on thse?
+ CheckUpperIs(node, Type::Any());
+ break;
+ }
+ case IrOpcode::kJSForInDone: {
+ // TODO(bmeurer): OSR breaks this invariant, although the node is not user
+ // visible, so we know it is safe (fullcodegen has an unsigned smi there).
+ // CheckValueInputIs(node, 0, Type::UnsignedSmall());
+ break;
+ }
+ case IrOpcode::kJSForInNext: {
+ CheckUpperIs(node, Type::Union(Type::Name(), Type::Undefined(), zone));
+ break;
+ }
+ case IrOpcode::kJSForInStep: {
+ // TODO(bmeurer): OSR breaks this invariant, although the node is not user
+ // visible, so we know it is safe (fullcodegen has an unsigned smi there).
+ // CheckValueInputIs(node, 0, Type::UnsignedSmall());
+ CheckUpperIs(node, Type::UnsignedSmall());
+ break;
+ }
+
+ case IrOpcode::kJSLoadMessage:
+ case IrOpcode::kJSStoreMessage:
+ break;
+
+ case IrOpcode::kJSStackCheck:
+ // Type is empty.
+ CheckNotTyped(node);
+ break;
+
// Simplified operators
// -------------------------------
- case IrOpcode::kAnyToBoolean:
- // Type is Boolean.
- CheckUpperIs(node, Type::Boolean());
- break;
case IrOpcode::kBooleanNot:
// Boolean -> Boolean
CheckValueInputIs(node, 0, Type::Boolean());
@@ -515,6 +651,27 @@
// TODO(rossberg): activate once we retype after opcode changes.
// CheckUpperIs(node, Type::Number());
break;
+ case IrOpcode::kNumberBitwiseOr:
+ case IrOpcode::kNumberBitwiseXor:
+ case IrOpcode::kNumberBitwiseAnd:
+ // (Signed32, Signed32) -> Signed32
+ CheckValueInputIs(node, 0, Type::Signed32());
+ CheckValueInputIs(node, 1, Type::Signed32());
+ CheckUpperIs(node, Type::Signed32());
+ break;
+ case IrOpcode::kNumberShiftLeft:
+ case IrOpcode::kNumberShiftRight:
+ // (Signed32, Unsigned32) -> Signed32
+ CheckValueInputIs(node, 0, Type::Signed32());
+ CheckValueInputIs(node, 1, Type::Unsigned32());
+ CheckUpperIs(node, Type::Signed32());
+ break;
+ case IrOpcode::kNumberShiftRightLogical:
+ // (Unsigned32, Unsigned32) -> Unsigned32
+ CheckValueInputIs(node, 0, Type::Unsigned32());
+ CheckValueInputIs(node, 1, Type::Unsigned32());
+ CheckUpperIs(node, Type::Unsigned32());
+ break;
case IrOpcode::kNumberToInt32:
// Number -> Signed32
CheckValueInputIs(node, 0, Type::Number());
@@ -525,6 +682,16 @@
CheckValueInputIs(node, 0, Type::Number());
CheckUpperIs(node, Type::Unsigned32());
break;
+ case IrOpcode::kNumberIsHoleNaN:
+ // Number -> Boolean
+ CheckValueInputIs(node, 0, Type::Number());
+ CheckUpperIs(node, Type::Boolean());
+ break;
+ case IrOpcode::kPlainPrimitiveToNumber:
+ // PlainPrimitive -> Number
+ CheckValueInputIs(node, 0, Type::PlainPrimitive());
+ CheckUpperIs(node, Type::Number());
+ break;
case IrOpcode::kStringEqual:
case IrOpcode::kStringLessThan:
case IrOpcode::kStringLessThanOrEqual:
@@ -533,29 +700,20 @@
CheckValueInputIs(node, 1, Type::String());
CheckUpperIs(node, Type::Boolean());
break;
- case IrOpcode::kStringAdd:
- // (String, String) -> String
- CheckValueInputIs(node, 0, Type::String());
- CheckValueInputIs(node, 1, Type::String());
- CheckUpperIs(node, Type::String());
- break;
case IrOpcode::kReferenceEqual: {
// (Unique, Any) -> Boolean and
// (Any, Unique) -> Boolean
- if (typing == TYPED) {
- CHECK(bounds(ValueInput(node, 0)).upper->Is(Type::Unique()) ||
- bounds(ValueInput(node, 1)).upper->Is(Type::Unique()));
- }
CheckUpperIs(node, Type::Boolean());
break;
}
+ case IrOpcode::kObjectIsNumber:
case IrOpcode::kObjectIsSmi:
CheckValueInputIs(node, 0, Type::Any());
CheckUpperIs(node, Type::Boolean());
break;
- case IrOpcode::kObjectIsNonNegativeSmi:
- CheckValueInputIs(node, 0, Type::Any());
- CheckUpperIs(node, Type::Boolean());
+ case IrOpcode::kAllocate:
+ CheckValueInputIs(node, 0, Type::PlainNumber());
+ CheckUpperIs(node, Type::TaggedPointer());
break;
case IrOpcode::kChangeTaggedToInt32: {
@@ -635,7 +793,7 @@
// Object -> fieldtype
// TODO(rossberg): activate once machine ops are typed.
// CheckValueInputIs(node, 0, Type::Object());
- // CheckUpperIs(node, Field(node).type));
+ // CheckUpperIs(node, FieldAccessOf(node->op()).type));
break;
case IrOpcode::kLoadBuffer:
break;
@@ -643,13 +801,13 @@
// Object -> elementtype
// TODO(rossberg): activate once machine ops are typed.
// CheckValueInputIs(node, 0, Type::Object());
- // CheckUpperIs(node, Element(node).type));
+ // CheckUpperIs(node, ElementAccessOf(node->op()).type));
break;
case IrOpcode::kStoreField:
// (Object, fieldtype) -> _|_
// TODO(rossberg): activate once machine ops are typed.
// CheckValueInputIs(node, 0, Type::Object());
- // CheckValueInputIs(node, 1, Field(node).type));
+ // CheckValueInputIs(node, 1, FieldAccessOf(node->op()).type));
CheckNotTyped(node);
break;
case IrOpcode::kStoreBuffer:
@@ -658,7 +816,7 @@
// (Object, elementtype) -> _|_
// TODO(rossberg): activate once machine ops are typed.
// CheckValueInputIs(node, 0, Type::Object());
- // CheckValueInputIs(node, 1, Element(node).type));
+ // CheckValueInputIs(node, 1, ElementAccessOf(node->op()).type));
CheckNotTyped(node);
break;
@@ -674,6 +832,9 @@
case IrOpcode::kWord32Sar:
case IrOpcode::kWord32Ror:
case IrOpcode::kWord32Equal:
+ case IrOpcode::kWord32Clz:
+ case IrOpcode::kWord32Ctz:
+ case IrOpcode::kWord32Popcnt:
case IrOpcode::kWord64And:
case IrOpcode::kWord64Or:
case IrOpcode::kWord64Xor:
@@ -681,6 +842,9 @@
case IrOpcode::kWord64Shr:
case IrOpcode::kWord64Sar:
case IrOpcode::kWord64Ror:
+ case IrOpcode::kWord64Clz:
+ case IrOpcode::kWord64Popcnt:
+ case IrOpcode::kWord64Ctz:
case IrOpcode::kWord64Equal:
case IrOpcode::kInt32Add:
case IrOpcode::kInt32AddWithOverflow:
@@ -698,7 +862,9 @@
case IrOpcode::kUint32LessThan:
case IrOpcode::kUint32LessThanOrEqual:
case IrOpcode::kInt64Add:
+ case IrOpcode::kInt64AddWithOverflow:
case IrOpcode::kInt64Sub:
+ case IrOpcode::kInt64SubWithOverflow:
case IrOpcode::kInt64Mul:
case IrOpcode::kInt64Div:
case IrOpcode::kInt64Mod:
@@ -707,22 +873,50 @@
case IrOpcode::kUint64Div:
case IrOpcode::kUint64Mod:
case IrOpcode::kUint64LessThan:
+ case IrOpcode::kUint64LessThanOrEqual:
+ case IrOpcode::kFloat32Add:
+ case IrOpcode::kFloat32Sub:
+ case IrOpcode::kFloat32Mul:
+ case IrOpcode::kFloat32Div:
+ case IrOpcode::kFloat32Max:
+ case IrOpcode::kFloat32Min:
+ case IrOpcode::kFloat32Abs:
+ case IrOpcode::kFloat32Sqrt:
+ case IrOpcode::kFloat32Equal:
+ case IrOpcode::kFloat32LessThan:
+ case IrOpcode::kFloat32LessThanOrEqual:
case IrOpcode::kFloat64Add:
case IrOpcode::kFloat64Sub:
case IrOpcode::kFloat64Mul:
case IrOpcode::kFloat64Div:
case IrOpcode::kFloat64Mod:
+ case IrOpcode::kFloat64Max:
+ case IrOpcode::kFloat64Min:
+ case IrOpcode::kFloat64Abs:
case IrOpcode::kFloat64Sqrt:
- case IrOpcode::kFloat64Floor:
- case IrOpcode::kFloat64Ceil:
+ case IrOpcode::kFloat32RoundDown:
+ case IrOpcode::kFloat64RoundDown:
+ case IrOpcode::kFloat32RoundUp:
+ case IrOpcode::kFloat64RoundUp:
+ case IrOpcode::kFloat32RoundTruncate:
case IrOpcode::kFloat64RoundTruncate:
case IrOpcode::kFloat64RoundTiesAway:
+ case IrOpcode::kFloat32RoundTiesEven:
+ case IrOpcode::kFloat64RoundTiesEven:
case IrOpcode::kFloat64Equal:
case IrOpcode::kFloat64LessThan:
case IrOpcode::kFloat64LessThanOrEqual:
case IrOpcode::kTruncateInt64ToInt32:
+ case IrOpcode::kRoundInt64ToFloat32:
+ case IrOpcode::kRoundInt64ToFloat64:
+ case IrOpcode::kRoundUint64ToFloat64:
+ case IrOpcode::kRoundUint64ToFloat32:
case IrOpcode::kTruncateFloat64ToFloat32:
case IrOpcode::kTruncateFloat64ToInt32:
+ case IrOpcode::kBitcastFloat32ToInt32:
+ case IrOpcode::kBitcastFloat64ToInt64:
+ case IrOpcode::kBitcastInt32ToFloat32:
+ case IrOpcode::kBitcastInt64ToFloat64:
case IrOpcode::kChangeInt32ToInt64:
case IrOpcode::kChangeUint32ToUint64:
case IrOpcode::kChangeInt32ToFloat64:
@@ -730,20 +924,46 @@
case IrOpcode::kChangeFloat32ToFloat64:
case IrOpcode::kChangeFloat64ToInt32:
case IrOpcode::kChangeFloat64ToUint32:
+ case IrOpcode::kTryTruncateFloat32ToInt64:
+ case IrOpcode::kTryTruncateFloat64ToInt64:
+ case IrOpcode::kTryTruncateFloat32ToUint64:
+ case IrOpcode::kTryTruncateFloat64ToUint64:
+ case IrOpcode::kFloat64ExtractLowWord32:
+ case IrOpcode::kFloat64ExtractHighWord32:
+ case IrOpcode::kFloat64InsertLowWord32:
+ case IrOpcode::kFloat64InsertHighWord32:
case IrOpcode::kLoadStackPointer:
+ case IrOpcode::kLoadFramePointer:
case IrOpcode::kCheckedLoad:
case IrOpcode::kCheckedStore:
// TODO(rossberg): Check.
break;
}
-}
+} // NOLINT(readability/fn_size)
void Verifier::Run(Graph* graph, Typing typing) {
- Visitor visitor(graph->zone(), typing);
- CHECK_NE(NULL, graph->start());
- CHECK_NE(NULL, graph->end());
- graph->VisitNodeInputsFromEnd(&visitor);
+ CHECK_NOT_NULL(graph->start());
+ CHECK_NOT_NULL(graph->end());
+ Zone zone;
+ Visitor visitor(&zone, typing);
+ AllNodes all(&zone, graph);
+ for (Node* node : all.live) visitor.Check(node);
+
+ // Check the uniqueness of projections.
+ for (Node* proj : all.live) {
+ if (proj->opcode() != IrOpcode::kProjection) continue;
+ Node* node = proj->InputAt(0);
+ for (Node* other : node->uses()) {
+ if (all.IsLive(other) && other != proj &&
+ other->opcode() == IrOpcode::kProjection &&
+ ProjectionIndexOf(other->op()) == ProjectionIndexOf(proj->op())) {
+ V8_Fatal(__FILE__, __LINE__,
+ "Node #%d:%s has duplicate projections #%d and #%d",
+ node->id(), node->op()->mnemonic(), proj->id(), other->id());
+ }
+ }
+ }
}
@@ -759,7 +979,7 @@
use_pos--;
}
block = block->dominator();
- if (block == NULL) break;
+ if (block == nullptr) break;
use_pos = static_cast<int>(block->NodeCount()) - 1;
if (node == block->control_input()) return true;
}
@@ -770,7 +990,7 @@
static bool Dominates(Schedule* schedule, Node* dominator, Node* dominatee) {
BasicBlock* dom = schedule->block(dominator);
BasicBlock* sub = schedule->block(dominatee);
- while (sub != NULL) {
+ while (sub != nullptr) {
if (sub == dom) {
return true;
}
@@ -793,7 +1013,7 @@
use_pos)) {
V8_Fatal(__FILE__, __LINE__,
"Node #%d:%s in B%d is not dominated by input@%d #%d:%s",
- node->id(), node->op()->mnemonic(), block->id().ToInt(), j,
+ node->id(), node->op()->mnemonic(), block->rpo_number(), j,
input->id(), input->op()->mnemonic());
}
}
@@ -806,8 +1026,8 @@
if (!Dominates(schedule, ctl, node)) {
V8_Fatal(__FILE__, __LINE__,
"Node #%d:%s in B%d is not dominated by control input #%d:%s",
- node->id(), node->op()->mnemonic(), block->id(), ctl->id(),
- ctl->op()->mnemonic());
+ node->id(), node->op()->mnemonic(), block->rpo_number(),
+ ctl->id(), ctl->op()->mnemonic());
}
}
}
@@ -815,7 +1035,7 @@
void ScheduleVerifier::Run(Schedule* schedule) {
const size_t count = schedule->BasicBlockCount();
- Zone tmp_zone(schedule->zone()->isolate());
+ Zone tmp_zone;
Zone* zone = &tmp_zone;
BasicBlock* start = schedule->start();
BasicBlockVector* rpo_order = schedule->rpo_order();
@@ -826,15 +1046,13 @@
++b) {
CHECK_EQ((*b), schedule->GetBlockById((*b)->id()));
// All predecessors and successors should be in rpo and in this schedule.
- for (BasicBlock::Predecessors::iterator j = (*b)->predecessors_begin();
- j != (*b)->predecessors_end(); ++j) {
- CHECK_GE((*j)->rpo_number(), 0);
- CHECK_EQ((*j), schedule->GetBlockById((*j)->id()));
+ for (BasicBlock const* predecessor : (*b)->predecessors()) {
+ CHECK_GE(predecessor->rpo_number(), 0);
+ CHECK_EQ(predecessor, schedule->GetBlockById(predecessor->id()));
}
- for (BasicBlock::Successors::iterator j = (*b)->successors_begin();
- j != (*b)->successors_end(); ++j) {
- CHECK_GE((*j)->rpo_number(), 0);
- CHECK_EQ((*j), schedule->GetBlockById((*j)->id()));
+ for (BasicBlock const* successor : (*b)->successors()) {
+ CHECK_GE(successor->rpo_number(), 0);
+ CHECK_EQ(successor, schedule->GetBlockById(successor->id()));
}
}
@@ -846,10 +1064,10 @@
BasicBlock* dom = block->dominator();
if (b == 0) {
// All blocks except start should have a dominator.
- CHECK_EQ(NULL, dom);
+ CHECK_NULL(dom);
} else {
// Check that the immediate dominator appears somewhere before the block.
- CHECK_NE(NULL, dom);
+ CHECK_NOT_NULL(dom);
CHECK_LT(dom->rpo_number(), block->rpo_number());
}
}
@@ -888,7 +1106,7 @@
{
// Verify the dominance relation.
ZoneVector<BitVector*> dominators(zone);
- dominators.resize(count, NULL);
+ dominators.resize(count, nullptr);
// Compute a set of all the nodes that dominate a given node by using
// a forward fixpoint. O(n^2).
@@ -901,15 +1119,15 @@
queue.pop();
BitVector* block_doms = dominators[block->id().ToSize()];
BasicBlock* idom = block->dominator();
- if (idom != NULL && !block_doms->Contains(idom->id().ToInt())) {
+ if (idom != nullptr && !block_doms->Contains(idom->id().ToInt())) {
V8_Fatal(__FILE__, __LINE__, "Block B%d is not dominated by B%d",
- block->id().ToInt(), idom->id().ToInt());
+ block->rpo_number(), idom->rpo_number());
}
for (size_t s = 0; s < block->SuccessorCount(); s++) {
BasicBlock* succ = block->SuccessorAt(s);
BitVector* succ_doms = dominators[succ->id().ToSize()];
- if (succ_doms == NULL) {
+ if (succ_doms == nullptr) {
// First time visiting the node. S.doms = B U B.doms
succ_doms = new (zone) BitVector(static_cast<int>(count), zone);
succ_doms->CopyFrom(*block_doms);
@@ -931,7 +1149,7 @@
b != rpo_order->end(); ++b) {
BasicBlock* block = *b;
BasicBlock* idom = block->dominator();
- if (idom == NULL) continue;
+ if (idom == nullptr) continue;
BitVector* block_doms = dominators[block->id().ToSize()];
for (BitVector::Iterator it(block_doms); !it.Done(); it.Advance()) {
@@ -941,7 +1159,7 @@
!dominators[idom->id().ToSize()]->Contains(dom->id().ToInt())) {
V8_Fatal(__FILE__, __LINE__,
"Block B%d is not immediately dominated by B%d",
- block->id().ToInt(), idom->id().ToInt());
+ block->rpo_number(), idom->rpo_number());
}
}
}
@@ -971,7 +1189,7 @@
// Check inputs to control for this block.
Node* control = block->control_input();
- if (control != NULL) {
+ if (control != nullptr) {
CHECK_EQ(block, schedule->block(control));
CheckInputsDominate(schedule, block, control,
static_cast<int>(block->NodeCount()) - 1);
@@ -983,6 +1201,68 @@
}
}
}
+
+
+#ifdef DEBUG
+
+// static
+void Verifier::VerifyNode(Node* node) {
+ CHECK_EQ(OperatorProperties::GetTotalInputCount(node->op()),
+ node->InputCount());
+ // If this node has no effect or no control outputs,
+ // we check that no its uses are effect or control inputs.
+ bool check_no_control = node->op()->ControlOutputCount() == 0;
+ bool check_no_effect = node->op()->EffectOutputCount() == 0;
+ bool check_no_frame_state = node->opcode() != IrOpcode::kFrameState;
+ if (check_no_effect || check_no_control) {
+ for (Edge edge : node->use_edges()) {
+ Node* const user = edge.from();
+ CHECK(!user->IsDead());
+ if (NodeProperties::IsControlEdge(edge)) {
+ CHECK(!check_no_control);
+ } else if (NodeProperties::IsEffectEdge(edge)) {
+ CHECK(!check_no_effect);
+ } else if (NodeProperties::IsFrameStateEdge(edge)) {
+ CHECK(!check_no_frame_state);
+ }
+ }
+ }
+ // Frame state inputs should be frame states (or sentinels).
+ for (int i = 0; i < OperatorProperties::GetFrameStateInputCount(node->op());
+ i++) {
+ Node* input = NodeProperties::GetFrameStateInput(node, i);
+ CHECK(input->opcode() == IrOpcode::kFrameState ||
+ input->opcode() == IrOpcode::kStart ||
+ input->opcode() == IrOpcode::kDead);
+ }
+ // Effect inputs should be effect-producing nodes (or sentinels).
+ for (int i = 0; i < node->op()->EffectInputCount(); i++) {
+ Node* input = NodeProperties::GetEffectInput(node, i);
+ CHECK(input->op()->EffectOutputCount() > 0 ||
+ input->opcode() == IrOpcode::kDead);
+ }
+ // Control inputs should be control-producing nodes (or sentinels).
+ for (int i = 0; i < node->op()->ControlInputCount(); i++) {
+ Node* input = NodeProperties::GetControlInput(node, i);
+ CHECK(input->op()->ControlOutputCount() > 0 ||
+ input->opcode() == IrOpcode::kDead);
+ }
}
+
+
+void Verifier::VerifyEdgeInputReplacement(const Edge& edge,
+ const Node* replacement) {
+ // Check that the user does not misuse the replacement.
+ DCHECK(!NodeProperties::IsControlEdge(edge) ||
+ replacement->op()->ControlOutputCount() > 0);
+ DCHECK(!NodeProperties::IsEffectEdge(edge) ||
+ replacement->op()->EffectOutputCount() > 0);
+ DCHECK(!NodeProperties::IsFrameStateEdge(edge) ||
+ replacement->opcode() == IrOpcode::kFrameState);
}
-} // namespace v8::internal::compiler
+
+#endif // DEBUG
+
+} // namespace compiler
+} // namespace internal
+} // namespace v8