📄 subroutines.java
字号:
package org.apache.bcel.verifier.structurals;/* ==================================================================== * The Apache Software License, Version 1.1 * * Copyright (c) 2001 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Apache" and "Apache Software Foundation" and * "Apache BCEL" must not be used to endorse or promote products * derived from this software without prior written permission. For * written permission, please contact apache@apache.org. * * 5. Products derived from this software may not be called "Apache", * "Apache BCEL", nor may "Apache" appear in their name, without * prior written permission of the Apache Software Foundation. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. */import org.apache.bcel.generic.*;import org.apache.bcel.verifier.exc.*;import java.awt.Color;import java.util.ArrayList;import java.util.Enumeration;import java.util.HashSet;import java.util.Hashtable;import java.util.Iterator; /** * Instances of this class contain information about the subroutines * found in a code array of a method. * This implementation considers the top-level (the instructions * reachable without a JSR or JSR_W starting off from the first * instruction in a code array of a method) being a special subroutine; * see getTopLevel() for that. * Please note that the definition of subroutines in the Java Virtual * Machine Specification, Second Edition is somewhat incomplete. * Therefore, JustIce uses an own, more rigid notion. * Basically, a subroutine is a piece of code that starts at the target * of a JSR of JSR_W instruction and ends at a corresponding RET * instruction. Note also that the control flow of a subroutine * may be complex and non-linear; and that subroutines may be nested. * JustIce also mandates subroutines not to be protected by exception * handling code (for the sake of control flow predictability). * To understand JustIce's notion of subroutines, please read * * TODO: refer to the paper. * * @version $Id: Subroutines.java,v 1.1.1.1 2001/10/29 20:00:42 jvanzyl Exp $ * @author <A HREF="http://www.inf.fu-berlin.de/~ehaase"/>Enver Haase</A> * @see #getTopLevel() */public class Subroutines{ /** * This inner class implements the Subroutine interface. */ private class SubroutineImpl implements Subroutine{ /** * UNSET, a symbol for an uninitialized localVariable * field. This is used for the "top-level" Subroutine; * i.e. no subroutine. */ private final int UNSET = -1; /** * The Local Variable slot where the first * instruction of this subroutine (an ASTORE) stores * the JsrInstruction's ReturnAddress in and * the RET of this subroutine operates on. */ private int localVariable = UNSET; /** The instructions that belong to this subroutine. */ private HashSet instructions = new HashSet(); // Elements: InstructionHandle /* * Refer to the Subroutine interface for documentation. */ public boolean contains(InstructionHandle inst){ return instructions.contains(inst); } /** * The JSR or JSR_W instructions that define this * subroutine by targeting it. */ private HashSet theJSRs = new HashSet(); /** * The RET instruction that leaves this subroutine. */ private InstructionHandle theRET; /** * Returns a String representation of this object, merely * for debugging purposes. * (Internal) Warning: Verbosity on a problematic subroutine may cause * stack overflow errors due to recursive subSubs() calls. * Don't use this, then. */ public String toString(){ String ret = "Subroutine: Local variable is '"+localVariable+"', JSRs are '"+theJSRs+"', RET is '"+theRET+"', Instructions: '"+instructions.toString()+"'."; ret += " Accessed local variable slots: '"; int[] alv = getAccessedLocalsIndices(); for (int i=0; i<alv.length; i++){ ret += alv[i]+" "; } ret+="'."; ret += " Recursively (via subsub...routines) accessed local variable slots: '"; alv = getRecursivelyAccessedLocalsIndices(); for (int i=0; i<alv.length; i++){ ret += alv[i]+" "; } ret+="'."; return ret; } /** * Sets the leaving RET instruction. Must be invoked after all instructions are added. * Must not be invoked for top-level 'subroutine'. */ void setLeavingRET(){ if (localVariable == UNSET){ throw new AssertionViolatedException("setLeavingRET() called for top-level 'subroutine' or forgot to set local variable first."); } Iterator iter = instructions.iterator(); InstructionHandle ret = null; while(iter.hasNext()){ InstructionHandle actual = (InstructionHandle) iter.next(); if (actual.getInstruction() instanceof RET){ if (ret != null){ throw new StructuralCodeConstraintException("Subroutine with more then one RET detected: '"+ret+"' and '"+actual+"'."); } else{ ret = actual; } } } if (ret == null){ throw new StructuralCodeConstraintException("Subroutine without a RET detected."); } if (((RET) ret.getInstruction()).getIndex() != localVariable){ throw new StructuralCodeConstraintException("Subroutine uses '"+ret+"' which does not match the correct local variable '"+localVariable+"'."); } theRET = ret; } /* * Refer to the Subroutine interface for documentation. */ public InstructionHandle[] getEnteringJsrInstructions(){ if (this == TOPLEVEL) { throw new AssertionViolatedException("getLeavingRET() called on top level pseudo-subroutine."); } InstructionHandle[] jsrs = new InstructionHandle[theJSRs.size()]; return (InstructionHandle[]) (theJSRs.toArray(jsrs)); } /** * Adds a new JSR or JSR_W that has this subroutine as its target. */ public void addEnteringJsrInstruction(InstructionHandle jsrInst){ if ( (jsrInst == null) || (! (jsrInst.getInstruction() instanceof JsrInstruction))){ throw new AssertionViolatedException("Expecting JsrInstruction InstructionHandle."); } if (localVariable == UNSET){ throw new AssertionViolatedException("Set the localVariable first!"); } else{ // Something is wrong when an ASTORE is targeted that does not operate on the same local variable than the rest of the // JsrInstruction-targets and the RET. // (We don't know out leader here so we cannot check if we're really targeted!) if (localVariable != ((ASTORE) (((JsrInstruction) jsrInst.getInstruction()).getTarget().getInstruction())).getIndex()){ throw new AssertionViolatedException("Setting a wrong JsrInstruction."); } } theJSRs.add(jsrInst); } /* * Refer to the Subroutine interface for documentation. */ public InstructionHandle getLeavingRET(){ if (this == TOPLEVEL) { throw new AssertionViolatedException("getLeavingRET() called on top level pseudo-subroutine."); } return theRET; } /* * Refer to the Subroutine interface for documentation. */ public InstructionHandle[] getInstructions(){ InstructionHandle[] ret = new InstructionHandle[instructions.size()]; return (InstructionHandle[]) instructions.toArray(ret); } /* * Adds an instruction to this subroutine. * All instructions must have been added before invoking setLeavingRET(). * @see #setLeavingRET */ void addInstruction(InstructionHandle ih){ if (theRET != null){ throw new AssertionViolatedException("All instructions must have been added before invoking setLeavingRET()."); } instructions.add(ih); } /* Satisfies Subroutine.getRecursivelyAccessedLocalsIndices(). */ public int[] getRecursivelyAccessedLocalsIndices(){ HashSet s = new HashSet(); int[] lvs = getAccessedLocalsIndices(); for (int j=0; j<lvs.length; j++){ s.add(new Integer(lvs[j])); } _getRecursivelyAccessedLocalsIndicesHelper(s, this.subSubs()); int[] ret = new int[s.size()]; Iterator i = s.iterator(); int j=-1; while (i.hasNext()){ j++; ret[j] = ((Integer) i.next()).intValue(); } return ret; } /** * A recursive helper method for getRecursivelyAccessedLocalsIndices(). * @see #getRecursivelyAccessedLocalsIndices() */ private void _getRecursivelyAccessedLocalsIndicesHelper(HashSet s, Subroutine[] subs){ for (int i=0; i<subs.length; i++){ int[] lvs = subs[i].getAccessedLocalsIndices(); for (int j=0; j<lvs.length; j++){ s.add(new Integer(lvs[j])); } if(subs[i].subSubs().length != 0){ _getRecursivelyAccessedLocalsIndicesHelper(s, subs[i].subSubs()); } } } /* * Satisfies Subroutine.getAccessedLocalIndices(). */ public int[] getAccessedLocalsIndices(){ //TODO: Implement caching. HashSet acc = new HashSet(); if (theRET == null && this != TOPLEVEL){ throw new AssertionViolatedException("This subroutine object must be built up completely before calculating accessed locals."); } Iterator i = instructions.iterator(); while (i.hasNext()){ InstructionHandle ih = (InstructionHandle) i.next(); // RET is not a LocalVariableInstruction in the current version of BCEL. if (ih.getInstruction() instanceof LocalVariableInstruction || ih.getInstruction() instanceof RET){ int idx = ((IndexedInstruction) (ih.getInstruction())).getIndex(); acc.add(new Integer(idx)); // LONG? DOUBLE?. try{ // LocalVariableInstruction instances are typed without the need to look into // the constant pool. if (ih.getInstruction() instanceof LocalVariableInstruction){ int s = ((LocalVariableInstruction) ih.getInstruction()).getType(null).getSize(); if (s==2) acc.add(new Integer(idx+1)); } } catch(RuntimeException re){ throw new AssertionViolatedException("Oops. BCEL did not like NULL as a ConstantPoolGen object."); } } } int[] ret = new int[acc.size()]; i = acc.iterator(); int j=-1; while (i.hasNext()){ j++; ret[j] = ((Integer) i.next()).intValue(); } return ret; } /* * Satisfies Subroutine.subSubs(). */ public Subroutine[] subSubs(){ HashSet h = new HashSet(); Iterator i = instructions.iterator(); while (i.hasNext()){ Instruction inst = ((InstructionHandle) i.next()).getInstruction(); if (inst instanceof JsrInstruction){ InstructionHandle targ = ((JsrInstruction) inst).getTarget();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -