001: /*
002: * Copyright 2000-2004 The Apache Software Foundation
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: *
016: */
017: package org.apache.bcel.generic;
018:
019: import java.util.Collection;
020: import java.util.HashMap;
021: import java.util.HashSet;
022: import java.util.Map;
023: import java.util.Set;
024: import org.apache.bcel.classfile.Utility;
025:
026: /**
027: * Instances of this class give users a handle to the instructions contained in
028: * an InstructionList. Instruction objects may be used more than once within a
029: * list, this is useful because it saves memory and may be much faster.
030: *
031: * Within an InstructionList an InstructionHandle object is wrapped
032: * around all instructions, i.e., it implements a cell in a
033: * doubly-linked list. From the outside only the next and the
034: * previous instruction (handle) are accessible. One
035: * can traverse the list via an Enumeration returned by
036: * InstructionList.elements().
037: *
038: * @version $Id: InstructionHandle.java 386056 2006-03-15 11:31:56Z tcurdt $
039: * @author <A HREF="mailto:m.dahm@gmx.de">M. Dahm</A>
040: * @see Instruction
041: * @see BranchHandle
042: * @see InstructionList
043: */
044: public class InstructionHandle implements java.io.Serializable {
045:
046: InstructionHandle next, prev; // Will be set from the outside
047: Instruction instruction;
048: protected int i_position = -1; // byte code offset of instruction
049: private Set targeters;
050: private Map attributes;
051:
052: public final InstructionHandle getNext() {
053: return next;
054: }
055:
056: public final InstructionHandle getPrev() {
057: return prev;
058: }
059:
060: public final Instruction getInstruction() {
061: return instruction;
062: }
063:
064: /**
065: * Replace current instruction contained in this handle.
066: * Old instruction is disposed using Instruction.dispose().
067: */
068: public void setInstruction(Instruction i) { // Overridden in BranchHandle
069: if (i == null) {
070: throw new ClassGenException("Assigning null to handle");
071: }
072: if ((this .getClass() != BranchHandle.class)
073: && (i instanceof BranchInstruction)) {
074: throw new ClassGenException("Assigning branch instruction "
075: + i + " to plain handle");
076: }
077: if (instruction != null) {
078: instruction.dispose();
079: }
080: instruction = i;
081: }
082:
083: /**
084: * Temporarily swap the current instruction, without disturbing
085: * anything. Meant to be used by a debugger, implementing
086: * breakpoints. Current instruction is returned.
087: */
088: public Instruction swapInstruction(Instruction i) {
089: Instruction oldInstruction = instruction;
090: instruction = i;
091: return oldInstruction;
092: }
093:
094: /*private*/protected InstructionHandle(Instruction i) {
095: setInstruction(i);
096: }
097:
098: private static InstructionHandle ih_list = null; // List of reusable handles
099:
100: /** Factory method.
101: */
102: static final InstructionHandle getInstructionHandle(Instruction i) {
103: if (ih_list == null) {
104: return new InstructionHandle(i);
105: } else {
106: InstructionHandle ih = ih_list;
107: ih_list = ih.next;
108: ih.setInstruction(i);
109: return ih;
110: }
111: }
112:
113: /**
114: * Called by InstructionList.setPositions when setting the position for every
115: * instruction. In the presence of variable length instructions `setPositions()'
116: * performs multiple passes over the instruction list to calculate the
117: * correct (byte) positions and offsets by calling this function.
118: *
119: * @param offset additional offset caused by preceding (variable length) instructions
120: * @param max_offset the maximum offset that may be caused by these instructions
121: * @return additional offset caused by possible change of this instruction's length
122: */
123: protected int updatePosition(int offset, int max_offset) {
124: i_position += offset;
125: return 0;
126: }
127:
128: /** @return the position, i.e., the byte code offset of the contained
129: * instruction. This is accurate only after
130: * InstructionList.setPositions() has been called.
131: */
132: public int getPosition() {
133: return i_position;
134: }
135:
136: /** Set the position, i.e., the byte code offset of the contained
137: * instruction.
138: */
139: void setPosition(int pos) {
140: i_position = pos;
141: }
142:
143: /** Overridden in BranchHandle
144: */
145: protected void addHandle() {
146: next = ih_list;
147: ih_list = this ;
148: }
149:
150: /**
151: * Delete contents, i.e., remove user access and make handle reusable.
152: */
153: void dispose() {
154: next = prev = null;
155: instruction.dispose();
156: instruction = null;
157: i_position = -1;
158: attributes = null;
159: removeAllTargeters();
160: addHandle();
161: }
162:
163: /** Remove all targeters, if any.
164: */
165: public void removeAllTargeters() {
166: if (targeters != null) {
167: targeters.clear();
168: }
169: }
170:
171: /**
172: * Denote this handle isn't referenced anymore by t.
173: */
174: public void removeTargeter(InstructionTargeter t) {
175: if (targeters != null) {
176: targeters.remove(t);
177: }
178: }
179:
180: /**
181: * Denote this handle is being referenced by t.
182: */
183: public void addTargeter(InstructionTargeter t) {
184: if (targeters == null) {
185: targeters = new HashSet();
186: }
187: //if(!targeters.contains(t))
188: targeters.add(t);
189: }
190:
191: public boolean hasTargeters() {
192: return (targeters != null) && (targeters.size() > 0);
193: }
194:
195: /**
196: * @return null, if there are no targeters
197: */
198: public InstructionTargeter[] getTargeters() {
199: if (!hasTargeters()) {
200: return null;
201: }
202: InstructionTargeter[] t = new InstructionTargeter[targeters
203: .size()];
204: targeters.toArray(t);
205: return t;
206: }
207:
208: /** @return a (verbose) string representation of the contained instruction.
209: */
210: public String toString(boolean verbose) {
211: return Utility.format(i_position, 4, false, ' ') + ": "
212: + instruction.toString(verbose);
213: }
214:
215: /** @return a string representation of the contained instruction.
216: */
217: public String toString() {
218: return toString(true);
219: }
220:
221: /** Add an attribute to an instruction handle.
222: *
223: * @param key the key object to store/retrieve the attribute
224: * @param attr the attribute to associate with this handle
225: */
226: public void addAttribute(Object key, Object attr) {
227: if (attributes == null) {
228: attributes = new HashMap(3);
229: }
230: attributes.put(key, attr);
231: }
232:
233: /** Delete an attribute of an instruction handle.
234: *
235: * @param key the key object to retrieve the attribute
236: */
237: public void removeAttribute(Object key) {
238: if (attributes != null) {
239: attributes.remove(key);
240: }
241: }
242:
243: /** Get attribute of an instruction handle.
244: *
245: * @param key the key object to store/retrieve the attribute
246: */
247: public Object getAttribute(Object key) {
248: if (attributes != null) {
249: return attributes.get(key);
250: }
251: return null;
252: }
253:
254: /** @return all attributes associated with this handle
255: */
256: public Collection getAttributes() {
257: if (attributes == null) {
258: attributes = new HashMap(3);
259: }
260: return attributes.values();
261: }
262:
263: /** Convenience method, simply calls accept() on the contained instruction.
264: *
265: * @param v Visitor object
266: */
267: public void accept(Visitor v) {
268: instruction.accept(v);
269: }
270: }
|