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 }