1 package org.apache.commons.javaflow.bytecode.transformation.bcel.analyser;
2
3 import org.apache.bcel.generic.Instruction;
4 import org.apache.bcel.generic.RET;
5 import org.apache.bcel.generic.JsrInstruction;
6
7 /**
8 * List of {@link InstructionContext} that represents a sequence of an execution.
9 *
10 * <p>
11 * This object is immutable.
12 * The sequence is represented in left-associative style; that is,
13 * a sequence of [a,b,c,d] is represented as prev=[a,b,c] and last=d.
14 *
15 * @author Kohsuke Kawaguchi
16 */
17 public final class ExecutionPath {
18 /**
19 * Singleton {@link ExecutionPath} that represents an empty sequence [].
20 */
21 public static final ExecutionPath EMPTY = new ExecutionPath(null,null);
22
23 private final ExecutionPath prev;
24 private final InstructionContext last;
25
26 private ExecutionPath(ExecutionPath prev, InstructionContext last) {
27 this.prev = prev;
28 this.last = last;
29 }
30
31 /**
32 * Creates a new {@link ExecutionPath} that has
33 * <tt>[... list in this ExecutionPath ..., ins]</tt>.
34 */
35 public ExecutionPath append(InstructionContext ins) {
36 return new ExecutionPath(this,ins);
37 }
38
39 /**
40 * Returns the InstructionContextImpl with an JSR/JSR_W
41 * that was last in the ExecutionChain, without
42 * a corresponding RET, i.e.
43 * we were called by this one.
44 * Returns null if we were called from the top level.
45 */
46 public InstructionContext lastExecutionJSR(){
47 int retcount = 0;
48
49 for( ExecutionPath ptr = this; ptr!=EMPTY; ptr=ptr.prev) {
50 Instruction i = ptr.last.getInstruction().getInstruction();
51 if (i instanceof RET) retcount++;
52 if (i instanceof JsrInstruction){
53 retcount--;
54 if (retcount == -1)
55 return ptr.last;
56 }
57 }
58
59 return null;
60 }
61
62 /**
63 * Returns a human readable representation.
64 */
65 public String toString() {
66 if(this==EMPTY)
67 return "";
68 else {
69 return prev.toString()+"\n"+last.toString();
70 }
71 }
72 }