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:
titzer@chromium.org 2014-10-22 14:39:41 +00:00
parent db000e307a
commit f843327ea0

View File

@ -6,6 +6,8 @@
#include <deque>
#include <queue>
#include <sstream>
#include <string>
#include "src/compiler/generic-algorithm.h"
#include "src/compiler/generic-node-inl.h"
@ -20,6 +22,7 @@
#include "src/compiler/schedule.h"
#include "src/compiler/simplified-operator.h"
#include "src/data-flow.h"
#include "src/ostreams.h"
namespace v8 {
namespace internal {
@ -56,10 +59,8 @@ class Verifier::Visitor : public NullNodeVisitor {
private:
// TODO(rossberg): Get rid of these once we got rid of NodeProperties.
Bounds bounds(Node* node) {
return NodeProperties::GetBounds(node);
}
Node* Operand(Node* node, int i = 0) {
Bounds bounds(Node* node) { return NodeProperties::GetBounds(node); }
Node* ValueInput(Node* node, int i = 0) {
return NodeProperties::GetValueInput(node, i);
}
FieldAccess Field(Node* node) {
@ -72,6 +73,50 @@ class Verifier::Visitor : public NullNodeVisitor {
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());
}
}
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()) {
// Control operators
// -----------------
case IrOpcode::kStart:
// Start has no inputs.
CHECK_EQ(0, input_count);
// Type is a tuple.
// TODO(rossberg): Multiple outputs are currently typed as Internal.
CHECK(bounds(node).upper->Is(Type::Internal()));
CheckUpperIs(node, Type::Internal());
break;
case IrOpcode::kEnd:
// End has no outputs.
@ -158,7 +200,7 @@ GenericGraphVisit::Control Verifier::Visitor::Pre(Node* node) {
CHECK(!OperatorProperties::HasEffectOutput(node->op()));
CHECK(!OperatorProperties::HasControlOutput(node->op()));
// Type is empty.
CHECK(!NodeProperties::IsTyped(node));
CheckNotTyped(node);
break;
case IrOpcode::kDead:
// 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);
// Type is empty.
CHECK(!NodeProperties::IsTyped(node));
CheckNotTyped(node);
break;
}
case IrOpcode::kIfTrue:
@ -183,22 +225,23 @@ GenericGraphVisit::Control Verifier::Visitor::Pre(Node* node) {
CHECK_EQ(IrOpcode::kBranch,
NodeProperties::GetControlInput(node, 0)->opcode());
// Type is empty.
CHECK(!NodeProperties::IsTyped(node));
CheckNotTyped(node);
break;
case IrOpcode::kLoop:
case IrOpcode::kMerge:
CHECK_EQ(control_count, input_count);
// Type is empty.
CHECK(!NodeProperties::IsTyped(node));
CheckNotTyped(node);
break;
case IrOpcode::kReturn:
// TODO(rossberg): check successor is End
// Type is empty.
CHECK(!NodeProperties::IsTyped(node));
CheckNotTyped(node);
break;
case IrOpcode::kThrow:
// TODO(rossberg): what are the constraints on these?
// Type is empty.
CHECK(!NodeProperties::IsTyped(node));
CheckNotTyped(node);
break;
// Common operators
@ -212,24 +255,23 @@ GenericGraphVisit::Control Verifier::Visitor::Pre(Node* node) {
int index = OpParameter<int>(node);
Node* input = NodeProperties::GetValueInput(node, 0);
// Currently, parameter indices start at -1 instead of 0.
CHECK_GT(
OperatorProperties::GetValueOutputCount(input->op()), index + 1);
CHECK_GT(OperatorProperties::GetValueOutputCount(input->op()), index + 1);
// Type can be anything.
CHECK(bounds(node).upper->Is(Type::Any()));
CheckUpperIs(node, Type::Any());
break;
}
case IrOpcode::kInt32Constant: // TODO(rossberg): rename Word32Constant?
// Constants have no inputs.
CHECK_EQ(0, input_count);
// Type is a 32 bit integer, signed or unsigned.
CHECK(bounds(node).upper->Is(Type::Integral32()));
CheckUpperIs(node, Type::Integral32());
break;
case IrOpcode::kInt64Constant:
// Constants have no inputs.
CHECK_EQ(0, input_count);
// Type is internal.
// TODO(rossberg): Introduce proper Int64 type.
CHECK(bounds(node).upper->Is(Type::Internal()));
CheckUpperIs(node, Type::Internal());
break;
case IrOpcode::kFloat32Constant:
case IrOpcode::kFloat64Constant:
@ -237,19 +279,19 @@ GenericGraphVisit::Control Verifier::Visitor::Pre(Node* node) {
// Constants have no inputs.
CHECK_EQ(0, input_count);
// Type is a number.
CHECK(bounds(node).upper->Is(Type::Number()));
CheckUpperIs(node, Type::Number());
break;
case IrOpcode::kHeapConstant:
// Constants have no inputs.
CHECK_EQ(0, input_count);
// Type can be anything represented as a heap pointer.
CHECK(bounds(node).upper->Is(Type::TaggedPtr()));
CheckUpperIs(node, Type::TaggedPtr());
break;
case IrOpcode::kExternalConstant:
// Constants have no inputs.
CHECK_EQ(0, input_count);
// Type is considered internal.
CHECK(bounds(node).upper->Is(Type::Internal()));
CheckUpperIs(node, Type::Internal());
break;
case IrOpcode::kProjection: {
// 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);
// Type can be anything.
// 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;
}
case IrOpcode::kPhi: {
// Phi input count matches parent control node.
CHECK_EQ(0, effect_count);
CHECK_EQ(1, control_count);
Node* control = NodeProperties::GetControlInput(node, 0);
CHECK_EQ(value_count,
OperatorProperties::GetControlInputCount(control->op()));
CHECK_EQ(input_count, 1 + value_count);
// Type must be subsumed by all input types.
// 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(Operand(node, i)).lower));
CHECK(bounds(Operand(node, i)).upper->Is(bounds(node).upper));
// CHECK(bounds(node).lower->Is(bounds(ValueInput(node, i)).lower));
CHECK(bounds(ValueInput(node, i)).upper->Is(bounds(node).upper));
}
*/
break;
}
case IrOpcode::kEffectPhi: {
// EffectPhi input count matches parent control node.
CHECK_EQ(0, value_count);
CHECK_EQ(1, control_count);
Node* control = NodeProperties::GetControlInput(node, 0);
CHECK_EQ(effect_count,
OperatorProperties::GetControlInputCount(control->op()));
CHECK_EQ(input_count, 1 + effect_count);
break;
}
case IrOpcode::kValueEffect:
@ -292,8 +339,10 @@ GenericGraphVisit::Control Verifier::Visitor::Pre(Node* node) {
case IrOpcode::kFinish: {
// TODO(rossberg): what are the constraints on these?
// Type must be subsumed by input type.
CHECK(bounds(Operand(node)).lower->Is(bounds(node).lower));
CHECK(bounds(Operand(node)).upper->Is(bounds(node).upper));
if (typing == TYPED) {
CHECK(bounds(ValueInput(node)).lower->Is(bounds(node).lower));
CHECK(bounds(ValueInput(node)).upper->Is(bounds(node).upper));
}
break;
}
case IrOpcode::kFrameState:
@ -318,7 +367,7 @@ GenericGraphVisit::Control Verifier::Visitor::Pre(Node* node) {
case IrOpcode::kJSGreaterThanOrEqual:
case IrOpcode::kJSUnaryNot:
// Type is Boolean.
CHECK(bounds(node).upper->Is(Type::Boolean()));
CheckUpperIs(node, Type::Boolean());
break;
case IrOpcode::kJSBitwiseOr:
@ -328,73 +377,73 @@ GenericGraphVisit::Control Verifier::Visitor::Pre(Node* node) {
case IrOpcode::kJSShiftRight:
case IrOpcode::kJSShiftRightLogical:
// Type is 32 bit integral.
CHECK(bounds(node).upper->Is(Type::Integral32()));
CheckUpperIs(node, Type::Integral32());
break;
case IrOpcode::kJSAdd:
// Type is Number or String.
CHECK(bounds(node).upper->Is(Type::NumberOrString()));
CheckUpperIs(node, Type::NumberOrString());
break;
case IrOpcode::kJSSubtract:
case IrOpcode::kJSMultiply:
case IrOpcode::kJSDivide:
case IrOpcode::kJSModulus:
// Type is Number.
CHECK(bounds(node).upper->Is(Type::Number()));
CheckUpperIs(node, Type::Number());
break;
case IrOpcode::kJSToBoolean:
// Type is Boolean.
CHECK(bounds(node).upper->Is(Type::Boolean()));
CheckUpperIs(node, Type::Boolean());
break;
case IrOpcode::kJSToNumber:
// Type is Number.
CHECK(bounds(node).upper->Is(Type::Number()));
CheckUpperIs(node, Type::Number());
break;
case IrOpcode::kJSToString:
// Type is String.
CHECK(bounds(node).upper->Is(Type::String()));
CheckUpperIs(node, Type::String());
break;
case IrOpcode::kJSToName:
// Type is Name.
CHECK(bounds(node).upper->Is(Type::Name()));
CheckUpperIs(node, Type::Name());
break;
case IrOpcode::kJSToObject:
// Type is Receiver.
CHECK(bounds(node).upper->Is(Type::Receiver()));
CheckUpperIs(node, Type::Receiver());
break;
case IrOpcode::kJSCreate:
// Type is Object.
CHECK(bounds(node).upper->Is(Type::Object()));
CheckUpperIs(node, Type::Object());
break;
case IrOpcode::kJSLoadProperty:
case IrOpcode::kJSLoadNamed:
// Type can be anything.
CHECK(bounds(node).upper->Is(Type::Any()));
CheckUpperIs(node, Type::Any());
break;
case IrOpcode::kJSStoreProperty:
case IrOpcode::kJSStoreNamed:
// Type is empty.
CHECK(!NodeProperties::IsTyped(node));
CheckNotTyped(node);
break;
case IrOpcode::kJSDeleteProperty:
case IrOpcode::kJSHasProperty:
case IrOpcode::kJSInstanceOf:
// Type is Boolean.
CHECK(bounds(node).upper->Is(Type::Boolean()));
CheckUpperIs(node, Type::Boolean());
break;
case IrOpcode::kJSTypeOf:
// Type is String.
CHECK(bounds(node).upper->Is(Type::String()));
CheckUpperIs(node, Type::String());
break;
case IrOpcode::kJSLoadContext:
// Type can be anything.
CHECK(bounds(node).upper->Is(Type::Any()));
CheckUpperIs(node, Type::Any());
break;
case IrOpcode::kJSStoreContext:
// Type is empty.
CHECK(!NodeProperties::IsTyped(node));
CheckNotTyped(node);
break;
case IrOpcode::kJSCreateFunctionContext:
case IrOpcode::kJSCreateCatchContext:
@ -403,45 +452,45 @@ GenericGraphVisit::Control Verifier::Visitor::Pre(Node* node) {
case IrOpcode::kJSCreateModuleContext:
case IrOpcode::kJSCreateGlobalContext: {
// 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
// currently can't do backwards propagation.
CHECK(outer.upper->Maybe(Type::Internal()));
CHECK(bounds(node).upper->IsContext());
CheckUpperMaybe(context, Type::Internal());
if (typing == TYPED) CHECK(bounds(node).upper->IsContext());
break;
}
case IrOpcode::kJSCallConstruct:
// Type is Receiver.
CHECK(bounds(node).upper->Is(Type::Receiver()));
CheckUpperIs(node, Type::Receiver());
break;
case IrOpcode::kJSCallFunction:
case IrOpcode::kJSCallRuntime:
case IrOpcode::kJSYield:
case IrOpcode::kJSDebugger:
// Type can be anything.
CHECK(bounds(node).upper->Is(Type::Any()));
CheckUpperIs(node, Type::Any());
break;
// Simplified operators
// -------------------------------
case IrOpcode::kBooleanNot:
// Boolean -> Boolean
CHECK(bounds(Operand(node)).upper->Is(Type::Boolean()));
CHECK(bounds(node).upper->Is(Type::Boolean()));
CheckValueInputIs(node, 0, Type::Boolean());
CheckUpperIs(node, Type::Boolean());
break;
case IrOpcode::kBooleanToNumber:
// Boolean -> Number
CHECK(bounds(Operand(node)).upper->Is(Type::Boolean()));
CHECK(bounds(node).upper->Is(Type::Number()));
CheckValueInputIs(node, 0, Type::Boolean());
CheckUpperIs(node, Type::Number());
break;
case IrOpcode::kNumberEqual:
case IrOpcode::kNumberLessThan:
case IrOpcode::kNumberLessThanOrEqual:
// (Number, Number) -> Boolean
CHECK(bounds(Operand(node, 0)).upper->Is(Type::Number()));
CHECK(bounds(Operand(node, 1)).upper->Is(Type::Number()));
CHECK(bounds(node).upper->Is(Type::Boolean()));
CheckValueInputIs(node, 0, Type::Number());
CheckValueInputIs(node, 1, Type::Number());
CheckUpperIs(node, Type::Boolean());
break;
case IrOpcode::kNumberAdd:
case IrOpcode::kNumberSubtract:
@ -449,50 +498,52 @@ GenericGraphVisit::Control Verifier::Visitor::Pre(Node* node) {
case IrOpcode::kNumberDivide:
case IrOpcode::kNumberModulus:
// (Number, Number) -> Number
CHECK(bounds(Operand(node, 0)).upper->Is(Type::Number()));
CHECK(bounds(Operand(node, 1)).upper->Is(Type::Number()));
CheckValueInputIs(node, 0, Type::Number());
CheckValueInputIs(node, 1, Type::Number());
// TODO(rossberg): activate once we retype after opcode changes.
// CHECK(bounds(node).upper->Is(Type::Number()));
// CheckUpperIs(node, Type::Number());
break;
case IrOpcode::kNumberToInt32:
// Number -> Signed32
CHECK(bounds(Operand(node)).upper->Is(Type::Number()));
CHECK(bounds(node).upper->Is(Type::Signed32()));
CheckValueInputIs(node, 0, Type::Number());
CheckUpperIs(node, Type::Signed32());
break;
case IrOpcode::kNumberToUint32:
// Number -> Unsigned32
CHECK(bounds(Operand(node)).upper->Is(Type::Number()));
CHECK(bounds(node).upper->Is(Type::Unsigned32()));
CheckValueInputIs(node, 0, Type::Number());
CheckUpperIs(node, Type::Unsigned32());
break;
case IrOpcode::kStringEqual:
case IrOpcode::kStringLessThan:
case IrOpcode::kStringLessThanOrEqual:
// (String, String) -> Boolean
CHECK(bounds(Operand(node, 0)).upper->Is(Type::String()));
CHECK(bounds(Operand(node, 1)).upper->Is(Type::String()));
CHECK(bounds(node).upper->Is(Type::Boolean()));
CheckValueInputIs(node, 0, Type::String());
CheckValueInputIs(node, 1, Type::String());
CheckUpperIs(node, Type::Boolean());
break;
case IrOpcode::kStringAdd:
// (String, String) -> String
CHECK(bounds(Operand(node, 0)).upper->Is(Type::String()));
CHECK(bounds(Operand(node, 1)).upper->Is(Type::String()));
CHECK(bounds(node).upper->Is(Type::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
CHECK(bounds(Operand(node, 0)).upper->Is(Type::Unique()) ||
bounds(Operand(node, 1)).upper->Is(Type::Unique()));
CHECK(bounds(node).upper->Is(Type::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::kObjectIsSmi:
CHECK(bounds(Operand(node)).upper->Is(Type::Any()));
CHECK(bounds(node).upper->Is(Type::Boolean()));
CheckValueInputIs(node, 0, Type::Any());
CheckUpperIs(node, Type::Boolean());
break;
case IrOpcode::kObjectIsNonNegativeSmi:
CHECK(bounds(Operand(node)).upper->Is(Type::Any()));
CHECK(bounds(node).upper->Is(Type::Boolean()));
CheckValueInputIs(node, 0, Type::Any());
CheckUpperIs(node, Type::Boolean());
break;
case IrOpcode::kChangeTaggedToInt32: {
@ -500,8 +551,8 @@ GenericGraphVisit::Control Verifier::Visitor::Pre(Node* node) {
// TODO(neis): Activate once ChangeRepresentation works in typer.
// Type* from = Type::Intersect(Type::Signed32(), Type::Tagged());
// Type* to = Type::Intersect(Type::Signed32(), Type::UntaggedInt32());
// CHECK(bounds(Operand(node)).upper->Is(from));
// CHECK(bounds(node).upper->Is(to));
// CheckValueInputIs(node, 0, from));
// CheckUpperIs(node, to));
break;
}
case IrOpcode::kChangeTaggedToUint32: {
@ -509,8 +560,8 @@ GenericGraphVisit::Control Verifier::Visitor::Pre(Node* node) {
// TODO(neis): Activate once ChangeRepresentation works in typer.
// Type* from = Type::Intersect(Type::Unsigned32(), Type::Tagged());
// Type* to =Type::Intersect(Type::Unsigned32(), Type::UntaggedInt32());
// CHECK(bounds(Operand(node)).upper->Is(from));
// CHECK(bounds(node).upper->Is(to));
// CheckValueInputIs(node, 0, from));
// CheckUpperIs(node, to));
break;
}
case IrOpcode::kChangeTaggedToFloat64: {
@ -518,8 +569,8 @@ GenericGraphVisit::Control Verifier::Visitor::Pre(Node* node) {
// TODO(neis): Activate once ChangeRepresentation works in typer.
// Type* from = Type::Intersect(Type::Number(), Type::Tagged());
// Type* to = Type::Intersect(Type::Number(), Type::UntaggedFloat64());
// CHECK(bounds(Operand(node)).upper->Is(from));
// CHECK(bounds(node).upper->Is(to));
// CheckValueInputIs(node, 0, from));
// CheckUpperIs(node, to));
break;
}
case IrOpcode::kChangeInt32ToTagged: {
@ -527,8 +578,8 @@ GenericGraphVisit::Control Verifier::Visitor::Pre(Node* node) {
// TODO(neis): Activate once ChangeRepresentation works in typer.
// Type* from =Type::Intersect(Type::Signed32(), Type::UntaggedInt32());
// Type* to = Type::Intersect(Type::Signed32(), Type::Tagged());
// CHECK(bounds(Operand(node)).upper->Is(from));
// CHECK(bounds(node).upper->Is(to));
// CheckValueInputIs(node, 0, from));
// CheckUpperIs(node, to));
break;
}
case IrOpcode::kChangeUint32ToTagged: {
@ -536,8 +587,8 @@ GenericGraphVisit::Control Verifier::Visitor::Pre(Node* node) {
// TODO(neis): Activate once ChangeRepresentation works in typer.
// Type* from=Type::Intersect(Type::Unsigned32(),Type::UntaggedInt32());
// Type* to = Type::Intersect(Type::Unsigned32(), Type::Tagged());
// CHECK(bounds(Operand(node)).upper->Is(from));
// CHECK(bounds(node).upper->Is(to));
// CheckValueInputIs(node, 0, from));
// CheckUpperIs(node, to));
break;
}
case IrOpcode::kChangeFloat64ToTagged: {
@ -545,8 +596,8 @@ GenericGraphVisit::Control Verifier::Visitor::Pre(Node* node) {
// TODO(neis): Activate once ChangeRepresentation works in typer.
// Type* from =Type::Intersect(Type::Number(), Type::UntaggedFloat64());
// Type* to = Type::Intersect(Type::Number(), Type::Tagged());
// CHECK(bounds(Operand(node)).upper->Is(from));
// CHECK(bounds(node).upper->Is(to));
// CheckValueInputIs(node, 0, from));
// CheckUpperIs(node, to));
break;
}
case IrOpcode::kChangeBoolToBit: {
@ -554,8 +605,8 @@ GenericGraphVisit::Control Verifier::Visitor::Pre(Node* node) {
// TODO(neis): Activate once ChangeRepresentation works in typer.
// Type* from = Type::Intersect(Type::Boolean(), Type::TaggedPtr());
// Type* to = Type::Intersect(Type::Boolean(), Type::UntaggedInt1());
// CHECK(bounds(Operand(node)).upper->Is(from));
// CHECK(bounds(node).upper->Is(to));
// CheckValueInputIs(node, 0, from));
// CheckUpperIs(node, to));
break;
}
case IrOpcode::kChangeBitToBool: {
@ -563,36 +614,36 @@ GenericGraphVisit::Control Verifier::Visitor::Pre(Node* node) {
// TODO(neis): Activate once ChangeRepresentation works in typer.
// Type* from = Type::Intersect(Type::Boolean(), Type::UntaggedInt1());
// Type* to = Type::Intersect(Type::Boolean(), Type::TaggedPtr());
// CHECK(bounds(Operand(node)).upper->Is(from));
// CHECK(bounds(node).upper->Is(to));
// CheckValueInputIs(node, 0, from));
// CheckUpperIs(node, to));
break;
}
case IrOpcode::kLoadField:
// Object -> fieldtype
// TODO(rossberg): activate once machine ops are typed.
// CHECK(bounds(Operand(node)).upper->Is(Type::Object()));
// CHECK(bounds(node).upper->Is(Field(node).type));
// CheckValueInputIs(node, 0, Type::Object());
// CheckUpperIs(node, Field(node).type));
break;
case IrOpcode::kLoadElement:
// Object -> elementtype
// TODO(rossberg): activate once machine ops are typed.
// CHECK(bounds(Operand(node)).upper->Is(Type::Object()));
// CHECK(bounds(node).upper->Is(Element(node).type));
// CheckValueInputIs(node, 0, Type::Object());
// CheckUpperIs(node, Element(node).type));
break;
case IrOpcode::kStoreField:
// (Object, fieldtype) -> _|_
// TODO(rossberg): activate once machine ops are typed.
// CHECK(bounds(Operand(node, 0)).upper->Is(Type::Object()));
// CHECK(bounds(Operand(node, 1)).upper->Is(Field(node).type));
CHECK(!NodeProperties::IsTyped(node));
// CheckValueInputIs(node, 0, Type::Object());
// CheckValueInputIs(node, 1, Field(node).type));
CheckNotTyped(node);
break;
case IrOpcode::kStoreElement:
// (Object, elementtype) -> _|_
// TODO(rossberg): activate once machine ops are typed.
// CHECK(bounds(Operand(node, 0)).upper->Is(Type::Object()));
// CHECK(bounds(Operand(node, 1)).upper->Is(Element(node).type));
CHECK(!NodeProperties::IsTyped(node));
// CheckValueInputIs(node, 0, Type::Object());
// CheckValueInputIs(node, 1, Element(node).type));
CheckNotTyped(node);
break;
// Machine operators
@ -662,7 +713,6 @@ GenericGraphVisit::Control Verifier::Visitor::Pre(Node* node) {
// TODO(rossberg): Check.
break;
}
}
return GenericGraphVisit::CONTINUE;
}