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 }