OLD | NEW |
1 // Copyright 2014 the V8 project authors. All rights reserved. | 1 // Copyright 2014 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/compiler/verifier.h" | 5 #include "src/compiler/verifier.h" |
6 | 6 |
7 #include <deque> | 7 #include <deque> |
8 #include <queue> | 8 #include <queue> |
9 | 9 |
10 #include "src/compiler/generic-algorithm.h" | 10 #include "src/compiler/generic-algorithm.h" |
11 #include "src/compiler/generic-node-inl.h" | 11 #include "src/compiler/generic-node-inl.h" |
12 #include "src/compiler/generic-node.h" | 12 #include "src/compiler/generic-node.h" |
13 #include "src/compiler/graph-inl.h" | 13 #include "src/compiler/graph-inl.h" |
14 #include "src/compiler/graph.h" | 14 #include "src/compiler/graph.h" |
15 #include "src/compiler/node.h" | 15 #include "src/compiler/node.h" |
16 #include "src/compiler/node-properties-inl.h" | 16 #include "src/compiler/node-properties-inl.h" |
17 #include "src/compiler/node-properties.h" | 17 #include "src/compiler/node-properties.h" |
18 #include "src/compiler/opcodes.h" | 18 #include "src/compiler/opcodes.h" |
19 #include "src/compiler/operator.h" | 19 #include "src/compiler/operator.h" |
20 #include "src/compiler/schedule.h" | 20 #include "src/compiler/schedule.h" |
| 21 #include "src/compiler/simplified-operator.h" |
21 #include "src/data-flow.h" | 22 #include "src/data-flow.h" |
22 | 23 |
23 namespace v8 { | 24 namespace v8 { |
24 namespace internal { | 25 namespace internal { |
25 namespace compiler { | 26 namespace compiler { |
26 | 27 |
27 | 28 |
28 static bool IsDefUseChainLinkPresent(Node* def, Node* use) { | 29 static bool IsDefUseChainLinkPresent(Node* def, Node* use) { |
29 Node::Uses uses = def->uses(); | 30 Node::Uses uses = def->uses(); |
30 for (Node::Uses::iterator it = uses.begin(); it != uses.end(); ++it) { | 31 for (Node::Uses::iterator it = uses.begin(); it != uses.end(); ++it) { |
31 if (*it == use) return true; | 32 if (*it == use) return true; |
32 } | 33 } |
33 return false; | 34 return false; |
34 } | 35 } |
35 | 36 |
36 | 37 |
37 static bool IsUseDefChainLinkPresent(Node* def, Node* use) { | 38 static bool IsUseDefChainLinkPresent(Node* def, Node* use) { |
38 Node::Inputs inputs = use->inputs(); | 39 Node::Inputs inputs = use->inputs(); |
39 for (Node::Inputs::iterator it = inputs.begin(); it != inputs.end(); ++it) { | 40 for (Node::Inputs::iterator it = inputs.begin(); it != inputs.end(); ++it) { |
40 if (*it == def) return true; | 41 if (*it == def) return true; |
41 } | 42 } |
42 return false; | 43 return false; |
43 } | 44 } |
44 | 45 |
45 | 46 |
46 class Verifier::Visitor : public NullNodeVisitor { | 47 class Verifier::Visitor : public NullNodeVisitor { |
47 public: | 48 public: |
48 explicit Visitor(Zone* zone) | 49 Visitor(Zone* z, bool is_typed) |
49 : reached_from_start(NodeSet::key_compare(), | 50 : zone(z), |
50 NodeSet::allocator_type(zone)), | 51 with_typing(is_typed), |
| 52 reached_from_start(NodeSet::key_compare(), |
| 53 NodeSet::allocator_type(z)), |
51 reached_from_end(NodeSet::key_compare(), | 54 reached_from_end(NodeSet::key_compare(), |
52 NodeSet::allocator_type(zone)) {} | 55 NodeSet::allocator_type(z)) {} |
53 | 56 |
54 // Fulfills the PreNodeCallback interface. | 57 // Fulfills the PreNodeCallback interface. |
55 GenericGraphVisit::Control Pre(Node* node); | 58 GenericGraphVisit::Control Pre(Node* node); |
56 | 59 |
| 60 Zone* zone; |
| 61 bool with_typing; |
57 bool from_start; | 62 bool from_start; |
58 NodeSet reached_from_start; | 63 NodeSet reached_from_start; |
59 NodeSet reached_from_end; | 64 NodeSet reached_from_end; |
| 65 |
| 66 private: |
| 67 // TODO(rossberg): Get rid of these once we got rid of NodeProperties. |
| 68 Bounds bounds(Node* node) { |
| 69 return NodeProperties::GetBounds(node); |
| 70 } |
| 71 Node* operand(Node* node, int i = 0) { |
| 72 return NodeProperties::GetValueInput(node, i); |
| 73 } |
| 74 FieldAccess field(Node* node) { |
| 75 DCHECK(node->opcode() == IrOpcode::kLoadField || |
| 76 node->opcode() == IrOpcode::kStoreField); |
| 77 return static_cast<Operator1<FieldAccess>*>(node->op())->parameter(); |
| 78 } |
| 79 ElementAccess element(Node* node) { |
| 80 DCHECK(node->opcode() == IrOpcode::kLoadElement || |
| 81 node->opcode() == IrOpcode::kStoreElement); |
| 82 return static_cast<Operator1<ElementAccess>*>(node->op())->parameter(); |
| 83 } |
60 }; | 84 }; |
61 | 85 |
62 | 86 |
63 GenericGraphVisit::Control Verifier::Visitor::Pre(Node* node) { | 87 GenericGraphVisit::Control Verifier::Visitor::Pre(Node* node) { |
64 int value_count = OperatorProperties::GetValueInputCount(node->op()); | 88 int value_count = OperatorProperties::GetValueInputCount(node->op()); |
65 int context_count = OperatorProperties::GetContextInputCount(node->op()); | 89 int context_count = OperatorProperties::GetContextInputCount(node->op()); |
66 int frame_state_count = | 90 int frame_state_count = |
67 OperatorProperties::GetFrameStateInputCount(node->op()); | 91 OperatorProperties::GetFrameStateInputCount(node->op()); |
68 int effect_count = OperatorProperties::GetEffectInputCount(node->op()); | 92 int effect_count = OperatorProperties::GetEffectInputCount(node->op()); |
69 int control_count = OperatorProperties::GetControlInputCount(node->op()); | 93 int control_count = OperatorProperties::GetControlInputCount(node->op()); |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
108 // Verify all successors are projections if multiple value outputs exist. | 132 // Verify all successors are projections if multiple value outputs exist. |
109 if (OperatorProperties::GetValueOutputCount(node->op()) > 1) { | 133 if (OperatorProperties::GetValueOutputCount(node->op()) > 1) { |
110 Node::Uses uses = node->uses(); | 134 Node::Uses uses = node->uses(); |
111 for (Node::Uses::iterator it = uses.begin(); it != uses.end(); ++it) { | 135 for (Node::Uses::iterator it = uses.begin(); it != uses.end(); ++it) { |
112 CHECK(!NodeProperties::IsValueEdge(it.edge()) || | 136 CHECK(!NodeProperties::IsValueEdge(it.edge()) || |
113 (*it)->opcode() == IrOpcode::kProjection || | 137 (*it)->opcode() == IrOpcode::kProjection || |
114 (*it)->opcode() == IrOpcode::kParameter); | 138 (*it)->opcode() == IrOpcode::kParameter); |
115 } | 139 } |
116 } | 140 } |
117 | 141 |
118 switch (node->opcode()) { | 142 if (with_typing) { |
119 case IrOpcode::kStart: | 143 // Multiple value outputs are currently typed as Internal. |
120 // Start has no inputs. | 144 // TODO(rossberg): Introduce tuple types. |
121 CHECK_EQ(0, input_count); | 145 if (OperatorProperties::GetValueOutputCount(node->op()) > 1) { |
122 break; | 146 CHECK(bounds(node).upper->Is(Type::Internal())); |
123 case IrOpcode::kEnd: | |
124 // End has no outputs. | |
125 CHECK(!OperatorProperties::HasValueOutput(node->op())); | |
126 CHECK(!OperatorProperties::HasEffectOutput(node->op())); | |
127 CHECK(!OperatorProperties::HasControlOutput(node->op())); | |
128 break; | |
129 case IrOpcode::kDead: | |
130 // Dead is never connected to the graph. | |
131 UNREACHABLE(); | |
132 case IrOpcode::kBranch: { | |
133 // Branch uses are IfTrue and IfFalse. | |
134 Node::Uses uses = node->uses(); | |
135 bool got_true = false, got_false = false; | |
136 for (Node::Uses::iterator it = uses.begin(); it != uses.end(); ++it) { | |
137 CHECK(((*it)->opcode() == IrOpcode::kIfTrue && !got_true) || | |
138 ((*it)->opcode() == IrOpcode::kIfFalse && !got_false)); | |
139 if ((*it)->opcode() == IrOpcode::kIfTrue) got_true = true; | |
140 if ((*it)->opcode() == IrOpcode::kIfFalse) got_false = true; | |
141 } | |
142 // TODO(rossberg): Currently fails for various tests. | |
143 // CHECK(got_true && got_false); | |
144 break; | |
145 } | 147 } |
146 case IrOpcode::kIfTrue: | 148 |
147 case IrOpcode::kIfFalse: | 149 switch (node->opcode()) { |
148 CHECK_EQ(IrOpcode::kBranch, | 150 // Control operators |
149 NodeProperties::GetControlInput(node, 0)->opcode()); | 151 // ----------------- |
150 break; | 152 case IrOpcode::kStart: |
151 case IrOpcode::kLoop: | 153 // Start has no inputs. |
152 case IrOpcode::kMerge: | 154 CHECK_EQ(0, input_count); |
153 break; | 155 // Type is Internal. |
154 case IrOpcode::kReturn: | 156 CHECK(bounds(node).upper->Is(Type::Internal())); |
155 // TODO(rossberg): check successor is End | 157 break; |
156 break; | 158 case IrOpcode::kEnd: |
157 case IrOpcode::kThrow: | 159 // End has no outputs. |
158 // TODO(rossberg): what are the constraints on these? | 160 CHECK(!OperatorProperties::HasValueOutput(node->op())); |
159 break; | 161 CHECK(!OperatorProperties::HasEffectOutput(node->op())); |
160 case IrOpcode::kParameter: { | 162 CHECK(!OperatorProperties::HasControlOutput(node->op())); |
161 // Parameters have the start node as inputs. | 163 break; |
162 CHECK_EQ(1, input_count); | 164 case IrOpcode::kDead: |
163 CHECK_EQ(IrOpcode::kStart, | 165 // Dead is never connected to the graph. |
164 NodeProperties::GetValueInput(node, 0)->opcode()); | 166 UNREACHABLE(); |
165 // Parameter has an input that produces enough values. | 167 case IrOpcode::kBranch: { |
166 int index = static_cast<Operator1<int>*>(node->op())->parameter(); | 168 // Ignore dead branches, because they may violate well-formedness. |
167 Node* input = NodeProperties::GetValueInput(node, 0); | 169 // TODO(rossberg): Can we avoid this? |
168 // Currently, parameter indices start at -1 instead of 0. | 170 Node* parent = NodeProperties::GetControlInput(node, 0); |
169 CHECK_GT(OperatorProperties::GetValueOutputCount(input->op()), index + 1); | 171 if (parent->opcode() == IrOpcode::kDead) break; |
170 break; | 172 // Branch uses are IfTrue and IfFalse. |
| 173 Node::Uses uses = node->uses(); |
| 174 bool count_true = 0, count_false = 0; |
| 175 for (Node::Uses::iterator it = uses.begin(); it != uses.end(); ++it) { |
| 176 CHECK((*it)->opcode() == IrOpcode::kIfTrue || |
| 177 (*it)->opcode() == IrOpcode::kIfFalse); |
| 178 if ((*it)->opcode() == IrOpcode::kIfTrue) ++count_true; |
| 179 if ((*it)->opcode() == IrOpcode::kIfFalse) ++count_false; |
| 180 } |
| 181 CHECK(count_true == 1 && count_false == 1); |
| 182 break; |
| 183 } |
| 184 case IrOpcode::kIfTrue: |
| 185 case IrOpcode::kIfFalse: |
| 186 CHECK_EQ(IrOpcode::kBranch, |
| 187 NodeProperties::GetControlInput(node, 0)->opcode()); |
| 188 break; |
| 189 case IrOpcode::kLoop: |
| 190 case IrOpcode::kMerge: |
| 191 break; |
| 192 case IrOpcode::kReturn: |
| 193 // TODO(rossberg): check successor is End |
| 194 break; |
| 195 case IrOpcode::kThrow: |
| 196 // TODO(rossberg): what are the constraints on these? |
| 197 break; |
| 198 |
| 199 // Common operators |
| 200 // ---------------- |
| 201 case IrOpcode::kParameter: { |
| 202 // Parameters have the start node as inputs. |
| 203 CHECK_EQ(1, input_count); |
| 204 CHECK_EQ(IrOpcode::kStart, |
| 205 NodeProperties::GetValueInput(node, 0)->opcode()); |
| 206 // Parameter has an input that produces enough values. |
| 207 int index = static_cast<Operator1<int>*>(node->op())->parameter(); |
| 208 Node* input = NodeProperties::GetValueInput(node, 0); |
| 209 // Currently, parameter indices start at -1 instead of 0. |
| 210 CHECK_GT( |
| 211 OperatorProperties::GetValueOutputCount(input->op()), index + 1); |
| 212 // Type can be anything. |
| 213 CHECK(bounds(node).upper->Is(Type::Any())); |
| 214 break; |
| 215 } |
| 216 case IrOpcode::kInt32Constant: // TODO(rossberg): rename Word32Constant? |
| 217 // Constants have no inputs. |
| 218 CHECK_EQ(0, input_count); |
| 219 // Type is a 32 bit integer, signed or unsigned. |
| 220 CHECK(bounds(node).upper->Is(Type::Integral32())); |
| 221 break; |
| 222 case IrOpcode::kInt64Constant: // Close enough... |
| 223 case IrOpcode::kFloat64Constant: |
| 224 case IrOpcode::kNumberConstant: |
| 225 // Constants have no inputs. |
| 226 CHECK_EQ(0, input_count); |
| 227 // Type is a number. |
| 228 CHECK(bounds(node).upper->Is(Type::Number())); |
| 229 break; |
| 230 case IrOpcode::kHeapConstant: |
| 231 // Constants have no inputs. |
| 232 CHECK_EQ(0, input_count); |
| 233 // Type can be anything represented as a heap pointer. |
| 234 CHECK(bounds(node).upper->Is(Type::TaggedPtr())); |
| 235 break; |
| 236 case IrOpcode::kExternalConstant: |
| 237 // Constants have no inputs. |
| 238 CHECK_EQ(0, input_count); |
| 239 // Type is considered internal. |
| 240 CHECK(bounds(node).upper->Is(Type::Internal())); |
| 241 break; |
| 242 case IrOpcode::kProjection: { |
| 243 // Projection has an input that produces enough values. |
| 244 int index = static_cast<Operator1<int>*>(node->op())->parameter(); |
| 245 Node* input = NodeProperties::GetValueInput(node, 0); |
| 246 CHECK_GT(OperatorProperties::GetValueOutputCount(input->op()), index); |
| 247 // Type can be anything. |
| 248 // TODO(rossberg): Introduce tuple types for this. |
| 249 CHECK(bounds(node).upper->Is(Type::Any())); |
| 250 break; |
| 251 } |
| 252 case IrOpcode::kPhi: { |
| 253 // Phi input count matches parent control node. |
| 254 CHECK_EQ(1, control_count); |
| 255 Node* control = NodeProperties::GetControlInput(node, 0); |
| 256 CHECK_EQ(value_count, |
| 257 OperatorProperties::GetControlInputCount(control->op())); |
| 258 // Type must be subsumed by all input types. |
| 259 for (int i = 0; i < value_count; ++i) { |
| 260 CHECK(bounds(node).lower->Is(bounds(operand(node, i)).lower)); |
| 261 CHECK(bounds(operand(node, i)).upper->Is(bounds(node).upper)); |
| 262 } |
| 263 break; |
| 264 } |
| 265 case IrOpcode::kEffectPhi: { |
| 266 // EffectPhi input count matches parent control node. |
| 267 CHECK_EQ(1, control_count); |
| 268 Node* control = NodeProperties::GetControlInput(node, 0); |
| 269 CHECK_EQ(effect_count, |
| 270 OperatorProperties::GetControlInputCount(control->op())); |
| 271 break; |
| 272 } |
| 273 case IrOpcode::kControlEffect: |
| 274 case IrOpcode::kValueEffect: |
| 275 // TODO(rossberg): what are the constraints on these? |
| 276 break; |
| 277 case IrOpcode::kFinish: { |
| 278 // TODO(rossberg): what are the constraints on these? |
| 279 // Type must be subsumed by input type. |
| 280 CHECK(bounds(operand(node)).lower->Is(bounds(node).lower)); |
| 281 CHECK(bounds(operand(node)).upper->Is(bounds(node).upper)); |
| 282 break; |
| 283 } |
| 284 case IrOpcode::kLazyDeoptimization: |
| 285 // TODO(jarin): what are the constraints on these? |
| 286 break; |
| 287 case IrOpcode::kDeoptimize: |
| 288 // TODO(jarin): what are the constraints on these? |
| 289 break; |
| 290 case IrOpcode::kFrameState: |
| 291 // TODO(jarin): what are the constraints on these? |
| 292 break; |
| 293 case IrOpcode::kStateValues: |
| 294 // TODO(jarin): what are the constraints on these? |
| 295 break; |
| 296 case IrOpcode::kCall: |
| 297 // TODO(rossberg): what are the constraints on these? |
| 298 break; |
| 299 case IrOpcode::kContinuation: |
| 300 // TODO(jarin): what are the constraints on these? |
| 301 break; |
| 302 |
| 303 // JavaScript operators |
| 304 // -------------------- |
| 305 case IrOpcode::kJSEqual: |
| 306 case IrOpcode::kJSNotEqual: |
| 307 case IrOpcode::kJSStrictEqual: |
| 308 case IrOpcode::kJSStrictNotEqual: |
| 309 case IrOpcode::kJSLessThan: |
| 310 case IrOpcode::kJSGreaterThan: |
| 311 case IrOpcode::kJSLessThanOrEqual: |
| 312 case IrOpcode::kJSGreaterThanOrEqual: |
| 313 case IrOpcode::kJSUnaryNot: |
| 314 // Type is Boolean. |
| 315 CHECK(bounds(node).upper->Is(Type::Boolean())); |
| 316 break; |
| 317 |
| 318 case IrOpcode::kJSBitwiseOr: |
| 319 case IrOpcode::kJSBitwiseXor: |
| 320 case IrOpcode::kJSBitwiseAnd: |
| 321 case IrOpcode::kJSShiftLeft: |
| 322 case IrOpcode::kJSShiftRight: |
| 323 case IrOpcode::kJSShiftRightLogical: |
| 324 // Type is 32 bit integral. |
| 325 CHECK(bounds(node).upper->Is(Type::Integral32())); |
| 326 break; |
| 327 case IrOpcode::kJSAdd: |
| 328 case IrOpcode::kJSSubtract: |
| 329 case IrOpcode::kJSMultiply: |
| 330 case IrOpcode::kJSDivide: |
| 331 case IrOpcode::kJSModulus: |
| 332 // Type is Number. |
| 333 CHECK(bounds(node).upper->Is(Type::Number())); |
| 334 break; |
| 335 |
| 336 case IrOpcode::kJSToBoolean: |
| 337 // Type is Boolean. |
| 338 CHECK(bounds(node).upper->Is(Type::Boolean())); |
| 339 break; |
| 340 case IrOpcode::kJSToNumber: |
| 341 // Type is Number. |
| 342 CHECK(bounds(node).upper->Is(Type::Number())); |
| 343 break; |
| 344 case IrOpcode::kJSToString: |
| 345 // Type is String. |
| 346 CHECK(bounds(node).upper->Is(Type::String())); |
| 347 break; |
| 348 case IrOpcode::kJSToName: |
| 349 // Type is Name. |
| 350 CHECK(bounds(node).upper->Is(Type::Name())); |
| 351 break; |
| 352 case IrOpcode::kJSToObject: |
| 353 // Type is Receiver. |
| 354 CHECK(bounds(node).upper->Is(Type::Receiver())); |
| 355 break; |
| 356 |
| 357 case IrOpcode::kJSCreate: |
| 358 // Type is Object. |
| 359 CHECK(bounds(node).upper->Is(Type::Object())); |
| 360 break; |
| 361 case IrOpcode::kJSLoadProperty: |
| 362 case IrOpcode::kJSLoadNamed: |
| 363 // Type can be anything. |
| 364 CHECK(bounds(node).upper->Is(Type::Any())); |
| 365 break; |
| 366 case IrOpcode::kJSStoreProperty: |
| 367 case IrOpcode::kJSStoreNamed: |
| 368 // Type is empty. |
| 369 CHECK(bounds(node).upper->Is(Type::None())); |
| 370 break; |
| 371 case IrOpcode::kJSDeleteProperty: |
| 372 case IrOpcode::kJSHasProperty: |
| 373 case IrOpcode::kJSInstanceOf: |
| 374 // Type is Boolean. |
| 375 CHECK(bounds(node).upper->Is(Type::Boolean())); |
| 376 break; |
| 377 case IrOpcode::kJSTypeOf: |
| 378 // Type is String. |
| 379 CHECK(bounds(node).upper->Is(Type::String())); |
| 380 break; |
| 381 |
| 382 case IrOpcode::kJSLoadContext: |
| 383 // Type can be anything. |
| 384 CHECK(bounds(node).upper->Is(Type::Any())); |
| 385 break; |
| 386 case IrOpcode::kJSStoreContext: |
| 387 // Type is empty. |
| 388 CHECK(bounds(node).upper->Is(Type::None())); |
| 389 break; |
| 390 case IrOpcode::kJSCreateFunctionContext: |
| 391 case IrOpcode::kJSCreateCatchContext: |
| 392 case IrOpcode::kJSCreateWithContext: |
| 393 case IrOpcode::kJSCreateBlockContext: |
| 394 case IrOpcode::kJSCreateModuleContext: |
| 395 case IrOpcode::kJSCreateGlobalContext: { |
| 396 // Type is Context, and operand is Internal. |
| 397 Bounds outer = bounds(NodeProperties::GetContextInput(node)); |
| 398 // TODO(rossberg): This should really be Is(Internal), but the typer |
| 399 // currently can't do backwards propagation. |
| 400 CHECK(outer.upper->Maybe(Type::Internal())); |
| 401 CHECK(bounds(node).upper->Is(Type::Context(outer.upper, zone))); |
| 402 CHECK(bounds(node).lower->Is(Type::Context(outer.lower, zone))); |
| 403 break; |
| 404 } |
| 405 |
| 406 case IrOpcode::kJSCallConstruct: |
| 407 // Type is Receiver. |
| 408 CHECK(bounds(node).upper->Is(Type::Receiver())); |
| 409 break; |
| 410 case IrOpcode::kJSCallFunction: |
| 411 case IrOpcode::kJSCallRuntime: |
| 412 case IrOpcode::kJSYield: |
| 413 case IrOpcode::kJSDebugger: |
| 414 // Type can be anything. |
| 415 CHECK(bounds(node).upper->Is(Type::Any())); |
| 416 break; |
| 417 |
| 418 // Simplified operators |
| 419 // ------------------------------- |
| 420 case IrOpcode::kBooleanNot: |
| 421 // Boolean -> Boolean |
| 422 CHECK(bounds(operand(node)).upper->Is(Type::Boolean())); |
| 423 CHECK(bounds(node).upper->Is(Type::Boolean())); |
| 424 break; |
| 425 case IrOpcode::kNumberEqual: |
| 426 case IrOpcode::kNumberLessThan: |
| 427 case IrOpcode::kNumberLessThanOrEqual: |
| 428 // (Number, Number) -> Boolean |
| 429 CHECK(bounds(operand(node, 0)).upper->Is(Type::Number())); |
| 430 CHECK(bounds(operand(node, 1)).upper->Is(Type::Number())); |
| 431 CHECK(bounds(node).upper->Is(Type::Boolean())); |
| 432 break; |
| 433 case IrOpcode::kNumberAdd: |
| 434 case IrOpcode::kNumberSubtract: |
| 435 case IrOpcode::kNumberMultiply: |
| 436 case IrOpcode::kNumberDivide: |
| 437 case IrOpcode::kNumberModulus: |
| 438 // (Number, Number) -> Number |
| 439 CHECK(bounds(operand(node, 0)).upper->Is(Type::Number())); |
| 440 CHECK(bounds(operand(node, 1)).upper->Is(Type::Number())); |
| 441 CHECK(bounds(node).upper->Is(Type::Number())); |
| 442 break; |
| 443 case IrOpcode::kNumberToInt32: |
| 444 // Number -> Signed32 |
| 445 CHECK(bounds(operand(node)).upper->Is(Type::Number())); |
| 446 CHECK(bounds(node).upper->Is(Type::Signed32())); |
| 447 break; |
| 448 case IrOpcode::kNumberToUint32: |
| 449 // Number -> Unsigned32 |
| 450 CHECK(bounds(operand(node)).upper->Is(Type::Number())); |
| 451 CHECK(bounds(node).upper->Is(Type::Unsigned32())); |
| 452 break; |
| 453 case IrOpcode::kStringEqual: |
| 454 case IrOpcode::kStringLessThan: |
| 455 case IrOpcode::kStringLessThanOrEqual: |
| 456 // (String, String) -> Boolean |
| 457 CHECK(bounds(operand(node, 0)).upper->Is(Type::String())); |
| 458 CHECK(bounds(operand(node, 1)).upper->Is(Type::String())); |
| 459 CHECK(bounds(node).upper->Is(Type::Boolean())); |
| 460 break; |
| 461 case IrOpcode::kStringAdd: |
| 462 // (String, String) -> String |
| 463 CHECK(bounds(operand(node, 0)).upper->Is(Type::String())); |
| 464 CHECK(bounds(operand(node, 1)).upper->Is(Type::String())); |
| 465 CHECK(bounds(node).upper->Is(Type::String())); |
| 466 break; |
| 467 case IrOpcode::kReferenceEqual: { |
| 468 // (Unique, Unique) -> Boolean |
| 469 CHECK(bounds(operand(node, 0)).upper->Is(Type::Unique())); |
| 470 CHECK(bounds(operand(node, 1)).upper->Is(Type::Unique())); |
| 471 CHECK(bounds(node).upper->Is(Type::Boolean())); |
| 472 break; |
| 473 } |
| 474 |
| 475 case IrOpcode::kChangeTaggedToInt32: { |
| 476 // Signed32 /\ Tagged -> Signed32 /\ UntaggedInt32 |
| 477 Type* from = Type::Intersect(Type::Signed32(), Type::Tagged()); |
| 478 Type* to = Type::Intersect(Type::Signed32(), Type::UntaggedInt32()); |
| 479 CHECK(bounds(operand(node)).upper->Is(from)); |
| 480 CHECK(bounds(node).upper->Is(to)); |
| 481 break; |
| 482 } |
| 483 case IrOpcode::kChangeTaggedToUint32: { |
| 484 // Unsigned32 /\ Tagged -> Unsigned32 /\ UntaggedInt32 |
| 485 Type* from = Type::Intersect(Type::Unsigned32(), Type::Tagged()); |
| 486 Type* to = Type::Intersect(Type::Unsigned32(), Type::UntaggedInt32()); |
| 487 CHECK(bounds(operand(node)).upper->Is(from)); |
| 488 CHECK(bounds(node).upper->Is(to)); |
| 489 break; |
| 490 } |
| 491 case IrOpcode::kChangeTaggedToFloat64: { |
| 492 // Number /\ Tagged -> Number /\ UntaggedFloat64 |
| 493 Type* from = Type::Intersect(Type::Number(), Type::Tagged()); |
| 494 Type* to = Type::Intersect(Type::Number(), Type::UntaggedFloat64()); |
| 495 CHECK(bounds(operand(node)).upper->Is(from)); |
| 496 CHECK(bounds(node).upper->Is(to)); |
| 497 break; |
| 498 } |
| 499 case IrOpcode::kChangeInt32ToTagged: { |
| 500 // Signed32 /\ UntaggedInt32 -> Signed32 /\ Tagged |
| 501 Type* from = Type::Intersect(Type::Signed32(), Type::UntaggedInt32()); |
| 502 Type* to = Type::Intersect(Type::Signed32(), Type::Tagged()); |
| 503 CHECK(bounds(operand(node)).upper->Is(from)); |
| 504 CHECK(bounds(node).upper->Is(to)); |
| 505 break; |
| 506 } |
| 507 case IrOpcode::kChangeUint32ToTagged: { |
| 508 // Unsigned32 /\ UntaggedInt32 -> Unsigned32 /\ Tagged |
| 509 Type* from = Type::Intersect(Type::Unsigned32(), Type::UntaggedInt32()); |
| 510 Type* to = Type::Intersect(Type::Unsigned32(), Type::Tagged()); |
| 511 CHECK(bounds(operand(node)).upper->Is(from)); |
| 512 CHECK(bounds(node).upper->Is(to)); |
| 513 break; |
| 514 } |
| 515 case IrOpcode::kChangeFloat64ToTagged: { |
| 516 // Number /\ UntaggedFloat64 -> Number /\ Tagged |
| 517 Type* from = Type::Intersect(Type::Number(), Type::UntaggedFloat64()); |
| 518 Type* to = Type::Intersect(Type::Number(), Type::Tagged()); |
| 519 CHECK(bounds(operand(node)).upper->Is(from)); |
| 520 CHECK(bounds(node).upper->Is(to)); |
| 521 break; |
| 522 } |
| 523 case IrOpcode::kChangeBoolToBit: { |
| 524 // Boolean /\ TaggedPtr -> Boolean /\ UntaggedInt1 |
| 525 Type* from = Type::Intersect(Type::Boolean(), Type::TaggedPtr()); |
| 526 Type* to = Type::Intersect(Type::Boolean(), Type::UntaggedInt1()); |
| 527 CHECK(bounds(operand(node)).upper->Is(from)); |
| 528 CHECK(bounds(node).upper->Is(to)); |
| 529 break; |
| 530 } |
| 531 case IrOpcode::kChangeBitToBool: { |
| 532 // Boolean /\ UntaggedInt1 -> Boolean /\ TaggedPtr |
| 533 Type* from = Type::Intersect(Type::Boolean(), Type::UntaggedInt1()); |
| 534 Type* to = Type::Intersect(Type::Boolean(), Type::TaggedPtr()); |
| 535 CHECK(bounds(operand(node)).upper->Is(from)); |
| 536 CHECK(bounds(node).upper->Is(to)); |
| 537 break; |
| 538 } |
| 539 |
| 540 case IrOpcode::kLoadField: |
| 541 // Object -> fieldtype |
| 542 CHECK(bounds(operand(node)).upper->Is(Type::Object())); |
| 543 CHECK(bounds(node).upper->Is(field(node).type)); |
| 544 break; |
| 545 case IrOpcode::kLoadElement: |
| 546 // Object -> elementtype |
| 547 CHECK(bounds(operand(node)).upper->Is(Type::Object())); |
| 548 CHECK(bounds(node).upper->Is(element(node).type)); |
| 549 break; |
| 550 case IrOpcode::kStoreField: |
| 551 // (Object, fieldtype) -> _|_ |
| 552 CHECK(bounds(operand(node, 0)).upper->Is(Type::Object())); |
| 553 CHECK(bounds(operand(node, 1)).upper->Is(field(node).type)); |
| 554 CHECK(bounds(node).upper->Is(Type::None())); |
| 555 break; |
| 556 case IrOpcode::kStoreElement: |
| 557 // (Object, elementtype) -> _|_ |
| 558 CHECK(bounds(operand(node, 0)).upper->Is(Type::Object())); |
| 559 CHECK(bounds(operand(node, 1)).upper->Is(element(node).type)); |
| 560 CHECK(bounds(node).upper->Is(Type::None())); |
| 561 break; |
| 562 |
| 563 // Machine operators |
| 564 // ----------------------- |
| 565 case IrOpcode::kLoad: |
| 566 case IrOpcode::kStore: |
| 567 case IrOpcode::kWord32And: |
| 568 case IrOpcode::kWord32Or: |
| 569 case IrOpcode::kWord32Xor: |
| 570 case IrOpcode::kWord32Shl: |
| 571 case IrOpcode::kWord32Shr: |
| 572 case IrOpcode::kWord32Sar: |
| 573 case IrOpcode::kWord32Ror: |
| 574 case IrOpcode::kWord32Equal: |
| 575 case IrOpcode::kWord64And: |
| 576 case IrOpcode::kWord64Or: |
| 577 case IrOpcode::kWord64Xor: |
| 578 case IrOpcode::kWord64Shl: |
| 579 case IrOpcode::kWord64Shr: |
| 580 case IrOpcode::kWord64Sar: |
| 581 case IrOpcode::kWord64Ror: |
| 582 case IrOpcode::kWord64Equal: |
| 583 case IrOpcode::kInt32Add: |
| 584 case IrOpcode::kInt32AddWithOverflow: |
| 585 case IrOpcode::kInt32Sub: |
| 586 case IrOpcode::kInt32SubWithOverflow: |
| 587 case IrOpcode::kInt32Mul: |
| 588 case IrOpcode::kInt32Div: |
| 589 case IrOpcode::kInt32UDiv: |
| 590 case IrOpcode::kInt32Mod: |
| 591 case IrOpcode::kInt32UMod: |
| 592 case IrOpcode::kInt32LessThan: |
| 593 case IrOpcode::kInt32LessThanOrEqual: |
| 594 case IrOpcode::kUint32LessThan: |
| 595 case IrOpcode::kUint32LessThanOrEqual: |
| 596 case IrOpcode::kInt64Add: |
| 597 case IrOpcode::kInt64Sub: |
| 598 case IrOpcode::kInt64Mul: |
| 599 case IrOpcode::kInt64Div: |
| 600 case IrOpcode::kInt64UDiv: |
| 601 case IrOpcode::kInt64Mod: |
| 602 case IrOpcode::kInt64UMod: |
| 603 case IrOpcode::kInt64LessThan: |
| 604 case IrOpcode::kInt64LessThanOrEqual: |
| 605 case IrOpcode::kFloat64Add: |
| 606 case IrOpcode::kFloat64Sub: |
| 607 case IrOpcode::kFloat64Mul: |
| 608 case IrOpcode::kFloat64Div: |
| 609 case IrOpcode::kFloat64Mod: |
| 610 case IrOpcode::kFloat64Equal: |
| 611 case IrOpcode::kFloat64LessThan: |
| 612 case IrOpcode::kFloat64LessThanOrEqual: |
| 613 case IrOpcode::kTruncateInt64ToInt32: |
| 614 case IrOpcode::kTruncateFloat64ToInt32: |
| 615 case IrOpcode::kChangeInt32ToInt64: |
| 616 case IrOpcode::kChangeUint32ToUint64: |
| 617 case IrOpcode::kChangeInt32ToFloat64: |
| 618 case IrOpcode::kChangeUint32ToFloat64: |
| 619 case IrOpcode::kChangeFloat64ToInt32: |
| 620 case IrOpcode::kChangeFloat64ToUint32: |
| 621 // TODO(rossberg): Check. |
| 622 break; |
171 } | 623 } |
172 case IrOpcode::kInt32Constant: | |
173 case IrOpcode::kInt64Constant: | |
174 case IrOpcode::kFloat64Constant: | |
175 case IrOpcode::kExternalConstant: | |
176 case IrOpcode::kNumberConstant: | |
177 case IrOpcode::kHeapConstant: | |
178 // Constants have no inputs. | |
179 CHECK_EQ(0, input_count); | |
180 break; | |
181 case IrOpcode::kPhi: { | |
182 // Phi input count matches parent control node. | |
183 CHECK_EQ(1, control_count); | |
184 Node* control = NodeProperties::GetControlInput(node, 0); | |
185 CHECK_EQ(value_count, | |
186 OperatorProperties::GetControlInputCount(control->op())); | |
187 break; | |
188 } | |
189 case IrOpcode::kEffectPhi: { | |
190 // EffectPhi input count matches parent control node. | |
191 CHECK_EQ(1, control_count); | |
192 Node* control = NodeProperties::GetControlInput(node, 0); | |
193 CHECK_EQ(effect_count, | |
194 OperatorProperties::GetControlInputCount(control->op())); | |
195 break; | |
196 } | |
197 case IrOpcode::kLazyDeoptimization: | |
198 // TODO(jarin): what are the constraints on these? | |
199 break; | |
200 case IrOpcode::kDeoptimize: | |
201 // TODO(jarin): what are the constraints on these? | |
202 break; | |
203 case IrOpcode::kFrameState: | |
204 // TODO(jarin): what are the constraints on these? | |
205 break; | |
206 case IrOpcode::kCall: | |
207 // TODO(rossberg): what are the constraints on these? | |
208 break; | |
209 case IrOpcode::kContinuation: | |
210 // TODO(jarin): what are the constraints on these? | |
211 break; | |
212 case IrOpcode::kProjection: { | |
213 // Projection has an input that produces enough values. | |
214 int index = static_cast<Operator1<int>*>(node->op())->parameter(); | |
215 Node* input = NodeProperties::GetValueInput(node, 0); | |
216 CHECK_GT(OperatorProperties::GetValueOutputCount(input->op()), index); | |
217 break; | |
218 } | |
219 default: | |
220 // TODO(rossberg): Check other node kinds. | |
221 break; | |
222 } | 624 } |
223 | 625 |
224 if (from_start) { | 626 if (from_start) { |
225 reached_from_start.insert(node); | 627 reached_from_start.insert(node); |
226 } else { | 628 } else { |
227 reached_from_end.insert(node); | 629 reached_from_end.insert(node); |
228 } | 630 } |
229 | 631 |
230 return GenericGraphVisit::CONTINUE; | 632 return GenericGraphVisit::CONTINUE; |
231 } | 633 } |
232 | 634 |
233 | 635 |
234 void Verifier::Run(Graph* graph) { | 636 void Verifier::Run(Graph* graph) { |
235 Visitor visitor(graph->zone()); | 637 Visitor visitor(graph->zone(), graph->is_typed()); |
236 | 638 |
237 CHECK_NE(NULL, graph->start()); | 639 CHECK_NE(NULL, graph->start()); |
238 visitor.from_start = true; | 640 visitor.from_start = true; |
239 graph->VisitNodeUsesFromStart(&visitor); | 641 graph->VisitNodeUsesFromStart(&visitor); |
240 CHECK_NE(NULL, graph->end()); | 642 CHECK_NE(NULL, graph->end()); |
241 visitor.from_start = false; | 643 visitor.from_start = false; |
242 graph->VisitNodeInputsFromEnd(&visitor); | 644 graph->VisitNodeInputsFromEnd(&visitor); |
243 | 645 |
244 // All control nodes reachable from end are reachable from start. | 646 // All control nodes reachable from end are reachable from start. |
245 for (NodeSet::iterator it = visitor.reached_from_end.begin(); | 647 for (NodeSet::iterator it = visitor.reached_from_end.begin(); |
246 it != visitor.reached_from_end.end(); ++it) { | 648 it != visitor.reached_from_end.end(); ++it) { |
247 CHECK(!NodeProperties::IsControl(*it) || | 649 CHECK(!NodeProperties::IsControl(*it) || |
248 visitor.reached_from_start.count(*it)); | 650 visitor.reached_from_start.count(*it)); |
249 } | 651 } |
250 } | 652 } |
251 | 653 |
252 | 654 |
| 655 // ----------------------------------------------------------------------------- |
| 656 |
253 static bool HasDominatingDef(Schedule* schedule, Node* node, | 657 static bool HasDominatingDef(Schedule* schedule, Node* node, |
254 BasicBlock* container, BasicBlock* use_block, | 658 BasicBlock* container, BasicBlock* use_block, |
255 int use_pos) { | 659 int use_pos) { |
256 BasicBlock* block = use_block; | 660 BasicBlock* block = use_block; |
257 while (true) { | 661 while (true) { |
258 while (use_pos >= 0) { | 662 while (use_pos >= 0) { |
259 if (block->nodes_[use_pos] == node) return true; | 663 if (block->nodes_[use_pos] == node) return true; |
260 use_pos--; | 664 use_pos--; |
261 } | 665 } |
262 block = schedule->dominator(block); | 666 block = schedule->dominator(block); |
(...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
443 // Check inputs for all nodes in the block. | 847 // Check inputs for all nodes in the block. |
444 for (size_t i = 0; i < block->nodes_.size(); i++) { | 848 for (size_t i = 0; i < block->nodes_.size(); i++) { |
445 Node* node = block->nodes_[i]; | 849 Node* node = block->nodes_[i]; |
446 CheckInputsDominate(schedule, block, node, static_cast<int>(i) - 1); | 850 CheckInputsDominate(schedule, block, node, static_cast<int>(i) - 1); |
447 } | 851 } |
448 } | 852 } |
449 } | 853 } |
450 } | 854 } |
451 } | 855 } |
452 } // namespace v8::internal::compiler | 856 } // namespace v8::internal::compiler |
OLD | NEW |