8284161: Implementation of Virtual Threads (Preview)

Co-authored-by: Ron Pressler <rpressler@openjdk.org>
Co-authored-by: Alan Bateman <alanb@openjdk.org>
Co-authored-by: Erik Österlund <eosterlund@openjdk.org>
Co-authored-by: Andrew Haley <aph@openjdk.org>
Co-authored-by: Rickard Bäckman <rbackman@openjdk.org>
Co-authored-by: Markus Grönlund <mgronlun@openjdk.org>
Co-authored-by: Leonid Mesnik <lmesnik@openjdk.org>
Co-authored-by: Serguei Spitsyn <sspitsyn@openjdk.org>
Co-authored-by: Chris Plummer <cjplummer@openjdk.org>
Co-authored-by: Coleen Phillimore <coleenp@openjdk.org>
Co-authored-by: Robbin Ehn <rehn@openjdk.org>
Co-authored-by: Stefan Karlsson <stefank@openjdk.org>
Co-authored-by: Thomas Schatzl <tschatzl@openjdk.org>
Co-authored-by: Sergey Kuksenko <skuksenko@openjdk.org>
Reviewed-by: lancea, eosterlund, rehn, sspitsyn, stefank, tschatzl, dfuchs, lmesnik, dcubed, kevinw, amenkov, dlong, mchung, psandoz, bpb, coleenp, smarks, egahlin, mseledtsov, coffeys, darcy
This commit is contained in:
Alan Bateman 2022-05-07 08:06:16 +00:00
parent 5212535a27
commit 9583e3657e
1133 changed files with 95935 additions and 8335 deletions

View File

@ -46,7 +46,9 @@ JVM_ConstantPoolGetSize
JVM_ConstantPoolGetStringAt
JVM_ConstantPoolGetTagAt
JVM_ConstantPoolGetUTF8At
JVM_CurrentCarrierThread
JVM_CurrentThread
JVM_SetCurrentThread
JVM_CurrentTimeMillis
JVM_DefineClass
JVM_DefineClassWithSource
@ -120,6 +122,7 @@ JVM_GetMethodTypeAnnotations
JVM_GetNanoTimeAdjustment
JVM_GetNestHost
JVM_GetNestMembers
JVM_GetNextThreadIdOffset
JVM_GetPermittedSubclasses
JVM_GetPrimitiveArrayElement
JVM_GetProperties
@ -135,6 +138,7 @@ JVM_GetVmArguments
JVM_Halt
JVM_HasReferencePendingList
JVM_HoldsLock
JVM_GetStackTrace
JVM_IHashCode
JVM_InitClassName
JVM_InitStackTraceElement
@ -150,6 +154,7 @@ JVM_IsDumpingClassList
JVM_IsFinalizationEnabled
JVM_IsHiddenClass
JVM_IsInterface
JVM_IsPreviewEnabled
JVM_IsPrimitiveClass
JVM_IsRecord
JVM_IsSameClassPackage
@ -182,15 +187,19 @@ JVM_RawMonitorEnter
JVM_RawMonitorExit
JVM_ReferenceClear
JVM_ReferenceRefersTo
JVM_RegisterContinuationMethods
JVM_RegisterLambdaProxyClassForArchiving
JVM_RegisterSignal
JVM_ReleaseUTF
JVM_ReportFinalizationComplete
JVM_ResumeThread
JVM_ExtentLocalCache
JVM_SetExtentLocalCache
JVM_SetArrayElement
JVM_SetClassSigners
JVM_SetNativeThreadName
JVM_SetPrimitiveArrayElement
JVM_SetStackWalkContinuation
JVM_SetThreadPriority
JVM_Sleep
JVM_StartThread
@ -210,3 +219,10 @@ JVM_AddReadsModule
JVM_DefineArchivedModules
JVM_DefineModule
JVM_SetBootLoaderUnnamedModule
# Virtual thread notifications for JVMTI
JVM_VirtualThreadMountBegin
JVM_VirtualThreadMountEnd
JVM_VirtualThreadUnmountBegin
JVM_VirtualThreadUnmountEnd
#

View File

@ -95,8 +95,12 @@ $(eval $(call SetupJavaCompilation, BUILD_JDK_MICROBENCHMARK, \
SRC := $(MICROBENCHMARK_SRC), \
BIN := $(MICROBENCHMARK_CLASSES), \
JAVAC_FLAGS := --add-exports java.base/sun.security.util=ALL-UNNAMED \
--add-exports java.base/sun.invoke.util=ALL-UNNAMED, \
JAVA_FLAGS := --add-modules jdk.unsupported --limit-modules java.management, \
--add-exports java.base/sun.invoke.util=ALL-UNNAMED \
--add-exports java.base/jdk.internal.vm=ALL-UNNAMED \
--enable-preview, \
JAVA_FLAGS := --add-modules jdk.unsupported --limit-modules java.management \
--add-exports java.base/jdk.internal.vm=ALL-UNNAMED \
--enable-preview, \
))
$(BUILD_JDK_MICROBENCHMARK): $(JMH_COMPILE_JARS)

View File

@ -1,5 +1,5 @@
#
# Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2015, 2022, 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
@ -148,8 +148,10 @@ BUILD_HOTSPOT_JTREG_LIBRARIES_CFLAGS_libNoFramePointer := $(NO_FRAMEPOINTER_CFLA
# Optimization -O3 needed, HIGH == -O3
BUILD_HOTSPOT_JTREG_LIBRARIES_OPTIMIZATION_libNoFramePointer := HIGH
BUILD_HOTSPOT_JTREG_LIBRARIES_CFLAGS := -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS
BUILD_HOTSPOT_JTREG_EXECUTABLES_CFLAGS := -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS
JVMTI_COMMON_INCLUDES=-I$(TOPDIR)/test/lib/jdk/test/lib/jvmti
BUILD_HOTSPOT_JTREG_LIBRARIES_CFLAGS := -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS $(JVMTI_COMMON_INCLUDES)
BUILD_HOTSPOT_JTREG_EXECUTABLES_CFLAGS := -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS $(JVMTI_COMMON_INCLUDES)
BUILD_HOTSPOT_JTREG_LIBRARIES_CFLAGS_libProcessUtils := $(VM_SHARE_INCLUDES)
@ -346,6 +348,7 @@ BUILD_HOTSPOT_JTREG_LIBRARIES_CFLAGS_libvminit001 := $(NSK_JVMTI_AGENT_INCLUDES)
BUILD_HOTSPOT_JTREG_LIBRARIES_CFLAGS_libsuspendthrd001 := $(NSK_JVMTI_AGENT_INCLUDES)
BUILD_HOTSPOT_JTREG_LIBRARIES_CFLAGS_libsuspendthrd002 := $(NSK_JVMTI_AGENT_INCLUDES)
BUILD_HOTSPOT_JTREG_LIBRARIES_CFLAGS_libsuspendthrd003 := $(NSK_JVMTI_AGENT_INCLUDES)
BUILD_HOTSPOT_JTREG_LIBRARIES_CFLAGS_libsuspendvthr001 := $(NSK_JVMTI_AGENT_INCLUDES)
BUILD_HOTSPOT_JTREG_LIBRARIES_CFLAGS_libdeclcls002 := $(NSK_JVMTI_AGENT_INCLUDES)
BUILD_HOTSPOT_JTREG_LIBRARIES_CFLAGS_libdeclcls003 := $(NSK_JVMTI_AGENT_INCLUDES)
BUILD_HOTSPOT_JTREG_LIBRARIES_CFLAGS_libdeclcls001 := $(NSK_JVMTI_AGENT_INCLUDES)
@ -1012,6 +1015,7 @@ else
BUILD_HOTSPOT_JTREG_LIBRARIES_LIBS_libsuspendthrd001 += -lpthread
BUILD_HOTSPOT_JTREG_LIBRARIES_LIBS_libsuspendthrd002 += -lpthread
BUILD_HOTSPOT_JTREG_LIBRARIES_LIBS_libsuspendthrd003 += -lpthread
BUILD_HOTSPOT_JTREG_LIBRARIES_LIBS_libsuspendvthr001 += -lpthread
BUILD_HOTSPOT_JTREG_LIBRARIES_LIBS_libdeclcls002 += -lpthread
BUILD_HOTSPOT_JTREG_LIBRARIES_LIBS_libdeclcls003 += -lpthread
BUILD_HOTSPOT_JTREG_LIBRARIES_LIBS_libdeclcls001 += -lpthread

View File

@ -3829,6 +3829,8 @@ encode %{
}
}
__ post_call_nop();
// Only non uncommon_trap calls need to reinitialize ptrue.
if (Compile::current()->max_vector_size() > 0 && uncommon_trap_request() == 0) {
__ reinitialize_ptrue();
@ -3842,7 +3844,9 @@ encode %{
if (call == NULL) {
ciEnv::current()->record_failure("CodeCache is full");
return;
} else if (Compile::current()->max_vector_size() > 0) {
}
__ post_call_nop();
if (Compile::current()->max_vector_size() > 0) {
__ reinitialize_ptrue();
}
%}
@ -3870,6 +3874,7 @@ encode %{
ciEnv::current()->record_failure("CodeCache is full");
return;
}
__ post_call_nop();
} else {
Label retaddr;
__ adr(rscratch2, retaddr);
@ -3878,6 +3883,7 @@ encode %{
__ stp(zr, rscratch2, Address(__ pre(sp, -2 * wordSize)));
__ blr(rscratch1);
__ bind(retaddr);
__ post_call_nop();
__ add(sp, sp, 2 * wordSize);
}
if (Compile::current()->max_vector_size() > 0) {

View File

@ -123,9 +123,9 @@ void AbstractInterpreter::layout_activation(Method* method,
// It is also guaranteed to be walkable even though it is in a
// skeletal state
int max_locals = method->max_locals() * Interpreter::stackElementWords;
int extra_locals = (method->max_locals() - method->size_of_parameters()) *
Interpreter::stackElementWords;
const int max_locals = method->max_locals() * Interpreter::stackElementWords;
const int params = method->size_of_parameters() * Interpreter::stackElementWords;
const int extra_locals = max_locals - params;
#ifdef ASSERT
assert(caller->sp() == interpreter_frame->sender_sp(), "Frame not properly walkable");
@ -144,12 +144,9 @@ void AbstractInterpreter::layout_activation(Method* method,
// align the incoming parameters with the caller's temporary
// expression stack. For other types of caller frame it doesn't
// matter.
intptr_t* locals;
if (caller->is_interpreted_frame()) {
locals = caller->interpreter_frame_last_sp() + caller_actual_parameters - 1;
} else {
locals = interpreter_frame->sender_sp() + max_locals - 1;
}
intptr_t* const locals = caller->is_interpreted_frame()
? caller->interpreter_frame_last_sp() + caller_actual_parameters - 1
: interpreter_frame->sender_sp() + max_locals - 1;
#ifdef ASSERT
if (caller->is_interpreted_frame()) {
@ -171,14 +168,10 @@ void AbstractInterpreter::layout_activation(Method* method,
// All frames but the initial (oldest) interpreter frame we fill in have
// a value for sender_sp that allows walking the stack but isn't
// truly correct. Correct the value here.
if (extra_locals != 0 &&
interpreter_frame->sender_sp() ==
interpreter_frame->interpreter_frame_sender_sp()) {
interpreter_frame->set_interpreter_frame_sender_sp(caller->sp() +
extra_locals);
if (extra_locals != 0 && interpreter_frame->sender_sp() == interpreter_frame->interpreter_frame_sender_sp()) {
interpreter_frame->set_interpreter_frame_sender_sp(caller->sp() + extra_locals);
}
*interpreter_frame->interpreter_frame_cache_addr() =
method->constants()->cache();
*interpreter_frame->interpreter_frame_mirror_addr() =
method->method_holder()->java_mirror();
*interpreter_frame->interpreter_frame_cache_addr() = method->constants()->cache();
*interpreter_frame->interpreter_frame_mirror_addr() = method->method_holder()->java_mirror();
}

View File

@ -438,6 +438,7 @@ int LIR_Assembler::emit_unwind_handler() {
__ unlock_object(r5, r4, r0, *stub->entry());
}
__ bind(*stub->continuation());
__ dec_held_monitor_count(rthread);
}
if (compilation()->env()->dtrace_method_probes()) {
@ -2037,6 +2038,7 @@ void LIR_Assembler::call(LIR_OpJavaCall* op, relocInfo::relocType rtype) {
return;
}
add_call_info(code_offset(), op->info());
__ post_call_nop();
}
@ -2047,6 +2049,7 @@ void LIR_Assembler::ic_call(LIR_OpJavaCall* op) {
return;
}
add_call_info(code_offset(), op->info());
__ post_call_nop();
}
void LIR_Assembler::emit_static_call_stub() {
@ -2571,7 +2574,18 @@ void LIR_Assembler::emit_lock(LIR_OpLock* op) {
} else {
Unimplemented();
}
if (op->code() == lir_lock) {
// If deoptimization happens in Runtime1::monitorenter, inc_held_monitor_count after backing from slowpath
// will be skipped. Solution is:
// 1. Increase only in fastpath
// 2. Runtime1::monitorenter increase count after locking
__ inc_held_monitor_count(rthread);
}
__ bind(*op->stub()->continuation());
if (op->code() == lir_unlock) {
// unlock in slowpath is JRT_Leaf stub, no deoptimization can happen
__ dec_held_monitor_count(rthread);
}
}
void LIR_Assembler::emit_load_klass(LIR_OpLoadKlass* op) {
@ -2899,6 +2913,7 @@ void LIR_Assembler::rt_call(LIR_Opr result, address dest, const LIR_OprList* arg
if (info != NULL) {
add_call_info_here(info);
}
__ post_call_nop();
}
void LIR_Assembler::volatile_move_op(LIR_Opr src, LIR_Opr dest, BasicType type, CodeEmitInfo* info) {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2005, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, Red Hat Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@ -338,6 +338,17 @@ void LIRGenerator::do_MonitorExit(MonitorExit* x) {
monitor_exit(obj_temp, lock, syncTempOpr(), LIR_OprFact::illegalOpr, x->monitor_no());
}
void LIRGenerator::do_continuation_doYield(Intrinsic* x) {
BasicTypeList signature(0);
CallingConvention* cc = frame_map()->java_calling_convention(&signature, true);
const LIR_Opr result_reg = result_register_for(x->type());
address entry = StubRoutines::cont_doYield();
LIR_Opr result = rlock_result(x);
CodeEmitInfo* info = state_for(x, x->state());
__ call_runtime(entry, LIR_OprFact::illegalOpr, result_reg, cc->args(), info);
__ move(result_reg, result);
}
void LIRGenerator::do_NegateOp(NegateOp* x) {

View File

@ -0,0 +1,51 @@
/*
* Copyright (c) 2022, 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.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#ifndef CPU_AARCH64_CONTINUATIONENTRY_AARCH64_INLINE_HPP
#define CPU_AARCH64_CONTINUATIONENTRY_AARCH64_INLINE_HPP
#include "runtime/continuationEntry.hpp"
#include "code/codeCache.hpp"
#include "runtime/frame.inline.hpp"
#include "runtime/registerMap.hpp"
inline frame ContinuationEntry::to_frame() const {
static CodeBlob* cb = CodeCache::find_blob_fast(entry_pc());
assert(cb != nullptr, "");
assert(cb->as_compiled_method()->method()->is_continuation_enter_intrinsic(), "");
return frame(entry_sp(), entry_sp(), entry_fp(), entry_pc(), cb);
}
inline intptr_t* ContinuationEntry::entry_fp() const {
return (intptr_t*)((address)this + size());
}
inline void ContinuationEntry::update_register_map(RegisterMap* map) const {
intptr_t** fp = (intptr_t**)(bottom_sender_sp() - frame::sender_sp_offset);
frame::update_map_with_saved_link(map, fp);
}
#endif // CPU_AARCH64_CONTINUATIONENTRY_AARCH64_INLINE_HPP

View File

@ -0,0 +1,301 @@
/*
* Copyright (c) 2019, 2022, 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.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#ifndef CPU_AARCH64_CONTINUATIONFREEZETHAW_AARCH64_INLINE_HPP
#define CPU_AARCH64_CONTINUATIONFREEZETHAW_AARCH64_INLINE_HPP
#include "code/codeBlob.inline.hpp"
#include "oops/stackChunkOop.inline.hpp"
#include "runtime/frame.hpp"
#include "runtime/frame.inline.hpp"
inline void patch_callee_link(const frame& f, intptr_t* fp) {
DEBUG_ONLY(intptr_t* orig = *ContinuationHelper::Frame::callee_link_address(f));
*ContinuationHelper::Frame::callee_link_address(f) = fp;
}
inline void patch_callee_link_relative(const frame& f, intptr_t* fp) {
intptr_t* la = (intptr_t*)ContinuationHelper::Frame::callee_link_address(f);
intptr_t new_value = fp - la;
*la = new_value;
}
////// Freeze
// Fast path
inline void FreezeBase::patch_stack_pd(intptr_t* frame_sp, intptr_t* heap_sp) {
// copy the spilled fp from the heap to the stack
*(frame_sp - frame::sender_sp_offset) = *(heap_sp - frame::sender_sp_offset);
}
// Slow path
template<typename FKind>
inline frame FreezeBase::sender(const frame& f) {
assert(FKind::is_instance(f), "");
if (FKind::interpreted) {
return frame(f.sender_sp(), f.interpreter_frame_sender_sp(), f.link(), f.sender_pc());
}
intptr_t** link_addr = link_address<FKind>(f);
intptr_t* sender_sp = (intptr_t*)(link_addr + frame::sender_sp_offset); // f.unextended_sp() + (fsize/wordSize); //
address sender_pc = (address) *(sender_sp-1);
assert(sender_sp != f.sp(), "must have changed");
int slot = 0;
CodeBlob* sender_cb = CodeCache::find_blob_and_oopmap(sender_pc, slot);
return sender_cb != nullptr
? frame(sender_sp, sender_sp, *link_addr, sender_pc, sender_cb,
slot == -1 ? nullptr : sender_cb->oop_map_for_slot(slot, sender_pc),
false /* on_heap ? */)
: frame(sender_sp, sender_sp, *link_addr, sender_pc);
}
template<typename FKind>
frame FreezeBase::new_heap_frame(frame& f, frame& caller) {
assert(FKind::is_instance(f), "");
assert(!caller.is_interpreted_frame()
|| caller.unextended_sp() == (intptr_t*)caller.at(frame::interpreter_frame_last_sp_offset), "");
intptr_t *sp, *fp; // sp is really our unextended_sp
if (FKind::interpreted) {
assert((intptr_t*)f.at(frame::interpreter_frame_last_sp_offset) == nullptr
|| f.unextended_sp() == (intptr_t*)f.at(frame::interpreter_frame_last_sp_offset), "");
int locals = f.interpreter_frame_method()->max_locals();
// If the caller.is_empty(), i.e. we're freezing into an empty chunk, then we set
// the chunk's argsize in finalize_freeze and make room for it above the unextended_sp
bool overlap_caller = caller.is_interpreted_frame() || caller.is_empty();
fp = caller.unextended_sp() - (locals + frame::sender_sp_offset) + (overlap_caller ? ContinuationHelper::InterpretedFrame::stack_argsize(f) : 0);
sp = fp - (f.fp() - f.unextended_sp());
assert(sp <= fp, "");
assert(fp <= caller.unextended_sp(), "");
caller.set_sp(fp + frame::sender_sp_offset);
assert(_cont.tail()->is_in_chunk(sp), "");
frame hf(sp, sp, fp, f.pc(), nullptr, nullptr, true /* on_heap */);
*hf.addr_at(frame::interpreter_frame_locals_offset) = frame::sender_sp_offset + locals - 1;
return hf;
} else {
// We need to re-read fp out of the frame because it may be an oop and we might have
// had a safepoint in finalize_freeze, after constructing f.
fp = *(intptr_t**)(f.sp() - frame::sender_sp_offset);
int fsize = FKind::size(f);
sp = caller.unextended_sp() - fsize;
if (caller.is_interpreted_frame()) {
// If the caller is interpreted, our stackargs are not supposed to overlap with it
// so we make more room by moving sp down by argsize
int argsize = FKind::stack_argsize(f);
sp -= argsize;
}
caller.set_sp(sp + fsize);
assert(_cont.tail()->is_in_chunk(sp), "");
return frame(sp, sp, fp, f.pc(), nullptr, nullptr, true /* on_heap */);
}
}
void FreezeBase::adjust_interpreted_frame_unextended_sp(frame& f) {
assert((f.at(frame::interpreter_frame_last_sp_offset) != 0) || (f.unextended_sp() == f.sp()), "");
intptr_t* real_unextended_sp = (intptr_t*)f.at(frame::interpreter_frame_last_sp_offset);
if (real_unextended_sp != nullptr) {
f.set_unextended_sp(real_unextended_sp); // can be null at a safepoint
}
}
static inline void relativize_one(intptr_t* const vfp, intptr_t* const hfp, int offset) {
assert(*(hfp + offset) == *(vfp + offset), "");
intptr_t* addr = hfp + offset;
intptr_t value = *(intptr_t**)addr - vfp;
*addr = value;
}
inline void FreezeBase::relativize_interpreted_frame_metadata(const frame& f, const frame& hf) {
intptr_t* vfp = f.fp();
intptr_t* hfp = hf.fp();
assert(hfp == hf.unextended_sp() + (f.fp() - f.unextended_sp()), "");
assert((f.at(frame::interpreter_frame_last_sp_offset) != 0)
|| (f.unextended_sp() == f.sp()), "");
assert(f.fp() > (intptr_t*)f.at(frame::interpreter_frame_initial_sp_offset), "");
// on AARCH64, we may insert padding between the locals and the rest of the frame
// (see TemplateInterpreterGenerator::generate_normal_entry, and AbstractInterpreter::layout_activation)
// so we compute locals "from scratch" rather than relativizing the value in the stack frame, which might include padding,
// since we don't freeze the padding word (see recurse_freeze_interpreted_frame).
// at(frame::interpreter_frame_last_sp_offset) can be NULL at safepoint preempts
*hf.addr_at(frame::interpreter_frame_last_sp_offset) = hf.unextended_sp() - hf.fp();
*hf.addr_at(frame::interpreter_frame_locals_offset) = frame::sender_sp_offset + f.interpreter_frame_method()->max_locals() - 1;
relativize_one(vfp, hfp, frame::interpreter_frame_initial_sp_offset); // == block_top == block_bottom
assert((hf.fp() - hf.unextended_sp()) == (f.fp() - f.unextended_sp()), "");
assert(hf.unextended_sp() == (intptr_t*)hf.at(frame::interpreter_frame_last_sp_offset), "");
assert(hf.unextended_sp() <= (intptr_t*)hf.at(frame::interpreter_frame_initial_sp_offset), "");
assert(hf.fp() > (intptr_t*)hf.at(frame::interpreter_frame_initial_sp_offset), "");
assert(hf.fp() <= (intptr_t*)hf.at(frame::interpreter_frame_locals_offset), "");
}
inline void FreezeBase::set_top_frame_metadata_pd(const frame& hf) {
stackChunkOop chunk = _cont.tail();
assert(chunk->is_in_chunk(hf.sp() - 1), "");
assert(chunk->is_in_chunk(hf.sp() - frame::sender_sp_offset), "");
*(hf.sp() - 1) = (intptr_t)hf.pc();
intptr_t* fp_addr = hf.sp() - frame::sender_sp_offset;
*fp_addr = hf.is_interpreted_frame() ? (intptr_t)(hf.fp() - fp_addr)
: (intptr_t)hf.fp();
}
inline void FreezeBase::patch_pd(frame& hf, const frame& caller) {
if (caller.is_interpreted_frame()) {
assert(!caller.is_empty(), "");
patch_callee_link_relative(caller, caller.fp());
} else {
// If we're the bottom-most frame frozen in this freeze, the caller might have stayed frozen in the chunk,
// and its oop-containing fp fixed. We've now just overwritten it, so we must patch it back to its value
// as read from the chunk.
patch_callee_link(caller, caller.fp());
}
}
//////// Thaw
// Fast path
inline void ThawBase::prefetch_chunk_pd(void* start, int size) {
size <<= LogBytesPerWord;
Prefetch::read(start, size);
Prefetch::read(start, size - 64);
}
void ThawBase::patch_chunk_pd(intptr_t* sp) {
intptr_t* fp = _cont.entryFP();
*(intptr_t**)(sp - frame::sender_sp_offset) = fp;
}
// Slow path
inline frame ThawBase::new_entry_frame() {
intptr_t* sp = _cont.entrySP();
return frame(sp, sp, _cont.entryFP(), _cont.entryPC()); // TODO PERF: This finds code blob and computes deopt state
}
template<typename FKind> frame ThawBase::new_stack_frame(const frame& hf, frame& caller, bool bottom) {
assert(FKind::is_instance(hf), "");
// The values in the returned frame object will be written into the callee's stack in patch.
if (FKind::interpreted) {
intptr_t* heap_sp = hf.unextended_sp();
const int fsize = ContinuationHelper::InterpretedFrame::frame_bottom(hf) - hf.unextended_sp();
const int locals = hf.interpreter_frame_method()->max_locals();
intptr_t* frame_sp = caller.unextended_sp() - fsize;
intptr_t* fp = frame_sp + (hf.fp() - heap_sp);
int padding = 0;
if ((intptr_t)fp % frame::frame_alignment != 0) {
fp--;
frame_sp--;
padding++;
log_develop_trace(continuations)("Adding internal interpreted frame alignment");
}
DEBUG_ONLY(intptr_t* unextended_sp = fp + *hf.addr_at(frame::interpreter_frame_last_sp_offset);)
assert(frame_sp == unextended_sp, "");
caller.set_sp(fp + frame::sender_sp_offset);
frame f(frame_sp, frame_sp, fp, hf.pc());
// it's set again later in set_interpreter_frame_bottom, but we need to set the locals now so that
// we could call ContinuationHelper::InterpretedFrame::frame_bottom
intptr_t offset = *hf.addr_at(frame::interpreter_frame_locals_offset);
assert((int)offset == frame::sender_sp_offset + locals - 1, "");
// derelativize locals
*(intptr_t**)f.addr_at(frame::interpreter_frame_locals_offset) = fp + padding + offset;
assert((intptr_t)f.fp() % frame::frame_alignment == 0, "");
return f;
} else {
int fsize = FKind::size(hf);
intptr_t* frame_sp = caller.unextended_sp() - fsize;
if (bottom || caller.is_interpreted_frame()) {
int argsize = hf.compiled_frame_stack_argsize();
fsize += argsize;
frame_sp -= argsize;
caller.set_sp(caller.sp() - argsize);
assert(caller.sp() == frame_sp + (fsize-argsize), "");
frame_sp = align(hf, frame_sp, caller, bottom);
}
assert(hf.cb() != nullptr, "");
assert(hf.oop_map() != nullptr, "");
intptr_t* fp;
if (PreserveFramePointer) {
// we need to recreate a "real" frame pointer, pointing into the stack
fp = frame_sp + FKind::size(hf) - frame::sender_sp_offset;
} else {
fp = FKind::stub
? frame_sp + fsize - frame::sender_sp_offset // on AArch64, this value is used for the safepoint stub
: *(intptr_t**)(hf.sp() - frame::sender_sp_offset); // we need to re-read fp because it may be an oop and we might have fixed the frame.
}
return frame(frame_sp, frame_sp, fp, hf.pc(), hf.cb(), hf.oop_map(), false); // TODO PERF : this computes deopt state; is it necessary?
}
}
inline intptr_t* ThawBase::align(const frame& hf, intptr_t* frame_sp, frame& caller, bool bottom) {
#ifdef _LP64
if (((intptr_t)frame_sp & 0xf) != 0) {
assert(caller.is_interpreted_frame() || (bottom && hf.compiled_frame_stack_argsize() % 2 != 0), "");
frame_sp--;
caller.set_sp(caller.sp() - 1);
}
assert(is_aligned(frame_sp, frame::frame_alignment), "");
#endif
return frame_sp;
}
inline void ThawBase::patch_pd(frame& f, const frame& caller) {
patch_callee_link(caller, caller.fp());
}
static inline void derelativize_one(intptr_t* const fp, int offset) {
intptr_t* addr = fp + offset;
*addr = (intptr_t)(fp + *addr);
}
inline void ThawBase::derelativize_interpreted_frame_metadata(const frame& hf, const frame& f) {
intptr_t* vfp = f.fp();
derelativize_one(vfp, frame::interpreter_frame_last_sp_offset);
derelativize_one(vfp, frame::interpreter_frame_initial_sp_offset);
}
inline void ThawBase::set_interpreter_frame_bottom(const frame& f, intptr_t* bottom) {
*(intptr_t**)f.addr_at(frame::interpreter_frame_locals_offset) = bottom - 1;
}
#endif // CPU_AARCH64_CONTINUATIONFREEZETHAW_AARCH64_INLINE_HPP

View File

@ -0,0 +1,140 @@
/*
* Copyright (c) 2022, 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.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#ifndef CPU_AARCH64_CONTINUATIONHELPER_AARCH64_INLINE_HPP
#define CPU_AARCH64_CONTINUATIONHELPER_AARCH64_INLINE_HPP
#include "runtime/continuationHelper.hpp"
#include "runtime/continuationEntry.inline.hpp"
#include "runtime/frame.inline.hpp"
#include "runtime/registerMap.hpp"
#include "utilities/macros.hpp"
template<typename FKind>
static inline intptr_t** link_address(const frame& f) {
assert(FKind::is_instance(f), "");
return FKind::interpreted
? (intptr_t**)(f.fp() + frame::link_offset)
: (intptr_t**)(f.unextended_sp() + f.cb()->frame_size() - frame::sender_sp_offset);
}
inline int ContinuationHelper::frame_align_words(int size) {
#ifdef _LP64
return size & 1;
#else
return 0;
#endif
}
inline intptr_t* ContinuationHelper::frame_align_pointer(intptr_t* sp) {
#ifdef _LP64
sp = align_down(sp, frame::frame_alignment);
#endif
return sp;
}
template<typename FKind>
inline void ContinuationHelper::update_register_map(const frame& f, RegisterMap* map) {
frame::update_map_with_saved_link(map, link_address<FKind>(f));
}
inline void ContinuationHelper::update_register_map_with_callee(const frame& f, RegisterMap* map) {
frame::update_map_with_saved_link(map, ContinuationHelper::Frame::callee_link_address(f));
}
inline void ContinuationHelper::push_pd(const frame& f) {
*(intptr_t**)(f.sp() - frame::sender_sp_offset) = f.fp();
}
inline void ContinuationHelper::set_anchor_to_entry_pd(JavaFrameAnchor* anchor, ContinuationEntry* entry) {
anchor->set_last_Java_fp(entry->entry_fp());
}
#ifdef ASSERT
inline void ContinuationHelper::set_anchor_pd(JavaFrameAnchor* anchor, intptr_t* sp) {
intptr_t* fp = *(intptr_t**)(sp - frame::sender_sp_offset);
anchor->set_last_Java_fp(fp);
}
inline bool ContinuationHelper::Frame::assert_frame_laid_out(frame f) {
intptr_t* sp = f.sp();
address pc = *(address*)(sp - frame::sender_sp_ret_address_offset());
intptr_t* fp = *(intptr_t**)(sp - frame::sender_sp_offset);
assert(f.raw_pc() == pc, "f.ra_pc: " INTPTR_FORMAT " actual: " INTPTR_FORMAT, p2i(f.raw_pc()), p2i(pc));
assert(f.fp() == fp, "f.fp: " INTPTR_FORMAT " actual: " INTPTR_FORMAT, p2i(f.fp()), p2i(fp));
return f.raw_pc() == pc && f.fp() == fp;
}
#endif
inline intptr_t** ContinuationHelper::Frame::callee_link_address(const frame& f) {
return (intptr_t**)(f.sp() - frame::sender_sp_offset);
}
inline address* ContinuationHelper::Frame::return_pc_address(const frame& f) {
return (address*)(f.real_fp() - 1);
}
inline address* ContinuationHelper::InterpretedFrame::return_pc_address(const frame& f) {
return (address*)(f.fp() + frame::return_addr_offset);
}
inline void ContinuationHelper::InterpretedFrame::patch_sender_sp(frame& f, intptr_t* sp) {
assert(f.is_interpreted_frame(), "");
intptr_t* la = f.addr_at(frame::interpreter_frame_sender_sp_offset);
*la = f.is_heap_frame() ? (intptr_t)(sp - f.fp()) : (intptr_t)sp;
}
inline address ContinuationHelper::Frame::real_pc(const frame& f) {
address* pc_addr = &(((address*) f.sp())[-1]);
return *pc_addr;
}
inline void ContinuationHelper::Frame::patch_pc(const frame& f, address pc) {
address* pc_addr = &(((address*) f.sp())[-1]);
*pc_addr = pc;
}
inline intptr_t* ContinuationHelper::InterpretedFrame::frame_top(const frame& f, InterpreterOopMap* mask) { // inclusive; this will be copied with the frame
// interpreter_frame_last_sp_offset, points to unextended_sp includes arguments in the frame
// interpreter_frame_initial_sp_offset excludes expression stack slots
int expression_stack_sz = expression_stack_size(f, mask);
intptr_t* res = *(intptr_t**)f.addr_at(frame::interpreter_frame_initial_sp_offset) - expression_stack_sz;
assert(res == (intptr_t*)f.interpreter_frame_monitor_end() - expression_stack_sz, "");
assert(res >= f.unextended_sp(),
"res: " INTPTR_FORMAT " initial_sp: " INTPTR_FORMAT " last_sp: " INTPTR_FORMAT " unextended_sp: " INTPTR_FORMAT " expression_stack_size: %d",
p2i(res), p2i(f.addr_at(frame::interpreter_frame_initial_sp_offset)), f.at(frame::interpreter_frame_last_sp_offset), p2i(f.unextended_sp()), expression_stack_sz);
return res;
}
inline intptr_t* ContinuationHelper::InterpretedFrame::frame_bottom(const frame& f) { // exclusive; this will not be copied with the frame
return (intptr_t*)f.at(frame::interpreter_frame_locals_offset) + 1; // exclusive, so we add 1 word
}
inline intptr_t* ContinuationHelper::InterpretedFrame::frame_top(const frame& f, int callee_argsize, bool callee_interpreted) {
return f.unextended_sp() + (callee_interpreted ? callee_argsize : 0);
}
#endif // CPU_AARCH64_CONTINUATIONHELPER_AARCH64_INLINE_HPP

View File

@ -56,6 +56,9 @@ void RegisterMap::check_location_valid() {
// Profiling/safepoint support
bool frame::safe_for_sender(JavaThread *thread) {
if (is_heap_frame()) {
return true;
}
address sp = (address)_sp;
address fp = (address)_fp;
address unextended_sp = (address)_unextended_sp;
@ -156,6 +159,12 @@ bool frame::safe_for_sender(JavaThread *thread) {
sender_pc = pauth_strip_verifiable((address) *(sender_sp-1), (address)saved_fp);
}
if (Continuation::is_return_barrier_entry(sender_pc)) {
// If our sender_pc is the return barrier, then our "real" sender is the continuation entry
frame s = Continuation::continuation_bottom_sender(thread, *this, sender_sp);
sender_sp = s.sp();
sender_pc = s.pc();
}
// If the potential sender is the interpreter then we can do some more checking
if (Interpreter::contains(sender_pc)) {
@ -271,6 +280,7 @@ void frame::patch_pc(Thread* thread, address pc) {
address signing_sp = (((address*) sp())[-2]);
address signed_pc = pauth_sign_return_address(pc, (address)signing_sp);
address pc_old = pauth_strip_verifiable(*pc_addr, (address)signing_sp);
if (TracePcPatching) {
tty->print("patch_pc at address " INTPTR_FORMAT " [" INTPTR_FORMAT " -> " INTPTR_FORMAT "]",
p2i(pc_addr), p2i(pc_old), p2i(pc));
@ -280,30 +290,24 @@ void frame::patch_pc(Thread* thread, address pc) {
tty->print_cr("");
}
assert(!Continuation::is_return_barrier_entry(pc_old), "return barrier");
// Either the return address is the original one or we are going to
// patch in the same address that's already there.
assert(_pc == pc_old || pc == pc_old, "must be");
assert(_pc == pc_old || pc == pc_old || pc_old == 0, "");
DEBUG_ONLY(address old_pc = _pc;)
*pc_addr = signed_pc;
_pc = pc; // must be set before call to get_deopt_original_pc
address original_pc = CompiledMethod::get_deopt_original_pc(this);
if (original_pc != NULL) {
assert(original_pc == _pc, "expected original PC to be stored before patching");
assert(original_pc == old_pc, "expected original PC to be stored before patching");
_deopt_state = is_deoptimized;
// leave _pc as is
_pc = original_pc;
} else {
_deopt_state = not_deoptimized;
_pc = pc;
}
}
bool frame::is_interpreted_frame() const {
return Interpreter::contains(pc());
}
int frame::frame_size(RegisterMap* map) const {
frame sender = this->sender(map);
return sender.sp() - sp();
}
intptr_t* frame::entry_frame_argument_at(int offset) const {
// convert offset to index to deal with tsi
int index = (Interpreter::expr_offset_in_bytes(offset)/wordSize);
@ -330,7 +334,7 @@ BasicObjectLock* frame::interpreter_frame_monitor_begin() const {
}
BasicObjectLock* frame::interpreter_frame_monitor_end() const {
BasicObjectLock* result = (BasicObjectLock*) *addr_at(interpreter_frame_monitor_block_top_offset);
BasicObjectLock* result = (BasicObjectLock*) at(interpreter_frame_monitor_block_top_offset);
// make sure the pointer points inside the frame
assert(sp() <= (intptr_t*) result, "monitor end should be above the stack pointer");
assert((intptr_t*) result < fp(), "monitor end should be strictly below the frame pointer");
@ -401,6 +405,7 @@ void frame::verify_deopt_original_pc(CompiledMethod* nm, intptr_t* unextended_sp
//------------------------------------------------------------------------------
// frame::adjust_unextended_sp
#ifdef ASSERT
void frame::adjust_unextended_sp() {
// On aarch64, sites calling method handle intrinsics and lambda forms are treated
// as any other call site. Therefore, no special action is needed when we are
@ -412,32 +417,12 @@ void frame::adjust_unextended_sp() {
// If the sender PC is a deoptimization point, get the original PC.
if (sender_cm->is_deopt_entry(_pc) ||
sender_cm->is_deopt_mh_entry(_pc)) {
DEBUG_ONLY(verify_deopt_original_pc(sender_cm, _unextended_sp));
verify_deopt_original_pc(sender_cm, _unextended_sp);
}
}
}
}
//------------------------------------------------------------------------------
// frame::update_map_with_saved_link
void frame::update_map_with_saved_link(RegisterMap* map, intptr_t** link_addr) {
// The interpreter and compiler(s) always save fp in a known
// location on entry. We must record where that location is
// so that if fp was live on callout from c2 we can find
// the saved copy no matter what it called.
// Since the interpreter always saves fp if we record where it is then
// we don't have to always save fp on entry and exit to c2 compiled
// code, on entry will be enough.
map->set_location(rfp->as_VMReg(), (address) link_addr);
// this is weird "H" ought to be at a higher address however the
// oopMaps seems to have the "H" regs at the same address and the
// vanilla register.
// XXXX make this go away
if (true) {
map->set_location(rfp->as_VMReg()->next(), (address) link_addr);
}
}
#endif
//------------------------------------------------------------------------------
@ -449,6 +434,7 @@ frame frame::sender_for_interpreter_frame(RegisterMap* map) const {
// This is the sp before any possible extension (adapter/locals).
intptr_t* unextended_sp = interpreter_frame_sender_sp();
intptr_t* sender_fp = link();
#if COMPILER2_OR_JVMCI
if (map->update_map()) {
@ -459,94 +445,15 @@ frame frame::sender_for_interpreter_frame(RegisterMap* map) const {
// For ROP protection, Interpreter will have signed the sender_pc, but there is no requirement to authenticate it here.
address sender_pc = pauth_strip_verifiable(sender_pc_maybe_signed(), (address)link());
return frame(sender_sp, unextended_sp, link(), sender_pc);
}
//------------------------------------------------------------------------------
// frame::sender_for_compiled_frame
frame frame::sender_for_compiled_frame(RegisterMap* map) const {
// When the sp of a compiled frame is correct, we can get the correct sender sp
// by unextended sp + frame size.
// For the following two scenarios, the sp of a compiled frame is correct:
// a) This compiled frame is built from the anchor.
// b) This compiled frame is built from a callee frame, and the callee frame can
// calculate its sp correctly.
//
// For b), if the callee frame is a native code frame (such as leaf call), the sp of
// the compiled frame cannot be calculated correctly. There is currently no suitable
// solution to solve this problem perfectly. But when PreserveFramePointer is enabled,
// we can get the correct sender sp by fp + 2 (that is sender_sp()).
assert(_cb->frame_size() >= 0, "must have non-zero frame size");
intptr_t* l_sender_sp = (!PreserveFramePointer || _sp_is_trusted) ? unextended_sp() + _cb->frame_size()
: sender_sp();
intptr_t* unextended_sp = l_sender_sp;
// the return_address is always the word on the stack
// For ROP protection, C1/C2 will have signed the sender_pc, but there is no requirement to authenticate it here.
address sender_pc = pauth_strip_verifiable((address) *(l_sender_sp-1), (address) *(l_sender_sp-2));
intptr_t** saved_fp_addr = (intptr_t**) (l_sender_sp - frame::sender_sp_offset);
// assert (sender_sp() == l_sender_sp, "should be");
// assert (*saved_fp_addr == link(), "should be");
if (map->update_map()) {
// Tell GC to use argument oopmaps for some runtime stubs that need it.
// For C1, the runtime stub might not have oop maps, so set this flag
// outside of update_register_map.
map->set_include_argument_oops(_cb->caller_must_gc_arguments(map->thread()));
if (_cb->oop_maps() != NULL) {
OopMapSet::update_register_map(this, map);
if (Continuation::is_return_barrier_entry(sender_pc)) {
if (map->walk_cont()) { // about to walk into an h-stack
return Continuation::top_frame(*this, map);
} else {
return Continuation::continuation_bottom_sender(map->thread(), *this, sender_sp);
}
// Since the prolog does the save and restore of FP there is no
// oopmap for it so we must fill in its location as if there was
// an oopmap entry since if our caller was compiled code there
// could be live jvm state in it.
update_map_with_saved_link(map, saved_fp_addr);
}
return frame(l_sender_sp, unextended_sp, *saved_fp_addr, sender_pc);
}
//------------------------------------------------------------------------------
// frame::sender_raw
frame frame::sender_raw(RegisterMap* map) const {
// Default is we done have to follow them. The sender_for_xxx will
// update it accordingly
map->set_include_argument_oops(false);
if (is_entry_frame())
return sender_for_entry_frame(map);
if (is_interpreted_frame())
return sender_for_interpreter_frame(map);
assert(_cb == CodeCache::find_blob(pc()),"Must be the same");
// This test looks odd: why is it not is_compiled_frame() ? That's
// because stubs also have OOP maps.
if (_cb != NULL) {
return sender_for_compiled_frame(map);
}
// Must be native-compiled frame, i.e. the marshaling code for native
// methods that exists in the core system.
// Native code may or may not have signed the return address, we have no way to be sure or what
// signing methods they used. Instead, just ensure the stripped value is used.
return frame(sender_sp(), link(), sender_pc());
}
frame frame::sender(RegisterMap* map) const {
frame result = sender_raw(map);
if (map->process_frames()) {
StackWatermarkSet::on_iteration(map->thread(), result);
}
return result;
return frame(sender_sp, unextended_sp, sender_fp, sender_pc);
}
bool frame::is_interpreted_frame_valid(JavaThread* thread) const {
@ -655,7 +562,6 @@ BasicType frame::interpreter_frame_result(oop* oop_result, jvalue* value_result)
return type;
}
intptr_t* frame::interpreter_frame_tos_at(jint offset) const {
int index = (Interpreter::expr_offset_in_bytes(offset)/wordSize);
return &interpreter_frame_tos_address()[index];
@ -678,6 +584,14 @@ void frame::describe_pd(FrameValues& values, int frame_no) {
DESCRIBE_FP_OFFSET(interpreter_frame_bcp);
DESCRIBE_FP_OFFSET(interpreter_frame_initial_sp);
}
intptr_t* ret_pc_loc = sp() - return_addr_offset;
address ret_pc = *(address*)ret_pc_loc;
if (Continuation::is_return_barrier_entry(ret_pc))
values.describe(frame_no, ret_pc_loc, "return address (return barrier)");
else
values.describe(frame_no, ret_pc_loc, err_msg("return address for #%d", frame_no));
values.describe(frame_no, sp() - sender_sp_offset, err_msg("saved fp for #%d", frame_no), 0);
}
#endif
@ -686,19 +600,6 @@ intptr_t *frame::initial_deoptimization_info() {
return NULL;
}
intptr_t* frame::real_fp() const {
if (_cb != NULL) {
// use the frame size if valid
int size = _cb->frame_size();
if (size > 0) {
return unextended_sp() + size;
}
}
// else rely on fp()
assert(! is_compiled_frame(), "unknown compiled frame size");
return fp();
}
#undef DESCRIBE_FP_OFFSET
#define DESCRIBE_FP_OFFSET(name) \

View File

@ -99,8 +99,14 @@
entry_frame_call_wrapper_offset = -8,
// we don't need a save area
arg_reg_save_area_bytes = 0
arg_reg_save_area_bytes = 0,
// size, in words, of frame metadata (e.g. pc and link)
metadata_words = sender_sp_offset,
// in bytes
frame_alignment = 16,
// size, in words, of maximum shift in frame position due to alignment
align_wiggle = 1
};
intptr_t ptr_at(int offset) const {
@ -113,7 +119,10 @@
private:
// an additional field beyond _sp and _pc:
intptr_t* _fp; // frame pointer
union {
intptr_t* _fp; // frame pointer
int _offset_fp; // relative frame pointer for use in stack-chunk frames
};
// The interpreter and adapters will extend the frame of the caller.
// Since oopMaps are based on the sp of the caller before extension
// we need to know that value. However in order to compute the address
@ -121,8 +130,12 @@
// uses sp() to mean "raw" sp and unextended_sp() to mean the caller's
// original sp we use that convention.
intptr_t* _unextended_sp;
void adjust_unextended_sp();
union {
intptr_t* _unextended_sp;
int _offset_unextended_sp; // for use in stack-chunk frames
};
void adjust_unextended_sp() NOT_DEBUG_RETURN;
// true means _sp value is correct and we can use it to get the sender's sp
// of the compiled frame, otherwise, _sp value may be invalid and we can use
@ -138,6 +151,8 @@
static void verify_deopt_original_pc( CompiledMethod* nm, intptr_t* unextended_sp);
#endif
const ImmutableOopMap* get_oop_map() const;
public:
// Constructors
@ -145,13 +160,21 @@
frame(intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, address pc);
frame(intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, address pc, CodeBlob* cb);
// used for fast frame construction by continuations
frame(intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, address pc, CodeBlob* cb, const ImmutableOopMap* oop_map, bool on_heap);
frame(intptr_t* sp, intptr_t* fp);
void init(intptr_t* sp, intptr_t* fp, address pc);
void setup(address pc);
// accessors for the instance variables
// Note: not necessarily the real 'frame pointer' (see real_fp)
intptr_t* fp() const { return _fp; }
intptr_t* fp() const { assert_absolute(); return _fp; }
void set_fp(intptr_t* newfp) { _fp = newfp; }
int offset_fp() const { assert_offset(); return _offset_fp; }
void set_offset_fp(int value) { assert_on_heap(); _offset_fp = value; }
inline address* sender_pc_addr() const;
inline address sender_pc_maybe_signed() const;
@ -159,8 +182,8 @@
// expression stack tos if we are nested in a java call
intptr_t* interpreter_frame_last_sp() const;
// helper to update a map with callee-saved RBP
static void update_map_with_saved_link(RegisterMap* map, intptr_t** link_addr);
template <typename RegisterMapT>
static void update_map_with_saved_link(RegisterMapT* map, intptr_t** link_addr);
// deoptimization support
void interpreter_frame_set_last_sp(intptr_t* sp);
@ -168,7 +191,7 @@
static jint interpreter_frame_expression_stack_direction() { return -1; }
// returns the sending frame, without applying any barriers
frame sender_raw(RegisterMap* map) const;
inline frame sender_raw(RegisterMap* map) const;
void set_sp_is_trusted() { _sp_is_trusted = true; }

View File

@ -26,8 +26,12 @@
#ifndef CPU_AARCH64_FRAME_AARCH64_INLINE_HPP
#define CPU_AARCH64_FRAME_AARCH64_INLINE_HPP
#include "code/codeCache.hpp"
#include "code/codeBlob.inline.hpp"
#include "code/codeCache.inline.hpp"
#include "code/vmreg.inline.hpp"
#include "interpreter/interpreter.hpp"
#include "interpreter/oopMapCache.hpp"
#include "runtime/sharedRuntime.hpp"
#include "pauth_aarch64.hpp"
// Inline functions for AArch64 frames:
@ -42,6 +46,8 @@ inline frame::frame() {
_cb = NULL;
_deopt_state = unknown;
_sp_is_trusted = false;
_on_heap = false;
DEBUG_ONLY(_frame_index = -1;)
}
static int spin;
@ -54,16 +60,30 @@ inline void frame::init(intptr_t* sp, intptr_t* fp, address pc) {
_unextended_sp = sp;
_fp = fp;
_pc = pc;
_oop_map = NULL;
_on_heap = false;
DEBUG_ONLY(_frame_index = -1;)
assert(pc != NULL, "no pc?");
_cb = CodeCache::find_blob(pc);
setup(pc);
}
inline void frame::setup(address pc) {
adjust_unextended_sp();
address original_pc = CompiledMethod::get_deopt_original_pc(this);
if (original_pc != NULL) {
_pc = original_pc;
_deopt_state = is_deoptimized;
assert(_cb == NULL || _cb->as_compiled_method()->insts_contains_inclusive(_pc),
"original PC must be in the main code section of the the compiled method (or must be immediately following it)");
} else {
_deopt_state = not_deoptimized;
if (_cb == SharedRuntime::deopt_blob()) {
_deopt_state = is_deoptimized;
} else {
_deopt_state = not_deoptimized;
}
}
_sp_is_trusted = false;
}
@ -72,7 +92,7 @@ inline frame::frame(intptr_t* sp, intptr_t* fp, address pc) {
init(sp, fp, pc);
}
inline frame::frame(intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, address pc) {
inline frame::frame(intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, address pc, CodeBlob* cb) {
assert(pauth_ptr_is_raw(pc), "cannot be signed");
intptr_t a = intptr_t(sp);
intptr_t b = intptr_t(fp);
@ -81,21 +101,59 @@ inline frame::frame(intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, address
_fp = fp;
_pc = pc;
assert(pc != NULL, "no pc?");
_cb = CodeCache::find_blob(pc);
adjust_unextended_sp();
_cb = cb;
_oop_map = NULL;
assert(_cb != NULL, "pc: " INTPTR_FORMAT, p2i(pc));
_on_heap = false;
DEBUG_ONLY(_frame_index = -1;)
address original_pc = CompiledMethod::get_deopt_original_pc(this);
if (original_pc != NULL) {
_pc = original_pc;
assert(_cb->as_compiled_method()->insts_contains_inclusive(_pc),
"original PC must be in the main code section of the the compiled method (or must be immediately following it)");
_deopt_state = is_deoptimized;
} else {
_deopt_state = not_deoptimized;
}
_sp_is_trusted = false;
setup(pc);
}
inline frame::frame(intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, address pc, CodeBlob* cb, const ImmutableOopMap* oop_map, bool on_heap) {
_sp = sp;
_unextended_sp = unextended_sp;
_fp = fp;
_pc = pc;
_cb = cb;
_oop_map = oop_map;
_deopt_state = not_deoptimized;
_sp_is_trusted = false;
_on_heap = on_heap;
DEBUG_ONLY(_frame_index = -1;)
// In thaw, non-heap frames use this constructor to pass oop_map. I don't know why.
assert(_on_heap || _cb != nullptr, "these frames are always heap frames");
if (cb != NULL) {
setup(pc);
}
#ifdef ASSERT
// The following assertion has been disabled because it would sometime trap for Continuation.run,
// which is not *in* a continuation and therefore does not clear the _cont_fastpath flag, but this
// is benign even in fast mode (see Freeze::setup_jump)
// We might freeze deoptimized frame in slow mode
// assert(_pc == pc && _deopt_state == not_deoptimized, "");
#endif
}
inline frame::frame(intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, address pc) {
intptr_t a = intptr_t(sp);
intptr_t b = intptr_t(fp);
_sp = sp;
_unextended_sp = unextended_sp;
_fp = fp;
_pc = pc;
_cb = CodeCache::find_blob_fast(pc);
_oop_map = NULL;
assert(_cb != NULL, "pc: " INTPTR_FORMAT " sp: " INTPTR_FORMAT " unextended_sp: " INTPTR_FORMAT " fp: " INTPTR_FORMAT, p2i(pc), p2i(sp), p2i(unextended_sp), p2i(fp));
_on_heap = false;
DEBUG_ONLY(_frame_index = -1;)
setup(pc);
}
inline frame::frame(intptr_t* sp) : frame(sp, sp, *(intptr_t**)(sp - frame::sender_sp_offset), *(address*)(sp - 1)) {}
inline frame::frame(intptr_t* sp, intptr_t* fp) {
intptr_t a = intptr_t(sp);
intptr_t b = intptr_t(fp);
@ -103,6 +161,8 @@ inline frame::frame(intptr_t* sp, intptr_t* fp) {
_unextended_sp = sp;
_fp = fp;
_pc = (address)(sp[-1]);
_on_heap = false;
DEBUG_ONLY(_frame_index = -1;)
// Here's a sticky one. This constructor can be called via AsyncGetCallTrace
// when last_Java_sp is non-null but the pc fetched is junk. If we are truly
@ -155,7 +215,41 @@ inline intptr_t* frame::link_or_null() const {
return os::is_readable_pointer(ptr) ? *ptr : NULL;
}
inline intptr_t* frame::unextended_sp() const { return _unextended_sp; }
inline intptr_t* frame::unextended_sp() const { assert_absolute(); return _unextended_sp; }
inline void frame::set_unextended_sp(intptr_t* value) { _unextended_sp = value; }
inline int frame::offset_unextended_sp() const { assert_offset(); return _offset_unextended_sp; }
inline void frame::set_offset_unextended_sp(int value) { assert_on_heap(); _offset_unextended_sp = value; }
inline intptr_t* frame::real_fp() const {
if (_cb != NULL) {
// use the frame size if valid
int size = _cb->frame_size();
if (size > 0) {
return unextended_sp() + size;
}
}
// else rely on fp()
assert(! is_compiled_frame(), "unknown compiled frame size");
return fp();
}
inline int frame::frame_size() const {
return is_interpreted_frame()
? sender_sp() - sp()
: cb()->frame_size();
}
inline int frame::compiled_frame_stack_argsize() const {
assert(cb()->is_compiled(), "");
return (cb()->as_compiled_method()->method()->num_stack_arg_slots() * VMRegImpl::stack_slot_size) >> LogBytesPerWord;
}
inline void frame::interpreted_frame_oop_map(InterpreterOopMap* mask) const {
assert(mask != NULL, "");
Method* m = interpreter_frame_method();
int bci = interpreter_frame_bci();
m->mask_for(bci, mask); // OopMapCache::compute_one_oop_map(m, bci, mask);
}
// Return address:
@ -170,7 +264,7 @@ inline intptr_t** frame::interpreter_frame_locals_addr() const {
}
inline intptr_t* frame::interpreter_frame_last_sp() const {
return *(intptr_t**)addr_at(interpreter_frame_last_sp_offset);
return (intptr_t*)at(interpreter_frame_last_sp_offset);
}
inline intptr_t* frame::interpreter_frame_bcp_addr() const {
@ -244,21 +338,147 @@ inline JavaCallWrapper** frame::entry_frame_call_wrapper_addr() const {
inline oop frame::saved_oop_result(RegisterMap* map) const {
PRAGMA_DIAG_PUSH
PRAGMA_NONNULL_IGNORED
oop* result_adr = (oop *)map->location(r0->as_VMReg());
oop* result_adr = (oop *)map->location(r0->as_VMReg(), sp());
PRAGMA_DIAG_POP
guarantee(result_adr != NULL, "bad register save location");
return (*result_adr);
return *result_adr;
}
inline void frame::set_saved_oop_result(RegisterMap* map, oop obj) {
PRAGMA_DIAG_PUSH
PRAGMA_NONNULL_IGNORED
oop* result_adr = (oop *)map->location(r0->as_VMReg());
oop* result_adr = (oop *)map->location(r0->as_VMReg(), sp());
PRAGMA_DIAG_POP
guarantee(result_adr != NULL, "bad register save location");
*result_adr = obj;
}
inline bool frame::is_interpreted_frame() const {
return Interpreter::contains(pc());
}
inline int frame::sender_sp_ret_address_offset() {
return frame::sender_sp_offset - frame::return_addr_offset;
}
inline const ImmutableOopMap* frame::get_oop_map() const {
if (_cb == NULL) return NULL;
if (_cb->oop_maps() != NULL) {
NativePostCallNop* nop = nativePostCallNop_at(_pc);
if (nop != NULL && nop->displacement() != 0) {
int slot = ((nop->displacement() >> 24) & 0xff);
return _cb->oop_map_for_slot(slot, _pc);
}
const ImmutableOopMap* oop_map = OopMapSet::find_map(this);
return oop_map;
}
return NULL;
}
//------------------------------------------------------------------------------
// frame::sender
inline frame frame::sender(RegisterMap* map) const {
frame result = sender_raw(map);
if (map->process_frames() && !map->in_cont()) {
StackWatermarkSet::on_iteration(map->thread(), result);
}
return result;
}
inline frame frame::sender_raw(RegisterMap* map) const {
// Default is we done have to follow them. The sender_for_xxx will
// update it accordingly
map->set_include_argument_oops(false);
if (map->in_cont()) { // already in an h-stack
return map->stack_chunk()->sender(*this, map);
}
if (is_entry_frame()) return sender_for_entry_frame(map);
if (is_optimized_entry_frame()) return sender_for_optimized_entry_frame(map);
if (is_interpreted_frame()) return sender_for_interpreter_frame(map);
assert(_cb == CodeCache::find_blob(pc()), "Must be the same");
if (_cb != NULL) return sender_for_compiled_frame(map);
// Must be native-compiled frame, i.e. the marshaling code for native
// methods that exists in the core system.
// Native code may or may not have signed the return address, we have no way to be sure or what
// signing methods they used. Instead, just ensure the stripped value is used.
return frame(sender_sp(), link(), sender_pc());
}
inline frame frame::sender_for_compiled_frame(RegisterMap* map) const {
// we cannot rely upon the last fp having been saved to the thread
// in C2 code but it will have been pushed onto the stack. so we
// have to find it relative to the unextended sp
assert(_cb->frame_size() >= 0, "must have non-zero frame size");
intptr_t* l_sender_sp = (!PreserveFramePointer || _sp_is_trusted) ? unextended_sp() + _cb->frame_size()
: sender_sp();
assert(!_sp_is_trusted || l_sender_sp == real_fp(), "");
// the return_address is always the word on the stack
// For ROP protection, C1/C2 will have signed the sender_pc, but there is no requirement to authenticate it here.
address sender_pc = pauth_strip_verifiable((address) *(l_sender_sp-1), (address) *(l_sender_sp-2));
intptr_t** saved_fp_addr = (intptr_t**) (l_sender_sp - frame::sender_sp_offset);
if (map->update_map()) {
// Tell GC to use argument oopmaps for some runtime stubs that need it.
// For C1, the runtime stub might not have oop maps, so set this flag
// outside of update_register_map.
if (!_cb->is_compiled()) { // compiled frames do not use callee-saved registers
map->set_include_argument_oops(_cb->caller_must_gc_arguments(map->thread()));
if (oop_map() != NULL) {
_oop_map->update_register_map(this, map);
}
} else {
assert(!_cb->caller_must_gc_arguments(map->thread()), "");
assert(!map->include_argument_oops(), "");
assert(oop_map() == NULL || !oop_map()->has_any(OopMapValue::callee_saved_value), "callee-saved value in compiled frame");
}
// Since the prolog does the save and restore of EBP there is no oopmap
// for it so we must fill in its location as if there was an oopmap entry
// since if our caller was compiled code there could be live jvm state in it.
update_map_with_saved_link(map, saved_fp_addr);
}
if (Continuation::is_return_barrier_entry(sender_pc)) {
if (map->walk_cont()) { // about to walk into an h-stack
return Continuation::top_frame(*this, map);
} else {
return Continuation::continuation_bottom_sender(map->thread(), *this, l_sender_sp);
}
}
intptr_t* unextended_sp = l_sender_sp;
return frame(l_sender_sp, unextended_sp, *saved_fp_addr, sender_pc);
}
template <typename RegisterMapT>
void frame::update_map_with_saved_link(RegisterMapT* map, intptr_t** link_addr) {
// The interpreter and compiler(s) always save EBP/RBP in a known
// location on entry. We must record where that location is
// so this if EBP/RBP was live on callout from c2 we can find
// the saved copy no matter what it called.
// Since the interpreter always saves EBP/RBP if we record where it is then
// we don't have to always save EBP/RBP on entry and exit to c2 compiled
// code, on entry will be enough.
map->set_location(rfp->as_VMReg(), (address) link_addr);
// this is weird "H" ought to be at a higher address however the
// oopMaps seems to have the "H" regs at the same address and the
// vanilla register.
// XXXX make this go away
if (true) {
map->set_location(rfp->as_VMReg()->next(), (address) link_addr);
}
}
#endif // CPU_AARCH64_FRAME_AARCH64_INLINE_HPP

View File

@ -154,12 +154,8 @@ void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm,
__ b(done);
__ bind(runtime);
// save the live input values
RegSet saved = RegSet::of(pre_val);
if (tosca_live) saved += RegSet::of(r0);
if (obj != noreg) saved += RegSet::of(obj);
__ push(saved, sp);
__ push_call_clobbered_registers();
// Calling the runtime using the regular call_VM_leaf mechanism generates
// code (generated by InterpreterMacroAssember::call_VM_leaf_base)
@ -180,7 +176,7 @@ void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm,
__ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_pre_entry), pre_val, thread);
}
__ pop(saved, sp);
__ pop_call_clobbered_registers();
__ bind(done);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2022, 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
@ -232,6 +232,20 @@ void BarrierSetAssembler::incr_allocated_bytes(MacroAssembler* masm,
__ str(t1, Address(rthread, in_bytes(JavaThread::allocated_bytes_offset())));
}
static volatile uint32_t _patching_epoch = 0;
address BarrierSetAssembler::patching_epoch_addr() {
return (address)&_patching_epoch;
}
void BarrierSetAssembler::increment_patching_epoch() {
Atomic::inc(&_patching_epoch);
}
void BarrierSetAssembler::clear_patching_epoch() {
_patching_epoch = 0;
}
void BarrierSetAssembler::nmethod_entry_barrier(MacroAssembler* masm) {
BarrierSetNMethod* bs_nm = BarrierSet::barrier_set()->barrier_set_nmethod();
@ -239,27 +253,51 @@ void BarrierSetAssembler::nmethod_entry_barrier(MacroAssembler* masm) {
return;
}
Label skip, guard;
Address thread_disarmed_addr(rthread, in_bytes(bs_nm->thread_disarmed_offset()));
Label skip_barrier, guard;
__ ldrw(rscratch1, guard);
// Subsequent loads of oops must occur after load of guard value.
// BarrierSetNMethod::disarm sets guard with release semantics.
__ membar(__ LoadLoad);
__ ldrw(rscratch2, thread_disarmed_addr);
__ cmpw(rscratch1, rscratch2);
__ br(Assembler::EQ, skip);
if (nmethod_code_patching()) {
// If we patch code we need both a code patching and a loadload
// fence. It's not super cheap, so we use a global epoch mechanism
// to hide them in a slow path.
// The high level idea of the global epoch mechanism is to detect
// when any thread has performed the required fencing, after the
// last nmethod was disarmed. This implies that the required
// fencing has been performed for all preceding nmethod disarms
// as well. Therefore, we do not need any further fencing.
__ lea(rscratch2, ExternalAddress((address)&_patching_epoch));
// Embed an artificial data dependency to order the guard load
// before the epoch load.
__ orr(rscratch2, rscratch2, rscratch1, Assembler::LSR, 32);
// Read the global epoch value.
__ ldrw(rscratch2, rscratch2);
// Combine the guard value (low order) with the epoch value (high order).
__ orr(rscratch1, rscratch1, rscratch2, Assembler::LSL, 32);
// Compare the global values with the thread-local values.
Address thread_disarmed_and_epoch_addr(rthread, in_bytes(bs_nm->thread_disarmed_offset()));
__ ldr(rscratch2, thread_disarmed_and_epoch_addr);
__ cmp(rscratch1, rscratch2);
__ br(Assembler::EQ, skip_barrier);
} else {
// Subsequent loads of oops must occur after load of guard value.
// BarrierSetNMethod::disarm sets guard with release semantics.
__ membar(__ LoadLoad);
Address thread_disarmed_addr(rthread, in_bytes(bs_nm->thread_disarmed_offset()));
__ ldrw(rscratch2, thread_disarmed_addr);
__ cmpw(rscratch1, rscratch2);
__ br(Assembler::EQ, skip_barrier);
}
__ movptr(rscratch1, (uintptr_t) StubRoutines::aarch64::method_entry_barrier());
__ blr(rscratch1);
__ b(skip);
__ b(skip_barrier);
__ bind(guard);
__ emit_int32(0); // nmethod guard value. Skipped over in common case.
__ bind(skip);
__ bind(skip_barrier);
}
void BarrierSetAssembler::c2i_entry_barrier(MacroAssembler* masm) {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2022, 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
@ -68,9 +68,14 @@ public:
);
virtual void barrier_stubs_init() {}
virtual bool nmethod_code_patching() { return true; }
virtual void nmethod_entry_barrier(MacroAssembler* masm);
virtual void c2i_entry_barrier(MacroAssembler* masm);
static address patching_epoch_addr();
static void clear_patching_epoch();
static void increment_patching_epoch();
};
#endif // CPU_AARCH64_GC_SHARED_BARRIERSETASSEMBLER_AARCH64_HPP

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2022, 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
@ -25,9 +25,12 @@
#include "precompiled.hpp"
#include "code/codeCache.hpp"
#include "code/nativeInst.hpp"
#include "gc/shared/barrierSet.hpp"
#include "gc/shared/barrierSetAssembler.hpp"
#include "gc/shared/barrierSetNMethod.hpp"
#include "logging/log.hpp"
#include "memory/resourceArea.hpp"
#include "runtime/frame.inline.hpp"
#include "runtime/sharedRuntime.hpp"
#include "runtime/registerMap.hpp"
#include "runtime/thread.hpp"
@ -37,8 +40,17 @@
class NativeNMethodBarrier: public NativeInstruction {
address instruction_address() const { return addr_at(0); }
int guard_offset() {
BarrierSetAssembler* bs_asm = BarrierSet::barrier_set()->barrier_set_assembler();
if (bs_asm->nmethod_code_patching()) {
return 4 * 15;
} else {
return 4 * 10;
}
}
int *guard_addr() {
return reinterpret_cast<int*>(instruction_address() + 10 * 4);
return reinterpret_cast<int*>(instruction_address() + guard_offset());
}
public:
@ -60,31 +72,14 @@ struct CheckInsn {
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.
// The first instruction of the nmethod entry barrier is an ldr (literal)
// instruction. Verify that it's really there, so the offsets are not skewed.
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;
uint32_t* addr = (uint32_t*) instruction_address();
uint32_t inst = *addr;
if ((inst & 0xff000000) != 0x18000000) {
tty->print_cr("Addr: " INTPTR_FORMAT " Code: 0x%x", (intptr_t)addr, inst);
fatal("not an ldr (literal) instruction.");
}
}
@ -132,10 +127,17 @@ void BarrierSetNMethod::deoptimize(nmethod* nm, address* return_address_ptr) {
// 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 int entry_barrier_offset() {
BarrierSetAssembler* bs_asm = BarrierSet::barrier_set()->barrier_set_assembler();
if (bs_asm->nmethod_code_patching()) {
return -4 * 16;
} else {
return -4 * 11;
}
}
static NativeNMethodBarrier* native_nmethod_barrier(nmethod* nm) {
address barrier_address = nm->code_begin() + nm->frame_complete_offset() + entry_barrier_offset;
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;
@ -146,13 +148,41 @@ void BarrierSetNMethod::disarm(nmethod* nm) {
return;
}
// The patching epoch is incremented before the nmethod is disarmed. Disarming
// is performed with a release store. In the nmethod entry barrier, the values
// are read in the opposite order, such that the load of the nmethod guard
// acquires the patching epoch. This way, the guard is guaranteed to block
// entries to the nmethod, until it has safely published the requirement for
// further fencing by mutators, before they are allowed to enter.
BarrierSetAssembler* bs_asm = BarrierSet::barrier_set()->barrier_set_assembler();
bs_asm->increment_patching_epoch();
// 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());
}
void BarrierSetNMethod::arm(nmethod* nm, int arm_value) {
if (!supports_entry_barrier(nm)) {
return;
}
if (arm_value == disarmed_value()) {
// The patching epoch is incremented before the nmethod is disarmed. Disarming
// is performed with a release store. In the nmethod entry barrier, the values
// are read in the opposite order, such that the load of the nmethod guard
// acquires the patching epoch. This way, the guard is guaranteed to block
// entries to the nmethod, until it has safely published the requirement for
// further fencing by mutators, before they are allowed to enter.
BarrierSetAssembler* bs_asm = BarrierSet::barrier_set()->barrier_set_assembler();
bs_asm->increment_patching_epoch();
}
NativeNMethodBarrier* barrier = native_nmethod_barrier(nm);
barrier->set_value(arm_value);
}
bool BarrierSetNMethod::is_armed(nmethod* nm) {
if (!supports_entry_barrier(nm)) {
return false;

View File

@ -62,6 +62,8 @@ public:
void iu_barrier(MacroAssembler* masm, Register dst, Register tmp);
virtual bool nmethod_code_patching() { return false; }
#ifdef COMPILER1
void gen_pre_barrier_stub(LIR_Assembler* ce, ShenandoahPreBarrierStub* stub);
void gen_load_reference_barrier_stub(LIR_Assembler* ce, ShenandoahLoadReferenceBarrierStub* stub);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 2022, 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
@ -76,6 +76,8 @@ public:
Register tmp,
Label& slowpath);
virtual bool nmethod_code_patching() { return false; }
#ifdef COMPILER1
void generate_c1_load_barrier_test(LIR_Assembler* ce,
LIR_Opr ref) const;

View File

@ -606,6 +606,7 @@ void InterpreterMacroAssembler::remove_activation(
bind(unlock);
unlock_object(c_rarg1);
dec_held_monitor_count(rthread);
pop(state);
// Check that for block-structured locking (i.e., that all locked
@ -648,6 +649,7 @@ void InterpreterMacroAssembler::remove_activation(
push(state);
unlock_object(c_rarg1);
dec_held_monitor_count(rthread);
pop(state);
if (install_monitor_exception) {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2002, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, Red Hat Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@ -82,4 +82,6 @@ public:
intptr_t* last_Java_fp(void) { return _last_Java_fp; }
void set_last_Java_fp(intptr_t* fp) { _last_Java_fp = fp; }
#endif // CPU_AARCH64_JAVAFRAMEANCHOR_AARCH64_HPP

View File

@ -46,6 +46,7 @@
#include "oops/accessDecorators.hpp"
#include "oops/compressedOops.inline.hpp"
#include "oops/klass.inline.hpp"
#include "runtime/continuation.hpp"
#include "runtime/icache.hpp"
#include "runtime/interfaceSupport.inline.hpp"
#include "runtime/jniHandles.inline.hpp"
@ -313,6 +314,41 @@ void MacroAssembler::safepoint_poll(Label& slow_path, bool at_return, bool acqui
}
}
void MacroAssembler::push_cont_fastpath(Register java_thread) {
if (!Continuations::enabled()) return;
Label done;
ldr(rscratch1, Address(java_thread, JavaThread::cont_fastpath_offset()));
cmp(sp, rscratch1);
br(Assembler::LS, done);
mov(rscratch1, sp); // we can't use sp as the source in str
str(rscratch1, Address(java_thread, JavaThread::cont_fastpath_offset()));
bind(done);
}
void MacroAssembler::pop_cont_fastpath(Register java_thread) {
if (!Continuations::enabled()) return;
Label done;
ldr(rscratch1, Address(java_thread, JavaThread::cont_fastpath_offset()));
cmp(sp, rscratch1);
br(Assembler::LO, done);
str(zr, Address(java_thread, JavaThread::cont_fastpath_offset()));
bind(done);
}
void MacroAssembler::inc_held_monitor_count(Register java_thread) {
if (!Continuations::enabled()) return;
incrementw(Address(java_thread, JavaThread::held_monitor_count_offset()));
}
void MacroAssembler::dec_held_monitor_count(Register java_thread) {
if (!Continuations::enabled()) return;
decrementw(Address(java_thread, JavaThread::held_monitor_count_offset()));
}
void MacroAssembler::reset_held_monitor_count(Register java_thread) {
strw(zr, Address(java_thread, JavaThread::held_monitor_count_offset()));
}
void MacroAssembler::reset_last_Java_frame(bool clear_fp) {
// we must set sp to zero to clear frame
str(zr, Address(rthread, JavaThread::last_Java_sp_offset()));
@ -566,9 +602,7 @@ void MacroAssembler::call_VM_helper(Register oop_result, address entry_point, in
// Maybe emit a call via a trampoline. If the code cache is small
// trampolines won't be emitted.
address MacroAssembler::trampoline_call(Address entry, CodeBuffer* cbuf) {
assert(JavaThread::current()->is_Compiler_thread(), "just checking");
address MacroAssembler::trampoline_call1(Address entry, CodeBuffer* cbuf, bool check_emit_size) {
assert(entry.rspec().type() == relocInfo::runtime_call_type
|| entry.rspec().type() == relocInfo::opt_virtual_call_type
|| entry.rspec().type() == relocInfo::static_call_type
@ -578,12 +612,14 @@ address MacroAssembler::trampoline_call(Address entry, CodeBuffer* cbuf) {
if (far_branches()) {
bool in_scratch_emit_size = false;
#ifdef COMPILER2
// We don't want to emit a trampoline if C2 is generating dummy
// code during its branch shortening phase.
CompileTask* task = ciEnv::current()->task();
in_scratch_emit_size =
(task != NULL && is_c2_compile(task->comp_level()) &&
Compile::current()->output()->in_scratch_emit_size());
if (check_emit_size) {
// We don't want to emit a trampoline if C2 is generating dummy
// code during its branch shortening phase.
CompileTask* task = ciEnv::current()->task();
in_scratch_emit_size =
(task != NULL && is_c2_compile(task->comp_level()) &&
Compile::current()->output()->in_scratch_emit_size());
}
#endif
if (!in_scratch_emit_size) {
address stub = emit_trampoline_stub(offset(), entry.target());
@ -790,6 +826,14 @@ void MacroAssembler::align(int modulus) {
while (offset() % modulus != 0) nop();
}
void MacroAssembler::post_call_nop() {
if (!Continuations::enabled()) {
return;
}
relocate(post_call_nop_Relocation::spec());
nop();
}
// these are no-ops overridden by InterpreterMacroAssembler
void MacroAssembler::check_and_handle_earlyret(Register java_thread) { }
@ -2196,6 +2240,15 @@ void MacroAssembler::unimplemented(const char* what) {
stop(buf);
}
void MacroAssembler::_assert_asm(Assembler::Condition cc, const char* msg) {
#ifdef ASSERT
Label OK;
br(cc, OK);
stop(msg);
bind(OK);
#endif
}
// If a constant does not fit in an immediate field, generate some
// number of MOV instructions and then perform the operation.
void MacroAssembler::wrap_add_sub_imm_insn(Register Rd, Register Rn, unsigned imm,
@ -4148,7 +4201,8 @@ void MacroAssembler::movoop(Register dst, jobject obj, bool immediate) {
// nmethod entry barrier necessitate using the constant pool. They have to be
// ordered with respected to oop accesses.
// Using immediate literals would necessitate ISBs.
if (BarrierSet::barrier_set()->barrier_set_nmethod() != NULL || !immediate) {
BarrierSet* bs = BarrierSet::barrier_set();
if ((bs->barrier_set_nmethod() != NULL && bs->barrier_set_assembler()->nmethod_code_patching()) || !immediate) {
address dummy = address(uintptr_t(pc()) & -wordSize); // A nearby aligned address
ldr_constant(dst, Address(dummy, rspec));
} else

View File

@ -687,6 +687,9 @@ public:
// Alignment
void align(int modulus);
// nop
void post_call_nop();
// Stack frame creation/removal
void enter(bool strip_ret_addr = false);
void leave();
@ -874,6 +877,12 @@ public:
void pop_CPU_state(bool restore_vectors = false, bool use_sve = false,
int sve_vector_size_in_bytes = 0, int total_predicate_in_bytes = 0);
void push_cont_fastpath(Register java_thread);
void pop_cont_fastpath(Register java_thread);
void inc_held_monitor_count(Register java_thread);
void dec_held_monitor_count(Register java_thread);
void reset_held_monitor_count(Register java_thread);
// Round up to a power of two
void round_to(Register reg, int modulus);
@ -1004,6 +1013,10 @@ public:
void should_not_reach_here() { stop("should not reach here"); }
void _assert_asm(Condition cc, const char* msg);
#define assert_asm0(cc, msg) _assert_asm(cc, FILE_AND_LINE ": " msg)
#define assert_asm(masm, command, cc, msg) DEBUG_ONLY(command; (masm)->_assert_asm(cc, FILE_AND_LINE ": " #command " " #cc ": " msg))
// Stack overflow checking
void bang_stack_with_offset(int offset) {
// stack grows down, caller passes positive offset
@ -1084,7 +1097,8 @@ private:
public:
// Calls
address trampoline_call(Address entry, CodeBuffer* cbuf = NULL);
address trampoline_call(Address entry, CodeBuffer* cbuf = NULL) { return trampoline_call1(entry, cbuf, true); }
address trampoline_call1(Address entry, CodeBuffer* cbuf, bool check_emit_size = true);
static bool far_branches() {
return ReservedCodeCacheSize > branch_range;

View File

@ -544,3 +544,29 @@ address NativeCall::trampoline_jump(CodeBuffer &cbuf, address dest) {
return stub;
}
void NativePostCallNop::make_deopt() {
NativeDeoptInstruction::insert(addr_at(0));
}
void NativePostCallNop::patch(jint diff) {
// unsupported for now
}
void NativeDeoptInstruction::verify() {
}
// Inserts an undefined instruction at a given pc
void NativeDeoptInstruction::insert(address code_pos) {
// 1 1 0 1 | 0 1 0 0 | 1 0 1 imm16 0 0 0 0 1
// d | 4 | a | de | 0 | 0 |
// 0xd4, 0x20, 0x00, 0x00
uint32_t insn = 0xd4ade001;
uint32_t *pos = (uint32_t *) code_pos;
*pos = insn;
/**code_pos = 0xd4;
*(code_pos+1) = 0x60;
*(code_pos+2) = 0x00;
*(code_pos+3) = 0x00;*/
ICache::invalidate_range(code_pos, 4);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2108, Red Hat Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@ -71,7 +71,7 @@ public:
return (encoding() & 0xff000000) == 0x10000000;
}
inline bool is_nop();
inline bool is_nop() const;
bool is_jump();
bool is_general_jump();
inline bool is_jump_or_nop();
@ -543,7 +543,7 @@ class NativeTstRegMem: public NativeInstruction {
public:
};
inline bool NativeInstruction::is_nop() {
inline bool NativeInstruction::is_nop() const{
uint32_t insn = *(uint32_t*)addr_at(0);
return insn == 0xd503201f;
}
@ -666,4 +666,48 @@ inline NativeLdSt* NativeLdSt_at(address addr) {
return (NativeLdSt*)addr;
}
class NativePostCallNop: public NativeInstruction {
public:
bool check() const { return is_nop(); }
int displacement() const { return 0; }
void patch(jint diff);
void make_deopt();
};
inline NativePostCallNop* nativePostCallNop_at(address address) {
NativePostCallNop* nop = (NativePostCallNop*) address;
if (nop->check()) {
return nop;
}
return NULL;
}
inline NativePostCallNop* nativePostCallNop_unsafe_at(address address) {
NativePostCallNop* nop = (NativePostCallNop*) address;
assert(nop->check(), "");
return nop;
}
class NativeDeoptInstruction: public NativeInstruction {
public:
enum {
instruction_size = 4,
instruction_offset = 0,
};
address instruction_address() const { return addr_at(instruction_offset); }
address next_instruction_address() const { return addr_at(instruction_size); }
void verify();
static bool is_deopt_at(address instr) {
assert(instr != NULL, "");
uint32_t value = *(uint32_t *) instr;
return value == 0xd4ade001;
}
// MT-safe patching
static void insert(address code_pos);
};
#endif // CPU_AARCH64_NATIVEINST_AARCH64_HPP

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, Arm Limited. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@ -36,13 +36,13 @@ address RegisterMap::pd_location(VMReg base_reg, int slot_idx) const {
int base_reg_enc = (base_reg->value() - ConcreteRegisterImpl::max_gpr) /
FloatRegisterImpl::max_slots_per_register;
intptr_t offset_in_bytes = slot_idx * VMRegImpl::stack_slot_size;
address base_location = location(base_reg);
address base_location = location(base_reg, nullptr);
if (base_location != NULL) {
return base_location + offset_in_bytes;
} else {
return NULL;
}
} else {
return location(base_reg->next(slot_idx));
return location(base_reg->next(slot_idx), nullptr);
}
}

View File

@ -28,6 +28,7 @@
#include "asm/macroAssembler.hpp"
#include "asm/macroAssembler.inline.hpp"
#include "code/codeCache.hpp"
#include "code/compiledIC.hpp"
#include "code/debugInfoRec.hpp"
#include "code/icBuffer.hpp"
#include "code/vtableStubs.hpp"
@ -41,6 +42,8 @@
#include "oops/compiledICHolder.hpp"
#include "oops/klass.inline.hpp"
#include "prims/methodHandles.hpp"
#include "runtime/continuation.hpp"
#include "runtime/continuationEntry.inline.hpp"
#include "runtime/jniHandles.hpp"
#include "runtime/safepointMechanism.hpp"
#include "runtime/sharedRuntime.hpp"
@ -267,7 +270,7 @@ void RegisterSaver::restore_live_registers(MacroAssembler* masm) {
#endif
__ pop_CPU_state(_save_vectors);
#endif
__ leave();
__ ldp(rfp, lr, Address(__ post(sp, 2 * wordSize)));
}
@ -720,6 +723,10 @@ void SharedRuntime::gen_i2c_adapter(MacroAssembler *masm,
}
}
__ mov(rscratch2, rscratch1);
__ push_cont_fastpath(rthread); // Set JavaThread::_cont_fastpath to the sp of the oldest interpreted frame we know about; kills rscratch1
__ mov(rscratch1, rscratch2);
// 6243940 We might end up in handle_wrong_method if
// the callee is deoptimized as we race thru here. If that
// happens we don't want to take a safepoint because the
@ -1182,6 +1189,91 @@ static void verify_oop_args(MacroAssembler* masm,
}
}
// defined in stubGenerator_aarch64.cpp
OopMap* continuation_enter_setup(MacroAssembler* masm, int& stack_slots);
void fill_continuation_entry(MacroAssembler* masm);
void continuation_enter_cleanup(MacroAssembler* masm);
// enterSpecial(Continuation c, boolean isContinue, boolean isVirtualThread)
// On entry: c_rarg1 -- the continuation object
// c_rarg2 -- isContinue
// c_rarg3 -- isVirtualThread
static void gen_continuation_enter(MacroAssembler* masm,
const methodHandle& method,
const BasicType* sig_bt,
const VMRegPair* regs,
int& exception_offset,
OopMapSet*oop_maps,
int& frame_complete,
int& stack_slots) {
//verify_oop_args(masm, method, sig_bt, regs);
Address resolve(SharedRuntime::get_resolve_static_call_stub(),
relocInfo::static_call_type);
stack_slots = 2; // will be overwritten
address start = __ pc();
Label call_thaw, exit;
__ enter();
OopMap* map = continuation_enter_setup(masm, stack_slots);
// Frame is now completed as far as size and linkage.
frame_complete =__ pc() - start;
fill_continuation_entry(masm);
__ cmp(c_rarg2, (u1)0);
__ br(Assembler::NE, call_thaw);
address mark = __ pc();
__ trampoline_call1(resolve, NULL, false);
oop_maps->add_gc_map(__ pc() - start, map);
__ post_call_nop();
__ b(exit);
__ bind(call_thaw);
rt_call(masm, CAST_FROM_FN_PTR(address, StubRoutines::cont_thaw()));
oop_maps->add_gc_map(__ pc() - start, map->deep_copy());
ContinuationEntry::return_pc_offset = __ pc() - start;
__ post_call_nop();
__ bind(exit);
continuation_enter_cleanup(masm);
__ leave();
__ ret(lr);
/// exception handling
exception_offset = __ pc() - start;
{
__ mov(r19, r0); // save return value contaning the exception oop in callee-saved R19
continuation_enter_cleanup(masm);
__ ldr(c_rarg1, Address(rfp, wordSize)); // return address
__ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::exception_handler_for_return_address), rthread, c_rarg1);
// see OptoRuntime::generate_exception_blob: r0 -- exception oop, r3 -- exception pc
__ mov(r1, r0); // the exception handler
__ mov(r0, r19); // restore return value contaning the exception oop
__ verify_oop(r0);
__ leave();
__ mov(r3, lr);
__ br(r1); // the exception handler
}
CodeBuffer* cbuf = masm->code_section()->outer();
address stub = CompiledStaticCall::emit_to_interp_stub(*cbuf, mark);
}
static void gen_special_dispatch(MacroAssembler* masm,
const methodHandle& method,
const BasicType* sig_bt,
@ -1263,6 +1355,37 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm,
BasicType* in_sig_bt,
VMRegPair* in_regs,
BasicType ret_type) {
if (method->is_continuation_enter_intrinsic()) {
vmIntrinsics::ID iid = method->intrinsic_id();
intptr_t start = (intptr_t)__ pc();
int vep_offset = ((intptr_t)__ pc()) - start;
int exception_offset = 0;
int frame_complete = 0;
int stack_slots = 0;
OopMapSet* oop_maps = new OopMapSet();
gen_continuation_enter(masm,
method,
in_sig_bt,
in_regs,
exception_offset,
oop_maps,
frame_complete,
stack_slots);
__ flush();
nmethod* nm = nmethod::new_native_nmethod(method,
compile_id,
masm->code(),
vep_offset,
frame_complete,
stack_slots,
in_ByteSize(-1),
in_ByteSize(-1),
oop_maps,
exception_offset);
ContinuationEntry::set_enter_nmethod(nm);
return nm;
}
if (method->is_method_handle_intrinsic()) {
vmIntrinsics::ID iid = method->intrinsic_id();
intptr_t start = (intptr_t)__ pc();

View File

@ -0,0 +1,91 @@
/*
* Copyright (c) 2019, 2022, 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.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#ifndef CPU_AARCH64_SMALLREGISTERMAP_AARCH64_INLINE_HPP
#define CPU_AARCH64_SMALLREGISTERMAP_AARCH64_INLINE_HPP
#include "runtime/frame.inline.hpp"
#include "runtime/registerMap.hpp"
// Java frames don't have callee saved registers (except for rfp), so we can use a smaller RegisterMap
class SmallRegisterMap {
public:
static constexpr SmallRegisterMap* instance = nullptr;
private:
static void assert_is_rfp(VMReg r) NOT_DEBUG_RETURN
DEBUG_ONLY({ assert (r == rfp->as_VMReg() || r == rfp->as_VMReg()->next(), "Reg: %s", r->name()); })
public:
// as_RegisterMap is used when we didn't want to templatize and abstract over RegisterMap type to support SmallRegisterMap
// Consider enhancing SmallRegisterMap to support those cases
const RegisterMap* as_RegisterMap() const { return nullptr; }
RegisterMap* as_RegisterMap() { return nullptr; }
RegisterMap* copy_to_RegisterMap(RegisterMap* map, intptr_t* sp) const {
map->clear();
map->set_include_argument_oops(this->include_argument_oops());
frame::update_map_with_saved_link(map, (intptr_t**)sp - frame::sender_sp_offset);
return map;
}
SmallRegisterMap() {}
SmallRegisterMap(const RegisterMap* map) {
#ifdef ASSERT
for(int i = 0; i < RegisterMap::reg_count; i++) {
VMReg r = VMRegImpl::as_VMReg(i);
if (map->location(r, (intptr_t*)nullptr) != nullptr) assert_is_rfp(r);
}
#endif
}
inline address location(VMReg reg, intptr_t* sp) const {
assert_is_rfp(reg);
return (address)(sp - frame::sender_sp_offset);
}
inline void set_location(VMReg reg, address loc) { assert_is_rfp(reg); }
JavaThread* thread() const {
#ifndef ASSERT
guarantee (false, "unreachable");
#endif
return nullptr;
}
bool update_map() const { return false; }
bool walk_cont() const { return false; }
bool include_argument_oops() const { return false; }
void set_include_argument_oops(bool f) {}
bool in_cont() const { return false; }
stackChunkHandle stack_chunk() const { return stackChunkHandle(); }
#ifdef ASSERT
bool should_skip_missing() const { return false; }
VMReg find_register_spilled_here(void* p, intptr_t* sp) { return rfp->as_VMReg(); }
void print() const { print_on(tty); }
void print_on(outputStream* st) const { st->print_cr("Small register map"); }
#endif
};
#endif // CPU_AARCH64_SMALLREGISTERMAP_AARCH64_INLINE_HPP

View File

@ -0,0 +1,149 @@
/*
* Copyright (c) 2019, 2022, 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.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#ifndef CPU_AARCH64_STACKCHUNKFRAMESTREAM_AARCH64_INLINE_HPP
#define CPU_AARCH64_STACKCHUNKFRAMESTREAM_AARCH64_INLINE_HPP
#include "interpreter/oopMapCache.hpp"
#include "runtime/frame.inline.hpp"
#include "runtime/registerMap.hpp"
#ifdef ASSERT
template <ChunkFrames frame_kind>
inline bool StackChunkFrameStream<frame_kind>::is_in_frame(void* p0) const {
assert(!is_done(), "");
intptr_t* p = (intptr_t*)p0;
int argsize = is_compiled() ? (_cb->as_compiled_method()->method()->num_stack_arg_slots() * VMRegImpl::stack_slot_size) >> LogBytesPerWord : 0;
int frame_size = _cb->frame_size() + argsize;
return p == sp() - frame::sender_sp_offset || ((p - unextended_sp()) >= 0 && (p - unextended_sp()) < frame_size);
}
#endif
template <ChunkFrames frame_kind>
inline frame StackChunkFrameStream<frame_kind>::to_frame() const {
if (is_done()) {
return frame(_sp, _sp, nullptr, nullptr, nullptr, nullptr, true);
} else {
return frame(sp(), unextended_sp(), fp(), pc(), cb(), _oopmap, true);
}
}
template <ChunkFrames frame_kind>
inline address StackChunkFrameStream<frame_kind>::get_pc() const {
assert(!is_done(), "");
return *(address*)(_sp - 1);
}
template <ChunkFrames frame_kind>
inline intptr_t* StackChunkFrameStream<frame_kind>::fp() const {
intptr_t* fp_addr = _sp - frame::sender_sp_offset;
return (frame_kind == ChunkFrames::Mixed && is_interpreted())
? fp_addr + *fp_addr // derelativize
: *(intptr_t**)fp_addr;
}
template <ChunkFrames frame_kind>
inline intptr_t* StackChunkFrameStream<frame_kind>::derelativize(int offset) const {
intptr_t* fp = this->fp();
assert(fp != nullptr, "");
return fp + fp[offset];
}
template <ChunkFrames frame_kind>
inline intptr_t* StackChunkFrameStream<frame_kind>::unextended_sp_for_interpreter_frame() const {
assert_is_interpreted_and_frame_type_mixed();
return derelativize(frame::interpreter_frame_last_sp_offset);
}
template <ChunkFrames frame_kind>
intptr_t* StackChunkFrameStream<frame_kind>::next_sp_for_interpreter_frame() const {
assert_is_interpreted_and_frame_type_mixed();
return (derelativize(frame::interpreter_frame_locals_offset) + 1 >= _end) ? _end : fp() + frame::sender_sp_offset;
}
template <ChunkFrames frame_kind>
inline void StackChunkFrameStream<frame_kind>::next_for_interpreter_frame() {
assert_is_interpreted_and_frame_type_mixed();
if (derelativize(frame::interpreter_frame_locals_offset) + 1 >= _end) {
_unextended_sp = _end;
_sp = _end;
} else {
intptr_t* fp = this->fp();
_unextended_sp = fp + fp[frame::interpreter_frame_sender_sp_offset];
_sp = fp + frame::sender_sp_offset;
}
}
template <ChunkFrames frame_kind>
inline int StackChunkFrameStream<frame_kind>::interpreter_frame_size() const {
assert_is_interpreted_and_frame_type_mixed();
intptr_t* top = unextended_sp(); // later subtract argsize if callee is interpreted
intptr_t* bottom = derelativize(frame::interpreter_frame_locals_offset) + 1; // the sender's unextended sp: derelativize(frame::interpreter_frame_sender_sp_offset);
return (int)(bottom - top);
}
template <ChunkFrames frame_kind>
inline int StackChunkFrameStream<frame_kind>::interpreter_frame_stack_argsize() const {
assert_is_interpreted_and_frame_type_mixed();
int diff = (int)(derelativize(frame::interpreter_frame_locals_offset) - derelativize(frame::interpreter_frame_sender_sp_offset) + 1);
return diff;
}
template <ChunkFrames frame_kind>
inline int StackChunkFrameStream<frame_kind>::interpreter_frame_num_oops() const {
assert_is_interpreted_and_frame_type_mixed();
ResourceMark rm;
InterpreterOopMap mask;
frame f = to_frame();
f.interpreted_frame_oop_map(&mask);
return mask.num_oops()
+ 1 // for the mirror oop
+ ((intptr_t*)f.interpreter_frame_monitor_begin()
- (intptr_t*)f.interpreter_frame_monitor_end())/BasicObjectLock::size();
}
template<>
template<>
inline void StackChunkFrameStream<ChunkFrames::Mixed>::update_reg_map_pd(RegisterMap* map) {
if (map->update_map()) {
frame::update_map_with_saved_link(map, map->in_cont() ? (intptr_t**)(intptr_t)frame::sender_sp_offset
: (intptr_t**)(_sp - frame::sender_sp_offset));
}
}
template<>
template<>
inline void StackChunkFrameStream<ChunkFrames::CompiledOnly>::update_reg_map_pd(RegisterMap* map) {
if (map->update_map()) {
frame::update_map_with_saved_link(map, map->in_cont() ? (intptr_t**)(intptr_t)frame::sender_sp_offset
: (intptr_t**)(_sp - frame::sender_sp_offset));
}
}
template <ChunkFrames frame_kind>
template <typename RegisterMapT>
inline void StackChunkFrameStream<frame_kind>::update_reg_map_pd(RegisterMapT* map) {}
#endif // CPU_AARCH64_STACKCHUNKFRAMESTREAM_AARCH64_INLINE_HPP

View File

@ -0,0 +1,42 @@
/*
* Copyright (c) 2019, 2022, 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.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#ifndef CPU_AARCH64_STACKCHUNKOOP_AARCH64_INLINE_HPP
#define CPU_AARCH64_STACKCHUNKOOP_AARCH64_INLINE_HPP
#include "runtime/frame.inline.hpp"
inline void stackChunkOopDesc::relativize_frame_pd(frame& fr) const {
if (fr.is_interpreted_frame()) {
fr.set_offset_fp(relativize_address(fr.fp()));
}
}
inline void stackChunkOopDesc::derelativize_frame_pd(frame& fr) const {
if (fr.is_interpreted_frame()) {
fr.set_fp(derelativize_address(fr.offset_fp()));
}
}
#endif // CPU_AARCH64_STACKCHUNKOOP_AARCH64_INLINE_HPP

View File

@ -42,6 +42,8 @@
#include "oops/oop.inline.hpp"
#include "prims/methodHandles.hpp"
#include "runtime/atomic.hpp"
#include "runtime/continuation.hpp"
#include "runtime/continuationEntry.inline.hpp"
#include "runtime/frame.inline.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/sharedRuntime.hpp"
@ -49,6 +51,7 @@
#include "runtime/stubRoutines.hpp"
#include "runtime/thread.inline.hpp"
#include "utilities/align.hpp"
#include "utilities/globalDefinitions.hpp"
#include "utilities/powerOfTwo.hpp"
#ifdef COMPILER2
#include "opto/runtime.hpp"
@ -73,6 +76,10 @@
#define BIND(label) bind(label); BLOCK_COMMENT(#label ":")
OopMap* continuation_enter_setup(MacroAssembler* masm, int& stack_slots);
void fill_continuation_entry(MacroAssembler* masm);
void continuation_enter_cleanup(MacroAssembler* masm);
// Stub Code definitions
class StubGenerator: public StubCodeGenerator {
@ -349,6 +356,8 @@ class StubGenerator: public StubCodeGenerator {
}
#endif
__ pop_cont_fastpath(rthread);
// restore callee-save registers
__ ldpd(v15, v14, d15_save);
__ ldpd(v13, v12, d13_save);
@ -5144,6 +5153,20 @@ class StubGenerator: public StubCodeGenerator {
address start = __ pc();
BarrierSetAssembler* bs_asm = BarrierSet::barrier_set()->barrier_set_assembler();
if (bs_asm->nmethod_code_patching()) {
BarrierSetNMethod* bs_nm = BarrierSet::barrier_set()->barrier_set_nmethod();
// We can get here despite the nmethod being good, if we have not
// yet applied our cross modification fence.
Address thread_epoch_addr(rthread, in_bytes(bs_nm->thread_disarmed_offset()) + 4);
__ lea(rscratch2, ExternalAddress(bs_asm->patching_epoch_addr()));
__ ldrw(rscratch2, rscratch2);
__ strw(rscratch2, thread_epoch_addr);
__ isb();
__ membar(__ LoadLoad);
}
__ set_last_Java_frame(sp, rfp, lr, rscratch1);
__ enter();
@ -6466,6 +6489,268 @@ class StubGenerator: public StubCodeGenerator {
}
#endif // LINUX
RuntimeStub* generate_cont_doYield() {
if (!Continuations::enabled()) return nullptr;
const char *name = "cont_doYield";
enum layout {
rfp_off1,
rfp_off2,
lr_off,
lr_off2,
framesize // inclusive of return address
};
// assert(is_even(framesize/2), "sp not 16-byte aligned");
int insts_size = 512;
int locs_size = 64;
CodeBuffer code(name, insts_size, locs_size);
OopMapSet* oop_maps = new OopMapSet();
MacroAssembler* masm = new MacroAssembler(&code);
MacroAssembler* _masm = masm;
address start = __ pc();
__ enter();
__ mov(c_rarg1, sp);
int frame_complete = __ pc() - start;
address the_pc = __ pc();
__ post_call_nop(); // this must be exactly after the pc value that is pushed into the frame info, we use this nop for fast CodeBlob lookup
__ mov(c_rarg0, rthread);
__ set_last_Java_frame(sp, rfp, the_pc, rscratch1);
__ call_VM_leaf(Continuation::freeze_entry(), 2);
__ reset_last_Java_frame(true);
Label pinned;
__ cbnz(r0, pinned);
// We've succeeded, set sp to the ContinuationEntry
__ ldr(rscratch1, Address(rthread, JavaThread::cont_entry_offset()));
__ mov(sp, rscratch1);
continuation_enter_cleanup(masm);
__ bind(pinned); // pinned -- return to caller
__ leave();
__ ret(lr);
OopMap* map = new OopMap(framesize, 1);
oop_maps->add_gc_map(the_pc - start, map);
RuntimeStub* stub = // codeBlob framesize is in words (not VMRegImpl::slot_size)
RuntimeStub::new_runtime_stub(name,
&code,
frame_complete,
(framesize >> (LogBytesPerWord - LogBytesPerInt)),
oop_maps, false);
return stub;
}
address generate_cont_thaw(bool return_barrier, bool exception) {
assert(return_barrier || !exception, "must be");
address start = __ pc();
if (return_barrier) {
__ ldr(rscratch1, Address(rthread, JavaThread::cont_entry_offset()));
__ mov(sp, rscratch1);
}
assert_asm(_masm, (__ ldr(rscratch1, Address(rthread, JavaThread::cont_entry_offset())), __ cmp(sp, rscratch1)), Assembler::EQ, "incorrect sp");
if (return_barrier) {
// preserve possible return value from a method returning to the return barrier
__ fmovd(rscratch1, v0);
__ stp(rscratch1, r0, Address(__ pre(sp, -2 * wordSize)));
}
__ movw(c_rarg1, (return_barrier ? 1 : 0) + (exception ? 1 : 0));
__ call_VM_leaf(CAST_FROM_FN_PTR(address, Continuation::prepare_thaw), rthread, c_rarg1);
__ mov(rscratch2, r0); // r0 contains the size of the frames to thaw, 0 if overflow or no more frames
if (return_barrier) {
// restore return value (no safepoint in the call to thaw, so even an oop return value should be OK)
__ ldp(rscratch1, r0, Address(__ post(sp, 2 * wordSize)));
__ fmovd(v0, rscratch1);
}
assert_asm(_masm, (__ ldr(rscratch1, Address(rthread, JavaThread::cont_entry_offset())), __ cmp(sp, rscratch1)), Assembler::EQ, "incorrect sp");
Label thaw_success;
// rscratch2 contains the size of the frames to thaw, 0 if overflow or no more frames
__ cbnz(rscratch2, thaw_success);
__ lea(rscratch1, ExternalAddress(StubRoutines::throw_StackOverflowError_entry()));
__ br(rscratch1);
__ bind(thaw_success);
// make room for the thawed frames
__ sub(rscratch1, sp, rscratch2);
__ andr(rscratch1, rscratch1, -16); // align
__ mov(sp, rscratch1);
if (return_barrier) {
// save original return value -- again
__ fmovd(rscratch1, v0);
__ stp(rscratch1, r0, Address(__ pre(sp, -2 * wordSize)));
}
// If we want, we can templatize thaw by kind, and have three different entries
if (exception) __ movw(c_rarg1, (uint32_t)Continuation::thaw_exception);
else if (return_barrier) __ movw(c_rarg1, (uint32_t)Continuation::thaw_return_barrier);
else __ movw(c_rarg1, (uint32_t)Continuation::thaw_top);
__ call_VM_leaf(Continuation::thaw_entry(), rthread, c_rarg1);
__ mov(rscratch2, r0); // r0 is the sp of the yielding frame
if (return_barrier) {
// restore return value (no safepoint in the call to thaw, so even an oop return value should be OK)
__ ldp(rscratch1, r0, Address(__ post(sp, 2 * wordSize)));
__ fmovd(v0, rscratch1);
} else {
__ mov(r0, zr); // return 0 (success) from doYield
}
// we're now on the yield frame (which is in an address above us b/c rsp has been pushed down)
__ sub(sp, rscratch2, 2*wordSize); // now pointing to rfp spill
__ mov(rfp, sp);
if (exception) {
__ ldr(c_rarg1, Address(rfp, wordSize)); // return address
__ verify_oop(r0);
__ mov(r19, r0); // save return value contaning the exception oop in callee-saved R19
__ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::exception_handler_for_return_address), rthread, c_rarg1);
// Reinitialize the ptrue predicate register, in case the external runtime call clobbers ptrue reg, as we may return to SVE compiled code.
// __ reinitialize_ptrue();
// see OptoRuntime::generate_exception_blob: r0 -- exception oop, r3 -- exception pc
__ mov(r1, r0); // the exception handler
__ mov(r0, r19); // restore return value contaning the exception oop
__ verify_oop(r0);
__ leave();
__ mov(r3, lr);
__ br(r1); // the exception handler
}
// We're "returning" into the topmost thawed frame; see Thaw::push_return_frame
__ leave();
__ ret(lr);
return start;
}
address generate_cont_thaw() {
if (!Continuations::enabled()) return nullptr;
StubCodeMark mark(this, "StubRoutines", "Cont thaw");
address start = __ pc();
generate_cont_thaw(false, false);
return start;
}
address generate_cont_returnBarrier() {
if (!Continuations::enabled()) return nullptr;
// TODO: will probably need multiple return barriers depending on return type
StubCodeMark mark(this, "StubRoutines", "cont return barrier");
address start = __ pc();
generate_cont_thaw(true, false);
return start;
}
address generate_cont_returnBarrier_exception() {
if (!Continuations::enabled()) return nullptr;
StubCodeMark mark(this, "StubRoutines", "cont return barrier exception handler");
address start = __ pc();
generate_cont_thaw(true, true);
return start;
}
#if INCLUDE_JFR
static void jfr_prologue(address the_pc, MacroAssembler* _masm, Register thread) {
__ set_last_Java_frame(sp, rfp, the_pc, rscratch1);
__ mov(c_rarg0, thread);
}
// The handle is dereferenced through a load barrier.
static void jfr_epilogue(MacroAssembler* _masm, Register thread) {
__ reset_last_Java_frame(true);
Label null_jobject;
__ cbz(r0, null_jobject);
DecoratorSet decorators = ACCESS_READ | IN_NATIVE;
BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler();
bs->load_at(_masm, decorators, T_OBJECT, r0, Address(r0, 0), c_rarg0, thread);
__ bind(null_jobject);
}
static RuntimeStub* generate_jfr_stub(const char* name, address entrypoint) {
enum layout {
rbp_off,
rbpH_off,
return_off,
return_off2,
framesize // inclusive of return address
};
int insts_size = 512;
int locs_size = 64;
CodeBuffer code(name, insts_size, locs_size);
OopMapSet* oop_maps = new OopMapSet();
MacroAssembler* masm = new MacroAssembler(&code);
MacroAssembler* _masm = masm;
address start = __ pc();
__ enter();
int frame_complete = __ pc() - start;
address the_pc = __ pc();
jfr_prologue(the_pc, _masm, rthread);
__ call_VM_leaf(entrypoint, 1);
jfr_epilogue(_masm, rthread);
__ leave();
__ ret(lr);
OopMap* map = new OopMap(framesize, 1); // rfp
oop_maps->add_gc_map(the_pc - start, map);
RuntimeStub* stub = // codeBlob framesize is in words (not VMRegImpl::slot_size)
RuntimeStub::new_runtime_stub(name, &code, frame_complete,
(framesize >> (LogBytesPerWord - LogBytesPerInt)),
oop_maps, false);
return stub;
}
// For c2: c_rarg0 is junk, call to runtime to write a checkpoint.
// It returns a jobject handle to the event writer.
// The handle is dereferenced and the return value is the event writer oop.
RuntimeStub* generate_jfr_write_checkpoint() {
return generate_jfr_stub("jfr_write_checkpoint",
CAST_FROM_FN_PTR(address, JfrIntrinsicSupport::write_checkpoint));
}
// For c1: call the corresponding runtime routine, it returns a jobject handle to the event writer.
// The handle is dereferenced and the return value is the event writer oop.
RuntimeStub* generate_jfr_get_event_writer() {
return generate_jfr_stub("jfr_get_event_writer",
CAST_FROM_FN_PTR(address, JfrIntrinsicSupport::event_writer));
}
#endif // INCLUDE_JFR
// Continuation point for throwing of implicit exceptions that are
// not handled in the current activation. Fabricates an exception
// oop and initiates normal exception dispatching in this
@ -7450,6 +7735,21 @@ class StubGenerator: public StubCodeGenerator {
}
}
void generate_phase1() {
// Continuation stubs:
StubRoutines::_cont_thaw = generate_cont_thaw();
StubRoutines::_cont_returnBarrier = generate_cont_returnBarrier();
StubRoutines::_cont_returnBarrierExc = generate_cont_returnBarrier_exception();
StubRoutines::_cont_doYield_stub = generate_cont_doYield();
StubRoutines::_cont_doYield = StubRoutines::_cont_doYield_stub == nullptr ? nullptr
: StubRoutines::_cont_doYield_stub->entry_point();
JFR_ONLY(StubRoutines::_jfr_write_checkpoint_stub = generate_jfr_write_checkpoint();)
JFR_ONLY(StubRoutines::_jfr_write_checkpoint = StubRoutines::_jfr_write_checkpoint_stub->entry_point();)
JFR_ONLY(StubRoutines::_jfr_get_event_writer_stub = generate_jfr_get_event_writer();)
JFR_ONLY(StubRoutines::_jfr_get_event_writer = StubRoutines::_jfr_get_event_writer_stub->entry_point();)
}
void generate_all() {
// support for verify_oop (must happen after universe_init)
if (VerifyOops) {
@ -7592,21 +7892,23 @@ class StubGenerator: public StubCodeGenerator {
}
public:
StubGenerator(CodeBuffer* code, bool all) : StubCodeGenerator(code) {
if (all) {
generate_all();
} else {
StubGenerator(CodeBuffer* code, int phase) : StubCodeGenerator(code) {
if (phase == 0) {
generate_initial();
} else if (phase == 1) {
generate_phase1(); // stubs that must be available for the interpreter
} else {
generate_all();
}
}
}; // end class declaration
#define UCM_TABLE_MAX_ENTRIES 8
void StubGenerator_generate(CodeBuffer* code, bool all) {
void StubGenerator_generate(CodeBuffer* code, int phase) {
if (UnsafeCopyMemory::_table == NULL) {
UnsafeCopyMemory::create_table(UCM_TABLE_MAX_ENTRIES);
}
StubGenerator g(code, all);
StubGenerator g(code, phase);
}
@ -7641,3 +7943,75 @@ DEFAULT_ATOMIC_OP(cmpxchg, 8, _seq_cst)
#undef DEFAULT_ATOMIC_OP
#endif // LINUX
#undef __
#define __ masm->
// on exit, sp points to the ContinuationEntry
OopMap* continuation_enter_setup(MacroAssembler* masm, int& stack_slots) {
assert(ContinuationEntry::size() % VMRegImpl::stack_slot_size == 0, "");
assert(in_bytes(ContinuationEntry::cont_offset()) % VMRegImpl::stack_slot_size == 0, "");
assert(in_bytes(ContinuationEntry::chunk_offset()) % VMRegImpl::stack_slot_size == 0, "");
stack_slots += (int)ContinuationEntry::size()/wordSize;
__ sub(sp, sp, (int)ContinuationEntry::size()); // place Continuation metadata
OopMap* map = new OopMap(((int)ContinuationEntry::size() + wordSize)/ VMRegImpl::stack_slot_size, 0 /* arg_slots*/);
ContinuationEntry::setup_oopmap(map);
__ ldr(rscratch1, Address(rthread, JavaThread::cont_entry_offset()));
__ str(rscratch1, Address(sp, ContinuationEntry::parent_offset()));
__ mov(rscratch1, sp); // we can't use sp as the source in str
__ str(rscratch1, Address(rthread, JavaThread::cont_entry_offset()));
return map;
}
// on entry c_rarg1 points to the continuation
// sp points to ContinuationEntry
// c_rarg3 -- isVirtualThread
void fill_continuation_entry(MacroAssembler* masm) {
#ifdef ASSERT
__ movw(rscratch1, 0x1234);
__ strw(rscratch1, Address(sp, ContinuationEntry::cookie_offset()));
#endif
__ str (c_rarg1, Address(sp, ContinuationEntry::cont_offset()));
__ strw(c_rarg3, Address(sp, ContinuationEntry::flags_offset()));
__ str (zr, Address(sp, ContinuationEntry::chunk_offset()));
__ strw(zr, Address(sp, ContinuationEntry::argsize_offset()));
__ strw(zr, Address(sp, ContinuationEntry::pin_count_offset()));
__ ldr(rscratch1, Address(rthread, JavaThread::cont_fastpath_offset()));
__ str(rscratch1, Address(sp, ContinuationEntry::parent_cont_fastpath_offset()));
__ ldrw(rscratch1, Address(rthread, JavaThread::held_monitor_count_offset()));
__ strw(rscratch1, Address(sp, ContinuationEntry::parent_held_monitor_count_offset()));
__ str(zr, Address(rthread, JavaThread::cont_fastpath_offset()));
__ reset_held_monitor_count(rthread);
}
// on entry, sp points to the ContinuationEntry
// on exit, rfp points to the spilled rfp in the entry frame
void continuation_enter_cleanup(MacroAssembler* masm) {
#ifndef PRODUCT
Label OK;
__ ldr(rscratch1, Address(rthread, JavaThread::cont_entry_offset()));
__ cmp(sp, rscratch1);
__ br(Assembler::EQ, OK);
__ stop("incorrect sp1");
__ bind(OK);
#endif
__ ldr(rscratch1, Address(sp, ContinuationEntry::parent_cont_fastpath_offset()));
__ str(rscratch1, Address(rthread, JavaThread::cont_fastpath_offset()));
__ ldrw(rscratch1, Address(sp, ContinuationEntry::parent_held_monitor_count_offset()));
__ strw(rscratch1, Address(rthread, JavaThread::held_monitor_count_offset()));
__ ldr(rscratch2, Address(sp, ContinuationEntry::parent_offset()));
__ str(rscratch2, Address(rthread, JavaThread::cont_entry_offset()));
__ add(rfp, sp, (int)ContinuationEntry::size());
}
#undef __

