diff --git a/src/hotspot/cpu/aarch64/codeBlob_aarch64.cpp b/src/hotspot/cpu/aarch64/codeBlob_aarch64.cpp new file mode 100644 index 0000000000000..55e5112964033 --- /dev/null +++ b/src/hotspot/cpu/aarch64/codeBlob_aarch64.cpp @@ -0,0 +1,131 @@ +/* + * 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 "code/nmethod.hpp" +#include "interpreter/interpreter.hpp" +#include "runtime/frame.hpp" + +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?) + + assert(sender_pc != NULL, "invariant"); + assert(sender_sp != NULL, "invariant"); + + // First check if frame is complete and tester is reliable + if (check && !is_frame_complete_at(pc)) { + // Adapter blobs never have a complete frame and are never ok. + if (is_adapter_blob()) { + return false; + } + } + + // check for a valid frame_size, otherwise we are unlikely to get a valid sender_pc + if (check && frame_size() <= 0) { + return false; + } + + *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; + } + *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::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; +} + +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::sender_frame(thread, check, pc, sp, unextended_sp, fp, fp_safe, + sender_pc, sender_sp, sender_unextended_sp, saved_fp); +} + +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 && !is_frame_complete_at(pc)) { + return false; + } + + return CodeBlob::sender_frame(thread, check, pc, sp, unextended_sp, fp, fp_safe, + sender_pc, sender_sp, sender_unextended_sp, saved_fp); +} + +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 && !is_frame_complete_at(pc)) { + return false; + } + + return CodeBlob::sender_frame(thread, check, pc, sp, unextended_sp, fp, fp_safe, + sender_pc, sender_sp, sender_unextended_sp, saved_fp); +} + +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::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 dd12c177ddc5c..4a5a090394870 100644 --- a/src/hotspot/cpu/aarch64/frame_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/frame_aarch64.cpp @@ -95,17 +95,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; @@ -117,46 +106,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->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 +123,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 +158,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(); @@ -468,13 +427,14 @@ frame frame::sender_for_compiled_frame(RegisterMap* map) const { // 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->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"); @@ -492,10 +452,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..296d9dcad6c75 --- /dev/null +++ b/src/hotspot/cpu/arm/codeBlob_arm.cpp @@ -0,0 +1,122 @@ +/* + * 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 "code/nmethod.hpp" +#include "interpreter/interpreter.hpp" +#include "runtime/frame.hpp" + +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?) + + assert(sender_pc != NULL, "invariant"); + assert(sender_sp != NULL, "invariant"); + + + // First check if frame is complete and tester is reliable + if (check && !is_frame_complete_at(pc)) { + // Adapter blobs never have a complete frame and are never ok. + if (is_adapter_blob()) { + return false; + } + } + + *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; + } + // 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::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; +} + +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::sender_frame(thread, check, pc, sp, unextended_sp, fp, fp_safe, + sender_pc, sender_sp, sender_unextended_sp, saved_fp); +} + +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 && !is_frame_complete_at(pc)) { + return false; + } + + return CodeBlob::sender_frame(thread, check, pc, sp, unextended_sp, fp, fp_safe, + sender_pc, sender_sp, sender_unextended_sp, saved_fp); +} + +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 && !is_frame_complete_at(pc)) { + return false; + } + + return CodeBlob::sender_frame(thread, check, pc, sp, unextended_sp, fp, fp_safe, + sender_pc, sender_sp, sender_unextended_sp, saved_fp); +} + +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::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 b3fd82b063755..eb3cbc4306dd3 100644 --- a/src/hotspot/cpu/arm/frame_arm.cpp +++ b/src/hotspot/cpu/arm/frame_arm.cpp @@ -74,17 +74,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; @@ -98,28 +87,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->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 @@ -396,15 +367,16 @@ frame frame::sender_for_compiled_frame(RegisterMap* map) const { assert(map != NULL, "map must be set"); // frame owned by optimizing compiler - assert(_cb->frame_size() >= 0, "must have non-zero frame size"); - intptr_t* sender_sp = unextended_sp() + _cb->frame_size(); - intptr_t* unextended_sp = sender_sp; - address sender_pc = (address) *(sender_sp - sender_sp_offset + return_addr_offset); + 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->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. @@ -418,11 +390,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..18c4ab68fad94 --- /dev/null +++ b/src/hotspot/cpu/ppc/codeBlob_ppc.cpp @@ -0,0 +1,103 @@ +/* + * 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 "code/nmethod.hpp" +#include "interpreter/interpreter.hpp" +#include "runtime/frame.hpp" + +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?) + + assert(sender_pc != NULL, "invariant"); + assert(sender_sp != NULL, "invariant"); + + + // First check if frame is complete and tester is reliable + if (check && !is_frame_complete_at(pc)) { + // Adapter blobs never have a complete frame and are never ok. + if (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; + + return true; +} + +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::sender_frame(thread, check, pc, sp, unextended_sp, fp, fp_safe, + sender_pc, sender_sp, sender_unextended_sp, saved_fp); +} + +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::sender_frame(thread, check, pc, sp, unextended_sp, fp, fp_safe, + sender_pc, sender_sp, sender_unextended_sp, saved_fp); +} + +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 && !is_frame_complete_at(pc)) { + return false; + } + + return CodeBlob::sender_frame(thread, check, pc, sp, unextended_sp, fp, fp_safe, + sender_pc, sender_sp, sender_unextended_sp, saved_fp); +} + +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 && !is_frame_complete_at(pc)) { + return false; + } + + return CodeBlob::sender_frame(thread, check, pc, sp, unextended_sp, fp, fp_safe, + sender_pc, sender_sp, sender_unextended_sp, saved_fp); +} + +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::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 3d0f4ab074166..f9bb57ed33226 100644 --- a/src/hotspot/cpu/ppc/frame_ppc.cpp +++ b/src/hotspot/cpu/ppc/frame_ppc.cpp @@ -87,17 +87,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; @@ -107,9 +96,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->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); @@ -211,8 +204,12 @@ frame frame::sender_for_compiled_frame(RegisterMap *map) const { assert(map != NULL, "map must be set"); // Frame owned by compiler. - address pc = *compiled_sender_pc_addr(_cb); - frame caller(compiled_sender_sp(_cb), pc); + + intptr_t* l_sender_sp; + address l_sender_pc; + _cb->sender_frame( + NULL, false, pc(), sp(), unextended_sp(), fp(), true, + &l_sender_pc, &l_sender_sp, NULL, NULL); // Now adjust the map. @@ -225,15 +222,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..f2f642f0f3029 --- /dev/null +++ b/src/hotspot/cpu/s390/codeBlob_s390.cpp @@ -0,0 +1,103 @@ +/* + * 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 "code/nmethod.hpp" +#include "interpreter/interpreter.hpp" +#include "runtime/frame.hpp" + +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?) + + assert(sender_pc != NULL, "invariant"); + assert(sender_sp != NULL, "invariant"); + + + // First check if frame is complete and tester is reliable + if (check && !is_frame_complete_at(pc)) { + // Adapter blobs never have a complete frame and are never ok. + if (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; + + return true; +} + +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::sender_frame(thread, check, pc, sp, unextended_sp, fp, fp_safe, + sender_pc, sender_sp, sender_unextended_sp, saved_fp); +} + +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::sender_frame(thread, check, pc, sp, unextended_sp, fp, fp_safe, + sender_pc, sender_sp, sender_unextended_sp, saved_fp); +} + +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 && !is_frame_complete_at(pc)) { + return false; + } + + return CodeBlob::sender_frame(thread, check, pc, sp, unextended_sp, fp, fp_safe, + sender_pc, sender_sp, sender_unextended_sp, saved_fp); +} + +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 && !is_frame_complete_at(pc)) { + return false; + } + + return CodeBlob::sender_frame(thread, check, pc, sp, unextended_sp, fp, fp_safe, + sender_pc, sender_sp, sender_unextended_sp, saved_fp); +} + +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::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 11d0b4a1217fa..bb0d54a2e713d 100644 --- a/src/hotspot/cpu/s390/frame_s390.cpp +++ b/src/hotspot/cpu/s390/frame_s390.cpp @@ -110,9 +110,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->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); @@ -220,10 +224,14 @@ frame frame::sender_for_interpreter_frame(RegisterMap *map) const { frame frame::sender_for_compiled_frame(RegisterMap *map) const { assert(map != NULL, "map must be set"); + // Frame owned by compiler. - address pc = *compiled_sender_pc_addr(_cb); - frame caller(compiled_sender_sp(_cb), pc); + intptr_t* l_sender_sp; + address l_sender_pc; + _cb->sender_frame( + NULL, false, pc(), sp(), unextended_sp(), fp(), true, + &l_sender_pc, &l_sender_sp, NULL, NULL); // Now adjust the map. @@ -236,7 +244,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..116fac1707160 --- /dev/null +++ b/src/hotspot/cpu/x86/codeBlob_x86.cpp @@ -0,0 +1,211 @@ +/* + * 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/codeCache.hpp" +#include "code/compiledMethod.hpp" +#include "code/nmethod.hpp" +#include "interpreter/interpreter.hpp" +#include "runtime/frame.hpp" + +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?) + + assert(sender_pc != NULL, "invariant"); + assert(sender_sp != NULL, "invariant"); + + + // First check if frame is complete and tester is reliable + if (check && !is_frame_complete_at(pc)) { + // Adapter blobs never have a complete frame and are never ok. + if (is_adapter_blob()) { + return false; + } + } + + // check for a valid frame_size, otherwise we are unlikely to get a valid sender_pc + if (check && frame_size() <= 0) { + return false; + } + + *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; + } + // 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::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; +} + +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"); + assert(sender_sp != NULL, "invariant"); + + *sender_sp = unextended_sp; + // 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::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::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_sp = fp + frame::sender_sp_offset; + // Is sender_sp safe? + if (check && 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; +} + +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 && !is_frame_complete_at(pc)) { + return false; + } + + return CodeBlob::sender_frame(thread, check, pc, sp, unextended_sp, fp, fp_safe, + sender_pc, sender_sp, sender_unextended_sp, saved_fp); +} + +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 (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 - 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)) { + 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 (check && thread != NULL && !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::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 b36ef8087c226..ce89f4cbcf6df 100644 --- a/src/hotspot/cpu/x86/frame_x86.cpp +++ b/src/hotspot/cpu/x86/frame_x86.cpp @@ -69,9 +69,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 @@ -82,17 +84,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; @@ -106,47 +97,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->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 +114,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 +149,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(); @@ -478,16 +438,16 @@ frame frame::sender_for_compiled_frame(RegisterMap* map) const { assert(map != NULL, "map must be set"); // frame owned by optimizing compiler - assert(_cb->frame_size() >= 0, "must have non-zero frame size"); - intptr_t* sender_sp = unextended_sp() + _cb->frame_size(); - intptr_t* unextended_sp = sender_sp; - // On Intel the return_address is always the word on the stack - address sender_pc = (address) *(sender_sp-1); + 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->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. @@ -501,11 +461,10 @@ 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); + 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..3b2debe057a9b --- /dev/null +++ b/src/hotspot/cpu/zero/codeBlob_zero.cpp @@ -0,0 +1,67 @@ +/* + * 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 "code/nmethod.hpp" +#include "interpreter/interpreter.hpp" +#include "runtime/frame.hpp" + +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::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::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::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::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::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/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..6f12a63b5ab77 100644 --- a/src/hotspot/share/code/codeBlob.cpp +++ b/src/hotspot/share/code/codeBlob.cpp @@ -307,6 +307,58 @@ 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 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 + 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..a56599a52382d 100644 --- a/src/hotspot/share/code/codeBlob.hpp +++ b/src/hotspot/share/code/codeBlob.hpp @@ -59,6 +59,8 @@ 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 +// 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 @@ -138,6 +140,8 @@ 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_stub_routines_blob() const { return false; } virtual bool is_compiled() const { return false; } virtual bool is_optimized_entry_blob() const { return false; } @@ -148,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; } @@ -193,6 +197,10 @@ class CodeBlob { code_contains(addr) && addr >= code_begin() + _frame_complete_offset; } int frame_complete_offset() const { return _frame_complete_offset; } + // Profiling/safepoint support + 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 // virtual here. @@ -336,7 +344,6 @@ class CodeBlobLayout : public StackObj { address content_end() const { return _content_end; } }; - class RuntimeBlob : public CodeBlob { friend class VMStructs; public: @@ -385,6 +392,8 @@ class BufferBlob: public RuntimeBlob { friend class VtableBlob; friend class MethodHandlesAdapterBlob; friend class OptimizedEntryBlob; + friend class InterpreterBlob; + friend class StubRoutinesBlob; friend class WhiteBox; private: @@ -446,6 +455,10 @@ class VtableBlob: public BufferBlob { // Typing virtual bool is_vtable_blob() const { return true; } + + // Profiling/safepoint support + 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); }; //---------------------------------------------------------------------------------------------------- @@ -464,6 +477,46 @@ 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 + 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); +}; + + +//---------------------------------------------------------------------------------------------------- +// 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 + 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); +}; + + //---------------------------------------------------------------------------------------------------- // RuntimeStub: describes stubs used by compiled code to call a (static) C++ runtime routine diff --git a/src/hotspot/share/code/compiledMethod.hpp b/src/hotspot/share/code/compiledMethod.hpp index 6c979f67a1d25..7c1ac5a5722b2 100644 --- a/src/hotspot/share/code/compiledMethod.hpp +++ b/src/hotspot/share/code/compiledMethod.hpp @@ -399,6 +399,11 @@ class CompiledMethod : public CodeBlob { bool unload_nmethod_caches(bool class_unloading_occurred); virtual void do_unloading(bool unloading_occurred) = 0; + public: + // Profiling/safepoint support + 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) { 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/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/nmethod.hpp b/src/hotspot/share/code/nmethod.hpp index d0154bc85a37a..cb2682886c58b 100644 --- a/src/hotspot/share/code/nmethod.hpp +++ b/src/hotspot/share/code/nmethod.hpp @@ -754,6 +754,11 @@ 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 + 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/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/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; } diff --git a/src/hotspot/share/runtime/frame.cpp b/src/hotspot/share/runtime/frame.cpp index 89dbc98b2212f..dba5bb46f4b9f 100644 --- a/src/hotspot/share/runtime/frame.cpp +++ b/src/hotspot/share/runtime/frame.cpp @@ -651,6 +651,10 @@ 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_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 5f0c7d38be64e..f8eabc13abefa 100644 --- a/src/hotspot/share/runtime/vmStructs.cpp +++ b/src/hotspot/share/runtime/vmStructs.cpp @@ -1364,6 +1364,8 @@ declare_type(AdapterBlob, BufferBlob) \ 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 1b95286395119..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 @@ -67,6 +67,8 @@ 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); + 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/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(); + } + +} 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(); + } + +}