public static boolean isThrower(BasicBlock target) { InstructionHandle ins = target.getFirstInstruction(); int maxCount = 7; while (ins != null) { if (maxCount-- <= 0) break; Instruction i = ins.getInstruction(); if (i instanceof ATHROW) { return true; } if (i instanceof InstructionTargeter || i instanceof ReturnInstruction) return false; ins = ins.getNext(); } return false; }
InstructionHandle insertThrowAbort(MethodGen m, InstructionList il, InstructionHandle pos) { InstructionHandle retval; retval = il.insert(pos, ins_f .createNew("ibis.cashmere.impl.aborts.AbortException")); il.insert(pos, new DUP()); il.insert(pos, ins_f.createInvoke( "ibis.cashmere.impl.aborts.AbortException", "<init>", Type.VOID, Type.NO_ARGS, Constants.INVOKESPECIAL)); il.insert(pos, new ATHROW()); return retval; }
InstructionHandle insertTypecheckCode(MethodGen m, InstructionList il, InstructionHandle pos, int spawnId, int exceptionPos) { ArrayList<CodeExceptionGen> catches = mtab.getCatchTypes(m, spawnId); InstructionHandle[] jumpTargets = new InstructionHandle[catches.size() + 1]; BranchHandle[] jumps = new BranchHandle[catches.size()]; for (int i = 0; i < catches.size(); i++) { CodeExceptionGen e = catches.get(i); ObjectType type = e.getCatchType(); InstructionHandle catchTarget = e.getHandlerPC(); jumpTargets[i] = il.insert(pos, new ALOAD(exceptionPos)); il.insert(pos, new INSTANCEOF(cpg.addClass(type))); il.insert(pos, new BIPUSH((byte) 1)); jumps[i] = il.insert(pos, new IF_ICMPNE(null)); il.insert(pos, new ALOAD(exceptionPos)); il.insert(pos, ins_f.createCheckCast(type)); il.insert(pos, new GOTO(catchTarget)); } InstructionHandle t = il.insert(pos, new ALOAD(exceptionPos)); il.insert(pos, new ATHROW()); jumpTargets[catches.size()] = t; for (int i = 0; i < catches.size(); i++) { jumps[i].setTarget(jumpTargets[i + 1]); } return pos; }
private void emitATHROW(Element xml_inst, ATHROW inst) { // The purpose of this method is to attempt to determine // the type of the Exception to be thrown. We do this by // searching backwards through the instructions preceeding // the current athrow. We look for a <new/> where we // assume that this instantiates the exception object. // If we encounter a <label/> while searching for <new/>, // we stop the search because flow control makes it unlikely // that we get the right <new/>. In that case we assume // java.lang.Throwable as the type. List<Element> list = ((Element) xml_inst.getParent()).getChildren(); Element[] siblings = list.toArray(new Element[0]); // java.lang.Throwable is the default type if we don't // find the proper type String type = "java.lang.Throwable"; for (int i = siblings.length - 1; i >= 0; i--) { Element elem = siblings[i]; String name = elem.getName(); if (name.equals("label")) break; if (name.equals("new")) { // We found the <new> that instantiates the exception // object // Now we need to copy the type type = elem.getAttributeValue("type"); break; } } xml_inst.setAttribute("type", type); }
/** * Get the Location where exception(s) thrown on given exception edge are * thrown. * * @param exceptionEdge * the exception Edge * @return Location where exception(s) are thrown from */ public Location getExceptionThrowerLocation(Edge exceptionEdge) { if (!exceptionEdge.isExceptionEdge()) throw new IllegalArgumentException(); InstructionHandle handle = exceptionEdge.getSource().getExceptionThrower(); if (handle == null) throw new IllegalStateException(); BasicBlock basicBlock = (handle.getInstruction() instanceof ATHROW) ? exceptionEdge.getSource() : getSuccessorWithEdgeType(exceptionEdge.getSource(), EdgeTypes.FALL_THROUGH_EDGE); if (basicBlock == null) { if (removedEdgeList != null) { // The fall-through edge might have been removed during // CFG pruning. Look for it in the removed edge list. for (Edge removedEdge : removedEdgeList) { if (removedEdge.getType() == EdgeTypes.FALL_THROUGH_EDGE && removedEdge.getSource() == exceptionEdge.getSource()) { basicBlock = removedEdge.getTarget(); break; } } } } if (basicBlock == null) { throw new IllegalStateException("No basic block for thrower " + handle + " in " + this.methodGen.getClassName() + "." + this.methodName + " : " + this.methodGen.getSignature()); } return new Location(handle, basicBlock); }
private boolean isEndInstruction(InstructionContext context) { return context.getInstruction().getInstruction() instanceof ReturnInstruction || context.getInstruction().getInstruction() instanceof ATHROW; }
boolean isEndInstruction(InstructionContext context) { return context.getInstruction().getInstruction() instanceof ReturnInstruction || context.getInstruction().getInstruction() instanceof ATHROW; }
@Override public void visitATHROW(ATHROW ins) { isThrow = true; }
/** * These are the checks if constraints are satisfied which are described in the * Java Virtual Machine Specification, Second Edition as Static Constraints on * the instructions of Java Virtual Machine Code (chapter 4.8.1). * * @throws StaticCodeConstraintException if the verification fails. */ private void pass3StaticInstructionChecks(){ // Code array must not be empty: // Enforced in pass 2 (also stated in the static constraints of the Code // array in vmspec2), together with pass 1 (reading code_length bytes and // interpreting them as code[]). So this must not be checked again here. if (! (code.getCode().length < 65536)){// contradicts vmspec2 page 152 ("Limitations"), but is on page 134. throw new StaticCodeInstructionConstraintException("Code array in code attribute '"+code+"' too big: must be smaller than 65536 bytes."); } // First opcode at offset 0: okay, that's clear. Nothing to do. // Only instances of the instructions documented in Section 6.4 may appear in // the code array. // For BCEL's sake, we cannot handle WIDE stuff, but hopefully BCEL does its job right :) // The last byte of the last instruction in the code array must be the byte at index // code_length-1 : See the do_verify() comments. We actually don't iterate through the // byte array, but use an InstructionList so we cannot check for this. But BCEL does // things right, so it's implicitly okay. // TODO: Check how BCEL handles (and will handle) instructions like IMPDEP1, IMPDEP2, // BREAKPOINT... that BCEL knows about but which are illegal anyway. // We currently go the safe way here. InstructionHandle ih = instructionList.getStart(); while (ih != null){ Instruction i = ih.getInstruction(); if (i instanceof IMPDEP1){ throw new StaticCodeInstructionConstraintException("IMPDEP1 must not be in the code, it is an illegal instruction for _internal_ JVM use!"); } if (i instanceof IMPDEP2){ throw new StaticCodeInstructionConstraintException("IMPDEP2 must not be in the code, it is an illegal instruction for _internal_ JVM use!"); } if (i instanceof BREAKPOINT){ throw new StaticCodeInstructionConstraintException("BREAKPOINT must not be in the code, it is an illegal instruction for _internal_ JVM use!"); } ih = ih.getNext(); } // The original verifier seems to do this check here, too. // An unreachable last instruction may also not fall through the // end of the code, which is stupid -- but with the original // verifier's subroutine semantics one cannot predict reachability. Instruction last = instructionList.getEnd().getInstruction(); if (! ((last instanceof ReturnInstruction) || (last instanceof RET) || (last instanceof GotoInstruction) || (last instanceof ATHROW) )) { throw new StaticCodeInstructionConstraintException("Execution must not fall off the bottom of the code array. This constraint is enforced statically as some existing verifiers do - so it may be a false alarm if the last instruction is not reachable."); } }
/** * A utility method that calculates the successors of a given InstructionHandle * <B>in the same subroutine</B>. That means, a RET does not have any successors * as defined here. A JsrInstruction has its physical successor as its successor * (opposed to its target) as defined here. */ private static InstructionHandle[] getSuccessors(InstructionHandle instruction){ final InstructionHandle[] empty = new InstructionHandle[0]; final InstructionHandle[] single = new InstructionHandle[1]; final InstructionHandle[] pair = new InstructionHandle[2]; Instruction inst = instruction.getInstruction(); if (inst instanceof RET){ return empty; } // Terminates method normally. if (inst instanceof ReturnInstruction){ return empty; } // Terminates method abnormally, because JustIce mandates // subroutines not to be protected by exception handlers. if (inst instanceof ATHROW){ return empty; } // See method comment. if (inst instanceof JsrInstruction){ single[0] = instruction.getNext(); return single; } if (inst instanceof GotoInstruction){ single[0] = ((GotoInstruction) inst).getTarget(); return single; } if (inst instanceof BranchInstruction){ if (inst instanceof Select){ // BCEL's getTargets() returns only the non-default targets, // thanks to Eli Tilevich for reporting. InstructionHandle[] matchTargets = ((Select) inst).getTargets(); InstructionHandle[] ret = new InstructionHandle[matchTargets.length+1]; ret[0] = ((Select) inst).getTarget(); System.arraycopy(matchTargets, 0, ret, 1, matchTargets.length); return ret; } else{ pair[0] = instruction.getNext(); pair[1] = ((BranchInstruction) inst).getTarget(); return pair; } } // default case: Fall through. single[0] = instruction.getNext(); return single; }
/** * A utility method that calculates the successors of a given InstructionHandle * <B>in the same subroutine</B>. That means, a RET does not have any successors * as defined here. A JsrInstruction has its physical successor as its successor * (opposed to its target) as defined here. */ private static InstructionHandle[] getSuccessors(InstructionHandle instruction){ Instruction inst = instruction.getInstruction(); if (inst instanceof RET){ return empty; } // Terminates method normally. if (inst instanceof ReturnInstruction){ return empty; } // Terminates method abnormally, because JustIce mandates // subroutines not to be protected by exception handlers. if (inst instanceof ATHROW){ return empty; } final InstructionHandle[] single = new InstructionHandle[1]; // See method comment. if (inst instanceof JsrInstruction){ single[0] = instruction.getNext(); return single; } if (inst instanceof GotoInstruction){ single[0] = ((GotoInstruction) inst).getTarget(); return single; } if (inst instanceof BranchInstruction){ if (inst instanceof Select){ // BCEL's getTargets() returns only the non-default targets, // thanks to Eli Tilevich for reporting. InstructionHandle[] matchTargets = ((Select) inst).getTargets(); InstructionHandle[] ret = new InstructionHandle[matchTargets.length+1]; ret[0] = ((Select) inst).getTarget(); System.arraycopy(matchTargets, 0, ret, 1, matchTargets.length); return ret; } else{ final InstructionHandle[] pair = new InstructionHandle[2]; pair[0] = instruction.getNext(); pair[1] = ((BranchInstruction) inst).getTarget(); return pair; } } // default case: Fall through. single[0] = instruction.getNext(); return single; }
/** * A utility method that calculates the successors of a given InstructionHandle * That means, a RET does have successors as defined here. * A JsrInstruction has its target as its successor * (opposed to its physical successor) as defined here. */ // TODO: implement caching! private InstructionHandle[] _getSuccessors(){ final InstructionHandle[] empty = new InstructionHandle[0]; final InstructionHandle[] single = new InstructionHandle[1]; final InstructionHandle[] pair = new InstructionHandle[2]; Instruction inst = getInstruction().getInstruction(); if (inst instanceof RET){ Subroutine s = subroutines.subroutineOf(getInstruction()); if (s==null){ //return empty; // RET in dead code. "empty" would be the correct answer, but we know something about the surrounding project... throw new AssertionViolatedException("Asking for successors of a RET in dead code?!"); } //TODO: remove throw new AssertionViolatedException("DID YOU REALLY WANT TO ASK FOR RET'S SUCCS?"); /* InstructionHandle[] jsrs = s.getEnteringJsrInstructions(); InstructionHandle[] ret = new InstructionHandle[jsrs.length]; for (int i=0; i<jsrs.length; i++){ ret[i] = jsrs[i].getNext(); } return ret; */ } // Terminates method normally. if (inst instanceof ReturnInstruction){ return empty; } // Terminates method abnormally, because JustIce mandates // subroutines not to be protected by exception handlers. if (inst instanceof ATHROW){ return empty; } // See method comment. if (inst instanceof JsrInstruction){ single[0] = ((JsrInstruction) inst).getTarget(); return single; } if (inst instanceof GotoInstruction){ single[0] = ((GotoInstruction) inst).getTarget(); return single; } if (inst instanceof BranchInstruction){ if (inst instanceof Select){ // BCEL's getTargets() returns only the non-default targets, // thanks to Eli Tilevich for reporting. InstructionHandle[] matchTargets = ((Select) inst).getTargets(); InstructionHandle[] ret = new InstructionHandle[matchTargets.length+1]; ret[0] = ((Select) inst).getTarget(); System.arraycopy(matchTargets, 0, ret, 1, matchTargets.length); return ret; } else{ pair[0] = getInstruction().getNext(); pair[1] = ((BranchInstruction) inst).getTarget(); return pair; } } // default case: Fall through. single[0] = getInstruction().getNext(); return single; }