< prev index next >

src/hotspot/share/classfile/classFileParser.cpp

Print this page

        

@@ -1088,11 +1088,11 @@
     : _location(location), _annotations_present(0)
   {
     assert((int)_annotation_LIMIT <= (int)sizeof(_annotations_present) * BitsPerByte, "");
   }
   // If this annotation name has an ID, report it (or _none).
-  ID annotation_index(const ClassLoaderData* loader_data, const Symbol* name);
+  ID annotation_index(const ClassLoaderData* loader_data, const Symbol* name, const bool can_access_vm_annotations);
   // Set the annotation name:
   void set_annotation(ID id) {
     assert((int)id >= 0 && (int)id < (int)_annotation_LIMIT, "oob");
     _annotations_present |= nth_bit((int)id);
   }

@@ -1221,10 +1221,11 @@
 // Sift through annotations, looking for those significant to the VM:
 static void parse_annotations(const ConstantPool* const cp,
                               const u1* buffer, int limit,
                               AnnotationCollector* coll,
                               ClassLoaderData* loader_data,
+                              const bool can_access_vm_annotations,
                               TRAPS) {
 
   assert(cp != NULL, "invariant");
   assert(buffer != NULL, "invariant");
   assert(coll != NULL, "invariant");

@@ -1266,11 +1267,11 @@
       member = check_symbol_at(cp, member_index);
       if (member == NULL)  break;  // invalid member name
     }
 
     // Here is where parsing particular annotations will take place.
