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 public static final StackMapType[] EMPTY_ARRAY = {}; // BCELifier code generator writes calls to constructor translating null to EMPTY_ARRAY 037 038 private byte type; 039 private int index = -1; // Index to CONSTANT_Class or offset 040 private ConstantPool constantPool; 041 042 /** 043 * @param type type tag as defined in the Constants interface. 044 * @param index index to constant pool, or byte code offset. 045 */ 046 public StackMapType(final byte type, final int index, final ConstantPool constantPool) { 047 this.type = checkType(type); 048 this.index = index; 049 this.constantPool = constantPool; 050 } 051 052 /** 053 * Constructs object from file stream. 054 * 055 * @param file Input stream. 056 * @throws IOException if an I/O error occurs. 057 */ 058 StackMapType(final DataInput file, final ConstantPool constantPool) throws IOException { 059 this(file.readByte(), -1, constantPool); 060 if (hasIndex()) { 061 this.index = file.readUnsignedShort(); 062 } 063 this.constantPool = constantPool; 064 } 065 066 /** 067 * Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class. 068 * I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects. 069 * 070 * @param v Visitor object. 071 * @since 6.8.0 072 */ 073 @Override 074 public void accept(final Visitor v) { 075 v.visitStackMapType(this); 076 } 077 078 private byte checkType(final byte type) { 079 if (type < Const.ITEM_Bogus || type > Const.ITEM_NewObject) { 080 throw new ClassFormatException("Illegal type for StackMapType: " + type); 081 } 082 return type; 083 } 084 085 /** 086 * @return deep copy of this object. 087 */ 088 public StackMapType copy() { 089 try { 090 return (StackMapType) clone(); 091 } catch (final CloneNotSupportedException e) { 092 // TODO should this throw? 093 } 094 return null; 095 } 096 097 /** 098 * Dumps type entries to file. 099 * 100 * @param file Output file stream. 101 * @throws IOException if an I/O error occurs. 102 */ 103 public void dump(final DataOutputStream file) throws IOException { 104 file.writeByte(type); 105 if (hasIndex()) { 106 file.writeShort(getIndex()); 107 } 108 } 109 110 /** 111 * Gets the class name of this StackMapType from the constant pool at index position. 112 * 113 * @return the fully qualified name of the class for this StackMapType. 114 * @since 6.8.0 115 */ 116 public String getClassName() { 117 return constantPool.constantToString(index, Const.CONSTANT_Class); 118 } 119 120 /** 121 * @return Constant pool used by this object. 122 */ 123 public ConstantPool getConstantPool() { 124 return constantPool; 125 } 126 127 /** 128 * @return index to constant pool if type == ITEM_Object, or offset in byte code, if type == ITEM_NewObject, and -1 129 * otherwise 130 */ 131 public int getIndex() { 132 return index; 133 } 134 135 public byte getType() { 136 return type; 137 } 138 139 /** 140 * @return true, if type is either ITEM_Object or ITEM_NewObject. 141 */ 142 public boolean hasIndex() { 143 return type == Const.ITEM_Object || type == Const.ITEM_NewObject; 144 } 145 146 private String printIndex() { 147 if (type == Const.ITEM_Object) { 148 if (index < 0) { 149 return ", class=<unknown>"; 150 } 151 return ", class=" + getClassName(); 152 } 153 if (type == Const.ITEM_NewObject) { 154 return ", offset=" + index; 155 } 156 return ""; 157 } 158 159 /** 160 * @param constantPool Constant pool to be used for this object. 161 */ 162 public void setConstantPool(final ConstantPool constantPool) { 163 this.constantPool = constantPool; 164 } 165 166 public void setIndex(final int index) { 167 this.index = index; 168 } 169 170 public void setType(final byte type) { 171 this.type = checkType(type); 172 } 173 174 /** 175 * @return String representation. 176 */ 177 @Override 178 public String toString() { 179 return "(type=" + Const.getItemName(type) + printIndex() + ")"; 180 } 181}