1 /* 2 * reserved comment block 3 * DO NOT REMOVE OR ALTER! 4 */ 5 package com.sun.org.apache.bcel.internal.generic; 6 7 /* ==================================================================== 8 * The Apache Software License, Version 1.1 9 * 10 * Copyright (c) 2001 The Apache Software Foundation. All rights 11 * reserved. 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 17 * 1. Redistributions of source code must retain the above copyright 18 * notice, this list of conditions and the following disclaimer. 19 * 20 * 2. Redistributions in binary form must reproduce the above copyright 21 * notice, this list of conditions and the following disclaimer in 22 * the documentation and/or other materials provided with the 23 * distribution. 24 * 25 * 3. The end-user documentation included with the redistribution, 26 * if any, must include the following acknowledgment: 27 * "This product includes software developed by the 28 * Apache Software Foundation (http://www.apache.org/)." 29 * Alternately, this acknowledgment may appear in the software itself, 30 * if and wherever such third-party acknowledgments normally appear. 31 * 32 * 4. The names "Apache" and "Apache Software Foundation" and 33 * "Apache BCEL" must not be used to endorse or promote products 34 * derived from this software without prior written permission. For 35 * written permission, please contact apache@apache.org. 36 * 37 * 5. Products derived from this software may not be called "Apache", 38 * "Apache BCEL", nor may "Apache" appear in their name, without 39 * prior written permission of the Apache Software Foundation. 40 * 41 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 42 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 43 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 44 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR 45 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 46 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 47 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 48 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 49 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 50 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 51 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 52 * SUCH DAMAGE. 53 * ==================================================================== 54 * 55 * This software consists of voluntary contributions made by many 56 * individuals on behalf of the Apache Software Foundation. For more 57 * information on the Apache Software Foundation, please see 58 * <http://www.apache.org/>. 59 */ 60 61 import com.sun.org.apache.bcel.internal.classfile.Utility; 62 import java.util.HashSet; 63 import java.util.Collection; 64 import java.util.HashMap; 65 66 /** 67 * Instances of this class give users a handle to the instructions contained in 68 * an InstructionList. Instruction objects may be used more than once within a 69 * list, this is useful because it saves memory and may be much faster. 70 * 71 * Within an InstructionList an InstructionHandle object is wrapped 72 * around all instructions, i.e., it implements a cell in a 73 * doubly-linked list. From the outside only the next and the 74 * previous instruction (handle) are accessible. One 75 * can traverse the list via an Enumeration returned by 76 * InstructionList.elements(). 77 * 78 * @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A> 79 * @see Instruction 80 * @see BranchHandle 81 * @see InstructionList 82 */ 83 public class InstructionHandle implements java.io.Serializable { 84 InstructionHandle next, prev; // Will be set from the outside 85 Instruction instruction; 86 protected int i_position = -1; // byte code offset of instruction 87 private HashSet targeters; 88 private HashMap attributes; 89 getNext()90 public final InstructionHandle getNext() { return next; } getPrev()91 public final InstructionHandle getPrev() { return prev; } getInstruction()92 public final Instruction getInstruction() { return instruction; } 93 94 /** 95 * Replace current instruction contained in this handle. 96 * Old instruction is disposed using Instruction.dispose(). 97 */ setInstruction(Instruction i)98 public void setInstruction(Instruction i) { // Overridden in BranchHandle 99 if(i == null) 100 throw new ClassGenException("Assigning null to handle"); 101 102 if((this.getClass() != BranchHandle.class) && (i instanceof BranchInstruction)) 103 throw new ClassGenException("Assigning branch instruction " + i + " to plain handle"); 104 105 if(instruction != null) 106 instruction.dispose(); 107 108 instruction = i; 109 } 110 111 /** 112 * Temporarily swap the current instruction, without disturbing 113 * anything. Meant to be used by a debugger, implementing 114 * breakpoints. Current instruction is returned. 115 */ swapInstruction(Instruction i)116 public Instruction swapInstruction(Instruction i) { 117 Instruction oldInstruction = instruction; 118 instruction = i; 119 return oldInstruction; 120 } 121 InstructionHandle(Instruction i)122 /*private*/ protected InstructionHandle(Instruction i) { 123 setInstruction(i); 124 } 125 126 private static InstructionHandle ih_list = null; // List of reusable handles 127 128 /** Factory method. 129 */ getInstructionHandle(Instruction i)130 static final InstructionHandle getInstructionHandle(Instruction i) { 131 if(ih_list == null) 132 return new InstructionHandle(i); 133 else { 134 InstructionHandle ih = ih_list; 135 ih_list = ih.next; 136 137 ih.setInstruction(i); 138 139 return ih; 140 } 141 } 142 143 /** 144 * Called by InstructionList.setPositions when setting the position for every 145 * instruction. In the presence of variable length instructions `setPositions()' 146 * performs multiple passes over the instruction list to calculate the 147 * correct (byte) positions and offsets by calling this function. 148 * 149 * @param offset additional offset caused by preceding (variable length) instructions 150 * @param max_offset the maximum offset that may be caused by these instructions 151 * @return additional offset caused by possible change of this instruction's length 152 */ updatePosition(int offset, int max_offset)153 protected int updatePosition(int offset, int max_offset) { 154 i_position += offset; 155 return 0; 156 } 157 158 /** @return the position, i.e., the byte code offset of the contained 159 * instruction. This is accurate only after 160 * InstructionList.setPositions() has been called. 161 */ getPosition()162 public int getPosition() { return i_position; } 163 164 /** Set the position, i.e., the byte code offset of the contained 165 * instruction. 166 */ setPosition(int pos)167 void setPosition(int pos) { i_position = pos; } 168 169 /** Overridden in BranchHandle 170 */ addHandle()171 protected void addHandle() { 172 next = ih_list; 173 ih_list = this; 174 } 175 176 /** 177 * Delete contents, i.e., remove user access and make handle reusable. 178 */ dispose()179 void dispose() { 180 next = prev = null; 181 instruction.dispose(); 182 instruction = null; 183 i_position = -1; 184 attributes = null; 185 removeAllTargeters(); 186 addHandle(); 187 } 188 189 /** Remove all targeters, if any. 190 */ removeAllTargeters()191 public void removeAllTargeters() { 192 if(targeters != null) 193 targeters.clear(); 194 } 195 196 /** 197 * Denote this handle isn't referenced anymore by t. 198 */ removeTargeter(InstructionTargeter t)199 public void removeTargeter(InstructionTargeter t) { 200 targeters.remove(t); 201 } 202 203 /** 204 * Denote this handle is being referenced by t. 205 */ addTargeter(InstructionTargeter t)206 public void addTargeter(InstructionTargeter t) { 207 if(targeters == null) 208 targeters = new HashSet(); 209 210 //if(!targeters.contains(t)) 211 targeters.add(t); 212 } 213 hasTargeters()214 public boolean hasTargeters() { 215 return (targeters != null) && (targeters.size() > 0); 216 } 217 218 /** 219 * @return null, if there are no targeters 220 */ getTargeters()221 public InstructionTargeter[] getTargeters() { 222 if(!hasTargeters()) 223 return null; 224 225 InstructionTargeter[] t = new InstructionTargeter[targeters.size()]; 226 targeters.toArray(t); 227 return t; 228 } 229 230 /** @return a (verbose) string representation of the contained instruction. 231 */ toString(boolean verbose)232 public String toString(boolean verbose) { 233 return Utility.format(i_position, 4, false, ' ') + ": " + instruction.toString(verbose); 234 } 235 236 /** @return a string representation of the contained instruction. 237 */ toString()238 public String toString() { 239 return toString(true); 240 } 241 242 /** Add an attribute to an instruction handle. 243 * 244 * @param key the key object to store/retrieve the attribute 245 * @param attr the attribute to associate with this handle 246 */ addAttribute(Object key, Object attr)247 public void addAttribute(Object key, Object attr) { 248 if(attributes == null) 249 attributes = new HashMap(3); 250 251 attributes.put(key, attr); 252 } 253 254 /** Delete an attribute of an instruction handle. 255 * 256 * @param key the key object to retrieve the attribute 257 */ removeAttribute(Object key)258 public void removeAttribute(Object key) { 259 if(attributes != null) 260 attributes.remove(key); 261 } 262 263 /** Get attribute of an instruction handle. 264 * 265 * @param key the key object to store/retrieve the attribute 266 */ getAttribute(Object key)267 public Object getAttribute(Object key) { 268 if(attributes != null) 269 return attributes.get(key); 270 271 return null; 272 } 273 274 /** @return all attributes associated with this handle 275 */ getAttributes()276 public Collection getAttributes() { 277 return attributes.values(); 278 } 279 280 /** Convenience method, simply calls accept() on the contained instruction. 281 * 282 * @param v Visitor object 283 */ accept(Visitor v)284 public void accept(Visitor v) { 285 instruction.accept(v); 286 } 287 } 288