/**
  @file   insnhelper.h
  @author K.S.
  $Date: 2004/01/10 14:46:21 $
  $Id: insnhelper.h 134 2005-02-17 20:59:04Z ko1 $

  Create : K.S. 04/01/01 15:50:34

  Instruction helper for "Single Thread"
*/

#ifndef _INSNHELPER_H_INCLUDED_
#define _INSNHELPER_H_INCLUDED_

#include "vm.h"


/**********************************************************/
/* deal with stack                                        */
/**********************************************************/

#define PUSH(x) (SET_SV(x), INC_SP(1))
#define TOPN(n) (*(GET_SP()-(n)-1))
#define POPN(n) (INC_SP(-(n)))
#define POP()   (INC_SP(-1))
#define STACK_ADDR_FROM_TOP(n) (&GET_SP()[-(n)])

#define GET_TOS()  (tos) /* dummy */

/**********************************************************/
/* deal with registers                                    */
/**********************************************************/

#define REG_PC  reg_pc
#define REG_SP  reg_sp
#define REG_LFP reg_lfp
#define REG_DFP reg_dfp
#define REG_CFP reg_cfp

#define REG_A   reg_a
#define REG_B   reg_b

#define RESTORE_REGS()       (0)

/* PC */
#define GET_PC()           (USAGE_ANALYSIS_REGISTER(0, 0), REG_PC)
#define SET_PC(x)          (REG_PC = (USAGE_ANALYSIS_REGISTER(0, 1), (x)))
#define GET_CURRENT_INSN() (*GET_PC())
#define GET_OPERAND(n)     (GET_PC()[(n)])
#define ADD_PC(n)          (SET_PC(REG_PC += (n)))

#ifdef DISPATCH_DIRECT_THREADED_CODE
#define GET_PC_COUNT()     (REG_PC - GET_ISEQ()->iseq_dt)
#else
#define GET_PC_COUNT()     (REG_PC - GET_ISEQ()->iseq)
#endif

#define JUMP(dst)          (REG_PC += (dst))


/* FP */
#define GET_CFP()  (USAGE_ANALYSIS_REGISTER(2, 0), REG_CFP)
#define SET_CFP(x) (th->cfp = REG_CFP = (USAGE_ANALYSIS_REGISTER(2, 1), (x)))
#define GET_LFP()  (USAGE_ANALYSIS_REGISTER(3, 0), REG_LFP)
#define SET_LFP(x) (th->lfp = REG_LFP = (USAGE_ANALYSIS_REGISTER(3, 1), (x)))
#define GET_DFP()  (USAGE_ANALYSIS_REGISTER(4, 0), REG_DFP)
#define SET_DFP(x) (th->dfp = REG_DFP = (USAGE_ANALYSIS_REGISTER(4, 1), (x)))

#define GET_CONTINUATION_FRAME_PTR(cfp) \
  ((struct continuation_frame *)((cfp) + CC_DIFF_WC()))

/* SP */
#define GET_SP()   (USAGE_ANALYSIS_REGISTER(1, 0), REG_SP)
#define SET_SP(x)  (th->sp = REG_SP  = (USAGE_ANALYSIS_REGISTER(1, 1), (x)))
#define INC_SP(x)  (th->sp = REG_SP += (USAGE_ANALYSIS_REGISTER(1, 1), (x)))
#define SET_SV(x)  (*GET_SP() = (x))
  /* set current stack value as x */

#define GET_SP_COUNT() (REG_SP - th->stack)



/* instruction sequence C struct */
#define GET_ISEQOBJ(cfp) (USAGE_ANALYSIS_REGISTER(6, 0), *((cfp) + 1))
#define GET_ISEQ()       (USAGE_ANALYSIS_REGISTER(6, 0), \
                          (struct iseq_object*)DATA_PTR(*(GET_CFP() + 1)))

#define CLEAR_ENV(env) (GET_ENV_CTRL(env)->is_orphan = Qundef)


/**********************************************************/
/* deal with variables                                    */
/**********************************************************/

#define GET_CURRENT_DYNAMIC(idx)         (GET_DFP()[-idx])

#define GET_GLOBAL(entry)                rb_gvar_get((struct global_entry*)entry)
#define SET_GLOBAL(entry, val)           rb_gvar_set((struct global_entry*)entry, val)

#define GET_EV_KLASS(klass)                                 \
  if(GET_ISEQ()->klass_nest_stack){                         \
    /* method scope? */                                     \
    klass = rb_ary_entry(GET_ISEQ()->klass_nest_stack, -1); \
  }                                                         \
  else{                                                     \
    /* class scope? */                                      \
    klass = GET_SELF();                                     \
  }



/**********************************************************/
/* deal with values                                       */
/**********************************************************/

#define GET_SELF() (USAGE_ANALYSIS_REGISTER(5, 0), *GET_CFP())


/**********************************************************/
/* deal with control flow 2: method/iterator              */
/**********************************************************/

/* block */
#define GET_BLOCK()        (GET_LFP()[0])


/**********************************************************/
/* deal with control flow 3: exception                    */
/**********************************************************/

#define RAISE(obj)


/**********************************************************/
/* others                                                 */
/**********************************************************/

#define GET_VM_STATE_VERSION() (yarvGlobalStateVersion)
#define INC_VM_STATE_VERSION() \
  (yarvGlobalStateVersion = (yarvGlobalStateVersion+1) & 0x8fffffff)


/* optimize insn */
#define FIXNUM_2_P(a, b) ((a) & (b) & 1)
#define BASIC_OP_UNREDEFINED(op) (yarv_unredefined_flag)


#endif	// _INSNHELPER_H_INCLUDED_

