1 /*
  2  * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.  Oracle designates this
  8  * particular file as subject to the "Classpath" exception as provided
  9  * by Oracle in the LICENSE file that accompanied this code.
 10  *
 11  * This code is distributed in the hope that it will be useful, but WITHOUT
 12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 14  * version 2 for more details (a copy is included in the LICENSE file that
 15  * accompanied this code).
 16  *
 17  * You should have received a copy of the GNU General Public License version
 18  * 2 along with this work; if not, write to the Free Software Foundation,
 19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 20  *
 21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 22  * or visit www.oracle.com if you need additional information or have any
 23  * questions.
 24  */
 25 
 26 package jdk.incubator.code;
 27 
 28 import jdk.incubator.code.type.FunctionType;
 29 import java.util.*;
 30 
 31 /**
 32  * A body containing a sequence of (basic) blocks.
 33  * <p>
 34  * The sequence of blocks form a graph. The last operation in a block, a terminating operation,
 35  * may refer to other blocks in the sequence as successors, thus forming the graph. Otherwise, the last
 36  * operation defines how the body passes control flow back to the parent operation, and in doing so may optionally
 37  * yield a value.
 38  * <p>
 39  * The first block in the sequence is the entry block, and no other blocks refer to it as a successor.
 40  * <p>
 41  * A body has a function type whose return type is the body's yield type and whose parameter types are the entry
 42  * block's parameters types, in order.
 43  * The function type describes the sequence of input parameters types for arguments that are passed to the
 44  * body when control flow is passed to it, and describes the return type of values that are returned when body passes
 45  * control back to its parent operation.
 46  */
 47 public final class Body implements CodeElement<Body, Block> {
 48     // Parent operation
 49     // Non-null when body is built, and therefore bound to operation
 50     Op parentOp;
 51 
 52     // The ancestor body, when null the body is isolated and cannot refer to values defined outside
 53     // When non-null and body is built, ancestorBody == parentOp.result.block.parentBody
 54     final Body ancestorBody;
 55 
 56     final TypeElement yieldType;
 57 
 58     // Sorted in reverse postorder
 59     final List<Block> blocks;
 60 
 61     // Map of a block to its immediate dominator
 62     // Computed lazily, null if not computed
 63     Map<Block, Block> idoms;
 64 
 65     /**
 66      * Constructs a body, whose ancestor is the given ancestor body.
 67      */
 68     Body(Body ancestorBody, TypeElement yieldType) {
 69         this.ancestorBody = ancestorBody;
 70         this.yieldType = yieldType;
 71         this.blocks = new ArrayList<>();
 72     }
 73 
 74     @Override
 75     public String toString() {
 76         return "body@" + Integer.toHexString(hashCode());
 77     }
 78 
 79     /**
 80      * Returns this body's parent operation.
 81      *
 82      * @return the body's parent operation.
 83      */
 84     @Override
 85     public Op parent() {
 86         return parentOp;
 87     }
 88 
 89     /**
 90      * Returns this body's parent operation.
 91      *
 92      * @return the body's parent operation.
 93      */
 94     public Op parentOp() {
 95         return parentOp;
 96     }
 97 
 98     @Override
 99     public List<Block> children() {
100         return blocks();
101     }
102 
103     /**
104      * Returns body's blocks in reverse-postorder as an unmodifiable list.
105      *
106      * @return the body's blocks in reverse-postorder.
107      */
108     public List<Block> blocks() {
109         return Collections.unmodifiableList(blocks);
110     }
111 
112     /**
113      * {@return the yield type of this body}
114      */
115     public TypeElement yieldType() {
116         return yieldType;
117     }
118 
119     /**
120      * Returns the body's function type.
121      * <p>The function type is composed of the body's entry block parameter types and
122      * the body's yield type.
123      *
124      * @return the body type.
125      */
126     public FunctionType bodyType() {
127         Block entryBlock = entryBlock();
128         return FunctionType.functionType(yieldType, entryBlock.parameterTypes());
129     }
130 
131     /**
132      * Finds the block in this body that is the ancestor of the given block.
133      *
134      * @param b the given block.
135      * @return the block in this body that is the ancestor of the given block,
136      * otherwise {@code null}
137      */
138     public Block findAncestorBlockInBody(Block b) {
139         Objects.requireNonNull(b);
140 
141         while (b != null && b.parentBody() != this) {
142             b = b.parentBody().parentOp().parentBlock();
143         }
144 
145         return b;
146     }
147 
148     /**
149      * Returns this body's entry block.
150      * <p>
151      * The entry block is the first block in the sequence. No other blocks refer to it as a successor.
152      *
153      * @return the body's entry block
154      */
155     public Block entryBlock() {
156         return blocks.getFirst();
157     }
158 
159     /**
160      * Returns a map of block to its immediate dominator.
161      *
162      * @return a map of block to its immediate dominator, as an unmodifiable map
163      */
164     public Map<Block, Block> immediateDominators() {
165         /*
166          * Compute dominators of blocks in a body.
167          * <p>
168          * https://www.cs.rice.edu/~keith/EMBED/dom.pdf
169          * A Simple, Fast Dominance Algorithm
170          * Keith D. Cooper, Timothy J. Harvey, and Ken Kennedy
171          */
172 
173         if (idoms != null) {
174             return idoms;
175         }
176 
177         // @@@ Compute the idoms as a block index mapping using int[]
178         // and wrap and a specific map implementation
179 
180         Map<Block, Block> doms = new HashMap<>();
181         doms.put(entryBlock(), entryBlock());
182 
183         // Blocks are sorted in reverse postorder
184         boolean changed;
185         do {
186             changed = false;
187             // Iterate through blocks in reverse postorder, except for entry block
188             for (int i = 1; i < blocks.size(); i++) {
189                 Block b = blocks.get(i);
190 
191                 // Find first processed predecessor of b
192                 Block newIdom = null;
193                 for (Block p : b.predecessors()) {
194                     if (doms.containsKey(p)) {
195                         newIdom = p;
196                         break;
197                     }
198                 }
199                 assert b.predecessors().isEmpty() || newIdom != null : b;
200 
201                 // For all other predecessors, p, of b
202                 for (Block p : b.predecessors()) {
203                     if (p == newIdom) {
204                         continue;
205                     }
206 
207                     if (doms.containsKey(p)) {
208                         // If already calculated
209                         newIdom = intersect(doms, p, newIdom);
210                     }
211                 }
212 
213                 if (doms.get(b) != newIdom) {
214                     doms.put(b, newIdom);
215                     changed = true;
216                 }
217             }
218         } while (changed);
219 
220         return idoms = Collections.unmodifiableMap(doms);
221     }
222 
223     static Block intersect(Map<Block, Block> doms, Block b1, Block b2) {
224         while (b1 != b2) {
225             while (b1.index > b2.index) {
226                 b1 = doms.get(b1);
227             }
228 
229             while (b2.index > b1.index) {
230                 b2 = doms.get(b2);
231             }
232         }
233 
234         return b1;
235     }
236 
237     /**
238      * Returns the dominance frontier of each block in the body.
239      * <p>
240      * The dominance frontier of block, {@code B} say, is the set of all blocks, {@code C} say,
241      * such that {@code B} dominates a predecessor of {@code C} but does not strictly dominate
242      * {@code C}.
243      *
244      * @return the dominance frontier of each block in the body, as a modifiable map
245      */
246     public Map<Block, Set<Block>> dominanceFrontier() {
247         // @@@ cache result?
248         Map<Block, Block> idoms = immediateDominators();
249         Map<Block, Set<Block>> df = new HashMap<>();
250 
251         for (Block b : blocks) {
252             Set<Block> preds = b.predecessors();
253 
254             if (preds.size() > 1) {
255                 for (Block p : preds) {
256                     Block runner = p;
257                     while (runner != idoms.get(b)) {
258                         df.computeIfAbsent(runner, _ -> new LinkedHashSet<>()).add(b);
259                         runner = idoms.get(runner);
260                     }
261                 }
262             }
263         }
264 
265         return df;
266     }
267 
268     /**
269      * A synthetic block representing the post dominator of all blocks
270      * when two or more blocks have no successors.
271      * <p>
272      * Computing the immediate post dominators requires a single exit point,
273      * one block that has no successors. When there are two or more blocks
274      * with no successors then this block represents the immediate post
275      * dominator of those blocks
276      */
277     public static final Block IPDOM_EXIT;
278     static {
279         IPDOM_EXIT = new Block(null);
280         IPDOM_EXIT.index = Integer.MAX_VALUE;
281     }
282 
283     /**
284      * Returns a map of block to its immediate post dominator.
285      * <p>
286      * If there are two or more blocks with no successors then
287      * a single exit point is synthesized using the {@link #IPDOM_EXIT}
288      * block, which represents the immediate post dominator of those blocks.
289      *
290      * @return a map of block to its immediate post dominator, as an unmodifiable map
291      */
292     public Map<Block, Block> immediatePostDominators() {
293         Map<Block, Block> pdoms = new HashMap<>();
294 
295         // If there are multiple exit blocks (those with zero successors)
296         // then use the block IPDOM_EXIT that is the synthetic successor of
297         // the exit blocks
298         boolean nSuccessors = blocks.stream().filter(b -> b.successors().isEmpty()).count() > 1;
299 
300         if (nSuccessors) {
301             pdoms.put(IPDOM_EXIT, IPDOM_EXIT);
302         } else {
303             Block exit = blocks.getLast();
304             assert blocks.stream().filter(b -> b.successors().isEmpty()).findFirst().orElseThrow() == exit;
305             pdoms.put(exit, exit);
306         }
307 
308         // Blocks are sorted in reverse postorder
309         boolean changed;
310         do {
311             changed = false;
312             // Iterate in reverse through blocks in reverse postorder, except for exit block
313             for (int i = blocks.size() - (nSuccessors ? 1 : 2); i >= 0; i--) {
314                 Block b = blocks.get(i);
315 
316                 // Find first processed successor of b
317                 Block newIpdom = null;
318                 Collection<Block> targets = b.successorTargets();
319                 for (Block s : nSuccessors && targets.isEmpty() ? List.of(IPDOM_EXIT) : targets) {
320                     if (pdoms.containsKey(s)) {
321                         newIpdom = s;
322                         break;
323                     }
324                 }
325 
326                 if (newIpdom == null) {
327                     // newIpdom can be null if all successors reference
328                     // prior blocks (back branch) yet to be encountered
329                     // in the dominator treee
330                     continue;
331                 }
332 
333                 // For all other successors, s, of b
334                 for (Block s : b.successorTargets()) {
335                     if (s == newIpdom) {
336                         continue;
337                     }
338 
339                     if (pdoms.containsKey(s)) {
340                         // If already calculated
341                         newIpdom = postIntersect(pdoms, s, newIpdom, blocks.size());
342                     }
343                 }
344 
345                 if (pdoms.get(b) != newIpdom) {
346                     pdoms.put(b, newIpdom);
347                     changed = true;
348                 }
349             }
350         } while (changed);
351 
352         return Collections.unmodifiableMap(pdoms);
353     }
354 
355     static Block postIntersect(Map<Block, Block> doms, Block b1, Block b2, int exitIndex) {
356         while (b1 != b2) {
357             while (b1.index() < b2.index()) {
358                 b1 = doms.get(b1);
359             }
360 
361             while (b2.index() < b1.index()) {
362                 b2 = doms.get(b2);
363             }
364         }
365 
366         return b1;
367     }
368 
369     /**
370      * Returns the post dominance frontier of each block in the body.
371      * <p>
372      * The post dominance frontier of block, {@code B} say, is the set of all blocks, {@code C} say,
373      * such that {@code B} post dominates a successor of {@code C} but does not strictly post dominate
374      * {@code C}.
375      *
376      * @return the post dominance frontier of each block in the body, as a modifiable map
377      */
378     public Map<Block, Set<Block>> postDominanceFrontier() {
379         // @@@ cache result?
380         Map<Block, Block> idoms = immediatePostDominators();
381         Map<Block, Set<Block>> df = new HashMap<>();
382 
383         for (Block b : blocks) {
384             Set<Block> succs = b.successorTargets();
385 
386             if (succs.size() > 1) {
387                 for (Block s : succs) {
388                     Block runner = s;
389                     while (runner != idoms.get(b)) {
390                         df.computeIfAbsent(runner, _ -> new LinkedHashSet<>()).add(b);
391                         runner = idoms.get(runner);
392                     }
393                 }
394             }
395         }
396 
397         return df;
398     }
399 
400     /**
401      * Returns {@code true} if this body is dominated by the given body {@code dom}.
402      * <p>
403      * A body, {@code b} say, is dominated by {@code dom} if {@code b} is the same as {@code dom} or a descendant of
404      * {@code dom}. Specifically, if {@code b} and {@code dom} are not equal then {@code b} becomes the nearest ancestor
405      * body, the result of {@code b.parentOp().parentBlock().parentBody()}, and so on until either:
406      * {@code b == dom}, therefore {@code b} is dominated by {@code dom} and this method returns {@code true};
407      * or {@code b.parentOp().parentBlock() == null}, therefore {@code b} is <b>not</b> dominated
408      * by {@code dom} and this method returns {@code false}.
409      *
410      * @param dom the dominating body
411      * @return {@code true} if this body is dominated by the given body {@code dom}.
412      */
413     public boolean isDominatedBy(Body dom) {
414         return isDominatedBy(this, dom);
415     }
416 
417     static boolean isDominatedBy(Body r, Body dom) {
418         while (r != dom) {
419             Block eb = r.parentOp().parentBlock();
420             if (eb == null) {
421                 return false;
422             }
423 
424             r = eb.parentBody();
425         }
426 
427         return true;
428     }
429 
430     /**
431      * Computes values captured by this body. A captured value is a value that dominates
432      * this body and is used by a descendant operation of this body.
433      * <p>
434      * The order of the captured values is first use encountered in depth
435      * first search of this body's descendant operations.
436      *
437      * @return the list of captured values, modifiable
438      */
439     public List<Value> capturedValues() {
440         Set<Value> cvs = new LinkedHashSet<>();
441 
442         capturedValues(cvs, new ArrayDeque<>(), this);
443         return new ArrayList<>(cvs);
444     }
445 
446     static void capturedValues(Set<Value> capturedValues, Deque<Body> bodyStack, Body body) {
447         bodyStack.push(body);
448 
449         for (Block b : body.blocks()) {
450             for (Op op : b.ops()) {
451                 for (Body childBody : op.bodies()) {
452                     capturedValues(capturedValues, bodyStack, childBody);
453                 }
454 
455                 for (Value a : op.operands()) {
456                     if (!bodyStack.contains(a.declaringBlock().parentBody())) {
457                         capturedValues.add(a);
458                     }
459                 }
460 
461                 for (Block.Reference s : op.successors()) {
462                     for (Value a : s.arguments()) {
463                         if (!bodyStack.contains(a.declaringBlock().parentBody())) {
464                             capturedValues.add(a);
465                         }
466                     }
467                 }
468             }
469         }
470 
471         bodyStack.pop();
472     }
473 
474     /**
475      * A builder of a body.
476      * <p>
477      * When the body builder is built any associated block builders are also considered built.
478      */
479     public final class Builder {
480         /**
481          * Creates a body build with a new context, and a copying transformer.
482          *
483          * @param ancestorBody the nearest ancestor body builder
484          * @param bodyType     the body's function type
485          * @return the body builder
486          * @throws IllegalStateException if the ancestor body builder is built
487          * @see #of(Builder, FunctionType, CopyContext, OpTransformer)
488          */
489         public static Builder of(Builder ancestorBody, FunctionType bodyType) {
490             // @@@ Creation of CopyContext
491             return of(ancestorBody, bodyType, CopyContext.create(), OpTransformer.COPYING_TRANSFORMER);
492         }
493 
494         /**
495          * Creates a body build with a copying transformer.
496          *
497          * @param ancestorBody the nearest ancestor body builder
498          * @param bodyType     the body's function type
499          * @param cc           the context
500          * @return the body builder
501          * @throws IllegalStateException if the ancestor body builder is built
502          * @see #of(Builder, FunctionType, CopyContext, OpTransformer)
503          */
504         public static Builder of(Builder ancestorBody, FunctionType bodyType, CopyContext cc) {
505             return of(ancestorBody, bodyType, cc, OpTransformer.COPYING_TRANSFORMER);
506         }
507 
508         /**
509          * Creates a body builder.
510          * <p>
511          * Structurally, the created body builder must be built before its ancestor body builder (if non-null) is built,
512          * otherwise an {@code IllegalStateException} will occur.
513          * <p>
514          * A function type, referred to as the body type, defines the body's yield type and the initial sequence of
515          * entry block parameters.
516          * The body's yield type is the function type's return type.
517          * An entry block builder is created with appended block parameters corresponding, in order, to
518          * the function type's parameter types.
519          * <p>
520          * If the ancestor body is null then the created body builder is isolated and descendant operations may only
521          * refer to values declared within the created body builder. Otherwise, operations
522          * may refer to values declared in the ancestor body builders (outside the created body builder).
523          *
524          * @param ancestorBody the nearest ancestor body builder, may be null if isolated
525          * @param bodyType     the body's function type
526          * @param cc           the context
527          * @param ot           the transformer
528          * @return the body builder
529          * @throws IllegalStateException if the ancestor body builder is built
530          * @see #of(Builder, FunctionType, CopyContext, OpTransformer)
531          */
532         public static Builder of(Builder ancestorBody, FunctionType bodyType,
533                                  CopyContext cc, OpTransformer ot) {
534             Body body = new Body(ancestorBody != null ? ancestorBody.target() : null, bodyType.returnType());
535             return body.new Builder(ancestorBody, bodyType, cc, ot);
536         }
537 
538         // The ancestor body, may be null
539         final Builder ancestorBody;
540 
541         // The entry block of this body, whose parameters are given by the body's function type
542         final Block.Builder entryBlock;
543 
544         // When non-null contains one or more great-grandchildren
545         List<Builder> greatgrandchildren;
546 
547         // True when built
548         boolean closed;
549 
550         Builder(Builder ancestorBody, FunctionType bodyType,
551                 CopyContext cc, OpTransformer ot) {
552             // Structural check
553             // The ancestor body should not be built before this body is created
554             if (ancestorBody != null) {
555                 ancestorBody.check();
556                 ancestorBody.addGreatgrandchild(this);
557             }
558 
559             this.ancestorBody = ancestorBody;
560             // Create entry block from the body's function type
561             Block eb = Body.this.createBlock(bodyType.parameterTypes());
562             this.entryBlock = eb.new Builder(this, cc, ot);
563         }
564 
565         void addGreatgrandchild(Builder greatgrandchild) {
566             var l = greatgrandchildren == null
567                     ? (greatgrandchildren = new ArrayList<>()) : greatgrandchildren;
568             l.add(greatgrandchild);
569         }
570 
571         /**
572          * Builds the body and its blocks, associating the body with a parent operation.
573          * <p>
574          * Structurally, any descendant body builders must be built before this body builder is built,
575          * otherwise an {@code IllegalStateException} will occur.
576          * <p>
577          * Blocks are sorted in reserve postorder.
578          * <p>
579          * Any unreferenced empty blocks are removed. An unreferenced block is a non-entry block with no predecessors.
580          *
581          * @param op the parent operation
582          * @return the build body
583          * @throws IllegalStateException if this body builder is built
584          * @throws IllegalStateException if any descendant body builders are not built
585          * @throws IllegalStateException if a block has no terminal operation, unless unreferenced and empty
586          */
587         // @@@ Validation
588         // e.g., every operand dominates the operation result (potentially expensive)
589         public Body build(Op op) {
590             // Structural check
591             // This body should not be closed
592             check();
593             closed = true;
594 
595             // Structural check
596             // All great-grandchildren bodies should be built
597             if (greatgrandchildren != null) {
598                 for (Builder greatgrandchild : greatgrandchildren) {
599                     if (!greatgrandchild.closed) {
600                         throw new IllegalStateException("Descendant body builder is not built");
601                     }
602                 }
603             }
604 
605             Iterator<Block> i = blocks.iterator();
606             while (i.hasNext()) {
607                 Block block = i.next();
608 
609                 // Structural check
610                 // All referenced blocks should have a terminating operation as the last operation
611                 if (block.ops.isEmpty()) {
612                     if (block.isEntryBlock() || !block.predecessors.isEmpty()) {
613                         throw noTerminatingOperation();
614                     }
615 
616                     // Remove unreferenced empty block
617                     assert !block.isEntryBlock() && block.predecessors.isEmpty();
618                     i.remove();
619                 } else if (!(block.ops.getLast() instanceof Op.Terminating)) {
620                     throw noTerminatingOperation();
621                 }
622             }
623 
624             sortReversePostorder();
625 
626             Body.this.parentOp = op;
627             return Body.this;
628         }
629 
630         static IllegalStateException noTerminatingOperation() {
631             return new IllegalStateException("Block has no terminating operation as the last operation");
632         }
633 
634         /**
635          * Returns the body builder's function type.
636          * <p>
637          * The function type is composed of the body builder's yield type, as the function type's return type, and the
638          * currently built entry block's parameter types, in order, as the function type's parameter types.
639          *
640          * @return the body builder's function type
641          */
642         public FunctionType bodyType() {
643             TypeElement returnType = Body.this.yieldType();
644             Block eb = Body.this.entryBlock();
645             return FunctionType.functionType(returnType, eb.parameterTypes());
646         }
647 
648         /**
649          * {@return the body builder's nearest ancestor body builder}
650          */
651         public Builder ancestorBody() {
652             return ancestorBody;
653         }
654 
655         /**
656          * {@return the body's entry block builder}
657          */
658         public Block.Builder entryBlock() {
659             return entryBlock;
660         }
661 
662         @Override
663         public boolean equals(Object o) {
664             if (this == o) return true;
665             return o instanceof Builder that && Body.this == that.target();
666         }
667 
668         @Override
669         public int hashCode() {
670             return Body.this.hashCode();
671         }
672 
673         void check() {
674             if (closed) {
675                 throw new IllegalStateException("Builder is closed");
676             }
677         }
678 
679         Body target() {
680             return Body.this;
681         }
682 
683         // Build new block in body
684         Block.Builder block(List<TypeElement> params, CopyContext cc, OpTransformer ot) {
685             check();
686             Block block = Body.this.createBlock(params);
687 
688             return block.new Builder(this, cc, ot);
689         }
690     }
691 
692     /**
693      * Copies the contents of this body.
694      *
695      * @param cc the copy context
696      * @return the builder of a body containing the copied body
697      * @see #transform(CopyContext, OpTransformer)
698      */
699     public Builder copy(CopyContext cc) {
700         return transform(cc, OpTransformer.COPYING_TRANSFORMER);
701     }
702 
703     /**
704      * Transforms this body.
705      * <p>
706      * A new body builder is created with the same function type as this body.
707      * Then, this body is {@link Block.Builder#transformBody(Body, java.util.List, CopyContext, OpTransformer) transformed}
708      * into the body builder's entry block builder with the given copy context, operation transformer, and values
709      * that are the entry block's parameters.
710      *
711      * @param cc the copy context
712      * @param ot the operation transformer
713      * @return a body builder containing the transformed body
714      */
715     public Builder transform(CopyContext cc, OpTransformer ot) {
716         Block.Builder ancestorBlockBuilder = ancestorBody != null
717                 ? cc.getBlock(ancestorBody.entryBlock()) : null;
718         Builder ancestorBodyBuilder = ancestorBlockBuilder != null
719                 ? ancestorBlockBuilder.parentBody() : null;
720         Builder body = Builder.of(ancestorBodyBuilder,
721                 // Create function type with just the return type and add parameters afterward
722                 FunctionType.functionType(yieldType),
723                 cc, ot);
724 
725         for (Block.Parameter p : entryBlock().parameters()) {
726             body.entryBlock.parameter(p.type());
727         }
728 
729         body.entryBlock.transformBody(this, body.entryBlock.parameters(), cc, ot);
730         return body;
731     }
732 
733     // Sort blocks in reverse post order
734     // After sorting the following holds for a block
735     //   block.parentBody().blocks().indexOf(block) == block.index()
736     private void sortReversePostorder() {
737         if (blocks.size() < 2) {
738             for (int i = 0; i < blocks.size(); i++) {
739                 blocks.get(i).index = i;
740             }
741             return;
742         }
743 
744         // Reset block indexes
745         // Also ensuring blocks with no predecessors occur last
746         for (Block b : blocks) {
747             b.index = Integer.MAX_VALUE;
748         }
749 
750         Deque<Block> stack = new ArrayDeque<>();
751         stack.push(blocks.get(0));
752 
753         // Postorder iteration
754         int index = blocks.size();
755         while (!stack.isEmpty()) {
756             Block n = stack.peek();
757             if (n.index == Integer.MIN_VALUE) {
758                 // If n's successor has been processed then add n
759                 stack.pop();
760                 n.index = --index;
761             } else if (n.index < Integer.MAX_VALUE) {
762                 // If n has already been processed then ignore
763                 stack.pop();
764             } else {
765                 // Mark before processing successors, a successor may refer back to n
766                 n.index = Integer.MIN_VALUE;
767                 for (Block.Reference s : n.successors()) {
768                     if (s.target.index < Integer.MAX_VALUE) {
769                         continue;
770                     }
771 
772                     stack.push(s.target);
773                 }
774             }
775         }
776 
777         blocks.sort(Comparator.comparingInt(b -> b.index));
778         if (blocks.get(0).index > 0) {
779             // There are blocks with no predecessors
780             // Reassign indexes to their natural indexes, sort order is preserved
781             for (int i = 0; i < blocks.size(); i++) {
782                 blocks.get(i).index = i;
783             }
784         }
785     }
786 
787     // Modifying methods
788 
789     // Create block
790     private Block createBlock(List<TypeElement> params) {
791         Block b = new Block(this, params);
792         blocks.add(b);
793         return b;
794     }
795 }