V8 API Reference, 7.2.502.16 (for Deno 0.2.4)
node-properties.cc
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
23 int NodeProperties::PastValueIndex(Node* node) {
24  return FirstValueIndex(node) + node->op()->ValueInputCount();
25 }
26 
27 
28 // static
29 int NodeProperties::PastContextIndex(Node* node) {
30  return FirstContextIndex(node) +
31  OperatorProperties::GetContextInputCount(node->op());
32 }
33 
34 
35 // static
36 int NodeProperties::PastFrameStateIndex(Node* node) {
37  return FirstFrameStateIndex(node) +
38  OperatorProperties::GetFrameStateInputCount(node->op());
39 }
40 
41 
42 // static
43 int NodeProperties::PastEffectIndex(Node* node) {
44  return FirstEffectIndex(node) + node->op()->EffectInputCount();
45 }
46 
47 
48 // static
49 int NodeProperties::PastControlIndex(Node* node) {
50  return FirstControlIndex(node) + node->op()->ControlInputCount();
51 }
52 
53 
54 // static
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
62 Node* NodeProperties::GetContextInput(Node* node) {
63  DCHECK(OperatorProperties::HasContextInput(node->op()));
64  return node->InputAt(FirstContextIndex(node));
65 }
66 
67 
68 // static
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
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
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
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
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
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
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
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
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
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
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
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
174 void NodeProperties::ReplaceContextInput(Node* node, Node* context) {
175  node->ReplaceInput(FirstContextIndex(node), context);
176 }
177 
178 
179 // static
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
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
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
201 void NodeProperties::RemoveNonValueInputs(Node* node) {
202  node->TrimInputCount(node->op()->ValueInputCount());
203 }
204 
205 
206 // static
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 
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
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
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
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
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
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
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
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
366 NodeProperties::InferReceiverMapsResult NodeProperties::InferReceiverMaps(
367  JSHeapBroker* broker, Node* receiver, Node* effect,
368  ZoneHandleSet<Map>* maps_return) {
369  HeapObjectMatcher m(receiver);
370  if (m.HasValue()) {
371  HeapObjectRef receiver = m.Ref(broker).AsHeapObject();
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 (!receiver.IsJSObject() ||
380  !broker->IsArrayOrObjectPrototype(receiver.AsJSObject())) {
381  if (receiver.map().is_stable()) {
382  // The {receiver_map} is only reliable when we install a stability
383  // code dependency.
384  *maps_return = ZoneHandleSet<Map>(receiver.map().object());
385  return kUnreliableReceiverMaps;
386  }
387  }
388  }
389  InferReceiverMapsResult result = kReliableReceiverMaps;
390  while (true) {
391  switch (effect->opcode()) {
392  case IrOpcode::kMapGuard: {
393  Node* const object = GetValueInput(effect, 0);
394  if (IsSame(receiver, object)) {
395  *maps_return = MapGuardMapsOf(effect->op()).maps();
396  return result;
397  }
398  break;
399  }
400  case IrOpcode::kCheckMaps: {
401  Node* const object = GetValueInput(effect, 0);
402  if (IsSame(receiver, object)) {
403  *maps_return = CheckMapsParametersOf(effect->op()).maps();
404  return result;
405  }
406  break;
407  }
408  case IrOpcode::kJSCreate: {
409  if (IsSame(receiver, effect)) {
410  HeapObjectMatcher mtarget(GetValueInput(effect, 0));
411  HeapObjectMatcher mnewtarget(GetValueInput(effect, 1));
412  if (mtarget.HasValue() && mnewtarget.HasValue() &&
413  mnewtarget.Ref(broker).IsJSFunction()) {
414  JSFunctionRef original_constructor =
415  mnewtarget.Ref(broker).AsJSFunction();
416  if (original_constructor.has_initial_map()) {
417  original_constructor.Serialize();
418  MapRef initial_map = original_constructor.initial_map();
419  if (initial_map.GetConstructor().equals(mtarget.Ref(broker))) {
420  *maps_return = ZoneHandleSet<Map>(initial_map.object());
421  return result;
422  }
423  }
424  }
425  // We reached the allocation of the {receiver}.
426  return kNoReceiverMaps;
427  }
428  break;
429  }
430  case IrOpcode::kJSCreatePromise: {
431  if (IsSame(receiver, effect)) {
432  *maps_return = ZoneHandleSet<Map>(broker->native_context()
433  .promise_function()
434  .initial_map()
435  .object());
436  return result;
437  }
438  break;
439  }
440  case IrOpcode::kStoreField: {
441  // We only care about StoreField of maps.
442  Node* const object = GetValueInput(effect, 0);
443  FieldAccess const& access = FieldAccessOf(effect->op());
444  if (access.base_is_tagged == kTaggedBase &&
445  access.offset == HeapObject::kMapOffset) {
446  if (IsSame(receiver, object)) {
447  Node* const value = GetValueInput(effect, 1);
448  HeapObjectMatcher m(value);
449  if (m.HasValue()) {
450  *maps_return = ZoneHandleSet<Map>(m.Ref(broker).AsMap().object());
451  return result;
452  }
453  }
454  // Without alias analysis we cannot tell whether this
455  // StoreField[map] affects {receiver} or not.
456  result = kUnreliableReceiverMaps;
457  }
458  break;
459  }
460  case IrOpcode::kJSStoreMessage:
461  case IrOpcode::kJSStoreModule:
462  case IrOpcode::kStoreElement:
463  case IrOpcode::kStoreTypedElement: {
464  // These never change the map of objects.
465  break;
466  }
467  case IrOpcode::kFinishRegion: {
468  // FinishRegion renames the output of allocations, so we need
469  // to update the {receiver} that we are looking for, if the
470  // {receiver} matches the current {effect}.
471  if (IsSame(receiver, effect)) receiver = GetValueInput(effect, 0);
472  break;
473  }
474  case IrOpcode::kEffectPhi: {
475  Node* control = GetControlInput(effect);
476  if (control->opcode() != IrOpcode::kLoop) {
477  DCHECK(control->opcode() == IrOpcode::kDead ||
478  control->opcode() == IrOpcode::kMerge);
479  return kNoReceiverMaps;
480  }
481 
482  // Continue search for receiver map outside the loop. Since operations
483  // inside the loop may change the map, the result is unreliable.
484  effect = GetEffectInput(effect, 0);
485  result = kUnreliableReceiverMaps;
486  continue;
487  }
488  default: {
489  DCHECK_EQ(1, effect->op()->EffectOutputCount());
490  if (effect->op()->EffectInputCount() != 1) {
491  // Didn't find any appropriate CheckMaps node.
492  return kNoReceiverMaps;
493  }
494  if (!effect->op()->HasProperty(Operator::kNoWrite)) {
495  // Without alias/escape analysis we cannot tell whether this
496  // {effect} affects {receiver} or not.
497  result = kUnreliableReceiverMaps;
498  }
499  break;
500  }
501  }
502 
503  // Stop walking the effect chain once we hit the definition of
504  // the {receiver} along the {effect}s.
505  if (IsSame(receiver, effect)) return kNoReceiverMaps;
506 
507  // Continue with the next {effect}.
508  DCHECK_EQ(1, effect->op()->EffectInputCount());
509  effect = NodeProperties::GetEffectInput(effect);
510  }
511 }
512 
513 // static
514 MaybeHandle<Map> NodeProperties::GetMapWitness(JSHeapBroker* broker,
515  Node* node) {
516  ZoneHandleSet<Map> maps;
517  Node* receiver = NodeProperties::GetValueInput(node, 1);
518  Node* effect = NodeProperties::GetEffectInput(node);
519  NodeProperties::InferReceiverMapsResult result =
520  NodeProperties::InferReceiverMaps(broker, receiver, effect, &maps);
521  if (result == NodeProperties::kReliableReceiverMaps && maps.size() == 1) {
522  return maps[0];
523  }
524  return MaybeHandle<Map>();
525 }
526 
527 // static
528 bool NodeProperties::HasInstanceTypeWitness(JSHeapBroker* broker,
529  Node* receiver, Node* effect,
530  InstanceType instance_type) {
531  ZoneHandleSet<Map> receiver_maps;
532  NodeProperties::InferReceiverMapsResult result =
533  NodeProperties::InferReceiverMaps(broker, receiver, effect,
534  &receiver_maps);
535  switch (result) {
536  case NodeProperties::kUnreliableReceiverMaps:
537  case NodeProperties::kReliableReceiverMaps:
538  DCHECK_NE(0, receiver_maps.size());
539  for (size_t i = 0; i < receiver_maps.size(); ++i) {
540  MapRef map(broker, receiver_maps[i]);
541  if (map.instance_type() != instance_type) return false;
542  }
543  return true;
544 
545  case NodeProperties::kNoReceiverMaps:
546  return false;
547  }
548  UNREACHABLE();
549 }
550 
551 // static
552 bool NodeProperties::NoObservableSideEffectBetween(Node* effect,
553  Node* dominator) {
554  while (effect != dominator) {
555  if (effect->op()->EffectInputCount() == 1 &&
556  effect->op()->properties() & Operator::kNoWrite) {
557  effect = NodeProperties::GetEffectInput(effect);
558  } else {
559  return false;
560  }
561  }
562  return true;
563 }
564 
565 // static
566 bool NodeProperties::CanBePrimitive(JSHeapBroker* broker, Node* receiver,
567  Node* effect) {
568  switch (receiver->opcode()) {
569 #define CASE(Opcode) case IrOpcode::k##Opcode:
570  JS_CONSTRUCT_OP_LIST(CASE)
571  JS_CREATE_OP_LIST(CASE)
572 #undef CASE
573  case IrOpcode::kCheckReceiver:
574  case IrOpcode::kConvertReceiver:
575  case IrOpcode::kJSGetSuperConstructor:
576  case IrOpcode::kJSToObject:
577  return false;
578  case IrOpcode::kHeapConstant: {
579  HeapObjectRef value =
580  HeapObjectMatcher(receiver).Ref(broker).AsHeapObject();
581  return value.map().IsPrimitiveMap();
582  }
583  default: {
584  // We don't really care about the exact maps here,
585  // just the instance types, which don't change
586  // across potential side-effecting operations.
587  ZoneHandleSet<Map> maps;
588  if (InferReceiverMaps(broker, receiver, effect, &maps) !=
589  kNoReceiverMaps) {
590  // Check if one of the {maps} is not a JSReceiver map.
591  for (size_t i = 0; i < maps.size(); ++i) {
592  MapRef map(broker, maps[i]);
593  if (!map.IsJSReceiverMap()) return true;
594  }
595  return false;
596  }
597  return true;
598  }
599  }
600 }
601 
602 // static
603 bool NodeProperties::CanBeNullOrUndefined(JSHeapBroker* broker, Node* receiver,
604  Node* effect) {
605  if (CanBePrimitive(broker, receiver, effect)) {
606  switch (receiver->opcode()) {
607  case IrOpcode::kCheckInternalizedString:
608  case IrOpcode::kCheckNumber:
609  case IrOpcode::kCheckSmi:
610  case IrOpcode::kCheckString:
611  case IrOpcode::kCheckSymbol:
612  case IrOpcode::kJSToLength:
613  case IrOpcode::kJSToName:
614  case IrOpcode::kJSToNumber:
615  case IrOpcode::kJSToNumberConvertBigInt:
616  case IrOpcode::kJSToNumeric:
617  case IrOpcode::kJSToString:
618  case IrOpcode::kToBoolean:
619  return false;
620  case IrOpcode::kHeapConstant: {
621  HeapObjectRef value =
622  HeapObjectMatcher(receiver).Ref(broker).AsHeapObject();
623  OddballType type = value.map().oddball_type();
624  return type == OddballType::kNull || type == OddballType::kUndefined;
625  }
626  default:
627  return true;
628  }
629  }
630  return false;
631 }
632 
633 // static
634 Node* NodeProperties::GetOuterContext(Node* node, size_t* depth) {
635  Node* context = NodeProperties::GetContextInput(node);
636  while (*depth > 0 &&
637  IrOpcode::IsContextChainExtendingOpcode(context->opcode())) {
638  context = NodeProperties::GetContextInput(context);
639  (*depth)--;
640  }
641  return context;
642 }
643 
644 // static
645 Type NodeProperties::GetTypeOrAny(Node* node) {
646  return IsTyped(node) ? node->type() : Type::Any();
647 }
648 
649 
650 // static
651 bool NodeProperties::AllValueInputsAreTyped(Node* node) {
652  int input_count = node->op()->ValueInputCount();
653  for (int index = 0; index < input_count; ++index) {
654  if (!IsTyped(GetValueInput(node, index))) return false;
655  }
656  return true;
657 }
658 
659 
660 // static
661 bool NodeProperties::IsInputRange(Edge edge, int first, int num) {
662  if (num == 0) return false;
663  int const index = edge.index();
664  return first <= index && index < first + num;
665 }
666 
667 // static
668 size_t NodeProperties::HashCode(Node* node) {
669  size_t h = base::hash_combine(node->op()->HashCode(), node->InputCount());
670  for (Node* input : node->inputs()) {
671  h = base::hash_combine(h, input->id());
672  }
673  return h;
674 }
675 
676 // static
677 bool NodeProperties::Equals(Node* a, Node* b) {
678  DCHECK_NOT_NULL(a);
679  DCHECK_NOT_NULL(b);
680  DCHECK_NOT_NULL(a->op());
681  DCHECK_NOT_NULL(b->op());
682  if (!a->op()->Equals(b->op())) return false;
683  if (a->InputCount() != b->InputCount()) return false;
684  Node::Inputs aInputs = a->inputs();
685  Node::Inputs bInputs = b->inputs();
686 
687  auto aIt = aInputs.begin();
688  auto bIt = bInputs.begin();
689  auto aEnd = aInputs.end();
690 
691  for (; aIt != aEnd; ++aIt, ++bIt) {
692  DCHECK_NOT_NULL(*aIt);
693  DCHECK_NOT_NULL(*bIt);
694  if ((*aIt)->id() != (*bIt)->id()) return false;
695  }
696  return true;
697 }
698 
699 } // namespace compiler
700 } // namespace internal
701 } // namespace v8
Definition: libplatform.h:13