1 /*
  2  * Copyright (c) 2019, 2022, Red Hat, Inc. 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 
 25 
 26 #include "gc/shenandoah/shenandoahBarrierSetAssembler.hpp"
 27 #include "gc/shenandoah/shenandoahBarrierSetNMethod.hpp"
 28 #include "gc/shenandoah/shenandoahClosures.inline.hpp"
 29 #include "gc/shenandoah/shenandoahCodeRoots.hpp"
 30 #include "gc/shenandoah/shenandoahHeap.inline.hpp"
 31 #include "gc/shenandoah/shenandoahLock.hpp"
 32 #include "gc/shenandoah/shenandoahNMethod.inline.hpp"
 33 #include "gc/shenandoah/shenandoahStackChunkGCData.hpp"
 34 #include "gc/shenandoah/shenandoahStackWatermark.hpp"
 35 #include "gc/shenandoah/shenandoahThreadLocalData.hpp"
 36 #include "memory/iterator.hpp"
 37 #include "memory/resourceArea.hpp"
 38 #include "runtime/threadWXSetters.inline.hpp"
 39 
 40 bool ShenandoahBarrierSetNMethod::nmethod_entry_barrier(nmethod* nm) {
 41   if (!is_armed(nm)) {
 42     // Some other thread got here first and healed the oops
 43     // and disarmed the nmethod. No need to continue.
 44     return true;
 45   }
 46 
 47   ShenandoahNMethodLock* lock = ShenandoahNMethod::lock_for_nmethod(nm);
 48   assert(lock != nullptr, "Must be");
 49   ShenandoahNMethodLocker locker(lock);
 50 
 51   if (!is_armed(nm)) {
 52     // Some other thread managed to complete while we were
 53     // waiting for lock. No need to continue.
 54     return true;
 55   }
 56 
 57   MACOS_AARCH64_ONLY(ThreadWXEnable wx(WXWrite, Thread::current());)
 58 
 59   if (nm->is_unloading()) {
 60     // We don't need to take the lock when unlinking nmethods from
 61     // the Method, because it is only concurrently unlinked by
 62     // the entry barrier, which acquires the per nmethod lock.
 63     nm->unlink_from_method();
 64 
 65     // We can end up calling nmethods that are unloading
 66     // since we clear compiled ICs lazily. Returning false
 67     // will re-resolve the call and update the compiled IC.
 68     return false;
 69   }
 70 
 71   bool changed = false;
 72 
 73   // Handle oops and jumps.
 74   changed |= ShenandoahNMethod::handle_oops(nm);
 75   changed |= ShenandoahNMethod::handle_jumps(nm);
 76 
 77   // If any code changed, bulk invalidate the entire nmethod.
 78   if (changed) {
 79     ICache::invalidate_range(nm->code_begin(), nm->code_size());
 80   }
 81 
 82   // CodeCache unloading support
 83   nm->mark_as_maybe_on_stack();
 84 
 85   // Disarm
 86   ShenandoahNMethod::disarm_nmethod(nm);
 87   return true;
 88 }
 89 
 90 void ShenandoahBarrierSetNMethod::finalize_relocations(nmethod* nm) {
 91   RelocIterator iter(nm);
 92   while (iter.next()) {
 93     if (iter.type() == relocInfo::patchable_barrier_type) {
 94       patchable_barrier_Relocation* r = iter.patchable_barrier_reloc();
 95       if (!r->is_target_offset_resolved()) {
 96         address pc = r->addr();
 97         address target = ShenandoahBarrierSetAssembler::parse_jump_address(pc);
 98         r->set_target_offset(target - nm->code_begin());
 99       } else {
100         // Already set. This is likely nmethod relocation, so just trust
101         // the existing relocation data.
102       }
103     }
104   }
105 }
106 
107 void ShenandoahBarrierSetNMethod::arm_all_nmethods() {
108   BarrierSetNMethod::arm_all_nmethods();
109 
110   // Arming should also activate stack watermark machinery.
111   // See ShenandoahNMethod::patch_jump.
112   ShenandoahStackWatermark::change_epoch_id();
113 
114   // All currently allocated stack chunks now need to be fixed up.
115   ShenandoahStackChunkGCData::change_epoch_id();
116 }