001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *   https://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied.  See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 */
019package org.apache.bcel.classfile;
020
021import java.io.DataInput;
022import java.io.DataOutputStream;
023import java.io.IOException;
024
025import org.apache.bcel.Const;
026
027/**
028 * This class represents the type of a local variable or item on stack used in the StackMap entries.
029 *
030 * @see StackMapEntry
031 * @see StackMap
032 * @see Const
033 */
034public final class StackMapType implements Node, Cloneable {
035
036    /**
037     * Empty array constant.
038     */
039    public static final StackMapType[] EMPTY_ARRAY = {}; // BCELifier code generator writes calls to constructor translating null to EMPTY_ARRAY
040
041    private byte type;
042    private int index = -1; // Index to CONSTANT_Class or offset
043    private ConstantPool constantPool;
044
045    /**
046     * Constructs a StackMapType.
047     *
048     * @param type type tag as defined in the Constants interface.
049     * @param index index to constant pool, or byte code offset.
050     * @param constantPool The constant pool.
051     */
052    public StackMapType(final byte type, final int index, final ConstantPool constantPool) {
053        this.type = checkType(type);
054        this.index = index;
055        this.constantPool = constantPool;
056    }
057
058    /**
059     * Constructs object from file stream.
060     *
061     * @param file Input stream.
062     * @param constantPool The constant pool.
063     * @throws IOException Thrown if an I/O error occurs.
064     */
065    StackMapType(final DataInput file, final ConstantPool constantPool) throws IOException {
066        this(file.readByte(), -1, constantPool);
067        if (hasIndex()) {
068            this.index = file.readUnsignedShort();
069        }
070        this.constantPool = constantPool;
071    }
072
073    /**
074     * Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
075     * I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
076     *
077     * @param v Visitor object.
078     * @since 6.8.0
079     */
080    @Override
081    public void accept(final Visitor v) {
082        v.visitStackMapType(this);
083    }
084
085    private byte checkType(final byte type) {
086        if (type < Const.ITEM_Bogus || type > Const.ITEM_NewObject) {
087            throw new ClassFormatException("Illegal type for StackMapType: " + type);
088        }
089        return type;
090    }
091
092    /**
093     * Creates a deep copy of this object.
094     *
095     * @return deep copy of this object.
096     */
097    public StackMapType copy() {
098        try {
099            return (StackMapType) clone();
100        } catch (final CloneNotSupportedException e) {
101            // TODO should this throw?
102        }
103        return null;
104    }
105
106    /**
107     * Dumps type entries to file.
108     *
109     * @param file Output file stream.
110     * @throws IOException Thrown if an I/O error occurs.
111     */
112    public void dump(final DataOutputStream file) throws IOException {
113        file.writeByte(type);
114        if (hasIndex()) {
115            file.writeShort(getIndex());
116        }
117    }
118
119    /**
120     * Gets the class name of this StackMapType from the constant pool at index position.
121     *
122     * @return The fully qualified name of the class for this StackMapType.
123     * @since 6.8.0
124     */
125    public String getClassName() {
126        return constantPool.constantToString(index, Const.CONSTANT_Class);
127    }
128
129    /**
130     * Gets the constant pool.
131     *
132     * @return Constant pool used by this object.
133     */
134    public ConstantPool getConstantPool() {
135        return constantPool;
136    }
137
138    /**
139     * Gets the index.
140     *
141     * @return index to constant pool if type == ITEM_Object, or offset in byte code, if type == ITEM_NewObject, and -1
142     *         otherwise.
143     */
144    public int getIndex() {
145        return index;
146    }
147
148    /**
149     * Gets the type.
150     *
151     * @return The type.
152     */
153    public byte getType() {
154        return type;
155    }
156
157    /**
158     * Checks if this type has an index.
159     *
160     * @return true, if type is either ITEM_Object or ITEM_NewObject.
161     */
162    public boolean hasIndex() {
163        return type == Const.ITEM_Object || type == Const.ITEM_NewObject;
164    }
165
166    private String printIndex() {
167        if (type == Const.ITEM_Object) {
168            if (index < 0) {
169                return ", class=<unknown>";
170            }
171            return ", class=" + getClassName();
172        }
173        if (type == Const.ITEM_NewObject) {
174            return ", offset=" + index;
175        }
176        return "";
177    }
178
179    /**
180     * Sets the constant pool.
181     *
182     * @param constantPool Constant pool to be used for this object.
183     */
184    public void setConstantPool(final ConstantPool constantPool) {
185        this.constantPool = constantPool;
186    }
187
188    /**
189     * Sets the index.
190     *
191     * @param index The index.
192     */
193    public void setIndex(final int index) {
194        this.index = index;
195    }
196
197    /**
198     * Sets the type.
199     *
200     * @param type The type.
201     */
202    public void setType(final byte type) {
203        this.type = checkType(type);
204    }
205
206    /**
207     * @return String representation.
208     */
209    @Override
210    public String toString() {
211        return "(type=" + Const.getItemName(type) + printIndex() + ")";
212    }
213}