View File

@ -573,7 +573,9 @@ address TemplateInterpreterGenerator::generate_safept_entry_for(
address runtime_entry) {
address entry = __ pc();
__ push(state);
__ push_cont_fastpath(rthread);
__ call_VM(noreg, runtime_entry);
__ pop_cont_fastpath(rthread);
__ membar(Assembler::AnyAny);
__ dispatch_via(vtos, Interpreter::_normal_table.table_for(vtos));
return entry;
@ -786,6 +788,7 @@ void TemplateInterpreterGenerator::lock_method() {
__ str(r0, Address(esp, BasicObjectLock::obj_offset_in_bytes()));
__ mov(c_rarg1, esp); // object address
__ lock_object(c_rarg1);
__ inc_held_monitor_count(rthread);
}
// Generate a fixed interpreter frame. This is identical setup for
@ -852,6 +855,18 @@ void TemplateInterpreterGenerator::generate_fixed_frame(bool native_call) {
// End of helpers
address TemplateInterpreterGenerator::generate_Continuation_doYield_entry(void) {
if (!Continuations::enabled()) return nullptr;
address entry = __ pc();
assert(StubRoutines::cont_doYield() != NULL, "stub not yet generated");
__ push_cont_fastpath(rthread);
__ far_jump(RuntimeAddress(CAST_FROM_FN_PTR(address, StubRoutines::cont_doYield())));
return entry;
}
// Various method entries
//------------------------------------------------------------------------------------------------------------------------
//
@ -1490,6 +1505,7 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) {
__ bind(unlock);
__ unlock_object(c_rarg1);
__ dec_held_monitor_count(rthread);
}
__ bind(L);
}

