/*
 *  This file is part of the Jikes RVM project (http://jikesrvm.org).
 *
 *  This file is licensed to You under the Common Public License (CPL);
 *  You may not use this file except in compliance with the License. You
 *  may obtain a copy of the License at
 *
 *      http://www.opensource.org/licenses/cpl1.0.php
 *
 *  See the COPYRIGHT.txt file distributed with this work for information
 *  regarding copyright ownership.
 */
package org.jikesrvm.ia32;

import org.jikesrvm.SizeConstants;
import org.vmmagic.unboxed.Address;

/**----------------------------------------------------------------------
 *                   Stackframe layout conventions - Intel version.
 *-----------------------------------------------------------------------
 *
 * A stack is an array of "slots", declared formally as integers, each slot
 * containing either a primitive (byte, int, float, etc), an object pointer,
 * a machine code pointer (a return address pointer), or a pointer to another
 * slot in the same stack (a frame pointer). The interpretation of a slot's
 * contents depends on the current value of IP, the machine instruction
 * address register.
 * Each machine code generator provides maps, for use by the garbage collector,
 * that tell how to interpret the stack slots at "safe points" in the
 * program's execution.
 *
 * Here's a picture of what a stack might look like in memory.
 *
 * Note: this (array) object is drawn upside down compared to other objects
 * because the hardware stack grows from high memory to low memory, but
 * array objects are layed out from low memory to high (header first).
 * <pre>
 *  hi-memory
 *              +---------------+                                            ...
 *              |     IP=0      |                                             .
 *              +---------------+                                             .
 *          +-> |     FP=0      |   <-- "end of vm stack" sentinel            .
 *          |   +---------------+                                             . caller's frame
 *          |   |    cmid=0      |   <-- "invisible method" id                .
 *          |   +---------------+                                          ---.
 *          |   |   parameter0  |  \                                        | .
 *          |   +---------------+   \ parameter area                        | .
 *          |   |   parameter1  |   /  (== caller's operand stack area)     | .
 *   ---    |   +---------------+  /                                        |...
 *    |     |   |   saved IP    |  <-- return address (in caller)           |
 *    |      \  +---------------+                                           |
 *  header FP-> |   saved FP    |  <-- this frame's caller's frame          |
 *    |         +---------------+                                           |
 *    |         |    cmid       |  <-- this frame's compiledmethod id       |
 *    |         +---------------+                                           |
 *    |         |   saved GPRs  |  \                                        |
 *    |         +---------------+   \ nonvolatile register save area        |
 *    |         |   saved FPRS  |   /                                       | frame
 *    |         +---------------+                                           |
 *    |         |   local0      |  \                                        |
 *   body       +---------------+   \_local variables area                  |
 *    |         |   local1      |   /                                       |
 *    |         +---------------+  /                                        |
 *    |         |   operand0    |  \                                        |
 *    |         +---------------+   \_operand stack area                    |
 *    |    SP-> |   operand1    |   /                                       |
 *    |         +---------------+  /                                        |
 *    |         |     ...       |                                           |
 *   ---        +===============+                                          ---
 *              |     ...       |
 *              +---------------+
 * stackLimit-> |     ...       | \
 *              +---------------+  \_guard region for detecting & processing stack overflow
 *              |     ...       |  /
 *              +---------------+ /
 *              |(object header)|
 *  low-memory  +---------------+
 *
 *
 *
 *  The opt compiler uses a different stackframe layout
 *
 *  hi-memory
 *              +---------------+                                            ...
 *              |     IP=0      |                                             .
 *              +---------------+                                             .
 *          +-> |     FP=0      |   <-- "end of vm stack" sentinel           .
 *          |   +---------------+                                             . caller's frame
 *          |   |    cmid=-1    |   <-- "invisible method" id                .
 *          |   +---------------+                                          ---.
 *          |   |   parameter0  |  \                                        | .
 *          |   +---------------+   \ parameter area                        | .
 *          |   |   parameter1  |   /  (== caller's operand stack area)     | .
 *   ---    |   +---------------+  /                                        |...
 *    |     |   |   saved IP    |  <-- return address (in caller)           |
 *    |      \  +---------------+                                           |
 *  header FP-> |   saved FP    |  <-- this frame's caller's frame          |
 *    |         +---------------+                                           |
 *    |         |    cmid       |  <-- this frame's compiledmethod id       |
 *   ---        +---------------+                                           |
 *    |         |               |                                           |
 *    |         |  Spill Area   |  <-- spills and other method-specific     |
 *    |         |     ...       |      compiler-managed storage             |
 *    |         +---------------+                                           |
 *    |         |   Saved FP    |     only SaveVolatile Frames              |
 *    |         |    State      |                                           |
 *    |         +---------------+                                           |
 *    |         |  VolGPR[0]    |                                           |
 *    |         |     ...       |     only SaveVolatile Frames              |
 *    |         |  VolGPR[n]    |                                           |
 *    |         +---------------+                                           |
 *   body       |  NVolGPR[k]   |  <-- info.getUnsignedNonVolatileOffset()  | frame
 *    |         |     ...       |   k == info.getFirstNonVolatileGPR()      |
 *    |         |  NVolGPR[n]   |                                           |
 *    |         +---------------+                                           |
 *    |         |  NVolFPR[k]   |                                           |
 *    |         |     ...       |   k == info.getFirstNonVolatileFPR()      |
 *    |         |  NVolFPR[n]   |                                           |
 *    |         +---------------+                                           |
 *    |         |   parameter0  |  \                                        |
 *    |         +---------------+   \_parameters to callee frame            |
 *    |    SP-> |   parameter1  |   /                                       |
 *    |         +---------------+  /                                        |
 *    |         |     ...       |                                           |
 *   ---        +===============+                                          ---
 *              |     ...       |
 *              +---------------+
 * stackLimit-> |     ...       | \
 *              +---------------+  \_guard region for detecting & processing stack overflow
 *              |     ...       |  /
 *              +---------------+ /
 *              |(object header)|
 *  low-memory  +---------------+
 *
 * </pre>
 */
