< prev index next >

src/hotspot/cpu/ppc/continuationFreezeThaw_ppc.inline.hpp

Print this page

  1 /*
  2  * Copyright (c) 2019, 2025, 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  *

 39   *la = new_value;
 40 }
 41 
 42 ////// Freeze
 43 
 44 // Fast path
 45 
 46 inline void FreezeBase::patch_stack_pd(intptr_t* frame_sp, intptr_t* heap_sp) {
 47   // Nothing to do. The backchain is reconstructed when thawing (see Thaw<ConfigT>::patch_caller_links())
 48 }
 49 
 50 // Slow path
 51 
 52 template<typename FKind>
 53 inline frame FreezeBase::sender(const frame& f) {
 54   assert(FKind::is_instance(f), "");
 55   if (FKind::interpreted) {
 56     return frame(f.sender_sp(), f.sender_pc(), f.interpreter_frame_sender_sp());
 57   }
 58 



 59   intptr_t* sender_sp = f.sender_sp();
 60   address sender_pc = f.sender_pc();
 61   assert(sender_sp != f.sp(), "must have changed");
 62 
 63   int slot = 0;
 64   CodeBlob* sender_cb = CodeCache::find_blob_and_oopmap(sender_pc, slot);
 65   return sender_cb != nullptr
 66     ? frame(sender_sp, sender_sp, nullptr, sender_pc, sender_cb, slot == -1 ? nullptr : sender_cb->oop_map_for_slot(slot, sender_pc))
 67     : frame(sender_sp, sender_pc, sender_sp);
 68 }
 69 
 70 void FreezeBase::adjust_interpreted_frame_unextended_sp(frame& f) {
 71   // nothing to do
 72 }
 73 
 74 inline void FreezeBase::prepare_freeze_interpreted_top_frame(frame& f) {
 75   // Nothing to do. We don't save a last sp since we cannot use sp as esp.
 76   // Instead the top frame is trimmed when making an i2i call. The original
 77   // top_frame_sp is set when the frame is pushed (see generate_fixed_frame()).
 78   // An interpreter top frame that was just thawed is resized to top_frame_sp by the

252 //     | frame::java_abi        |                          | frame::java_abi        |
253 //     | (metadata_words_at_top)|<- FP of caller           | (metadata_words_at_top)|<- FP of caller
254 //     ==========================                          ==========================
255 //     |                        |                          |                        |
256 //     |                        |                          |                        |
257 //     |------------------------|                   -----  |------------------------|
258 //     | Stack Args             |                     ^    | Stack Args             |
259 //     | (if any)               |                     |    | (if any)               |
260 //     |------------------------|                  overlap |------------------------|
261 //     | frame::java_abi        |                     |    | frame::java_abi        |
262 //     | (metadata_words_at_top)|<- SP == unext. SP   v    | (metadata_words_at_top)|<- SP == unext. SP of caller
263 //     ==========================   of caller       -----  ==========================   / FP of new frame
264 //                                                         |                        |
265 //      overlap = stack_argsize(f)                         |                        |
266 //                + frame::metadata_words_at_top           |------------------------|
267 //                                                         | frame::java_abi        |
268 //      Where f is the frame to be relocated on the heap.  | (metadata_words_at_top)|<- SP == unext. SP of new frame
269 //      See also StackChunkFrameStream::frame_size().      ==========================
270 //
271 template<typename FKind>
272 frame FreezeBase::new_heap_frame(frame& f, frame& caller) {

273   assert(FKind::is_instance(f), "");
274 
275   intptr_t *sp, *fp;
276   if (FKind::interpreted) {
277     intptr_t locals_offset = *f.addr_at(ijava_idx(locals));
278     // If the caller.is_empty(), i.e. we're freezing into an empty chunk, then we set
279     // the chunk's argsize in finalize_freeze and make room for it above the unextended_sp
280     // See also comment on StackChunkFrameStream<frame_kind>::interpreter_frame_size()
281     int overlap =
282         (caller.is_interpreted_frame() || caller.is_empty())
283         ? ContinuationHelper::InterpretedFrame::stack_argsize(f) + frame::metadata_words_at_top
284         : 0;
285     fp = caller.unextended_sp() - 1 - locals_offset + overlap;
286     // esp points one slot below the last argument
287     intptr_t* x86_64_like_unextended_sp = f.interpreter_frame_esp() + 1 - frame::metadata_words_at_top;
288     sp = fp - (f.fp() - x86_64_like_unextended_sp);
289 
290     assert (sp <= fp && (fp <= caller.unextended_sp() || caller.is_interpreted_frame()),
291             "sp=" PTR_FORMAT " fp=" PTR_FORMAT " caller.unextended_sp()=" PTR_FORMAT " caller.is_interpreted_frame()=%d",
292             p2i(sp), p2i(fp), p2i(caller.unextended_sp()), caller.is_interpreted_frame());

300     *hf.addr_at(ijava_idx(esp))    = f.interpreter_frame_esp() - f.fp();
301     return hf;
302   } else {
303     int fsize = FKind::size(f);
304     sp = caller.unextended_sp() - fsize;
305     if (caller.is_interpreted_frame()) {
306       // If the caller is interpreted, our stackargs are not supposed to overlap with it
307       // so we make more room by moving sp down by argsize
308       int argsize = FKind::stack_argsize(f);
309       sp -= argsize + frame::metadata_words_at_top;
310     }
311     fp = sp + fsize;
312     caller.set_sp(fp);
313 
314     assert(_cont.tail()->is_in_chunk(sp), "");
315 
316     return frame(sp, sp, fp, f.pc(), nullptr, nullptr, true /* on_heap */);
317   }
318 }
319 
320 inline void FreezeBase::patch_pd(frame& hf, const frame& caller) {
321   if (caller.is_interpreted_frame()) {
322     assert(!caller.is_empty(), "");
323     patch_callee_link_relative(caller, caller.fp());
324   }
325 #ifdef ASSERT
326   else {
327     // For compiled frames the back link is actually redundant. It gets computed
328     // as unextended_sp + frame_size.
329 
330     // Note the difference on x86_64: the link is not made relative if the caller
331     // is a compiled frame because there rbp is used as a non-volatile register by
332     // c1/c2 so it could be a computed value local to the caller.
333 
334     // See also:
335     // - FreezeBase::set_top_frame_metadata_pd
336     // - StackChunkFrameStream<frame_kind>::fp()
337     // - UseContinuationFastPath: compiled frames are copied in a batch w/o patching the back link.
338     //   The backlinks are restored when thawing (see Thaw<ConfigT>::patch_caller_links())
339     patch_callee_link(hf, (intptr_t*)badAddress);
340   }

486 //   l    | frame::java_abi      |<- unext. SP / SP    | (unused)             |<- unal.unext.SP
487 //  - - - ======================== - - - - - - - - - - |----------------------|- - - - - - - - - - - - - - - - - - - - - - - - - - - -
488 //    N   |                      |                     | Opt. Align. Padding  |
489 //    e   |                      |                     |----------------------|
490 //    w   |----------------------|                     | Stack Args           |
491 //        | frame::java_abi      |<- unext. SP / SP    | (if any)             |
492 //    F   ========================                     |----------------------|
493 //    r                                                | frame::java_abi      |<- caller's SP
494 //    a                                                ======================== / new frame's FP
495 //    m                                                |                      |   (aligned)
496 //    e                                                |                      |
497 //                                                     |----------------------|
498 //                                                     | frame::java_abi      |<- unext. SP / SP
499 //                                                     ========================
500 //
501 //  If the new frame is at the bottom just above the ContinuationEntry frame then the stackargs
502 //  don't overlap the caller either even though it is compiled because the size is not
503 //  limited/known. In contrast to the interpreted caller case the abi overlaps with the caller
504 //  if there are no stackargs. This is to comply with shared code (see e.g. StackChunkFrameStream::frame_size())
505 //
506 template<typename FKind> frame ThawBase::new_stack_frame(const frame& hf, frame& caller, bool bottom) {

507   assert(FKind::is_instance(hf), "");
508 
509   assert(is_aligned(caller.fp(), frame::frame_alignment), PTR_FORMAT, p2i(caller.fp()));
510   // caller.sp() can be unaligned. This is fixed below.
511   if (FKind::interpreted) {
512     // Note: we have to overlap with the caller, at least if it is interpreted, to match the
513     // max_thawing_size calculation during freeze. See also comment above.
514     intptr_t* heap_sp = hf.unextended_sp();
515     const int fsize = ContinuationHelper::InterpretedFrame::frame_bottom(hf) - hf.unextended_sp();
516     const int overlap = !caller.is_interpreted_frame() ? 0
517                         : ContinuationHelper::InterpretedFrame::stack_argsize(hf) + frame::metadata_words_at_top;
518     intptr_t* frame_sp = caller.unextended_sp() + overlap - fsize;
519     intptr_t* fp = frame_sp + (hf.fp() - heap_sp);
520     // align fp
521     int padding = fp - align_down(fp, frame::frame_alignment);
522     fp -= padding;
523     // alignment of sp is done by callee or in finish_thaw()
524     frame_sp -= padding;
525 
526     // On ppc esp points to the next free slot on the expression stack and sp + metadata points to the last parameter

  1 /*
  2  * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved.
  3  * Copyright (c) 2026 SAP SE. All rights reserved.
  4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  5  *
  6  * This code is free software; you can redistribute it and/or modify it
  7  * under the terms of the GNU General Public License version 2 only, as
  8  * published by the Free Software Foundation.
  9  *
 10  * This code is distributed in the hope that it will be useful, but WITHOUT
 11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 13  * version 2 for more details (a copy is included in the LICENSE file that
 14  * accompanied this code).
 15  *
 16  * You should have received a copy of the GNU General Public License version
 17  * 2 along with this work; if not, write to the Free Software Foundation,
 18  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 19  *
 20  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 21  * or visit www.oracle.com if you need additional information or have any
 22  * questions.
 23  *

 40   *la = new_value;
 41 }
 42 
 43 ////// Freeze
 44 
 45 // Fast path
 46 
 47 inline void FreezeBase::patch_stack_pd(intptr_t* frame_sp, intptr_t* heap_sp) {
 48   // Nothing to do. The backchain is reconstructed when thawing (see Thaw<ConfigT>::patch_caller_links())
 49 }
 50 
 51 // Slow path
 52 
 53 template<typename FKind>
 54 inline frame FreezeBase::sender(const frame& f) {
 55   assert(FKind::is_instance(f), "");
 56   if (FKind::interpreted) {
 57     return frame(f.sender_sp(), f.sender_pc(), f.interpreter_frame_sender_sp());
 58   }
 59 
 60   assert(f.cb() == nullptr || !f.cb()->is_nmethod() || !f.cb()->as_nmethod()->needs_stack_repair(),
 61          "unsupported");
 62 
 63   intptr_t* sender_sp = f.sender_sp();
 64   address sender_pc = f.sender_pc();
 65   assert(sender_sp != f.sp(), "must have changed");
 66 
 67   int slot = 0;
 68   CodeBlob* sender_cb = CodeCache::find_blob_and_oopmap(sender_pc, slot);
 69   return sender_cb != nullptr
 70     ? frame(sender_sp, sender_sp, nullptr, sender_pc, sender_cb, slot == -1 ? nullptr : sender_cb->oop_map_for_slot(slot, sender_pc))
 71     : frame(sender_sp, sender_pc, sender_sp);
 72 }
 73 
 74 void FreezeBase::adjust_interpreted_frame_unextended_sp(frame& f) {
 75   // nothing to do
 76 }
 77 
 78 inline void FreezeBase::prepare_freeze_interpreted_top_frame(frame& f) {
 79   // Nothing to do. We don't save a last sp since we cannot use sp as esp.
 80   // Instead the top frame is trimmed when making an i2i call. The original
 81   // top_frame_sp is set when the frame is pushed (see generate_fixed_frame()).
 82   // An interpreter top frame that was just thawed is resized to top_frame_sp by the

256 //     | frame::java_abi        |                          | frame::java_abi        |
257 //     | (metadata_words_at_top)|<- FP of caller           | (metadata_words_at_top)|<- FP of caller
258 //     ==========================                          ==========================
259 //     |                        |                          |                        |
260 //     |                        |                          |                        |
261 //     |------------------------|                   -----  |------------------------|
262 //     | Stack Args             |                     ^    | Stack Args             |
263 //     | (if any)               |                     |    | (if any)               |
264 //     |------------------------|                  overlap |------------------------|
265 //     | frame::java_abi        |                     |    | frame::java_abi        |
266 //     | (metadata_words_at_top)|<- SP == unext. SP   v    | (metadata_words_at_top)|<- SP == unext. SP of caller
267 //     ==========================   of caller       -----  ==========================   / FP of new frame
268 //                                                         |                        |
269 //      overlap = stack_argsize(f)                         |                        |
270 //                + frame::metadata_words_at_top           |------------------------|
271 //                                                         | frame::java_abi        |
272 //      Where f is the frame to be relocated on the heap.  | (metadata_words_at_top)|<- SP == unext. SP of new frame
273 //      See also StackChunkFrameStream::frame_size().      ==========================
274 //
275 template<typename FKind>
276 frame FreezeBase::new_heap_frame(frame& f, frame& caller, int size_adjust) {
277   assert(size_adjust == 0, "unsupported");
278   assert(FKind::is_instance(f), "");
279 
280   intptr_t *sp, *fp;
281   if (FKind::interpreted) {
282     intptr_t locals_offset = *f.addr_at(ijava_idx(locals));
283     // If the caller.is_empty(), i.e. we're freezing into an empty chunk, then we set
284     // the chunk's argsize in finalize_freeze and make room for it above the unextended_sp
285     // See also comment on StackChunkFrameStream<frame_kind>::interpreter_frame_size()
286     int overlap =
287         (caller.is_interpreted_frame() || caller.is_empty())
288         ? ContinuationHelper::InterpretedFrame::stack_argsize(f) + frame::metadata_words_at_top
289         : 0;
290     fp = caller.unextended_sp() - 1 - locals_offset + overlap;
291     // esp points one slot below the last argument
292     intptr_t* x86_64_like_unextended_sp = f.interpreter_frame_esp() + 1 - frame::metadata_words_at_top;
293     sp = fp - (f.fp() - x86_64_like_unextended_sp);
294 
295     assert (sp <= fp && (fp <= caller.unextended_sp() || caller.is_interpreted_frame()),
296             "sp=" PTR_FORMAT " fp=" PTR_FORMAT " caller.unextended_sp()=" PTR_FORMAT " caller.is_interpreted_frame()=%d",
297             p2i(sp), p2i(fp), p2i(caller.unextended_sp()), caller.is_interpreted_frame());

305     *hf.addr_at(ijava_idx(esp))    = f.interpreter_frame_esp() - f.fp();
306     return hf;
307   } else {
308     int fsize = FKind::size(f);
309     sp = caller.unextended_sp() - fsize;
310     if (caller.is_interpreted_frame()) {
311       // If the caller is interpreted, our stackargs are not supposed to overlap with it
312       // so we make more room by moving sp down by argsize
313       int argsize = FKind::stack_argsize(f);
314       sp -= argsize + frame::metadata_words_at_top;
315     }
316     fp = sp + fsize;
317     caller.set_sp(fp);
318 
319     assert(_cont.tail()->is_in_chunk(sp), "");
320 
321     return frame(sp, sp, fp, f.pc(), nullptr, nullptr, true /* on_heap */);
322   }
323 }
324 
325 inline void FreezeBase::patch_pd(frame& hf, const frame& caller, bool is_bottom_frame) {
326   if (caller.is_interpreted_frame()) {
327     assert(!caller.is_empty(), "");
328     patch_callee_link_relative(caller, caller.fp());
329   }
330 #ifdef ASSERT
331   else {
332     // For compiled frames the back link is actually redundant. It gets computed
333     // as unextended_sp + frame_size.
334 
335     // Note the difference on x86_64: the link is not made relative if the caller
336     // is a compiled frame because there rbp is used as a non-volatile register by
337     // c1/c2 so it could be a computed value local to the caller.
338 
339     // See also:
340     // - FreezeBase::set_top_frame_metadata_pd
341     // - StackChunkFrameStream<frame_kind>::fp()
342     // - UseContinuationFastPath: compiled frames are copied in a batch w/o patching the back link.
343     //   The backlinks are restored when thawing (see Thaw<ConfigT>::patch_caller_links())
344     patch_callee_link(hf, (intptr_t*)badAddress);
345   }

491 //   l    | frame::java_abi      |<- unext. SP / SP    | (unused)             |<- unal.unext.SP
492 //  - - - ======================== - - - - - - - - - - |----------------------|- - - - - - - - - - - - - - - - - - - - - - - - - - - -
493 //    N   |                      |                     | Opt. Align. Padding  |
494 //    e   |                      |                     |----------------------|
495 //    w   |----------------------|                     | Stack Args           |
496 //        | frame::java_abi      |<- unext. SP / SP    | (if any)             |
497 //    F   ========================                     |----------------------|
498 //    r                                                | frame::java_abi      |<- caller's SP
499 //    a                                                ======================== / new frame's FP
500 //    m                                                |                      |   (aligned)
501 //    e                                                |                      |
502 //                                                     |----------------------|
503 //                                                     | frame::java_abi      |<- unext. SP / SP
504 //                                                     ========================
505 //
506 //  If the new frame is at the bottom just above the ContinuationEntry frame then the stackargs
507 //  don't overlap the caller either even though it is compiled because the size is not
508 //  limited/known. In contrast to the interpreted caller case the abi overlaps with the caller
509 //  if there are no stackargs. This is to comply with shared code (see e.g. StackChunkFrameStream::frame_size())
510 //
511 template<typename FKind> frame ThawBase::new_stack_frame(const frame& hf, frame& caller, bool bottom, int size_adjust) {
512   assert(size_adjust == 0, "unsupported");
513   assert(FKind::is_instance(hf), "");
514 
515   assert(is_aligned(caller.fp(), frame::frame_alignment), PTR_FORMAT, p2i(caller.fp()));
516   // caller.sp() can be unaligned. This is fixed below.
517   if (FKind::interpreted) {
518     // Note: we have to overlap with the caller, at least if it is interpreted, to match the
519     // max_thawing_size calculation during freeze. See also comment above.
520     intptr_t* heap_sp = hf.unextended_sp();
521     const int fsize = ContinuationHelper::InterpretedFrame::frame_bottom(hf) - hf.unextended_sp();
522     const int overlap = !caller.is_interpreted_frame() ? 0
523                         : ContinuationHelper::InterpretedFrame::stack_argsize(hf) + frame::metadata_words_at_top;
524     intptr_t* frame_sp = caller.unextended_sp() + overlap - fsize;
525     intptr_t* fp = frame_sp + (hf.fp() - heap_sp);
526     // align fp
527     int padding = fp - align_down(fp, frame::frame_alignment);
528     fp -= padding;
529     // alignment of sp is done by callee or in finish_thaw()
530     frame_sp -= padding;
531 
532     // On ppc esp points to the next free slot on the expression stack and sp + metadata points to the last parameter
< prev index next >