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