< prev index next >

src/share/vm/oops/method.cpp

Print this page

        

@@ -1473,11 +1473,11 @@
   bool sig_is_loaded = true;
   Handle class_loader(THREAD, m->method_holder()->class_loader());
   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;
       Klass* klass = SystemDictionary::resolve_or_null(name, class_loader,
                                              protection_domain, THREAD);

@@ -1500,16 +1500,54 @@
 bool Method::has_unloaded_classes_in_signature(methodHandle m, TRAPS) {
   Handle class_loader(THREAD, m->method_holder()->class_loader());
   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 (<init>),
+          // 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;
 }
 
< prev index next >