Skip to content
This repository has been archived by the owner. It is now read-only.
Permalink
Browse files
8251557: Avoid dumping unused symbols/strings into the CDS archive
Reviewed-by: minqi, ccheung
  • Loading branch information
iklam committed Aug 28, 2020
1 parent 1845dd2 commit 3af532e7df336f6a88f3c5252e2fb195db70379d
Show file tree
Hide file tree
Showing 12 changed files with 164 additions and 113 deletions.
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -719,10 +719,7 @@ oop StringTable::lookup_shared(const jchar* name, int len, unsigned int hash) {

oop StringTable::create_archived_string(oop s, Thread* THREAD) {
assert(DumpSharedSpaces, "this function is only used with -Xshare:dump");

if (HeapShared::is_archived_object(s)) {
return s;
}
assert(!HeapShared::is_archived_object(s), "sanity");

oop new_s = NULL;
typeArrayOop v = java_lang_String::value_no_keepalive(s);
@@ -740,42 +737,34 @@ oop StringTable::create_archived_string(oop s, Thread* THREAD) {
return new_s;
}

struct CopyToArchive : StackObj {
class CopyToArchive : StackObj {
CompactHashtableWriter* _writer;
public:
CopyToArchive(CompactHashtableWriter* writer) : _writer(writer) {}
bool operator()(WeakHandle* val) {
oop s = val->peek();
if (s == NULL) {
return true;
}
bool do_entry(oop s, bool value_ignored) {
assert(s != NULL, "sanity");
unsigned int hash = java_lang_String::hash_code(s);
oop new_s = StringTable::create_archived_string(s, Thread::current());
if (new_s == NULL) {
return true;
}

val->replace(new_s);
// add to the compact table
_writer->add(hash, CompressedOops::encode(new_s));
return true;
}
};

void StringTable::copy_shared_string_table(CompactHashtableWriter* writer) {
assert(HeapShared::is_heap_object_archiving_allowed(), "must be");

CopyToArchive copy(writer);
_local_table->do_safepoint_scan(copy);
}

void StringTable::write_to_archive() {
void StringTable::write_to_archive(const DumpedInternedStrings* dumped_interned_strings) {
assert(HeapShared::is_heap_object_archiving_allowed(), "must be");

_shared_table.reset();
CompactHashtableWriter writer(_items_count, &MetaspaceShared::stats()->string);

// Copy the interned strings into the "string space" within the java heap
copy_shared_string_table(&writer);
CopyToArchive copier(&writer);
dumped_interned_strings->iterate(&copier);

writer.dump(&_shared_table, "string");
}

@@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -32,6 +32,7 @@
#include "utilities/tableStatistics.hpp"

class CompactHashtableWriter;
class DumpedInternedStrings;
class JavaThread;
class SerializeClosure;

@@ -105,11 +106,10 @@ class StringTable : public CHeapObj<mtSymbol>{
// Sharing
private:
static oop lookup_shared(const jchar* name, int len, unsigned int hash) NOT_CDS_JAVA_HEAP_RETURN_(NULL);
static void copy_shared_string_table(CompactHashtableWriter* ch_table) NOT_CDS_JAVA_HEAP_RETURN;
public:
static oop create_archived_string(oop s, Thread* THREAD) NOT_CDS_JAVA_HEAP_RETURN_(NULL);
static void shared_oops_do(OopClosure* f) NOT_CDS_JAVA_HEAP_RETURN;
static void write_to_archive() NOT_CDS_JAVA_HEAP_RETURN;
static void write_to_archive(const DumpedInternedStrings* dumped_interned_strings) NOT_CDS_JAVA_HEAP_RETURN;
static void serialize_shared_table_header(SerializeClosure* soc) NOT_CDS_JAVA_HEAP_RETURN;

// Jcmd
@@ -28,6 +28,7 @@
#include "classfile/javaClasses.hpp"
#include "classfile/symbolTable.hpp"
#include "memory/allocation.inline.hpp"
#include "memory/archiveBuilder.hpp"
#include "memory/dynamicArchive.hpp"
#include "memory/metaspaceClosure.hpp"
#include "memory/metaspaceShared.hpp"
@@ -56,7 +57,6 @@ const size_t ON_STACK_BUFFER_LENGTH = 128;

inline bool symbol_equals_compact_hashtable_entry(Symbol* value, const char* key, int len) {
if (value->equals(key, len)) {
assert(value->is_permanent(), "must be shared");
return true;
} else {
return false;
@@ -176,11 +176,6 @@ void SymbolTable::create_table () {
}

void SymbolTable::delete_symbol(Symbol* sym) {
if (Arguments::is_dumping_archive()) {
// Do not delete symbols as we may be in the middle of preparing the
// symbols for dumping.
return;
}
if (sym->is_permanent()) {
MutexLocker ml(SymbolArena_lock, Mutex::_no_safepoint_check_flag); // Protect arena
// Deleting permanent symbol should not occur very often (insert race condition),
@@ -225,9 +220,9 @@ Symbol* SymbolTable::allocate_symbol(const char* name, int len, bool c_heap) {
assert (len <= Symbol::max_length(), "should be checked by caller");

Symbol* sym;
if (Arguments::is_dumping_archive()) {
// Need to make all symbols permanent -- or else some symbols may be GC'ed
// during the archive dumping code that's executed outside of a safepoint.
if (DumpSharedSpaces) {
// TODO: Special handling of Symbol allocation for DumpSharedSpaces will be removed
// in JDK-8250989
c_heap = false;
}
if (c_heap) {
@@ -280,24 +275,6 @@ void SymbolTable::symbols_do(SymbolClosure *cl) {
_local_table->do_safepoint_scan(sd);
}

class MetaspacePointersDo : StackObj {
MetaspaceClosure *_it;
public:
MetaspacePointersDo(MetaspaceClosure *it) : _it(it) {}
bool operator()(Symbol** value) {
assert(value != NULL, "expected valid value");
assert(*value != NULL, "value should point to a symbol");
_it->push(value);
return true;
};
};

void SymbolTable::metaspace_pointers_do(MetaspaceClosure* it) {
Arguments::assert_is_dumping_archive();
MetaspacePointersDo mpd(it);
_local_table->do_safepoint_scan(mpd);
}

Symbol* SymbolTable::lookup_dynamic(const char* name,
int len, unsigned int hash) {
Symbol* sym = do_lookup(name, len, hash);
@@ -606,42 +583,37 @@ void SymbolTable::dump(outputStream* st, bool verbose) {
}

#if INCLUDE_CDS
struct CopyToArchive : StackObj {
CompactHashtableWriter* _writer;
CopyToArchive(CompactHashtableWriter* writer) : _writer(writer) {}
bool operator()(Symbol** value) {
assert(value != NULL, "expected valid value");
assert(*value != NULL, "value should point to a symbol");
Symbol* sym = *value;
void SymbolTable::copy_shared_symbol_table(GrowableArray<Symbol*>* symbols,
CompactHashtableWriter* writer) {
int len = symbols->length();
for (int i = 0; i < len; i++) {
Symbol* sym = ArchiveBuilder::get_relocated_symbol(symbols->at(i));
unsigned int fixed_hash = hash_shared_symbol((const char*)sym->bytes(), sym->utf8_length());
assert(fixed_hash == hash_symbol((const char*)sym->bytes(), sym->utf8_length(), false),
"must not rehash during dumping");
sym->set_permanent();
if (DynamicDumpSharedSpaces) {
sym = DynamicArchive::original_to_target(sym);
sym = DynamicArchive::buffer_to_target(sym);
}
_writer->add(fixed_hash, MetaspaceShared::object_delta_u4(sym));
return true;
writer->add(fixed_hash, MetaspaceShared::object_delta_u4(sym));
}
};

void SymbolTable::copy_shared_symbol_table(CompactHashtableWriter* writer) {
CopyToArchive copy(writer);
_local_table->do_safepoint_scan(copy);
}

size_t SymbolTable::estimate_size_for_archive() {
return CompactHashtableWriter::estimate_size(int(_items_count));
}

void SymbolTable::write_to_archive(bool is_static_archive) {
void SymbolTable::write_to_archive(GrowableArray<Symbol*>* symbols) {
CompactHashtableWriter writer(int(_items_count),
&MetaspaceShared::stats()->symbol);
copy_shared_symbol_table(&writer);
if (is_static_archive) {
copy_shared_symbol_table(symbols, &writer);
if (!DynamicDumpSharedSpaces) {
_shared_table.reset();
writer.dump(&_shared_table, "symbol");

// Verify table is correct
// Verify the written shared table is correct -- at this point,
// vmSymbols has already been relocated to point to the archived
// version of the Symbols.
Symbol* sym = vmSymbols::java_lang_Object();
const char* name = (const char*)sym->bytes();
int len = sym->utf8_length();
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -31,6 +31,7 @@
#include "utilities/tableStatistics.hpp"

class JavaThread;
template <typename T> class GrowableArray;

// TempNewSymbol acts as a handle class in a handle/body idiom and is
// responsible for proper resource management of the body (which is a Symbol*).
@@ -207,13 +208,13 @@ class SymbolTable : public AllStatic {

// Sharing
private:
static void copy_shared_symbol_table(CompactHashtableWriter* ch_table);
static void copy_shared_symbol_table(GrowableArray<Symbol*>* symbols,
CompactHashtableWriter* ch_table);
public:
static size_t estimate_size_for_archive() NOT_CDS_RETURN_(0);
static void write_to_archive(bool is_static_archive = true) NOT_CDS_RETURN;
static void write_to_archive(GrowableArray<Symbol*>* symbols) NOT_CDS_RETURN;
static void serialize_shared_table_header(SerializeClosure* soc,
bool is_static_archive = true) NOT_CDS_RETURN;
static void metaspace_pointers_do(MetaspaceClosure* it);

// Jcmd
static void dump(outputStream* st, bool verbose=false);
@@ -157,6 +157,10 @@ ArchiveBuilder::~ArchiveBuilder() {

clean_up_src_obj_table();

for (int i = 0; i < _symbols->length(); i++) {
_symbols->at(i)->decrement_refcount();
}

delete _klasses;
delete _symbols;
delete _special_refs;
@@ -197,7 +201,10 @@ bool ArchiveBuilder::gather_klass_and_symbol(MetaspaceClosure::Ref* ref, bool re
}
_estimated_metsapceobj_bytes += BytesPerWord; // See RunTimeSharedClassInfo::get_for()
} else if (ref->msotype() == MetaspaceObj::SymbolType) {
_symbols->append((Symbol*)ref->obj());
// Make sure the symbol won't be GC'ed while we are dumping the archive.
Symbol* sym = (Symbol*)ref->obj();
sym->increment_refcount();
_symbols->append(sym);
}

int bytes = ref->size() * BytesPerWord;
@@ -274,9 +281,13 @@ void ArchiveBuilder::sort_klasses() {
void ArchiveBuilder::iterate_sorted_roots(MetaspaceClosure* it, bool is_relocating_pointers) {
int i;

int num_symbols = _symbols->length();
for (i = 0; i < num_symbols; i++) {
it->push(&_symbols->at(i));
if (!is_relocating_pointers) {
// Don't relocate _symbol, so we can safely call decrement_refcount on the
// original symbols.
int num_symbols = _symbols->length();
for (i = 0; i < num_symbols; i++) {
it->push(&_symbols->at(i));
}
}

int num_klasses = _klasses->length();
@@ -27,14 +27,14 @@

#include "memory/archiveUtils.hpp"
#include "memory/metaspaceClosure.hpp"
#include "oops/klass.hpp"
#include "utilities/bitMap.hpp"
#include "utilities/growableArray.hpp"
#include "utilities/hashtable.hpp"
#include "utilities/resourceHash.hpp"

class CHeapBitMap;
class Klass;
class DumpRegion;
class Symbol;
class DumpAllocStats;

@@ -230,6 +230,10 @@ class ArchiveBuilder : public StackObj {
return klass;
}

static Symbol* get_relocated_symbol(Symbol* orig_symbol) {
return (Symbol*)singleton()->get_dumped_addr((address)orig_symbol);
}

void print_stats(int ro_all, int rw_all, int mc_all);
};

@@ -238,7 +238,7 @@ class DynamicArchiveBuilder : public ArchiveBuilder {
// they would need to call DynamicArchive::original_to_target() to
// get the correct addresses.
assert(current_dump_space() == ro_space, "Must be RO space");
SymbolTable::write_to_archive(false);
SymbolTable::write_to_archive(symbols());
SystemDictionaryShared::write_to_archive(false);

serialized_data = ro_space->top();
@@ -270,7 +270,6 @@ class DynamicArchiveBuilder : public ArchiveBuilder {
virtual void iterate_roots(MetaspaceClosure* it, bool is_relocating_pointers) {
if (!is_relocating_pointers) {
SystemDictionaryShared::dumptime_classes_do(it);
SymbolTable::metaspace_pointers_do(it);
}
FileMapInfo::metaspace_pointers_do(it);
}
@@ -56,9 +56,9 @@
bool HeapShared::_closed_archive_heap_region_mapped = false;
bool HeapShared::_open_archive_heap_region_mapped = false;
bool HeapShared::_archive_heap_region_fixed = false;

address HeapShared::_narrow_oop_base;
int HeapShared::_narrow_oop_shift;
DumpedInternedStrings *HeapShared::_dumped_interned_strings = NULL;

//
// If you add new entries to the following tables, you should know what you're doing!
@@ -233,7 +233,6 @@ void HeapShared::archive_java_heap_objects(GrowableArray<MemRegion> *closed,
create_archived_object_cache();

log_info(cds)("Dumping objects to closed archive heap region ...");
NOT_PRODUCT(StringTable::verify());
copy_closed_archive_heap_objects(closed);

log_info(cds)("Dumping objects to open archive heap region ...");
@@ -253,7 +252,7 @@ void HeapShared::copy_closed_archive_heap_objects(
G1CollectedHeap::heap()->begin_archive_alloc_range();

// Archive interned string objects
StringTable::write_to_archive();
StringTable::write_to_archive(_dumped_interned_strings);

archive_object_subgraphs(closed_archive_subgraph_entry_fields,
num_closed_archive_subgraph_entry_fields,
@@ -962,6 +961,11 @@ void HeapShared::init_subgraph_entry_fields(Thread* THREAD) {
THREAD);
}

void HeapShared::init_for_dumping(Thread* THREAD) {
_dumped_interned_strings = new (ResourceObj::C_HEAP, mtClass)DumpedInternedStrings();
init_subgraph_entry_fields(THREAD);
}

void HeapShared::archive_object_subgraphs(ArchivableStaticFieldInfo fields[],
int num, bool is_closed_archive,
Thread* THREAD) {
@@ -1015,6 +1019,17 @@ void HeapShared::archive_object_subgraphs(ArchivableStaticFieldInfo fields[],
#endif
}

// Not all the strings in the global StringTable are dumped into the archive, because
// some of those strings may be only referenced by classes that are excluded from
// the archive. We need to explicitly mark the strings that are:
// [1] used by classes that WILL be archived;
// [2] included in the SharedArchiveConfigFile.
void HeapShared::add_to_dumped_interned_strings(oop string) {
assert_at_safepoint(); // DumpedInternedStrings uses raw oops
bool created;
_dumped_interned_strings->put_if_absent(string, true, &created);
}

// At dump-time, find the location of all the non-null oop pointers in an archived heap
// region. This way we can quickly relocate all the pointers without using
// BasicOopIterateClosure at runtime.

0 comments on commit 3af532e

Please sign in to comment.