001 /* 002 * The JastAdd Extensible Java Compiler (http://jastadd.org) is covered 003 * by the modified BSD License. You should have received a copy of the 004 * modified BSD license with this compiler. 005 * 006 * Copyright (c) 2005-2008, Torbjorn Ekman 007 * All rights reserved. 008 */ 009 010 import java.util.HashSet; 011 012 aspect BranchTarget { 013 014 // public interface 015 016 // find the target statement for break and continue 017 // this can be a try statement with a finally block that can not complete normally 018 syn lazy Stmt BreakStmt.targetStmt(); 019 syn lazy Stmt ContinueStmt.targetStmt(); 020 021 // an ordered list of TryStmts with finally blocks that are reached until the final target of this statement is reached 022 syn lazy ArrayList BreakStmt.finallyList(); 023 syn lazy ArrayList ContinueStmt.finallyList(); 024 syn lazy ArrayList ReturnStmt.finallyList(); 025 026 027 // --------------------------------------------------------------------------- 028 029 // propagate branch statements to the statements that are their respective 030 // targets taking finally blocks that can not complete normally into account 031 interface BranchPropagation { 032 syn lazy Collection targetContinues(); 033 syn lazy Collection targetBreaks(); 034 syn lazy Collection targetBranches(); 035 syn lazy Collection escapedBranches(); 036 syn lazy Collection branches(); 037 //public void collectBranches(Collection c); 038 039 syn lazy boolean targetOf(ContinueStmt stmt); 040 syn lazy boolean targetOf(BreakStmt stmt); 041 } 042 BranchTargetStmt implements BranchPropagation; 043 044 public void ASTNode.collectBranches(Collection c) { 045 for(int i = 0; i < getNumChild(); i++) 046 getChild(i).collectBranches(c); 047 } 048 public void ContinueStmt.collectBranches(Collection c) { 049 c.add(this); 050 } 051 public void BreakStmt.collectBranches(Collection c) { 052 c.add(this); 053 } 054 public void ReturnStmt.collectBranches(Collection c) { 055 c.add(this); 056 } 057 public void BranchPropagation.collectBranches(Collection c) { 058 c.addAll(escapedBranches()); 059 } 060 public void TryStmt.collectBranches(Collection c) { 061 c.addAll(escapedBranches()); 062 } 063 064 syn boolean ContinueStmt.hasLabel() = !getLabel().equals(""); 065 syn boolean BreakStmt.hasLabel() = !getLabel().equals(""); 066 067 eq LabeledStmt.targetOf(ContinueStmt stmt) = 068 stmt.hasLabel() && stmt.getLabel().equals(getLabel()); 069 eq WhileStmt.targetOf(ContinueStmt stmt) = !stmt.hasLabel(); 070 eq DoStmt.targetOf(ContinueStmt stmt) = !stmt.hasLabel(); 071 eq ForStmt.targetOf(ContinueStmt stmt) = !stmt.hasLabel(); 072 eq SwitchStmt.targetOf(ContinueStmt stmt) = false; 073 074 eq LabeledStmt.targetOf(BreakStmt stmt) = 075 stmt.hasLabel() && stmt.getLabel().equals(getLabel()); 076 eq SwitchStmt.targetOf(BreakStmt stmt) = !stmt.hasLabel(); 077 eq WhileStmt.targetOf(BreakStmt stmt) = !stmt.hasLabel(); 078 eq DoStmt.targetOf(BreakStmt stmt) = !stmt.hasLabel(); 079 eq ForStmt.targetOf(BreakStmt stmt) = !stmt.hasLabel(); 080 081 // the branches for which this node is the target 082 eq BranchPropagation.targetBranches() { 083 HashSet set = new HashSet(); 084 for(Iterator iter = branches().iterator(); iter.hasNext(); ) { 085 Object o = iter.next(); 086 if(o instanceof ContinueStmt && targetOf((ContinueStmt)o)) 087 set.add(o); 088 if(o instanceof BreakStmt && targetOf((BreakStmt)o)) 089 set.add(o); 090 } 091 return set; 092 } 093 // the branches that escape this node 094 eq BranchPropagation.escapedBranches() { 095 HashSet set = new HashSet(); 096 for(Iterator iter = branches().iterator(); iter.hasNext(); ) { 097 Object o = iter.next(); 098 if(o instanceof ContinueStmt && !targetOf((ContinueStmt)o)) 099 set.add(o); 100 if(o instanceof BreakStmt && !targetOf((BreakStmt)o)) 101 set.add(o); 102 if(o instanceof ReturnStmt) 103 set.add(o); 104 } 105 return set; 106 } 107 // all branches that reach this node 108 eq BranchPropagation.branches() { 109 HashSet set = new HashSet(); 110 super.collectBranches(set); 111 return set; 112 } 113 114 // all branches that reach this node 115 syn lazy Collection TryStmt.branches() { 116 HashSet set = new HashSet(); 117 getBlock().collectBranches(set); 118 for(int i = 0; i < getNumCatchClause(); i++) 119 getCatchClause(i).collectBranches(set); 120 return set; 121 } 122 123 syn lazy Collection TryStmt.branchesFromFinally() { 124 HashSet set = new HashSet(); 125 if(hasFinally()) 126 getFinally().collectBranches(set); 127 return set; 128 } 129 130 // all branches the this node is target for 131 syn lazy Collection TryStmt.targetBranches() { 132 HashSet set = new HashSet(); 133 if(hasFinally() && !getFinally().canCompleteNormally()) 134 set.addAll(branches()); 135 return set; 136 } 137 138 // all branches that escapes 139 syn lazy Collection TryStmt.escapedBranches() { 140 HashSet set = new HashSet(); 141 if(hasFinally()) 142 set.addAll(branchesFromFinally()); 143 if(!hasFinally() || getFinally().canCompleteNormally()) 144 set.addAll(branches()); 145 return set; 146 } 147 // find the target statement for break and continue 148 eq BreakStmt.targetStmt() = branchTarget(this); 149 eq ContinueStmt.targetStmt() = branchTarget(this); 150 public Stmt ASTNode.branchTarget(Stmt branchStmt) { 151 if(getParent() != null) 152 return getParent().branchTarget(branchStmt); 153 else 154 return null; 155 } 156 public Stmt BranchPropagation.branchTarget(Stmt branchStmt) { 157 if(targetBranches().contains(branchStmt)) 158 return this; 159 return super.branchTarget(branchStmt); 160 } 161 public Stmt TryStmt.branchTarget(Stmt branchStmt) { 162 if(targetBranches().contains(branchStmt)) 163 return this; 164 return super.branchTarget(branchStmt); 165 } 166 167 // lookup visible label 168 inh lazy LabeledStmt BreakStmt.lookupLabel(String name); 169 inh lazy LabeledStmt ContinueStmt.lookupLabel(String name); 170 inh lazy LabeledStmt LabeledStmt.lookupLabel(String name); 171 eq LabeledStmt.getStmt().lookupLabel(String name) = name.equals(getLabel()) ? this : lookupLabel(name); 172 eq Program.getChild().lookupLabel(String name) = null; 173 174 // compute the list of finally blocks that are reached on the way to the target 175 eq BreakStmt.finallyList() { 176 ArrayList list = new ArrayList(); 177 collectFinally(this, list); 178 return list; 179 } 180 eq ContinueStmt.finallyList() { 181 ArrayList list = new ArrayList(); 182 collectFinally(this, list); 183 return list; 184 } 185 eq ReturnStmt.finallyList() { 186 ArrayList list = new ArrayList(); 187 collectFinally(this, list); 188 return list; 189 } 190 public void ASTNode.collectFinally(Stmt branchStmt, ArrayList list) { 191 if(getParent() != null) 192 getParent().collectFinally(branchStmt, list); 193 } 194 public void BranchPropagation.collectFinally(Stmt branchStmt, ArrayList list) { 195 if(targetBranches().contains(branchStmt)) 196 return; 197 super.collectFinally(branchStmt, list); 198 } 199 public void TryStmt.collectFinally(Stmt branchStmt, ArrayList list) { 200 if(hasFinally() && !branchesFromFinally().contains(branchStmt)) 201 list.add(this); 202 if(targetBranches().contains(branchStmt)) 203 return; 204 super.collectFinally(branchStmt, list); 205 } 206 public void SynchronizedStmt.collectFinally(Stmt branchStmt, ArrayList list) { 207 list.add(this); 208 super.collectFinally(branchStmt, list); 209 } 210 public void BodyDecl.collectFinally(Stmt branchStmt, ArrayList list) { 211 // terminate search if body declaration is reached 212 } 213 214 // find the continue statements that have this node as actual target 215 eq BranchPropagation.targetContinues() { 216 HashSet set = new HashSet(); 217 for(Iterator iter = targetBranches().iterator(); iter.hasNext(); ) { 218 Object o = iter.next(); 219 if(o instanceof ContinueStmt) 220 set.add(o); 221 } 222 if(getParent() instanceof LabeledStmt) { 223 for(Iterator iter = ((LabeledStmt)getParent()).targetBranches().iterator(); iter.hasNext(); ) { 224 Object o = iter.next(); 225 if(o instanceof ContinueStmt) 226 set.add(o); 227 } 228 } 229 return set; 230 } 231 // find the break statements that have this node as their actual target 232 eq BranchPropagation.targetBreaks() { 233 HashSet set = new HashSet(); 234 for(Iterator iter = targetBranches().iterator(); iter.hasNext(); ) { 235 Object o = iter.next(); 236 if(o instanceof BreakStmt) 237 set.add(o); 238 } 239 return set; 240 } 241 242 } 243