< prev index next >

src/hotspot/share/classfile/systemDictionary.cpp

Print this page
@@ -53,10 +53,11 @@
  #include "memory/metaspaceClosure.hpp"
  #include "memory/oopFactory.hpp"
  #include "memory/resourceArea.hpp"
  #include "memory/universe.hpp"
  #include "oops/access.inline.hpp"
+ #include "oops/fieldStreams.inline.hpp"
  #include "oops/instanceKlass.hpp"
  #include "oops/klass.inline.hpp"
  #include "oops/method.inline.hpp"
  #include "oops/objArrayKlass.hpp"
  #include "oops/objArrayOop.inline.hpp"

@@ -64,18 +65,20 @@
  #include "oops/oop.hpp"
  #include "oops/oopHandle.hpp"
  #include "oops/oopHandle.inline.hpp"
  #include "oops/symbol.hpp"
  #include "oops/typeArrayKlass.hpp"
+ #include "oops/inlineKlass.inline.hpp"
  #include "prims/jvmtiExport.hpp"
  #include "prims/methodHandles.hpp"
  #include "runtime/arguments.hpp"
  #include "runtime/atomic.hpp"
  #include "runtime/handles.inline.hpp"
  #include "runtime/java.hpp"
  #include "runtime/javaCalls.hpp"
  #include "runtime/mutexLocker.hpp"
+ #include "runtime/os.hpp"
  #include "runtime/sharedRuntime.hpp"
  #include "runtime/signature.hpp"
  #include "runtime/synchronizer.hpp"
  #include "services/classLoadingService.hpp"
  #include "services/diagnosticCommand.hpp"

@@ -332,11 +335,11 @@
      return resolve_array_class_or_null(class_name, class_loader, protection_domain, THREAD);
    } else {
      assert(class_name != nullptr && !Signature::is_array(class_name), "must be");
      if (Signature::has_envelope(class_name)) {
        ResourceMark rm(THREAD);
-       // Ignore wrapping L and ;.
+       // Ignore wrapping L and ; (and Q and ; for value types).
        TempNewSymbol name = SymbolTable::new_symbol(class_name->as_C_string() + 1,
                                                     class_name->utf8_length() - 2);
        return resolve_instance_class_or_null(name, class_loader, protection_domain, THREAD);
      } else {
        return resolve_instance_class_or_null(class_name, class_loader, protection_domain, THREAD);

@@ -361,11 +364,18 @@
      k = SystemDictionary::resolve_instance_class_or_null(obj_class,
                                                           class_loader,
                                                           protection_domain,
                                                           CHECK_NULL);
      if (k != nullptr) {
-       k = k->array_klass(ndims, CHECK_NULL);
+       if (class_name->is_Q_array_signature()) {
+         if (!k->is_inline_klass()) {
+           THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), "L/Q mismatch on bottom type");
+         }
+         k = InlineKlass::cast(k)->value_array_klass(ndims, CHECK_NULL);
+       } else {
+         k = k->array_klass(ndims, CHECK_NULL);
+       }
      }
    } else {
      k = Universe::typeArrayKlassObj(t);
      k = TypeArrayKlass::cast(k)->array_klass(ndims, CHECK_NULL);
    }

@@ -488,10 +498,53 @@
    }
  
    return superk;
  }
  
+ Klass* SystemDictionary::resolve_inline_type_field_or_fail(Symbol* signature,
+                                                            Handle class_loader,
+                                                            Handle protection_domain,
+                                                            bool throw_error,
+                                                            TRAPS) {
+   Symbol* class_name = signature->fundamental_name(THREAD);
+   class_loader = Handle(THREAD, java_lang_ClassLoader::non_reflection_class_loader(class_loader()));
+   ClassLoaderData* loader_data = class_loader_data(class_loader);
+   bool throw_circularity_error = false;
+   PlaceholderEntry* oldprobe;
+ 
+   {
+     MutexLocker mu(THREAD, SystemDictionary_lock);
+     oldprobe = PlaceholderTable::get_entry(class_name, loader_data);
+     if (oldprobe != nullptr &&
+       oldprobe->check_seen_thread(THREAD, PlaceholderTable::PRIMITIVE_OBJECT_FIELD)) {
+       throw_circularity_error = true;
+ 
+     } else {
+       PlaceholderTable::find_and_add(class_name, loader_data,
+                                    PlaceholderTable::PRIMITIVE_OBJECT_FIELD, nullptr, THREAD);
+     }
+   }
+ 
+   Klass* klass = nullptr;
+   if (!throw_circularity_error) {
+     klass = SystemDictionary::resolve_or_fail(class_name, class_loader,
+                                                protection_domain, true, THREAD);
+   } else {
+     ResourceMark rm(THREAD);
+     THROW_MSG_NULL(vmSymbols::java_lang_ClassCircularityError(), class_name->as_C_string());
+   }
+ 
+   {
+     MutexLocker mu(THREAD, SystemDictionary_lock);
+     PlaceholderTable::find_and_remove(class_name, loader_data,
+                                       PlaceholderTable::PRIMITIVE_OBJECT_FIELD, THREAD);
+   }
+ 
+   class_name->decrement_refcount();
+   return klass;
+ }
+ 
  // If the class in is in the placeholder table, class loading is in progress.
  // For cases where the application changes threads to load classes, it
  // is critical to ClassCircularity detection that we try loading
  // the superclass on the new thread internally, so we do parallel
  // superclass loading here.  This avoids deadlock for ClassCircularity

