1 /* 2 * Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 * 23 */ 24 25 package sun.jvm.hotspot.interpreter; 26 27 import sun.jvm.hotspot.oops.*; 28 import sun.jvm.hotspot.runtime.*; 29 import sun.jvm.hotspot.utilities.*; 30 import sun.jvm.hotspot.ui.classbrowser.*; 31 32 public class BytecodeLoadConstant extends Bytecode { 33 BytecodeLoadConstant(Method method, int bci) { 34 super(method, bci); 35 } 36 37 public boolean hasCacheIndex() { 38 // normal ldc uses CP index, but fast_aldc uses swapped CP cache index 39 return code() >= Bytecodes.number_of_java_codes; 40 } 41 42 int rawIndex() { 43 if (javaCode() == Bytecodes._ldc) 44 return getIndexU1(); 45 else 46 return getIndexU2(code(), false); 47 } 48 49 public int poolIndex() { 50 int i = rawIndex(); 51 if (hasCacheIndex()) { 52 ConstantPoolCache cpCache = method().getConstants().getCache(); 53 return cpCache.getEntryAt(i).getConstantPoolIndex(); 54 } else { 55 return i; 56 } 57 } 58 59 public int cacheIndex() { 60 if (hasCacheIndex()) { 61 return rawIndex(); 62 } else { 63 return -1; // no cache index 64 } 65 } 66 67 public BasicType resultType() { 68 int index = poolIndex(); 69 ConstantTag tag = method().getConstants().getTagAt(index); 70 return tag.basicType(); 71 } 72 73 private Oop getCachedConstant() { 74 int i = cacheIndex(); 75 if (i >= 0) { 76 ConstantPoolCache cpCache = method().getConstants().getCache(); 77 return cpCache.getEntryAt(i).getF1(); 78 } 79 return null; 80 } 81 82 public void verify() { 83 if (Assert.ASSERTS_ENABLED) { 84 Assert.that(isValid(), "check load constant"); 85 } 86 } 87 88 public boolean isValid() { 89 method().printValueOn(System.out); 90 System.out.printf(" @ %d %d: %d", bci(), code(), hasCacheIndex() ? 1 : 0); 91 System.out.printf(" %d %d\n", poolIndex(), cacheIndex()); 92 93 int jcode = javaCode(); 94 boolean codeOk = jcode == Bytecodes._ldc || jcode == Bytecodes._ldc_w || 95 jcode == Bytecodes._ldc2_w; 96 if (! codeOk) return false; 97 98 ConstantTag ctag = method().getConstants().getTagAt(rawIndex()); 99 System.err.println(jcode + " " + ctag.value()); 100 if (jcode == Bytecodes._ldc2_w) { 101 // has to be double or long 102 return (ctag.isDouble() || ctag.isLong()) ? true: false; 103 } else { 104 // has to be int or float or String or Klass 105 return (ctag.isUnresolvedString() || ctag.isString() 106 || ctag.isUnresolvedKlass() || ctag.isKlass() 107 || ctag.isMethodHandle() || ctag.isMethodType() 108 || ctag.isMethod() 109 || ctag.isInt() || ctag.isFloat())? true: false; 110 } 111 } 112 113 public boolean isKlassConstant() { 114 int jcode = javaCode(); 115 if (jcode == Bytecodes._ldc2_w) { 116 return false; 117 } 118 119 ConstantTag ctag = method().getConstants().getTagAt(poolIndex()); 120 return ctag.isKlass() || ctag.isUnresolvedKlass(); 121 } 122 123 // return Symbol (if unresolved) or Klass (if resolved) 124 public Object getKlass() { 125 if (Assert.ASSERTS_ENABLED) { 126 Assert.that(isKlassConstant(), "not a klass literal"); 127 } 128 // tag change from 'unresolved' to 'klass' does not happen atomically. 129 // We just look at the object at the corresponding index and 130 // decide based on the oop type. 131 ConstantPool cpool = method().getConstants(); 132 int cpIndex = poolIndex(); 133 ConstantPool.CPSlot oop = cpool.getSlotAt(cpIndex); 134 if (oop.isOop()) { 135 return (Klass) oop.getOop(); 136 } else if (oop.isMetaData()) { 137 return oop.getSymbol(); 138 } else { 139 throw new RuntimeException("should not reach here"); 140 } 141 } 142 143 public static BytecodeLoadConstant at(Method method, int bci) { 144 BytecodeLoadConstant b = new BytecodeLoadConstant(method, bci); 145 if (Assert.ASSERTS_ENABLED) { 146 b.verify(); 147 } 148 return b; 149 } 150 151 /** Like at, but returns null if the BCI is not at ldc or ldc_w or ldc2_w */ 152 public static BytecodeLoadConstant atCheck(Method method, int bci) { 153 BytecodeLoadConstant b = new BytecodeLoadConstant(method, bci); 154 return (b.isValid() ? b : null); 155 } 156 157 public static BytecodeLoadConstant at(BytecodeStream bcs) { 158 return new BytecodeLoadConstant(bcs.method(), bcs.bci()); 159 } 160 161 public String getConstantValue() { 162 ConstantPool cpool = method().getConstants(); 163 int cpIndex = poolIndex(); 164 ConstantTag ctag = cpool.getTagAt(cpIndex); 165 if (ctag.isInt()) { 166 return "<int " + Integer.toString(cpool.getIntAt(cpIndex)) +">"; 167 } else if (ctag.isLong()) { 168 return "<long " + Long.toString(cpool.getLongAt(cpIndex)) + "L>"; 169 } else if (ctag.isFloat()) { 170 return "<float " + Float.toString(cpool.getFloatAt(cpIndex)) + "F>"; 171 } else if (ctag.isDouble()) { 172 return "<double " + Double.toString(cpool.getDoubleAt(cpIndex)) + "D>"; 173 } else if (ctag.isString() || ctag.isUnresolvedString()) { 174 // tag change from 'unresolved' to 'string' does not happen atomically. 175 // We just look at the object at the corresponding index and 176 // decide based on the oop type. 177 ConstantPool.CPSlot obj = cpool.getSlotAt(cpIndex); 178 if (obj.isMetaData()) { 179 Symbol sym = obj.getSymbol(); 180 return "<String \"" + sym.asString() + "\">"; 181 } else if (obj.isOop()) { 182 return "<String \"" + OopUtilities.stringOopToString(obj.getOop()) + "\">"; 183 } else { 184 throw new RuntimeException("should not reach here"); 185 } 186 } else if (ctag.isKlass() || ctag.isUnresolvedKlass()) { 187 // tag change from 'unresolved' to 'klass' does not happen atomically. 188 // We just look at the object at the corresponding index and 189 // decide based on the oop type. 190 ConstantPool.CPSlot obj = cpool.getSlotAt(cpIndex); 191 if (obj.isOop()) { 192 Klass k = (Klass) obj.getOop(); 193 return "<Class " + k.getName().asString() + "@" + k.getHandle() + ">"; 194 } else if (obj.isMetaData()) { 195 Symbol sym = obj.getSymbol(); 196 return "<Class " + sym.asString() + ">"; 197 } else { 198 throw new RuntimeException("should not reach here"); 199 } 200 } else if (ctag.isMethodHandle()) { 201 Oop x = getCachedConstant(); 202 int refidx = cpool.getMethodHandleIndexAt(cpIndex); 203 int refkind = cpool.getMethodHandleRefKindAt(cpIndex); 204 return "<MethodHandle kind=" + Integer.toString(refkind) + 205 " ref=" + Integer.toString(refidx) 206 + (x == null ? "" : " @" + x.getHandle()) + ">"; 207 } else if (ctag.isMethodType()) { 208 Oop x = getCachedConstant(); 209 int refidx = cpool.getMethodTypeIndexAt(cpIndex); 210 return "<MethodType " + cpool.getSymbolAt(refidx).asString() 211 + (x == null ? "" : " @" + x.getHandle()) + ">"; 212 } else { 213 if (Assert.ASSERTS_ENABLED) { 214 Assert.that(false, "invalid load constant type"); 215 } 216 return null; 217 } 218 } 219 220 public String toString() { 221 StringBuffer buf = new StringBuffer(); 222 buf.append(getJavaBytecodeName()); 223 buf.append(spaces); 224 buf.append('#'); 225 buf.append(Integer.toString(poolIndex())); 226 if (hasCacheIndex()) { 227 buf.append('('); 228 buf.append(Integer.toString(cacheIndex())); 229 buf.append(')'); 230 } 231 buf.append(spaces); 232 buf.append(getConstantValue()); 233 if (code() != javaCode()) { 234 buf.append(spaces); 235 buf.append('['); 236 buf.append(getBytecodeName()); 237 buf.append(']'); 238 } 239 return buf.toString(); 240 } 241 }