< prev index next >

src/hotspot/share/gc/z/zNMethodTable.cpp

Print this page


   1 /*
   2  * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 #include "precompiled.hpp"
  25 #include "code/relocInfo.hpp"
  26 #include "code/nmethod.hpp"
  27 #include "code/icBuffer.hpp"
  28 #include "gc/shared/barrierSet.hpp"
  29 #include "gc/shared/barrierSetNMethod.hpp"
  30 #include "gc/z/zArray.inline.hpp"
  31 #include "gc/z/zGlobals.hpp"
  32 #include "gc/z/zHash.inline.hpp"
  33 #include "gc/z/zLock.inline.hpp"

  34 #include "gc/z/zNMethodTable.hpp"
  35 #include "gc/z/zOopClosures.inline.hpp"
  36 #include "gc/z/zTask.hpp"
  37 #include "gc/z/zWorkers.hpp"
  38 #include "logging/log.hpp"
  39 #include "memory/allocation.inline.hpp"
  40 #include "memory/resourceArea.hpp"
  41 #include "runtime/atomic.hpp"
  42 #include "runtime/orderAccess.hpp"
  43 #include "utilities/debug.hpp"
  44 
  45 class ZNMethodDataOops {
  46 private:
  47   const size_t _nimmediates;
  48   bool         _has_non_immediates;
  49 
  50   static size_t header_size();
  51 
  52   ZNMethodDataOops(const GrowableArray<oop*>& immediates, bool has_non_immediates);
  53 
  54 public:
  55   static ZNMethodDataOops* create(const GrowableArray<oop*>& immediates, bool has_non_immediates);
  56   static void destroy(ZNMethodDataOops* oops);
  57 
  58   size_t immediates_count() const;
  59   oop**  immediates_begin() const;
  60   oop**  immediates_end()   const;
  61 
  62   bool   has_non_immediates() const;
  63 };
  64 
  65 size_t ZNMethodDataOops::header_size() {
  66   const size_t size = sizeof(ZNMethodDataOops);
  67   assert(is_aligned(size, sizeof(oop*)), "Header misaligned");
  68   return size;
  69 }
  70 
  71 ZNMethodDataOops* ZNMethodDataOops::create(const GrowableArray<oop*>& immediates, bool has_non_immediates) {
  72   // Allocate memory for the ZNMethodDataOops object
  73   // plus the immediate oop* array that follows right after.
  74   const size_t size = ZNMethodDataOops::header_size() + (sizeof(oop*) * immediates.length());
  75   void* const data = NEW_C_HEAP_ARRAY(uint8_t, size, mtGC);
  76   return ::new (data) ZNMethodDataOops(immediates, has_non_immediates);
  77 }
  78 
  79 void ZNMethodDataOops::destroy(ZNMethodDataOops* oops) {
  80   ZNMethodTable::safe_delete(oops);
  81 }
  82 
  83 ZNMethodDataOops::ZNMethodDataOops(const GrowableArray<oop*>& immediates, bool has_non_immediates) :
  84     _nimmediates(immediates.length()),
  85     _has_non_immediates(has_non_immediates) {
  86   // Save all immediate oops
  87   for (size_t i = 0; i < _nimmediates; i++) {
  88     immediates_begin()[i] = immediates.at(i);
  89   }
  90 }
  91 
  92 size_t ZNMethodDataOops::immediates_count() const {
  93   return _nimmediates;
  94 }
  95 
  96 oop** ZNMethodDataOops::immediates_begin() const {
  97   // The immediate oop* array starts immediately after this object
  98   return (oop**)((uintptr_t)this + header_size());
  99 }
 100 


 107 }
 108 
 109 class ZNMethodData {
 110 private:
 111   ZReentrantLock             _lock;
 112   ZNMethodDataOops* volatile _oops;
 113 
 114   ZNMethodData(nmethod* nm);
 115 
 116 public:
 117   static ZNMethodData* create(nmethod* nm);
 118   static void destroy(ZNMethodData* data);
 119 
 120   ZReentrantLock* lock();
 121 
 122   ZNMethodDataOops* oops() const;
 123   ZNMethodDataOops* swap_oops(ZNMethodDataOops* oops);
 124 };
 125 
 126 ZNMethodData* ZNMethodData::create(nmethod* nm) {
 127   void* const method = NEW_C_HEAP_ARRAY(uint8_t, sizeof(ZNMethodData), mtGC);
 128   return ::new (method) ZNMethodData(nm);
 129 }
 130 
 131 void ZNMethodData::destroy(ZNMethodData* data) {
 132   ZNMethodDataOops::destroy(data->oops());
 133   ZNMethodTable::safe_delete(data);
 134 }
 135 
 136 ZNMethodData::ZNMethodData(nmethod* nm) :
 137     _lock(),
 138     _oops(NULL) {}
 139 
 140 ZReentrantLock* ZNMethodData::lock() {
 141   return &_lock;
 142 }
 143 
 144 ZNMethodDataOops* ZNMethodData::oops() const {
 145   return OrderAccess::load_acquire(&_oops);
 146 }
 147 
 148 ZNMethodDataOops* ZNMethodData::swap_oops(ZNMethodDataOops* new_oops) {
 149   return Atomic::xchg(new_oops, &_oops);
 150 }
 151 
 152 static ZNMethodData* gc_data(const nmethod* nm) {
 153   return nm->gc_data<ZNMethodData>();
 154 }
 155 
 156 static void set_gc_data(nmethod* nm, ZNMethodData* data) {
 157   return nm->set_gc_data<ZNMethodData>(data);
 158 }
 159 
 160 ZNMethodTableEntry* ZNMethodTable::_table = NULL;
 161 size_t ZNMethodTable::_size = 0;
 162 ZNMethodTableEntry* ZNMethodTable::_iter_table = NULL;
 163 size_t ZNMethodTable::_iter_table_size = 0;
 164 ZArray<void*> ZNMethodTable::_iter_deferred_deletes;
 165 size_t ZNMethodTable::_nregistered = 0;
 166 size_t ZNMethodTable::_nunregistered = 0;
 167 volatile size_t ZNMethodTable::_claimed = 0;
 168 
 169 void ZNMethodTable::safe_delete(void* data) {
 170   assert(CodeCache_lock->owned_by_self(), "Lock must be held");
 171 
 172   if (data == NULL) {
 173     return;
 174   }
 175 
 176   if (_iter_table != NULL) {
 177     // Iteration in progress, defer delete
 178     _iter_deferred_deletes.add(data);
 179   } else {
 180     // Iteration not in progress, delete now
 181     FREE_C_HEAP_ARRAY(uint8_t, data);
 182   }
 183 }
 184 
 185 void ZNMethodTable::attach_gc_data(nmethod* nm) {
 186   GrowableArray<oop*> immediate_oops;
 187   bool non_immediate_oops = false;
 188 
 189   // Find all oops relocations
 190   RelocIterator iter(nm);
 191   while (iter.next()) {
 192     if (iter.type() != relocInfo::oop_type) {
 193       // Not an oop
 194       continue;
 195     }
 196 
 197     oop_Relocation* r = iter.oop_reloc();
 198 
 199     if (!r->oop_is_immediate()) {
 200       // Non-immediate oop found
 201       non_immediate_oops = true;
 202       continue;
 203     }
 204 


 462   log_unregister(nm);
 463 
 464   // Remove entry
 465   unregister_entry(_table, _size, nm);
 466   _nunregistered++;
 467   _nregistered--;
 468 
 469   detach_gc_data(nm);
 470 }
 471 
 472 void ZNMethodTable::disarm_nmethod(nmethod* nm) {
 473   BarrierSetNMethod* const bs = BarrierSet::barrier_set()->barrier_set_nmethod();
 474   if (bs != NULL) {
 475     bs->disarm(nm);
 476   }
 477 }
 478 
 479 void ZNMethodTable::nmethods_do_begin() {
 480   MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
 481 



 482   // Prepare iteration
 483   _iter_table = _table;
 484   _iter_table_size = _size;
 485   _claimed = 0;
 486   assert(_iter_deferred_deletes.is_empty(), "Should be emtpy");
 487 }
 488 
 489 void ZNMethodTable::nmethods_do_end() {
 490   MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
 491 
 492   // Finish iteration
 493   if (_iter_table != _table) {
 494     delete [] _iter_table;
 495   }
 496   _iter_table = NULL;
 497 
 498   assert(_claimed >= _iter_table_size, "Failed to claim all table entries");
 499 
 500   // Process deferred deletes
 501   ZArrayIterator<void*> iter(&_iter_deferred_deletes);
 502   for (void* data; iter.next(&data);) {
 503     FREE_C_HEAP_ARRAY(uint8_t, data);
 504   }
 505   _iter_deferred_deletes.clear();
 506 
 507   // Notify iteration done
 508   CodeCache_lock->notify_all();
 509 }
 510 
 511 void ZNMethodTable::oops_do(nmethod* nm, OopClosure* cl) {
 512   // Process oops table
 513   oop* const begin = nm->oops_begin();
 514   oop* const end = nm->oops_end();
 515   for (oop* p = begin; p < end; p++) {
 516     if (*p != Universe::non_oop_word()) {
 517       cl->do_oop(p);
 518     }
 519   }
 520 
 521   ZNMethodDataOops* const oops = gc_data(nm)->oops();
 522 
 523   // Process immediate oops
 524   if (oops->immediates_count() > 0) {
 525     oop** const begin = oops->immediates_begin();


   1 /*
   2  * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 #include "precompiled.hpp"
  25 #include "code/relocInfo.hpp"
  26 #include "code/nmethod.hpp"
  27 #include "code/icBuffer.hpp"
  28 #include "gc/shared/barrierSet.hpp"
  29 #include "gc/shared/barrierSetNMethod.hpp"

  30 #include "gc/z/zGlobals.hpp"
  31 #include "gc/z/zHash.inline.hpp"
  32 #include "gc/z/zLock.inline.hpp"
  33 #include "gc/z/zNMethodAllocator.hpp"
  34 #include "gc/z/zNMethodTable.hpp"
  35 #include "gc/z/zOopClosures.inline.hpp"
  36 #include "gc/z/zTask.hpp"
  37 #include "gc/z/zWorkers.hpp"
  38 #include "logging/log.hpp"
  39 #include "memory/allocation.hpp"
  40 #include "memory/resourceArea.hpp"
  41 #include "runtime/atomic.hpp"
  42 #include "runtime/orderAccess.hpp"
  43 #include "utilities/debug.hpp"
  44 
  45 class ZNMethodDataOops {
  46 private:
  47   const size_t _nimmediates;
  48   bool         _has_non_immediates;
  49 
  50   static size_t header_size();
  51 
  52   ZNMethodDataOops(const GrowableArray<oop*>& immediates, bool has_non_immediates);
  53 
  54 public:
  55   static ZNMethodDataOops* create(const GrowableArray<oop*>& immediates, bool has_non_immediates);
  56   static void destroy(ZNMethodDataOops* oops);
  57 
  58   size_t immediates_count() const;
  59   oop**  immediates_begin() const;
  60   oop**  immediates_end()   const;
  61 
  62   bool   has_non_immediates() const;
  63 };
  64 
  65 size_t ZNMethodDataOops::header_size() {
  66   const size_t size = sizeof(ZNMethodDataOops);
  67   assert(is_aligned(size, sizeof(oop*)), "Header misaligned");
  68   return size;
  69 }
  70 
  71 ZNMethodDataOops* ZNMethodDataOops::create(const GrowableArray<oop*>& immediates, bool has_non_immediates) {
  72   // Allocate memory for the ZNMethodDataOops object
  73   // plus the immediate oop* array that follows right after.
  74   const size_t size = ZNMethodDataOops::header_size() + (sizeof(oop*) * immediates.length());
  75   void* const mem = ZNMethodAllocator::allocate(size);
  76   return ::new (mem) ZNMethodDataOops(immediates, has_non_immediates);
  77 }
  78 
  79 void ZNMethodDataOops::destroy(ZNMethodDataOops* oops) {
  80   ZNMethodAllocator::free(oops);
  81 }
  82 
  83 ZNMethodDataOops::ZNMethodDataOops(const GrowableArray<oop*>& immediates, bool has_non_immediates) :
  84     _nimmediates(immediates.length()),
  85     _has_non_immediates(has_non_immediates) {
  86   // Save all immediate oops
  87   for (size_t i = 0; i < _nimmediates; i++) {
  88     immediates_begin()[i] = immediates.at(i);
  89   }
  90 }
  91 
  92 size_t ZNMethodDataOops::immediates_count() const {
  93   return _nimmediates;
  94 }
  95 
  96 oop** ZNMethodDataOops::immediates_begin() const {
  97   // The immediate oop* array starts immediately after this object
  98   return (oop**)((uintptr_t)this + header_size());
  99 }
 100 


 107 }
 108 
 109 class ZNMethodData {
 110 private:
 111   ZReentrantLock             _lock;
 112   ZNMethodDataOops* volatile _oops;
 113 
 114   ZNMethodData(nmethod* nm);
 115 
 116 public:
 117   static ZNMethodData* create(nmethod* nm);
 118   static void destroy(ZNMethodData* data);
 119 
 120   ZReentrantLock* lock();
 121 
 122   ZNMethodDataOops* oops() const;
 123   ZNMethodDataOops* swap_oops(ZNMethodDataOops* oops);
 124 };
 125 
 126 ZNMethodData* ZNMethodData::create(nmethod* nm) {
 127   void* const mem = ZNMethodAllocator::allocate(sizeof(ZNMethodData));
 128   return ::new (mem) ZNMethodData(nm);
 129 }
 130 
 131 void ZNMethodData::destroy(ZNMethodData* data) {
 132   ZNMethodAllocator::free(data->oops());
 133   ZNMethodAllocator::free(data);
 134 }
 135 
 136 ZNMethodData::ZNMethodData(nmethod* nm) :
 137     _lock(),
 138     _oops(NULL) {}
 139 
 140 ZReentrantLock* ZNMethodData::lock() {
 141   return &_lock;
 142 }
 143 
 144 ZNMethodDataOops* ZNMethodData::oops() const {
 145   return OrderAccess::load_acquire(&_oops);
 146 }
 147 
 148 ZNMethodDataOops* ZNMethodData::swap_oops(ZNMethodDataOops* new_oops) {
 149   return Atomic::xchg(new_oops, &_oops);
 150 }
 151 
 152 static ZNMethodData* gc_data(const nmethod* nm) {
 153   return nm->gc_data<ZNMethodData>();
 154 }
 155 
 156 static void set_gc_data(nmethod* nm, ZNMethodData* data) {
 157   return nm->set_gc_data<ZNMethodData>(data);
 158 }
 159 
 160 ZNMethodTableEntry* ZNMethodTable::_table = NULL;
 161 size_t ZNMethodTable::_size = 0;
 162 ZNMethodTableEntry* ZNMethodTable::_iter_table = NULL;
 163 size_t ZNMethodTable::_iter_table_size = 0;

 164 size_t ZNMethodTable::_nregistered = 0;
 165 size_t ZNMethodTable::_nunregistered = 0;
 166 volatile size_t ZNMethodTable::_claimed = 0;
 167 
















 168 void ZNMethodTable::attach_gc_data(nmethod* nm) {
 169   GrowableArray<oop*> immediate_oops;
 170   bool non_immediate_oops = false;
 171 
 172   // Find all oops relocations
 173   RelocIterator iter(nm);
 174   while (iter.next()) {
 175     if (iter.type() != relocInfo::oop_type) {
 176       // Not an oop
 177       continue;
 178     }
 179 
 180     oop_Relocation* r = iter.oop_reloc();
 181 
 182     if (!r->oop_is_immediate()) {
 183       // Non-immediate oop found
 184       non_immediate_oops = true;
 185       continue;
 186     }
 187 


 445   log_unregister(nm);
 446 
 447   // Remove entry
 448   unregister_entry(_table, _size, nm);
 449   _nunregistered++;
 450   _nregistered--;
 451 
 452   detach_gc_data(nm);
 453 }
 454 
 455 void ZNMethodTable::disarm_nmethod(nmethod* nm) {
 456   BarrierSetNMethod* const bs = BarrierSet::barrier_set()->barrier_set_nmethod();
 457   if (bs != NULL) {
 458     bs->disarm(nm);
 459   }
 460 }
 461 
 462 void ZNMethodTable::nmethods_do_begin() {
 463   MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
 464 
 465   // Make sure we don't free data while iterating
 466   ZNMethodAllocator::activate_deferred_frees();
 467 
 468   // Prepare iteration
 469   _iter_table = _table;
 470   _iter_table_size = _size;
 471   _claimed = 0;

 472 }
 473 
 474 void ZNMethodTable::nmethods_do_end() {
 475   MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
 476 
 477   // Finish iteration
 478   if (_iter_table != _table) {
 479     delete [] _iter_table;
 480   }
 481   _iter_table = NULL;
 482 
 483   assert(_claimed >= _iter_table_size, "Failed to claim all table entries");
 484 
 485   // Process deferred frees
 486   ZNMethodAllocator::deactivate_and_process_deferred_frees();




 487 
 488   // Notify iteration done
 489   CodeCache_lock->notify_all();
 490 }
 491 
 492 void ZNMethodTable::oops_do(nmethod* nm, OopClosure* cl) {
 493   // Process oops table
 494   oop* const begin = nm->oops_begin();
 495   oop* const end = nm->oops_end();
 496   for (oop* p = begin; p < end; p++) {
 497     if (*p != Universe::non_oop_word()) {
 498       cl->do_oop(p);
 499     }
 500   }
 501 
 502   ZNMethodDataOops* const oops = gc_data(nm)->oops();
 503 
 504   // Process immediate oops
 505   if (oops->immediates_count() > 0) {
 506     oop** const begin = oops->immediates_begin();


< prev index next >