@@ -573,11 +626,11 @@
                                                                  Handle class_loader,
                                                                  Handle protection_domain,
                                                                  TRAPS) {
    // name must be in the form of "java/lang/Object" -- cannot be "Ljava/lang/Object;"
    assert(name != nullptr && !Signature::is_array(name) &&
-          !Signature::has_envelope(name), "invalid class name");
+          !Signature::has_envelope(name), "invalid class name: %s", name == nullptr ? "nullptr" : name->as_C_string());
  
    EventClassLoad class_load_start_event;
  
    HandleMark hm(THREAD);
  

@@ -778,17 +831,21 @@
      // dimension and object_key in FieldArrayInfo are assigned as a
      // side-effect of this call
      SignatureStream ss(class_name, false);
      int ndims = ss.skip_array_prefix();  // skip all '['s
      BasicType t = ss.type();
-     if (t != T_OBJECT) {
+     if (t != T_OBJECT && t != T_PRIMITIVE_OBJECT) {
        k = Universe::typeArrayKlassObj(t);
      } else {
        k = SystemDictionary::find_instance_klass(current, ss.as_symbol(), class_loader, protection_domain);
      }
      if (k != nullptr) {
-       k = k->array_klass_or_null(ndims);
+       if (class_name->is_Q_array_signature()) {
+         k = InlineKlass::cast(k)->value_array_klass_or_null(ndims);
+       } else {
+         k = k->array_klass_or_null(ndims);
+       }
      }
    } else {
      k = find_instance_klass(current, class_name, class_loader, protection_domain);
    }
    return k;

@@ -1138,10 +1195,29 @@
  
    if (!check_shared_class_super_types(ik, class_loader, protection_domain, THREAD)) {
      return nullptr;
    }
  
+ 
+   if (ik->has_inline_type_fields()) {
+     for (AllFieldStream fs(ik); !fs.done(); fs.next()) {
+       Symbol* sig = fs.signature();
+       if (fs.is_null_free_inline_type()) {
+         if (!fs.access_flags().is_static()) {
+           // Pre-load inline class
+           Klass* real_k = SystemDictionary::resolve_inline_type_field_or_fail(sig,
+             class_loader, protection_domain, true, CHECK_NULL);
+           Klass* k = ik->get_inline_type_field_klass_or_null(fs.index());
+           if (real_k != k) {
+             // oops, the app has substituted a different version of k!
+             return nullptr;
+           }
+         }
+       }
+     }
+   }
+ 
    InstanceKlass* new_ik = nullptr;
    // CFLH check is skipped for VM hidden classes (see KlassFactory::create_from_stream).
    // It will be skipped for shared VM hidden lambda proxy classes.
    if (!SystemDictionaryShared::is_hidden_lambda_proxy(ik)) {
      new_ik = KlassFactory::check_shared_class_file_load_hook(

@@ -1173,10 +1249,11 @@
      // restore_unshareable_info which calls ik->set_package()
      ik->restore_unshareable_info(loader_data, protection_domain, pkg_entry, CHECK_NULL);
    }
  
    load_shared_class_misc(ik, loader_data);
+ 
    return ik;
  }
  
  void SystemDictionary::load_shared_class_misc(InstanceKlass* ik, ClassLoaderData* loader_data) {
    ik->print_class_load_logging(loader_data, nullptr, nullptr);

@@ -1722,19 +1799,23 @@
      // For array classes, their Klass*s are not kept in the
      // constraint table. The element Klass*s are.
      SignatureStream ss(class_name, false);
      int ndims = ss.skip_array_prefix();  // skip all '['s
      BasicType t = ss.type();
-     if (t != T_OBJECT) {
+     if (t != T_OBJECT && t != T_PRIMITIVE_OBJECT) {
        klass = Universe::typeArrayKlassObj(t);
      } else {
        MutexLocker mu(current, SystemDictionary_lock);
        klass = LoaderConstraintTable::find_constrained_klass(ss.as_symbol(), class_loader_data(class_loader));
      }
      // If element class already loaded, allocate array klass
      if (klass != nullptr) {
-       klass = klass->array_klass_or_null(ndims);
+       if (class_name->is_Q_array_signature()) {
+         klass = InlineKlass::cast(klass)->value_array_klass_or_null(ndims);
+       } else {
+         klass = klass->array_klass_or_null(ndims);
+       }
      }
    } else {
      MutexLocker mu(current, SystemDictionary_lock);
      // Non-array classes are easy: simply check the constraint table.
      klass = LoaderConstraintTable::find_constrained_klass(class_name, class_loader_data(class_loader));
< prev index next >