| /* | |
| * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. | |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| * | |
| * This code is free software; you can redistribute it and/or modify it | |
| * under the terms of the GNU General Public License version 2 only, as | |
| * published by the Free Software Foundation. | |
| * | |
| * This code is distributed in the hope that it will be useful, but WITHOUT | |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| * version 2 for more details (a copy is included in the LICENSE file that | |
| * accompanied this code). | |
| * | |
| * You should have received a copy of the GNU General Public License version | |
| * 2 along with this work; if not, write to the Free Software Foundation, | |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| * | |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| * or visit www.oracle.com if you need additional information or have any | |
| * questions. | |
| * | |
| */ | |
| #ifndef SHARE_VM_RUNTIME_CONTINUATIONHELPER_INLINE_HPP | |
| #define SHARE_VM_RUNTIME_CONTINUATIONHELPER_INLINE_HPP | |
| #include "runtime/continuationHelper.hpp" | |
| #include "code/scopeDesc.hpp" | |
| #include "compiler/oopMap.hpp" | |
| #include "compiler/oopMap.inline.hpp" | |
| #include "interpreter/oopMapCache.hpp" | |
| #include "runtime/frame.inline.hpp" | |
| #include "runtime/objectMonitor.hpp" | |
| #include "runtime/stackValue.hpp" | |
| #include "runtime/synchronizer.hpp" | |
| #include "utilities/macros.hpp" | |
| #include CPU_HEADER_INLINE(continuationHelper) | |
| #ifndef CPU_OVERRIDES_RETURN_ADDRESS_ACCESSORS | |
| inline address ContinuationHelper::return_address_at(intptr_t* sp) { | |
| return *(address*)sp; | |
| } | |
| inline void ContinuationHelper::patch_return_address_at(intptr_t* sp, | |
| address pc) { | |
| *(address*)sp = pc; | |
| } | |
| #endif // !CPU_OVERRIDES_RETURN_ADDRESS_ACCESSORS | |
| inline bool ContinuationHelper::NonInterpretedUnknownFrame::is_instance(const frame& f) { | |
| return !f.is_interpreted_frame(); | |
| } | |
| inline bool ContinuationHelper::Frame::is_stub(CodeBlob* cb) { | |
| return cb != nullptr && cb->is_runtime_stub(); | |
| } | |
| inline Method* ContinuationHelper::Frame::frame_method(const frame& f) { | |
| return f.is_interpreted_frame() ? f.interpreter_frame_method() : f.cb()->as_nmethod()->method(); | |
| } | |
| inline address ContinuationHelper::Frame::return_pc(const frame& f) { | |
| return return_address_at((intptr_t *)return_pc_address(f)); | |
| } | |
| #ifdef ASSERT | |
| inline intptr_t* ContinuationHelper::Frame::frame_top(const frame &f) { | |
| if (f.is_interpreted_frame()) { | |
| ResourceMark rm; | |
| InterpreterOopMap mask; | |
| f.interpreted_frame_oop_map(&mask); | |
| return InterpretedFrame::frame_top(f, &mask); | |
| } else { | |
| return CompiledFrame::frame_top(f); | |
| } | |
| } | |
| inline bool ContinuationHelper::Frame::is_deopt_return(address pc, const frame& sender) { | |
| if (sender.is_interpreted_frame()) return false; | |
| nmethod* nm = sender.cb()->as_nmethod(); | |
| return nm->is_deopt_pc(pc); | |
| } | |
| #endif | |
| inline bool ContinuationHelper::InterpretedFrame::is_instance(const frame& f) { | |
| return f.is_interpreted_frame(); | |
| } | |
| inline address ContinuationHelper::InterpretedFrame::return_pc(const frame& f) { | |
| return return_address_at((intptr_t *)return_pc_address(f)); | |
| } | |
| inline int ContinuationHelper::InterpretedFrame::size(const frame&f) { | |
| return pointer_delta_as_int(InterpretedFrame::frame_bottom(f), InterpretedFrame::frame_top(f)); | |
| } | |
| inline int ContinuationHelper::InterpretedFrame::stack_argsize(const frame& f) { | |
| return f.interpreter_frame_method()->size_of_parameters(); | |
| } | |
| inline int ContinuationHelper::InterpretedFrame::expression_stack_size(const frame &f, InterpreterOopMap* mask) { | |
| int size = mask->expression_stack_size(); | |
| assert(size <= f.interpreter_frame_expression_stack_size(), "size1: %d size2: %d", size, f.interpreter_frame_expression_stack_size()); | |
| return size; | |
| } | |
| #ifdef ASSERT | |
| inline bool ContinuationHelper::InterpretedFrame::is_owning_locks(const frame& f) { | |
| assert(f.interpreter_frame_monitor_end() <= f.interpreter_frame_monitor_begin(), "must be"); | |
| if (f.interpreter_frame_monitor_end() == f.interpreter_frame_monitor_begin()) { | |
| return false; | |
| } | |
| for (BasicObjectLock* current = f.previous_monitor_in_interpreter_frame(f.interpreter_frame_monitor_begin()); | |
| current >= f.interpreter_frame_monitor_end(); | |
| current = f.previous_monitor_in_interpreter_frame(current)) { | |
| oop obj = current->obj(); | |
| if (obj != nullptr) { | |
| return true; | |
| } | |
| } | |
| return false; | |
| } | |
| #endif | |
| inline intptr_t* ContinuationHelper::InterpretedFrame::frame_top(const frame& f) { // inclusive; this will be copied with the frame | |
| return f.unextended_sp(); | |
| } | |
| inline intptr_t* ContinuationHelper::NonInterpretedFrame::frame_top(const frame& f, int callee_argsize, bool callee_interpreted) { | |
| return f.unextended_sp() + (callee_interpreted ? 0 : callee_argsize); | |
| } | |
| inline intptr_t* ContinuationHelper::NonInterpretedFrame::frame_top(const frame& f) { // inclusive; this will be copied with the frame | |
| return f.unextended_sp(); | |
| } | |
| inline intptr_t* ContinuationHelper::NonInterpretedFrame::frame_bottom(const frame& f) { // exclusive; this will not be copied with the frame | |
| return f.unextended_sp() + f.cb()->frame_size(); | |
| } | |
| inline int ContinuationHelper::NonInterpretedFrame::size(const frame& f) { | |
| assert(!f.is_interpreted_frame(), ""); | |
| return f.cb()->frame_size(); | |
| } | |
| inline int ContinuationHelper::NonInterpretedFrame::stack_argsize(const frame& f) { | |
| return f.compiled_frame_stack_argsize(); | |
| } | |
| inline bool ContinuationHelper::CompiledFrame::is_instance(const frame& f) { | |
| return f.is_compiled_frame(); | |
| } | |
| #ifdef ASSERT | |
| template<typename RegisterMapT> | |
| bool ContinuationHelper::CompiledFrame::is_owning_locks(JavaThread* thread, RegisterMapT* map, const frame& f) { | |
| assert(!f.is_interpreted_frame(), ""); | |
| assert(CompiledFrame::is_instance(f), ""); | |
| nmethod* nm = f.cb()->as_nmethod(); | |
| assert(!nm->is_native_method(), ""); // See compiledVFrame::compiledVFrame(...) in vframe_hp.cpp | |
| if (!nm->has_monitors()) { | |
| return false; | |
| } | |
| frame::update_map_with_saved_link(map, Frame::callee_link_address(f)); // the monitor object could be stored in the link register | |
| ResourceMark rm; | |
| for (ScopeDesc* scope = nm->scope_desc_at(f.pc()); scope != nullptr; scope = scope->sender()) { | |
| GrowableArray<MonitorValue*>* mons = scope->monitors(); | |
| if (mons == nullptr || mons->is_empty()) { | |
| continue; | |
| } | |
| for (int index = (mons->length()-1); index >= 0; index--) { // see compiledVFrame::monitors() | |
| MonitorValue* mon = mons->at(index); | |
| if (mon->eliminated()) { | |
| continue; // we ignore scalar-replaced monitors | |
| } | |
| ScopeValue* ov = mon->owner(); | |
| StackValue* owner_sv = StackValue::create_stack_value(&f, map, ov); // it is an oop | |
| oop owner = owner_sv->get_obj()(); | |
| if (owner != nullptr) { | |
| //assert(nm->has_monitors(), ""); | |
| return true; | |
| } | |
| } | |
| } | |
| return false; | |
| } | |
| #endif | |
| inline bool ContinuationHelper::NativeFrame::is_instance(const frame& f) { | |
| return f.is_native_frame(); | |
| } | |
| #ifdef ASSERT | |
| inline bool ContinuationHelper::NativeFrame::is_owning_locks(JavaThread* thread, const frame& f) { | |
| assert(NativeFrame::is_instance(f), ""); | |
| Method* method = f.cb()->as_nmethod()->method(); | |
| if (!method->is_synchronized()) { | |
| return false; | |
| } else { | |
| // Just verify we are actually the owner | |
| oop synced_obj = f.get_native_receiver(); | |
| assert(ObjectSynchronizer::current_thread_holds_lock(thread, Handle(thread, synced_obj)), "must be owner"); | |
| return true; | |
| } | |
| } | |
| #endif | |
| inline bool ContinuationHelper::StubFrame::is_instance(const frame& f) { | |
| return !f.is_interpreted_frame() && is_stub(f.cb()); | |
| } | |
| #endif // SHARE_VM_RUNTIME_CONTINUATIONHELPER_INLINE_HPP |