-    AnnotationCollector::ID id = coll->annotation_index(loader_data, aname);
+    AnnotationCollector::ID id = coll->annotation_index(loader_data, aname, can_access_vm_annotations);
     if (AnnotationCollector::_unknown == id)  continue;
     coll->set_annotation(id);
 
     if (AnnotationCollector::_jdk_internal_vm_annotation_Contended == id) {
       // @Contended can optionally specify the contention group.

@@ -1392,10 +1393,11 @@
         parse_annotations(cp,
                           runtime_visible_annotations,
                           runtime_visible_annotations_length,
                           parsed_annotations,
                           _loader_data,
+                          _can_access_vm_annotations,
                           CHECK);
         cfs->skip_u1_fast(runtime_visible_annotations_length);
       } else if (attribute_name == vmSymbols::tag_runtime_invisible_annotations()) {
         if (runtime_invisible_annotations_exists) {
           classfile_parse_error(

@@ -2051,16 +2053,18 @@
       name->as_C_string(), _class_name->as_C_string(), sig->as_C_string());
 }
 
 AnnotationCollector::ID
 AnnotationCollector::annotation_index(const ClassLoaderData* loader_data,
-                                      const Symbol* name) {
+                                      const Symbol* name,
+                                      const bool can_access_vm_annotations) {
   const vmSymbols::SID sid = vmSymbols::find_sid(name);
   // Privileged code can use all annotations.  Other code silently drops some.
   const bool privileged = loader_data->is_the_null_class_loader_data() ||
                           loader_data->is_platform_class_loader_data() ||
-                          loader_data->is_unsafe_anonymous();
+                          loader_data->is_shortlived() ||
+                          can_access_vm_annotations;
   switch (sid) {
     case vmSymbols::VM_SYMBOL_ENUM_NAME(reflect_CallerSensitive_signature): {
       if (_location != _in_method)  break;  // only allow for methods
       if (!privileged)              break;  // only allow in privileged code
       return _method_CallerSensitive;

@@ -2663,10 +2667,11 @@
         parse_annotations(cp,
                           runtime_visible_annotations,
                           runtime_visible_annotations_length,
                           &parsed_annotations,
                           _loader_data,
+                          _can_access_vm_annotations,
                           CHECK_NULL);
         cfs->skip_u1_fast(runtime_visible_annotations_length);
       } else if (method_attribute_name == vmSymbols::tag_runtime_invisible_annotations()) {
         if (runtime_invisible_annotations_exists) {
           classfile_parse_error(

@@ -3425,10 +3430,11 @@
         parse_annotations(cp,
                           runtime_visible_annotations,
                           runtime_visible_annotations_length,
                           parsed_annotations,
                           _loader_data,
+                          _can_access_vm_annotations,
                           CHECK);
         cfs->skip_u1_fast(runtime_visible_annotations_length);
       } else if (tag == vmSymbols::tag_runtime_invisible_annotations()) {
         if (runtime_invisible_annotations_exists) {
           classfile_parse_error(

@@ -5415,19 +5421,21 @@
     } // CheckIntrinsics
 #endif // ASSERT
   }
 }
 
-InstanceKlass* ClassFileParser::create_instance_klass(bool changed_by_loadhook, TRAPS) {
+InstanceKlass* ClassFileParser::create_instance_klass(bool changed_by_loadhook,
+                                                      const ClassInstanceInfo& cl_inst_info,
+                                                      TRAPS) {
   if (_klass != NULL) {
     return _klass;
   }
 
   InstanceKlass* const ik =
     InstanceKlass::allocate_instance_klass(*this, CHECK_NULL);
 
-  fill_instance_klass(ik, changed_by_loadhook, CHECK_NULL);
+  fill_instance_klass(ik, changed_by_loadhook, cl_inst_info, CHECK_NULL);
 
   assert(_klass == ik, "invariant");
 
 
   if (ik->should_store_fingerprint()) {

@@ -5449,11 +5457,14 @@
   }
 
   return ik;
 }
 
-void ClassFileParser::fill_instance_klass(InstanceKlass* ik, bool changed_by_loadhook, TRAPS) {
+void ClassFileParser::fill_instance_klass(InstanceKlass* ik,
+                                          bool changed_by_loadhook,
+                                          const ClassInstanceInfo& cl_inst_info,
+                                          TRAPS) {
   assert(ik != NULL, "invariant");
 
   // Set name and CLD before adding to CLD
   ik->set_class_loader_data(_loader_data);
   ik->set_name(_class_name);

@@ -5485,10 +5496,15 @@
 
   // this transfers ownership of a lot of arrays from
   // the parser onto the InstanceKlass*
   apply_parsed_class_metadata(ik, _java_fields_count, CHECK);
 
+  // can only set dynamic nest-host after static nest information is set
+  if (cl_inst_info.dynamic_nest_host() != NULL) {
+    ik->set_nest_host(cl_inst_info.dynamic_nest_host(), CHECK);
+  }
+
   // note that is not safe to use the fields in the parser from this point on
   assert(NULL == _cp, "invariant");
   assert(NULL == _fields, "invariant");
   assert(NULL == _methods, "invariant");
   assert(NULL == _inner_classes, "invariant");

@@ -5508,15 +5524,15 @@
   // has to be changed accordingly.
   ik->set_initial_method_idnum(ik->methods()->length());
 
   ik->set_this_class_index(_this_class_index);
 
-  if (is_unsafe_anonymous()) {
+  if (_is_hidden || is_unsafe_anonymous()) {
     // _this_class_index is a CONSTANT_Class entry that refers to this
-    // anonymous class itself. If this class needs to refer to its own methods or
-    // fields, it would use a CONSTANT_MethodRef, etc, which would reference
-    // _this_class_index. However, because this class is anonymous (it's
+    // hidden or anonymous class itself. If this class needs to refer to its own
+    // methods or fields, it would use a CONSTANT_MethodRef, etc, which would reference
+    // _this_class_index. However, because this class is hidden or anonymous (it's
     // not stored in SystemDictionary), _this_class_index cannot be resolved
     // with ConstantPool::klass_at_impl, which does a SystemDictionary lookup.
     // Therefore, we must eagerly resolve _this_class_index now.
     ik->constants()->klass_at_put(_this_class_index, ik);
   }

@@ -5528,16 +5544,23 @@
 
   if (_unsafe_anonymous_host != NULL) {
     assert (ik->is_unsafe_anonymous(), "should be the same");
     ik->set_unsafe_anonymous_host(_unsafe_anonymous_host);
   }
+  if (_is_hidden) {
+    ik->set_is_hidden();
+  }
 
   // Set PackageEntry for this_klass
   oop cl = ik->class_loader();
   Handle clh = Handle(THREAD, java_lang_ClassLoader::non_reflection_class_loader(cl));
   ClassLoaderData* cld = ClassLoaderData::class_loader_data_or_null(clh());
   ik->set_package(cld, CHECK);
+  // Obtain this_klass' module entry
+  ModuleEntry* module_entry = ik->module();
+  assert(module_entry != NULL, "module_entry should always be set");
+
 
   const Array<Method*>* const methods = ik->methods();
   assert(methods != NULL, "invariant");
   const int methods_len = methods->length();
 

@@ -5589,23 +5612,20 @@
   // reject static interface methods prior to Java 8
   if (ik->is_interface() && _major_version < JAVA_8_VERSION) {
     check_illegal_static_method(ik, CHECK);
   }
 
-  // Obtain this_klass' module entry
-  ModuleEntry* module_entry = ik->module();
-  assert(module_entry != NULL, "module_entry should always be set");
-
   // Obtain java.lang.Module
   Handle module_handle(THREAD, module_entry->module());
 
   // Allocate mirror and initialize static fields
   // The create_mirror() call will also call compute_modifiers()
   java_lang_Class::create_mirror(ik,
                                  Handle(THREAD, _loader_data->class_loader()),
                                  module_handle,
                                  _protection_domain,
+                                 cl_inst_info.class_data(),
                                  CHECK);
 
   assert(_all_mirandas != NULL, "invariant");
 
   // Generate any default methods - default methods are public interface methods

@@ -5675,22 +5695,10 @@
   set_klass(ik);
 
   debug_only(ik->verify();)
 }
 
-void ClassFileParser::update_class_name(Symbol* new_class_name) {
-  // Decrement the refcount in the old name, since we're clobbering it.
-  _class_name->decrement_refcount();
-
-  _class_name = new_class_name;
-  // Increment the refcount of the new name.
-  // Now the ClassFileParser owns this name and will decrement in
-  // the destructor.
-  _class_name->increment_refcount();
-}
-
-
 // For an unsafe anonymous class that is in the unnamed package, move it to its host class's
 // package by prepending its host class's package name to its class name and setting
 // its _class_name field.
 void ClassFileParser::prepend_host_package_name(const InstanceKlass* unsafe_anonymous_host, TRAPS) {
   ResourceMark rm(THREAD);

@@ -5755,18 +5763,21 @@
                                  Symbol* name,
                                  ClassLoaderData* loader_data,
                                  Handle protection_domain,
                                  const InstanceKlass* unsafe_anonymous_host,
                                  GrowableArray<Handle>* cp_patches,
+                                 const bool is_hidden,
+                                 const bool can_access_vm_annotations,
                                  Publicity pub_level,
                                  TRAPS) :
   _stream(stream),
-  _requested_name(name),
   _class_name(NULL),
   _loader_data(loader_data),
   _unsafe_anonymous_host(unsafe_anonymous_host),
   _cp_patches(cp_patches),
+  _is_hidden(is_hidden),
+  _can_access_vm_annotations(can_access_vm_annotations),
   _num_patched_klasses(0),
   _max_num_patched_klasses(0),
   _orig_cp_size(0),
   _first_patched_klass_resolved_index(0),
   _super_klass(),

@@ -5989,14 +6000,19 @@
   guarantee_property(
     cp_size >= 1, "Illegal constant pool size %u in class file %s",
     cp_size, CHECK);
 
   _orig_cp_size = cp_size;
+  if (is_hidden()) { // Add a slot for hidden class name.
+    assert(_max_num_patched_klasses == 0, "Sanity check");
+    cp_size++;
+  } else {
   if (int(cp_size) + _max_num_patched_klasses > 0xffff) {
     THROW_MSG(vmSymbols::java_lang_InternalError(), "not enough space for patched classes");
   }
   cp_size += _max_num_patched_klasses;
+  }
 
   _cp = ConstantPool::allocate(_loader_data,
                                cp_size,
                                CHECK);
 

@@ -6043,40 +6059,104 @@
     _this_class_index, CHECK);
 
   Symbol* const class_name_in_cp = cp->klass_name_at(_this_class_index);
   assert(class_name_in_cp != NULL, "class_name can't be null");
 
-  // Update _class_name to reflect the name in the constant pool
-  update_class_name(class_name_in_cp);
-
   // Don't need to check whether this class name is legal or not.
   // It has been checked when constant pool is parsed.
   // However, make sure it is not an array type.
   if (_need_verify) {
-    guarantee_property(_class_name->char_at(0) != JVM_SIGNATURE_ARRAY,
+    guarantee_property(class_name_in_cp->char_at(0) != JVM_SIGNATURE_ARRAY,
                        "Bad class name in class file %s",
                        CHECK);
   }
 
-  // Checks if name in class file matches requested name
-  if (_requested_name != NULL && _requested_name != _class_name) {
+#ifdef ASSERT
+  // Basic sanity checks
+  assert(!(_is_hidden && (_unsafe_anonymous_host != NULL)), "mutually exclusive variants");
+
+  if (_unsafe_anonymous_host != NULL) {
+    assert(_class_name == vmSymbols::unknown_class_name(), "A named anonymous class???");
+  }
+  if (_is_hidden) {
+    assert(_class_name != vmSymbols::unknown_class_name(), "hidden classes should have a special name");
+  }
+#endif
+
+  // Update the _class_name as needed depending on whether this is a named,
+  // un-named, hidden or unsafe-anonymous class.
+
+  if (_is_hidden) {
+    ResourceMark rm(THREAD);
+    assert(_class_name != NULL, "Unexpected null _class_name");
+#ifdef ASSERT
+    if (_need_verify) {
+      verify_legal_class_name(_class_name, CHECK);
+    }
+#endif
+
+    // Construct hidden name from _class_name, "+", and &_cp. Note that we can't
+    // use a '/' because that confuses finding the class's package.  Also, can't
+    // use an illegal char such as ';' because that causes serialization issues
+    // and issues with hidden classes that create their own hidden classes.
+    char addr_buf[20];
+    jio_snprintf(addr_buf, 20, INTPTR_FORMAT, p2i(_cp));
+    size_t new_name_len = _class_name->utf8_length() + 2 + strlen(addr_buf);
+    char* new_name = NEW_RESOURCE_ARRAY(char, new_name_len);
+    jio_snprintf(new_name, new_name_len, "%s+%s",
+                 _class_name->as_C_string(), addr_buf);
+    _class_name->decrement_refcount();
+    _class_name = SymbolTable::new_symbol(new_name);
+    _class_name->increment_refcount();
+
+    // Add a Utf8 entry containing the hidden name.
+    assert(_class_name != NULL, "Unexpected null _class_name");
+    int hidden_index = _orig_cp_size; // this is an extra slot we added
+    cp->symbol_at_put(hidden_index, _class_name);
+
+    // Update this_class_index's slot in the constant pool with the new Utf8 entry.
+    // We have to update the resolved_klass_index and the name_index together
+    // so extract the existing resolved_klass_index first.
+    CPKlassSlot cp_klass_slot = cp->klass_slot_at(_this_class_index);
+    int resolved_klass_index = cp_klass_slot.resolved_klass_index();
+    cp->unresolved_klass_at_put(_this_class_index, hidden_index, resolved_klass_index);
+    assert(cp->klass_slot_at(_this_class_index).name_index() == _orig_cp_size,
+           "Bad name_index");
+
+  // NOTE: !_is_hidden does not imply "findable" as it could be an old-style
+  //       "hidden" unsafe-anonymous class
+
+  // If this is an anonymous class fix up its name if it is in the unnamed
+  // package.  Otherwise, throw IAE if it is in a different package than
+  // its host class.
+  } else if (_unsafe_anonymous_host != NULL) {
+    Symbol* old_class_name = _class_name;
+    _class_name = class_name_in_cp;
+    _class_name->increment_refcount();
+    fix_unsafe_anonymous_class_name(CHECK);
+    old_class_name->decrement_refcount();
+
+  } else {
+    // Check if name in class file matches given name
+    if (_class_name != class_name_in_cp) {
+      if (_class_name != vmSymbols::unknown_class_name()) {
     ResourceMark rm(THREAD);
-    Exceptions::fthrow(
-      THREAD_AND_LOCATION,
+        Exceptions::fthrow(THREAD_AND_LOCATION,
       vmSymbols::java_lang_NoClassDefFoundError(),
       "%s (wrong name: %s)",
-      _class_name->as_C_string(),
-      _requested_name != NULL ? _requested_name->as_C_string() : "NoName"
+                           class_name_in_cp->as_C_string(),
+                           _class_name->as_C_string()
     );
     return;
+      } else {
+        // The class name was not known by the caller so we set it from
+        // the value in the CP.
+        _class_name = class_name_in_cp;
+        _class_name->increment_refcount();
+      }
+      // else nothing to do: the expected class name matches what is in the CP
   }
-
-  // if this is an anonymous class fix up its name if it's in the unnamed
-  // package.  Otherwise, throw IAE if it is in a different package than
-  // its host class.
-  if (_unsafe_anonymous_host != NULL) {
-    fix_unsafe_anonymous_class_name(CHECK);
   }
 
   // Verification prevents us from creating names with dots in them, this
   // asserts that that's the case.
   assert(is_internal_format(_class_name), "external class name format used internally");

@@ -6097,13 +6177,14 @@
     if (DumpLoadedClassList != NULL && stream->source() != NULL && classlist_file->is_open()) {
       if (!ClassLoader::has_jrt_entry()) {
         warning("DumpLoadedClassList and CDS are not supported in exploded build");
         DumpLoadedClassList = NULL;
       } else if (SystemDictionaryShared::is_sharing_possible(_loader_data) &&
+                 !_is_hidden &&
                  _unsafe_anonymous_host == NULL) {
         // Only dump the classes that can be stored into CDS archive.
-        // Unsafe anonymous classes such as generated LambdaForm classes are also not included.
+        // Hidden and unsafe anonymous classes such as generated LambdaForm classes are also not included.
         oop class_loader = _loader_data->class_loader();
         ResourceMark rm(THREAD);
         bool skip = false;
         if (class_loader == NULL || SystemDictionary::is_platform_class_loader(class_loader)) {
           // For the boot and platform class loaders, skip classes that are not found in the
< prev index next >