6845426: non-static <clinit> method with no args is called during the class initialization process
authorkamg
Fri, 04 Mar 2011 14:40:46 -0500
changeset 8653 8797d788a4f1
parent 8652 209b2ce94ce5
child 8654 dd743af4c937
6845426: non-static <clinit> method with no args is called during the class initialization process Summary: Only call <clinit> with ACC_STATIC for classfiles with version > 50 Reviewed-by: acorn, dholmes, coleenp
hotspot/src/share/vm/classfile/classFileParser.cpp
hotspot/src/share/vm/oops/instanceKlass.cpp
hotspot/src/share/vm/oops/klassVtable.cpp
hotspot/src/share/vm/oops/methodOop.cpp
hotspot/src/share/vm/oops/methodOop.hpp
--- a/hotspot/src/share/vm/classfile/classFileParser.cpp	Thu Mar 03 19:53:03 2011 -0500
+++ b/hotspot/src/share/vm/classfile/classFileParser.cpp	Fri Mar 04 14:40:46 2011 -0500
@@ -1616,8 +1616,13 @@
 
   AccessFlags access_flags;
   if (name == vmSymbols::class_initializer_name()) {
-    // We ignore the access flags for a class initializer. (JVM Spec. p. 116)
-    flags = JVM_ACC_STATIC;
+    // We ignore the other access flags for a valid class initializer.
+    // (JVM Spec 2nd ed., chapter 4.6)
+    if (_major_version < 51) { // backward compatibility
+      flags = JVM_ACC_STATIC;
+    } else if ((flags & JVM_ACC_STATIC) == JVM_ACC_STATIC) {
+      flags &= JVM_ACC_STATIC | JVM_ACC_STRICT;
+    }
   } else {
     verify_legal_method_modifiers(flags, is_interface, name, CHECK_(nullHandle));
   }
--- a/hotspot/src/share/vm/oops/instanceKlass.cpp	Thu Mar 03 19:53:03 2011 -0500
+++ b/hotspot/src/share/vm/oops/instanceKlass.cpp	Fri Mar 04 14:40:46 2011 -0500
@@ -735,7 +735,12 @@
 static int call_class_initializer_impl_counter = 0;   // for debugging
 
 methodOop instanceKlass::class_initializer() {
-  return find_method(vmSymbols::class_initializer_name(), vmSymbols::void_method_signature());
+  methodOop clinit = find_method(
+      vmSymbols::class_initializer_name(), vmSymbols::void_method_signature());
+  if (clinit != NULL && clinit->has_valid_initializer_flags()) {
+    return clinit;
+  }
+  return NULL;
 }
 
 void instanceKlass::call_class_initializer_impl(instanceKlassHandle this_oop, TRAPS) {
--- a/hotspot/src/share/vm/oops/klassVtable.cpp	Thu Mar 03 19:53:03 2011 -0500
+++ b/hotspot/src/share/vm/oops/klassVtable.cpp	Fri Mar 04 14:40:46 2011 -0500
@@ -883,7 +883,7 @@
   int ime_num = 0;
 
   // Skip first methodOop if it is a class initializer
-  int i = ((methodOop)methods()->obj_at(0))->name() != vmSymbols::class_initializer_name() ? 0 : 1;
+  int i = ((methodOop)methods()->obj_at(0))->is_static_initializer() ? 1 : 0;
 
   // m, method_name, method_signature, klass reset each loop so they
   // don't need preserving across check_signature_loaders call
@@ -1121,7 +1121,7 @@
     assert(index < methods->length(), "should find index for resolve_invoke");
   }
   // Adjust for <clinit>, which is left out of table if first method
-  if (methods->length() > 0 && ((methodOop)methods->obj_at(0))->name() == vmSymbols::class_initializer_name()) {
+  if (methods->length() > 0 && ((methodOop)methods->obj_at(0))->is_static_initializer()) {
     index--;
   }
   return index;
@@ -1135,7 +1135,7 @@
 
   int index = itable_index;
   // Adjust for <clinit>, which is left out of table if first method
-  if (methods->length() > 0 && ((methodOop)methods->obj_at(0))->name() == vmSymbols::class_initializer_name()) {
+  if (methods->length() > 0 && ((methodOop)methods->obj_at(0))->is_static_initializer()) {
     index++;
   }
 
--- a/hotspot/src/share/vm/oops/methodOop.cpp	Thu Mar 03 19:53:03 2011 -0500
+++ b/hotspot/src/share/vm/oops/methodOop.cpp	Fri Mar 04 14:40:46 2011 -0500
@@ -466,7 +466,20 @@
 
 
 bool methodOopDesc::is_initializer() const {
-  return name() == vmSymbols::object_initializer_name() || name() == vmSymbols::class_initializer_name();
+  return name() == vmSymbols::object_initializer_name() || is_static_initializer();
+}
+
+bool methodOopDesc::has_valid_initializer_flags() const {
+  return (is_static() ||
+          instanceKlass::cast(method_holder())->major_version() < 51);
+}
+
+bool methodOopDesc::is_static_initializer() const {
+  // For classfiles version 51 or greater, ensure that the clinit method is
+  // static.  Non-static methods with the name "<clinit>" are not static
+  // initializers. (older classfiles exempted for backward compatibility)
+  return name() == vmSymbols::class_initializer_name() &&
+         has_valid_initializer_flags();
 }
 
 
--- a/hotspot/src/share/vm/oops/methodOop.hpp	Thu Mar 03 19:53:03 2011 -0500
+++ b/hotspot/src/share/vm/oops/methodOop.hpp	Fri Mar 04 14:40:46 2011 -0500
@@ -497,6 +497,13 @@
   // returns true if the method is an initializer (<init> or <clinit>).
   bool is_initializer() const;
 
+  // returns true if the method is static OR if the classfile version < 51
+  bool has_valid_initializer_flags() const;
+
+  // returns true if the method name is <clinit> and the method has
+  // valid static initializer flags.
+  bool is_static_initializer() const;
+
   // compiled code support
   // NOTE: code() is inherently racy as deopt can be clearing code
   // simultaneously. Use with caution.