pline 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README +134 -0
- data/ext/pline/depend +55 -0
- data/ext/pline/extconf.rb +14 -0
- data/ext/pline/iseq.c +124 -0
- data/ext/pline/minfo.c +167 -0
- data/ext/pline/pline.c.rb +68 -0
- data/ext/pline/profiler.c +125 -0
- data/ext/pline/ruby_source/1.9.2/debug.h +36 -0
- data/ext/pline/ruby_source/1.9.2/eval_intern.h +232 -0
- data/ext/pline/ruby_source/1.9.2/gc.h +77 -0
- data/ext/pline/ruby_source/1.9.2/id.h +170 -0
- data/ext/pline/ruby_source/1.9.2/insns.inc +179 -0
- data/ext/pline/ruby_source/1.9.2/insns_info.inc +695 -0
- data/ext/pline/ruby_source/1.9.2/iseq.h +104 -0
- data/ext/pline/ruby_source/1.9.2/manual_update.h +19 -0
- data/ext/pline/ruby_source/1.9.2/method.h +103 -0
- data/ext/pline/ruby_source/1.9.2/node.h +483 -0
- data/ext/pline/ruby_source/1.9.2/thread_pthread.h +27 -0
- data/ext/pline/ruby_source/1.9.2/thread_win32.h +33 -0
- data/ext/pline/ruby_source/1.9.2/vm_core.h +706 -0
- data/ext/pline/ruby_source/1.9.2/vm_exec.h +184 -0
- data/ext/pline/ruby_source/1.9.2/vm_insnhelper.c +1734 -0
- data/ext/pline/ruby_source/1.9.2/vm_insnhelper.h +208 -0
- data/ext/pline/ruby_source/1.9.2/vm_opts.h +51 -0
- data/ext/pline/ruby_source/1.9.3/atomic.h +56 -0
- data/ext/pline/ruby_source/1.9.3/constant.h +34 -0
- data/ext/pline/ruby_source/1.9.3/debug.h +41 -0
- data/ext/pline/ruby_source/1.9.3/eval_intern.h +234 -0
- data/ext/pline/ruby_source/1.9.3/gc.h +98 -0
- data/ext/pline/ruby_source/1.9.3/id.h +175 -0
- data/ext/pline/ruby_source/1.9.3/insns.inc +179 -0
- data/ext/pline/ruby_source/1.9.3/insns_info.inc +695 -0
- data/ext/pline/ruby_source/1.9.3/internal.h +227 -0
- data/ext/pline/ruby_source/1.9.3/iseq.h +125 -0
- data/ext/pline/ruby_source/1.9.3/manual_update.h +19 -0
- data/ext/pline/ruby_source/1.9.3/method.h +105 -0
- data/ext/pline/ruby_source/1.9.3/node.h +503 -0
- data/ext/pline/ruby_source/1.9.3/thread_pthread.h +51 -0
- data/ext/pline/ruby_source/1.9.3/thread_win32.h +40 -0
- data/ext/pline/ruby_source/1.9.3/vm_core.h +756 -0
- data/ext/pline/ruby_source/1.9.3/vm_exec.h +184 -0
- data/ext/pline/ruby_source/1.9.3/vm_insnhelper.c +1749 -0
- data/ext/pline/ruby_source/1.9.3/vm_insnhelper.h +220 -0
- data/ext/pline/ruby_source/1.9.3/vm_opts.h +51 -0
- data/ext/pline/sinfo.c +311 -0
- data/lib/pline.rb +11 -0
- data/lib/pline/minfo.rb +22 -0
- data/lib/pline/summarize.rb +127 -0
- data/lib/pline/util.rb +54 -0
- data/pline.gemspec +28 -0
- metadata +102 -0
@@ -0,0 +1,184 @@
|
|
1
|
+
/**********************************************************************
|
2
|
+
|
3
|
+
vm.h -
|
4
|
+
|
5
|
+
$Author: yugui $
|
6
|
+
created at: 04/01/01 16:56:59 JST
|
7
|
+
|
8
|
+
Copyright (C) 2004-2007 Koichi Sasada
|
9
|
+
|
10
|
+
**********************************************************************/
|
11
|
+
|
12
|
+
#ifndef RUBY_VM_EXEC_H
|
13
|
+
#define RUBY_VM_EXEC_H
|
14
|
+
|
15
|
+
typedef long OFFSET;
|
16
|
+
typedef unsigned long lindex_t;
|
17
|
+
typedef unsigned long dindex_t;
|
18
|
+
typedef rb_num_t GENTRY;
|
19
|
+
typedef rb_iseq_t *ISEQ;
|
20
|
+
|
21
|
+
#ifdef COLLECT_USAGE_ANALYSIS
|
22
|
+
#define USAGE_ANALYSIS_INSN(insn) vm_analysis_insn(insn)
|
23
|
+
#define USAGE_ANALYSIS_OPERAND(insn, n, op) vm_analysis_operand(insn, n, (VALUE)op)
|
24
|
+
#define USAGE_ANALYSIS_REGISTER(reg, s) vm_analysis_register(reg, s)
|
25
|
+
#else
|
26
|
+
#define USAGE_ANALYSIS_INSN(insn) /* none */
|
27
|
+
#define USAGE_ANALYSIS_OPERAND(insn, n, op) /* none */
|
28
|
+
#define USAGE_ANALYSIS_REGISTER(reg, s) /* none */
|
29
|
+
#endif
|
30
|
+
|
31
|
+
#ifdef __GCC__
|
32
|
+
/* TODO: machine dependent prefetch instruction */
|
33
|
+
#define PREFETCH(pc)
|
34
|
+
#else
|
35
|
+
#define PREFETCH(pc)
|
36
|
+
#endif
|
37
|
+
|
38
|
+
#if VMDEBUG > 0
|
39
|
+
#define debugs printf
|
40
|
+
#define DEBUG_ENTER_INSN(insn) \
|
41
|
+
debug_print_pre(th, GET_CFP());
|
42
|
+
|
43
|
+
#if OPT_STACK_CACHING
|
44
|
+
#define SC_REGS() , reg_a, reg_b
|
45
|
+
#else
|
46
|
+
#define SC_REGS()
|
47
|
+
#endif
|
48
|
+
|
49
|
+
#define DEBUG_END_INSN() \
|
50
|
+
debug_print_post(th, GET_CFP() SC_REGS());
|
51
|
+
|
52
|
+
#else
|
53
|
+
|
54
|
+
#define debugs
|
55
|
+
#define DEBUG_ENTER_INSN(insn)
|
56
|
+
#define DEBUG_END_INSN()
|
57
|
+
#endif
|
58
|
+
|
59
|
+
#define throwdebug if(0)printf
|
60
|
+
/* #define throwdebug printf */
|
61
|
+
|
62
|
+
/************************************************/
|
63
|
+
#if DISPATCH_XXX
|
64
|
+
error !
|
65
|
+
/************************************************/
|
66
|
+
#elif OPT_CALL_THREADED_CODE
|
67
|
+
|
68
|
+
#define LABEL(x) insn_func_##x
|
69
|
+
#define ELABEL(x)
|
70
|
+
#define LABEL_PTR(x) &LABEL(x)
|
71
|
+
|
72
|
+
#define INSN_ENTRY(insn) \
|
73
|
+
static rb_control_frame_t * \
|
74
|
+
FUNC_FASTCALL(LABEL(insn))(rb_thread_t *th, rb_control_frame_t *reg_cfp) {
|
75
|
+
|
76
|
+
#define END_INSN(insn) return reg_cfp;}
|
77
|
+
|
78
|
+
#define NEXT_INSN() return reg_cfp;
|
79
|
+
|
80
|
+
/************************************************/
|
81
|
+
#elif OPT_TOKEN_THREADED_CODE || OPT_DIRECT_THREADED_CODE
|
82
|
+
/* threaded code with gcc */
|
83
|
+
|
84
|
+
#define LABEL(x) INSN_LABEL_##x
|
85
|
+
#define ELABEL(x) INSN_ELABEL_##x
|
86
|
+
#define LABEL_PTR(x) &&LABEL(x)
|
87
|
+
|
88
|
+
#define INSN_ENTRY_SIG(insn)
|
89
|
+
|
90
|
+
|
91
|
+
#define INSN_DISPATCH_SIG(insn)
|
92
|
+
|
93
|
+
#define INSN_ENTRY(insn) \
|
94
|
+
LABEL(insn): \
|
95
|
+
INSN_ENTRY_SIG(insn); \
|
96
|
+
|
97
|
+
/* dispather */
|
98
|
+
#if __GNUC__ && (__i386__ || __x86_64__) && __GNUC__ == 3
|
99
|
+
#define DISPATCH_ARCH_DEPEND_WAY(addr) \
|
100
|
+
asm volatile("jmp *%0;\t# -- inseted by vm.h\t[length = 2]" : : "r" (addr))
|
101
|
+
|
102
|
+
#else
|
103
|
+
#define DISPATCH_ARCH_DEPEND_WAY(addr) \
|
104
|
+
/* do nothing */
|
105
|
+
|
106
|
+
#endif
|
107
|
+
|
108
|
+
|
109
|
+
/**********************************/
|
110
|
+
#if OPT_DIRECT_THREADED_CODE
|
111
|
+
|
112
|
+
/* for GCC 3.4.x */
|
113
|
+
#define TC_DISPATCH(insn) \
|
114
|
+
INSN_DISPATCH_SIG(insn); \
|
115
|
+
goto *GET_CURRENT_INSN(); \
|
116
|
+
;
|
117
|
+
|
118
|
+
#else
|
119
|
+
/* token threade code */
|
120
|
+
|
121
|
+
#define TC_DISPATCH(insn) \
|
122
|
+
DISPATCH_ARCH_DEPEND_WAY(insns_address_table[GET_CURRENT_INSN()]); \
|
123
|
+
INSN_DISPATCH_SIG(insn); \
|
124
|
+
goto *insns_address_table[GET_CURRENT_INSN()]; \
|
125
|
+
rb_bug("tc error");
|
126
|
+
|
127
|
+
|
128
|
+
#endif /* DISPATCH_DIRECT_THREADED_CODE */
|
129
|
+
|
130
|
+
#define END_INSN(insn) \
|
131
|
+
DEBUG_END_INSN(); \
|
132
|
+
TC_DISPATCH(insn); \
|
133
|
+
|
134
|
+
#define INSN_DISPATCH() \
|
135
|
+
TC_DISPATCH(__START__) \
|
136
|
+
{
|
137
|
+
|
138
|
+
#define END_INSNS_DISPATCH() \
|
139
|
+
rb_bug("unknown insn: %ld", GET_CURRENT_INSN()); \
|
140
|
+
} /* end of while loop */ \
|
141
|
+
|
142
|
+
#define NEXT_INSN() TC_DISPATCH(__NEXT_INSN__)
|
143
|
+
|
144
|
+
/************************************************/
|
145
|
+
#else /* no threaded code */
|
146
|
+
/* most common method */
|
147
|
+
|
148
|
+
#define INSN_ENTRY(insn) \
|
149
|
+
case BIN(insn):
|
150
|
+
|
151
|
+
#define END_INSN(insn) \
|
152
|
+
DEBUG_END_INSN(); \
|
153
|
+
break;
|
154
|
+
|
155
|
+
|
156
|
+
#define INSN_DISPATCH() \
|
157
|
+
while(1){ \
|
158
|
+
switch(GET_CURRENT_INSN()){
|
159
|
+
|
160
|
+
#define END_INSNS_DISPATCH() \
|
161
|
+
default: \
|
162
|
+
SDR(); \
|
163
|
+
rb_bug("unknown insn: %ld", GET_CURRENT_INSN()); \
|
164
|
+
} /* end of switch */ \
|
165
|
+
} /* end of while loop */ \
|
166
|
+
|
167
|
+
#define NEXT_INSN() goto first
|
168
|
+
|
169
|
+
#endif
|
170
|
+
|
171
|
+
#define VM_SP_CNT(th, sp) ((sp) - (th)->stack)
|
172
|
+
|
173
|
+
#if OPT_CALL_THREADED_CODE
|
174
|
+
#define THROW_EXCEPTION(exc) do { \
|
175
|
+
th->errinfo = (VALUE)(exc); \
|
176
|
+
return 0; \
|
177
|
+
} while (0)
|
178
|
+
#else
|
179
|
+
#define THROW_EXCEPTION(exc) return (VALUE)(exc)
|
180
|
+
#endif
|
181
|
+
|
182
|
+
#define SCREG(r) (reg_##r)
|
183
|
+
|
184
|
+
#endif /* RUBY_VM_EXEC_H */
|
@@ -0,0 +1,1734 @@
|
|
1
|
+
/**********************************************************************
|
2
|
+
|
3
|
+
vm_insnhelper.c - instruction helper functions.
|
4
|
+
|
5
|
+
$Author: yugui $
|
6
|
+
|
7
|
+
Copyright (C) 2007 Koichi Sasada
|
8
|
+
|
9
|
+
**********************************************************************/
|
10
|
+
|
11
|
+
/* finish iseq array */
|
12
|
+
#include "insns.inc"
|
13
|
+
#include <math.h>
|
14
|
+
|
15
|
+
/* control stack frame */
|
16
|
+
|
17
|
+
#ifndef INLINE
|
18
|
+
#define INLINE inline
|
19
|
+
#endif
|
20
|
+
|
21
|
+
static rb_control_frame_t *vm_get_ruby_level_caller_cfp(rb_thread_t *th, rb_control_frame_t *cfp);
|
22
|
+
|
23
|
+
static inline rb_control_frame_t *
|
24
|
+
vm_push_frame(rb_thread_t * th, const rb_iseq_t * iseq,
|
25
|
+
VALUE type, VALUE self, VALUE specval,
|
26
|
+
const VALUE *pc, VALUE *sp, VALUE *lfp,
|
27
|
+
int local_size)
|
28
|
+
{
|
29
|
+
rb_control_frame_t * const cfp = th->cfp - 1;
|
30
|
+
int i;
|
31
|
+
|
32
|
+
if ((void *)(sp + local_size) >= (void *)cfp) {
|
33
|
+
rb_exc_raise(sysstack_error);
|
34
|
+
}
|
35
|
+
th->cfp = cfp;
|
36
|
+
/* setup vm value stack */
|
37
|
+
|
38
|
+
/* nil initialize */
|
39
|
+
for (i=0; i < local_size; i++) {
|
40
|
+
*sp = Qnil;
|
41
|
+
sp++;
|
42
|
+
}
|
43
|
+
|
44
|
+
/* set special val */
|
45
|
+
*sp = GC_GUARDED_PTR(specval);
|
46
|
+
|
47
|
+
if (lfp == 0) {
|
48
|
+
lfp = sp;
|
49
|
+
}
|
50
|
+
|
51
|
+
/* setup vm control frame stack */
|
52
|
+
|
53
|
+
cfp->pc = (VALUE *)pc;
|
54
|
+
cfp->sp = sp + 1;
|
55
|
+
cfp->bp = sp + 1;
|
56
|
+
cfp->iseq = (rb_iseq_t *) iseq;
|
57
|
+
cfp->flag = type;
|
58
|
+
cfp->self = self;
|
59
|
+
cfp->lfp = lfp;
|
60
|
+
cfp->dfp = sp;
|
61
|
+
cfp->block_iseq = 0;
|
62
|
+
cfp->proc = 0;
|
63
|
+
cfp->me = 0;
|
64
|
+
|
65
|
+
#define COLLECT_PROFILE 0
|
66
|
+
#if COLLECT_PROFILE
|
67
|
+
cfp->prof_time_self = clock();
|
68
|
+
cfp->prof_time_chld = 0;
|
69
|
+
#endif
|
70
|
+
|
71
|
+
if (VMDEBUG == 2) {
|
72
|
+
SDR();
|
73
|
+
}
|
74
|
+
|
75
|
+
return cfp;
|
76
|
+
}
|
77
|
+
|
78
|
+
static inline void
|
79
|
+
vm_pop_frame(rb_thread_t *th)
|
80
|
+
{
|
81
|
+
#if COLLECT_PROFILE
|
82
|
+
rb_control_frame_t *cfp = th->cfp;
|
83
|
+
|
84
|
+
if (RUBY_VM_NORMAL_ISEQ_P(cfp->iseq)) {
|
85
|
+
VALUE current_time = clock();
|
86
|
+
rb_control_frame_t *cfp = th->cfp;
|
87
|
+
cfp->prof_time_self = current_time - cfp->prof_time_self;
|
88
|
+
(cfp+1)->prof_time_chld += cfp->prof_time_self;
|
89
|
+
|
90
|
+
cfp->iseq->profile.count++;
|
91
|
+
cfp->iseq->profile.time_cumu = cfp->prof_time_self;
|
92
|
+
cfp->iseq->profile.time_self = cfp->prof_time_self - cfp->prof_time_chld;
|
93
|
+
}
|
94
|
+
else if (0 /* c method? */) {
|
95
|
+
|
96
|
+
}
|
97
|
+
#endif
|
98
|
+
th->cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(th->cfp);
|
99
|
+
|
100
|
+
if (VMDEBUG == 2) {
|
101
|
+
SDR();
|
102
|
+
}
|
103
|
+
}
|
104
|
+
|
105
|
+
/* method dispatch */
|
106
|
+
|
107
|
+
NORETURN(static void argument_error(const rb_iseq_t *iseq, int miss_argc, int correct_argc));
|
108
|
+
static void
|
109
|
+
argument_error(const rb_iseq_t *iseq, int miss_argc, int correct_argc)
|
110
|
+
{
|
111
|
+
VALUE mesg = rb_sprintf("wrong number of arguments (%d for %d)", miss_argc, correct_argc);
|
112
|
+
VALUE exc = rb_exc_new3(rb_eArgError, mesg);
|
113
|
+
VALUE bt = rb_make_backtrace();
|
114
|
+
VALUE err_line = 0;
|
115
|
+
|
116
|
+
if (iseq) {
|
117
|
+
int line_no = 1;
|
118
|
+
|
119
|
+
if (iseq->insn_info_size) {
|
120
|
+
line_no = iseq->insn_info_table[0].line_no;
|
121
|
+
}
|
122
|
+
|
123
|
+
err_line = rb_sprintf("%s:%d:in `%s'",
|
124
|
+
RSTRING_PTR(iseq->filename),
|
125
|
+
line_no, RSTRING_PTR(iseq->name));
|
126
|
+
rb_funcall(bt, rb_intern("unshift"), 1, err_line);
|
127
|
+
}
|
128
|
+
|
129
|
+
rb_funcall(exc, rb_intern("set_backtrace"), 1, bt);
|
130
|
+
rb_exc_raise(exc);
|
131
|
+
}
|
132
|
+
|
133
|
+
#define VM_CALLEE_SETUP_ARG(ret, th, iseq, orig_argc, orig_argv, block) \
|
134
|
+
if (LIKELY(iseq->arg_simple & 0x01)) { \
|
135
|
+
/* simple check */ \
|
136
|
+
if (orig_argc != iseq->argc) { \
|
137
|
+
argument_error(iseq, orig_argc, iseq->argc); \
|
138
|
+
} \
|
139
|
+
ret = 0; \
|
140
|
+
} \
|
141
|
+
else { \
|
142
|
+
ret = vm_callee_setup_arg_complex(th, iseq, orig_argc, orig_argv, block); \
|
143
|
+
}
|
144
|
+
|
145
|
+
static inline int
|
146
|
+
vm_callee_setup_arg_complex(rb_thread_t *th, const rb_iseq_t * iseq,
|
147
|
+
int orig_argc, VALUE * orig_argv,
|
148
|
+
const rb_block_t **block)
|
149
|
+
{
|
150
|
+
const int m = iseq->argc;
|
151
|
+
int argc = orig_argc;
|
152
|
+
VALUE *argv = orig_argv;
|
153
|
+
rb_num_t opt_pc = 0;
|
154
|
+
|
155
|
+
th->mark_stack_len = argc + iseq->arg_size;
|
156
|
+
|
157
|
+
/* mandatory */
|
158
|
+
if (argc < (m + iseq->arg_post_len)) { /* check with post arg */
|
159
|
+
argument_error(iseq, argc, m + iseq->arg_post_len);
|
160
|
+
}
|
161
|
+
|
162
|
+
argv += m;
|
163
|
+
argc -= m;
|
164
|
+
|
165
|
+
/* post arguments */
|
166
|
+
if (iseq->arg_post_len) {
|
167
|
+
if (!(orig_argc < iseq->arg_post_start)) {
|
168
|
+
VALUE *new_argv = ALLOCA_N(VALUE, argc);
|
169
|
+
MEMCPY(new_argv, argv, VALUE, argc);
|
170
|
+
argv = new_argv;
|
171
|
+
}
|
172
|
+
|
173
|
+
MEMCPY(&orig_argv[iseq->arg_post_start], &argv[argc -= iseq->arg_post_len],
|
174
|
+
VALUE, iseq->arg_post_len);
|
175
|
+
}
|
176
|
+
|
177
|
+
/* opt arguments */
|
178
|
+
if (iseq->arg_opts) {
|
179
|
+
const int opts = iseq->arg_opts - 1 /* no opt */;
|
180
|
+
|
181
|
+
if (iseq->arg_rest == -1 && argc > opts) {
|
182
|
+
argument_error(iseq, orig_argc, m + opts + iseq->arg_post_len);
|
183
|
+
}
|
184
|
+
|
185
|
+
if (argc > opts) {
|
186
|
+
argc -= opts;
|
187
|
+
argv += opts;
|
188
|
+
opt_pc = iseq->arg_opt_table[opts]; /* no opt */
|
189
|
+
}
|
190
|
+
else {
|
191
|
+
int i;
|
192
|
+
for (i = argc; i<opts; i++) {
|
193
|
+
orig_argv[i + m] = Qnil;
|
194
|
+
}
|
195
|
+
opt_pc = iseq->arg_opt_table[argc];
|
196
|
+
argc = 0;
|
197
|
+
}
|
198
|
+
}
|
199
|
+
|
200
|
+
/* rest arguments */
|
201
|
+
if (iseq->arg_rest != -1) {
|
202
|
+
orig_argv[iseq->arg_rest] = rb_ary_new4(argc, argv);
|
203
|
+
argc = 0;
|
204
|
+
}
|
205
|
+
|
206
|
+
/* block arguments */
|
207
|
+
if (block && iseq->arg_block != -1) {
|
208
|
+
VALUE blockval = Qnil;
|
209
|
+
const rb_block_t *blockptr = *block;
|
210
|
+
|
211
|
+
if (argc != 0) {
|
212
|
+
argument_error(iseq, orig_argc, m + iseq->arg_post_len);
|
213
|
+
}
|
214
|
+
|
215
|
+
if (blockptr) {
|
216
|
+
/* make Proc object */
|
217
|
+
if (blockptr->proc == 0) {
|
218
|
+
rb_proc_t *proc;
|
219
|
+
blockval = rb_vm_make_proc(th, blockptr, rb_cProc);
|
220
|
+
GetProcPtr(blockval, proc);
|
221
|
+
*block = &proc->block;
|
222
|
+
}
|
223
|
+
else {
|
224
|
+
blockval = blockptr->proc;
|
225
|
+
}
|
226
|
+
}
|
227
|
+
|
228
|
+
orig_argv[iseq->arg_block] = blockval; /* Proc or nil */
|
229
|
+
}
|
230
|
+
|
231
|
+
th->mark_stack_len = 0;
|
232
|
+
return (int)opt_pc;
|
233
|
+
}
|
234
|
+
|
235
|
+
static inline int
|
236
|
+
caller_setup_args(const rb_thread_t *th, rb_control_frame_t *cfp, VALUE flag,
|
237
|
+
int argc, rb_iseq_t *blockiseq, rb_block_t **block)
|
238
|
+
{
|
239
|
+
rb_block_t *blockptr = 0;
|
240
|
+
|
241
|
+
if (block) {
|
242
|
+
if (flag & VM_CALL_ARGS_BLOCKARG_BIT) {
|
243
|
+
rb_proc_t *po;
|
244
|
+
VALUE proc;
|
245
|
+
|
246
|
+
proc = *(--cfp->sp);
|
247
|
+
|
248
|
+
if (proc != Qnil) {
|
249
|
+
if (!rb_obj_is_proc(proc)) {
|
250
|
+
VALUE b = rb_check_convert_type(proc, T_DATA, "Proc", "to_proc");
|
251
|
+
if (NIL_P(b) || !rb_obj_is_proc(b)) {
|
252
|
+
rb_raise(rb_eTypeError,
|
253
|
+
"wrong argument type %s (expected Proc)",
|
254
|
+
rb_obj_classname(proc));
|
255
|
+
}
|
256
|
+
proc = b;
|
257
|
+
}
|
258
|
+
GetProcPtr(proc, po);
|
259
|
+
blockptr = &po->block;
|
260
|
+
RUBY_VM_GET_BLOCK_PTR_IN_CFP(cfp)->proc = proc;
|
261
|
+
*block = blockptr;
|
262
|
+
}
|
263
|
+
}
|
264
|
+
else if (blockiseq) {
|
265
|
+
blockptr = RUBY_VM_GET_BLOCK_PTR_IN_CFP(cfp);
|
266
|
+
blockptr->iseq = blockiseq;
|
267
|
+
blockptr->proc = 0;
|
268
|
+
*block = blockptr;
|
269
|
+
}
|
270
|
+
}
|
271
|
+
|
272
|
+
/* expand top of stack? */
|
273
|
+
if (flag & VM_CALL_ARGS_SPLAT_BIT) {
|
274
|
+
VALUE ary = *(cfp->sp - 1);
|
275
|
+
VALUE *ptr;
|
276
|
+
int i;
|
277
|
+
VALUE tmp = rb_check_convert_type(ary, T_ARRAY, "Array", "to_a");
|
278
|
+
|
279
|
+
if (NIL_P(tmp)) {
|
280
|
+
/* do nothing */
|
281
|
+
}
|
282
|
+
else {
|
283
|
+
long len = RARRAY_LEN(tmp);
|
284
|
+
ptr = RARRAY_PTR(tmp);
|
285
|
+
cfp->sp -= 1;
|
286
|
+
|
287
|
+
CHECK_STACK_OVERFLOW(cfp, len);
|
288
|
+
|
289
|
+
for (i = 0; i < len; i++) {
|
290
|
+
*cfp->sp++ = ptr[i];
|
291
|
+
}
|
292
|
+
argc += i-1;
|
293
|
+
}
|
294
|
+
}
|
295
|
+
|
296
|
+
return argc;
|
297
|
+
}
|
298
|
+
|
299
|
+
static inline VALUE
|
300
|
+
call_cfunc(VALUE (*func)(), VALUE recv,
|
301
|
+
int len, int argc, const VALUE *argv)
|
302
|
+
{
|
303
|
+
/* printf("len: %d, argc: %d\n", len, argc); */
|
304
|
+
|
305
|
+
if (len >= 0 && argc != len) {
|
306
|
+
rb_raise(rb_eArgError, "wrong number of arguments(%d for %d)",
|
307
|
+
argc, len);
|
308
|
+
}
|
309
|
+
|
310
|
+
switch (len) {
|
311
|
+
case -2:
|
312
|
+
return (*func) (recv, rb_ary_new4(argc, argv));
|
313
|
+
break;
|
314
|
+
case -1:
|
315
|
+
return (*func) (argc, argv, recv);
|
316
|
+
break;
|
317
|
+
case 0:
|
318
|
+
return (*func) (recv);
|
319
|
+
break;
|
320
|
+
case 1:
|
321
|
+
return (*func) (recv, argv[0]);
|
322
|
+
break;
|
323
|
+
case 2:
|
324
|
+
return (*func) (recv, argv[0], argv[1]);
|
325
|
+
break;
|
326
|
+
case 3:
|
327
|
+
return (*func) (recv, argv[0], argv[1], argv[2]);
|
328
|
+
break;
|
329
|
+
case 4:
|
330
|
+
return (*func) (recv, argv[0], argv[1], argv[2], argv[3]);
|
331
|
+
break;
|
332
|
+
case 5:
|
333
|
+
return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4]);
|
334
|
+
break;
|
335
|
+
case 6:
|
336
|
+
return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4],
|
337
|
+
argv[5]);
|
338
|
+
break;
|
339
|
+
case 7:
|
340
|
+
return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4],
|
341
|
+
argv[5], argv[6]);
|
342
|
+
break;
|
343
|
+
case 8:
|
344
|
+
return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4],
|
345
|
+
argv[5], argv[6], argv[7]);
|
346
|
+
break;
|
347
|
+
case 9:
|
348
|
+
return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4],
|
349
|
+
argv[5], argv[6], argv[7], argv[8]);
|
350
|
+
break;
|
351
|
+
case 10:
|
352
|
+
return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4],
|
353
|
+
argv[5], argv[6], argv[7], argv[8], argv[9]);
|
354
|
+
break;
|
355
|
+
case 11:
|
356
|
+
return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4],
|
357
|
+
argv[5], argv[6], argv[7], argv[8], argv[9],
|
358
|
+
argv[10]);
|
359
|
+
break;
|
360
|
+
case 12:
|
361
|
+
return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4],
|
362
|
+
argv[5], argv[6], argv[7], argv[8], argv[9],
|
363
|
+
argv[10], argv[11]);
|
364
|
+
break;
|
365
|
+
case 13:
|
366
|
+
return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4],
|
367
|
+
argv[5], argv[6], argv[7], argv[8], argv[9], argv[10],
|
368
|
+
argv[11], argv[12]);
|
369
|
+
break;
|
370
|
+
case 14:
|
371
|
+
return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4],
|
372
|
+
argv[5], argv[6], argv[7], argv[8], argv[9], argv[10],
|
373
|
+
argv[11], argv[12], argv[13]);
|
374
|
+
break;
|
375
|
+
case 15:
|
376
|
+
return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4],
|
377
|
+
argv[5], argv[6], argv[7], argv[8], argv[9], argv[10],
|
378
|
+
argv[11], argv[12], argv[13], argv[14]);
|
379
|
+
break;
|
380
|
+
default:
|
381
|
+
rb_raise(rb_eArgError, "too many arguments(%d)", len);
|
382
|
+
return Qundef; /* not reached */
|
383
|
+
}
|
384
|
+
}
|
385
|
+
|
386
|
+
static inline VALUE
|
387
|
+
vm_call_cfunc(rb_thread_t *th, rb_control_frame_t *reg_cfp,
|
388
|
+
int num, VALUE recv, const rb_block_t *blockptr,
|
389
|
+
const rb_method_entry_t *me)
|
390
|
+
{
|
391
|
+
VALUE val = 0;
|
392
|
+
const rb_method_definition_t *def = me->def;
|
393
|
+
rb_control_frame_t *cfp;
|
394
|
+
|
395
|
+
EXEC_EVENT_HOOK(th, RUBY_EVENT_C_CALL, recv, me->called_id, me->klass);
|
396
|
+
|
397
|
+
cfp = vm_push_frame(th, 0, VM_FRAME_MAGIC_CFUNC,
|
398
|
+
recv, (VALUE) blockptr, 0, reg_cfp->sp, 0, 1);
|
399
|
+
cfp->me = me;
|
400
|
+
reg_cfp->sp -= num + 1;
|
401
|
+
|
402
|
+
val = call_cfunc(def->body.cfunc.func, recv, (int)def->body.cfunc.argc, num, reg_cfp->sp + 1);
|
403
|
+
|
404
|
+
if (reg_cfp != th->cfp + 1) {
|
405
|
+
rb_bug("cfp consistency error - send");
|
406
|
+
}
|
407
|
+
|
408
|
+
vm_pop_frame(th);
|
409
|
+
|
410
|
+
EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, recv, me->called_id, me->klass);
|
411
|
+
|
412
|
+
return val;
|
413
|
+
}
|
414
|
+
|
415
|
+
static inline VALUE
|
416
|
+
vm_call_bmethod(rb_thread_t *th, VALUE recv, int argc, const VALUE *argv,
|
417
|
+
const rb_block_t *blockptr, const rb_method_entry_t *me)
|
418
|
+
{
|
419
|
+
rb_proc_t *proc;
|
420
|
+
VALUE val;
|
421
|
+
|
422
|
+
EXEC_EVENT_HOOK(th, RUBY_EVENT_CALL, recv, me->called_id, me->klass);
|
423
|
+
|
424
|
+
/* control block frame */
|
425
|
+
th->passed_me = me;
|
426
|
+
GetProcPtr(me->def->body.proc, proc);
|
427
|
+
val = rb_vm_invoke_proc(th, proc, recv, argc, argv, blockptr);
|
428
|
+
|
429
|
+
EXEC_EVENT_HOOK(th, RUBY_EVENT_RETURN, recv, me->called_id, me->klass);
|
430
|
+
|
431
|
+
return val;
|
432
|
+
}
|
433
|
+
|
434
|
+
static inline void
|
435
|
+
vm_method_missing_args(rb_thread_t *th, VALUE *argv,
|
436
|
+
int num, const rb_block_t *blockptr, int opt)
|
437
|
+
{
|
438
|
+
rb_control_frame_t * const reg_cfp = th->cfp;
|
439
|
+
MEMCPY(argv, STACK_ADDR_FROM_TOP(num + 1), VALUE, num + 1);
|
440
|
+
th->method_missing_reason = opt;
|
441
|
+
th->passed_block = blockptr;
|
442
|
+
POPN(num + 1);
|
443
|
+
}
|
444
|
+
|
445
|
+
static inline VALUE
|
446
|
+
vm_method_missing(rb_thread_t *th, ID id, VALUE recv,
|
447
|
+
int num, const rb_block_t *blockptr, int opt)
|
448
|
+
{
|
449
|
+
VALUE *argv = ALLOCA_N(VALUE, num + 1);
|
450
|
+
vm_method_missing_args(th, argv, num, blockptr, opt);
|
451
|
+
argv[0] = ID2SYM(id);
|
452
|
+
return rb_funcall2(recv, idMethodMissing, num + 1, argv);
|
453
|
+
}
|
454
|
+
|
455
|
+
static inline void
|
456
|
+
vm_setup_method(rb_thread_t *th, rb_control_frame_t *cfp,
|
457
|
+
VALUE recv, int argc, const rb_block_t *blockptr, VALUE flag,
|
458
|
+
const rb_method_entry_t *me)
|
459
|
+
{
|
460
|
+
int opt_pc, i;
|
461
|
+
VALUE *sp, *rsp = cfp->sp - argc;
|
462
|
+
rb_iseq_t *iseq = me->def->body.iseq;
|
463
|
+
|
464
|
+
VM_CALLEE_SETUP_ARG(opt_pc, th, iseq, argc, rsp, &blockptr);
|
465
|
+
|
466
|
+
/* stack overflow check */
|
467
|
+
CHECK_STACK_OVERFLOW(cfp, iseq->stack_max);
|
468
|
+
|
469
|
+
sp = rsp + iseq->arg_size;
|
470
|
+
|
471
|
+
if (LIKELY(!(flag & VM_CALL_TAILCALL_BIT))) {
|
472
|
+
if (0) printf("local_size: %d, arg_size: %d\n",
|
473
|
+
iseq->local_size, iseq->arg_size);
|
474
|
+
|
475
|
+
/* clear local variables */
|
476
|
+
for (i = 0; i < iseq->local_size - iseq->arg_size; i++) {
|
477
|
+
*sp++ = Qnil;
|
478
|
+
}
|
479
|
+
|
480
|
+
vm_push_frame(th, iseq,
|
481
|
+
VM_FRAME_MAGIC_METHOD, recv, (VALUE) blockptr,
|
482
|
+
iseq->iseq_encoded + opt_pc, sp, 0, 0);
|
483
|
+
|
484
|
+
cfp->sp = rsp - 1 /* recv */;
|
485
|
+
}
|
486
|
+
else {
|
487
|
+
VALUE *p_rsp;
|
488
|
+
th->cfp++; /* pop cf */
|
489
|
+
p_rsp = th->cfp->sp;
|
490
|
+
|
491
|
+
/* copy arguments */
|
492
|
+
for (i=0; i < (sp - rsp); i++) {
|
493
|
+
p_rsp[i] = rsp[i];
|
494
|
+
}
|
495
|
+
|
496
|
+
sp -= rsp - p_rsp;
|
497
|
+
|
498
|
+
/* clear local variables */
|
499
|
+
for (i = 0; i < iseq->local_size - iseq->arg_size; i++) {
|
500
|
+
*sp++ = Qnil;
|
501
|
+
}
|
502
|
+
|
503
|
+
vm_push_frame(th, iseq,
|
504
|
+
VM_FRAME_MAGIC_METHOD, recv, (VALUE) blockptr,
|
505
|
+
iseq->iseq_encoded + opt_pc, sp, 0, 0);
|
506
|
+
}
|
507
|
+
}
|
508
|
+
|
509
|
+
static inline VALUE
|
510
|
+
vm_call_method(rb_thread_t *th, rb_control_frame_t *cfp,
|
511
|
+
int num, const rb_block_t *blockptr, VALUE flag,
|
512
|
+
ID id, const rb_method_entry_t *me, VALUE recv)
|
513
|
+
{
|
514
|
+
VALUE val;
|
515
|
+
|
516
|
+
start_method_dispatch:
|
517
|
+
|
518
|
+
if (me != 0) {
|
519
|
+
if ((me->flag == 0)) {
|
520
|
+
normal_method_dispatch:
|
521
|
+
switch (me->def->type) {
|
522
|
+
case VM_METHOD_TYPE_ISEQ:{
|
523
|
+
vm_setup_method(th, cfp, recv, num, blockptr, flag, me);
|
524
|
+
return Qundef;
|
525
|
+
}
|
526
|
+
case VM_METHOD_TYPE_NOTIMPLEMENTED:
|
527
|
+
case VM_METHOD_TYPE_CFUNC:{
|
528
|
+
val = vm_call_cfunc(th, cfp, num, recv, blockptr, me);
|
529
|
+
break;
|
530
|
+
}
|
531
|
+
case VM_METHOD_TYPE_ATTRSET:{
|
532
|
+
if (num != 1) {
|
533
|
+
rb_raise(rb_eArgError, "wrong number of arguments (%d for 1)", num);
|
534
|
+
}
|
535
|
+
val = rb_ivar_set(recv, me->def->body.attr.id, *(cfp->sp - 1));
|
536
|
+
cfp->sp -= 2;
|
537
|
+
break;
|
538
|
+
}
|
539
|
+
case VM_METHOD_TYPE_IVAR:{
|
540
|
+
if (num != 0) {
|
541
|
+
rb_raise(rb_eArgError, "wrong number of arguments (%d for 0)", num);
|
542
|
+
}
|
543
|
+
val = rb_attr_get(recv, me->def->body.attr.id);
|
544
|
+
cfp->sp -= 1;
|
545
|
+
break;
|
546
|
+
}
|
547
|
+
case VM_METHOD_TYPE_MISSING:{
|
548
|
+
VALUE *argv = ALLOCA_N(VALUE, num+1);
|
549
|
+
argv[0] = ID2SYM(me->def->original_id);
|
550
|
+
MEMCPY(argv+1, cfp->sp - num, VALUE, num);
|
551
|
+
cfp->sp += - num - 1;
|
552
|
+
val = rb_funcall2(recv, rb_intern("method_missing"), num+1, argv);
|
553
|
+
break;
|
554
|
+
}
|
555
|
+
case VM_METHOD_TYPE_BMETHOD:{
|
556
|
+
VALUE *argv = ALLOCA_N(VALUE, num);
|
557
|
+
MEMCPY(argv, cfp->sp - num, VALUE, num);
|
558
|
+
cfp->sp += - num - 1;
|
559
|
+
val = vm_call_bmethod(th, recv, num, argv, blockptr, me);
|
560
|
+
break;
|
561
|
+
}
|
562
|
+
case VM_METHOD_TYPE_ZSUPER:{
|
563
|
+
VALUE klass = RCLASS_SUPER(me->klass);
|
564
|
+
me = rb_method_entry(klass, id);
|
565
|
+
|
566
|
+
if (me != 0) {
|
567
|
+
goto normal_method_dispatch;
|
568
|
+
}
|
569
|
+
else {
|
570
|
+
goto start_method_dispatch;
|
571
|
+
}
|
572
|
+
}
|
573
|
+
case VM_METHOD_TYPE_OPTIMIZED:{
|
574
|
+
switch (me->def->body.optimize_type) {
|
575
|
+
case OPTIMIZED_METHOD_TYPE_SEND: {
|
576
|
+
rb_control_frame_t *reg_cfp = cfp;
|
577
|
+
rb_num_t i = num - 1;
|
578
|
+
VALUE sym;
|
579
|
+
|
580
|
+
if (num == 0) {
|
581
|
+
rb_raise(rb_eArgError, "no method name given");
|
582
|
+
}
|
583
|
+
|
584
|
+
sym = TOPN(i);
|
585
|
+
id = SYMBOL_P(sym) ? SYM2ID(sym) : rb_to_id(sym);
|
586
|
+
/* shift arguments */
|
587
|
+
if (i > 0) {
|
588
|
+
MEMMOVE(&TOPN(i), &TOPN(i-1), VALUE, i);
|
589
|
+
}
|
590
|
+
me = rb_method_entry(CLASS_OF(recv), id);
|
591
|
+
num -= 1;
|
592
|
+
DEC_SP(1);
|
593
|
+
flag |= VM_CALL_FCALL_BIT | VM_CALL_OPT_SEND_BIT;
|
594
|
+
|
595
|
+
goto start_method_dispatch;
|
596
|
+
}
|
597
|
+
case OPTIMIZED_METHOD_TYPE_CALL: {
|
598
|
+
rb_proc_t *proc;
|
599
|
+
int argc = num;
|
600
|
+
VALUE *argv = ALLOCA_N(VALUE, num);
|
601
|
+
GetProcPtr(recv, proc);
|
602
|
+
MEMCPY(argv, cfp->sp - num, VALUE, num);
|
603
|
+
cfp->sp -= num + 1;
|
604
|
+
|
605
|
+
val = rb_vm_invoke_proc(th, proc, proc->block.self, argc, argv, blockptr);
|
606
|
+
break;
|
607
|
+
}
|
608
|
+
default:
|
609
|
+
rb_bug("eval_invoke_method: unsupported optimized method type (%d)",
|
610
|
+
me->def->body.optimize_type);
|
611
|
+
}
|
612
|
+
break;
|
613
|
+
}
|
614
|
+
default:{
|
615
|
+
rb_bug("eval_invoke_method: unsupported method type (%d)", me->def->type);
|
616
|
+
break;
|
617
|
+
}
|
618
|
+
}
|
619
|
+
}
|
620
|
+
else {
|
621
|
+
int noex_safe;
|
622
|
+
|
623
|
+
if (!(flag & VM_CALL_FCALL_BIT) &&
|
624
|
+
(me->flag & NOEX_MASK) & NOEX_PRIVATE) {
|
625
|
+
int stat = NOEX_PRIVATE;
|
626
|
+
|
627
|
+
if (flag & VM_CALL_VCALL_BIT) {
|
628
|
+
stat |= NOEX_VCALL;
|
629
|
+
}
|
630
|
+
val = vm_method_missing(th, id, recv, num, blockptr, stat);
|
631
|
+
}
|
632
|
+
else if (!(flag & VM_CALL_OPT_SEND_BIT) && (me->flag & NOEX_MASK) & NOEX_PROTECTED) {
|
633
|
+
VALUE defined_class = me->klass;
|
634
|
+
|
635
|
+
if (TYPE(defined_class) == T_ICLASS) {
|
636
|
+
defined_class = RBASIC(defined_class)->klass;
|
637
|
+
}
|
638
|
+
|
639
|
+
if (!rb_obj_is_kind_of(cfp->self, defined_class)) {
|
640
|
+
val = vm_method_missing(th, id, recv, num, blockptr, NOEX_PROTECTED);
|
641
|
+
}
|
642
|
+
else {
|
643
|
+
goto normal_method_dispatch;
|
644
|
+
}
|
645
|
+
}
|
646
|
+
else if ((noex_safe = NOEX_SAFE(me->flag)) > th->safe_level &&
|
647
|
+
(noex_safe > 2)) {
|
648
|
+
rb_raise(rb_eSecurityError, "calling insecure method: %s", rb_id2name(id));
|
649
|
+
}
|
650
|
+
else {
|
651
|
+
goto normal_method_dispatch;
|
652
|
+
}
|
653
|
+
}
|
654
|
+
}
|
655
|
+
else {
|
656
|
+
/* method missing */
|
657
|
+
int stat = 0;
|
658
|
+
if (flag & VM_CALL_VCALL_BIT) {
|
659
|
+
stat |= NOEX_VCALL;
|
660
|
+
}
|
661
|
+
if (flag & VM_CALL_SUPER_BIT) {
|
662
|
+
stat |= NOEX_SUPER;
|
663
|
+
}
|
664
|
+
if (id == idMethodMissing) {
|
665
|
+
VALUE *argv = ALLOCA_N(VALUE, num);
|
666
|
+
vm_method_missing_args(th, argv, num - 1, 0, stat);
|
667
|
+
rb_raise_method_missing(th, num, argv, recv, stat);
|
668
|
+
}
|
669
|
+
else {
|
670
|
+
val = vm_method_missing(th, id, recv, num, blockptr, stat);
|
671
|
+
}
|
672
|
+
}
|
673
|
+
|
674
|
+
RUBY_VM_CHECK_INTS();
|
675
|
+
return val;
|
676
|
+
}
|
677
|
+
|
678
|
+
/* yield */
|
679
|
+
|
680
|
+
static inline int
|
681
|
+
block_proc_is_lambda(const VALUE procval)
|
682
|
+
{
|
683
|
+
rb_proc_t *proc;
|
684
|
+
|
685
|
+
if (procval) {
|
686
|
+
GetProcPtr(procval, proc);
|
687
|
+
return proc->is_lambda;
|
688
|
+
}
|
689
|
+
else {
|
690
|
+
return 0;
|
691
|
+
}
|
692
|
+
}
|
693
|
+
|
694
|
+
static inline VALUE
|
695
|
+
vm_yield_with_cfunc(rb_thread_t *th, const rb_block_t *block,
|
696
|
+
VALUE self, int argc, const VALUE *argv,
|
697
|
+
const rb_block_t *blockargptr)
|
698
|
+
{
|
699
|
+
NODE *ifunc = (NODE *) block->iseq;
|
700
|
+
VALUE val, arg, blockarg;
|
701
|
+
int lambda = block_proc_is_lambda(block->proc);
|
702
|
+
|
703
|
+
if (lambda) {
|
704
|
+
arg = rb_ary_new4(argc, argv);
|
705
|
+
}
|
706
|
+
else if (argc == 0) {
|
707
|
+
arg = Qnil;
|
708
|
+
}
|
709
|
+
else {
|
710
|
+
arg = argv[0];
|
711
|
+
}
|
712
|
+
|
713
|
+
if (blockargptr) {
|
714
|
+
if (blockargptr->proc) {
|
715
|
+
blockarg = blockargptr->proc;
|
716
|
+
}
|
717
|
+
else {
|
718
|
+
blockarg = rb_vm_make_proc(th, blockargptr, rb_cProc);
|
719
|
+
}
|
720
|
+
}
|
721
|
+
else {
|
722
|
+
blockarg = Qnil;
|
723
|
+
}
|
724
|
+
|
725
|
+
vm_push_frame(th, 0, VM_FRAME_MAGIC_IFUNC,
|
726
|
+
self, (VALUE)block->dfp,
|
727
|
+
0, th->cfp->sp, block->lfp, 1);
|
728
|
+
|
729
|
+
if (blockargptr) {
|
730
|
+
th->cfp->lfp[0] = GC_GUARDED_PTR((VALUE)blockargptr);
|
731
|
+
}
|
732
|
+
val = (*ifunc->nd_cfnc) (arg, ifunc->nd_tval, argc, argv, blockarg);
|
733
|
+
|
734
|
+
th->cfp++;
|
735
|
+
return val;
|
736
|
+
}
|
737
|
+
|
738
|
+
|
739
|
+
/*--
|
740
|
+
* @brief on supplied all of optional, rest and post parameters.
|
741
|
+
* @pre iseq is block style (not lambda style)
|
742
|
+
*/
|
743
|
+
static inline int
|
744
|
+
vm_yield_setup_block_args_complex(rb_thread_t *th, const rb_iseq_t *iseq,
|
745
|
+
int argc, VALUE *argv)
|
746
|
+
{
|
747
|
+
rb_num_t opt_pc = 0;
|
748
|
+
int i;
|
749
|
+
const int m = iseq->argc;
|
750
|
+
const int r = iseq->arg_rest;
|
751
|
+
int len = iseq->arg_post_len;
|
752
|
+
int start = iseq->arg_post_start;
|
753
|
+
int rsize = argc > m ? argc - m : 0; /* # of arguments which did not consumed yet */
|
754
|
+
int psize = rsize > len ? len : rsize; /* # of post arguments */
|
755
|
+
int osize = 0; /* # of opt arguments */
|
756
|
+
VALUE ary;
|
757
|
+
|
758
|
+
/* reserves arguments for post parameters */
|
759
|
+
rsize -= psize;
|
760
|
+
|
761
|
+
if (iseq->arg_opts) {
|
762
|
+
const int opts = iseq->arg_opts - 1;
|
763
|
+
if (rsize > opts) {
|
764
|
+
osize = opts;
|
765
|
+
opt_pc = iseq->arg_opt_table[opts];
|
766
|
+
}
|
767
|
+
else {
|
768
|
+
osize = rsize;
|
769
|
+
opt_pc = iseq->arg_opt_table[rsize];
|
770
|
+
}
|
771
|
+
}
|
772
|
+
rsize -= osize;
|
773
|
+
|
774
|
+
if (0) {
|
775
|
+
printf(" argc: %d\n", argc);
|
776
|
+
printf(" len: %d\n", len);
|
777
|
+
printf("start: %d\n", start);
|
778
|
+
printf("rsize: %d\n", rsize);
|
779
|
+
}
|
780
|
+
|
781
|
+
if (r == -1) {
|
782
|
+
/* copy post argument */
|
783
|
+
MEMMOVE(&argv[start], &argv[m+osize], VALUE, psize);
|
784
|
+
}
|
785
|
+
else {
|
786
|
+
ary = rb_ary_new4(rsize, &argv[r]);
|
787
|
+
|
788
|
+
/* copy post argument */
|
789
|
+
MEMMOVE(&argv[start], &argv[m+rsize+osize], VALUE, psize);
|
790
|
+
argv[r] = ary;
|
791
|
+
}
|
792
|
+
|
793
|
+
for (i=psize; i<len; i++) {
|
794
|
+
argv[start + i] = Qnil;
|
795
|
+
}
|
796
|
+
|
797
|
+
return (int)opt_pc;
|
798
|
+
}
|
799
|
+
|
800
|
+
static inline int
|
801
|
+
vm_yield_setup_block_args(rb_thread_t *th, const rb_iseq_t * iseq,
|
802
|
+
int orig_argc, VALUE *argv,
|
803
|
+
const rb_block_t *blockptr)
|
804
|
+
{
|
805
|
+
int i;
|
806
|
+
int argc = orig_argc;
|
807
|
+
const int m = iseq->argc;
|
808
|
+
VALUE ary, arg0;
|
809
|
+
int opt_pc = 0;
|
810
|
+
|
811
|
+
th->mark_stack_len = argc;
|
812
|
+
|
813
|
+
/*
|
814
|
+
* yield [1, 2]
|
815
|
+
* => {|a|} => a = [1, 2]
|
816
|
+
* => {|a, b|} => a, b = [1, 2]
|
817
|
+
*/
|
818
|
+
arg0 = argv[0];
|
819
|
+
if (!(iseq->arg_simple & 0x02) && /* exclude {|a|} */
|
820
|
+
(m + iseq->arg_post_len) > 0 && /* this process is meaningful */
|
821
|
+
argc == 1 && !NIL_P(ary = rb_check_array_type(arg0))) { /* rhs is only an array */
|
822
|
+
th->mark_stack_len = argc = RARRAY_LENINT(ary);
|
823
|
+
|
824
|
+
CHECK_STACK_OVERFLOW(th->cfp, argc);
|
825
|
+
|
826
|
+
MEMCPY(argv, RARRAY_PTR(ary), VALUE, argc);
|
827
|
+
}
|
828
|
+
else {
|
829
|
+
argv[0] = arg0;
|
830
|
+
}
|
831
|
+
|
832
|
+
for (i=argc; i<m; i++) {
|
833
|
+
argv[i] = Qnil;
|
834
|
+
}
|
835
|
+
|
836
|
+
if (iseq->arg_rest == -1 && iseq->arg_opts == 0) {
|
837
|
+
const int arg_size = iseq->arg_size;
|
838
|
+
if (arg_size < argc) {
|
839
|
+
/*
|
840
|
+
* yield 1, 2
|
841
|
+
* => {|a|} # truncate
|
842
|
+
*/
|
843
|
+
th->mark_stack_len = argc = arg_size;
|
844
|
+
}
|
845
|
+
}
|
846
|
+
else {
|
847
|
+
int r = iseq->arg_rest;
|
848
|
+
|
849
|
+
if (iseq->arg_post_len ||
|
850
|
+
iseq->arg_opts) { /* TODO: implement simple version for (iseq->arg_post_len==0 && iseq->arg_opts > 0) */
|
851
|
+
opt_pc = vm_yield_setup_block_args_complex(th, iseq, argc, argv);
|
852
|
+
}
|
853
|
+
else {
|
854
|
+
if (argc < r) {
|
855
|
+
/* yield 1
|
856
|
+
* => {|a, b, *r|}
|
857
|
+
*/
|
858
|
+
for (i=argc; i<r; i++) {
|
859
|
+
argv[i] = Qnil;
|
860
|
+
}
|
861
|
+
argv[r] = rb_ary_new();
|
862
|
+
}
|
863
|
+
else {
|
864
|
+
argv[r] = rb_ary_new4(argc-r, &argv[r]);
|
865
|
+
}
|
866
|
+
}
|
867
|
+
|
868
|
+
th->mark_stack_len = iseq->arg_size;
|
869
|
+
}
|
870
|
+
|
871
|
+
/* {|&b|} */
|
872
|
+
if (iseq->arg_block != -1) {
|
873
|
+
VALUE procval = Qnil;
|
874
|
+
|
875
|
+
if (blockptr) {
|
876
|
+
if (blockptr->proc == 0) {
|
877
|
+
procval = rb_vm_make_proc(th, blockptr, rb_cProc);
|
878
|
+
}
|
879
|
+
else {
|
880
|
+
procval = blockptr->proc;
|
881
|
+
}
|
882
|
+
}
|
883
|
+
|
884
|
+
argv[iseq->arg_block] = procval;
|
885
|
+
}
|
886
|
+
|
887
|
+
th->mark_stack_len = 0;
|
888
|
+
return opt_pc;
|
889
|
+
}
|
890
|
+
|
891
|
+
static inline int
|
892
|
+
vm_yield_setup_args(rb_thread_t * const th, const rb_iseq_t *iseq,
|
893
|
+
int argc, VALUE *argv,
|
894
|
+
const rb_block_t *blockptr, int lambda)
|
895
|
+
{
|
896
|
+
if (0) { /* for debug */
|
897
|
+
printf(" argc: %d\n", argc);
|
898
|
+
printf("iseq argc: %d\n", iseq->argc);
|
899
|
+
printf("iseq opts: %d\n", iseq->arg_opts);
|
900
|
+
printf("iseq rest: %d\n", iseq->arg_rest);
|
901
|
+
printf("iseq post: %d\n", iseq->arg_post_len);
|
902
|
+
printf("iseq blck: %d\n", iseq->arg_block);
|
903
|
+
printf("iseq smpl: %d\n", iseq->arg_simple);
|
904
|
+
printf(" lambda: %s\n", lambda ? "true" : "false");
|
905
|
+
}
|
906
|
+
|
907
|
+
if (lambda) {
|
908
|
+
/* call as method */
|
909
|
+
int opt_pc;
|
910
|
+
VM_CALLEE_SETUP_ARG(opt_pc, th, iseq, argc, argv, &blockptr);
|
911
|
+
return opt_pc;
|
912
|
+
}
|
913
|
+
else {
|
914
|
+
return vm_yield_setup_block_args(th, iseq, argc, argv, blockptr);
|
915
|
+
}
|
916
|
+
}
|
917
|
+
|
918
|
+
static VALUE
|
919
|
+
vm_invoke_block(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_num_t num, rb_num_t flag)
|
920
|
+
{
|
921
|
+
const rb_block_t *block = GET_BLOCK_PTR();
|
922
|
+
rb_iseq_t *iseq;
|
923
|
+
int argc = (int)num;
|
924
|
+
VALUE type = GET_ISEQ()->local_iseq->type;
|
925
|
+
|
926
|
+
if ((type != ISEQ_TYPE_METHOD && type != ISEQ_TYPE_CLASS) || block == 0) {
|
927
|
+
rb_vm_localjump_error("no block given (yield)", Qnil, 0);
|
928
|
+
}
|
929
|
+
iseq = block->iseq;
|
930
|
+
|
931
|
+
argc = caller_setup_args(th, GET_CFP(), flag, argc, 0, 0);
|
932
|
+
|
933
|
+
if (BUILTIN_TYPE(iseq) != T_NODE) {
|
934
|
+
int opt_pc;
|
935
|
+
const int arg_size = iseq->arg_size;
|
936
|
+
VALUE * const rsp = GET_SP() - argc;
|
937
|
+
SET_SP(rsp);
|
938
|
+
|
939
|
+
CHECK_STACK_OVERFLOW(GET_CFP(), iseq->stack_max);
|
940
|
+
opt_pc = vm_yield_setup_args(th, iseq, argc, rsp, 0,
|
941
|
+
block_proc_is_lambda(block->proc));
|
942
|
+
|
943
|
+
vm_push_frame(th, iseq,
|
944
|
+
VM_FRAME_MAGIC_BLOCK, block->self, (VALUE) block->dfp,
|
945
|
+
iseq->iseq_encoded + opt_pc, rsp + arg_size, block->lfp,
|
946
|
+
iseq->local_size - arg_size);
|
947
|
+
|
948
|
+
return Qundef;
|
949
|
+
}
|
950
|
+
else {
|
951
|
+
VALUE val = vm_yield_with_cfunc(th, block, block->self, argc, STACK_ADDR_FROM_TOP(argc), 0);
|
952
|
+
POPN(argc); /* TODO: should put before C/yield? */
|
953
|
+
return val;
|
954
|
+
}
|
955
|
+
}
|
956
|
+
|
957
|
+
/* svar */
|
958
|
+
|
959
|
+
static inline NODE *
|
960
|
+
lfp_svar_place(rb_thread_t *th, VALUE *lfp)
|
961
|
+
{
|
962
|
+
VALUE *svar;
|
963
|
+
|
964
|
+
if (lfp && th->local_lfp != lfp) {
|
965
|
+
svar = &lfp[-1];
|
966
|
+
}
|
967
|
+
else {
|
968
|
+
svar = &th->local_svar;
|
969
|
+
}
|
970
|
+
if (NIL_P(*svar)) {
|
971
|
+
*svar = (VALUE)NEW_IF(Qnil, Qnil, Qnil);
|
972
|
+
}
|
973
|
+
return (NODE *)*svar;
|
974
|
+
}
|
975
|
+
|
976
|
+
static VALUE
|
977
|
+
lfp_svar_get(rb_thread_t *th, VALUE *lfp, VALUE key)
|
978
|
+
{
|
979
|
+
NODE *svar = lfp_svar_place(th, lfp);
|
980
|
+
|
981
|
+
switch (key) {
|
982
|
+
case 0:
|
983
|
+
return svar->u1.value;
|
984
|
+
case 1:
|
985
|
+
return svar->u2.value;
|
986
|
+
default: {
|
987
|
+
const VALUE hash = svar->u3.value;
|
988
|
+
|
989
|
+
if (hash == Qnil) {
|
990
|
+
return Qnil;
|
991
|
+
}
|
992
|
+
else {
|
993
|
+
return rb_hash_lookup(hash, key);
|
994
|
+
}
|
995
|
+
}
|
996
|
+
}
|
997
|
+
}
|
998
|
+
|
999
|
+
static void
|
1000
|
+
lfp_svar_set(rb_thread_t *th, VALUE *lfp, VALUE key, VALUE val)
|
1001
|
+
{
|
1002
|
+
NODE *svar = lfp_svar_place(th, lfp);
|
1003
|
+
|
1004
|
+
switch (key) {
|
1005
|
+
case 0:
|
1006
|
+
svar->u1.value = val;
|
1007
|
+
return;
|
1008
|
+
case 1:
|
1009
|
+
svar->u2.value = val;
|
1010
|
+
return;
|
1011
|
+
default: {
|
1012
|
+
VALUE hash = svar->u3.value;
|
1013
|
+
|
1014
|
+
if (hash == Qnil) {
|
1015
|
+
svar->u3.value = hash = rb_hash_new();
|
1016
|
+
}
|
1017
|
+
rb_hash_aset(hash, key, val);
|
1018
|
+
}
|
1019
|
+
}
|
1020
|
+
}
|
1021
|
+
|
1022
|
+
static inline VALUE
|
1023
|
+
vm_getspecial(rb_thread_t *th, VALUE *lfp, VALUE key, rb_num_t type)
|
1024
|
+
{
|
1025
|
+
VALUE val;
|
1026
|
+
|
1027
|
+
if (type == 0) {
|
1028
|
+
VALUE k = key;
|
1029
|
+
if (FIXNUM_P(key)) {
|
1030
|
+
k = FIX2INT(key);
|
1031
|
+
}
|
1032
|
+
val = lfp_svar_get(th, lfp, k);
|
1033
|
+
}
|
1034
|
+
else {
|
1035
|
+
VALUE backref = lfp_svar_get(th, lfp, 1);
|
1036
|
+
|
1037
|
+
if (type & 0x01) {
|
1038
|
+
switch (type >> 1) {
|
1039
|
+
case '&':
|
1040
|
+
val = rb_reg_last_match(backref);
|
1041
|
+
break;
|
1042
|
+
case '`':
|
1043
|
+
val = rb_reg_match_pre(backref);
|
1044
|
+
break;
|
1045
|
+
case '\'':
|
1046
|
+
val = rb_reg_match_post(backref);
|
1047
|
+
break;
|
1048
|
+
case '+':
|
1049
|
+
val = rb_reg_match_last(backref);
|
1050
|
+
break;
|
1051
|
+
default:
|
1052
|
+
rb_bug("unexpected back-ref");
|
1053
|
+
}
|
1054
|
+
}
|
1055
|
+
else {
|
1056
|
+
val = rb_reg_nth_match((int)(type >> 1), backref);
|
1057
|
+
}
|
1058
|
+
}
|
1059
|
+
return val;
|
1060
|
+
}
|
1061
|
+
|
1062
|
+
static NODE *
|
1063
|
+
vm_get_cref0(const rb_iseq_t *iseq, const VALUE *lfp, const VALUE *dfp)
|
1064
|
+
{
|
1065
|
+
while (1) {
|
1066
|
+
if (lfp == dfp) {
|
1067
|
+
return iseq->cref_stack;
|
1068
|
+
}
|
1069
|
+
else if (dfp[-1] != Qnil) {
|
1070
|
+
return (NODE *)dfp[-1];
|
1071
|
+
}
|
1072
|
+
dfp = GET_PREV_DFP(dfp);
|
1073
|
+
}
|
1074
|
+
}
|
1075
|
+
|
1076
|
+
static NODE *
|
1077
|
+
vm_get_cref(const rb_iseq_t *iseq, const VALUE *lfp, const VALUE *dfp)
|
1078
|
+
{
|
1079
|
+
NODE *cref = vm_get_cref0(iseq, lfp, dfp);
|
1080
|
+
|
1081
|
+
if (cref == 0) {
|
1082
|
+
rb_bug("vm_get_cref: unreachable");
|
1083
|
+
}
|
1084
|
+
return cref;
|
1085
|
+
}
|
1086
|
+
|
1087
|
+
static NODE *
|
1088
|
+
vm_cref_push(rb_thread_t *th, VALUE klass, int noex, rb_block_t *blockptr)
|
1089
|
+
{
|
1090
|
+
rb_control_frame_t *cfp = vm_get_ruby_level_caller_cfp(th, th->cfp);
|
1091
|
+
NODE *cref = NEW_BLOCK(klass);
|
1092
|
+
cref->nd_file = 0;
|
1093
|
+
cref->nd_visi = noex;
|
1094
|
+
|
1095
|
+
if (blockptr) {
|
1096
|
+
cref->nd_next = vm_get_cref0(blockptr->iseq, blockptr->lfp, blockptr->dfp);
|
1097
|
+
}
|
1098
|
+
else if (cfp) {
|
1099
|
+
cref->nd_next = vm_get_cref0(cfp->iseq, cfp->lfp, cfp->dfp);
|
1100
|
+
}
|
1101
|
+
|
1102
|
+
return cref;
|
1103
|
+
}
|
1104
|
+
|
1105
|
+
static inline VALUE
|
1106
|
+
vm_get_cbase(const rb_iseq_t *iseq, const VALUE *lfp, const VALUE *dfp)
|
1107
|
+
{
|
1108
|
+
NODE *cref = vm_get_cref(iseq, lfp, dfp);
|
1109
|
+
VALUE klass = Qundef;
|
1110
|
+
|
1111
|
+
while (cref) {
|
1112
|
+
if ((klass = cref->nd_clss) != 0) {
|
1113
|
+
break;
|
1114
|
+
}
|
1115
|
+
cref = cref->nd_next;
|
1116
|
+
}
|
1117
|
+
|
1118
|
+
return klass;
|
1119
|
+
}
|
1120
|
+
|
1121
|
+
static inline VALUE
|
1122
|
+
vm_get_const_base(const rb_iseq_t *iseq, const VALUE *lfp, const VALUE *dfp)
|
1123
|
+
{
|
1124
|
+
NODE *cref = vm_get_cref(iseq, lfp, dfp);
|
1125
|
+
VALUE klass = Qundef;
|
1126
|
+
|
1127
|
+
while (cref) {
|
1128
|
+
if (!(cref->flags & NODE_FL_CREF_PUSHED_BY_EVAL) &&
|
1129
|
+
(klass = cref->nd_clss) != 0) {
|
1130
|
+
break;
|
1131
|
+
}
|
1132
|
+
cref = cref->nd_next;
|
1133
|
+
}
|
1134
|
+
|
1135
|
+
return klass;
|
1136
|
+
}
|
1137
|
+
|
1138
|
+
static inline void
|
1139
|
+
vm_check_if_namespace(VALUE klass)
|
1140
|
+
{
|
1141
|
+
VALUE str;
|
1142
|
+
switch (TYPE(klass)) {
|
1143
|
+
case T_CLASS:
|
1144
|
+
case T_MODULE:
|
1145
|
+
break;
|
1146
|
+
default:
|
1147
|
+
str = rb_inspect(klass);
|
1148
|
+
rb_raise(rb_eTypeError, "%s is not a class/module",
|
1149
|
+
StringValuePtr(str));
|
1150
|
+
}
|
1151
|
+
}
|
1152
|
+
|
1153
|
+
static inline VALUE
|
1154
|
+
vm_get_ev_const(rb_thread_t *th, const rb_iseq_t *iseq,
|
1155
|
+
VALUE orig_klass, ID id, int is_defined)
|
1156
|
+
{
|
1157
|
+
VALUE val;
|
1158
|
+
|
1159
|
+
if (orig_klass == Qnil) {
|
1160
|
+
/* in current lexical scope */
|
1161
|
+
const NODE *cref = vm_get_cref(iseq, th->cfp->lfp, th->cfp->dfp);
|
1162
|
+
const NODE *root_cref = NULL;
|
1163
|
+
VALUE klass = orig_klass;
|
1164
|
+
|
1165
|
+
while (cref && cref->nd_next) {
|
1166
|
+
if (!(cref->flags & NODE_FL_CREF_PUSHED_BY_EVAL)) {
|
1167
|
+
klass = cref->nd_clss;
|
1168
|
+
if (root_cref == NULL)
|
1169
|
+
root_cref = cref;
|
1170
|
+
}
|
1171
|
+
cref = cref->nd_next;
|
1172
|
+
|
1173
|
+
if (!NIL_P(klass)) {
|
1174
|
+
VALUE am = 0;
|
1175
|
+
search_continue:
|
1176
|
+
if (RCLASS_IV_TBL(klass) &&
|
1177
|
+
st_lookup(RCLASS_IV_TBL(klass), id, &val)) {
|
1178
|
+
if (val == Qundef) {
|
1179
|
+
if (am == klass) break;
|
1180
|
+
am = klass;
|
1181
|
+
rb_autoload_load(klass, id);
|
1182
|
+
goto search_continue;
|
1183
|
+
}
|
1184
|
+
else {
|
1185
|
+
if (is_defined) {
|
1186
|
+
return 1;
|
1187
|
+
}
|
1188
|
+
else {
|
1189
|
+
return val;
|
1190
|
+
}
|
1191
|
+
}
|
1192
|
+
}
|
1193
|
+
}
|
1194
|
+
}
|
1195
|
+
|
1196
|
+
/* search self */
|
1197
|
+
if (root_cref && !NIL_P(root_cref->nd_clss)) {
|
1198
|
+
klass = root_cref->nd_clss;
|
1199
|
+
}
|
1200
|
+
else {
|
1201
|
+
klass = CLASS_OF(th->cfp->self);
|
1202
|
+
}
|
1203
|
+
|
1204
|
+
if (is_defined) {
|
1205
|
+
return rb_const_defined(klass, id);
|
1206
|
+
}
|
1207
|
+
else {
|
1208
|
+
return rb_const_get(klass, id);
|
1209
|
+
}
|
1210
|
+
}
|
1211
|
+
else {
|
1212
|
+
vm_check_if_namespace(orig_klass);
|
1213
|
+
if (is_defined) {
|
1214
|
+
return rb_const_defined_from(orig_klass, id);
|
1215
|
+
}
|
1216
|
+
else {
|
1217
|
+
return rb_const_get_from(orig_klass, id);
|
1218
|
+
}
|
1219
|
+
}
|
1220
|
+
}
|
1221
|
+
|
1222
|
+
static inline VALUE
|
1223
|
+
vm_get_cvar_base(NODE *cref)
|
1224
|
+
{
|
1225
|
+
VALUE klass;
|
1226
|
+
|
1227
|
+
while (cref && cref->nd_next &&
|
1228
|
+
(NIL_P(cref->nd_clss) || FL_TEST(cref->nd_clss, FL_SINGLETON) ||
|
1229
|
+
(cref->flags & NODE_FL_CREF_PUSHED_BY_EVAL))) {
|
1230
|
+
cref = cref->nd_next;
|
1231
|
+
|
1232
|
+
if (!cref->nd_next) {
|
1233
|
+
rb_warn("class variable access from toplevel");
|
1234
|
+
}
|
1235
|
+
}
|
1236
|
+
|
1237
|
+
klass = cref->nd_clss;
|
1238
|
+
|
1239
|
+
if (NIL_P(klass)) {
|
1240
|
+
rb_raise(rb_eTypeError, "no class variables available");
|
1241
|
+
}
|
1242
|
+
return klass;
|
1243
|
+
}
|
1244
|
+
|
1245
|
+
|
1246
|
+
#ifndef USE_IC_FOR_IVAR
|
1247
|
+
#define USE_IC_FOR_IVAR 1
|
1248
|
+
#endif
|
1249
|
+
|
1250
|
+
static VALUE
|
1251
|
+
vm_getivar(VALUE obj, ID id, IC ic)
|
1252
|
+
{
|
1253
|
+
#if USE_IC_FOR_IVAR
|
1254
|
+
if (TYPE(obj) == T_OBJECT) {
|
1255
|
+
VALUE val = Qundef;
|
1256
|
+
VALUE klass = RBASIC(obj)->klass;
|
1257
|
+
|
1258
|
+
if (LIKELY(ic->ic_class == klass &&
|
1259
|
+
ic->ic_vmstat == GET_VM_STATE_VERSION())) {
|
1260
|
+
long index = ic->ic_value.index;
|
1261
|
+
long len = ROBJECT_NUMIV(obj);
|
1262
|
+
VALUE *ptr = ROBJECT_IVPTR(obj);
|
1263
|
+
|
1264
|
+
if (index < len) {
|
1265
|
+
val = ptr[index];
|
1266
|
+
}
|
1267
|
+
}
|
1268
|
+
else {
|
1269
|
+
st_data_t index;
|
1270
|
+
long len = ROBJECT_NUMIV(obj);
|
1271
|
+
VALUE *ptr = ROBJECT_IVPTR(obj);
|
1272
|
+
struct st_table *iv_index_tbl = ROBJECT_IV_INDEX_TBL(obj);
|
1273
|
+
|
1274
|
+
if (iv_index_tbl) {
|
1275
|
+
if (st_lookup(iv_index_tbl, id, &index)) {
|
1276
|
+
if ((long)index < len) {
|
1277
|
+
val = ptr[index];
|
1278
|
+
}
|
1279
|
+
ic->ic_class = klass;
|
1280
|
+
ic->ic_value.index = index;
|
1281
|
+
ic->ic_vmstat = GET_VM_STATE_VERSION();
|
1282
|
+
}
|
1283
|
+
}
|
1284
|
+
}
|
1285
|
+
if (UNLIKELY(val == Qundef)) {
|
1286
|
+
rb_warning("instance variable %s not initialized", rb_id2name(id));
|
1287
|
+
val = Qnil;
|
1288
|
+
}
|
1289
|
+
return val;
|
1290
|
+
}
|
1291
|
+
else {
|
1292
|
+
return rb_ivar_get(obj, id);
|
1293
|
+
}
|
1294
|
+
#else
|
1295
|
+
return rb_ivar_get(obj, id);
|
1296
|
+
#endif
|
1297
|
+
}
|
1298
|
+
|
1299
|
+
static void
|
1300
|
+
vm_setivar(VALUE obj, ID id, VALUE val, IC ic)
|
1301
|
+
{
|
1302
|
+
#if USE_IC_FOR_IVAR
|
1303
|
+
if (!OBJ_UNTRUSTED(obj) && rb_safe_level() >= 4) {
|
1304
|
+
rb_raise(rb_eSecurityError, "Insecure: can't modify instance variable");
|
1305
|
+
}
|
1306
|
+
if (OBJ_FROZEN(obj)) {
|
1307
|
+
rb_error_frozen("object");
|
1308
|
+
}
|
1309
|
+
|
1310
|
+
if (TYPE(obj) == T_OBJECT) {
|
1311
|
+
VALUE klass = RBASIC(obj)->klass;
|
1312
|
+
st_data_t index;
|
1313
|
+
|
1314
|
+
if (LIKELY(ic->ic_class == klass &&
|
1315
|
+
ic->ic_vmstat == GET_VM_STATE_VERSION())) {
|
1316
|
+
long index = ic->ic_value.index;
|
1317
|
+
long len = ROBJECT_NUMIV(obj);
|
1318
|
+
VALUE *ptr = ROBJECT_IVPTR(obj);
|
1319
|
+
|
1320
|
+
if (index < len) {
|
1321
|
+
ptr[index] = val;
|
1322
|
+
return; /* inline cache hit */
|
1323
|
+
}
|
1324
|
+
}
|
1325
|
+
else {
|
1326
|
+
struct st_table *iv_index_tbl = ROBJECT_IV_INDEX_TBL(obj);
|
1327
|
+
|
1328
|
+
if (iv_index_tbl && st_lookup(iv_index_tbl, (st_data_t)id, &index)) {
|
1329
|
+
ic->ic_class = klass;
|
1330
|
+
ic->ic_value.index = index;
|
1331
|
+
ic->ic_vmstat = GET_VM_STATE_VERSION();
|
1332
|
+
}
|
1333
|
+
/* fall through */
|
1334
|
+
}
|
1335
|
+
}
|
1336
|
+
rb_ivar_set(obj, id, val);
|
1337
|
+
#else
|
1338
|
+
rb_ivar_set(obj, id, val);
|
1339
|
+
#endif
|
1340
|
+
}
|
1341
|
+
|
1342
|
+
static inline const rb_method_entry_t *
|
1343
|
+
vm_method_search(VALUE id, VALUE klass, IC ic)
|
1344
|
+
{
|
1345
|
+
rb_method_entry_t *me;
|
1346
|
+
#if OPT_INLINE_METHOD_CACHE
|
1347
|
+
if (LIKELY(klass == ic->ic_class) &&
|
1348
|
+
LIKELY(GET_VM_STATE_VERSION() == ic->ic_vmstat)) {
|
1349
|
+
me = ic->ic_value.method;
|
1350
|
+
}
|
1351
|
+
else {
|
1352
|
+
me = rb_method_entry(klass, id);
|
1353
|
+
ic->ic_class = klass;
|
1354
|
+
ic->ic_value.method = me;
|
1355
|
+
ic->ic_vmstat = GET_VM_STATE_VERSION();
|
1356
|
+
}
|
1357
|
+
#else
|
1358
|
+
me = rb_method_entry(klass, id);
|
1359
|
+
#endif
|
1360
|
+
return me;
|
1361
|
+
}
|
1362
|
+
|
1363
|
+
static inline VALUE
|
1364
|
+
vm_search_normal_superclass(VALUE klass, VALUE recv)
|
1365
|
+
{
|
1366
|
+
if (BUILTIN_TYPE(klass) == T_CLASS) {
|
1367
|
+
return RCLASS_SUPER(klass);
|
1368
|
+
}
|
1369
|
+
else if (BUILTIN_TYPE(klass) == T_MODULE) {
|
1370
|
+
VALUE k = CLASS_OF(recv);
|
1371
|
+
while (k) {
|
1372
|
+
if (BUILTIN_TYPE(k) == T_ICLASS && RBASIC(k)->klass == klass) {
|
1373
|
+
return RCLASS_SUPER(k);
|
1374
|
+
}
|
1375
|
+
k = RCLASS_SUPER(k);
|
1376
|
+
}
|
1377
|
+
return rb_cObject;
|
1378
|
+
}
|
1379
|
+
else {
|
1380
|
+
rb_bug("vm_search_normal_superclass: should not be reach here");
|
1381
|
+
}
|
1382
|
+
}
|
1383
|
+
|
1384
|
+
static void
|
1385
|
+
vm_search_superclass(rb_control_frame_t *reg_cfp, rb_iseq_t *ip,
|
1386
|
+
VALUE recv, VALUE sigval,
|
1387
|
+
ID *idp, VALUE *klassp)
|
1388
|
+
{
|
1389
|
+
ID id;
|
1390
|
+
VALUE klass;
|
1391
|
+
|
1392
|
+
while (ip && !ip->klass) {
|
1393
|
+
ip = ip->parent_iseq;
|
1394
|
+
}
|
1395
|
+
|
1396
|
+
if (ip == 0) {
|
1397
|
+
rb_raise(rb_eNoMethodError, "super called outside of method");
|
1398
|
+
}
|
1399
|
+
|
1400
|
+
id = ip->defined_method_id;
|
1401
|
+
|
1402
|
+
if (ip != ip->local_iseq) {
|
1403
|
+
/* defined by Module#define_method() */
|
1404
|
+
rb_control_frame_t *lcfp = GET_CFP();
|
1405
|
+
|
1406
|
+
if (!sigval) {
|
1407
|
+
/* zsuper */
|
1408
|
+
rb_raise(rb_eRuntimeError, "implicit argument passing of super from method defined by define_method() is not supported. Specify all arguments explicitly.");
|
1409
|
+
}
|
1410
|
+
|
1411
|
+
while (lcfp->iseq != ip) {
|
1412
|
+
rb_thread_t *th = GET_THREAD();
|
1413
|
+
VALUE *tdfp = GET_PREV_DFP(lcfp->dfp);
|
1414
|
+
while (1) {
|
1415
|
+
lcfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(lcfp);
|
1416
|
+
if (RUBY_VM_CONTROL_FRAME_STACK_OVERFLOW_P(th, lcfp)) {
|
1417
|
+
rb_raise(rb_eNoMethodError,
|
1418
|
+
"super called outside of method");
|
1419
|
+
}
|
1420
|
+
if (lcfp->dfp == tdfp) {
|
1421
|
+
break;
|
1422
|
+
}
|
1423
|
+
}
|
1424
|
+
}
|
1425
|
+
|
1426
|
+
/* temporary measure for [Bug #2420] [Bug #3136] */
|
1427
|
+
if (!lcfp->me) {
|
1428
|
+
rb_raise(rb_eNoMethodError, "super called outside of method");
|
1429
|
+
}
|
1430
|
+
|
1431
|
+
id = lcfp->me->def->original_id;
|
1432
|
+
klass = vm_search_normal_superclass(lcfp->me->klass, recv);
|
1433
|
+
}
|
1434
|
+
else {
|
1435
|
+
klass = vm_search_normal_superclass(ip->klass, recv);
|
1436
|
+
}
|
1437
|
+
|
1438
|
+
*idp = id;
|
1439
|
+
*klassp = klass;
|
1440
|
+
}
|
1441
|
+
|
1442
|
+
static VALUE
|
1443
|
+
vm_throw(rb_thread_t *th, rb_control_frame_t *reg_cfp,
|
1444
|
+
rb_num_t throw_state, VALUE throwobj)
|
1445
|
+
{
|
1446
|
+
int state = (int)(throw_state & 0xff);
|
1447
|
+
int flag = (int)(throw_state & 0x8000);
|
1448
|
+
rb_num_t level = throw_state >> 16;
|
1449
|
+
|
1450
|
+
if (state != 0) {
|
1451
|
+
VALUE *pt = 0;
|
1452
|
+
if (flag != 0) {
|
1453
|
+
pt = (void *) 1;
|
1454
|
+
}
|
1455
|
+
else {
|
1456
|
+
if (state == TAG_BREAK) {
|
1457
|
+
rb_control_frame_t *cfp = GET_CFP();
|
1458
|
+
VALUE *dfp = GET_DFP();
|
1459
|
+
int is_orphan = 1;
|
1460
|
+
rb_iseq_t *base_iseq = GET_ISEQ();
|
1461
|
+
|
1462
|
+
search_parent:
|
1463
|
+
if (cfp->iseq->type != ISEQ_TYPE_BLOCK) {
|
1464
|
+
if (cfp->iseq->type == ISEQ_TYPE_CLASS) {
|
1465
|
+
cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
|
1466
|
+
dfp = cfp->dfp;
|
1467
|
+
goto search_parent;
|
1468
|
+
}
|
1469
|
+
dfp = GC_GUARDED_PTR_REF((VALUE *) *dfp);
|
1470
|
+
base_iseq = base_iseq->parent_iseq;
|
1471
|
+
|
1472
|
+
while ((VALUE *) cfp < th->stack + th->stack_size) {
|
1473
|
+
if (cfp->dfp == dfp) {
|
1474
|
+
goto search_parent;
|
1475
|
+
}
|
1476
|
+
cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
|
1477
|
+
}
|
1478
|
+
rb_bug("VM (throw): can't find break base.");
|
1479
|
+
}
|
1480
|
+
|
1481
|
+
if (VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_LAMBDA) {
|
1482
|
+
/* lambda{... break ...} */
|
1483
|
+
is_orphan = 0;
|
1484
|
+
pt = cfp->dfp;
|
1485
|
+
state = TAG_RETURN;
|
1486
|
+
}
|
1487
|
+
else {
|
1488
|
+
dfp = GC_GUARDED_PTR_REF((VALUE *) *dfp);
|
1489
|
+
|
1490
|
+
while ((VALUE *)cfp < th->stack + th->stack_size) {
|
1491
|
+
if (cfp->dfp == dfp) {
|
1492
|
+
VALUE epc = cfp->pc - cfp->iseq->iseq_encoded;
|
1493
|
+
rb_iseq_t *iseq = cfp->iseq;
|
1494
|
+
int i;
|
1495
|
+
|
1496
|
+
for (i=0; i<iseq->catch_table_size; i++) {
|
1497
|
+
struct iseq_catch_table_entry *entry = &iseq->catch_table[i];
|
1498
|
+
|
1499
|
+
if (entry->type == CATCH_TYPE_BREAK &&
|
1500
|
+
entry->start < epc && entry->end >= epc) {
|
1501
|
+
if (entry->cont == epc) {
|
1502
|
+
goto found;
|
1503
|
+
}
|
1504
|
+
else {
|
1505
|
+
break;
|
1506
|
+
}
|
1507
|
+
}
|
1508
|
+
}
|
1509
|
+
break;
|
1510
|
+
|
1511
|
+
found:
|
1512
|
+
pt = dfp;
|
1513
|
+
is_orphan = 0;
|
1514
|
+
break;
|
1515
|
+
}
|
1516
|
+
cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
|
1517
|
+
}
|
1518
|
+
}
|
1519
|
+
|
1520
|
+
if (is_orphan) {
|
1521
|
+
rb_vm_localjump_error("break from proc-closure", throwobj, TAG_BREAK);
|
1522
|
+
}
|
1523
|
+
}
|
1524
|
+
else if (state == TAG_RETRY) {
|
1525
|
+
rb_num_t i;
|
1526
|
+
pt = GC_GUARDED_PTR_REF((VALUE *) * GET_DFP());
|
1527
|
+
for (i = 0; i < level; i++) {
|
1528
|
+
pt = GC_GUARDED_PTR_REF((VALUE *) * pt);
|
1529
|
+
}
|
1530
|
+
}
|
1531
|
+
else if (state == TAG_RETURN) {
|
1532
|
+
rb_control_frame_t *cfp = GET_CFP();
|
1533
|
+
VALUE *dfp = GET_DFP();
|
1534
|
+
VALUE *lfp = GET_LFP();
|
1535
|
+
|
1536
|
+
/* check orphan and get dfp */
|
1537
|
+
while ((VALUE *) cfp < th->stack + th->stack_size) {
|
1538
|
+
if (!lfp) {
|
1539
|
+
lfp = cfp->lfp;
|
1540
|
+
}
|
1541
|
+
if (cfp->dfp == lfp && cfp->iseq->type == ISEQ_TYPE_CLASS) {
|
1542
|
+
lfp = 0;
|
1543
|
+
}
|
1544
|
+
|
1545
|
+
if (cfp->lfp == lfp) {
|
1546
|
+
if (VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_LAMBDA) {
|
1547
|
+
VALUE *tdfp = dfp;
|
1548
|
+
|
1549
|
+
while (lfp != tdfp) {
|
1550
|
+
if (cfp->dfp == tdfp) {
|
1551
|
+
/* in lambda */
|
1552
|
+
dfp = cfp->dfp;
|
1553
|
+
goto valid_return;
|
1554
|
+
}
|
1555
|
+
tdfp = GC_GUARDED_PTR_REF((VALUE *)*tdfp);
|
1556
|
+
}
|
1557
|
+
}
|
1558
|
+
}
|
1559
|
+
|
1560
|
+
if (cfp->dfp == lfp && cfp->iseq->type == ISEQ_TYPE_METHOD) {
|
1561
|
+
dfp = lfp;
|
1562
|
+
goto valid_return;
|
1563
|
+
}
|
1564
|
+
|
1565
|
+
cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
|
1566
|
+
}
|
1567
|
+
|
1568
|
+
rb_vm_localjump_error("unexpected return", throwobj, TAG_RETURN);
|
1569
|
+
|
1570
|
+
valid_return:
|
1571
|
+
pt = dfp;
|
1572
|
+
}
|
1573
|
+
else {
|
1574
|
+
rb_bug("isns(throw): unsupport throw type");
|
1575
|
+
}
|
1576
|
+
}
|
1577
|
+
th->state = state;
|
1578
|
+
return (VALUE)NEW_THROW_OBJECT(throwobj, (VALUE) pt, state);
|
1579
|
+
}
|
1580
|
+
else {
|
1581
|
+
/* continue throw */
|
1582
|
+
VALUE err = throwobj;
|
1583
|
+
|
1584
|
+
if (FIXNUM_P(err)) {
|
1585
|
+
th->state = FIX2INT(err);
|
1586
|
+
}
|
1587
|
+
else if (SYMBOL_P(err)) {
|
1588
|
+
th->state = TAG_THROW;
|
1589
|
+
}
|
1590
|
+
else if (BUILTIN_TYPE(err) == T_NODE) {
|
1591
|
+
th->state = GET_THROWOBJ_STATE(err);
|
1592
|
+
}
|
1593
|
+
else {
|
1594
|
+
th->state = TAG_RAISE;
|
1595
|
+
/*th->state = FIX2INT(rb_ivar_get(err, idThrowState));*/
|
1596
|
+
}
|
1597
|
+
return err;
|
1598
|
+
}
|
1599
|
+
}
|
1600
|
+
|
1601
|
+
static inline void
|
1602
|
+
vm_expandarray(rb_control_frame_t *cfp, VALUE ary, rb_num_t num, int flag)
|
1603
|
+
{
|
1604
|
+
int is_splat = flag & 0x01;
|
1605
|
+
rb_num_t space_size = num + is_splat;
|
1606
|
+
VALUE *base = cfp->sp, *ptr;
|
1607
|
+
volatile VALUE tmp_ary;
|
1608
|
+
rb_num_t len;
|
1609
|
+
|
1610
|
+
if (TYPE(ary) != T_ARRAY) {
|
1611
|
+
ary = rb_ary_to_ary(ary);
|
1612
|
+
}
|
1613
|
+
|
1614
|
+
cfp->sp += space_size;
|
1615
|
+
|
1616
|
+
tmp_ary = ary;
|
1617
|
+
ptr = RARRAY_PTR(ary);
|
1618
|
+
len = (rb_num_t)RARRAY_LEN(ary);
|
1619
|
+
|
1620
|
+
if (flag & 0x02) {
|
1621
|
+
/* post: ..., nil ,ary[-1], ..., ary[0..-num] # top */
|
1622
|
+
rb_num_t i = 0, j;
|
1623
|
+
|
1624
|
+
if (len < num) {
|
1625
|
+
for (i=0; i<num-len; i++) {
|
1626
|
+
*base++ = Qnil;
|
1627
|
+
}
|
1628
|
+
}
|
1629
|
+
for (j=0; i<num; i++, j++) {
|
1630
|
+
VALUE v = ptr[len - j - 1];
|
1631
|
+
*base++ = v;
|
1632
|
+
}
|
1633
|
+
if (is_splat) {
|
1634
|
+
*base = rb_ary_new4(len - j, ptr);
|
1635
|
+
}
|
1636
|
+
}
|
1637
|
+
else {
|
1638
|
+
/* normal: ary[num..-1], ary[num-2], ary[num-3], ..., ary[0] # top */
|
1639
|
+
rb_num_t i;
|
1640
|
+
VALUE *bptr = &base[space_size - 1];
|
1641
|
+
|
1642
|
+
for (i=0; i<num; i++) {
|
1643
|
+
if (len <= i) {
|
1644
|
+
for (; i<num; i++) {
|
1645
|
+
*bptr-- = Qnil;
|
1646
|
+
}
|
1647
|
+
break;
|
1648
|
+
}
|
1649
|
+
*bptr-- = ptr[i];
|
1650
|
+
}
|
1651
|
+
if (is_splat) {
|
1652
|
+
if (num > len) {
|
1653
|
+
*bptr = rb_ary_new();
|
1654
|
+
}
|
1655
|
+
else {
|
1656
|
+
*bptr = rb_ary_new4(len - num, ptr + num);
|
1657
|
+
}
|
1658
|
+
}
|
1659
|
+
}
|
1660
|
+
}
|
1661
|
+
|
1662
|
+
static inline int
|
1663
|
+
check_cfunc(const rb_method_entry_t *me, VALUE (*func)())
|
1664
|
+
{
|
1665
|
+
if (me && me->def->type == VM_METHOD_TYPE_CFUNC &&
|
1666
|
+
me->def->body.cfunc.func == func) {
|
1667
|
+
return 1;
|
1668
|
+
}
|
1669
|
+
else {
|
1670
|
+
return 0;
|
1671
|
+
}
|
1672
|
+
}
|
1673
|
+
|
1674
|
+
static
|
1675
|
+
#ifndef NO_BIG_INLINE
|
1676
|
+
inline
|
1677
|
+
#endif
|
1678
|
+
VALUE
|
1679
|
+
opt_eq_func(VALUE recv, VALUE obj, IC ic)
|
1680
|
+
{
|
1681
|
+
if (FIXNUM_2_P(recv, obj) &&
|
1682
|
+
BASIC_OP_UNREDEFINED_P(BOP_EQ)) {
|
1683
|
+
return (recv == obj) ? Qtrue : Qfalse;
|
1684
|
+
}
|
1685
|
+
else if (!SPECIAL_CONST_P(recv) && !SPECIAL_CONST_P(obj)) {
|
1686
|
+
if (HEAP_CLASS_OF(recv) == rb_cFloat &&
|
1687
|
+
HEAP_CLASS_OF(obj) == rb_cFloat &&
|
1688
|
+
BASIC_OP_UNREDEFINED_P(BOP_EQ)) {
|
1689
|
+
double a = RFLOAT_VALUE(recv);
|
1690
|
+
double b = RFLOAT_VALUE(obj);
|
1691
|
+
|
1692
|
+
if (isnan(a) || isnan(b)) {
|
1693
|
+
return Qfalse;
|
1694
|
+
}
|
1695
|
+
return (a == b) ? Qtrue : Qfalse;
|
1696
|
+
}
|
1697
|
+
else if (HEAP_CLASS_OF(recv) == rb_cString &&
|
1698
|
+
HEAP_CLASS_OF(obj) == rb_cString &&
|
1699
|
+
BASIC_OP_UNREDEFINED_P(BOP_EQ)) {
|
1700
|
+
return rb_str_equal(recv, obj);
|
1701
|
+
}
|
1702
|
+
}
|
1703
|
+
|
1704
|
+
{
|
1705
|
+
const rb_method_entry_t *me = vm_method_search(idEq, CLASS_OF(recv), ic);
|
1706
|
+
extern VALUE rb_obj_equal(VALUE obj1, VALUE obj2);
|
1707
|
+
|
1708
|
+
if (check_cfunc(me, rb_obj_equal)) {
|
1709
|
+
return recv == obj ? Qtrue : Qfalse;
|
1710
|
+
}
|
1711
|
+
}
|
1712
|
+
|
1713
|
+
return Qundef;
|
1714
|
+
}
|
1715
|
+
|
1716
|
+
struct opt_case_dispatch_i_arg {
|
1717
|
+
VALUE obj;
|
1718
|
+
int label;
|
1719
|
+
};
|
1720
|
+
|
1721
|
+
static int
|
1722
|
+
opt_case_dispatch_i(st_data_t key, st_data_t data, st_data_t p)
|
1723
|
+
{
|
1724
|
+
struct opt_case_dispatch_i_arg *arg = (void *)p;
|
1725
|
+
|
1726
|
+
if (RTEST(rb_funcall((VALUE)key, idEqq, 1, arg->obj))) {
|
1727
|
+
arg->label = FIX2INT((VALUE)data);
|
1728
|
+
return ST_STOP;
|
1729
|
+
}
|
1730
|
+
else {
|
1731
|
+
return ST_CONTINUE;
|
1732
|
+
}
|
1733
|
+
}
|
1734
|
+
|