< prev index next >
src/share/vm/memory/metaspaceShared.cpp
Print this page
*** 1,7 ****
/*
! * Copyright (c) 2012, 2016, 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
--- 1,7 ----
/*
! * Copyright (c) 2012, 2017, 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*** 38,49 ****
--- 38,54 ----
#include "interpreter/bytecodes.hpp"
#include "memory/filemap.hpp"
#include "memory/metaspace.hpp"
#include "memory/metaspaceShared.hpp"
#include "memory/resourceArea.hpp"
+ #include "oops/instanceClassLoaderKlass.hpp"
+ #include "oops/instanceMirrorKlass.hpp"
+ #include "oops/instanceRefKlass.hpp"
+ #include "oops/objArrayKlass.hpp"
#include "oops/objArrayOop.hpp"
#include "oops/oop.inline.hpp"
+ #include "oops/typeArrayKlass.hpp"
#include "runtime/timerTrace.hpp"
#include "runtime/os.hpp"
#include "runtime/signature.hpp"
#include "runtime/vmThread.hpp"
#include "runtime/vm_operations.hpp"
*** 231,315 ****
}
}
}
}
! // Patch C++ vtable pointer in metadata.
!
! // Klass and other metadata objects contain references to c++ vtables in the
! // JVM library.
! // Fix them to point to our constructed vtables. However, don't iterate
! // across the space while doing this, as that causes the vtables to be
! // patched, undoing our useful work. Instead, iterate to make a list,
! // then use the list to do the fixing.
//
! // Our constructed vtables:
! // Dump time:
! // 1. init_self_patching_vtbl_list: table of pointers to current virtual method addrs
! // 2. generate_vtable_methods: create jump table, appended to above vtbl_list
! // 3. patch_klass_vtables: for Klass list, patch the vtable entry in klass and
! // associated metadata to point to jump table rather than to current vtbl
! // Table layout: NOTE FIXED SIZE
! // 1. vtbl pointers
! // 2. #Klass X #virtual methods per Klass
! // 1 entry for each, in the order:
! // Klass1:method1 entry, Klass1:method2 entry, ... Klass1:method<num_virtuals> entry
! // Klass2:method1 entry, Klass2:method2 entry, ... Klass2:method<num_virtuals> entry
! // ...
! // Klass<vtbl_list_size>:method1 entry, Klass<vtbl_list_size>:method2 entry,
! // ... Klass<vtbl_list_size>:method<num_virtuals> entry
! // Sample entry: (Sparc):
! // save(sp, -256, sp)
! // ba,pt common_code
! // mov XXX, %L0 %L0 gets: Klass index <<8 + method index (note: max method index 255)
//
! // Restore time:
! // 1. initialize_shared_space: reserve space for table
! // 2. init_self_patching_vtbl_list: update pointers to NEW virtual method addrs in text
//
! // Execution time:
! // First virtual method call for any object of these metadata types:
! // 1. object->klass
! // 2. vtable entry for that klass points to the jump table entries
! // 3. branches to common_code with %O0/klass, %L0: Klass index <<8 + method index
! // 4. common_code:
! // Get address of new vtbl pointer for this Klass from updated table
! // Update new vtbl pointer in the Klass: future virtual calls go direct
! // Jump to method, using new vtbl pointer and method index
!
!
! static void* find_matching_vtbl_ptr(void** vtbl_list, void* new_vtable_start, void* obj) {
! void* old_vtbl_ptr = *(void**)obj;
! for (int i = 0; i < MetaspaceShared::vtbl_list_size; i++) {
! if (vtbl_list[i] == old_vtbl_ptr) {
! return (void**)new_vtable_start + i * MetaspaceShared::num_virtuals;
}
}
! ShouldNotReachHere();
! return NULL;
}
! // Assumes the vtable is in first slot in object.
! static void patch_klass_vtables(void** vtbl_list, void* new_vtable_start) {
int n = _global_klass_objects->length();
for (int i = 0; i < n; i++) {
Klass* obj = _global_klass_objects->at(i);
// Note is_instance_klass() is a virtual call in debug. After patching vtables
// all virtual calls on the dummy vtables will restore the original!
if (obj->is_instance_klass()) {
InstanceKlass* ik = InstanceKlass::cast(obj);
! *(void**)ik = find_matching_vtbl_ptr(vtbl_list, new_vtable_start, ik);
ConstantPool* cp = ik->constants();
! *(void**)cp = find_matching_vtbl_ptr(vtbl_list, new_vtable_start, cp);
for (int j = 0; j < ik->methods()->length(); j++) {
Method* m = ik->methods()->at(j);
! *(void**)m = find_matching_vtbl_ptr(vtbl_list, new_vtable_start, m);
}
} else {
! // Array klasses
! Klass* k = obj;
! *(void**)k = find_matching_vtbl_ptr(vtbl_list, new_vtable_start, k);
}
}
}
// Closure for serializing initialization data out to a data area to be
--- 236,495 ----
}
}
}
}
! // Objects of the Metadata types (such as Klass and ConstantPool) have C++ vtables.
! // (In GCC this is the field <Type>::_vptr, i.e., first word in the object.)
! //
! // Addresses of the vtables and the methods may be different across JVM runs,
! // if libjvm.so is dynamically loaded at a different base address.
//
! // To ensure that the Metadata objects in the CDS archive always have the correct vtable:
//
! // + at dump time: we redirect the _vptr to point to our own vtables inside
! // the CDS image
! // + at run time: we clone the actual contents of the vtables from libjvm.so
! // into our own tables.
//
! // We conservatively estimate that each class's vtable has less than 150 entries. See
! // CppVtabCloner::MAX_VTABLE_SIZE
!
! // Currently, the archive contain ONLY the following types of objects that have C++ vtables.
! #define CPP_VTAB_PATCH_TYPES_DO(f) \
! f(ConstantPool) \
! f(InstanceKlass) \
! f(InstanceClassLoaderKlass) \
! f(InstanceMirrorKlass) \
! f(InstanceRefKlass) \
! f(Method) \
! f(ObjArrayKlass) \
! f(TypeArrayKlass)
!
! #ifndef PRODUCT
! template <class T> class CppVtabTesterB: public T {
! public:
! virtual int last_virtual_method() {return 1;}
! };
!
! template <class T> class CppVtabTesterA : public T {
! public:
! virtual void* last_virtual_method() {
! // Make this different than CppVtabTesterB::last_virtual_method so the C++
! // compiler/linker won't alias the two functions.
! return NULL;
}
+ };
+ #endif
+
+ class CppVtabInfo {
+ intptr_t _vtab_size;
+ intptr_t _vtab[1];
+ public:
+ static int num_slots(int vtab_size) {
+ return 1 + vtab_size; // Need to add the space occupied by _vtab_size;
}
! int vtab_size() { return int(uintx(_vtab_size)); }
! void set_vtab_size(int n) { _vtab_size = intptr_t(n); }
! intptr_t* vtab() { return &_vtab[0]; }
! void zero() { memset(_vtab, 0, sizeof(intptr_t) * vtab_size()); }
! };
!
! template <class T> class CppVtabCloner : public T {
! static intptr_t* vtab_of(Metadata& m) {
! return *((intptr_t**)&m);
! }
! // Currently we have no more than 120 virtual methods for all
! // Metadata subclasses for all platforms. If you add more virtual
! // method you will trigger the assert in verify_sufficient_size().
! const static int MAX_VTABLE_SIZE = 150;
! static CppVtabInfo* _info;
!
! #ifndef PRODUCT
! // To determine the size of the vtable for each type, we use the following
! // trick by declaring 2 subclasses:
! //
! // class CppVtabTesterA: public InstanceKlass {virtual int last_virtual_method() {return 1;} };
! // class CppVtabTesterB: public InstanceKlass {virtual void* last_virtual_method() {return NULL}; };
! //
! // CppVtabTesterA and CppVtabTesterB's vtables have the following properties:
! // - Their size (N+1) is exactly one more than the size of InstanceKlass's vtable (N)
! // - The first N entries have are exactly the same as in InstanceKlass's vtable.
! // - Their last entry is different.
! //
! // So to determine the value of N, we just walk CppVtabTesterA and CppVtabTesterB's tables
! // and find the first entry that's different.
! //
! // This works on all C++ compilers supported by Oracle, but you may need to tweak it for more
! // esoteric compilers.
!
! static void verify_sufficient_size(const char* name) {
! CppVtabTesterA<T> a;
! CppVtabTesterB<T> b;
!
! intptr_t* avtab = vtab_of(a);
! intptr_t* bvtab = vtab_of(b);
!
! // Start at slot 1, because slot 0 may be RTTI (on Solaris/Sparc)
! int i;
! for (i=1; ; i++) {
! if (avtab[i] != bvtab[i]) {
! break;
! }
! }
! if (PrintSharedSpaces) {
! tty->print_cr("%s has %d virtual methods", name, i);
! }
! if (i > MAX_VTABLE_SIZE) {
! tty->print_cr("The C++ vtable size of %s (%d) is larger than the hard-coded default %d",
! name, i, MAX_VTABLE_SIZE);
! assert(0, "Please increase CppVtabCloner<T>::MAX_VTABLE_SIZE");
! }
! }
! #endif
!
! public:
! static intptr_t* allocate(const char* name, intptr_t* md_top, intptr_t* md_end) {
! DEBUG_ONLY(verify_sufficient_size(name));
! int n = MAX_VTABLE_SIZE;
! intptr_t* next = md_top + CppVtabInfo::num_slots(n);
!
! if (next > md_end) {
! report_out_of_shared_space(SharedMiscData);
! }
!
! _info = (CppVtabInfo*)md_top;
! _info->set_vtab_size(n);
!
! T tmp;
! intptr_t* srcvtab = vtab_of(tmp);
! intptr_t* dstvtab = _info->vtab();
!
! // It is not safe to call memcpy(), because srcvtab may be shorter than MAX_VTABLE_SIZE, and
! // may be at the last page of an addressable space. Crossing over to the next page would
! // cause a page fault.
! if (!CanUseSafeFetchN()) {
! vm_exit_during_initialization("CanUseSafeFetchN() must be true to enable CDS");
! }
!
! for (int i=0; i<n; i++) {
! const intptr_t bad = intptr_t(0xdeadbeef);
! intptr_t num = SafeFetchN(&srcvtab[i], bad);
! if (num == bad
! // || i > 120 /* uncomment this line to test */
! ) {
! _info->set_vtab_size(i-1);
! break;
! }
! dstvtab[i] = num;
! }
!
! return md_top + CppVtabInfo::num_slots(_info->vtab_size());
! }
!
! static intptr_t* clone_vtable(const char* name, intptr_t* p) {
! T tmp;
! CppVtabInfo* info = (CppVtabInfo*)p;
! int n = info->vtab_size();
! intptr_t* srcvtab = vtab_of(tmp);
! intptr_t* dstvtab = info->vtab();
!
! // We already checked (and, if necessary, adjusted n) when the vtables were allocated, so we are
! // safe to do memcpy.
! if (PrintSharedSpaces) {
! tty->print_cr("%s copying %d vtable entries", name, n);
! }
! memcpy(dstvtab, srcvtab, sizeof(intptr_t) * n);
! return dstvtab + n;
! }
!
! static void zero_vtable_clone() {
! assert(DumpSharedSpaces, "dump-time only");
! _info->zero();
! }
!
! static void patch(Metadata* obj) {
! assert(DumpSharedSpaces, "dump-time only");
! *(void**)obj = (void*)(_info->vtab());
! }
! };
!
! template <class T> CppVtabInfo* CppVtabCloner<T>::_info = NULL;
!
!
! #define ALLOC_CPP_VTAB_CLONE(c) \
! md_top = CppVtabCloner<c>::allocate(#c, md_top, md_end);
!
! #define CLONE_CPP_VTABLE(c) \
! p = CppVtabCloner<c>::clone_vtable(#c, p);
!
! #define ZERO_CPP_VTABLE(c) \
! CppVtabCloner<c>::zero_vtable_clone();
!
!
! intptr_t* MetaspaceShared::allocate_cpp_vtable_clones(intptr_t* md_top, intptr_t* md_end) {
! assert(DumpSharedSpaces, "dump-time only");
! CPP_VTAB_PATCH_TYPES_DO(ALLOC_CPP_VTAB_CLONE);
! return md_top;
}
! // This can be called at both dump time and run time.
! intptr_t* MetaspaceShared::clone_cpp_vtables(intptr_t* p) {
! assert(DumpSharedSpaces || UseSharedSpaces, "sanity");
! CPP_VTAB_PATCH_TYPES_DO(CLONE_CPP_VTABLE);
! return p;
! }
!
! void MetaspaceShared::zero_cpp_vtable_clones_for_writing() {
! assert(DumpSharedSpaces, "dump-time only");
! CPP_VTAB_PATCH_TYPES_DO(ZERO_CPP_VTABLE);
! }
!
! intptr_t* MetaspaceShared::init_cpp_vtable_clones(intptr_t* md_top, intptr_t* md_end) {
! assert(DumpSharedSpaces, "dump-time only");
! // Layout (each slot is a intptr_t):
! // [number of slots in the first vtable = n1]
! // [ <n1> slots for the first vtable]
! // [number of slots in the first second = n2]
! // [ <n2> slots for the second vtable]
! // ...
! // The order of the vtables is the same as the CPP_VTAB_PATCH_TYPES_DO macro.
!
! intptr_t* start = md_top;
! md_top = allocate_cpp_vtable_clones(md_top, md_end);
! return md_top;
! }
!
! // Assumes the vtable pointer is in first slot in object.
! void MetaspaceShared::patch_cpp_vtable_pointers() {
int n = _global_klass_objects->length();
for (int i = 0; i < n; i++) {
Klass* obj = _global_klass_objects->at(i);
// Note is_instance_klass() is a virtual call in debug. After patching vtables
// all virtual calls on the dummy vtables will restore the original!
if (obj->is_instance_klass()) {
InstanceKlass* ik = InstanceKlass::cast(obj);
! if (ik->is_class_loader_instance_klass()) {
! CppVtabCloner<InstanceClassLoaderKlass>::patch(ik);
! } else if (ik->is_reference_instance_klass()) {
! CppVtabCloner<InstanceRefKlass>::patch(ik);
! } else if (ik->is_mirror_instance_klass()) {
! CppVtabCloner<InstanceMirrorKlass>::patch(ik);
! } else {
! CppVtabCloner<InstanceKlass>::patch(ik);
! }
ConstantPool* cp = ik->constants();
! CppVtabCloner<ConstantPool>::patch(cp);
for (int j = 0; j < ik->methods()->length(); j++) {
Method* m = ik->methods()->at(j);
! CppVtabCloner<Method>::patch(m);
}
+ } else if (obj->is_objArray_klass()) {
+ CppVtabCloner<ObjArrayKlass>::patch(obj);
} else {
! assert(obj->is_typeArray_klass(), "sanity");
! CppVtabCloner<TypeArrayKlass>::patch(obj);
}
}
}
// Closure for serializing initialization data out to a data area to be
*** 339,349 ****
*top = (intptr_t)*p;
++top;
}
void do_u4(u4* p) {
! void* ptr = (void*)(uintx(*p));
do_ptr(&ptr);
}
void do_tag(int tag) {
check_space();
--- 519,529 ----
*top = (intptr_t)*p;
++top;
}
void do_u4(u4* p) {
! void* ptr = (void*)(intptr_t(*p));
do_ptr(&ptr);
}
void do_tag(int tag) {
check_space();
*** 620,647 ****
char* mc_end = _mc_vs.high();
char* od_low = _od_vs.low();
char* od_top = MetaspaceShared::optional_data_region()->alloc_top();
char* od_end = _od_vs.high();
! // Reserve space for the list of Klass*s whose vtables are used
! // for patching others as needed.
!
! void** vtbl_list = (void**)md_top;
! int vtbl_list_size = MetaspaceShared::vtbl_list_size;
! Universe::init_self_patching_vtbl_list(vtbl_list, vtbl_list_size);
! md_top += vtbl_list_size * sizeof(void*);
! void* vtable = md_top;
!
! // Reserve space for a new dummy vtable for klass objects in the
! // heap. Generate self-patching vtable entries.
!
! MetaspaceShared::generate_vtable_methods(vtbl_list, &vtable,
! &md_top, md_end,
! &mc_top, mc_end);
!
! guarantee(md_top <= md_end, "Insufficient space for vtables.");
// Reorder the system dictionary. (Moving the symbols affects
// how the hash table indices are calculated.)
// Not doing this either.
--- 800,815 ----
char* mc_end = _mc_vs.high();
char* od_low = _od_vs.low();
char* od_top = MetaspaceShared::optional_data_region()->alloc_top();
char* od_end = _od_vs.high();
! char* vtbl_list = md_top;
! md_top = (char*)MetaspaceShared::init_cpp_vtable_clones((intptr_t*)md_top, (intptr_t*)md_end);
! // We don't use MC section anymore. We will remove it in a future RFE. For now, put one
! // byte inside so the region writing/mapping code works.
! mc_top ++;
// Reorder the system dictionary. (Moving the symbols affects
// how the hash table indices are calculated.)
// Not doing this either.
*** 711,734 ****
tty->print_cr(fmt_space, "st", ss_bytes, ss_t_perc, ss_bytes, 100.0, p2i(ss_low));
tty->print_cr(fmt_space, "od", od_bytes, od_t_perc, od_alloced, od_u_perc, p2i(od_low));
tty->print_cr("total : " SIZE_FORMAT_W(9) " [100.0%% of total] out of " SIZE_FORMAT_W(9) " bytes [%5.1f%% used]",
total_bytes, total_alloced, total_u_perc);
! // Update the vtable pointers in all of the Klass objects in the
! // heap. They should point to newly generated vtable.
! patch_klass_vtables(vtbl_list, vtable);
!
! // dunno what this is for.
! char* saved_vtbl = (char*)os::malloc(vtbl_list_size * sizeof(void*), mtClass);
! memmove(saved_vtbl, vtbl_list, vtbl_list_size * sizeof(void*));
! memset(vtbl_list, 0, vtbl_list_size * sizeof(void*));
// Create and write the archive file that maps the shared spaces.
FileMapInfo* mapinfo = new FileMapInfo();
mapinfo->populate_header(MetaspaceShared::max_alignment());
! mapinfo->set_misc_data_patching_start((char*)vtbl_list);
mapinfo->set_cds_i2i_entry_code_buffers(MetaspaceShared::cds_i2i_entry_code_buffers());
mapinfo->set_cds_i2i_entry_code_buffers_size(MetaspaceShared::cds_i2i_entry_code_buffers_size());
for (int pass=1; pass<=2; pass++) {
if (pass == 1) {
--- 879,899 ----
tty->print_cr(fmt_space, "st", ss_bytes, ss_t_perc, ss_bytes, 100.0, p2i(ss_low));
tty->print_cr(fmt_space, "od", od_bytes, od_t_perc, od_alloced, od_u_perc, p2i(od_low));
tty->print_cr("total : " SIZE_FORMAT_W(9) " [100.0%% of total] out of " SIZE_FORMAT_W(9) " bytes [%5.1f%% used]",
total_bytes, total_alloced, total_u_perc);
! MetaspaceShared::patch_cpp_vtable_pointers();
!
! // The vtable clones contain addresses of the current process.
! // We don't want to write addresses these into the archive.
! MetaspaceShared::zero_cpp_vtable_clones_for_writing();
// Create and write the archive file that maps the shared spaces.
FileMapInfo* mapinfo = new FileMapInfo();
mapinfo->populate_header(MetaspaceShared::max_alignment());
! mapinfo->set_misc_data_patching_start(vtbl_list);
mapinfo->set_cds_i2i_entry_code_buffers(MetaspaceShared::cds_i2i_entry_code_buffers());
mapinfo->set_cds_i2i_entry_code_buffers_size(MetaspaceShared::cds_i2i_entry_code_buffers_size());
for (int pass=1; pass<=2; pass++) {
if (pass == 1) {
*** 759,770 ****
true, false);
}
mapinfo->close();
! memmove(vtbl_list, saved_vtbl, vtbl_list_size * sizeof(void*));
! os::free(saved_vtbl);
if (PrintSharedSpaces) {
DumpAllocClosure dac;
dac.iterate_metaspace(_loader_data->ro_metaspace(), DumpAllocClosure::RO);
dac.iterate_metaspace(_loader_data->rw_metaspace(), DumpAllocClosure::RW);
--- 924,935 ----
true, false);
}
mapinfo->close();
! // Restore the vtable in case we invoke any virtual methods.
! MetaspaceShared::clone_cpp_vtables((intptr_t*)vtbl_list);
if (PrintSharedSpaces) {
DumpAllocClosure dac;
dac.iterate_metaspace(_loader_data->ro_metaspace(), DumpAllocClosure::RO);
dac.iterate_metaspace(_loader_data->rw_metaspace(), DumpAllocClosure::RW);
*** 1136,1158 ****
FileMapInfo *mapinfo = FileMapInfo::current_info();
_cds_i2i_entry_code_buffers = mapinfo->cds_i2i_entry_code_buffers();
_cds_i2i_entry_code_buffers_size = mapinfo->cds_i2i_entry_code_buffers_size();
char* buffer = mapinfo->misc_data_patching_start();
! // Skip over (reserve space for) a list of addresses of C++ vtables
! // for Klass objects. They get filled in later.
!
! void** vtbl_list = (void**)buffer;
! buffer += MetaspaceShared::vtbl_list_size * sizeof(void*);
! Universe::init_self_patching_vtbl_list(vtbl_list, vtbl_list_size);
!
! // Skip over (reserve space for) dummy C++ vtables Klass objects.
! // They are used as is.
!
! intptr_t vtable_size = *(intptr_t*)buffer;
! buffer += sizeof(intptr_t);
! buffer += vtable_size;
int sharedDictionaryLen = *(intptr_t*)buffer;
buffer += sizeof(intptr_t);
int number_of_entries = *(intptr_t*)buffer;
buffer += sizeof(intptr_t);
--- 1301,1311 ----
FileMapInfo *mapinfo = FileMapInfo::current_info();
_cds_i2i_entry_code_buffers = mapinfo->cds_i2i_entry_code_buffers();
_cds_i2i_entry_code_buffers_size = mapinfo->cds_i2i_entry_code_buffers_size();
char* buffer = mapinfo->misc_data_patching_start();
! buffer = (char*)clone_cpp_vtables((intptr_t*)buffer);
int sharedDictionaryLen = *(intptr_t*)buffer;
buffer += sizeof(intptr_t);
int number_of_entries = *(intptr_t*)buffer;
buffer += sizeof(intptr_t);
< prev index next >