/**
 * $Id: yarvcore.h 146 2005-02-23 15:48:20Z ko1 $
 * Create : K.S. 04/01/01 19:41:38
 */

#ifndef _YARVCORE_H_INCLUDED_
#define _YARVCORE_H_INCLUDED_

#include "version.h"
#include "debug.h"

/* classes and modules */
extern VALUE mYarvCore;
extern VALUE cYarvISeq;
extern VALUE cYarvInsn;
extern VALUE cYarvLabel;
extern VALUE cYarvVM;
extern VALUE cYarvThread;
extern VALUE mYarvInsns;
extern VALUE cYarvThrowObject;
extern VALUE cYarvEnv;
extern VALUE cYarvProc;

extern VALUE symIFUNC;
extern VALUE symCFUNC;

/* special id */
extern ID idPLUS;
extern ID idMINUS;
extern ID idLT;
extern ID idLTLT;
extern ID idEqq;
extern ID idBackquote;
extern ID idEqTilde;
extern ID idThrowState;
extern ID idThrowBackDFP;
extern ID idThrowObject;
extern ID idAREF;
extern ID idASET;
extern ID idIntern;
extern ID idMethodMissing;


extern unsigned long yarvGlobalStateVersion;


/* internal structure */

#define GetLabelVal(obj, lobj) \
  Data_Get_Struct(obj, struct label_object, lobj)

struct label_object{
  int label_no;
  long position;
  unsigned long sc_state;
  VALUE set;
};


#define GetInsnVal(obj, iobj) \
  Data_Get_Struct(obj, struct insn_object, iobj)

struct insn_object{
  int insn_id;
  unsigned long line_no;
  VALUE operands;
  unsigned long sc_state;
};

#define GetISeqVal(obj, tobj) \
  Data_Get_Struct(obj, struct iseq_object, tobj)

struct insn_info_struct{
  unsigned short position;
  unsigned short line_no;
};

#define ISEQ_TYPE_TOP    INT2FIX(1)
#define ISEQ_TYPE_METHOD INT2FIX(2)
#define ISEQ_TYPE_BLOCK  INT2FIX(3)
#define ISEQ_TYPE_CLASS  INT2FIX(4)
#define ISEQ_TYPE_RESCUE INT2FIX(5)
#define ISEQ_TYPE_ENSURE INT2FIX(6)

#define CATCH_TYPE_RESCUE INT2FIX(1)
#define CATCH_TYPE_ENSURE INT2FIX(2)
#define CATCH_TYPE_RETRY  INT2FIX(3)

struct catch_table_entry{
  VALUE type;
  VALUE iseq;
  unsigned long start;
  unsigned long end;
  unsigned long sp;
  unsigned long cont;
};

struct iseq_compile_data{
  VALUE current_block;
  
  VALUE start_label;
  VALUE end_label;
  VALUE redo_label;
  
  VALUE loopval_popped;  /* used by NODE_BREAK */
  VALUE in_ensure;       /* used by NODE_RETURN */

  VALUE err_info;
  
  int   cached_const;

  VALUE compile_data;
};

struct iseq_object{
  VALUE  name; /* String: iseq name */
  VALUE *iseq; /* iseq */
  VALUE  iseq_mark_ary; /* Array: includes operands which should be GC marked */
  VALUE  insns_ary;

#ifdef DISPATCH_DIRECT_THREADED_CODE
  VALUE *iseq_dt;
#endif
  
  /* sequence size */
  unsigned long size;

  /* insn info, must be freed */
  struct insn_info_struct *insn_info_tbl;
  
  /* insn info size, this value shows also instruction count */
  unsigned int insn_info_size;

  /* file information where this sequence from */
  VALUE file_name;
  
  ID *local_tbl;                  /* must free */
  int local_size;

  /* jit compiled or not */
  void *jit_compiled;
  void *iseq_orig;
  
  
  /**
   * argument information
   *
   *  def m(a1, a2, ..., aM, b1=(...), b2=(...), ..., bN=(...), *c, &d)
   * =>
   *
   *  argc          = M
   *  arg_rest      = M+N
   *  arg_opts      = N
   *  arg_opts_tbl  = [ (N entries) ]
   *  arg_initstart = M+N+1
   *
   *  check:
   *    M <= num
   */
  
  
  int argc;
  int arg_simple;
  int arg_rest;
  int arg_block;
  int arg_opts;
  VALUE *arg_opt_tbl;
  
  /* rewind frame size from dfp */
  int rewind_frame_size;
  
