• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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