--- old/src/hotspot/share/memory/heapShared.cpp 2018-09-02 12:26:09.183524282 -0700 +++ new/src/hotspot/share/memory/heapShared.cpp 2018-09-02 12:26:08.927514735 -0700 @@ -185,8 +185,8 @@ if (log_is_enabled(Info, cds, heap)) { ResourceMark rm; log_info(cds, heap)( - "Archived object klass (%d): %s in %s sub-graphs", - i, subgraph_k->external_name(), _k->external_name()); + "Archived object klass %s (%2d) => %s", + _k->external_name(), i, subgraph_k->external_name()); } _subgraph_klasses->at_put(i, subgraph_k); } @@ -348,11 +348,13 @@ int _level; oop _orig_referencing_obj; oop _archived_referencing_obj; + Thread* _thread; public: WalkOopAndArchiveClosure(int level, - oop orig, oop archived) : _level(level), + oop orig, oop archived, TRAPS) : _level(level), _orig_referencing_obj(orig), - _archived_referencing_obj(archived) {} + _archived_referencing_obj(archived), + _thread(THREAD) {} void do_oop(narrowOop *p) { WalkOopAndArchiveClosure::do_oop_work(p); } void do_oop( oop *p) { WalkOopAndArchiveClosure::do_oop_work(p); } @@ -360,78 +362,79 @@ template void do_oop_work(T *p) { oop obj = RawAccess<>::oop_load(p); if (!CompressedOops::is_null(obj)) { + assert(!MetaspaceShared::is_archive_object(obj), + "original objects must not directly point to archived object"); + size_t field_delta = pointer_delta(p, _orig_referencing_obj, sizeof(char)); + T* new_p = (T*)(address(_archived_referencing_obj) + field_delta); + // A java.lang.Class instance cannot be included in an archived // object sub-graph. if (java_lang_Class::is_instance(obj)) { - log_error(cds, heap)("Unknown java.lang.Class object is in the archived sub-graph"); + log_error(cds, heap)("(%d) Unknown java.lang.Class object is in the archived sub-graph", _level); vm_exit(1); } if (log_is_enabled(Debug, cds, heap)) { - LogTarget(Debug, cds, heap) log; - LogStream ls(log); - outputStream* out = &ls; ResourceMark rm; - log.print("(%d) %s <--- referenced from: %s", - _level, obj->klass()->external_name(), - CompressedOops::is_null(_orig_referencing_obj) ? - "" : _orig_referencing_obj->klass()->external_name()); - obj->print_on(out); + log_debug(cds, heap)("(%d) %s[" SIZE_FORMAT "] ==> " PTR_FORMAT " size %d %s", _level, + _orig_referencing_obj->klass()->external_name(), field_delta, + p2i(obj), obj->size() * HeapWordSize, obj->klass()->external_name()); + LogTarget(Trace, cds, heap) log; + LogStream out(log); + obj->print_on(&out); } - assert(!MetaspaceShared::is_archive_object(obj), - "original objects must not directly point to archived object"); - - size_t field_delta = pointer_delta( - p, _orig_referencing_obj, sizeof(char)); - T* new_p = (T*)(address(_archived_referencing_obj) + field_delta); oop archived = MetaspaceShared::find_archived_heap_object(obj); - if (archived != NULL) { - // There is an archived copy existing, update reference to point - // to the archived copy - RawAccess::oop_store(new_p, archived); - log_debug(cds, heap)("--- found existing archived copy, store archived " PTR_FORMAT " in " PTR_FORMAT, - p2i(archived), p2i(new_p)); - return; - } - - Thread* THREAD = Thread::current(); - // Archive the current oop before iterating through its references - archived = MetaspaceShared::archive_heap_object(obj, THREAD); if (archived == NULL) { - ResourceMark rm; - LogTarget(Error, cds, heap) log_err; - LogStream ls_err(log_err); - outputStream* out_err = &ls_err; - log_err.print("Failed to archive %s object (" - PTR_FORMAT "), size[" SIZE_FORMAT "] in sub-graph", - obj->klass()->external_name(), p2i(obj), (size_t)obj->size()); - obj->print_on(out_err); - vm_exit(1); + Thread* THREAD = _thread; + archived = HeapShared::archive_reachable_objects_from(_level + 1, obj, THREAD); + assert(archived != NULL, "VM should have exited"); } - assert(MetaspaceShared::is_archive_object(archived), "must be archived"); - log_debug(cds, heap)("=== archiving oop " PTR_FORMAT " ==> " PTR_FORMAT, - p2i(obj), p2i(archived)); - - // Following the references in the current oop and archive any - // encountered objects during the process - WalkOopAndArchiveClosure walker(_level + 1, obj, archived); - obj->oop_iterate(&walker); + assert(MetaspaceShared::is_archive_object(archived), "must be"); - // Update the reference in the archived copy of the referencing object + // Update the reference in the archived copy of the referencing object. + log_debug(cds, heap)("(%d) archiving oop @[" PTR_FORMAT "] " PTR_FORMAT " ==> " PTR_FORMAT, + _level, p2i(new_p), p2i(obj), p2i(archived)); RawAccess::oop_store(new_p, archived); - log_debug(cds,heap)("=== store archived " PTR_FORMAT " in " PTR_FORMAT, - p2i(archived), p2i(new_p)); } } }; +oop HeapShared::archive_reachable_objects_from(int level, oop orig_obj, TRAPS) { + assert(orig_obj != NULL, "must be"); + assert(!MetaspaceShared::is_archive_object(orig_obj), "sanity"); + + // get the archived copy of the field referenced object + oop archived_obj = MetaspaceShared::archive_heap_object(orig_obj, THREAD); + if (archived_obj == NULL) { + // Skip archiving the sub-graph referenced from the current entry field. + ResourceMark rm; + log_error(cds, heap)( + "Cannot archive the sub-graph referenced from %s object (" + PTR_FORMAT ") size %d, skipped.", + orig_obj->klass()->external_name(), p2i(orig_obj), orig_obj->size() * HeapWordSize); + if (level == 1) { + // See runtime/appcds/cacheObject/ArchivedIntegerCacheTest.java + return NULL; + } else { + // We don't know how to handle an object that has been archived, but some of its reachable + // objects cannot be archived. Bail out for now. We might need to fix this in the future if + // we have a real use case. + vm_exit(1); + } + } + + WalkOopAndArchiveClosure walker(level, orig_obj, archived_obj, THREAD); + orig_obj->oop_iterate(&walker); + assert(archived_obj != NULL, "must be"); + return archived_obj; +} + // // Start from the given static field in a java mirror and archive the // complete sub-graph of java heap objects that are reached directly // or indirectly from the starting object by following references. -// Currently, only ArchivedModuleGraph class instance (mirror) has archived -// object subgraphs. Sub-graph archiving restrictions (current): +// Sub-graph archiving restrictions (current): // // - All classes of objects in the archived sub-graph (including the // entry class) must be boot class only. @@ -455,7 +458,7 @@ // archive the sub-graph of objects starting from each reference. // // 4) Updates the pointer in the archived copy of referencing object to -// point to the current archived object. +// point to the current archived object. void HeapShared::archive_reachable_objects_from_static_field(InstanceKlass *k, const char* klass_name, int field_offset, @@ -470,50 +473,27 @@ return; } - // obtain k's subGraph Info KlassSubGraphInfo* subgraph_info = get_subgraph_info(k); - - // get the object referenced by the field oop f = m->obj_field(field_offset); - if (log_is_enabled(Debug, cds, heap)) { - LogTarget(Debug, cds, heap) log; - LogStream ls(log); - outputStream* out = &ls; - log.print("Start archiving from: %s::%s ", klass_name, field_name); - if (!CompressedOops::is_null(f)) { - f->print_on(out); - } else { - log.print("null"); - } + log_debug(cds, heap)("Start archiving from: %s::%s ", klass_name, field_name); + if (log_is_enabled(Trace, cds, heap) && !CompressedOops::is_null(f)) { + LogTarget(Trace, cds, heap) log; + LogStream out(log); + f->print_on(&out); } if (!CompressedOops::is_null(f)) { - // get the archived copy of the field referenced object - oop af = MetaspaceShared::archive_heap_object(f, THREAD); + oop af = archive_reachable_objects_from(1, f, CHECK); if (af == NULL) { - // Skip archiving the sub-graph referenced from the current entry field. - ResourceMark rm; - log_info(cds, heap)( - "Cannot archive the sub-graph referenced from %s object (" - PTR_FORMAT ") size[" SIZE_FORMAT "], skipped.", - f->klass()->external_name(), p2i(f), (size_t)f->size()); - return; - } - if (!MetaspaceShared::is_archive_object(f)) { - WalkOopAndArchiveClosure walker(1, f, af); - f->oop_iterate(&walker); - } - - // The field value is not preserved in the archived mirror. - // Record the field as a new subGraph entry point. The recorded - // information is restored from the archive at runtime. - subgraph_info->add_subgraph_entry_field(field_offset, af); - if (log_is_enabled(Info, cds, heap)) { - ResourceMark rm; - log_info(cds, heap)( - "Archived the sub-graph referenced from %s object " PTR_FORMAT, - f->klass()->external_name(), p2i(f)); + log_error(cds, heap)("Archiving failed %s::%s (some reachable objects cannot be archived)", + klass_name, field_name); + } else { + // Note: the field value is not preserved in the archived mirror. + // Record the field as a new subGraph entry point. The recorded + // information is restored from the archive at runtime. + subgraph_info->add_subgraph_entry_field(field_offset, af); + log_info(cds, heap)("Archived field %s::%s => " PTR_FORMAT, klass_name, field_name, p2i(af)); } } else { // The field contains null, we still need to record the entry point, @@ -551,12 +531,7 @@ assert(DumpSharedSpaces, "dump time only"); assert(k->is_shared_boot_class(), "must be boot class"); - if (log_is_enabled(Debug, cds, heap)) { - LogTarget(Debug, cds, heap) log; - LogStream ls(log); - outputStream* out = &ls; - log.print("Start recording from: %s::%s", klass_name, field_name); - } + log_debug(cds, heap)("Start recording from: %s::%s", klass_name, field_name); oop m = k->java_mirror(); oop f = m->obj_field(field_offset);