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