public interface StackframeLayoutConstants {

  int LOG_BYTES_IN_STACKSLOT = SizeConstants.LOG_BYTES_IN_ADDRESS;
  int BYTES_IN_STACKSLOT = 1 << LOG_BYTES_IN_STACKSLOT;

  /** offset of caller's return address from FP */
  int STACKFRAME_RETURN_ADDRESS_OFFSET = 4;
  /** base of this frame */
  int STACKFRAME_FRAME_POINTER_OFFSET = 0;
  /** offset of method id from FP */
  int STACKFRAME_METHOD_ID_OFFSET = -4;
  /** offset of work area from FP */
  int STACKFRAME_BODY_OFFSET = -8;
  /** size of frame header, in bytes */
  int STACKFRAME_HEADER_SIZE = 12;

  // space to save entire FPU state.  The FPU state is saved only for 'bridge' frames
  int FPU_STATE_SIZE = 108;
  int XMM_STATE_SIZE = 8 * 4; // Currently only use the low 8 bytes, only use 4 SSE2 params

  /** fp value indicating end of stack walkback */
  Address STACKFRAME_SENTINEL_FP = Address.fromIntSignExtend(-2);
  /** marker for "assembler" frames that have no associated RVMMethod */
  int INVISIBLE_METHOD_ID = -1;

  // Stackframe alignment.
  // Align to 8 byte boundary for good floating point save/restore performance (on powerPC, anyway).
  //
  int STACKFRAME_ALIGNMENT = 8;

  // Sizes for stacks and subregions thereof.
  // Values are in bytes and must be a multiple of 4 (size of a stack slot).
  //
  /** how much to grow stack when overflow detected */
  int STACK_SIZE_GROW = 8 * 1024;
  /** max space needed for stack overflow trap processing */
  int STACK_SIZE_GUARD = 64 * 1024;
  /** max space needed for any native code called by vm */
  int STACK_SIZE_SYSCALL = 4 * 1024;
  /** max space needed for dlopen sys call */
  int STACK_SIZE_DLOPEN = 30 * 1024;
  /** max space needed while running with gc disabled */
  int STACK_SIZE_GCDISABLED = 4 * 1024;

  // Complications:
  // - STACK_SIZE_GUARD must be greater than STACK_SIZE_NATIVE or STACK_SIZE_GCDISABLED
  //   to ensure that frames allocated by stack growing code will fit within guard region.
  // - STACK_SIZE_GROW must be greater than STACK_SIZE_NATIVE or STACK_SIZE_GCDISABLED
  //   to ensure that, if stack is grown prior to disabling gc or calling native code,
  //   the new stack will accomodate that code without generating a stack overflow trap.
  // - Values chosen for STACK_SIZE_NATIVE and STACK_SIZE_GCDISABLED are pure guesswork
  //   selected by trial and error.

  // Stacks for "normal" threads grow as needed by trapping on guard region.
  // Stacks for "boot" and "collector" threads are fixed in size and cannot grow.
  //
  /** initial stack space to allocate for normal    thread (includes guard region) */
  int STACK_SIZE_NORMAL =
      STACK_SIZE_GUARD +
      STACK_SIZE_GCDISABLED +
      200 * 1024; // initial stack space to allocate for normal    thread (includes guard region)
  int STACK_SIZE_BOOT =
      STACK_SIZE_GUARD +
      STACK_SIZE_GCDISABLED +
      30 * 1024; // total   stack space to allocate for boot      thread (includes guard region)
  int STACK_SIZE_COLLECTOR =
      STACK_SIZE_GUARD +
      STACK_SIZE_GCDISABLED +
      20 * 1024; // total   stack space to allocate for collector thread (includes guard region)
  int STACK_SIZE_MAX =
      STACK_SIZE_GUARD + STACK_SIZE_GCDISABLED + 200 * 1024; // upper limit on stack size (includes guard region)

  int STACK_SIZE_JNINATIVE_GROW = 0; // TODO!!;
}
