8019192: StringIndexOutOfBoundsException: in Class.getSimpleName()
authortwisti
Thu, 26 Sep 2013 18:20:25 -0700
changeset 20472 6adc9f6bb215
parent 20199 0a9d1d17b076
child 20473 801df8862d7a
8019192: StringIndexOutOfBoundsException: in Class.getSimpleName() Reviewed-by: jrose
jdk/src/share/classes/java/lang/invoke/MemberName.java
--- a/jdk/src/share/classes/java/lang/invoke/MemberName.java	Thu Sep 26 11:13:34 2013 -0700
+++ b/jdk/src/share/classes/java/lang/invoke/MemberName.java	Thu Sep 26 18:20:25 2013 -0700
@@ -70,13 +70,13 @@
  * @author jrose
  */
 /*non-public*/ final class MemberName implements Member, Cloneable {
-    private Class<?>   clazz;       // class in which the method is defined
-    private String     name;        // may be null if not yet materialized
-    private Object     type;        // may be null if not yet materialized
-    private int        flags;       // modifier bits; see reflect.Modifier
+    private Class<?> clazz;       // class in which the method is defined
+    private String   name;        // may be null if not yet materialized
+    private Object   type;        // may be null if not yet materialized
+    private int      flags;       // modifier bits; see reflect.Modifier
     //@Injected JVM_Method* vmtarget;
     //@Injected int         vmindex;
-    private Object     resolution;  // if null, this guy is resolved
+    private Object   resolution;  // if null, this guy is resolved
 
     /** Return the declaring class of this member.
      *  In the case of a bare name and type, the declaring class will be null.
@@ -98,7 +98,9 @@
     public String getName() {
         if (name == null) {
             expandFromVM();
-            if (name == null)  return null;
+            if (name == null) {
+                return null;
+            }
         }
         return name;
     }
@@ -119,28 +121,39 @@
     public MethodType getMethodType() {
         if (type == null) {
             expandFromVM();
-            if (type == null)  return null;
+            if (type == null) {
+                return null;
+            }
+        }
+        if (!isInvocable()) {
+            throw newIllegalArgumentException("not invocable, no method type");
         }
-        if (!isInvocable())
-            throw newIllegalArgumentException("not invocable, no method type");
-        if (type instanceof MethodType) {
-            return (MethodType) type;
+
+        {
+            // Get a snapshot of type which doesn't get changed by racing threads.
+            final Object type = this.type;
+            if (type instanceof MethodType) {
+                return (MethodType) type;
+            }
         }
-        if (type instanceof String) {
-            String sig = (String) type;
-            MethodType res = MethodType.fromMethodDescriptorString(sig, getClassLoader());
-            this.type = res;
-            return res;
+
+        // type is not a MethodType yet.  Convert it thread-safely.
+        synchronized (this) {
+            if (type instanceof String) {
+                String sig = (String) type;
+                MethodType res = MethodType.fromMethodDescriptorString(sig, getClassLoader());
+                type = res;
+            } else if (type instanceof Object[]) {
+                Object[] typeInfo = (Object[]) type;
+                Class<?>[] ptypes = (Class<?>[]) typeInfo[1];
+                Class<?> rtype = (Class<?>) typeInfo[0];
+                MethodType res = MethodType.methodType(rtype, ptypes);
+                type = res;
+            }
+            // Make sure type is a MethodType for racing threads.
+            assert type instanceof MethodType : "bad method type " + type;
         }
-        if (type instanceof Object[]) {
-            Object[] typeInfo = (Object[]) type;
-            Class<?>[] ptypes = (Class<?>[]) typeInfo[1];
-            Class<?> rtype = (Class<?>) typeInfo[0];
-            MethodType res = MethodType.methodType(rtype, ptypes);
-            this.type = res;
-            return res;
-        }
-        throw new InternalError("bad method type "+type);
+        return (MethodType) type;
     }
 
     /** Return the actual type under which this method or constructor must be invoked.
@@ -173,21 +186,34 @@
     public Class<?> getFieldType() {
         if (type == null) {
             expandFromVM();
-            if (type == null)  return null;
+            if (type == null) {
+                return null;
+            }
         }
-        if (isInvocable())
+        if (isInvocable()) {
             throw newIllegalArgumentException("not a field or nested class, no simple type");
-        if (type instanceof Class<?>) {
-            return (Class<?>) type;
         }
-        if (type instanceof String) {
-            String sig = (String) type;
-            MethodType mtype = MethodType.fromMethodDescriptorString("()"+sig, getClassLoader());
-            Class<?> res = mtype.returnType();
-            this.type = res;
-            return res;
+
+        {
+            // Get a snapshot of type which doesn't get changed by racing threads.
+            final Object type = this.type;
+            if (type instanceof Class<?>) {
+                return (Class<?>) type;
+            }
         }
-        throw new InternalError("bad field type "+type);
+
+        // type is not a Class yet.  Convert it thread-safely.
+        synchronized (this) {
+            if (type instanceof String) {
+                String sig = (String) type;
+                MethodType mtype = MethodType.fromMethodDescriptorString("()"+sig, getClassLoader());
+                Class<?> res = mtype.returnType();
+                type = res;
+            }
+            // Make sure type is a Class for racing threads.
+            assert type instanceof Class<?> : "bad field type " + type;
+        }
+        return (Class<?>) type;
     }
 
     /** Utility method to produce either the method type or field type of this member. */
@@ -201,10 +227,10 @@
     public String getSignature() {
         if (type == null) {
             expandFromVM();
-            if (type == null)  return null;
+            if (type == null) {
+                return null;
+            }
         }
-        if (type instanceof String)
-            return (String) type;
         if (isInvocable())
             return BytecodeDescriptor.unparse(getMethodType());
         else
@@ -463,10 +489,17 @@
         //assert(referenceKindIsConsistent());  // do this after resolution
     }
 
+    /**
+     * Calls down to the VM to fill in the fields.  This method is
+     * synchronized to avoid racing calls.
+     */
     private void expandFromVM() {
-        if (!isResolved())  return;
-        if (type instanceof Object[])
-            type = null;  // don't saddle JVM w/ typeInfo
+        if (type != null) {
+            return;
+        }
+        if (!isResolved()) {
+            return;
+        }
         MethodHandleNatives.expand(this);
     }