src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java
changeset 54669 ad45b3802d4e
parent 52645 74cf02d5f6e2
child 55463 31bf7b93df5d
child 55532 6546a2ae6773
child 58678 9cf78a70fa4f
--- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java	Wed May 01 12:41:26 2019 -0400
+++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java	Wed May 01 12:31:29 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2019, 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
@@ -31,10 +31,7 @@
 import static jdk.vm.ci.hotspot.UnsafeAccess.UNSAFE;
 
 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;
 import java.util.HashMap;
@@ -56,9 +53,11 @@
 import jdk.vm.ci.meta.UnresolvedJavaType;
 
 /**
- * Implementation of {@link JavaType} for resolved non-primitive HotSpot classes.
+ * Implementation of {@link JavaType} for resolved non-primitive HotSpot classes. This class is not
+ * an {@link MetaspaceHandleObject} because it doesn't have to be scanned for GC. It's liveness is
+ * maintained by a reference to the {@link Class} instance.
  */
-final class HotSpotResolvedObjectTypeImpl extends HotSpotResolvedJavaType implements HotSpotResolvedObjectType, MetaspaceWrapperObject {
+final class HotSpotResolvedObjectTypeImpl extends HotSpotResolvedJavaType implements HotSpotResolvedObjectType, MetaspaceObject {
 
     private static final HotSpotResolvedJavaField[] NO_FIELDS = new HotSpotResolvedJavaField[0];
     private static final int METHOD_CACHE_ARRAY_CAPACITY = 8;
@@ -66,94 +65,71 @@
     /**
      * The Java class this type represents.
      */
-    private final Class<?> javaClass;
+    private final long metadataPointer;
+
     private HotSpotResolvedJavaMethodImpl[] methodCacheArray;
     private HashMap<Long, HotSpotResolvedJavaMethodImpl> methodCacheHashMap;
-    private HotSpotResolvedJavaField[] instanceFields;
-    private HotSpotResolvedObjectTypeImpl[] interfaces;
+    private volatile HotSpotResolvedJavaField[] instanceFields;
+    private volatile HotSpotResolvedObjectTypeImpl[] interfaces;
     private HotSpotConstantPool constantPool;
-    final HotSpotJVMCIMetaAccessContext context;
     private HotSpotResolvedObjectType arrayOfType;
+    private final JavaConstant mirror;
+    private HotSpotResolvedObjectTypeImpl superClass;
 
     /**
-     * Managed exclusively by {@link HotSpotResolvedJavaFieldImpl#toJava}.
+     * Managed exclusively by {@link HotSpotJDKReflection#getField}.
      */
     HashMap<HotSpotResolvedJavaFieldImpl, Field> reflectionFieldCache;
 
-    /**
-     * Gets the JVMCI mirror for a {@link Class} object.
-     *
-     * @return the {@link HotSpotResolvedJavaType} corresponding to {@code javaClass}
-     */
-    static HotSpotResolvedObjectTypeImpl fromObjectClass(Class<?> javaClass) {
-        return (HotSpotResolvedObjectTypeImpl) runtime().fromClass(javaClass);
+    static HotSpotResolvedObjectTypeImpl getJavaLangObject() {
+        return runtime().getJavaLangObject();
     }
 
     /**
-     * Gets the JVMCI mirror from a HotSpot type. Since {@link Class} is already a proxy for the
-     * underlying Klass*, it is used instead of the raw Klass*.
+     * Gets the JVMCI mirror from a HotSpot type.
      *
      * Called from the VM.
      *
-     * @param javaClass a {@link Class} object
+     * @param klassPointer a native pointer to the Klass*
      * @return the {@link ResolvedJavaType} corresponding to {@code javaClass}
      */
     @SuppressWarnings("unused")
-    private static HotSpotResolvedObjectTypeImpl fromMetaspace(Class<?> javaClass) {
-        return fromObjectClass(javaClass);
+    @VMEntryPoint
+    private static HotSpotResolvedObjectTypeImpl fromMetaspace(long klassPointer, String signature) {
+        return runtime().fromMetaspace(klassPointer, signature);
     }
 
     /**
      * Creates the JVMCI mirror for a {@link Class} object.
      *
-     * <p>
      * <b>NOTE</b>: Creating an instance of this class does not install the mirror for the
-     * {@link Class} type. Use {@link #fromObjectClass(Class)} or {@link #fromMetaspace(Class)}
-     * instead.
+     * {@link Class} type. {@link #fromMetaspace} instead.
      * </p>
      *
-     * @param javaClass the Class to create the mirror for
-     * @param context
+     * @param metadataPointer the Klass* to create the mirror for
      */
-    HotSpotResolvedObjectTypeImpl(Class<?> javaClass, HotSpotJVMCIMetaAccessContext context) {
-        super(getSignatureName(javaClass));
-        this.javaClass = javaClass;
-        this.context = context;
+    HotSpotResolvedObjectTypeImpl(long metadataPointer, String name) {
+        super(name);
+        this.metadataPointer = metadataPointer;
+        this.mirror = runtime().compilerToVm.getJavaMirror(this);
+        assert metadataPointer != 0;
         assert getName().charAt(0) != '[' || isArray() : getName();
     }
 
     /**
-     * Returns the name of this type as it would appear in a signature.
-     */
-    private static String getSignatureName(Class<?> javaClass) {
-        if (javaClass.isArray()) {
-            return javaClass.getName().replace('.', '/');
-        }
-        return "L" + javaClass.getName().replace('.', '/') + ";";
-    }
-
-    /**
      * Gets the metaspace Klass for this type.
      */
     long getMetaspaceKlass() {
-        if (HotSpotJVMCIRuntime.getHostWordKind() == JavaKind.Long) {
-            return UNSAFE.getLong(javaClass, config().klassOffset);
+        long metaspacePointer = getMetaspacePointer();
+        if (metaspacePointer == 0) {
+            throw new NullPointerException("Klass* is null");
         }
-        return UNSAFE.getInt(javaClass, config().klassOffset) & 0xFFFFFFFFL;
+        return metaspacePointer;
     }
 
     @Override
     public long getMetaspacePointer() {
-        return getMetaspaceKlass();
-    }
-
-    /**
-     * The Klass* for this object is kept alive by the direct reference to {@link #javaClass} so no
-     * extra work is required.
-     */
-    @Override
-    public boolean isRegistered() {
-        return true;
+        return metadataPointer;
     }
 
     @Override
@@ -173,15 +149,18 @@
     @Override
     public HotSpotResolvedObjectType getArrayClass() {
         if (arrayOfType == null) {
-            arrayOfType = fromObjectClass(Array.newInstance(mirror(), 0).getClass());
+            try {
+                arrayOfType = (HotSpotResolvedObjectType) runtime().compilerToVm.lookupType("[" + getName(), this, true);
+            } catch (ClassNotFoundException e) {
+                throw new JVMCIError(e);
+            }
         }
         return arrayOfType;
     }
 
     @Override
     public ResolvedJavaType getComponentType() {
-        Class<?> javaComponentType = mirror().getComponentType();
-        return javaComponentType == null ? null : runtime().fromClass(javaComponentType);
+        return runtime().compilerToVm.getComponentType(this);
     }
 
     @Override
@@ -279,19 +258,35 @@
 
     @Override
     public HotSpotResolvedObjectTypeImpl getSuperclass() {
-        Class<?> javaSuperclass = mirror().getSuperclass();
-        return javaSuperclass == null ? null : fromObjectClass(javaSuperclass);
+        if (isInterface()) {
+            return null;
+        }
+        HotSpotResolvedObjectTypeImpl javaLangObject = runtime().getJavaLangObject();
+        if (this.equals(javaLangObject)) {
+            return null;
+        }
+        if (isArray()) {
+            return javaLangObject;
+        }
+
+        // Cache result of native call
+        if (superClass == null) {
+            superClass = compilerToVM().getResolvedJavaType(this, config().superOffset, false);
+        }
+        return superClass;
     }
 
     @Override
     public HotSpotResolvedObjectTypeImpl[] getInterfaces() {
         if (interfaces == null) {
-            Class<?>[] javaInterfaces = mirror().getInterfaces();
-            HotSpotResolvedObjectTypeImpl[] result = new HotSpotResolvedObjectTypeImpl[javaInterfaces.length];
-            for (int i = 0; i < javaInterfaces.length; i++) {
-                result[i] = fromObjectClass(javaInterfaces[i]);
+            if (isArray()) {
+                HotSpotResolvedObjectTypeImpl[] types = new HotSpotResolvedObjectTypeImpl[2];
+                types[0] = runtime().getJavaLangCloneable();
+                types[1] = runtime().getJavaLangSerializable();
+                this.interfaces = types;
+            } else {
+                interfaces = runtime().compilerToVm.getInterfaces(this);
             }
-            interfaces = result;
         }
         return interfaces;
     }
@@ -308,13 +303,14 @@
     public HotSpotResolvedObjectTypeImpl getSupertype() {
         if (isArray()) {
             ResolvedJavaType componentType = getComponentType();
-            if (mirror() == Object[].class || componentType.isPrimitive()) {
-                return fromObjectClass(Object.class);
+            if (componentType.equals(getJavaLangObject()) || componentType.isPrimitive()) {
+                return getJavaLangObject();
             }
-            return (HotSpotResolvedObjectTypeImpl) ((HotSpotResolvedObjectTypeImpl) componentType).getSupertype().getArrayClass();
+            HotSpotResolvedObjectTypeImpl supertype = ((HotSpotResolvedObjectTypeImpl) componentType).getSupertype();
+            return (HotSpotResolvedObjectTypeImpl) supertype.getArrayClass();
         }
         if (isInterface()) {
-            return fromObjectClass(Object.class);
+            return getJavaLangObject();
         }
         return getSuperclass();
     }
@@ -354,18 +350,14 @@
     }
 
     @Override
-    public boolean isPrimitive() {
-        return false;
-    }
-
-    @Override
     public boolean isArray() {
-        return mirror().isArray();
+        return layoutHelper() < config().klassLayoutHelperNeutralValue;
     }
 
     @Override
     public boolean isEnum() {
-        return mirror().isEnum();
+        HotSpotResolvedObjectTypeImpl superclass = getSuperclass();
+        return superclass != null && superclass.equals(runtime().getJavaLangEnum());
     }
 
     @Override
@@ -392,7 +384,7 @@
     @Override
     public void initialize() {
         if (!isInitialized()) {
-            UNSAFE.ensureClassInitialized(mirror());
+            runtime().compilerToVm.ensureInitialized(this);
             assert isInitialized();
         }
     }
@@ -400,7 +392,7 @@
     @Override
     public boolean isInstance(JavaConstant obj) {
         if (obj.getJavaKind() == JavaKind.Object && !obj.isNull()) {
-            return mirror().isInstance(((HotSpotObjectConstantImpl) obj).object());
+            return runtime().reflection.isInstance(this, (HotSpotObjectConstantImpl) obj);
         }
         return false;
     }
@@ -412,7 +404,7 @@
 
     @Override
     public boolean isInterface() {
-        return mirror().isInterface();
+        return (getAccessFlags() & config().jvmAccInterface) != 0;
     }
 
     @Override
@@ -420,7 +412,7 @@
         assert other != null;
         if (other instanceof HotSpotResolvedObjectTypeImpl) {
             HotSpotResolvedObjectTypeImpl otherType = (HotSpotResolvedObjectTypeImpl) other;
-            return mirror().isAssignableFrom(otherType.mirror());
+            return runtime().reflection.isAssignableFrom(this, otherType);
         }
         return false;
     }
@@ -435,7 +427,7 @@
 
     @Override
     public boolean isJavaLangObject() {
-        return javaClass.equals(Object.class);
+        return getName().equals("Ljava/lang/Object;");
     }
 
     @Override
@@ -501,6 +493,7 @@
     @Override
     public int layoutHelper() {
         HotSpotVMConfig config = config();
+        assert getMetaspaceKlass() != 0 : getName();
         return UNSAFE.getInt(getMetaspaceKlass() + config.klassLayoutHelperOffset);
     }
 
@@ -509,7 +502,8 @@
         return compilerToVM().getFingerprint(getMetaspaceKlass());
     }
 
-    synchronized HotSpotResolvedJavaMethod createMethod(long metaspaceMethod) {
+    synchronized HotSpotResolvedJavaMethod createMethod(long metaspaceHandle) {
+        long metaspaceMethod = UNSAFE.getLong(metaspaceHandle);
         // Maintain cache as array.
         if (methodCacheArray == null) {
             methodCacheArray = new HotSpotResolvedJavaMethodImpl[METHOD_CACHE_ARRAY_CAPACITY];
@@ -519,11 +513,10 @@
         for (; i < methodCacheArray.length; ++i) {
             HotSpotResolvedJavaMethodImpl curMethod = methodCacheArray[i];
             if (curMethod == null) {
-                HotSpotResolvedJavaMethodImpl newMethod = new HotSpotResolvedJavaMethodImpl(this, metaspaceMethod);
+                HotSpotResolvedJavaMethodImpl newMethod = new HotSpotResolvedJavaMethodImpl(this, metaspaceHandle);
                 methodCacheArray[i] = newMethod;
-                context.add(newMethod);
                 return newMethod;
-            } else if (curMethod.getMetaspacePointer() == metaspaceMethod) {
+            } else if (curMethod.getMetaspaceMethod() == metaspaceMethod) {
                 return curMethod;
             }
         }
@@ -535,9 +528,8 @@
 
         HotSpotResolvedJavaMethodImpl lookupResult = methodCacheHashMap.get(metaspaceMethod);
         if (lookupResult == null) {
-            HotSpotResolvedJavaMethodImpl newMethod = new HotSpotResolvedJavaMethodImpl(this, metaspaceMethod);
+            HotSpotResolvedJavaMethodImpl newMethod = new HotSpotResolvedJavaMethodImpl(this, metaspaceHandle);
             methodCacheHashMap.put(metaspaceMethod, newMethod);
-            context.add(lookupResult);
             return newMethod;
         } else {
             return lookupResult;
@@ -599,6 +591,27 @@
         return new FieldInfo(index);
     }
 
+    public void ensureInitialized() {
+        runtime().compilerToVm.ensureInitialized(this);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == this) {
+            return true;
+        }
+        if (!(obj instanceof HotSpotResolvedObjectTypeImpl)) {
+            return false;
+        }
+        HotSpotResolvedObjectTypeImpl that = (HotSpotResolvedObjectTypeImpl) obj;
+        return getMetaspaceKlass() == that.getMetaspaceKlass();
+    }
+
+    @Override
+    JavaConstant getJavaMirror() {
+        return mirror;
+    }
+
     /**
      * This class represents the field information for one field contained in the fields array of an
      * {@code InstanceKlass}. The implementation is similar to the native {@code FieldInfo} class.
@@ -782,11 +795,6 @@
     }
 
     @Override
-    public Class<?> mirror() {
-        return javaClass;
-    }
-
-    @Override
     public String getSourceFileName() {
         HotSpotVMConfig config = config();
         final int sourceFileNameIndex = UNSAFE.getChar(getMetaspaceKlass() + config.instanceKlassSourceFileNameIndexOffset);
@@ -798,17 +806,17 @@
 
     @Override
     public Annotation[] getAnnotations() {
-        return mirror().getAnnotations();
+        return runtime().reflection.getAnnotations(this);
     }
 
     @Override
     public Annotation[] getDeclaredAnnotations() {
-        return mirror().getDeclaredAnnotations();
+        return runtime().reflection.getDeclaredAnnotations(this);
     }
 
     @Override
     public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
-        return mirror().getAnnotation(annotationClass);
+        return runtime().reflection.getAnnotation(this, annotationClass);
     }
 
     /**
@@ -828,12 +836,17 @@
         }
         if (elementType.getName().startsWith("Ljava/")) {
             // Classes in a java.* package can only be defined by the
-            // boot or platform class loader.
+            // boot class loader. This is enforced by ClassLoader.preDefineClass()
+            assert hasSameClassLoader(runtime().getJavaLangObject());
             return true;
         }
-        ClassLoader thisCl = mirror().getClassLoader();
-        ClassLoader accessingClassCl = ((HotSpotResolvedObjectTypeImpl) accessingClass).mirror().getClassLoader();
-        return thisCl == accessingClassCl;
+        HotSpotResolvedObjectTypeImpl otherMirror = ((HotSpotResolvedObjectTypeImpl) accessingClass);
+        return hasSameClassLoader(otherMirror);
+    }
+
+    private boolean hasSameClassLoader(HotSpotResolvedObjectTypeImpl otherMirror) {
+        return UnsafeAccess.UNSAFE.getAddress(getMetaspaceKlass() + config().classLoaderDataOffset) == UnsafeAccess.UNSAFE.getAddress(
+                        otherMirror.getMetaspaceKlass() + config().classLoaderDataOffset);
     }
 
     @Override
@@ -887,16 +900,15 @@
 
     private static ResolvedJavaField findFieldWithOffset(long offset, JavaKind expectedEntryKind, ResolvedJavaField[] declaredFields) {
         for (ResolvedJavaField field : declaredFields) {
-            HotSpotResolvedJavaField resolvedField = (HotSpotResolvedJavaField) field;
-            long resolvedFieldOffset = resolvedField.getOffset();
+            long resolvedFieldOffset = field.getOffset();
             // @formatter:off
-            if (ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN  &&
-                            expectedEntryKind.isPrimitive() &&
-                            !expectedEntryKind.equals(JavaKind.Void) &&
-                            resolvedField.getJavaKind().isPrimitive()) {
+            if (ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN &&
+                    expectedEntryKind.isPrimitive() &&
+                    !expectedEntryKind.equals(JavaKind.Void) &&
+                    field.getJavaKind().isPrimitive()) {
                 resolvedFieldOffset +=
-                                resolvedField.getJavaKind().getByteCount() -
-                                Math.min(resolvedField.getJavaKind().getByteCount(), 4 + expectedEntryKind.getByteCount());
+                        field.getJavaKind().getByteCount() -
+                                Math.min(field.getJavaKind().getByteCount(), 4 + expectedEntryKind.getByteCount());
             }
             if (resolvedFieldOffset == offset) {
                 return field;
@@ -908,40 +920,27 @@
 
     @Override
     public boolean isLocal() {
-        return mirror().isLocalClass();
+        return runtime().reflection.isLocalClass(this);
     }
 
     @Override
     public boolean isMember() {
-        return mirror().isMemberClass();
+        return runtime().reflection.isMemberClass(this);
     }
 
     @Override
-    public HotSpotResolvedObjectTypeImpl getEnclosingType() {
-        final Class<?> encl = mirror().getEnclosingClass();
-        return encl == null ? null : fromObjectClass(encl);
+    public HotSpotResolvedObjectType getEnclosingType() {
+        return runtime().reflection.getEnclosingClass(this);
     }
 
     @Override
     public ResolvedJavaMethod[] getDeclaredConstructors() {
-        Constructor<?>[] constructors = mirror().getDeclaredConstructors();
-        ResolvedJavaMethod[] result = new ResolvedJavaMethod[constructors.length];
-        for (int i = 0; i < constructors.length; i++) {
-            result[i] = runtime().getHostJVMCIBackend().getMetaAccess().lookupJavaMethod(constructors[i]);
-            assert result[i].isConstructor();
-        }
-        return result;
+        return runtime().compilerToVm.getDeclaredConstructors(this);
     }
 
     @Override
     public ResolvedJavaMethod[] getDeclaredMethods() {
-        Method[] methods = mirror().getDeclaredMethods();
-        ResolvedJavaMethod[] result = new ResolvedJavaMethod[methods.length];
-        for (int i = 0; i < methods.length; i++) {
-            result[i] = runtime().getHostJVMCIBackend().getMetaAccess().lookupJavaMethod(methods[i]);
-            assert !result[i].isConstructor();
-        }
-        return result;
+        return runtime().compilerToVm.getDeclaredMethods(this);
     }
 
     @Override
@@ -986,6 +985,10 @@
         return (getAccessFlags() & config().jvmAccIsCloneableFast) != 0;
     }
 
+    JavaConstant readFieldValue(HotSpotResolvedJavaField field, boolean isVolatile) {
+        return runtime().reflection.readFieldValue(this, field, isVolatile);
+    }
+
     private int getMiscFlags() {
         return UNSAFE.getInt(getMetaspaceKlass() + config().instanceKlassMiscFlagsOffset);
     }