| /* |
| * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| package org.graalvm.compiler.replacements.classfile; |
| |
| import static org.graalvm.compiler.replacements.classfile.Classfile.skipFully; |
| import static org.graalvm.compiler.replacements.classfile.ClassfileConstant.CONSTANT_Class; |
| |
| import java.io.DataInputStream; |
| import java.io.IOException; |
| |
| import org.graalvm.compiler.debug.GraalError; |
| import org.graalvm.compiler.replacements.classfile.ClassfileConstant.ClassRef; |
| import org.graalvm.compiler.replacements.classfile.ClassfileConstant.ExecutableRef; |
| import org.graalvm.compiler.replacements.classfile.ClassfileConstant.FieldRef; |
| import org.graalvm.compiler.replacements.classfile.ClassfileConstant.Primitive; |
| import org.graalvm.compiler.replacements.classfile.ClassfileConstant.Utf8; |
| |
| import jdk.vm.ci.meta.ConstantPool; |
| import jdk.vm.ci.meta.JavaConstant; |
| import jdk.vm.ci.meta.JavaField; |
| import jdk.vm.ci.meta.JavaMethod; |
| import jdk.vm.ci.meta.JavaType; |
| import jdk.vm.ci.meta.ResolvedJavaMethod; |
| import jdk.vm.ci.meta.Signature; |
| |
| class ClassfileConstantPool implements ConstantPool { |
| |
| final ClassfileConstant[] entries; |
| final ClassfileBytecodeProvider context; |
| |
| public static class Bytecodes { |
| public static final int GETSTATIC = 178; // 0xB2 |
| public static final int PUTSTATIC = 179; // 0xB3 |
| public static final int GETFIELD = 180; // 0xB4 |
| public static final int PUTFIELD = 181; // 0xB5 |
| public static final int INVOKEVIRTUAL = 182; // 0xB6 |
| public static final int INVOKESPECIAL = 183; // 0xB7 |
| public static final int INVOKESTATIC = 184; // 0xB8 |
| public static final int INVOKEINTERFACE = 185; // 0xB9 |
| public static final int INVOKEDYNAMIC = 186; // 0xBA |
| } |
| |
| ClassfileConstantPool(DataInputStream stream, ClassfileBytecodeProvider context) throws IOException { |
| this.context = context; |
| byte tag; |
| |
| int count = stream.readUnsignedShort(); |
| entries = new ClassfileConstant[count]; |
| |
| int i = 1; |
| while (i < count) { |
| entries[i] = readConstant(stream); |
| tag = entries[i].tag; |
| |
| if ((tag == ClassfileConstant.CONSTANT_Double) || (tag == ClassfileConstant.CONSTANT_Long)) { |
| i += 2; |
| } else { |
| i += 1; |
| } |
| } |
| } |
| |
| static final ClassfileConstant readConstant(DataInputStream stream) throws IOException { |
| byte tag = stream.readByte(); |
| |
| switch (tag) { |
| case ClassfileConstant.CONSTANT_Class: |
| return new ClassfileConstant.ClassRef(stream); |
| case ClassfileConstant.CONSTANT_Fieldref: |
| return new ClassfileConstant.FieldRef(stream); |
| case ClassfileConstant.CONSTANT_Methodref: |
| return new ClassfileConstant.MethodRef(stream); |
| case ClassfileConstant.CONSTANT_InterfaceMethodref: |
| return new ClassfileConstant.InterfaceMethodRef(stream); |
| case ClassfileConstant.CONSTANT_String: |
| return new ClassfileConstant.StringRef(stream); |
| case ClassfileConstant.CONSTANT_Integer: |
| return new ClassfileConstant.Primitive(tag, JavaConstant.forInt(stream.readInt())); |
| case ClassfileConstant.CONSTANT_Float: |
| return new ClassfileConstant.Primitive(tag, JavaConstant.forFloat(stream.readFloat())); |
| case ClassfileConstant.CONSTANT_Long: |
| return new ClassfileConstant.Primitive(tag, JavaConstant.forLong(stream.readLong())); |
| case ClassfileConstant.CONSTANT_Double: |
| return new ClassfileConstant.Primitive(tag, JavaConstant.forDouble(stream.readDouble())); |
| case ClassfileConstant.CONSTANT_NameAndType: |
| return new ClassfileConstant.NameAndType(stream); |
| case ClassfileConstant.CONSTANT_Utf8: |
| return new ClassfileConstant.Utf8(stream.readUTF()); |
| case ClassfileConstant.CONSTANT_MethodHandle: |
| skipFully(stream, 3); // reference_kind, reference_index |
| return new ClassfileConstant.Unsupported(tag, "CONSTANT_MethodHandle_info"); |
| case ClassfileConstant.CONSTANT_MethodType: |
| skipFully(stream, 2); // descriptor_index |
| return new ClassfileConstant.Unsupported(tag, "CONSTANT_MethodType_info"); |
| case ClassfileConstant.CONSTANT_InvokeDynamic: |
| skipFully(stream, 4); // bootstrap_method_attr_index, name_and_type_index |
| return new ClassfileConstant.Unsupported(tag, "CONSTANT_InvokeDynamic_info"); |
| default: |
| throw new GraalError("Invalid constant pool tag: " + tag); |
| } |
| } |
| |
| @Override |
| public int length() { |
| return entries.length; |
| } |
| |
| <T extends ClassfileConstant> T get(Class<T> c, int index) { |
| return c.cast(entries[index]); |
| } |
| |
| @Override |
| public void loadReferencedType(int index, int opcode) { |
| if (opcode == Bytecodes.INVOKEDYNAMIC) { |
| throw new GraalError("INVOKEDYNAMIC not supported by " + ClassfileBytecodeProvider.class.getSimpleName()); |
| } |
| entries[index].loadReferencedType(this, index, opcode); |
| } |
| |
| @Override |
| public JavaField lookupField(int index, ResolvedJavaMethod method, int opcode) { |
| return get(FieldRef.class, index).resolve(this, opcode); |
| } |
| |
| @Override |
| public JavaMethod lookupMethod(int index, int opcode) { |
| if (opcode == Bytecodes.INVOKEDYNAMIC) { |
| throw new GraalError("INVOKEDYNAMIC not supported by" + ClassfileBytecodeProvider.class.getSimpleName()); |
| } |
| return get(ExecutableRef.class, index).resolve(this, opcode); |
| } |
| |
| @Override |
| public JavaType lookupType(int index, int opcode) { |
| return get(ClassRef.class, index).resolve(this); |
| } |
| |
| @Override |
| public String lookupUtf8(int index) { |
| return ((Utf8) entries[index]).value; |
| } |
| |
| @Override |
| public Signature lookupSignature(int index) { |
| throw GraalError.shouldNotReachHere(); |
| } |
| |
| @Override |
| public Object lookupConstant(int index) { |
| ClassfileConstant c = entries[index]; |
| if (c instanceof Primitive) { |
| Primitive p = (Primitive) c; |
| return p.value; |
| } |
| switch (c.tag) { |
| case CONSTANT_Class: |
| final int opcode = -1; |
| return lookupType(index, opcode); |
| case ClassfileConstant.CONSTANT_String: |
| return ((ClassfileConstant.StringRef) c).getValue(this); |
| default: |
| throw new GraalError("Unexpected constant pool tag %s", c.tag); |
| } |
| } |
| |
| @Override |
| public JavaConstant lookupAppendix(int index, int opcode) { |
| if (opcode == Bytecodes.INVOKEVIRTUAL) { |
| return null; |
| } |
| throw GraalError.shouldNotReachHere(); |
| } |
| } |