View File

@ -3862,6 +3862,9 @@ void TemplateTable::monitorenter()
__ str(r0, Address(c_rarg1, BasicObjectLock::obj_offset_in_bytes()));
__ lock_object(c_rarg1);
// The object is stored so counter should be increased even if stackoverflow is generated
__ inc_held_monitor_count(rthread);
// check to make sure this monitor doesn't cause stack overflow after locking
__ save_bcp(); // in case of exception
__ generate_stack_overflow_check(0);
@ -3920,6 +3923,7 @@ void TemplateTable::monitorexit()
__ bind(found);
__ push_ptr(r0); // make sure object is on stack (contract with oopMaps)
__ unlock_object(c_rarg1);
__ dec_held_monitor_count(rthread);
__ pop_ptr(r0); // discard object
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2022, 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
@ -1328,3 +1328,7 @@ void LIRGenerator::volatile_field_load(LIR_Address* address, LIR_Opr result,
}
__ load(address, result, info, lir_patch_none);
}
void LIRGenerator::do_continuation_doYield(Intrinsic* x) {
fatal("Continuation.doYield intrinsic is not implemented on this platform");
}

View File

@ -0,0 +1,47 @@
/*
* Copyright (c) 2022, 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.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#ifndef CPU_ARM_CONTINUATIONENTRY_ARM_INLINE_HPP
#define CPU_ARM_CONTINUATIONENTRY_ARM_INLINE_HPP
#include "runtime/continuationEntry.hpp"
// TODO: Implement
inline frame ContinuationEntry::to_frame() const {
Unimplemented();
return frame();
}
inline intptr_t* ContinuationEntry::entry_fp() const {
Unimplemented();
return nullptr;
}
inline void ContinuationEntry::update_register_map(RegisterMap* map) const {
Unimplemented();
}
#endif // CPU_ARM_CONTINUATIONENTRY_ARM_INLINE_HPP

View File

@ -0,0 +1,98 @@
/*
* Copyright (c) 2019, 2022, 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.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#ifndef CPU_ARM_CONTINUATION_ARM_INLINE_HPP
#define CPU_ARM_CONTINUATION_ARM_INLINE_HPP
#include "oops/stackChunkOop.inline.hpp"
#include "runtime/frame.hpp"
#include "runtime/frame.inline.hpp"
inline void FreezeBase::set_top_frame_metadata_pd(const frame& hf) {
Unimplemented();
}
template<typename FKind>
inline frame FreezeBase::sender(const frame& f) {
Unimplemented();
return frame();
}
template<typename FKind> frame FreezeBase::new_heap_frame(frame& f, frame& caller) {
Unimplemented();
return frame();
}
void FreezeBase::adjust_interpreted_frame_unextended_sp(frame& f) {
Unimplemented();
}
inline void FreezeBase::relativize_interpreted_frame_metadata(const frame& f, const frame& hf) {
Unimplemented();
}
inline void FreezeBase::patch_pd(frame& hf, const frame& caller) {
Unimplemented();
}
inline void FreezeBase::patch_stack_pd(intptr_t* frame_sp, intptr_t* heap_sp) {
Unimplemented();
}
inline frame ThawBase::new_entry_frame() {
Unimplemented();
return frame();
}
template<typename FKind> frame ThawBase::new_stack_frame(const frame& hf, frame& caller, bool bottom) {
Unimplemented();
return frame();
}
inline void ThawBase::set_interpreter_frame_bottom(const frame& f, intptr_t* bottom) {
Unimplemented();
}
inline void ThawBase::derelativize_interpreted_frame_metadata(const frame& hf, const frame& f) {
Unimplemented();
}
inline intptr_t* ThawBase::align(const frame& hf, intptr_t* frame_sp, frame& caller, bool bottom) {
Unimplemented();
return NULL;
}
inline void ThawBase::patch_pd(frame& f, const frame& caller) {
Unimplemented();
}
void ThawBase::patch_chunk_pd(intptr_t* sp) {
Unimplemented();
}
inline void ThawBase::prefetch_chunk_pd(void* start, int size) {
Unimplemented();
}
#endif // CPU_ARM_CONTINUATION_ARM_INLINE_HPP

View File

@ -0,0 +1,125 @@
/*
* Copyright (c) 2022, 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.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#ifndef CPU_ARM_CONTINUATIONHELPER_ARM_INLINE_HPP
#define CPU_ARM_CONTINUATIONHELPER_ARM_INLINE_HPP
#include "runtime/continuationHelper.hpp"
// TODO: Implement
template<typename FKind>
static inline intptr_t** link_address(const frame& f) {
Unimplemented();
return NULL;
}
inline int ContinuationHelper::frame_align_words(int size) {
Unimplemented();
return 0;
}
inline intptr_t* ContinuationHelper::frame_align_pointer(intptr_t* sp) {
Unimplemented();
return NULL;
}
template<typename FKind>
inline void ContinuationHelper::update_register_map(const frame& f, RegisterMap* map) {
Unimplemented();
}
inline void ContinuationHelper::update_register_map_with_callee(const frame& f, RegisterMap* map) {
Unimplemented();
}
inline void ContinuationHelper::push_pd(const frame& f) {
Unimplemented();
}
inline void ContinuationHelper::set_anchor_to_entry_pd(JavaFrameAnchor* anchor, ContinuationEntry* cont) {
Unimplemented();
}
#ifdef ASSERT
inline void ContinuationHelper::set_anchor_pd(JavaFrameAnchor* anchor, intptr_t* sp) {
Unimplemented();
}
inline bool ContinuationHelper::Frame::assert_frame_laid_out(frame f) {
Unimplemented();
return false;
}
#endif
inline intptr_t** ContinuationHelper::Frame::callee_link_address(const frame& f) {
Unimplemented();
return NULL;
}
template<typename FKind>
static inline intptr_t* real_fp(const frame& f) {
Unimplemented();
return NULL;
}
inline address* ContinuationHelper::InterpretedFrame::return_pc_address(const frame& f) {
Unimplemented();
return NULL;
}
inline void ContinuationHelper::InterpretedFrame::patch_sender_sp(frame& f, intptr_t* sp) {
Unimplemented();
}
inline address* ContinuationHelper::Frame::return_pc_address(const frame& f) {
Unimplemented();
return NULL;
}
inline address ContinuationHelper::Frame::real_pc(const frame& f) {
Unimplemented();
return NULL;
}
inline void ContinuationHelper::Frame::patch_pc(const frame& f, address pc) {
Unimplemented();
}
inline intptr_t* ContinuationHelper::InterpretedFrame::frame_top(const frame& f, InterpreterOopMap* mask) { // inclusive; this will be copied with the frame
Unimplemented();
return NULL;
}
inline intptr_t* ContinuationHelper::InterpretedFrame::frame_bottom(const frame& f) { // exclusive; this will not be copied with the frame
Unimplemented();
return NULL;
}
inline intptr_t* ContinuationHelper::InterpretedFrame::frame_top(const frame& f, int callee_argsize, bool callee_interpreted) {
Unimplemented();
return NULL;
}
#endif // CPU_ARM_CONTINUATIONHELPER_ARM_INLINE_HPP

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2022, 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
@ -230,10 +230,12 @@ void frame::patch_pc(Thread* thread, address pc) {
tty->print_cr("patch_pc at address" INTPTR_FORMAT " [" INTPTR_FORMAT " -> " INTPTR_FORMAT "] ",
p2i(pc_addr), p2i(*pc_addr), p2i(pc));
}
DEBUG_ONLY(address old_pc = _pc;)
*pc_addr = pc;
_pc = pc; // must be set before call to get_deopt_original_pc
address original_pc = CompiledMethod::get_deopt_original_pc(this);
if (original_pc != NULL) {
assert(original_pc == _pc, "expected original PC to be stored before patching");
assert(original_pc == old_pc, "expected original PC to be stored before patching");
_deopt_state = is_deoptimized;
// leave _pc as is
} else {
@ -246,11 +248,6 @@ bool frame::is_interpreted_frame() const {
return Interpreter::contains(pc());
}
int frame::frame_size(RegisterMap* map) const {
frame sender = this->sender(map);
return sender.sp() - sp();
}
intptr_t* frame::entry_frame_argument_at(int offset) const {
assert(is_entry_frame(), "entry frame expected");
// convert offset to index to deal with tsi
@ -277,6 +274,7 @@ BasicObjectLock* frame::interpreter_frame_monitor_begin() const {
return (BasicObjectLock*) addr_at(interpreter_frame_monitor_block_bottom_offset);
}
// Pointer beyond the "oldest/deepest" BasicObjectLock on stack.
BasicObjectLock* frame::interpreter_frame_monitor_end() const {
BasicObjectLock* result = (BasicObjectLock*) *addr_at(interpreter_frame_monitor_block_top_offset);
// make sure the pointer points inside the frame
@ -397,56 +395,6 @@ frame frame::sender_for_interpreter_frame(RegisterMap* map) const {
return frame(sender_sp, unextended_sp, link(), sender_pc());
}
frame frame::sender_for_compiled_frame(RegisterMap* map) const {
assert(map != NULL, "map must be set");
// frame owned by optimizing compiler
assert(_cb->frame_size() >= 0, "must have non-zero frame size");
intptr_t* sender_sp = unextended_sp() + _cb->frame_size();
intptr_t* unextended_sp = sender_sp;
address sender_pc = (address) *(sender_sp - sender_sp_offset + return_addr_offset);
// This is the saved value of FP which may or may not really be an FP.
// It is only an FP if the sender is an interpreter frame (or C1?).
intptr_t** saved_fp_addr = (intptr_t**) (sender_sp - sender_sp_offset + link_offset);
if (map->update_map()) {
// Tell GC to use argument oopmaps for some runtime stubs that need it.
// For C1, the runtime stub might not have oop maps, so set this flag
// outside of update_register_map.
map->set_include_argument_oops(_cb->caller_must_gc_arguments(map->thread()));
if (_cb->oop_maps() != NULL) {
OopMapSet::update_register_map(this, map);
}
// Since the prolog does the save and restore of FP there is no oopmap
// for it so we must fill in its location as if there was an oopmap entry
// since if our caller was compiled code there could be live jvm state in it.
update_map_with_saved_link(map, saved_fp_addr);
}
assert(sender_sp != sp(), "must have changed");
return frame(sender_sp, unextended_sp, *saved_fp_addr, sender_pc);
}
frame frame::sender(RegisterMap* map) const {
// Default is we done have to follow them. The sender_for_xxx will
// update it accordingly
map->set_include_argument_oops(false);
if (is_entry_frame()) return sender_for_entry_frame(map);
if (is_interpreted_frame()) return sender_for_interpreter_frame(map);
assert(_cb == CodeCache::find_blob(pc()),"Must be the same");
if (_cb != NULL) {
return sender_for_compiled_frame(map);
}
assert(false, "should not be called for a C frame");
return frame();
}
bool frame::is_interpreted_frame_valid(JavaThread* thread) const {
assert(is_interpreted_frame(), "Not an interpreted frame");
// These are reasonable sanity checks
@ -545,7 +493,6 @@ BasicType frame::interpreter_frame_result(oop* oop_result, jvalue* value_result)
return type;
}
intptr_t* frame::interpreter_frame_tos_at(jint offset) const {
int index = (Interpreter::expr_offset_in_bytes(offset)/wordSize);
return &interpreter_frame_tos_address()[index];

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2022, 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
@ -54,7 +54,11 @@
interpreter_frame_monitor_block_bottom_offset = interpreter_frame_initial_sp_offset,
// Entry frames
entry_frame_call_wrapper_offset = 0
entry_frame_call_wrapper_offset = 0,
metadata_words = sender_sp_offset,
frame_alignment = 16,
// size, in words, of maximum shift in frame position due to alignment
align_wiggle = 1
};
intptr_t ptr_at(int offset) const {
@ -90,6 +94,8 @@
}
#endif
const ImmutableOopMap* get_oop_map() const;
public:
// Constructors
@ -110,6 +116,9 @@
// expression stack tos if we are nested in a java call
intptr_t* interpreter_frame_last_sp() const;
template <typename RegisterMapT>
static void update_map_with_saved_link(RegisterMapT* map, intptr_t** link_addr);
// deoptimization support
void interpreter_frame_set_last_sp(intptr_t* sp);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2022, 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
@ -39,6 +39,12 @@ inline frame::frame() {
_fp = NULL;
_cb = NULL;
_deopt_state = unknown;
_on_heap = false;
DEBUG_ONLY(_frame_index = -1;)
}
inline frame::frame(intptr_t* sp) {
Unimplemented();
}
inline void frame::init(intptr_t* sp, intptr_t* fp, address pc) {
@ -49,6 +55,7 @@ inline void frame::init(intptr_t* sp, intptr_t* fp, address pc) {
assert(pc != NULL, "no pc?");
_cb = CodeCache::find_blob(pc);
adjust_unextended_sp();
DEBUG_ONLY(_frame_index = -1;)
address original_pc = CompiledMethod::get_deopt_original_pc(this);
if (original_pc != NULL) {
@ -57,6 +64,7 @@ inline void frame::init(intptr_t* sp, intptr_t* fp, address pc) {
} else {
_deopt_state = not_deoptimized;
}
_on_heap = false;
}
inline frame::frame(intptr_t* sp, intptr_t* fp, address pc) {
@ -71,6 +79,7 @@ inline frame::frame(intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, address
assert(pc != NULL, "no pc?");
_cb = CodeCache::find_blob(pc);
adjust_unextended_sp();
DEBUG_ONLY(_frame_index = -1;)
address original_pc = CompiledMethod::get_deopt_original_pc(this);
if (original_pc != NULL) {
@ -81,6 +90,7 @@ inline frame::frame(intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, address
} else {
_deopt_state = not_deoptimized;
}
_on_heap = false;
}
@ -93,6 +103,7 @@ inline frame::frame(intptr_t* sp, intptr_t* fp) {
// assert(_pc != NULL, "no pc?"); // see comments in x86
_cb = CodeCache::find_blob(_pc);
adjust_unextended_sp();
DEBUG_ONLY(_frame_index = -1;)
address original_pc = CompiledMethod::get_deopt_original_pc(this);
if (original_pc != NULL) {
@ -101,6 +112,7 @@ inline frame::frame(intptr_t* sp, intptr_t* fp) {
} else {
_deopt_state = not_deoptimized;
}
_on_heap = false;
}
@ -215,15 +227,107 @@ inline JavaCallWrapper** frame::entry_frame_call_wrapper_addr() const {
// Compiled frames
inline oop frame::saved_oop_result(RegisterMap* map) const {
oop* result_adr = (oop*) map->location(R0->as_VMReg());
oop* result_adr = (oop*) map->location(R0->as_VMReg(), nullptr);
guarantee(result_adr != NULL, "bad register save location");
return (*result_adr);
}
inline void frame::set_saved_oop_result(RegisterMap* map, oop obj) {
oop* result_adr = (oop*) map->location(R0->as_VMReg());
oop* result_adr = (oop*) map->location(R0->as_VMReg(), nullptr);
guarantee(result_adr != NULL, "bad register save location");
*result_adr = obj;
}
inline int frame::frame_size() const {
return sender_sp() - sp();
}
inline const ImmutableOopMap* frame::get_oop_map() const {
Unimplemented();
return NULL;
}
inline int frame::compiled_frame_stack_argsize() const {
Unimplemented();
return 0;
}
inline void frame::interpreted_frame_oop_map(InterpreterOopMap* mask) const {
Unimplemented();
}
inline int frame::sender_sp_ret_address_offset() {
Unimplemented();
return 0;
}
inline void frame::set_unextended_sp(intptr_t* value) {
Unimplemented();
}
inline int frame::offset_unextended_sp() const {
Unimplemented();
return 0;
}
inline void frame::set_offset_unextended_sp(int value) {
Unimplemented();
}
//------------------------------------------------------------------------------
// frame::sender
inline frame frame::sender(RegisterMap* map) const {
// Default is we done have to follow them. The sender_for_xxx will
// update it accordingly
map->set_include_argument_oops(false);
if (is_entry_frame()) return sender_for_entry_frame(map);
if (is_interpreted_frame()) return sender_for_interpreter_frame(map);
assert(_cb == CodeCache::find_blob(pc()),"Must be the same");
if (_cb != NULL) return sender_for_compiled_frame(map);
assert(false, "should not be called for a C frame");
return frame();
}
inline frame frame::sender_for_compiled_frame(RegisterMap* map) const {
assert(map != NULL, "map must be set");
// frame owned by optimizing compiler
assert(_cb->frame_size() >= 0, "must have non-zero frame size");
intptr_t* sender_sp = unextended_sp() + _cb->frame_size();
intptr_t* unextended_sp = sender_sp;
address sender_pc = (address) *(sender_sp - sender_sp_offset + return_addr_offset);
// This is the saved value of FP which may or may not really be an FP.
// It is only an FP if the sender is an interpreter frame (or C1?).
intptr_t** saved_fp_addr = (intptr_t**) (sender_sp - sender_sp_offset + link_offset);
if (map->update_map()) {
// Tell GC to use argument oopmaps for some runtime stubs that need it.
// For C1, the runtime stub might not have oop maps, so set this flag
// outside of update_register_map.
map->set_include_argument_oops(_cb->caller_must_gc_arguments(map->thread()));
if (_cb->oop_maps() != NULL) {
OopMapSet::update_register_map(this, map);
}
// Since the prolog does the save and restore of FP there is no oopmap
// for it so we must fill in its location as if there was an oopmap entry
// since if our caller was compiled code there could be live jvm state in it.
update_map_with_saved_link(map, saved_fp_addr);
}
assert(sender_sp != sp(), "must have changed");
return frame(sender_sp, unextended_sp, *saved_fp_addr, sender_pc);
}
template <typename RegisterMapT>
void frame::update_map_with_saved_link(RegisterMapT* map, intptr_t** link_addr) {
Unimplemented();
}
#endif // CPU_ARM_FRAME_ARM_INLINE_HPP

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2022, 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
@ -432,4 +432,35 @@ inline NativeCall* nativeCall_before(address return_address) {
return (NativeCall *) rawNativeCall_before(return_address);
}
class NativePostCallNop: public NativeInstruction {
public:
bool check() const { Unimplemented(); return false; }
int displacement() const { Unimplemented(); return 0; }
void patch(jint diff) { Unimplemented(); }
void make_deopt() { Unimplemented(); }
};
inline NativePostCallNop* nativePostCallNop_at(address address) {
Unimplemented();
return NULL;
}
class NativeDeoptInstruction: public NativeInstruction {
public:
address instruction_address() const { Unimplemented(); return NULL; }
address next_instruction_address() const { Unimplemented(); return NULL; }
void verify() { Unimplemented(); }
static bool is_deopt_at(address instr) {
Unimplemented();
return false;
}
// MT-safe patching
static void insert(address code_pos) {
Unimplemented();
}
};
#endif // CPU_ARM_NATIVEINST_ARM_32_HPP

View File

@ -37,7 +37,7 @@
address pd_location(VMReg reg) const {return NULL;}
address pd_location(VMReg base_reg, int slot_idx) const {
return location(base_reg->next(slot_idx));
return location(base_reg->next(slot_idx), nullptr);
}
// no PD state to clear or copy:

View File

@ -0,0 +1,87 @@
/*
* Copyright (c) 2019, 2022, 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.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#ifndef CPU_ARM_SMALLREGISTERMAP_ARM_INLINE_HPP
#define CPU_ARM_SMALLREGISTERMAP_ARM_INLINE_HPP
#include "runtime/frame.inline.hpp"
#include "runtime/registerMap.hpp"
// Java frames don't have callee saved registers (except for rfp), so we can use a smaller RegisterMap
class SmallRegisterMap {
public:
static constexpr SmallRegisterMap* instance = nullptr;
private:
static void assert_is_rfp(VMReg r) PRODUCT_RETURN
DEBUG_ONLY({ Unimplemented(); })
public:
// as_RegisterMap is used when we didn't want to templatize and abstract over RegisterMap type to support SmallRegisterMap
// Consider enhancing SmallRegisterMap to support those cases
const RegisterMap* as_RegisterMap() const { return nullptr; }
RegisterMap* as_RegisterMap() { return nullptr; }
RegisterMap* copy_to_RegisterMap(RegisterMap* map, intptr_t* sp) const {
Unimplemented();
return map;
}
SmallRegisterMap() {}
SmallRegisterMap(const RegisterMap* map) {
Unimplemented();
}
inline address location(VMReg reg, intptr_t* sp) const {
Unimplemented();
return NULL;
}
inline void set_location(VMReg reg, address loc) { assert_is_rfp(reg); }
JavaThread* thread() const {
#ifndef ASSERT
guarantee (false, "");
#endif
return nullptr;
}
bool update_map() const { return false; }
bool walk_cont() const { return false; }
bool include_argument_oops() const { return false; }
void set_include_argument_oops(bool f) {}
bool in_cont() const { return false; }
stackChunkHandle stack_chunk() const { return stackChunkHandle(); }
#ifdef ASSERT
bool should_skip_missing() const { return false; }
VMReg find_register_spilled_here(void* p, intptr_t* sp) {
Unimplemented();
return NULL;
}
void print() const { print_on(tty); }
void print_on(outputStream* st) const { st->print_cr("Small register map"); }
#endif
};
#endif // CPU_ARM_SMALLREGISTERMAP_ARM_INLINE_HPP

View File

@ -0,0 +1,115 @@
/*
* Copyright (c) 2019, 2022, 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.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#ifndef CPU_ARM_STACKCHUNKFRAMESTREAM_ARM_INLINE_HPP
#define CPU_ARM_STACKCHUNKFRAMESTREAM_ARM_INLINE_HPP
#include "interpreter/oopMapCache.hpp"
#include "runtime/frame.inline.hpp"
#include "runtime/registerMap.hpp"
#ifdef ASSERT
template <ChunkFrames frame_kind>
inline bool StackChunkFrameStream<frame_kind>::is_in_frame(void* p0) const {
Unimplemented();
return true;
}
#endif
template <ChunkFrames frame_kind>
inline frame StackChunkFrameStream<frame_kind>::to_frame() const {
Unimplemented();
return frame();
}
template <ChunkFrames frame_kind>
inline address StackChunkFrameStream<frame_kind>::get_pc() const {
Unimplemented();
return NULL;
}
template <ChunkFrames frame_kind>
inline intptr_t* StackChunkFrameStream<frame_kind>::fp() const {
Unimplemented();
return NULL;
}
template <ChunkFrames frame_kind>
inline intptr_t* StackChunkFrameStream<frame_kind>::derelativize(int offset) const {
Unimplemented();
return NULL;
}
template <ChunkFrames frame_kind>
inline intptr_t* StackChunkFrameStream<frame_kind>::unextended_sp_for_interpreter_frame() const {
Unimplemented();
return NULL;
}
template <ChunkFrames frame_kind>
intptr_t* StackChunkFrameStream<frame_kind>::next_sp_for_interpreter_frame() const {
Unimplemented();
return NULL;
}
template <ChunkFrames frame_kind>
inline void StackChunkFrameStream<frame_kind>::next_for_interpreter_frame() {
Unimplemented();
}
template <ChunkFrames frame_kind>
inline int StackChunkFrameStream<frame_kind>::interpreter_frame_size() const {
Unimplemented();
return 0;
}
template <ChunkFrames frame_kind>
inline int StackChunkFrameStream<frame_kind>::interpreter_frame_stack_argsize() const {
Unimplemented();
return 0;
}
template <ChunkFrames frame_kind>
inline int StackChunkFrameStream<frame_kind>::interpreter_frame_num_oops() const {
Unimplemented();
return 0;
}
template<>
template<>
inline void StackChunkFrameStream<ChunkFrames::Mixed>::update_reg_map_pd(RegisterMap* map) {
Unimplemented();
}
template<>
template<>
inline void StackChunkFrameStream<ChunkFrames::CompiledOnly>::update_reg_map_pd(RegisterMap* map) {
Unimplemented();
}
template <ChunkFrames frame_kind>
template <typename RegisterMapT>
inline void StackChunkFrameStream<frame_kind>::update_reg_map_pd(RegisterMapT* map) {}
#endif // CPU_ARM_STACKCHUNKFRAMESTREAM_ARM_INLINE_HPP

View File

@ -0,0 +1,36 @@
/*
* Copyright (c) 2019, 2022, 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.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#ifndef CPU_ARM_STACKCHUNKOOP_ARM_INLINE_HPP
#define CPU_ARM_STACKCHUNKOOP_ARM_INLINE_HPP
inline void stackChunkOopDesc::relativize_frame_pd(frame& fr) const {
Unimplemented();
}
inline void stackChunkOopDesc::derelativize_frame_pd(frame& fr) const {
Unimplemented();
}
#endif // CPU_ARM_STACKCHUNKOOP_ARM_INLINE_HPP

View File

@ -3039,9 +3039,9 @@ class StubGenerator: public StubCodeGenerator {
}; // end class declaration
#define UCM_TABLE_MAX_ENTRIES 32
void StubGenerator_generate(CodeBuffer* code, bool all) {
void StubGenerator_generate(CodeBuffer* code, int phase) {
if (UnsafeCopyMemory::_table == NULL) {
UnsafeCopyMemory::create_table(UCM_TABLE_MAX_ENTRIES);
}
StubGenerator g(code, all);
StubGenerator g(code, phase);
}

View File

@ -728,6 +728,11 @@ void TemplateInterpreterGenerator::generate_fixed_frame(bool native_call) {
// [ parameter 1 ] <--- Rlocals
//
address TemplateInterpreterGenerator::generate_Continuation_doYield_entry(void) {
Unimplemented();
return NULL;
}
address TemplateInterpreterGenerator::generate_Reference_get_entry(void) {
// Code: _aload_0, _getfield, _areturn
// parameter size = 1

View File

@ -140,6 +140,9 @@ class Argument {
// shows that xlC places all float args after argument 8 on the stack AND
// in a register. This is not documented, but we follow this convention, too.
n_regs_not_on_stack_c = 8,
n_int_register_parameters_j = 8,
n_float_register_parameters_j = 13
};
// creation
Argument(int number) : _number(number) {}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2005, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2019 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@ -1381,3 +1381,7 @@ void LIRGenerator::do_FmaIntrinsic(Intrinsic* x) {
void LIRGenerator::do_vectorizedMismatch(Intrinsic* x) {
fatal("vectorizedMismatch intrinsic is not implemented on this platform");
}
void LIRGenerator::do_continuation_doYield(Intrinsic* x) {
fatal("Continuation.doYield intrinsic is not implemented on this platform");
}

View File

@ -0,0 +1,46 @@
/*
* Copyright (c) 2022, 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.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#ifndef CPU_PPC_CONTINUATIONENTRY_PPC_INLINE_HPP
#define CPU_PPC_CONTINUATIONENTRY_PPC_INLINE_HPP
#include "runtime/continuationEntry.hpp"
// TODO: Implement
inline frame ContinuationEntry::to_frame() const {
Unimplemented();
return frame();
}
inline intptr_t* ContinuationEntry::entry_fp() const {
Unimplemented();
return nullptr;
}
inline void ContinuationEntry::update_register_map(RegisterMap* map) const {
Unimplemented();
}
#endif // CPU_PPC_CONTINUATIONENTRY_PPC_INLINE_HPP

View File

@ -0,0 +1,99 @@
/*
* Copyright (c) 2019, 2022, 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.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#ifndef CPU_PPC_CONTINUATION_PPC_INLINE_HPP
#define CPU_PPC_CONTINUATION_PPC_INLINE_HPP
#include "oops/stackChunkOop.inline.hpp"
#include "runtime/frame.hpp"
#include "runtime/frame.inline.hpp"
inline void FreezeBase::set_top_frame_metadata_pd(const frame& hf) {
Unimplemented();
}
template<typename FKind>
inline frame FreezeBase::sender(const frame& f) {
Unimplemented();
return frame();
}
template<typename FKind> frame FreezeBase::new_heap_frame(frame& f, frame& caller) {
Unimplemented();
return frame();
}
void FreezeBase::adjust_interpreted_frame_unextended_sp(frame& f) {
Unimplemented();
}
inline void FreezeBase::relativize_interpreted_frame_metadata(const frame& f, const frame& hf) {
Unimplemented();
}
inline void FreezeBase::patch_pd(frame& hf, const frame& caller) {
Unimplemented();
}
inline void FreezeBase::patch_stack_pd(intptr_t* frame_sp, intptr_t* heap_sp) {
Unimplemented();
}
inline frame ThawBase::new_entry_frame() {
Unimplemented();
return frame();
}
template<typename FKind> frame ThawBase::new_stack_frame(const frame& hf, frame& caller, bool bottom) {
Unimplemented();
return frame();
}
inline void ThawBase::set_interpreter_frame_bottom(const frame& f, intptr_t* bottom) {
Unimplemented();
}
inline void ThawBase::derelativize_interpreted_frame_metadata(const frame& hf, const frame& f) {
Unimplemented();
}
inline intptr_t* ThawBase::align(const frame& hf, intptr_t* frame_sp, frame& caller, bool bottom) {
Unimplemented();
return NULL;
}
inline void ThawBase::patch_pd(frame& f, const frame& caller) {
Unimplemented();
}
void ThawBase::patch_chunk_pd(intptr_t* sp) {
Unimplemented();
}
inline void ThawBase::prefetch_chunk_pd(void* start, int size) {
Unimplemented();
}
#endif // CPU_PPC_CONTINUATION_PPC_INLINE_HPP

View File

@ -0,0 +1,124 @@
/*
* Copyright (c) 2022, 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.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#ifndef CPU_PPC_CONTINUATIONHELPER_PPC_INLINE_HPP
#define CPU_PPC_CONTINUATIONHELPER_PPC_INLINE_HPP
#include "runtime/continuationHelper.hpp"
template<typename FKind>
static inline intptr_t** link_address(const frame& f) {
Unimplemented();
return NULL;
}
inline int ContinuationHelper::frame_align_words(int size) {
Unimplemented();
return 0;
}
inline intptr_t* ContinuationHelper::frame_align_pointer(intptr_t* sp) {
Unimplemented();
return NULL;
}
template<typename FKind>
inline void ContinuationHelper::update_register_map(const frame& f, RegisterMap* map) {
Unimplemented();
}
inline void ContinuationHelper::update_register_map_with_callee(const frame& f, RegisterMap* map) {
Unimplemented();
}
inline void ContinuationHelper::push_pd(const frame& f) {
Unimplemented();
}
inline void ContinuationHelper::set_anchor_to_entry_pd(JavaFrameAnchor* anchor, ContinuationEntry* cont) {
Unimplemented();
}
#ifdef ASSERT
inline void ContinuationHelper::set_anchor_pd(JavaFrameAnchor* anchor, intptr_t* sp) {
Unimplemented();
}
inline bool ContinuationHelper::Frame::assert_frame_laid_out(frame f) {
Unimplemented();
return false;
}
#endif
inline intptr_t** ContinuationHelper::Frame::callee_link_address(const frame& f) {
Unimplemented();
return NULL;
}
template<typename FKind>
static inline intptr_t* real_fp(const frame& f) {
Unimplemented();
return NULL;
}
inline address* ContinuationHelper::InterpretedFrame::return_pc_address(const frame& f) {
Unimplemented();
return NULL;
}
inline void ContinuationHelper::InterpretedFrame::patch_sender_sp(frame& f, intptr_t* sp) {
Unimplemented();
}
inline address* ContinuationHelper::Frame::return_pc_address(const frame& f) {
Unimplemented();
return NULL;
}
inline address ContinuationHelper::Frame::real_pc(const frame& f) {
Unimplemented();
return NULL;
}
inline void ContinuationHelper::Frame::patch_pc(const frame& f, address pc) {
Unimplemented();
}
inline intptr_t* ContinuationHelper::InterpretedFrame::frame_top(const frame& f, InterpreterOopMap* mask) { // inclusive; this will be copied with the frame
Unimplemented();
return NULL;
}
inline intptr_t* ContinuationHelper::InterpretedFrame::frame_bottom(const frame& f) { // exclusive; this will not be copied with the frame
Unimplemented();
return NULL;
}
inline intptr_t* ContinuationHelper::InterpretedFrame::frame_top(const frame& f, int callee_argsize, bool callee_interpreted) {
Unimplemented();
return NULL;
}
#endif // CPU_PPC_CONTINUATIONFRAMEHELPERS_PPC_INLINE_HPP

View File

@ -219,27 +219,6 @@ frame frame::sender_for_interpreter_frame(RegisterMap *map) const {
return frame(sender_sp(), sender_pc(), (intptr_t*)get_ijava_state()->sender_sp);
}
frame frame::sender_for_compiled_frame(RegisterMap *map) const {
assert(map != NULL, "map must be set");
// Frame owned by compiler.
address pc = *compiled_sender_pc_addr(_cb);
frame caller(compiled_sender_sp(_cb), pc);
// Now adjust the map.
// Get the rest.
if (map->update_map()) {
// Tell GC to use argument oopmaps for some runtime stubs that need it.
map->set_include_argument_oops(_cb->caller_must_gc_arguments(map->thread()));
if (_cb->oop_maps() != NULL) {
OopMapSet::update_register_map(this, map);
}
}
return caller;
}
intptr_t* frame::compiled_sender_sp(CodeBlob* cb) const {
return sender_sp();
}
@ -248,33 +227,6 @@ address* frame::compiled_sender_pc_addr(CodeBlob* cb) const {
return sender_pc_addr();
}
frame frame::sender_raw(RegisterMap* map) const {
// Default is we do have to follow them. The sender_for_xxx will
// update it accordingly.
map->set_include_argument_oops(false);
if (is_entry_frame()) return sender_for_entry_frame(map);
if (is_interpreted_frame()) return sender_for_interpreter_frame(map);
assert(_cb == CodeCache::find_blob(pc()),"Must be the same");
if (_cb != NULL) {
return sender_for_compiled_frame(map);
}
// Must be native-compiled frame, i.e. the marshaling code for native
// methods that exists in the core system.
return frame(sender_sp(), sender_pc());
}
frame frame::sender(RegisterMap* map) const {
frame result = sender_raw(map);
if (map->process_frames()) {
StackWatermarkSet::on_iteration(map->thread(), result);
}
return result;
}
void frame::patch_pc(Thread* thread, address pc) {
assert(_cb == CodeCache::find_blob(pc), "unexpected pc");
if (TracePcPatching) {
@ -431,8 +383,19 @@ intptr_t *frame::initial_deoptimization_info() {
#ifndef PRODUCT
// This is a generic constructor which is only used by pns() in debug.cpp.
frame::frame(void* sp, void* fp, void* pc) : _sp((intptr_t*)sp), _unextended_sp((intptr_t*)sp) {
frame::frame(void* sp, void* fp, void* pc) : _sp((intptr_t*)sp),
_on_heap(false),
_unextended_sp((intptr_t*)sp) {
find_codeblob_and_set_pc_and_deopt_state((address)pc); // also sets _fp and adjusts _unextended_sp
}
#endif
// Pointer beyond the "oldest/deepest" BasicObjectLock on stack.
BasicObjectLock* frame::interpreter_frame_monitor_end() const {
return (BasicObjectLock*) get_ijava_state()->monitors;
}
intptr_t* frame::interpreter_frame_tos_at(jint offset) const {
return &interpreter_frame_tos_address()[offset];
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2021 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@ -379,8 +379,9 @@
public:
const ImmutableOopMap* get_oop_map() const;
// Constructors
inline frame(intptr_t* sp);
inline frame(intptr_t* sp, address pc);
inline frame(intptr_t* sp, address pc, intptr_t* unextended_sp);
@ -400,6 +401,11 @@
inline void interpreter_frame_set_top_frame_sp(intptr_t* top_frame_sp);
inline void interpreter_frame_set_sender_sp(intptr_t* sender_sp);
inline intptr_t* interpreter_frame_last_sp() const;
template <typename RegisterMapT>
static void update_map_with_saved_link(RegisterMapT* map, intptr_t** link_addr);
// Size of a monitor in bytes.
static int interpreter_frame_monitor_size_in_bytes();
@ -413,12 +419,16 @@
enum {
// normal return address is 1 bundle past PC
pc_return_offset = 0
pc_return_offset = 0,
metadata_words = 0,
frame_alignment = 16,
// size, in words, of maximum shift in frame position due to alignment
align_wiggle = 1
};
static jint interpreter_frame_expression_stack_direction() { return -1; }
// returns the sending frame, without applying any barriers
frame sender_raw(RegisterMap* map) const;
inline frame sender_raw(RegisterMap* map) const;
#endif // CPU_PPC_FRAME_PPC_HPP

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2015 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@ -55,17 +55,33 @@ inline void frame::find_codeblob_and_set_pc_and_deopt_state(address pc) {
// Constructors
// Initialize all fields, _unextended_sp will be adjusted in find_codeblob_and_set_pc_and_deopt_state.
inline frame::frame() : _sp(NULL), _pc(NULL), _cb(NULL), _deopt_state(unknown), _unextended_sp(NULL), _fp(NULL) {}
inline frame::frame() : _sp(NULL), _pc(NULL), _cb(NULL), _deopt_state(unknown), _on_heap(false),
#ifdef ASSERT
_frame_index(-1),
#endif
_unextended_sp(NULL), _fp(NULL) {}
inline frame::frame(intptr_t* sp) : _sp(sp), _unextended_sp(sp) {
inline frame::frame(intptr_t* sp) : _sp(sp), _on_heap(false),
#ifdef ASSERT
_frame_index(-1),
#endif
_unextended_sp(sp) {
find_codeblob_and_set_pc_and_deopt_state((address)own_abi()->lr); // also sets _fp and adjusts _unextended_sp
}
inline frame::frame(intptr_t* sp, address pc) : _sp(sp), _unextended_sp(sp) {
inline frame::frame(intptr_t* sp, address pc) : _sp(sp), _on_heap(false),
#ifdef ASSERT
_frame_index(-1),
#endif
_unextended_sp(sp) {
find_codeblob_and_set_pc_and_deopt_state(pc); // also sets _fp and adjusts _unextended_sp
}
inline frame::frame(intptr_t* sp, address pc, intptr_t* unextended_sp) : _sp(sp), _unextended_sp(unextended_sp) {
inline frame::frame(intptr_t* sp, address pc, intptr_t* unextended_sp) : _sp(sp), _on_heap(false),
#ifdef ASSERT
_frame_index(-1),
#endif
_unextended_sp(unextended_sp) {
find_codeblob_and_set_pc_and_deopt_state(pc); // also sets _fp and adjusts _unextended_sp
}
@ -87,7 +103,7 @@ inline bool frame::is_older(intptr_t* id) const {
return this->id() > id;
}
inline int frame::frame_size(RegisterMap* map) const {
inline int frame::frame_size() const {
// Stack grows towards smaller addresses on PPC64: sender is at a higher address.
return sender_sp() - sp();
}
@ -143,11 +159,6 @@ inline intptr_t* frame::interpreter_frame_mdp_addr() const {
return (intptr_t*) &(get_ijava_state()->mdx);
}
// Pointer beyond the "oldest/deepest" BasicObjectLock on stack.
inline BasicObjectLock* frame::interpreter_frame_monitor_end() const {
return (BasicObjectLock*) get_ijava_state()->monitors;
}
inline BasicObjectLock* frame::interpreter_frame_monitor_begin() const {
return (BasicObjectLock*) get_ijava_state();
}
@ -189,10 +200,6 @@ inline intptr_t* frame::interpreter_frame_tos_address() const {
return ((intptr_t*) get_ijava_state()->esp) + Interpreter::stackElementWords;
}
inline intptr_t* frame::interpreter_frame_tos_at(jint offset) const {
return &interpreter_frame_tos_address()[offset];
}
inline int frame::interpreter_frame_monitor_size() {
// Number of stack slots for a monitor.
return align_up(BasicObjectLock::size(), // number of stack slots
@ -218,11 +225,103 @@ inline JavaCallWrapper** frame::entry_frame_call_wrapper_addr() const {
}
inline oop frame::saved_oop_result(RegisterMap* map) const {
return *((oop*)map->location(R3->as_VMReg()));
return *((oop*)map->location(R3->as_VMReg(), nullptr));
}
inline void frame::set_saved_oop_result(RegisterMap* map, oop obj) {
*((oop*)map->location(R3->as_VMReg())) = obj;
*((oop*)map->location(R3->as_VMReg(), nullptr)) = obj;
}
inline const ImmutableOopMap* frame::get_oop_map() const {
Unimplemented();
return NULL;
}
inline int frame::compiled_frame_stack_argsize() const {
Unimplemented();
return 0;
}
inline void frame::interpreted_frame_oop_map(InterpreterOopMap* mask) const {
Unimplemented();
}
inline intptr_t* frame::interpreter_frame_last_sp() const {
Unimplemented();
return NULL;
}
inline int frame::sender_sp_ret_address_offset() {
Unimplemented();
return 0;
}
inline void frame::set_unextended_sp(intptr_t* value) {
Unimplemented();
}
inline int frame::offset_unextended_sp() const {
Unimplemented();
return 0;
}
inline void frame::set_offset_unextended_sp(int value) {
Unimplemented();
}
//------------------------------------------------------------------------------
// frame::sender
frame frame::sender(RegisterMap* map) const {
frame result = sender_raw(map);
if (map->process_frames()) {
StackWatermarkSet::on_iteration(map->thread(), result);
}
return result;
}
inline frame frame::sender_raw(RegisterMap* map) const {
// Default is we do have to follow them. The sender_for_xxx will
// update it accordingly.
map->set_include_argument_oops(false);
if (is_entry_frame()) return sender_for_entry_frame(map);
if (is_interpreted_frame()) return sender_for_interpreter_frame(map);
assert(_cb == CodeCache::find_blob(pc()),"Must be the same");
if (_cb != NULL) return sender_for_compiled_frame(map);
// Must be native-compiled frame, i.e. the marshaling code for native
// methods that exists in the core system.
return frame(sender_sp(), sender_pc());
}
inline frame frame::sender_for_compiled_frame(RegisterMap *map) const {
assert(map != NULL, "map must be set");
// Frame owned by compiler.
address pc = *compiled_sender_pc_addr(_cb);
frame caller(compiled_sender_sp(_cb), pc);
// Now adjust the map.
// Get the rest.
if (map->update_map()) {
// Tell GC to use argument oopmaps for some runtime stubs that need it.
map->set_include_argument_oops(_cb->caller_must_gc_arguments(map->thread()));
if (_cb->oop_maps() != NULL) {
OopMapSet::update_register_map(this, map);
}
}
return caller;
}
template <typename RegisterMapT>
void frame::update_map_with_saved_link(RegisterMapT* map, intptr_t** link_addr) {
Unimplemented();
}
#endif // CPU_PPC_FRAME_PPC_INLINE_HPP

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2022, 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
@ -121,6 +121,10 @@ void BarrierSetNMethod::disarm(nmethod* nm) {
barrier->release_set_guard_value(disarmed_value());
}
void BarrierSetNMethod::arm(nmethod* nm, int arm_value) {
Unimplemented();
}
bool BarrierSetNMethod::is_armed(nmethod* nm) {
if (!supports_entry_barrier(nm)) {
return false;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2002, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2021 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@ -503,4 +503,35 @@ class NativeMovRegMem: public NativeInstruction {
}
};
class NativePostCallNop: public NativeInstruction {
public:
bool check() const { Unimplemented(); return false; }
int displacement() const { Unimplemented(); return 0; }
void patch(jint diff) { Unimplemented(); }
void make_deopt() { Unimplemented(); }
};
inline NativePostCallNop* nativePostCallNop_at(address address) {
Unimplemented();
return NULL;
}
class NativeDeoptInstruction: public NativeInstruction {
public:
address instruction_address() const { Unimplemented(); return NULL; }
address next_instruction_address() const { Unimplemented(); return NULL; }
void verify() { Unimplemented(); }
static bool is_deopt_at(address instr) {
Unimplemented();
return false;
}
// MT-safe patching
static void insert(address code_pos) {
Unimplemented();
}
};
#endif // CPU_PPC_NATIVEINST_PPC_HPP

View File

@ -36,7 +36,7 @@
address pd_location(VMReg reg) const { return NULL; }
address pd_location(VMReg base_reg, int slot_idx) const {
return location(base_reg->next(slot_idx));
return location(base_reg->next(slot_idx), nullptr);
}
// no PD state to clear or copy:

View File

@ -0,0 +1,87 @@
/*
* Copyright (c) 2019, 2022, 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.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#ifndef CPU_PPC_SMALLREGISTERMAP_PPC_INLINE_HPP
#define CPU_PPC_SMALLREGISTERMAP_PPC_INLINE_HPP
#include "runtime/frame.inline.hpp"
#include "runtime/registerMap.hpp"
// Java frames don't have callee saved registers (except for rfp), so we can use a smaller RegisterMap
class SmallRegisterMap {
public:
static constexpr SmallRegisterMap* instance = nullptr;
private:
static void assert_is_rfp(VMReg r) PRODUCT_RETURN
DEBUG_ONLY({ Unimplemented(); })
public:
// as_RegisterMap is used when we didn't want to templatize and abstract over RegisterMap type to support SmallRegisterMap
// Consider enhancing SmallRegisterMap to support those cases
const RegisterMap* as_RegisterMap() const { return nullptr; }
RegisterMap* as_RegisterMap() { return nullptr; }
RegisterMap* copy_to_RegisterMap(RegisterMap* map, intptr_t* sp) const {
Unimplemented();
return map;
}
SmallRegisterMap() {}
SmallRegisterMap(const RegisterMap* map) {
Unimplemented();
}
inline address location(VMReg reg, intptr_t* sp) const {
Unimplemented();
return NULL;
}
inline void set_location(VMReg reg, address loc) { assert_is_rfp(reg); }
JavaThread* thread() const {
#ifndef ASSERT
guarantee (false, "");
#endif
return nullptr;
}
bool update_map() const { return false; }
bool walk_cont() const { return false; }
bool include_argument_oops() const { return false; }
void set_include_argument_oops(bool f) {}
bool in_cont() const { return false; }
stackChunkHandle stack_chunk() const { return stackChunkHandle(); }
#ifdef ASSERT
bool should_skip_missing() const { return false; }
VMReg find_register_spilled_here(void* p, intptr_t* sp) {
Unimplemented();
return NULL;
}
void print() const { print_on(tty); }
void print_on(outputStream* st) const { st->print_cr("Small register map"); }
#endif
};
#endif // CPU_PPC_SMALLREGISTERMAP_PPC_INLINE_HPP

View File

@ -0,0 +1,115 @@
/*
* Copyright (c) 2019, 2022, 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.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#ifndef CPU_PPC_STACKCHUNKFRAMESTREAM_PPC_INLINE_HPP
#define CPU_PPC_STACKCHUNKFRAMESTREAM_PPC_INLINE_HPP
#include "interpreter/oopMapCache.hpp"
#include "runtime/frame.inline.hpp"
#include "runtime/registerMap.hpp"
#ifdef ASSERT
template <ChunkFrames frame_kind>
inline bool StackChunkFrameStream<frame_kind>::is_in_frame(void* p0) const {
Unimplemented();
return true;
}
#endif
template <ChunkFrames frame_kind>
inline frame StackChunkFrameStream<frame_kind>::to_frame() const {
Unimplemented();
return frame();
}
template <ChunkFrames frame_kind>
inline address StackChunkFrameStream<frame_kind>::get_pc() const {
Unimplemented();
return NULL;
}
template <ChunkFrames frame_kind>
inline intptr_t* StackChunkFrameStream<frame_kind>::fp() const {
Unimplemented();
return NULL;
}
template <ChunkFrames frame_kind>
inline intptr_t* StackChunkFrameStream<frame_kind>::derelativize(int offset) const {
Unimplemented();
return NULL;
}
template <ChunkFrames frame_kind>
inline intptr_t* StackChunkFrameStream<frame_kind>::unextended_sp_for_interpreter_frame() const {
Unimplemented();
return NULL;
}
template <ChunkFrames frame_kind>
intptr_t* StackChunkFrameStream<frame_kind>::next_sp_for_interpreter_frame() const {
Unimplemented();
return NULL;
}
template <ChunkFrames frame_kind>
inline void StackChunkFrameStream<frame_kind>::next_for_interpreter_frame() {
Unimplemented();
}
template <ChunkFrames frame_kind>
inline int StackChunkFrameStream<frame_kind>::interpreter_frame_size() const {
Unimplemented();
return 0;
}
template <ChunkFrames frame_kind>
inline int StackChunkFrameStream<frame_kind>::interpreter_frame_stack_argsize() const {
Unimplemented();
return 0;
}
template <ChunkFrames frame_kind>
inline int StackChunkFrameStream<frame_kind>::interpreter_frame_num_oops() const {
Unimplemented();
return 0;
}
template<>
template<>
inline void StackChunkFrameStream<ChunkFrames::Mixed>::update_reg_map_pd(RegisterMap* map) {
Unimplemented();
}
template<>
template<>
inline void StackChunkFrameStream<ChunkFrames::CompiledOnly>::update_reg_map_pd(RegisterMap* map) {
Unimplemented();
}
template <ChunkFrames frame_kind>
template <typename RegisterMapT>
inline void StackChunkFrameStream<frame_kind>::update_reg_map_pd(RegisterMapT* map) {}
#endif // CPU_PPC_STACKCHUNKFRAMESTREAM_PPC_INLINE_HPP

View File

@ -0,0 +1,36 @@
/*
* Copyright (c) 2019, 2022, 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.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#ifndef CPU_PPC_STACKCHUNKOOP_PPC_INLINE_HPP
#define CPU_PPC_STACKCHUNKOOP_PPC_INLINE_HPP
inline void stackChunkOopDesc::relativize_frame_pd(frame& fr) const {
Unimplemented();
}
inline void stackChunkOopDesc::derelativize_frame_pd(frame& fr) const {
Unimplemented();
}
#endif // CPU_PPC_STACKCHUNKOOP_PPC_INLINE_HPP

View File

@ -4618,9 +4618,9 @@ class StubGenerator: public StubCodeGenerator {
};
#define UCM_TABLE_MAX_ENTRIES 8
void StubGenerator_generate(CodeBuffer* code, bool all) {
void StubGenerator_generate(CodeBuffer* code, int phase) {
if (UnsafeCopyMemory::_table == NULL) {
UnsafeCopyMemory::create_table(UCM_TABLE_MAX_ENTRIES);
}
StubGenerator g(code, all);
StubGenerator g(code, phase);
}

View File

@ -476,6 +476,11 @@ address TemplateInterpreterGenerator::generate_abstract_entry(void) {
return entry;
}
address TemplateInterpreterGenerator::generate_Continuation_doYield_entry(void) {
Unimplemented();
return NULL;
}
// Interpreter intrinsic for WeakReference.get().
// 1. Don't push a full blown frame and go on dispatching, but fetch the value
// into R8 and return quickly

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2005, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, Red Hat Inc. All rights reserved.
* Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@ -301,6 +301,10 @@ void LIRGenerator::do_MonitorExit(MonitorExit* x) {
monitor_exit(obj_temp, lock, syncTempOpr(), LIR_OprFact::illegalOpr, x->monitor_no());
}
void LIRGenerator::do_continuation_doYield(Intrinsic* x) {
fatal("Continuation.doYield intrinsic is not implemented on this platform");
}
// neg
void LIRGenerator::do_NegateOp(NegateOp* x) {
LIRItem from(x->x(), this);

View File

@ -0,0 +1,46 @@
/*
* Copyright (c) 2022, 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.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#ifndef CPU_RISCV_CONTINUATIONENTRY_RISCV_INLINE_HPP
#define CPU_RISCV_CONTINUATIONENTRY_RISCV_INLINE_HPP
#include "runtime/continuationEntry.hpp"
// TODO: Implement
inline frame ContinuationEntry::to_frame() const {
Unimplemented();
return frame();
}
inline intptr_t* ContinuationEntry::entry_fp() const {
Unimplemented();
return nullptr;
}
inline void ContinuationEntry::update_register_map(RegisterMap* map) const {
Unimplemented();
}
#endif // CPU_RISCV_CONTINUATIONENTRY_RISCV_INLINE_HPP

View File

@ -0,0 +1,99 @@
/*
* Copyright (c) 2019, 2022, 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.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#ifndef CPU_RISCV_CONTINUATIONFREEZETHAW_RISCV_INLINE_HPP
#define CPU_RISCV_CONTINUATIONFREEZETHAW_RISCV_INLINE_HPP
#include "oops/stackChunkOop.inline.hpp"
#include "runtime/frame.hpp"
#include "runtime/frame.inline.hpp"
inline void FreezeBase::set_top_frame_metadata_pd(const frame& hf) {
Unimplemented();
}
template<typename FKind>
inline frame FreezeBase::sender(const frame& f) {
Unimplemented();
return frame();
}
template<typename FKind> frame FreezeBase::new_heap_frame(frame& f, frame& caller) {
Unimplemented();
return frame();
}
void FreezeBase::adjust_interpreted_frame_unextended_sp(frame& f) {
Unimplemented();
}
inline void FreezeBase::relativize_interpreted_frame_metadata(const frame& f, const frame& hf) {
Unimplemented();
}
inline void FreezeBase::patch_pd(frame& hf, const frame& caller) {
Unimplemented();
}
inline void FreezeBase::patch_stack_pd(intptr_t* frame_sp, intptr_t* heap_sp) {
Unimplemented();
}
inline frame ThawBase::new_entry_frame() {
Unimplemented();
return frame();
}
template<typename FKind> frame ThawBase::new_stack_frame(const frame& hf, frame& caller, bool bottom) {
Unimplemented();
return frame();
}
inline void ThawBase::set_interpreter_frame_bottom(const frame& f, intptr_t* bottom) {
Unimplemented();
}
inline void ThawBase::derelativize_interpreted_frame_metadata(const frame& hf, const frame& f) {
Unimplemented();
}
inline intptr_t* ThawBase::align(const frame& hf, intptr_t* frame_sp, frame& caller, bool bottom) {
Unimplemented();
return NULL;
}
inline void ThawBase::patch_pd(frame& f, const frame& caller) {
Unimplemented();
}
void ThawBase::patch_chunk_pd(intptr_t* sp) {
Unimplemented();
}
inline void ThawBase::prefetch_chunk_pd(void* start, int size) {
Unimplemented();
}
#endif // CPU_RISCV_CONTINUATIONFREEZETHAW_RISCV_INLINE_HPP

View File

@ -0,0 +1,124 @@
/*
* Copyright (c) 2022, 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.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#ifndef CPU_RISCV_CONTINUATIONHELPER_RISCV_INLINE_HPP
#define CPU_RISCV_CONTINUATIONHELPER_RISCV_INLINE_HPP
#include "runtime/continuationHelper.hpp"
template<typename FKind>
static inline intptr_t** link_address(const frame& f) {
Unimplemented();
return NULL;
}
inline int ContinuationHelper::frame_align_words(int size) {
Unimplemented();
return 0;
}
inline intptr_t* ContinuationHelper::frame_align_pointer(intptr_t* sp) {
Unimplemented();
return NULL;
}
template<typename FKind>
inline void ContinuationHelper::update_register_map(const frame& f, RegisterMap* map) {
Unimplemented();
}
inline void ContinuationHelper::update_register_map_with_callee(const frame& f, RegisterMap* map) {
Unimplemented();
}
inline void ContinuationHelper::push_pd(const frame& f) {
Unimplemented();
}
inline void ContinuationHelper::set_anchor_to_entry_pd(JavaFrameAnchor* anchor, ContinuationEntry* cont) {
Unimplemented();
}
#ifdef ASSERT
inline void ContinuationHelper::set_anchor_pd(JavaFrameAnchor* anchor, intptr_t* sp) {
Unimplemented();
}
inline bool ContinuationHelper::Frame::assert_frame_laid_out(frame f) {
Unimplemented();
return false;
}
#endif
inline intptr_t** ContinuationHelper::Frame::callee_link_address(const frame& f) {
Unimplemented();
return NULL;
}
template<typename FKind>
static inline intptr_t* real_fp(const frame& f) {
Unimplemented();
return NULL;
}
inline address* ContinuationHelper::InterpretedFrame::return_pc_address(const frame& f) {
Unimplemented();
return NULL;
}
inline void ContinuationHelper::InterpretedFrame::patch_sender_sp(frame& f, intptr_t* sp) {
Unimplemented();
}
inline address* ContinuationHelper::Frame::return_pc_address(const frame& f) {
Unimplemented();
return NULL;
}
inline address ContinuationHelper::Frame::real_pc(const frame& f) {
Unimplemented();
return NULL;
}
inline void ContinuationHelper::Frame::patch_pc(const frame& f, address pc) {
Unimplemented();
}
inline intptr_t* ContinuationHelper::InterpretedFrame::frame_top(const frame& f, InterpreterOopMap* mask) { // inclusive; this will be copied with the frame
Unimplemented();
return NULL;
}
inline intptr_t* ContinuationHelper::InterpretedFrame::frame_bottom(const frame& f) { // exclusive; this will not be copied with the frame
Unimplemented();
return NULL;
}
inline intptr_t* ContinuationHelper::InterpretedFrame::frame_top(const frame& f, int callee_argsize, bool callee_interpreted) {
Unimplemented();
return NULL;
}
#endif // CPU_RISCV_CONTINUATIONFRAMEHELPERS_RISCV_INLINE_HPP

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved.
* Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@ -282,11 +282,6 @@ bool frame::is_interpreted_frame() const {
return Interpreter::contains(pc());
}
int frame::frame_size(RegisterMap* map) const {
frame sender = this->sender(map);
return sender.sp() - sp();
}
intptr_t* frame::entry_frame_argument_at(int offset) const {
// convert offset to index to deal with tsi
int index = (Interpreter::expr_offset_in_bytes(offset)/wordSize);
@ -394,32 +389,12 @@ void frame::adjust_unextended_sp() {
// If the sender PC is a deoptimization point, get the original PC.
if (sender_cm->is_deopt_entry(_pc) ||
sender_cm->is_deopt_mh_entry(_pc)) {
DEBUG_ONLY(verify_deopt_original_pc(sender_cm, _unextended_sp));
verify_deopt_original_pc(sender_cm, _unextended_sp);
}
}
}
}
//------------------------------------------------------------------------------
// frame::update_map_with_saved_link
void frame::update_map_with_saved_link(RegisterMap* map, intptr_t** link_addr) {
// The interpreter and compiler(s) always save fp in a known
// location on entry. We must record where that location is
// so that if fp was live on callout from c2 we can find
// the saved copy no matter what it called.
// Since the interpreter always saves fp if we record where it is then
// we don't have to always save fp on entry and exit to c2 compiled
// code, on entry will be enough.
assert(map != NULL, "map must be set");
map->set_location(::fp->as_VMReg(), (address) link_addr);
// this is weird "H" ought to be at a higher address however the
// oopMaps seems to have the "H" regs at the same address and the
// vanilla register.
map->set_location(::fp->as_VMReg()->next(), (address) link_addr);
}
//------------------------------------------------------------------------------
// frame::sender_for_interpreter_frame
frame frame::sender_for_interpreter_frame(RegisterMap* map) const {
@ -440,80 +415,6 @@ frame frame::sender_for_interpreter_frame(RegisterMap* map) const {
return frame(sender_sp, unextended_sp, link(), sender_pc());
}
//------------------------------------------------------------------------------
// frame::sender_for_compiled_frame
frame frame::sender_for_compiled_frame(RegisterMap* map) const {
// we cannot rely upon the last fp having been saved to the thread
// in C2 code but it will have been pushed onto the stack. so we
// have to find it relative to the unextended sp
assert(_cb->frame_size() >= 0, "must have non-zero frame size");
intptr_t* l_sender_sp = unextended_sp() + _cb->frame_size();
intptr_t* unextended_sp = l_sender_sp;
// the return_address is always the word on the stack
address sender_pc = (address) *(l_sender_sp + frame::return_addr_offset);
intptr_t** saved_fp_addr = (intptr_t**) (l_sender_sp + frame::link_offset);
assert(map != NULL, "map must be set");
if (map->update_map()) {
// Tell GC to use argument oopmaps for some runtime stubs that need it.
// For C1, the runtime stub might not have oop maps, so set this flag
// outside of update_register_map.
map->set_include_argument_oops(_cb->caller_must_gc_arguments(map->thread()));
if (_cb->oop_maps() != NULL) {
OopMapSet::update_register_map(this, map);
}
// Since the prolog does the save and restore of FP there is no
// oopmap for it so we must fill in its location as if there was
// an oopmap entry since if our caller was compiled code there
// could be live jvm state in it.
update_map_with_saved_link(map, saved_fp_addr);
}
return frame(l_sender_sp, unextended_sp, *saved_fp_addr, sender_pc);
}
//------------------------------------------------------------------------------
// frame::sender_raw
frame frame::sender_raw(RegisterMap* map) const {
// Default is we done have to follow them. The sender_for_xxx will
// update it accordingly
assert(map != NULL, "map must be set");
map->set_include_argument_oops(false);
if (is_entry_frame()) {
return sender_for_entry_frame(map);
}
if (is_interpreted_frame()) {
return sender_for_interpreter_frame(map);
}
assert(_cb == CodeCache::find_blob(pc()),"Must be the same");
// This test looks odd: why is it not is_compiled_frame() ? That's
// because stubs also have OOP maps.
if (_cb != NULL) {
return sender_for_compiled_frame(map);
}
// Must be native-compiled frame, i.e. the marshaling code for native
// methods that exists in the core system.
return frame(sender_sp(), link(), sender_pc());
}
frame frame::sender(RegisterMap* map) const {
frame result = sender_raw(map);
if (map->process_frames()) {
StackWatermarkSet::on_iteration(map->thread(), result);
}
return result;
}
bool frame::is_interpreted_frame_valid(JavaThread* thread) const {
assert(is_interpreted_frame(), "Not an interpreted frame");
// These are reasonable sanity checks
@ -651,24 +552,11 @@ intptr_t *frame::initial_deoptimization_info() {
return NULL;
}
intptr_t* frame::real_fp() const {
if (_cb != NULL) {
// use the frame size if valid
int size = _cb->frame_size();
if (size > 0) {
return unextended_sp() + size;
}
}
// else rely on fp()
assert(!is_compiled_frame(), "unknown compiled frame size");
return fp();
}
#undef DESCRIBE_FP_OFFSET
#ifndef PRODUCT
// This is a generic constructor which is only used by pns() in debug.cpp.
frame::frame(void* ptr_sp, void* ptr_fp, void* pc) {
frame::frame(void* ptr_sp, void* ptr_fp, void* pc) : _on_heap(false) {
init((intptr_t*)ptr_sp, (intptr_t*)ptr_fp, (address)pc);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@ -137,7 +137,14 @@
entry_frame_call_wrapper_offset = -10,
// we don't need a save area
arg_reg_save_area_bytes = 0
arg_reg_save_area_bytes = 0,
// size, in words, of frame metadata (e.g. pc and link)
metadata_words = sender_sp_offset,
// in bytes
frame_alignment = 16,
// size, in words, of maximum shift in frame position due to alignment
align_wiggle = 1
};
intptr_t ptr_at(int offset) const {
@ -170,6 +177,8 @@
static void verify_deopt_original_pc( CompiledMethod* nm, intptr_t* unextended_sp);
#endif
const ImmutableOopMap* get_oop_map() const;
public:
// Constructors
@ -183,15 +192,15 @@
// accessors for the instance variables
// Note: not necessarily the real 'frame pointer' (see real_fp)
intptr_t* fp() const { return _fp; }
intptr_t* fp() const { return _fp; }
inline address* sender_pc_addr() const;
// expression stack tos if we are nested in a java call
intptr_t* interpreter_frame_last_sp() const;
// helper to update a map with callee-saved RBP
static void update_map_with_saved_link(RegisterMap* map, intptr_t** link_addr);
template <typename RegisterMapT>
static void update_map_with_saved_link(RegisterMapT* map, intptr_t** link_addr);
// deoptimization support
void interpreter_frame_set_last_sp(intptr_t* last_sp);
@ -199,6 +208,6 @@
static jint interpreter_frame_expression_stack_direction() { return -1; }
// returns the sending frame, without applying any barriers
frame sender_raw(RegisterMap* map) const;
inline frame sender_raw(RegisterMap* map) const;
#endif // CPU_RISCV_FRAME_RISCV_HPP

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, Red Hat Inc. All rights reserved.
* Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@ -41,6 +41,8 @@ inline frame::frame() {
_fp = NULL;
_cb = NULL;
_deopt_state = unknown;
_on_heap = false;
DEBUG_ONLY(_frame_index = -1;)
}
static int spin;
@ -63,6 +65,9 @@ inline void frame::init(intptr_t* ptr_sp, intptr_t* ptr_fp, address pc) {
} else {
_deopt_state = not_deoptimized;
}
_on_heap = false;
DEBUG_ONLY(_frame_index = -1;)
}
inline frame::frame(intptr_t* ptr_sp, intptr_t* ptr_fp, address pc) {
@ -89,6 +94,13 @@ inline frame::frame(intptr_t* ptr_sp, intptr_t* unextended_sp, intptr_t* ptr_fp,
} else {
_deopt_state = not_deoptimized;
}
_on_heap = false;
DEBUG_ONLY(_frame_index = -1;)
}
inline frame::frame(intptr_t* ptr_sp) {
Unimplemented();
}
inline frame::frame(intptr_t* ptr_sp, intptr_t* ptr_fp) {
@ -119,6 +131,9 @@ inline frame::frame(intptr_t* ptr_sp, intptr_t* ptr_fp) {
} else {
_deopt_state = not_deoptimized;
}
_on_heap = false;
DEBUG_ONLY(_frame_index = -1;)
}
// Accessors
@ -150,6 +165,38 @@ inline intptr_t* frame::link_or_null() const {
inline intptr_t* frame::unextended_sp() const { return _unextended_sp; }
inline void frame::set_unextended_sp(intptr_t* value) {
Unimplemented();
}
inline int frame::offset_unextended_sp() const {
Unimplemented();
return 0;
}
inline void frame::set_offset_unextended_sp(int value) {
Unimplemented();
}
inline intptr_t* frame::real_fp() const {
if (_cb != NULL) {
// use the frame size if valid
int size = _cb->frame_size();
if (size > 0) {
return unextended_sp() + size;
}
}
// else rely on fp()
assert(!is_compiled_frame(), "unknown compiled frame size");
return fp();
}
inline int frame::frame_size() const {
return is_interpreted_frame()
? sender_sp() - sp()
: cb()->frame_size();
}
// Return address
inline address* frame::sender_pc_addr() const { return (address*) addr_at(return_addr_offset); }
inline address frame::sender_pc() const { return *sender_pc_addr(); }
@ -160,7 +207,7 @@ inline intptr_t** frame::interpreter_frame_locals_addr() const {
}
inline intptr_t* frame::interpreter_frame_last_sp() const {
return *(intptr_t**)addr_at(interpreter_frame_last_sp_offset);
return (intptr_t*)at(interpreter_frame_last_sp_offset);
}
inline intptr_t* frame::interpreter_frame_bcp_addr() const {
@ -233,16 +280,130 @@ inline JavaCallWrapper** frame::entry_frame_call_wrapper_addr() const {
PRAGMA_DIAG_PUSH
PRAGMA_NONNULL_IGNORED
inline oop frame::saved_oop_result(RegisterMap* map) const {
oop* result_adr = (oop *)map->location(x10->as_VMReg());
oop* result_adr = (oop *)map->location(x10->as_VMReg(), nullptr);
guarantee(result_adr != NULL, "bad register save location");
return (*result_adr);
}
inline void frame::set_saved_oop_result(RegisterMap* map, oop obj) {
oop* result_adr = (oop *)map->location(x10->as_VMReg());
oop* result_adr = (oop *)map->location(x10->as_VMReg(), nullptr);
guarantee(result_adr != NULL, "bad register save location");
*result_adr = obj;
}
PRAGMA_DIAG_POP
inline const ImmutableOopMap* frame::get_oop_map() const {
Unimplemented();
return NULL;
}
inline int frame::compiled_frame_stack_argsize() const {
Unimplemented();
return 0;
}
inline void frame::interpreted_frame_oop_map(InterpreterOopMap* mask) const {
Unimplemented();
}
inline int frame::sender_sp_ret_address_offset() {
Unimplemented();
return 0;
}
//------------------------------------------------------------------------------
// frame::sender
frame frame::sender(RegisterMap* map) const {
frame result = sender_raw(map);
if (map->process_frames()) {
StackWatermarkSet::on_iteration(map->thread(), result);
}
return result;
}
//------------------------------------------------------------------------------
// frame::sender_raw
frame frame::sender_raw(RegisterMap* map) const {
// Default is we done have to follow them. The sender_for_xxx will
// update it accordingly
assert(map != NULL, "map must be set");
map->set_include_argument_oops(false);
if (is_entry_frame()) {
return sender_for_entry_frame(map);
}
if (is_interpreted_frame()) {
return sender_for_interpreter_frame(map);
}
assert(_cb == CodeCache::find_blob(pc()),"Must be the same");
// This test looks odd: why is it not is_compiled_frame() ? That's
// because stubs also have OOP maps.
if (_cb != NULL) {
return sender_for_compiled_frame(map);
}
// Must be native-compiled frame, i.e. the marshaling code for native
// methods that exists in the core system.
return frame(sender_sp(), link(), sender_pc());
}
//------------------------------------------------------------------------------
// frame::sender_for_compiled_frame
frame frame::sender_for_compiled_frame(RegisterMap* map) const {
// we cannot rely upon the last fp having been saved to the thread
// in C2 code but it will have been pushed onto the stack. so we
// have to find it relative to the unextended sp
assert(_cb->frame_size() >= 0, "must have non-zero frame size");
intptr_t* l_sender_sp = unextended_sp() + _cb->frame_size();
intptr_t* unextended_sp = l_sender_sp;
// the return_address is always the word on the stack
address sender_pc = (address) *(l_sender_sp + frame::return_addr_offset);
intptr_t** saved_fp_addr = (intptr_t**) (l_sender_sp + frame::link_offset);
assert(map != NULL, "map must be set");
if (map->update_map()) {
// Tell GC to use argument oopmaps for some runtime stubs that need it.
// For C1, the runtime stub might not have oop maps, so set this flag
// outside of update_register_map.
map->set_include_argument_oops(_cb->caller_must_gc_arguments(map->thread()));
if (_cb->oop_maps() != NULL) {
OopMapSet::update_register_map(this, map);
}
// Since the prolog does the save and restore of FP there is no
// oopmap for it so we must fill in its location as if there was
// an oopmap entry since if our caller was compiled code there
// could be live jvm state in it.
update_map_with_saved_link(map, saved_fp_addr);
}
return frame(l_sender_sp, unextended_sp, *saved_fp_addr, sender_pc);
}
//------------------------------------------------------------------------------
// frame::update_map_with_saved_link
template <typename RegisterMapT>
void frame::update_map_with_saved_link(RegisterMapT* map, intptr_t** link_addr) {
// The interpreter and compiler(s) always save fp in a known
// location on entry. We must record where that location is
// so that if fp was live on callout from c2 we can find
// the saved copy no matter what it called.
// Since the interpreter always saves fp if we record where it is then
// we don't have to always save fp on entry and exit to c2 compiled
// code, on entry will be enough.
assert(map != NULL, "map must be set");
map->set_location(::fp->as_VMReg(), (address) link_addr);
// this is weird "H" ought to be at a higher address however the
// oopMaps seems to have the "H" regs at the same address and the
// vanilla register.
map->set_location(::fp->as_VMReg()->next(), (address) link_addr);
}
#endif // CPU_RISCV_FRAME_RISCV_INLINE_HPP

View File

@ -1,6 +1,6 @@
/*
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, 2021, Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. 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
@ -29,6 +29,7 @@
#include "gc/shared/barrierSetNMethod.hpp"
#include "logging/log.hpp"
#include "memory/resourceArea.hpp"
#include "runtime/frame.inline.hpp"
#include "runtime/sharedRuntime.hpp"
#include "runtime/registerMap.hpp"
#include "runtime/thread.hpp"
@ -161,6 +162,10 @@ void BarrierSetNMethod::disarm(nmethod* nm) {
barrier->set_value(disarmed_value());
}
void BarrierSetNMethod::arm(nmethod* nm, int arm_value) {
Unimplemented();
}
bool BarrierSetNMethod::is_armed(nmethod* nm) {
if (!supports_entry_barrier(nm)) {
return false;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2018, Red Hat Inc. All rights reserved.
* Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@ -569,4 +569,35 @@ public:
}
};
class NativePostCallNop: public NativeInstruction {
public:
bool check() const { Unimplemented(); return false; }
int displacement() const { Unimplemented(); return 0; }
void patch(jint diff) { Unimplemented(); }
void make_deopt() { Unimplemented(); }
};
inline NativePostCallNop* nativePostCallNop_at(address address) {
Unimplemented();
return NULL;
}
class NativeDeoptInstruction: public NativeInstruction {
public:
address instruction_address() const { Unimplemented(); return NULL; }
address next_instruction_address() const { Unimplemented(); return NULL; }
void verify() { Unimplemented(); }
static bool is_deopt_at(address instr) {
Unimplemented();
return false;
}
// MT-safe patching
static void insert(address code_pos) {
Unimplemented();
}
};
#endif // CPU_RISCV_NATIVEINST_RISCV_HPP

View File

@ -1,6 +1,6 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, 2022, Huawei Technologies Co., Ltd. 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
@ -33,13 +33,13 @@ address RegisterMap::pd_location(VMReg base_reg, int slot_idx) const {
int base_reg_enc = (base_reg->value() - ConcreteRegisterImpl::max_fpr) /
VectorRegisterImpl::max_slots_per_register;
intptr_t offset_in_bytes = slot_idx * VMRegImpl::stack_slot_size;
address base_location = location(base_reg);
address base_location = location(base_reg, nullptr);
if (base_location != NULL) {
return base_location + offset_in_bytes;
} else {
return NULL;
}
} else {
return location(base_reg->next(slot_idx));
return location(base_reg->next(slot_idx), nullptr);
}
}

View File

@ -0,0 +1,87 @@
/*
* Copyright (c) 2019, 2022, 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.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#ifndef CPU_RISCV_SMALLREGISTERMAP_RISCV_INLINE_HPP
#define CPU_RISCV_SMALLREGISTERMAP_RISCV_INLINE_HPP
#include "runtime/frame.inline.hpp"
#include "runtime/registerMap.hpp"
// Java frames don't have callee saved registers (except for rfp), so we can use a smaller RegisterMap
class SmallRegisterMap {
public:
static constexpr SmallRegisterMap* instance = nullptr;
private:
static void assert_is_rfp(VMReg r) PRODUCT_RETURN
DEBUG_ONLY({ Unimplemented(); })
public:
// as_RegisterMap is used when we didn't want to templatize and abstract over RegisterMap type to support SmallRegisterMap
// Consider enhancing SmallRegisterMap to support those cases
const RegisterMap* as_RegisterMap() const { return nullptr; }
RegisterMap* as_RegisterMap() { return nullptr; }
RegisterMap* copy_to_RegisterMap(RegisterMap* map, intptr_t* sp) const {
Unimplemented();
return map;
}
SmallRegisterMap() {}
SmallRegisterMap(const RegisterMap* map) {
Unimplemented();
}
inline address location(VMReg reg, intptr_t* sp) const {
Unimplemented();
return NULL;
}
inline void set_location(VMReg reg, address loc) { assert_is_rfp(reg); }
JavaThread* thread() const {
#ifndef ASSERT
guarantee (false, "");
#endif
return nullptr;
}
bool update_map() const { return false; }
bool walk_cont() const { return false; }
bool include_argument_oops() const { return false; }
void set_include_argument_oops(bool f) {}
bool in_cont() const { return false; }
stackChunkHandle stack_chunk() const { return stackChunkHandle(); }
#ifdef ASSERT
bool should_skip_missing() const { return false; }
VMReg find_register_spilled_here(void* p, intptr_t* sp) {
Unimplemented();
return NULL;
}
void print() const { print_on(tty); }
void print_on(outputStream* st) const { st->print_cr("Small register map"); }
#endif
};
#endif // CPU_RISCV_SMALLREGISTERMAP_RISCV_INLINE_HPP

View File

@ -0,0 +1,115 @@
/*
* Copyright (c) 2019, 2022, 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.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#ifndef CPU_RISCV_STACKCHUNKFRAMESTREAM_RISCV_INLINE_HPP
#define CPU_RISCV_STACKCHUNKFRAMESTREAM_RISCV_INLINE_HPP
#include "interpreter/oopMapCache.hpp"
#include "runtime/frame.inline.hpp"
#include "runtime/registerMap.hpp"
#ifdef ASSERT
template <ChunkFrames frame_kind>
inline bool StackChunkFrameStream<frame_kind>::is_in_frame(void* p0) const {
Unimplemented();
return true;
}
#endif
template <ChunkFrames frame_kind>
inline frame StackChunkFrameStream<frame_kind>::to_frame() const {
Unimplemented();
return frame();
}
template <ChunkFrames frame_kind>
inline address StackChunkFrameStream<frame_kind>::get_pc() const {
Unimplemented();
return NULL;
}
template <ChunkFrames frame_kind>
inline intptr_t* StackChunkFrameStream<frame_kind>::fp() const {
Unimplemented();
return NULL;
}
template <ChunkFrames frame_kind>
inline intptr_t* StackChunkFrameStream<frame_kind>::derelativize(int offset) const {
Unimplemented();
return NULL;
}
template <ChunkFrames frame_kind>
inline intptr_t* StackChunkFrameStream<frame_kind>::unextended_sp_for_interpreter_frame() const {
Unimplemented();
return NULL;
}
template <ChunkFrames frame_kind>
intptr_t* StackChunkFrameStream<frame_kind>::next_sp_for_interpreter_frame() const {
Unimplemented();
return NULL;
}
template <ChunkFrames frame_kind>
inline void StackChunkFrameStream<frame_kind>::next_for_interpreter_frame() {
Unimplemented();
}
template <ChunkFrames frame_kind>
inline int StackChunkFrameStream<frame_kind>::interpreter_frame_size() const {
Unimplemented();
return 0;
}
template <ChunkFrames frame_kind>
inline int StackChunkFrameStream<frame_kind>::interpreter_frame_stack_argsize() const {
Unimplemented();
return 0;
}
template <ChunkFrames frame_kind>
inline int StackChunkFrameStream<frame_kind>::interpreter_frame_num_oops() const {
Unimplemented();
return 0;
}
template<>
template<>
inline void StackChunkFrameStream<ChunkFrames::Mixed>::update_reg_map_pd(RegisterMap* map) {
Unimplemented();
}
template<>
template<>
inline void StackChunkFrameStream<ChunkFrames::CompiledOnly>::update_reg_map_pd(RegisterMap* map) {
Unimplemented();
}
template <ChunkFrames frame_kind>
template <typename RegisterMapT>
inline void StackChunkFrameStream<frame_kind>::update_reg_map_pd(RegisterMapT* map) {}
#endif // CPU_RISCV_STACKCHUNKFRAMESTREAM_RISCV_INLINE_HPP

View File

@ -0,0 +1,36 @@
/*
* Copyright (c) 2019, 2022, 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.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#ifndef CPU_RISCV_STACKCHUNKOOP_RISCV_INLINE_HPP
#define CPU_RISCV_STACKCHUNKOOP_RISCV_INLINE_HPP
inline void stackChunkOopDesc::relativize_frame_pd(frame& fr) const {
Unimplemented();
}
inline void stackChunkOopDesc::derelativize_frame_pd(frame& fr) const {
Unimplemented();
}
#endif // CPU_RISCV_STACKCHUNKOOP_RISCV_INLINE_HPP

View File

@ -3810,10 +3810,10 @@ class StubGenerator: public StubCodeGenerator {
}; // end class declaration
#define UCM_TABLE_MAX_ENTRIES 8
void StubGenerator_generate(CodeBuffer* code, bool all) {
void StubGenerator_generate(CodeBuffer* code, int phase) {
if (UnsafeCopyMemory::_table == NULL) {
UnsafeCopyMemory::create_table(UCM_TABLE_MAX_ENTRIES);
}
StubGenerator g(code, all);
StubGenerator g(code, phase);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved.
* Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@ -797,6 +797,11 @@ void TemplateInterpreterGenerator::generate_fixed_frame(bool native_call) {
// End of helpers
address TemplateInterpreterGenerator::generate_Continuation_doYield_entry(void) {
Unimplemented();
return NULL;
}
// Various method entries
//------------------------------------------------------------------------------------------------------------------------
//

View File

@ -392,7 +392,10 @@ class Argument {
// Only 5 registers may contain integer parameters.
n_register_parameters = 5,
// Can have up to 4 floating registers.
n_float_register_parameters = 4
n_float_register_parameters = 4,
n_int_register_parameters_j = n_register_parameters,
n_float_register_parameters_j = n_float_register_parameters
};
// creation

View File

@ -1183,3 +1183,7 @@ void LIRGenerator::do_FmaIntrinsic(Intrinsic* x) {
void LIRGenerator::do_vectorizedMismatch(Intrinsic* x) {
fatal("vectorizedMismatch intrinsic is not implemented on this platform");
}
void LIRGenerator::do_continuation_doYield(Intrinsic* x) {
fatal("Continuation.doYield intrinsic is not implemented on this platform");
}

View File

@ -0,0 +1,46 @@
/*
* Copyright (c) 2022, 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.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#ifndef CPU_S390_CONTINUATIONENTRY_S390_INLINE_HPP
#define CPU_S390_CONTINUATIONENTRY_S390_INLINE_HPP
#include "runtime/continuationEntry.hpp"
// TODO: Implement
inline frame ContinuationEntry::to_frame() const {
Unimplemented();
return frame();
}
inline intptr_t* ContinuationEntry::entry_fp() const {
Unimplemented();
return nullptr;
}
inline void ContinuationEntry::update_register_map(RegisterMap* map) const {
Unimplemented();
}
#endif // CPU_S390_CONTINUATIONENTRY_S390_INLINE_HPP

View File

@ -0,0 +1,98 @@
/*
* Copyright (c) 2019, 2022, 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.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#ifndef CPU_S390_CONTINUATION_S390_INLINE_HPP
#define CPU_S390_CONTINUATION_S390_INLINE_HPP
#include "oops/stackChunkOop.inline.hpp"
#include "runtime/frame.hpp"
#include "runtime/frame.inline.hpp"
inline void FreezeBase::set_top_frame_metadata_pd(const frame& hf) {
Unimplemented();
}
template<typename FKind>
inline frame FreezeBase::sender(const frame& f) {
Unimplemented();
return frame();
}
template<typename FKind> frame FreezeBase::new_heap_frame(frame& f, frame& caller) {
Unimplemented();
return frame();
}
void FreezeBase::adjust_interpreted_frame_unextended_sp(frame& f) {
Unimplemented();
}
inline void FreezeBase::relativize_interpreted_frame_metadata(const frame& f, const frame& hf) {
Unimplemented();
}
inline void FreezeBase::patch_pd(frame& hf, const frame& caller) {
Unimplemented();
}
inline void FreezeBase::patch_stack_pd(intptr_t* frame_sp, intptr_t* heap_sp) {
Unimplemented();
}
inline frame ThawBase::new_entry_frame() {
Unimplemented();
return frame();
}
template<typename FKind> frame ThawBase::new_stack_frame(const frame& hf, frame& caller, bool bottom) {
Unimplemented();
return frame();
}
inline void ThawBase::set_interpreter_frame_bottom(const frame& f, intptr_t* bottom) {
Unimplemented();
}
inline void ThawBase::derelativize_interpreted_frame_metadata(const frame& hf, const frame& f) {
Unimplemented();
}
inline intptr_t* ThawBase::align(const frame& hf, intptr_t* frame_sp, frame& caller, bool bottom) {
Unimplemented();
return NULL;
}
inline void ThawBase::patch_pd(frame& f, const frame& caller) {
Unimplemented();
}
void ThawBase::patch_chunk_pd(intptr_t* sp) {
Unimplemented();
}
inline void ThawBase::prefetch_chunk_pd(void* start, int size) {
Unimplemented();
}
#endif // CPU_S390_CONTINUATION_S390_INLINE_HPP

View File

@ -0,0 +1,125 @@
/*
* Copyright (c) 2022, 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.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#ifndef CPU_S390_CONTINUATIONHELPER_S390_INLINE_HPP
#define CPU_S390_CONTINUATIONHELPER_S390_INLINE_HPP
#include "runtime/continuationHelper.hpp"
// TODO: Implement
template<typename FKind>
static inline intptr_t** link_address(const frame& f) {
Unimplemented();
return NULL;
}
inline int ContinuationHelper::frame_align_words(int size) {
Unimplemented();
return 0;
}
inline intptr_t* ContinuationHelper::frame_align_pointer(intptr_t* sp) {
Unimplemented();
return NULL;
}
template<typename FKind>
inline void ContinuationHelper::update_register_map(const frame& f, RegisterMap* map) {
Unimplemented();
}
inline void ContinuationHelper::update_register_map_with_callee(const frame& f, RegisterMap* map) {
Unimplemented();
}
inline void ContinuationHelper::push_pd(const frame& f) {
Unimplemented();
}
inline void ContinuationHelper::set_anchor_to_entry_pd(JavaFrameAnchor* anchor, ContinuationEntry* cont) {
Unimplemented();
}
#ifdef ASSERT
inline void ContinuationHelper::set_anchor_pd(JavaFrameAnchor* anchor, intptr_t* sp) {
Unimplemented();
}
inline bool ContinuationHelper::Frame::assert_frame_laid_out(frame f) {
Unimplemented();
return false;
}
#endif
inline intptr_t** ContinuationHelper::Frame::callee_link_address(const frame& f) {
Unimplemented();
return NULL;
}
template<typename FKind>
static inline intptr_t* real_fp(const frame& f) {
Unimplemented();
return NULL;
}
inline address* ContinuationHelper::InterpretedFrame::return_pc_address(const frame& f) {
Unimplemented();
return NULL;
}
inline void ContinuationHelper::InterpretedFrame::patch_sender_sp(frame& f, intptr_t* sp) {
Unimplemented();
}
inline address* ContinuationHelper::Frame::return_pc_address(const frame& f) {
Unimplemented();
return NULL;
}
inline address ContinuationHelper::Frame::real_pc(const frame& f) {
Unimplemented();
return NULL;
}
inline void ContinuationHelper::Frame::patch_pc(const frame& f, address pc) {
Unimplemented();
}
inline intptr_t* ContinuationHelper::InterpretedFrame::frame_top(const frame& f, InterpreterOopMap* mask) { // inclusive; this will be copied with the frame
Unimplemented();
return NULL;
}
inline intptr_t* ContinuationHelper::InterpretedFrame::frame_bottom(const frame& f) { // exclusive; this will not be copied with the frame
Unimplemented();
return NULL;
}
inline intptr_t* ContinuationHelper::InterpretedFrame::frame_top(const frame& f, int callee_argsize, bool callee_interpreted) {
Unimplemented();
return NULL;
}
#endif // CPU_S390_CONTINUATIONHELPER_S390_INLINE_HPP

View File

@ -230,27 +230,6 @@ frame frame::sender_for_interpreter_frame(RegisterMap *map) const {
return frame(sender_sp(), sender_pc(), (intptr_t*)(ijava_state()->sender_sp));
}
frame frame::sender_for_compiled_frame(RegisterMap *map) const {
assert(map != NULL, "map must be set");
// Frame owned by compiler.
address pc = *compiled_sender_pc_addr(_cb);
frame caller(compiled_sender_sp(_cb), pc);
// Now adjust the map.
// Get the rest.
if (map->update_map()) {
// Tell GC to use argument oopmaps for some runtime stubs that need it.
map->set_include_argument_oops(_cb->caller_must_gc_arguments(map->thread()));
if (_cb->oop_maps() != NULL) {
OopMapSet::update_register_map(this, map);
}
}
return caller;
}
intptr_t* frame::compiled_sender_sp(CodeBlob* cb) const {
return sender_sp();
}
@ -259,26 +238,6 @@ address* frame::compiled_sender_pc_addr(CodeBlob* cb) const {
return sender_pc_addr();
}
frame frame::sender(RegisterMap* map) const {
// Default is we don't have to follow them. The sender_for_xxx will
// update it accordingly.
map->set_include_argument_oops(false);
if (is_entry_frame()) {
return sender_for_entry_frame(map);
}
if (is_interpreted_frame()) {
return sender_for_interpreter_frame(map);
}
assert(_cb == CodeCache::find_blob(pc()),"Must be the same");
if (_cb != NULL) {
return sender_for_compiled_frame(map);
}
// Must be native-compiled frame, i.e. the marshaling code for native
// methods that exists in the core system.
return frame(sender_sp(), sender_pc());
}
void frame::patch_pc(Thread* thread, address pc) {
assert(_cb == CodeCache::find_blob(pc), "unexpected pc");
if (TracePcPatching) {
@ -680,3 +639,13 @@ intptr_t *frame::initial_deoptimization_info() {
// Used to reset the saved FP.
return fp();
}
// Pointer beyond the "oldest/deepest" BasicObjectLock on stack.
BasicObjectLock* frame::interpreter_frame_monitor_end() const {
return interpreter_frame_monitors();
}
intptr_t* frame::interpreter_frame_tos_at(jint offset) const {
return &interpreter_frame_tos_address()[offset];
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@ -461,11 +461,11 @@
private:
inline void find_codeblob_and_set_pc_and_deopt_state(address pc);
const ImmutableOopMap* get_oop_map() const;
// Constructors
public:
inline frame(intptr_t* sp);
// To be used, if sp was not extended to match callee's calling convention.
inline frame(intptr_t* sp, address pc);
inline frame(intptr_t* sp, address pc, intptr_t* unextended_sp);
@ -486,6 +486,10 @@
address* sender_pc_addr(void) const;
public:
inline intptr_t* interpreter_frame_last_sp() const;
template <typename RegisterMapT>
static void update_map_with_saved_link(RegisterMapT* map, intptr_t** link_addr);
// Additional interface for interpreter frames:
static int interpreter_frame_interpreterstate_size_in_bytes();
@ -550,6 +554,10 @@
//
// Normal return address is the instruction following the branch.
pc_return_offset = 0,
metadata_words = 0,
frame_alignment = 16,
// size, in words, of maximum shift in frame position due to alignment
align_wiggle = 1
};
static jint interpreter_frame_expression_stack_direction() { return -1; }

View File

@ -54,24 +54,44 @@ inline void frame::find_codeblob_and_set_pc_and_deopt_state(address pc) {
// Constructors
// Initialize all fields, _unextended_sp will be adjusted in find_codeblob_and_set_pc_and_deopt_state.
inline frame::frame() : _sp(NULL), _pc(NULL), _cb(NULL), _deopt_state(unknown), _unextended_sp(NULL), _fp(NULL) {}
inline frame::frame() : _sp(NULL), _pc(NULL), _cb(NULL), _deopt_state(unknown), _on_heap(false),
#ifdef ASSERT
_frame_index(-1),
#endif
_unextended_sp(NULL), _fp(NULL) {}
inline frame::frame(intptr_t* sp) : _sp(sp), _unextended_sp(sp) {
inline frame::frame(intptr_t* sp) : _sp(sp), _on_heap(false),
#ifdef ASSERT
_frame_index(-1),
#endif
_unextended_sp(sp) {
find_codeblob_and_set_pc_and_deopt_state((address)own_abi()->return_pc);
}
inline frame::frame(intptr_t* sp, address pc) : _sp(sp), _unextended_sp(sp) {
inline frame::frame(intptr_t* sp, address pc) : _sp(sp), _on_heap(false),
#ifdef ASSERT
_frame_index(-1),
#endif
_unextended_sp(sp) {
find_codeblob_and_set_pc_and_deopt_state(pc); // Also sets _fp and adjusts _unextended_sp.
}
inline frame::frame(intptr_t* sp, address pc, intptr_t* unextended_sp) : _sp(sp), _unextended_sp(unextended_sp) {
inline frame::frame(intptr_t* sp, address pc, intptr_t* unextended_sp) : _sp(sp), _on_heap(false),
#ifdef ASSERT
_frame_index(-1),
#endif
_unextended_sp(unextended_sp) {
find_codeblob_and_set_pc_and_deopt_state(pc); // Also sets _fp and adjusts _unextended_sp.
}
// Generic constructor. Used by pns() in debug.cpp only
#ifndef PRODUCT
inline frame::frame(void* sp, void* pc, void* unextended_sp) :
_sp((intptr_t*)sp), _pc(NULL), _cb(NULL), _unextended_sp((intptr_t*)unextended_sp) {
_sp((intptr_t*)sp), _pc(NULL), _cb(NULL), _on_heap(false),
#ifdef ASSERT
_frame_index(-1),
#endif
_unextended_sp((intptr_t*)unextended_sp) {
find_codeblob_and_set_pc_and_deopt_state((address)pc); // Also sets _fp and adjusts _unextended_sp.
}
#endif
@ -119,7 +139,7 @@ inline bool frame::is_older(intptr_t* id) const {
return this->id() > id;
}
inline int frame::frame_size(RegisterMap* map) const {
inline int frame::frame_size() const {
// Stack grows towards smaller addresses on z/Linux: sender is at a higher address.
return sender_sp() - sp();
}
@ -176,11 +196,6 @@ inline intptr_t* frame::interpreter_frame_expression_stack() const {
return (intptr_t*)interpreter_frame_monitor_end() - 1;
}
inline intptr_t* frame::interpreter_frame_tos_at(jint offset) const {
return &interpreter_frame_tos_address()[offset];
}
// monitor elements
// End is lower in memory than begin, and beginning element is oldest element.
@ -229,10 +244,6 @@ inline BasicObjectLock * frame::interpreter_frame_monitor_begin() const {
return (BasicObjectLock*)ijava_state();
}
inline BasicObjectLock * frame::interpreter_frame_monitor_end() const {
return interpreter_frame_monitors();
}
inline void frame::interpreter_frame_set_monitor_end(BasicObjectLock* monitors) {
interpreter_frame_set_monitors((BasicObjectLock *)monitors);
}
@ -281,15 +292,100 @@ inline JavaCallWrapper** frame::entry_frame_call_wrapper_addr() const {
}
inline oop frame::saved_oop_result(RegisterMap* map) const {
return *((oop*) map->location(Z_R2->as_VMReg())); // R2 is return register.
return *((oop*) map->location(Z_R2->as_VMReg(), nullptr)); // R2 is return register.
}
inline void frame::set_saved_oop_result(RegisterMap* map, oop obj) {
*((oop*) map->location(Z_R2->as_VMReg())) = obj; // R2 is return register.
*((oop*) map->location(Z_R2->as_VMReg(), nullptr)) = obj; // R2 is return register.
}
inline intptr_t* frame::real_fp() const {
return fp();
}
inline const ImmutableOopMap* frame::get_oop_map() const {
Unimplemented();
return NULL;
}
inline int frame::compiled_frame_stack_argsize() const {
Unimplemented();
return 0;
}
inline void frame::interpreted_frame_oop_map(InterpreterOopMap* mask) const {
Unimplemented();
}
inline intptr_t* frame::interpreter_frame_last_sp() const {
Unimplemented();
return NULL;
}
inline int frame::sender_sp_ret_address_offset() {
Unimplemented();
return 0;
}
inline void frame::set_unextended_sp(intptr_t* value) {
Unimplemented();
}
inline int frame::offset_unextended_sp() const {
Unimplemented();
return 0;
}
inline void frame::set_offset_unextended_sp(int value) {
Unimplemented();
}
//------------------------------------------------------------------------------
// frame::sender
inline frame frame::sender(RegisterMap* map) const {
// Default is we don't have to follow them. The sender_for_xxx will
// update it accordingly.
map->set_include_argument_oops(false);
if (is_entry_frame()) {
return sender_for_entry_frame(map);
}
if (is_interpreted_frame()) {
return sender_for_interpreter_frame(map);
}
assert(_cb == CodeCache::find_blob(pc()),"Must be the same");
if (_cb != NULL) return sender_for_compiled_frame(map);
// Must be native-compiled frame, i.e. the marshaling code for native
// methods that exists in the core system.
return frame(sender_sp(), sender_pc());
}
inline frame frame::sender_for_compiled_frame(RegisterMap *map) const {
assert(map != NULL, "map must be set");
// Frame owned by compiler.
address pc = *compiled_sender_pc_addr(_cb);
frame caller(compiled_sender_sp(_cb), pc);
// Now adjust the map.
// Get the rest.
if (map->update_map()) {
// Tell GC to use argument oopmaps for some runtime stubs that need it.
map->set_include_argument_oops(_cb->caller_must_gc_arguments(map->thread()));
if (_cb->oop_maps() != NULL) {
OopMapSet::update_register_map(this, map);
}
}
return caller;
}
template <typename RegisterMapT>
void frame::update_map_with_saved_link(RegisterMapT* map, intptr_t** link_addr) {
Unimplemented();
}
#endif // CPU_S390_FRAME_S390_INLINE_HPP

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@ -654,4 +654,35 @@ class NativeGeneralJump: public NativeInstruction {
void verify() PRODUCT_RETURN;
};
class NativePostCallNop: public NativeInstruction {
public:
bool check() const { Unimplemented(); return false; }
int displacement() const { Unimplemented(); return 0; }
void patch(jint diff) { Unimplemented(); }
void make_deopt() { Unimplemented(); }
};
inline NativePostCallNop* nativePostCallNop_at(address address) {
Unimplemented();
return NULL;
}
class NativeDeoptInstruction: public NativeInstruction {
public:
address instruction_address() const { Unimplemented(); return NULL; }
address next_instruction_address() const { Unimplemented(); return NULL; }
void verify() { Unimplemented(); }
static bool is_deopt_at(address instr) {
Unimplemented();
return false;
}
// MT-safe patching
static void insert(address code_pos) {
Unimplemented();
}
};
#endif // CPU_S390_NATIVEINST_S390_HPP

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@ -37,7 +37,7 @@
address pd_location(VMReg reg) const {return NULL;}
address pd_location(VMReg base_reg, int slot_idx) const {
return location(base_reg->next(slot_idx));
return location(base_reg->next(slot_idx), nullptr);
}
// No PD state to clear or copy.

View File

@ -0,0 +1,87 @@
/*
* Copyright (c) 2019, 2022, 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.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#ifndef CPU_S390_SMALLREGISTERMAP_S390_INLINE_HPP
#define CPU_S390_SMALLREGISTERMAP_S390_INLINE_HPP
#include "runtime/frame.inline.hpp"
#include "runtime/registerMap.hpp"
// Java frames don't have callee saved registers (except for rfp), so we can use a smaller RegisterMap
class SmallRegisterMap {
public:
static constexpr SmallRegisterMap* instance = nullptr;
private:
static void assert_is_rfp(VMReg r) PRODUCT_RETURN
DEBUG_ONLY({ Unimplemented(); })
public:
// as_RegisterMap is used when we didn't want to templatize and abstract over RegisterMap type to support SmallRegisterMap
// Consider enhancing SmallRegisterMap to support those cases
const RegisterMap* as_RegisterMap() const { return nullptr; }
RegisterMap* as_RegisterMap() { return nullptr; }
RegisterMap* copy_to_RegisterMap(RegisterMap* map, intptr_t* sp) const {
Unimplemented();
return map;
}
SmallRegisterMap() {}
SmallRegisterMap(const RegisterMap* map) {
Unimplemented();
}
inline address location(VMReg reg, intptr_t* sp) const {
Unimplemented();
return NULL;
}
inline void set_location(VMReg reg, address loc) { assert_is_rfp(reg); }
JavaThread* thread() const {
#ifndef ASSERT
guarantee (false, "");
#endif
return nullptr;
}
bool update_map() const { return false; }
bool walk_cont() const { return false; }
bool include_argument_oops() const { return false; }
void set_include_argument_oops(bool f) {}
bool in_cont() const { return false; }
stackChunkHandle stack_chunk() const { return stackChunkHandle(); }
#ifdef ASSERT
bool should_skip_missing() const { return false; }
VMReg find_register_spilled_here(void* p, intptr_t* sp) {
Unimplemented();
return NULL;
}
void print() const { print_on(tty); }
void print_on(outputStream* st) const { st->print_cr("Small register map"); }
#endif
};
#endif // CPU_S390_SMALLREGISTERMAP_S390_INLINE_HPP

View File

@ -0,0 +1,115 @@
/*
* Copyright (c) 2019, 2022, 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.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#ifndef CPU_S390_STACKCHUNKFRAMESTREAM_S390_INLINE_HPP
#define CPU_S390_STACKCHUNKFRAMESTREAM_S390_INLINE_HPP
#include "interpreter/oopMapCache.hpp"
#include "runtime/frame.inline.hpp"
#include "runtime/registerMap.hpp"
#ifdef ASSERT
template <ChunkFrames frame_kind>
inline bool StackChunkFrameStream<frame_kind>::is_in_frame(void* p0) const {
Unimplemented();
return true;
}
#endif
template <ChunkFrames frame_kind>
inline frame StackChunkFrameStream<frame_kind>::to_frame() const {
Unimplemented();
return frame();
}
template <ChunkFrames frame_kind>
inline address StackChunkFrameStream<frame_kind>::get_pc() const {
Unimplemented();
return NULL;
}
template <ChunkFrames frame_kind>
inline intptr_t* StackChunkFrameStream<frame_kind>::fp() const {
Unimplemented();
return NULL;
}
template <ChunkFrames frame_kind>
inline intptr_t* StackChunkFrameStream<frame_kind>::derelativize(int offset) const {
Unimplemented();
return NULL;
}
template <ChunkFrames frame_kind>
inline intptr_t* StackChunkFrameStream<frame_kind>::unextended_sp_for_interpreter_frame() const {
Unimplemented();
return NULL;
}
template <ChunkFrames frame_kind>
intptr_t* StackChunkFrameStream<frame_kind>::next_sp_for_interpreter_frame() const {
Unimplemented();
return NULL;
}
template <ChunkFrames frame_kind>
inline void StackChunkFrameStream<frame_kind>::next_for_interpreter_frame() {
Unimplemented();
}
template <ChunkFrames frame_kind>
inline int StackChunkFrameStream<frame_kind>::interpreter_frame_size() const {
Unimplemented();
return 0;
}
template <ChunkFrames frame_kind>
inline int StackChunkFrameStream<frame_kind>::interpreter_frame_stack_argsize() const {
Unimplemented();
return 0;
}
template <ChunkFrames frame_kind>
inline int StackChunkFrameStream<frame_kind>::interpreter_frame_num_oops() const {
Unimplemented();
return 0;
}
template<>
template<>
inline void StackChunkFrameStream<ChunkFrames::Mixed>::update_reg_map_pd(RegisterMap* map) {
Unimplemented();
}
template<>
template<>
inline void StackChunkFrameStream<ChunkFrames::CompiledOnly>::update_reg_map_pd(RegisterMap* map) {
Unimplemented();
}
template <ChunkFrames frame_kind>
template <typename RegisterMapT>
inline void StackChunkFrameStream<frame_kind>::update_reg_map_pd(RegisterMapT* map) {}
#endif // CPU_S390_STACKCHUNKFRAMESTREAM_S390_INLINE_HPP

View File

@ -0,0 +1,36 @@
/*
* Copyright (c) 2019, 2022, 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.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#ifndef CPU_S390_STACKCHUNKOOP_S390_INLINE_HPP
#define CPU_S390_STACKCHUNKOOP_S390_INLINE_HPP
inline void stackChunkOopDesc::relativize_frame_pd(frame& fr) const {
Unimplemented();
}
inline void stackChunkOopDesc::derelativize_frame_pd(frame& fr) const {
Unimplemented();
}
#endif // CPU_S390_STACKCHUNKOOP_S390_INLINE_HPP

View File

@ -3014,6 +3014,6 @@ class StubGenerator: public StubCodeGenerator {
};
void StubGenerator_generate(CodeBuffer* code, bool all) {
StubGenerator g(code, all);
void StubGenerator_generate(CodeBuffer* code, int phase) {
StubGenerator g(code, phase);
}

View File

@ -482,6 +482,11 @@ address TemplateInterpreterGenerator::generate_abstract_entry(void) {
return __ addr_at(entry_offset);
}
address TemplateInterpreterGenerator::generate_Continuation_doYield_entry(void) {
Unimplemented();
return NULL;
}
address TemplateInterpreterGenerator::generate_Reference_get_entry(void) {
// Inputs:
// Z_ARG1 - receiver

View File

@ -49,7 +49,9 @@ class Argument {
n_int_register_parameters_j = 6, // j_rarg0, j_rarg1, ...
n_float_register_parameters_j = 8 // j_farg0, j_farg1, ...
#else
n_register_parameters = 0 // 0 registers used to pass arguments
n_register_parameters = 0, // 0 registers used to pass arguments
n_int_register_parameters_j = 0,
n_float_register_parameters_j = 0
#endif // _LP64
};
};

View File

@ -438,7 +438,7 @@ int LIR_Assembler::emit_unwind_handler() {
// Fetch the exception from TLS and clear out exception related thread state
Register thread = NOT_LP64(rsi) LP64_ONLY(r15_thread);
NOT_LP64(__ get_thread(rsi));
NOT_LP64(__ get_thread(thread));
__ movptr(rax, Address(thread, JavaThread::exception_oop_offset()));
__ movptr(Address(thread, JavaThread::exception_oop_offset()), (intptr_t)NULL_WORD);
__ movptr(Address(thread, JavaThread::exception_pc_offset()), (intptr_t)NULL_WORD);
@ -460,6 +460,8 @@ int LIR_Assembler::emit_unwind_handler() {
__ unlock_object(rdi, rsi, rax, *stub->entry());
}
__ bind(*stub->continuation());
NOT_LP64(__ get_thread(thread);)
__ dec_held_monitor_count(thread);
}
if (compilation()->env()->dtrace_method_probes()) {
@ -2864,6 +2866,7 @@ void LIR_Assembler::call(LIR_OpJavaCall* op, relocInfo::relocType rtype) {
"must be aligned");
__ call(AddressLiteral(op->addr(), rtype));
add_call_info(code_offset(), op->info());
__ post_call_nop();
}
@ -2872,6 +2875,7 @@ void LIR_Assembler::ic_call(LIR_OpJavaCall* op) {
add_call_info(code_offset(), op->info());
assert((__ offset() - NativeCall::instruction_size + NativeCall::displacement_offset) % BytesPerWord == 0,
"must be aligned");
__ post_call_nop();
}
@ -3507,7 +3511,38 @@ void LIR_Assembler::emit_lock(LIR_OpLock* op) {
} else {
Unimplemented();
}
if (op->code() == lir_lock) {
// If deoptimization happens in Runtime1::monitorenter, inc_held_monitor_count after backing from slowpath
// will be skipped. Solution is
// 1. Increase only in fastpath
// 2. Runtime1::monitorenter increase count after locking
#ifndef _LP64
Register thread = rsi;
__ push(thread);
__ get_thread(thread);
#else
Register thread = r15_thread;
#endif
__ inc_held_monitor_count(thread);
#ifndef _LP64
__ pop(thread);
#endif
}
__ bind(*op->stub()->continuation());
if (op->code() == lir_unlock) {
// unlock in slowpath is JRT_Leaf stub, no deoptimization can happen
#ifndef _LP64
Register thread = rsi;
__ push(thread);
__ get_thread(thread);
#else
Register thread = r15_thread;
#endif
__ dec_held_monitor_count(thread);
#ifndef _LP64
__ pop(thread);
#endif
}
}
void LIR_Assembler::emit_load_klass(LIR_OpLoadKlass* op) {
@ -3868,6 +3903,7 @@ void LIR_Assembler::rt_call(LIR_Opr result, address dest, const LIR_OprList* arg
if (info != NULL) {
add_call_info_here(info);
}
__ post_call_nop();
}

View File

@ -336,6 +336,17 @@ void LIRGenerator::do_MonitorExit(MonitorExit* x) {
monitor_exit(obj_temp, lock, syncTempOpr(), LIR_OprFact::illegalOpr, x->monitor_no());
}
void LIRGenerator::do_continuation_doYield(Intrinsic* x) {
BasicTypeList signature(0);
CallingConvention* cc = frame_map()->java_calling_convention(&signature, true);
const LIR_Opr result_reg = result_register_for(x->type());
address entry = StubRoutines::cont_doYield();
LIR_Opr result = rlock_result(x);
CodeEmitInfo* info = state_for(x, x->state());
__ call_runtime(entry, LIR_OprFact::illegalOpr, result_reg, cc->args(), info);
__ move(result_reg, result);
}
// _ineg, _lneg, _fneg, _dneg
void LIRGenerator::do_NegateOp(NegateOp* x) {
@ -362,7 +373,6 @@ void LIRGenerator::do_NegateOp(NegateOp* x) {
set_result(x, round_item(reg));
}
// for _fadd, _fmul, _fsub, _fdiv, _frem
// _dadd, _dmul, _dsub, _ddiv, _drem
void LIRGenerator::do_ArithmeticOp_FPU(ArithmeticOp* x) {

View File

@ -0,0 +1,50 @@
/*
* Copyright (c) 2022, 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.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#ifndef CPU_X86_CONTINUATIONENTRY_X86_INLINE_HPP
#define CPU_X86_CONTINUATIONENTRY_X86_INLINE_HPP
#include "runtime/continuationEntry.hpp"
#include "runtime/frame.inline.hpp"
#include "runtime/registerMap.hpp"
#include "utilities/macros.hpp"
inline frame ContinuationEntry::to_frame() const {
static CodeBlob* cb = CodeCache::find_blob_fast(entry_pc());
assert(cb != nullptr, "");
assert(cb->as_compiled_method()->method()->is_continuation_enter_intrinsic(), "");
return frame(entry_sp(), entry_sp(), entry_fp(), entry_pc(), cb);
}
inline intptr_t* ContinuationEntry::entry_fp() const {
return (intptr_t*)((address)this + size());
}
inline void ContinuationEntry::update_register_map(RegisterMap* map) const {
intptr_t** fp = (intptr_t**)(bottom_sender_sp() - frame::sender_sp_offset);
frame::update_map_with_saved_link(map, fp);
}
#endif // CPU_X86_CONTINUATIONENTRY_X86_INLINE_HPP

View File

@ -0,0 +1,289 @@
/*
* Copyright (c) 2019, 2022, 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.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#ifndef CPU_X86_CONTINUATIONFREEZETHAW_X86_INLINE_HPP
#define CPU_X86_CONTINUATIONFREEZETHAW_X86_INLINE_HPP
#include "code/codeBlob.inline.hpp"
#include "oops/stackChunkOop.inline.hpp"
#include "runtime/frame.hpp"
#include "runtime/frame.inline.hpp"
inline void patch_callee_link(const frame& f, intptr_t* fp) {
*ContinuationHelper::Frame::callee_link_address(f) = fp;
}
inline void patch_callee_link_relative(const frame& f, intptr_t* fp) {
intptr_t* la = (intptr_t*)ContinuationHelper::Frame::callee_link_address(f);
intptr_t new_value = fp - la;
*la = new_value;
}
////// Freeze
// Fast path
inline void FreezeBase::patch_stack_pd(intptr_t* frame_sp, intptr_t* heap_sp) {
// copy the spilled rbp from the heap to the stack
*(frame_sp - frame::sender_sp_offset) = *(heap_sp - frame::sender_sp_offset);
}
// Slow path
template<typename FKind>
inline frame FreezeBase::sender(const frame& f) {
assert(FKind::is_instance(f), "");
if (FKind::interpreted) {
return frame(f.sender_sp(), f.interpreter_frame_sender_sp(), f.link(), f.sender_pc());
}
intptr_t** link_addr = link_address<FKind>(f);
intptr_t* sender_sp = (intptr_t*)(link_addr + frame::sender_sp_offset); // f.unextended_sp() + (fsize/wordSize); //
address sender_pc = (address) *(sender_sp-1);
assert(sender_sp != f.sp(), "must have changed");
int slot = 0;
CodeBlob* sender_cb = CodeCache::find_blob_and_oopmap(sender_pc, slot);
return sender_cb != nullptr
? frame(sender_sp, sender_sp, *link_addr, sender_pc, sender_cb,
slot == -1 ? nullptr : sender_cb->oop_map_for_slot(slot, sender_pc), false)
: frame(sender_sp, sender_sp, *link_addr, sender_pc);
}
template<typename FKind>
frame FreezeBase::new_heap_frame(frame& f, frame& caller) {
assert(FKind::is_instance(f), "");
assert(!caller.is_interpreted_frame()
|| caller.unextended_sp() == (intptr_t*)caller.at(frame::interpreter_frame_last_sp_offset), "");
intptr_t *sp, *fp; // sp is really our unextended_sp
if (FKind::interpreted) {
assert((intptr_t*)f.at(frame::interpreter_frame_last_sp_offset) == nullptr
|| f.unextended_sp() == (intptr_t*)f.at(frame::interpreter_frame_last_sp_offset), "");
int locals = f.interpreter_frame_method()->max_locals();
// If the caller.is_empty(), i.e. we're freezing into an empty chunk, then we set
// the chunk's argsize in finalize_freeze and make room for it above the unextended_sp
bool overlap_caller = caller.is_interpreted_frame() || caller.is_empty();
fp = caller.unextended_sp() - (locals + frame::sender_sp_offset) + (overlap_caller ? ContinuationHelper::InterpretedFrame::stack_argsize(f) : 0);
sp = fp - (f.fp() - f.unextended_sp());
assert(sp <= fp, "");
assert(fp <= caller.unextended_sp(), "");
caller.set_sp(fp + frame::sender_sp_offset);
assert(_cont.tail()->is_in_chunk(sp), "");
frame hf(sp, sp, fp, f.pc(), nullptr, nullptr, true /* on_heap */);
*hf.addr_at(frame::interpreter_frame_locals_offset) = frame::sender_sp_offset + locals - 1;
return hf;
} else {
// We need to re-read fp out of the frame because it may be an oop and we might have
// had a safepoint in finalize_freeze, after constructing f.
fp = *(intptr_t**)(f.sp() - frame::sender_sp_offset);
int fsize = FKind::size(f);
sp = caller.unextended_sp() - fsize;
if (caller.is_interpreted_frame()) {
// If the caller is interpreted, our stackargs are not supposed to overlap with it
// so we make more room by moving sp down by argsize
int argsize = FKind::stack_argsize(f);
sp -= argsize;
}
caller.set_sp(sp + fsize);
assert(_cont.tail()->is_in_chunk(sp), "");
return frame(sp, sp, fp, f.pc(), nullptr, nullptr, true /* on_heap */);
}
}
void FreezeBase::adjust_interpreted_frame_unextended_sp(frame& f) {
assert((f.at(frame::interpreter_frame_last_sp_offset) != 0) || (f.unextended_sp() == f.sp()), "");
intptr_t* real_unextended_sp = (intptr_t*)f.at(frame::interpreter_frame_last_sp_offset);
if (real_unextended_sp != nullptr) {
f.set_unextended_sp(real_unextended_sp); // can be null at a safepoint
}
}
static inline void relativize_one(intptr_t* const vfp, intptr_t* const hfp, int offset) {
assert(*(hfp + offset) == *(vfp + offset), "");
intptr_t* addr = hfp + offset;
intptr_t value = *(intptr_t**)addr - vfp;
*addr = value;
}
inline void FreezeBase::relativize_interpreted_frame_metadata(const frame& f, const frame& hf) {
intptr_t* vfp = f.fp();
intptr_t* hfp = hf.fp();
assert(hfp == hf.unextended_sp() + (f.fp() - f.unextended_sp()), "");
assert((f.at(frame::interpreter_frame_last_sp_offset) != 0)
|| (f.unextended_sp() == f.sp()), "");
assert(f.fp() > (intptr_t*)f.at(frame::interpreter_frame_initial_sp_offset), "");
// We compute the locals as below rather than relativize the value in the frame because then we can use the same
// code on AArch64, which has an added complication (see this method in continuation_aarch64.inline.hpp)
// at(frame::interpreter_frame_last_sp_offset) can be NULL at safepoint preempts
*hf.addr_at(frame::interpreter_frame_last_sp_offset) = hf.unextended_sp() - hf.fp();
*hf.addr_at(frame::interpreter_frame_locals_offset) = frame::sender_sp_offset + f.interpreter_frame_method()->max_locals() - 1;
relativize_one(vfp, hfp, frame::interpreter_frame_initial_sp_offset); // == block_top == block_bottom
assert((hf.fp() - hf.unextended_sp()) == (f.fp() - f.unextended_sp()), "");
assert(hf.unextended_sp() == (intptr_t*)hf.at(frame::interpreter_frame_last_sp_offset), "");
assert(hf.unextended_sp() <= (intptr_t*)hf.at(frame::interpreter_frame_initial_sp_offset), "");
assert(hf.fp() > (intptr_t*)hf.at(frame::interpreter_frame_initial_sp_offset), "");
assert(hf.fp() <= (intptr_t*)hf.at(frame::interpreter_frame_locals_offset), "");
}
inline void FreezeBase::set_top_frame_metadata_pd(const frame& hf) {
stackChunkOop chunk = _cont.tail();
assert(chunk->is_in_chunk(hf.sp() - 1), "");
assert(chunk->is_in_chunk(hf.sp() - frame::sender_sp_offset), "");
address frame_pc = hf.pc();
*(hf.sp() - 1) = (intptr_t)hf.pc();
intptr_t* fp_addr = hf.sp() - frame::sender_sp_offset;
*fp_addr = hf.is_interpreted_frame() ? (intptr_t)(hf.fp() - fp_addr)
: (intptr_t)hf.fp();
assert(frame_pc == ContinuationHelper::Frame::real_pc(hf), "");
}
inline void FreezeBase::patch_pd(frame& hf, const frame& caller) {
if (caller.is_interpreted_frame()) {
assert(!caller.is_empty(), "");
patch_callee_link_relative(caller, caller.fp());
} else {
// If we're the bottom-most frame frozen in this freeze, the caller might have stayed frozen in the chunk,
// and its oop-containing fp fixed. We've now just overwritten it, so we must patch it back to its value
// as read from the chunk.
patch_callee_link(caller, caller.fp());
}
}
//////// Thaw
// Fast path
inline void ThawBase::prefetch_chunk_pd(void* start, int size) {
size <<= LogBytesPerWord;
Prefetch::read(start, size);
Prefetch::read(start, size - 64);
}
void ThawBase::patch_chunk_pd(intptr_t* sp) {
intptr_t* fp = _cont.entryFP();
*(intptr_t**)(sp - frame::sender_sp_offset) = fp;
}
// Slow path
inline frame ThawBase::new_entry_frame() {
intptr_t* sp = _cont.entrySP();
return frame(sp, sp, _cont.entryFP(), _cont.entryPC()); // TODO PERF: This finds code blob and computes deopt state
}
template<typename FKind> frame ThawBase::new_stack_frame(const frame& hf, frame& caller, bool bottom) {
assert(FKind::is_instance(hf), "");
// The values in the returned frame object will be written into the callee's stack in patch.
if (FKind::interpreted) {
intptr_t* heap_sp = hf.unextended_sp();
const int fsize = ContinuationHelper::InterpretedFrame::frame_bottom(hf) - hf.unextended_sp();
const int locals = hf.interpreter_frame_method()->max_locals();
intptr_t* frame_sp = caller.unextended_sp() - fsize;
intptr_t* fp = frame_sp + (hf.fp() - heap_sp);
DEBUG_ONLY(intptr_t* unextended_sp = fp + *hf.addr_at(frame::interpreter_frame_last_sp_offset);)
assert(frame_sp == unextended_sp, "");
caller.set_sp(fp + frame::sender_sp_offset);
frame f(frame_sp, frame_sp, fp, hf.pc());
// it's set again later in set_interpreter_frame_bottom, but we need to set the locals now so that
// we could call ContinuationHelper::InterpretedFrame::frame_bottom
intptr_t offset = *hf.addr_at(frame::interpreter_frame_locals_offset);
assert((int)offset == frame::sender_sp_offset + locals - 1, "");
// derelativize locals
*(intptr_t**)f.addr_at(frame::interpreter_frame_locals_offset) = fp + offset;
return f;
} else {
int fsize = FKind::size(hf);
intptr_t* frame_sp = caller.unextended_sp() - fsize;
if (bottom || caller.is_interpreted_frame()) {
int argsize = hf.compiled_frame_stack_argsize();
fsize += argsize;
frame_sp -= argsize;
caller.set_sp(caller.sp() - argsize);
assert(caller.sp() == frame_sp + (fsize-argsize), "");
frame_sp = align(hf, frame_sp, caller, bottom);
}
assert(hf.cb() != nullptr, "");
assert(hf.oop_map() != nullptr, "");
intptr_t* fp;
if (PreserveFramePointer) {
// we need to recreate a "real" frame pointer, pointing into the stack
fp = frame_sp + FKind::size(hf) - frame::sender_sp_offset;
} else {
// we need to re-read fp because it may be an oop and we might have fixed the frame.
fp = *(intptr_t**)(hf.sp() - frame::sender_sp_offset);
}
return frame(frame_sp, frame_sp, fp, hf.pc(), hf.cb(), hf.oop_map(), false); // TODO PERF : this computes deopt state; is it necessary?
}
}
inline intptr_t* ThawBase::align(const frame& hf, intptr_t* frame_sp, frame& caller, bool bottom) {
#ifdef _LP64
if (((intptr_t)frame_sp & 0xf) != 0) {
assert(caller.is_interpreted_frame() || (bottom && hf.compiled_frame_stack_argsize() % 2 != 0), "");
frame_sp--;
caller.set_sp(caller.sp() - 1);
}
assert(is_aligned(frame_sp, frame::frame_alignment), "");
#endif
return frame_sp;
}
inline void ThawBase::patch_pd(frame& f, const frame& caller) {
patch_callee_link(caller, caller.fp());
}
static inline void derelativize_one(intptr_t* const fp, int offset) {
intptr_t* addr = fp + offset;
*addr = (intptr_t)(fp + *addr);
}
inline void ThawBase::derelativize_interpreted_frame_metadata(const frame& hf, const frame& f) {
intptr_t* vfp = f.fp();
derelativize_one(vfp, frame::interpreter_frame_last_sp_offset);
derelativize_one(vfp, frame::interpreter_frame_initial_sp_offset);
}
inline void ThawBase::set_interpreter_frame_bottom(const frame& f, intptr_t* bottom) {
*(intptr_t**)f.addr_at(frame::interpreter_frame_locals_offset) = bottom - 1;
}
#endif // CPU_X86_CONTINUATIONFREEZE_THAW_X86_INLINE_HPP

