1/* 2 * reserved comment block 3 * DO NOT REMOVE OR ALTER! 4 */ 5/* 6 * Licensed to the Apache Software Foundation (ASF) under one or more 7 * contributor license agreements. See the NOTICE file distributed with 8 * this work for additional information regarding copyright ownership. 9 * The ASF licenses this file to You under the Apache License, Version 2.0 10 * (the "License"); you may not use this file except in compliance with 11 * the License. You may obtain a copy of the License at 12 * 13 * http://www.apache.org/licenses/LICENSE-2.0 14 * 15 * Unless required by applicable law or agreed to in writing, software 16 * distributed under the License is distributed on an "AS IS" BASIS, 17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 * See the License for the specific language governing permissions and 19 * limitations under the License. 20 */ 21 22package com.sun.org.apache.bcel.internal.generic; 23 24 25import com.sun.org.apache.bcel.internal.classfile.Utility; 26import java.util.HashSet; 27import java.util.Collection; 28import java.util.HashMap; 29 30/** 31 * Instances of this class give users a handle to the instructions contained in 32 * an InstructionList. Instruction objects may be used more than once within a 33 * list, this is useful because it saves memory and may be much faster. 34 * 35 * Within an InstructionList an InstructionHandle object is wrapped 36 * around all instructions, i.e., it implements a cell in a 37 * doubly-linked list. From the outside only the next and the 38 * previous instruction (handle) are accessible. One 39 * can traverse the list via an Enumeration returned by 40 * InstructionList.elements(). 41 * 42 * @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A> 43 * @see Instruction 44 * @see BranchHandle 45 * @see InstructionList 46 */ 47public class InstructionHandle implements java.io.Serializable { 48 InstructionHandle next, prev; // Will be set from the outside 49 Instruction instruction; 50 protected int i_position = -1; // byte code offset of instruction 51 private HashSet targeters; 52 private HashMap attributes; 53 54 public final InstructionHandle getNext() { return next; } 55 public final InstructionHandle getPrev() { return prev; } 56 public final Instruction getInstruction() { return instruction; } 57 58 /** 59 * Replace current instruction contained in this handle. 60 * Old instruction is disposed using Instruction.dispose(). 61 */ 62 public void setInstruction(Instruction i) { // Overridden in BranchHandle 63 if(i == null) 64 throw new ClassGenException("Assigning null to handle"); 65 66 if((this.getClass() != BranchHandle.class) && (i instanceof BranchInstruction)) 67 throw new ClassGenException("Assigning branch instruction " + i + " to plain handle"); 68 69 if(instruction != null) 70 instruction.dispose(); 71 72 instruction = i; 73 } 74 75 /** 76 * Temporarily swap the current instruction, without disturbing 77 * anything. Meant to be used by a debugger, implementing 78 * breakpoints. Current instruction is returned. 79 */ 80 public Instruction swapInstruction(Instruction i) { 81 Instruction oldInstruction = instruction; 82 instruction = i; 83 return oldInstruction; 84 } 85 86 /*private*/ protected InstructionHandle(Instruction i) { 87 setInstruction(i); 88 } 89 90 private static InstructionHandle ih_list = null; // List of reusable handles 91 92 /** Factory method. 93 */ 94 static final InstructionHandle getInstructionHandle(Instruction i) { 95 if(ih_list == null) 96 return new InstructionHandle(i); 97 else { 98 InstructionHandle ih = ih_list; 99 ih_list = ih.next; 100 101 ih.setInstruction(i); 102 103 return ih; 104 } 105 } 106 107 /** 108 * Called by InstructionList.setPositions when setting the position for every 109 * instruction. In the presence of variable length instructions `setPositions()' 110 * performs multiple passes over the instruction list to calculate the 111 * correct (byte) positions and offsets by calling this function. 112 * 113 * @param offset additional offset caused by preceding (variable length) instructions 114 * @param max_offset the maximum offset that may be caused by these instructions 115 * @return additional offset caused by possible change of this instruction's length 116 */ 117 protected int updatePosition(int offset, int max_offset) { 118 i_position += offset; 119 return 0; 120 } 121 122 /** @return the position, i.e., the byte code offset of the contained 123 * instruction. This is accurate only after 124 * InstructionList.setPositions() has been called. 125 */ 126 public int getPosition() { return i_position; } 127 128 /** Set the position, i.e., the byte code offset of the contained 129 * instruction. 130 */ 131 void setPosition(int pos) { i_position = pos; } 132 133 /** Overridden in BranchHandle 134 */ 135 protected void addHandle() { 136 next = ih_list; 137 ih_list = this; 138 } 139 140 /** 141 * Delete contents, i.e., remove user access and make handle reusable. 142 */ 143 void dispose() { 144 next = prev = null; 145 instruction.dispose(); 146 instruction = null; 147 i_position = -1; 148 attributes = null; 149 removeAllTargeters(); 150 addHandle(); 151 } 152 153 /** Remove all targeters, if any. 154 */ 155 public void removeAllTargeters() { 156 if(targeters != null) 157 targeters.clear(); 158 } 159 160 /** 161 * Denote this handle isn't referenced anymore by t. 162 */ 163 public void removeTargeter(InstructionTargeter t) { 164 targeters.remove(t); 165 } 166 167 /** 168 * Denote this handle is being referenced by t. 169 */ 170 public void addTargeter(InstructionTargeter t) { 171 if(targeters == null) 172 targeters = new HashSet(); 173 174 //if(!targeters.contains(t)) 175 targeters.add(t); 176 } 177 178 public boolean hasTargeters() { 179 return (targeters != null) && (targeters.size() > 0); 180 } 181 182 /** 183 * @return null, if there are no targeters 184 */ 185 public InstructionTargeter[] getTargeters() { 186 if(!hasTargeters()) 187 return null; 188 189 InstructionTargeter[] t = new InstructionTargeter[targeters.size()]; 190 targeters.toArray(t); 191 return t; 192 } 193 194 /** @return a (verbose) string representation of the contained instruction. 195 */ 196 public String toString(boolean verbose) { 197 return Utility.format(i_position, 4, false, ' ') + ": " + instruction.toString(verbose); 198 } 199 200 /** @return a string representation of the contained instruction. 201 */ 202 public String toString() { 203 return toString(true); 204 } 205 206 /** Add an attribute to an instruction handle. 207 * 208 * @param key the key object to store/retrieve the attribute 209 * @param attr the attribute to associate with this handle 210 */ 211 public void addAttribute(Object key, Object attr) { 212 if(attributes == null) 213 attributes = new HashMap(3); 214 215 attributes.put(key, attr); 216 } 217 218 /** Delete an attribute of an instruction handle. 219 * 220 * @param key the key object to retrieve the attribute 221 */ 222 public void removeAttribute(Object key) { 223 if(attributes != null) 224 attributes.remove(key); 225 } 226 227 /** Get attribute of an instruction handle. 228 * 229 * @param key the key object to store/retrieve the attribute 230 */ 231 public Object getAttribute(Object key) { 232 if(attributes != null) 233 return attributes.get(key); 234 235 return null; 236 } 237 238 /** @return all attributes associated with this handle 239 */ 240 public Collection getAttributes() { 241 return attributes.values(); 242 } 243 244 /** Convenience method, simply calls accept() on the contained instruction. 245 * 246 * @param v Visitor object 247 */ 248 public void accept(Visitor v) { 249 instruction.accept(v); 250 } 251} 252