1 package com.sun.org.apache.bcel.internal.verifier.structurals; 2 3 56 57 import com.sun.org.apache.bcel.internal.generic.*; 58 import com.sun.org.apache.bcel.internal.verifier.exc.*; 59 import java.awt.Color ; 60 import java.util.ArrayList ; 61 import java.util.Enumeration ; 62 import java.util.HashSet ; 63 import java.util.Hashtable ; 64 import java.util.Iterator ; 65 66 90 public class Subroutines{ 91 94 private class SubroutineImpl implements Subroutine{ 95 100 private final int UNSET = -1; 101 102 108 private int localVariable = UNSET; 109 110 111 private HashSet instructions = new HashSet (); 113 116 public boolean contains(InstructionHandle inst){ 117 return instructions.contains(inst); 118 } 119 120 124 private HashSet theJSRs = new HashSet (); 125 126 129 private InstructionHandle theRET; 130 131 138 public String toString(){ 139 String ret = "Subroutine: Local variable is '"+localVariable+"', JSRs are '"+theJSRs+"', RET is '"+theRET+"', Instructions: '"+instructions.toString()+"'."; 140 141 ret += " Accessed local variable slots: '"; 142 int[] alv = getAccessedLocalsIndices(); 143 for (int i=0; i<alv.length; i++){ 144 ret += alv[i]+" "; 145 } 146 ret+="'."; 147 148 ret += " Recursively (via subsub...routines) accessed local variable slots: '"; 149 alv = getRecursivelyAccessedLocalsIndices(); 150 for (int i=0; i<alv.length; i++){ 151 ret += alv[i]+" "; 152 } 153 ret+="'."; 154 155 return ret; 156 } 157 158 162 void setLeavingRET(){ 163 if (localVariable == UNSET){ 164 throw new AssertionViolatedException("setLeavingRET() called for top-level 'subroutine' or forgot to set local variable first."); 165 } 166 Iterator iter = instructions.iterator(); 167 InstructionHandle ret = null; 168 while(iter.hasNext()){ 169 InstructionHandle actual = (InstructionHandle) iter.next(); 170 if (actual.getInstruction() instanceof RET){ 171 if (ret != null){ 172 throw new StructuralCodeConstraintException("Subroutine with more then one RET detected: '"+ret+"' and '"+actual+"'."); 173 } 174 else{ 175 ret = actual; 176 } 177 } 178 } 179 if (ret == null){ 180 throw new StructuralCodeConstraintException("Subroutine without a RET detected."); 181 } 182 if (((RET) ret.getInstruction()).getIndex() != localVariable){ 183 throw new StructuralCodeConstraintException("Subroutine uses '"+ret+"' which does not match the correct local variable '"+localVariable+"'."); 184 } 185 theRET = ret; 186 } 187 188 191 public InstructionHandle[] getEnteringJsrInstructions(){ 192 if (this == TOPLEVEL) { 193 throw new AssertionViolatedException("getLeavingRET() called on top level pseudo-subroutine."); 194 } 195 InstructionHandle[] jsrs = new InstructionHandle[theJSRs.size()]; 196 return (InstructionHandle[]) (theJSRs.toArray(jsrs)); 197 } 198 199 202 public void addEnteringJsrInstruction(InstructionHandle jsrInst){ 203 if ( (jsrInst == null) || (! (jsrInst.getInstruction() instanceof JsrInstruction))){ 204 throw new AssertionViolatedException("Expecting JsrInstruction InstructionHandle."); 205 } 206 if (localVariable == UNSET){ 207 throw new AssertionViolatedException("Set the localVariable first!"); 208 } 209 else{ 210 if (localVariable != ((ASTORE) (((JsrInstruction) jsrInst.getInstruction()).getTarget().getInstruction())).getIndex()){ 214 throw new AssertionViolatedException("Setting a wrong JsrInstruction."); 215 } 216 } 217 theJSRs.add(jsrInst); 218 } 219 220 223 public InstructionHandle getLeavingRET(){ 224 if (this == TOPLEVEL) { 225 throw new AssertionViolatedException("getLeavingRET() called on top level pseudo-subroutine."); 226 } 227 return theRET; 228 } 229 230 233 public InstructionHandle[] getInstructions(){ 234 InstructionHandle[] ret = new InstructionHandle[instructions.size()]; 235 return (InstructionHandle[]) instructions.toArray(ret); 236 } 237 238 243 void addInstruction(InstructionHandle ih){ 244 if (theRET != null){ 245 throw new AssertionViolatedException("All instructions must have been added before invoking setLeavingRET()."); 246 } 247 instructions.add(ih); 248 } 249 250 251 public int[] getRecursivelyAccessedLocalsIndices(){ 252 HashSet s = new HashSet (); 253 int[] lvs = getAccessedLocalsIndices(); 254 for (int j=0; j<lvs.length; j++){ 255 s.add(new Integer (lvs[j])); 256 } 257 _getRecursivelyAccessedLocalsIndicesHelper(s, this.subSubs()); 258 int[] ret = new int[s.size()]; 259 Iterator i = s.iterator(); 260 int j=-1; 261 while (i.hasNext()){ 262 j++; 263 ret[j] = ((Integer ) i.next()).intValue(); 264 } 265 return ret; 266 } 267 268 272 private void _getRecursivelyAccessedLocalsIndicesHelper(HashSet s, Subroutine[] subs){ 273 for (int i=0; i<subs.length; i++){ 274 int[] lvs = subs[i].getAccessedLocalsIndices(); 275 for (int j=0; j<lvs.length; j++){ 276 s.add(new Integer (lvs[j])); 277 } 278 if(subs[i].subSubs().length != 0){ 279 _getRecursivelyAccessedLocalsIndicesHelper(s, subs[i].subSubs()); 280 } 281 } 282 } 283 284 287 public int[] getAccessedLocalsIndices(){ 288 HashSet acc = new HashSet (); 290 if (theRET == null && this != TOPLEVEL){ 291 throw new AssertionViolatedException("This subroutine object must be built up completely before calculating accessed locals."); 292 } 293 Iterator i = instructions.iterator(); 294 while (i.hasNext()){ 295 InstructionHandle ih = (InstructionHandle) i.next(); 296 if (ih.getInstruction() instanceof LocalVariableInstruction || ih.getInstruction() instanceof RET){ 298 int idx = ((IndexedInstruction) (ih.getInstruction())).getIndex(); 299 acc.add(new Integer (idx)); 300 try{ 302 if (ih.getInstruction() instanceof LocalVariableInstruction){ 305 int s = ((LocalVariableInstruction) ih.getInstruction()).getType(null).getSize(); 306 if (s==2) acc.add(new Integer (idx+1)); 307 } 308 } 309 catch(RuntimeException re){ 310 throw new AssertionViolatedException("Oops. BCEL did not like NULL as a ConstantPoolGen object."); 311 } 312 } 313 } 314 315 int[] ret = new int[acc.size()]; 316 i = acc.iterator(); 317 int j=-1; 318 while (i.hasNext()){ 319 j++; 320 ret[j] = ((Integer ) i.next()).intValue(); 321 } 322 return ret; 323 } 324 325 328 public Subroutine[] subSubs(){ 329 HashSet h = new HashSet (); 330 331 Iterator i = instructions.iterator(); 332 while (i.hasNext()){ 333 Instruction inst = ((InstructionHandle) i.next()).getInstruction(); 334 if (inst instanceof JsrInstruction){ 335 InstructionHandle targ = ((JsrInstruction) inst).getTarget(); 336 h.add(getSubroutine(targ)); 337 } 338 } 339 Subroutine[] ret = new Subroutine[h.size()]; 340 return (Subroutine[]) h.toArray(ret); 341 } 342 343 349 void setLocalVariable(int i){ 350 if (localVariable != UNSET){ 351 throw new AssertionViolatedException("localVariable set twice."); 352 } 353 else{ 354 localVariable = i; 355 } 356 } 357 358 361 public SubroutineImpl(){ 362 } 363 364 } 366 371 private Hashtable subroutines = new Hashtable (); 372 373 379 public final Subroutine TOPLEVEL; 380 381 386 public Subroutines(MethodGen mg){ 387 388 InstructionHandle[] all = mg.getInstructionList().getInstructionHandles(); 389 CodeExceptionGen[] handlers = mg.getExceptionHandlers(); 390 391 TOPLEVEL = new SubroutineImpl(); 393 394 HashSet sub_leaders = new HashSet (); InstructionHandle ih = all[0]; 397 for (int i=0; i<all.length; i++){ 398 Instruction inst = all[i].getInstruction(); 399 if (inst instanceof JsrInstruction){ 400 sub_leaders.add(((JsrInstruction) inst).getTarget()); 401 } 402 } 403 404 Iterator iter = sub_leaders.iterator(); 406 while (iter.hasNext()){ 407 SubroutineImpl sr = new SubroutineImpl(); 408 InstructionHandle astore = (InstructionHandle) (iter.next()); 409 sr.setLocalVariable( ((ASTORE) (astore.getInstruction())).getIndex() ); 410 subroutines.put(astore, sr); 411 } 412 413 subroutines.put(all[0], TOPLEVEL); 415 sub_leaders.add(all[0]); 416 417 for (int i=0; i<all.length; i++){ 423 Instruction inst = all[i].getInstruction(); 424 if (inst instanceof JsrInstruction){ 425 InstructionHandle leader = ((JsrInstruction) inst).getTarget(); 426 ((SubroutineImpl) getSubroutine(leader)).addEnteringJsrInstruction(all[i]); 427 } 428 } 429 430 HashSet instructions_assigned = new HashSet (); 434 Hashtable colors = new Hashtable (); 436 iter = sub_leaders.iterator(); 437 while (iter.hasNext()){ 438 InstructionHandle actual = (InstructionHandle) (iter.next()); 440 for (int i=0; i<all.length; i++){ 442 colors.put(all[i], Color.white); 443 } 444 colors.put(actual, Color.gray); 445 ArrayList Q = new ArrayList (); 447 Q.add(actual); 449 450 if (actual == all[0]){ 451 for (int j=0; j<handlers.length; j++){ 452 colors.put(handlers[j].getHandlerPC(), Color.gray); 453 Q.add(handlers[j].getHandlerPC()); 454 } 455 } 456 457 458 while (Q.size() != 0){ 460 InstructionHandle u = (InstructionHandle) Q.remove(0); 461 InstructionHandle[] successors = getSuccessors(u); 462 for (int i=0; i<successors.length; i++){ 463 if (((Color ) colors.get(successors[i])) == Color.white){ 464 colors.put(successors[i], Color.gray); 465 Q.add(successors[i]); 466 } 467 } 468 colors.put(u, Color.black); 469 } 470 for (int i=0; i<all.length; i++){ 472 if (colors.get(all[i]) == Color.black){ 473 ((SubroutineImpl) (actual==all[0]?getTopLevel():getSubroutine(actual))).addInstruction(all[i]); 474 if (instructions_assigned.contains(all[i])){ 475 throw new StructuralCodeConstraintException("Instruction '"+all[i]+"' is part of more than one subroutine (or of the top level and a subroutine)."); 476 } 477 else{ 478 instructions_assigned.add(all[i]); 479 } 480 } 481 } 482 if (actual != all[0]){ ((SubroutineImpl) getSubroutine(actual)).setLeavingRET(); 484 } 485 } 486 487 for (int i=0; i<handlers.length; i++){ 490 InstructionHandle _protected = handlers[i].getStartPC(); 491 while (_protected != handlers[i].getEndPC().getNext()){ Enumeration subs = subroutines.elements(); 493 while (subs.hasMoreElements()){ 494 Subroutine sub = (Subroutine) subs.nextElement(); 495 if (sub != subroutines.get(all[0])){ if (sub.contains(_protected)){ 497 throw new StructuralCodeConstraintException("Subroutine instruction '"+_protected+"' is protected by an exception handler, '"+handlers[i]+"'. This is forbidden by the JustIce verifier due to its clear definition of subroutines."); 498 } 499 } 500 } 501 _protected = _protected.getNext(); 502 } 503 } 504 505 noRecursiveCalls(getTopLevel(), new HashSet ()); 512 513 } 514 515 526 private void noRecursiveCalls(Subroutine sub, HashSet set){ 527 Subroutine[] subs = sub.subSubs(); 528 529 for (int i=0; i<subs.length; i++){ 530 int index = ((RET) (subs[i].getLeavingRET().getInstruction())).getIndex(); 531 532 if (!set.add(new Integer (index))){ 533 SubroutineImpl si = (SubroutineImpl) subs[i]; 535 throw new StructuralCodeConstraintException("Subroutine with local variable '"+si.localVariable+"', JSRs '"+si.theJSRs+"', RET '"+si.theRET+"' is called by a subroutine which uses the same local variable index as itself; maybe even a recursive call? JustIce's clean definition of a subroutine forbids both."); 536 } 537 538 noRecursiveCalls(subs[i], set); 539 540 set.remove(new Integer (index)); 541 } 542 } 543 544 552 public Subroutine getSubroutine(InstructionHandle leader){ 553 Subroutine ret = (Subroutine) subroutines.get(leader); 554 555 if (ret == null){ 556 throw new AssertionViolatedException("Subroutine requested for an InstructionHandle that is not a leader of a subroutine."); 557 } 558 559 if (ret == TOPLEVEL){ 560 throw new AssertionViolatedException("TOPLEVEL special subroutine requested; use getTopLevel()."); 561 } 562 563 return ret; 564 } 565 566 577 public Subroutine subroutineOf(InstructionHandle any){ 578 Iterator i = subroutines.values().iterator(); 579 while (i.hasNext()){ 580 Subroutine s = (Subroutine) i.next(); 581 if (s.contains(any)) return s; 582 } 583 System.err.println("DEBUG: Please verify '"+any+"' lies in dead code."); 584 return null; 585 } 587 588 598 public Subroutine getTopLevel(){ 599 return TOPLEVEL; 600 } 601 607 private static InstructionHandle[] getSuccessors(InstructionHandle instruction){ 608 final InstructionHandle[] empty = new InstructionHandle[0]; 609 final InstructionHandle[] single = new InstructionHandle[1]; 610 final InstructionHandle[] pair = new InstructionHandle[2]; 611 612 Instruction inst = instruction.getInstruction(); 613 614 if (inst instanceof RET){ 615 return empty; 616 } 617 618 if (inst instanceof ReturnInstruction){ 620 return empty; 621 } 622 623 if (inst instanceof ATHROW){ 626 return empty; 627 } 628 629 if (inst instanceof JsrInstruction){ 631 single[0] = instruction.getNext(); 632 return single; 633 } 634 635 if (inst instanceof GotoInstruction){ 636 single[0] = ((GotoInstruction) inst).getTarget(); 637 return single; 638 } 639 640 if (inst instanceof BranchInstruction){ 641 if (inst instanceof Select){ 642 InstructionHandle[] matchTargets = ((Select) inst).getTargets(); 645 InstructionHandle[] ret = new InstructionHandle[matchTargets.length+1]; 646 ret[0] = ((Select) inst).getTarget(); 647 System.arraycopy(matchTargets, 0, ret, 1, matchTargets.length); 648 return ret; 649 } 650 else{ 651 pair[0] = instruction.getNext(); 652 pair[1] = ((BranchInstruction) inst).getTarget(); 653 return pair; 654 } 655 } 656 657 single[0] = instruction.getNext(); 659 return single; 660 } 661 662 665 public String toString(){ 666 return "---\n"+subroutines.toString()+"\n---\n"; 667 } 668 } 669 | Popular Tags |