From b0ecec2efa2aae3f22fcffeda946c67c96b69ffa Mon Sep 17 00:00:00 2001 From: Ludovic Henry Date: Thu, 3 Jun 2021 14:22:13 +0000 Subject: [PATCH 1/7] Extract sender frame parsing to CodeBlock::FrameParser Whether and how a frame is setup is controlled by the code generator for the specific CodeBlock. The CodeBlock is then in the best place to know how to parse the sender's frame from the current frame in the given CodeBlock. This refactoring proposes to extract this parsing out of `frame` and into a `CodeBlock::FrameParser`. This FrameParser is then specialized in the relevant inherited children of CodeBlock. This change is to largely facilitate adding new supported cases for JDK-8252417 like runtime stubs. --- src/hotspot/cpu/aarch64/codeBlob_aarch64.cpp | 80 ++++++++++++++++++ src/hotspot/cpu/aarch64/frame_aarch64.cpp | 75 ++++++----------- src/hotspot/cpu/arm/codeBlob_arm.cpp | 70 ++++++++++++++++ src/hotspot/cpu/arm/frame_arm.cpp | 51 +++++------- src/hotspot/cpu/ppc/codeBlob_ppc.cpp | 51 ++++++++++++ src/hotspot/cpu/ppc/frame_ppc.cpp | 32 ++++---- src/hotspot/cpu/ppc/frame_ppc.hpp | 8 -- src/hotspot/cpu/ppc/frame_ppc.inline.hpp | 3 - src/hotspot/cpu/s390/codeBlob_s390.cpp | 51 ++++++++++++ src/hotspot/cpu/s390/frame_s390.cpp | 24 ++++-- src/hotspot/cpu/x86/codeBlob_x86.cpp | 81 +++++++++++++++++++ src/hotspot/cpu/x86/frame_x86.cpp | 81 +++++++------------ src/hotspot/cpu/zero/codeBlob_zero.cpp | 42 ++++++++++ src/hotspot/cpu/zero/zeroInterpreter_zero.cpp | 8 +- src/hotspot/share/code/codeBlob.cpp | 27 +++++++ src/hotspot/share/code/codeBlob.hpp | 54 ++++++++++++- src/hotspot/share/code/icBuffer.cpp | 7 +- src/hotspot/share/code/stubs.cpp | 9 +-- src/hotspot/share/code/stubs.hpp | 3 +- .../share/interpreter/templateInterpreter.cpp | 9 ++- src/hotspot/share/runtime/frame.cpp | 2 + src/hotspot/share/runtime/vmStructs.cpp | 1 + .../sun/jvm/hotspot/code/CodeCache.java | 1 + .../sun/jvm/hotspot/code/InterpreterBlob.java | 44 ++++++++++ 24 files changed, 628 insertions(+), 186 deletions(-) create mode 100644 src/hotspot/cpu/aarch64/codeBlob_aarch64.cpp create mode 100644 src/hotspot/cpu/arm/codeBlob_arm.cpp create mode 100644 src/hotspot/cpu/ppc/codeBlob_ppc.cpp create mode 100644 src/hotspot/cpu/s390/codeBlob_s390.cpp create mode 100644 src/hotspot/cpu/x86/codeBlob_x86.cpp create mode 100644 src/hotspot/cpu/zero/codeBlob_zero.cpp create mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/InterpreterBlob.java diff --git a/src/hotspot/cpu/aarch64/codeBlob_aarch64.cpp b/src/hotspot/cpu/aarch64/codeBlob_aarch64.cpp new file mode 100644 index 0000000000000..2ac143a296d0a --- /dev/null +++ b/src/hotspot/cpu/aarch64/codeBlob_aarch64.cpp @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, Datadog, Inc. 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. + * + */ + +#include "precompiled.hpp" +#include "code/codeBlob.hpp" +#include "code/compiledMethod.hpp" +#include "interpreter/interpreter.hpp" +#include "runtime/frame.hpp" + +bool CodeBlob::FrameParser::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, + address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { + // must be some sort of compiled/runtime frame + // fp does not have to be safe (although it could be check for c1?) + + assert(sender_pc != NULL, "invariant"); + assert(sender_sp != NULL, "invariant"); + + // check for a valid frame_size, otherwise we are unlikely to get a valid sender_pc + if (check && _cb->frame_size() <= 0) { + return false; + } + + *sender_sp = unextended_sp + _cb->frame_size(); + // Is sender_sp safe? + if (check && thread != NULL && !thread->is_in_full_stack_checked((address)*sender_sp)) { + return false; + } + *sender_pc = (address)*((*sender_sp) - frame::return_addr_offset); + + if (sender_unextended_sp) *sender_unextended_sp = *sender_sp; + // Note: frame::sender_sp_offset is only valid for compiled frame + if (saved_fp) *saved_fp = (intptr_t**)((*sender_sp) - frame::sender_sp_offset); + + return true; +} + +bool InterpreterBlob::FrameParser::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, + address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { + + assert(sender_pc != NULL, "invariant"); + assert(sender_sp != NULL, "invariant"); + + // fp must be safe + if (check && !fp_safe) { + return false; + } + + *sender_pc = (address)*(fp + frame::return_addr_offset); + // for interpreted frames, the value below is the sender "raw" sp, + // which can be different from the sender unextended sp (the sp seen + // by the sender) because of current frame local variables + *sender_sp = fp + frame::sender_sp_offset; + + if (sender_unextended_sp) *sender_unextended_sp = (intptr_t*)*(fp + frame::interpreter_frame_sender_sp_offset); + if (saved_fp) *saved_fp = (intptr_t**)(fp + frame::link_offset); + + return true; +} diff --git a/src/hotspot/cpu/aarch64/frame_aarch64.cpp b/src/hotspot/cpu/aarch64/frame_aarch64.cpp index e025895e392b4..a4c15dfbb95ac 100644 --- a/src/hotspot/cpu/aarch64/frame_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/frame_aarch64.cpp @@ -56,6 +56,8 @@ void RegisterMap::check_location_valid() { // Profiling/safepoint support bool frame::safe_for_sender(JavaThread *thread) { + ResourceMark rm; + address sp = (address)_sp; address fp = (address)_fp; address unextended_sp = (address)_unextended_sp; @@ -117,46 +119,16 @@ bool frame::safe_for_sender(JavaThread *thread) { return fp_safe && is_entry_frame_valid(thread); } - intptr_t* sender_sp = NULL; - intptr_t* sender_unextended_sp = NULL; - address sender_pc = NULL; - intptr_t* saved_fp = NULL; - - if (is_interpreted_frame()) { - // fp must be safe - if (!fp_safe) { - return false; - } - - sender_pc = (address) this->fp()[return_addr_offset]; - // for interpreted frames, the value below is the sender "raw" sp, - // which can be different from the sender unextended sp (the sp seen - // by the sender) because of current frame local variables - sender_sp = (intptr_t*) addr_at(sender_sp_offset); - sender_unextended_sp = (intptr_t*) this->fp()[interpreter_frame_sender_sp_offset]; - saved_fp = (intptr_t*) this->fp()[link_offset]; - - } else { - // must be some sort of compiled/runtime frame - // fp does not have to be safe (although it could be check for c1?) - - // check for a valid frame_size, otherwise we are unlikely to get a valid sender_pc - if (_cb->frame_size() <= 0) { - return false; - } - - sender_sp = _unextended_sp + _cb->frame_size(); - // Is sender_sp safe? - if (!thread->is_in_full_stack_checked((address)sender_sp)) { - return false; - } - sender_unextended_sp = sender_sp; - sender_pc = (address) *(sender_sp-1); - // Note: frame::sender_sp_offset is only valid for compiled frame - saved_fp = (intptr_t*) *(sender_sp - frame::sender_sp_offset); + intptr_t* sender_sp = NULL; + intptr_t* sender_unextended_sp = NULL; + address sender_pc = NULL; + intptr_t** saved_fp = NULL; + if (!_cb->frame_parser()->sender_frame( + thread, true, _pc, (intptr_t*)sp, (intptr_t*)unextended_sp, (intptr_t*)fp, fp_safe, + &sender_pc, &sender_sp, &sender_unextended_sp, &saved_fp)) { + return false; } - // If the potential sender is the interpreter then we can do some more checking if (Interpreter::contains(sender_pc)) { @@ -164,13 +136,13 @@ bool frame::safe_for_sender(JavaThread *thread) { // only if the sender is interpreted/call_stub (c1 too?) are we certain that the saved fp // is really a frame pointer. - if (!thread->is_in_stack_range_excl((address)saved_fp, (address)sender_sp)) { + if (!thread->is_in_stack_range_excl((address)*saved_fp, (address)sender_sp)) { return false; } // construct the potential sender - frame sender(sender_sp, sender_unextended_sp, saved_fp, sender_pc); + frame sender(sender_sp, sender_unextended_sp, *saved_fp, sender_pc); return sender.is_interpreted_frame_valid(thread); @@ -199,13 +171,13 @@ bool frame::safe_for_sender(JavaThread *thread) { // Could be the call_stub if (StubRoutines::returns_to_call_stub(sender_pc)) { - if (!thread->is_in_stack_range_excl((address)saved_fp, (address)sender_sp)) { + if (!thread->is_in_stack_range_excl((address)*saved_fp, (address)sender_sp)) { return false; } // construct the potential sender - frame sender(sender_sp, sender_unextended_sp, saved_fp, sender_pc); + frame sender(sender_sp, sender_unextended_sp, *saved_fp, sender_pc); // Validate the JavaCallWrapper an entry frame must have address jcw = (address)sender.entry_frame_call_wrapper(); @@ -453,18 +425,21 @@ frame frame::sender_for_interpreter_frame(RegisterMap* map) const { //------------------------------------------------------------------------------ // frame::sender_for_compiled_frame frame frame::sender_for_compiled_frame(RegisterMap* map) const { + ResourceMark rm; + // 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-1); - intptr_t** saved_fp_addr = (intptr_t**) (l_sender_sp - frame::sender_sp_offset); + intptr_t* l_sender_sp; + intptr_t* l_unextended_sp; + address l_sender_pc; + intptr_t** l_saved_fp; + _cb->frame_parser()->sender_frame( + NULL, false, pc(), sp(), unextended_sp(), fp(), true, + &l_sender_pc, &l_sender_sp, &l_unextended_sp, &l_saved_fp); // assert (sender_sp() == l_sender_sp, "should be"); // assert (*saved_fp_addr == link(), "should be"); @@ -482,10 +457,10 @@ frame frame::sender_for_compiled_frame(RegisterMap* map) const { // 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); + update_map_with_saved_link(map, l_saved_fp); } - return frame(l_sender_sp, unextended_sp, *saved_fp_addr, sender_pc); + return frame(l_sender_sp, l_unextended_sp, *l_saved_fp, l_sender_pc); } //------------------------------------------------------------------------------ diff --git a/src/hotspot/cpu/arm/codeBlob_arm.cpp b/src/hotspot/cpu/arm/codeBlob_arm.cpp new file mode 100644 index 0000000000000..ca2f7764f4dff --- /dev/null +++ b/src/hotspot/cpu/arm/codeBlob_arm.cpp @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, Datadog, Inc. 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. + * + */ + +#include "precompiled.hpp" +#include "code/codeBlob.hpp" +#include "code/compiledMethod.hpp" +#include "interpreter/interpreter.hpp" +#include "runtime/frame.hpp" + +bool CodeBlob::FrameParser::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, + address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { + // must be some sort of compiled/runtime frame + // fp does not have to be safe (although it could be check for c1?) + + assert(sender_pc != NULL, "invariant"); + assert(sender_sp != NULL, "invariant"); + + *sender_sp = unextended_sp + _cb->frame_size(); + // Is sender_sp safe? + if (check && thread != NULL && !thread->is_in_full_stack_checked((address)*sender_sp)) { + return false; + } + // With our calling conventions, the return_address should + // end up being the word on the stack + *sender_pc = (address)*((*sender_sp) - frame::sender_sp_offset + frame::return_addr_offset); + + if (sender_unextended_sp) *sender_unextended_sp = *sender_sp; + if (saved_fp) *saved_fp = (intptr_t**)((*sender_sp) - frame::sender_sp_offset + frame::link_offset); + + return true; +} + +bool InterpreterBlob::FrameParser::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, + address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { + + assert(sender_pc != NULL, "invariant"); + assert(sender_sp != NULL, "invariant"); + + // fp must be safe + if (check && !fp_safe) { + return false; + } + + *sender_pc = (address)*(fp + frame::return_addr_offset); + *sender_sp = fp + frame::sender_sp_offset; + + return true; +} diff --git a/src/hotspot/cpu/arm/frame_arm.cpp b/src/hotspot/cpu/arm/frame_arm.cpp index 17841a8cf7152..a2fcefce8c0a6 100644 --- a/src/hotspot/cpu/arm/frame_arm.cpp +++ b/src/hotspot/cpu/arm/frame_arm.cpp @@ -54,6 +54,8 @@ void RegisterMap::check_location_valid() { // Profiling/safepoint support bool frame::safe_for_sender(JavaThread *thread) { + ResourceMark rm; + address sp = (address)_sp; address fp = (address)_fp; address unextended_sp = (address)_unextended_sp; @@ -98,28 +100,10 @@ bool frame::safe_for_sender(JavaThread *thread) { intptr_t* sender_sp = NULL; address sender_pc = NULL; - - if (is_interpreted_frame()) { - // fp must be safe - if (!fp_safe) { - return false; - } - - sender_pc = (address) this->fp()[return_addr_offset]; - sender_sp = (intptr_t*) addr_at(sender_sp_offset); - - } else { - // must be some sort of compiled/runtime frame - // fp does not have to be safe (although it could be check for c1?) - - sender_sp = _unextended_sp + _cb->frame_size(); - // Is sender_sp safe? - if (!thread->is_in_full_stack_checked((address)sender_sp)) { - return false; - } - // With our calling conventions, the return_address should - // end up being the word on the stack - sender_pc = (address) *(sender_sp - sender_sp_offset + return_addr_offset); + if (!_cb->frame_parser()->sender_frame( + thread, true, _pc, (intptr_t*)sp, (intptr_t*)unextended_sp, (intptr_t*)fp, fp_safe, + &sender_pc, &sender_sp, NULL, NULL)) { + return false; } // We must always be able to find a recognizable pc @@ -388,18 +372,21 @@ frame frame::sender_for_interpreter_frame(RegisterMap* map) const { } frame frame::sender_for_compiled_frame(RegisterMap* map) const { + ResourceMark rm; + 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); + assert(_cb->frame_size() >= 0, "must have non-zero frame size"); - // 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); + intptr_t* l_sender_sp; + intptr_t* l_unextended_sp; + address l_sender_pc; + intptr_t** l_saved_fp; + _cb->frame_parser()->sender_frame( + NULL, false, pc(), sp(), unextended_sp(), fp(), true, + &l_sender_pc, &l_sender_sp, &l_unextended_sp, &l_saved_fp); if (map->update_map()) { // Tell GC to use argument oopmaps for some runtime stubs that need it. @@ -413,11 +400,11 @@ frame frame::sender_for_compiled_frame(RegisterMap* map) const { // 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); + update_map_with_saved_link(map, l_saved_fp); } - assert(sender_sp != sp(), "must have changed"); - return frame(sender_sp, unextended_sp, *saved_fp_addr, sender_pc); + assert(l_sender_sp != sp(), "must have changed"); + return frame(l_sender_sp, l_unextended_sp, *l_saved_fp, l_sender_pc); } frame frame::sender(RegisterMap* map) const { diff --git a/src/hotspot/cpu/ppc/codeBlob_ppc.cpp b/src/hotspot/cpu/ppc/codeBlob_ppc.cpp new file mode 100644 index 0000000000000..c9f30a5bc1944 --- /dev/null +++ b/src/hotspot/cpu/ppc/codeBlob_ppc.cpp @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, Datadog, Inc. 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. + * + */ + +#include "precompiled.hpp" +#include "code/codeBlob.hpp" +#include "code/compiledMethod.hpp" +#include "interpreter/interpreter.hpp" +#include "runtime/frame.hpp" + +bool CodeBlob::FrameParser::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, + address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { + // must be some sort of compiled/runtime frame + // fp does not have to be safe (although it could be check for c1?) + + assert(sender_pc != NULL, "invariant"); + assert(sender_sp != NULL, "invariant"); + + frame::abi_minframe* sender_abi = (frame::abi_minframe*) fp; + *sender_sp = (intptr_t*) fp; + *sender_pc = (address) sender_abi->lr; + + return true; +} + +bool InterpreterBlob::FrameParser::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, + address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { + return CodeBlob::FrameParser::sender_frame(thread, check, pc, sp, unextended_sp, fp, fp_safe, + sender_pc, sender_sp, sender_unextended_sp, saved_fp); +} diff --git a/src/hotspot/cpu/ppc/frame_ppc.cpp b/src/hotspot/cpu/ppc/frame_ppc.cpp index 0f4e34dc9e74e..83fccf3f3c1de 100644 --- a/src/hotspot/cpu/ppc/frame_ppc.cpp +++ b/src/hotspot/cpu/ppc/frame_ppc.cpp @@ -52,6 +52,8 @@ void RegisterMap::check_location_valid() { #endif // ASSERT bool frame::safe_for_sender(JavaThread *thread) { + ResourceMark rm; + bool safe = false; address sp = (address)_sp; address fp = (address)_fp; @@ -107,9 +109,13 @@ bool frame::safe_for_sender(JavaThread *thread) { return false; } - abi_minframe* sender_abi = (abi_minframe*) fp; - intptr_t* sender_sp = (intptr_t*) fp; - address sender_pc = (address) sender_abi->lr;; + intptr_t* sender_sp = NULL; + address sender_pc = NULL; + if (!_cb->frame_parser()->sender_frame( + thread, true, _pc, (intptr_t*)sp, (intptr_t*)unextended_sp, (intptr_t*)fp, fp_safe, + &sender_pc, &sender_sp, NULL, NULL)) { + return false; + } // We must always be able to find a recognizable pc. CodeBlob* sender_blob = CodeCache::find_blob_unsafe(sender_pc); @@ -203,11 +209,17 @@ frame frame::sender_for_interpreter_frame(RegisterMap *map) const { } frame frame::sender_for_compiled_frame(RegisterMap *map) const { + ResourceMark rm; + 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); + + intptr_t* l_sender_sp; + address l_sender_pc; + _cb->frame_parser()->sender_frame( + NULL, false, pc(), sp(), unextended_sp(), fp(), true, + &l_sender_pc, &l_sender_sp, NULL, NULL); // Now adjust the map. @@ -220,15 +232,7 @@ frame frame::sender_for_compiled_frame(RegisterMap *map) const { } } - return caller; -} - -intptr_t* frame::compiled_sender_sp(CodeBlob* cb) const { - return sender_sp(); -} - -address* frame::compiled_sender_pc_addr(CodeBlob* cb) const { - return sender_pc_addr(); + return frame(l_sender_sp, l_sender_pc); } frame frame::sender_raw(RegisterMap* map) const { diff --git a/src/hotspot/cpu/ppc/frame_ppc.hpp b/src/hotspot/cpu/ppc/frame_ppc.hpp index ac717bd4734a9..c4668d13aac0c 100644 --- a/src/hotspot/cpu/ppc/frame_ppc.hpp +++ b/src/hotspot/cpu/ppc/frame_ppc.hpp @@ -384,14 +384,6 @@ inline frame(intptr_t* sp, address pc); inline frame(intptr_t* sp, address pc, intptr_t* unextended_sp); - private: - - intptr_t* compiled_sender_sp(CodeBlob* cb) const; - address* compiled_sender_pc_addr(CodeBlob* cb) const; - address* sender_pc_addr(void) const; - - public: - inline ijava_state* get_ijava_state() const; // Some convenient register frame setters/getters for deoptimization. inline intptr_t* interpreter_frame_esp() const; diff --git a/src/hotspot/cpu/ppc/frame_ppc.inline.hpp b/src/hotspot/cpu/ppc/frame_ppc.inline.hpp index 705b4abefdbd7..d8a17007965f4 100644 --- a/src/hotspot/cpu/ppc/frame_ppc.inline.hpp +++ b/src/hotspot/cpu/ppc/frame_ppc.inline.hpp @@ -103,9 +103,6 @@ inline intptr_t* frame::unextended_sp() const { inline address frame::sender_pc() const { return (address)callers_abi()->lr; } -inline address* frame::sender_pc_addr() const { - return (address*)&(callers_abi()->lr); -} // All frames have this field. inline intptr_t* frame::sender_sp() const { diff --git a/src/hotspot/cpu/s390/codeBlob_s390.cpp b/src/hotspot/cpu/s390/codeBlob_s390.cpp new file mode 100644 index 0000000000000..e4ac4029e1fe0 --- /dev/null +++ b/src/hotspot/cpu/s390/codeBlob_s390.cpp @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, Datadog, Inc. 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. + * + */ + +#include "precompiled.hpp" +#include "code/codeBlob.hpp" +#include "code/compiledMethod.hpp" +#include "interpreter/interpreter.hpp" +#include "runtime/frame.hpp" + +bool CodeBlob::FrameParser::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, + address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { + // must be some sort of compiled/runtime frame + // fp does not have to be safe (although it could be check for c1?) + + assert(sender_pc != NULL, "invariant"); + assert(sender_sp != NULL, "invariant"); + + frame::z_abi_160* sender_abi = (frame::z_abi_160*) fp; + *sender_sp = (intptr_t*) sender_abi->callers_sp; + *sender_pc = (address) sender_abi->return_pc; + + return true; +} + +bool InterpreterBlob::FrameParser::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, + address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { + return CodeBlob::FrameParser::sender_frame(thread, check, pc, sp, unextended_sp, fp, fp_safe, + sender_pc, sender_sp, sender_unextended_sp, saved_fp); +} diff --git a/src/hotspot/cpu/s390/frame_s390.cpp b/src/hotspot/cpu/s390/frame_s390.cpp index 2c1155e6de561..74515ddf9aa7f 100644 --- a/src/hotspot/cpu/s390/frame_s390.cpp +++ b/src/hotspot/cpu/s390/frame_s390.cpp @@ -55,6 +55,8 @@ void RegisterMap::check_location_valid() { // Profiling/safepoint support bool frame::safe_for_sender(JavaThread *thread) { + ResourceMark rm; + bool safe = false; address sp = (address)_sp; address fp = (address)_fp; @@ -110,9 +112,13 @@ bool frame::safe_for_sender(JavaThread *thread) { return false; } - z_abi_160* sender_abi = (z_abi_160*) fp; - intptr_t* sender_sp = (intptr_t*) sender_abi->callers_sp; - address sender_pc = (address) sender_abi->return_pc; + intptr_t* sender_sp = NULL; + address sender_pc = NULL; + if (!_cb->frame_parser()->sender_frame( + thread, true, _pc, (intptr_t*)sp, (intptr_t*)unextended_sp, (intptr_t*)fp, fp_safe, + &sender_pc, &sender_sp, NULL, NULL)) { + return false; + } // We must always be able to find a recognizable pc. CodeBlob* sender_blob = CodeCache::find_blob_unsafe(sender_pc); @@ -214,11 +220,17 @@ frame frame::sender_for_interpreter_frame(RegisterMap *map) const { } frame frame::sender_for_compiled_frame(RegisterMap *map) const { + ResourceMark rm; + 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); + intptr_t* l_sender_sp; + address l_sender_pc; + _cb->frame_parser()->sender_frame( + NULL, false, pc(), sp(), unextended_sp(), fp(), true, + &l_sender_pc, &l_sender_sp, NULL, NULL); // Now adjust the map. @@ -231,7 +243,7 @@ frame frame::sender_for_compiled_frame(RegisterMap *map) const { } } - return caller; + return frame(l_sender_sp, l_sender_pc); } intptr_t* frame::compiled_sender_sp(CodeBlob* cb) const { diff --git a/src/hotspot/cpu/x86/codeBlob_x86.cpp b/src/hotspot/cpu/x86/codeBlob_x86.cpp new file mode 100644 index 0000000000000..cc62d005fbe98 --- /dev/null +++ b/src/hotspot/cpu/x86/codeBlob_x86.cpp @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, Datadog, Inc. 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. + * + */ + +#include "precompiled.hpp" +#include "code/codeBlob.hpp" +#include "code/compiledMethod.hpp" +#include "interpreter/interpreter.hpp" +#include "runtime/frame.hpp" + +bool CodeBlob::FrameParser::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, + address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { + // must be some sort of compiled/runtime frame + // fp does not have to be safe (although it could be check for c1?) + + assert(sender_pc != NULL, "invariant"); + assert(sender_sp != NULL, "invariant"); + + // check for a valid frame_size, otherwise we are unlikely to get a valid sender_pc + if (check && _cb->frame_size() <= 0) { + return false; + } + + *sender_sp = unextended_sp + _cb->frame_size(); + // Is sender_sp safe? + if (check && thread != NULL && !thread->is_in_full_stack_checked((address)*sender_sp)) { + return false; + } + // On Intel the return_address is always the word on the stack + *sender_pc = (address)*((*sender_sp) - frame::return_addr_offset); + + if (sender_unextended_sp) *sender_unextended_sp = *sender_sp; + // Note: frame::sender_sp_offset is only valid for compiled frame + if (saved_fp) *saved_fp = (intptr_t**)((*sender_sp) - frame::sender_sp_offset); + + return true; +} + +bool InterpreterBlob::FrameParser::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, + address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { + + assert(sender_pc != NULL, "invariant"); + assert(sender_sp != NULL, "invariant"); + + // fp must be safe + if (check && !fp_safe) { + return false; + } + + *sender_pc = (address)*(fp + frame::return_addr_offset); + // for interpreted frames, the value below is the sender "raw" sp, + // which can be different from the sender unextended sp (the sp seen + // by the sender) because of current frame local variables + *sender_sp = fp + frame::sender_sp_offset; + + if (sender_unextended_sp) *sender_unextended_sp = (intptr_t*)*(fp + frame::interpreter_frame_sender_sp_offset); + if (saved_fp) *saved_fp = (intptr_t**)(fp + frame::link_offset); + + return true; +} diff --git a/src/hotspot/cpu/x86/frame_x86.cpp b/src/hotspot/cpu/x86/frame_x86.cpp index 7c9804974d302..1b223e5ff474c 100644 --- a/src/hotspot/cpu/x86/frame_x86.cpp +++ b/src/hotspot/cpu/x86/frame_x86.cpp @@ -54,6 +54,8 @@ void RegisterMap::check_location_valid() { // Profiling/safepoint support bool frame::safe_for_sender(JavaThread *thread) { + ResourceMark rm; + address sp = (address)_sp; address fp = (address)_fp; address unextended_sp = (address)_unextended_sp; @@ -106,47 +108,16 @@ bool frame::safe_for_sender(JavaThread *thread) { return fp_safe; } - intptr_t* sender_sp = NULL; - intptr_t* sender_unextended_sp = NULL; - address sender_pc = NULL; - intptr_t* saved_fp = NULL; - - if (is_interpreted_frame()) { - // fp must be safe - if (!fp_safe) { - return false; - } - - sender_pc = (address) this->fp()[return_addr_offset]; - // for interpreted frames, the value below is the sender "raw" sp, - // which can be different from the sender unextended sp (the sp seen - // by the sender) because of current frame local variables - sender_sp = (intptr_t*) addr_at(sender_sp_offset); - sender_unextended_sp = (intptr_t*) this->fp()[interpreter_frame_sender_sp_offset]; - saved_fp = (intptr_t*) this->fp()[link_offset]; - - } else { - // must be some sort of compiled/runtime frame - // fp does not have to be safe (although it could be check for c1?) - - // check for a valid frame_size, otherwise we are unlikely to get a valid sender_pc - if (_cb->frame_size() <= 0) { - return false; - } - - sender_sp = _unextended_sp + _cb->frame_size(); - // Is sender_sp safe? - if (!thread->is_in_full_stack_checked((address)sender_sp)) { - return false; - } - sender_unextended_sp = sender_sp; - // On Intel the return_address is always the word on the stack - sender_pc = (address) *(sender_sp-1); - // Note: frame::sender_sp_offset is only valid for compiled frame - saved_fp = (intptr_t*) *(sender_sp - frame::sender_sp_offset); + intptr_t* sender_sp = NULL; + intptr_t* sender_unextended_sp = NULL; + address sender_pc = NULL; + intptr_t** saved_fp = NULL; + if (!_cb->frame_parser()->sender_frame( + thread, true, _pc, (intptr_t*)sp, (intptr_t*)unextended_sp, (intptr_t*)fp, fp_safe, + &sender_pc, &sender_sp, &sender_unextended_sp, &saved_fp)) { + return false; } - // If the potential sender is the interpreter then we can do some more checking if (Interpreter::contains(sender_pc)) { @@ -154,13 +125,13 @@ bool frame::safe_for_sender(JavaThread *thread) { // only if the sender is interpreted/call_stub (c1 too?) are we certain that the saved ebp // is really a frame pointer. - if (!thread->is_in_stack_range_excl((address)saved_fp, (address)sender_sp)) { + if (!thread->is_in_stack_range_excl((address)*saved_fp, (address)sender_sp)) { return false; } // construct the potential sender - frame sender(sender_sp, sender_unextended_sp, saved_fp, sender_pc); + frame sender(sender_sp, sender_unextended_sp, *saved_fp, sender_pc); return sender.is_interpreted_frame_valid(thread); @@ -189,13 +160,13 @@ bool frame::safe_for_sender(JavaThread *thread) { // Could be the call_stub if (StubRoutines::returns_to_call_stub(sender_pc)) { - if (!thread->is_in_stack_range_excl((address)saved_fp, (address)sender_sp)) { + if (!thread->is_in_stack_range_excl((address)*saved_fp, (address)sender_sp)) { return false; } // construct the potential sender - frame sender(sender_sp, sender_unextended_sp, saved_fp, sender_pc); + frame sender(sender_sp, sender_unextended_sp, *saved_fp, sender_pc); // Validate the JavaCallWrapper an entry frame must have address jcw = (address)sender.entry_frame_call_wrapper(); @@ -467,19 +438,21 @@ frame frame::sender_for_interpreter_frame(RegisterMap* map) const { //------------------------------------------------------------------------------ // frame::sender_for_compiled_frame frame frame::sender_for_compiled_frame(RegisterMap* map) const { + ResourceMark rm; + 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); + assert(_cb->frame_size() >= 0, "must have non-zero frame size"); - // 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); + intptr_t* l_sender_sp = NULL; + intptr_t* l_unextended_sp = NULL; + address l_sender_pc = NULL; + intptr_t** l_saved_fp = NULL; + _cb->frame_parser()->sender_frame( + NULL, false, pc(), sp(), unextended_sp(), fp(), true, + &l_sender_pc, &l_sender_sp, &l_unextended_sp, &l_saved_fp); if (map->update_map()) { // Tell GC to use argument oopmaps for some runtime stubs that need it. @@ -493,11 +466,11 @@ frame frame::sender_for_compiled_frame(RegisterMap* map) const { // 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); + update_map_with_saved_link(map, l_saved_fp); } - assert(sender_sp != sp(), "must have changed"); - return frame(sender_sp, unextended_sp, *saved_fp_addr, sender_pc); + assert(l_sender_sp != sp(), "must have changed"); + return frame(l_sender_sp, l_unextended_sp, *l_saved_fp, l_sender_pc); } diff --git a/src/hotspot/cpu/zero/codeBlob_zero.cpp b/src/hotspot/cpu/zero/codeBlob_zero.cpp new file mode 100644 index 0000000000000..fa035db46ba7c --- /dev/null +++ b/src/hotspot/cpu/zero/codeBlob_zero.cpp @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, Datadog, Inc. 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. + * + */ + +#include "precompiled.hpp" +#include "code/codeBlob.hpp" +#include "code/compiledMethod.hpp" +#include "interpreter/interpreter.hpp" +#include "runtime/frame.hpp" + +bool CodeBlob::FrameParser::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, + address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { + ShouldNotCallThis(); + return false; +} + +bool InterpreterBlob::FrameParser::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, + address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { + return CodeBlob::FrameParser::sender_frame(thread, pc, sp, unextended_sp, fp, fp_safe, + sender_pc, sender_sp, sender_unextended_sp, saved_fp); +} diff --git a/src/hotspot/cpu/zero/zeroInterpreter_zero.cpp b/src/hotspot/cpu/zero/zeroInterpreter_zero.cpp index 14fc8c0b00c03..dc03c6c453896 100644 --- a/src/hotspot/cpu/zero/zeroInterpreter_zero.cpp +++ b/src/hotspot/cpu/zero/zeroInterpreter_zero.cpp @@ -53,10 +53,10 @@ void ZeroInterpreter::initialize_stub() { if (_code != NULL) return; // generate interpreter - int code_size = InterpreterCodeSize; - NOT_PRODUCT(code_size *= 4;) // debug uses extra interpreter code space - _code = new StubQueue(new InterpreterCodeletInterface, code_size, NULL, - "Interpreter"); + // debug uses extra interpreter code space + BufferBlob* blob = InterpreterBlob::create(InterpreterCodeSize NOT_PRODUCT( * 4)); + assert(blob != NULL, "invariant"); + _code = new StubQueue(new InterpreterCodeletInterface, blob, NULL); } void ZeroInterpreter::initialize_code() { diff --git a/src/hotspot/share/code/codeBlob.cpp b/src/hotspot/share/code/codeBlob.cpp index da225bc2b0f9d..35d43ade33863 100644 --- a/src/hotspot/share/code/codeBlob.cpp +++ b/src/hotspot/share/code/codeBlob.cpp @@ -307,6 +307,33 @@ AdapterBlob* AdapterBlob::create(CodeBuffer* cb) { return blob; } +//---------------------------------------------------------------------------------------------------- +// Implementation of InterpreterBlob + +InterpreterBlob* InterpreterBlob::create(int buffer_size) { + ThreadInVMfromUnknown __tiv; // get to VM state in case we block on CodeCache_lock + + InterpreterBlob* blob = NULL; + unsigned int size = sizeof(InterpreterBlob); + // align the size to CodeEntryAlignment + size = CodeBlob::align_code_offset(size); + size += align_up(buffer_size, 2 * oopSize); + { + MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); + blob = new (size) InterpreterBlob(size); + if (blob == NULL) { + vm_exit_out_of_memory(size, OOM_MALLOC_ERROR, "CodeCache: no room for Interpreter blob"); + } + } + // Track memory usage statistic after releasing CodeCache_lock + MemoryService::track_code_cache_memory_usage(); + + return blob; +} + +//---------------------------------------------------------------------------------------------------- +// Implementation of VtableBlob + void* VtableBlob::operator new(size_t s, unsigned size) throw() { // Handling of allocation failure stops compilation and prints a bunch of // stuff, which requires unlocking the CodeCache_lock, so that the Compile_lock diff --git a/src/hotspot/share/code/codeBlob.hpp b/src/hotspot/share/code/codeBlob.hpp index 61d3346338738..a44a64b3d18ab 100644 --- a/src/hotspot/share/code/codeBlob.hpp +++ b/src/hotspot/share/code/codeBlob.hpp @@ -59,6 +59,7 @@ struct CodeBlobType { // VtableBlob : Used for holding vtable chunks // MethodHandlesAdapterBlob : Used to hold MethodHandles adapters // OptimizedEntryBlob : Used for upcalls from native code +// InterpreterBlob : Used to hold Interpreter // RuntimeStub : Call to VM runtime methods // SingletonBlob : Super-class for all blobs that exist in only one instance // DeoptimizationBlob : Used for deoptimization @@ -138,6 +139,7 @@ class CodeBlob { virtual bool is_adapter_blob() const { return false; } virtual bool is_vtable_blob() const { return false; } virtual bool is_method_handles_adapter_blob() const { return false; } + virtual bool is_interpreter_blob() const { return false; } virtual bool is_compiled() const { return false; } virtual bool is_optimized_entry_blob() const { return false; } @@ -193,6 +195,18 @@ class CodeBlob { code_contains(addr) && addr >= code_begin() + _frame_complete_offset; } int frame_complete_offset() const { return _frame_complete_offset; } + // Profiling/safepoint support + class FrameParser: public ResourceObj { + protected: + const CodeBlob* _cb; + public: + FrameParser(const CodeBlob* cb) : _cb(cb) {} + virtual bool sender_frame(JavaThread *thread, bool check_frame_complete, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, + address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp); + }; + + virtual FrameParser* frame_parser() const { return new FrameParser(this); } + // CodeCache support: really only used by the nmethods, but in order to get // asserts and certain bookkeeping to work in the CodeCache they are defined // virtual here. @@ -336,7 +350,6 @@ class CodeBlobLayout : public StackObj { address content_end() const { return _content_end; } }; - class RuntimeBlob : public CodeBlob { friend class VMStructs; public: @@ -359,6 +372,12 @@ class RuntimeBlob : public CodeBlob { bool caller_must_gc_arguments = false ); + // Profiling/safepoint support + class FrameParser : public CodeBlob::FrameParser { + public: + FrameParser(const RuntimeBlob* cb) : CodeBlob::FrameParser(cb) {} + }; + // GC support virtual bool is_alive() const = 0; @@ -385,6 +404,7 @@ class BufferBlob: public RuntimeBlob { friend class VtableBlob; friend class MethodHandlesAdapterBlob; friend class OptimizedEntryBlob; + friend class InterpreterBlob; friend class WhiteBox; private: @@ -408,6 +428,12 @@ class BufferBlob: public RuntimeBlob { // Typing virtual bool is_buffer_blob() const { return true; } + // Profiling/safepoint support + class FrameParser : public RuntimeBlob::FrameParser { + public: + FrameParser(const BufferBlob* cb) : RuntimeBlob::FrameParser(cb) {} + }; + // GC/Verification support void preserve_callee_argument_oops(frame fr, const RegisterMap* reg_map, OopClosure* f) { /* nothing to do */ } bool is_alive() const { return true; } @@ -464,6 +490,32 @@ class MethodHandlesAdapterBlob: public BufferBlob { }; +//---------------------------------------------------------------------------------------------------- +// InterpreterBlob: used to hold Interpreter + +class InterpreterBlob: public BufferBlob { +private: + InterpreterBlob(int size) : BufferBlob("Interpreter", size) {} + +public: + // Creation + static InterpreterBlob* create(int buffer_size); + + // Typing + virtual bool is_interpreter_blob() const { return true; } + + // Profiling/safepoint support + class FrameParser : public BufferBlob::FrameParser { + public: + FrameParser(const InterpreterBlob* cb) : BufferBlob::FrameParser(cb) {} + virtual bool sender_frame(JavaThread *thread, bool check_frame_complete, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, + address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp); + }; + + virtual FrameParser* frame_parser() const { return new FrameParser(this); } +}; + + //---------------------------------------------------------------------------------------------------- // RuntimeStub: describes stubs used by compiled code to call a (static) C++ runtime routine diff --git a/src/hotspot/share/code/icBuffer.cpp b/src/hotspot/share/code/icBuffer.cpp index 1da48f0bd13bd..ea2caca30a8d0 100644 --- a/src/hotspot/share/code/icBuffer.cpp +++ b/src/hotspot/share/code/icBuffer.cpp @@ -140,7 +140,12 @@ void ICStub::print() { void InlineCacheBuffer::initialize() { if (_buffer != NULL) return; // already initialized - _buffer = new StubQueue(new ICStubInterface, 10*K, InlineCacheBuffer_lock, "InlineCacheBuffer"); + int code_size = align_up((int)(10*K), 2*BytesPerWord); + BufferBlob* blob = BufferBlob::create("InlineCacheBuffer", code_size); + if (blob == NULL) { + vm_exit_out_of_memory(code_size, OOM_MALLOC_ERROR, "CodeCache: no room for InlineCacheBuffer"); + } + _buffer = new StubQueue(new ICStubInterface, blob, InlineCacheBuffer_lock); assert (_buffer != NULL, "cannot allocate InlineCacheBuffer"); } diff --git a/src/hotspot/share/code/stubs.cpp b/src/hotspot/share/code/stubs.cpp index d022bf1971fc4..bf7b754381d26 100644 --- a/src/hotspot/share/code/stubs.cpp +++ b/src/hotspot/share/code/stubs.cpp @@ -64,13 +64,8 @@ // ITS CORRECTNESS! THIS CODE IS MORE SUBTLE THAN IT LOOKS! -StubQueue::StubQueue(StubInterface* stub_interface, int buffer_size, - Mutex* lock, const char* name) : _mutex(lock) { - intptr_t size = align_up(buffer_size, 2*BytesPerWord); - BufferBlob* blob = BufferBlob::create(name, size); - if( blob == NULL) { - vm_exit_out_of_memory(size, OOM_MALLOC_ERROR, "CodeCache: no room for %s", name); - } +StubQueue::StubQueue(StubInterface* stub_interface, BufferBlob* blob, + Mutex* lock) : _mutex(lock) { _stub_interface = stub_interface; _buffer_size = blob->content_size(); _buffer_limit = blob->content_size(); diff --git a/src/hotspot/share/code/stubs.hpp b/src/hotspot/share/code/stubs.hpp index 60ca20679cc60..e309b7f37a8bd 100644 --- a/src/hotspot/share/code/stubs.hpp +++ b/src/hotspot/share/code/stubs.hpp @@ -173,8 +173,7 @@ class StubQueue: public CHeapObj { void stub_print(Stub* s) { _stub_interface->print(s); } public: - StubQueue(StubInterface* stub_interface, int buffer_size, Mutex* lock, - const char* name); + StubQueue(StubInterface* stub_interface, BufferBlob* blob, Mutex* lock); ~StubQueue(); // General queue info diff --git a/src/hotspot/share/interpreter/templateInterpreter.cpp b/src/hotspot/share/interpreter/templateInterpreter.cpp index 732c12532f7f2..fae86fe87de2a 100644 --- a/src/hotspot/share/interpreter/templateInterpreter.cpp +++ b/src/hotspot/share/interpreter/templateInterpreter.cpp @@ -23,6 +23,7 @@ */ #include "precompiled.hpp" +#include "code/codeBlob.hpp" #include "interpreter/interpreter.hpp" #include "interpreter/interpreterRuntime.hpp" #include "interpreter/interp_masm.hpp" @@ -45,10 +46,10 @@ void TemplateInterpreter::initialize_stub() { "dispatch table too small"); // allocate interpreter - int code_size = InterpreterCodeSize; - NOT_PRODUCT(code_size *= 4;) // debug uses extra interpreter code space - _code = new StubQueue(new InterpreterCodeletInterface, code_size, NULL, - "Interpreter"); + // debug uses extra interpreter code space + BufferBlob* blob = InterpreterBlob::create(InterpreterCodeSize NOT_PRODUCT( * 4)); + assert(blob != NULL, "invariant"); + _code = new StubQueue(new InterpreterCodeletInterface, blob, NULL); } void TemplateInterpreter::initialize_code() { diff --git a/src/hotspot/share/runtime/frame.cpp b/src/hotspot/share/runtime/frame.cpp index 89dbc98b2212f..9fff58426e862 100644 --- a/src/hotspot/share/runtime/frame.cpp +++ b/src/hotspot/share/runtime/frame.cpp @@ -651,6 +651,8 @@ void frame::print_on_error(outputStream* st, char* buf, int buflen, bool verbose st->print("v ~AdapterBlob"); } else if (_cb->is_vtable_blob()) { st->print("v ~VtableBlob"); + } else if (_cb->is_interpreter_blob()) { + st->print("v ~InterpreterBlob"); } else if (_cb->is_method_handles_adapter_blob()) { st->print("v ~MethodHandlesAdapterBlob"); } else if (_cb->is_uncommon_trap_stub()) { diff --git a/src/hotspot/share/runtime/vmStructs.cpp b/src/hotspot/share/runtime/vmStructs.cpp index 265bbf1d29038..d3a24cc783d63 100644 --- a/src/hotspot/share/runtime/vmStructs.cpp +++ b/src/hotspot/share/runtime/vmStructs.cpp @@ -1400,6 +1400,7 @@ typedef HashtableEntry KlassHashtableEntry; declare_type(AdapterBlob, BufferBlob) \ declare_type(MethodHandlesAdapterBlob, BufferBlob) \ declare_type(VtableBlob, BufferBlob) \ + declare_type(InterpreterBlob, BufferBlob) \ declare_type(CompiledMethod, CodeBlob) \ declare_type(nmethod, CompiledMethod) \ declare_type(RuntimeStub, RuntimeBlob) \ diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/CodeCache.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/CodeCache.java index 1b95286395119..08c10a5adde12 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/CodeCache.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/CodeCache.java @@ -67,6 +67,7 @@ private static synchronized void initialize(TypeDataBase db) { virtualConstructor.addMapping("VtableBlob", VtableBlob.class); virtualConstructor.addMapping("SafepointBlob", SafepointBlob.class); virtualConstructor.addMapping("DeoptimizationBlob", DeoptimizationBlob.class); + virtualConstructor.addMapping("InterpreterBlob", InterpreterBlob.class); if (VM.getVM().isServerCompiler()) { virtualConstructor.addMapping("ExceptionBlob", ExceptionBlob.class); virtualConstructor.addMapping("UncommonTrapBlob", UncommonTrapBlob.class); diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/InterpreterBlob.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/InterpreterBlob.java new file mode 100644 index 0000000000000..ebba6bd830e53 --- /dev/null +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/InterpreterBlob.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, Datadog, Inc. 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. + * + */ + +package sun.jvm.hotspot.code; + +import sun.jvm.hotspot.debugger.Address; + +public class InterpreterBlob extends BufferBlob { + + public InterpreterBlob(Address addr) { + super(addr); + } + + public boolean isInterpreterBlob() { + return true; + } + + public String getName() { + return "InterpreterBlob: " + super.getName(); + } + +} From 28a090eaa858503b7beded6f94d4237b47062ec0 Mon Sep 17 00:00:00 2001 From: Ludovic Henry Date: Thu, 3 Jun 2021 14:10:38 +0000 Subject: [PATCH 2/7] Allow AsyncGetCallTrace and JFR to walk a stub frame When the signal sent for AsyncGetCallTrace or JFR would land on a stub (like arraycopy), it wouldn't be able to detect the sender (caller) frame because `_cb->frame_size() == 0`. Because we fully control how the prolog and epilog of stub code is generated, we know there are two cases: 1. A stack frame is allocated via macroAssembler->enter(), and consists in `push rbp; mov rsp, rbp;`. 2. No stack frames are allocated and rbp is left unchanged and rsp is decremented with the `call` instruction that push the return `pc` on the stack. For case 1., we can easily know the sender frame by simply looking at rbp, especially since we know that all stubs preserve the frame pointer (on x86 at least). For case 2., we end up returning the sender's sender, but that already gives us more information than what we have today. The results are as follows: - Baseline: Flat Profile (by method): (t 99.4,s 99.4) AGCT::Unknown Java[ERR=-5] (t 0.5,s 0.2) Prof1::main (t 0.2,s 0.2) java.lang.AbstractStringBuilder::append (t 0.1,s 0.1) AGCT::Unknown not Java[ERR=-3] (t 0.0,s 0.0) java.lang.AbstractStringBuilder::ensureCapacityInternal (t 0.0,s 0.0) java.lang.AbstractStringBuilder::shift (t 0.0,s 0.0) java.lang.String::getBytes (t 0.0,s 0.0) java.lang.AbstractStringBuilder::putStringAt (t 0.0,s 0.0) java.lang.StringBuilder::delete (t 0.2,s 0.0) java.lang.StringBuilder::append (t 0.0,s 0.0) java.lang.AbstractStringBuilder::delete (t 0.0,s 0.0) java.lang.AbstractStringBuilder::putStringAt - With StubRoutinesBlob::FrameParser Flat Profile (by method): (t 98.7,s 98.7) java.lang.AbstractStringBuilder::ensureCapacityInternal (t 0.9,s 0.9) java.lang.AbstractStringBuilder::delete (t 99.8,s 0.2) Prof1::main (t 0.1,s 0.1) AGCT::Unknown not Java[ERR=-3] (t 0.0,s 0.0) AGCT::Unknown Java[ERR=-5] (t 98.8,s 0.0) java.lang.AbstractStringBuilder::append (t 98.8,s 0.0) java.lang.StringBuilder::append (t 0.9,s 0.0) java.lang.StringBuilder::delete The program is as follows: ``` public class Prof1 { public static void main(String[] args) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < 1000000; i++) { sb.append("ab"); sb.delete(0, 1); } System.out.println(sb.length()); } } ``` We now account for the arraycopy stub which is called by AbstractStringBuilder::ensureCapacityInternal. It was previously ignored because it would not know how to parse the frame for the arraycopy stub and would fall in the AGCT::Unknown Java[ERR=-5] section. However, it still isn't perfect since it doesn't point to the arraycopy stub directly. --- src/hotspot/cpu/aarch64/codeBlob_aarch64.cpp | 26 +++++++++++ src/hotspot/cpu/aarch64/frame_aarch64.cpp | 11 ----- src/hotspot/cpu/arm/codeBlob_arm.cpp | 26 +++++++++++ src/hotspot/cpu/arm/frame_arm.cpp | 11 ----- src/hotspot/cpu/ppc/codeBlob_ppc.cpp | 26 +++++++++++ src/hotspot/cpu/ppc/frame_ppc.cpp | 11 ----- src/hotspot/cpu/s390/codeBlob_s390.cpp | 26 +++++++++++ src/hotspot/cpu/x86/codeBlob_x86.cpp | 37 ++++++++++++++++ src/hotspot/cpu/x86/frame_x86.cpp | 18 ++------ src/hotspot/cpu/zero/codeBlob_zero.cpp | 6 +++ src/hotspot/share/code/codeBlob.cpp | 25 +++++++++++ src/hotspot/share/code/codeBlob.hpp | 29 ++++++++++++ src/hotspot/share/runtime/frame.cpp | 2 + src/hotspot/share/runtime/stubRoutines.cpp | 12 ++--- src/hotspot/share/runtime/vmStructs.cpp | 1 + .../sun/jvm/hotspot/code/CodeCache.java | 1 + .../jvm/hotspot/code/StubRoutinesBlob.java | 44 +++++++++++++++++++ 17 files changed, 257 insertions(+), 55 deletions(-) create mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/StubRoutinesBlob.java diff --git a/src/hotspot/cpu/aarch64/codeBlob_aarch64.cpp b/src/hotspot/cpu/aarch64/codeBlob_aarch64.cpp index 2ac143a296d0a..d08bf7d6e8036 100644 --- a/src/hotspot/cpu/aarch64/codeBlob_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/codeBlob_aarch64.cpp @@ -37,6 +37,17 @@ bool CodeBlob::FrameParser::sender_frame(JavaThread *thread, bool check, address assert(sender_pc != NULL, "invariant"); assert(sender_sp != NULL, "invariant"); + // First check if frame is complete and tester is reliable + // Unfortunately we can only check frame complete for runtime stubs and nmethod + // other generic buffer blobs are more problematic so we just assume they are + // ok. adapter blobs never have a frame complete and are never ok. + + if (!_cb->is_frame_complete_at(pc)) { + if (_cb->is_compiled() || _cb->is_adapter_blob()) { + return false; + } + } + // check for a valid frame_size, otherwise we are unlikely to get a valid sender_pc if (check && _cb->frame_size() <= 0) { return false; @@ -78,3 +89,18 @@ bool InterpreterBlob::FrameParser::sender_frame(JavaThread *thread, bool check, return true; } + +bool StubRoutinesBlob::FrameParser::sender_frame(JavaThread *thread, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, + address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { + + assert(sender_pc != NULL, "invariant"); + assert(sender_sp != NULL, "invariant"); + + // First check if frame is complete and tester is reliable + if (!_cb->is_frame_complete_at(pc)) { + return false; + } + + return CodeBlob::FrameParser::sender_frame(thread, pc, sp, unextended_sp, fp, fp_safe, + sender_pc, sender_sp, sender_unextended_sp, saved_fp); +} diff --git a/src/hotspot/cpu/aarch64/frame_aarch64.cpp b/src/hotspot/cpu/aarch64/frame_aarch64.cpp index a4c15dfbb95ac..489459e23c885 100644 --- a/src/hotspot/cpu/aarch64/frame_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/frame_aarch64.cpp @@ -97,17 +97,6 @@ bool frame::safe_for_sender(JavaThread *thread) { if (_cb != NULL ) { - // First check if frame is complete and tester is reliable - // Unfortunately we can only check frame complete for runtime stubs and nmethod - // other generic buffer blobs are more problematic so we just assume they are - // ok. adapter blobs never have a frame complete and are never ok. - - if (!_cb->is_frame_complete_at(_pc)) { - if (_cb->is_nmethod() || _cb->is_adapter_blob() || _cb->is_runtime_stub()) { - return false; - } - } - // Could just be some random pointer within the codeBlob if (!_cb->code_contains(_pc)) { return false; diff --git a/src/hotspot/cpu/arm/codeBlob_arm.cpp b/src/hotspot/cpu/arm/codeBlob_arm.cpp index ca2f7764f4dff..6fbfeaf2d9052 100644 --- a/src/hotspot/cpu/arm/codeBlob_arm.cpp +++ b/src/hotspot/cpu/arm/codeBlob_arm.cpp @@ -37,6 +37,17 @@ bool CodeBlob::FrameParser::sender_frame(JavaThread *thread, bool check, address assert(sender_pc != NULL, "invariant"); assert(sender_sp != NULL, "invariant"); + // First check if frame is complete and tester is reliable + // Unfortunately we can only check frame complete for runtime stubs and nmethod + // other generic buffer blobs are more problematic so we just assume they are + // ok. adapter blobs never have a frame complete and are never ok. + + if (!_cb->is_frame_complete_at(pc)) { + if (_cb->is_compiled() || _cb->is_adapter_blob()) { + return false; + } + } + *sender_sp = unextended_sp + _cb->frame_size(); // Is sender_sp safe? if (check && thread != NULL && !thread->is_in_full_stack_checked((address)*sender_sp)) { @@ -68,3 +79,18 @@ bool InterpreterBlob::FrameParser::sender_frame(JavaThread *thread, bool check, return true; } + +bool StubRoutinesBlob::FrameParser::sender_frame(JavaThread *thread, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, + address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { + + assert(sender_pc != NULL, "invariant"); + assert(sender_sp != NULL, "invariant"); + + // First check if frame is complete and tester is reliable + if (!_cb->is_frame_complete_at(pc)) { + return false; + } + + return CodeBlob::FrameParser::sender_frame(thread, pc, sp, unextended_sp, fp, fp_safe, + sender_pc, sender_sp, sender_unextended_sp, saved_fp); +} diff --git a/src/hotspot/cpu/arm/frame_arm.cpp b/src/hotspot/cpu/arm/frame_arm.cpp index a2fcefce8c0a6..fd937c0d3506f 100644 --- a/src/hotspot/cpu/arm/frame_arm.cpp +++ b/src/hotspot/cpu/arm/frame_arm.cpp @@ -76,17 +76,6 @@ bool frame::safe_for_sender(JavaThread *thread) { if (_cb != NULL ) { - // First check if frame is complete and tester is reliable - // Unfortunately we can only check frame complete for runtime stubs and nmethod - // other generic buffer blobs are more problematic so we just assume they are - // ok. adapter blobs never have a frame complete and are never ok. - - if (!_cb->is_frame_complete_at(_pc)) { - if (_cb->is_compiled() || _cb->is_adapter_blob() || _cb->is_runtime_stub()) { - return false; - } - } - // Could just be some random pointer within the codeBlob if (!_cb->code_contains(_pc)) { return false; diff --git a/src/hotspot/cpu/ppc/codeBlob_ppc.cpp b/src/hotspot/cpu/ppc/codeBlob_ppc.cpp index c9f30a5bc1944..b5c5b9538031a 100644 --- a/src/hotspot/cpu/ppc/codeBlob_ppc.cpp +++ b/src/hotspot/cpu/ppc/codeBlob_ppc.cpp @@ -37,6 +37,17 @@ bool CodeBlob::FrameParser::sender_frame(JavaThread *thread, bool check, address assert(sender_pc != NULL, "invariant"); assert(sender_sp != NULL, "invariant"); + // First check if frame is complete and tester is reliable + // Unfortunately we can only check frame complete for runtime stubs and nmethod + // other generic buffer blobs are more problematic so we just assume they are + // ok. adapter blobs never have a frame complete and are never ok. + + if (!_cb->is_frame_complete_at(pc)) { + if (_cb->is_compiled() || _cb->is_adapter_blob()) { + return false; + } + } + frame::abi_minframe* sender_abi = (frame::abi_minframe*) fp; *sender_sp = (intptr_t*) fp; *sender_pc = (address) sender_abi->lr; @@ -49,3 +60,18 @@ bool InterpreterBlob::FrameParser::sender_frame(JavaThread *thread, bool check, return CodeBlob::FrameParser::sender_frame(thread, check, pc, sp, unextended_sp, fp, fp_safe, sender_pc, sender_sp, sender_unextended_sp, saved_fp); } + +bool StubRoutinesBlob::FrameParser::sender_frame(JavaThread *thread, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, + address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { + + assert(sender_pc != NULL, "invariant"); + assert(sender_sp != NULL, "invariant"); + + // First check if frame is complete and tester is reliable + if (!_cb->is_frame_complete_at(pc)) { + return false; + } + + return CodeBlob::FrameParser::sender_frame(thread, pc, sp, unextended_sp, fp, fp_safe, + sender_pc, sender_sp, sender_unextended_sp, saved_fp); +} diff --git a/src/hotspot/cpu/ppc/frame_ppc.cpp b/src/hotspot/cpu/ppc/frame_ppc.cpp index 83fccf3f3c1de..14a3b35ca939c 100644 --- a/src/hotspot/cpu/ppc/frame_ppc.cpp +++ b/src/hotspot/cpu/ppc/frame_ppc.cpp @@ -89,17 +89,6 @@ bool frame::safe_for_sender(JavaThread *thread) { return fp_safe && is_entry_frame_valid(thread); } - // Now check if the frame is complete and the test is - // reliable. Unfortunately we can only check frame completeness for - // runtime stubs and nmethods. Other generic buffer blobs are more - // problematic so we just assume they are OK. Adapter blobs never have a - // complete frame and are never OK - if (!_cb->is_frame_complete_at(_pc)) { - if (_cb->is_compiled() || _cb->is_adapter_blob() || _cb->is_runtime_stub()) { - return false; - } - } - // Could just be some random pointer within the codeBlob. if (!_cb->code_contains(_pc)) { return false; diff --git a/src/hotspot/cpu/s390/codeBlob_s390.cpp b/src/hotspot/cpu/s390/codeBlob_s390.cpp index e4ac4029e1fe0..8fa6ecedf4a8d 100644 --- a/src/hotspot/cpu/s390/codeBlob_s390.cpp +++ b/src/hotspot/cpu/s390/codeBlob_s390.cpp @@ -37,6 +37,17 @@ bool CodeBlob::FrameParser::sender_frame(JavaThread *thread, bool check, address assert(sender_pc != NULL, "invariant"); assert(sender_sp != NULL, "invariant"); + // First check if frame is complete and tester is reliable + // Unfortunately we can only check frame complete for runtime stubs and nmethod + // other generic buffer blobs are more problematic so we just assume they are + // ok. adapter blobs never have a frame complete and are never ok. + + if (!_cb->is_frame_complete_at(pc)) { + if (_cb->is_compiled() || _cb->is_adapter_blob()) { + return false; + } + } + frame::z_abi_160* sender_abi = (frame::z_abi_160*) fp; *sender_sp = (intptr_t*) sender_abi->callers_sp; *sender_pc = (address) sender_abi->return_pc; @@ -49,3 +60,18 @@ bool InterpreterBlob::FrameParser::sender_frame(JavaThread *thread, bool check, return CodeBlob::FrameParser::sender_frame(thread, check, pc, sp, unextended_sp, fp, fp_safe, sender_pc, sender_sp, sender_unextended_sp, saved_fp); } + +bool StubRoutinesBlob::FrameParser::sender_frame(JavaThread *thread, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, + address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { + + assert(sender_pc != NULL, "invariant"); + assert(sender_sp != NULL, "invariant"); + + // First check if frame is complete and tester is reliable + if (!_cb->is_frame_complete_at(pc)) { + return false; + } + + return CodeBlob::FrameParser::sender_frame(thread, pc, sp, unextended_sp, fp, fp_safe, + sender_pc, sender_sp, sender_unextended_sp, saved_fp); +} diff --git a/src/hotspot/cpu/x86/codeBlob_x86.cpp b/src/hotspot/cpu/x86/codeBlob_x86.cpp index cc62d005fbe98..a63da87342f73 100644 --- a/src/hotspot/cpu/x86/codeBlob_x86.cpp +++ b/src/hotspot/cpu/x86/codeBlob_x86.cpp @@ -37,6 +37,17 @@ bool CodeBlob::FrameParser::sender_frame(JavaThread *thread, bool check, address assert(sender_pc != NULL, "invariant"); assert(sender_sp != NULL, "invariant"); + // First check if frame is complete and tester is reliable + // Unfortunately we can only check frame complete for runtime stubs and nmethod + // other generic buffer blobs are more problematic so we just assume they are + // ok. adapter blobs never have a frame complete and are never ok. + + if (!_cb->is_frame_complete_at(pc)) { + if (_cb->is_compiled() || _cb->is_adapter_blob()) { + return false; + } + } + // check for a valid frame_size, otherwise we are unlikely to get a valid sender_pc if (check && _cb->frame_size() <= 0) { return false; @@ -79,3 +90,29 @@ bool InterpreterBlob::FrameParser::sender_frame(JavaThread *thread, bool check, return true; } + +bool StubRoutinesBlob::FrameParser::sender_frame(JavaThread *thread, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, + address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { + + assert(sender_pc != NULL, "invariant"); + assert(sender_sp != NULL, "invariant"); + + // fp must be safe + if (!fp_safe) { + return false; + } + + *sender_sp = fp + frame::sender_sp_offset; + // Is sender_sp safe? + if (thread != NULL && !thread->is_in_full_stack_checked((address)*sender_sp)) { + return false; + } + *sender_unextended_sp = *sender_sp; + + // On Intel the return_address is always the word on the stack + *sender_pc = (address)*(fp + frame::return_addr_offset); + // Note: frame::sender_sp_offset is only valid for compiled frame + *saved_fp = (intptr_t**)(fp + frame::link_offset); + + return true; +} diff --git a/src/hotspot/cpu/x86/frame_x86.cpp b/src/hotspot/cpu/x86/frame_x86.cpp index 1b223e5ff474c..2119db58c2500 100644 --- a/src/hotspot/cpu/x86/frame_x86.cpp +++ b/src/hotspot/cpu/x86/frame_x86.cpp @@ -71,9 +71,11 @@ bool frame::safe_for_sender(JavaThread *thread) { return false; } - // an fp must be within the stack and above (but not equal) sp + // an fp must be within the stack and above or equal to sp + // it may be equal when the stack frame size is 0 which is the case + // for some stubs for example. // second evaluation on fp+ is added to handle situation where fp is -1 - bool fp_safe = thread->is_in_stack_range_excl(fp, sp) && + bool fp_safe = thread->is_in_stack_range_incl(fp, sp) && thread->is_in_full_stack_checked(fp + (return_addr_offset * sizeof(void*))); // We know sp/unextended_sp are safe only fp is questionable here @@ -84,17 +86,6 @@ bool frame::safe_for_sender(JavaThread *thread) { if (_cb != NULL ) { - // First check if frame is complete and tester is reliable - // Unfortunately we can only check frame complete for runtime stubs and nmethod - // other generic buffer blobs are more problematic so we just assume they are - // ok. adapter blobs never have a frame complete and are never ok. - - if (!_cb->is_frame_complete_at(_pc)) { - if (_cb->is_compiled() || _cb->is_adapter_blob() || _cb->is_runtime_stub()) { - return false; - } - } - // Could just be some random pointer within the codeBlob if (!_cb->code_contains(_pc)) { return false; @@ -469,7 +460,6 @@ frame frame::sender_for_compiled_frame(RegisterMap* map) const { update_map_with_saved_link(map, l_saved_fp); } - assert(l_sender_sp != sp(), "must have changed"); return frame(l_sender_sp, l_unextended_sp, *l_saved_fp, l_sender_pc); } diff --git a/src/hotspot/cpu/zero/codeBlob_zero.cpp b/src/hotspot/cpu/zero/codeBlob_zero.cpp index fa035db46ba7c..e49a342555174 100644 --- a/src/hotspot/cpu/zero/codeBlob_zero.cpp +++ b/src/hotspot/cpu/zero/codeBlob_zero.cpp @@ -40,3 +40,9 @@ bool InterpreterBlob::FrameParser::sender_frame(JavaThread *thread, bool check, return CodeBlob::FrameParser::sender_frame(thread, pc, sp, unextended_sp, fp, fp_safe, sender_pc, sender_sp, sender_unextended_sp, saved_fp); } + +bool StubRoutinesBlob::FrameParser::sender_frame(JavaThread *thread, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, + address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { + return CodeBlob::FrameParser::sender_frame(thread, pc, sp, unextended_sp, fp, fp_safe, + sender_pc, sender_sp, sender_unextended_sp, saved_fp); +} diff --git a/src/hotspot/share/code/codeBlob.cpp b/src/hotspot/share/code/codeBlob.cpp index 35d43ade33863..6f12a63b5ab77 100644 --- a/src/hotspot/share/code/codeBlob.cpp +++ b/src/hotspot/share/code/codeBlob.cpp @@ -331,6 +331,31 @@ InterpreterBlob* InterpreterBlob::create(int buffer_size) { return blob; } +//---------------------------------------------------------------------------------------------------- +// Implementation of StubRoutinesBlob + +StubRoutinesBlob* StubRoutinesBlob::create(const char* name, int buffer_size) { + ThreadInVMfromUnknown __tiv; // get to VM state in case we block on CodeCache_lock + + StubRoutinesBlob* blob = NULL; + unsigned int size = sizeof(StubRoutinesBlob); + // align the size to CodeEntryAlignment + size = CodeBlob::align_code_offset(size); + size += align_up(buffer_size, oopSize); + assert(name != NULL, "must provide a name"); + { + MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); + blob = new (size) StubRoutinesBlob(name, size); + if (blob == NULL) { + vm_exit_out_of_memory(size, OOM_MALLOC_ERROR, "CodeCache: no room for %s", name); + } + } + // Track memory usage statistic after releasing CodeCache_lock + MemoryService::track_code_cache_memory_usage(); + + return blob; +} + //---------------------------------------------------------------------------------------------------- // Implementation of VtableBlob diff --git a/src/hotspot/share/code/codeBlob.hpp b/src/hotspot/share/code/codeBlob.hpp index a44a64b3d18ab..9363eb389970c 100644 --- a/src/hotspot/share/code/codeBlob.hpp +++ b/src/hotspot/share/code/codeBlob.hpp @@ -60,6 +60,7 @@ struct CodeBlobType { // MethodHandlesAdapterBlob : Used to hold MethodHandles adapters // OptimizedEntryBlob : Used for upcalls from native code // InterpreterBlob : Used to hold Interpreter +// StubRoutinesBlob : Used for stubroutines // RuntimeStub : Call to VM runtime methods // SingletonBlob : Super-class for all blobs that exist in only one instance // DeoptimizationBlob : Used for deoptimization @@ -140,6 +141,7 @@ class CodeBlob { virtual bool is_vtable_blob() const { return false; } virtual bool is_method_handles_adapter_blob() const { return false; } virtual bool is_interpreter_blob() const { return false; } + virtual bool is_stub_routines_blob() const { return false; } virtual bool is_compiled() const { return false; } virtual bool is_optimized_entry_blob() const { return false; } @@ -405,6 +407,7 @@ class BufferBlob: public RuntimeBlob { friend class MethodHandlesAdapterBlob; friend class OptimizedEntryBlob; friend class InterpreterBlob; + friend class StubRoutinesBlob; friend class WhiteBox; private: @@ -516,6 +519,32 @@ class InterpreterBlob: public BufferBlob { }; +//---------------------------------------------------------------------------------------------------- +// StubRoutinesBlob: used to hold stubroutines + +class StubRoutinesBlob: public BufferBlob { +private: + StubRoutinesBlob(const char* name, int size) : BufferBlob(name, size) {} + +public: + // Creation + static StubRoutinesBlob* create(const char* name, int buffer_size); + + // Typing + virtual bool is_stub_routines_blob() const { return true; } + + // Profiling/safepoint support + class FrameParser : public BufferBlob::FrameParser { + public: + FrameParser(const StubRoutinesBlob* cb) : BufferBlob::FrameParser(cb) {} + virtual bool sender_frame(JavaThread *thread, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, + address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp); + }; + + virtual FrameParser* frame_parser() const { return new FrameParser(this); } +}; + + //---------------------------------------------------------------------------------------------------- // RuntimeStub: describes stubs used by compiled code to call a (static) C++ runtime routine diff --git a/src/hotspot/share/runtime/frame.cpp b/src/hotspot/share/runtime/frame.cpp index 9fff58426e862..dba5bb46f4b9f 100644 --- a/src/hotspot/share/runtime/frame.cpp +++ b/src/hotspot/share/runtime/frame.cpp @@ -653,6 +653,8 @@ void frame::print_on_error(outputStream* st, char* buf, int buflen, bool verbose st->print("v ~VtableBlob"); } else if (_cb->is_interpreter_blob()) { st->print("v ~InterpreterBlob"); + } else if (_cb->is_stub_routines_blob()) { + st->print("v ~StubRoutinesBlob"); } else if (_cb->is_method_handles_adapter_blob()) { st->print("v ~MethodHandlesAdapterBlob"); } else if (_cb->is_uncommon_trap_stub()) { diff --git a/src/hotspot/share/runtime/stubRoutines.cpp b/src/hotspot/share/runtime/stubRoutines.cpp index b231ce533fb74..31cd218dca6b2 100644 --- a/src/hotspot/share/runtime/stubRoutines.cpp +++ b/src/hotspot/share/runtime/stubRoutines.cpp @@ -214,10 +214,8 @@ void StubRoutines::initialize1() { if (_code1 == NULL) { ResourceMark rm; TraceTime timer("StubRoutines generation 1", TRACETIME_LOG(Info, startuptime)); - _code1 = BufferBlob::create("StubRoutines (1)", code_size1); - if (_code1 == NULL) { - vm_exit_out_of_memory(code_size1, OOM_MALLOC_ERROR, "CodeCache: no room for StubRoutines (1)"); - } + _code1 = StubRoutinesBlob::create("StubRoutines (1)", code_size1); + assert(_code1, "invariant"); CodeBuffer buffer(_code1); StubGenerator_generate(&buffer, false); // When new stubs added we need to make sure there is some space left @@ -268,10 +266,8 @@ void StubRoutines::initialize2() { if (_code2 == NULL) { ResourceMark rm; TraceTime timer("StubRoutines generation 2", TRACETIME_LOG(Info, startuptime)); - _code2 = BufferBlob::create("StubRoutines (2)", code_size2); - if (_code2 == NULL) { - vm_exit_out_of_memory(code_size2, OOM_MALLOC_ERROR, "CodeCache: no room for StubRoutines (2)"); - } + _code2 = StubRoutinesBlob::create("StubRoutines (2)", code_size2); + assert(_code2, "invariant"); CodeBuffer buffer(_code2); StubGenerator_generate(&buffer, true); // When new stubs added we need to make sure there is some space left diff --git a/src/hotspot/share/runtime/vmStructs.cpp b/src/hotspot/share/runtime/vmStructs.cpp index d3a24cc783d63..ab47c32a494c7 100644 --- a/src/hotspot/share/runtime/vmStructs.cpp +++ b/src/hotspot/share/runtime/vmStructs.cpp @@ -1401,6 +1401,7 @@ typedef HashtableEntry KlassHashtableEntry; declare_type(MethodHandlesAdapterBlob, BufferBlob) \ declare_type(VtableBlob, BufferBlob) \ declare_type(InterpreterBlob, BufferBlob) \ + declare_type(StubRoutinesBlob, BufferBlob) \ declare_type(CompiledMethod, CodeBlob) \ declare_type(nmethod, CompiledMethod) \ declare_type(RuntimeStub, RuntimeBlob) \ diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/CodeCache.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/CodeCache.java index 08c10a5adde12..0fe6fb97ff082 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/CodeCache.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/CodeCache.java @@ -68,6 +68,7 @@ private static synchronized void initialize(TypeDataBase db) { virtualConstructor.addMapping("SafepointBlob", SafepointBlob.class); virtualConstructor.addMapping("DeoptimizationBlob", DeoptimizationBlob.class); virtualConstructor.addMapping("InterpreterBlob", InterpreterBlob.class); + virtualConstructor.addMapping("StubRoutinesBlob", StubRoutinesBlob.class); if (VM.getVM().isServerCompiler()) { virtualConstructor.addMapping("ExceptionBlob", ExceptionBlob.class); virtualConstructor.addMapping("UncommonTrapBlob", UncommonTrapBlob.class); diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/StubRoutinesBlob.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/StubRoutinesBlob.java new file mode 100644 index 0000000000000..3dfa91b749559 --- /dev/null +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/StubRoutinesBlob.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, Datadog, Inc. 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. + * + */ + +package sun.jvm.hotspot.code; + +import sun.jvm.hotspot.debugger.Address; + +public class StubRoutinesBlob extends BufferBlob { + + public StubRoutinesBlob(Address addr) { + super(addr); + } + + public boolean isStubRoutinesBlob() { + return true; + } + + public String getName() { + return "StubRoutinesBlob: " + super.getName(); + } + +} From df2d275851dbaa26c0f2f572831928be82f3c285 Mon Sep 17 00:00:00 2001 From: Ludovic Henry Date: Tue, 8 Jun 2021 06:37:23 +0000 Subject: [PATCH 3/7] Allow AsyncGetCallTrace and JFR to unwind stack from nmethod's prolog When sampling hits the prolog of a method, Hotspot assumes it's unable to parse the frame. This change allows to parse such frame on x86 by specializing which instruction it's hitting in the prolog. The results are as follows: - Baseline: Flat Profile (by method): (t 60.7,s 60.7) AGCT::Unknown Java[ERR=-5] (t 39.2,s 35.2) Prof2::main (t 1.4,s 1.4) Prof2::lambda$main$3 (t 1.0,s 1.0) Prof2::lambda$main$2 (t 0.9,s 0.9) Prof2::lambda$main$1 (t 0.7,s 0.7) Prof2::lambda$main$0 (t 0.1,s 0.1) AGCT::Unknown not Java[ERR=-3] (t 0.0,s 0.0) java.lang.Thread::exit (t 0.9,s 0.0) Prof2$$Lambda$2.0x0000000800c00c28::get (t 1.0,s 0.0) Prof2$$Lambda$3.0x0000000800c01000::get (t 1.4,s 0.0) Prof2$$Lambda$4.0x0000000800c01220::get (t 0.7,s 0.0) Prof2$$Lambda$1.0x0000000800c00a08::get - With incomplete frame parsing: Flat Profile (by method): (t 39.3,s 39.3) AGCT::Unknown Java[ERR=-5] (t 40.3,s 36.1) Prof2::main (t 6.4,s 5.3) Prof2$$Lambda$28.0x0000000800081000::get (t 6.1,s 5.1) Prof2$$Lambda$29.0x0000000800081220::get (t 6.0,s 5.0) Prof2$$Lambda$27.0x0000000800080c28::get (t 6.1,s 5.0) Prof2$$Lambda$26.0x0000000800080a08::get (t 1.1,s 1.1) Prof2::lambda$main$2 (t 1.1,s 1.1) Prof2::lambda$main$0 (t 1.0,s 1.0) Prof2::lambda$main$1 (t 0.9,s 0.9) Prof2::lambda$main$3 (t 0.1,s 0.1) AGCT::Unknown not Java[ERR=-3] (t 0.0,s 0.0) java.util.Locale::getInstance (t 0.0,s 0.0) AGCT::Not walkable Java[ERR=-6] (t 0.0,s 0.0) jdk.internal.loader.BuiltinClassLoader::loadClassOrNull (t 0.0,s 0.0) java.lang.ClassLoader::loadClass (t 0.0,s 0.0) sun.net.util.URLUtil::urlNoFragString (t 0.0,s 0.0) java.lang.Class::forName0 (t 0.0,s 0.0) java.util.Locale::initDefault (t 0.0,s 0.0) jdk.internal.loader.BuiltinClassLoader::loadClass (t 0.0,s 0.0) jdk.internal.loader.URLClassPath::getLoader (t 0.0,s 0.0) jdk.internal.loader.URLClassPath::getResource (t 0.0,s 0.0) java.lang.String::toLowerCase (t 0.0,s 0.0) sun.launcher.LauncherHelper::loadMainClass (t 0.0,s 0.0) sun.launcher.LauncherHelper::checkAndLoadMain (t 0.0,s 0.0) java.util.Locale:: (t 0.0,s 0.0) jdk.internal.loader.BuiltinClassLoader::findClassOnClassPathOrNull (t 0.0,s 0.0) jdk.internal.loader.ClassLoaders$AppClassLoader::loadClass (t 0.0,s 0.0) java.lang.Class::forName The program is as follows: ``` import java.util.function.Supplier; public class Prof2 { public static void main(String[] args) { var rand = new java.util.Random(0); Supplier[] suppliers = { () -> 0, () -> 1, () -> 2, () -> 3, }; long sum = 0; for (int i = 0; i >= 0; i++) { sum += (int)suppliers[i % suppliers.length].get(); } } } ``` We see that the results are particularely useful in this case as the methods are very short (it only returns an integer), and the probability of hitting the prolog is then very high. --- src/hotspot/cpu/aarch64/codeBlob_aarch64.cpp | 23 +++++- src/hotspot/cpu/arm/codeBlob_arm.cpp | 23 +++++- src/hotspot/cpu/ppc/codeBlob_ppc.cpp | 23 +++++- src/hotspot/cpu/s390/codeBlob_s390.cpp | 23 +++++- src/hotspot/cpu/x86/codeBlob_x86.cpp | 75 +++++++++++++++++++- src/hotspot/cpu/zero/codeBlob_zero.cpp | 21 ++++-- src/hotspot/share/code/codeBlob.hpp | 12 ++-- src/hotspot/share/code/compiledMethod.hpp | 11 +++ src/hotspot/share/code/nmethod.hpp | 11 +++ 9 files changed, 207 insertions(+), 15 deletions(-) diff --git a/src/hotspot/cpu/aarch64/codeBlob_aarch64.cpp b/src/hotspot/cpu/aarch64/codeBlob_aarch64.cpp index d08bf7d6e8036..925ff6c7753d9 100644 --- a/src/hotspot/cpu/aarch64/codeBlob_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/codeBlob_aarch64.cpp @@ -26,6 +26,7 @@ #include "precompiled.hpp" #include "code/codeBlob.hpp" #include "code/compiledMethod.hpp" +#include "code/nmethod.hpp" #include "interpreter/interpreter.hpp" #include "runtime/frame.hpp" @@ -43,7 +44,7 @@ bool CodeBlob::FrameParser::sender_frame(JavaThread *thread, bool check, address // ok. adapter blobs never have a frame complete and are never ok. if (!_cb->is_frame_complete_at(pc)) { - if (_cb->is_compiled() || _cb->is_adapter_blob()) { + if (_cb->is_adapter_blob()) { return false; } } @@ -104,3 +105,23 @@ bool StubRoutinesBlob::FrameParser::sender_frame(JavaThread *thread, address pc, return CodeBlob::FrameParser::sender_frame(thread, pc, sp, unextended_sp, fp, fp_safe, sender_pc, sender_sp, sender_unextended_sp, saved_fp); } + +bool CompiledMethod::FrameParser::sender_frame(JavaThread *thread, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, + address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { + + assert(sender_pc != NULL, "invariant"); + assert(sender_sp != NULL, "invariant"); + + if (!_cb->is_frame_complete_at(pc)) { + return false; + } + + return CodeBlob::FrameParser::sender_frame(thread, pc, sp, unextended_sp, fp, fp_safe, + sender_pc, sender_sp, sender_unextended_sp, saved_fp); +} + +bool nmethod::FrameParser::sender_frame(JavaThread *thread, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, + address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { + return CompiledMethod::FrameParser::sender_frame(thread, pc, sp, unextended_sp, fp, fp_safe, + sender_pc, sender_sp, sender_unextended_sp, saved_fp); +} diff --git a/src/hotspot/cpu/arm/codeBlob_arm.cpp b/src/hotspot/cpu/arm/codeBlob_arm.cpp index 6fbfeaf2d9052..029273709c0e1 100644 --- a/src/hotspot/cpu/arm/codeBlob_arm.cpp +++ b/src/hotspot/cpu/arm/codeBlob_arm.cpp @@ -26,6 +26,7 @@ #include "precompiled.hpp" #include "code/codeBlob.hpp" #include "code/compiledMethod.hpp" +#include "code/nmethod.hpp" #include "interpreter/interpreter.hpp" #include "runtime/frame.hpp" @@ -43,7 +44,7 @@ bool CodeBlob::FrameParser::sender_frame(JavaThread *thread, bool check, address // ok. adapter blobs never have a frame complete and are never ok. if (!_cb->is_frame_complete_at(pc)) { - if (_cb->is_compiled() || _cb->is_adapter_blob()) { + if (_cb->is_adapter_blob()) { return false; } } @@ -94,3 +95,23 @@ bool StubRoutinesBlob::FrameParser::sender_frame(JavaThread *thread, address pc, return CodeBlob::FrameParser::sender_frame(thread, pc, sp, unextended_sp, fp, fp_safe, sender_pc, sender_sp, sender_unextended_sp, saved_fp); } + +bool CompiledMethod::FrameParser::sender_frame(JavaThread *thread, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, + address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { + + assert(sender_pc != NULL, "invariant"); + assert(sender_sp != NULL, "invariant"); + + if (!_cb->is_frame_complete_at(pc)) { + return false; + } + + return CodeBlob::FrameParser::sender_frame(thread, pc, sp, unextended_sp, fp, fp_safe, + sender_pc, sender_sp, sender_unextended_sp, saved_fp); +} + +bool nmethod::FrameParser::sender_frame(JavaThread *thread, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, + address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { + return CompiledMethod::FrameParser::sender_frame(thread, pc, sp, unextended_sp, fp, fp_safe, + sender_pc, sender_sp, sender_unextended_sp, saved_fp); +} diff --git a/src/hotspot/cpu/ppc/codeBlob_ppc.cpp b/src/hotspot/cpu/ppc/codeBlob_ppc.cpp index b5c5b9538031a..f79e54e1cec54 100644 --- a/src/hotspot/cpu/ppc/codeBlob_ppc.cpp +++ b/src/hotspot/cpu/ppc/codeBlob_ppc.cpp @@ -26,6 +26,7 @@ #include "precompiled.hpp" #include "code/codeBlob.hpp" #include "code/compiledMethod.hpp" +#include "code/nmethod.hpp" #include "interpreter/interpreter.hpp" #include "runtime/frame.hpp" @@ -43,7 +44,7 @@ bool CodeBlob::FrameParser::sender_frame(JavaThread *thread, bool check, address // ok. adapter blobs never have a frame complete and are never ok. if (!_cb->is_frame_complete_at(pc)) { - if (_cb->is_compiled() || _cb->is_adapter_blob()) { + if (_cb->is_adapter_blob()) { return false; } } @@ -75,3 +76,23 @@ bool StubRoutinesBlob::FrameParser::sender_frame(JavaThread *thread, address pc, return CodeBlob::FrameParser::sender_frame(thread, pc, sp, unextended_sp, fp, fp_safe, sender_pc, sender_sp, sender_unextended_sp, saved_fp); } + +bool CompiledMethod::FrameParser::sender_frame(JavaThread *thread, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, + address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { + + assert(sender_pc != NULL, "invariant"); + assert(sender_sp != NULL, "invariant"); + + if (!_cb->is_frame_complete_at(pc)) { + return false; + } + + return CodeBlob::FrameParser::sender_frame(thread, pc, sp, unextended_sp, fp, fp_safe, + sender_pc, sender_sp, sender_unextended_sp, saved_fp); +} + +bool nmethod::FrameParser::sender_frame(JavaThread *thread, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, + address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { + return CompiledMethod::FrameParser::sender_frame(thread, pc, sp, unextended_sp, fp, fp_safe, + sender_pc, sender_sp, sender_unextended_sp, saved_fp); +} diff --git a/src/hotspot/cpu/s390/codeBlob_s390.cpp b/src/hotspot/cpu/s390/codeBlob_s390.cpp index 8fa6ecedf4a8d..b07b106ae065f 100644 --- a/src/hotspot/cpu/s390/codeBlob_s390.cpp +++ b/src/hotspot/cpu/s390/codeBlob_s390.cpp @@ -26,6 +26,7 @@ #include "precompiled.hpp" #include "code/codeBlob.hpp" #include "code/compiledMethod.hpp" +#include "code/nmethod.hpp" #include "interpreter/interpreter.hpp" #include "runtime/frame.hpp" @@ -43,7 +44,7 @@ bool CodeBlob::FrameParser::sender_frame(JavaThread *thread, bool check, address // ok. adapter blobs never have a frame complete and are never ok. if (!_cb->is_frame_complete_at(pc)) { - if (_cb->is_compiled() || _cb->is_adapter_blob()) { + if (_cb->is_adapter_blob()) { return false; } } @@ -75,3 +76,23 @@ bool StubRoutinesBlob::FrameParser::sender_frame(JavaThread *thread, address pc, return CodeBlob::FrameParser::sender_frame(thread, pc, sp, unextended_sp, fp, fp_safe, sender_pc, sender_sp, sender_unextended_sp, saved_fp); } + +bool CompiledMethod::FrameParser::sender_frame(JavaThread *thread, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, + address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { + + assert(sender_pc != NULL, "invariant"); + assert(sender_sp != NULL, "invariant"); + + if (!_cb->is_frame_complete_at(pc)) { + return false; + } + + return CodeBlob::FrameParser::sender_frame(thread, pc, sp, unextended_sp, fp, fp_safe, + sender_pc, sender_sp, sender_unextended_sp, saved_fp); +} + +bool nmethod::FrameParser::sender_frame(JavaThread *thread, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, + address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { + return CompiledMethod::FrameParser::sender_frame(thread, pc, sp, unextended_sp, fp, fp_safe, + sender_pc, sender_sp, sender_unextended_sp, saved_fp); +} diff --git a/src/hotspot/cpu/x86/codeBlob_x86.cpp b/src/hotspot/cpu/x86/codeBlob_x86.cpp index a63da87342f73..b9d4bfbe14c60 100644 --- a/src/hotspot/cpu/x86/codeBlob_x86.cpp +++ b/src/hotspot/cpu/x86/codeBlob_x86.cpp @@ -25,7 +25,9 @@ #include "precompiled.hpp" #include "code/codeBlob.hpp" +#include "code/codeCache.hpp" #include "code/compiledMethod.hpp" +#include "code/nmethod.hpp" #include "interpreter/interpreter.hpp" #include "runtime/frame.hpp" @@ -43,7 +45,7 @@ bool CodeBlob::FrameParser::sender_frame(JavaThread *thread, bool check, address // ok. adapter blobs never have a frame complete and are never ok. if (!_cb->is_frame_complete_at(pc)) { - if (_cb->is_compiled() || _cb->is_adapter_blob()) { + if (_cb->is_adapter_blob()) { return false; } } @@ -116,3 +118,74 @@ bool StubRoutinesBlob::FrameParser::sender_frame(JavaThread *thread, address pc, return true; } + +bool CompiledMethod::FrameParser::sender_frame(JavaThread *thread, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, + address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { + + assert(sender_pc != NULL, "invariant"); + assert(sender_sp != NULL, "invariant"); + + if (!_cb->is_frame_complete_at(pc)) { + return false; + } + + return CodeBlob::FrameParser::sender_frame(thread, pc, sp, unextended_sp, fp, fp_safe, + sender_pc, sender_sp, sender_unextended_sp, saved_fp); +} + +bool nmethod::FrameParser::sender_frame(JavaThread *thread, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, + address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { + + assert(sender_pc != NULL, "invariant"); + assert(sender_sp != NULL, "invariant"); + + if (_cb->is_compiled_by_c1() || _cb->is_compiled_by_c2()) { + // We landed on the prolog which looks like: + // mov %eax,-0x16000(%rsp) == stack banging + // push %rbp + // sub N, %rsp + // Let's first figure out which instruction we're on + int offset = pc - _cb->as_nmethod()->verified_entry_point(); + // If it's stack banging or `push %rbp`, %rsp hasn't been modified by this method + if (offset == 0 /* stack banging */ || offset == 7 /* `push %rbp` */) { + if (!thread->is_in_full_stack_checked((address)sp)) { + return false; + } + + *sender_sp = sp; + *sender_unextended_sp = *sender_sp; + *sender_pc = (address)*(*sender_sp); + + CodeBlob *sender_cb = CodeCache::find_blob_unsafe(*sender_pc); + if (*sender_pc == NULL || sender_cb == NULL) { + return false; + } + // Could be a zombie method + if (sender_cb->is_zombie() || sender_cb->is_unloaded()) { + return false; + } + // Could just be some random pointer within the codeBlob + if (!sender_cb->code_contains(*sender_pc)) { + return false; + } + + *saved_fp = (intptr_t**)((*sender_sp) + sender_cb->frame_size() - frame::sender_sp_offset); + return true; + // If it's `sub N, %rsp`, %rsp has been incremented by `push %rbp` already + // but the stack frame hasn't been allocated + } else if (offset == 8 /* `sub N, %rsp` */) { + if (!thread->is_in_full_stack_checked((address)sp)) { + return false; + } + + *sender_sp = sp; + *sender_unextended_sp = *sender_sp; + *sender_pc = (address)*((*sender_sp) + frame::return_addr_offset); + *saved_fp = (intptr_t**)((*sender_sp) + frame::link_offset); + return true; + } + } + + return CompiledMethod::FrameParser::sender_frame(thread, pc, sp, unextended_sp, fp, fp_safe, + sender_pc, sender_sp, sender_unextended_sp, saved_fp); +} diff --git a/src/hotspot/cpu/zero/codeBlob_zero.cpp b/src/hotspot/cpu/zero/codeBlob_zero.cpp index e49a342555174..207e93bcf2fe9 100644 --- a/src/hotspot/cpu/zero/codeBlob_zero.cpp +++ b/src/hotspot/cpu/zero/codeBlob_zero.cpp @@ -26,6 +26,7 @@ #include "precompiled.hpp" #include "code/codeBlob.hpp" #include "code/compiledMethod.hpp" +#include "code/nmethod.hpp" #include "interpreter/interpreter.hpp" #include "runtime/frame.hpp" @@ -37,12 +38,24 @@ bool CodeBlob::FrameParser::sender_frame(JavaThread *thread, bool check, address bool InterpreterBlob::FrameParser::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { - return CodeBlob::FrameParser::sender_frame(thread, pc, sp, unextended_sp, fp, fp_safe, - sender_pc, sender_sp, sender_unextended_sp, saved_fp); + ShouldNotCallThis(); + return false; } bool StubRoutinesBlob::FrameParser::sender_frame(JavaThread *thread, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { - return CodeBlob::FrameParser::sender_frame(thread, pc, sp, unextended_sp, fp, fp_safe, - sender_pc, sender_sp, sender_unextended_sp, saved_fp); + ShouldNotCallThis(); + return false; +} + +bool CompiledMethod::FrameParser::sender_frame(JavaThread *thread, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, + address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { + ShouldNotCallThis(); + return false; +} + +bool nmethod::FrameParser::sender_frame(JavaThread *thread, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, + address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { + ShouldNotCallThis(); + return false; } diff --git a/src/hotspot/share/code/codeBlob.hpp b/src/hotspot/share/code/codeBlob.hpp index 9363eb389970c..075742a4fbbdd 100644 --- a/src/hotspot/share/code/codeBlob.hpp +++ b/src/hotspot/share/code/codeBlob.hpp @@ -152,12 +152,12 @@ class CodeBlob { CompilerType compiler_type() const { return _type; } // Casting - nmethod* as_nmethod_or_null() { return is_nmethod() ? (nmethod*) this : NULL; } - nmethod* as_nmethod() { assert(is_nmethod(), "must be nmethod"); return (nmethod*) this; } - CompiledMethod* as_compiled_method_or_null() { return is_compiled() ? (CompiledMethod*) this : NULL; } - CompiledMethod* as_compiled_method() { assert(is_compiled(), "must be compiled"); return (CompiledMethod*) this; } - CodeBlob* as_codeblob_or_null() const { return (CodeBlob*) this; } - OptimizedEntryBlob* as_optimized_entry_blob() const { assert(is_optimized_entry_blob(), "must be entry blob"); return (OptimizedEntryBlob*) this; } + nmethod* as_nmethod_or_null() const { return is_nmethod() ? (nmethod*) this : NULL; } + nmethod* as_nmethod() const { assert(is_nmethod(), "must be nmethod"); return (nmethod*) this; } + CompiledMethod* as_compiled_method_or_null() const { return is_compiled() ? (CompiledMethod*) this : NULL; } + CompiledMethod* as_compiled_method() const { assert(is_compiled(), "must be compiled"); return (CompiledMethod*) this; } + CodeBlob* as_codeblob_or_null() const { return (CodeBlob*) this; } + OptimizedEntryBlob* as_optimized_entry_blob() const { assert(is_optimized_entry_blob(), "must be entry blob"); return (OptimizedEntryBlob*) this; } // Boundaries address header_begin() const { return (address) this; } diff --git a/src/hotspot/share/code/compiledMethod.hpp b/src/hotspot/share/code/compiledMethod.hpp index 6c979f67a1d25..407f8e40a14b5 100644 --- a/src/hotspot/share/code/compiledMethod.hpp +++ b/src/hotspot/share/code/compiledMethod.hpp @@ -399,6 +399,17 @@ class CompiledMethod : public CodeBlob { bool unload_nmethod_caches(bool class_unloading_occurred); virtual void do_unloading(bool unloading_occurred) = 0; + public: + // Profiling/safepoint support + class FrameParser : public CodeBlob::FrameParser { + public: + FrameParser(const CompiledMethod* cb) : CodeBlob::FrameParser(cb) {} + virtual bool sender_frame(JavaThread *thread, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, + address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp); + }; + + virtual FrameParser* frame_parser() const { return new FrameParser(this); } + private: PcDesc* find_pc_desc(address pc, bool approximate) { return _pc_desc_container.find_pc_desc(pc, approximate, PcDescSearch(code_begin(), scopes_pcs_begin(), scopes_pcs_end())); diff --git a/src/hotspot/share/code/nmethod.hpp b/src/hotspot/share/code/nmethod.hpp index 893f28863a60e..8f712438189ca 100644 --- a/src/hotspot/share/code/nmethod.hpp +++ b/src/hotspot/share/code/nmethod.hpp @@ -758,6 +758,17 @@ class nmethod : public CompiledMethod { virtual CompiledStaticCall* compiledStaticCall_at(Relocation* call_site) const; virtual CompiledStaticCall* compiledStaticCall_at(address addr) const; virtual CompiledStaticCall* compiledStaticCall_before(address addr) const; + + public: + // Profiling/safepoint support + class FrameParser : public CompiledMethod::FrameParser { + public: + FrameParser(const nmethod* cb) : CompiledMethod::FrameParser(cb) {} + virtual bool sender_frame(JavaThread *thread, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, + address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp); + }; + + virtual FrameParser* frame_parser() const { return new FrameParser(this); } }; // Locks an nmethod so its code will not get removed and it will not From 2f2e49bbd9e944a02899d30b01888144250d40d3 Mon Sep 17 00:00:00 2001 From: Ludovic Henry Date: Wed, 9 Jun 2021 12:06:31 +0000 Subject: [PATCH 4/7] Allow AsyncGetCallTrace and JFR to unwind stack from vtable stub The program is the following: ``` import java.util.function.Supplier; public class Prof2 { public static void main(String[] args) { var rand = new java.util.Random(0); Supplier[] suppliers = { () -> 0, () -> 1, () -> 2, () -> 3, }; long sum = 0; for (int i = 0; i >= 0; i++) { sum += (int)suppliers[i % suppliers.length].get(); } } } ``` The results are as follows: - Baseline (from previous commit): Flat Profile (by method): (t 39.3,s 39.3) AGCT::Unknown Java[ERR=-5] (t 40.3,s 36.1) Prof2::main (t 6.4,s 5.3) Prof2$$Lambda$28.0x0000000800081000::get (t 6.1,s 5.1) Prof2$$Lambda$29.0x0000000800081220::get (t 6.0,s 5.0) Prof2$$Lambda$27.0x0000000800080c28::get (t 6.1,s 5.0) Prof2$$Lambda$26.0x0000000800080a08::get (t 1.1,s 1.1) Prof2::lambda$main$2 (t 1.1,s 1.1) Prof2::lambda$main$0 (t 1.0,s 1.0) Prof2::lambda$main$1 (t 0.9,s 0.9) Prof2::lambda$main$3 (t 0.1,s 0.1) AGCT::Unknown not Java[ERR=-3] - With unwind from vtable stub Flat Profile (by method): (t 74.1,s 70.3) Prof2::main (t 6.5,s 5.5) Prof2$$Lambda$29.0x0000000800081220::get (t 6.6,s 5.4) Prof2$$Lambda$28.0x0000000800081000::get (t 5.7,s 5.0) Prof2$$Lambda$26.0x0000000800080a08::get (t 5.9,s 5.0) Prof2$$Lambda$27.0x0000000800080c28::get (t 4.9,s 4.9) AGCT::Unknown Java[ERR=-5] (t 1.2,s 1.2) Prof2::lambda$main$2 (t 0.9,s 0.9) Prof2::lambda$main$3 (t 0.9,s 0.9) Prof2::lambda$main$1 (t 0.7,s 0.7) Prof2::lambda$main$0 (t 0.1,s 0.1) AGCT::Unknown not Java[ERR=-3] We attribute the vtable stub to the caller and not the callee, which is already an improvement from the existing case. --- src/hotspot/cpu/aarch64/codeBlob_aarch64.cpp | 6 ++++++ src/hotspot/cpu/arm/codeBlob_arm.cpp | 6 ++++++ src/hotspot/cpu/ppc/codeBlob_ppc.cpp | 6 ++++++ src/hotspot/cpu/s390/codeBlob_s390.cpp | 6 ++++++ src/hotspot/cpu/x86/codeBlob_x86.cpp | 21 ++++++++++++++++++++ src/hotspot/cpu/zero/codeBlob_zero.cpp | 6 ++++++ src/hotspot/share/code/codeBlob.hpp | 10 ++++++++++ 7 files changed, 61 insertions(+) diff --git a/src/hotspot/cpu/aarch64/codeBlob_aarch64.cpp b/src/hotspot/cpu/aarch64/codeBlob_aarch64.cpp index 925ff6c7753d9..2aaea88105ee5 100644 --- a/src/hotspot/cpu/aarch64/codeBlob_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/codeBlob_aarch64.cpp @@ -91,6 +91,12 @@ bool InterpreterBlob::FrameParser::sender_frame(JavaThread *thread, bool check, return true; } +bool VtableBlob::FrameParser::sender_frame(JavaThread *thread, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, + address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { + return CodeBlob::FrameParser::sender_frame(thread, pc, sp, unextended_sp, fp, fp_safe, + sender_pc, sender_sp, sender_unextended_sp, saved_fp); +} + bool StubRoutinesBlob::FrameParser::sender_frame(JavaThread *thread, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { diff --git a/src/hotspot/cpu/arm/codeBlob_arm.cpp b/src/hotspot/cpu/arm/codeBlob_arm.cpp index 029273709c0e1..6690cb17f9fff 100644 --- a/src/hotspot/cpu/arm/codeBlob_arm.cpp +++ b/src/hotspot/cpu/arm/codeBlob_arm.cpp @@ -81,6 +81,12 @@ bool InterpreterBlob::FrameParser::sender_frame(JavaThread *thread, bool check, return true; } +bool VtableBlob::FrameParser::sender_frame(JavaThread *thread, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, + address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { + return CodeBlob::FrameParser::sender_frame(thread, pc, sp, unextended_sp, fp, fp_safe, + sender_pc, sender_sp, sender_unextended_sp, saved_fp); +} + bool StubRoutinesBlob::FrameParser::sender_frame(JavaThread *thread, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { diff --git a/src/hotspot/cpu/ppc/codeBlob_ppc.cpp b/src/hotspot/cpu/ppc/codeBlob_ppc.cpp index f79e54e1cec54..10e41c15e7ac4 100644 --- a/src/hotspot/cpu/ppc/codeBlob_ppc.cpp +++ b/src/hotspot/cpu/ppc/codeBlob_ppc.cpp @@ -62,6 +62,12 @@ bool InterpreterBlob::FrameParser::sender_frame(JavaThread *thread, bool check, sender_pc, sender_sp, sender_unextended_sp, saved_fp); } +bool VtableBlob::FrameParser::sender_frame(JavaThread *thread, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, + address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { + return CodeBlob::FrameParser::sender_frame(thread, pc, sp, unextended_sp, fp, fp_safe, + sender_pc, sender_sp, sender_unextended_sp, saved_fp); +} + bool StubRoutinesBlob::FrameParser::sender_frame(JavaThread *thread, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { diff --git a/src/hotspot/cpu/s390/codeBlob_s390.cpp b/src/hotspot/cpu/s390/codeBlob_s390.cpp index b07b106ae065f..27c9223eb1179 100644 --- a/src/hotspot/cpu/s390/codeBlob_s390.cpp +++ b/src/hotspot/cpu/s390/codeBlob_s390.cpp @@ -62,6 +62,12 @@ bool InterpreterBlob::FrameParser::sender_frame(JavaThread *thread, bool check, sender_pc, sender_sp, sender_unextended_sp, saved_fp); } +bool VtableBlob::FrameParser::sender_frame(JavaThread *thread, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, + address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { + return CodeBlob::FrameParser::sender_frame(thread, pc, sp, unextended_sp, fp, fp_safe, + sender_pc, sender_sp, sender_unextended_sp, saved_fp); +} + bool StubRoutinesBlob::FrameParser::sender_frame(JavaThread *thread, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { diff --git a/src/hotspot/cpu/x86/codeBlob_x86.cpp b/src/hotspot/cpu/x86/codeBlob_x86.cpp index b9d4bfbe14c60..72234f0d4c474 100644 --- a/src/hotspot/cpu/x86/codeBlob_x86.cpp +++ b/src/hotspot/cpu/x86/codeBlob_x86.cpp @@ -93,6 +93,27 @@ bool InterpreterBlob::FrameParser::sender_frame(JavaThread *thread, bool check, return true; } +bool VtableBlob::FrameParser::sender_frame(JavaThread *thread, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, + address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { + + assert(sender_pc != NULL, "invariant"); + assert(sender_sp != NULL, "invariant"); + + *sender_sp = unextended_sp; + // Is sender_sp safe? + if (thread != NULL && !thread->is_in_full_stack_checked((address)*sender_sp)) { + return false; + } + // On Intel the return_address is always the word on the stack + *sender_pc = (address)*((*sender_sp) - frame::pc_return_offset); + + if (sender_unextended_sp) *sender_unextended_sp = *sender_sp; + // Note: frame::sender_sp_offset is only valid for compiled frame + if (saved_fp) *saved_fp = (intptr_t**)((*sender_sp) - frame::sender_sp_offset); + + return true; +} + bool StubRoutinesBlob::FrameParser::sender_frame(JavaThread *thread, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { diff --git a/src/hotspot/cpu/zero/codeBlob_zero.cpp b/src/hotspot/cpu/zero/codeBlob_zero.cpp index 207e93bcf2fe9..8a59d188d98e7 100644 --- a/src/hotspot/cpu/zero/codeBlob_zero.cpp +++ b/src/hotspot/cpu/zero/codeBlob_zero.cpp @@ -42,6 +42,12 @@ bool InterpreterBlob::FrameParser::sender_frame(JavaThread *thread, bool check, return false; } +bool VtableBlob::FrameParser::sender_frame(JavaThread *thread, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, + address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { + ShouldNotCallThis(); + return false; +} + bool StubRoutinesBlob::FrameParser::sender_frame(JavaThread *thread, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { ShouldNotCallThis(); diff --git a/src/hotspot/share/code/codeBlob.hpp b/src/hotspot/share/code/codeBlob.hpp index 075742a4fbbdd..7066a21348217 100644 --- a/src/hotspot/share/code/codeBlob.hpp +++ b/src/hotspot/share/code/codeBlob.hpp @@ -475,6 +475,16 @@ class VtableBlob: public BufferBlob { // Typing virtual bool is_vtable_blob() const { return true; } + + // Profiling/safepoint support + class FrameParser : public BufferBlob::FrameParser { + public: + FrameParser(const VtableBlob* cb) : BufferBlob::FrameParser(cb) {} + virtual bool sender_frame(JavaThread *thread, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, + address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp); + }; + + virtual FrameParser* frame_parser() const { return new FrameParser(this); } }; //---------------------------------------------------------------------------------------------------- From 85f218c82d0c435388c325992713713cfeb72749 Mon Sep 17 00:00:00 2001 From: Ludovic Henry Date: Wed, 9 Jun 2021 15:09:47 +0000 Subject: [PATCH 5/7] Disable checks in FrameParser when known to be safe --- src/hotspot/cpu/aarch64/codeBlob_aarch64.cpp | 22 ++++++++--------- src/hotspot/cpu/arm/codeBlob_arm.cpp | 22 ++++++++--------- src/hotspot/cpu/ppc/codeBlob_ppc.cpp | 22 ++++++++--------- src/hotspot/cpu/s390/codeBlob_s390.cpp | 22 ++++++++--------- src/hotspot/cpu/x86/codeBlob_x86.cpp | 26 ++++++++++---------- src/hotspot/cpu/zero/codeBlob_zero.cpp | 8 +++--- src/hotspot/share/code/codeBlob.hpp | 4 +-- src/hotspot/share/code/compiledMethod.hpp | 2 +- src/hotspot/share/code/nmethod.hpp | 2 +- 9 files changed, 65 insertions(+), 65 deletions(-) diff --git a/src/hotspot/cpu/aarch64/codeBlob_aarch64.cpp b/src/hotspot/cpu/aarch64/codeBlob_aarch64.cpp index 2aaea88105ee5..04fedd1c5ee34 100644 --- a/src/hotspot/cpu/aarch64/codeBlob_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/codeBlob_aarch64.cpp @@ -43,7 +43,7 @@ bool CodeBlob::FrameParser::sender_frame(JavaThread *thread, bool check, address // other generic buffer blobs are more problematic so we just assume they are // ok. adapter blobs never have a frame complete and are never ok. - if (!_cb->is_frame_complete_at(pc)) { + if (check && !_cb->is_frame_complete_at(pc)) { if (_cb->is_adapter_blob()) { return false; } @@ -91,43 +91,43 @@ bool InterpreterBlob::FrameParser::sender_frame(JavaThread *thread, bool check, return true; } -bool VtableBlob::FrameParser::sender_frame(JavaThread *thread, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, +bool VtableBlob::FrameParser::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { - return CodeBlob::FrameParser::sender_frame(thread, pc, sp, unextended_sp, fp, fp_safe, + return CodeBlob::FrameParser::sender_frame(thread, check, pc, sp, unextended_sp, fp, fp_safe, sender_pc, sender_sp, sender_unextended_sp, saved_fp); } -bool StubRoutinesBlob::FrameParser::sender_frame(JavaThread *thread, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, +bool StubRoutinesBlob::FrameParser::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { assert(sender_pc != NULL, "invariant"); assert(sender_sp != NULL, "invariant"); // First check if frame is complete and tester is reliable - if (!_cb->is_frame_complete_at(pc)) { + if (check && !_cb->is_frame_complete_at(pc)) { return false; } - return CodeBlob::FrameParser::sender_frame(thread, pc, sp, unextended_sp, fp, fp_safe, + return CodeBlob::FrameParser::sender_frame(thread, check, pc, sp, unextended_sp, fp, fp_safe, sender_pc, sender_sp, sender_unextended_sp, saved_fp); } -bool CompiledMethod::FrameParser::sender_frame(JavaThread *thread, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, +bool CompiledMethod::FrameParser::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { assert(sender_pc != NULL, "invariant"); assert(sender_sp != NULL, "invariant"); - if (!_cb->is_frame_complete_at(pc)) { + if (check && !_cb->is_frame_complete_at(pc)) { return false; } - return CodeBlob::FrameParser::sender_frame(thread, pc, sp, unextended_sp, fp, fp_safe, + return CodeBlob::FrameParser::sender_frame(thread, check, pc, sp, unextended_sp, fp, fp_safe, sender_pc, sender_sp, sender_unextended_sp, saved_fp); } -bool nmethod::FrameParser::sender_frame(JavaThread *thread, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, +bool nmethod::FrameParser::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { - return CompiledMethod::FrameParser::sender_frame(thread, pc, sp, unextended_sp, fp, fp_safe, + return CompiledMethod::FrameParser::sender_frame(thread, check, pc, sp, unextended_sp, fp, fp_safe, sender_pc, sender_sp, sender_unextended_sp, saved_fp); } diff --git a/src/hotspot/cpu/arm/codeBlob_arm.cpp b/src/hotspot/cpu/arm/codeBlob_arm.cpp index 6690cb17f9fff..4aa51d951f53a 100644 --- a/src/hotspot/cpu/arm/codeBlob_arm.cpp +++ b/src/hotspot/cpu/arm/codeBlob_arm.cpp @@ -43,7 +43,7 @@ bool CodeBlob::FrameParser::sender_frame(JavaThread *thread, bool check, address // other generic buffer blobs are more problematic so we just assume they are // ok. adapter blobs never have a frame complete and are never ok. - if (!_cb->is_frame_complete_at(pc)) { + if (check && !_cb->is_frame_complete_at(pc)) { if (_cb->is_adapter_blob()) { return false; } @@ -81,43 +81,43 @@ bool InterpreterBlob::FrameParser::sender_frame(JavaThread *thread, bool check, return true; } -bool VtableBlob::FrameParser::sender_frame(JavaThread *thread, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, +bool VtableBlob::FrameParser::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { - return CodeBlob::FrameParser::sender_frame(thread, pc, sp, unextended_sp, fp, fp_safe, + return CodeBlob::FrameParser::sender_frame(thread, check, pc, sp, unextended_sp, fp, fp_safe, sender_pc, sender_sp, sender_unextended_sp, saved_fp); } -bool StubRoutinesBlob::FrameParser::sender_frame(JavaThread *thread, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, +bool StubRoutinesBlob::FrameParser::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { assert(sender_pc != NULL, "invariant"); assert(sender_sp != NULL, "invariant"); // First check if frame is complete and tester is reliable - if (!_cb->is_frame_complete_at(pc)) { + if (check && !_cb->is_frame_complete_at(pc)) { return false; } - return CodeBlob::FrameParser::sender_frame(thread, pc, sp, unextended_sp, fp, fp_safe, + return CodeBlob::FrameParser::sender_frame(thread, check, pc, sp, unextended_sp, fp, fp_safe, sender_pc, sender_sp, sender_unextended_sp, saved_fp); } -bool CompiledMethod::FrameParser::sender_frame(JavaThread *thread, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, +bool CompiledMethod::FrameParser::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { assert(sender_pc != NULL, "invariant"); assert(sender_sp != NULL, "invariant"); - if (!_cb->is_frame_complete_at(pc)) { + if (check && !_cb->is_frame_complete_at(pc)) { return false; } - return CodeBlob::FrameParser::sender_frame(thread, pc, sp, unextended_sp, fp, fp_safe, + return CodeBlob::FrameParser::sender_frame(thread, check, pc, sp, unextended_sp, fp, fp_safe, sender_pc, sender_sp, sender_unextended_sp, saved_fp); } -bool nmethod::FrameParser::sender_frame(JavaThread *thread, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, +bool nmethod::FrameParser::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { - return CompiledMethod::FrameParser::sender_frame(thread, pc, sp, unextended_sp, fp, fp_safe, + return CompiledMethod::FrameParser::sender_frame(thread, check, pc, sp, unextended_sp, fp, fp_safe, sender_pc, sender_sp, sender_unextended_sp, saved_fp); } diff --git a/src/hotspot/cpu/ppc/codeBlob_ppc.cpp b/src/hotspot/cpu/ppc/codeBlob_ppc.cpp index 10e41c15e7ac4..c44aa4176e823 100644 --- a/src/hotspot/cpu/ppc/codeBlob_ppc.cpp +++ b/src/hotspot/cpu/ppc/codeBlob_ppc.cpp @@ -43,7 +43,7 @@ bool CodeBlob::FrameParser::sender_frame(JavaThread *thread, bool check, address // other generic buffer blobs are more problematic so we just assume they are // ok. adapter blobs never have a frame complete and are never ok. - if (!_cb->is_frame_complete_at(pc)) { + if (check && !_cb->is_frame_complete_at(pc)) { if (_cb->is_adapter_blob()) { return false; } @@ -62,43 +62,43 @@ bool InterpreterBlob::FrameParser::sender_frame(JavaThread *thread, bool check, sender_pc, sender_sp, sender_unextended_sp, saved_fp); } -bool VtableBlob::FrameParser::sender_frame(JavaThread *thread, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, +bool VtableBlob::FrameParser::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { - return CodeBlob::FrameParser::sender_frame(thread, pc, sp, unextended_sp, fp, fp_safe, + return CodeBlob::FrameParser::sender_frame(thread, check, pc, sp, unextended_sp, fp, fp_safe, sender_pc, sender_sp, sender_unextended_sp, saved_fp); } -bool StubRoutinesBlob::FrameParser::sender_frame(JavaThread *thread, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, +bool StubRoutinesBlob::FrameParser::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { assert(sender_pc != NULL, "invariant"); assert(sender_sp != NULL, "invariant"); // First check if frame is complete and tester is reliable - if (!_cb->is_frame_complete_at(pc)) { + if (check && !_cb->is_frame_complete_at(pc)) { return false; } - return CodeBlob::FrameParser::sender_frame(thread, pc, sp, unextended_sp, fp, fp_safe, + return CodeBlob::FrameParser::sender_frame(thread, check, pc, sp, unextended_sp, fp, fp_safe, sender_pc, sender_sp, sender_unextended_sp, saved_fp); } -bool CompiledMethod::FrameParser::sender_frame(JavaThread *thread, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, +bool CompiledMethod::FrameParser::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { assert(sender_pc != NULL, "invariant"); assert(sender_sp != NULL, "invariant"); - if (!_cb->is_frame_complete_at(pc)) { + if (check && !_cb->is_frame_complete_at(pc)) { return false; } - return CodeBlob::FrameParser::sender_frame(thread, pc, sp, unextended_sp, fp, fp_safe, + return CodeBlob::FrameParser::sender_frame(thread, check, pc, sp, unextended_sp, fp, fp_safe, sender_pc, sender_sp, sender_unextended_sp, saved_fp); } -bool nmethod::FrameParser::sender_frame(JavaThread *thread, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, +bool nmethod::FrameParser::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { - return CompiledMethod::FrameParser::sender_frame(thread, pc, sp, unextended_sp, fp, fp_safe, + return CompiledMethod::FrameParser::sender_frame(thread, check, pc, sp, unextended_sp, fp, fp_safe, sender_pc, sender_sp, sender_unextended_sp, saved_fp); } diff --git a/src/hotspot/cpu/s390/codeBlob_s390.cpp b/src/hotspot/cpu/s390/codeBlob_s390.cpp index 27c9223eb1179..8a579a0a70b1a 100644 --- a/src/hotspot/cpu/s390/codeBlob_s390.cpp +++ b/src/hotspot/cpu/s390/codeBlob_s390.cpp @@ -43,7 +43,7 @@ bool CodeBlob::FrameParser::sender_frame(JavaThread *thread, bool check, address // other generic buffer blobs are more problematic so we just assume they are // ok. adapter blobs never have a frame complete and are never ok. - if (!_cb->is_frame_complete_at(pc)) { + if (check && !_cb->is_frame_complete_at(pc)) { if (_cb->is_adapter_blob()) { return false; } @@ -62,43 +62,43 @@ bool InterpreterBlob::FrameParser::sender_frame(JavaThread *thread, bool check, sender_pc, sender_sp, sender_unextended_sp, saved_fp); } -bool VtableBlob::FrameParser::sender_frame(JavaThread *thread, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, +bool VtableBlob::FrameParser::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { - return CodeBlob::FrameParser::sender_frame(thread, pc, sp, unextended_sp, fp, fp_safe, + return CodeBlob::FrameParser::sender_frame(thread, check, pc, sp, unextended_sp, fp, fp_safe, sender_pc, sender_sp, sender_unextended_sp, saved_fp); } -bool StubRoutinesBlob::FrameParser::sender_frame(JavaThread *thread, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, +bool StubRoutinesBlob::FrameParser::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { assert(sender_pc != NULL, "invariant"); assert(sender_sp != NULL, "invariant"); // First check if frame is complete and tester is reliable - if (!_cb->is_frame_complete_at(pc)) { + if (check && !_cb->is_frame_complete_at(pc)) { return false; } - return CodeBlob::FrameParser::sender_frame(thread, pc, sp, unextended_sp, fp, fp_safe, + return CodeBlob::FrameParser::sender_frame(thread, check, pc, sp, unextended_sp, fp, fp_safe, sender_pc, sender_sp, sender_unextended_sp, saved_fp); } -bool CompiledMethod::FrameParser::sender_frame(JavaThread *thread, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, +bool CompiledMethod::FrameParser::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { assert(sender_pc != NULL, "invariant"); assert(sender_sp != NULL, "invariant"); - if (!_cb->is_frame_complete_at(pc)) { + if (check && !_cb->is_frame_complete_at(pc)) { return false; } - return CodeBlob::FrameParser::sender_frame(thread, pc, sp, unextended_sp, fp, fp_safe, + return CodeBlob::FrameParser::sender_frame(thread, check, pc, sp, unextended_sp, fp, fp_safe, sender_pc, sender_sp, sender_unextended_sp, saved_fp); } -bool nmethod::FrameParser::sender_frame(JavaThread *thread, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, +bool nmethod::FrameParser::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { - return CompiledMethod::FrameParser::sender_frame(thread, pc, sp, unextended_sp, fp, fp_safe, + return CompiledMethod::FrameParser::sender_frame(thread, check, pc, sp, unextended_sp, fp, fp_safe, sender_pc, sender_sp, sender_unextended_sp, saved_fp); } diff --git a/src/hotspot/cpu/x86/codeBlob_x86.cpp b/src/hotspot/cpu/x86/codeBlob_x86.cpp index 72234f0d4c474..7f811f0625b5a 100644 --- a/src/hotspot/cpu/x86/codeBlob_x86.cpp +++ b/src/hotspot/cpu/x86/codeBlob_x86.cpp @@ -44,7 +44,7 @@ bool CodeBlob::FrameParser::sender_frame(JavaThread *thread, bool check, address // other generic buffer blobs are more problematic so we just assume they are // ok. adapter blobs never have a frame complete and are never ok. - if (!_cb->is_frame_complete_at(pc)) { + if (check && !_cb->is_frame_complete_at(pc)) { if (_cb->is_adapter_blob()) { return false; } @@ -93,7 +93,7 @@ bool InterpreterBlob::FrameParser::sender_frame(JavaThread *thread, bool check, return true; } -bool VtableBlob::FrameParser::sender_frame(JavaThread *thread, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, +bool VtableBlob::FrameParser::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { assert(sender_pc != NULL, "invariant"); @@ -101,7 +101,7 @@ bool VtableBlob::FrameParser::sender_frame(JavaThread *thread, address pc, intpt *sender_sp = unextended_sp; // Is sender_sp safe? - if (thread != NULL && !thread->is_in_full_stack_checked((address)*sender_sp)) { + if (check && thread != NULL && !thread->is_in_full_stack_checked((address)*sender_sp)) { return false; } // On Intel the return_address is always the word on the stack @@ -114,20 +114,20 @@ bool VtableBlob::FrameParser::sender_frame(JavaThread *thread, address pc, intpt return true; } -bool StubRoutinesBlob::FrameParser::sender_frame(JavaThread *thread, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, +bool StubRoutinesBlob::FrameParser::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { assert(sender_pc != NULL, "invariant"); assert(sender_sp != NULL, "invariant"); // fp must be safe - if (!fp_safe) { + if (check && !fp_safe) { return false; } *sender_sp = fp + frame::sender_sp_offset; // Is sender_sp safe? - if (thread != NULL && !thread->is_in_full_stack_checked((address)*sender_sp)) { + if (check && thread != NULL && !thread->is_in_full_stack_checked((address)*sender_sp)) { return false; } *sender_unextended_sp = *sender_sp; @@ -140,21 +140,21 @@ bool StubRoutinesBlob::FrameParser::sender_frame(JavaThread *thread, address pc, return true; } -bool CompiledMethod::FrameParser::sender_frame(JavaThread *thread, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, +bool CompiledMethod::FrameParser::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { assert(sender_pc != NULL, "invariant"); assert(sender_sp != NULL, "invariant"); - if (!_cb->is_frame_complete_at(pc)) { + if (check && !_cb->is_frame_complete_at(pc)) { return false; } - return CodeBlob::FrameParser::sender_frame(thread, pc, sp, unextended_sp, fp, fp_safe, + return CodeBlob::FrameParser::sender_frame(thread, check, pc, sp, unextended_sp, fp, fp_safe, sender_pc, sender_sp, sender_unextended_sp, saved_fp); } -bool nmethod::FrameParser::sender_frame(JavaThread *thread, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, +bool nmethod::FrameParser::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { assert(sender_pc != NULL, "invariant"); @@ -169,7 +169,7 @@ bool nmethod::FrameParser::sender_frame(JavaThread *thread, address pc, intptr_t int offset = pc - _cb->as_nmethod()->verified_entry_point(); // If it's stack banging or `push %rbp`, %rsp hasn't been modified by this method if (offset == 0 /* stack banging */ || offset == 7 /* `push %rbp` */) { - if (!thread->is_in_full_stack_checked((address)sp)) { + if (check && thread != NULL && !thread->is_in_full_stack_checked((address)sp)) { return false; } @@ -195,7 +195,7 @@ bool nmethod::FrameParser::sender_frame(JavaThread *thread, address pc, intptr_t // If it's `sub N, %rsp`, %rsp has been incremented by `push %rbp` already // but the stack frame hasn't been allocated } else if (offset == 8 /* `sub N, %rsp` */) { - if (!thread->is_in_full_stack_checked((address)sp)) { + if (check && thread != NULL && !thread->is_in_full_stack_checked((address)sp)) { return false; } @@ -207,6 +207,6 @@ bool nmethod::FrameParser::sender_frame(JavaThread *thread, address pc, intptr_t } } - return CompiledMethod::FrameParser::sender_frame(thread, pc, sp, unextended_sp, fp, fp_safe, + return CompiledMethod::FrameParser::sender_frame(thread, check, pc, sp, unextended_sp, fp, fp_safe, sender_pc, sender_sp, sender_unextended_sp, saved_fp); } diff --git a/src/hotspot/cpu/zero/codeBlob_zero.cpp b/src/hotspot/cpu/zero/codeBlob_zero.cpp index 8a59d188d98e7..417589b9c01a2 100644 --- a/src/hotspot/cpu/zero/codeBlob_zero.cpp +++ b/src/hotspot/cpu/zero/codeBlob_zero.cpp @@ -42,25 +42,25 @@ bool InterpreterBlob::FrameParser::sender_frame(JavaThread *thread, bool check, return false; } -bool VtableBlob::FrameParser::sender_frame(JavaThread *thread, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, +bool VtableBlob::FrameParser::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { ShouldNotCallThis(); return false; } -bool StubRoutinesBlob::FrameParser::sender_frame(JavaThread *thread, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, +bool StubRoutinesBlob::FrameParser::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { ShouldNotCallThis(); return false; } -bool CompiledMethod::FrameParser::sender_frame(JavaThread *thread, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, +bool CompiledMethod::FrameParser::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { ShouldNotCallThis(); return false; } -bool nmethod::FrameParser::sender_frame(JavaThread *thread, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, +bool nmethod::FrameParser::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { ShouldNotCallThis(); return false; diff --git a/src/hotspot/share/code/codeBlob.hpp b/src/hotspot/share/code/codeBlob.hpp index 7066a21348217..c7ef4d69bad2c 100644 --- a/src/hotspot/share/code/codeBlob.hpp +++ b/src/hotspot/share/code/codeBlob.hpp @@ -480,7 +480,7 @@ class VtableBlob: public BufferBlob { class FrameParser : public BufferBlob::FrameParser { public: FrameParser(const VtableBlob* cb) : BufferBlob::FrameParser(cb) {} - virtual bool sender_frame(JavaThread *thread, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, + virtual bool sender_frame(JavaThread *thread, bool check_frame_complete, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp); }; @@ -547,7 +547,7 @@ class StubRoutinesBlob: public BufferBlob { class FrameParser : public BufferBlob::FrameParser { public: FrameParser(const StubRoutinesBlob* cb) : BufferBlob::FrameParser(cb) {} - virtual bool sender_frame(JavaThread *thread, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, + virtual bool sender_frame(JavaThread *thread, bool check_frame_complete, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp); }; diff --git a/src/hotspot/share/code/compiledMethod.hpp b/src/hotspot/share/code/compiledMethod.hpp index 407f8e40a14b5..7a261c43cbdad 100644 --- a/src/hotspot/share/code/compiledMethod.hpp +++ b/src/hotspot/share/code/compiledMethod.hpp @@ -404,7 +404,7 @@ class CompiledMethod : public CodeBlob { class FrameParser : public CodeBlob::FrameParser { public: FrameParser(const CompiledMethod* cb) : CodeBlob::FrameParser(cb) {} - virtual bool sender_frame(JavaThread *thread, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, + virtual bool sender_frame(JavaThread *thread, bool check_frame_complete, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp); }; diff --git a/src/hotspot/share/code/nmethod.hpp b/src/hotspot/share/code/nmethod.hpp index 8f712438189ca..2d0f561e94150 100644 --- a/src/hotspot/share/code/nmethod.hpp +++ b/src/hotspot/share/code/nmethod.hpp @@ -764,7 +764,7 @@ class nmethod : public CompiledMethod { class FrameParser : public CompiledMethod::FrameParser { public: FrameParser(const nmethod* cb) : CompiledMethod::FrameParser(cb) {} - virtual bool sender_frame(JavaThread *thread, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, + virtual bool sender_frame(JavaThread *thread, bool check_frame_complete, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp); }; From b1d8611c38b11aab00d011cb279a5c52199bd7c1 Mon Sep 17 00:00:00 2001 From: Ludovic Henry Date: Fri, 18 Jun 2021 08:50:43 +0000 Subject: [PATCH 6/7] Fix comments --- src/hotspot/cpu/aarch64/codeBlob_aarch64.cpp | 6 ++---- src/hotspot/cpu/arm/codeBlob_arm.cpp | 7 +++---- src/hotspot/cpu/ppc/codeBlob_ppc.cpp | 7 +++---- src/hotspot/cpu/s390/codeBlob_s390.cpp | 7 +++---- src/hotspot/cpu/x86/codeBlob_x86.cpp | 7 +++---- 5 files changed, 14 insertions(+), 20 deletions(-) diff --git a/src/hotspot/cpu/aarch64/codeBlob_aarch64.cpp b/src/hotspot/cpu/aarch64/codeBlob_aarch64.cpp index 04fedd1c5ee34..1f4f8593bd1d7 100644 --- a/src/hotspot/cpu/aarch64/codeBlob_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/codeBlob_aarch64.cpp @@ -39,11 +39,8 @@ bool CodeBlob::FrameParser::sender_frame(JavaThread *thread, bool check, address assert(sender_sp != NULL, "invariant"); // First check if frame is complete and tester is reliable - // Unfortunately we can only check frame complete for runtime stubs and nmethod - // other generic buffer blobs are more problematic so we just assume they are - // ok. adapter blobs never have a frame complete and are never ok. - if (check && !_cb->is_frame_complete_at(pc)) { + // Adapter blobs never have a complete frame and are never ok. if (_cb->is_adapter_blob()) { return false; } @@ -118,6 +115,7 @@ bool CompiledMethod::FrameParser::sender_frame(JavaThread *thread, bool check, a assert(sender_pc != NULL, "invariant"); assert(sender_sp != NULL, "invariant"); + // First check if frame is complete and tester is reliable if (check && !_cb->is_frame_complete_at(pc)) { return false; } diff --git a/src/hotspot/cpu/arm/codeBlob_arm.cpp b/src/hotspot/cpu/arm/codeBlob_arm.cpp index 4aa51d951f53a..94ebaeff72dad 100644 --- a/src/hotspot/cpu/arm/codeBlob_arm.cpp +++ b/src/hotspot/cpu/arm/codeBlob_arm.cpp @@ -38,12 +38,10 @@ bool CodeBlob::FrameParser::sender_frame(JavaThread *thread, bool check, address assert(sender_pc != NULL, "invariant"); assert(sender_sp != NULL, "invariant"); - // First check if frame is complete and tester is reliable - // Unfortunately we can only check frame complete for runtime stubs and nmethod - // other generic buffer blobs are more problematic so we just assume they are - // ok. adapter blobs never have a frame complete and are never ok. + // First check if frame is complete and tester is reliable if (check && !_cb->is_frame_complete_at(pc)) { + // Adapter blobs never have a complete frame and are never ok. if (_cb->is_adapter_blob()) { return false; } @@ -108,6 +106,7 @@ bool CompiledMethod::FrameParser::sender_frame(JavaThread *thread, bool check, a assert(sender_pc != NULL, "invariant"); assert(sender_sp != NULL, "invariant"); + // First check if frame is complete and tester is reliable if (check && !_cb->is_frame_complete_at(pc)) { return false; } diff --git a/src/hotspot/cpu/ppc/codeBlob_ppc.cpp b/src/hotspot/cpu/ppc/codeBlob_ppc.cpp index c44aa4176e823..12deed1caa610 100644 --- a/src/hotspot/cpu/ppc/codeBlob_ppc.cpp +++ b/src/hotspot/cpu/ppc/codeBlob_ppc.cpp @@ -38,12 +38,10 @@ bool CodeBlob::FrameParser::sender_frame(JavaThread *thread, bool check, address assert(sender_pc != NULL, "invariant"); assert(sender_sp != NULL, "invariant"); - // First check if frame is complete and tester is reliable - // Unfortunately we can only check frame complete for runtime stubs and nmethod - // other generic buffer blobs are more problematic so we just assume they are - // ok. adapter blobs never have a frame complete and are never ok. + // First check if frame is complete and tester is reliable if (check && !_cb->is_frame_complete_at(pc)) { + // Adapter blobs never have a complete frame and are never ok. if (_cb->is_adapter_blob()) { return false; } @@ -89,6 +87,7 @@ bool CompiledMethod::FrameParser::sender_frame(JavaThread *thread, bool check, a assert(sender_pc != NULL, "invariant"); assert(sender_sp != NULL, "invariant"); + // First check if frame is complete and tester is reliable if (check && !_cb->is_frame_complete_at(pc)) { return false; } diff --git a/src/hotspot/cpu/s390/codeBlob_s390.cpp b/src/hotspot/cpu/s390/codeBlob_s390.cpp index 8a579a0a70b1a..196505019ca7c 100644 --- a/src/hotspot/cpu/s390/codeBlob_s390.cpp +++ b/src/hotspot/cpu/s390/codeBlob_s390.cpp @@ -38,12 +38,10 @@ bool CodeBlob::FrameParser::sender_frame(JavaThread *thread, bool check, address assert(sender_pc != NULL, "invariant"); assert(sender_sp != NULL, "invariant"); - // First check if frame is complete and tester is reliable - // Unfortunately we can only check frame complete for runtime stubs and nmethod - // other generic buffer blobs are more problematic so we just assume they are - // ok. adapter blobs never have a frame complete and are never ok. + // First check if frame is complete and tester is reliable if (check && !_cb->is_frame_complete_at(pc)) { + // Adapter blobs never have a complete frame and are never ok. if (_cb->is_adapter_blob()) { return false; } @@ -89,6 +87,7 @@ bool CompiledMethod::FrameParser::sender_frame(JavaThread *thread, bool check, a assert(sender_pc != NULL, "invariant"); assert(sender_sp != NULL, "invariant"); + // First check if frame is complete and tester is reliable if (check && !_cb->is_frame_complete_at(pc)) { return false; } diff --git a/src/hotspot/cpu/x86/codeBlob_x86.cpp b/src/hotspot/cpu/x86/codeBlob_x86.cpp index 7f811f0625b5a..3b8423edf3bd5 100644 --- a/src/hotspot/cpu/x86/codeBlob_x86.cpp +++ b/src/hotspot/cpu/x86/codeBlob_x86.cpp @@ -39,12 +39,10 @@ bool CodeBlob::FrameParser::sender_frame(JavaThread *thread, bool check, address assert(sender_pc != NULL, "invariant"); assert(sender_sp != NULL, "invariant"); - // First check if frame is complete and tester is reliable - // Unfortunately we can only check frame complete for runtime stubs and nmethod - // other generic buffer blobs are more problematic so we just assume they are - // ok. adapter blobs never have a frame complete and are never ok. + // First check if frame is complete and tester is reliable if (check && !_cb->is_frame_complete_at(pc)) { + // Adapter blobs never have a complete frame and are never ok. if (_cb->is_adapter_blob()) { return false; } @@ -146,6 +144,7 @@ bool CompiledMethod::FrameParser::sender_frame(JavaThread *thread, bool check, a assert(sender_pc != NULL, "invariant"); assert(sender_sp != NULL, "invariant"); + // First check if frame is complete and tester is reliable if (check && !_cb->is_frame_complete_at(pc)) { return false; } From 5433993cadfebf7ef20551e140682767b343bc93 Mon Sep 17 00:00:00 2001 From: Ludovic Henry Date: Mon, 19 Jul 2021 09:03:33 +0000 Subject: [PATCH 7/7] Remove FrameParser and the required allocation The need for the allocation would be it non async-safe. However, AsyncGetCallTrace is async-safe and thus can't allow for allocations. --- src/hotspot/cpu/aarch64/codeBlob_aarch64.cpp | 32 +++++------ src/hotspot/cpu/aarch64/frame_aarch64.cpp | 8 +-- src/hotspot/cpu/arm/codeBlob_arm.cpp | 30 +++++------ src/hotspot/cpu/arm/frame_arm.cpp | 8 +-- src/hotspot/cpu/ppc/codeBlob_ppc.cpp | 30 +++++------ src/hotspot/cpu/ppc/frame_ppc.cpp | 8 +-- src/hotspot/cpu/s390/codeBlob_s390.cpp | 30 +++++------ src/hotspot/cpu/s390/frame_s390.cpp | 8 +-- src/hotspot/cpu/x86/codeBlob_x86.cpp | 30 +++++------ src/hotspot/cpu/x86/frame_x86.cpp | 8 +-- src/hotspot/cpu/zero/codeBlob_zero.cpp | 12 ++--- src/hotspot/share/code/codeBlob.hpp | 54 +++---------------- src/hotspot/share/code/compiledMethod.hpp | 10 +--- src/hotspot/share/code/nmethod.hpp | 10 +--- .../jfr/periodic/sampling/jfrCallTrace.cpp | 4 +- 15 files changed, 105 insertions(+), 177 deletions(-) diff --git a/src/hotspot/cpu/aarch64/codeBlob_aarch64.cpp b/src/hotspot/cpu/aarch64/codeBlob_aarch64.cpp index 1f4f8593bd1d7..55e5112964033 100644 --- a/src/hotspot/cpu/aarch64/codeBlob_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/codeBlob_aarch64.cpp @@ -30,7 +30,7 @@ #include "interpreter/interpreter.hpp" #include "runtime/frame.hpp" -bool CodeBlob::FrameParser::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, +bool CodeBlob::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { // must be some sort of compiled/runtime frame // fp does not have to be safe (although it could be check for c1?) @@ -39,19 +39,19 @@ bool CodeBlob::FrameParser::sender_frame(JavaThread *thread, bool check, address assert(sender_sp != NULL, "invariant"); // First check if frame is complete and tester is reliable - if (check && !_cb->is_frame_complete_at(pc)) { + if (check && !is_frame_complete_at(pc)) { // Adapter blobs never have a complete frame and are never ok. - if (_cb->is_adapter_blob()) { + if (is_adapter_blob()) { return false; } } // check for a valid frame_size, otherwise we are unlikely to get a valid sender_pc - if (check && _cb->frame_size() <= 0) { + if (check && frame_size() <= 0) { return false; } - *sender_sp = unextended_sp + _cb->frame_size(); + *sender_sp = unextended_sp + frame_size(); // Is sender_sp safe? if (check && thread != NULL && !thread->is_in_full_stack_checked((address)*sender_sp)) { return false; @@ -65,7 +65,7 @@ bool CodeBlob::FrameParser::sender_frame(JavaThread *thread, bool check, address return true; } -bool InterpreterBlob::FrameParser::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, +bool InterpreterBlob::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { assert(sender_pc != NULL, "invariant"); @@ -88,44 +88,44 @@ bool InterpreterBlob::FrameParser::sender_frame(JavaThread *thread, bool check, return true; } -bool VtableBlob::FrameParser::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, +bool VtableBlob::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { - return CodeBlob::FrameParser::sender_frame(thread, check, pc, sp, unextended_sp, fp, fp_safe, + return CodeBlob::sender_frame(thread, check, pc, sp, unextended_sp, fp, fp_safe, sender_pc, sender_sp, sender_unextended_sp, saved_fp); } -bool StubRoutinesBlob::FrameParser::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, +bool StubRoutinesBlob::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { assert(sender_pc != NULL, "invariant"); assert(sender_sp != NULL, "invariant"); // First check if frame is complete and tester is reliable - if (check && !_cb->is_frame_complete_at(pc)) { + if (check && !is_frame_complete_at(pc)) { return false; } - return CodeBlob::FrameParser::sender_frame(thread, check, pc, sp, unextended_sp, fp, fp_safe, + return CodeBlob::sender_frame(thread, check, pc, sp, unextended_sp, fp, fp_safe, sender_pc, sender_sp, sender_unextended_sp, saved_fp); } -bool CompiledMethod::FrameParser::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, +bool CompiledMethod::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { assert(sender_pc != NULL, "invariant"); assert(sender_sp != NULL, "invariant"); // First check if frame is complete and tester is reliable - if (check && !_cb->is_frame_complete_at(pc)) { + if (check && !is_frame_complete_at(pc)) { return false; } - return CodeBlob::FrameParser::sender_frame(thread, check, pc, sp, unextended_sp, fp, fp_safe, + return CodeBlob::sender_frame(thread, check, pc, sp, unextended_sp, fp, fp_safe, sender_pc, sender_sp, sender_unextended_sp, saved_fp); } -bool nmethod::FrameParser::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, +bool nmethod::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { - return CompiledMethod::FrameParser::sender_frame(thread, check, pc, sp, unextended_sp, fp, fp_safe, + return CompiledMethod::sender_frame(thread, check, pc, sp, unextended_sp, fp, fp_safe, sender_pc, sender_sp, sender_unextended_sp, saved_fp); } diff --git a/src/hotspot/cpu/aarch64/frame_aarch64.cpp b/src/hotspot/cpu/aarch64/frame_aarch64.cpp index 8a961ccb265bf..4a5a090394870 100644 --- a/src/hotspot/cpu/aarch64/frame_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/frame_aarch64.cpp @@ -56,8 +56,6 @@ void RegisterMap::check_location_valid() { // Profiling/safepoint support bool frame::safe_for_sender(JavaThread *thread) { - ResourceMark rm; - address sp = (address)_sp; address fp = (address)_fp; address unextended_sp = (address)_unextended_sp; @@ -112,7 +110,7 @@ bool frame::safe_for_sender(JavaThread *thread) { intptr_t* sender_unextended_sp = NULL; address sender_pc = NULL; intptr_t** saved_fp = NULL; - if (!_cb->frame_parser()->sender_frame( + if (!_cb->sender_frame( thread, true, _pc, (intptr_t*)sp, (intptr_t*)unextended_sp, (intptr_t*)fp, fp_safe, &sender_pc, &sender_sp, &sender_unextended_sp, &saved_fp)) { return false; @@ -424,8 +422,6 @@ frame frame::sender_for_interpreter_frame(RegisterMap* map) const { //------------------------------------------------------------------------------ // frame::sender_for_compiled_frame frame frame::sender_for_compiled_frame(RegisterMap* map) const { - ResourceMark rm; - // 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 @@ -436,7 +432,7 @@ frame frame::sender_for_compiled_frame(RegisterMap* map) const { intptr_t* l_unextended_sp; address l_sender_pc; intptr_t** l_saved_fp; - _cb->frame_parser()->sender_frame( + _cb->sender_frame( NULL, false, pc(), sp(), unextended_sp(), fp(), true, &l_sender_pc, &l_sender_sp, &l_unextended_sp, &l_saved_fp); diff --git a/src/hotspot/cpu/arm/codeBlob_arm.cpp b/src/hotspot/cpu/arm/codeBlob_arm.cpp index 94ebaeff72dad..296d9dcad6c75 100644 --- a/src/hotspot/cpu/arm/codeBlob_arm.cpp +++ b/src/hotspot/cpu/arm/codeBlob_arm.cpp @@ -30,7 +30,7 @@ #include "interpreter/interpreter.hpp" #include "runtime/frame.hpp" -bool CodeBlob::FrameParser::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, +bool CodeBlob::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { // must be some sort of compiled/runtime frame // fp does not have to be safe (although it could be check for c1?) @@ -40,14 +40,14 @@ bool CodeBlob::FrameParser::sender_frame(JavaThread *thread, bool check, address // First check if frame is complete and tester is reliable - if (check && !_cb->is_frame_complete_at(pc)) { + if (check && !is_frame_complete_at(pc)) { // Adapter blobs never have a complete frame and are never ok. - if (_cb->is_adapter_blob()) { + if (is_adapter_blob()) { return false; } } - *sender_sp = unextended_sp + _cb->frame_size(); + *sender_sp = unextended_sp + frame_size(); // Is sender_sp safe? if (check && thread != NULL && !thread->is_in_full_stack_checked((address)*sender_sp)) { return false; @@ -62,7 +62,7 @@ bool CodeBlob::FrameParser::sender_frame(JavaThread *thread, bool check, address return true; } -bool InterpreterBlob::FrameParser::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, +bool InterpreterBlob::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { assert(sender_pc != NULL, "invariant"); @@ -79,44 +79,44 @@ bool InterpreterBlob::FrameParser::sender_frame(JavaThread *thread, bool check, return true; } -bool VtableBlob::FrameParser::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, +bool VtableBlob::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { - return CodeBlob::FrameParser::sender_frame(thread, check, pc, sp, unextended_sp, fp, fp_safe, + return CodeBlob::sender_frame(thread, check, pc, sp, unextended_sp, fp, fp_safe, sender_pc, sender_sp, sender_unextended_sp, saved_fp); } -bool StubRoutinesBlob::FrameParser::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, +bool StubRoutinesBlob::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { assert(sender_pc != NULL, "invariant"); assert(sender_sp != NULL, "invariant"); // First check if frame is complete and tester is reliable - if (check && !_cb->is_frame_complete_at(pc)) { + if (check && !is_frame_complete_at(pc)) { return false; } - return CodeBlob::FrameParser::sender_frame(thread, check, pc, sp, unextended_sp, fp, fp_safe, + return CodeBlob::sender_frame(thread, check, pc, sp, unextended_sp, fp, fp_safe, sender_pc, sender_sp, sender_unextended_sp, saved_fp); } -bool CompiledMethod::FrameParser::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, +bool CompiledMethod::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { assert(sender_pc != NULL, "invariant"); assert(sender_sp != NULL, "invariant"); // First check if frame is complete and tester is reliable - if (check && !_cb->is_frame_complete_at(pc)) { + if (check && !is_frame_complete_at(pc)) { return false; } - return CodeBlob::FrameParser::sender_frame(thread, check, pc, sp, unextended_sp, fp, fp_safe, + return CodeBlob::sender_frame(thread, check, pc, sp, unextended_sp, fp, fp_safe, sender_pc, sender_sp, sender_unextended_sp, saved_fp); } -bool nmethod::FrameParser::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, +bool nmethod::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { - return CompiledMethod::FrameParser::sender_frame(thread, check, pc, sp, unextended_sp, fp, fp_safe, + return CompiledMethod::sender_frame(thread, check, pc, sp, unextended_sp, fp, fp_safe, sender_pc, sender_sp, sender_unextended_sp, saved_fp); } diff --git a/src/hotspot/cpu/arm/frame_arm.cpp b/src/hotspot/cpu/arm/frame_arm.cpp index a9c7e623a9e7c..eb3cbc4306dd3 100644 --- a/src/hotspot/cpu/arm/frame_arm.cpp +++ b/src/hotspot/cpu/arm/frame_arm.cpp @@ -54,8 +54,6 @@ void RegisterMap::check_location_valid() { // Profiling/safepoint support bool frame::safe_for_sender(JavaThread *thread) { - ResourceMark rm; - address sp = (address)_sp; address fp = (address)_fp; address unextended_sp = (address)_unextended_sp; @@ -89,7 +87,7 @@ bool frame::safe_for_sender(JavaThread *thread) { intptr_t* sender_sp = NULL; address sender_pc = NULL; - if (!_cb->frame_parser()->sender_frame( + if (!_cb->sender_frame( thread, true, _pc, (intptr_t*)sp, (intptr_t*)unextended_sp, (intptr_t*)fp, fp_safe, &sender_pc, &sender_sp, NULL, NULL)) { return false; @@ -366,8 +364,6 @@ frame frame::sender_for_interpreter_frame(RegisterMap* map) const { } frame frame::sender_for_compiled_frame(RegisterMap* map) const { - ResourceMark rm; - assert(map != NULL, "map must be set"); // frame owned by optimizing compiler @@ -378,7 +374,7 @@ frame frame::sender_for_compiled_frame(RegisterMap* map) const { intptr_t* l_unextended_sp; address l_sender_pc; intptr_t** l_saved_fp; - _cb->frame_parser()->sender_frame( + _cb->sender_frame( NULL, false, pc(), sp(), unextended_sp(), fp(), true, &l_sender_pc, &l_sender_sp, &l_unextended_sp, &l_saved_fp); diff --git a/src/hotspot/cpu/ppc/codeBlob_ppc.cpp b/src/hotspot/cpu/ppc/codeBlob_ppc.cpp index 12deed1caa610..18c4ab68fad94 100644 --- a/src/hotspot/cpu/ppc/codeBlob_ppc.cpp +++ b/src/hotspot/cpu/ppc/codeBlob_ppc.cpp @@ -30,7 +30,7 @@ #include "interpreter/interpreter.hpp" #include "runtime/frame.hpp" -bool CodeBlob::FrameParser::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, +bool CodeBlob::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { // must be some sort of compiled/runtime frame // fp does not have to be safe (although it could be check for c1?) @@ -40,9 +40,9 @@ bool CodeBlob::FrameParser::sender_frame(JavaThread *thread, bool check, address // First check if frame is complete and tester is reliable - if (check && !_cb->is_frame_complete_at(pc)) { + if (check && !is_frame_complete_at(pc)) { // Adapter blobs never have a complete frame and are never ok. - if (_cb->is_adapter_blob()) { + if (is_adapter_blob()) { return false; } } @@ -54,50 +54,50 @@ bool CodeBlob::FrameParser::sender_frame(JavaThread *thread, bool check, address return true; } -bool InterpreterBlob::FrameParser::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, +bool InterpreterBlob::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { - return CodeBlob::FrameParser::sender_frame(thread, check, pc, sp, unextended_sp, fp, fp_safe, + return CodeBlob::sender_frame(thread, check, pc, sp, unextended_sp, fp, fp_safe, sender_pc, sender_sp, sender_unextended_sp, saved_fp); } -bool VtableBlob::FrameParser::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, +bool VtableBlob::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { - return CodeBlob::FrameParser::sender_frame(thread, check, pc, sp, unextended_sp, fp, fp_safe, + return CodeBlob::sender_frame(thread, check, pc, sp, unextended_sp, fp, fp_safe, sender_pc, sender_sp, sender_unextended_sp, saved_fp); } -bool StubRoutinesBlob::FrameParser::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, +bool StubRoutinesBlob::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { assert(sender_pc != NULL, "invariant"); assert(sender_sp != NULL, "invariant"); // First check if frame is complete and tester is reliable - if (check && !_cb->is_frame_complete_at(pc)) { + if (check && !is_frame_complete_at(pc)) { return false; } - return CodeBlob::FrameParser::sender_frame(thread, check, pc, sp, unextended_sp, fp, fp_safe, + return CodeBlob::sender_frame(thread, check, pc, sp, unextended_sp, fp, fp_safe, sender_pc, sender_sp, sender_unextended_sp, saved_fp); } -bool CompiledMethod::FrameParser::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, +bool CompiledMethod::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { assert(sender_pc != NULL, "invariant"); assert(sender_sp != NULL, "invariant"); // First check if frame is complete and tester is reliable - if (check && !_cb->is_frame_complete_at(pc)) { + if (check && !is_frame_complete_at(pc)) { return false; } - return CodeBlob::FrameParser::sender_frame(thread, check, pc, sp, unextended_sp, fp, fp_safe, + return CodeBlob::sender_frame(thread, check, pc, sp, unextended_sp, fp, fp_safe, sender_pc, sender_sp, sender_unextended_sp, saved_fp); } -bool nmethod::FrameParser::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, +bool nmethod::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { - return CompiledMethod::FrameParser::sender_frame(thread, check, pc, sp, unextended_sp, fp, fp_safe, + return CompiledMethod::sender_frame(thread, check, pc, sp, unextended_sp, fp, fp_safe, sender_pc, sender_sp, sender_unextended_sp, saved_fp); } diff --git a/src/hotspot/cpu/ppc/frame_ppc.cpp b/src/hotspot/cpu/ppc/frame_ppc.cpp index 402ad28e11830..f9bb57ed33226 100644 --- a/src/hotspot/cpu/ppc/frame_ppc.cpp +++ b/src/hotspot/cpu/ppc/frame_ppc.cpp @@ -52,8 +52,6 @@ void RegisterMap::check_location_valid() { #endif // ASSERT bool frame::safe_for_sender(JavaThread *thread) { - ResourceMark rm; - bool safe = false; address sp = (address)_sp; address fp = (address)_fp; @@ -100,7 +98,7 @@ bool frame::safe_for_sender(JavaThread *thread) { intptr_t* sender_sp = NULL; address sender_pc = NULL; - if (!_cb->frame_parser()->sender_frame( + if (!_cb->sender_frame( thread, true, _pc, (intptr_t*)sp, (intptr_t*)unextended_sp, (intptr_t*)fp, fp_safe, &sender_pc, &sender_sp, NULL, NULL)) { return false; @@ -203,15 +201,13 @@ frame frame::sender_for_interpreter_frame(RegisterMap *map) const { } frame frame::sender_for_compiled_frame(RegisterMap *map) const { - ResourceMark rm; - assert(map != NULL, "map must be set"); // Frame owned by compiler. intptr_t* l_sender_sp; address l_sender_pc; - _cb->frame_parser()->sender_frame( + _cb->sender_frame( NULL, false, pc(), sp(), unextended_sp(), fp(), true, &l_sender_pc, &l_sender_sp, NULL, NULL); diff --git a/src/hotspot/cpu/s390/codeBlob_s390.cpp b/src/hotspot/cpu/s390/codeBlob_s390.cpp index 196505019ca7c..f2f642f0f3029 100644 --- a/src/hotspot/cpu/s390/codeBlob_s390.cpp +++ b/src/hotspot/cpu/s390/codeBlob_s390.cpp @@ -30,7 +30,7 @@ #include "interpreter/interpreter.hpp" #include "runtime/frame.hpp" -bool CodeBlob::FrameParser::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, +bool CodeBlob::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { // must be some sort of compiled/runtime frame // fp does not have to be safe (although it could be check for c1?) @@ -40,9 +40,9 @@ bool CodeBlob::FrameParser::sender_frame(JavaThread *thread, bool check, address // First check if frame is complete and tester is reliable - if (check && !_cb->is_frame_complete_at(pc)) { + if (check && !is_frame_complete_at(pc)) { // Adapter blobs never have a complete frame and are never ok. - if (_cb->is_adapter_blob()) { + if (is_adapter_blob()) { return false; } } @@ -54,50 +54,50 @@ bool CodeBlob::FrameParser::sender_frame(JavaThread *thread, bool check, address return true; } -bool InterpreterBlob::FrameParser::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, +bool InterpreterBlob::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { - return CodeBlob::FrameParser::sender_frame(thread, check, pc, sp, unextended_sp, fp, fp_safe, + return CodeBlob::sender_frame(thread, check, pc, sp, unextended_sp, fp, fp_safe, sender_pc, sender_sp, sender_unextended_sp, saved_fp); } -bool VtableBlob::FrameParser::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, +bool VtableBlob::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { - return CodeBlob::FrameParser::sender_frame(thread, check, pc, sp, unextended_sp, fp, fp_safe, + return CodeBlob::sender_frame(thread, check, pc, sp, unextended_sp, fp, fp_safe, sender_pc, sender_sp, sender_unextended_sp, saved_fp); } -bool StubRoutinesBlob::FrameParser::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, +bool StubRoutinesBlob::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { assert(sender_pc != NULL, "invariant"); assert(sender_sp != NULL, "invariant"); // First check if frame is complete and tester is reliable - if (check && !_cb->is_frame_complete_at(pc)) { + if (check && !is_frame_complete_at(pc)) { return false; } - return CodeBlob::FrameParser::sender_frame(thread, check, pc, sp, unextended_sp, fp, fp_safe, + return CodeBlob::sender_frame(thread, check, pc, sp, unextended_sp, fp, fp_safe, sender_pc, sender_sp, sender_unextended_sp, saved_fp); } -bool CompiledMethod::FrameParser::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, +bool CompiledMethod::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { assert(sender_pc != NULL, "invariant"); assert(sender_sp != NULL, "invariant"); // First check if frame is complete and tester is reliable - if (check && !_cb->is_frame_complete_at(pc)) { + if (check && !is_frame_complete_at(pc)) { return false; } - return CodeBlob::FrameParser::sender_frame(thread, check, pc, sp, unextended_sp, fp, fp_safe, + return CodeBlob::sender_frame(thread, check, pc, sp, unextended_sp, fp, fp_safe, sender_pc, sender_sp, sender_unextended_sp, saved_fp); } -bool nmethod::FrameParser::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, +bool nmethod::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { - return CompiledMethod::FrameParser::sender_frame(thread, check, pc, sp, unextended_sp, fp, fp_safe, + return CompiledMethod::sender_frame(thread, check, pc, sp, unextended_sp, fp, fp_safe, sender_pc, sender_sp, sender_unextended_sp, saved_fp); } diff --git a/src/hotspot/cpu/s390/frame_s390.cpp b/src/hotspot/cpu/s390/frame_s390.cpp index e6aac725ecf53..bb0d54a2e713d 100644 --- a/src/hotspot/cpu/s390/frame_s390.cpp +++ b/src/hotspot/cpu/s390/frame_s390.cpp @@ -55,8 +55,6 @@ void RegisterMap::check_location_valid() { // Profiling/safepoint support bool frame::safe_for_sender(JavaThread *thread) { - ResourceMark rm; - bool safe = false; address sp = (address)_sp; address fp = (address)_fp; @@ -114,7 +112,7 @@ bool frame::safe_for_sender(JavaThread *thread) { intptr_t* sender_sp = NULL; address sender_pc = NULL; - if (!_cb->frame_parser()->sender_frame( + if (!_cb->sender_frame( thread, true, _pc, (intptr_t*)sp, (intptr_t*)unextended_sp, (intptr_t*)fp, fp_safe, &sender_pc, &sender_sp, NULL, NULL)) { return false; @@ -225,15 +223,13 @@ frame frame::sender_for_interpreter_frame(RegisterMap *map) const { } frame frame::sender_for_compiled_frame(RegisterMap *map) const { - ResourceMark rm; - assert(map != NULL, "map must be set"); // Frame owned by compiler. intptr_t* l_sender_sp; address l_sender_pc; - _cb->frame_parser()->sender_frame( + _cb->sender_frame( NULL, false, pc(), sp(), unextended_sp(), fp(), true, &l_sender_pc, &l_sender_sp, NULL, NULL); diff --git a/src/hotspot/cpu/x86/codeBlob_x86.cpp b/src/hotspot/cpu/x86/codeBlob_x86.cpp index 3b8423edf3bd5..116fac1707160 100644 --- a/src/hotspot/cpu/x86/codeBlob_x86.cpp +++ b/src/hotspot/cpu/x86/codeBlob_x86.cpp @@ -31,7 +31,7 @@ #include "interpreter/interpreter.hpp" #include "runtime/frame.hpp" -bool CodeBlob::FrameParser::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, +bool CodeBlob::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { // must be some sort of compiled/runtime frame // fp does not have to be safe (although it could be check for c1?) @@ -41,19 +41,19 @@ bool CodeBlob::FrameParser::sender_frame(JavaThread *thread, bool check, address // First check if frame is complete and tester is reliable - if (check && !_cb->is_frame_complete_at(pc)) { + if (check && !is_frame_complete_at(pc)) { // Adapter blobs never have a complete frame and are never ok. - if (_cb->is_adapter_blob()) { + if (is_adapter_blob()) { return false; } } // check for a valid frame_size, otherwise we are unlikely to get a valid sender_pc - if (check && _cb->frame_size() <= 0) { + if (check && frame_size() <= 0) { return false; } - *sender_sp = unextended_sp + _cb->frame_size(); + *sender_sp = unextended_sp + frame_size(); // Is sender_sp safe? if (check && thread != NULL && !thread->is_in_full_stack_checked((address)*sender_sp)) { return false; @@ -68,7 +68,7 @@ bool CodeBlob::FrameParser::sender_frame(JavaThread *thread, bool check, address return true; } -bool InterpreterBlob::FrameParser::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, +bool InterpreterBlob::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { assert(sender_pc != NULL, "invariant"); @@ -91,7 +91,7 @@ bool InterpreterBlob::FrameParser::sender_frame(JavaThread *thread, bool check, return true; } -bool VtableBlob::FrameParser::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, +bool VtableBlob::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { assert(sender_pc != NULL, "invariant"); @@ -112,7 +112,7 @@ bool VtableBlob::FrameParser::sender_frame(JavaThread *thread, bool check, addre return true; } -bool StubRoutinesBlob::FrameParser::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, +bool StubRoutinesBlob::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { assert(sender_pc != NULL, "invariant"); @@ -138,34 +138,34 @@ bool StubRoutinesBlob::FrameParser::sender_frame(JavaThread *thread, bool check, return true; } -bool CompiledMethod::FrameParser::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, +bool CompiledMethod::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { assert(sender_pc != NULL, "invariant"); assert(sender_sp != NULL, "invariant"); // First check if frame is complete and tester is reliable - if (check && !_cb->is_frame_complete_at(pc)) { + if (check && !is_frame_complete_at(pc)) { return false; } - return CodeBlob::FrameParser::sender_frame(thread, check, pc, sp, unextended_sp, fp, fp_safe, + return CodeBlob::sender_frame(thread, check, pc, sp, unextended_sp, fp, fp_safe, sender_pc, sender_sp, sender_unextended_sp, saved_fp); } -bool nmethod::FrameParser::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, +bool nmethod::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { assert(sender_pc != NULL, "invariant"); assert(sender_sp != NULL, "invariant"); - if (_cb->is_compiled_by_c1() || _cb->is_compiled_by_c2()) { + if (is_compiled_by_c1() || is_compiled_by_c2()) { // We landed on the prolog which looks like: // mov %eax,-0x16000(%rsp) == stack banging // push %rbp // sub N, %rsp // Let's first figure out which instruction we're on - int offset = pc - _cb->as_nmethod()->verified_entry_point(); + int offset = pc - as_nmethod()->verified_entry_point(); // If it's stack banging or `push %rbp`, %rsp hasn't been modified by this method if (offset == 0 /* stack banging */ || offset == 7 /* `push %rbp` */) { if (check && thread != NULL && !thread->is_in_full_stack_checked((address)sp)) { @@ -206,6 +206,6 @@ bool nmethod::FrameParser::sender_frame(JavaThread *thread, bool check, address } } - return CompiledMethod::FrameParser::sender_frame(thread, check, pc, sp, unextended_sp, fp, fp_safe, + return CompiledMethod::sender_frame(thread, check, pc, sp, unextended_sp, fp, fp_safe, sender_pc, sender_sp, sender_unextended_sp, saved_fp); } diff --git a/src/hotspot/cpu/x86/frame_x86.cpp b/src/hotspot/cpu/x86/frame_x86.cpp index c2b6368b8348d..ce89f4cbcf6df 100644 --- a/src/hotspot/cpu/x86/frame_x86.cpp +++ b/src/hotspot/cpu/x86/frame_x86.cpp @@ -54,8 +54,6 @@ void RegisterMap::check_location_valid() { // Profiling/safepoint support bool frame::safe_for_sender(JavaThread *thread) { - ResourceMark rm; - address sp = (address)_sp; address fp = (address)_fp; address unextended_sp = (address)_unextended_sp; @@ -103,7 +101,7 @@ bool frame::safe_for_sender(JavaThread *thread) { intptr_t* sender_unextended_sp = NULL; address sender_pc = NULL; intptr_t** saved_fp = NULL; - if (!_cb->frame_parser()->sender_frame( + if (!_cb->sender_frame( thread, true, _pc, (intptr_t*)sp, (intptr_t*)unextended_sp, (intptr_t*)fp, fp_safe, &sender_pc, &sender_sp, &sender_unextended_sp, &saved_fp)) { return false; @@ -437,8 +435,6 @@ frame frame::sender_for_interpreter_frame(RegisterMap* map) const { //------------------------------------------------------------------------------ // frame::sender_for_compiled_frame frame frame::sender_for_compiled_frame(RegisterMap* map) const { - ResourceMark rm; - assert(map != NULL, "map must be set"); // frame owned by optimizing compiler @@ -449,7 +445,7 @@ frame frame::sender_for_compiled_frame(RegisterMap* map) const { intptr_t* l_unextended_sp = NULL; address l_sender_pc = NULL; intptr_t** l_saved_fp = NULL; - _cb->frame_parser()->sender_frame( + _cb->sender_frame( NULL, false, pc(), sp(), unextended_sp(), fp(), true, &l_sender_pc, &l_sender_sp, &l_unextended_sp, &l_saved_fp); diff --git a/src/hotspot/cpu/zero/codeBlob_zero.cpp b/src/hotspot/cpu/zero/codeBlob_zero.cpp index 417589b9c01a2..3b2debe057a9b 100644 --- a/src/hotspot/cpu/zero/codeBlob_zero.cpp +++ b/src/hotspot/cpu/zero/codeBlob_zero.cpp @@ -30,37 +30,37 @@ #include "interpreter/interpreter.hpp" #include "runtime/frame.hpp" -bool CodeBlob::FrameParser::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, +bool CodeBlob::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { ShouldNotCallThis(); return false; } -bool InterpreterBlob::FrameParser::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, +bool InterpreterBlob::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { ShouldNotCallThis(); return false; } -bool VtableBlob::FrameParser::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, +bool VtableBlob::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { ShouldNotCallThis(); return false; } -bool StubRoutinesBlob::FrameParser::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, +bool StubRoutinesBlob::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { ShouldNotCallThis(); return false; } -bool CompiledMethod::FrameParser::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, +bool CompiledMethod::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { ShouldNotCallThis(); return false; } -bool nmethod::FrameParser::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, +bool nmethod::sender_frame(JavaThread *thread, bool check, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp) { ShouldNotCallThis(); return false; diff --git a/src/hotspot/share/code/codeBlob.hpp b/src/hotspot/share/code/codeBlob.hpp index c7ef4d69bad2c..a56599a52382d 100644 --- a/src/hotspot/share/code/codeBlob.hpp +++ b/src/hotspot/share/code/codeBlob.hpp @@ -198,16 +198,8 @@ class CodeBlob { int frame_complete_offset() const { return _frame_complete_offset; } // Profiling/safepoint support - class FrameParser: public ResourceObj { - protected: - const CodeBlob* _cb; - public: - FrameParser(const CodeBlob* cb) : _cb(cb) {} - virtual bool sender_frame(JavaThread *thread, bool check_frame_complete, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, - address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp); - }; - - virtual FrameParser* frame_parser() const { return new FrameParser(this); } + virtual bool sender_frame(JavaThread *thread, bool check_frame_complete, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, + address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp); // CodeCache support: really only used by the nmethods, but in order to get // asserts and certain bookkeeping to work in the CodeCache they are defined @@ -374,12 +366,6 @@ class RuntimeBlob : public CodeBlob { bool caller_must_gc_arguments = false ); - // Profiling/safepoint support - class FrameParser : public CodeBlob::FrameParser { - public: - FrameParser(const RuntimeBlob* cb) : CodeBlob::FrameParser(cb) {} - }; - // GC support virtual bool is_alive() const = 0; @@ -431,12 +417,6 @@ class BufferBlob: public RuntimeBlob { // Typing virtual bool is_buffer_blob() const { return true; } - // Profiling/safepoint support - class FrameParser : public RuntimeBlob::FrameParser { - public: - FrameParser(const BufferBlob* cb) : RuntimeBlob::FrameParser(cb) {} - }; - // GC/Verification support void preserve_callee_argument_oops(frame fr, const RegisterMap* reg_map, OopClosure* f) { /* nothing to do */ } bool is_alive() const { return true; } @@ -477,14 +457,8 @@ class VtableBlob: public BufferBlob { virtual bool is_vtable_blob() const { return true; } // Profiling/safepoint support - class FrameParser : public BufferBlob::FrameParser { - public: - FrameParser(const VtableBlob* cb) : BufferBlob::FrameParser(cb) {} - virtual bool sender_frame(JavaThread *thread, bool check_frame_complete, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, - address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp); - }; - - virtual FrameParser* frame_parser() const { return new FrameParser(this); } + virtual bool sender_frame(JavaThread *thread, bool check_frame_complete, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, + address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp); }; //---------------------------------------------------------------------------------------------------- @@ -518,14 +492,8 @@ class InterpreterBlob: public BufferBlob { virtual bool is_interpreter_blob() const { return true; } // Profiling/safepoint support - class FrameParser : public BufferBlob::FrameParser { - public: - FrameParser(const InterpreterBlob* cb) : BufferBlob::FrameParser(cb) {} - virtual bool sender_frame(JavaThread *thread, bool check_frame_complete, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, - address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp); - }; - - virtual FrameParser* frame_parser() const { return new FrameParser(this); } + virtual bool sender_frame(JavaThread *thread, bool check_frame_complete, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, + address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp); }; @@ -544,14 +512,8 @@ class StubRoutinesBlob: public BufferBlob { virtual bool is_stub_routines_blob() const { return true; } // Profiling/safepoint support - class FrameParser : public BufferBlob::FrameParser { - public: - FrameParser(const StubRoutinesBlob* cb) : BufferBlob::FrameParser(cb) {} - virtual bool sender_frame(JavaThread *thread, bool check_frame_complete, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, - address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp); - }; - - virtual FrameParser* frame_parser() const { return new FrameParser(this); } + virtual bool sender_frame(JavaThread *thread, bool check_frame_complete, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, + address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp); }; diff --git a/src/hotspot/share/code/compiledMethod.hpp b/src/hotspot/share/code/compiledMethod.hpp index 7a261c43cbdad..7c1ac5a5722b2 100644 --- a/src/hotspot/share/code/compiledMethod.hpp +++ b/src/hotspot/share/code/compiledMethod.hpp @@ -401,14 +401,8 @@ class CompiledMethod : public CodeBlob { public: // Profiling/safepoint support - class FrameParser : public CodeBlob::FrameParser { - public: - FrameParser(const CompiledMethod* cb) : CodeBlob::FrameParser(cb) {} - virtual bool sender_frame(JavaThread *thread, bool check_frame_complete, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, - address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp); - }; - - virtual FrameParser* frame_parser() const { return new FrameParser(this); } + virtual bool sender_frame(JavaThread *thread, bool check_frame_complete, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, + address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp); private: PcDesc* find_pc_desc(address pc, bool approximate) { diff --git a/src/hotspot/share/code/nmethod.hpp b/src/hotspot/share/code/nmethod.hpp index d400485ddfe1b..cb2682886c58b 100644 --- a/src/hotspot/share/code/nmethod.hpp +++ b/src/hotspot/share/code/nmethod.hpp @@ -757,14 +757,8 @@ class nmethod : public CompiledMethod { public: // Profiling/safepoint support - class FrameParser : public CompiledMethod::FrameParser { - public: - FrameParser(const nmethod* cb) : CompiledMethod::FrameParser(cb) {} - virtual bool sender_frame(JavaThread *thread, bool check_frame_complete, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, - address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp); - }; - - virtual FrameParser* frame_parser() const { return new FrameParser(this); } + virtual bool sender_frame(JavaThread *thread, bool check_frame_complete, address pc, intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, bool fp_safe, + address* sender_pc, intptr_t** sender_sp, intptr_t** sender_unextended_sp, intptr_t*** saved_fp); }; // Locks an nmethod so its code will not get removed and it will not diff --git a/src/hotspot/share/jfr/periodic/sampling/jfrCallTrace.cpp b/src/hotspot/share/jfr/periodic/sampling/jfrCallTrace.cpp index c822c1be1a0fc..b8a03408654ae 100644 --- a/src/hotspot/share/jfr/periodic/sampling/jfrCallTrace.cpp +++ b/src/hotspot/share/jfr/periodic/sampling/jfrCallTrace.cpp @@ -82,9 +82,7 @@ bool JfrGetCallTrace::find_top_frame(frame& top_frame, Method** method, frame& f return true; } - if (!candidate.safe_for_sender(_thread) || - candidate.is_stub_frame() || - candidate.cb()->frame_size() <= 0) { + if (!candidate.safe_for_sender(_thread)) { return false; }