--- old/src/java.base/share/classes/sun/reflect/generics/reflectiveObjects/TypeVariableImpl.java 2014-11-10 17:05:34.896227508 +0100 +++ new/src/java.base/share/classes/sun/reflect/generics/reflectiveObjects/TypeVariableImpl.java 2014-11-10 17:05:34.796229327 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2014, 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 @@ -51,17 +51,17 @@ */ public class TypeVariableImpl extends LazyReflectiveObjectGenerator implements TypeVariable { - D genericDeclaration; - private String name; + final D genericDeclaration; + private final String name; // upper bounds - evaluated lazily - private Type[] bounds; + private volatile Type[] bounds; // The ASTs for the bounds. We are required to evaluate the bounds - // lazily, so we store these at least until we are first asked + // lazily, so we store these until we are first asked // for the bounds. This also neatly solves the // problem with F-bounds - you can't reify them before the formal // is defined. - private FieldTypeSignature[] boundASTs; + private volatile FieldTypeSignature[] boundASTs; // constructor is private to enforce access through static factory private TypeVariableImpl(D decl, String n, FieldTypeSignature[] bs, @@ -72,17 +72,6 @@ boundASTs = bs; } - // Accessors - - // accessor for ASTs for bounds. Must not be called after - // bounds have been evaluated, because we might throw the ASTs - // away (but that is not thread-safe, is it?) - private FieldTypeSignature[] getBoundASTs() { - // check that bounds were not evaluated yet - assert(bounds == null); - return boundASTs; - } - /** * Factory method. * @param decl - the reflective object that declared the type variable @@ -133,22 +122,30 @@ */ public Type[] getBounds() { // lazily initialize bounds if necessary - if (bounds == null) { - FieldTypeSignature[] fts = getBoundASTs(); // get AST - // allocate result array; note that - // keeping ts and bounds separate helps with threads - Type[] ts = new Type[fts.length]; - // iterate over bound trees, reifying each in turn - for ( int j = 0; j < fts.length; j++) { - Reifier r = getReifier(); - fts[j].accept(r); - ts[j] = r.getResult(); + Type[] ts = bounds; + if (ts == null) { + FieldTypeSignature[] fts = boundASTs; // get AST + if (fts == null) { + // race with concurrent initialization + ts = bounds; + assert ts != null; + } else { + // allocate result array; note that + // keeping ts and bounds separate helps with threads + ts = new Type[fts.length]; + // iterate over bound trees, reifying each in turn + for ( int j = 0; j < fts.length; j++) { + Reifier r = getReifier(); + fts[j].accept(r); + ts[j] = r.getResult(); + } + // cache result + bounds = ts; + // throw away bound ASTs + boundASTs = null; } - // cache result - bounds = ts; - // could throw away bound ASTs here; thread safety? } - return bounds.clone(); // return cached bounds + return ts.clone(); // return cached bounds } /**