30
30
#include " opto/opaquenode.hpp"
31
31
32
32
class IdealLoopTree ;
33
+ class InitializedAssertionPredicate ;
34
+ class ParsePredicate ;
35
+ class PredicateVisitor ;
36
+ class RuntimePredicate ;
37
+ class TemplateAssertionPredicate ;
33
38
34
39
/*
35
40
* There are different kinds of predicates throughout the code. We differentiate between the following predicates:
@@ -152,7 +157,8 @@ class IdealLoopTree;
152
157
* together.
153
158
* - Loop Limit Check Groups the Loop Limit Check Predicate (if created) and the Loop Limit
154
159
* Predicate Block: Check Parse Predicate (if not removed, yet) together.
155
- *
160
+ * - Regular Predicate Block: A block that only contains the Regular Predicates of a Predicate Block without the
161
+ * Parse Predicate.
156
162
*
157
163
* Initially, before applying any loop-splitting optimizations, we find the following structure after Loop Predication
158
164
* (predicates inside square brackets [] do not need to exist if there are no checks to hoist):
@@ -205,6 +211,41 @@ enum class AssertionPredicateType {
205
211
};
206
212
#endif // NOT PRODUCT
207
213
214
+ // Interface to represent a C2 predicate. A predicate is always represented by two CFG nodes:
215
+ // - An If node (head)
216
+ // - An IfProj node representing the success projection of the If node (tail).
217
+ class Predicate : public StackObj {
218
+ public:
219
+ // Return the unique entry CFG node into the predicate.
220
+ virtual Node* entry () const = 0;
221
+
222
+ // Return the head node of the predicate which is either:
223
+ // - A ParsePredicateNode if the predicate is a Parse Predicate
224
+ // - An IfNode or RangeCheckNode, otherwise.
225
+ virtual IfNode* head () const = 0;
226
+
227
+ // Return the tail node of the predicate. Runtime Predicates can either have a true of false projection as success
228
+ // projection while Parse Predicates and Assertion Predicates always have a true projection as success projection.
229
+ virtual IfProjNode* tail () const = 0;
230
+ };
231
+
232
+ // Generic predicate visitor that does nothing. Subclass this visitor to add customized actions for each predicate.
233
+ // The visit methods of this visitor are called from the predicate iterator classes which walk the predicate chain.
234
+ // Use the UnifiedPredicateVisitor if the type of the predicate does not matter.
235
+ class PredicateVisitor : StackObj {
236
+ public:
237
+ virtual void visit (const ParsePredicate& parse_predicate) {}
238
+ virtual void visit (const RuntimePredicate& runtime_predicate) {}
239
+ virtual void visit (const TemplateAssertionPredicate& template_assertion_predicate) {}
240
+ virtual void visit (const InitializedAssertionPredicate& initialized_assertion_predicate) {}
241
+
242
+ // This method can be overridden to stop the predicate iterators from visiting more predicates further up in the
243
+ // predicate chain.
244
+ virtual bool should_continue () const {
245
+ return true ;
246
+ }
247
+ };
248
+
208
249
// Class to represent Assertion Predicates with a HaltNode instead of an UCT (i.e. either an Initialized Assertion
209
250
// Predicate or a Template Assertion Predicate created after the initial one at Loop Predication).
210
251
class AssertionPredicatesWithHalt : public StackObj {
@@ -228,9 +269,15 @@ class AssertionPredicatesWithHalt : public StackObj {
228
269
// Note that all other Regular Predicates have an UCT node.
229
270
class AssertionPredicateWithHalt : public StackObj {
230
271
static bool has_assertion_predicate_opaque (const Node* predicate_proj);
231
- static bool has_halt (const Node* success_proj);
232
272
public:
233
273
static bool is_predicate (const Node* maybe_success_proj);
274
+ static bool has_halt (const Node* success_proj);
275
+ };
276
+
277
+ // Utility class representing a Regular Predicate which is either a Runtime Predicate or an Assertion Predicate.
278
+ class RegularPredicate : public StackObj {
279
+ public:
280
+ static bool may_be_predicate_if (const Node* node);
234
281
};
235
282
236
283
// Class to represent a single Regular Predicate with an UCT. This could either be:
@@ -239,15 +286,15 @@ class AssertionPredicateWithHalt : public StackObj {
239
286
// Note that all other Regular Predicates have a Halt node.
240
287
class RegularPredicateWithUCT : public StackObj {
241
288
static Deoptimization::DeoptReason uncommon_trap_reason (IfProjNode* if_proj);
242
- static bool may_be_predicate_if (Node* node);
243
289
244
290
public:
245
291
static bool is_predicate (Node* maybe_success_proj);
246
- static bool is_predicate (Node* node, Deoptimization::DeoptReason deopt_reason);
292
+ static bool is_predicate (const Node* node, Deoptimization::DeoptReason deopt_reason);
293
+ static bool has_valid_uncommon_trap (const Node* success_proj);
247
294
};
248
295
249
296
// Class to represent a Parse Predicate.
250
- class ParsePredicate : public StackObj {
297
+ class ParsePredicate : public Predicate {
251
298
ParsePredicateSuccessProj* _success_proj;
252
299
ParsePredicateNode* _parse_predicate_node;
253
300
Node* _entry;
@@ -267,7 +314,7 @@ class ParsePredicate : public StackObj {
267
314
268
315
// Returns the control input node into this Parse Predicate if it is valid. Otherwise, it returns the passed node
269
316
// into the constructor of this class.
270
- Node* entry () const {
317
+ Node* entry () const override {
271
318
return _entry;
272
319
}
273
320
@@ -277,23 +324,102 @@ class ParsePredicate : public StackObj {
277
324
return _parse_predicate_node != nullptr ;
278
325
}
279
326
280
- ParsePredicateNode* node () const {
327
+ ParsePredicateNode* head () const override {
281
328
assert (is_valid (), " must be valid" );
282
329
return _parse_predicate_node;
283
330
}
284
331
285
- ParsePredicateSuccessProj* success_proj () const {
332
+ ParsePredicateSuccessProj* tail () const override {
286
333
assert (is_valid (), " must be valid" );
287
334
return _success_proj;
288
335
}
336
+ };
337
+
338
+ // Class to represent a Runtime Predicate which always has an associated UCT on the failing path.
339
+ class RuntimePredicate : public Predicate {
340
+ IfProjNode* _success_proj;
341
+ IfNode* _if_node;
342
+
343
+ public:
344
+ explicit RuntimePredicate (IfProjNode* success_proj)
345
+ : _success_proj(success_proj),
346
+ _if_node(success_proj->in (0 )->as_If()) {
347
+ assert (is_predicate (success_proj), " must be valid" );
348
+ }
349
+ NONCOPYABLE (RuntimePredicate);
289
350
351
+ private:
290
352
static bool is_predicate (Node* maybe_success_proj);
353
+
354
+ public:
355
+ Node* entry () const override {
356
+ return _if_node->in (0 );
357
+ }
358
+
359
+ IfNode* head () const override {
360
+ return _if_node;
361
+ }
362
+
363
+ IfProjNode* tail () const override {
364
+ return _success_proj;
365
+ }
366
+
367
+ static bool is_predicate (Node* node, Deoptimization::DeoptReason deopt_reason);
291
368
};
292
369
293
- // Utility class for queries on Runtime Predicates.
294
- class RuntimePredicate : public StackObj {
370
+ // Class to represent a Template Assertion Predicate.
371
+ class TemplateAssertionPredicate : public Predicate {
372
+ IfTrueNode* _success_proj;
373
+ IfNode* _if_node;
374
+
295
375
public:
296
- static bool is_success_proj (Node* node, Deoptimization::DeoptReason deopt_reason);
376
+ explicit TemplateAssertionPredicate (IfTrueNode* success_proj)
377
+ : _success_proj(success_proj),
378
+ _if_node(success_proj->in (0 )->as_If()) {
379
+ assert (is_predicate (success_proj), " must be valid" );
380
+ }
381
+
382
+ Node* entry () const override {
383
+ return _if_node->in (0 );
384
+ }
385
+
386
+ IfNode* head () const override {
387
+ return _if_node;
388
+ }
389
+
390
+ IfTrueNode* tail () const override {
391
+ return _success_proj;
392
+ }
393
+
394
+ static bool is_predicate (Node* node);
395
+ };
396
+
397
+ // Class to represent an Initialized Assertion Predicate which always has a halt node on the failing path.
398
+ // This predicate should never fail at runtime by design.
399
+ class InitializedAssertionPredicate : public Predicate {
400
+ IfTrueNode* _success_proj;
401
+ IfNode* _if_node;
402
+
403
+ public:
404
+ explicit InitializedAssertionPredicate (IfTrueNode* success_proj)
405
+ : _success_proj(success_proj),
406
+ _if_node(success_proj->in (0 )->as_If()) {
407
+ assert (is_predicate (success_proj), " must be valid" );
408
+ }
409
+
410
+ Node* entry () const override {
411
+ return _if_node->in (0 );
412
+ }
413
+
414
+ IfNode* head () const override {
415
+ return _if_node;
416
+ }
417
+
418
+ IfTrueNode* tail () const override {
419
+ return _success_proj;
420
+ }
421
+
422
+ static bool is_predicate (Node* node);
297
423
};
298
424
299
425
// Interface to transform OpaqueLoopInit and OpaqueLoopStride nodes of a Template Assertion Expression.
@@ -395,16 +521,16 @@ class TemplateAssertionExpressionNode : public StackObj {
395
521
};
396
522
397
523
// This class creates a new Initialized Assertion Predicate.
398
- class InitializedAssertionPredicate : public StackObj {
524
+ class InitializedAssertionPredicateCreator : public StackObj {
399
525
IfNode* const _template_assertion_predicate;
400
526
Node* const _new_init;
401
527
Node* const _new_stride;
402
528
PhaseIdealLoop* const _phase;
403
529
404
530
public:
405
- InitializedAssertionPredicate (IfNode* template_assertion_predicate, Node* new_init, Node* new_stride,
406
- PhaseIdealLoop* phase);
407
- NONCOPYABLE (InitializedAssertionPredicate );
531
+ InitializedAssertionPredicateCreator (IfNode* template_assertion_predicate, Node* new_init, Node* new_stride,
532
+ PhaseIdealLoop* phase);
533
+ NONCOPYABLE (InitializedAssertionPredicateCreator );
408
534
409
535
IfTrueNode* create (Node* control);
410
536
@@ -416,23 +542,208 @@ class InitializedAssertionPredicate : public StackObj {
416
542
IfTrueNode* create_success_path (IfNode* if_node, IdealLoopTree* loop);
417
543
};
418
544
545
+ // This class iterates through all predicates of a Regular Predicate Block and applies the given visitor to each.
546
+ class RegularPredicateBlockIterator : public StackObj {
547
+ Node* const _start_node;
548
+ const Deoptimization::DeoptReason _deopt_reason;
549
+
550
+ public:
551
+ RegularPredicateBlockIterator (Node* start_node, Deoptimization::DeoptReason deopt_reason)
552
+ : _start_node(start_node),
553
+ _deopt_reason (deopt_reason) {}
554
+ NONCOPYABLE (RegularPredicateBlockIterator);
555
+
556
+ // Skip all predicates by just following the inputs. We do not call any user provided visitor.
557
+ Node* skip_all () const {
558
+ PredicateVisitor do_nothing; // No real visits, just do nothing.
559
+ return for_each (do_nothing);
560
+ }
561
+
562
+ // Walk over all predicates of this block (if any) and apply the given 'predicate_visitor' to each predicate.
563
+ // Returns the entry to the earliest predicate.
564
+ Node* for_each (PredicateVisitor& predicate_visitor) const {
565
+ Node* current = _start_node;
566
+ while (predicate_visitor.should_continue ()) {
567
+ if (TemplateAssertionPredicate::is_predicate (current)) {
568
+ TemplateAssertionPredicate template_assertion_predicate (current->as_IfTrue ());
569
+ predicate_visitor.visit (template_assertion_predicate);
570
+ current = template_assertion_predicate.entry ();
571
+ } else if (RuntimePredicate::is_predicate (current, _deopt_reason)) {
572
+ RuntimePredicate runtime_predicate (current->as_IfProj ());
573
+ predicate_visitor.visit (runtime_predicate);
574
+ current = runtime_predicate.entry ();
575
+ } else if (InitializedAssertionPredicate::is_predicate (current)) {
576
+ InitializedAssertionPredicate initialized_assertion_predicate (current->as_IfTrue ());
577
+ predicate_visitor.visit (initialized_assertion_predicate);
578
+ current = initialized_assertion_predicate.entry ();
579
+ } else {
580
+ // Either a Parse Predicate or not a Regular Predicate. In both cases, the node does not belong to this block.
581
+ break ;
582
+ }
583
+ }
584
+ return current;
585
+ }
586
+ };
587
+
588
+ // This class iterates through all predicates of a Predicate Block and applies the given visitor to each.
589
+ class PredicateBlockIterator : public StackObj {
590
+ Node* const _start_node;
591
+ const ParsePredicate _parse_predicate; // Could be missing.
592
+ const RegularPredicateBlockIterator _regular_predicate_block_iterator;
593
+
594
+ public:
595
+ PredicateBlockIterator (Node* start_node, Deoptimization::DeoptReason deopt_reason)
596
+ : _start_node(start_node),
597
+ _parse_predicate (start_node, deopt_reason),
598
+ _regular_predicate_block_iterator(_parse_predicate.entry(), deopt_reason) {}
599
+
600
+ // Walk over all predicates of this block (if any) and apply the given 'predicate_visitor' to each predicate.
601
+ // Returns the entry to the earliest predicate.
602
+ Node* for_each (PredicateVisitor& predicate_visitor) const {
603
+ if (!predicate_visitor.should_continue ()) {
604
+ return _start_node;
605
+ }
606
+ if (_parse_predicate.is_valid ()) {
607
+ predicate_visitor.visit (_parse_predicate);
608
+ }
609
+ return _regular_predicate_block_iterator.for_each (predicate_visitor);
610
+ }
611
+ };
612
+
613
+ // Class to walk over all predicates starting at a node, which usually is the loop entry node, and following the inputs.
614
+ // At each predicate, a PredicateVisitor is applied which the user can implement freely.
615
+ class PredicateIterator : public StackObj {
616
+ Node* _start_node;
617
+
618
+ public:
619
+ explicit PredicateIterator (Node* start_node)
620
+ : _start_node(start_node) {}
621
+ NONCOPYABLE (PredicateIterator);
622
+
623
+ // Apply the 'predicate_visitor' for each predicate found in the predicate chain started at the provided node.
624
+ // Returns the entry to the earliest predicate.
625
+ Node* for_each (PredicateVisitor& predicate_visitor) const {
626
+ Node* current = _start_node;
627
+ PredicateBlockIterator loop_limit_check_predicate_iterator (current, Deoptimization::Reason_loop_limit_check);
628
+ current = loop_limit_check_predicate_iterator.for_each (predicate_visitor);
629
+ PredicateBlockIterator profiled_loop_predicate_iterator (current, Deoptimization::Reason_profile_predicate);
630
+ current = profiled_loop_predicate_iterator.for_each (predicate_visitor);
631
+ PredicateBlockIterator loop_predicate_iterator (current, Deoptimization::Reason_predicate);
632
+ return loop_predicate_iterator.for_each (predicate_visitor);
633
+ }
634
+ };
635
+
636
+ // Unified PredicateVisitor which only provides a single visit method for a generic Predicate. This visitor can be used
637
+ // when it does not matter what kind of predicate is visited. Note that we override all normal visit methods from
638
+ // PredicateVisitor by calling the unified method. These visit methods are marked final such that they cannot be
639
+ // overridden by implementors of this class.
640
+ class UnifiedPredicateVisitor : public PredicateVisitor {
641
+ public:
642
+ virtual void visit (const TemplateAssertionPredicate& template_assertion_predicate) override final {
643
+ visit_predicate (template_assertion_predicate);
644
+ }
645
+
646
+ virtual void visit (const ParsePredicate& parse_predicate) override final {
647
+ visit_predicate (parse_predicate);
648
+ }
649
+
650
+ virtual void visit (const RuntimePredicate& runtime_predicate) override final {
651
+ visit_predicate (runtime_predicate);
652
+ }
653
+
654
+ virtual void visit (const InitializedAssertionPredicate& initialized_assertion_predicate) override final {
655
+ visit_predicate (initialized_assertion_predicate);
656
+ }
657
+
658
+ virtual void visit_predicate (const Predicate& predicate) = 0;
659
+ };
660
+
661
+ // A block of Regular Predicates inside a Predicate Block without its Parse Predicate.
662
+ class RegularPredicateBlock : public StackObj {
663
+ const Deoptimization::DeoptReason _deopt_reason;
664
+ Node* const _entry;
665
+
666
+ public:
667
+ RegularPredicateBlock (Node* tail, Deoptimization::DeoptReason deopt_reason)
668
+ : _deopt_reason(deopt_reason),
669
+ _entry (skip_all(tail)) {
670
+ DEBUG_ONLY (verify_block (tail);)
671
+ }
672
+ NONCOPYABLE (RegularPredicateBlock);
673
+
674
+ private:
675
+ // Walk over all Regular Predicates of this block (if any) and return the first node not belonging to the block
676
+ // anymore (i.e. entry to the first Regular Predicate in this block if any or `tail` otherwise).
677
+ Node* skip_all (Node* tail) const {
678
+ RegularPredicateBlockIterator iterator (tail, _deopt_reason);
679
+ return iterator.skip_all ();
680
+ }
681
+
682
+ DEBUG_ONLY (void verify_block (Node* tail);)
683
+
684
+ public:
685
+ Node* entry() const {
686
+ return _entry;
687
+ }
688
+ };
689
+
690
+ #ifndef PRODUCT
691
+ // Visitor class to print all the visited predicates. Used by the Predicates class which does the printing starting
692
+ // at the loop node and then following the inputs to the earliest predicate.
693
+ class PredicatePrinter : public PredicateVisitor {
694
+ const char * _prefix; // Prefix added to each dumped string.
695
+
696
+ public:
697
+ explicit PredicatePrinter (const char * prefix) : _prefix(prefix) {}
698
+ NONCOPYABLE (PredicatePrinter);
699
+
700
+ void visit (const ParsePredicate& parse_predicate) override {
701
+ print_predicate_node (" Parse Predicate" , parse_predicate);
702
+ }
703
+
704
+ void visit (const RuntimePredicate& runtime_predicate) override {
705
+ print_predicate_node (" Runtime Predicate" , runtime_predicate);
706
+ }
707
+
708
+ void visit (const TemplateAssertionPredicate& template_assertion_predicate) override {
709
+ print_predicate_node (" Template Assertion Predicate" , template_assertion_predicate);
710
+ }
711
+
712
+ void visit (const InitializedAssertionPredicate& initialized_assertion_predicate) override {
713
+ print_predicate_node (" Initialized Assertion Predicate" , initialized_assertion_predicate);
714
+ }
715
+
716
+ private:
717
+ void print_predicate_node (const char * predicate_name, const Predicate& predicate) const {
718
+ tty->print_cr (" %s- %s: %d %s" , _prefix, predicate_name, predicate.head ()->_idx , predicate.head ()->Name ());
719
+ }
720
+ };
721
+ #endif // NOT PRODUCT
419
722
420
723
// This class represents a Predicate Block (i.e. either a Loop Predicate Block, a Profiled Loop Predicate Block,
421
724
// or a Loop Limit Check Predicate Block). It contains zero or more Regular Predicates followed by a Parse Predicate
422
725
// which, however, does not need to exist (we could already have decided to remove Parse Predicates for this loop).
423
726
class PredicateBlock : public StackObj {
424
- ParsePredicate _parse_predicate; // Could be missing.
425
- Node* _entry;
426
-
427
- static Node* skip_regular_predicates (Node* regular_predicate_proj, Deoptimization::DeoptReason deopt_reason);
428
- DEBUG_ONLY (void verify_block ();)
727
+ const ParsePredicate _parse_predicate; // Could be missing.
728
+ const RegularPredicateBlock _regular_predicate_block;
729
+ Node* const _entry;
730
+ #ifndef PRODUCT
731
+ // Used for dumping.
732
+ Node* const _tail;
733
+ const Deoptimization::DeoptReason _deopt_reason;
734
+ #endif // NOT PRODUCT
429
735
430
736
public:
431
- PredicateBlock (Node* predicate_proj, Deoptimization::DeoptReason deopt_reason)
432
- : _parse_predicate(predicate_proj, deopt_reason),
433
- _entry (skip_regular_predicates(_parse_predicate.entry(), deopt_reason)) {
434
- DEBUG_ONLY (verify_block ();)
435
- }
737
+ PredicateBlock (Node* tail, Deoptimization::DeoptReason deopt_reason)
738
+ : _parse_predicate(tail, deopt_reason),
739
+ _regular_predicate_block (_parse_predicate.entry(), deopt_reason),
740
+ _entry(_regular_predicate_block.entry())
741
+ #ifndef PRODUCT
742
+ , _tail(tail)
743
+ , _deopt_reason(deopt_reason)
744
+ #endif // NOT PRODUCT
745
+ {}
746
+ NONCOPYABLE (PredicateBlock);
436
747
437
748
// Returns the control input node into this Regular Predicate block. This is either:
438
749
// - The control input to the first If node in the block representing a Runtime Predicate if there is at least one
@@ -453,11 +764,11 @@ class PredicateBlock : public StackObj {
453
764
}
454
765
455
766
ParsePredicateNode* parse_predicate () const {
456
- return _parse_predicate.node ();
767
+ return _parse_predicate.head ();
457
768
}
458
769
459
770
ParsePredicateSuccessProj* parse_predicate_success_proj () const {
460
- return _parse_predicate.success_proj ();
771
+ return _parse_predicate.tail ();
461
772
}
462
773
463
774
bool has_runtime_predicates () const {
@@ -471,25 +782,31 @@ class PredicateBlock : public StackObj {
471
782
Node* skip_parse_predicate () const {
472
783
return _parse_predicate.entry ();
473
784
}
785
+
786
+ #ifndef PRODUCT
787
+ void dump () const ;
788
+ void dump (const char * prefix) const ;
789
+ #endif // NOT PRODUCT
474
790
};
475
791
476
792
// This class takes a loop entry node and finds all the available predicates for the loop.
477
793
class Predicates : public StackObj {
478
- Node* _loop_entry ;
479
- PredicateBlock _loop_limit_check_predicate_block;
480
- PredicateBlock _profiled_loop_predicate_block;
481
- PredicateBlock _loop_predicate_block;
482
- Node* _entry;
794
+ Node* const _tail ;
795
+ const PredicateBlock _loop_limit_check_predicate_block;
796
+ const PredicateBlock _profiled_loop_predicate_block;
797
+ const PredicateBlock _loop_predicate_block;
798
+ Node* const _entry;
483
799
484
800
public:
485
- Predicates (Node* loop_entry)
486
- : _loop_entry (loop_entry),
801
+ explicit Predicates (Node* loop_entry)
802
+ : _tail (loop_entry),
487
803
_loop_limit_check_predicate_block(loop_entry, Deoptimization::Reason_loop_limit_check),
488
804
_profiled_loop_predicate_block(_loop_limit_check_predicate_block.entry(),
489
805
Deoptimization::Reason_profile_predicate),
490
806
_loop_predicate_block(_profiled_loop_predicate_block.entry(),
491
807
Deoptimization::Reason_predicate),
492
808
_entry(_loop_predicate_block.entry()) {}
809
+ NONCOPYABLE (Predicates);
493
810
494
811
// Returns the control input the first predicate if there are any predicates. If there are no predicates, the same
495
812
// node initially passed to the constructor is returned.
@@ -510,35 +827,17 @@ class Predicates : public StackObj {
510
827
}
511
828
512
829
bool has_any () const {
513
- return _entry != _loop_entry ;
830
+ return _entry != _tail ;
514
831
}
515
- };
516
-
517
- // This class iterates over the Parse Predicates of a loop.
518
- class ParsePredicateIterator : public StackObj {
519
- GrowableArray<ParsePredicateNode*> _parse_predicates;
520
- int _current_index;
521
-
522
- public:
523
- ParsePredicateIterator (const Predicates& predicates);
524
832
525
- bool has_next () const {
526
- return _current_index < _parse_predicates.length ();
527
- }
528
-
529
- ParsePredicateNode* next ();
833
+ #ifndef PRODUCT
834
+ /*
835
+ * Debug printing functions.
836
+ */
837
+ void dump () const ;
838
+ static void dump_at (Node* node);
839
+ static void dump_for_loop (LoopNode* loop_node);
840
+ #endif // NOT PRODUCT
530
841
};
531
842
532
- // Special predicate iterator that can be used to walk through predicate entries, regardless of whether the predicate
533
- // belongs to the same loop or not (i.e. leftovers from already folded nodes). The iterator returns the next entry
534
- // to a predicate.
535
- class PredicateEntryIterator : public StackObj {
536
- Node* _current;
537
-
538
- public:
539
- explicit PredicateEntryIterator (Node* start) : _current(start) {};
540
-
541
- bool has_next () const ;
542
- Node* next_entry ();
543
- };
544
843
#endif // SHARE_OPTO_PREDICATES_HPP
0 commit comments