< prev index next >
src/hotspot/cpu/aarch64/gc/shared/barrierSetNMethod_aarch64.cpp
Print this page
rev 58823 : [mq]: aarch64-jdk-nmethod-barriers-3.patch
*** 1,7 ****
/*
! * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
--- 1,7 ----
/*
! * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*** 21,40 ****
* questions.
*
*/
#include "precompiled.hpp"
#include "gc/shared/barrierSetNMethod.hpp"
#include "utilities/debug.hpp"
void BarrierSetNMethod::deoptimize(nmethod* nm, address* return_address_ptr) {
! ShouldNotReachHere();
}
void BarrierSetNMethod::disarm(nmethod* nm) {
! ShouldNotReachHere();
}
bool BarrierSetNMethod::is_armed(nmethod* nm) {
! ShouldNotReachHere();
return false;
}
--- 21,166 ----
* questions.
*
*/
#include "precompiled.hpp"
+ #include "code/codeCache.hpp"
+ #include "code/nativeInst.hpp"
#include "gc/shared/barrierSetNMethod.hpp"
+ #include "logging/log.hpp"
+ #include "memory/resourceArea.hpp"
+ #include "runtime/sharedRuntime.hpp"
+ #include "runtime/thread.hpp"
+ #include "utilities/align.hpp"
#include "utilities/debug.hpp"
+ #include "icache_aarch64.hpp"
+ class NativeNMethodBarrier: public NativeInstruction {
+ address instruction_address() const { return addr_at(0); }
+
+ int *guard_addr() {
+ return reinterpret_cast<int*>(instruction_address() + 10 * 4);
+ }
+
+ public:
+ int get_value() {
+ return Atomic::load_acquire(guard_addr());
+ }
+
+ void set_value(int value) {
+ Atomic::release_store(guard_addr(), value);
+ }
+
+ void verify() const;
+ };
+
+ // Store the instruction bitmask, bits and name for checking the barrier.
+ struct CheckInsn {
+ uint32_t mask;
+ uint32_t bits;
+ const char *name;
+ };
+
+ static const struct CheckInsn barrierInsn[] = {
+ { 0xff000000, 0x18000000, "ldr (literal)" },
+ { 0xfffff0ff, 0xd50330bf, "dmb" },
+ { 0xffc00000, 0xb9400000, "ldr"},
+ { 0x7f20001f, 0x6b00001f, "cmp"},
+ { 0xff00001f, 0x54000000, "b.eq"},
+ { 0xff800000, 0xd2800000, "mov"},
+ { 0xff800000, 0xf2800000, "movk"},
+ { 0xff800000, 0xf2800000, "movk"},
+ { 0xfffffc1f, 0xd63f0000, "blr"},
+ { 0xfc000000, 0x14000000, "b"}
+ };
+
+ // The encodings must match the instructions emitted by
+ // BarrierSetAssembler::nmethod_entry_barrier. The matching ignores the specific
+ // register numbers and immediate values in the encoding.
+ void NativeNMethodBarrier::verify() const {
+ intptr_t addr = (intptr_t) instruction_address();
+ for(unsigned int i = 0; i < sizeof(barrierInsn)/sizeof(struct CheckInsn); i++ ) {
+ uint32_t inst = *((uint32_t*) addr);
+ if ((inst & barrierInsn[i].mask) != barrierInsn[i].bits) {
+ tty->print_cr("Addr: " INTPTR_FORMAT " Code: 0x%x", addr, inst);
+ fatal("not an %s instruction.", barrierInsn[i].name);
+ }
+ addr +=4;
+ }
+ }
+
+
+ /* We're called from an nmethod when we need to deoptimize it. We do
+ this by throwing away the nmethod's frame and jumping to the
+ ic_miss stub. This looks like there has been an IC miss at the
+ entry of the nmethod, so we resolve the call, which will fall back
+ to the interpreter if the nmethod has been unloaded. */
void BarrierSetNMethod::deoptimize(nmethod* nm, address* return_address_ptr) {
!
! typedef struct {
! intptr_t *sp; intptr_t *fp; address lr; address pc;
! } frame_pointers_t;
!
! frame_pointers_t *new_frame = (frame_pointers_t *)(return_address_ptr - 5);
!
! JavaThread *thread = (JavaThread*)Thread::current();
! RegisterMap reg_map(thread, false);
! frame frame = thread->last_frame();
!
! assert(frame.is_compiled_frame() || frame.is_native_frame(), "must be");
! assert(frame.cb() == nm, "must be");
! frame = frame.sender(®_map);
!
! LogTarget(Trace, nmethod, barrier) out;
! if (out.is_enabled()) {
! Thread* thread = Thread::current();
! assert(thread->is_Java_thread(), "must be JavaThread");
! JavaThread* jth = (JavaThread*) thread;
! ResourceMark mark;
! log_trace(nmethod, barrier)("deoptimize(nmethod: %s(%p), return_addr: %p, osr: %d, thread: %p(%s), making rsp: %p) -> %p",
! nm->method()->name_and_sig_as_C_string(),
! nm, *(address *) return_address_ptr, nm->is_osr_method(), jth,
! jth->get_thread_name(), frame.sp(), nm->verified_entry_point());
! }
!
! new_frame->sp = frame.sp();
! new_frame->fp = frame.fp();
! new_frame->lr = frame.pc();
! new_frame->pc = SharedRuntime::get_handle_wrong_method_stub();
! }
!
! // This is the offset of the entry barrier from where the frame is completed.
! // If any code changes between the end of the verified entry where the entry
! // barrier resides, and the completion of the frame, then
! // NativeNMethodCmpBarrier::verify() will immediately complain when it does
! // not find the expected native instruction at this offset, which needs updating.
! // Note that this offset is invariant of PreserveFramePointer.
!
! static const int entry_barrier_offset = -4 * 11;
!
! static NativeNMethodBarrier* native_nmethod_barrier(nmethod* nm) {
! address barrier_address = nm->code_begin() + nm->frame_complete_offset() + entry_barrier_offset;
! NativeNMethodBarrier* barrier = reinterpret_cast<NativeNMethodBarrier*>(barrier_address);
! debug_only(barrier->verify());
! return barrier;
}
void BarrierSetNMethod::disarm(nmethod* nm) {
! if (!supports_entry_barrier(nm)) {
! return;
! }
!
! // Disarms the nmethod guard emitted by BarrierSetAssembler::nmethod_entry_barrier.
! // Symmetric "LDR; DMB ISHLD" is in the nmethod barrier.
! NativeNMethodBarrier* barrier = native_nmethod_barrier(nm);
!
! barrier->set_value(disarmed_value());
}
bool BarrierSetNMethod::is_armed(nmethod* nm) {
! if (!supports_entry_barrier(nm)) {
return false;
+ }
+
+ NativeNMethodBarrier* barrier = native_nmethod_barrier(nm);
+ return barrier->get_value() != disarmed_value();
}
< prev index next >