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 * Dump 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 * @return the fully qualified name of the class for this StackMapType. 113 * @since 6.8.0 114 */ 115 public String getClassName() { 116 return constantPool.constantToString(index, Const.CONSTANT_Class); 117 } 118 119 /** 120 * @return Constant pool used by this object. 121 */ 122 public ConstantPool getConstantPool() { 123 return constantPool; 124 } 125 126 /** 127 * @return index to constant pool if type == ITEM_Object, or offset in byte code, if type == ITEM_NewObject, and -1 128 * otherwise 129 */ 130 public int getIndex() { 131 return index; 132 } 133 134 public byte getType() { 135 return type; 136 } 137 138 /** 139 * @return true, if type is either ITEM_Object or ITEM_NewObject 140 */ 141 public boolean hasIndex() { 142 return type == Const.ITEM_Object || type == Const.ITEM_NewObject; 143 } 144 145 private String printIndex() { 146 if (type == Const.ITEM_Object) { 147 if (index < 0) { 148 return ", class=<unknown>"; 149 } 150 return ", class=" + getClassName(); 151 } 152 if (type == Const.ITEM_NewObject) { 153 return ", offset=" + index; 154 } 155 return ""; 156 } 157 158 /** 159 * @param constantPool Constant pool to be used for this object. 160 */ 161 public void setConstantPool(final ConstantPool constantPool) { 162 this.constantPool = constantPool; 163 } 164 165 public void setIndex(final int index) { 166 this.index = index; 167 } 168 169 public void setType(final byte type) { 170 this.type = checkType(type); 171 } 172 173 /** 174 * @return String representation 175 */ 176 @Override 177 public String toString() { 178 return "(type=" + Const.getItemName(type) + printIndex() + ")"; 179 } 180}