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