/*
 * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved.
 * Copyright (c) 2012, 2025 SAP SE. 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 CPU_PPC_FRAME_PPC_HPP
#define CPU_PPC_FRAME_PPC_HPP

  //  C frame layout on PPC-64.
  //
  //  In this figure the stack grows upwards, while memory grows
  //  downwards. See "64-bit PowerPC ELF ABI Supplement Version 1.7",
  //  IBM Corp. (2003-10-29)
  //  (http://math-atlas.sourceforge.net/devel/assembly/PPC-elf64abi-1.7.pdf).
  //
  //  Square brackets denote stack regions possibly larger
  //  than a single 64 bit slot.
  //
  //  STACK:
  //    0       [C_FRAME]               <-- SP after prolog (mod 16 = 0)
  //            [C_FRAME]               <-- SP before prolog
  //            ...
  //            [C_FRAME]
  //
  //  C_FRAME:
  //    0       [ABI_REG_ARGS]
  //    112     CARG_9: outgoing arg 9 (arg_1 ... arg_8 via gpr_3 ... gpr_{10})
  //            ...
  //    40+M*8  CARG_M: outgoing arg M (M is the maximum of outgoing args taken over all call sites in the procedure)
  //            local 1
  //            ...
  //            local N
  //            spill slot for vector reg (16 bytes aligned)
  //            ...
  //            spill slot for vector reg
  //            alignment       (4 or 12 bytes)
  //    V       SR_VRSAVE
  //    V+4     spill slot for GR
  //    ...     ...
  //            spill slot for GR
  //            spill slot for FR
  //            ...
  //            spill slot for FR
  //
  //  ABI_MINFRAME:
  //    0       caller's SP
  //    8       space for condition register (CR) for next call
  //    16      space for link register (LR) for next call
  //    24      reserved (ABI_ELFv2 only)
  //    32      reserved (ABI_ELFv2 only)
  //    40      space for TOC (=R2) register for next call
  //
  //  ABI_REG_ARGS:
  //    0       [ABI_MINFRAME]
  //    48      CARG_1: spill slot for outgoing arg 1. used by next callee.
  //    ...     ...
  //    104     CARG_8: spill slot for outgoing arg 8. used by next callee.
  //

 public:

  // C frame layout
  static const int alignment_in_bytes = 16;

  // Common ABI. On top of all frames, C and Java
  struct common_abi {
    uint64_t callers_sp;
    uint64_t cr;
    uint64_t lr;
  };

  // ABI_MINFRAME. Used for native C frames.
  struct native_abi_minframe : common_abi {
#if !defined(ABI_ELFv2)
    uint64_t reserved1;                           //_16
    uint64_t reserved2;
#endif
    uint64_t toc;                                 //_16
    // nothing to add here!
    // aligned to frame::alignment_in_bytes (16)
  };

  struct native_abi_reg_args : native_abi_minframe {
    uint64_t carg_1;
    uint64_t carg_2;                              //_16
    uint64_t carg_3;
    uint64_t carg_4;                              //_16
    uint64_t carg_5;
    uint64_t carg_6;                              //_16
    uint64_t carg_7;
    uint64_t carg_8;                              //_16
    // aligned to frame::alignment_in_bytes (16)
  };

  enum {
    native_abi_minframe_size = sizeof(native_abi_minframe),
    native_abi_reg_args_size = sizeof(native_abi_reg_args)
  };

  #define _abi0(_component) \
          (offset_of(frame::native_abi_reg_args, _component))

  struct native_abi_reg_args_spill : native_abi_reg_args {
    // additional spill slots
    uint64_t spill_ret;
    uint64_t spill_fret;                          //_16
    // aligned to frame::alignment_in_bytes (16)
  };

  enum {
    native_abi_reg_args_spill_size = sizeof(native_abi_reg_args_spill)
  };

  #define _native_abi_reg_args_spill(_component) \
          (offset_of(frame::native_abi_reg_args_spill, _component))


  // Frame layout for the Java template interpreter on PPC64.
  //
  // We differnetiate between TOP and PARENT frames.
  // TOP frames allow for calling native C code.
  // A TOP frame is trimmed to a PARENT frame when calling a Java method.
  //
  // In these figures the stack grows upwards, while memory grows
  // downwards. Square brackets denote regions possibly larger than
  // single 64 bit slots.
  //
  //  STACK (interpreter is active):
  //    0       [TOP_IJAVA_FRAME]
  //            [PARENT_IJAVA_FRAME]
  //            ...
  //            [PARENT_IJAVA_FRAME]
  //            [ENTRY_FRAME]
  //            [C_FRAME]
  //            ...
  //            [C_FRAME]
  //
  //  With the following frame layouts:
  //  TOP_IJAVA_FRAME:
  //    0       [TOP_IJAVA_FRAME_ABI]
  //            alignment (optional)
  //            [operand stack]
  //            [monitors] (optional)
  //            [IJAVA_STATE]
  //            note: own locals are located in the caller frame.
  //
  //  PARENT_IJAVA_FRAME:
  //    0       [PARENT_IJAVA_FRAME_ABI]
  //            alignment (optional)
  //            [callee's Java result]
  //            [callee's locals w/o arguments]
  //            [outgoing arguments]
  //            [used part of operand stack w/o arguments]
  //            [monitors] (optional)
  //            [IJAVA_STATE]
  //
  //  ENTRY_FRAME:
  //    0       [PARENT_IJAVA_FRAME_ABI]
  //            alignment (optional)
  //            [callee's Java result]
  //            [callee's locals w/o arguments]
  //            [outgoing arguments]
  //            [non-volatiles]
  //            [ENTRY_FRAME_LOCALS]

  // ABI for every Java frame, compiled and interpreted
  struct java_abi : common_abi {
    uint64_t toc;
  };

  struct parent_ijava_frame_abi : java_abi {
  };

#define _parent_ijava_frame_abi(_component) \
        (offset_of(frame::parent_ijava_frame_abi, _component))

  struct top_ijava_frame_abi : native_abi_reg_args {
  };

  enum {
    java_abi_size = sizeof(java_abi),
    parent_ijava_frame_abi_size = sizeof(parent_ijava_frame_abi),
    top_ijava_frame_abi_size = sizeof(top_ijava_frame_abi)
  };

#define _top_ijava_frame_abi(_component) \
        (offset_of(frame::top_ijava_frame_abi, _component))

  struct ijava_state {
    uint64_t method;
    uint64_t mirror;
    uint64_t locals;
    uint64_t monitors;
    uint64_t cpoolCache;
    uint64_t bcp;
    uint64_t esp;
    uint64_t mdx;
    uint64_t top_frame_sp; // Original sp to be restored when returning from an i2i call
    uint64_t sender_sp;
    // Slots only needed for native calls. Maybe better to move elsewhere.
    uint64_t oop_tmp;
    uint64_t lresult;
    uint64_t fresult;
  };

  enum {
    ijava_state_size = sizeof(ijava_state)
  };

// Byte offset relative to fp
#define _ijava_state_neg(_component) \
        (int) (-frame::ijava_state_size + offset_of(frame::ijava_state, _component))

// Frame slot index relative to fp
#define ijava_idx(_component) \
        (_ijava_state_neg(_component) >> LogBytesPerWord)

  // ENTRY_FRAME

  struct entry_frame_locals {
    uint64_t call_wrapper_address;
    uint64_t result_address;                      //_16
    uint64_t result_type;
    uint64_t arguments_tos_address;               //_16
    // aligned to frame::alignment_in_bytes (16)
  };

  enum {
    entry_frame_locals_size = sizeof(entry_frame_locals)
  };

  #define _entry_frame_locals_neg(_component) \
    (int)(-frame::entry_frame_locals_size + offset_of(frame::entry_frame_locals, _component))


  //  Frame layout for JIT generated methods
  //
  //  In these figures the stack grows upwards, while memory grows
  //  downwards. Square brackets denote regions possibly larger than single
  //  64 bit slots.
  //
  //  STACK (interpreted Java calls JIT generated Java):
  //          [JIT_FRAME]                                <-- SP (mod 16 = 0)
  //          [TOP_IJAVA_FRAME]
  //         ...
  //
  //  JIT_FRAME (is a C frame according to PPC-64 ABI):
  //          [out_preserve]
  //          [out_args]
  //          [spills]
  //          [pad_1]
  //          [monitor] (optional)
  //       ...
  //          [monitor] (optional)
  //          [pad_2]
  //          [in_preserve] added / removed by prolog / epilog
  //

  // For JIT frames we don't differentiate between TOP and PARENT frames.
  // Runtime calls go through stubs which push a new frame.

  struct jit_out_preserve : java_abi {
    // Nothing to add here!
  };

  struct jit_in_preserve {
    // Nothing to add here!
  };

  enum {
    jit_out_preserve_size = sizeof(jit_out_preserve),
    jit_in_preserve_size  = sizeof(jit_in_preserve)
  };

  struct jit_monitor {
    uint64_t monitor[1];
  };

  enum {
    jit_monitor_size = sizeof(jit_monitor),
  };

 private:

#ifdef ASSERT
  enum special_backlink_values : uint64_t {
    NOT_FULLY_INITIALIZED = 0xBBAADDF9
  };
  bool is_fully_initialized()       const { return (uint64_t)_fp != NOT_FULLY_INITIALIZED; }
#endif // ASSERT

  //  STACK:
  //            ...
  //            [THIS_FRAME]             <-- this._sp (stack pointer for this frame)
  //            [CALLER_FRAME]           <-- this.fp() (_sp of caller's frame)
  //            ...
  //

  // The frame's stack pointer before it has been extended by a c2i adapter;
  // needed by deoptimization
  union {
    intptr_t* _unextended_sp;
    int _offset_unextended_sp; // for use in stack-chunk frames
  };

  union {
    intptr_t* _fp;  // frame pointer
    int _offset_fp; // relative frame pointer for use in stack-chunk frames
  };

 public:

  // Accessors for fields
  intptr_t* fp() const { assert_absolute(); return _fp; }
  void set_fp(intptr_t* newfp)  { _fp = newfp; }
  int offset_fp() const         { assert_offset();  return _offset_fp; }
  void set_offset_fp(int value) { assert_on_heap(); _offset_fp = value; }

  // Mark a frame as not fully initialized. Must not be used for frames in the valid back chain.
  void mark_not_fully_initialized() const { DEBUG_ONLY(own_abi()->callers_sp = NOT_FULLY_INITIALIZED;)  }

  // Accessors for ABIs
  inline common_abi* own_abi()     const { return (common_abi*) _sp; }
  inline common_abi* callers_abi() const { return (common_abi*) _fp; }

  enum class kind {
    unknown,          // The frame's pc is not necessarily in the CodeCache.
                      // CodeCache::find_blob_fast(void* pc) can yield wrong results in this case and must not be used.
    code_blob,        // The frame's pc is known to be in the CodeCache but it is likely not in an nmethod.
                      // CodeCache::find_blob_fast() will be correct but not faster in this case.
    nmethod           // This is likely the frame of a nmethod.
                      // The code cache lookup is optimized based on NativePostCallNops.
  };

 private:

  // Initialize frame members (_pc and _sp must be given)
  inline void setup(kind knd);

 public:

  // Constructors
  inline frame(intptr_t* sp, intptr_t* fp, address pc);
  inline frame(intptr_t* sp, address pc, kind knd = kind::nmethod);
  inline frame(intptr_t* sp, address pc, intptr_t* unextended_sp, intptr_t* fp = nullptr, CodeBlob* cb = nullptr);
  inline frame(intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, address pc, CodeBlob* cb, const ImmutableOopMap* oop_map = nullptr);
  inline frame(intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, address pc, CodeBlob* cb, const ImmutableOopMap* oop_map, bool on_heap);

 private:
  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;
  inline void interpreter_frame_set_cpcache(ConstantPoolCache* cp);
  inline void interpreter_frame_set_esp(intptr_t* esp);
  inline void interpreter_frame_set_top_frame_sp(intptr_t* top_frame_sp);
  inline void interpreter_frame_set_sender_sp(intptr_t* sender_sp);

  template <typename RegisterMapT>
  static void update_map_with_saved_link(RegisterMapT* map, intptr_t** link_addr);

  // The size of a cInterpreter object.
  static inline int interpreter_frame_cinterpreterstate_size_in_bytes();

  // Additional interface for entry frames:
  inline entry_frame_locals* get_entry_frame_locals() const {
    return (entry_frame_locals*) (((address) fp()) - entry_frame_locals_size);
  }

  enum {
    // normal return address is 1 bundle past PC
    pc_return_offset                       = 0,
    // size, in words, of frame metadata (e.g. pc and link)
    metadata_words                         = sizeof(java_abi) >> LogBytesPerWord,
    // size, in words, of metadata at frame bottom, i.e. it is not part of the
    // caller/callee overlap
    metadata_words_at_bottom               = 0,
    // size, in words, of frame metadata at the frame top, i.e. it is located
    // between a callee frame and its stack arguments, where it is part
    // of the caller/callee overlap
    metadata_words_at_top                  = sizeof(java_abi) >> LogBytesPerWord,
    // size, in words, of frame metadata at the frame top that needs
    // to be reserved for callee functions in the runtime
    frame_alignment                        = 16,
    frame_alignment_in_words               = frame_alignment >> LogBytesPerWord,
    // size, in words, of maximum shift in frame position due to alignment
    align_wiggle                           =  1,
    // This is wrong and unimplemented
    sender_sp_offset                       =  0
  };

  static jint interpreter_frame_expression_stack_direction() { return -1; }

  // returns the sending frame, without applying any barriers
  inline frame sender_raw(RegisterMap* map) const;

  intptr_t* repair_sender_sp(intptr_t* sender_sp, intptr_t** saved_fp_addr) const;
  static intptr_t* repair_sender_sp(nmethod* nm, intptr_t* sp, intptr_t** saved_fp_addr);
  bool was_augmented_on_entry(int& real_size) const;

#endif // CPU_PPC_FRAME_PPC_HPP
