Ruby 3.2.1p31 (2023-02-08 revision 31819e82c88c6f8ecfaeb162519bfa26a14b21fd)
vm_exec.c
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 VM_COLLECT_USAGE_DETAILS
15static void vm_analysis_insn(int insn);
16#endif
17
18MAYBE_UNUSED(static void vm_insns_counter_count_insn(int insn));
19#if USE_INSNS_COUNTER
20static size_t rb_insns_counter[VM_INSTRUCTION_SIZE];
21
22static void
23vm_insns_counter_count_insn(int insn)
24{
25 rb_insns_counter[insn]++;
26}
27
28__attribute__((destructor))
29static void
30vm_insns_counter_show_results_at_exit(void)
31{
32 int insn_end = (ruby_vm_event_enabled_global_flags & ISEQ_TRACE_EVENTS)
33 ? VM_INSTRUCTION_SIZE : VM_INSTRUCTION_SIZE / 2;
34
35 size_t total = 0;
36 for (int insn = 0; insn < insn_end; insn++)
37 total += rb_insns_counter[insn];
38
39 for (int insn = 0; insn < insn_end; insn++) {
40 fprintf(stderr, "[RUBY_INSNS_COUNTER]\t%-32s%'12"PRIuSIZE" (%4.1f%%)\n",
41 insn_name(insn), rb_insns_counter[insn],
42 100.0 * rb_insns_counter[insn] / total);
43 }
44}
45#else
46static void vm_insns_counter_count_insn(int insn) {}
47#endif
48
49#if VMDEBUG > 0
50#define DECL_SC_REG(type, r, reg) register type reg_##r
51
52#elif defined(__GNUC__) && defined(__x86_64__)
53#define DECL_SC_REG(type, r, reg) register type reg_##r __asm__("r" reg)
54
55#elif defined(__GNUC__) && defined(__i386__)
56#define DECL_SC_REG(type, r, reg) register type reg_##r __asm__("e" reg)
57
58#elif defined(__GNUC__) && (defined(__powerpc64__) || defined(__POWERPC__))
59#define DECL_SC_REG(type, r, reg) register type reg_##r __asm__("r" reg)
60
61#elif defined(__GNUC__) && defined(__aarch64__)
62#define DECL_SC_REG(type, r, reg) register type reg_##r __asm__("x" reg)
63
64#else
65#define DECL_SC_REG(type, r, reg) register type reg_##r
66#endif
67/* #define DECL_SC_REG(r, reg) VALUE reg_##r */
68
69#if !OPT_CALL_THREADED_CODE
70static VALUE
71vm_exec_core(rb_execution_context_t *ec, VALUE initial)
72{
73
74#if OPT_STACK_CACHING
75#if 0
76#elif __GNUC__ && __x86_64__
77 DECL_SC_REG(VALUE, a, "12");
78 DECL_SC_REG(VALUE, b, "13");
79#else
80 register VALUE reg_a;
81 register VALUE reg_b;
82#endif
83#endif
84
85#if defined(__GNUC__) && defined(__i386__)
86 DECL_SC_REG(const VALUE *, pc, "di");
87 DECL_SC_REG(rb_control_frame_t *, cfp, "si");
88#define USE_MACHINE_REGS 1
89
90#elif defined(__GNUC__) && defined(__x86_64__)
91 DECL_SC_REG(const VALUE *, pc, "14");
92 DECL_SC_REG(rb_control_frame_t *, cfp, "15");
93#define USE_MACHINE_REGS 1
94
95#elif defined(__GNUC__) && (defined(__powerpc64__) || defined(__POWERPC__))
96 DECL_SC_REG(const VALUE *, pc, "14");
97 DECL_SC_REG(rb_control_frame_t *, cfp, "15");
98#define USE_MACHINE_REGS 1
99
100#elif defined(__GNUC__) && defined(__aarch64__)
101 DECL_SC_REG(const VALUE *, pc, "19");
102 DECL_SC_REG(rb_control_frame_t *, cfp, "20");
103#define USE_MACHINE_REGS 1
104
105#else
106 register rb_control_frame_t *reg_cfp;
107 const VALUE *reg_pc;
108#define USE_MACHINE_REGS 0
109
110#endif
111
112#if USE_MACHINE_REGS
113
114#undef RESTORE_REGS
115#define RESTORE_REGS() \
116{ \
117 VM_REG_CFP = ec->cfp; \
118 reg_pc = reg_cfp->pc; \
119}
120
121#undef VM_REG_PC
122#define VM_REG_PC reg_pc
123#undef GET_PC
124#define GET_PC() (reg_pc)
125#undef SET_PC
126#define SET_PC(x) (reg_cfp->pc = VM_REG_PC = (x))
127#endif
128
129#if OPT_TOKEN_THREADED_CODE || OPT_DIRECT_THREADED_CODE
130#include "vmtc.inc"
131 if (UNLIKELY(ec == 0)) {
132 return (VALUE)insns_address_table;
133 }
134#endif
135 reg_cfp = ec->cfp;
136 reg_pc = reg_cfp->pc;
137
138#if OPT_STACK_CACHING
139 reg_a = initial;
140 reg_b = 0;
141#endif
142
143 first:
144 INSN_DISPATCH();
145/*****************/
146 #include "vm.inc"
147/*****************/
148 END_INSNS_DISPATCH();
149
150 /* unreachable */
151 rb_bug("vm_eval: unreachable");
152 goto first;
153}
154
155const void **
156rb_vm_get_insns_address_table(void)
157{
158 return (const void **)vm_exec_core(0, 0);
159}
160
161#else /* OPT_CALL_THREADED_CODE */
162
163#include "vm.inc"
164#include "vmtc.inc"
165
166const void **
167rb_vm_get_insns_address_table(void)
168{
169 return (const void **)insns_address_table;
170}
171
172static VALUE
173vm_exec_core(rb_execution_context_t *ec, VALUE initial)
174{
175 register rb_control_frame_t *reg_cfp = ec->cfp;
176 rb_thread_t *th;
177
178 while (1) {
179 reg_cfp = ((rb_insn_func_t) (*GET_PC()))(ec, reg_cfp);
180
181 if (UNLIKELY(reg_cfp == 0)) {
182 break;
183 }
184 }
185
186 if (!UNDEF_P((th = rb_ec_thread_ptr(ec))->retval)) {
187 VALUE ret = th->retval;
188 th->retval = Qundef;
189 return ret;
190 }
191 else {
192 VALUE err = ec->errinfo;
193 ec->errinfo = Qnil;
194 return err;
195 }
196}
197#endif
#define Qundef
Old name of RUBY_Qundef.
#define Qnil
Old name of RUBY_Qnil.
void rb_bug(const char *fmt,...)
Interpreter panic switch.
Definition: error.c:794
uintptr_t VALUE
Type that represents a Ruby object.
Definition: value.h:40