1/* -*-c-*- */
2/**********************************************************************
3
4  vm_exec.c -
5
6  $Author: nagachika $
7
8  Copyright (C) 2004-2007 Koichi Sasada
9
10**********************************************************************/
11
12#include <math.h>
13
14#if VM_COLLECT_USAGE_DETAILS
15static void vm_analysis_insn(int insn);
16#endif
17
18#if VMDEBUG > 0
19#define DECL_SC_REG(type, r, reg) register type reg_##r
20
21#elif defined(__GNUC__) && defined(__x86_64__)
22#define DECL_SC_REG(type, r, reg) register type reg_##r __asm__("r" reg)
23
24#elif defined(__GNUC__) && defined(__i386__)
25#define DECL_SC_REG(type, r, reg) register type reg_##r __asm__("e" reg)
26
27#else
28#define DECL_SC_REG(type, r, reg) register type reg_##r
29#endif
30/* #define DECL_SC_REG(r, reg) VALUE reg_##r */
31
32#if !OPT_CALL_THREADED_CODE
33static VALUE
34vm_exec_core(rb_thread_t *th, VALUE initial)
35{
36
37#if OPT_STACK_CACHING
38#if 0
39#elif __GNUC__ && __x86_64__
40    DECL_SC_REG(VALUE, a, "12");
41    DECL_SC_REG(VALUE, b, "13");
42#else
43    register VALUE reg_a;
44    register VALUE reg_b;
45#endif
46#endif
47
48#if defined(__GNUC__) && defined(__i386__)
49    DECL_SC_REG(VALUE *, pc, "di");
50    DECL_SC_REG(rb_control_frame_t *, cfp, "si");
51#define USE_MACHINE_REGS 1
52
53#elif defined(__GNUC__) && defined(__x86_64__)
54    DECL_SC_REG(VALUE *, pc, "14");
55    DECL_SC_REG(rb_control_frame_t *, cfp, "15");
56#define USE_MACHINE_REGS 1
57
58#else
59    register rb_control_frame_t *reg_cfp;
60    VALUE *reg_pc;
61#endif
62
63#if USE_MACHINE_REGS
64
65#undef  RESTORE_REGS
66#define RESTORE_REGS() \
67{ \
68  REG_CFP = th->cfp; \
69  reg_pc  = reg_cfp->pc; \
70}
71
72#undef  REG_PC
73#define REG_PC reg_pc
74#undef  GET_PC
75#define GET_PC() (reg_pc)
76#undef  SET_PC
77#define SET_PC(x) (reg_cfp->pc = REG_PC = (x))
78#endif
79
80#if OPT_TOKEN_THREADED_CODE || OPT_DIRECT_THREADED_CODE
81#include "vmtc.inc"
82    if (UNLIKELY(th == 0)) {
83	return (VALUE)insns_address_table;
84    }
85#endif
86    reg_cfp = th->cfp;
87    reg_pc = reg_cfp->pc;
88
89#if OPT_STACK_CACHING
90    reg_a = initial;
91    reg_b = 0;
92#endif
93
94  first:
95    INSN_DISPATCH();
96/*****************/
97 #include "vm.inc"
98/*****************/
99    END_INSNS_DISPATCH();
100
101    /* unreachable */
102    rb_bug("vm_eval: unreachable");
103    goto first;
104}
105
106const void **
107rb_vm_get_insns_address_table(void)
108{
109    return (const void **)vm_exec_core(0, 0);
110}
111
112#else /* OPT_CALL_THREADED_CODE */
113
114#include "vm.inc"
115#include "vmtc.inc"
116
117const void **
118rb_vm_get_insns_address_table(void)
119{
120    return (const void **)insns_address_table;
121}
122
123static VALUE
124vm_exec_core(rb_thread_t *th, VALUE initial)
125{
126    register rb_control_frame_t *reg_cfp = th->cfp;
127
128    while (1) {
129	reg_cfp = ((rb_insn_func_t) (*GET_PC()))(th, reg_cfp);
130
131	if (UNLIKELY(reg_cfp == 0)) {
132	    break;
133	}
134    }
135
136    if (th->retval != Qundef) {
137	VALUE ret = th->retval;
138	th->retval = Qundef;
139	return ret;
140    }
141    else {
142	VALUE err = th->errinfo;
143	th->errinfo = Qnil;
144	return err;
145    }
146}
147#endif
148