--- old/src/share/vm/oops/method.cpp 2016-09-28 08:26:22.000000000 -0700 +++ new/src/share/vm/oops/method.cpp 2016-09-28 08:26:22.000000000 -0700 @@ -1475,7 +1475,7 @@ Handle protection_domain(THREAD, m->method_holder()->protection_domain()); ResourceMark rm(THREAD); Symbol* signature = m->signature(); - for(SignatureStream ss(signature); !ss.is_done(); ss.next()) { + for (SignatureStream ss(signature); !ss.is_done(); ss.next()) { if (ss.is_object()) { Symbol* sym = ss.as_symbol(CHECK_(false)); Symbol* name = sym; @@ -1502,12 +1502,50 @@ Handle protection_domain(THREAD, m->method_holder()->protection_domain()); ResourceMark rm(THREAD); Symbol* signature = m->signature(); - for(SignatureStream ss(signature); !ss.is_done(); ss.next()) { + for (SignatureStream ss(signature); !ss.is_done(); ss.next()) { if (ss.type() == T_OBJECT) { Symbol* name = ss.as_symbol_or_null(); if (name == NULL) return true; Klass* klass = SystemDictionary::find(name, class_loader, protection_domain, THREAD); - if (klass == NULL) return true; + if (klass == NULL) { + if (IgnoreUnloadedAccessConstructorTags && + ss.is_last_arg() && m->is_synthetic() && + m->name() == vmSymbols::object_initializer_name()) { + // Check for the "accessConstructorTag" that javac generates merely for + // overload resolution purpose. Ignore it even if it's not loaded, because + // the only value that's going to be passed in is null - thus the class + // never needs to be loaded. + // + // e.g. For java.util.ArrayList.iterator(), + // return new Itr(); + // actually desugars to: + // return new ArrayList$Itr(this, /*accessConstructorTag*/ null); + // This is because Itr is a private inner class of ArrayList without + // an explicit constructor, so javac synthesizes a default constructor + // for it: + // private java.util.ArrayList$Itr(java.util.ArrayList); + // But this one follows the accessibility of the class so it's private. + // In order to allow the enclosing class to have access to Itr's + // constructor, javac synthesizes yet another bridge constructor with + // the right accessibility: + // java.util.ArrayList$Itr(java.util.ArrayList, java.util.ArrayList$1); + // These two constructors would have exactly the same name (), + // the same argument list (the enclosing 'this'), and the same return + // type (void). So, javac introduces a marker argument at the end of + // the bridge constructor's argument list, so that the two constructors + // can be well-formed overloads, and always pass a null to that argument. + // Thus, even when the class of this argument isn't loaded, it's still + // safe to compile/inline this bridge constructor. + // + // javac forms the name of the type 'accessConstructorTag' by appending + // "$1" to the name fo the top-level class. Using a simple heuristic + // here should be good enough. + if (name->ends_with("$1")) continue; // skip this marker arg + } else { + // this is a normal argument whose class isn't loaded + return true; + } + } } } return false;