From f843327ea0cb88257851c2c8ffcaac4df82221f5 Mon Sep 17 00:00:00 2001 From: "titzer@chromium.org" Date: Wed, 22 Oct 2014 14:39:41 +0000 Subject: [PATCH] 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 --- src/compiler/verifier.cc | 1088 ++++++++++++++++++++++++---------------------- 1 file changed, 569 insertions(+), 519 deletions(-) diff --git a/src/compiler/verifier.cc b/src/compiler/verifier.cc index f2ad4ba..ab70ade 100644 --- a/src/compiler/verifier.cc +++ b/src/compiler/verifier.cc @@ -6,6 +6,8 @@ #include #include +#include +#include #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(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,527 +186,532 @@ 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())); - break; - case IrOpcode::kEnd: - // End has no outputs. - CHECK(!OperatorProperties::HasValueOutput(node->op())); - CHECK(!OperatorProperties::HasEffectOutput(node->op())); - CHECK(!OperatorProperties::HasControlOutput(node->op())); - // Type is empty. - CHECK(!NodeProperties::IsTyped(node)); - break; - case IrOpcode::kDead: - // Dead is never connected to the graph. - UNREACHABLE(); - 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; - } - CHECK(count_true == 1 && count_false == 1); - // Type is empty. - CHECK(!NodeProperties::IsTyped(node)); - break; + switch (node->opcode()) { + 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. + CheckUpperIs(node, Type::Internal()); + break; + case IrOpcode::kEnd: + // End has no outputs. + CHECK(!OperatorProperties::HasValueOutput(node->op())); + CHECK(!OperatorProperties::HasEffectOutput(node->op())); + CHECK(!OperatorProperties::HasControlOutput(node->op())); + // Type is empty. + CheckNotTyped(node); + break; + case IrOpcode::kDead: + // Dead is never connected to the graph. + UNREACHABLE(); + 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; } - case IrOpcode::kIfTrue: - case IrOpcode::kIfFalse: - CHECK_EQ(IrOpcode::kBranch, - NodeProperties::GetControlInput(node, 0)->opcode()); - // Type is empty. - CHECK(!NodeProperties::IsTyped(node)); - break; - case IrOpcode::kLoop: - case IrOpcode::kMerge: - // Type is empty. - CHECK(!NodeProperties::IsTyped(node)); - break; - case IrOpcode::kReturn: - // TODO(rossberg): check successor is End - // Type is empty. - CHECK(!NodeProperties::IsTyped(node)); - break; - case IrOpcode::kThrow: - // TODO(rossberg): what are the constraints on these? - // Type is empty. - CHECK(!NodeProperties::IsTyped(node)); - break; - - // Common operators - // ---------------- - 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(node); - Node* input = NodeProperties::GetValueInput(node, 0); - // Currently, parameter indices start at -1 instead of 0. - CHECK_GT( - OperatorProperties::GetValueOutputCount(input->op()), index + 1); - // Type can be anything. - CHECK(bounds(node).upper->Is(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())); - 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())); - break; - case IrOpcode::kFloat32Constant: - case IrOpcode::kFloat64Constant: - case IrOpcode::kNumberConstant: - // Constants have no inputs. - CHECK_EQ(0, input_count); - // Type is a number. - CHECK(bounds(node).upper->Is(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())); - break; - case IrOpcode::kExternalConstant: - // Constants have no inputs. - CHECK_EQ(0, input_count); - // Type is considered internal. - CHECK(bounds(node).upper->Is(Type::Internal())); - break; - case IrOpcode::kProjection: { - // Projection has an input that produces enough values. - int index = OpParameter(node->op()); - Node* input = NodeProperties::GetValueInput(node, 0); - 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())); - break; - } - case IrOpcode::kPhi: { - // Phi input count matches parent control node. - CHECK_EQ(1, control_count); - Node* control = NodeProperties::GetControlInput(node, 0); - CHECK_EQ(value_count, - OperatorProperties::GetControlInputCount(control->op())); - // 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)); - } - */ - break; - } - case IrOpcode::kEffectPhi: { - // EffectPhi input count matches parent control node. - CHECK_EQ(1, control_count); - Node* control = NodeProperties::GetControlInput(node, 0); - CHECK_EQ(effect_count, - OperatorProperties::GetControlInputCount(control->op())); - break; - } - case IrOpcode::kValueEffect: - // TODO(rossberg): what are the constraints on these? - break; - 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)); - break; + CHECK(count_true == 1 && count_false == 1); + // Type is empty. + CheckNotTyped(node); + break; + } + case IrOpcode::kIfTrue: + case IrOpcode::kIfFalse: + CHECK_EQ(IrOpcode::kBranch, + NodeProperties::GetControlInput(node, 0)->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::kReturn: + // TODO(rossberg): check successor is End + // Type is empty. + CheckNotTyped(node); + break; + case IrOpcode::kThrow: + // TODO(rossberg): what are the constraints on these? + // Type is empty. + CheckNotTyped(node); + break; + + // Common operators + // ---------------- + 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(node); + Node* input = NodeProperties::GetValueInput(node, 0); + // Currently, parameter indices start at -1 instead of 0. + CHECK_GT(OperatorProperties::GetValueOutputCount(input->op()), index + 1); + // Type can be anything. + 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. + 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. + CheckUpperIs(node, Type::Internal()); + break; + case IrOpcode::kFloat32Constant: + case IrOpcode::kFloat64Constant: + case IrOpcode::kNumberConstant: + // Constants have no inputs. + CHECK_EQ(0, input_count); + // Type is a 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. + CheckUpperIs(node, Type::TaggedPtr()); + break; + case IrOpcode::kExternalConstant: + // Constants have no inputs. + CHECK_EQ(0, input_count); + // Type is considered internal. + CheckUpperIs(node, Type::Internal()); + break; + case IrOpcode::kProjection: { + // Projection has an input that produces enough values. + int index = OpParameter(node->op()); + Node* input = NodeProperties::GetValueInput(node, 0); + CHECK_GT(OperatorProperties::GetValueOutputCount(input->op()), index); + // Type can be anything. + // TODO(rossberg): Introduce tuple types for this. + // 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(ValueInput(node, i)).lower)); + CHECK(bounds(ValueInput(node, i)).upper->Is(bounds(node).upper)); } - case IrOpcode::kFrameState: - // TODO(jarin): what are the constraints on these? - break; - case IrOpcode::kStateValues: - // TODO(jarin): what are the constraints on these? - break; - case IrOpcode::kCall: - // TODO(rossberg): what are the constraints on these? - break; - - // JavaScript operators - // -------------------- - case IrOpcode::kJSEqual: - case IrOpcode::kJSNotEqual: - case IrOpcode::kJSStrictEqual: - case IrOpcode::kJSStrictNotEqual: - case IrOpcode::kJSLessThan: - case IrOpcode::kJSGreaterThan: - case IrOpcode::kJSLessThanOrEqual: - case IrOpcode::kJSGreaterThanOrEqual: - case IrOpcode::kJSUnaryNot: - // Type is Boolean. - CHECK(bounds(node).upper->Is(Type::Boolean())); - break; - - case IrOpcode::kJSBitwiseOr: - case IrOpcode::kJSBitwiseXor: - case IrOpcode::kJSBitwiseAnd: - case IrOpcode::kJSShiftLeft: - case IrOpcode::kJSShiftRight: - case IrOpcode::kJSShiftRightLogical: - // Type is 32 bit integral. - CHECK(bounds(node).upper->Is(Type::Integral32())); - break; - case IrOpcode::kJSAdd: - // Type is Number or String. - CHECK(bounds(node).upper->Is(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())); - break; - - case IrOpcode::kJSToBoolean: - // Type is Boolean. - CHECK(bounds(node).upper->Is(Type::Boolean())); - break; - case IrOpcode::kJSToNumber: - // Type is Number. - CHECK(bounds(node).upper->Is(Type::Number())); - break; - case IrOpcode::kJSToString: - // Type is String. - CHECK(bounds(node).upper->Is(Type::String())); - break; - case IrOpcode::kJSToName: - // Type is Name. - CHECK(bounds(node).upper->Is(Type::Name())); - break; - case IrOpcode::kJSToObject: - // Type is Receiver. - CHECK(bounds(node).upper->Is(Type::Receiver())); - break; - - case IrOpcode::kJSCreate: - // Type is Object. - CHECK(bounds(node).upper->Is(Type::Object())); - break; - case IrOpcode::kJSLoadProperty: - case IrOpcode::kJSLoadNamed: - // Type can be anything. - CHECK(bounds(node).upper->Is(Type::Any())); - break; - case IrOpcode::kJSStoreProperty: - case IrOpcode::kJSStoreNamed: - // Type is empty. - CHECK(!NodeProperties::IsTyped(node)); - break; - case IrOpcode::kJSDeleteProperty: - case IrOpcode::kJSHasProperty: - case IrOpcode::kJSInstanceOf: - // Type is Boolean. - CHECK(bounds(node).upper->Is(Type::Boolean())); - break; - case IrOpcode::kJSTypeOf: - // Type is String. - CHECK(bounds(node).upper->Is(Type::String())); - break; - - case IrOpcode::kJSLoadContext: - // Type can be anything. - CHECK(bounds(node).upper->Is(Type::Any())); - break; - case IrOpcode::kJSStoreContext: - // Type is empty. - CHECK(!NodeProperties::IsTyped(node)); - break; - case IrOpcode::kJSCreateFunctionContext: - case IrOpcode::kJSCreateCatchContext: - case IrOpcode::kJSCreateWithContext: - case IrOpcode::kJSCreateBlockContext: - case IrOpcode::kJSCreateModuleContext: - case IrOpcode::kJSCreateGlobalContext: { - // Type is Context, and operand is Internal. - Bounds outer = bounds(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()); - break; + */ + 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: + // TODO(rossberg): what are the constraints on these? + break; + case IrOpcode::kFinish: { + // 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)); } + break; + } + case IrOpcode::kFrameState: + // TODO(jarin): what are the constraints on these? + break; + case IrOpcode::kStateValues: + // TODO(jarin): what are the constraints on these? + break; + case IrOpcode::kCall: + // TODO(rossberg): what are the constraints on these? + break; + + // JavaScript operators + // -------------------- + case IrOpcode::kJSEqual: + case IrOpcode::kJSNotEqual: + case IrOpcode::kJSStrictEqual: + case IrOpcode::kJSStrictNotEqual: + case IrOpcode::kJSLessThan: + case IrOpcode::kJSGreaterThan: + case IrOpcode::kJSLessThanOrEqual: + case IrOpcode::kJSGreaterThanOrEqual: + case IrOpcode::kJSUnaryNot: + // Type is Boolean. + CheckUpperIs(node, Type::Boolean()); + break; + + case IrOpcode::kJSBitwiseOr: + case IrOpcode::kJSBitwiseXor: + case IrOpcode::kJSBitwiseAnd: + case IrOpcode::kJSShiftLeft: + case IrOpcode::kJSShiftRight: + case IrOpcode::kJSShiftRightLogical: + // Type is 32 bit integral. + CheckUpperIs(node, Type::Integral32()); + break; + case IrOpcode::kJSAdd: + // Type is Number or String. + CheckUpperIs(node, Type::NumberOrString()); + break; + case IrOpcode::kJSSubtract: + case IrOpcode::kJSMultiply: + case IrOpcode::kJSDivide: + case IrOpcode::kJSModulus: + // Type is Number. + CheckUpperIs(node, Type::Number()); + break; + + case IrOpcode::kJSToBoolean: + // Type is Boolean. + CheckUpperIs(node, Type::Boolean()); + break; + case IrOpcode::kJSToNumber: + // Type is Number. + CheckUpperIs(node, Type::Number()); + break; + case IrOpcode::kJSToString: + // Type is String. + CheckUpperIs(node, Type::String()); + break; + case IrOpcode::kJSToName: + // Type is Name. + CheckUpperIs(node, Type::Name()); + break; + case IrOpcode::kJSToObject: + // Type is Receiver. + CheckUpperIs(node, Type::Receiver()); + break; + + case IrOpcode::kJSCreate: + // Type is Object. + CheckUpperIs(node, Type::Object()); + break; + case IrOpcode::kJSLoadProperty: + case IrOpcode::kJSLoadNamed: + // Type can be anything. + CheckUpperIs(node, Type::Any()); + break; + case IrOpcode::kJSStoreProperty: + case IrOpcode::kJSStoreNamed: + // Type is empty. + CheckNotTyped(node); + break; + case IrOpcode::kJSDeleteProperty: + case IrOpcode::kJSHasProperty: + case IrOpcode::kJSInstanceOf: + // Type is Boolean. + CheckUpperIs(node, Type::Boolean()); + break; + case IrOpcode::kJSTypeOf: + // Type is String. + CheckUpperIs(node, Type::String()); + break; + + case IrOpcode::kJSLoadContext: + // Type can be anything. + CheckUpperIs(node, Type::Any()); + break; + case IrOpcode::kJSStoreContext: + // Type is empty. + CheckNotTyped(node); + break; + case IrOpcode::kJSCreateFunctionContext: + case IrOpcode::kJSCreateCatchContext: + case IrOpcode::kJSCreateWithContext: + case IrOpcode::kJSCreateBlockContext: + case IrOpcode::kJSCreateModuleContext: + case IrOpcode::kJSCreateGlobalContext: { + // Type is Context, and operand is Internal. + Node* context = NodeProperties::GetContextInput(node); + // 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()); + break; + } - case IrOpcode::kJSCallConstruct: - // Type is Receiver. - CHECK(bounds(node).upper->Is(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())); - break; - - // Simplified operators - // ------------------------------- - case IrOpcode::kBooleanNot: - // Boolean -> Boolean - CHECK(bounds(Operand(node)).upper->Is(Type::Boolean())); - CHECK(bounds(node).upper->Is(Type::Boolean())); - break; - case IrOpcode::kBooleanToNumber: - // Boolean -> Number - CHECK(bounds(Operand(node)).upper->Is(Type::Boolean())); - CHECK(bounds(node).upper->Is(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())); - break; - case IrOpcode::kNumberAdd: - case IrOpcode::kNumberSubtract: - case IrOpcode::kNumberMultiply: - 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())); - // TODO(rossberg): activate once we retype after opcode changes. - // CHECK(bounds(node).upper->Is(Type::Number())); - break; - case IrOpcode::kNumberToInt32: - // Number -> Signed32 - CHECK(bounds(Operand(node)).upper->Is(Type::Number())); - CHECK(bounds(node).upper->Is(Type::Signed32())); - break; - case IrOpcode::kNumberToUint32: - // Number -> Unsigned32 - CHECK(bounds(Operand(node)).upper->Is(Type::Number())); - CHECK(bounds(node).upper->Is(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())); - 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())); - 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())); - break; - } - case IrOpcode::kObjectIsSmi: - CHECK(bounds(Operand(node)).upper->Is(Type::Any())); - CHECK(bounds(node).upper->Is(Type::Boolean())); - break; - case IrOpcode::kObjectIsNonNegativeSmi: - CHECK(bounds(Operand(node)).upper->Is(Type::Any())); - CHECK(bounds(node).upper->Is(Type::Boolean())); - break; - - case IrOpcode::kChangeTaggedToInt32: { - // Signed32 /\ Tagged -> Signed32 /\ UntaggedInt32 - // 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)); - break; - } - case IrOpcode::kChangeTaggedToUint32: { - // Unsigned32 /\ Tagged -> Unsigned32 /\ UntaggedInt32 - // 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)); - break; - } - case IrOpcode::kChangeTaggedToFloat64: { - // Number /\ Tagged -> Number /\ UntaggedFloat64 - // 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)); - break; - } - case IrOpcode::kChangeInt32ToTagged: { - // Signed32 /\ UntaggedInt32 -> Signed32 /\ Tagged - // 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)); - break; - } - case IrOpcode::kChangeUint32ToTagged: { - // Unsigned32 /\ UntaggedInt32 -> Unsigned32 /\ Tagged - // 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)); - break; - } - case IrOpcode::kChangeFloat64ToTagged: { - // Number /\ UntaggedFloat64 -> Number /\ Tagged - // 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)); - break; - } - case IrOpcode::kChangeBoolToBit: { - // Boolean /\ TaggedPtr -> Boolean /\ UntaggedInt1 - // 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)); - break; - } - case IrOpcode::kChangeBitToBool: { - // Boolean /\ UntaggedInt1 -> Boolean /\ TaggedPtr - // 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)); - break; + case IrOpcode::kJSCallConstruct: + // 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; + + // Simplified operators + // ------------------------------- + case IrOpcode::kBooleanNot: + // Boolean -> Boolean + CheckValueInputIs(node, 0, Type::Boolean()); + CheckUpperIs(node, Type::Boolean()); + break; + case IrOpcode::kBooleanToNumber: + // Boolean -> Number + CheckValueInputIs(node, 0, Type::Boolean()); + CheckUpperIs(node, Type::Number()); + break; + case IrOpcode::kNumberEqual: + case IrOpcode::kNumberLessThan: + case IrOpcode::kNumberLessThanOrEqual: + // (Number, Number) -> Boolean + CheckValueInputIs(node, 0, Type::Number()); + CheckValueInputIs(node, 1, Type::Number()); + CheckUpperIs(node, Type::Boolean()); + break; + case IrOpcode::kNumberAdd: + case IrOpcode::kNumberSubtract: + case IrOpcode::kNumberMultiply: + case IrOpcode::kNumberDivide: + case IrOpcode::kNumberModulus: + // (Number, Number) -> Number + CheckValueInputIs(node, 0, Type::Number()); + CheckValueInputIs(node, 1, Type::Number()); + // TODO(rossberg): activate once we retype after opcode changes. + // CheckUpperIs(node, Type::Number()); + break; + case IrOpcode::kNumberToInt32: + // Number -> Signed32 + CheckValueInputIs(node, 0, Type::Number()); + CheckUpperIs(node, Type::Signed32()); + break; + case IrOpcode::kNumberToUint32: + // Number -> Unsigned32 + CheckValueInputIs(node, 0, Type::Number()); + CheckUpperIs(node, Type::Unsigned32()); + break; + case IrOpcode::kStringEqual: + case IrOpcode::kStringLessThan: + case IrOpcode::kStringLessThanOrEqual: + // (String, String) -> Boolean + CheckValueInputIs(node, 0, Type::String()); + 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())); } - - 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)); - 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)); - 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)); - 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)); - break; - - // Machine operators - // ----------------------- - case IrOpcode::kLoad: - case IrOpcode::kStore: - case IrOpcode::kWord32And: - case IrOpcode::kWord32Or: - case IrOpcode::kWord32Xor: - case IrOpcode::kWord32Shl: - case IrOpcode::kWord32Shr: - case IrOpcode::kWord32Sar: - case IrOpcode::kWord32Ror: - case IrOpcode::kWord32Equal: - case IrOpcode::kWord64And: - case IrOpcode::kWord64Or: - case IrOpcode::kWord64Xor: - case IrOpcode::kWord64Shl: - case IrOpcode::kWord64Shr: - case IrOpcode::kWord64Sar: - case IrOpcode::kWord64Ror: - case IrOpcode::kWord64Equal: - case IrOpcode::kInt32Add: - case IrOpcode::kInt32AddWithOverflow: - case IrOpcode::kInt32Sub: - case IrOpcode::kInt32SubWithOverflow: - case IrOpcode::kInt32Mul: - case IrOpcode::kInt32MulHigh: - case IrOpcode::kInt32Div: - case IrOpcode::kInt32Mod: - case IrOpcode::kInt32LessThan: - case IrOpcode::kInt32LessThanOrEqual: - case IrOpcode::kUint32Div: - case IrOpcode::kUint32Mod: - case IrOpcode::kUint32LessThan: - case IrOpcode::kUint32LessThanOrEqual: - case IrOpcode::kInt64Add: - case IrOpcode::kInt64Sub: - case IrOpcode::kInt64Mul: - case IrOpcode::kInt64Div: - case IrOpcode::kInt64Mod: - case IrOpcode::kInt64LessThan: - case IrOpcode::kInt64LessThanOrEqual: - case IrOpcode::kUint64Div: - case IrOpcode::kUint64Mod: - case IrOpcode::kUint64LessThan: - case IrOpcode::kFloat64Add: - case IrOpcode::kFloat64Sub: - case IrOpcode::kFloat64Mul: - case IrOpcode::kFloat64Div: - case IrOpcode::kFloat64Mod: - case IrOpcode::kFloat64Sqrt: - case IrOpcode::kFloat64Equal: - case IrOpcode::kFloat64LessThan: - case IrOpcode::kFloat64LessThanOrEqual: - case IrOpcode::kTruncateInt64ToInt32: - case IrOpcode::kTruncateFloat64ToFloat32: - case IrOpcode::kTruncateFloat64ToInt32: - case IrOpcode::kChangeInt32ToInt64: - case IrOpcode::kChangeUint32ToUint64: - case IrOpcode::kChangeInt32ToFloat64: - case IrOpcode::kChangeUint32ToFloat64: - case IrOpcode::kChangeFloat32ToFloat64: - case IrOpcode::kChangeFloat64ToInt32: - case IrOpcode::kChangeFloat64ToUint32: - case IrOpcode::kLoadStackPointer: - // TODO(rossberg): Check. - break; + CheckUpperIs(node, Type::Boolean()); + break; + } + 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()); + break; + + case IrOpcode::kChangeTaggedToInt32: { + // Signed32 /\ Tagged -> Signed32 /\ UntaggedInt32 + // TODO(neis): Activate once ChangeRepresentation works in typer. + // Type* from = Type::Intersect(Type::Signed32(), Type::Tagged()); + // Type* to = Type::Intersect(Type::Signed32(), Type::UntaggedInt32()); + // CheckValueInputIs(node, 0, from)); + // CheckUpperIs(node, to)); + break; + } + case IrOpcode::kChangeTaggedToUint32: { + // Unsigned32 /\ Tagged -> Unsigned32 /\ UntaggedInt32 + // TODO(neis): Activate once ChangeRepresentation works in typer. + // Type* from = Type::Intersect(Type::Unsigned32(), Type::Tagged()); + // Type* to =Type::Intersect(Type::Unsigned32(), Type::UntaggedInt32()); + // CheckValueInputIs(node, 0, from)); + // CheckUpperIs(node, to)); + break; + } + case IrOpcode::kChangeTaggedToFloat64: { + // Number /\ Tagged -> Number /\ UntaggedFloat64 + // TODO(neis): Activate once ChangeRepresentation works in typer. + // Type* from = Type::Intersect(Type::Number(), Type::Tagged()); + // Type* to = Type::Intersect(Type::Number(), Type::UntaggedFloat64()); + // CheckValueInputIs(node, 0, from)); + // CheckUpperIs(node, to)); + break; + } + case IrOpcode::kChangeInt32ToTagged: { + // Signed32 /\ UntaggedInt32 -> Signed32 /\ Tagged + // TODO(neis): Activate once ChangeRepresentation works in typer. + // Type* from =Type::Intersect(Type::Signed32(), Type::UntaggedInt32()); + // Type* to = Type::Intersect(Type::Signed32(), Type::Tagged()); + // CheckValueInputIs(node, 0, from)); + // CheckUpperIs(node, to)); + break; } + case IrOpcode::kChangeUint32ToTagged: { + // Unsigned32 /\ UntaggedInt32 -> Unsigned32 /\ Tagged + // TODO(neis): Activate once ChangeRepresentation works in typer. + // Type* from=Type::Intersect(Type::Unsigned32(),Type::UntaggedInt32()); + // Type* to = Type::Intersect(Type::Unsigned32(), Type::Tagged()); + // CheckValueInputIs(node, 0, from)); + // CheckUpperIs(node, to)); + break; + } + case IrOpcode::kChangeFloat64ToTagged: { + // Number /\ UntaggedFloat64 -> Number /\ Tagged + // TODO(neis): Activate once ChangeRepresentation works in typer. + // Type* from =Type::Intersect(Type::Number(), Type::UntaggedFloat64()); + // Type* to = Type::Intersect(Type::Number(), Type::Tagged()); + // CheckValueInputIs(node, 0, from)); + // CheckUpperIs(node, to)); + break; + } + case IrOpcode::kChangeBoolToBit: { + // Boolean /\ TaggedPtr -> Boolean /\ UntaggedInt1 + // TODO(neis): Activate once ChangeRepresentation works in typer. + // Type* from = Type::Intersect(Type::Boolean(), Type::TaggedPtr()); + // Type* to = Type::Intersect(Type::Boolean(), Type::UntaggedInt1()); + // CheckValueInputIs(node, 0, from)); + // CheckUpperIs(node, to)); + break; + } + case IrOpcode::kChangeBitToBool: { + // Boolean /\ UntaggedInt1 -> Boolean /\ TaggedPtr + // TODO(neis): Activate once ChangeRepresentation works in typer. + // Type* from = Type::Intersect(Type::Boolean(), Type::UntaggedInt1()); + // Type* to = Type::Intersect(Type::Boolean(), Type::TaggedPtr()); + // CheckValueInputIs(node, 0, from)); + // CheckUpperIs(node, to)); + break; + } + + case IrOpcode::kLoadField: + // Object -> fieldtype + // TODO(rossberg): activate once machine ops are typed. + // CheckValueInputIs(node, 0, Type::Object()); + // CheckUpperIs(node, Field(node).type)); + break; + case IrOpcode::kLoadElement: + // Object -> elementtype + // TODO(rossberg): activate once machine ops are typed. + // CheckValueInputIs(node, 0, Type::Object()); + // CheckUpperIs(node, Element(node).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)); + CheckNotTyped(node); + break; + case IrOpcode::kStoreElement: + // (Object, elementtype) -> _|_ + // TODO(rossberg): activate once machine ops are typed. + // CheckValueInputIs(node, 0, Type::Object()); + // CheckValueInputIs(node, 1, Element(node).type)); + CheckNotTyped(node); + break; + + // Machine operators + // ----------------------- + case IrOpcode::kLoad: + case IrOpcode::kStore: + case IrOpcode::kWord32And: + case IrOpcode::kWord32Or: + case IrOpcode::kWord32Xor: + case IrOpcode::kWord32Shl: + case IrOpcode::kWord32Shr: + case IrOpcode::kWord32Sar: + case IrOpcode::kWord32Ror: + case IrOpcode::kWord32Equal: + case IrOpcode::kWord64And: + case IrOpcode::kWord64Or: + case IrOpcode::kWord64Xor: + case IrOpcode::kWord64Shl: + case IrOpcode::kWord64Shr: + case IrOpcode::kWord64Sar: + case IrOpcode::kWord64Ror: + case IrOpcode::kWord64Equal: + case IrOpcode::kInt32Add: + case IrOpcode::kInt32AddWithOverflow: + case IrOpcode::kInt32Sub: + case IrOpcode::kInt32SubWithOverflow: + case IrOpcode::kInt32Mul: + case IrOpcode::kInt32MulHigh: + case IrOpcode::kInt32Div: + case IrOpcode::kInt32Mod: + case IrOpcode::kInt32LessThan: + case IrOpcode::kInt32LessThanOrEqual: + case IrOpcode::kUint32Div: + case IrOpcode::kUint32Mod: + case IrOpcode::kUint32LessThan: + case IrOpcode::kUint32LessThanOrEqual: + case IrOpcode::kInt64Add: + case IrOpcode::kInt64Sub: + case IrOpcode::kInt64Mul: + case IrOpcode::kInt64Div: + case IrOpcode::kInt64Mod: + case IrOpcode::kInt64LessThan: + case IrOpcode::kInt64LessThanOrEqual: + case IrOpcode::kUint64Div: + case IrOpcode::kUint64Mod: + case IrOpcode::kUint64LessThan: + case IrOpcode::kFloat64Add: + case IrOpcode::kFloat64Sub: + case IrOpcode::kFloat64Mul: + case IrOpcode::kFloat64Div: + case IrOpcode::kFloat64Mod: + case IrOpcode::kFloat64Sqrt: + case IrOpcode::kFloat64Equal: + case IrOpcode::kFloat64LessThan: + case IrOpcode::kFloat64LessThanOrEqual: + case IrOpcode::kTruncateInt64ToInt32: + case IrOpcode::kTruncateFloat64ToFloat32: + case IrOpcode::kTruncateFloat64ToInt32: + case IrOpcode::kChangeInt32ToInt64: + case IrOpcode::kChangeUint32ToUint64: + case IrOpcode::kChangeInt32ToFloat64: + case IrOpcode::kChangeUint32ToFloat64: + case IrOpcode::kChangeFloat32ToFloat64: + case IrOpcode::kChangeFloat64ToInt32: + case IrOpcode::kChangeFloat64ToUint32: + case IrOpcode::kLoadStackPointer: + // TODO(rossberg): Check. + break; } return GenericGraphVisit::CONTINUE; -- 2.7.4