--- old/src/share/vm/memory/metaspaceShared.cpp 2017-02-28 17:55:11.184031347 -0800 +++ new/src/share/vm/memory/metaspaceShared.cpp 2017-02-28 17:55:11.024025349 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -40,8 +40,13 @@ #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" @@ -233,63 +238,229 @@ } } -// 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. +// Objects of the Metadata types (such as Klass and ConstantPool) have C++ vtables. +// (In GCC this is the field ::_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. // -// 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 entry -// Klass2:method1 entry, Klass2:method2 entry, ... Klass2:method entry -// ... -// Klass:method1 entry, Klass:method2 entry, -// ... Klass:method 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) +// To ensure that the Metadata objects in the CDS archive always have the correct vtable: // -// 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 +// + 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. // -// 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; +// 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 CppVtabTesterB: public T { +public: + virtual int last_virtual_method() {return 1;} +}; + +template 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 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 a; + CppVtabTesterB 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::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 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()); } - ShouldNotReachHere(); - return NULL; +}; + +template CppVtabInfo* CppVtabCloner::_info = NULL; + + +#define ALLOC_CPP_VTAB_CLONE(c) \ + md_top = CppVtabCloner::allocate(#c, md_top, md_end); + +#define CLONE_CPP_VTABLE(c) \ + p = CppVtabCloner::clone_vtable(#c, p); + +#define ZERO_CPP_VTABLE(c) \ + CppVtabCloner::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; } -// Assumes the vtable is in first slot in object. -static void patch_klass_vtables(void** vtbl_list, void* new_vtable_start) { +// 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] + // [ slots for the first vtable] + // [number of slots in the first second = 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); @@ -297,17 +468,26 @@ // 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); + if (ik->is_class_loader_instance_klass()) { + CppVtabCloner::patch(ik); + } else if (ik->is_reference_instance_klass()) { + CppVtabCloner::patch(ik); + } else if (ik->is_mirror_instance_klass()) { + CppVtabCloner::patch(ik); + } else { + CppVtabCloner::patch(ik); + } ConstantPool* cp = ik->constants(); - *(void**)cp = find_matching_vtbl_ptr(vtbl_list, new_vtable_start, cp); + CppVtabCloner::patch(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); + CppVtabCloner::patch(m); } + } else if (obj->is_objArray_klass()) { + CppVtabCloner::patch(obj); } else { - // Array klasses - Klass* k = obj; - *(void**)k = find_matching_vtbl_ptr(vtbl_list, new_vtable_start, k); + assert(obj->is_typeArray_klass(), "sanity"); + CppVtabCloner::patch(obj); } } } @@ -341,7 +521,7 @@ } void do_u4(u4* p) { - void* ptr = (void*)(uintx(*p)); + void* ptr = (void*)(intptr_t(*p)); do_ptr(&ptr); } @@ -622,24 +802,12 @@ 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); + char* vtbl_list = md_top; + md_top = (char*)MetaspaceShared::init_cpp_vtable_clones((intptr_t*)md_top, (intptr_t*)md_end); - 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."); + // 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.) @@ -713,20 +881,17 @@ 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*)); + 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((char*)vtbl_list); + 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()); @@ -761,8 +926,8 @@ mapinfo->close(); - memmove(vtbl_list, saved_vtbl, vtbl_list_size * sizeof(void*)); - os::free(saved_vtbl); + // Restore the vtable in case we invoke any virtual methods. + MetaspaceShared::clone_cpp_vtables((intptr_t*)vtbl_list); if (PrintSharedSpaces) { DumpAllocClosure dac; @@ -1138,19 +1303,7 @@ _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; + buffer = (char*)clone_cpp_vtables((intptr_t*)buffer); int sharedDictionaryLen = *(intptr_t*)buffer; buffer += sizeof(intptr_t);