| /********************************************************************** |
| * This file is part of "Object Teams Runtime Environment"-Software |
| * |
| * Copyright 2012 GK Software AG |
| * |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Please visit http://www.eclipse.org/objectteams for updates and contact. |
| * |
| * Contributors: |
| * Stephan Herrmann - Initial API and implementation |
| * |
| * This file is based on class org.apache.bcel.classfile.ConstantPool |
| * originating from the Apache BCEL project which was provided under the |
| * Apache 2.0 license. Original Copyright from BCEL: |
| * |
| * Copyright 2000-2004 The Apache Software Foundation |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| */ |
| package org.apache.bcel.generic; |
| |
| import java.util.Collection; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.Map; |
| import java.util.Set; |
| import org.apache.bcel.classfile.Utility; |
| |
| /** |
| * Instances of this class give users a handle to the instructions contained in |
| * an InstructionList. Instruction objects may be used more than once within a |
| * list, this is useful because it saves memory and may be much faster. |
| * |
| * Within an InstructionList an InstructionHandle object is wrapped |
| * around all instructions, i.e., it implements a cell in a |
| * doubly-linked list. From the outside only the next and the |
| * previous instruction (handle) are accessible. One |
| * can traverse the list via an Enumeration returned by |
| * InstructionList.elements(). |
| * |
| * @version $Id: InstructionHandle.java 386056 2006-03-15 11:31:56Z tcurdt $ |
| * @author <A HREF="mailto:m.dahm@gmx.de">M. Dahm</A> |
| * @see Instruction |
| * @see BranchHandle |
| * @see InstructionList |
| */ |
| public class InstructionHandle implements java.io.Serializable { |
| |
| InstructionHandle next, prev; // Will be set from the outside |
| Instruction instruction; |
| protected int i_position = -1; // byte code offset of instruction |
| private Set targeters; |
| private Map attributes; |
| |
| |
| public final InstructionHandle getNext() { |
| return next; |
| } |
| |
| |
| public final InstructionHandle getPrev() { |
| return prev; |
| } |
| |
| |
| public final Instruction getInstruction() { |
| return instruction; |
| } |
| |
| |
| /** |
| * Replace current instruction contained in this handle. |
| * Old instruction is disposed using Instruction.dispose(). |
| */ |
| public void setInstruction( Instruction i ) { // Overridden in BranchHandle |
| if (i == null) { |
| throw new ClassGenException("Assigning null to handle"); |
| } |
| if ((this.getClass() != BranchHandle.class) && (i instanceof BranchInstruction)) { |
| throw new ClassGenException("Assigning branch instruction " + i + " to plain handle"); |
| } |
| if (instruction != null) { |
| instruction.dispose(); |
| } |
| instruction = i; |
| } |
| |
| |
| /** |
| * Temporarily swap the current instruction, without disturbing |
| * anything. Meant to be used by a debugger, implementing |
| * breakpoints. Current instruction is returned. |
| */ |
| public Instruction swapInstruction( Instruction i ) { |
| Instruction oldInstruction = instruction; |
| instruction = i; |
| return oldInstruction; |
| } |
| |
| |
| /*private*/protected InstructionHandle(Instruction i) { |
| setInstruction(i); |
| } |
| |
| /** Factory method. |
| */ |
| static final InstructionHandle getInstructionHandle( Instruction i ) { |
| return new InstructionHandle(i); |
| } |
| |
| |
| /** |
| * Called by InstructionList.setPositions when setting the position for every |
| * instruction. In the presence of variable length instructions `setPositions()' |
| * performs multiple passes over the instruction list to calculate the |
| * correct (byte) positions and offsets by calling this function. |
| * |
| * @param offset additional offset caused by preceding (variable length) instructions |
| * @param max_offset the maximum offset that may be caused by these instructions |
| * @return additional offset caused by possible change of this instruction's length |
| */ |
| protected int updatePosition( int offset, int max_offset ) { |
| i_position += offset; |
| return 0; |
| } |
| |
| |
| /** @return the position, i.e., the byte code offset of the contained |
| * instruction. This is accurate only after |
| * InstructionList.setPositions() has been called. |
| */ |
| public int getPosition() { |
| return i_position; |
| } |
| |
| |
| /** Set the position, i.e., the byte code offset of the contained |
| * instruction. |
| */ |
| void setPosition( int pos ) { |
| i_position = pos; |
| } |
| |
| /** |
| * Delete contents, i.e., remove user access and make handle reusable. |
| */ |
| void dispose() { |
| next = prev = null; |
| instruction.dispose(); |
| instruction = null; |
| i_position = -1; |
| attributes = null; |
| removeAllTargeters(); |
| } |
| |
| |
| /** Remove all targeters, if any. |
| */ |
| public void removeAllTargeters() { |
| if (targeters != null) { |
| targeters.clear(); |
| } |
| } |
| |
| |
| /** |
| * Denote this handle isn't referenced anymore by t. |
| */ |
| public void removeTargeter( InstructionTargeter t ) { |
| if (targeters != null) { |
| targeters.remove(t); |
| } |
| } |
| |
| |
| /** |
| * Denote this handle is being referenced by t. |
| */ |
| public void addTargeter( InstructionTargeter t ) { |
| if (targeters == null) { |
| targeters = new HashSet(); |
| } |
| //if(!targeters.contains(t)) |
| targeters.add(t); |
| } |
| |
| |
| public boolean hasTargeters() { |
| return (targeters != null) && (targeters.size() > 0); |
| } |
| |
| |
| /** |
| * @return null, if there are no targeters |
| */ |
| public InstructionTargeter[] getTargeters() { |
| if (!hasTargeters()) { |
| return null; |
| } |
| InstructionTargeter[] t = new InstructionTargeter[targeters.size()]; |
| targeters.toArray(t); |
| return t; |
| } |
| |
| |
| /** @return a (verbose) string representation of the contained instruction. |
| */ |
| public String toString( boolean verbose ) { |
| return Utility.format(i_position, 4, false, ' ') + ": " + instruction.toString(verbose); |
| } |
| |
| |
| /** @return a string representation of the contained instruction. |
| */ |
| public String toString() { |
| return toString(true); |
| } |
| |
| |
| /** Add an attribute to an instruction handle. |
| * |
| * @param key the key object to store/retrieve the attribute |
| * @param attr the attribute to associate with this handle |
| */ |
| public void addAttribute( Object key, Object attr ) { |
| if (attributes == null) { |
| attributes = new HashMap(3); |
| } |
| attributes.put(key, attr); |
| } |
| |
| |
| /** Delete an attribute of an instruction handle. |
| * |
| * @param key the key object to retrieve the attribute |
| */ |
| public void removeAttribute( Object key ) { |
| if (attributes != null) { |
| attributes.remove(key); |
| } |
| } |
| |
| |
| /** Get attribute of an instruction handle. |
| * |
| * @param key the key object to store/retrieve the attribute |
| */ |
| public Object getAttribute( Object key ) { |
| if (attributes != null) { |
| return attributes.get(key); |
| } |
| return null; |
| } |
| |
| |
| /** @return all attributes associated with this handle |
| */ |
| public Collection getAttributes() { |
| if (attributes == null) { |
| attributes = new HashMap(3); |
| } |
| return attributes.values(); |
| } |
| |
| |
| /** Convenience method, simply calls accept() on the contained instruction. |
| * |
| * @param v Visitor object |
| */ |
| public void accept( Visitor v ) { |
| instruction.accept(v); |
| } |
| } |