1 /*
  2  * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved.
  3  * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. All rights reserved.
  4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  5  *
  6  * This code is free software; you can redistribute it and/or modify it
  7  * under the terms of the GNU General Public License version 2 only, as
  8  * published by the Free Software Foundation.
  9  *
 10  * This code is distributed in the hope that it will be useful, but WITHOUT
 11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 13  * version 2 for more details (a copy is included in the LICENSE file that
 14  * accompanied this code).
 15  *
 16  * You should have received a copy of the GNU General Public License version
 17  * 2 along with this work; if not, write to the Free Software Foundation,
 18  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 19  *
 20  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 21  * or visit www.oracle.com if you need additional information or have any
 22  * questions.
 23  *
 24  */
 25 
 26 #include "code/codeCache.hpp"
 27 #include "code/nativeInst.hpp"
 28 #include "gc/shared/barrierSetAssembler.hpp"
 29 #include "gc/shared/barrierSetNMethod.hpp"
 30 #include "logging/log.hpp"
 31 #include "memory/resourceArea.hpp"
 32 #include "runtime/frame.inline.hpp"
 33 #include "runtime/javaThread.hpp"
 34 #include "runtime/registerMap.hpp"
 35 #include "runtime/sharedRuntime.hpp"
 36 #include "utilities/align.hpp"
 37 #include "utilities/debug.hpp"
 38 
 39 static int slow_path_size(nmethod* nm) {
 40   // The slow path code is out of line with C2.
 41   return nm->is_compiled_by_c2() ? 0 : 4;
 42 }
 43 
 44 static int entry_barrier_offset(nmethod* nm) {
 45   BarrierSetAssembler* bs_asm = BarrierSet::barrier_set()->barrier_set_assembler();
 46   switch (bs_asm->nmethod_patching_type()) {
 47     case NMethodPatchingType::stw_instruction_and_data_patch:
 48       return -4 * (5 + slow_path_size(nm));
 49     case NMethodPatchingType::conc_instruction_and_data_patch:
 50       return -4 * ((UseZtso ? 14 : 16) + slow_path_size(nm));
 51   }
 52   ShouldNotReachHere();
 53   return 0;
 54 }
 55 
 56 class NativeNMethodBarrier {
 57   address  _instruction_address;
 58   int*     _guard_addr;
 59   nmethod* _nm;
 60 
 61   address instruction_address() const { return _instruction_address; }
 62 
 63   int *guard_addr() {
 64     return _guard_addr;
 65   }
 66 
 67   int local_guard_offset(nmethod* nm) {
 68     // It's the last instruction
 69     return (-entry_barrier_offset(nm)) - 4;
 70   }
 71 
 72 public:
 73   NativeNMethodBarrier(nmethod* nm): _nm(nm) {
 74     _instruction_address = nm->code_begin() + nm->frame_complete_offset() + entry_barrier_offset(nm);
 75     if (nm->is_compiled_by_c2()) {
 76       // With c2 compiled code, the guard is out-of-line in a stub
 77       // We find it using the RelocIterator.
 78       RelocIterator iter(nm);
 79       while (iter.next()) {
 80         if (iter.type() == relocInfo::entry_guard_type) {
 81           entry_guard_Relocation* const reloc = iter.entry_guard_reloc();
 82           _guard_addr = reinterpret_cast<int*>(reloc->addr());
 83           return;
 84         }
 85       }
 86 
 87       ShouldNotReachHere();
 88     }
 89     _guard_addr = reinterpret_cast<int*>(instruction_address() + local_guard_offset(nm));
 90 
 91     // Perform the checking as verification.
 92     err_msg msg("%s", "");
 93     assert(check_barrier(msg), "%s", msg.buffer());
 94   }
 95 
 96   int get_value() {
 97     return AtomicAccess::load_acquire(guard_addr());
 98   }
 99 
100   void set_value(int value, int bit_mask) {
101     if (bit_mask == ~0) {
102       AtomicAccess::release_store(guard_addr(), value);
103       return;
104     }
105     assert((value & ~bit_mask) == 0, "trying to set bits outside the mask");
106     value &= bit_mask;
107     int old_value = AtomicAccess::load(guard_addr());
108     while (true) {
109       // Only bits in the mask are changed
110       int new_value = value | (old_value & ~bit_mask);
111       if (new_value == old_value) break;
112       int v = AtomicAccess::cmpxchg(guard_addr(), old_value, new_value, memory_order_release);
113       if (v == old_value) break;
114       old_value = v;
115     }
116   }
117 
118   bool check_barrier(err_msg& msg) const;
119 };
120 
121 // Store the instruction bitmask, bits and name for checking the barrier.
122 struct CheckInsn {
123   uint32_t mask;
124   uint32_t bits;
125   const char *name;
126 };
127 
128 static const struct CheckInsn barrierInsn[] = {
129   { 0x00000fff, 0x00000297, "auipc  t0, 0               " },
130   { 0x000fffff, 0x0002e283, "lwu    t0, guard_offset(t0)" },
131   /* ...... */
132   /* ...... */
133   /* guard: */
134   /* 32bit nmethod guard value */
135 };
136 
137 // The encodings must match the instructions emitted by
138 // BarrierSetAssembler::nmethod_entry_barrier. The matching ignores the specific
139 // register numbers and immediate values in the encoding.
140 bool NativeNMethodBarrier::check_barrier(err_msg& msg) const {
141   address addr = instruction_address();
142   for (unsigned int i = 0; i < sizeof(barrierInsn) / sizeof(struct CheckInsn); i++) {
143     uint32_t inst = Assembler::ld_instr(addr);
144     if ((inst & barrierInsn[i].mask) != barrierInsn[i].bits) {
145       msg.print("Nmethod entry barrier did not start with auipc & lwu as expected. "
146                 "Addr: " INTPTR_FORMAT " Code: 0x%x not an %s instruction.", p2i(addr), inst, barrierInsn[i].name);
147       return false;
148     }
149     addr += 4;
150   }
151   return true;
152 }
153 
154 
155 /* We're called from an nmethod when we need to deoptimize it. We do
156    this by throwing away the nmethod's frame and jumping to the
157    ic_miss stub. This looks like there has been an IC miss at the
158    entry of the nmethod, so we resolve the call, which will fall back
159    to the interpreter if the nmethod has been unloaded. */
160 void BarrierSetNMethod::deoptimize(nmethod* nm, address* return_address_ptr) {
161 
162   typedef struct {
163     intptr_t *sp; intptr_t *fp; address ra; address pc;
164   } frame_pointers_t;
165 
166   frame_pointers_t *new_frame = (frame_pointers_t *)(return_address_ptr - 5);
167 
168   JavaThread *thread = JavaThread::current();
169   RegisterMap reg_map(thread,
170                       RegisterMap::UpdateMap::skip,
171                       RegisterMap::ProcessFrames::include,
172                       RegisterMap::WalkContinuation::skip);
173   frame frame = thread->last_frame();
174 
175   assert(frame.is_compiled_frame() || frame.is_native_frame(), "must be");
176   assert(frame.cb() == nm, "must be");
177   frame = frame.sender(&reg_map);
178 
179   LogTarget(Trace, nmethod, barrier) out;
180   if (out.is_enabled()) {
181     ResourceMark mark;
182     log_trace(nmethod, barrier)("deoptimize(nmethod: %s(%p), return_addr: %p, osr: %d, thread: %p(%s), making rsp: %p) -> %p",
183                                 nm->method()->name_and_sig_as_C_string(),
184                                 nm, *(address *) return_address_ptr, nm->is_osr_method(), thread,
185                                 thread->name(), frame.sp(), nm->verified_entry_point());
186   }
187 
188   new_frame->sp = frame.sp();
189   new_frame->fp = frame.fp();
190   new_frame->ra = frame.pc();
191   new_frame->pc = SharedRuntime::get_handle_wrong_method_stub();
192 }
193 
194 void BarrierSetNMethod::set_guard_value(nmethod* nm, int value, int bit_mask) {
195   if (!supports_entry_barrier(nm)) {
196     return;
197   }
198 
199   if (value == disarmed_guard_value()) {
200     // The patching epoch is incremented before the nmethod is disarmed. Disarming
201     // is performed with a release store. In the nmethod entry barrier, the values
202     // are read in the opposite order, such that the load of the nmethod guard
203     // acquires the patching epoch. This way, the guard is guaranteed to block
204     // entries to the nmethod, until it has safely published the requirement for
205     // further fencing by mutators, before they are allowed to enter.
206     BarrierSetAssembler* bs_asm = BarrierSet::barrier_set()->barrier_set_assembler();
207     bs_asm->increment_patching_epoch();
208   }
209 
210   NativeNMethodBarrier barrier(nm);
211   barrier.set_value(value, bit_mask);
212 }
213 
214 int BarrierSetNMethod::guard_value(nmethod* nm) {
215   if (!supports_entry_barrier(nm)) {
216     return disarmed_guard_value();
217   }
218 
219   NativeNMethodBarrier barrier(nm);
220   return barrier.get_value();
221 }