< prev index next >

src/share/vm/memory/metaspaceShared.cpp

Print this page

        

@@ -1,7 +1,7 @@
 /*
- * 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
  * under the terms of the GNU General Public License version 2 only, as
  * published by the Free Software Foundation.

@@ -38,12 +38,17 @@
 #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,85 +236,260 @@
       }
     }
   }
 }
 
-// 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 <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.
 //
-// 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)
+// 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 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;
   }
-  ShouldNotReachHere();
-  return NULL;
+  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;
 }
 
-// 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]
+  //   [ <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);
-      *(void**)ik = find_matching_vtbl_ptr(vtbl_list, new_vtable_start, ik);
+      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();
-      *(void**)cp = find_matching_vtbl_ptr(vtbl_list, new_vtable_start, cp);
+      CppVtabCloner<ConstantPool>::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<Method>::patch(m);
       }
+    } else if (obj->is_objArray_klass()) {
+      CppVtabCloner<ObjArrayKlass>::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<TypeArrayKlass>::patch(obj);
     }
   }
 }
 
 // Closure for serializing initialization data out to a data area to be

@@ -339,11 +519,11 @@
     *top = (intptr_t)*p;
     ++top;
   }
 
   void do_u4(u4* p) {
-    void* ptr = (void*)(uintx(*p));
+    void* ptr = (void*)(intptr_t(*p));
     do_ptr(&ptr);
   }
 
   void do_tag(int tag) {
     check_space();

@@ -620,28 +800,16 @@
   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);
+  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.)
   // Not doing this either.
 

@@ -711,24 +879,21 @@
   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*));
+   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());
 
   for (int pass=1; pass<=2; pass++) {
     if (pass == 1) {

@@ -759,12 +924,12 @@
                           true, false);
   }
 
   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;
     dac.iterate_metaspace(_loader_data->ro_metaspace(), DumpAllocClosure::RO);
     dac.iterate_metaspace(_loader_data->rw_metaspace(), DumpAllocClosure::RW);

@@ -1136,23 +1301,11 @@
   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;
+  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 >