8213907: [JVMCI] avoid Class.getDeclared* methods when converting JVMCI objects to reflection objects
authordnsimon
Wed, 21 Nov 2018 22:02:17 +0100
changeset 52645 74cf02d5f6e2
parent 52644 43efb4ca6d6c
child 52646 05e830a833f7
8213907: [JVMCI] avoid Class.getDeclared* methods when converting JVMCI objects to reflection objects Reviewed-by: kvn, never
src/hotspot/share/jvmci/jvmciCompilerToVM.cpp
src/hotspot/share/jvmci/jvmciCompilerToVM.hpp
src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp
src/hotspot/share/jvmci/vmStructs_jvmci.cpp
src/hotspot/share/oops/annotations.hpp
src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/CompilerToVM.java
src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java
src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java
src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java
src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfig.java
test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaField.java
test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java
--- a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp	Wed Nov 21 12:36:16 2018 -0800
+++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp	Wed Nov 21 22:02:17 2018 +0100
@@ -1498,6 +1498,38 @@
   }
 C2V_END
 
+C2V_VMENTRY(jobject, asReflectionExecutable, (JNIEnv* env, jobject, jobject jvmci_method))
+  methodHandle m = CompilerToVM::asMethod(jvmci_method);
+  oop executable;
+  if (m->is_initializer()) {
+    if (m->is_static_initializer()) {
+      THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(),
+        "Cannot create java.lang.reflect.Method for class initializer");
+    }
+    executable = Reflection::new_constructor(m, CHECK_NULL);
+  } else {
+    executable = Reflection::new_method(m, false, CHECK_NULL);
+  }
+  return JNIHandles::make_local(thread, executable);
+}
+
+C2V_VMENTRY(jobject, asReflectionField, (JNIEnv* env, jobject, jobject jvmci_type, jint index))
+  Klass* klass = CompilerToVM::asKlass(jvmci_type);
+  if (!klass->is_instance_klass()) {
+    THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(),
+        err_msg("Expected non-primitive type, got %s", klass->external_name()));
+  }
+  InstanceKlass* iklass = InstanceKlass::cast(klass);
+  Array<u2>* fields = iklass->fields();
+  if (index < 0 || index > fields->length()) {
+    THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(),
+        err_msg("Field index %d out of bounds for %s", index, klass->external_name()));
+  }
+  fieldDescriptor fd(iklass, index);
+  oop reflected = Reflection::new_field(&fd, CHECK_NULL);
+  return JNIHandles::make_local(env, reflected);
+}
+
 #define CC (char*)  /*cast a literal from (const char*)*/
 #define FN_PTR(f) CAST_FROM_FN_PTR(void*, &(c2v_ ## f))
 
@@ -1519,6 +1551,8 @@
 #define HS_METADATA             "Ljdk/vm/ci/hotspot/HotSpotMetaData;"
 #define HS_STACK_FRAME_REF      "Ljdk/vm/ci/hotspot/HotSpotStackFrameReference;"
 #define HS_SPECULATION_LOG      "Ljdk/vm/ci/hotspot/HotSpotSpeculationLog;"
