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