Cleanups to Verifier.
This CL broadens the checks done by the verifier in untyped mode and introduces some subroutines to shorten the code a bit. Introduce routines CheckUpperIs() CheckUpperMaybe() and CheckValueInputIs() that are called unconditionally by the verifier. If the typing mode is untyped, then don't check anything. Also added a couple checks for Merge and Loop nodes that catch bugs where the operator and the node disagree on input counts (a bug encountered today). R=mstarzinger@chromium.org, rossberg@chromium.org BUG= Review URL: https://codereview.chromium.org/669073002 git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24809 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
db000e307a
commit
f843327ea0
@ -6,6 +6,8 @@
|
|||||||
|
|
||||||
#include <deque>
|
#include <deque>
|
||||||
#include <queue>
|
#include <queue>
|
||||||
|
#include <sstream>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
#include "src/compiler/generic-algorithm.h"
|
#include "src/compiler/generic-algorithm.h"
|
||||||
#include "src/compiler/generic-node-inl.h"
|
#include "src/compiler/generic-node-inl.h"
|
||||||
@ -20,6 +22,7 @@
|
|||||||
#include "src/compiler/schedule.h"
|
#include "src/compiler/schedule.h"
|
||||||
#include "src/compiler/simplified-operator.h"
|
#include "src/compiler/simplified-operator.h"
|
||||||
#include "src/data-flow.h"
|
#include "src/data-flow.h"
|
||||||
|
#include "src/ostreams.h"
|
||||||
|
|
||||||
namespace v8 {
|
namespace v8 {
|
||||||
namespace internal {
|
namespace internal {
|
||||||
@ -56,10 +59,8 @@ class Verifier::Visitor : public NullNodeVisitor {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
// TODO(rossberg): Get rid of these once we got rid of NodeProperties.
|
// TODO(rossberg): Get rid of these once we got rid of NodeProperties.
|
||||||
Bounds bounds(Node* node) {
|
Bounds bounds(Node* node) { return NodeProperties::GetBounds(node); }
|
||||||
return NodeProperties::GetBounds(node);
|
Node* ValueInput(Node* node, int i = 0) {
|
||||||
}
|
|
||||||
Node* Operand(Node* node, int i = 0) {
|
|
||||||
return NodeProperties::GetValueInput(node, i);
|
return NodeProperties::GetValueInput(node, i);
|
||||||
}
|
}
|
||||||
FieldAccess Field(Node* node) {
|
FieldAccess Field(Node* node) {
|
||||||
@ -72,6 +73,50 @@ class Verifier::Visitor : public NullNodeVisitor {
|
|||||||
node->opcode() == IrOpcode::kStoreElement);
|
node->opcode() == IrOpcode::kStoreElement);
|
||||||
return OpParameter<ElementAccess>(node);
|
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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void CheckUpperIs(Node* node, Type* type) {
|
||||||
|
if (typing == TYPED && !bounds(node).upper->Is(type)) {
|
||||||
|
std::ostringstream str;
|
||||||
|
str << "TypeError: node #" << node->opcode() << ":"
|
||||||
|
<< node->op()->mnemonic() << " upper bound ";
|
||||||
|
bounds(node).upper->PrintTo(str);
|
||||||
|
str << " is not ";
|
||||||
|
type->PrintTo(str);
|
||||||
|
V8_Fatal(__FILE__, __LINE__, str.str().c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void CheckUpperMaybe(Node* node, Type* type) {
|
||||||
|
if (typing == TYPED && !bounds(node).upper->Maybe(type)) {
|
||||||
|
std::ostringstream str;
|
||||||
|
str << "TypeError: node #" << node->opcode() << ":"
|
||||||
|
<< node->op()->mnemonic() << " upper bound ";
|
||||||
|
bounds(node).upper->PrintTo(str);
|
||||||
|
str << " must intersect ";
|
||||||
|
type->PrintTo(str);
|
||||||
|
V8_Fatal(__FILE__, __LINE__, 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)) {
|
||||||
|
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 << " is not ";
|
||||||
|
type->PrintTo(str);
|
||||||
|
V8_Fatal(__FILE__, __LINE__, str.str().c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -141,16 +186,13 @@ GenericGraphVisit::Control Verifier::Visitor::Pre(Node* node) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typing == TYPED) {
|
|
||||||
switch (node->opcode()) {
|
switch (node->opcode()) {
|
||||||
// Control operators
|
|
||||||
// -----------------
|
|
||||||
case IrOpcode::kStart:
|
case IrOpcode::kStart:
|
||||||
// Start has no inputs.
|
// Start has no inputs.
|
||||||
CHECK_EQ(0, input_count);
|
CHECK_EQ(0, input_count);
|
||||||
// Type is a tuple.
|
// Type is a tuple.
|
||||||
// TODO(rossberg): Multiple outputs are currently typed as Internal.
|
// TODO(rossberg): Multiple outputs are currently typed as Internal.
|
||||||
CHECK(bounds(node).upper->Is(Type::Internal()));
|
CheckUpperIs(node, Type::Internal());
|
||||||
break;
|
break;
|
||||||
case IrOpcode::kEnd:
|
case IrOpcode::kEnd:
|
||||||
// End has no outputs.
|
// End has no outputs.
|
||||||
@ -158,7 +200,7 @@ GenericGraphVisit::Control Verifier::Visitor::Pre(Node* node) {
|
|||||||
CHECK(!OperatorProperties::HasEffectOutput(node->op()));
|
CHECK(!OperatorProperties::HasEffectOutput(node->op()));
|
||||||
CHECK(!OperatorProperties::HasControlOutput(node->op()));
|
CHECK(!OperatorProperties::HasControlOutput(node->op()));
|
||||||
// Type is empty.
|
// Type is empty.
|
||||||
CHECK(!NodeProperties::IsTyped(node));
|
CheckNotTyped(node);
|
||||||
break;
|
break;
|
||||||
case IrOpcode::kDead:
|
case IrOpcode::kDead:
|
||||||
// Dead is never connected to the graph.
|
// Dead is never connected to the graph.
|
||||||
@ -175,7 +217,7 @@ GenericGraphVisit::Control Verifier::Visitor::Pre(Node* node) {
|
|||||||
}
|
}
|
||||||
CHECK(count_true == 1 && count_false == 1);
|
CHECK(count_true == 1 && count_false == 1);
|
||||||
// Type is empty.
|
// Type is empty.
|
||||||
CHECK(!NodeProperties::IsTyped(node));
|
CheckNotTyped(node);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case IrOpcode::kIfTrue:
|
case IrOpcode::kIfTrue:
|
||||||
@ -183,22 +225,23 @@ GenericGraphVisit::Control Verifier::Visitor::Pre(Node* node) {
|
|||||||
CHECK_EQ(IrOpcode::kBranch,
|
CHECK_EQ(IrOpcode::kBranch,
|
||||||
NodeProperties::GetControlInput(node, 0)->opcode());
|
NodeProperties::GetControlInput(node, 0)->opcode());
|
||||||
// Type is empty.
|
// Type is empty.
|
||||||
CHECK(!NodeProperties::IsTyped(node));
|
CheckNotTyped(node);
|
||||||
break;
|
break;
|
||||||
case IrOpcode::kLoop:
|
case IrOpcode::kLoop:
|
||||||
case IrOpcode::kMerge:
|
case IrOpcode::kMerge:
|
||||||
|
CHECK_EQ(control_count, input_count);
|
||||||
// Type is empty.
|
// Type is empty.
|
||||||
CHECK(!NodeProperties::IsTyped(node));
|
CheckNotTyped(node);
|
||||||
break;
|
break;
|
||||||
case IrOpcode::kReturn:
|
case IrOpcode::kReturn:
|
||||||
// TODO(rossberg): check successor is End
|
// TODO(rossberg): check successor is End
|
||||||
// Type is empty.
|
// Type is empty.
|
||||||
CHECK(!NodeProperties::IsTyped(node));
|
CheckNotTyped(node);
|
||||||
break;
|
break;
|
||||||
case IrOpcode::kThrow:
|
case IrOpcode::kThrow:
|
||||||
// TODO(rossberg): what are the constraints on these?
|
// TODO(rossberg): what are the constraints on these?
|
||||||
// Type is empty.
|
// Type is empty.
|
||||||
CHECK(!NodeProperties::IsTyped(node));
|
CheckNotTyped(node);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Common operators
|
// Common operators
|
||||||
@ -212,24 +255,23 @@ GenericGraphVisit::Control Verifier::Visitor::Pre(Node* node) {
|
|||||||
int index = OpParameter<int>(node);
|
int index = OpParameter<int>(node);
|
||||||
Node* input = NodeProperties::GetValueInput(node, 0);
|
Node* input = NodeProperties::GetValueInput(node, 0);
|
||||||
// Currently, parameter indices start at -1 instead of 0.
|
// Currently, parameter indices start at -1 instead of 0.
|
||||||
CHECK_GT(
|
CHECK_GT(OperatorProperties::GetValueOutputCount(input->op()), index + 1);
|
||||||
OperatorProperties::GetValueOutputCount(input->op()), index + 1);
|
|
||||||
// Type can be anything.
|
// Type can be anything.
|
||||||
CHECK(bounds(node).upper->Is(Type::Any()));
|
CheckUpperIs(node, Type::Any());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case IrOpcode::kInt32Constant: // TODO(rossberg): rename Word32Constant?
|
case IrOpcode::kInt32Constant: // TODO(rossberg): rename Word32Constant?
|
||||||
// Constants have no inputs.
|
// Constants have no inputs.
|
||||||
CHECK_EQ(0, input_count);
|
CHECK_EQ(0, input_count);
|
||||||
// Type is a 32 bit integer, signed or unsigned.
|
// Type is a 32 bit integer, signed or unsigned.
|
||||||
CHECK(bounds(node).upper->Is(Type::Integral32()));
|
CheckUpperIs(node, Type::Integral32());
|
||||||
break;
|
break;
|
||||||
case IrOpcode::kInt64Constant:
|
case IrOpcode::kInt64Constant:
|
||||||
// Constants have no inputs.
|
// Constants have no inputs.
|
||||||
CHECK_EQ(0, input_count);
|
CHECK_EQ(0, input_count);
|
||||||
// Type is internal.
|
// Type is internal.
|
||||||
// TODO(rossberg): Introduce proper Int64 type.
|
// TODO(rossberg): Introduce proper Int64 type.
|
||||||
CHECK(bounds(node).upper->Is(Type::Internal()));
|
CheckUpperIs(node, Type::Internal());
|
||||||
break;
|
break;
|
||||||
case IrOpcode::kFloat32Constant:
|
case IrOpcode::kFloat32Constant:
|
||||||
case IrOpcode::kFloat64Constant:
|
case IrOpcode::kFloat64Constant:
|
||||||
@ -237,19 +279,19 @@ GenericGraphVisit::Control Verifier::Visitor::Pre(Node* node) {
|
|||||||
// Constants have no inputs.
|
// Constants have no inputs.
|
||||||
CHECK_EQ(0, input_count);
|
CHECK_EQ(0, input_count);
|
||||||
// Type is a number.
|
// Type is a number.
|
||||||
CHECK(bounds(node).upper->Is(Type::Number()));
|
CheckUpperIs(node, Type::Number());
|
||||||
break;
|
break;
|
||||||
case IrOpcode::kHeapConstant:
|
case IrOpcode::kHeapConstant:
|
||||||
// Constants have no inputs.
|
// Constants have no inputs.
|
||||||
CHECK_EQ(0, input_count);
|
CHECK_EQ(0, input_count);
|
||||||
// Type can be anything represented as a heap pointer.
|
// Type can be anything represented as a heap pointer.
|
||||||
CHECK(bounds(node).upper->Is(Type::TaggedPtr()));
|
CheckUpperIs(node, Type::TaggedPtr());
|
||||||
break;
|
break;
|
||||||
case IrOpcode::kExternalConstant:
|
case IrOpcode::kExternalConstant:
|
||||||
// Constants have no inputs.
|
// Constants have no inputs.
|
||||||
CHECK_EQ(0, input_count);
|
CHECK_EQ(0, input_count);
|
||||||
// Type is considered internal.
|
// Type is considered internal.
|
||||||
CHECK(bounds(node).upper->Is(Type::Internal()));
|
CheckUpperIs(node, Type::Internal());
|
||||||
break;
|
break;
|
||||||
case IrOpcode::kProjection: {
|
case IrOpcode::kProjection: {
|
||||||
// Projection has an input that produces enough values.
|
// Projection has an input that produces enough values.
|
||||||
@ -258,32 +300,37 @@ GenericGraphVisit::Control Verifier::Visitor::Pre(Node* node) {
|
|||||||
CHECK_GT(OperatorProperties::GetValueOutputCount(input->op()), index);
|
CHECK_GT(OperatorProperties::GetValueOutputCount(input->op()), index);
|
||||||
// Type can be anything.
|
// Type can be anything.
|
||||||
// TODO(rossberg): Introduce tuple types for this.
|
// TODO(rossberg): Introduce tuple types for this.
|
||||||
CHECK(bounds(node).upper->Is(Type::Any()));
|
// TODO(titzer): Convince rossberg not to.
|
||||||
|
CheckUpperIs(node, Type::Any());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case IrOpcode::kPhi: {
|
case IrOpcode::kPhi: {
|
||||||
// Phi input count matches parent control node.
|
// Phi input count matches parent control node.
|
||||||
|
CHECK_EQ(0, effect_count);
|
||||||
CHECK_EQ(1, control_count);
|
CHECK_EQ(1, control_count);
|
||||||
Node* control = NodeProperties::GetControlInput(node, 0);
|
Node* control = NodeProperties::GetControlInput(node, 0);
|
||||||
CHECK_EQ(value_count,
|
CHECK_EQ(value_count,
|
||||||
OperatorProperties::GetControlInputCount(control->op()));
|
OperatorProperties::GetControlInputCount(control->op()));
|
||||||
|
CHECK_EQ(input_count, 1 + value_count);
|
||||||
// Type must be subsumed by all input types.
|
// Type must be subsumed by all input types.
|
||||||
// TODO(rossberg): for now at least, narrowing does not really hold.
|
// TODO(rossberg): for now at least, narrowing does not really hold.
|
||||||
/*
|
/*
|
||||||
for (int i = 0; i < value_count; ++i) {
|
for (int i = 0; i < value_count; ++i) {
|
||||||
// TODO(rossberg, jarin): Figure out what to do about lower bounds.
|
// TODO(rossberg, jarin): Figure out what to do about lower bounds.
|
||||||
// CHECK(bounds(node).lower->Is(bounds(Operand(node, i)).lower));
|
// CHECK(bounds(node).lower->Is(bounds(ValueInput(node, i)).lower));
|
||||||
CHECK(bounds(Operand(node, i)).upper->Is(bounds(node).upper));
|
CHECK(bounds(ValueInput(node, i)).upper->Is(bounds(node).upper));
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case IrOpcode::kEffectPhi: {
|
case IrOpcode::kEffectPhi: {
|
||||||
// EffectPhi input count matches parent control node.
|
// EffectPhi input count matches parent control node.
|
||||||
|
CHECK_EQ(0, value_count);
|
||||||
CHECK_EQ(1, control_count);
|
CHECK_EQ(1, control_count);
|
||||||
Node* control = NodeProperties::GetControlInput(node, 0);
|
Node* control = NodeProperties::GetControlInput(node, 0);
|
||||||
CHECK_EQ(effect_count,
|
CHECK_EQ(effect_count,
|
||||||
OperatorProperties::GetControlInputCount(control->op()));
|
OperatorProperties::GetControlInputCount(control->op()));
|
||||||
|
CHECK_EQ(input_count, 1 + effect_count);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case IrOpcode::kValueEffect:
|
case IrOpcode::kValueEffect:
|
||||||
@ -292,8 +339,10 @@ GenericGraphVisit::Control Verifier::Visitor::Pre(Node* node) {
|
|||||||
case IrOpcode::kFinish: {
|
case IrOpcode::kFinish: {
|
||||||
// TODO(rossberg): what are the constraints on these?
|
// TODO(rossberg): what are the constraints on these?
|
||||||
// Type must be subsumed by input type.
|
// Type must be subsumed by input type.
|
||||||
CHECK(bounds(Operand(node)).lower->Is(bounds(node).lower));
|
if (typing == TYPED) {
|
||||||
CHECK(bounds(Operand(node)).upper->Is(bounds(node).upper));
|
CHECK(bounds(ValueInput(node)).lower->Is(bounds(node).lower));
|
||||||
|
CHECK(bounds(ValueInput(node)).upper->Is(bounds(node).upper));
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case IrOpcode::kFrameState:
|
case IrOpcode::kFrameState:
|
||||||
@ -318,7 +367,7 @@ GenericGraphVisit::Control Verifier::Visitor::Pre(Node* node) {
|
|||||||
case IrOpcode::kJSGreaterThanOrEqual:
|
case IrOpcode::kJSGreaterThanOrEqual:
|
||||||
case IrOpcode::kJSUnaryNot:
|
case IrOpcode::kJSUnaryNot:
|
||||||
// Type is Boolean.
|
// Type is Boolean.
|
||||||
CHECK(bounds(node).upper->Is(Type::Boolean()));
|
CheckUpperIs(node, Type::Boolean());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case IrOpcode::kJSBitwiseOr:
|
case IrOpcode::kJSBitwiseOr:
|
||||||
@ -328,73 +377,73 @@ GenericGraphVisit::Control Verifier::Visitor::Pre(Node* node) {
|
|||||||
case IrOpcode::kJSShiftRight:
|
case IrOpcode::kJSShiftRight:
|
||||||
case IrOpcode::kJSShiftRightLogical:
|
case IrOpcode::kJSShiftRightLogical:
|
||||||
// Type is 32 bit integral.
|
// Type is 32 bit integral.
|
||||||
CHECK(bounds(node).upper->Is(Type::Integral32()));
|
CheckUpperIs(node, Type::Integral32());
|
||||||
break;
|
break;
|
||||||
case IrOpcode::kJSAdd:
|
case IrOpcode::kJSAdd:
|
||||||
// Type is Number or String.
|
// Type is Number or String.
|
||||||
CHECK(bounds(node).upper->Is(Type::NumberOrString()));
|
CheckUpperIs(node, Type::NumberOrString());
|
||||||
break;
|
break;
|
||||||
case IrOpcode::kJSSubtract:
|
case IrOpcode::kJSSubtract:
|
||||||
case IrOpcode::kJSMultiply:
|
case IrOpcode::kJSMultiply:
|
||||||
case IrOpcode::kJSDivide:
|
case IrOpcode::kJSDivide:
|
||||||
case IrOpcode::kJSModulus:
|
case IrOpcode::kJSModulus:
|
||||||
// Type is Number.
|
// Type is Number.
|
||||||
CHECK(bounds(node).upper->Is(Type::Number()));
|
CheckUpperIs(node, Type::Number());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case IrOpcode::kJSToBoolean:
|
case IrOpcode::kJSToBoolean:
|
||||||
// Type is Boolean.
|
// Type is Boolean.
|
||||||
CHECK(bounds(node).upper->Is(Type::Boolean()));
|
CheckUpperIs(node, Type::Boolean());
|
||||||
break;
|
break;
|
||||||
case IrOpcode::kJSToNumber:
|
case IrOpcode::kJSToNumber:
|
||||||
// Type is Number.
|
// Type is Number.
|
||||||
CHECK(bounds(node).upper->Is(Type::Number()));
|
CheckUpperIs(node, Type::Number());
|
||||||
break;
|
break;
|
||||||
case IrOpcode::kJSToString:
|
case IrOpcode::kJSToString:
|
||||||
// Type is String.
|
// Type is String.
|
||||||
CHECK(bounds(node).upper->Is(Type::String()));
|
CheckUpperIs(node, Type::String());
|
||||||
break;
|
break;
|
||||||
case IrOpcode::kJSToName:
|
case IrOpcode::kJSToName:
|
||||||
// Type is Name.
|
// Type is Name.
|
||||||
CHECK(bounds(node).upper->Is(Type::Name()));
|
CheckUpperIs(node, Type::Name());
|
||||||
break;
|
break;
|
||||||
case IrOpcode::kJSToObject:
|
case IrOpcode::kJSToObject:
|
||||||
// Type is Receiver.
|
// Type is Receiver.
|
||||||
CHECK(bounds(node).upper->Is(Type::Receiver()));
|
CheckUpperIs(node, Type::Receiver());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case IrOpcode::kJSCreate:
|
case IrOpcode::kJSCreate:
|
||||||
// Type is Object.
|
// Type is Object.
|
||||||
CHECK(bounds(node).upper->Is(Type::Object()));
|
CheckUpperIs(node, Type::Object());
|
||||||
break;
|
break;
|
||||||
case IrOpcode::kJSLoadProperty:
|
case IrOpcode::kJSLoadProperty:
|
||||||
case IrOpcode::kJSLoadNamed:
|
case IrOpcode::kJSLoadNamed:
|
||||||
// Type can be anything.
|
// Type can be anything.
|
||||||
CHECK(bounds(node).upper->Is(Type::Any()));
|
CheckUpperIs(node, Type::Any());
|
||||||
break;
|
break;
|
||||||
case IrOpcode::kJSStoreProperty:
|
case IrOpcode::kJSStoreProperty:
|
||||||
case IrOpcode::kJSStoreNamed:
|
case IrOpcode::kJSStoreNamed:
|
||||||
// Type is empty.
|
// Type is empty.
|
||||||
CHECK(!NodeProperties::IsTyped(node));
|
CheckNotTyped(node);
|
||||||
break;
|
break;
|
||||||
case IrOpcode::kJSDeleteProperty:
|
case IrOpcode::kJSDeleteProperty:
|
||||||
case IrOpcode::kJSHasProperty:
|
case IrOpcode::kJSHasProperty:
|
||||||
case IrOpcode::kJSInstanceOf:
|
case IrOpcode::kJSInstanceOf:
|
||||||
// Type is Boolean.
|
// Type is Boolean.
|
||||||
CHECK(bounds(node).upper->Is(Type::Boolean()));
|
CheckUpperIs(node, Type::Boolean());
|
||||||
break;
|
break;
|
||||||
case IrOpcode::kJSTypeOf:
|
case IrOpcode::kJSTypeOf:
|
||||||
// Type is String.
|
// Type is String.
|
||||||
CHECK(bounds(node).upper->Is(Type::String()));
|
CheckUpperIs(node, Type::String());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case IrOpcode::kJSLoadContext:
|
case IrOpcode::kJSLoadContext:
|
||||||
// Type can be anything.
|
// Type can be anything.
|
||||||
CHECK(bounds(node).upper->Is(Type::Any()));
|
CheckUpperIs(node, Type::Any());
|
||||||
break;
|
break;
|
||||||
case IrOpcode::kJSStoreContext:
|
case IrOpcode::kJSStoreContext:
|
||||||
// Type is empty.
|
// Type is empty.
|
||||||
CHECK(!NodeProperties::IsTyped(node));
|
CheckNotTyped(node);
|
||||||
break;
|
break;
|
||||||
case IrOpcode::kJSCreateFunctionContext:
|
case IrOpcode::kJSCreateFunctionContext:
|
||||||
case IrOpcode::kJSCreateCatchContext:
|
case IrOpcode::kJSCreateCatchContext:
|
||||||
@ -403,45 +452,45 @@ GenericGraphVisit::Control Verifier::Visitor::Pre(Node* node) {
|
|||||||
case IrOpcode::kJSCreateModuleContext:
|
case IrOpcode::kJSCreateModuleContext:
|
||||||
case IrOpcode::kJSCreateGlobalContext: {
|
case IrOpcode::kJSCreateGlobalContext: {
|
||||||
// Type is Context, and operand is Internal.
|
// Type is Context, and operand is Internal.
|
||||||
Bounds outer = bounds(NodeProperties::GetContextInput(node));
|
Node* context = NodeProperties::GetContextInput(node);
|
||||||
// TODO(rossberg): This should really be Is(Internal), but the typer
|
// TODO(rossberg): This should really be Is(Internal), but the typer
|
||||||
// currently can't do backwards propagation.
|
// currently can't do backwards propagation.
|
||||||
CHECK(outer.upper->Maybe(Type::Internal()));
|
CheckUpperMaybe(context, Type::Internal());
|
||||||
CHECK(bounds(node).upper->IsContext());
|
if (typing == TYPED) CHECK(bounds(node).upper->IsContext());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case IrOpcode::kJSCallConstruct:
|
case IrOpcode::kJSCallConstruct:
|
||||||
// Type is Receiver.
|
// Type is Receiver.
|
||||||
CHECK(bounds(node).upper->Is(Type::Receiver()));
|
CheckUpperIs(node, Type::Receiver());
|
||||||
break;
|
break;
|
||||||
case IrOpcode::kJSCallFunction:
|
case IrOpcode::kJSCallFunction:
|
||||||
case IrOpcode::kJSCallRuntime:
|
case IrOpcode::kJSCallRuntime:
|
||||||
case IrOpcode::kJSYield:
|
case IrOpcode::kJSYield:
|
||||||
case IrOpcode::kJSDebugger:
|
case IrOpcode::kJSDebugger:
|
||||||
// Type can be anything.
|
// Type can be anything.
|
||||||
CHECK(bounds(node).upper->Is(Type::Any()));
|
CheckUpperIs(node, Type::Any());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Simplified operators
|
// Simplified operators
|
||||||
// -------------------------------
|
// -------------------------------
|
||||||
case IrOpcode::kBooleanNot:
|
case IrOpcode::kBooleanNot:
|
||||||
// Boolean -> Boolean
|
// Boolean -> Boolean
|
||||||
CHECK(bounds(Operand(node)).upper->Is(Type::Boolean()));
|
CheckValueInputIs(node, 0, Type::Boolean());
|
||||||
CHECK(bounds(node).upper->Is(Type::Boolean()));
|
CheckUpperIs(node, Type::Boolean());
|
||||||
break;
|
break;
|
||||||
case IrOpcode::kBooleanToNumber:
|
case IrOpcode::kBooleanToNumber:
|
||||||
// Boolean -> Number
|
// Boolean -> Number
|
||||||
CHECK(bounds(Operand(node)).upper->Is(Type::Boolean()));
|
CheckValueInputIs(node, 0, Type::Boolean());
|
||||||
CHECK(bounds(node).upper->Is(Type::Number()));
|
CheckUpperIs(node, Type::Number());
|
||||||
break;
|
break;
|
||||||
case IrOpcode::kNumberEqual:
|
case IrOpcode::kNumberEqual:
|
||||||
case IrOpcode::kNumberLessThan:
|
case IrOpcode::kNumberLessThan:
|
||||||
case IrOpcode::kNumberLessThanOrEqual:
|
case IrOpcode::kNumberLessThanOrEqual:
|
||||||
// (Number, Number) -> Boolean
|
// (Number, Number) -> Boolean
|
||||||
CHECK(bounds(Operand(node, 0)).upper->Is(Type::Number()));
|
CheckValueInputIs(node, 0, Type::Number());
|
||||||
CHECK(bounds(Operand(node, 1)).upper->Is(Type::Number()));
|
CheckValueInputIs(node, 1, Type::Number());
|
||||||
CHECK(bounds(node).upper->Is(Type::Boolean()));
|
CheckUpperIs(node, Type::Boolean());
|
||||||
break;
|
break;
|
||||||
case IrOpcode::kNumberAdd:
|
case IrOpcode::kNumberAdd:
|
||||||
case IrOpcode::kNumberSubtract:
|
case IrOpcode::kNumberSubtract:
|
||||||
@ -449,50 +498,52 @@ GenericGraphVisit::Control Verifier::Visitor::Pre(Node* node) {
|
|||||||
case IrOpcode::kNumberDivide:
|
case IrOpcode::kNumberDivide:
|
||||||
case IrOpcode::kNumberModulus:
|
case IrOpcode::kNumberModulus:
|
||||||
// (Number, Number) -> Number
|
// (Number, Number) -> Number
|
||||||
CHECK(bounds(Operand(node, 0)).upper->Is(Type::Number()));
|
CheckValueInputIs(node, 0, Type::Number());
|
||||||
CHECK(bounds(Operand(node, 1)).upper->Is(Type::Number()));
|
CheckValueInputIs(node, 1, Type::Number());
|
||||||
// TODO(rossberg): activate once we retype after opcode changes.
|
// TODO(rossberg): activate once we retype after opcode changes.
|
||||||
// CHECK(bounds(node).upper->Is(Type::Number()));
|
// CheckUpperIs(node, Type::Number());
|
||||||
break;
|
break;
|
||||||
case IrOpcode::kNumberToInt32:
|
case IrOpcode::kNumberToInt32:
|
||||||
// Number -> Signed32
|
// Number -> Signed32
|
||||||
CHECK(bounds(Operand(node)).upper->Is(Type::Number()));
|
CheckValueInputIs(node, 0, Type::Number());
|
||||||
CHECK(bounds(node).upper->Is(Type::Signed32()));
|
CheckUpperIs(node, Type::Signed32());
|
||||||
break;
|
break;
|
||||||
case IrOpcode::kNumberToUint32:
|
case IrOpcode::kNumberToUint32:
|
||||||
// Number -> Unsigned32
|
// Number -> Unsigned32
|
||||||
CHECK(bounds(Operand(node)).upper->Is(Type::Number()));
|
CheckValueInputIs(node, 0, Type::Number());
|
||||||
CHECK(bounds(node).upper->Is(Type::Unsigned32()));
|
CheckUpperIs(node, Type::Unsigned32());
|
||||||
break;
|
break;
|
||||||
case IrOpcode::kStringEqual:
|
case IrOpcode::kStringEqual:
|
||||||
case IrOpcode::kStringLessThan:
|
case IrOpcode::kStringLessThan:
|
||||||
case IrOpcode::kStringLessThanOrEqual:
|
case IrOpcode::kStringLessThanOrEqual:
|
||||||
// (String, String) -> Boolean
|
// (String, String) -> Boolean
|
||||||
CHECK(bounds(Operand(node, 0)).upper->Is(Type::String()));
|
CheckValueInputIs(node, 0, Type::String());
|
||||||
CHECK(bounds(Operand(node, 1)).upper->Is(Type::String()));
|
CheckValueInputIs(node, 1, Type::String());
|
||||||
CHECK(bounds(node).upper->Is(Type::Boolean()));
|
CheckUpperIs(node, Type::Boolean());
|
||||||
break;
|
break;
|
||||||
case IrOpcode::kStringAdd:
|
case IrOpcode::kStringAdd:
|
||||||
// (String, String) -> String
|
// (String, String) -> String
|
||||||
CHECK(bounds(Operand(node, 0)).upper->Is(Type::String()));
|
CheckValueInputIs(node, 0, Type::String());
|
||||||
CHECK(bounds(Operand(node, 1)).upper->Is(Type::String()));
|
CheckValueInputIs(node, 1, Type::String());
|
||||||
CHECK(bounds(node).upper->Is(Type::String()));
|
CheckUpperIs(node, Type::String());
|
||||||
break;
|
break;
|
||||||
case IrOpcode::kReferenceEqual: {
|
case IrOpcode::kReferenceEqual: {
|
||||||
// (Unique, Any) -> Boolean and
|
// (Unique, Any) -> Boolean and
|
||||||
// (Any, Unique) -> Boolean
|
// (Any, Unique) -> Boolean
|
||||||
CHECK(bounds(Operand(node, 0)).upper->Is(Type::Unique()) ||
|
if (typing == TYPED) {
|
||||||
bounds(Operand(node, 1)).upper->Is(Type::Unique()));
|
CHECK(bounds(ValueInput(node, 0)).upper->Is(Type::Unique()) ||
|
||||||
CHECK(bounds(node).upper->Is(Type::Boolean()));
|
bounds(ValueInput(node, 1)).upper->Is(Type::Unique()));
|
||||||
|
}
|
||||||
|
CheckUpperIs(node, Type::Boolean());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case IrOpcode::kObjectIsSmi:
|
case IrOpcode::kObjectIsSmi:
|
||||||
CHECK(bounds(Operand(node)).upper->Is(Type::Any()));
|
CheckValueInputIs(node, 0, Type::Any());
|
||||||
CHECK(bounds(node).upper->Is(Type::Boolean()));
|
CheckUpperIs(node, Type::Boolean());
|
||||||
break;
|
break;
|
||||||
case IrOpcode::kObjectIsNonNegativeSmi:
|
case IrOpcode::kObjectIsNonNegativeSmi:
|
||||||
CHECK(bounds(Operand(node)).upper->Is(Type::Any()));
|
CheckValueInputIs(node, 0, Type::Any());
|
||||||
CHECK(bounds(node).upper->Is(Type::Boolean()));
|
CheckUpperIs(node, Type::Boolean());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case IrOpcode::kChangeTaggedToInt32: {
|
case IrOpcode::kChangeTaggedToInt32: {
|
||||||
@ -500,8 +551,8 @@ GenericGraphVisit::Control Verifier::Visitor::Pre(Node* node) {
|
|||||||
// TODO(neis): Activate once ChangeRepresentation works in typer.
|
// TODO(neis): Activate once ChangeRepresentation works in typer.
|
||||||
// Type* from = Type::Intersect(Type::Signed32(), Type::Tagged());
|
// Type* from = Type::Intersect(Type::Signed32(), Type::Tagged());
|
||||||
// Type* to = Type::Intersect(Type::Signed32(), Type::UntaggedInt32());
|
// Type* to = Type::Intersect(Type::Signed32(), Type::UntaggedInt32());
|
||||||
// CHECK(bounds(Operand(node)).upper->Is(from));
|
// CheckValueInputIs(node, 0, from));
|
||||||
// CHECK(bounds(node).upper->Is(to));
|
// CheckUpperIs(node, to));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case IrOpcode::kChangeTaggedToUint32: {
|
case IrOpcode::kChangeTaggedToUint32: {
|
||||||
@ -509,8 +560,8 @@ GenericGraphVisit::Control Verifier::Visitor::Pre(Node* node) {
|
|||||||
// TODO(neis): Activate once ChangeRepresentation works in typer.
|
// TODO(neis): Activate once ChangeRepresentation works in typer.
|
||||||
// Type* from = Type::Intersect(Type::Unsigned32(), Type::Tagged());
|
// Type* from = Type::Intersect(Type::Unsigned32(), Type::Tagged());
|
||||||
// Type* to =Type::Intersect(Type::Unsigned32(), Type::UntaggedInt32());
|
// Type* to =Type::Intersect(Type::Unsigned32(), Type::UntaggedInt32());
|
||||||
// CHECK(bounds(Operand(node)).upper->Is(from));
|
// CheckValueInputIs(node, 0, from));
|
||||||
// CHECK(bounds(node).upper->Is(to));
|
// CheckUpperIs(node, to));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case IrOpcode::kChangeTaggedToFloat64: {
|
case IrOpcode::kChangeTaggedToFloat64: {
|
||||||
@ -518,8 +569,8 @@ GenericGraphVisit::Control Verifier::Visitor::Pre(Node* node) {
|
|||||||
// TODO(neis): Activate once ChangeRepresentation works in typer.
|
// TODO(neis): Activate once ChangeRepresentation works in typer.
|
||||||
// Type* from = Type::Intersect(Type::Number(), Type::Tagged());
|
// Type* from = Type::Intersect(Type::Number(), Type::Tagged());
|
||||||
// Type* to = Type::Intersect(Type::Number(), Type::UntaggedFloat64());
|
// Type* to = Type::Intersect(Type::Number(), Type::UntaggedFloat64());
|
||||||
// CHECK(bounds(Operand(node)).upper->Is(from));
|
// CheckValueInputIs(node, 0, from));
|
||||||
// CHECK(bounds(node).upper->Is(to));
|
// CheckUpperIs(node, to));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case IrOpcode::kChangeInt32ToTagged: {
|
case IrOpcode::kChangeInt32ToTagged: {
|
||||||
@ -527,8 +578,8 @@ GenericGraphVisit::Control Verifier::Visitor::Pre(Node* node) {
|
|||||||
// TODO(neis): Activate once ChangeRepresentation works in typer.
|
// TODO(neis): Activate once ChangeRepresentation works in typer.
|
||||||
// Type* from =Type::Intersect(Type::Signed32(), Type::UntaggedInt32());
|
// Type* from =Type::Intersect(Type::Signed32(), Type::UntaggedInt32());
|
||||||
// Type* to = Type::Intersect(Type::Signed32(), Type::Tagged());
|
// Type* to = Type::Intersect(Type::Signed32(), Type::Tagged());
|
||||||
// CHECK(bounds(Operand(node)).upper->Is(from));
|
// CheckValueInputIs(node, 0, from));
|
||||||
// CHECK(bounds(node).upper->Is(to));
|
// CheckUpperIs(node, to));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case IrOpcode::kChangeUint32ToTagged: {
|
case IrOpcode::kChangeUint32ToTagged: {
|
||||||
@ -536,8 +587,8 @@ GenericGraphVisit::Control Verifier::Visitor::Pre(Node* node) {
|
|||||||
// TODO(neis): Activate once ChangeRepresentation works in typer.
|
// TODO(neis): Activate once ChangeRepresentation works in typer.
|
||||||
// Type* from=Type::Intersect(Type::Unsigned32(),Type::UntaggedInt32());
|
// Type* from=Type::Intersect(Type::Unsigned32(),Type::UntaggedInt32());
|
||||||
// Type* to = Type::Intersect(Type::Unsigned32(), Type::Tagged());
|
// Type* to = Type::Intersect(Type::Unsigned32(), Type::Tagged());
|
||||||
// CHECK(bounds(Operand(node)).upper->Is(from));
|
// CheckValueInputIs(node, 0, from));
|
||||||
// CHECK(bounds(node).upper->Is(to));
|
// CheckUpperIs(node, to));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case IrOpcode::kChangeFloat64ToTagged: {
|
case IrOpcode::kChangeFloat64ToTagged: {
|
||||||
@ -545,8 +596,8 @@ GenericGraphVisit::Control Verifier::Visitor::Pre(Node* node) {
|
|||||||
// TODO(neis): Activate once ChangeRepresentation works in typer.
|
// TODO(neis): Activate once ChangeRepresentation works in typer.
|
||||||
// Type* from =Type::Intersect(Type::Number(), Type::UntaggedFloat64());
|
// Type* from =Type::Intersect(Type::Number(), Type::UntaggedFloat64());
|
||||||
// Type* to = Type::Intersect(Type::Number(), Type::Tagged());
|
// Type* to = Type::Intersect(Type::Number(), Type::Tagged());
|
||||||
// CHECK(bounds(Operand(node)).upper->Is(from));
|
// CheckValueInputIs(node, 0, from));
|
||||||
// CHECK(bounds(node).upper->Is(to));
|
// CheckUpperIs(node, to));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case IrOpcode::kChangeBoolToBit: {
|
case IrOpcode::kChangeBoolToBit: {
|
||||||
@ -554,8 +605,8 @@ GenericGraphVisit::Control Verifier::Visitor::Pre(Node* node) {
|
|||||||
// TODO(neis): Activate once ChangeRepresentation works in typer.
|
// TODO(neis): Activate once ChangeRepresentation works in typer.
|
||||||
// Type* from = Type::Intersect(Type::Boolean(), Type::TaggedPtr());
|
// Type* from = Type::Intersect(Type::Boolean(), Type::TaggedPtr());
|
||||||
// Type* to = Type::Intersect(Type::Boolean(), Type::UntaggedInt1());
|
// Type* to = Type::Intersect(Type::Boolean(), Type::UntaggedInt1());
|
||||||
// CHECK(bounds(Operand(node)).upper->Is(from));
|
// CheckValueInputIs(node, 0, from));
|
||||||
// CHECK(bounds(node).upper->Is(to));
|
// CheckUpperIs(node, to));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case IrOpcode::kChangeBitToBool: {
|
case IrOpcode::kChangeBitToBool: {
|
||||||
@ -563,36 +614,36 @@ GenericGraphVisit::Control Verifier::Visitor::Pre(Node* node) {
|
|||||||
// TODO(neis): Activate once ChangeRepresentation works in typer.
|
// TODO(neis): Activate once ChangeRepresentation works in typer.
|
||||||
// Type* from = Type::Intersect(Type::Boolean(), Type::UntaggedInt1());
|
// Type* from = Type::Intersect(Type::Boolean(), Type::UntaggedInt1());
|
||||||
// Type* to = Type::Intersect(Type::Boolean(), Type::TaggedPtr());
|
// Type* to = Type::Intersect(Type::Boolean(), Type::TaggedPtr());
|
||||||
// CHECK(bounds(Operand(node)).upper->Is(from));
|
// CheckValueInputIs(node, 0, from));
|
||||||
// CHECK(bounds(node).upper->Is(to));
|
// CheckUpperIs(node, to));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case IrOpcode::kLoadField:
|
case IrOpcode::kLoadField:
|
||||||
// Object -> fieldtype
|
// Object -> fieldtype
|
||||||
// TODO(rossberg): activate once machine ops are typed.
|
// TODO(rossberg): activate once machine ops are typed.
|
||||||
// CHECK(bounds(Operand(node)).upper->Is(Type::Object()));
|
// CheckValueInputIs(node, 0, Type::Object());
|
||||||
// CHECK(bounds(node).upper->Is(Field(node).type));
|
// CheckUpperIs(node, Field(node).type));
|
||||||
break;
|
break;
|
||||||
case IrOpcode::kLoadElement:
|
case IrOpcode::kLoadElement:
|
||||||
// Object -> elementtype
|
// Object -> elementtype
|
||||||
// TODO(rossberg): activate once machine ops are typed.
|
// TODO(rossberg): activate once machine ops are typed.
|
||||||
// CHECK(bounds(Operand(node)).upper->Is(Type::Object()));
|
// CheckValueInputIs(node, 0, Type::Object());
|
||||||
// CHECK(bounds(node).upper->Is(Element(node).type));
|
// CheckUpperIs(node, Element(node).type));
|
||||||
break;
|
break;
|
||||||
case IrOpcode::kStoreField:
|
case IrOpcode::kStoreField:
|
||||||
// (Object, fieldtype) -> _|_
|
// (Object, fieldtype) -> _|_
|
||||||
// TODO(rossberg): activate once machine ops are typed.
|
// TODO(rossberg): activate once machine ops are typed.
|
||||||
// CHECK(bounds(Operand(node, 0)).upper->Is(Type::Object()));
|
// CheckValueInputIs(node, 0, Type::Object());
|
||||||
// CHECK(bounds(Operand(node, 1)).upper->Is(Field(node).type));
|
// CheckValueInputIs(node, 1, Field(node).type));
|
||||||
CHECK(!NodeProperties::IsTyped(node));
|
CheckNotTyped(node);
|
||||||
break;
|
break;
|
||||||
case IrOpcode::kStoreElement:
|
case IrOpcode::kStoreElement:
|
||||||
// (Object, elementtype) -> _|_
|
// (Object, elementtype) -> _|_
|
||||||
// TODO(rossberg): activate once machine ops are typed.
|
// TODO(rossberg): activate once machine ops are typed.
|
||||||
// CHECK(bounds(Operand(node, 0)).upper->Is(Type::Object()));
|
// CheckValueInputIs(node, 0, Type::Object());
|
||||||
// CHECK(bounds(Operand(node, 1)).upper->Is(Element(node).type));
|
// CheckValueInputIs(node, 1, Element(node).type));
|
||||||
CHECK(!NodeProperties::IsTyped(node));
|
CheckNotTyped(node);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Machine operators
|
// Machine operators
|
||||||
@ -662,7 +713,6 @@ GenericGraphVisit::Control Verifier::Visitor::Pre(Node* node) {
|
|||||||
// TODO(rossberg): Check.
|
// TODO(rossberg): Check.
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return GenericGraphVisit::CONTINUE;
|
return GenericGraphVisit::CONTINUE;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user