1 /* 2 * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 * 23 */ 24 25 #ifndef SHARE_VM_RUNTIME_CONTINUATIONHELPER_INLINE_HPP 26 #define SHARE_VM_RUNTIME_CONTINUATIONHELPER_INLINE_HPP 27 28 #include "runtime/continuationHelper.hpp" 29 30 #include "code/scopeDesc.hpp" 31 #include "compiler/oopMap.hpp" 32 #include "compiler/oopMap.inline.hpp" 33 #include "interpreter/oopMapCache.hpp" 34 #include "runtime/frame.inline.hpp" 35 #include "runtime/objectMonitor.hpp" 36 #include "runtime/stackValue.hpp" 37 #include "utilities/macros.hpp" 38 39 #include CPU_HEADER_INLINE(continuationHelper) 40 41 #ifndef CPU_OVERRIDES_RETURN_ADDRESS_ACCESSORS 42 inline address ContinuationHelper::return_address_at(intptr_t* sp) { 43 return *(address*)sp; 44 } 45 46 inline void ContinuationHelper::patch_return_address_at(intptr_t* sp, 47 address pc) { 48 *(address*)sp = pc; 49 } 50 #endif // !CPU_OVERRIDES_RETURN_ADDRESS_ACCESSORS 51 52 inline bool ContinuationHelper::NonInterpretedUnknownFrame::is_instance(const frame& f) { 53 return !f.is_interpreted_frame(); 54 } 55 56 inline bool ContinuationHelper::Frame::is_stub(CodeBlob* cb) { 57 return cb != nullptr && cb->is_runtime_stub(); 58 } 59 60 inline Method* ContinuationHelper::Frame::frame_method(const frame& f) { 61 return f.is_interpreted_frame() ? f.interpreter_frame_method() : f.cb()->as_nmethod()->method(); 62 } 63 64 inline address ContinuationHelper::Frame::return_pc(const frame& f) { 65 return return_address_at((intptr_t *)return_pc_address(f)); 66 } 67 68 #ifdef ASSERT 69 inline intptr_t* ContinuationHelper::Frame::frame_top(const frame &f) { 70 if (f.is_interpreted_frame()) { 71 ResourceMark rm; 72 InterpreterOopMap mask; 73 f.interpreted_frame_oop_map(&mask); 74 return InterpretedFrame::frame_top(f, &mask); 75 } else { 76 return CompiledFrame::frame_top(f); 77 } 78 } 79 80 inline bool ContinuationHelper::Frame::is_deopt_return(address pc, const frame& sender) { 81 if (sender.is_interpreted_frame()) return false; 82 83 nmethod* nm = sender.cb()->as_nmethod(); 84 return nm->is_deopt_pc(pc); 85 } 86 87 #endif 88 89 inline bool ContinuationHelper::InterpretedFrame::is_instance(const frame& f) { 90 return f.is_interpreted_frame(); 91 } 92 93 inline address ContinuationHelper::InterpretedFrame::return_pc(const frame& f) { 94 return return_address_at((intptr_t *)return_pc_address(f)); 95 } 96 97 inline int ContinuationHelper::InterpretedFrame::size(const frame&f) { 98 return pointer_delta_as_int(InterpretedFrame::frame_bottom(f), InterpretedFrame::frame_top(f)); 99 } 100 101 inline int ContinuationHelper::InterpretedFrame::stack_argsize(const frame& f) { 102 return f.interpreter_frame_method()->size_of_parameters(); 103 } 104 105 inline int ContinuationHelper::InterpretedFrame::expression_stack_size(const frame &f, InterpreterOopMap* mask) { 106 int size = mask->expression_stack_size(); 107 assert(size <= f.interpreter_frame_expression_stack_size(), "size1: %d size2: %d", size, f.interpreter_frame_expression_stack_size()); 108 return size; 109 } 110 111 #ifdef ASSERT 112 inline int ContinuationHelper::InterpretedFrame::monitors_to_fix(JavaThread* thread, const frame& f, ResourceHashtable<oopDesc*, bool> &table, stackChunkOop chunk) { 113 BasicObjectLock* first_mon = f.interpreter_frame_monitor_begin(); 114 BasicObjectLock* last_mon = f.interpreter_frame_monitor_end(); 115 assert(last_mon <= first_mon, "must be"); 116 117 if (first_mon == last_mon) { 118 // No monitors in this frame 119 return 0; 120 } 121 122 int monitor_count = 0; 123 oop monitorenter_oop = thread->is_on_monitorenter() ? thread->current_pending_monitor()->object() : nullptr; 124 125 for (BasicObjectLock* current = f.previous_monitor_in_interpreter_frame(first_mon); 126 current >= last_mon; current = f.previous_monitor_in_interpreter_frame(current)) { 127 oop* obj_adr = current->obj_adr(); 128 129 oop obj; 130 if (f.is_heap_frame()) { 131 assert(chunk != nullptr, "null stackChunk"); 132 obj = chunk->has_bitmap() && UseCompressedOops ? chunk->load_oop((narrowOop*)obj_adr) : chunk->load_oop(obj_adr); 133 } else { 134 // We have already processed oops when getting this frame. 135 obj = *obj_adr; 136 } 137 assert(obj == nullptr || dbg_is_good_oop(obj), "obj_adr: " PTR_FORMAT " obj: " PTR_FORMAT, p2i(obj_adr), p2i(obj)); 138 139 if (obj != nullptr && obj != monitorenter_oop) { 140 markWord mark = obj->mark(); 141 if (mark.has_monitor() && !mark.monitor()->is_owner_anonymous()) { 142 // Nothing to do 143 assert(mark.monitor()->is_owner(thread), "invariant"); 144 continue; 145 } 146 assert(!f.is_heap_frame() || LockingMode == LM_LIGHTWEIGHT, 147 "monitors found on heap frame that need to be fixed should only be those saved in the LockStack"); 148 bool created; 149 table.put_if_absent(obj, true, &created); 150 if (created) { 151 monitor_count++; 152 } 153 } 154 } 155 return monitor_count; 156 } 157 #endif 158 159 inline intptr_t* ContinuationHelper::InterpretedFrame::frame_top(const frame& f) { // inclusive; this will be copied with the frame 160 return f.unextended_sp(); 161 } 162 163 inline intptr_t* ContinuationHelper::NonInterpretedFrame::frame_top(const frame& f, int callee_argsize, bool callee_interpreted) { 164 return f.unextended_sp() + (callee_interpreted ? 0 : callee_argsize); 165 } 166 167 inline intptr_t* ContinuationHelper::NonInterpretedFrame::frame_top(const frame& f) { // inclusive; this will be copied with the frame 168 return f.unextended_sp(); 169 } 170 171 inline intptr_t* ContinuationHelper::NonInterpretedFrame::frame_bottom(const frame& f) { // exclusive; this will not be copied with the frame 172 return f.unextended_sp() + f.cb()->frame_size(); 173 } 174 175 inline int ContinuationHelper::NonInterpretedFrame::size(const frame& f) { 176 assert(!f.is_interpreted_frame(), ""); 177 return f.cb()->frame_size(); 178 } 179 180 inline int ContinuationHelper::NonInterpretedFrame::stack_argsize(const frame& f) { 181 return f.compiled_frame_stack_argsize(); 182 } 183 184 inline bool ContinuationHelper::CompiledFrame::is_instance(const frame& f) { 185 return f.is_compiled_frame(); 186 } 187 188 inline bool ContinuationHelper::NativeFrame::is_instance(const frame& f) { 189 return f.is_native_frame(); 190 } 191 192 #ifdef ASSERT 193 template<typename RegisterMapT> 194 int ContinuationHelper::CompiledFrame::monitors_to_fix(JavaThread* thread, RegisterMapT* map, const frame& f, ResourceHashtable<oopDesc*, bool> &table) { 195 assert(!f.is_interpreted_frame(), ""); 196 assert(CompiledFrame::is_instance(f), ""); 197 198 nmethod* nm = f.cb()->as_nmethod(); 199 assert(!nm->is_nmethod() || !nm->as_nmethod()->is_native_method(), ""); // See compiledVFrame::compiledVFrame(...) in vframe_hp.cpp 200 201 if (!nm->has_monitors()) { 202 // No monitors in this frame 203 return 0; 204 } 205 206 int monitor_count = 0; 207 oop monitorenter_oop = thread->is_on_monitorenter() ? thread->current_pending_monitor()->object() : nullptr; 208 209 for (ScopeDesc* scope = nm->scope_desc_at(f.pc()); scope != nullptr; scope = scope->sender()) { 210 GrowableArray<MonitorValue*>* mons = scope->monitors(); 211 if (mons == nullptr || mons->is_empty()) { 212 continue; 213 } 214 215 for (int index = (mons->length()-1); index >= 0; index--) { // see compiledVFrame::monitors() 216 MonitorValue* mon = mons->at(index); 217 if (mon->eliminated()) { 218 continue; // we ignore eliminated monitors 219 } 220 221 ScopeValue* ov = mon->owner(); 222 StackValue* owner_sv = StackValue::create_stack_value(&f, map, ov); // it is an oop 223 oop owner = owner_sv->get_obj()(); 224 if (owner != nullptr && owner != monitorenter_oop) { 225 markWord mark = owner->mark(); 226 if (mark.has_monitor() && !mark.monitor()->is_owner_anonymous()) { 227 // Nothing to do 228 assert(mark.monitor()->is_owner(thread), "invariant"); 229 continue; 230 } 231 assert(!f.is_heap_frame() || LockingMode == LM_LIGHTWEIGHT, 232 "monitors found on heap frame that need to be fixed should only be those saved in the LockStack"); 233 bool created; 234 table.put_if_absent(owner, true, &created); 235 if (created) { 236 monitor_count++; 237 } 238 } 239 } 240 } 241 return monitor_count; 242 } 243 244 inline int ContinuationHelper::NativeFrame::monitors_to_fix(JavaThread* thread, const frame& f, ResourceHashtable<oopDesc*, bool> &table) { 245 assert(NativeFrame::is_instance(f), ""); 246 247 Method* method = f.cb()->as_nmethod()->method(); 248 if (!method->is_synchronized()) { 249 return 0; 250 } 251 252 oop synced_obj = f.get_native_receiver(); 253 oop monitorenter_oop = thread->is_on_monitorenter() ? thread->current_pending_monitor()->object() : nullptr; 254 255 bool is_first_frame = f.sp() == thread->last_Java_sp(); 256 if (!is_first_frame) { 257 assert(ObjectSynchronizer::current_thread_holds_lock(thread, Handle(thread, synced_obj)), "must be owner"); 258 assert(monitorenter_oop == nullptr || monitorenter_oop != synced_obj, "owner already, should not be contended"); 259 260 markWord mark = synced_obj->mark(); 261 if (mark.has_monitor() && !mark.monitor()->is_owner_anonymous()) { 262 // Nothing to do 263 assert(mark.monitor()->is_owner(thread), "invariant"); 264 return 0; 265 } 266 assert(!f.is_heap_frame(), "native frame on the heap???"); 267 bool created; 268 table.put_if_absent(synced_obj, true, &created); 269 if (created) { 270 return 1; 271 } 272 } else { 273 assert(thread->is_on_monitorenter() && monitorenter_oop != nullptr && monitorenter_oop == synced_obj, 274 "should be freeze case due to preempt on monitorenter contention"); 275 assert(!ObjectSynchronizer::current_thread_holds_lock(thread, Handle(thread, synced_obj)), "should not be owner"); 276 } 277 return 0; 278 } 279 #endif 280 281 inline bool ContinuationHelper::StubFrame::is_instance(const frame& f) { 282 return !f.is_interpreted_frame() && is_stub(f.cb()); 283 } 284 285 #endif // SHARE_VM_RUNTIME_CONTINUATIONHELPER_INLINE_HPP