+#define REFLECTION_EXECUTABLE   "Ljava/lang/reflect/Executable;"
+#define REFLECTION_FIELD        "Ljava/lang/reflect/Field;"
 #define METASPACE_METHOD_DATA   "J"
 
 JNINativeMethod CompilerToVM::methods[] = {
@@ -1586,6 +1620,8 @@
   {CC "interpreterFrameSize",                         CC "(" BYTECODE_FRAME ")I",                                                           FN_PTR(interpreterFrameSize)},
   {CC "compileToBytecode",                            CC "(" OBJECT ")V",                                                                   FN_PTR(compileToBytecode)},
   {CC "getFlagValue",                                 CC "(" STRING ")" OBJECT,                                                             FN_PTR(getFlagValue)},
+  {CC "asReflectionExecutable",                       CC "(" HS_RESOLVED_METHOD ")" REFLECTION_EXECUTABLE,                                  FN_PTR(asReflectionExecutable)},
+  {CC "asReflectionField",                            CC "(" HS_RESOLVED_KLASS "I)" REFLECTION_FIELD,                                       FN_PTR(asReflectionField)},
 };
 
 int CompilerToVM::methods_count() {
--- a/src/hotspot/share/jvmci/jvmciCompilerToVM.hpp	Wed Nov 21 12:36:16 2018 -0800
+++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.hpp	Wed Nov 21 22:02:17 2018 +0100
@@ -91,6 +91,7 @@
     static HeapWord** _heap_end_addr;
     static HeapWord* volatile* _heap_top_addr;
     static int _max_oop_map_stack_offset;
+    static int _fields_annotations_base_offset;
 
     static jbyte* cardtable_start_address;
     static int cardtable_shift;
@@ -101,7 +102,6 @@
     static int sizeof_ExceptionTableElement;
     static int sizeof_LocalVariableTableElement;
     static int sizeof_ConstantPool;
-    static int sizeof_SymbolPointer;
     static int sizeof_narrowKlass;
     static int sizeof_arrayOopDesc;
     static int sizeof_BasicLock;
--- a/src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp	Wed Nov 21 12:36:16 2018 -0800
+++ b/src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp	Wed Nov 21 22:02:17 2018 +0100
@@ -61,6 +61,7 @@
 HeapWord** CompilerToVM::Data::_heap_end_addr;
 HeapWord* volatile* CompilerToVM::Data::_heap_top_addr;
 int CompilerToVM::Data::_max_oop_map_stack_offset;
+int CompilerToVM::Data::_fields_annotations_base_offset;
 
 jbyte* CompilerToVM::Data::cardtable_start_address;
 int CompilerToVM::Data::cardtable_shift;
@@ -71,7 +72,6 @@
 int CompilerToVM::Data::sizeof_ExceptionTableElement = sizeof(ExceptionTableElement);
 int CompilerToVM::Data::sizeof_LocalVariableTableElement = sizeof(LocalVariableTableElement);
 int CompilerToVM::Data::sizeof_ConstantPool = sizeof(ConstantPool);
-int CompilerToVM::Data::sizeof_SymbolPointer = sizeof(Symbol*);
 int CompilerToVM::Data::sizeof_narrowKlass = sizeof(narrowKlass);
 int CompilerToVM::Data::sizeof_arrayOopDesc = sizeof(arrayOopDesc);
 int CompilerToVM::Data::sizeof_BasicLock = sizeof(BasicLock);
@@ -122,6 +122,8 @@
   symbol_init = (address) vmSymbols::object_initializer_name();
   symbol_clinit = (address) vmSymbols::class_initializer_name();
 
+  _fields_annotations_base_offset = Array<AnnotationArray*>::base_offset_in_bytes();
+
   BarrierSet* bs = BarrierSet::barrier_set();
   if (bs->is_a(BarrierSet::CardTableBarrierSet)) {
     jbyte* base = ci_card_table_address();
--- a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp	Wed Nov 21 12:36:16 2018 -0800
+++ b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp	Wed Nov 21 22:02:17 2018 +0100
@@ -76,6 +76,7 @@
   static_field(CompilerToVM::Data,             _heap_top_addr,                         HeapWord* volatile*)                          \
                                                                                                                                      \
   static_field(CompilerToVM::Data,             _max_oop_map_stack_offset,              int)                                          \
+  static_field(CompilerToVM::Data,             _fields_annotations_base_offset,        int)                                          \
                                                                                                                                      \
   static_field(CompilerToVM::Data,             cardtable_start_address,                jbyte*)                                       \
   static_field(CompilerToVM::Data,             cardtable_shift,                        int)                                          \
@@ -86,7 +87,6 @@
   static_field(CompilerToVM::Data,             sizeof_ExceptionTableElement,           int)                                          \
   static_field(CompilerToVM::Data,             sizeof_LocalVariableTableElement,       int)                                          \
   static_field(CompilerToVM::Data,             sizeof_ConstantPool,                    int)                                          \
-  static_field(CompilerToVM::Data,             sizeof_SymbolPointer,                   int)                                          \
   static_field(CompilerToVM::Data,             sizeof_narrowKlass,                     int)                                          \
   static_field(CompilerToVM::Data,             sizeof_arrayOopDesc,                    int)                                          \
   static_field(CompilerToVM::Data,             sizeof_BasicLock,                       int)                                          \
@@ -104,6 +104,8 @@
                                                                                                                                      \
   static_field(Abstract_VM_Version,            _features,                              uint64_t)                                     \
                                                                                                                                      \
+  nonstatic_field(Annotations,                 _fields_annotations,                    Array<AnnotationArray*>*)                     \
+                                                                                                                                     \
   nonstatic_field(Array<int>,                  _length,                                int)                                          \
   unchecked_nonstatic_field(Array<u1>,         _data,                                  sizeof(u1))                                   \
   unchecked_nonstatic_field(Array<u2>,         _data,                                  sizeof(u2))                                   \
@@ -164,6 +166,7 @@
   nonstatic_field(InstanceKlass,               _source_file_name_index,                       u2)                                    \
   nonstatic_field(InstanceKlass,               _init_state,                                   u1)                                    \
   nonstatic_field(InstanceKlass,               _misc_flags,                                   u2)                                    \
+  nonstatic_field(InstanceKlass,               _annotations,                                  Annotations*)                          \
                                                                                                                                      \
   volatile_nonstatic_field(JavaFrameAnchor,    _last_Java_sp,                                 intptr_t*)                             \
   volatile_nonstatic_field(JavaFrameAnchor,    _last_Java_pc,                                 address)                               \
@@ -462,6 +465,8 @@
   declare_constant(ConstMethod::_has_linenumber_table)                    \
   declare_constant(ConstMethod::_has_localvariable_table)                 \
   declare_constant(ConstMethod::_has_exception_table)                     \
+  declare_constant(ConstMethod::_has_method_annotations)                  \
+  declare_constant(ConstMethod::_has_parameter_annotations)               \
                                                                           \
   declare_constant(CounterData::count_off)                                \
                                                                           \
--- a/src/hotspot/share/oops/annotations.hpp	Wed Nov 21 12:36:16 2018 -0800
+++ b/src/hotspot/share/oops/annotations.hpp	Wed Nov 21 22:02:17 2018 +0100
@@ -42,6 +42,8 @@
 // a type_annotation instance.
 
 class Annotations: public MetaspaceObj {
+ friend class JVMCIVMStructs;
+
   // If you add a new field that points to any metaspace object, you
   // must add this field to Annotations::metaspace_pointers_do().
 
--- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/CompilerToVM.java	Wed Nov 21 12:36:16 2018 -0800
+++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/CompilerToVM.java	Wed Nov 21 22:02:17 2018 +0100
@@ -27,6 +27,7 @@
 import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.runtime;
 
 import java.lang.reflect.Executable;
+import java.lang.reflect.Field;
 
 import jdk.vm.ci.code.BytecodeFrame;
 import jdk.vm.ci.code.InstalledCode;
@@ -657,4 +658,17 @@
      * Gets the host class for {@code type}.
      */
     native HotSpotResolvedObjectTypeImpl getHostClass(HotSpotResolvedObjectTypeImpl type);
+
+    /**
+     * Gets a {@link Executable} corresponding to {@code method}.
+     */
+    native Executable asReflectionExecutable(HotSpotResolvedJavaMethodImpl method);
+
+    /**
+     * Gets a {@link Field} denoted by {@code holder} and {@code index}.
+     *
+     * @param holder the class in which the requested field is declared
+     * @param fieldIndex the {@code fieldDescriptor::index()} denoting the field
+     */
+    native Field asReflectionField(HotSpotResolvedObjectTypeImpl holder, int fieldIndex);
 }
--- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java	Wed Nov 21 12:36:16 2018 -0800
+++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java	Wed Nov 21 22:02:17 2018 +0100
@@ -22,11 +22,15 @@
  */
 package jdk.vm.ci.hotspot;
 
+import static jdk.internal.misc.Unsafe.ADDRESS_SIZE;
+import static jdk.vm.ci.hotspot.CompilerToVM.compilerToVM;
 import static jdk.vm.ci.hotspot.HotSpotModifiers.jvmFieldModifiers;
 import static jdk.vm.ci.hotspot.HotSpotVMConfig.config;
+import static jdk.vm.ci.hotspot.UnsafeAccess.UNSAFE;
 
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Field;
+import java.util.HashMap;
 
 import jdk.vm.ci.meta.JavaConstant;
 import jdk.vm.ci.meta.JavaType;
@@ -156,41 +160,65 @@
         return (config().jvmAccFieldStable & modifiers) != 0;
     }
 
+    private boolean hasAnnotations() {
+        if (!isInternal()) {
+            HotSpotVMConfig config = config();
+            final long metaspaceAnnotations = UNSAFE.getAddress(holder.getMetaspaceKlass() + config.instanceKlassAnnotationsOffset);
+            if (metaspaceAnnotations != 0) {
+                long fieldsAnnotations = UNSAFE.getAddress(metaspaceAnnotations + config.annotationsFieldAnnotationsOffset);
+                if (fieldsAnnotations != 0) {
+                    long fieldAnnotations = UNSAFE.getAddress(fieldsAnnotations + config.fieldsAnnotationsBaseOffset + (ADDRESS_SIZE * index));
+                    return fieldAnnotations != 0;
+                }
+            }
+        }
+        return false;
+    }
+
     @Override
     public Annotation[] getAnnotations() {
-        Field javaField = toJava();
-        if (javaField != null) {
-            return javaField.getAnnotations();
+        if (!hasAnnotations()) {
+            return new Annotation[0];
         }
-        return new Annotation[0];
+        return toJava().getAnnotations();
     }
 
     @Override
     public Annotation[] getDeclaredAnnotations() {
-        Field javaField = toJava();
-        if (javaField != null) {
-            return javaField.getDeclaredAnnotations();
+        if (!hasAnnotations()) {
+            return new Annotation[0];
         }
-        return new Annotation[0];
+        return toJava().getDeclaredAnnotations();
     }
 
     @Override
     public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
-        Field javaField = toJava();
-        if (javaField != null) {
-            return javaField.getAnnotation(annotationClass);
+        if (!hasAnnotations()) {
+            return null;
         }
-        return null;
+        return toJava().getAnnotation(annotationClass);
     }
 
+    /**
+     * Gets a {@link Field} object corresponding to this object. This method always returns the same
+     * {@link Field} object for a given {@link HotSpotResolvedJavaFieldImpl}. This ensures
+     * {@link #getDeclaredAnnotations()}, {@link #getAnnotations()} and
+     * {@link #getAnnotation(Class)} are stable with respect to the identity of the
+     * {@link Annotation} objects they return.
+     */
     private Field toJava() {
-        if (isInternal()) {
-            return null;
-        }
-        try {
-            return holder.mirror().getDeclaredField(getName());
-        } catch (NoSuchFieldException e) {
-            return null;
+        synchronized (holder) {
+            HashMap<HotSpotResolvedJavaFieldImpl, Field> cache = holder.reflectionFieldCache;
+            if (cache == null) {
+                cache = new HashMap<>();
+                holder.reflectionFieldCache = cache;
+            }
+            Field reflect = cache.get(this);
+            if (reflect == null) {
+                reflect = compilerToVM().asReflectionField(holder, index);
+                cache.put(this, reflect);
+            }
+            return reflect;
         }
     }
 }
--- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java	Wed Nov 21 12:36:16 2018 -0800
+++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java	Wed Nov 21 22:02:17 2018 +0100
@@ -33,10 +33,8 @@
 
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Executable;
-import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
 import java.lang.reflect.Type;
-import java.util.Arrays;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -54,7 +52,6 @@
 import jdk.vm.ci.meta.ProfilingInfo;
 import jdk.vm.ci.meta.ResolvedJavaMethod;
 import jdk.vm.ci.meta.ResolvedJavaType;
-import jdk.vm.ci.meta.Signature;
 import jdk.vm.ci.meta.SpeculationLog;
 import jdk.vm.ci.meta.TriState;
 
@@ -75,11 +72,9 @@
     private byte[] code;
 
     /**
-     * Cache for {@link #toJava()}. Set to {@link #signature} when resolving reflection object fails
-     * due to reflection filtering (see {@code Reflection.fieldFilterMap} and
-     * {@code Reflection.methodFilterMap}).
+     * Cache for {@link #toJava()}.
      */
-    private Object toJavaCache;
+    private volatile Executable toJavaCache;
 
     /**
      * Only 30% of {@link HotSpotResolvedJavaMethodImpl}s have their name accessed so compute it
@@ -492,12 +487,10 @@
 
     @Override
     public Parameter[] getParameters() {
-        Executable javaMethod = toJava();
-        if (javaMethod == null) {
-            return null;
+        if (signature.getParameterCount(false) == 0) {
+            return new ResolvedJavaMethod.Parameter[0];
         }
-
-        java.lang.reflect.Parameter[] javaParameters = javaMethod.getParameters();
+        java.lang.reflect.Parameter[] javaParameters = toJava().getParameters();
         Parameter[] res = new Parameter[javaParameters.length];
         for (int i = 0; i < res.length; i++) {
             java.lang.reflect.Parameter src = javaParameters[i];
@@ -509,32 +502,34 @@
 
     @Override
     public Annotation[][] getParameterAnnotations() {
-        Executable javaMethod = toJava();
-        return javaMethod == null ? new Annotation[signature.getParameterCount(false)][0] : javaMethod.getParameterAnnotations();
+        if ((getConstMethodFlags() & config().constMethodHasParameterAnnotations) == 0) {
+            return new Annotation[signature.getParameterCount(false)][0];
+        }
+        return toJava().getParameterAnnotations();
     }
 
     @Override
     public Annotation[] getAnnotations() {
-        Executable javaMethod = toJava();
-        if (javaMethod != null) {
-            return javaMethod.getAnnotations();
+        if ((getConstMethodFlags() & config().constMethodHasMethodAnnotations) == 0) {
+            return new Annotation[0];
         }
-        return new Annotation[0];
+        return toJava().getAnnotations();
     }
 
     @Override
     public Annotation[] getDeclaredAnnotations() {
-        Executable javaMethod = toJava();
-        if (javaMethod != null) {
-            return javaMethod.getDeclaredAnnotations();
+        if ((getConstMethodFlags() & config().constMethodHasMethodAnnotations) == 0) {
+            return new Annotation[0];
         }
-        return new Annotation[0];
+        return toJava().getDeclaredAnnotations();
     }
 
     @Override
     public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
-        Executable javaMethod = toJava();
-        return javaMethod == null ? null : javaMethod.getAnnotation(annotationClass);
+        if ((getConstMethodFlags() & config().constMethodHasMethodAnnotations) == 0) {
+            return null;
+        }
+        return toJava().getAnnotation(annotationClass);
     }
 
     @Override
@@ -561,60 +556,22 @@
 
     @Override
     public Type[] getGenericParameterTypes() {
-        Executable javaMethod = toJava();
-        return javaMethod == null ? null : javaMethod.getGenericParameterTypes();
-    }
-
-    public Class<?>[] signatureToTypes() {
-        Signature sig = getSignature();
-        int count = sig.getParameterCount(false);
-        Class<?>[] result = new Class<?>[count];
-        for (int i = 0; i < result.length; ++i) {
-            JavaType parameterType = sig.getParameterType(i, holder);
-            HotSpotResolvedJavaType resolvedParameterType = (HotSpotResolvedJavaType) parameterType.resolve(holder);
-            result[i] = resolvedParameterType.mirror();
+        if (isClassInitializer()) {
+            return new Type[0];
         }
-        return result;
-    }
-
-    private static Method searchMethods(Method[] methods, String name, Class<?> returnType, Class<?>[] parameterTypes) {
-        for (Method m : methods) {
-            if (m.getName().equals(name) && returnType.equals(m.getReturnType()) && Arrays.equals(m.getParameterTypes(), parameterTypes)) {
-                return m;
-            }
-        }
-        return null;
+        return toJava().getGenericParameterTypes();
     }
 
     private Executable toJava() {
-        if (toJavaCache != null) {
-            if (toJavaCache == signature) {
-                return null;
-            }
-            return (Executable) toJavaCache;
-        }
-        Class<?>[] parameterTypes = signatureToTypes();
-        Class<?> returnType = ((HotSpotResolvedJavaType) getSignature().getReturnType(holder).resolve(holder)).mirror();
-
-        Executable result;
-        if (isConstructor()) {
-            try {
-                result = holder.mirror().getDeclaredConstructor(parameterTypes);
-            } catch (NoSuchMethodException e) {
-                toJavaCache = signature;
-                return null;
-            }
-        } else {
-            // Do not use Method.getDeclaredMethod() as it can return a bridge method
-            // when this.isBridge() is false and vice versa.
-            result = searchMethods(holder.mirror().getDeclaredMethods(), getName(), returnType, parameterTypes);
-            if (result == null) {
-                toJavaCache = signature;
-                return null;
+        if (toJavaCache == null) {
+            assert !isClassInitializer() : this;
+            synchronized (this) {
+                if (toJavaCache == null) {
+                    toJavaCache = compilerToVM().asReflectionExecutable(this);
+                }
             }
         }
-        toJavaCache = result;
-        return result;
+        return toJavaCache;
     }
 
     @Override
--- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java	Wed Nov 21 12:36:16 2018 -0800
+++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java	Wed Nov 21 22:02:17 2018 +0100
@@ -33,6 +33,7 @@
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Array;
 import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
 import java.nio.ByteOrder;
@@ -75,6 +76,11 @@
     private HotSpotResolvedObjectType arrayOfType;
 
     /**
+     * Managed exclusively by {@link HotSpotResolvedJavaFieldImpl#toJava}.
+     */
+    HashMap<HotSpotResolvedJavaFieldImpl, Field> reflectionFieldCache;
+
+    /**
      * Gets the JVMCI mirror for a {@link Class} object.
      *
      * @return the {@link HotSpotResolvedJavaType} corresponding to {@code javaClass}
--- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfig.java	Wed Nov 21 12:36:16 2018 -0800
+++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfig.java	Wed Nov 21 22:02:17 2018 +0100
@@ -94,6 +94,7 @@
     final int instanceKlassInitStateOffset = getFieldOffset("InstanceKlass::_init_state", Integer.class, "u1");
     final int instanceKlassConstantsOffset = getFieldOffset("InstanceKlass::_constants", Integer.class, "ConstantPool*");
     final int instanceKlassFieldsOffset = getFieldOffset("InstanceKlass::_fields", Integer.class, "Array<u2>*");
+    final int instanceKlassAnnotationsOffset = getFieldOffset("InstanceKlass::_annotations", Integer.class, "Annotations*");
     final int instanceKlassMiscFlagsOffset = getFieldOffset("InstanceKlass::_misc_flags", Integer.class, "u2");
     final int klassVtableStartOffset = getFieldValue("CompilerToVM::Data::Klass_vtable_start_offset", Integer.class, "int");
     final int klassVtableLengthOffset = getFieldValue("CompilerToVM::Data::Klass_vtable_length_offset", Integer.class, "int");
@@ -102,6 +103,9 @@
     final int instanceKlassStateFullyInitialized = getConstant("InstanceKlass::fully_initialized", Integer.class);
     final int instanceKlassMiscIsUnsafeAnonymous = getConstant("InstanceKlass::_misc_is_unsafe_anonymous", Integer.class);
 
+    final int annotationsFieldAnnotationsOffset = getFieldOffset("Annotations::_fields_annotations", Integer.class, "Array<AnnotationArray*>*");
+    final int fieldsAnnotationsBaseOffset = getFieldValue("CompilerToVM::Data::_fields_annotations_base_offset", Integer.class, "int");
+
     final int arrayU1LengthOffset = getFieldOffset("Array<int>::_length", Integer.class, "int");
     final int arrayU1DataOffset = getFieldOffset("Array<u1>::_data", Integer.class);
     final int arrayU2DataOffset = getFieldOffset("Array<u2>::_data", Integer.class);
@@ -195,6 +199,8 @@
 
     final int constMethodHasLineNumberTable = getConstant("ConstMethod::_has_linenumber_table", Integer.class);
     final int constMethodHasLocalVariableTable = getConstant("ConstMethod::_has_localvariable_table", Integer.class);
+    final int constMethodHasMethodAnnotations = getConstant("ConstMethod::_has_method_annotations", Integer.class);
+    final int constMethodHasParameterAnnotations = getConstant("ConstMethod::_has_parameter_annotations", Integer.class);
     final int constMethodHasExceptionTable = getConstant("ConstMethod::_has_exception_table", Integer.class);
 
     final int exceptionTableElementSize = getFieldValue("CompilerToVM::Data::sizeof_ExceptionTableElement", Integer.class, "int");
@@ -244,8 +250,6 @@
 
     final int heapWordSize = getConstant("HeapWordSize", Integer.class);
 
-    final int symbolPointerSize = getFieldValue("CompilerToVM::Data::sizeof_SymbolPointer", Integer.class, "int");
-
     final long vmSymbolsSymbols = getFieldAddress("vmSymbols::_symbols[0]", "Symbol*");
     final int vmSymbolsFirstSID = getConstant("vmSymbols::FIRST_SID", Integer.class);
     final int vmSymbolsSIDLimit = getConstant("vmSymbols::SID_LIMIT", Integer.class);
@@ -263,8 +267,7 @@
     String symbolAt(int index) {
         HotSpotJVMCIRuntime runtime = runtime();
         assert vmSymbolsFirstSID <= index && index < vmSymbolsSIDLimit : "index " + index + " is out of bounds";
-        assert symbolPointerSize == Unsafe.ADDRESS_SIZE : "the following address read is broken";
-        int offset = index * symbolPointerSize;
+        int offset = index * Unsafe.ADDRESS_SIZE;
         return runtime.getCompilerToVM().getSymbol(UNSAFE.getAddress(vmSymbolsSymbols + offset));
     }
 
--- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaField.java	Wed Nov 21 12:36:16 2018 -0800
+++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaField.java	Wed Nov 21 22:02:17 2018 +0100
@@ -142,16 +142,15 @@
             }
         }
     }
+
+    private static final String NON_EXISTENT_CLASS_NAME = "XXXXXXXXXXX";
+
     static class TestClassLoader extends ClassLoader {
 
         @Override
-        protected Class<?> findClass(final String name) {
+        protected Class<?> findClass(final String name) throws ClassNotFoundException {
             if (!name.equals(TypeWithUnresolvedFieldType.class.getName())) {
-                try {
-                    return super.findClass(name);
-                } catch (ClassNotFoundException e) {
-                    throw new AssertionError("unexpected: " + e);
-                }
+                return super.findClass(name);
             }
             // copy classfile to byte array
             byte[] classData = null;
@@ -176,7 +175,7 @@
             int index = -1;
 
             while ((index = indexOf(classData, index + 1, "PrintStream")) != -1) {
-                replace(classData, index, "XXXXXXXXXXX");
+                replace(classData, index, NON_EXISTENT_CLASS_NAME);
             }
 
             Class<?> c = defineClass(null, classData, 0, classData.length);
@@ -211,13 +210,14 @@
      * type of the field is not resolvable.
      */
     @Test
-    public void testGetType() {
+    public void testGetType() throws ClassNotFoundException {
         Class<?> c = new TestClassLoader().findClass(TypeWithUnresolvedFieldType.class.getName());
         ResolvedJavaType type = metaAccess.lookupJavaType(c);
         for (ResolvedJavaField field : type.getInstanceFields(false)) {
             assertTrue(field.getName().equals("fieldWithUnresolvableType"));
             field.getType();
             field.toString();
+            field.getAnnotations();
         }
     }
 }
--- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java	Wed Nov 21 12:36:16 2018 -0800
+++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java	Wed Nov 21 22:02:17 2018 +0100
@@ -855,17 +855,25 @@
 
     }
 
+    private static ResolvedJavaMethod getClassInitializer(Class<?> c) {
+        ResolvedJavaMethod clinit = metaAccess.lookupJavaType(c).getClassInitializer();
+        if (clinit != null) {
+            assertEquals(0, clinit.getAnnotations().length);
+            assertEquals(0, clinit.getDeclaredAnnotations().length);
+        }
+        return clinit;
+    }
+
     @Test
     public void getClassInitializerTest() {
-        assertNotNull(metaAccess.lookupJavaType(A.class).getClassInitializer());
-        assertNotNull(metaAccess.lookupJavaType(D.class).getClassInitializer());
-        assertNull(metaAccess.lookupJavaType(B.class).getClassInitializer());
-        assertNull(metaAccess.lookupJavaType(C.class).getClassInitializer());
-        assertNull(metaAccess.lookupJavaType(int.class).getClassInitializer());
-        assertNull(metaAccess.lookupJavaType(void.class).getClassInitializer());
+        assertNotNull(getClassInitializer(A.class));
+        assertNotNull(getClassInitializer(D.class));
+        assertNull(getClassInitializer(B.class));
+        assertNull(getClassInitializer(C.class));
+        assertNull(getClassInitializer(int.class));
+        assertNull(getClassInitializer(void.class));
         for (Class<?> c : classes) {
-            ResolvedJavaType type = metaAccess.lookupJavaType(c);
-            type.getClassInitializer();
+            getClassInitializer(c);
         }
     }