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:
parent
5212535a27
commit
9583e3657e
@ -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
|
||||
#
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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) {
|
||||
|
||||
|
51
src/hotspot/cpu/aarch64/continuationEntry_aarch64.inline.hpp
Normal file
51
src/hotspot/cpu/aarch64/continuationEntry_aarch64.inline.hpp
Normal 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
|
@ -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
|
140
src/hotspot/cpu/aarch64/continuationHelper_aarch64.inline.hpp
Normal file
140
src/hotspot/cpu/aarch64/continuationHelper_aarch64.inline.hpp
Normal 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
|
@ -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) \
|
||||
|
@ -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; }
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
|
91
src/hotspot/cpu/aarch64/smallRegisterMap_aarch64.inline.hpp
Normal file
91
src/hotspot/cpu/aarch64/smallRegisterMap_aarch64.inline.hpp
Normal 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
|
149
src/hotspot/cpu/aarch64/stackChunkFrameStream_aarch64.inline.hpp
Normal file
149
src/hotspot/cpu/aarch64/stackChunkFrameStream_aarch64.inline.hpp
Normal 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
|
42
src/hotspot/cpu/aarch64/stackChunkOop_aarch64.inline.hpp
Normal file
42
src/hotspot/cpu/aarch64/stackChunkOop_aarch64.inline.hpp
Normal 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
|
@ -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 __
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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");
|
||||
}
|
||||
|
47
src/hotspot/cpu/arm/continuationEntry_arm.inline.hpp
Normal file
47
src/hotspot/cpu/arm/continuationEntry_arm.inline.hpp
Normal 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
|
98
src/hotspot/cpu/arm/continuationFreezeThaw_arm.inline.hpp
Normal file
98
src/hotspot/cpu/arm/continuationFreezeThaw_arm.inline.hpp
Normal 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
|
125
src/hotspot/cpu/arm/continuationHelper_arm.inline.hpp
Normal file
125
src/hotspot/cpu/arm/continuationHelper_arm.inline.hpp
Normal 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
|
@ -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];
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
87
src/hotspot/cpu/arm/smallRegisterMap_arm.inline.hpp
Normal file
87
src/hotspot/cpu/arm/smallRegisterMap_arm.inline.hpp
Normal 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
|
115
src/hotspot/cpu/arm/stackChunkFrameStream_arm.inline.hpp
Normal file
115
src/hotspot/cpu/arm/stackChunkFrameStream_arm.inline.hpp
Normal 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
|
36
src/hotspot/cpu/arm/stackChunkOop_arm.inline.hpp
Normal file
36
src/hotspot/cpu/arm/stackChunkOop_arm.inline.hpp
Normal 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
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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) {}
|
||||
|
@ -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");
|
||||
}
|
||||
|
46
src/hotspot/cpu/ppc/continuationEntry_ppc.inline.hpp
Normal file
46
src/hotspot/cpu/ppc/continuationEntry_ppc.inline.hpp
Normal 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
|
99
src/hotspot/cpu/ppc/continuationFreezeThaw_ppc.inline.hpp
Normal file
99
src/hotspot/cpu/ppc/continuationFreezeThaw_ppc.inline.hpp
Normal 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
|
124
src/hotspot/cpu/ppc/continuationHelper_ppc.inline.hpp
Normal file
124
src/hotspot/cpu/ppc/continuationHelper_ppc.inline.hpp
Normal 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
|
@ -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];
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
87
src/hotspot/cpu/ppc/smallRegisterMap_ppc.inline.hpp
Normal file
87
src/hotspot/cpu/ppc/smallRegisterMap_ppc.inline.hpp
Normal 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
|
115
src/hotspot/cpu/ppc/stackChunkFrameStream_ppc.inline.hpp
Normal file
115
src/hotspot/cpu/ppc/stackChunkFrameStream_ppc.inline.hpp
Normal 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
|
36
src/hotspot/cpu/ppc/stackChunkOop_ppc.inline.hpp
Normal file
36
src/hotspot/cpu/ppc/stackChunkOop_ppc.inline.hpp
Normal 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
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
46
src/hotspot/cpu/riscv/continuationEntry_riscv.inline.hpp
Normal file
46
src/hotspot/cpu/riscv/continuationEntry_riscv.inline.hpp
Normal 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
|
@ -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
|
124
src/hotspot/cpu/riscv/continuationHelper_riscv.inline.hpp
Normal file
124
src/hotspot/cpu/riscv/continuationHelper_riscv.inline.hpp
Normal 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
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
87
src/hotspot/cpu/riscv/smallRegisterMap_riscv.inline.hpp
Normal file
87
src/hotspot/cpu/riscv/smallRegisterMap_riscv.inline.hpp
Normal 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
|
115
src/hotspot/cpu/riscv/stackChunkFrameStream_riscv.inline.hpp
Normal file
115
src/hotspot/cpu/riscv/stackChunkFrameStream_riscv.inline.hpp
Normal 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
|
36
src/hotspot/cpu/riscv/stackChunkOop_riscv.inline.hpp
Normal file
36
src/hotspot/cpu/riscv/stackChunkOop_riscv.inline.hpp
Normal 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
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
//------------------------------------------------------------------------------------------------------------------------
|
||||
//
|
||||
|
@ -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
|
||||
|
@ -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");
|
||||
}
|
||||
|
46
src/hotspot/cpu/s390/continuationEntry_s390.inline.hpp
Normal file
46
src/hotspot/cpu/s390/continuationEntry_s390.inline.hpp
Normal 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
|
98
src/hotspot/cpu/s390/continuationFreezeThaw_s390.inline.hpp
Normal file
98
src/hotspot/cpu/s390/continuationFreezeThaw_s390.inline.hpp
Normal 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
|
125
src/hotspot/cpu/s390/continuationHelper_s390.inline.hpp
Normal file
125
src/hotspot/cpu/s390/continuationHelper_s390.inline.hpp
Normal 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
|
@ -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];
|
||||
}
|
||||
|
||||
|
@ -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; }
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
87
src/hotspot/cpu/s390/smallRegisterMap_s390.inline.hpp
Normal file
87
src/hotspot/cpu/s390/smallRegisterMap_s390.inline.hpp
Normal 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
|
115
src/hotspot/cpu/s390/stackChunkFrameStream_s390.inline.hpp
Normal file
115
src/hotspot/cpu/s390/stackChunkFrameStream_s390.inline.hpp
Normal 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
|
36
src/hotspot/cpu/s390/stackChunkOop_s390.inline.hpp
Normal file
36
src/hotspot/cpu/s390/stackChunkOop_s390.inline.hpp
Normal 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
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
};
|
||||
};
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
||||
|
@ -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) {
|
||||
|
50
src/hotspot/cpu/x86/continuationEntry_x86.inline.hpp
Normal file
50
src/hotspot/cpu/x86/continuationEntry_x86.inline.hpp
Normal 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
|
289
src/hotspot/cpu/x86/continuationFreezeThaw_x86.inline.hpp
Normal file
289
src/hotspot/cpu/x86/continuationFreezeThaw_x86.inline.hpp
Normal 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
|
139
src/hotspot/cpu/x86/continuationHelper_x86.inline.hpp
Normal file
139
src/hotspot/cpu/x86/continuationHelper_x86.inline.hpp
Normal 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
|
@ -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
Loading…
Reference in New Issue
Block a user