1 // Copyright 2015 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "src/compiler/node-properties.h"
6 #include "src/compiler/common-operator.h"
7 #include "src/compiler/graph.h"
8 #include "src/compiler/js-operator.h"
9 #include "src/compiler/linkage.h"
10 #include "src/compiler/node-matchers.h"
11 #include "src/compiler/operator-properties.h"
12 #include "src/compiler/simplified-operator.h"
13 #include "src/compiler/verifier.h"
14 #include "src/handles-inl.h"
15 #include "src/objects-inl.h"
16 #include "src/zone/zone-handle-set.h"
17
18 namespace v8 {
19 namespace internal {
20 namespace compiler {
21
22 // static
PastValueIndex(Node * node)23 int NodeProperties::PastValueIndex(Node* node) {
24 return FirstValueIndex(node) + node->op()->ValueInputCount();
25 }
26
27
28 // static
PastContextIndex(Node * node)29 int NodeProperties::PastContextIndex(Node* node) {
30 return FirstContextIndex(node) +
31 OperatorProperties::GetContextInputCount(node->op());
32 }
33
34
35 // static
PastFrameStateIndex(Node * node)36 int NodeProperties::PastFrameStateIndex(Node* node) {
37 return FirstFrameStateIndex(node) +
38 OperatorProperties::GetFrameStateInputCount(node->op());
39 }
40
41
42 // static
PastEffectIndex(Node * node)43 int NodeProperties::PastEffectIndex(Node* node) {
44 return FirstEffectIndex(node) + node->op()->EffectInputCount();
45 }
46
47
48 // static
PastControlIndex(Node * node)49 int NodeProperties::PastControlIndex(Node* node) {
50 return FirstControlIndex(node) + node->op()->ControlInputCount();
51 }
52
53
54 // static
GetValueInput(Node * node,int index)55 Node* NodeProperties::GetValueInput(Node* node, int index) {
56 DCHECK(0 <= index && index < node->op()->ValueInputCount());
57 return node->InputAt(FirstValueIndex(node) + index);
58 }
59
60
61 // static
GetContextInput(Node * node)62 Node* NodeProperties::GetContextInput(Node* node) {
63 DCHECK(OperatorProperties::HasContextInput(node->op()));
64 return node->InputAt(FirstContextIndex(node));
65 }
66
67
68 // static
GetFrameStateInput(Node * node)69 Node* NodeProperties::GetFrameStateInput(Node* node) {
70 DCHECK_EQ(1, OperatorProperties::GetFrameStateInputCount(node->op()));
71 return node->InputAt(FirstFrameStateIndex(node));
72 }
73
74
75 // static
GetEffectInput(Node * node,int index)76 Node* NodeProperties::GetEffectInput(Node* node, int index) {
77 DCHECK(0 <= index && index < node->op()->EffectInputCount());
78 return node->InputAt(FirstEffectIndex(node) + index);
79 }
80
81
82 // static
GetControlInput(Node * node,int index)83 Node* NodeProperties::GetControlInput(Node* node, int index) {
84 DCHECK(0 <= index && index < node->op()->ControlInputCount());
85 return node->InputAt(FirstControlIndex(node) + index);
86 }
87
88
89 // static
IsValueEdge(Edge edge)90 bool NodeProperties::IsValueEdge(Edge edge) {
91 Node* const node = edge.from();
92 return IsInputRange(edge, FirstValueIndex(node),
93 node->op()->ValueInputCount());
94 }
95
96
97 // static
IsContextEdge(Edge edge)98 bool NodeProperties::IsContextEdge(Edge edge) {
99 Node* const node = edge.from();
100 return IsInputRange(edge, FirstContextIndex(node),
101 OperatorProperties::GetContextInputCount(node->op()));
102 }
103
104
105 // static
IsFrameStateEdge(Edge edge)106 bool NodeProperties::IsFrameStateEdge(Edge edge) {
107 Node* const node = edge.from();
108 return IsInputRange(edge, FirstFrameStateIndex(node),
109 OperatorProperties::GetFrameStateInputCount(node->op()));
110 }
111
112
113 // static
IsEffectEdge(Edge edge)114 bool NodeProperties::IsEffectEdge(Edge edge) {
115 Node* const node = edge.from();
116 return IsInputRange(edge, FirstEffectIndex(node),
117 node->op()->EffectInputCount());
118 }
119
120
121 // static
IsControlEdge(Edge edge)122 bool NodeProperties::IsControlEdge(Edge edge) {
123 Node* const node = edge.from();
124 return IsInputRange(edge, FirstControlIndex(node),
125 node->op()->ControlInputCount());
126 }
127
128
129 // static
IsExceptionalCall(Node * node,Node ** out_exception)130 bool NodeProperties::IsExceptionalCall(Node* node, Node** out_exception) {
131 if (node->op()->HasProperty(Operator::kNoThrow)) return false;
132 for (Edge const edge : node->use_edges()) {
133 if (!NodeProperties::IsControlEdge(edge)) continue;
134 if (edge.from()->opcode() == IrOpcode::kIfException) {
135 if (out_exception != nullptr) *out_exception = edge.from();
136 return true;
137 }
138 }
139 return false;
140 }
141
142 // static
FindSuccessfulControlProjection(Node * node)143 Node* NodeProperties::FindSuccessfulControlProjection(Node* node) {
144 DCHECK_GT(node->op()->ControlOutputCount(), 0);
145 if (node->op()->HasProperty(Operator::kNoThrow)) return node;
146 for (Edge const edge : node->use_edges()) {
147 if (!NodeProperties::IsControlEdge(edge)) continue;
148 if (edge.from()->opcode() == IrOpcode::kIfSuccess) {
149 return edge.from();
150 }
151 }
152 return node;
153 }
154
155 // static
ReplaceValueInput(Node * node,Node * value,int index)156 void NodeProperties::ReplaceValueInput(Node* node, Node* value, int index) {
157 DCHECK(index < node->op()->ValueInputCount());
158 node->ReplaceInput(FirstValueIndex(node) + index, value);
159 }
160
161
162 // static
ReplaceValueInputs(Node * node,Node * value)163 void NodeProperties::ReplaceValueInputs(Node* node, Node* value) {
164 int value_input_count = node->op()->ValueInputCount();
165 DCHECK_LE(1, value_input_count);
166 node->ReplaceInput(0, value);
167 while (--value_input_count > 0) {
168 node->RemoveInput(value_input_count);
169 }
170 }
171
172
173 // static
ReplaceContextInput(Node * node,Node * context)174 void NodeProperties::ReplaceContextInput(Node* node, Node* context) {
175 node->ReplaceInput(FirstContextIndex(node), context);
176 }
177
178
179 // static
ReplaceControlInput(Node * node,Node * control,int index)180 void NodeProperties::ReplaceControlInput(Node* node, Node* control, int index) {
181 DCHECK(index < node->op()->ControlInputCount());
182 node->ReplaceInput(FirstControlIndex(node) + index, control);
183 }
184
185
186 // static
ReplaceEffectInput(Node * node,Node * effect,int index)187 void NodeProperties::ReplaceEffectInput(Node* node, Node* effect, int index) {
188 DCHECK(index < node->op()->EffectInputCount());
189 return node->ReplaceInput(FirstEffectIndex(node) + index, effect);
190 }
191
192
193 // static
ReplaceFrameStateInput(Node * node,Node * frame_state)194 void NodeProperties::ReplaceFrameStateInput(Node* node, Node* frame_state) {
195 DCHECK_EQ(1, OperatorProperties::GetFrameStateInputCount(node->op()));
196 node->ReplaceInput(FirstFrameStateIndex(node), frame_state);
197 }
198
199
200 // static
RemoveNonValueInputs(Node * node)201 void NodeProperties::RemoveNonValueInputs(Node* node) {
202 node->TrimInputCount(node->op()->ValueInputCount());
203 }
204
205
206 // static
RemoveValueInputs(Node * node)207 void NodeProperties::RemoveValueInputs(Node* node) {
208 int value_input_count = node->op()->ValueInputCount();
209 while (--value_input_count >= 0) {
210 node->RemoveInput(value_input_count);
211 }
212 }
213
214
MergeControlToEnd(Graph * graph,CommonOperatorBuilder * common,Node * node)215 void NodeProperties::MergeControlToEnd(Graph* graph,
216 CommonOperatorBuilder* common,
217 Node* node) {
218 graph->end()->AppendInput(graph->zone(), node);
219 graph->end()->set_op(common->End(graph->end()->InputCount()));
220 }
221
222
223 // static
ReplaceUses(Node * node,Node * value,Node * effect,Node * success,Node * exception)224 void NodeProperties::ReplaceUses(Node* node, Node* value, Node* effect,
225 Node* success, Node* exception) {
226 // Requires distinguishing between value, effect and control edges.
227 for (Edge edge : node->use_edges()) {
228 if (IsControlEdge(edge)) {
229 if (edge.from()->opcode() == IrOpcode::kIfSuccess) {
230 DCHECK_NOT_NULL(success);
231 edge.UpdateTo(success);
232 } else if (edge.from()->opcode() == IrOpcode::kIfException) {
233 DCHECK_NOT_NULL(exception);
234 edge.UpdateTo(exception);
235 } else {
236 DCHECK_NOT_NULL(success);
237 edge.UpdateTo(success);
238 }
239 } else if (IsEffectEdge(edge)) {
240 DCHECK_NOT_NULL(effect);
241 edge.UpdateTo(effect);
242 } else {
243 DCHECK_NOT_NULL(value);
244 edge.UpdateTo(value);
245 }
246 }
247 }
248
249
250 // static
ChangeOp(Node * node,const Operator * new_op)251 void NodeProperties::ChangeOp(Node* node, const Operator* new_op) {
252 node->set_op(new_op);
253 Verifier::VerifyNode(node);
254 }
255
256
257 // static
FindFrameStateBefore(Node * node)258 Node* NodeProperties::FindFrameStateBefore(Node* node) {
259 Node* effect = NodeProperties::GetEffectInput(node);
260 while (effect->opcode() != IrOpcode::kCheckpoint) {
261 if (effect->opcode() == IrOpcode::kDead) return effect;
262 DCHECK_EQ(1, effect->op()->EffectInputCount());
263 effect = NodeProperties::GetEffectInput(effect);
264 }
265 Node* frame_state = GetFrameStateInput(effect);
266 return frame_state;
267 }
268
269 // static
FindProjection(Node * node,size_t projection_index)270 Node* NodeProperties::FindProjection(Node* node, size_t projection_index) {
271 for (auto use : node->uses()) {
272 if (use->opcode() == IrOpcode::kProjection &&
273 ProjectionIndexOf(use->op()) == projection_index) {
274 return use;
275 }
276 }
277 return nullptr;
278 }
279
280
281 // static
CollectValueProjections(Node * node,Node ** projections,size_t projection_count)282 void NodeProperties::CollectValueProjections(Node* node, Node** projections,
283 size_t projection_count) {
284 #ifdef DEBUG
285 for (size_t index = 0; index < projection_count; ++index) {
286 DCHECK_NULL(projections[index]);
287 }
288 #endif
289 for (Edge const edge : node->use_edges()) {
290 if (!IsValueEdge(edge)) continue;
291 Node* use = edge.from();
292 DCHECK_EQ(IrOpcode::kProjection, use->opcode());
293 projections[ProjectionIndexOf(use->op())] = use;
294 }
295 }
296
297
298 // static
CollectControlProjections(Node * node,Node ** projections,size_t projection_count)299 void NodeProperties::CollectControlProjections(Node* node, Node** projections,
300 size_t projection_count) {
301 #ifdef DEBUG
302 DCHECK_LE(static_cast<int>(projection_count), node->UseCount());
303 std::memset(projections, 0, sizeof(*projections) * projection_count);
304 #endif
305 size_t if_value_index = 0;
306 for (Edge const edge : node->use_edges()) {
307 if (!IsControlEdge(edge)) continue;
308 Node* use = edge.from();
309 size_t index;
310 switch (use->opcode()) {
311 case IrOpcode::kIfTrue:
312 DCHECK_EQ(IrOpcode::kBranch, node->opcode());
313 index = 0;
314 break;
315 case IrOpcode::kIfFalse:
316 DCHECK_EQ(IrOpcode::kBranch, node->opcode());
317 index = 1;
318 break;
319 case IrOpcode::kIfSuccess:
320 DCHECK(!node->op()->HasProperty(Operator::kNoThrow));
321 index = 0;
322 break;
323 case IrOpcode::kIfException:
324 DCHECK(!node->op()->HasProperty(Operator::kNoThrow));
325 index = 1;
326 break;
327 case IrOpcode::kIfValue:
328 DCHECK_EQ(IrOpcode::kSwitch, node->opcode());
329 index = if_value_index++;
330 break;
331 case IrOpcode::kIfDefault:
332 DCHECK_EQ(IrOpcode::kSwitch, node->opcode());
333 index = projection_count - 1;
334 break;
335 default:
336 continue;
337 }
338 DCHECK_LT(if_value_index, projection_count);
339 DCHECK_LT(index, projection_count);
340 DCHECK_NULL(projections[index]);
341 projections[index] = use;
342 }
343 #ifdef DEBUG
344 for (size_t index = 0; index < projection_count; ++index) {
345 DCHECK_NOT_NULL(projections[index]);
346 }
347 #endif
348 }
349
350 // static
IsSame(Node * a,Node * b)351 bool NodeProperties::IsSame(Node* a, Node* b) {
352 for (;;) {
353 if (a->opcode() == IrOpcode::kCheckHeapObject) {
354 a = GetValueInput(a, 0);
355 continue;
356 }
357 if (b->opcode() == IrOpcode::kCheckHeapObject) {
358 b = GetValueInput(b, 0);
359 continue;
360 }
361 return a == b;
362 }
363 }
364
365 // static
InferReceiverMaps(Isolate * isolate,Node * receiver,Node * effect,ZoneHandleSet<Map> * maps_return)366 NodeProperties::InferReceiverMapsResult NodeProperties::InferReceiverMaps(
367 Isolate* isolate, Node* receiver, Node* effect,
368 ZoneHandleSet<Map>* maps_return) {
369 HeapObjectMatcher m(receiver);
370 if (m.HasValue()) {
371 Handle<HeapObject> receiver = m.Value();
372 // We don't use ICs for the Array.prototype and the Object.prototype
373 // because the runtime has to be able to intercept them properly, so
374 // we better make sure that TurboFan doesn't outsmart the system here
375 // by storing to elements of either prototype directly.
376 //
377 // TODO(bmeurer): This can be removed once the Array.prototype and
378 // Object.prototype have NO_ELEMENTS elements kind.
379 if (!isolate->IsInAnyContext(*receiver,
380 Context::INITIAL_ARRAY_PROTOTYPE_INDEX) &&
381 !isolate->IsInAnyContext(*receiver,
382 Context::INITIAL_OBJECT_PROTOTYPE_INDEX)) {
383 Handle<Map> receiver_map(receiver->map(), isolate);
384 if (receiver_map->is_stable()) {
385 // The {receiver_map} is only reliable when we install a stability
386 // code dependency.
387 *maps_return = ZoneHandleSet<Map>(receiver_map);
388 return kUnreliableReceiverMaps;
389 }
390 }
391 }
392 InferReceiverMapsResult result = kReliableReceiverMaps;
393 while (true) {
394 switch (effect->opcode()) {
395 case IrOpcode::kMapGuard: {
396 Node* const object = GetValueInput(effect, 0);
397 if (IsSame(receiver, object)) {
398 *maps_return = MapGuardMapsOf(effect->op()).maps();
399 return result;
400 }
401 break;
402 }
403 case IrOpcode::kCheckMaps: {
404 Node* const object = GetValueInput(effect, 0);
405 if (IsSame(receiver, object)) {
406 *maps_return = CheckMapsParametersOf(effect->op()).maps();
407 return result;
408 }
409 break;
410 }
411 case IrOpcode::kJSCreate: {
412 if (IsSame(receiver, effect)) {
413 HeapObjectMatcher mtarget(GetValueInput(effect, 0));
414 HeapObjectMatcher mnewtarget(GetValueInput(effect, 1));
415 if (mtarget.HasValue() && mnewtarget.HasValue() &&
416 mnewtarget.Value()->IsJSFunction()) {
417 Handle<JSFunction> original_constructor =
418 Handle<JSFunction>::cast(mnewtarget.Value());
419 if (original_constructor->has_initial_map()) {
420 Handle<Map> initial_map(original_constructor->initial_map(),
421 isolate);
422 if (initial_map->constructor_or_backpointer() ==
423 *mtarget.Value()) {
424 *maps_return = ZoneHandleSet<Map>(initial_map);
425 return result;
426 }
427 }
428 }
429 // We reached the allocation of the {receiver}.
430 return kNoReceiverMaps;
431 }
432 break;
433 }
434 case IrOpcode::kStoreField: {
435 // We only care about StoreField of maps.
436 Node* const object = GetValueInput(effect, 0);
437 FieldAccess const& access = FieldAccessOf(effect->op());
438 if (access.base_is_tagged == kTaggedBase &&
439 access.offset == HeapObject::kMapOffset) {
440 if (IsSame(receiver, object)) {
441 Node* const value = GetValueInput(effect, 1);
442 HeapObjectMatcher m(value);
443 if (m.HasValue()) {
444 *maps_return = ZoneHandleSet<Map>(Handle<Map>::cast(m.Value()));
445 return result;
446 }
447 }
448 // Without alias analysis we cannot tell whether this
449 // StoreField[map] affects {receiver} or not.
450 result = kUnreliableReceiverMaps;
451 }
452 break;
453 }
454 case IrOpcode::kJSStoreMessage:
455 case IrOpcode::kJSStoreModule:
456 case IrOpcode::kStoreElement:
457 case IrOpcode::kStoreTypedElement: {
458 // These never change the map of objects.
459 break;
460 }
461 case IrOpcode::kFinishRegion: {
462 // FinishRegion renames the output of allocations, so we need
463 // to update the {receiver} that we are looking for, if the
464 // {receiver} matches the current {effect}.
465 if (IsSame(receiver, effect)) receiver = GetValueInput(effect, 0);
466 break;
467 }
468 case IrOpcode::kEffectPhi: {
469 Node* control = GetControlInput(effect);
470 if (control->opcode() != IrOpcode::kLoop) {
471 DCHECK(control->opcode() == IrOpcode::kDead ||
472 control->opcode() == IrOpcode::kMerge);
473 return kNoReceiverMaps;
474 }
475
476 // Continue search for receiver map outside the loop. Since operations
477 // inside the loop may change the map, the result is unreliable.
478 effect = GetEffectInput(effect, 0);
479 result = kUnreliableReceiverMaps;
480 continue;
481 }
482 default: {
483 DCHECK_EQ(1, effect->op()->EffectOutputCount());
484 if (effect->op()->EffectInputCount() != 1) {
485 // Didn't find any appropriate CheckMaps node.
486 return kNoReceiverMaps;
487 }
488 if (!effect->op()->HasProperty(Operator::kNoWrite)) {
489 // Without alias/escape analysis we cannot tell whether this
490 // {effect} affects {receiver} or not.
491 result = kUnreliableReceiverMaps;
492 }
493 break;
494 }
495 }
496
497 // Stop walking the effect chain once we hit the definition of
498 // the {receiver} along the {effect}s.
499 if (IsSame(receiver, effect)) return kNoReceiverMaps;
500
501 // Continue with the next {effect}.
502 DCHECK_EQ(1, effect->op()->EffectInputCount());
503 effect = NodeProperties::GetEffectInput(effect);
504 }
505 }
506
507 // static
GetMapWitness(Isolate * isolate,Node * node)508 MaybeHandle<Map> NodeProperties::GetMapWitness(Isolate* isolate, Node* node) {
509 ZoneHandleSet<Map> maps;
510 Node* receiver = NodeProperties::GetValueInput(node, 1);
511 Node* effect = NodeProperties::GetEffectInput(node);
512 NodeProperties::InferReceiverMapsResult result =
513 NodeProperties::InferReceiverMaps(isolate, receiver, effect, &maps);
514 if (result == NodeProperties::kReliableReceiverMaps && maps.size() == 1) {
515 return maps[0];
516 }
517 return MaybeHandle<Map>();
518 }
519
520 // static
HasInstanceTypeWitness(Isolate * isolate,Node * receiver,Node * effect,InstanceType instance_type)521 bool NodeProperties::HasInstanceTypeWitness(Isolate* isolate, Node* receiver,
522 Node* effect,
523 InstanceType instance_type) {
524 ZoneHandleSet<Map> receiver_maps;
525 NodeProperties::InferReceiverMapsResult result =
526 NodeProperties::InferReceiverMaps(isolate, receiver, effect,
527 &receiver_maps);
528 switch (result) {
529 case NodeProperties::kUnreliableReceiverMaps:
530 case NodeProperties::kReliableReceiverMaps:
531 DCHECK_NE(0, receiver_maps.size());
532 for (size_t i = 0; i < receiver_maps.size(); ++i) {
533 if (receiver_maps[i]->instance_type() != instance_type) return false;
534 }
535 return true;
536
537 case NodeProperties::kNoReceiverMaps:
538 return false;
539 }
540 UNREACHABLE();
541 }
542
543 // static
NoObservableSideEffectBetween(Node * effect,Node * dominator)544 bool NodeProperties::NoObservableSideEffectBetween(Node* effect,
545 Node* dominator) {
546 while (effect != dominator) {
547 if (effect->op()->EffectInputCount() == 1 &&
548 effect->op()->properties() & Operator::kNoWrite) {
549 effect = NodeProperties::GetEffectInput(effect);
550 } else {
551 return false;
552 }
553 }
554 return true;
555 }
556
557 // static
CanBePrimitive(Isolate * isolate,Node * receiver,Node * effect)558 bool NodeProperties::CanBePrimitive(Isolate* isolate, Node* receiver,
559 Node* effect) {
560 switch (receiver->opcode()) {
561 #define CASE(Opcode) case IrOpcode::k##Opcode:
562 JS_CONSTRUCT_OP_LIST(CASE)
563 JS_CREATE_OP_LIST(CASE)
564 #undef CASE
565 case IrOpcode::kCheckReceiver:
566 case IrOpcode::kConvertReceiver:
567 case IrOpcode::kJSGetSuperConstructor:
568 case IrOpcode::kJSToObject:
569 return false;
570 case IrOpcode::kHeapConstant: {
571 Handle<HeapObject> value = HeapObjectMatcher(receiver).Value();
572 return value->IsPrimitive();
573 }
574 default: {
575 // We don't really care about the exact maps here,
576 // just the instance types, which don't change
577 // across potential side-effecting operations.
578 ZoneHandleSet<Map> maps;
579 if (InferReceiverMaps(isolate, receiver, effect, &maps) !=
580 kNoReceiverMaps) {
581 // Check if all {maps} are actually JSReceiver maps.
582 for (size_t i = 0; i < maps.size(); ++i) {
583 if (!maps[i]->IsJSReceiverMap()) return true;
584 }
585 return false;
586 }
587 return true;
588 }
589 }
590 }
591
592 // static
CanBeNullOrUndefined(Isolate * isolate,Node * receiver,Node * effect)593 bool NodeProperties::CanBeNullOrUndefined(Isolate* isolate, Node* receiver,
594 Node* effect) {
595 if (CanBePrimitive(isolate, receiver, effect)) {
596 switch (receiver->opcode()) {
597 case IrOpcode::kCheckInternalizedString:
598 case IrOpcode::kCheckNumber:
599 case IrOpcode::kCheckSmi:
600 case IrOpcode::kCheckString:
601 case IrOpcode::kCheckSymbol:
602 case IrOpcode::kJSToInteger:
603 case IrOpcode::kJSToLength:
604 case IrOpcode::kJSToName:
605 case IrOpcode::kJSToNumber:
606 case IrOpcode::kJSToNumberConvertBigInt:
607 case IrOpcode::kJSToNumeric:
608 case IrOpcode::kJSToString:
609 case IrOpcode::kToBoolean:
610 return false;
611 case IrOpcode::kHeapConstant: {
612 Handle<HeapObject> value = HeapObjectMatcher(receiver).Value();
613 return value->IsNullOrUndefined(isolate);
614 }
615 default:
616 return true;
617 }
618 }
619 return false;
620 }
621
622 // static
GetOuterContext(Node * node,size_t * depth)623 Node* NodeProperties::GetOuterContext(Node* node, size_t* depth) {
624 Node* context = NodeProperties::GetContextInput(node);
625 while (*depth > 0 &&
626 IrOpcode::IsContextChainExtendingOpcode(context->opcode())) {
627 context = NodeProperties::GetContextInput(context);
628 (*depth)--;
629 }
630 return context;
631 }
632
633 // static
GetTypeOrAny(Node * node)634 Type NodeProperties::GetTypeOrAny(Node* node) {
635 return IsTyped(node) ? node->type() : Type::Any();
636 }
637
638
639 // static
AllValueInputsAreTyped(Node * node)640 bool NodeProperties::AllValueInputsAreTyped(Node* node) {
641 int input_count = node->op()->ValueInputCount();
642 for (int index = 0; index < input_count; ++index) {
643 if (!IsTyped(GetValueInput(node, index))) return false;
644 }
645 return true;
646 }
647
648
649 // static
IsInputRange(Edge edge,int first,int num)650 bool NodeProperties::IsInputRange(Edge edge, int first, int num) {
651 if (num == 0) return false;
652 int const index = edge.index();
653 return first <= index && index < first + num;
654 }
655
656 // static
HashCode(Node * node)657 size_t NodeProperties::HashCode(Node* node) {
658 size_t h = base::hash_combine(node->op()->HashCode(), node->InputCount());
659 for (Node* input : node->inputs()) {
660 h = base::hash_combine(h, input->id());
661 }
662 return h;
663 }
664
665 // static
Equals(Node * a,Node * b)666 bool NodeProperties::Equals(Node* a, Node* b) {
667 DCHECK_NOT_NULL(a);
668 DCHECK_NOT_NULL(b);
669 DCHECK_NOT_NULL(a->op());
670 DCHECK_NOT_NULL(b->op());
671 if (!a->op()->Equals(b->op())) return false;
672 if (a->InputCount() != b->InputCount()) return false;
673 Node::Inputs aInputs = a->inputs();
674 Node::Inputs bInputs = b->inputs();
675
676 auto aIt = aInputs.begin();
677 auto bIt = bInputs.begin();
678 auto aEnd = aInputs.end();
679
680 for (; aIt != aEnd; ++aIt, ++bIt) {
681 DCHECK_NOT_NULL(*aIt);
682 DCHECK_NOT_NULL(*bIt);
683 if ((*aIt)->id() != (*bIt)->id()) return false;
684 }
685 return true;
686 }
687
688 } // namespace compiler
689 } // namespace internal
690 } // namespace v8
691