1 30 package com.tc.asm.tree.analysis; 31 32 import java.util.ArrayList ; 33 import java.util.List ; 34 35 import com.tc.asm.Opcodes; 36 import com.tc.asm.Label; 37 import com.tc.asm.Type; 38 import com.tc.asm.tree.AbstractInsnNode; 39 import com.tc.asm.tree.IincInsnNode; 40 import com.tc.asm.tree.JumpInsnNode; 41 import com.tc.asm.tree.LabelNode; 42 import com.tc.asm.tree.LookupSwitchInsnNode; 43 import com.tc.asm.tree.MethodNode; 44 import com.tc.asm.tree.TableSwitchInsnNode; 45 import com.tc.asm.tree.TryCatchBlockNode; 46 import com.tc.asm.tree.VarInsnNode; 47 48 53 public class Analyzer implements Opcodes { 54 55 private Interpreter interpreter; 56 57 private int n; 58 59 private IntMap indexes; 60 61 private List [] handlers; 62 63 private Frame[] frames; 64 65 private Subroutine[] subroutines; 66 67 private boolean[] queued; 68 69 private int[] queue; 70 71 private int top; 72 73 private boolean jsr; 74 75 81 public Analyzer(final Interpreter interpreter) { 82 this.interpreter = interpreter; 83 } 84 85 97 public Frame[] analyze(final String owner, final MethodNode m) 98 throws AnalyzerException 99 { 100 n = m.instructions.size(); 101 indexes = new IntMap(2 * n); 102 handlers = new List [n]; 103 frames = new Frame[n]; 104 subroutines = new Subroutine[n]; 105 queued = new boolean[n]; 106 queue = new int[n]; 107 top = 0; 108 109 for (int i = 0; i < n; ++i) { 111 Object insn = m.instructions.get(i); 112 if (insn instanceof LabelNode) { 113 insn = ((LabelNode) insn).label; 114 } 115 indexes.put(insn, i); 116 } 117 118 for (int i = 0; i < m.tryCatchBlocks.size(); ++i) { 120 TryCatchBlockNode tcb = (TryCatchBlockNode) m.tryCatchBlocks.get(i); 121 int begin = indexes.get(tcb.start); 122 int end = indexes.get(tcb.end); 123 for (int j = begin; j < end; ++j) { 124 List insnHandlers = handlers[j]; 125 if (insnHandlers == null) { 126 insnHandlers = new ArrayList (); 127 handlers[j] = insnHandlers; 128 } 129 insnHandlers.add(tcb); 130 } 131 } 132 133 Frame current = newFrame(m.maxLocals, m.maxStack); 136 Frame handler = newFrame(m.maxLocals, m.maxStack); 137 Type[] args = Type.getArgumentTypes(m.desc); 138 int local = 0; 139 if ((m.access & ACC_STATIC) == 0) { 140 Type ctype = Type.getType("L" + owner + ";"); 141 current.setLocal(local++, interpreter.newValue(ctype)); 142 } 143 for (int i = 0; i < args.length; ++i) { 144 current.setLocal(local++, interpreter.newValue(args[i])); 145 if (args[i].getSize() == 2) { 146 current.setLocal(local++, interpreter.newValue(null)); 147 } 148 } 149 while (local < m.maxLocals) { 150 current.setLocal(local++, interpreter.newValue(null)); 151 } 152 merge(0, current, null); 153 154 while (top > 0) { 156 int insn = queue[--top]; 157 Frame f = frames[insn]; 158 Subroutine subroutine = subroutines[insn]; 159 queued[insn] = false; 160 161 try { 162 Object o = m.instructions.get(insn); 163 jsr = false; 164 165 if (o instanceof LabelNode) { 166 merge(insn + 1, f, subroutine); 167 } else { 168 AbstractInsnNode insnNode = (AbstractInsnNode) o; 169 int insnOpcode = insnNode.getOpcode(); 170 171 current.init(f).execute(insnNode, interpreter); 172 subroutine = subroutine == null ? null : subroutine.copy(); 173 174 if (insnNode instanceof JumpInsnNode) { 175 JumpInsnNode j = (JumpInsnNode) insnNode; 176 if (insnOpcode != GOTO && insnOpcode != JSR) { 177 merge(insn + 1, current, subroutine); 178 } 179 if (insnOpcode == JSR) { 180 jsr = true; 181 merge(indexes.get(j.label), 182 current, 183 new Subroutine(j.label, m.maxLocals, j)); 184 } else { 185 merge(indexes.get(j.label), current, subroutine); 186 } 187 } else if (insnNode instanceof LookupSwitchInsnNode) { 188 LookupSwitchInsnNode lsi = (LookupSwitchInsnNode) insnNode; 189 merge(indexes.get(lsi.dflt), current, subroutine); 190 for (int j = 0; j < lsi.labels.size(); ++j) { 191 Label label = (Label) lsi.labels.get(j); 192 merge(indexes.get(label), current, subroutine); 193 } 194 } else if (insnNode instanceof TableSwitchInsnNode) { 195 TableSwitchInsnNode tsi = (TableSwitchInsnNode) insnNode; 196 merge(indexes.get(tsi.dflt), current, subroutine); 197 for (int j = 0; j < tsi.labels.size(); ++j) { 198 Label label = (Label) tsi.labels.get(j); 199 merge(indexes.get(label), current, subroutine); 200 } 201 } else if (insnOpcode == RET) { 202 if (subroutine == null) { 203 throw new AnalyzerException("RET instruction outside of a sub routine"); 204 } 205 for (int i = 0; i < subroutine.callers.size(); ++i) { 206 int caller = indexes.get(subroutine.callers.get(i)); 207 merge(caller + 1, 208 frames[caller], 209 current, 210 subroutines[caller], 211 subroutine.access); 212 } 213 } else if (insnOpcode != ATHROW 214 && (insnOpcode < IRETURN || insnOpcode > RETURN)) 215 { 216 if (subroutine != null) { 217 if (insnNode instanceof VarInsnNode) { 218 int var = ((VarInsnNode) insnNode).var; 219 subroutine.access[var] = true; 220 if (insnOpcode == LLOAD || insnOpcode == DLOAD 221 || insnOpcode == LSTORE 222 || insnOpcode == DSTORE) 223 { 224 subroutine.access[var + 1] = true; 225 } 226 } else if (insnNode instanceof IincInsnNode) { 227 int var = ((IincInsnNode) insnNode).var; 228 subroutine.access[var] = true; 229 } 230 } 231 merge(insn + 1, current, subroutine); 232 } 233 } 234 235 List insnHandlers = handlers[insn]; 236 if (insnHandlers != null) { 237 for (int i = 0; i < insnHandlers.size(); ++i) { 238 TryCatchBlockNode tcb = (TryCatchBlockNode) insnHandlers.get(i); 239 Type type; 240 if (tcb.type == null) { 241 type = Type.getType("Ljava/lang/Throwable;"); 242 } else { 243 type = Type.getType("L" + tcb.type + ";"); 244 } 245 handler.init(f); 246 handler.clearStack(); 247 handler.push(interpreter.newValue(type)); 248 merge(indexes.get(tcb.handler), handler, subroutine); 249 } 250 } 251 } catch (AnalyzerException e) { 252 throw new AnalyzerException("Error at instruction " + insn 253 + ": " + e.getMessage(), e); 254 } catch(Exception e) { 255 throw new AnalyzerException("Error at instruction " + insn 256 + ": " + e.getMessage(), e); 257 } 258 } 259 260 return frames; 261 } 262 263 274 public Frame[] getFrames() { 275 return frames; 276 } 277 278 286 public int getIndex(final Object insn) { 287 return indexes.get(insn); 288 } 289 290 297 public List getHandlers(final int insn) { 298 return handlers[insn]; 299 } 300 301 308 protected Frame newFrame(final int nLocals, final int nStack) { 309 return new Frame(nLocals, nStack); 310 } 311 312 318 protected Frame newFrame(final Frame src) { 319 return new Frame(src); 320 } 321 322 331 protected void newControlFlowEdge(final Frame frame, final Frame successor) 332 { 333 } 334 335 337 private void merge( 338 final int insn, 339 final Frame frame, 340 final Subroutine subroutine) throws AnalyzerException 341 { 342 if (insn > n - 1) { 343 throw new AnalyzerException("Execution can fall off end of the code"); 344 } 345 346 Frame oldFrame = frames[insn]; 347 Subroutine oldSubroutine = subroutines[insn]; 348 boolean changes = false; 349 350 if (oldFrame == null) { 351 frames[insn] = newFrame(frame); 352 changes = true; 353 } else { 354 changes |= oldFrame.merge(frame, interpreter); 355 } 356 357 newControlFlowEdge(frame, oldFrame); 358 359 if (oldSubroutine == null) { 360 if (subroutine != null) { 361 subroutines[insn] = subroutine.copy(); 362 changes = true; 363 } 364 } else { 365 if (subroutine != null) { 366 changes |= oldSubroutine.merge(subroutine, !jsr); 367 } 368 } 369 if (changes && !queued[insn]) { 370 queued[insn] = true; 371 queue[top++] = insn; 372 } 373 } 374 375 private void merge( 376 final int insn, 377 final Frame beforeJSR, 378 final Frame afterRET, 379 final Subroutine subroutineBeforeJSR, 380 final boolean[] access) throws AnalyzerException 381 { 382 if (insn > n - 1) { 383 throw new AnalyzerException("Execution can fall off end of the code"); 384 } 385 386 Frame oldFrame = frames[insn]; 387 Subroutine oldSubroutine = subroutines[insn]; 388 boolean changes = false; 389 390 afterRET.merge(beforeJSR, access); 391 392 if (oldFrame == null) { 393 frames[insn] = newFrame(afterRET); 394 changes = true; 395 } else { 396 changes |= oldFrame.merge(afterRET, access); 397 } 398 399 newControlFlowEdge(afterRET, oldFrame); 400 401 if (oldSubroutine == null) { 402 if (subroutineBeforeJSR != null) { 403 subroutines[insn] = subroutineBeforeJSR.copy(); 404 changes = true; 405 } 406 } else { 407 if (subroutineBeforeJSR != null) { 408 changes |= oldSubroutine.merge(subroutineBeforeJSR, !jsr); 409 } 410 } 411 if (changes && !queued[insn]) { 412 queued[insn] = true; 413 queue[top++] = insn; 414 } 415 } 416 } 417 | Popular Tags |