View Javadoc

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