summaryrefslogtreecommitdiff
path: root/vm.h
blob: a40cc57f9673edecf7572e87e59d8f0474978700 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
/**********************************************************************

  vm.h -

  $Author$
  $Date$
  created at: 04/01/01 16:56:59 JST

  Copyright (C) 2004-2007 Koichi Sasada

**********************************************************************/

#ifndef RUBY_VM_H
#define RUBY_VM_H

typedef long OFFSET;
typedef unsigned long rb_num_t;
typedef unsigned long lindex_t;
typedef unsigned long dindex_t;
typedef rb_num_t GENTRY;
typedef rb_iseq_t *ISEQ;

extern VALUE rb_cEnv;
extern VALUE ruby_vm_global_state_version;
extern VALUE ruby_vm_redefined_flag;


/**
 * VM Debug Level
 *
 * debug level:
 *  0: no debug output
 *  1: show instruction name
 *  2: show stack frame when control stack frame is changed
 *  3: show stack status
 *  4: show register
 *  5:
 * 10: gc check
 */


#ifndef VMDEBUG
#define VMDEBUG 0
#endif

#if 0
#undef  VMDEBUG
#define VMDEBUG 3
#endif

#ifdef  COLLECT_USAGE_ANALYSIS
#define USAGE_ANALYSIS_INSN(insn)           vm_analysis_insn(insn)
#define USAGE_ANALYSIS_OPERAND(insn, n, op) vm_analysis_operand(insn, n, (VALUE)op)
#define USAGE_ANALYSIS_REGISTER(reg, s)     vm_analysis_register(reg, s)
#else
#define USAGE_ANALYSIS_INSN(insn)		/* none */
#define USAGE_ANALYSIS_OPERAND(insn, n, op)	/* none */
#define USAGE_ANALYSIS_REGISTER(reg, s)		/* none */
#endif

#ifdef __GCC__
/* TODO: machine dependent prefetch instruction */
#define PREFETCH(pc)
#else
#define PREFETCH(pc)
#endif

#if VMDEBUG > 0
#define debugs printf
#define DEBUG_ENTER_INSN(insn) \
  debug_print_pre(th, GET_CFP());

#if OPT_STACK_CACHING
#define SC_REGS() , reg_a, reg_b
#else
#define SC_REGS()
#endif

#define DEBUG_END_INSN() \
  debug_print_post(th, GET_CFP() SC_REGS());

#else

#define debugs
#define DEBUG_ENTER_INSN(insn)
#define DEBUG_END_INSN()
#endif

#define throwdebug if(0)printf
/* #define throwdebug printf */

#define SDR2(cfp) vm_stack_dump_raw(GET_THREAD(), (cfp))


/************************************************/
#if   DISPATCH_XXX
error !
/************************************************/
#elif OPT_CALL_THREADED_CODE

#define LABEL(x)  insn_func_##x
#define ELABEL(x)
#define LABEL_PTR(x) &LABEL(x)

