1 /* 2 * Copyright (c) 2016, 2018, 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 org.graalvm.compiler.replacements.classfile; 26 27 import static org.graalvm.compiler.replacements.classfile.Classfile.skipFully; 28 import static org.graalvm.compiler.replacements.classfile.ClassfileConstant.CONSTANT_Class; 29 30 import java.io.DataInputStream; 31 import java.io.IOException; 32 33 import org.graalvm.compiler.debug.GraalError; 34 import org.graalvm.compiler.replacements.classfile.ClassfileConstant.ClassRef; 35 import org.graalvm.compiler.replacements.classfile.ClassfileConstant.ExecutableRef; 36 import org.graalvm.compiler.replacements.classfile.ClassfileConstant.FieldRef; 37 import org.graalvm.compiler.replacements.classfile.ClassfileConstant.Primitive; 38 import org.graalvm.compiler.replacements.classfile.ClassfileConstant.Utf8; 39 40 import jdk.vm.ci.meta.ConstantPool; 41 import jdk.vm.ci.meta.JavaConstant; 42 import jdk.vm.ci.meta.JavaField; 43 import jdk.vm.ci.meta.JavaMethod; 44 import jdk.vm.ci.meta.JavaType; 45 import jdk.vm.ci.meta.ResolvedJavaMethod; 46 import jdk.vm.ci.meta.Signature; 47 48 class ClassfileConstantPool implements ConstantPool, ConstantPoolPatch { 49 50 final ClassfileConstant[] entries; 51 final ClassfileBytecodeProvider context; 52 53 public static class Bytecodes { 54 public static final int LDC = 18; // 0x12 55 public static final int LDC_W = 19; // 0x13 56 public static final int LDC2_W = 20; // 0x14 57 public static final int GETSTATIC = 178; // 0xB2 58 public static final int PUTSTATIC = 179; // 0xB3 59 public static final int GETFIELD = 180; // 0xB4 60 public static final int PUTFIELD = 181; // 0xB5 61 public static final int INVOKEVIRTUAL = 182; // 0xB6 62 public static final int INVOKESPECIAL = 183; // 0xB7 63 public static final int INVOKESTATIC = 184; // 0xB8 64 public static final int INVOKEINTERFACE = 185; // 0xB9 65 public static final int INVOKEDYNAMIC = 186; // 0xBA 66 public static final int NEW = 187; // 0xBB 67 public static final int NEWARRAY = 188; // 0xBC 68 public static final int ANEWARRAY = 189; // 0xBD 69 public static final int CHECKCAST = 192; // 0xC0 70 public static final int INSTANCEOF = 193; // 0xC1 71 public static final int MULTIANEWARRAY = 197; // 0xC5 72 } 73 ClassfileConstantPool(DataInputStream stream, ClassfileBytecodeProvider context)74 ClassfileConstantPool(DataInputStream stream, ClassfileBytecodeProvider context) throws IOException { 75 this.context = context; 76 byte tag; 77 78 int count = stream.readUnsignedShort(); 79 entries = new ClassfileConstant[count]; 80 81 int i = 1; 82 while (i < count) { 83 entries[i] = readConstant(stream); 84 tag = entries[i].tag; 85 86 if ((tag == ClassfileConstant.CONSTANT_Double) || (tag == ClassfileConstant.CONSTANT_Long)) { 87 i += 2; 88 } else { 89 i += 1; 90 } 91 } 92 } 93 readConstant(DataInputStream stream)94 static final ClassfileConstant readConstant(DataInputStream stream) throws IOException { 95 byte tag = stream.readByte(); 96 97 switch (tag) { 98 case ClassfileConstant.CONSTANT_Class: 99 return new ClassfileConstant.ClassRef(stream); 100 case ClassfileConstant.CONSTANT_Fieldref: 101 return new ClassfileConstant.FieldRef(stream); 102 case ClassfileConstant.CONSTANT_Methodref: 103 return new ClassfileConstant.MethodRef(stream); 104 case ClassfileConstant.CONSTANT_InterfaceMethodref: 105 return new ClassfileConstant.InterfaceMethodRef(stream); 106 case ClassfileConstant.CONSTANT_String: 107 return new ClassfileConstant.StringRef(stream); 108 case ClassfileConstant.CONSTANT_Integer: 109 return new ClassfileConstant.Primitive(tag, JavaConstant.forInt(stream.readInt())); 110 case ClassfileConstant.CONSTANT_Float: 111 return new ClassfileConstant.Primitive(tag, JavaConstant.forFloat(stream.readFloat())); 112 case ClassfileConstant.CONSTANT_Long: 113 return new ClassfileConstant.Primitive(tag, JavaConstant.forLong(stream.readLong())); 114 case ClassfileConstant.CONSTANT_Double: 115 return new ClassfileConstant.Primitive(tag, JavaConstant.forDouble(stream.readDouble())); 116 case ClassfileConstant.CONSTANT_NameAndType: 117 return new ClassfileConstant.NameAndType(stream); 118 case ClassfileConstant.CONSTANT_Utf8: 119 return new ClassfileConstant.Utf8(stream.readUTF()); 120 case ClassfileConstant.CONSTANT_MethodHandle: 121 skipFully(stream, 3); // reference_kind, reference_index 122 return new ClassfileConstant.Unsupported(tag, "CONSTANT_MethodHandle_info"); 123 case ClassfileConstant.CONSTANT_MethodType: 124 skipFully(stream, 2); // descriptor_index 125 return new ClassfileConstant.Unsupported(tag, "CONSTANT_MethodType_info"); 126 case ClassfileConstant.CONSTANT_Dynamic: 127 skipFully(stream, 4); // bootstrap_method_attr_index, name_and_type_index 128 return new ClassfileConstant.Unsupported(tag, "CONSTANT_Dynamic_info"); 129 case ClassfileConstant.CONSTANT_InvokeDynamic: 130 skipFully(stream, 4); // bootstrap_method_attr_index, name_and_type_index 131 return new ClassfileConstant.Unsupported(tag, "CONSTANT_InvokeDynamic_info"); 132 default: 133 throw new GraalError("Invalid constant pool tag: " + tag); 134 } 135 } 136 137 @Override length()138 public int length() { 139 return entries.length; 140 } 141 get(Class<T> c, int index)142 <T extends ClassfileConstant> T get(Class<T> c, int index) { 143 return c.cast(entries[index]); 144 } 145 146 @Override loadReferencedType(int index, int opcode)147 public void loadReferencedType(int index, int opcode) { 148 if (opcode == Bytecodes.INVOKEDYNAMIC) { 149 throw new GraalError("INVOKEDYNAMIC not supported by " + ClassfileBytecodeProvider.class.getSimpleName()); 150 } 151 entries[index].loadReferencedType(this, index, opcode); 152 } 153 154 @Override lookupField(int index, ResolvedJavaMethod method, int opcode)155 public JavaField lookupField(int index, ResolvedJavaMethod method, int opcode) { 156 return get(FieldRef.class, index).resolve(this, opcode); 157 } 158 159 @Override lookupMethod(int index, int opcode)160 public JavaMethod lookupMethod(int index, int opcode) { 161 if (opcode == Bytecodes.INVOKEDYNAMIC) { 162 throw new GraalError("INVOKEDYNAMIC not supported by" + ClassfileBytecodeProvider.class.getSimpleName()); 163 } 164 return get(ExecutableRef.class, index).resolve(this, opcode); 165 } 166 167 @Override lookupType(int index, int opcode)168 public JavaType lookupType(int index, int opcode) { 169 return get(ClassRef.class, index).resolve(this); 170 } 171 172 @Override lookupReferencedType(int index, int opcode)173 public JavaType lookupReferencedType(int index, int opcode) { 174 switch (opcode) { 175 case Bytecodes.CHECKCAST: 176 case Bytecodes.INSTANCEOF: 177 case Bytecodes.NEW: 178 case Bytecodes.ANEWARRAY: 179 case Bytecodes.MULTIANEWARRAY: 180 case Bytecodes.LDC: 181 case Bytecodes.LDC_W: 182 case Bytecodes.LDC2_W: 183 return get(ClassRef.class, index).resolve(this); 184 case Bytecodes.GETSTATIC: 185 case Bytecodes.PUTSTATIC: 186 case Bytecodes.GETFIELD: 187 case Bytecodes.PUTFIELD: 188 FieldRef f = get(FieldRef.class, index); 189 return get(ClassRef.class, f.classIndex).resolve(this); 190 case Bytecodes.INVOKEVIRTUAL: 191 case Bytecodes.INVOKESPECIAL: 192 case Bytecodes.INVOKESTATIC: 193 case Bytecodes.INVOKEINTERFACE: 194 ExecutableRef e = get(ExecutableRef.class, index); 195 return get(ClassRef.class, e.classIndex).resolve(this); 196 default: 197 throw GraalError.shouldNotReachHere("Unexpected opcode: " + opcode); 198 } 199 } 200 201 @Override lookupUtf8(int index)202 public String lookupUtf8(int index) { 203 return ((Utf8) entries[index]).value; 204 } 205 206 @Override lookupSignature(int index)207 public Signature lookupSignature(int index) { 208 throw GraalError.shouldNotReachHere(); 209 } 210 211 @Override lookupConstant(int index)212 public Object lookupConstant(int index) { 213 ClassfileConstant c = entries[index]; 214 if (c instanceof Primitive) { 215 Primitive p = (Primitive) c; 216 return p.value; 217 } 218 switch (c.tag) { 219 case CONSTANT_Class: 220 final int opcode = -1; 221 return lookupType(index, opcode); 222 case ClassfileConstant.CONSTANT_String: 223 return ((ClassfileConstant.StringRef) c).getValue(this); 224 default: 225 throw new GraalError("Unexpected constant pool tag %s", c.tag); 226 } 227 } 228 229 @Override lookupAppendix(int index, int opcode)230 public JavaConstant lookupAppendix(int index, int opcode) { 231 if (opcode == Bytecodes.INVOKEVIRTUAL) { 232 return null; 233 } 234 throw GraalError.shouldNotReachHere(); 235 } 236 } 237