Skip to content

Commit 245f0cf

Browse files
Aleksei VoitylovTheRealMDoerr
authored andcommitted
8291302: ARM32: nmethod entry barriers support
Reviewed-by: eosterlund, rrich, mdoerr, aph
1 parent a9ce772 commit 245f0cf

12 files changed

+268
-5
lines changed

src/hotspot/cpu/arm/arm.ad

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,9 @@ source_hpp %{
5959
// To keep related declarations/definitions/uses close together,
6060
// we switch between source %{ }% and source_hpp %{ }% freely as needed.
6161

62+
#include "asm/macroAssembler.hpp"
63+
#include "gc/shared/barrierSetAssembler.hpp"
64+
6265
// Does destination need to be loaded in a register then passed to a
6366
// branch instruction?
6467
extern bool maybe_far_call(const CallNode *n);
@@ -286,6 +289,17 @@ void MachPrologNode::format( PhaseRegAlloc *ra_, outputStream *st ) const {
286289
if (framesize != 0) {
287290
st->print ("SUB R_SP, R_SP, " SIZE_FORMAT,framesize);
288291
}
292+
293+
if (C->stub_function() == NULL && BarrierSet::barrier_set()->barrier_set_nmethod() != NULL) {
294+
st->print("ldr t0, [guard]\n\t");
295+
st->print("ldr t1, [Rthread, #thread_disarmed_offset]\n\t");
296+
st->print("cmp t0, t1\n\t");
297+
st->print("beq skip\n\t");
298+
st->print("blr #nmethod_entry_barrier_stub\n\t");
299+
st->print("b skip\n\t");
300+
st->print("guard: int\n\t");
301+
st->print("skip:\n\t");
302+
}
289303
}
290304
#endif
291305

@@ -318,6 +332,11 @@ void MachPrologNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {
318332
__ sub_slow(SP, SP, framesize);
319333
}
320334

335+
if (C->stub_function() == NULL) {
336+
BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler();
337+
bs->nmethod_entry_barrier(&_masm);
338+
}
339+
321340
// offset from scratch buffer is not valid
322341
if (strcmp(cbuf.name(), "Compile::Fill_buffer") == 0) {
323342
C->output()->set_frame_complete( __ offset() );

src/hotspot/cpu/arm/c1_MacroAssembler_arm.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
#include "precompiled.hpp"
2626
#include "c1/c1_MacroAssembler.hpp"
2727
#include "c1/c1_Runtime1.hpp"
28+
#include "gc/shared/barrierSet.hpp"
29+
#include "gc/shared/barrierSetAssembler.hpp"
2830
#include "gc/shared/collectedHeap.hpp"
2931
#include "gc/shared/tlab_globals.hpp"
3032
#include "interpreter/interpreter.hpp"
@@ -62,6 +64,10 @@ void C1_MacroAssembler::build_frame(int frame_size_in_bytes, int bang_size_in_by
6264
// if this method contains a methodHandle call site
6365
raw_push(FP, LR);
6466
sub_slow(SP, SP, frame_size_in_bytes);
67+
68+
// Insert nmethod entry barrier into frame.
69+
BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler();
70+
bs->nmethod_entry_barrier(this);
6571
}
6672

6773
void C1_MacroAssembler::remove_frame(int frame_size_in_bytes) {

src/hotspot/cpu/arm/gc/shared/barrierSetAssembler_arm.cpp

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,13 @@
2323
*/
2424

2525
#include "precompiled.hpp"
26+
#include "gc/shared/barrierSet.hpp"
2627
#include "gc/shared/barrierSetAssembler.hpp"
28+
#include "gc/shared/barrierSetNMethod.hpp"
2729
#include "gc/shared/collectedHeap.hpp"
2830
#include "memory/universe.hpp"
2931
#include "runtime/javaThread.hpp"
32+
#include "runtime/stubRoutines.hpp"
3033

3134
#define __ masm->
3235

@@ -195,3 +198,47 @@ void BarrierSetAssembler::incr_allocated_bytes(MacroAssembler* masm, RegisterOrC
195198
// Unborrow the Rthread
196199
__ sub(Rthread, Ralloc, in_bytes(JavaThread::allocated_bytes_offset()));
197200
}
201+
202+
void BarrierSetAssembler::nmethod_entry_barrier(MacroAssembler* masm) {
203+
204+
BarrierSetNMethod* bs_nm = BarrierSet::barrier_set()->barrier_set_nmethod();
205+
206+
Register tmp0 = Rtemp;
207+
Register tmp1 = R5; // must be callee-save register
208+
209+
if (bs_nm == NULL) {
210+
return;
211+
}
212+
213+
// The are no GCs that require memory barrier on arm32 now
214+
#ifdef ASSERT
215+
NMethodPatchingType patching_type = nmethod_patching_type();
216+
assert(patching_type == NMethodPatchingType::stw_instruction_and_data_patch, "Unsupported patching type");
217+
#endif
218+
219+
Label skip, guard;
220+
Address thread_disarmed_addr(Rthread, in_bytes(bs_nm->thread_disarmed_offset()));
221+
222+
__ block_comment("nmethod_barrier begin");
223+
__ ldr_label(tmp0, guard);
224+
225+
// No memory barrier here
226+
__ ldr(tmp1, thread_disarmed_addr);
227+
__ cmp(tmp0, tmp1);
228+
__ b(skip, eq);
229+
230+
__ mov_address(tmp0, StubRoutines::Arm::method_entry_barrier());
231+
__ call(tmp0);
232+
__ b(skip);
233+
234+
__ bind(guard);
235+
236+
// nmethod guard value. Skipped over in common case.
237+
//
238+
// Put a debug value to make any offsets skew
239+
// clearly visible in coredump
240+
__ emit_int32(0xDEADBEAF);
241+
242+
__ bind(skip);
243+
__ block_comment("nmethod_barrier end");
244+
}

src/hotspot/cpu/arm/gc/shared/barrierSetAssembler_arm.hpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@
2929
#include "memory/allocation.hpp"
3030
#include "oops/access.hpp"
3131

32+
enum class NMethodPatchingType {
33+
stw_instruction_and_data_patch,
34+
};
35+
3236
class BarrierSetAssembler: public CHeapObj<mtGC> {
3337
private:
3438
void incr_allocated_bytes(MacroAssembler* masm,
@@ -56,6 +60,8 @@ class BarrierSetAssembler: public CHeapObj<mtGC> {
5660
);
5761

5862
virtual void barrier_stubs_init() {}
63+
virtual NMethodPatchingType nmethod_patching_type() { return NMethodPatchingType::stw_instruction_and_data_patch; }
64+
virtual void nmethod_entry_barrier(MacroAssembler* masm);
5965
};
6066

6167
#endif // CPU_ARM_GC_SHARED_BARRIERSETASSEMBLER_ARM_HPP

src/hotspot/cpu/arm/gc/shared/barrierSetNMethod_arm.cpp

Lines changed: 110 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,18 +23,124 @@
2323
*/
2424

2525
#include "precompiled.hpp"
26+
#include "code/nativeInst.hpp"
27+
#include "gc/shared/barrierSetAssembler.hpp"
2628
#include "gc/shared/barrierSetNMethod.hpp"
29+
#include "logging/log.hpp"
30+
#include "memory/resourceArea.hpp"
31+
#include "runtime/frame.inline.hpp"
32+
#include "runtime/javaThread.hpp"
33+
#include "runtime/sharedRuntime.hpp"
34+
#include "runtime/registerMap.hpp"
35+
#include "utilities/align.hpp"
2736
#include "utilities/debug.hpp"
2837

38+
// The constant below reflects the size of the barrier
39+
// in barrierSetAssembler_arm.cpp
40+
static const int entry_barrier_bytes = 9 * NativeInstruction::size();
41+
42+
class NativeNMethodBarrier: public NativeInstruction {
43+
address instruction_address() const { return addr_at(0); }
44+
45+
int *guard_addr() const {
46+
// Last instruction in a barrier
47+
return reinterpret_cast<int*>(instruction_address() + entry_barrier_bytes - wordSize);
48+
}
49+
50+
public:
51+
int get_value() {
52+
return Atomic::load_acquire(guard_addr());
53+
}
54+
55+
void set_value(int value) {
56+
Atomic::release_store(guard_addr(), value);
57+
}
58+
59+
void verify() const;
60+
};
61+
62+
// Check the first instruction of the nmethod entry barrier
63+
// to make sure that the offsets are not skewed.
64+
void NativeNMethodBarrier::verify() const {
65+
NativeInstruction *ni = (NativeInstruction *) instruction_address();
66+
if (!ni->is_ldr()) {
67+
uint32_t *addr = (uint32_t *) ni;
68+
tty->print_cr("Addr: " INTPTR_FORMAT " Code: 0x%x", (intptr_t) addr, (uint32_t) *addr);
69+
fatal("not an ldr instruction.");
70+
}
71+
}
72+
73+
static NativeNMethodBarrier* native_nmethod_barrier(nmethod* nm) {
74+
address barrier_address = nm->code_begin() + nm->frame_complete_offset() - entry_barrier_bytes;
75+
NativeNMethodBarrier* barrier = reinterpret_cast<NativeNMethodBarrier*>(barrier_address);
76+
debug_only(barrier->verify());
77+
return barrier;
78+
}
79+
80+
/* We're called from an nmethod when we need to deoptimize it. We do
81+
this by throwing away the nmethod's frame and jumping to the
82+
ic_miss stub. This looks like there has been an IC miss at the
83+
entry of the nmethod, so we resolve the call, which will fall back
84+
to the interpreter if the nmethod has been unloaded. */
2985
void BarrierSetNMethod::deoptimize(nmethod* nm, address* return_address_ptr) {
30-
ShouldNotReachHere();
86+
87+
typedef struct {
88+
intptr_t *sp; intptr_t *fp; address lr; address pc;
89+
} frame_pointers_t;
90+
91+
frame_pointers_t *new_frame = (frame_pointers_t *)(return_address_ptr - 5);
92+
93+
JavaThread *thread = JavaThread::current();
94+
RegisterMap reg_map(thread,
95+
RegisterMap::UpdateMap::skip,
96+
RegisterMap::ProcessFrames::include,
97+
RegisterMap::WalkContinuation::skip);
98+
frame frame = thread->last_frame();
99+
100+
assert(frame.is_compiled_frame() || frame.is_native_frame(), "must be");
101+
assert(frame.cb() == nm, "must be");
102+
frame = frame.sender(&reg_map);
103+
104+
LogTarget(Trace, nmethod, barrier) out;
105+
if (out.is_enabled()) {
106+
ResourceMark mark;
107+
log_trace(nmethod, barrier)("deoptimize(nmethod: %s(%p), return_addr: %p, osr: %d, thread: %p(%s), making rsp: %p) -> %p",
108+
nm->method()->name_and_sig_as_C_string(),
109+
nm, *(address *) return_address_ptr, nm->is_osr_method(), thread,
110+
thread->name(), frame.sp(), nm->verified_entry_point());
111+
}
112+
113+
new_frame->sp = frame.sp();
114+
new_frame->fp = frame.fp();
115+
new_frame->lr = frame.pc();
116+
new_frame->pc = SharedRuntime::get_handle_wrong_method_stub();
31117
}
32118

33119
void BarrierSetNMethod::disarm(nmethod* nm) {
34-
ShouldNotReachHere();
120+
if (!supports_entry_barrier(nm)) {
121+
return;
122+
}
123+
124+
// Disarms the nmethod guard emitted by BarrierSetAssembler::nmethod_entry_barrier.
125+
// Symmetric "LDR; DMB ISHLD" is in the nmethod barrier.
126+
NativeNMethodBarrier* barrier = native_nmethod_barrier(nm);
127+
barrier->set_value(disarmed_value());
128+
}
129+
130+
void BarrierSetNMethod::arm(nmethod* nm, int arm_value) {
131+
if (!supports_entry_barrier(nm)) {
132+
return;
133+
}
134+
135+
NativeNMethodBarrier* barrier = native_nmethod_barrier(nm);
136+
barrier->set_value(arm_value);
35137
}
36138

37139
bool BarrierSetNMethod::is_armed(nmethod* nm) {
38-
ShouldNotReachHere();
39-
return false;
140+
if (!supports_entry_barrier(nm)) {
141+
return false;
142+
}
143+
144+
NativeNMethodBarrier* barrier = native_nmethod_barrier(nm);
145+
return barrier->get_value() != disarmed_value();
40146
}

src/hotspot/cpu/arm/macroAssembler_arm.hpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -587,9 +587,23 @@ class MacroAssembler: public Assembler {
587587
AbstractAssembler::emit_address((address)L.data());
588588
}
589589

590+
void ldr_label(Register rd, Label& L) {
591+
ldr(rd, Address(PC, target(L) - pc() - 8));
592+
}
593+
590594
void resolve_oop_handle(Register result);
591595
void load_mirror(Register mirror, Register method, Register tmp);
592596

597+
void enter() {
598+
raw_push(FP, LR);
599+
mov(FP, SP);
600+
}
601+
602+
void leave() {
603+
mov(SP, FP);
604+
raw_pop(FP, LR);
605+
}
606+
593607
#define ARM_INSTR_1(common_mnemonic, arm32_mnemonic, arg_type) \
594608
void common_mnemonic(arg_type arg) { \
595609
arm32_mnemonic(arg); \

src/hotspot/cpu/arm/nativeInst_arm_32.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,9 +77,12 @@ class RawNativeInstruction {
7777
address instruction_address() const { return addr_at(0); }
7878
address next_raw_instruction_address() const { return addr_at(instruction_size); }
7979

80+
static int size() { return instruction_size; }
81+
8082
static RawNativeInstruction* at(address address) {
8183
return (RawNativeInstruction*)address;
8284
}
85+
8386
RawNativeInstruction* next_raw() const {
8487
return at(next_raw_instruction_address());
8588
}

src/hotspot/cpu/arm/sharedRuntime_arm.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include "code/icBuffer.hpp"
2929
#include "code/vtableStubs.hpp"
3030
#include "compiler/oopMap.hpp"
31+
#include "gc/shared/barrierSetAssembler.hpp"
3132
#include "interpreter/interpreter.hpp"
3233
#include "logging/log.hpp"
3334
#include "memory/resourceArea.hpp"
@@ -873,6 +874,10 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm,
873874
__ mov(FP, SP);
874875
__ sub_slow(SP, SP, stack_size - 2*wordSize);
875876

877+
BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler();
878+
assert(bs != NULL, "Sanity");
879+
bs->nmethod_entry_barrier(masm);
880+
876881
int frame_complete = __ pc() - start;
877882

878883
OopMapSet* oop_maps = new OopMapSet();

0 commit comments

Comments
 (0)