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