OpenJDK / portola / portola
changeset 20472:6adc9f6bb215
8019192: StringIndexOutOfBoundsException: in Class.getSimpleName()
Reviewed-by: jrose
author | twisti |
---|---|
date | Thu, 26 Sep 2013 18:20:25 -0700 |
parents | 0a9d1d17b076 |
children | 801df8862d7a |
files | jdk/src/share/classes/java/lang/invoke/MemberName.java |
diffstat | 1 files changed, 75 insertions(+), 42 deletions(-) [+] |
line wrap: on
line diff
--- 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); }