View File

@ -0,0 +1,139 @@
/*
* Copyright (c) 2022, 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.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#ifndef CPU_X86_CONTINUATIONHELPER_X86_INLINE_HPP
#define CPU_X86_CONTINUATIONHELPER_X86_INLINE_HPP
#include "runtime/continuationHelper.hpp"
#include "runtime/continuationEntry.inline.hpp"
#include "runtime/frame.inline.hpp"
#include "runtime/registerMap.hpp"
#include "utilities/macros.hpp"
template<typename FKind>
static inline intptr_t** link_address(const frame& f) {
assert(FKind::is_instance(f), "");
return FKind::interpreted
? (intptr_t**)(f.fp() + frame::link_offset)
: (intptr_t**)(f.unextended_sp() + f.cb()->frame_size() - frame::sender_sp_offset);
}
inline int ContinuationHelper::frame_align_words(int size) {
#ifdef _LP64
return size & 1;
#else
return 0;
#endif
}
inline intptr_t* ContinuationHelper::frame_align_pointer(intptr_t* sp) {
#ifdef _LP64
sp = align_down(sp, frame::frame_alignment);
#endif
return sp;
}
template<typename FKind>
inline void ContinuationHelper::update_register_map(const frame& f, RegisterMap* map) {
frame::update_map_with_saved_link(map, link_address<FKind>(f));
}
inline void ContinuationHelper::update_register_map_with_callee(const frame& f, RegisterMap* map) {
frame::update_map_with_saved_link(map, ContinuationHelper::Frame::callee_link_address(f));
}
inline void ContinuationHelper::push_pd(const frame& f) {
*(intptr_t**)(f.sp() - frame::sender_sp_offset) = f.fp();
}
inline void ContinuationHelper::set_anchor_to_entry_pd(JavaFrameAnchor* anchor, ContinuationEntry* entry) {
anchor->set_last_Java_fp(entry->entry_fp());
}
#ifdef ASSERT
inline void ContinuationHelper::set_anchor_pd(JavaFrameAnchor* anchor, intptr_t* sp) {
intptr_t* fp = *(intptr_t**)(sp - frame::sender_sp_offset);
anchor->set_last_Java_fp(fp);
}
inline bool ContinuationHelper::Frame::assert_frame_laid_out(frame f) {
intptr_t* sp = f.sp();
address pc = *(address*)(sp - frame::sender_sp_ret_address_offset());
intptr_t* fp = *(intptr_t**)(sp - frame::sender_sp_offset);
assert(f.raw_pc() == pc, "f.ra_pc: " INTPTR_FORMAT " actual: " INTPTR_FORMAT, p2i(f.raw_pc()), p2i(pc));
assert(f.fp() == fp, "f.fp: " INTPTR_FORMAT " actual: " INTPTR_FORMAT, p2i(f.fp()), p2i(fp));
return f.raw_pc() == pc && f.fp() == fp;
}
#endif
inline intptr_t** ContinuationHelper::Frame::callee_link_address(const frame& f) {
return (intptr_t**)(f.sp() - frame::sender_sp_offset);
}
inline address* ContinuationHelper::Frame::return_pc_address(const frame& f) {
return (address*)(f.real_fp() - 1);
}
inline address* ContinuationHelper::InterpretedFrame::return_pc_address(const frame& f) {
return (address*)(f.fp() + frame::return_addr_offset);
}
inline void ContinuationHelper::InterpretedFrame::patch_sender_sp(frame& f, intptr_t* sp) {
assert(f.is_interpreted_frame(), "");
intptr_t* la = f.addr_at(frame::interpreter_frame_sender_sp_offset);
*la = f.is_heap_frame() ? (intptr_t)(sp - f.fp()) : (intptr_t)sp;
}
inline address ContinuationHelper::Frame::real_pc(const frame& f) {
address* pc_addr = &(((address*) f.sp())[-1]);
return *pc_addr;
}
inline void ContinuationHelper::Frame::patch_pc(const frame& f, address pc) {
address* pc_addr = &(((address*) f.sp())[-1]);
*pc_addr = pc;
}
inline intptr_t* ContinuationHelper::InterpretedFrame::frame_top(const frame& f, InterpreterOopMap* mask) { // inclusive; this will be copied with the frame
// interpreter_frame_last_sp_offset, points to unextended_sp includes arguments in the frame
// interpreter_frame_initial_sp_offset excludes expression stack slots
int expression_stack_sz = expression_stack_size(f, mask);
intptr_t* res = *(intptr_t**)f.addr_at(frame::interpreter_frame_initial_sp_offset) - expression_stack_sz;
assert(res == (intptr_t*)f.interpreter_frame_monitor_end() - expression_stack_sz, "");
assert(res >= f.unextended_sp(),
"res: " INTPTR_FORMAT " initial_sp: " INTPTR_FORMAT " last_sp: " INTPTR_FORMAT " unextended_sp: " INTPTR_FORMAT " expression_stack_size: %d",
p2i(res), p2i(f.addr_at(frame::interpreter_frame_initial_sp_offset)), f.at(frame::interpreter_frame_last_sp_offset), p2i(f.unextended_sp()), expression_stack_sz);
return res;
}
inline intptr_t* ContinuationHelper::InterpretedFrame::frame_bottom(const frame& f) { // exclusive; this will not be copied with the frame
return (intptr_t*)f.at(frame::interpreter_frame_locals_offset) + 1; // exclusive, so we add 1 word
}
inline intptr_t* ContinuationHelper::InterpretedFrame::frame_top(const frame& f, int callee_argsize, bool callee_interpreted) {
return f.unextended_sp() + (callee_interpreted ? callee_argsize : 0);
}
#endif // CPU_X86_CONTINUATIONHELPER_X86_INLINE_HPP

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2022, 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
@ -31,6 +31,7 @@
#include "oops/method.hpp"
#include "oops/oop.inline.hpp"
#include "prims/methodHandles.hpp"
#include "runtime/continuation.hpp"
#include "runtime/frame.inline.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/javaCalls.hpp"
@ -54,6 +55,9 @@ void RegisterMap::check_location_valid() {
// Profiling/safepoint support
bool frame::safe_for_sender(JavaThread *thread) {
if (is_heap_frame()) {
return true;
}
address sp = (address)_sp;
address fp = (address)_fp;
address unextended_sp = (address)_unextended_sp;
@ -146,6 +150,12 @@ bool frame::safe_for_sender(JavaThread *thread) {
saved_fp = (intptr_t*) *(sender_sp - frame::sender_sp_offset);
}
if (Continuation::is_return_barrier_entry(sender_pc)) {
// If our sender_pc is the return barrier, then our "real" sender is the continuation entry
frame s = Continuation::continuation_bottom_sender(thread, *this, sender_sp);
sender_sp = s.sp();
sender_pc = s.pc();
}
// If the potential sender is the interpreter then we can do some more checking
if (Interpreter::contains(sender_pc)) {
@ -261,32 +271,39 @@ bool frame::safe_for_sender(JavaThread *thread) {
void frame::patch_pc(Thread* thread, address pc) {
assert(_cb == CodeCache::find_blob(pc), "unexpected pc");
address* pc_addr = &(((address*) sp())[-1]);
if (TracePcPatching) {
tty->print_cr("patch_pc at address " INTPTR_FORMAT " [" INTPTR_FORMAT " -> " INTPTR_FORMAT "]",
p2i(pc_addr), p2i(*pc_addr), p2i(pc));
}
// Either the return address is the original one or we are going to
// patch in the same address that's already there.
assert(_pc == *pc_addr || pc == *pc_addr, "must be");
assert(!Continuation::is_return_barrier_entry(*pc_addr), "return barrier");
assert(_pc == *pc_addr || pc == *pc_addr || *pc_addr == 0, "");
DEBUG_ONLY(address old_pc = _pc;)
*pc_addr = pc;
_pc = pc; // must be set before call to get_deopt_original_pc
address original_pc = CompiledMethod::get_deopt_original_pc(this);
if (original_pc != NULL) {
assert(original_pc == _pc, "expected original PC to be stored before patching");
assert(original_pc == old_pc, "expected original PC to be stored before patching");
_deopt_state = is_deoptimized;
// leave _pc as is
_pc = original_pc;
} else {
_deopt_state = not_deoptimized;
_pc = pc;
}
}
assert(!is_compiled_frame() || !_cb->as_compiled_method()->is_deopt_entry(_pc), "must be");
bool frame::is_interpreted_frame() const {
return Interpreter::contains(pc());
}
int frame::frame_size(RegisterMap* map) const {
frame sender = this->sender(map);
return sender.sp() - sp();
#ifdef ASSERT
{
frame f(this->sp(), this->unextended_sp(), this->fp(), pc);
assert(f.is_deoptimized_frame() == this->is_deoptimized_frame() && f.pc() == this->pc() && f.raw_pc() == this->raw_pc(),
"must be (f.is_deoptimized_frame(): %d this->is_deoptimized_frame(): %d "
"f.pc(): " INTPTR_FORMAT " this->pc(): " INTPTR_FORMAT " f.raw_pc(): " INTPTR_FORMAT " this->raw_pc(): " INTPTR_FORMAT ")",
f.is_deoptimized_frame(), this->is_deoptimized_frame(), p2i(f.pc()), p2i(this->pc()), p2i(f.raw_pc()), p2i(this->raw_pc()));
}
#endif
}
intptr_t* frame::entry_frame_argument_at(int offset) const {
@ -316,10 +333,10 @@ BasicObjectLock* frame::interpreter_frame_monitor_begin() const {
}
BasicObjectLock* frame::interpreter_frame_monitor_end() const {
BasicObjectLock* result = (BasicObjectLock*) *addr_at(interpreter_frame_monitor_block_top_offset);
BasicObjectLock* result = (BasicObjectLock*) at(interpreter_frame_monitor_block_top_offset);
// make sure the pointer points inside the frame
assert(sp() <= (intptr_t*) result, "monitor end should be above the stack pointer");
assert((intptr_t*) result < fp(), "monitor end should be strictly below the frame pointer");
assert((intptr_t*) result < fp(), "monitor end should be strictly below the frame pointer: result: " INTPTR_FORMAT " fp: " INTPTR_FORMAT, p2i(result), p2i(fp()));
return result;
}
@ -397,7 +414,7 @@ void frame::verify_deopt_original_pc(CompiledMethod* nm, intptr_t* unextended_sp
address original_pc = nm->get_original_pc(&fr);
assert(nm->insts_contains_inclusive(original_pc),
"original PC must be in the main code section of the the compiled method (or must be immediately following it)");
"original PC must be in the main code section of the the compiled method (or must be immediately following it) original_pc: " INTPTR_FORMAT " unextended_sp: " INTPTR_FORMAT " name: %s", p2i(original_pc), p2i(unextended_sp), nm->name());
}
#endif
@ -422,30 +439,6 @@ void frame::adjust_unextended_sp() {
}
#endif
//------------------------------------------------------------------------------
// frame::update_map_with_saved_link
void frame::update_map_with_saved_link(RegisterMap* map, intptr_t** link_addr) {
// The interpreter and compiler(s) always save EBP/RBP in a known
// location on entry. We must record where that location is
// so this if EBP/RBP was live on callout from c2 we can find
// the saved copy no matter what it called.
// Since the interpreter always saves EBP/RBP if we record where it is then
// we don't have to always save EBP/RBP on entry and exit to c2 compiled
// code, on entry will be enough.
map->set_location(rbp->as_VMReg(), (address) link_addr);
#ifdef AMD64
// this is weird "H" ought to be at a higher address however the
// oopMaps seems to have the "H" regs at the same address and the
// vanilla register.
// XXXX make this go away
if (true) {
map->set_location(rbp->as_VMReg()->next(), (address) link_addr);
}
#endif // AMD64
}
//------------------------------------------------------------------------------
// frame::sender_for_interpreter_frame
frame frame::sender_for_interpreter_frame(RegisterMap* map) const {
@ -455,6 +448,7 @@ frame frame::sender_for_interpreter_frame(RegisterMap* map) const {
// This is the sp before any possible extension (adapter/locals).
intptr_t* unextended_sp = interpreter_frame_sender_sp();
intptr_t* sender_fp = link();
#if COMPILER2_OR_JVMCI
if (map->update_map()) {
@ -462,75 +456,17 @@ frame frame::sender_for_interpreter_frame(RegisterMap* map) const {
}
#endif // COMPILER2_OR_JVMCI
return frame(sender_sp, unextended_sp, link(), sender_pc());
}
address sender_pc = this->sender_pc();
//------------------------------------------------------------------------------
// frame::sender_for_compiled_frame
frame frame::sender_for_compiled_frame(RegisterMap* map) const {
assert(map != NULL, "map must be set");
// frame owned by optimizing compiler
assert(_cb->frame_size() >= 0, "must have non-zero frame size");
intptr_t* sender_sp = unextended_sp() + _cb->frame_size();
intptr_t* unextended_sp = sender_sp;
// On Intel the return_address is always the word on the stack
address sender_pc = (address) *(sender_sp-1);
// This is the saved value of EBP which may or may not really be an FP.
// It is only an FP if the sender is an interpreter frame (or C1?).
intptr_t** saved_fp_addr = (intptr_t**) (sender_sp - frame::sender_sp_offset);
if (map->update_map()) {
// Tell GC to use argument oopmaps for some runtime stubs that need it.
// For C1, the runtime stub might not have oop maps, so set this flag
// outside of update_register_map.
map->set_include_argument_oops(_cb->caller_must_gc_arguments(map->thread()));
if (_cb->oop_maps() != NULL) {
OopMapSet::update_register_map(this, map);
if (Continuation::is_return_barrier_entry(sender_pc)) {
if (map->walk_cont()) { // about to walk into an h-stack
return Continuation::top_frame(*this, map);
} else {
return Continuation::continuation_bottom_sender(map->thread(), *this, sender_sp);
}
// Since the prolog does the save and restore of EBP there is no oopmap
// for it so we must fill in its location as if there was an oopmap entry
// since if our caller was compiled code there could be live jvm state in it.
update_map_with_saved_link(map, saved_fp_addr);
}
assert(sender_sp != sp(), "must have changed");
return frame(sender_sp, unextended_sp, *saved_fp_addr, sender_pc);
}
//------------------------------------------------------------------------------
// frame::sender_raw
frame frame::sender_raw(RegisterMap* map) const {
// Default is we done have to follow them. The sender_for_xxx will
// update it accordingly
map->set_include_argument_oops(false);
if (is_entry_frame()) return sender_for_entry_frame(map);
if (is_optimized_entry_frame()) return sender_for_optimized_entry_frame(map);
if (is_interpreted_frame()) return sender_for_interpreter_frame(map);
assert(_cb == CodeCache::find_blob(pc()),"Must be the same");
if (_cb != NULL) {
return sender_for_compiled_frame(map);
}
// Must be native-compiled frame, i.e. the marshaling code for native
// methods that exists in the core system.
return frame(sender_sp(), link(), sender_pc());
}
frame frame::sender(RegisterMap* map) const {
frame result = sender_raw(map);
if (map->process_frames()) {
StackWatermarkSet::on_iteration(map->thread(), result);
}
return result;
return frame(sender_sp, unextended_sp, sender_fp, sender_pc);
}
bool frame::is_interpreted_frame_valid(JavaThread* thread) const {
@ -651,7 +587,6 @@ BasicType frame::interpreter_frame_result(oop* oop_result, jvalue* value_result)
return type;
}
intptr_t* frame::interpreter_frame_tos_at(jint offset) const {
int index = (Interpreter::expr_offset_in_bytes(offset)/wordSize);
return &interpreter_frame_tos_address()[index];
@ -660,7 +595,7 @@ intptr_t* frame::interpreter_frame_tos_at(jint offset) const {
#ifndef PRODUCT
#define DESCRIBE_FP_OFFSET(name) \
values.describe(frame_no, fp() + frame::name##_offset, #name)
values.describe(frame_no, fp() + frame::name##_offset, #name, 1)
void frame::describe_pd(FrameValues& values, int frame_no) {
if (is_interpreted_frame()) {
@ -683,7 +618,16 @@ void frame::describe_pd(FrameValues& values, int frame_no) {
}
#endif // AMD64
}
intptr_t* ret_pc_loc = sp() - return_addr_offset;
address ret_pc = *(address*)ret_pc_loc;
if (Continuation::is_return_barrier_entry(ret_pc))
values.describe(frame_no, ret_pc_loc, "return address (return barrier)");
else
values.describe(frame_no, ret_pc_loc, err_msg("return address for #%d", frame_no));
values.describe(frame_no, sp() - sender_sp_offset, err_msg("saved fp for #%d", frame_no), 0);
}
#endif // !PRODUCT
intptr_t *frame::initial_deoptimization_info() {
@ -691,19 +635,6 @@ intptr_t *frame::initial_deoptimization_info() {
return fp();
}
intptr_t* frame::real_fp() const {
if (_cb != NULL) {
// use the frame size if valid
int size = _cb->frame_size();
if (size > 0) {
return unextended_sp() + size;
}
}
// else rely on fp()
assert(! is_compiled_frame(), "unknown compiled frame size");
return fp();
}
#ifndef PRODUCT
// This is a generic constructor which is only used by pns() in debug.cpp.
frame::frame(void* sp, void* fp, void* pc) {

Some files were not shown because too many files have changed in this diff Show More