  /* to stack overflow check */
  int stack_max;

  /* instruction sequence type */
  int type;

  /* klass/module nest information stack */
  VALUE klass_nest_stack; /* Array */

  /* catch table */
  VALUE catch_table_ary; /* Array */
  struct catch_table_entry *catch_table;
  int                       catch_table_size;
  
  /* for child iseq */
  struct iseq_object *parent_iseqobj;
  struct iseq_object *root_iseqobj;
  
  struct iseq_compile_data *compile_data;
};


#define GetVMVal(obj, tobj) \
  Data_Get_Struct(obj, struct vm_object, tobj)

struct vm_object{
  VALUE main_thread;

  /* this data structure should include all
     runtime information (e.g. method table, object management table, ...) */
};



#define GetThreadVal(obj, tobj) \
  Data_Get_Struct(obj, struct thread_object, tobj)


struct thread_object{
  /* execution information */
  VALUE *stack;                   /* must free, must mark*/
  unsigned long stack_size;
  
  VALUE *stack_mark_pointer;
  
  VALUE *pc;
  VALUE *sp;
  VALUE *lfp;
  VALUE *dfp;
  VALUE *cfp;

  /* for rb_iterate */
  NODE *block_ptr;
  
  /* */
  VALUE vm;

  /* other information */
  VALUE stat_insn_usage;

  /* klass/module nest information stack */
  VALUE klass_nest_stack; /* Array */
};

/** node -> yarv instruction sequence object */
VALUE iseq_compile(VALUE self, VALUE node);

/** disassemble instruction sequence */
VALUE iseq_disasm(VALUE self);

VALUE iseq_disasm_insn(VALUE str, VALUE *iseq, int pos,
                       struct iseq_object *iseqobj, VALUE child);
char* node_name(int node);

/* insns_info.c */
char *insn_name(int insn);
int insn_len(int insn);
char *insn_op_types(int insn);
int insn_op_type(int insn, int pos);


/* each thread has this size stack : 2MB */
#define YARV_THREAD_STACK_SIZE 0x20000



/* from ruby 1.9 variable.c */
struct global_entry {
    struct global_variable *var;
    ID id;
};


/* for VM */

/* these structure description is written in  vm.h */


struct vm_block_object{
  VALUE *lfp; /* share with method frame if it's only block */
  VALUE *dfp; /* share with method frame if it's only block */
  VALUE self;
  VALUE iseq;
  VALUE proc;
};

#define VM_BLOCK_OBJECT_SAHRE_SIZE 2
#define VM_BLOCK_OBJECT_OVER_SIZE  3


#define GetProcVal(obj, iobj) \
  Data_Get_Struct(obj, struct vm_proc_object, iobj)

struct vm_proc_object{
  struct vm_block_object bo;
  VALUE envobj;       /* for GC mark */
  VALUE blockobj;
};


#define GetEnvVal(obj, iobj) \
  Data_Get_Struct(obj, struct vm_env_object, iobj)

struct vm_env_object{
  VALUE *env;
  int    env_size;    /* for GC mark */
  VALUE  prev_envobj; /* for GC mark */
  VALUE *lfp;
  VALUE *dfp; /* point &env[localsize] */
  VALUE *orig_prev_dfp;
};


/* used by compile time and send insn */
#define VM_CALL_ARGS_SPLAT_BIT    0x01
#define VM_CALL_ARGS_BLOCKARG_BIT 0x02
                         /* 0x04, 0x08 */
#define VM_CALL_TAILCALL_BIT      0x10


VALUE thread_invoke_proc_call(VALUE self, VALUE proc, int argc, VALUE *args);
VALUE thread_eval_body(VALUE self);
VALUE iseq_inspect(VALUE self);


/* inline method cache */
#define NEW_INLINE_CACHE_ENTRY() NEW_WHILE(Qundef, 0, 0)
#define ic_klass  u1.value
#define ic_method u2.node
#define ic_value  u2.value
#define ic_vmstat u3.cnt
typedef NODE * IC;

#include "yarv.h"

#define YARV_METHOD_NODE NODE_ERRINFO


/* defined? */
#define DEFINED_IVAR   INT2FIX(1)
#define DEFINED_GVAR   INT2FIX(2)
#define DEFINED_CVAR   INT2FIX(3)
#define DEFINED_CONST  INT2FIX(4)
#define DEFINED_METHOD INT2FIX(5)

#endif	// _YARVCORE_H_INCLUDED_



