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     // No need to continue. We only need to sync up the changes done by others.
 44     cross_modify_fence();
 45     return true;
 46   }
 47 
 48   ShenandoahNMethodLock* lock = ShenandoahNMethod::lock_for_nmethod(nm);
 49   assert(lock != nullptr, "Must be");
 50   ShenandoahNMethodLocker locker(lock);
 51 
 52   if (!is_armed(nm)) {
 53     // Some other thread managed to complete while we were waiting for lock.
 54     // No need to continue. We only need to sync up the changes done by others.
 55     cross_modify_fence();
 56     return true;
 57   }
 58 
 59   MACOS_AARCH64_ONLY(ThreadWXEnable wx(WXWrite, Thread::current());)
 60 
 61   if (nm->is_unloading()) {
 62     // We don't need to take the lock when unlinking nmethods from
 63     // the Method, because it is only concurrently unlinked by
 64     // the entry barrier, which acquires the per nmethod lock.
 65     nm->unlink_from_method();
 66 
 67     // We can end up calling nmethods that are unloading
 68     // since we clear compiled ICs lazily. Returning false
 69     // will re-resolve the call and update the compiled IC.
 70     return false;
 71   }
 72 
 73   bool changed = false;
 74 
 75   // Handle oops and jumps.
 76   changed |= ShenandoahNMethod::handle_oops(nm);
 77   changed |= ShenandoahNMethod::handle_jumps(nm);
 78 
 79   // If any code changed, bulk invalidate the entire nmethod.
 80   if (changed) {
 81     ICache::invalidate_range(nm->code_begin(), nm->code_size());
 82   }
 83 
 84   // CodeCache unloading support
 85   nm->mark_as_maybe_on_stack();
 86 
 87   // Disarm
 88   ShenandoahNMethod::disarm_nmethod(nm);
 89 
 90   // Paranoia: sync up the changes done by others, even though we did a lot ourselves.
 91   cross_modify_fence();
 92 
 93   return true;
 94 }
 95 
 96 void ShenandoahBarrierSetNMethod::cross_modify_fence() {
 97   // For Java threads that can execute the nmethod code, we need to sync up
 98   // the code changes with current execution. Non-Java threads do not execute
 99   // the code, and thus do not need this fence. (VM has VerifyCrossModifyFence code
100   // that barfs when we attempt to do this.)
101   if (Thread::current()->is_Java_thread()) {
102     OrderAccess::cross_modify_fence();
103   }
104 }
105 
106 void ShenandoahBarrierSetNMethod::finalize_relocations(nmethod* nm) {
107   RelocIterator iter(nm);
108   while (iter.next()) {
109     if (iter.type() == relocInfo::patchable_barrier_type) {
110       patchable_barrier_Relocation* r = iter.patchable_barrier_reloc();
111       if (!r->is_target_offset_resolved()) {
112         address pc = r->addr();
113         address target = ShenandoahBarrierSetAssembler::parse_jump_address(pc);
114         r->set_target_offset(target - nm->code_begin());
115       } else {
116         // Already set. This is likely nmethod relocation, so just trust
117         // the existing relocation data.
118       }
119     }
120   }
121 }
122 
123 void ShenandoahBarrierSetNMethod::arm_all_nmethods() {
124   BarrierSetNMethod::arm_all_nmethods();
125 
126   // Arming should also activate stack watermark machinery.
127   // See ShenandoahNMethod::patch_jump.
128   ShenandoahStackWatermark::change_epoch_id();
129 
130   // All currently allocated stack chunks now need to be fixed up.
131   ShenandoahStackChunkGCData::change_epoch_id();
132 }