< 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 >