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