#define INSN_ENTRY(insn) \
  static rb_control_frame_t * \
    FUNC_FASTCALL(LABEL(insn))(rb_thread_t *th, rb_control_frame_t *reg_cfp) {

#define END_INSN(insn) return reg_cfp;}

#define NEXT_INSN() return reg_cfp;

/************************************************/
#elif OPT_TOKEN_THREADED_CODE || OPT_DIRECT_THREADED_CODE
/* threaded code with gcc */

#define LABEL(x)  INSN_LABEL_##x
#define ELABEL(x) INSN_ELABEL_##x
#define LABEL_PTR(x) &&LABEL(x)

#define INSN_ENTRY_SIG(insn)


#define INSN_DISPATCH_SIG(insn)

#define INSN_ENTRY(insn) \
  LABEL(insn): \
  INSN_ENTRY_SIG(insn); \

/* dispather */
#if __GNUC__ && (__i386__ || __x86_64__) && __GNUC__ == 3
#define DISPATCH_ARCH_DEPEND_WAY(addr) \
  asm volatile("jmp *%0;\t# -- inseted by vm.h\t[length = 2]" : : "r" (addr))

#else
#define DISPATCH_ARCH_DEPEND_WAY(addr) \
				/* do nothing */

#endif


/**********************************/
#if OPT_DIRECT_THREADED_CODE

/* for GCC 3.4.x */
#define TC_DISPATCH(insn) \
  DISPATCH_ARCH_DEPEND_WAY(GET_CURRENT_INSN()); \
  INSN_DISPATCH_SIG(insn); \
  goto *GET_CURRENT_INSN(); \
  ;

#else
/* token threade code */

#define TC_DISPATCH(insn)  \
  DISPATCH_ARCH_DEPEND_WAY(insns_address_table[GET_CURRENT_INSN()]); \
  INSN_DISPATCH_SIG(insn); \
  goto *insns_address_table[GET_CURRENT_INSN()]; \
  rb_bug("tc error");


#endif /* DISPATCH_DIRECT_THREADED_CODE */

#define END_INSN(insn)      \
  DEBUG_END_INSN();         \
  TC_DISPATCH(insn);        \

#define INSN_DISPATCH()     \
  TC_DISPATCH(__START__)    \
  {

#define END_INSNS_DISPATCH()    \
      rb_bug("unknown insn: %ld", GET_CURRENT_INSN());   \
  }   /* end of while loop */   \

#define NEXT_INSN() TC_DISPATCH(__NEXT_INSN__)

/************************************************/
#else /* no threaded code */
/* most common method */

#define INSN_ENTRY(insn) \
case BIN(insn):

#define END_INSN(insn)                        \
  DEBUG_END_INSN();                           \
  break;


#define INSN_DISPATCH()         \
  while(1){                     \
    switch(GET_CURRENT_INSN()){

#define END_INSNS_DISPATCH()    \
default:                        \
  SDR(); \
      rb_bug("unknown insn: %ld", GET_CURRENT_INSN());   \
    } /* end of switch */       \
  }   /* end of while loop */   \

#define NEXT_INSN() goto first

#endif


/************************************************/
/************************************************/

#define VM_CFP_CNT(th, cfp) \
  ((rb_control_frame_t *)(th->stack + th->stack_size) - (rb_control_frame_t *)(cfp))
#define VM_SP_CNT(th, sp) ((sp) - (th)->stack)

/*
  env{
    env[0] // special (block or prev env)
    env[1] // env object
    env[2] // prev env val
  };
 */

#define ENV_IN_HEAP_P(th, env)  \
  (!((th)->stack < (env) && (env) < ((th)->stack + (th)->stack_size)))
#define ENV_VAL(env)        ((env)[1])

#define FRAME_MAGIC_METHOD 0x11
#define FRAME_MAGIC_BLOCK  0x21
#define FRAME_MAGIC_CLASS  0x31
#define FRAME_MAGIC_TOP    0x41
#define FRAME_MAGIC_FINISH 0x51
#define FRAME_MAGIC_CFUNC  0x61
#define FRAME_MAGIC_PROC   0x71
#define FRAME_MAGIC_IFUNC  0x81
#define FRAME_MAGIC_EVAL   0x91
#define FRAME_MAGIC_LAMBDA 0xa1
#define FRAME_MAGIC_MASK_BITS   8
#define FRAME_MAGIC_MASK   (~(~0<<FRAME_MAGIC_MASK_BITS))

#define VM_FRAME_FLAG(type) ((VALUE)((type) & FRAME_MAGIC_MASK))

#define VM_FRAME_TYPE(cfp) \
  ((cfp)->flag & FRAME_MAGIC_MASK)

#define RUBYVM_CFUNC_FRAME_P(cfp) \
  (VM_FRAME_TYPE(cfp) == FRAME_MAGIC_CFUNC)

#if OPT_CALL_THREADED_CODE
#define THROW_EXCEPTION(exc) do { \
    th->errinfo = (VALUE)(exc); \
    return 0; \
} while (0)
#else
#define THROW_EXCEPTION(exc) return (VALUE)(exc)
#endif

#define SCREG(r) (reg_##r)

/* VM state version */

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

#define BOP_PLUS     0x01
#define BOP_MINUS    0x02
#define BOP_MULT     0x04
#define BOP_DIV      0x08
#define BOP_MOD      0x10
#define BOP_EQ       0x20
#define BOP_LT       0x40
#define BOP_LE       0x80
#define BOP_LTLT    0x100
#define BOP_AREF    0x200
#define BOP_ASET    0x400
#define BOP_LENGTH  0x800
#define BOP_SUCC   0x1000
#define BOP_GT     0x2000
#define BOP_GE     0x4000
#define BOP_NOT    0x8000
#define BOP_NEQ   0x10000

#endif /* RUBY_VM_H */