Ruby 2.7.0p0(2019-12-25revision647ee6f091eafcce70ffb75ddf7e121e192ab217)

compile.c
Go to the documentation of this file.
1 /**********************************************************************
2
3 compile.c - ruby node tree -> VM instruction sequence
4
5 $Author$
6 created at: 04/01/01 03:42:15 JST
7
8 Copyright (C) 2004-2007 Koichi Sasada
9
10 **********************************************************************/
11
12 #include "ruby/encoding.h"
13 #include "ruby/re.h"
14 #include "ruby/util.h"
15 #include "internal.h"
16 #include "encindex.h"
17 #include <math.h>
18
19 #include "vm_core.h"
20 #include "vm_debug.h"
21 #include "builtin.h"
22 #include "iseq.h"
23 #include "insns.inc"
24 #include "insns_info.inc"
25 #include "id_table.h"
26 #include "gc.h"
27
28 #ifdef HAVE_DLADDR
29 # include <dlfcn.h>
30 #endif
31
32 #undef RUBY_UNTYPED_DATA_WARNING
33 #define RUBY_UNTYPED_DATA_WARNING 0
34
35 #define FIXNUM_INC(n, i) ((n)+(INT2FIX(i)&~FIXNUM_FLAG))
36 #define FIXNUM_OR(n, i) ((n)|INT2FIX(i))
37
38 typedef struct iseq_link_element {
39 enum {
40 ISEQ_ELEMENT_ANCHOR,
41 ISEQ_ELEMENT_LABEL,
42 ISEQ_ELEMENT_INSN,
43 ISEQ_ELEMENT_ADJUST,
44 ISEQ_ELEMENT_TRACE,
45 } type;
46 struct iseq_link_element *next;
47 struct iseq_link_element *prev;
48 } LINK_ELEMENT;
49
50 typedef struct iseq_link_anchor {
51 LINK_ELEMENT anchor;
52 LINK_ELEMENT *last;
53 } LINK_ANCHOR;
54
55 typedef enum {
56 LABEL_RESCUE_NONE,
57 LABEL_RESCUE_BEG,
58 LABEL_RESCUE_END,
59 LABEL_RESCUE_TYPE_MAX
60 } LABEL_RESCUE_TYPE;
61
62 typedef struct iseq_label_data {
63 LINK_ELEMENT link;
64 int label_no;
65 int position;
66 int sc_state;
67 int sp;
68 int refcnt;
69 unsigned int set: 1;
70 unsigned int rescued: 2;
71 unsigned int unremovable: 1;
72 } LABEL;
73
74 typedef struct iseq_insn_data {
75 LINK_ELEMENT link;
76 enum ruby_vminsn_type insn_id;
77 int operand_size;
78 int sc_state;
79 VALUE *operands;
80 struct {
81 int line_no;
82 rb_event_flag_t events;
83 } insn_info;
84 } INSN;
85
86 typedef struct iseq_adjust_data {
87 LINK_ELEMENT link;
88 LABEL *label;
89 int line_no;
90 } ADJUST;
91
92 typedef struct iseq_trace_data {
93 LINK_ELEMENT link;
94 rb_event_flag_t event;
95 long data;
96 } TRACE;
97
98 struct ensure_range {
99 LABEL *begin;
100 LABEL *end;
101 struct ensure_range *next;
102 };
103
104 struct iseq_compile_data_ensure_node_stack {
105 const NODE *ensure_node;
106 struct iseq_compile_data_ensure_node_stack *prev;
107 struct ensure_range *erange;
108 };
109
110 const ID rb_iseq_shared_exc_local_tbl[] = {idERROR_INFO};
111
125 #ifndef CPDEBUG
126 #define CPDEBUG 0
127 #endif
128
129 #if CPDEBUG >= 0
130 #define compile_debug CPDEBUG
131 #else
132 #define compile_debug ISEQ_COMPILE_DATA(iseq)->option->debug_level
133 #endif
134
135 #if CPDEBUG
136
137 #define compile_debug_print_indent(level) \
138 ruby_debug_print_indent((level), compile_debug, gl_node_level * 2)
139
140 #define debugp(header, value) (void) \
141 (compile_debug_print_indent(1) && \
142 ruby_debug_print_value(1, compile_debug, (header), (value)))
143
144 #define debugi(header, id) (void) \
145 (compile_debug_print_indent(1) && \
146 ruby_debug_print_id(1, compile_debug, (header), (id)))
147
148 #define debugp_param(header, value) (void) \
149 (compile_debug_print_indent(1) && \
150 ruby_debug_print_value(1, compile_debug, (header), (value)))
151
152 #define debugp_verbose(header, value) (void) \
153 (compile_debug_print_indent(2) && \
154 ruby_debug_print_value(2, compile_debug, (header), (value)))
155
156 #define debugp_verbose_node(header, value) (void) \
157 (compile_debug_print_indent(10) && \
158 ruby_debug_print_value(10, compile_debug, (header), (value)))
159
160 #define debug_node_start(node) ((void) \
161 (compile_debug_print_indent(1) && \
162 (ruby_debug_print_node(1, CPDEBUG, "", (const NODE *)(node)), gl_node_level)), \
163 gl_node_level++)
164
165 #define debug_node_end() gl_node_level --
166
167 #else
168
169 #define debugi(header, id) ((void)0)
170 #define debugp(header, value) ((void)0)
171 #define debugp_verbose(header, value) ((void)0)
172 #define debugp_verbose_node(header, value) ((void)0)
173 #define debugp_param(header, value) ((void)0)
174 #define debug_node_start(node) ((void)0)
175 #define debug_node_end() ((void)0)
176 #endif
177
178 #if CPDEBUG > 1 || CPDEBUG < 0
179 #define printf ruby_debug_printf
180 #define debugs if (compile_debug_print_indent(1)) ruby_debug_printf
181 #define debug_compile(msg, v) ((void)(compile_debug_print_indent(1) && fputs((msg), stderr)), (v))
182 #else
183 #define debugs if(0)printf
184 #define debug_compile(msg, v) (v)
185 #endif
186
187 #define LVAR_ERRINFO (1)
188
189 /* create new label */
190 #define NEW_LABEL(l) new_label_body(iseq, (l))
191 #define LABEL_FORMAT "<L%03d>"
192
193 #define NEW_ISEQ(node, name, type, line_no) \
194 new_child_iseq(iseq, (node), rb_fstring(name), 0, (type), (line_no))
195
196 #define NEW_CHILD_ISEQ(node, name, type, line_no) \
197 new_child_iseq(iseq, (node), rb_fstring(name), iseq, (type), (line_no))
198
199 /* add instructions */
200 #define ADD_SEQ(seq1, seq2) \
201 APPEND_LIST((seq1), (seq2))
202
203 /* add an instruction */
204 #define ADD_INSN(seq, line, insn) \
205 ADD_ELEM((seq), (LINK_ELEMENT *) new_insn_body(iseq, (line), BIN(insn), 0))
206
207 /* insert an instruction before next */
208 #define INSERT_BEFORE_INSN(next, line, insn) \
209 ELEM_INSERT_PREV(&(next)->link, (LINK_ELEMENT *) new_insn_body(iseq, (line), BIN(insn), 0))
210
211 /* insert an instruction after prev */
212 #define INSERT_AFTER_INSN(prev, line, insn) \
213 ELEM_INSERT_NEXT(&(prev)->link, (LINK_ELEMENT *) new_insn_body(iseq, (line), BIN(insn), 0))
214
215 /* add an instruction with some operands (1, 2, 3, 5) */
216 #define ADD_INSN1(seq, line, insn, op1) \
217 ADD_ELEM((seq), (LINK_ELEMENT *) \
218 new_insn_body(iseq, (line), BIN(insn), 1, (VALUE)(op1)))
219
220 /* insert an instruction with some operands (1, 2, 3, 5) before next */
221 #define INSERT_BEFORE_INSN1(next, line, insn, op1) \
222 ELEM_INSERT_PREV(&(next)->link, (LINK_ELEMENT *) \
223 new_insn_body(iseq, (line), BIN(insn), 1, (VALUE)(op1)))
224
225 /* insert an instruction with some operands (1, 2, 3, 5) after prev */
226 #define INSERT_AFTER_INSN1(prev, line, insn, op1) \
227 ELEM_INSERT_NEXT(&(prev)->link, (LINK_ELEMENT *) \
228 new_insn_body(iseq, (line), BIN(insn), 1, (VALUE)(op1)))
229
230 #define LABEL_REF(label) ((label)->refcnt++)
231
232 /* add an instruction with label operand (alias of ADD_INSN1) */
233 #define ADD_INSNL(seq, line, insn, label) (ADD_INSN1(seq, line, insn, label), LABEL_REF(label))
234
235 #define ADD_INSN2(seq, line, insn, op1, op2) \
236 ADD_ELEM((seq), (LINK_ELEMENT *) \
237 new_insn_body(iseq, (line), BIN(insn), 2, (VALUE)(op1), (VALUE)(op2)))
238
239 #define ADD_INSN3(seq, line, insn, op1, op2, op3) \
240 ADD_ELEM((seq), (LINK_ELEMENT *) \
241 new_insn_body(iseq, (line), BIN(insn), 3, (VALUE)(op1), (VALUE)(op2), (VALUE)(op3)))
242
243 /* Specific Insn factory */
244 #define ADD_SEND(seq, line, id, argc) \
245 ADD_SEND_R((seq), (line), (id), (argc), NULL, (VALUE)INT2FIX(0), NULL)
246
247 #define ADD_SEND_WITH_FLAG(seq, line, id, argc, flag) \
248 ADD_SEND_R((seq), (line), (id), (argc), NULL, (VALUE)(flag), NULL)
249
250 #define ADD_SEND_WITH_BLOCK(seq, line, id, argc, block) \
251 ADD_SEND_R((seq), (line), (id), (argc), (block), (VALUE)INT2FIX(0), NULL)
252
253 #define ADD_CALL_RECEIVER(seq, line) \
254 ADD_INSN((seq), (line), putself)
255
256 #define ADD_CALL(seq, line, id, argc) \
257 ADD_SEND_R((seq), (line), (id), (argc), NULL, (VALUE)INT2FIX(VM_CALL_FCALL), NULL)
258
259 #define ADD_CALL_WITH_BLOCK(seq, line, id, argc, block) \
260 ADD_SEND_R((seq), (line), (id), (argc), (block), (VALUE)INT2FIX(VM_CALL_FCALL), NULL)
261
262 #define ADD_SEND_R(seq, line, id, argc, block, flag, keywords) \
263 ADD_ELEM((seq), (LINK_ELEMENT *) new_insn_send(iseq, (line), (id), (VALUE)(argc), (block), (VALUE)(flag), (keywords)))
264
265 #define ADD_TRACE(seq, event) \
266 ADD_ELEM((seq), (LINK_ELEMENT *)new_trace_body(iseq, (event), 0))
267 #define ADD_TRACE_WITH_DATA(seq, event, data) \
268 ADD_ELEM((seq), (LINK_ELEMENT *)new_trace_body(iseq, (event), (data)))
269
270
271 #define DECL_BRANCH_BASE(branches, first_line, first_column, last_line, last_column, type) \
272 do { \
273 if (ISEQ_COVERAGE(iseq) && \
274 ISEQ_BRANCH_COVERAGE(iseq) && \
275 (first_line) > 0) { \
276 VALUE structure = RARRAY_AREF(ISEQ_BRANCH_COVERAGE(iseq), 0); \
277 branches = rb_ary_tmp_new(5); \
278 rb_ary_push(structure, branches); \
279 rb_ary_push(branches, ID2SYM(rb_intern(type))); \
280 rb_ary_push(branches, INT2FIX(first_line)); \
281 rb_ary_push(branches, INT2FIX(first_column)); \
282 rb_ary_push(branches, INT2FIX(last_line)); \
283 rb_ary_push(branches, INT2FIX(last_column)); \
284 } \
285 } while (0)
286 #define ADD_TRACE_BRANCH_COVERAGE(seq, first_line, first_column, last_line, last_column, type, branches) \
287 do { \
288 if (ISEQ_COVERAGE(iseq) && \
289 ISEQ_BRANCH_COVERAGE(iseq) && \
290 (first_line) > 0) { \
291 VALUE counters = RARRAY_AREF(ISEQ_BRANCH_COVERAGE(iseq), 1); \
292 long counter_idx = RARRAY_LEN(counters); \
293 rb_ary_push(counters, INT2FIX(0)); \
294 rb_ary_push(branches, ID2SYM(rb_intern(type))); \
295 rb_ary_push(branches, INT2FIX(first_line)); \
296 rb_ary_push(branches, INT2FIX(first_column)); \
297 rb_ary_push(branches, INT2FIX(last_line)); \
298 rb_ary_push(branches, INT2FIX(last_column)); \
299 rb_ary_push(branches, INT2FIX(counter_idx)); \
300 ADD_TRACE_WITH_DATA(seq, RUBY_EVENT_COVERAGE_BRANCH, counter_idx); \
301 ADD_INSN(seq, last_line, nop); \
302 } \
303 } while (0)
304
305 static void iseq_add_getlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, int line, int idx, int level);
306 static void iseq_add_setlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, int line, int idx, int level);
307
308 #define ADD_GETLOCAL(seq, line, idx, level) iseq_add_getlocal(iseq, (seq), (line), (idx), (level))
309 #define ADD_SETLOCAL(seq, line, idx, level) iseq_add_setlocal(iseq, (seq), (line), (idx), (level))
310
311 /* add label */
312 #define ADD_LABEL(seq, label) \
313 ADD_ELEM((seq), (LINK_ELEMENT *) (label))
314
315 #define APPEND_LABEL(seq, before, label) \
316 APPEND_ELEM((seq), (before), (LINK_ELEMENT *) (label))
317
318 #define ADD_ADJUST(seq, line, label) \
319 ADD_ELEM((seq), (LINK_ELEMENT *) new_adjust_body(iseq, (label), (line)))
320
321 #define ADD_ADJUST_RESTORE(seq, label) \
322 ADD_ELEM((seq), (LINK_ELEMENT *) new_adjust_body(iseq, (label), -1))
323
324 #define LABEL_UNREMOVABLE(label) \
325 ((label) ? (LABEL_REF(label), (label)->unremovable=1) : 0)
326 #define ADD_CATCH_ENTRY(type, ls, le, iseqv, lc) do { \
327 VALUE _e = rb_ary_new3(5, (type), \
328 (VALUE)(ls) | 1, (VALUE)(le) | 1, \
329 (VALUE)(iseqv), (VALUE)(lc) | 1); \
330 LABEL_UNREMOVABLE(ls); \
331 LABEL_REF(le); \
332 LABEL_REF(lc); \
333 if (NIL_P(ISEQ_COMPILE_DATA(iseq)->catch_table_ary)) \
334 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->catch_table_ary, rb_ary_tmp_new(3)); \
335 rb_ary_push(ISEQ_COMPILE_DATA(iseq)->catch_table_ary, freeze_hide_obj(_e)); \
336 } while (0)
337
338 /* compile node */
339 #define COMPILE(anchor, desc, node) \
340 (debug_compile("== " desc "\n", \
341 iseq_compile_each(iseq, (anchor), (node), 0)))
342
343 /* compile node, this node's value will be popped */
344 #define COMPILE_POPPED(anchor, desc, node) \
345 (debug_compile("== " desc "\n", \
346 iseq_compile_each(iseq, (anchor), (node), 1)))
347
348 /* compile node, which is popped when 'popped' is true */
349 #define COMPILE_(anchor, desc, node, popped) \
350 (debug_compile("== " desc "\n", \
351 iseq_compile_each(iseq, (anchor), (node), (popped))))
352
353 #define COMPILE_RECV(anchor, desc, node) \
354 (private_recv_p(node) ? \
355 (ADD_INSN(anchor, nd_line(node), putself), VM_CALL_FCALL) : \
356 COMPILE(anchor, desc, node->nd_recv) ? 0 : -1)
357
358 #define OPERAND_AT(insn, idx) \
359 (((INSN*)(insn))->operands[(idx)])
360
361 #define INSN_OF(insn) \
362 (((INSN*)(insn))->insn_id)
363
364 #define IS_INSN(link) ((link)->type == ISEQ_ELEMENT_INSN)
365 #define IS_LABEL(link) ((link)->type == ISEQ_ELEMENT_LABEL)
366 #define IS_ADJUST(link) ((link)->type == ISEQ_ELEMENT_ADJUST)
367 #define IS_TRACE(link) ((link)->type == ISEQ_ELEMENT_TRACE)
368 #define IS_INSN_ID(iobj, insn) (INSN_OF(iobj) == BIN(insn))
369 #define IS_NEXT_INSN_ID(link, insn) \
370 ((link)->next && IS_INSN((link)->next) && IS_INSN_ID((link)->next, insn))
371
372 /* error */
373 #if CPDEBUG > 0
374 NORETURN(static void append_compile_error(const rb_iseq_t *iseq, int line, const char *fmt, ...));
375 #endif
376
377 static void
378 append_compile_error(const rb_iseq_t *iseq, int line, const char *fmt, ...)
379 {
380 VALUE err_info = ISEQ_COMPILE_DATA(iseq)->err_info;
381 VALUE file = rb_iseq_path(iseq);
382 VALUE err = err_info == Qtrue ? Qfalse : err_info;
383 va_list args;
384
385 va_start(args, fmt);
386 err = rb_syntax_error_append(err, file, line, -1, NULL, fmt, args);
387 va_end(args);
388 if (NIL_P(err_info)) {
389 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->err_info, err);
390 rb_set_errinfo(err);
391 }
392 else if (!err_info) {
393 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->err_info, Qtrue);
394 }
395 if (compile_debug) {
396 if (SPECIAL_CONST_P(err)) err = rb_eSyntaxError;
397 rb_exc_fatal(err);
398 }
399 }
400
401 #if 0
402 static void
403 compile_bug(rb_iseq_t *iseq, int line, const char *fmt, ...)
404 {
405 va_list args;
406 va_start(args, fmt);
407 rb_report_bug_valist(rb_iseq_path(iseq), line, fmt, args);
408 va_end(args);
409 abort();
410 }
411 #endif
412
413 #define COMPILE_ERROR append_compile_error
414
415 #define ERROR_ARGS_AT(n) iseq, nd_line(n),
416 #define ERROR_ARGS ERROR_ARGS_AT(node)
417
418 #define EXPECT_NODE(prefix, node, ndtype, errval) \
419 do { \
420 const NODE *error_node = (node); \
421 enum node_type error_type = nd_type(error_node); \
422 if (error_type != (ndtype)) { \
423 COMPILE_ERROR(ERROR_ARGS_AT(error_node) \
424 prefix ": " #ndtype " is expected, but %s", \
425 ruby_node_name(error_type)); \
426 return errval; \
427 } \
428 } while (0)
429
430 #define EXPECT_NODE_NONULL(prefix, parent, ndtype, errval) \
431 do { \
432 COMPILE_ERROR(ERROR_ARGS_AT(parent) \
433 prefix ": must be " #ndtype ", but 0"); \
434 return errval; \
435 } while (0)
436
437 #define UNKNOWN_NODE(prefix, node, errval) \
438 do { \
439 const NODE *error_node = (node); \
440 COMPILE_ERROR(ERROR_ARGS_AT(error_node) prefix ": unknown node (%s)", \
441 ruby_node_name(nd_type(error_node))); \
442 return errval; \
443 } while (0)
444
445 #define COMPILE_OK 1
446 #define COMPILE_NG 0
447
448 #define CHECK(sub) if (!(sub)) {BEFORE_RETURN;return COMPILE_NG;}
449 #define NO_CHECK(sub) (void)(sub)
450 #define BEFORE_RETURN
451
452 /* leave name uninitialized so that compiler warn if INIT_ANCHOR is
453 * missing */
454 #define DECL_ANCHOR(name) \
455 LINK_ANCHOR name[1] = {{{ISEQ_ELEMENT_ANCHOR,},}}
456 #define INIT_ANCHOR(name) \
457 (name->last = &name->anchor)
458
459 static inline VALUE
460 freeze_hide_obj(VALUE obj)
461 {
462 OBJ_FREEZE(obj);
463 RBASIC_CLEAR_CLASS(obj);
464 return obj;
465 }
466
467 #include "optinsn.inc"
468 #if OPT_INSTRUCTIONS_UNIFICATION
469 #include "optunifs.inc"
470 #endif
471
472 /* for debug */
473 #if CPDEBUG < 0
474 #define ISEQ_ARG iseq,
475 #define ISEQ_ARG_DECLARE rb_iseq_t *iseq,
476 #else
477 #define ISEQ_ARG
478 #define ISEQ_ARG_DECLARE
479 #endif
480
481 #if CPDEBUG
482 #define gl_node_level ISEQ_COMPILE_DATA(iseq)->node_level
483 #endif
484
485 static void dump_disasm_list_with_cursor(const LINK_ELEMENT *link, const LINK_ELEMENT *curr, const LABEL *dest);
486 static void dump_disasm_list(const LINK_ELEMENT *elem);
487
488 static int insn_data_length(INSN *iobj);
489 static int calc_sp_depth(int depth, INSN *iobj);
490
491 static INSN *new_insn_body(rb_iseq_t *iseq, int line_no, enum ruby_vminsn_type insn_id, int argc, ...);
492 static LABEL *new_label_body(rb_iseq_t *iseq, long line);
493 static ADJUST *new_adjust_body(rb_iseq_t *iseq, LABEL *label, int line);
494 static TRACE *new_trace_body(rb_iseq_t *iseq, rb_event_flag_t event, long data);
495
496
497 static int iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *anchor, const NODE *n, int);
498 static int iseq_setup(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
499 static int iseq_setup_insn(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
500 static int iseq_optimize(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
501 static int iseq_insns_unification(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
502
503 static int iseq_set_local_table(rb_iseq_t *iseq, const ID *tbl);
504 static int iseq_set_exception_local_table(rb_iseq_t *iseq);
505 static int iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *const anchor, const NODE *const node);
506
507 static int iseq_set_sequence_stackcaching(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
508 static int iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
509 static int iseq_set_exception_table(rb_iseq_t *iseq);
510 static int iseq_set_optargs_table(rb_iseq_t *iseq);
511
512 static int compile_defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE needstr);
513
514 /*
515 * To make Array to LinkedList, use link_anchor
516 */
517
518 static void
519 verify_list(ISEQ_ARG_DECLARE const char *info, LINK_ANCHOR *const anchor)
520 {
521 #if CPDEBUG
522 int flag = 0;
523 LINK_ELEMENT *list, *plist;
524
525 if (!compile_debug) return;
526
527 list = anchor->anchor.next;
528 plist = &anchor->anchor;
529 while (list) {
530 if (plist != list->prev) {
531 flag += 1;
532 }
533 plist = list;
534 list = list->next;
535 }
536
537 if (anchor->last != plist && anchor->last != 0) {
538 flag |= 0x70000;
539 }
540
541 if (flag != 0) {
542 rb_bug("list verify error: %08x (%s)", flag, info);
543 }
544 #endif
545 }
546 #if CPDEBUG < 0
547 #define verify_list(info, anchor) verify_list(iseq, (info), (anchor))
548 #endif
549
550 static void
551 verify_call_cache(rb_iseq_t *iseq)
552 {
553 #if CPDEBUG
554 VALUE *original = rb_iseq_original_iseq(iseq);
555 size_t i = 0;
556 while (i < iseq->body->iseq_size) {
557 VALUE insn = original[i];
558 const char *types = insn_op_types(insn);
559
560 for (int j=0; types[j]; j++) {
561 if (types[j] == TS_CALLDATA) {
562 struct rb_call_cache cc;
563 struct rb_call_data *cd = (struct rb_call_data *)original[i+j+1];
564 MEMZERO(&cc, cc, 1);
565 if (memcmp(&cc, &cd->cc, sizeof(cc))) {
566 rb_bug("call cache not zero for fresh iseq");
567 }
568 }
569 }
570 i += insn_len(insn);
571 }
572 #endif
573 }
574
575 /*
576 * elem1, elem2 => elem1, elem2, elem
577 */
578 static void
579 ADD_ELEM(ISEQ_ARG_DECLARE LINK_ANCHOR *const anchor, LINK_ELEMENT *elem)
580 {
581 elem->prev = anchor->last;
582 anchor->last->next = elem;
583 anchor->last = elem;
584 verify_list("add", anchor);
585 }
586
587 /*
588 * elem1, before, elem2 => elem1, before, elem, elem2
589 */
590 static void
591 APPEND_ELEM(ISEQ_ARG_DECLARE LINK_ANCHOR *const anchor, LINK_ELEMENT *before, LINK_ELEMENT *elem)
592 {
593 elem->prev = before;
594 elem->next = before->next;
595 elem->next->prev = elem;
596 before->next = elem;
597 if (before == anchor->last) anchor->last = elem;
598 verify_list("add", anchor);
599 }
600 #if CPDEBUG < 0
601 #define ADD_ELEM(anchor, elem) ADD_ELEM(iseq, (anchor), (elem))
602 #define APPEND_ELEM(anchor, before, elem) APPEND_ELEM(iseq, (anchor), (before), (elem))
603 #endif
604
605 #define ISEQ_LAST_LINE(iseq) (ISEQ_COMPILE_DATA(iseq)->last_line)
606
607 static int
608 validate_label(st_data_t name, st_data_t label, st_data_t arg)
609 {
610 rb_iseq_t *iseq = (rb_iseq_t *)arg;
611 LABEL *lobj = (LABEL *)label;
612 if (!lobj->link.next) {
613 do {
614 COMPILE_ERROR(iseq, lobj->position,
615 "%"PRIsVALUE": undefined label",
616 rb_sym2str((VALUE)name));
617 } while (0);
618 }
619 return ST_CONTINUE;
620 }
621
622 static void
623 validate_labels(rb_iseq_t *iseq, st_table *labels_table)
624 {
625 st_foreach(labels_table, validate_label, (st_data_t)iseq);
626 st_free_table(labels_table);
627 }
628
629 VALUE
630 rb_iseq_compile_callback(rb_iseq_t *iseq, const struct rb_iseq_new_with_callback_callback_func * ifunc)
631 {
632 DECL_ANCHOR(ret);
633 INIT_ANCHOR(ret);
634
635 (*ifunc->func)(iseq, ret, ifunc->data);
636
637 ADD_INSN(ret, ISEQ_COMPILE_DATA(iseq)->last_line, leave);
638
639 CHECK(iseq_setup_insn(iseq, ret));
640 return iseq_setup(iseq, ret);
641 }
642
643 VALUE
644 rb_iseq_compile_node(rb_iseq_t *iseq, const NODE *node)
645 {
646 DECL_ANCHOR(ret);
647 INIT_ANCHOR(ret);
648
649 if (imemo_type_p((VALUE)node, imemo_ifunc)) {
650 rb_raise(rb_eArgError, "unexpected imemo_ifunc");
651 }
652
653 if (node == 0) {
654 NO_CHECK(COMPILE(ret, "nil", node));
655 iseq_set_local_table(iseq, 0);
656 }
657 /* assume node is T_NODE */
658 else if (nd_type(node) == NODE_SCOPE) {
659 /* iseq type of top, method, class, block */
660 iseq_set_local_table(iseq, node->nd_tbl);
661 iseq_set_arguments(iseq, ret, node->nd_args);
662
663 switch (iseq->body->type) {
664 case ISEQ_TYPE_BLOCK:
665 {
666 LABEL *start = ISEQ_COMPILE_DATA(iseq)->start_label = NEW_LABEL(0);
667 LABEL *end = ISEQ_COMPILE_DATA(iseq)->end_label = NEW_LABEL(0);
668
669 start->rescued = LABEL_RESCUE_BEG;
670 end->rescued = LABEL_RESCUE_END;
671
672 ADD_TRACE(ret, RUBY_EVENT_B_CALL);
673 ADD_INSN (ret, FIX2INT(iseq->body->location.first_lineno), nop);
674 ADD_LABEL(ret, start);
675 CHECK(COMPILE(ret, "block body", node->nd_body));
676 ADD_LABEL(ret, end);
677 ADD_TRACE(ret, RUBY_EVENT_B_RETURN);
678 ISEQ_COMPILE_DATA(iseq)->last_line = iseq->body->location.code_location.end_pos.lineno;
679
680 /* wide range catch handler must put at last */
681 ADD_CATCH_ENTRY(CATCH_TYPE_REDO, start, end, NULL, start);
682 ADD_CATCH_ENTRY(CATCH_TYPE_NEXT, start, end, NULL, end);
683 break;
684 }
685 case ISEQ_TYPE_CLASS:
686 {
687 ADD_TRACE(ret, RUBY_EVENT_CLASS);
688 CHECK(COMPILE(ret, "scoped node", node->nd_body));
689 ADD_TRACE(ret, RUBY_EVENT_END);
690 ISEQ_COMPILE_DATA(iseq)->last_line = nd_line(node);
691 break;
692 }
693 case ISEQ_TYPE_METHOD:
694 {
695 ADD_TRACE(ret, RUBY_EVENT_CALL);
696 CHECK(COMPILE(ret, "scoped node", node->nd_body));
697 ADD_TRACE(ret, RUBY_EVENT_RETURN);
698 ISEQ_COMPILE_DATA(iseq)->last_line = nd_line(node);
699 break;
700 }
701 default: {
702 CHECK(COMPILE(ret, "scoped node", node->nd_body));
703 break;
704 }
705 }
706 }
707 else {
708 const char *m;
709 #define INVALID_ISEQ_TYPE(type) \
710 ISEQ_TYPE_##type: m = #type; goto invalid_iseq_type
711 switch (iseq->body->type) {
712 case INVALID_ISEQ_TYPE(METHOD);
713 case INVALID_ISEQ_TYPE(CLASS);
714 case INVALID_ISEQ_TYPE(BLOCK);
715 case INVALID_ISEQ_TYPE(EVAL);
716 case INVALID_ISEQ_TYPE(MAIN);
717 case INVALID_ISEQ_TYPE(TOP);
718 #undef INVALID_ISEQ_TYPE /* invalid iseq types end */
719 case ISEQ_TYPE_RESCUE:
720 iseq_set_exception_local_table(iseq);
721 CHECK(COMPILE(ret, "rescue", node));
722 break;
723 case ISEQ_TYPE_ENSURE:
724 iseq_set_exception_local_table(iseq);
725 CHECK(COMPILE_POPPED(ret, "ensure", node));
726 break;
727 case ISEQ_TYPE_PLAIN:
728 CHECK(COMPILE(ret, "ensure", node));
729 break;
730 default:
731 COMPILE_ERROR(ERROR_ARGS "unknown scope: %d", iseq->body->type);
732 return COMPILE_NG;
733 invalid_iseq_type:
734 COMPILE_ERROR(ERROR_ARGS "compile/ISEQ_TYPE_%s should not be reached", m);
735 return COMPILE_NG;
736 }
737 }
738
739 if (iseq->body->type == ISEQ_TYPE_RESCUE || iseq->body->type == ISEQ_TYPE_ENSURE) {
740 ADD_GETLOCAL(ret, 0, LVAR_ERRINFO, 0);
741 ADD_INSN1(ret, 0, throw, INT2FIX(0) /* continue throw */ );
742 }
743 else {
744 ADD_INSN(ret, ISEQ_COMPILE_DATA(iseq)->last_line, leave);
745 }
746
747 #if OPT_SUPPORT_JOKE
748 if (ISEQ_COMPILE_DATA(iseq)->labels_table) {
749 st_table *labels_table = ISEQ_COMPILE_DATA(iseq)->labels_table;
750 ISEQ_COMPILE_DATA(iseq)->labels_table = 0;
751 validate_labels(iseq, labels_table);
752 }
753 #endif
754 CHECK(iseq_setup_insn(iseq, ret));
755 return iseq_setup(iseq, ret);
756 }
757
758 static int
759 rb_iseq_translate_threaded_code(rb_iseq_t *iseq)
760 {
761 #if OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE
762 const void * const *table = rb_vm_get_insns_address_table();
763 unsigned int i;
764 VALUE *encoded = (VALUE *)iseq->body->iseq_encoded;
765
766 for (i = 0; i < iseq->body->iseq_size; /* */ ) {
767 int insn = (int)iseq->body->iseq_encoded[i];
768 int len = insn_len(insn);
769 encoded[i] = (VALUE)table[insn];
770 i += len;
771 }
772 FL_SET(iseq, ISEQ_TRANSLATED);
773 #endif
774 return COMPILE_OK;
775 }
776
777 VALUE *
778 rb_iseq_original_iseq(const rb_iseq_t *iseq) /* cold path */
779 {
780 VALUE *original_code;
781
782 if (ISEQ_ORIGINAL_ISEQ(iseq)) return ISEQ_ORIGINAL_ISEQ(iseq);
783 original_code = ISEQ_ORIGINAL_ISEQ_ALLOC(iseq, iseq->body->iseq_size);
784 MEMCPY(original_code, iseq->body->iseq_encoded, VALUE, iseq->body->iseq_size);
785
786 #if OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE
787 {
788 unsigned int i;
789
790 for (i = 0; i < iseq->body->iseq_size; /* */ ) {
791 const void *addr = (const void *)original_code[i];
792 const int insn = rb_vm_insn_addr2insn(addr);
793
794 original_code[i] = insn;
795 i += insn_len(insn);
796 }
797 }
798 #endif
799 return original_code;
800 }
801
802 /*********************************************/
803 /* definition of data structure for compiler */
804 /*********************************************/
805
806 /*
807 * On 32-bit SPARC, GCC by default generates SPARC V7 code that may require
808 * 8-byte word alignment. On the other hand, Oracle Solaris Studio seems to
809 * generate SPARCV8PLUS code with unaligned memory access instructions.
810 * That is why the STRICT_ALIGNMENT is defined only with GCC.
811 */
812 #if defined(__sparc) && SIZEOF_VOIDP == 4 && defined(__GNUC__)
813 #define STRICT_ALIGNMENT
814 #endif
815
816 #ifdef STRICT_ALIGNMENT
817 #if defined(HAVE_TRUE_LONG_LONG) && SIZEOF_LONG_LONG > SIZEOF_VALUE
818 #define ALIGNMENT_SIZE SIZEOF_LONG_LONG
819 #else
820 #define ALIGNMENT_SIZE SIZEOF_VALUE
821 #endif
822 #define PADDING_SIZE_MAX ((size_t)((ALIGNMENT_SIZE) - 1))
823 #define ALIGNMENT_SIZE_MASK PADDING_SIZE_MAX
824 /* Note: ALIGNMENT_SIZE == (2 ** N) is expected. */
825 #else
826 #define PADDING_SIZE_MAX 0
827 #endif /* STRICT_ALIGNMENT */
828
829 #ifdef STRICT_ALIGNMENT
830 /* calculate padding size for aligned memory access */
831 static size_t
832 calc_padding(void *ptr, size_t size)
833 {
834 size_t mis;
835 size_t padding = 0;
836
837 mis = (size_t)ptr & ALIGNMENT_SIZE_MASK;
838 if (mis > 0) {
839 padding = ALIGNMENT_SIZE - mis;
840 }
841 /*
842 * On 32-bit sparc or equivalents, when a single VALUE is requested
843 * and padding == sizeof(VALUE), it is clear that no padding is needed.
844 */
845 #if ALIGNMENT_SIZE > SIZEOF_VALUE
846 if (size == sizeof(VALUE) && padding == sizeof(VALUE)) {
847 padding = 0;
848 }
849 #endif
850
851 return padding;
852 }
853 #endif /* STRICT_ALIGNMENT */
854
855 static void *
856 compile_data_alloc_with_arena(struct iseq_compile_data_storage **arena, size_t size)
857 {
858 void *ptr = 0;
859 struct iseq_compile_data_storage *storage = *arena;
860 #ifdef STRICT_ALIGNMENT
861 size_t padding = calc_padding((void *)&storage->buff[storage->pos], size);
862 #else
863 const size_t padding = 0; /* expected to be optimized by compiler */
864 #endif /* STRICT_ALIGNMENT */
865
866 if (size >= INT_MAX - padding) rb_memerror();
867 if (storage->pos + size + padding > storage->size) {
868 unsigned int alloc_size = storage->size;
869
870 while (alloc_size < size + PADDING_SIZE_MAX) {
871 if (alloc_size >= INT_MAX / 2) rb_memerror();
872 alloc_size *= 2;
873 }
874 storage->next = (void *)ALLOC_N(char, alloc_size +
875 offsetof(struct iseq_compile_data_storage, buff));
876 storage = *arena = storage->next;
877 storage->next = 0;
878 storage->pos = 0;
879 storage->size = alloc_size;
880 #ifdef STRICT_ALIGNMENT
881 padding = calc_padding((void *)&storage->buff[storage->pos], size);
882 #endif /* STRICT_ALIGNMENT */
883 }
884
885 #ifdef STRICT_ALIGNMENT
886 storage->pos += (int)padding;
887 #endif /* STRICT_ALIGNMENT */
888
889 ptr = (void *)&storage->buff[storage->pos];
890 storage->pos += (int)size;
891 return ptr;
892 }
893
894 static void *
895 compile_data_alloc(rb_iseq_t *iseq, size_t size)
896 {
897 struct iseq_compile_data_storage ** arena = &ISEQ_COMPILE_DATA(iseq)->node.storage_current;
898 return compile_data_alloc_with_arena(arena, size);
899 }
900
901 static inline void *
902 compile_data_alloc2(rb_iseq_t *iseq, size_t x, size_t y)
903 {
904 size_t size = rb_size_mul_or_raise(x, y, rb_eRuntimeError);
905 return compile_data_alloc(iseq, size);
906 }
907
908 static INSN *
909 compile_data_alloc_insn(rb_iseq_t *iseq)
910 {
911 struct iseq_compile_data_storage ** arena = &ISEQ_COMPILE_DATA(iseq)->insn.storage_current;
912 return (INSN *)compile_data_alloc_with_arena(arena, sizeof(INSN));
913 }
914
915 static LABEL *
916 compile_data_alloc_label(rb_iseq_t *iseq)
917 {
918 return (LABEL *)compile_data_alloc(iseq, sizeof(LABEL));
919 }
920
921 static ADJUST *
922 compile_data_alloc_adjust(rb_iseq_t *iseq)
923 {
924 return (ADJUST *)compile_data_alloc(iseq, sizeof(ADJUST));
925 }
926
927 static TRACE *
928 compile_data_alloc_trace(rb_iseq_t *iseq)
929 {
930 return (TRACE *)compile_data_alloc(iseq, sizeof(TRACE));
931 }
932
933 /*
934 * elem1, elemX => elem1, elem2, elemX
935 */
936 static void
937 ELEM_INSERT_NEXT(LINK_ELEMENT *elem1, LINK_ELEMENT *elem2)
938 {
939 elem2->next = elem1->next;
940 elem2->prev = elem1;
941 elem1->next = elem2;
942 if (elem2->next) {
943 elem2->next->prev = elem2;
944 }
945 }
946
947 /*
948 * elem1, elemX => elemX, elem2, elem1
949 */
950 static void
951 ELEM_INSERT_PREV(LINK_ELEMENT *elem1, LINK_ELEMENT *elem2)
952 {
953 elem2->prev = elem1->prev;
954 elem2->next = elem1;
955 elem1->prev = elem2;
956 if (elem2->prev) {
957 elem2->prev->next = elem2;
958 }
959 }
960
961 /*
962 * elemX, elem1, elemY => elemX, elem2, elemY
963 */
964 static void
965 ELEM_REPLACE(LINK_ELEMENT *elem1, LINK_ELEMENT *elem2)
966 {
967 elem2->prev = elem1->prev;
968 elem2->next = elem1->next;
969 if (elem1->prev) {
970 elem1->prev->next = elem2;
971 }
972 if (elem1->next) {
973 elem1->next->prev = elem2;
974 }
975 }
976
977 static void
978 ELEM_REMOVE(LINK_ELEMENT *elem)
979 {
980 elem->prev->next = elem->next;
981 if (elem->next) {
982 elem->next->prev = elem->prev;
983 }
984 }
985
986 static LINK_ELEMENT *
987 FIRST_ELEMENT(const LINK_ANCHOR *const anchor)
988 {
989 return anchor->anchor.next;
990 }
991
992 static LINK_ELEMENT *
993 LAST_ELEMENT(LINK_ANCHOR *const anchor)
994 {
995 return anchor->last;
996 }
997
998 static LINK_ELEMENT *
999 POP_ELEMENT(ISEQ_ARG_DECLARE LINK_ANCHOR *const anchor)
1000 {
1001 LINK_ELEMENT *elem = anchor->last;
1002 anchor->last = anchor->last->prev;
1003 anchor->last->next = 0;
1004 verify_list("pop", anchor);
1005 return elem;
1006 }
1007 #if CPDEBUG < 0
1008 #define POP_ELEMENT(anchor) POP_ELEMENT(iseq, (anchor))
1009 #endif
1010
1011 static LINK_ELEMENT *
1012 ELEM_FIRST_INSN(LINK_ELEMENT *elem)
1013 {
1014 while (elem) {
1015 switch (elem->type) {
1016 case ISEQ_ELEMENT_INSN:
1017 case ISEQ_ELEMENT_ADJUST:
1018 return elem;
1019 default:
1020 elem = elem->next;
1021 }
1022 }
1023 return NULL;
1024 }
1025
1026 static int
1027 LIST_INSN_SIZE_ONE(const LINK_ANCHOR *const anchor)
1028 {
1029 LINK_ELEMENT *first_insn = ELEM_FIRST_INSN(FIRST_ELEMENT(anchor));
1030 if (first_insn != NULL &&
1031 ELEM_FIRST_INSN(first_insn->next) == NULL) {
1032 return TRUE;
1033 }
1034 else {
1035 return FALSE;
1036 }
1037 }
1038
1039 static int
1040 LIST_INSN_SIZE_ZERO(const LINK_ANCHOR *const anchor)
1041 {
1042 if (ELEM_FIRST_INSN(FIRST_ELEMENT(anchor)) == NULL) {
1043 return TRUE;
1044 }
1045 else {
1046 return FALSE;
1047 }
1048 }
1049
1050 /*
1051 * anc1: e1, e2, e3
1052 * anc2: e4, e5
1053 *#=>
1054 * anc1: e1, e2, e3, e4, e5
1055 * anc2: e4, e5 (broken)
1056 */
1057 static void
1058 APPEND_LIST(ISEQ_ARG_DECLARE LINK_ANCHOR *const anc1, LINK_ANCHOR *const anc2)
1059 {
1060 if (anc2->anchor.next) {
1061 anc1->last->next = anc2->anchor.next;
1062 anc2->anchor.next->prev = anc1->last;
1063 anc1->last = anc2->last;
1064 }
1065 verify_list("append", anc1);
1066 }
1067 #if CPDEBUG < 0
1068 #define APPEND_LIST(anc1, anc2) APPEND_LIST(iseq, (anc1), (anc2))
1069 #endif
1070
1071 #if CPDEBUG && 0
1072 static void
1073 debug_list(ISEQ_ARG_DECLARE LINK_ANCHOR *const anchor)
1074 {
1075 LINK_ELEMENT *list = FIRST_ELEMENT(anchor);
1076 printf("----\n");
1077 printf("anch: %p, frst: %p, last: %p\n", &anchor->anchor,
1078 anchor->anchor.next, anchor->last);
1079 while (list) {
1080 printf("curr: %p, next: %p, prev: %p, type: %d\n", list, list->next,
1081 list->prev, FIX2INT(list->type));
1082 list = list->next;
1083 }
1084 printf("----\n");
1085
1086 dump_disasm_list(anchor->anchor.next);
1087 verify_list("debug list", anchor);
1088 }
1089 #if CPDEBUG < 0
1090 #define debug_list(anc) debug_list(iseq, (anc))
1091 #endif
1092 #else
1093 #define debug_list(anc) ((void)0)
1094 #endif
1095
1096 static TRACE *
1097 new_trace_body(rb_iseq_t *iseq, rb_event_flag_t event, long data)
1098 {
1099 TRACE *trace = compile_data_alloc_trace(iseq);
1100
1101 trace->link.type = ISEQ_ELEMENT_TRACE;
1102 trace->link.next = NULL;
1103 trace->event = event;
1104 trace->data = data;
1105
1106 return trace;
1107 }
1108
1109 static LABEL *
1110 new_label_body(rb_iseq_t *iseq, long line)
1111 {
1112 LABEL *labelobj = compile_data_alloc_label(iseq);
1113
1114 labelobj->link.type = ISEQ_ELEMENT_LABEL;
1115 labelobj->link.next = 0;
1116
1117 labelobj->label_no = ISEQ_COMPILE_DATA(iseq)->label_no++;
1118 labelobj->sc_state = 0;
1119 labelobj->sp = -1;
1120 labelobj->refcnt = 0;
1121 labelobj->set = 0;
1122 labelobj->rescued = LABEL_RESCUE_NONE;
1123 labelobj->unremovable = 0;
1124 return labelobj;
1125 }
1126
1127 static ADJUST *
1128 new_adjust_body(rb_iseq_t *iseq, LABEL *label, int line)
1129 {
1130 ADJUST *adjust = compile_data_alloc_adjust(iseq);
1131 adjust->link.type = ISEQ_ELEMENT_ADJUST;
1132 adjust->link.next = 0;
1133 adjust->label = label;
1134 adjust->line_no = line;
1135 LABEL_UNREMOVABLE(label);
1136 return adjust;
1137 }
1138
1139 static INSN *
1140 new_insn_core(rb_iseq_t *iseq, int line_no,
1141 int insn_id, int argc, VALUE *argv)
1142 {
1143 INSN *iobj = compile_data_alloc_insn(iseq);
1144
1145 /* printf("insn_id: %d, line: %d\n", insn_id, line_no); */
1146
1147 iobj->link.type = ISEQ_ELEMENT_INSN;
1148 iobj->link.next = 0;
1149 iobj->insn_id = insn_id;
1150 iobj->insn_info.line_no = line_no;
1151 iobj->insn_info.events = 0;
1152 iobj->operands = argv;
1153 iobj->operand_size = argc;
1154 iobj->sc_state = 0;
1155 return iobj;
1156 }
1157
1158 static INSN *
1159 new_insn_body(rb_iseq_t *iseq, int line_no, enum ruby_vminsn_type insn_id, int argc, ...)
1160 {
1161 VALUE *operands = 0;
1162 va_list argv;
1163 if (argc > 0) {
1164 int i;
1165 va_init_list(argv, argc);
1166 operands = compile_data_alloc2(iseq, sizeof(VALUE), argc);
1167 for (i = 0; i < argc; i++) {
1168 VALUE v = va_arg(argv, VALUE);
1169 operands[i] = v;
1170 }
1171 va_end(argv);
1172 }
1173 return new_insn_core(iseq, line_no, insn_id, argc, operands);
1174 }
1175
1176 static struct rb_call_info *
1177 new_callinfo(rb_iseq_t *iseq, ID mid, int argc, unsigned int flag, struct rb_call_info_kw_arg *kw_arg, int has_blockiseq)
1178 {
1179 size_t size = kw_arg != NULL ? sizeof(struct rb_call_info_with_kwarg) : sizeof(struct rb_call_info);
1180 struct rb_call_info *ci = (struct rb_call_info *)compile_data_alloc(iseq, size);
1181 struct rb_call_info_with_kwarg *ci_kw = (struct rb_call_info_with_kwarg *)ci;
1182
1183 ci->mid = mid;
1184 ci->flag = flag;
1185 ci->orig_argc = argc;
1186
1187 if (kw_arg) {
1188 ci->flag |= VM_CALL_KWARG;
1189 ci_kw->kw_arg = kw_arg;
1190 ci->orig_argc += kw_arg->keyword_len;
1191 iseq->body->ci_kw_size++;
1192 }
1193 else {
1194 iseq->body->ci_size++;
1195 }
1196
1197 if (!(ci->flag & (VM_CALL_ARGS_SPLAT | VM_CALL_ARGS_BLOCKARG | VM_CALL_KW_SPLAT)) &&
1198 kw_arg == NULL && !has_blockiseq) {
1199 ci->flag |= VM_CALL_ARGS_SIMPLE;
1200 }
1201 return ci;
1202 }
1203
1204 static INSN *
1205 new_insn_send(rb_iseq_t *iseq, int line_no, ID id, VALUE argc, const rb_iseq_t *blockiseq, VALUE flag, struct rb_call_info_kw_arg *keywords)
1206 {
1207 VALUE *operands = compile_data_alloc2(iseq, sizeof(VALUE), 2);
1208 operands[0] = (VALUE)new_callinfo(iseq, id, FIX2INT(argc), FIX2INT(flag), keywords, blockiseq != NULL);
1209 operands[1] = (VALUE)blockiseq;
1210 return new_insn_core(iseq, line_no, BIN(send), 2, operands);
1211 }
1212
1213 static rb_iseq_t *
1214 new_child_iseq(rb_iseq_t *iseq, const NODE *const node,
1215 VALUE name, const rb_iseq_t *parent, enum iseq_type type, int line_no)
1216 {
1217 rb_iseq_t *ret_iseq;
1218 rb_ast_body_t ast;
1219
1220 ast.root = node;
1221 ast.compile_option = 0;
1222 ast.line_count = -1;
1223
1224 debugs("[new_child_iseq]> ---------------------------------------\n");
1225 ret_iseq = rb_iseq_new_with_opt(&ast, name,
1226 rb_iseq_path(iseq), rb_iseq_realpath(iseq),
1227 INT2FIX(line_no), parent, type, ISEQ_COMPILE_DATA(iseq)->option);
1228 debugs("[new_child_iseq]< ---------------------------------------\n");
1229 return ret_iseq;
1230 }
1231
1232 static rb_iseq_t *
1233 new_child_iseq_with_callback(rb_iseq_t *iseq, const struct rb_iseq_new_with_callback_callback_func *ifunc,
1234 VALUE name, const rb_iseq_t *parent, enum iseq_type type, int line_no)
1235 {
1236 rb_iseq_t *ret_iseq;
1237
1238 debugs("[new_child_iseq_with_callback]> ---------------------------------------\n");
1239 ret_iseq = rb_iseq_new_with_callback(ifunc, name,
1240 rb_iseq_path(iseq), rb_iseq_realpath(iseq),
1241 INT2FIX(line_no), parent, type, ISEQ_COMPILE_DATA(iseq)->option);
1242 debugs("[new_child_iseq_with_callback]< ---------------------------------------\n");
1243 return ret_iseq;
1244 }
1245
1246 static void
1247 set_catch_except_p(struct rb_iseq_constant_body *body)
1248 {
1249 body->catch_except_p = TRUE;
1250 if (body->parent_iseq != NULL) {
1251 set_catch_except_p(body->parent_iseq->body);
1252 }
1253 }
1254
1255 /* Set body->catch_except_p to TRUE if the ISeq may catch an exception. If it is FALSE,
1256 JIT-ed code may be optimized. If we are extremely conservative, we should set TRUE
1257 if catch table exists. But we want to optimize while loop, which always has catch
1258 table entries for break/next/redo.
1259
1260 So this function sets TRUE for limited ISeqs with break/next/redo catch table entries
1261 whose child ISeq would really raise an exception. */
1262 static void
1263 update_catch_except_flags(struct rb_iseq_constant_body *body)
1264 {
1265 unsigned int pos;
1266 size_t i;
1267 int insn;
1268 const struct iseq_catch_table *ct = body->catch_table;
1269
1270 /* This assumes that a block has parent_iseq which may catch an exception from the block, and that
1271 BREAK/NEXT/REDO catch table entries are used only when `throw` insn is used in the block. */
1272 pos = 0;
1273 while (pos < body->iseq_size) {
1274 #if OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE
1275 insn = rb_vm_insn_addr2insn((void *)body->iseq_encoded[pos]);
1276 #else
1277 insn = (int)body->iseq_encoded[pos];
1278 #endif
1279 if (insn == BIN(throw)) {
1280 set_catch_except_p(body);
1281 break;
1282 }
1283 pos += insn_len(insn);
1284 }
1285
1286 if (ct == NULL)
1287 return;
1288
1289 for (i = 0; i < ct->size; i++) {
1290 const struct iseq_catch_table_entry *entry =
1291 UNALIGNED_MEMBER_PTR(ct, entries[i]);
1292 if (entry->type != CATCH_TYPE_BREAK
1293 && entry->type != CATCH_TYPE_NEXT
1294 && entry->type != CATCH_TYPE_REDO) {
1295 body->catch_except_p = TRUE;
1296 break;
1297 }
1298 }
1299 }
1300
1301 static void
1302 iseq_insert_nop_between_end_and_cont(rb_iseq_t *iseq)
1303 {
1304 VALUE catch_table_ary = ISEQ_COMPILE_DATA(iseq)->catch_table_ary;
1305 if (NIL_P(catch_table_ary)) return;
1306 unsigned int i, tlen = (unsigned int)RARRAY_LEN(catch_table_ary);
1307 const VALUE *tptr = RARRAY_CONST_PTR_TRANSIENT(catch_table_ary);
1308 for (i = 0; i < tlen; i++) {
1309 const VALUE *ptr = RARRAY_CONST_PTR_TRANSIENT(tptr[i]);
1310 LINK_ELEMENT *end = (LINK_ELEMENT *)(ptr[2] & ~1);
1311 LINK_ELEMENT *cont = (LINK_ELEMENT *)(ptr[4] & ~1);
1312 LINK_ELEMENT *e;
1313 for (e = end; e && (IS_LABEL(e) || IS_TRACE(e)); e = e->next) {
1314 if (e == cont) {
1315 INSN *nop = new_insn_core(iseq, 0, BIN(nop), 0, 0);
1316 ELEM_INSERT_NEXT(end, &nop->link);
1317 break;
1318 }
1319 }
1320 }
1321 }
1322
1323 static int
1324 iseq_setup_insn(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
1325 {
1326 if (RTEST(ISEQ_COMPILE_DATA(iseq)->err_info))
1327 return COMPILE_NG;
1328
1329 /* debugs("[compile step 2] (iseq_array_to_linkedlist)\n"); */
1330
1331 if (compile_debug > 5)
1332 dump_disasm_list(FIRST_ELEMENT(anchor));
1333
1334 debugs("[compile step 3.1 (iseq_optimize)]\n");
1335 iseq_optimize(iseq, anchor);
1336
1337 if (compile_debug > 5)
1338 dump_disasm_list(FIRST_ELEMENT(anchor));
1339
1340 if (ISEQ_COMPILE_DATA(iseq)->option->instructions_unification) {
1341 debugs("[compile step 3.2 (iseq_insns_unification)]\n");
1342 iseq_insns_unification(iseq, anchor);
1343 if (compile_debug > 5)
1344 dump_disasm_list(FIRST_ELEMENT(anchor));
1345 }
1346
1347 if (ISEQ_COMPILE_DATA(iseq)->option->stack_caching) {
1348 debugs("[compile step 3.3 (iseq_set_sequence_stackcaching)]\n");
1349 iseq_set_sequence_stackcaching(iseq, anchor);
1350 if (compile_debug > 5)
1351 dump_disasm_list(FIRST_ELEMENT(anchor));
1352 }
1353
1354 debugs("[compile step 3.4 (iseq_insert_nop_between_end_and_cont)]\n");
1355 iseq_insert_nop_between_end_and_cont(iseq);
1356
1357 return COMPILE_OK;
1358 }
1359
1360 static int
1361 iseq_setup(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
1362 {
1363 if (RTEST(ISEQ_COMPILE_DATA(iseq)->err_info))
1364 return COMPILE_NG;
1365
1366 debugs("[compile step 4.1 (iseq_set_sequence)]\n");
1367 if (!iseq_set_sequence(iseq, anchor)) return COMPILE_NG;
1368 if (compile_debug > 5)
1369 dump_disasm_list(FIRST_ELEMENT(anchor));
1370
1371 debugs("[compile step 4.2 (iseq_set_exception_table)]\n");
1372 if (!iseq_set_exception_table(iseq)) return COMPILE_NG;
1373
1374 debugs("[compile step 4.3 (set_optargs_table)] \n");
1375 if (!iseq_set_optargs_table(iseq)) return COMPILE_NG;
1376
1377 debugs("[compile step 5 (iseq_translate_threaded_code)] \n");
1378 if (!rb_iseq_translate_threaded_code(iseq)) return COMPILE_NG;
1379
1380 update_catch_except_flags(iseq->body);
1381
1382 if (compile_debug > 1) {
1383 VALUE str = rb_iseq_disasm(iseq);
1384 printf("%s\n", StringValueCStr(str));
1385 }
1386 verify_call_cache(iseq);
1387 debugs("[compile step: finish]\n");
1388
1389 return COMPILE_OK;
1390 }
1391
1392 static int
1393 iseq_set_exception_local_table(rb_iseq_t *iseq)
1394 {
1395 iseq->body->local_table_size = numberof(rb_iseq_shared_exc_local_tbl);
1396 iseq->body->local_table = rb_iseq_shared_exc_local_tbl;
1397 return COMPILE_OK;
1398 }
1399
1400 static int
1401 get_lvar_level(const rb_iseq_t *iseq)
1402 {
1403 int lev = 0;
1404 while (iseq != iseq->body->local_iseq) {
1405 lev++;
1406 iseq = iseq->body->parent_iseq;
1407 }
1408 return lev;
1409 }
1410
1411 static int
1412 get_dyna_var_idx_at_raw(const rb_iseq_t *iseq, ID id)
1413 {
1414 unsigned int i;
1415
1416 for (i = 0; i < iseq->body->local_table_size; i++) {
1417 if (iseq->body->local_table[i] == id) {
1418 return (int)i;
1419 }
1420 }
1421 return -1;
1422 }
1423
1424 static int
1425 get_local_var_idx(const rb_iseq_t *iseq, ID id)
1426 {
1427 int idx = get_dyna_var_idx_at_raw(iseq->body->local_iseq, id);
1428
1429 if (idx < 0) {
1430 COMPILE_ERROR(iseq, ISEQ_LAST_LINE(iseq),
1431 "get_local_var_idx: %d", idx);
1432 }
1433
1434 return idx;
1435 }
1436
1437 static int
1438 get_dyna_var_idx(const rb_iseq_t *iseq, ID id, int *level, int *ls)
1439 {
1440 int lv = 0, idx = -1;
1441 const rb_iseq_t *const topmost_iseq = iseq;
1442
1443 while (iseq) {
1444 idx = get_dyna_var_idx_at_raw(iseq, id);
1445 if (idx >= 0) {
1446 break;
1447 }
1448 iseq = iseq->body->parent_iseq;
1449 lv++;
1450 }
1451
1452 if (idx < 0) {
1453 COMPILE_ERROR(topmost_iseq, ISEQ_LAST_LINE(topmost_iseq),
1454 "get_dyna_var_idx: -1");
1455 }
1456
1457 *level = lv;
1458 *ls = iseq->body->local_table_size;
1459 return idx;
1460 }
1461
1462 static int
1463 iseq_local_block_param_p(const rb_iseq_t *iseq, unsigned int idx, unsigned int level)
1464 {
1465 const struct rb_iseq_constant_body *body;
1466 while (level > 0) {
1467 iseq = iseq->body->parent_iseq;
1468 level--;
1469 }
1470 body = iseq->body;
1471 if (body->local_iseq == iseq && /* local variables */
1472 body->param.flags.has_block &&
1473 body->local_table_size - body->param.block_start == idx) {
1474 return TRUE;
1475 }
1476 else {
1477 return FALSE;
1478 }
1479 }
1480
1481 static int
1482 iseq_block_param_id_p(const rb_iseq_t *iseq, ID id, int *pidx, int *plevel)
1483 {
1484 int level, ls;
1485 int idx = get_dyna_var_idx(iseq, id, &level, &ls);
1486 if (iseq_local_block_param_p(iseq, ls - idx, level)) {
1487 *pidx = ls - idx;
1488 *plevel = level;
1489 return TRUE;
1490 }
1491 else {
1492 return FALSE;
1493 }
1494 }
1495
1496 static void
1497 iseq_add_getlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, int line, int idx, int level)
1498 {
1499 if (iseq_local_block_param_p(iseq, idx, level)) {
1500 ADD_INSN2(seq, line, getblockparam, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1501 }
1502 else {
1503 ADD_INSN2(seq, line, getlocal, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1504 }
1505 }
1506
1507 static void
1508 iseq_add_setlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, int line, int idx, int level)
1509 {
1510 if (iseq_local_block_param_p(iseq, idx, level)) {
1511 ADD_INSN2(seq, line, setblockparam, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1512 }
1513 else {
1514 ADD_INSN2(seq, line, setlocal, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1515 }
1516 }
1517
1518
1519
1520 static void
1521 iseq_calc_param_size(rb_iseq_t *iseq)
1522 {
1523 struct rb_iseq_constant_body *const body = iseq->body;
1524 if (body->param.flags.has_opt ||
1525 body->param.flags.has_post ||
1526 body->param.flags.has_rest ||
1527 body->param.flags.has_block ||
1528 body->param.flags.has_kw ||
1529 body->param.flags.has_kwrest) {
1530
1531 if (body->param.flags.has_block) {
1532 body->param.size = body->param.block_start + 1;
1533 }
1534 else if (body->param.flags.has_kwrest) {
1535 body->param.size = body->param.keyword->rest_start + 1;
1536 }
1537 else if (body->param.flags.has_kw) {
1538 body->param.size = body->param.keyword->bits_start + 1;
1539 }
1540 else if (body->param.flags.has_post) {
1541 body->param.size = body->param.post_start + body->param.post_num;
1542 }
1543 else if (body->param.flags.has_rest) {
1544 body->param.size = body->param.rest_start + 1;
1545 }
1546 else if (body->param.flags.has_opt) {
1547 body->param.size = body->param.lead_num + body->param.opt_num;
1548 }
1549 else {
1550 UNREACHABLE;
1551 }
1552 }
1553 else {
1554 body->param.size = body->param.lead_num;
1555 }
1556 }
1557
1558 static int
1559 iseq_set_arguments_keywords(rb_iseq_t *iseq, LINK_ANCHOR *const optargs,
1560 const struct rb_args_info *args, int arg_size)
1561 {
1562 const NODE *node = args->kw_args;
1563 struct rb_iseq_constant_body *const body = iseq->body;
1564 struct rb_iseq_param_keyword *keyword;
1565 const VALUE default_values = rb_ary_tmp_new(1);
1566 const VALUE complex_mark = rb_str_tmp_new(0);
1567 int kw = 0, rkw = 0, di = 0, i;
1568
1569 body->param.flags.has_kw = TRUE;
1570 body->param.keyword = keyword = ZALLOC_N(struct rb_iseq_param_keyword, 1);
1571
1572 while (node) {
1573 kw++;
1574 node = node->nd_next;
1575 }
1576 arg_size += kw;
1577 keyword->bits_start = arg_size++;
1578
1579 node = args->kw_args;
1580 while (node) {
1581 const NODE *val_node = node->nd_body->nd_value;
1582 VALUE dv;
1583
1584 if (val_node == NODE_SPECIAL_REQUIRED_KEYWORD) {
1585 ++rkw;
1586 }
1587 else {
1588 switch (nd_type(val_node)) {
1589 case NODE_LIT:
1590 dv = val_node->nd_lit;
1591 break;
1592 case NODE_NIL:
1593 dv = Qnil;
1594 break;
1595 case NODE_TRUE:
1596 dv = Qtrue;
1597 break;
1598 case NODE_FALSE:
1599 dv = Qfalse;
1600 break;
1601 default:
1602 NO_CHECK(COMPILE_POPPED(optargs, "kwarg", node)); /* nd_type(node) == NODE_KW_ARG */
1603 dv = complex_mark;
1604 }
1605
1606 keyword->num = ++di;
1607 rb_ary_push(default_values, dv);
1608 }
1609
1610 node = node->nd_next;
1611 }
1612
1613 keyword->num = kw;
1614
1615 if (args->kw_rest_arg->nd_vid != 0) {
1616 keyword->rest_start = arg_size++;
1617 body->param.flags.has_kwrest = TRUE;
1618 }
1619 keyword->required_num = rkw;
1620 keyword->table = &body->local_table[keyword->bits_start - keyword->num];
1621
1622 {
1623 VALUE *dvs = ALLOC_N(VALUE, RARRAY_LEN(default_values));
1624
1625 for (i = 0; i < RARRAY_LEN(default_values); i++) {
1626 VALUE dv = RARRAY_AREF(default_values, i);
1627 if (dv == complex_mark) dv = Qundef;
1628 if (!SPECIAL_CONST_P(dv)) {
1629 RB_OBJ_WRITTEN(iseq, Qundef, dv);
1630 }
1631 dvs[i] = dv;
1632 }
1633
1634 keyword->default_values = dvs;
1635 }
1636 return arg_size;
1637 }
1638
1639 static int
1640 iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *const optargs, const NODE *const node_args)
1641 {
1642 debugs("iseq_set_arguments: %s\n", node_args ? "" : "0");
1643
1644 if (node_args) {
1645 struct rb_iseq_constant_body *const body = iseq->body;
1646 struct rb_args_info *args = node_args->nd_ainfo;
1647 ID rest_id = 0;
1648 int last_comma = 0;
1649 ID block_id = 0;
1650 int arg_size;
1651
1652 EXPECT_NODE("iseq_set_arguments", node_args, NODE_ARGS, COMPILE_NG);
1653
1654 body->param.flags.ruby2_keywords = args->ruby2_keywords;
1655 body->param.lead_num = arg_size = (int)args->pre_args_num;
1656 if (body->param.lead_num > 0) body->param.flags.has_lead = TRUE;
1657 debugs(" - argc: %d\n", body->param.lead_num);
1658
1659 rest_id = args->rest_arg;
1660 if (rest_id == NODE_SPECIAL_EXCESSIVE_COMMA) {
1661 last_comma = 1;
1662 rest_id = 0;
1663 }
1664 block_id = args->block_arg;
1665
1666 if (args->opt_args) {
1667 const NODE *node = args->opt_args;
1668 LABEL *label;
1669 VALUE labels = rb_ary_tmp_new(1);
1670 VALUE *opt_table;
1671 int i = 0, j;
1672
1673 while (node) {
1674 label = NEW_LABEL(nd_line(node));
1675 rb_ary_push(labels, (VALUE)label | 1);
1676 ADD_LABEL(optargs, label);
1677 NO_CHECK(COMPILE_POPPED(optargs, "optarg", node->nd_body));
1678 node = node->nd_next;
1679 i += 1;
1680 }
1681
1682 /* last label */
1683 label = NEW_LABEL(nd_line(node_args));
1684 rb_ary_push(labels, (VALUE)label | 1);
1685 ADD_LABEL(optargs, label);
1686
1687 opt_table = ALLOC_N(VALUE, i+1);
1688
1689 MEMCPY(opt_table, RARRAY_CONST_PTR_TRANSIENT(labels), VALUE, i+1);
1690 for (j = 0; j < i+1; j++) {
1691 opt_table[j] &= ~1;
1692 }
1693 rb_ary_clear(labels);
1694
1695 body->param.flags.has_opt = TRUE;
1696 body->param.opt_num = i;
1697 body->param.opt_table = opt_table;
1698 arg_size += i;
1699 }
1700
1701 if (rest_id) {
1702 body->param.rest_start = arg_size++;
1703 body->param.flags.has_rest = TRUE;
1704 assert(body->param.rest_start != -1);
1705 }
1706
1707 if (args->first_post_arg) {
1708 body->param.post_start = arg_size;
1709 body->param.post_num = args->post_args_num;
1710 body->param.flags.has_post = TRUE;
1711 arg_size += args->post_args_num;
1712
1713 if (body->param.flags.has_rest) { /* TODO: why that? */
1714 body->param.post_start = body->param.rest_start + 1;
1715 }
1716 }
1717
1718 if (args->kw_args) {
1719 arg_size = iseq_set_arguments_keywords(iseq, optargs, args, arg_size);
1720 }
1721 else if (args->kw_rest_arg) {
1722 struct rb_iseq_param_keyword *keyword = ZALLOC_N(struct rb_iseq_param_keyword, 1);
1723 keyword->rest_start = arg_size++;
1724 body->param.keyword = keyword;
1725 body->param.flags.has_kwrest = TRUE;
1726 }
1727 else if (args->no_kwarg) {
1728 body->param.flags.accepts_no_kwarg = TRUE;
1729 }
1730
1731 if (block_id) {
1732 body->param.block_start = arg_size++;
1733 body->param.flags.has_block = TRUE;
1734 }
1735
1736 iseq_calc_param_size(iseq);
1737 body->param.size = arg_size;
1738
1739 if (args->pre_init) { /* m_init */
1740 NO_CHECK(COMPILE_POPPED(optargs, "init arguments (m)", args->pre_init));
1741 }
1742 if (args->post_init) { /* p_init */
1743 NO_CHECK(COMPILE_POPPED(optargs, "init arguments (p)", args->post_init));
1744 }
1745
1746 if (body->type == ISEQ_TYPE_BLOCK) {
1747 if (body->param.flags.has_opt == FALSE &&
1748 body->param.flags.has_post == FALSE &&
1749 body->param.flags.has_rest == FALSE &&
1750 body->param.flags.has_kw == FALSE &&
1751 body->param.flags.has_kwrest == FALSE) {
1752
1753 if (body->param.lead_num == 1 && last_comma == 0) {
1754 /* {|a|} */
1755 body->param.flags.ambiguous_param0 = TRUE;
1756 }
1757 }
1758 }
1759 }
1760
1761 return COMPILE_OK;
1762 }
1763
1764 static int
1765 iseq_set_local_table(rb_iseq_t *iseq, const ID *tbl)
1766 {
1767 unsigned int size;
1768
1769 if (tbl) {
1770 size = (unsigned int)*tbl;
1771 tbl++;
1772 }
1773 else {
1774 size = 0;
1775 }
1776
1777 if (size > 0) {
1778 ID *ids = (ID *)ALLOC_N(ID, size);
1779 MEMCPY(ids, tbl, ID, size);
1780 iseq->body->local_table = ids;
1781 }
1782 iseq->body->local_table_size = size;
1783
1784 debugs("iseq_set_local_table: %u\n", iseq->body->local_table_size);
1785 return COMPILE_OK;
1786 }
1787
1788 static int
1789 cdhash_cmp(VALUE val, VALUE lit)
1790 {
1791 int tval, tlit;
1792
1793 if (val == lit) {
1794 return 0;
1795 }
1796 else if ((tlit = OBJ_BUILTIN_TYPE(lit)) == -1) {
1797 return val != lit;
1798 }
1799 else if ((tval = OBJ_BUILTIN_TYPE(val)) == -1) {
1800 return -1;
1801 }
1802 else if (tlit != tval) {
1803 return -1;
1804 }
1805 else if (tlit == T_SYMBOL) {
1806 return val != lit;
1807 }
1808 else if (tlit == T_STRING) {
1809 return rb_str_hash_cmp(lit, val);
1810 }
1811 else if (tlit == T_BIGNUM) {
1812 long x = FIX2LONG(rb_big_cmp(lit, val));
1813
1814 /* Given lit and val are both Bignum, x must be -1, 0, 1.
1815 * There is no need to call rb_fix2int here. */
1816 RUBY_ASSERT((x == 1) || (x == 0) || (x == -1));
1817 return (int)x;
1818 }
1819 else if (tlit == T_FLOAT) {
1820 return rb_float_cmp(lit, val);
1821 }
1822 else {
1823 UNREACHABLE_RETURN(-1);
1824 }
1825 }
1826
1827 static st_index_t
1828 cdhash_hash(VALUE a)
1829 {
1830 switch (OBJ_BUILTIN_TYPE(a)) {
1831 case -1:
1832 case T_SYMBOL:
1833 return (st_index_t)a;
1834 case T_STRING:
1835 return rb_str_hash(a);
1836 case T_BIGNUM:
1837 return FIX2LONG(rb_big_hash(a));
1838 case T_FLOAT:
1839 return rb_dbl_long_hash(RFLOAT_VALUE(a));
1840 default:
1841 UNREACHABLE_RETURN(0);
1842 }
1843 }
1844
1845 static const struct st_hash_type cdhash_type = {
1846 cdhash_cmp,
1847 cdhash_hash,
1848 };
1849
1850 struct cdhash_set_label_struct {
1851 VALUE hash;
1852 int pos;
1853 int len;
1854 };
1855
1856 static int
1857 cdhash_set_label_i(VALUE key, VALUE val, VALUE ptr)
1858 {
1859 struct cdhash_set_label_struct *data = (struct cdhash_set_label_struct *)ptr;
1860 LABEL *lobj = (LABEL *)(val & ~1);
1861 rb_hash_aset(data->hash, key, INT2FIX(lobj->position - (data->pos+data->len)));
1862 return ST_CONTINUE;
1863 }
1864
1865
1866 static inline VALUE
1867 get_ivar_ic_value(rb_iseq_t *iseq,ID id)
1868 {
1869 VALUE val;
1870 struct rb_id_table *tbl = ISEQ_COMPILE_DATA(iseq)->ivar_cache_table;
1871 if (tbl) {
1872 if (rb_id_table_lookup(tbl,id,&val)) {
1873 return val;
1874 }
1875 }
1876 else {
1877 tbl = rb_id_table_create(1);
1878 ISEQ_COMPILE_DATA(iseq)->ivar_cache_table = tbl;
1879 }
1880 val = INT2FIX(iseq->body->is_size++);
1881 rb_id_table_insert(tbl,id,val);
1882 return val;
1883 }
1884
1885 #define BADINSN_DUMP(anchor, list, dest) \
1886 dump_disasm_list_with_cursor(FIRST_ELEMENT(anchor), list, dest)
1887
1888 #define BADINSN_ERROR \
1889 (xfree(generated_iseq), \
1890 xfree(insns_info), \
1891 BADINSN_DUMP(anchor, list, NULL), \
1892 COMPILE_ERROR)
1893
1894 static int
1895 fix_sp_depth(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
1896 {
1897 int stack_max = 0, sp = 0, line = 0;
1898 LINK_ELEMENT *list;
1899
1900 for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
1901 if (list->type == ISEQ_ELEMENT_LABEL) {
1902 LABEL *lobj = (LABEL *)list;
1903 lobj->set = TRUE;
1904 }
1905 }
1906
1907 for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
1908 switch (list->type) {
1909 case ISEQ_ELEMENT_INSN:
1910 {
1911 int j, len, insn;
1912 const char *types;
1913 VALUE *operands;
1914 INSN *iobj = (INSN *)list;
1915
1916 /* update sp */
1917 sp = calc_sp_depth(sp, iobj);
1918 if (sp < 0) {
1919 BADINSN_DUMP(anchor, list, NULL);
1920 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
1921 "argument stack underflow (%d)", sp);
1922 return -1;
1923 }
1924 if (sp > stack_max) {
1925 stack_max = sp;
1926 }
1927
1928 line = iobj->insn_info.line_no;
1929 /* fprintf(stderr, "insn: %-16s, sp: %d\n", insn_name(iobj->insn_id), sp); */
1930 operands = iobj->operands;
1931 insn = iobj->insn_id;
1932 types = insn_op_types(insn);
1933 len = insn_len(insn);
1934
1935 /* operand check */
1936 if (iobj->operand_size != len - 1) {
1937 /* printf("operand size miss! (%d, %d)\n", iobj->operand_size, len); */
1938 BADINSN_DUMP(anchor, list, NULL);
1939 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
1940 "operand size miss! (%d for %d)",
1941 iobj->operand_size, len - 1);
1942 return -1;
1943 }
1944
1945 for (j = 0; types[j]; j++) {
1946 if (types[j] == TS_OFFSET) {
1947 /* label(destination position) */
1948 LABEL *lobj = (LABEL *)operands[j];
1949 if (!lobj->set) {
1950 BADINSN_DUMP(anchor, list, NULL);
1951 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
1952 "unknown label: "LABEL_FORMAT, lobj->label_no);
1953 return -1;
1954 }
1955 if (lobj->sp == -1) {
1956 lobj->sp = sp;
1957 }
1958 }
1959 }
1960 break;
1961 }
1962 case ISEQ_ELEMENT_LABEL:
1963 {
1964 LABEL *lobj = (LABEL *)list;
1965 if (lobj->sp == -1) {
1966 lobj->sp = sp;
1967 }
1968 else {
1969 sp = lobj->sp;
1970 }
1971 break;
1972 }
1973 case ISEQ_ELEMENT_TRACE:
1974 {
1975 /* ignore */
1976 break;
1977 }
1978 case ISEQ_ELEMENT_ADJUST:
1979 {
1980 ADJUST *adjust = (ADJUST *)list;
1981 int orig_sp = sp;
1982
1983 sp = adjust->label ? adjust->label->sp : 0;
1984 if (adjust->line_no != -1 && orig_sp - sp < 0) {
1985 BADINSN_DUMP(anchor, list, NULL);
1986 COMPILE_ERROR(iseq, adjust->line_no,
1987 "iseq_set_sequence: adjust bug %d < %d",
1988 orig_sp, sp);
1989 return -1;
1990 }
1991 break;
1992 }
1993 default:
1994 BADINSN_DUMP(anchor, list, NULL);
1995 COMPILE_ERROR(iseq, line, "unknown list type: %d", list->type);
1996 return -1;
1997 }
1998 }
1999 return stack_max;
2000 }
2001
2002 static int
2003 add_insn_info(struct iseq_insn_info_entry *insns_info, unsigned int *positions,
2004 int insns_info_index, int code_index, const INSN *iobj)
2005 {
2006 if (insns_info_index == 0 ||
2007 insns_info[insns_info_index-1].line_no != iobj->insn_info.line_no ||
2008 insns_info[insns_info_index-1].events != iobj->insn_info.events) {
2009 insns_info[insns_info_index].line_no = iobj->insn_info.line_no;
2010 insns_info[insns_info_index].events = iobj->insn_info.events;
2011 positions[insns_info_index] = code_index;
2012 return TRUE;
2013 }
2014 return FALSE;
2015 }
2016
2017 static int
2018 add_adjust_info(struct iseq_insn_info_entry *insns_info, unsigned int *positions,
2019 int insns_info_index, int code_index, const ADJUST *adjust)
2020 {
2021 if (insns_info_index > 0 ||
2022 insns_info[insns_info_index-1].line_no != adjust->line_no) {
2023 insns_info[insns_info_index].line_no = adjust->line_no;
2024 insns_info[insns_info_index].events = 0;
2025 positions[insns_info_index] = code_index;
2026 return TRUE;
2027 }
2028 return FALSE;
2029 }
2030
2034 static int
2035 iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
2036 {
2037 struct iseq_insn_info_entry *insns_info;
2038 struct rb_iseq_constant_body *const body = iseq->body;
2039 unsigned int *positions;
2040 LINK_ELEMENT *list;
2041 VALUE *generated_iseq;
2042 rb_event_flag_t events = 0;
2043 long data = 0;
2044
2045 int insn_num, code_index, insns_info_index, sp = 0;
2046 int stack_max = fix_sp_depth(iseq, anchor);
2047
2048 if (stack_max < 0) return COMPILE_NG;
2049
2050 /* fix label position */
2051 insn_num = code_index = 0;
2052 for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
2053 switch (list->type) {
2054 case ISEQ_ELEMENT_INSN:
2055 {
2056 INSN *iobj = (INSN *)list;
2057 /* update sp */
2058 sp = calc_sp_depth(sp, iobj);
2059 insn_num++;
2060 events = iobj->insn_info.events |= events;
2061 if (ISEQ_COVERAGE(iseq)) {
2062 if (ISEQ_LINE_COVERAGE(iseq) && (events & RUBY_EVENT_COVERAGE_LINE) &&
2063 !(rb_get_coverage_mode() & COVERAGE_TARGET_ONESHOT_LINES)) {
2064 int line = iobj->insn_info.line_no;
2065 if (line >= 1) {
2066 RARRAY_ASET(ISEQ_LINE_COVERAGE(iseq), line - 1, INT2FIX(0));
2067 }
2068 }
2069 if (ISEQ_BRANCH_COVERAGE(iseq) && (events & RUBY_EVENT_COVERAGE_BRANCH)) {
2070 while (RARRAY_LEN(ISEQ_PC2BRANCHINDEX(iseq)) <= code_index) {
2071 rb_ary_push(ISEQ_PC2BRANCHINDEX(iseq), Qnil);
2072 }
2073 RARRAY_ASET(ISEQ_PC2BRANCHINDEX(iseq), code_index, INT2FIX(data));
2074 }
2075 }
2076 code_index += insn_data_length(iobj);
2077 events = 0;
2078 data = 0;
2079 break;
2080 }
2081 case ISEQ_ELEMENT_LABEL:
2082 {
2083 LABEL *lobj = (LABEL *)list;
2084 lobj->position = code_index;
2085 sp = lobj->sp;
2086 break;
2087 }
2088 case ISEQ_ELEMENT_TRACE:
2089 {
2090 TRACE *trace = (TRACE *)list;
2091 events |= trace->event;
2092 if (trace->event & RUBY_EVENT_COVERAGE_BRANCH) data = trace->data;
2093 break;
2094 }
2095 case ISEQ_ELEMENT_ADJUST:
2096 {
2097 ADJUST *adjust = (ADJUST *)list;
2098 if (adjust->line_no != -1) {
2099 int orig_sp = sp;
2100 sp = adjust->label ? adjust->label->sp : 0;
2101 if (orig_sp - sp > 0) {
2102 if (orig_sp - sp > 1) code_index++; /* 1 operand */
2103 code_index++; /* insn */
2104 insn_num++;
2105 }
2106 }
2107 break;
2108 }
2109 default: break;
2110 }
2111 }
2112
2113 /* make instruction sequence */
2114 generated_iseq = ALLOC_N(VALUE, code_index);
2115 insns_info = ALLOC_N(struct iseq_insn_info_entry, insn_num);
2116 positions = ALLOC_N(unsigned int, insn_num);
2117 body->is_entries = ZALLOC_N(union iseq_inline_storage_entry, body->is_size);
2118 body->call_data =
2119 rb_xcalloc_mul_add_mul(
2120 sizeof(struct rb_call_data), body->ci_size,
2121 sizeof(struct rb_kwarg_call_data), body->ci_kw_size);
2122 ISEQ_COMPILE_DATA(iseq)->ci_index = ISEQ_COMPILE_DATA(iseq)->ci_kw_index = 0;
2123
2124 list = FIRST_ELEMENT(anchor);
2125 insns_info_index = code_index = sp = 0;
2126
2127 while (list) {
2128 switch (list->type) {
2129 case ISEQ_ELEMENT_INSN:
2130 {
2131 int j, len, insn;
2132 const char *types;
2133 VALUE *operands;
2134 INSN *iobj = (INSN *)list;
2135
2136 /* update sp */
2137 sp = calc_sp_depth(sp, iobj);
2138 /* fprintf(stderr, "insn: %-16s, sp: %d\n", insn_name(iobj->insn_id), sp); */
2139 operands = iobj->operands;
2140 insn = iobj->insn_id;
2141 generated_iseq[code_index] = insn;
2142 types = insn_op_types(insn);
2143 len = insn_len(insn);
2144
2145 for (j = 0; types[j]; j++) {
2146 char type = types[j];
2147 /* printf("--> [%c - (%d-%d)]\n", type, k, j); */
2148 switch (type) {
2149 case TS_OFFSET:
2150 {
2151 /* label(destination position) */
2152 LABEL *lobj = (LABEL *)operands[j];
2153 generated_iseq[code_index + 1 + j] = lobj->position - (code_index + len);
2154 break;
2155 }
2156 case TS_CDHASH:
2157 {
2158 VALUE map = operands[j];
2159 struct cdhash_set_label_struct data;
2160 data.hash = map;
2161 data.pos = code_index;
2162 data.len = len;
2163 rb_hash_foreach(map, cdhash_set_label_i, (VALUE)&data);
2164
2165 rb_hash_rehash(map);
2166 freeze_hide_obj(map);
2167 generated_iseq[code_index + 1 + j] = map;
2168 RB_OBJ_WRITTEN(iseq, Qundef, map);
2169 FL_SET(iseq, ISEQ_MARKABLE_ISEQ);
2170 break;
2171 }
2172 case TS_LINDEX:
2173 case TS_NUM: /* ulong */
2174 generated_iseq[code_index + 1 + j] = FIX2INT(operands[j]);
2175 break;
2176 case TS_VALUE: /* VALUE */
2177 case TS_ISEQ: /* iseq */
2178 {
2179 VALUE v = operands[j];
2180 generated_iseq[code_index + 1 + j] = v;
2181 /* to mark ruby object */
2182 if (!SPECIAL_CONST_P(v)) {
2183 RB_OBJ_WRITTEN(iseq, Qundef, v);
2184 FL_SET(iseq, ISEQ_MARKABLE_ISEQ);
2185 }
2186 break;
2187 }
2188 case TS_ISE: /* inline storage entry */
2189 /* Treated as an IC, but may contain a markable VALUE */
2190 FL_SET(iseq, ISEQ_MARKABLE_ISEQ);
2191 /* fall through */
2192 case TS_IC: /* inline cache */
2193 case TS_IVC: /* inline ivar cache */
2194 {
2195 unsigned int ic_index = FIX2UINT(operands[j]);
2196 IC ic = (IC)&body->is_entries[ic_index];
2197 if (UNLIKELY(ic_index >= body->is_size)) {
2198 BADINSN_DUMP(anchor, &iobj->link, 0);
2199 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2200 "iseq_set_sequence: ic_index overflow: index: %d, size: %d",
2201 ic_index, body->is_size);
2202 }
2203 generated_iseq[code_index + 1 + j] = (VALUE)ic;
2204 break;
2205 }
2206 case TS_CALLDATA:
2207 {
2208 struct rb_call_info *source_ci = (struct rb_call_info *)operands[j];
2209 struct rb_call_data *cd;
2210
2211 if (source_ci->flag & VM_CALL_KWARG) {
2212 struct rb_kwarg_call_data *kw_calls = (struct rb_kwarg_call_data *)&body->call_data[body->ci_size];
2213 struct rb_kwarg_call_data *cd_kw = &kw_calls[ISEQ_COMPILE_DATA(iseq)->ci_kw_index++];
2214 cd_kw->ci_kw = *((struct rb_call_info_with_kwarg *)source_ci);
2215 cd = (struct rb_call_data *)cd_kw;
2216 assert(ISEQ_COMPILE_DATA(iseq)->ci_kw_index <= body->ci_kw_size);
2217 }
2218 else {
2219 cd = &body->call_data[ISEQ_COMPILE_DATA(iseq)->ci_index++];
2220 cd->ci = *source_ci;
2221 assert(ISEQ_COMPILE_DATA(iseq)->ci_index <= body->ci_size);
2222 }
2223
2224 generated_iseq[code_index + 1 + j] = (VALUE)cd;
2225 break;
2226 }
2227 case TS_ID: /* ID */
2228 generated_iseq[code_index + 1 + j] = SYM2ID(operands[j]);
2229 break;
2230 case TS_GENTRY:
2231 {
2232 struct rb_global_entry *entry =
2233 (struct rb_global_entry *)(operands[j] & (~1));
2234 generated_iseq[code_index + 1 + j] = (VALUE)entry;
2235 }
2236 break;
2237 case TS_FUNCPTR:
2238 generated_iseq[code_index + 1 + j] = operands[j];
2239 break;
2240 case TS_BUILTIN:
2241 generated_iseq[code_index + 1 + j] = operands[j];
2242 break;
2243 default:
2244 BADINSN_ERROR(iseq, iobj->insn_info.line_no,
2245 "unknown operand type: %c", type);
2246 return COMPILE_NG;
2247 }
2248 }
2249 if (add_insn_info(insns_info, positions, insns_info_index, code_index, iobj)) insns_info_index++;
2250 code_index += len;
2251 break;
2252 }
2253 case ISEQ_ELEMENT_LABEL:
2254 {
2255 LABEL *lobj = (LABEL *)list;
2256 sp = lobj->sp;
2257 break;
2258 }
2259 case ISEQ_ELEMENT_ADJUST:
2260 {
2261 ADJUST *adjust = (ADJUST *)list;
2262 int orig_sp = sp;
2263
2264 if (adjust->label) {
2265 sp = adjust->label->sp;
2266 }
2267 else {
2268 sp = 0;
2269 }
2270
2271 if (adjust->line_no != -1) {
2272 const int diff = orig_sp - sp;
2273 if (diff > 0) {
2274 if (add_adjust_info(insns_info, positions, insns_info_index, code_index, adjust)) insns_info_index++;
2275 }
2276 if (diff > 1) {
2277 generated_iseq[code_index++] = BIN(adjuststack);
2278 generated_iseq[code_index++] = orig_sp - sp;
2279 }
2280 else if (diff == 1) {
2281 generated_iseq[code_index++] = BIN(pop);
2282 }
2283 else if (diff < 0) {
2284 int label_no = adjust->label ? adjust->label->label_no : -1;
2285 xfree(generated_iseq);
2286 xfree(insns_info);
2287 xfree(positions);
2288 debug_list(anchor);
2289 COMPILE_ERROR(iseq, adjust->line_no,
2290 "iseq_set_sequence: adjust bug to %d %d < %d",
2291 label_no, orig_sp, sp);
2292 return COMPILE_NG;
2293 }
2294 }
2295 break;
2296 }
2297 default:
2298 /* ignore */
2299 break;
2300 }
2301 list = list->next;
2302 }
2303
2304 body->iseq_encoded = (void *)generated_iseq;
2305 body->iseq_size = code_index;
2306 body->stack_max = stack_max;
2307
2308 /* get rid of memory leak when REALLOC failed */
2309 body->insns_info.body = insns_info;
2310 body->insns_info.positions = positions;
2311
2312 REALLOC_N(insns_info, struct iseq_insn_info_entry, insns_info_index);
2313 body->insns_info.body = insns_info;
2314 REALLOC_N(positions, unsigned int, insns_info_index);
2315 body->insns_info.positions = positions;
2316 body->insns_info.size = insns_info_index;
2317
2318 return COMPILE_OK;
2319 }
2320
2321 static int
2322 label_get_position(LABEL *lobj)
2323 {
2324 return lobj->position;
2325 }
2326
2327 static int
2328 label_get_sp(LABEL *lobj)
2329 {
2330 return lobj->sp;
2331 }
2332
2333 static int
2334 iseq_set_exception_table(rb_iseq_t *iseq)
2335 {
2336 const VALUE *tptr, *ptr;
2337 unsigned int tlen, i;
2338 struct iseq_catch_table_entry *entry;
2339
2340 if (NIL_P(ISEQ_COMPILE_DATA(iseq)->catch_table_ary)) goto no_catch_table;
2341 tlen = (int)RARRAY_LEN(ISEQ_COMPILE_DATA(iseq)->catch_table_ary);
2342 tptr = RARRAY_CONST_PTR_TRANSIENT(ISEQ_COMPILE_DATA(iseq)->catch_table_ary);
2343
2344 if (tlen > 0) {
2345 struct iseq_catch_table *table = xmalloc(iseq_catch_table_bytes(tlen));
2346 table->size = tlen;
2347
2348 for (i = 0; i < table->size; i++) {
2349 ptr = RARRAY_CONST_PTR_TRANSIENT(tptr[i]);
2350 entry = UNALIGNED_MEMBER_PTR(table, entries[i]);
2351 entry->type = (enum catch_type)(ptr[0] & 0xffff);
2352 entry->start = label_get_position((LABEL *)(ptr[1] & ~1));
2353 entry->end = label_get_position((LABEL *)(ptr[2] & ~1));
2354 entry->iseq = (rb_iseq_t *)ptr[3];
2355 RB_OBJ_WRITTEN(iseq, Qundef, entry->iseq);
2356
2357 /* stack depth */
2358 if (ptr[4]) {
2359 LABEL *lobj = (LABEL *)(ptr[4] & ~1);
2360 entry->cont = label_get_position(lobj);
2361 entry->sp = label_get_sp(lobj);
2362
2363 /* TODO: Dirty Hack! Fix me */
2364 if (entry->type == CATCH_TYPE_RESCUE ||
2365 entry->type == CATCH_TYPE_BREAK ||
2366 entry->type == CATCH_TYPE_NEXT) {
2367 entry->sp--;
2368 }
2369 }
2370 else {
2371 entry->cont = 0;
2372 }
2373 }
2374 iseq->body->catch_table = table;
2375 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->catch_table_ary, 0); /* free */
2376 }
2377 else {
2378 no_catch_table:
2379 iseq->body->catch_table = NULL;
2380 }
2381
2382 return COMPILE_OK;
2383 }
2384
2385 /*
2386 * set optional argument table
2387 * def foo(a, b=expr1, c=expr2)
2388 * =>
2389 * b:
2390 * expr1
2391 * c:
2392 * expr2
2393 */
2394 static int
2395 iseq_set_optargs_table(rb_iseq_t *iseq)
2396 {
2397 int i;
2398 VALUE *opt_table = (VALUE *)iseq->body->param.opt_table;
2399
2400 if (iseq->body->param.flags.has_opt) {
2401 for (i = 0; i < iseq->body->param.opt_num + 1; i++) {
2402 opt_table[i] = label_get_position((LABEL *)opt_table[i]);
2403 }
2404 }
2405 return COMPILE_OK;
2406 }
2407
2408 static LINK_ELEMENT *
2409 get_destination_insn(INSN *iobj)
2410 {
2411 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, 0);
2412 LINK_ELEMENT *list;
2413 rb_event_flag_t events = 0;
2414
2415 list = lobj->link.next;
2416 while (list) {
2417 switch (list->type) {
2418 case ISEQ_ELEMENT_INSN:
2419 case ISEQ_ELEMENT_ADJUST:
2420 goto found;
2421 case ISEQ_ELEMENT_LABEL:
2422 /* ignore */
2423 break;
2424 case ISEQ_ELEMENT_TRACE:
2425 {
2426 TRACE *trace = (TRACE *)list;
2427 events |= trace->event;
2428 }
2429 break;
2430 default: break;
2431 }
2432 list = list->next;
2433 }
2434 found:
2435 if (list && IS_INSN(list)) {
2436 INSN *iobj = (INSN *)list;
2437 iobj->insn_info.events |= events;
2438 }
2439 return list;
2440 }
2441
2442 static LINK_ELEMENT *
2443 get_next_insn(INSN *iobj)
2444 {
2445 LINK_ELEMENT *list = iobj->link.next;
2446
2447 while (list) {
2448 if (IS_INSN(list) || IS_ADJUST(list)) {
2449 return list;
2450 }
2451 list = list->next;
2452 }
2453 return 0;
2454 }
2455
2456 static LINK_ELEMENT *
2457 get_prev_insn(INSN *iobj)
2458 {
2459 LINK_ELEMENT *list = iobj->link.prev;
2460
2461 while (list) {
2462 if (IS_INSN(list) || IS_ADJUST(list)) {
2463 return list;
2464 }
2465 list = list->prev;
2466 }
2467 return 0;
2468 }
2469
2470 static void
2471 unref_destination(INSN *iobj, int pos)
2472 {
2473 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, pos);
2474 --lobj->refcnt;
2475 if (!lobj->refcnt) ELEM_REMOVE(&lobj->link);
2476 }
2477
2478 static void
2479 replace_destination(INSN *dobj, INSN *nobj)
2480 {
2481 VALUE n = OPERAND_AT(nobj, 0);
2482 LABEL *dl = (LABEL *)OPERAND_AT(dobj, 0);
2483 LABEL *nl = (LABEL *)n;
2484 --dl->refcnt;
2485 ++nl->refcnt;
2486 OPERAND_AT(dobj, 0) = n;
2487 if (!dl->refcnt) ELEM_REMOVE(&dl->link);
2488 }
2489
2490 static LABEL*
2491 find_destination(INSN *i)
2492 {
2493 int pos, len = insn_len(i->insn_id);
2494 for (pos = 0; pos < len; ++pos) {
2495 if (insn_op_types(i->insn_id)[pos] == TS_OFFSET) {
2496 return (LABEL *)OPERAND_AT(i, pos);
2497 }
2498 }
2499 return 0;
2500 }
2501
2502 static int
2503 remove_unreachable_chunk(rb_iseq_t *iseq, LINK_ELEMENT *i)
2504 {
2505 LINK_ELEMENT *first = i, *end;
2506 int *unref_counts = 0, nlabels = ISEQ_COMPILE_DATA(iseq)->label_no;
2507
2508 if (!i) return 0;
2509 unref_counts = ALLOCA_N(int, nlabels);
2510 MEMZERO(unref_counts, int, nlabels);
2511 end = i;
2512 do {
2513 LABEL *lab;
2514 if (IS_INSN(i)) {
2515 if (IS_INSN_ID(i, leave)) {
2516 end = i;
2517 break;
2518 }
2519 else if ((lab = find_destination((INSN *)i)) != 0) {
2520 if (lab->unremovable) break;
2521 unref_counts[lab->label_no]++;
2522 }
2523 }
2524 else if (IS_LABEL(i)) {
2525 lab = (LABEL *)i;
2526 if (lab->unremovable) return 0;
2527 if (lab->refcnt > unref_counts[lab->label_no]) {
2528 if (i == first) return 0;
2529 break;
2530 }
2531 continue;
2532 }
2533 else if (IS_TRACE(i)) {
2534 /* do nothing */
2535 }
2536 else if (IS_ADJUST(i)) {
2537 LABEL *dest = ((ADJUST *)i)->label;
2538 if (dest && dest->unremovable) return 0;
2539 }
2540 end = i;
2541 } while ((i = i->next) != 0);
2542 i = first;
2543 do {
2544 if (IS_INSN(i)) {
2545 struct rb_iseq_constant_body *body = iseq->body;
2546 VALUE insn = INSN_OF(i);
2547 int pos, len = insn_len(insn);
2548 for (pos = 0; pos < len; ++pos) {
2549 switch (insn_op_types(insn)[pos]) {
2550 case TS_OFFSET:
2551 unref_destination((INSN *)i, pos);
2552 break;
2553 case TS_CALLDATA:
2554 if (((struct rb_call_info *)OPERAND_AT(i, pos))->flag & VM_CALL_KWARG)
2555 --(body->ci_kw_size);
2556 else
2557 --(body->ci_size);
2558 break;
2559 }
2560 }
2561 }
2562 ELEM_REMOVE(i);
2563 } while ((i != end) && (i = i->next) != 0);
2564 return 1;
2565 }
2566
2567 static int
2568 iseq_pop_newarray(rb_iseq_t *iseq, INSN *iobj)
2569 {
2570 switch (OPERAND_AT(iobj, 0)) {
2571 case INT2FIX(0): /* empty array */
2572 ELEM_REMOVE(&iobj->link);
2573 return TRUE;
2574 case INT2FIX(1): /* single element array */
2575 ELEM_REMOVE(&iobj->link);
2576 return FALSE;
2577 default:
2578 iobj->insn_id = BIN(adjuststack);
2579 return TRUE;
2580 }
2581 }
2582
2583 static int
2584 same_debug_pos_p(LINK_ELEMENT *iobj1, LINK_ELEMENT *iobj2)
2585 {
2586 VALUE debug1 = OPERAND_AT(iobj1, 0);
2587 VALUE debug2 = OPERAND_AT(iobj2, 0);
2588 if (debug1 == debug2) return TRUE;
2589 if (!RB_TYPE_P(debug1, T_ARRAY)) return FALSE;
2590 if (!RB_TYPE_P(debug2, T_ARRAY)) return FALSE;
2591 if (RARRAY_LEN(debug1) != 2) return FALSE;
2592 if (RARRAY_LEN(debug2) != 2) return FALSE;
2593 if (RARRAY_AREF(debug1, 0) != RARRAY_AREF(debug2, 0)) return FALSE;
2594 if (RARRAY_AREF(debug1, 1) != RARRAY_AREF(debug2, 1)) return FALSE;
2595 return TRUE;
2596 }
2597
2598 static int
2599 is_frozen_putstring(INSN *insn, VALUE *op)
2600 {
2601 if (IS_INSN_ID(insn, putstring)) {
2602 *op = OPERAND_AT(insn, 0);
2603 return 1;
2604 }
2605 else if (IS_INSN_ID(insn, putobject)) { /* frozen_string_literal */
2606 *op = OPERAND_AT(insn, 0);
2607 return RB_TYPE_P(*op, T_STRING);
2608 }
2609 return 0;
2610 }
2611
2612 static int
2613 optimize_checktype(rb_iseq_t *iseq, INSN *iobj)
2614 {
2615 /*
2616 * putobject obj
2617 * dup
2618 * checktype T_XXX
2619 * branchif l1
2620 * l2:
2621 * ...
2622 * l1:
2623 *
2624 * => obj is a T_XXX
2625 *
2626 * putobject obj (T_XXX)
2627 * jump L1
2628 * L1:
2629 *
2630 * => obj is not a T_XXX
2631 *
2632 * putobject obj (T_XXX)
2633 * jump L2
2634 * L2:
2635 */
2636 int line;
2637 INSN *niobj, *ciobj, *dup = 0;
2638 LABEL *dest = 0;
2639 VALUE type;
2640
2641 switch (INSN_OF(iobj)) {
2642 case BIN(putstring):
2643 type = INT2FIX(T_STRING);
2644 break;
2645 case BIN(putnil):
2646 type = INT2FIX(T_NIL);
2647 break;
2648 case BIN(putobject):
2649 type = INT2FIX(TYPE(OPERAND_AT(iobj, 0)));
2650 break;
2651 default: return FALSE;
2652 }
2653
2654 ciobj = (INSN *)get_next_insn(iobj);
2655 if (IS_INSN_ID(ciobj, jump)) {
2656 ciobj = (INSN *)get_next_insn((INSN*)OPERAND_AT(ciobj, 0));
2657 }
2658 if (IS_INSN_ID(ciobj, dup)) {
2659 ciobj = (INSN *)get_next_insn(dup = ciobj);
2660 }
2661 if (!ciobj || !IS_INSN_ID(ciobj, checktype)) return FALSE;
2662 niobj = (INSN *)get_next_insn(ciobj);
2663 if (!niobj) {
2664 no_branch:
2665 /* TODO: putobject true/false */
2666 return FALSE;
2667 }
2668 switch (INSN_OF(niobj)) {
2669 case BIN(branchif):
2670 if (OPERAND_AT(ciobj, 0) == type) {
2671 dest = (LABEL *)OPERAND_AT(niobj, 0);
2672 }
2673 break;
2674 case BIN(branchunless):
2675 if (OPERAND_AT(ciobj, 0) != type) {
2676 dest = (LABEL *)OPERAND_AT(niobj, 0);
2677 }
2678 break;
2679 default:
2680 goto no_branch;
2681 }
2682 line = ciobj->insn_info.line_no;
2683 if (!dest) {
2684 if (niobj->link.next && IS_LABEL(niobj->link.next)) {
2685 dest = (LABEL *)niobj->link.next; /* reuse label */
2686 }
2687 else {
2688 dest = NEW_LABEL(line);
2689 ELEM_INSERT_NEXT(&niobj->link, &dest->link);
2690 }
2691 }
2692 INSERT_AFTER_INSN1(iobj, line, jump, dest);
2693 LABEL_REF(dest);
2694 if (!dup) INSERT_AFTER_INSN(iobj, line, pop);
2695 return TRUE;
2696 }
2697
2698 static int
2699 iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcallopt)
2700 {
2701 INSN *const iobj = (INSN *)list;
2702
2703 again:
2704 optimize_checktype(iseq, iobj);
2705
2706 if (IS_INSN_ID(iobj, jump)) {
2707 INSN *niobj, *diobj, *piobj;
2708 diobj = (INSN *)get_destination_insn(iobj);
2709 niobj = (INSN *)get_next_insn(iobj);
2710
2711 if (diobj == niobj) {
2712 /*
2713 * jump LABEL
2714 * LABEL:
2715 * =>
2716 * LABEL:
2717 */
2718 unref_destination(iobj, 0);
2719 ELEM_REMOVE(&iobj->link);
2720 return COMPILE_OK;
2721 }
2722 else if (iobj != diobj && IS_INSN_ID(diobj, jump) &&
2723 OPERAND_AT(iobj, 0) != OPERAND_AT(diobj, 0)) {
2724 /*
2725 * useless jump elimination:
2726 * jump LABEL1
2727 * ...
2728 * LABEL1:
2729 * jump LABEL2
2730 *
2731 * => in this case, first jump instruction should jump to
2732 * LABEL2 directly
2733 */
2734 replace_destination(iobj, diobj);
2735 remove_unreachable_chunk(iseq, iobj->link.next);
2736 goto again;
2737 }
2738 else if (IS_INSN_ID(diobj, leave)) {
2739 INSN *pop;
2740 /*
2741 * jump LABEL
2742 * ...
2743 * LABEL:
2744 * leave
2745 * =>
2746 * leave
2747 * pop
2748 * ...
2749 * LABEL:
2750 * leave
2751 */
2752 /* replace */
2753 unref_destination(iobj, 0);
2754 iobj->insn_id = BIN(leave);
2755 iobj->operand_size = 0;
2756 iobj->insn_info = diobj->insn_info;
2757 /* adjust stack depth */
2758 pop = new_insn_body(iseq, diobj->insn_info.line_no, BIN(pop), 0);
2759 ELEM_INSERT_NEXT(&iobj->link, &pop->link);
2760 goto again;
2761 }
2762 else if (IS_INSN(iobj->link.prev) &&
2763 (piobj = (INSN *)iobj->link.prev) &&
2764 (IS_INSN_ID(piobj, branchif) ||
2765 IS_INSN_ID(piobj, branchunless))) {
2766 INSN *pdiobj = (INSN *)get_destination_insn(piobj);
2767 if (niobj == pdiobj) {
2768 int refcnt = IS_LABEL(piobj->link.next) ?
2769 ((LABEL *)piobj->link.next)->refcnt : 0;
2770 /*
2771 * useless jump elimination (if/unless destination):
2772 * if L1
2773 * jump L2
2774 * L1:
2775 * ...
2776 * L2:
2777 *
2778 * ==>
2779 * unless L2
2780 * L1:
2781 * ...
2782 * L2:
2783 */
2784 piobj->insn_id = (IS_INSN_ID(piobj, branchif))
2785 ? BIN(branchunless) : BIN(branchif);
2786 replace_destination(piobj, iobj);
2787 if (refcnt <= 1) {
2788 ELEM_REMOVE(&iobj->link);
2789 }
2790 else {
2791 /* TODO: replace other branch destinations too */
2792 }
2793 return COMPILE_OK;
2794 }
2795 else if (diobj == pdiobj) {
2796 /*
2797 * useless jump elimination (if/unless before jump):
2798 * L1:
2799 * ...
2800 * if L1
2801 * jump L1
2802 *
2803 * ==>
2804 * L1:
2805 * ...
2806 * pop
2807 * jump L1
2808 */
2809 INSN *popiobj = new_insn_core(iseq, iobj->insn_info.line_no,
2810 BIN(pop), 0, 0);
2811 ELEM_REPLACE(&piobj->link, &popiobj->link);
2812 }
2813 }
2814 if (remove_unreachable_chunk(iseq, iobj->link.next)) {
2815 goto again;
2816 }
2817 }
2818
2819 /*
2820 * putstring "beg"
2821 * putstring "end"
2822 * newrange excl
2823 *
2824 * ==>
2825 *
2826 * putobject "beg".."end"
2827 */
2828 if (IS_INSN_ID(iobj, checkmatch)) {
2829 INSN *range = (INSN *)get_prev_insn(iobj);
2830 INSN *beg, *end;
2831 VALUE str_beg, str_end;
2832
2833 if (range && IS_INSN_ID(range, newrange) &&
2834 (end = (INSN *)get_prev_insn(range)) != 0 &&
2835 is_frozen_putstring(end, &str_end) &&
2836 (beg = (INSN *)get_prev_insn(end)) != 0 &&
2837 is_frozen_putstring(beg, &str_beg)) {
2838 int excl = FIX2INT(OPERAND_AT(range, 0));
2839 VALUE lit_range = rb_range_new(str_beg, str_end, excl);
2840
2841 ELEM_REMOVE(&beg->link);
2842 ELEM_REMOVE(&end->link);
2843 range->insn_id = BIN(putobject);
2844 OPERAND_AT(range, 0) = lit_range;
2845 RB_OBJ_WRITTEN(iseq, Qundef, lit_range);
2846 }
2847 }
2848
2849 if (IS_INSN_ID(iobj, leave)) {
2850 remove_unreachable_chunk(iseq, iobj->link.next);
2851 }
2852
2853 if (IS_INSN_ID(iobj, branchif) ||
2854 IS_INSN_ID(iobj, branchnil) ||
2855 IS_INSN_ID(iobj, branchunless)) {
2856 /*
2857 * if L1
2858 * ...
2859 * L1:
2860 * jump L2
2861 * =>
2862 * if L2
2863 */
2864 INSN *nobj = (INSN *)get_destination_insn(iobj);
2865
2866 /* This is super nasty hack!!!
2867 *
2868 * This jump-jump optimization may ignore event flags of the jump
2869 * instruction being skipped. Actually, Line 2 TracePoint event
2870 * is never fired in the following code:
2871 *
2872 * 1: raise if 1 == 2
2873 * 2: while true
2874 * 3: break
2875 * 4: end
2876 *
2877 * This is critical for coverage measurement. [Bug #15980]
2878 *
2879 * This is a stopgap measure: stop the jump-jump optimization if
2880 * coverage measurement is enabled and if the skipped instruction
2881 * has any event flag.
2882 *
2883 * Note that, still, TracePoint Line event does not occur on Line 2.
2884 * This should be fixed in future.
2885 */
2886 int stop_optimization =
2887 ISEQ_COVERAGE(iseq) && ISEQ_LINE_COVERAGE(iseq) &&
2888 nobj->insn_info.events;
2889 if (!stop_optimization) {
2890 INSN *pobj = (INSN *)iobj->link.prev;
2891 int prev_dup = 0;
2892 if (pobj) {
2893 if (!IS_INSN(&pobj->link))
2894 pobj = 0;
2895 else if (IS_INSN_ID(pobj, dup))
2896 prev_dup = 1;
2897 }
2898
2899 for (;;) {
2900 if (IS_INSN_ID(nobj, jump)) {
2901 replace_destination(iobj, nobj);
2902 }
2903 else if (prev_dup && IS_INSN_ID(nobj, dup) &&
2904 !!(nobj = (INSN *)nobj->link.next) &&
2905 /* basic blocks, with no labels in the middle */
2906 nobj->insn_id == iobj->insn_id) {
2907 /*
2908 * dup
2909 * if L1
2910 * ...
2911 * L1:
2912 * dup
2913 * if L2
2914 * =>
2915 * dup
2916 * if L2
2917 * ...
2918 * L1:
2919 * dup
2920 * if L2
2921 */
2922 replace_destination(iobj, nobj);
2923 }
2924 else if (pobj) {
2925 /*
2926 * putnil
2927 * if L1
2928 * =>
2929 * # nothing
2930 *
2931 * putobject true
2932 * if L1
2933 * =>
2934 * jump L1
2935 *
2936 * putstring ".."
2937 * if L1
2938 * =>
2939 * jump L1
2940 *
2941 * putstring ".."
2942 * dup
2943 * if L1
2944 * =>
2945 * putstring ".."
2946 * jump L1
2947 *
2948 */
2949 int cond;
2950 if (prev_dup && IS_INSN(pobj->link.prev)) {
2951 pobj = (INSN *)pobj->link.prev;
2952 }
2953 if (IS_INSN_ID(pobj, putobject)) {
2954 cond = (IS_INSN_ID(iobj, branchif) ?
2955 OPERAND_AT(pobj, 0) != Qfalse :
2956 IS_INSN_ID(iobj, branchunless) ?
2957 OPERAND_AT(pobj, 0) == Qfalse :
2958 FALSE);
2959 }
2960 else if (IS_INSN_ID(pobj, putstring) ||
2961 IS_INSN_ID(pobj, duparray) ||
2962 IS_INSN_ID(pobj, newarray)) {
2963 cond = IS_INSN_ID(iobj, branchif);
2964 }
2965 else if (IS_INSN_ID(pobj, putnil)) {
2966 cond = !IS_INSN_ID(iobj, branchif);
2967 }
2968 else break;
2969 if (prev_dup || !IS_INSN_ID(pobj, newarray)) {
2970 ELEM_REMOVE(iobj->link.prev);
2971 }
2972 else if (!iseq_pop_newarray(iseq, pobj)) {
2973 pobj = new_insn_core(iseq, pobj->insn_info.line_no, BIN(pop), 0, NULL);
2974 ELEM_INSERT_PREV(&iobj->link, &pobj->link);
2975 }
2976 if (cond) {
2977 if (prev_dup) {
2978 pobj = new_insn_core(iseq, pobj->insn_info.line_no, BIN(putnil), 0, NULL);
2979 ELEM_INSERT_NEXT(&iobj->link, &pobj->link);
2980 }
2981 iobj->insn_id = BIN(jump);
2982 goto again;
2983 }
2984 else {
2985 unref_destination(iobj, 0);
2986 ELEM_REMOVE(&iobj->link);
2987 }
2988 break;
2989 }
2990 else break;
2991 nobj = (INSN *)get_destination_insn(nobj);
2992 }
2993 }
2994 }
2995
2996 if (IS_INSN_ID(iobj, pop)) {
2997 /*
2998 * putself / putnil / putobject obj / putstring "..."
2999 * pop
3000 * =>
3001 * # do nothing
3002 */
3003 LINK_ELEMENT *prev = iobj->link.prev;
3004 if (IS_INSN(prev)) {
3005 enum ruby_vminsn_type previ = ((INSN *)prev)->insn_id;
3006 if (previ == BIN(putobject) || previ == BIN(putnil) ||
3007 previ == BIN(putself) || previ == BIN(putstring) ||
3008 previ == BIN(dup) ||
3009 previ == BIN(getlocal) ||
3010 previ == BIN(getblockparam) ||
3011 previ == BIN(getblockparamproxy) ||
3012 /* getinstancevariable may issue a warning */
3013 previ == BIN(duparray)) {
3014 /* just push operand or static value and pop soon, no
3015 * side effects */
3016 ELEM_REMOVE(prev);
3017 ELEM_REMOVE(&iobj->link);
3018 }
3019 else if (previ == BIN(newarray) && iseq_pop_newarray(iseq, (INSN*)prev)) {
3020 ELEM_REMOVE(&iobj->link);
3021 }
3022 else if (previ == BIN(concatarray)) {
3023 INSN *piobj = (INSN *)prev;
3024 INSERT_BEFORE_INSN1(piobj, piobj->insn_info.line_no, splatarray, Qfalse);
3025 INSN_OF(piobj) = BIN(pop);
3026 }
3027 else if (previ == BIN(concatstrings)) {
3028 if (OPERAND_AT(prev, 0) == INT2FIX(1)) {
3029 ELEM_REMOVE(prev);
3030 }
3031 else {
3032 ELEM_REMOVE(&iobj->link);
3033 INSN_OF(prev) = BIN(adjuststack);
3034 }
3035 }
3036 }
3037 }
3038
3039 if (IS_INSN_ID(iobj, newarray) ||
3040 IS_INSN_ID(iobj, duparray) ||
3041 IS_INSN_ID(iobj, expandarray) ||
3042 IS_INSN_ID(iobj, concatarray) ||
3043 IS_INSN_ID(iobj, splatarray) ||
3044 0) {
3045 /*
3046 * newarray N
3047 * splatarray
3048 * =>
3049 * newarray N
3050 * newarray always puts an array
3051 */
3052 LINK_ELEMENT *next = iobj->link.next;
3053 if (IS_INSN(next) && IS_INSN_ID(next, splatarray)) {
3054 /* remove splatarray following always-array insn */
3055 ELEM_REMOVE(next);
3056 }
3057 }
3058
3059 if (IS_INSN_ID(iobj, tostring)) {
3060 LINK_ELEMENT *next = iobj->link.next;
3061 /*
3062 * tostring
3063 * concatstrings 1
3064 * =>
3065 * tostring
3066 */
3067 if (IS_INSN(next) && IS_INSN_ID(next, concatstrings) &&
3068 OPERAND_AT(next, 0) == INT2FIX(1)) {
3069 ELEM_REMOVE(next);
3070 }
3071 }
3072
3073 if (IS_INSN_ID(iobj, putstring) ||
3074 (IS_INSN_ID(iobj, putobject) && RB_TYPE_P(OPERAND_AT(iobj, 0), T_STRING))) {
3075 /*
3076 * putstring ""
3077 * concatstrings N
3078 * =>
3079 * concatstrings N-1
3080 */
3081 if (IS_NEXT_INSN_ID(&iobj->link, concatstrings) &&
3082 RSTRING_LEN(OPERAND_AT(iobj, 0)) == 0) {
3083 INSN *next = (INSN *)iobj->link.next;
3084 if ((OPERAND_AT(next, 0) = FIXNUM_INC(OPERAND_AT(next, 0), -1)) == INT2FIX(1)) {
3085 ELEM_REMOVE(&next->link);
3086 }
3087 ELEM_REMOVE(&iobj->link);
3088 }
3089 }
3090
3091 if (IS_INSN_ID(iobj, concatstrings)) {
3092 /*
3093 * concatstrings N
3094 * concatstrings M
3095 * =>
3096 * concatstrings N+M-1
3097 */
3098 LINK_ELEMENT *next = iobj->link.next, *freeze = 0;
3099 INSN *jump = 0;
3100 if (IS_INSN(next) && IS_INSN_ID(next, freezestring))
3101 next = (freeze = next)->next;
3102 if (IS_INSN(next) && IS_INSN_ID(next, jump))
3103 next = get_destination_insn(jump = (INSN *)next);
3104 if (IS_INSN(next) && IS_INSN_ID(next, concatstrings)) {
3105 int n = FIX2INT(OPERAND_AT(iobj, 0)) + FIX2INT(OPERAND_AT(next, 0)) - 1;
3106 OPERAND_AT(iobj, 0) = INT2FIX(n);
3107 if (jump) {
3108 LABEL *label = ((LABEL *)OPERAND_AT(jump, 0));
3109 if (!--label->refcnt) {
3110 ELEM_REMOVE(&label->link);
3111 }
3112 else {
3113 label = NEW_LABEL(0);
3114 OPERAND_AT(jump, 0) = (VALUE)label;
3115 }
3116 label->refcnt++;
3117 if (freeze && IS_NEXT_INSN_ID(next, freezestring)) {
3118 if (same_debug_pos_p(freeze, next->next)) {
3119 ELEM_REMOVE(freeze);
3120 }
3121 else {
3122 next = next->next;
3123 }
3124 }
3125 ELEM_INSERT_NEXT(next, &label->link);
3126 CHECK(iseq_peephole_optimize(iseq, get_next_insn(jump), do_tailcallopt));
3127 }
3128 else {
3129 if (freeze) ELEM_REMOVE(freeze);
3130 ELEM_REMOVE(next);
3131 }
3132 }
3133 }
3134
3135 if (IS_INSN_ID(iobj, freezestring) &&
3136 NIL_P(OPERAND_AT(iobj, 0)) &&
3137 IS_NEXT_INSN_ID(&iobj->link, send)) {
3138 INSN *niobj = (INSN *)iobj->link.next;
3139 struct rb_call_info *ci = (struct rb_call_info *)OPERAND_AT(niobj, 0);
3140 /*
3141 * freezestring nil # no debug_info
3142 * send <:+@, 0, ARG_SIMPLE> # :-@, too
3143 * =>
3144 * send <:+@, 0, ARG_SIMPLE> # :-@, too
3145 */
3146 if ((ci->mid == idUPlus || ci->mid == idUMinus) &&
3147 (ci->flag & VM_CALL_ARGS_SIMPLE) &&
3148 ci->orig_argc == 0) {
3149 ELEM_REMOVE(list);
3150 return COMPILE_OK;
3151 }
3152 }
3153
3154 if (do_tailcallopt &&
3155 (IS_INSN_ID(iobj, send) ||
3156 IS_INSN_ID(iobj, opt_aref_with) ||
3157 IS_INSN_ID(iobj, opt_aset_with) ||
3158 IS_INSN_ID(iobj, invokesuper))) {
3159 /*
3160 * send ...
3161 * leave
3162 * =>
3163 * send ..., ... | VM_CALL_TAILCALL, ...
3164 * leave # unreachable
3165 */
3166 INSN *piobj = NULL;
3167 if (iobj->link.next) {
3168 LINK_ELEMENT *next = iobj->link.next;
3169 do {
3170 if (!IS_INSN(next)) {
3171 next = next->next;
3172 continue;
3173 }
3174 switch (INSN_OF(next)) {
3175 case BIN(nop):
3176 next = next->next;
3177 break;
3178 case BIN(jump):
3179 /* if cond
3180 * return tailcall
3181 * end
3182 */
3183 next = get_destination_insn((INSN *)next);
3184 break;
3185 case BIN(leave):
3186 piobj = iobj;
3187 /* fall through */
3188 default:
3189 next = NULL;
3190 break;
3191 }
3192 } while (next);
3193 }
3194
3195 if (piobj) {
3196 struct rb_call_info *ci = (struct rb_call_info *)OPERAND_AT(piobj, 0);
3197 if (IS_INSN_ID(piobj, send) || IS_INSN_ID(piobj, invokesuper)) {
3198 if (OPERAND_AT(piobj, 1) == 0) { /* no blockiseq */
3199 ci->flag |= VM_CALL_TAILCALL;
3200 }
3201 }
3202 else {
3203 ci->flag |= VM_CALL_TAILCALL;
3204 }
3205 }
3206 }
3207
3208 if (IS_INSN_ID(iobj, dup)) {
3209 if (IS_NEXT_INSN_ID(&iobj->link, setlocal)) {
3210 LINK_ELEMENT *set1 = iobj->link.next, *set2 = NULL;
3211 if (IS_NEXT_INSN_ID(set1, setlocal)) {
3212 set2 = set1->next;
3213 if (OPERAND_AT(set1, 0) == OPERAND_AT(set2, 0) &&
3214 OPERAND_AT(set1, 1) == OPERAND_AT(set2, 1)) {
3215 ELEM_REMOVE(set1);
3216 ELEM_REMOVE(&iobj->link);
3217 }
3218 }
3219 else if (IS_NEXT_INSN_ID(set1, dup) &&
3220 IS_NEXT_INSN_ID(set1->next, setlocal)) {
3221 set2 = set1->next->next;
3222 if (OPERAND_AT(set1, 0) == OPERAND_AT(set2, 0) &&
3223 OPERAND_AT(set1, 1) == OPERAND_AT(set2, 1)) {
3224 ELEM_REMOVE(set1->next);
3225 ELEM_REMOVE(set2);
3226 }
3227 }
3228 }
3229 }
3230
3231 if (IS_INSN_ID(iobj, getlocal)) {
3232 LINK_ELEMENT *niobj = &iobj->link;
3233 if (IS_NEXT_INSN_ID(niobj, dup)) {
3234 niobj = niobj->next;
3235 }
3236 if (IS_NEXT_INSN_ID(niobj, setlocal)) {
3237 LINK_ELEMENT *set1 = niobj->next;
3238 if (OPERAND_AT(iobj, 0) == OPERAND_AT(set1, 0) &&
3239 OPERAND_AT(iobj, 1) == OPERAND_AT(set1, 1)) {
3240 ELEM_REMOVE(set1);
3241 ELEM_REMOVE(niobj);
3242 }
3243 }
3244 }
3245
3246 if (IS_INSN_ID(iobj, opt_invokebuiltin_delegate)) {
3247 if (IS_TRACE(iobj->link.next)) {
3248 if (IS_NEXT_INSN_ID(iobj->link.next, leave)) {
3249 iobj->insn_id = BIN(opt_invokebuiltin_delegate_leave);
3250 }
3251 }
3252 }
3253
3254 return COMPILE_OK;
3255 }
3256
3257 static int
3258 insn_set_specialized_instruction(rb_iseq_t *iseq, INSN *iobj, int insn_id)
3259 {
3260 iobj->insn_id = insn_id;
3261 iobj->operand_size = insn_len(insn_id) - 1;
3262
3263 if (insn_id == BIN(opt_neq)) {
3264 VALUE *old_operands = iobj->operands;
3265 iobj->operand_size = 2;
3266 iobj->operands = compile_data_alloc2(iseq, iobj->operand_size, sizeof(VALUE));
3267 iobj->operands[0] = (VALUE)new_callinfo(iseq, idEq, 1, 0, NULL, FALSE);
3268 iobj->operands[1] = old_operands[0];
3269 }
3270
3271 return COMPILE_OK;
3272 }
3273
3274 static int
3275 iseq_specialized_instruction(rb_iseq_t *iseq, INSN *iobj)
3276 {
3277 if (IS_INSN_ID(iobj, newarray) && iobj->link.next &&
3278 IS_INSN(iobj->link.next)) {
3279 /*
3280 * [a, b, ...].max/min -> a, b, c, opt_newarray_max/min
3281 */
3282 INSN *niobj = (INSN *)iobj->link.next;
3283 if (IS_INSN_ID(niobj, send)) {
3284 struct rb_call_info *ci = (struct rb_call_info *)OPERAND_AT(niobj, 0);
3285 if ((ci->flag & VM_CALL_ARGS_SIMPLE) && ci->orig_argc == 0) {
3286 switch (ci->mid) {
3287 case idMax:
3288 iobj->insn_id = BIN(opt_newarray_max);
3289 ELEM_REMOVE(&niobj->link);
3290 return COMPILE_OK;
3291 case idMin:
3292 iobj->insn_id = BIN(opt_newarray_min);
3293 ELEM_REMOVE(&niobj->link);
3294 return COMPILE_OK;
3295 }
3296 }
3297 }
3298 }
3299
3300 if (IS_INSN_ID(iobj, send)) {
3301 struct rb_call_info *ci = (struct rb_call_info *)OPERAND_AT(iobj, 0);
3302 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(iobj, 1);
3303
3304 #define SP_INSN(opt) insn_set_specialized_instruction(iseq, iobj, BIN(opt_##opt))
3305 if (ci->flag & VM_CALL_ARGS_SIMPLE) {
3306 switch (ci->orig_argc) {
3307 case 0:
3308 switch (ci->mid) {
3309 case idLength: SP_INSN(length); return COMPILE_OK;
3310 case idSize: SP_INSN(size); return COMPILE_OK;
3311 case idEmptyP: SP_INSN(empty_p);return COMPILE_OK;
3312 case idNilP: SP_INSN(nil_p); return COMPILE_OK;
3313 case idSucc: SP_INSN(succ); return COMPILE_OK;
3314 case idNot: SP_INSN(not); return COMPILE_OK;
3315 }
3316 break;
3317 case 1:
3318 switch (ci->mid) {
3319 case idPLUS: SP_INSN(plus); return COMPILE_OK;
3320 case idMINUS: SP_INSN(minus); return COMPILE_OK;
3321 case idMULT: SP_INSN(mult); return COMPILE_OK;
3322 case idDIV: SP_INSN(div); return COMPILE_OK;
3323 case idMOD: SP_INSN(mod); return COMPILE_OK;
3324 case idEq: SP_INSN(eq); return COMPILE_OK;
3325 case idNeq: SP_INSN(neq); return COMPILE_OK;
3326 case idEqTilde:SP_INSN(regexpmatch2);return COMPILE_OK;
3327 case idLT: SP_INSN(lt); return COMPILE_OK;
3328 case idLE: SP_INSN(le); return COMPILE_OK;
3329 case idGT: SP_INSN(gt); return COMPILE_OK;
3330 case idGE: SP_INSN(ge); return COMPILE_OK;
3331 case idLTLT: SP_INSN(ltlt); return COMPILE_OK;
3332 case idAREF: SP_INSN(aref); return COMPILE_OK;
3333 case idAnd: SP_INSN(and); return COMPILE_OK;
3334 case idOr: SP_INSN(or); return COMPILE_OK;
3335 }
3336 break;
3337 case 2:
3338 switch (ci->mid) {
3339 case idASET: SP_INSN(aset); return COMPILE_OK;
3340 }
3341 break;
3342 }
3343 }
3344
3345 if ((ci->flag & VM_CALL_ARGS_BLOCKARG) == 0 && blockiseq == NULL) {
3346 iobj->insn_id = BIN(opt_send_without_block);
3347 iobj->operand_size = insn_len(iobj->insn_id) - 1;
3348 }
3349 }
3350 #undef SP_INSN
3351
3352 return COMPILE_OK;
3353 }
3354
3355 static inline int
3356 tailcallable_p(rb_iseq_t *iseq)
3357 {
3358 switch (iseq->body->type) {
3359 case ISEQ_TYPE_TOP:
3360 case ISEQ_TYPE_EVAL:
3361 case ISEQ_TYPE_MAIN:
3362 /* not tail callable because cfp will be over popped */
3363 case ISEQ_TYPE_RESCUE:
3364 case ISEQ_TYPE_ENSURE:
3365 /* rescue block can't tail call because of errinfo */
3366 return FALSE;
3367 default:
3368 return TRUE;
3369 }
3370 }
3371
3372 static int
3373 iseq_optimize(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
3374 {
3375 LINK_ELEMENT *list;
3376 const int do_peepholeopt = ISEQ_COMPILE_DATA(iseq)->option->peephole_optimization;
3377 const int do_tailcallopt = tailcallable_p(iseq) &&
3378 ISEQ_COMPILE_DATA(iseq)->option->tailcall_optimization;
3379 const int do_si = ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction;
3380 const int do_ou = ISEQ_COMPILE_DATA(iseq)->option->operands_unification;
3381 int rescue_level = 0;
3382 int tailcallopt = do_tailcallopt;
3383
3384 list = FIRST_ELEMENT(anchor);
3385
3386 while (list) {
3387 if (IS_INSN(list)) {
3388 if (do_peepholeopt) {
3389 iseq_peephole_optimize(iseq, list, tailcallopt);
3390 }
3391 if (do_si) {
3392 iseq_specialized_instruction(iseq, (INSN *)list);
3393 }
3394 if (do_ou) {
3395 insn_operands_unification((INSN *)list);
3396 }
3397 }
3398 if (IS_LABEL(list)) {
3399 switch (((LABEL *)list)->rescued) {
3400 case LABEL_RESCUE_BEG:
3401 rescue_level++;
3402 tailcallopt = FALSE;
3403 break;
3404 case LABEL_RESCUE_END:
3405 if (!--rescue_level) tailcallopt = do_tailcallopt;
3406 break;
3407 }
3408 }
3409 list = list->next;
3410 }
3411 return COMPILE_OK;
3412 }
3413
3414 #if OPT_INSTRUCTIONS_UNIFICATION
3415 static INSN *
3416 new_unified_insn(rb_iseq_t *iseq,
3417 int insn_id, int size, LINK_ELEMENT *seq_list)
3418 {
3419 INSN *iobj = 0;
3420 LINK_ELEMENT *list = seq_list;
3421 int i, argc = 0;
3422 VALUE *operands = 0, *ptr = 0;
3423
3424
3425 /* count argc */
3426 for (i = 0; i < size; i++) {
3427 iobj = (INSN *)list;
3428 argc += iobj->operand_size;
3429 list = list->next;
3430 }
3431
3432 if (argc > 0) {
3433 ptr = operands =
3434 compile_data_alloc2(iseq, sizeof(VALUE), argc);
3435 }
3436
3437 /* copy operands */
3438 list = seq_list;
3439 for (i = 0; i < size; i++) {
3440 iobj = (INSN *)list;
3441 MEMCPY(ptr, iobj->operands, VALUE, iobj->operand_size);
3442 ptr += iobj->operand_size;
3443 list = list->next;
3444 }
3445
3446 return new_insn_core(iseq, iobj->insn_info.line_no, insn_id, argc, operands);
3447 }
3448 #endif
3449
3450 /*
3451 * This scheme can get more performance if do this optimize with
3452 * label address resolving.
3453 * It's future work (if compile time was bottle neck).
3454 */
3455 static int
3456 iseq_insns_unification(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
3457 {
3458 #if OPT_INSTRUCTIONS_UNIFICATION
3459 LINK_ELEMENT *list;
3460 INSN *iobj, *niobj;
3461 int id, k;
3462 intptr_t j;
3463
3464 list = FIRST_ELEMENT(anchor);
3465 while (list) {
3466 if (IS_INSN(list)) {
3467 iobj = (INSN *)list;
3468 id = iobj->insn_id;
3469 if (unified_insns_data[id] != 0) {
3470 const int *const *entry = unified_insns_data[id];
3471 for (j = 1; j < (intptr_t)entry[0]; j++) {
3472 const int *unified = entry[j];
3473 LINK_ELEMENT *li = list->next;
3474 for (k = 2; k < unified[1]; k++) {
3475 if (!IS_INSN(li) ||
3476 ((INSN *)li)->insn_id != unified[k]) {
3477 goto miss;
3478 }
3479 li = li->next;
3480 }
3481 /* matched */
3482 niobj =
3483 new_unified_insn(iseq, unified[0], unified[1] - 1,
3484 list);
3485
3486 /* insert to list */
3487 niobj->link.prev = (LINK_ELEMENT *)iobj->link.prev;
3488 niobj->link.next = li;
3489 if (li) {
3490 li->prev = (LINK_ELEMENT *)niobj;
3491 }
3492
3493 list->prev->next = (LINK_ELEMENT *)niobj;
3494 list = (LINK_ELEMENT *)niobj;
3495 break;
3496 miss:;
3497 }
3498 }
3499 }
3500 list = list->next;
3501 }
3502 #endif
3503 return COMPILE_OK;
3504 }
3505
3506 #if OPT_STACK_CACHING
3507
3508 #define SC_INSN(insn, stat) sc_insn_info[(insn)][(stat)]
3509 #define SC_NEXT(insn) sc_insn_next[(insn)]
3510
3511 #include "opt_sc.inc"
3512
3513 static int
3514 insn_set_sc_state(rb_iseq_t *iseq, const LINK_ELEMENT *anchor, INSN *iobj, int state)
3515 {
3516 int nstate;
3517 int insn_id;
3518
3519 insn_id = iobj->insn_id;
3520 iobj->insn_id = SC_INSN(insn_id, state);
3521 nstate = SC_NEXT(iobj->insn_id);
3522
3523 if (insn_id == BIN(jump) ||
3524 insn_id == BIN(branchif) || insn_id == BIN(branchunless)) {
3525 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, 0);
3526
3527 if (lobj->sc_state != 0) {
3528 if (lobj->sc_state != nstate) {
3529 BADINSN_DUMP(anchor, iobj, lobj);
3530 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
3531 "insn_set_sc_state error: %d at "LABEL_FORMAT
3532 ", %d expected\n",
3533 lobj->sc_state, lobj->label_no, nstate);
3534 return COMPILE_NG;
3535 }
3536 }
3537 else {
3538 lobj->sc_state = nstate;
3539 }
3540 if (insn_id == BIN(jump)) {
3541 nstate = SCS_XX;
3542 }
3543 }
3544 else if (insn_id == BIN(leave)) {
3545 nstate = SCS_XX;
3546 }
3547
3548 return nstate;
3549 }
3550
3551 static int
3552 label_set_sc_state(LABEL *lobj, int state)
3553 {
3554 if (lobj->sc_state != 0) {
3555 if (lobj->sc_state != state) {
3556 state = lobj->sc_state;
3557 }
3558 }
3559 else {
3560 lobj->sc_state = state;
3561 }
3562
3563 return state;
3564 }
3565
3566
3567 #endif
3568
3569 static int
3570 iseq_set_sequence_stackcaching(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
3571 {
3572 #if OPT_STACK_CACHING
3573 LINK_ELEMENT *list;
3574 int state, insn_id;
3575
3576 /* initialize */
3577 state = SCS_XX;
3578 list = FIRST_ELEMENT(anchor);
3579 /* dump_disasm_list(list); */
3580
3581 /* for each list element */
3582 while (list) {
3583 redo_point:
3584 switch (list->type) {
3585 case ISEQ_ELEMENT_INSN:
3586 {
3587 INSN *iobj = (INSN *)list;
3588 insn_id = iobj->insn_id;
3589
3590 /* dump_disasm_list(list); */
3591
3592 switch (insn_id) {
3593 case BIN(nop):
3594 {
3595 /* exception merge point */
3596 if (state != SCS_AX) {
3597 INSN *rpobj =
3598 new_insn_body(iseq, 0, BIN(reput), 0);
3599
3600 /* replace this insn */
3601 ELEM_REPLACE(list, (LINK_ELEMENT *)rpobj);
3602 list = (LINK_ELEMENT *)rpobj;
3603 goto redo_point;
3604 }
3605 break;
3606 }
3607 case BIN(swap):
3608 {
3609 if (state == SCS_AB || state == SCS_BA) {
3610 state = (state == SCS_AB ? SCS_BA : SCS_AB);
3611
3612 ELEM_REMOVE(list);
3613 list = list->next;
3614 goto redo_point;
3615 }
3616 break;
3617 }
3618 case BIN(pop):
3619 {
3620 switch (state) {
3621 case SCS_AX:
3622 case SCS_BX:
3623 state = SCS_XX;
3624 break;
3625 case SCS_AB:
3626 state = SCS_AX;
3627 break;
3628 case SCS_BA:
3629 state = SCS_BX;
3630 break;
3631 case SCS_XX:
3632 goto normal_insn;
3633 default:
3634 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
3635 "unreachable");
3636 return COMPILE_NG;
3637 }
3638 /* remove useless pop */
3639 ELEM_REMOVE(list);
3640 list = list->next;
3641 goto redo_point;
3642 }
3643 default:;
3644 /* none */
3645 } /* end of switch */
3646 normal_insn:
3647 state = insn_set_sc_state(iseq, anchor, iobj, state);
3648 break;
3649 }
3650 case ISEQ_ELEMENT_LABEL:
3651 {
3652 LABEL *lobj;
3653 lobj = (LABEL *)list;
3654
3655 state = label_set_sc_state(lobj, state);
3656 }
3657 default:
3658 break;
3659 }
3660 list = list->next;
3661 }
3662 #endif
3663 return COMPILE_OK;
3664 }
3665
3666 static int
3667 all_string_result_p(const NODE *node)
3668 {
3669 if (!node) return FALSE;
3670 switch (nd_type(node)) {
3671 case NODE_STR: case NODE_DSTR:
3672 return TRUE;
3673 case NODE_IF: case NODE_UNLESS:
3674 if (!node->nd_body || !node->nd_else) return FALSE;
3675 if (all_string_result_p(node->nd_body))
3676 return all_string_result_p(node->nd_else);
3677 return FALSE;
3678 case NODE_AND: case NODE_OR:
3679 if (!node->nd_2nd)
3680 return all_string_result_p(node->nd_1st);
3681 if (!all_string_result_p(node->nd_1st))
3682 return FALSE;
3683 return all_string_result_p(node->nd_2nd);
3684 default:
3685 return FALSE;
3686 }
3687 }
3688
3689 static int
3690 compile_dstr_fragments(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int *cntp)
3691 {
3692 const NODE *list = node->nd_next;
3693 VALUE lit = node->nd_lit;
3694 LINK_ELEMENT *first_lit = 0;
3695 int cnt = 0;
3696
3697 debugp_param("nd_lit", lit);
3698 if (!NIL_P(lit)) {
3699 cnt++;
3700 if (!RB_TYPE_P(lit, T_STRING)) {
3701 COMPILE_ERROR(ERROR_ARGS "dstr: must be string: %s",
3702 rb_builtin_type_name(TYPE(lit)));
3703 return COMPILE_NG;
3704 }
3705 lit = rb_fstring(lit);
3706 ADD_INSN1(ret, nd_line(node), putobject, lit);
3707 RB_OBJ_WRITTEN(iseq, Qundef, lit);
3708 if (RSTRING_LEN(lit) == 0) first_lit = LAST_ELEMENT(ret);
3709 }
3710
3711 while (list) {
3712 const NODE *const head = list->nd_head;
3713 if (nd_type(head) == NODE_STR) {
3714 lit = rb_fstring(head->nd_lit);
3715 ADD_INSN1(ret, nd_line(head), putobject, lit);
3716 RB_OBJ_WRITTEN(iseq, Qundef, lit);
3717 lit = Qnil;
3718 }
3719 else {
3720 CHECK(COMPILE(ret, "each string", head));
3721 }
3722 cnt++;
3723 list = list->nd_next;
3724 }
3725 if (NIL_P(lit) && first_lit) {
3726 ELEM_REMOVE(first_lit);
3727 --cnt;
3728 }
3729 *cntp = cnt;
3730
3731 return COMPILE_OK;
3732 }
3733
3734 static int
3735 compile_dstr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node)
3736 {
3737 int cnt;
3738 CHECK(compile_dstr_fragments(iseq, ret, node, &cnt));
3739 ADD_INSN1(ret, nd_line(node), concatstrings, INT2FIX(cnt));
3740 return COMPILE_OK;
3741 }
3742
3743 static int
3744 compile_dregx(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node)
3745 {
3746 int cnt;
3747 CHECK(compile_dstr_fragments(iseq, ret, node, &cnt));
3748 ADD_INSN2(ret, nd_line(node), toregexp, INT2FIX(node->nd_cflag), INT2FIX(cnt));
3749 return COMPILE_OK;
3750 }
3751
3752 static int
3753 compile_flip_flop(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int again,
3754 LABEL *then_label, LABEL *else_label)
3755 {
3756 const int line = nd_line(node);
3757 LABEL *lend = NEW_LABEL(line);
3758 rb_num_t cnt = ISEQ_FLIP_CNT_INCREMENT(iseq->body->local_iseq)
3759 + VM_SVAR_FLIPFLOP_START;
3760 VALUE key = INT2FIX(cnt);
3761
3762 ADD_INSN2(ret, line, getspecial, key, INT2FIX(0));
3763 ADD_INSNL(ret, line, branchif, lend);
3764
3765 /* *flip == 0 */
3766 CHECK(COMPILE(ret, "flip2 beg", node->nd_beg));
3767 ADD_INSNL(ret, line, branchunless, else_label);
3768 ADD_INSN1(ret, line, putobject, Qtrue);
3769 ADD_INSN1(ret, line, setspecial, key);
3770 if (!again) {
3771 ADD_INSNL(ret, line, jump, then_label);
3772 }
3773
3774 /* *flip == 1 */
3775 ADD_LABEL(ret, lend);
3776 CHECK(COMPILE(ret, "flip2 end", node->nd_end));
3777 ADD_INSNL(ret, line, branchunless, then_label);
3778 ADD_INSN1(ret, line, putobject, Qfalse);
3779 ADD_INSN1(ret, line, setspecial, key);
3780 ADD_INSNL(ret, line, jump, then_label);
3781
3782 return COMPILE_OK;
3783 }
3784
3785 static int
3786 compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *cond,
3787 LABEL *then_label, LABEL *else_label)
3788 {
3789 again:
3790 switch (nd_type(cond)) {
3791 case NODE_AND:
3792 {
3793 LABEL *label = NEW_LABEL(nd_line(cond));
3794 CHECK(compile_branch_condition(iseq, ret, cond->nd_1st, label,
3795 else_label));
3796 if (!label->refcnt) break;
3797 ADD_LABEL(ret, label);
3798 cond = cond->nd_2nd;
3799 goto again;
3800 }
3801 case NODE_OR:
3802 {
3803 LABEL *label = NEW_LABEL(nd_line(cond));
3804 CHECK(compile_branch_condition(iseq, ret, cond->nd_1st, then_label,
3805 label));
3806 if (!label->refcnt) break;
3807 ADD_LABEL(ret, label);
3808 cond = cond->nd_2nd;
3809 goto again;
3810 }
3811 case NODE_LIT: /* NODE_LIT is always true */
3812 case NODE_TRUE:
3813 case NODE_STR:
3814 case NODE_ZLIST:
3815 case NODE_LAMBDA:
3816 /* printf("useless condition eliminate (%s)\n", ruby_node_name(nd_type(cond))); */
3817 ADD_INSNL(ret, nd_line(cond), jump, then_label);
3818 break;
3819 case NODE_FALSE:
3820 case NODE_NIL:
3821 /* printf("useless condition eliminate (%s)\n", ruby_node_name(nd_type(cond))); */
3822 ADD_INSNL(ret, nd_line(cond), jump, else_label);
3823 break;
3824 case NODE_LIST:
3825 case NODE_ARGSCAT:
3826 case NODE_DREGX:
3827 case NODE_DSTR:
3828 CHECK(COMPILE_POPPED(ret, "branch condition", cond));
3829 ADD_INSNL(ret, nd_line(cond), jump, then_label);
3830 break;
3831 case NODE_FLIP2:
3832 CHECK(compile_flip_flop(iseq, ret, cond, TRUE, then_label, else_label));
3833 break;
3834 case NODE_FLIP3:
3835 CHECK(compile_flip_flop(iseq, ret, cond, FALSE, then_label, else_label));
3836 break;
3837 case NODE_DEFINED:
3838 CHECK(compile_defined_expr(iseq, ret, cond, Qfalse));
3839 goto branch;
3840 default:
3841 CHECK(COMPILE(ret, "branch condition", cond));
3842 branch:
3843 ADD_INSNL(ret, nd_line(cond), branchunless, else_label);
3844 ADD_INSNL(ret, nd_line(cond), jump, then_label);
3845 break;
3846 }
3847 return COMPILE_OK;
3848 }
3849
3850 static int
3851 keyword_node_p(const NODE *const node)
3852 {
3853 return nd_type(node) == NODE_HASH && node->nd_brace == FALSE;
3854 }
3855
3856 static int
3857 compile_keyword_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
3858 const NODE *const root_node,
3859 struct rb_call_info_kw_arg **const kw_arg_ptr,
3860 unsigned int *flag)
3861 {
3862 if (kw_arg_ptr == NULL) return FALSE;
3863
3864 if (keyword_node_p(root_node) && root_node->nd_head && nd_type(root_node->nd_head) == NODE_LIST) {
3865 const NODE *node = root_node->nd_head;
3866
3867 while (node) {
3868 const NODE *key_node = node->nd_head;
3869
3870 assert(nd_type(node) == NODE_LIST);
3871 if (!key_node) {
3872 if (flag) *flag |= VM_CALL_KW_SPLAT;
3873 return FALSE;
3874 }
3875 else if (nd_type(key_node) == NODE_LIT && RB_TYPE_P(key_node->nd_lit, T_SYMBOL)) {
3876 /* can be keywords */
3877 }
3878 else {
3879 if (flag) *flag |= VM_CALL_KW_SPLAT;
3880 return FALSE;
3881 }
3882 node = node->nd_next; /* skip value node */
3883 node = node->nd_next;
3884 }
3885
3886 /* may be keywords */
3887 node = root_node->nd_head;
3888 {
3889 int len = (int)node->nd_alen / 2;
3890 struct rb_call_info_kw_arg *kw_arg =
3891 rb_xmalloc_mul_add(len - 1, sizeof(VALUE), sizeof(struct rb_call_info_kw_arg));
3892 VALUE *keywords = kw_arg->keywords;
3893 int i = 0;
3894 kw_arg->keyword_len = len;
3895
3896 *kw_arg_ptr = kw_arg;
3897
3898 for (i=0; node != NULL; i++, node = node->nd_next->nd_next) {
3899 const NODE *key_node = node->nd_head;
3900 const NODE *val_node = node->nd_next->nd_head;
3901 keywords[i] = key_node->nd_lit;
3902 NO_CHECK(COMPILE(ret, "keyword values", val_node));
3903 }
3904 assert(i == len);
3905 return TRUE;
3906 }
3907 }
3908 return FALSE;
3909 }
3910
3911 static int
3912 compile_args(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node,
3913 struct rb_call_info_kw_arg **keywords_ptr, unsigned int *flag)
3914 {
3915 int len = 0;
3916
3917 for (; node; len++, node = node->nd_next) {
3918 if (CPDEBUG > 0) {
3919 EXPECT_NODE("compile_args", node, NODE_LIST, -1);
3920 }
3921
3922 if (node->nd_next == NULL /* last node */ &&
3923 compile_keyword_arg(iseq, ret, node->nd_head, keywords_ptr, flag)) {
3924 len--;
3925 }
3926 else {
3927 NO_CHECK(COMPILE_(ret, "array element", node->nd_head, FALSE));
3928 }
3929 }
3930
3931 return len;
3932 }
3933
3934 static inline int
3935 static_literal_node_p(const NODE *node, const rb_iseq_t *iseq)
3936 {
3937 node = node->nd_head;
3938 switch (nd_type(node)) {
3939 case NODE_LIT:
3940 case NODE_NIL:
3941 case NODE_TRUE:
3942 case NODE_FALSE:
3943 return TRUE;
3944 case NODE_STR:
3945 return ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal;
3946 default:
3947 return FALSE;
3948 }
3949 }
3950
3951 static inline VALUE
3952 static_literal_value(const NODE *node, rb_iseq_t *iseq)
3953 {
3954 node = node->nd_head;
3955 switch (nd_type(node)) {
3956 case NODE_NIL:
3957 return Qnil;
3958 case NODE_TRUE:
3959 return Qtrue;
3960 case NODE_FALSE:
3961 return Qfalse;
3962 case NODE_STR:
3963 if (ISEQ_COMPILE_DATA(iseq)->option->debug_frozen_string_literal || RTEST(ruby_debug)) {
3964 VALUE lit;
3965 VALUE debug_info = rb_ary_new_from_args(2, rb_iseq_path(iseq), INT2FIX((int)nd_line(node)));
3966 lit = rb_str_dup(node->nd_lit);
3967 rb_ivar_set(lit, id_debug_created_info, rb_obj_freeze(debug_info));
3968 return rb_str_freeze(lit);
3969 }
3970 else {
3971 return rb_fstring(node->nd_lit);
3972 }
3973 default:
3974 return node->nd_lit;
3975 }
3976 }
3977
3978 static int
3979 compile_array(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int popped)
3980 {
3981 int line = (int)nd_line(node);
3982
3983 if (nd_type(node) == NODE_ZLIST) {
3984 if (!popped) {
3985 ADD_INSN1(ret, line, newarray, INT2FIX(0));
3986 }
3987 return 0;
3988 }
3989
3990 EXPECT_NODE("compile_array", node, NODE_LIST, -1);
3991
3992 if (popped) {
3993 for (; node; node = node->nd_next) {
3994 NO_CHECK(COMPILE_(ret, "array element", node->nd_head, popped));
3995 }
3996 return 1;
3997 }
3998
3999 /* Compilation of an array literal.
4000 * The following code is essentially the same as:
4001 *
4002 * for (int count = 0; node; count++; node->nd_next) {
4003 * compile(node->nd_head);
4004 * }
4005 * ADD_INSN(newarray, count);
4006 *
4007 * However, there are three points.
4008 *
4009 * - The code above causes stack overflow for a big string literal.
4010 * The following limits the stack length up to max_stack_len.
4011 *
4012 * [x1,x2,...,x10000] =>
4013 * push x1 ; push x2 ; ...; push x256; newarray 256;
4014 * push x257; push x258; ...; push x512; newarray 256; concatarray;
4015 * push x513; push x514; ...; push x768; newarray 256; concatarray;
4016 * ...
4017 *
4018 * - Long subarray can be optimized by pre-allocating a hidden array.
4019 *
4020 * [1,2,3,...,100] =>
4021 * duparray [1,2,3,...,100]
4022 *
4023 * [x, 1,2,3,...,100, z] =>
4024 * push x; newarray 1;
4025 * putobject [1,2,3,...,100] (<- hidden array); concatarray;
4026 * push z; newarray 1; concatarray
4027 *
4028 * - If the last element is a keyword, newarraykwsplat should be emitted
4029 * to check and remove empty keyword arguments hash from array.
4030 * (Note: a keyword is NODE_HASH which is not static_literal_node_p.)
4031 *
4032 * [1,2,3,**kw] =>
4033 * putobject 1; putobject 2; putobject 3; push kw; newarraykwsplat
4034 */
4035
4036 const int max_stack_len = 0x100;
4037 const int min_tmp_ary_len = 0x40;
4038 int stack_len = 0;
4039 int first_chunk = 1;
4040
4041 /* Convert pushed elements to an array, and concatarray if needed */
4042 #define FLUSH_CHUNK(newarrayinsn) \
4043 if (stack_len) { \
4044 ADD_INSN1(ret, line, newarrayinsn, INT2FIX(stack_len)); \
4045 if (!first_chunk) ADD_INSN(ret, line, concatarray); \
4046 first_chunk = stack_len = 0; \
4047 }
4048
4049 while (node) {
4050 int count = 1;
4051
4052 /* pre-allocation check (this branch can be omittable) */
4053 if (static_literal_node_p(node, iseq)) {
4054 /* count the elements that are optimizable */
4055 const NODE *node_tmp = node->nd_next;
4056 for (; node_tmp && static_literal_node_p(node_tmp, iseq); node_tmp = node_tmp->nd_next)
4057 count++;
4058
4059 if ((first_chunk && stack_len == 0 && !node_tmp) || count >= min_tmp_ary_len) {
4060 /* The literal contains only optimizable elements, or the subarray is long enough */
4061 VALUE ary = rb_ary_tmp_new(count);
4062
4063 /* Create a hidden array */
4064 for (; count; count--, node = node->nd_next)
4065 rb_ary_push(ary, static_literal_value(node, iseq));
4066 OBJ_FREEZE(ary);
4067
4068 /* Emit optimized code */
4069 FLUSH_CHUNK(newarray);
4070 if (first_chunk) {
4071 ADD_INSN1(ret, line, duparray, ary);
4072 first_chunk = 0;
4073 }
4074 else {
4075 ADD_INSN1(ret, line, putobject, ary);
4076 ADD_INSN(ret, line, concatarray);
4077 }
4078 RB_OBJ_WRITTEN(iseq, Qundef, ary);
4079 }
4080 }
4081
4082 /* Base case: Compile "count" elements */
4083 for (; count; count--, node = node->nd_next) {
4084 if (CPDEBUG > 0) {
4085 EXPECT_NODE("compile_array", node, NODE_LIST, -1);
4086 }
4087
4088 NO_CHECK(COMPILE_(ret, "array element", node->nd_head, 0));
4089 stack_len++;
4090
4091 if (!node->nd_next && keyword_node_p(node->nd_head)) {
4092 /* Reached the end, and the last element is a keyword */
4093 FLUSH_CHUNK(newarraykwsplat);
4094 return 1;
4095 }
4096
4097 /* If there are many pushed elements, flush them to avoid stack overflow */
4098 if (stack_len >= max_stack_len) FLUSH_CHUNK(newarray);
4099 }
4100 }
4101
4102 FLUSH_CHUNK(newarray);
4103 #undef FLUSH_CHUNK
4104 return 1;
4105 }
4106
4107 static inline int
4108 static_literal_node_pair_p(const NODE *node, const rb_iseq_t *iseq)
4109 {
4110 return node->nd_head && static_literal_node_p(node, iseq) && static_literal_node_p(node->nd_next, iseq);
4111 }
4112
4113 static int
4114 compile_hash(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int popped)
4115 {
4116 int line = (int)nd_line(node);
4117
4118 node = node->nd_head;
4119
4120 if (!node || nd_type(node) == NODE_ZLIST) {
4121 if (!popped) {
4122 ADD_INSN1(ret, line, newhash, INT2FIX(0));
4123 }
4124 return 0;
4125 }
4126
4127 EXPECT_NODE("compile_hash", node, NODE_LIST, -1);
4128
4129 if (popped) {
4130 for (; node; node = node->nd_next) {
4131 NO_CHECK(COMPILE_(ret, "hash element", node->nd_head, popped));
4132 }
4133 return 1;
4134 }
4135
4136 /* Compilation of a hash literal (or keyword arguments).
4137 * This is very similar to compile_array, but there are some differences:
4138 *
4139 * - It contains key-value pairs. So we need to take every two elements.
4140 * We can assume that the length is always even.
4141 *
4142 * - Merging is done by a method call (id_core_hash_merge_ptr).
4143 * Sometimes we need to insert the receiver, so "anchor" is needed.
4144 * In addition, a method call is much slower than concatarray.
4145 * So it pays only when the subsequence is really long.
4146 * (min_tmp_hash_len must be much larger than min_tmp_ary_len.)
4147 *
4148 * - We need to handle keyword splat: **kw.
4149 * For **kw, the key part (node->nd_head) is NULL, and the value part
4150 * (node->nd_next->nd_head) is "kw".
4151 * The code is a bit difficult to avoid hash allocation for **{}.
4152 */
4153
4154 const int max_stack_len = 0x100;
4155 const int min_tmp_hash_len = 0x800;
4156 int stack_len = 0;
4157 int first_chunk = 1;
4158 DECL_ANCHOR(anchor);
4159 INIT_ANCHOR(anchor);
4160
4161 /* Convert pushed elements to a hash, and merge if needed */
4162 #define FLUSH_CHUNK() \
4163 if (stack_len) { \
4164 if (first_chunk) { \
4165 APPEND_LIST(ret, anchor); \
4166 ADD_INSN1(ret, line, newhash, INT2FIX(stack_len)); \
4167 } \
4168 else { \
4169 ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE)); \
4170 ADD_INSN(ret, line, swap); \
4171 APPEND_LIST(ret, anchor); \
4172 ADD_SEND(ret, line, id_core_hash_merge_ptr, INT2FIX(stack_len + 1)); \
4173 } \
4174 INIT_ANCHOR(anchor); \
4175 first_chunk = stack_len = 0; \
4176 }
4177
4178 while (node) {
4179 int count = 1;
4180
4181 /* pre-allocation check (this branch can be omittable) */
4182 if (static_literal_node_pair_p(node, iseq)) {
4183 /* count the elements that are optimizable */
4184 const NODE *node_tmp = node->nd_next->nd_next;
4185 for (; node_tmp && static_literal_node_pair_p(node_tmp, iseq); node_tmp = node_tmp->nd_next->nd_next)
4186 count++;
4187
4188 if ((first_chunk && stack_len == 0 && !node_tmp) || count >= min_tmp_hash_len) {
4189 /* The literal contains only optimizable elements, or the subsequence is long enough */
4190 VALUE ary = rb_ary_tmp_new(count);
4191
4192 /* Create a hidden hash */
4193 for (; count; count--, node = node->nd_next->nd_next) {
4194 VALUE elem[2];
4195 elem[0] = static_literal_value(node, iseq);
4196 elem[1] = static_literal_value(node->nd_next, iseq);
4197 rb_ary_cat(ary, elem, 2);
4198 }
4199 VALUE hash = rb_hash_new_with_size(RARRAY_LEN(ary) / 2);
4200 rb_hash_bulk_insert(RARRAY_LEN(ary), RARRAY_CONST_PTR_TRANSIENT(ary), hash);
4201 hash = rb_obj_hide(hash);
4202 OBJ_FREEZE(hash);
4203
4204 /* Emit optimized code */
4205 FLUSH_CHUNK();
4206 if (first_chunk) {
4207 ADD_INSN1(ret, line, duphash, hash);
4208 first_chunk = 0;
4209 }
4210 else {
4211 ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
4212 ADD_INSN(ret, line, swap);
4213
4214 ADD_INSN1(ret, line, putobject, hash);
4215
4216 ADD_SEND(ret, line, id_core_hash_merge_kwd, INT2FIX(2));
4217 }
4218 RB_OBJ_WRITTEN(iseq, Qundef, hash);
4219 }
4220 }
4221
4222 /* Base case: Compile "count" elements */
4223 for (; count; count--, node = node->nd_next->nd_next) {
4224
4225 if (CPDEBUG > 0) {
4226 EXPECT_NODE("compile_hash", node, NODE_LIST, -1);
4227 }
4228
4229 if (node->nd_head) {
4230 /* Normal key-value pair */
4231 NO_CHECK(COMPILE_(anchor, "hash key element", node->nd_head, 0));
4232 NO_CHECK(COMPILE_(anchor, "hash value element", node->nd_next->nd_head, 0));
4233 stack_len += 2;
4234
4235 /* If there are many pushed elements, flush them to avoid stack overflow */
4236 if (stack_len >= max_stack_len) FLUSH_CHUNK();
4237 }
4238 else {
4239 /* kwsplat case: foo(..., **kw, ...) */
4240 FLUSH_CHUNK();
4241
4242 const NODE *kw = node->nd_next->nd_head;
4243 int empty_kw = nd_type(kw) == NODE_LIT; /* foo( ..., **{}, ...) */
4244 int first_kw = first_chunk && stack_len == 0; /* foo(1,2,3, **kw, ...) */
4245 int last_kw = !node->nd_next->nd_next; /* foo( ..., **kw) */
4246 int only_kw = last_kw && first_kw; /* foo(1,2,3, **kw) */
4247
4248 if (empty_kw) {
4249 if (only_kw) {
4250 /* **{} appears at the last, so it won't be modified.
4251 * kw is a special NODE_LIT that contains a special empty hash,
4252 * so this emits: putobject {}
4253 */
4254 NO_CHECK(COMPILE(ret, "keyword splat", kw));
4255 }
4256 else if (first_kw) {
4257 /* **{} appears at the first, so it may be modified.
4258 * We need to create a fresh hash object.
4259 */
4260 ADD_INSN1(ret, line, newhash, INT2FIX(0));
4261 }
4262 }
4263 else {
4264 /* This is not empty hash: **{k:1}.
4265 * We need to clone the hash (if first), or merge the hash to
4266 * the accumulated hash (if not first).
4267 */
4268 ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
4269 if (first_kw) ADD_INSN1(ret, line, newhash, INT2FIX(0));
4270 else ADD_INSN(ret, line, swap);
4271
4272 NO_CHECK(COMPILE(ret, "keyword splat", kw));
4273
4274 ADD_SEND(ret, line, id_core_hash_merge_kwd, INT2FIX(2));
4275 }
4276
4277 first_chunk = 0;
4278 }
4279 }
4280 }
4281
4282 FLUSH_CHUNK();
4283 #undef FLUSH_CHUNK
4284 return 1;
4285 }
4286
4287 VALUE
4288 rb_node_case_when_optimizable_literal(const NODE *const node)
4289 {
4290 switch (nd_type(node)) {
4291 case NODE_LIT: {
4292 VALUE v = node->nd_lit;
4293 double ival;
4294 if (RB_TYPE_P(v, T_FLOAT) &&
4295 modf(RFLOAT_VALUE(v), &ival) == 0.0) {
4296 return FIXABLE(ival) ? LONG2FIX((long)ival) : rb_dbl2big(ival);
4297 }
4298 if (SYMBOL_P(v) || rb_obj_is_kind_of(v, rb_cNumeric)) {
4299 return v;
4300 }
4301 break;
4302 }
4303 case NODE_NIL:
4304 return Qnil;
4305 case NODE_TRUE:
4306 return Qtrue;
4307 case NODE_FALSE:
4308 return Qfalse;
4309 case NODE_STR:
4310 return rb_fstring(node->nd_lit);
4311 }
4312 return Qundef;
4313 }
4314
4315 static int
4316 when_vals(rb_iseq_t *iseq, LINK_ANCHOR *const cond_seq, const NODE *vals,
4317 LABEL *l1, int only_special_literals, VALUE literals)
4318 {
4319 while (vals) {
4320 const NODE *val = vals->nd_head;
4321 VALUE lit = rb_node_case_when_optimizable_literal(val);
4322
4323 if (lit == Qundef) {
4324 only_special_literals = 0;
4325 }
4326 else if (NIL_P(rb_hash_lookup(literals, lit))) {
4327 rb_hash_aset(literals, lit, (VALUE)(l1) | 1);
4328 }
4329
4330 ADD_INSN(cond_seq, nd_line(val), dup); /* dup target */
4331
4332 if (nd_type(val) == NODE_STR) {
4333 debugp_param("nd_lit", val->nd_lit);
4334 lit = rb_fstring(val->nd_lit);
4335 ADD_INSN1(cond_seq, nd_line(val), putobject, lit);
4336 RB_OBJ_WRITTEN(iseq, Qundef, lit);
4337 }
4338 else {
4339 if (!COMPILE(cond_seq, "when cond", val)) return -1;
4340 }
4341
4342 ADD_INSN1(cond_seq, nd_line(vals), checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE));
4343 ADD_INSNL(cond_seq, nd_line(val), branchif, l1);
4344 vals = vals->nd_next;
4345 }
4346 return only_special_literals;
4347 }
4348
4349 static int
4350 when_splat_vals(rb_iseq_t *iseq, LINK_ANCHOR *const cond_seq, const NODE *vals,
4351 LABEL *l1, int only_special_literals, VALUE literals)
4352 {
4353 const int line = nd_line(vals);
4354
4355 switch (nd_type(vals)) {
4356 case NODE_LIST:
4357 if (when_vals(iseq, cond_seq, vals, l1, only_special_literals, literals) < 0)
4358 return COMPILE_NG;
4359 break;
4360 case NODE_SPLAT:
4361 ADD_INSN (cond_seq, line, dup);
4362 CHECK(COMPILE(cond_seq, "when splat", vals->nd_head));
4363 ADD_INSN1(cond_seq, line, splatarray, Qfalse);
4364 ADD_INSN1(cond_seq, line, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE | VM_CHECKMATCH_ARRAY));
4365 ADD_INSNL(cond_seq, line, branchif, l1);
4366 break;
4367 case NODE_ARGSCAT:
4368 CHECK(when_splat_vals(iseq, cond_seq, vals->nd_head, l1, only_special_literals, literals));
4369 CHECK(when_splat_vals(iseq, cond_seq, vals->nd_body, l1, only_special_literals, literals));
4370 break;
4371 case NODE_ARGSPUSH:
4372 CHECK(when_splat_vals(iseq, cond_seq, vals->nd_head, l1, only_special_literals, literals));
4373 ADD_INSN (cond_seq, line, dup);
4374 CHECK(COMPILE(cond_seq, "when argspush body", vals->nd_body));
4375 ADD_INSN1(cond_seq, line, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE));
4376 ADD_INSNL(cond_seq, line, branchif, l1);
4377 break;
4378 default:
4379 ADD_INSN (cond_seq, line, dup);
4380 CHECK(COMPILE(cond_seq, "when val", vals));
4381 ADD_INSN1(cond_seq, line, splatarray, Qfalse);
4382 ADD_INSN1(cond_seq, line, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE | VM_CHECKMATCH_ARRAY));
4383 ADD_INSNL(cond_seq, line, branchif, l1);
4384 break;
4385 }
4386 return COMPILE_OK;
4387 }
4388
4389
4390 static int
4391 compile_massign_lhs(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node)
4392 {
4393 switch (nd_type(node)) {
4394 case NODE_ATTRASGN: {
4395 INSN *iobj;
4396 struct rb_call_info *ci;
4397 VALUE dupidx;
4398 int line = nd_line(node);
4399
4400 CHECK(COMPILE_POPPED(ret, "masgn lhs (NODE_ATTRASGN)", node));
4401
4402 iobj = (INSN *)get_prev_insn((INSN *)LAST_ELEMENT(ret)); /* send insn */
4403 ci = (struct rb_call_info *)OPERAND_AT(iobj, 0);
4404 ci->orig_argc += 1;
4405 dupidx = INT2FIX(ci->orig_argc);
4406
4407 INSERT_BEFORE_INSN1(iobj, line, topn, dupidx);
4408 if (ci->flag & VM_CALL_ARGS_SPLAT) {
4409 --ci->orig_argc;
4410 INSERT_BEFORE_INSN1(iobj, line, newarray, INT2FIX(1));
4411 INSERT_BEFORE_INSN(iobj, line, concatarray);
4412 }
4413 ADD_INSN(ret, line, pop); /* result */
4414 break;
4415 }
4416 case NODE_MASGN: {
4417 DECL_ANCHOR(anchor);
4418 INIT_ANCHOR(anchor);
4419 CHECK(COMPILE_POPPED(anchor, "nest masgn lhs", node));
4420 ELEM_REMOVE(FIRST_ELEMENT(anchor));
4421 ADD_SEQ(ret, anchor);
4422 break;
4423 }
4424 default: {
4425 DECL_ANCHOR(anchor);
4426 INIT_ANCHOR(anchor);
4427 CHECK(COMPILE_POPPED(anchor, "masgn lhs", node));
4428 ELEM_REMOVE(FIRST_ELEMENT(anchor));
4429 ADD_SEQ(ret, anchor);
4430 }
4431 }
4432
4433 return COMPILE_OK;
4434 }
4435
4436 static int
4437 compile_massign_opt_lhs(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *lhsn)
4438 {
4439 if (lhsn) {
4440 CHECK(compile_massign_opt_lhs(iseq, ret, lhsn->nd_next));
4441 CHECK(compile_massign_lhs(iseq, ret, lhsn->nd_head));
4442 }
4443 return COMPILE_OK;
4444 }
4445
4446 static int
4447 compile_massign_opt(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
4448 const NODE *rhsn, const NODE *orig_lhsn)
4449 {
4450 VALUE mem[64];
4451 const int memsize = numberof(mem);
4452 int memindex = 0;
4453 int llen = 0, rlen = 0;
4454 int i;
4455 const NODE *lhsn = orig_lhsn;
4456
4457 #define MEMORY(v) { \
4458 int i; \
4459 if (memindex == memsize) return 0; \
4460 for (i=0; i<memindex; i++) { \
4461 if (mem[i] == (v)) return 0; \
4462 } \
4463 mem[memindex++] = (v); \
4464 }
4465
4466 if (rhsn == 0 || nd_type(rhsn) != NODE_LIST) {
4467 return 0;
4468 }
4469
4470 while (lhsn) {
4471 const NODE *ln = lhsn->nd_head;
4472 switch (nd_type(ln)) {
4473 case NODE_LASGN:
4474 MEMORY(ln->nd_vid);
4475 break;
4476 case NODE_DASGN:
4477 case NODE_DASGN_CURR:
4478 case NODE_IASGN:
4479 case NODE_CVASGN:
4480 MEMORY(ln->nd_vid);
4481 break;
4482 default:
4483 return 0;
4484 }
4485 lhsn = lhsn->nd_next;
4486 llen++;
4487 }
4488
4489 while (rhsn) {
4490 if (llen <= rlen) {
4491 NO_CHECK(COMPILE_POPPED(ret, "masgn val (popped)", rhsn->nd_head));
4492 }
4493 else {
4494 NO_CHECK(COMPILE(ret, "masgn val", rhsn->nd_head));
4495 }
4496 rhsn = rhsn->nd_next;
4497 rlen++;
4498 }
4499
4500 if (llen > rlen) {
4501 for (i=0; i<llen-rlen; i++) {
4502 ADD_INSN(ret, nd_line(orig_lhsn), putnil);
4503 }
4504 }
4505
4506 compile_massign_opt_lhs(iseq, ret, orig_lhsn);
4507 return 1;
4508 }
4509
4510 static void
4511 adjust_stack(rb_iseq_t *iseq, LINK_ANCHOR *const ret, int line, int rlen, int llen)
4512 {
4513 if (rlen < llen) {
4514 do {ADD_INSN(ret, line, putnil);} while (++rlen < llen);
4515 }
4516 else if (rlen > llen) {
4517 do {ADD_INSN(ret, line, pop);} while (--rlen > llen);
4518 }
4519 }
4520
4521 static int
4522 compile_massign(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
4523 {
4524 const NODE *rhsn = node->nd_value;
4525 const NODE *splatn = node->nd_args;
4526 const NODE *lhsn = node->nd_head;
4527 int lhs_splat = (splatn && NODE_NAMED_REST_P(splatn)) ? 1 : 0;
4528
4529 if (!popped || splatn || !compile_massign_opt(iseq, ret, rhsn, lhsn)) {
4530 int llen = 0;
4531 int expand = 1;
4532 DECL_ANCHOR(lhsseq);
4533
4534 INIT_ANCHOR(lhsseq);
4535
4536 while (lhsn) {
4537 CHECK(compile_massign_lhs(iseq, lhsseq, lhsn->nd_head));
4538 llen += 1;
4539 lhsn = lhsn->nd_next;
4540 }
4541
4542 NO_CHECK(COMPILE(ret, "normal masgn rhs", rhsn));
4543
4544 if (!popped) {
4545 ADD_INSN(ret, nd_line(node), dup);
4546 }
4547 else if (!lhs_splat) {
4548 INSN *last = (INSN*)ret->last;
4549 if (IS_INSN(&last->link) &&
4550 IS_INSN_ID(last, newarray) &&
4551 last->operand_size == 1) {
4552 int rlen = FIX2INT(OPERAND_AT(last, 0));
4553 /* special case: assign to aset or attrset */
4554 if (llen == 2) {
4555 POP_ELEMENT(ret);
4556 adjust_stack(iseq, ret, nd_line(node), rlen, llen);
4557 ADD_INSN(ret, nd_line(node), swap);
4558 expand = 0;
4559 }
4560 else if (llen > 2 && llen != rlen) {
4561 POP_ELEMENT(ret);
4562 adjust_stack(iseq, ret, nd_line(node), rlen, llen);
4563 ADD_INSN1(ret, nd_line(node), reverse, INT2FIX(llen));
4564 expand = 0;
4565 }
4566 else if (llen > 2) {
4567 last->insn_id = BIN(reverse);
4568 expand = 0;
4569 }
4570 }
4571 }
4572 if (expand) {
4573 ADD_INSN2(ret, nd_line(node), expandarray,
4574 INT2FIX(llen), INT2FIX(lhs_splat));
4575 }
4576 ADD_SEQ(ret, lhsseq);
4577
4578 if (lhs_splat) {
4579 if (nd_type(splatn) == NODE_POSTARG) {
4580 /*a, b, *r, p1, p2 */
4581 const NODE *postn = splatn->nd_2nd;
4582 const NODE *restn = splatn->nd_1st;
4583 int num = (int)postn->nd_alen;
4584 int flag = 0x02 | (NODE_NAMED_REST_P(restn) ? 0x01 : 0x00);
4585
4586 ADD_INSN2(ret, nd_line(splatn), expandarray,
4587 INT2FIX(num), INT2FIX(flag));
4588
4589 if (NODE_NAMED_REST_P(restn)) {
4590 CHECK(compile_massign_lhs(iseq, ret, restn));
4591 }
4592 while (postn) {
4593 CHECK(compile_massign_lhs(iseq, ret, postn->nd_head));
4594 postn = postn->nd_next;
4595 }
4596 }
4597 else {
4598 /* a, b, *r */
4599 CHECK(compile_massign_lhs(iseq, ret, splatn));
4600 }
4601 }
4602 }
4603 return COMPILE_OK;
4604 }
4605
4606 static int
4607 compile_const_prefix(rb_iseq_t *iseq, const NODE *const node,
4608 LINK_ANCHOR *const pref, LINK_ANCHOR *const body)
4609 {
4610 switch (nd_type(node)) {
4611 case NODE_CONST:
4612 debugi("compile_const_prefix - colon", node->nd_vid);
4613 ADD_INSN1(body, nd_line(node), putobject, Qtrue);
4614 ADD_INSN1(body, nd_line(node), getconstant, ID2SYM(node->nd_vid));
4615 break;
4616 case NODE_COLON3:
4617 debugi("compile_const_prefix - colon3", node->nd_mid);
4618 ADD_INSN(body, nd_line(node), pop);
4619 ADD_INSN1(body, nd_line(node), putobject, rb_cObject);
4620 ADD_INSN1(body, nd_line(node), putobject, Qtrue);
4621 ADD_INSN1(body, nd_line(node), getconstant, ID2SYM(node->nd_mid));
4622 break;
4623 case NODE_COLON2:
4624 CHECK(compile_const_prefix(iseq, node->nd_head, pref, body));
4625 debugi("compile_const_prefix - colon2", node->nd_mid);
4626 ADD_INSN1(body, nd_line(node), putobject, Qfalse);
4627 ADD_INSN1(body, nd_line(node), getconstant, ID2SYM(node->nd_mid));
4628 break;
4629 default:
4630 CHECK(COMPILE(pref, "const colon2 prefix", node));
4631 break;
4632 }
4633 return COMPILE_OK;
4634 }
4635
4636 static int
4637 compile_cpath(LINK_ANCHOR *const ret, rb_iseq_t *iseq, const NODE *cpath)
4638 {
4639 if (nd_type(cpath) == NODE_COLON3) {
4640 /* toplevel class ::Foo */
4641 ADD_INSN1(ret, nd_line(cpath), putobject, rb_cObject);
4642 return VM_DEFINECLASS_FLAG_SCOPED;
4643 }
4644 else if (cpath->nd_head) {
4645 /* Bar::Foo */
4646 NO_CHECK(COMPILE(ret, "nd_else->nd_head", cpath->nd_head));
4647 return VM_DEFINECLASS_FLAG_SCOPED;
4648 }
4649 else {
4650 /* class at cbase Foo */
4651 ADD_INSN1(ret, nd_line(cpath), putspecialobject,
4652 INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
4653 return 0;
4654 }
4655 }
4656
4657 static inline int
4658 private_recv_p(const NODE *node)
4659 {
4660 if (nd_type(node->nd_recv) == NODE_SELF) {
4661 NODE *self = node->nd_recv;
4662 return self->nd_state != 0;
4663 }
4664 return 0;
4665 }
4666
4667 static void
4668 defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
4669 const NODE *const node, LABEL **lfinish, VALUE needstr);
4670
4671 static void
4672 defined_expr0(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
4673 const NODE *const node, LABEL **lfinish, VALUE needstr)
4674 {
4675 enum defined_type expr_type = DEFINED_NOT_DEFINED;
4676 enum node_type type;
4677 const int line = nd_line(node);
4678
4679 switch (type = nd_type(node)) {
4680
4681 /* easy literals */
4682 case NODE_NIL:
4683 expr_type = DEFINED_NIL;
4684 break;
4685 case NODE_SELF:
4686 expr_type = DEFINED_SELF;
4687 break;
4688 case NODE_TRUE:
4689 expr_type = DEFINED_TRUE;
4690 break;
4691 case NODE_FALSE:
4692 expr_type = DEFINED_FALSE;
4693 break;
4694
4695 case NODE_LIST:{
4696 const NODE *vals = node;
4697
4698 do {
4699 defined_expr0(iseq, ret, vals->nd_head, lfinish, Qfalse);
4700
4701 if (!lfinish[1]) {
4702 lfinish[1] = NEW_LABEL(line);
4703 }
4704 ADD_INSNL(ret, line, branchunless, lfinish[1]);
4705 } while ((vals = vals->nd_next) != NULL);
4706 }
4707 /* fall through */
4708 case NODE_STR:
4709 case NODE_LIT:
4710 case NODE_ZLIST:
4711 case NODE_AND:
4712 case NODE_OR:
4713 default:
4714 expr_type = DEFINED_EXPR;
4715 break;
4716
4717 /* variables */
4718 case NODE_LVAR:
4719 case NODE_DVAR:
4720 expr_type = DEFINED_LVAR;
4721 break;
4722
4723 case NODE_IVAR:
4724 ADD_INSN(ret, line, putnil);
4725 ADD_INSN3(ret, line, defined, INT2FIX(DEFINED_IVAR),
4726 ID2SYM(node->nd_vid), needstr);
4727 return;
4728
4729 case NODE_GVAR:
4730 ADD_INSN(ret, line, putnil);
4731 ADD_INSN3(ret, line, defined, INT2FIX(DEFINED_GVAR),
4732 ID2SYM(node->nd_entry->id), needstr);
4733 return;
4734
4735 case NODE_CVAR:
4736 ADD_INSN(ret, line, putnil);
4737 ADD_INSN3(ret, line, defined, INT2FIX(DEFINED_CVAR),
4738 ID2SYM(node->nd_vid), needstr);
4739 return;
4740
4741 case NODE_CONST:
4742 ADD_INSN(ret, line, putnil);
4743 ADD_INSN3(ret, line, defined, INT2FIX(DEFINED_CONST),
4744 ID2SYM(node->nd_vid), needstr);
4745 return;
4746 case NODE_COLON2:
4747 if (!lfinish[1]) {
4748 lfinish[1] = NEW_LABEL(line);
4749 }
4750 defined_expr0(iseq, ret, node->nd_head, lfinish, Qfalse);
4751 ADD_INSNL(ret, line, branchunless, lfinish[1]);
4752 NO_CHECK(COMPILE(ret, "defined/colon2#nd_head", node->nd_head));
4753
4754 ADD_INSN3(ret, line, defined,
4755 (rb_is_const_id(node->nd_mid) ?
4756 INT2FIX(DEFINED_CONST_FROM) : INT2FIX(DEFINED_METHOD)),
4757 ID2SYM(node->nd_mid), needstr);
4758 return;
4759 case NODE_COLON3:
4760 ADD_INSN1(ret, line, putobject, rb_cObject);
4761 ADD_INSN3(ret, line, defined,
4762 INT2FIX(DEFINED_CONST_FROM), ID2SYM(node->nd_mid), needstr);
4763 return;
4764
4765 /* method dispatch */
4766 case NODE_CALL:
4767 case NODE_OPCALL:
4768 case NODE_VCALL:
4769 case NODE_FCALL:
4770 case NODE_ATTRASGN:{
4771 const int explicit_receiver =
4772 (type == NODE_CALL || type == NODE_OPCALL ||
4773 (type == NODE_ATTRASGN && !private_recv_p(node)));
4774
4775 if (!lfinish[1] && (node->nd_args || explicit_receiver)) {
4776 lfinish[1] = NEW_LABEL(line);
4777 }
4778 if (node->nd_args) {
4779 defined_expr0(iseq, ret, node->nd_args, lfinish, Qfalse);
4780 ADD_INSNL(ret, line, branchunless, lfinish[1]);
4781 }
4782 if (explicit_receiver) {
4783 defined_expr0(iseq, ret, node->nd_recv, lfinish, Qfalse);
4784 ADD_INSNL(ret, line, branchunless, lfinish[1]);
4785 NO_CHECK(COMPILE(ret, "defined/recv", node->nd_recv));
4786 ADD_INSN3(ret, line, defined, INT2FIX(DEFINED_METHOD),
4787 ID2SYM(node->nd_mid), needstr);
4788 }
4789 else {
4790 ADD_INSN(ret, line, putself);
4791 ADD_INSN3(ret, line, defined, INT2FIX(DEFINED_FUNC),
4792 ID2SYM(node->nd_mid), needstr);
4793 }
4794 return;
4795 }
4796
4797 case NODE_YIELD:
4798 ADD_INSN(ret, line, putnil);
4799 ADD_INSN3(ret, line, defined, INT2FIX(DEFINED_YIELD), 0,
4800 needstr);
4801 return;
4802
4803 case NODE_BACK_REF:
4804 case NODE_NTH_REF:
4805 ADD_INSN(ret, line, putnil);
4806 ADD_INSN3(ret, line, defined, INT2FIX(DEFINED_REF),
4807 INT2FIX((node->nd_nth << 1) | (type == NODE_BACK_REF)),
4808 needstr);
4809 return;
4810
4811 case NODE_SUPER:
4812 case NODE_ZSUPER:
4813 ADD_INSN(ret, line, putnil);
4814 ADD_INSN3(ret, line, defined, INT2FIX(DEFINED_ZSUPER), 0,
4815 needstr);
4816 return;
4817
4818 case NODE_OP_ASGN1:
4819 case NODE_OP_ASGN2:
4820 case NODE_OP_ASGN_OR:
4821 case NODE_OP_ASGN_AND:
4822 case NODE_MASGN:
4823 case NODE_LASGN:
4824 case NODE_DASGN:
4825 case NODE_DASGN_CURR:
4826 case NODE_GASGN:
4827 case NODE_IASGN:
4828 case NODE_CDECL:
4829 case NODE_CVASGN:
4830 expr_type = DEFINED_ASGN;
4831 break;
4832 }
4833
4834 assert(expr_type != DEFINED_NOT_DEFINED);
4835
4836 if (needstr != Qfalse) {
4837 VALUE str = rb_iseq_defined_string(expr_type);
4838 ADD_INSN1(ret, line, putobject, str);
4839 }
4840 else {
4841 ADD_INSN1(ret, line, putobject, Qtrue);
4842 }
4843 }
4844
4845 static void
4846 build_defined_rescue_iseq(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const void *unused)
4847 {
4848 ADD_INSN(ret, 0, putnil);
4849 iseq_set_exception_local_table(iseq);
4850 }
4851
4852 static void
4853 defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
4854 const NODE *const node, LABEL **lfinish, VALUE needstr)
4855 {
4856 LINK_ELEMENT *lcur = ret->last;
4857 defined_expr0(iseq, ret, node, lfinish, needstr);
4858 if (lfinish[1]) {
4859 int line = nd_line(node);
4860 LABEL *lstart = NEW_LABEL(line);
4861 LABEL *lend = NEW_LABEL(line);
4862 const rb_iseq_t *rescue;
4863 struct rb_iseq_new_with_callback_callback_func *ifunc =
4864 rb_iseq_new_with_callback_new_callback(build_defined_rescue_iseq, NULL);
4865 rescue = new_child_iseq_with_callback(iseq, ifunc,
4866 rb_str_concat(rb_str_new2("defined guard in "),
4867 iseq->body->location.label),
4868 iseq, ISEQ_TYPE_RESCUE, 0);
4869 lstart->rescued = LABEL_RESCUE_BEG;
4870 lend->rescued = LABEL_RESCUE_END;
4871 APPEND_LABEL(ret, lcur, lstart);
4872 ADD_LABEL(ret, lend);
4873 ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lfinish[1]);
4874 }
4875 }
4876
4877 static int
4878 compile_defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE needstr)
4879 {
4880 const int line = nd_line(node);
4881 if (!node->nd_head) {
4882 VALUE str = rb_iseq_defined_string(DEFINED_NIL);
4883 ADD_INSN1(ret, line, putobject, str);
4884 }
4885 else {
4886 LABEL *lfinish[2];
4887 LINK_ELEMENT *last = ret->last;
4888 lfinish[0] = NEW_LABEL(line);
4889 lfinish[1] = 0;
4890 defined_expr(iseq, ret, node->nd_head, lfinish, needstr);
4891 if (lfinish[1]) {
4892 ELEM_INSERT_NEXT(last, &new_insn_body(iseq, line, BIN(putnil), 0)->link);
4893 ADD_INSN(ret, line, swap);
4894 ADD_INSN(ret, line, pop);
4895 ADD_LABEL(ret, lfinish[1]);
4896 }
4897 ADD_LABEL(ret, lfinish[0]);
4898 }
4899 return COMPILE_OK;
4900 }
4901
4902 static VALUE
4903 make_name_for_block(const rb_iseq_t *orig_iseq)
4904 {
4905 int level = 1;
4906 const rb_iseq_t *iseq = orig_iseq;
4907
4908 if (orig_iseq->body->parent_iseq != 0) {
4909 while (orig_iseq->body->local_iseq != iseq) {
4910 if (iseq->body->type == ISEQ_TYPE_BLOCK) {
4911 level++;
4912 }
4913 iseq = iseq->body->parent_iseq;
4914 }
4915 }
4916
4917 if (level == 1) {
4918 return rb_sprintf("block in %"PRIsVALUE, iseq->body->location.label);
4919 }
4920 else {
4921 return rb_sprintf("block (%d levels) in %"PRIsVALUE, level, iseq->body->location.label);
4922 }
4923 }
4924
4925 static void
4926 push_ensure_entry(rb_iseq_t *iseq,
4927 struct iseq_compile_data_ensure_node_stack *enl,
4928 struct ensure_range *er, const NODE *const node)
4929 {
4930 enl->ensure_node = node;
4931 enl->prev = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack; /* prev */
4932 enl->erange = er;
4933 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enl;
4934 }
4935
4936 static void
4937 add_ensure_range(rb_iseq_t *iseq, struct ensure_range *erange,
4938 LABEL *lstart, LABEL *lend)
4939 {
4940 struct ensure_range *ne =
4941 compile_data_alloc(iseq, sizeof(struct ensure_range));
4942
4943 while (erange->next != 0) {
4944 erange = erange->next;
4945 }
4946 ne->next = 0;
4947 ne->begin = lend;
4948 ne->end = erange->end;
4949 erange->end = lstart;
4950
4951 erange->next = ne;
4952 }
4953
4954 static void
4955 add_ensure_iseq(LINK_ANCHOR *const ret, rb_iseq_t *iseq, int is_return)
4956 {
4957 struct iseq_compile_data_ensure_node_stack *enlp =
4958 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack;
4959 struct iseq_compile_data_ensure_node_stack *prev_enlp = enlp;
4960 DECL_ANCHOR(ensure);
4961
4962 INIT_ANCHOR(ensure);
4963 while (enlp) {
4964 if (enlp->erange != NULL) {
4965 DECL_ANCHOR(ensure_part);
4966 LABEL *lstart = NEW_LABEL(0);
4967 LABEL *lend = NEW_LABEL(0);
4968 INIT_ANCHOR(ensure_part);
4969
4970 add_ensure_range(iseq, enlp->erange, lstart, lend);
4971
4972 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enlp->prev;
4973 ADD_LABEL(ensure_part, lstart);
4974 NO_CHECK(COMPILE_POPPED(ensure_part, "ensure part", enlp->ensure_node));
4975 ADD_LABEL(ensure_part, lend);
4976 ADD_SEQ(ensure, ensure_part);
4977 }
4978 else {
4979 if (!is_return) {
4980 break;
4981 }
4982 }
4983 enlp = enlp->prev;
4984 }
4985 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = prev_enlp;
4986 ADD_SEQ(ret, ensure);
4987 }
4988
4989 static int
4990 check_keyword(const NODE *node)
4991 {
4992 /* This check is essentially a code clone of compile_keyword_arg. */
4993
4994 if (nd_type(node) == NODE_LIST) {
4995 while (node->nd_next) {
4996 node = node->nd_next;
4997 }
4998 node = node->nd_head;
4999 }
5000
5001 return keyword_node_p(node);
5002 }
5003
5004 static VALUE
5005 setup_args_core(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
5006 int dup_rest, unsigned int *flag, struct rb_call_info_kw_arg **keywords)
5007 {
5008 if (argn) {
5009 switch (nd_type(argn)) {
5010 case NODE_SPLAT: {
5011 NO_CHECK(COMPILE(args, "args (splat)", argn->nd_head));
5012 ADD_INSN1(args, nd_line(argn), splatarray, dup_rest ? Qtrue : Qfalse);
5013 if (flag) *flag |= VM_CALL_ARGS_SPLAT;
5014 return INT2FIX(1);
5015 }
5016 case NODE_ARGSCAT:
5017 case NODE_ARGSPUSH: {
5018 int next_is_list = (nd_type(argn->nd_head) == NODE_LIST);
5019 VALUE argc = setup_args_core(iseq, args, argn->nd_head, 1, NULL, NULL);
5020 if (nd_type(argn->nd_body) == NODE_LIST) {
5021 /* This branch is needed to avoid "newarraykwsplat" [Bug #16442] */
5022 int rest_len = compile_args(iseq, args, argn->nd_body, NULL, NULL);
5023 ADD_INSN1(args, nd_line(argn), newarray, INT2FIX(rest_len));
5024 }
5025 else {
5026 NO_CHECK(COMPILE(args, "args (cat: splat)", argn->nd_body));
5027 }
5028 if (flag) {
5029 *flag |= VM_CALL_ARGS_SPLAT;
5030 /* This is a dirty hack. It traverses the AST twice.
5031 * In a long term, it should be fixed by a redesign of keyword arguments */
5032 if (check_keyword(argn->nd_body))
5033 *flag |= VM_CALL_KW_SPLAT;
5034 }
5035 if (nd_type(argn) == NODE_ARGSCAT) {
5036 if (next_is_list) {
5037 ADD_INSN1(args, nd_line(argn), splatarray, Qtrue);
5038 return INT2FIX(FIX2INT(argc) + 1);
5039 }
5040 else {
5041 ADD_INSN1(args, nd_line(argn), splatarray, Qfalse);
5042 ADD_INSN(args, nd_line(argn), concatarray);
5043 return argc;
5044 }
5045 }
5046 else {
5047 ADD_INSN1(args, nd_line(argn), newarray, INT2FIX(1));
5048 ADD_INSN(args, nd_line(argn), concatarray);
5049 return argc;
5050 }
5051 }
5052 case NODE_LIST: {
5053 int len = compile_args(iseq, args, argn, keywords, flag);
5054 return INT2FIX(len);
5055 }
5056 default: {
5057 UNKNOWN_NODE("setup_arg", argn, Qnil);
5058 }
5059 }
5060 }
5061 return INT2FIX(0);
5062 }
5063
5064 static VALUE
5065 setup_args(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
5066 unsigned int *flag, struct rb_call_info_kw_arg **keywords)
5067 {
5068 VALUE ret;
5069 if (argn && nd_type(argn) == NODE_BLOCK_PASS) {
5070 DECL_ANCHOR(arg_block);
5071 INIT_ANCHOR(arg_block);
5072 NO_CHECK(COMPILE(arg_block, "block", argn->nd_body));
5073
5074 *flag |= VM_CALL_ARGS_BLOCKARG;
5075 ret = setup_args_core(iseq, args, argn->nd_head, 0, flag, keywords);
5076
5077 if (LIST_INSN_SIZE_ONE(arg_block)) {
5078 LINK_ELEMENT *elem = FIRST_ELEMENT(arg_block);
5079 if (elem->type == ISEQ_ELEMENT_INSN) {
5080 INSN *iobj = (INSN *)elem;
5081 if (iobj->insn_id == BIN(getblockparam)) {
5082 iobj->insn_id = BIN(getblockparamproxy);
5083 }
5084 }
5085 }
5086 ADD_SEQ(args, arg_block);
5087 }
5088 else {
5089 ret = setup_args_core(iseq, args, argn, 0, flag, keywords);
5090 }
5091 return ret;
5092 }
5093
5094 static void
5095 build_postexe_iseq(rb_iseq_t *iseq, LINK_ANCHOR *ret, const void *ptr)
5096 {
5097 const NODE *body = ptr;
5098 int line = nd_line(body);
5099 VALUE argc = INT2FIX(0);
5100 const rb_iseq_t *block = NEW_CHILD_ISEQ(body, make_name_for_block(iseq->body->parent_iseq), ISEQ_TYPE_BLOCK, line);
5101
5102 ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
5103 ADD_CALL_WITH_BLOCK(ret, line, id_core_set_postexe, argc, block);
5104 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block);
5105 iseq_set_local_table(iseq, 0);
5106 }
5107
5108 static void
5109 compile_named_capture_assign(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node)
5110 {
5111 const NODE *vars;
5112 LINK_ELEMENT *last;
5113 int line = nd_line(node);
5114 LABEL *fail_label = NEW_LABEL(line), *end_label = NEW_LABEL(line);
5115
5116 #if !(defined(NAMED_CAPTURE_BY_SVAR) && NAMED_CAPTURE_BY_SVAR-0)
5117 ADD_INSN1(ret, line, getglobal, ((VALUE)rb_global_entry(idBACKREF) | 1));
5118 #else
5119 ADD_INSN2(ret, line, getspecial, INT2FIX(1) /* '~' */, INT2FIX(0));
5120 #endif
5121 ADD_INSN(ret, line, dup);
5122 ADD_INSNL(ret, line, branchunless, fail_label);
5123
5124 for (vars = node; vars; vars = vars->nd_next) {
5125 INSN *cap;
5126 if (vars->nd_next) {
5127 ADD_INSN(ret, line, dup);
5128 }
5129 last = ret->last;
5130 NO_CHECK(COMPILE_POPPED(ret, "capture", vars->nd_head));
5131 last = last->next; /* putobject :var */
5132 cap = new_insn_send(iseq, line, idAREF, INT2FIX(1),
5133 NULL, INT2FIX(0), NULL);
5134 ELEM_INSERT_PREV(last->next, (LINK_ELEMENT *)cap);
5135 #if !defined(NAMED_CAPTURE_SINGLE_OPT) || NAMED_CAPTURE_SINGLE_OPT-0
5136 if (!vars->nd_next && vars == node) {
5137 /* only one name */
5138 DECL_ANCHOR(nom);
5139
5140 INIT_ANCHOR(nom);
5141 ADD_INSNL(nom, line, jump, end_label);
5142 ADD_LABEL(nom, fail_label);
5143 # if 0 /* $~ must be MatchData or nil */
5144 ADD_INSN(nom, line, pop);
5145 ADD_INSN(nom, line, putnil);
5146 # endif
5147 ADD_LABEL(nom, end_label);
5148 (nom->last->next = cap->link.next)->prev = nom->last;
5149 (cap->link.next = nom->anchor.next)->prev = &cap->link;
5150 return;
5151 }
5152 #endif
5153 }
5154 ADD_INSNL(ret, line, jump, end_label);
5155 ADD_LABEL(ret, fail_label);
5156 ADD_INSN(ret, line, pop);
5157 for (vars = node; vars; vars = vars->nd_next) {
5158 last = ret->last;
5159 NO_CHECK(COMPILE_POPPED(ret, "capture", vars->nd_head));
5160 last = last->next; /* putobject :var */
5161 ((INSN*)last)->insn_id = BIN(putnil);
5162 ((INSN*)last)->operand_size = 0;
5163 }
5164 ADD_LABEL(ret, end_label);
5165 }
5166
5167 static int
5168 number_literal_p(const NODE *n)
5169 {
5170 return (n && nd_type(n) == NODE_LIT && RB_INTEGER_TYPE_P(n->nd_lit));
5171 }
5172
5173 static int
5174 compile_if(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
5175 {
5176 struct rb_iseq_constant_body *const body = iseq->body;
5177 const NODE *const node_body = type == NODE_IF ? node->nd_body : node->nd_else;
5178 const NODE *const node_else = type == NODE_IF ? node->nd_else : node->nd_body;
5179
5180 const int line = nd_line(node);
5181 const int lineno = nd_first_lineno(node);
5182 const int column = nd_first_column(node);
5183 const int last_lineno = nd_last_lineno(node);
5184 const int last_column = nd_last_column(node);
5185 DECL_ANCHOR(cond_seq);
5186 DECL_ANCHOR(then_seq);
5187 DECL_ANCHOR(else_seq);
5188 LABEL *then_label, *else_label, *end_label;
5189 VALUE branches = Qfalse;
5190 int ci_size, ci_kw_size;
5191 VALUE catch_table = ISEQ_COMPILE_DATA(iseq)->catch_table_ary;
5192 long catch_table_size = NIL_P(catch_table) ? 0 : RARRAY_LEN(catch_table);
5193
5194 INIT_ANCHOR(cond_seq);
5195 INIT_ANCHOR(then_seq);
5196 INIT_ANCHOR(else_seq);
5197 then_label = NEW_LABEL(line);
5198 else_label = NEW_LABEL(line);
5199 end_label = 0;
5200
5201 compile_branch_condition(iseq, cond_seq, node->nd_cond,
5202 then_label, else_label);
5203
5204 ci_size = body->ci_size;
5205 ci_kw_size = body->ci_kw_size;
5206 CHECK(COMPILE_(then_seq, "then", node_body, popped));
5207 catch_table = ISEQ_COMPILE_DATA(iseq)->catch_table_ary;
5208 if (!then_label->refcnt) {
5209 body->ci_size = ci_size;
5210 body->ci_kw_size = ci_kw_size;
5211 if (!NIL_P(catch_table)) rb_ary_set_len(catch_table, catch_table_size);
5212 }
5213 else {
5214 if (!NIL_P(catch_table)) catch_table_size = RARRAY_LEN(catch_table);
5215 }
5216
5217 ci_size = body->ci_size;
5218 ci_kw_size = body->ci_kw_size;
5219 CHECK(COMPILE_(else_seq, "else", node_else, popped));
5220 catch_table = ISEQ_COMPILE_DATA(iseq)->catch_table_ary;
5221 if (!else_label->refcnt) {
5222 body->ci_size = ci_size;
5223 body->ci_kw_size = ci_kw_size;
5224 if (!NIL_P(catch_table)) rb_ary_set_len(catch_table, catch_table_size);
5225 }
5226 else {
5227 if (!NIL_P(catch_table)) catch_table_size = RARRAY_LEN(catch_table);
5228 }
5229
5230 ADD_SEQ(ret, cond_seq);
5231
5232 if (then_label->refcnt && else_label->refcnt) {
5233 DECL_BRANCH_BASE(branches, lineno, column, last_lineno, last_column, type == NODE_IF ? "if" : "unless");
5234 }
5235
5236 if (then_label->refcnt) {
5237 ADD_LABEL(ret, then_label);
5238 if (else_label->refcnt) {
5239 ADD_TRACE_BRANCH_COVERAGE(
5240 ret,
5241 node_body ? nd_first_lineno(node_body) : lineno,
5242 node_body ? nd_first_column(node_body) : column,
5243 node_body ? nd_last_lineno(node_body) : last_lineno,
5244 node_body ? nd_last_column(node_body) : last_column,
5245 type == NODE_IF ? "then" : "else",
5246 branches);
5247 end_label = NEW_LABEL(line);
5248 ADD_INSNL(then_seq, line, jump, end_label);
5249 }
5250 ADD_SEQ(ret, then_seq);
5251 }
5252
5253 if (else_label->refcnt) {
5254 ADD_LABEL(ret, else_label);
5255 if (then_label->refcnt) {
5256 ADD_TRACE_BRANCH_COVERAGE(
5257 ret,
5258 node_else ? nd_first_lineno(node_else) : lineno,
5259 node_else ? nd_first_column(node_else) : column,
5260 node_else ? nd_last_lineno(node_else) : last_lineno,
5261 node_else ? nd_last_column(node_else) : last_column,
5262 type == NODE_IF ? "else" : "then",
5263 branches);
5264 }
5265 ADD_SEQ(ret, else_seq);
5266 }
5267
5268 if (end_label) {
5269 ADD_LABEL(ret, end_label);
5270 }
5271
5272 return COMPILE_OK;
5273 }
5274
5275 static int
5276 compile_case(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
5277 {
5278 const NODE *vals;
5279 const NODE *node = orig_node;
5280 LABEL *endlabel, *elselabel;
5281 DECL_ANCHOR(head);
5282 DECL_ANCHOR(body_seq);
5283 DECL_ANCHOR(cond_seq);
5284 int only_special_literals = 1;
5285 VALUE literals = rb_hash_new();
5286 int line, lineno, column, last_lineno, last_column;
5287 enum node_type type;
5288 VALUE branches = Qfalse;
5289
5290 INIT_ANCHOR(head);
5291 INIT_ANCHOR(body_seq);
5292 INIT_ANCHOR(cond_seq);
5293
5294 RHASH_TBL_RAW(literals)->type = &cdhash_type;
5295
5296 CHECK(COMPILE(head, "case base", node->nd_head));
5297
5298 DECL_BRANCH_BASE(branches, nd_first_lineno(node), nd_first_column(node), nd_last_lineno(node), nd_last_column(node), "case");
5299
5300 node = node->nd_body;
5301 EXPECT_NODE("NODE_CASE", node, NODE_WHEN, COMPILE_NG);
5302 type = nd_type(node);
5303 line = nd_line(node);
5304 lineno = nd_first_lineno(node);
5305 column = nd_first_column(node);
5306 last_lineno = nd_last_lineno(node);
5307 last_column = nd_last_column(node);
5308
5309 endlabel = NEW_LABEL(line);
5310 elselabel = NEW_LABEL(line);
5311
5312 ADD_SEQ(ret, head); /* case VAL */
5313
5314 while (type == NODE_WHEN) {
5315 LABEL *l1;
5316
5317 l1 = NEW_LABEL(line);
5318 ADD_LABEL(body_seq, l1);
5319 ADD_INSN(body_seq, line, pop);
5320 ADD_TRACE_BRANCH_COVERAGE(
5321 body_seq,
5322 node->nd_body ? nd_first_lineno(node->nd_body) : lineno,
5323 node->nd_body ? nd_first_column(node->nd_body) : column,
5324 node->nd_body ? nd_last_lineno(node->nd_body) : last_lineno,
5325 node->nd_body ? nd_last_column(node->nd_body) : last_column,
5326 "when",
5327 branches);
5328 CHECK(COMPILE_(body_seq, "when body", node->nd_body, popped));
5329 ADD_INSNL(body_seq, line, jump, endlabel);
5330
5331 vals = node->nd_head;
5332 if (vals) {
5333 switch (nd_type(vals)) {
5334 case NODE_LIST:
5335 only_special_literals = when_vals(iseq, cond_seq, vals, l1, only_special_literals, literals);
5336 if (only_special_literals < 0) return COMPILE_NG;
5337 break;
5338 case NODE_SPLAT:
5339 case NODE_ARGSCAT:
5340 case NODE_ARGSPUSH:
5341 only_special_literals = 0;
5342 CHECK(when_splat_vals(iseq, cond_seq, vals, l1, only_special_literals, literals));
5343 break;
5344 default:
5345 UNKNOWN_NODE("NODE_CASE", vals, COMPILE_NG);
5346 }
5347 }
5348 else {
5349 EXPECT_NODE_NONULL("NODE_CASE", node, NODE_LIST, COMPILE_NG);
5350 }
5351
5352 node = node->nd_next;
5353 if (!node) {
5354 break;
5355 }
5356 type = nd_type(node);
5357 line = nd_line(node);
5358 lineno = nd_first_lineno(node);
5359 column = nd_first_column(node);
5360 last_lineno = nd_last_lineno(node);
5361 last_column = nd_last_column(node);
5362 }
5363 /* else */
5364 if (node) {
5365 ADD_LABEL(cond_seq, elselabel);
5366 ADD_INSN(cond_seq, line, pop);
5367 ADD_TRACE_BRANCH_COVERAGE(cond_seq, nd_first_lineno(node), nd_first_column(node), nd_last_lineno(node), nd_last_column(node), "else", branches);
5368 CHECK(COMPILE_(cond_seq, "else", node, popped));
5369 ADD_INSNL(cond_seq, line, jump, endlabel);
5370 }
5371 else {
5372 debugs("== else (implicit)\n");
5373 ADD_LABEL(cond_seq, elselabel);
5374 ADD_INSN(cond_seq, nd_line(orig_node), pop);
5375 ADD_TRACE_BRANCH_COVERAGE(cond_seq, nd_first_lineno(orig_node), nd_first_column(orig_node), nd_last_lineno(orig_node), nd_last_column(orig_node), "else", branches);
5376 if (!popped) {
5377 ADD_INSN(cond_seq, nd_line(orig_node), putnil);
5378 }
5379 ADD_INSNL(cond_seq, nd_line(orig_node), jump, endlabel);
5380 }
5381
5382 if (only_special_literals && ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
5383 ADD_INSN(ret, nd_line(orig_node), dup);
5384 ADD_INSN2(ret, nd_line(orig_node), opt_case_dispatch, literals, elselabel);
5385 RB_OBJ_WRITTEN(iseq, Qundef, literals);
5386 LABEL_REF(elselabel);
5387 }
5388
5389 ADD_SEQ(ret, cond_seq);
5390 ADD_SEQ(ret, body_seq);
5391 ADD_LABEL(ret, endlabel);
5392 return COMPILE_OK;
5393 }
5394
5395 static int
5396 compile_case2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
5397 {
5398 const NODE *vals;
5399 const NODE *val;
5400 const NODE *node = orig_node->nd_body;
5401 LABEL *endlabel;
5402 DECL_ANCHOR(body_seq);
5403 VALUE branches = Qfalse;
5404
5405 DECL_BRANCH_BASE(branches, nd_first_lineno(orig_node), nd_first_column(orig_node), nd_last_lineno(orig_node), nd_last_column(orig_node), "case");
5406
5407 INIT_ANCHOR(body_seq);
5408 endlabel = NEW_LABEL(nd_line(node));
5409
5410 while (node && nd_type(node) == NODE_WHEN) {
5411 const int line = nd_line(node);
5412 const int lineno = nd_first_lineno(node);
5413 const int column = nd_first_column(node);
5414 const int last_lineno = nd_last_lineno(node);
5415 const int last_column = nd_last_column(node);
5416 LABEL *l1 = NEW_LABEL(line);
5417 ADD_LABEL(body_seq, l1);
5418 ADD_TRACE_BRANCH_COVERAGE(
5419 body_seq,
5420 node->nd_body ? nd_first_lineno(node->nd_body) : lineno,
5421 node->nd_body ? nd_first_column(node->nd_body) : column,
5422 node->nd_body ? nd_last_lineno(node->nd_body) : last_lineno,
5423 node->nd_body ? nd_last_column(node->nd_body) : last_column,
5424 "when",
5425 branches);
5426 CHECK(COMPILE_(body_seq, "when", node->nd_body, popped));
5427 ADD_INSNL(body_seq, line, jump, endlabel);
5428
5429 vals = node->nd_head;
5430 if (!vals) {
5431 EXPECT_NODE_NONULL("NODE_WHEN", node, NODE_LIST, COMPILE_NG);
5432 }
5433 switch (nd_type(vals)) {
5434 case NODE_LIST:
5435 while (vals) {
5436 LABEL *lnext;
5437 val = vals->nd_head;
5438 lnext = NEW_LABEL(nd_line(val));
5439 debug_compile("== when2\n", (void)0);
5440 CHECK(compile_branch_condition(iseq, ret, val, l1, lnext));
5441 ADD_LABEL(ret, lnext);
5442 vals = vals->nd_next;
5443 }
5444 break;
5445 case NODE_SPLAT:
5446 case NODE_ARGSCAT:
5447 case NODE_ARGSPUSH:
5448 ADD_INSN(ret, nd_line(vals), putnil);
5449 CHECK(COMPILE(ret, "when2/cond splat", vals));
5450 ADD_INSN1(ret, nd_line(vals), checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_WHEN | VM_CHECKMATCH_ARRAY));
5451 ADD_INSNL(ret, nd_line(vals), branchif, l1);
5452 break;
5453 default:
5454 UNKNOWN_NODE("NODE_WHEN", vals, COMPILE_NG);
5455 }
5456 node = node->nd_next;
5457 }
5458 /* else */
5459 ADD_TRACE_BRANCH_COVERAGE(
5460 ret,
5461 node ? nd_first_lineno(node) : nd_first_lineno(orig_node),
5462 node ? nd_first_column(node) : nd_first_column(orig_node),
5463 node ? nd_last_lineno(node) : nd_last_lineno(orig_node),
5464 node ? nd_last_column(node) : nd_last_column(orig_node),
5465 "else",
5466 branches);
5467 CHECK(COMPILE_(ret, "else", node, popped));
5468 ADD_INSNL(ret, nd_line(orig_node), jump, endlabel);
5469
5470 ADD_SEQ(ret, body_seq);
5471 ADD_LABEL(ret, endlabel);
5472 return COMPILE_OK;
5473 }
5474
5475 static int
5476 iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int in_alt_pattern)
5477 {
5478 const int line = nd_line(node);
5479
5480 switch (nd_type(node)) {
5481 case NODE_ARYPTN: {
5482 /*
5483 * if pattern.use_rest_num?
5484 * rest_num = 0
5485 * end
5486 * if pattern.has_constant_node?
5487 * unless pattern.constant === obj
5488 * goto match_failed
5489 * end
5490 * end
5491 * unless obj.respond_to?(:deconstruct)
5492 * goto match_failed
5493 * end
5494 * d = obj.deconstruct
5495 * unless Array === d
5496 * goto type_error
5497 * end
5498 * min_argc = pattern.pre_args_num + pattern.post_args_num
5499 * if pattern.has_rest_arg?
5500 * unless d.length >= min_argc
5501 * goto match_failed
5502 * end
5503 * else
5504 * unless d.length == min_argc
5505 * goto match_failed
5506 * end
5507 * end
5508 * pattern.pre_args_num.each do |i|
5509 * unless pattern.pre_args[i].match?(d[i])
5510 * goto match_failed
5511 * end
5512 * end
5513 * if pattern.use_rest_num?
5514 * rest_num = d.length - min_argc
5515 * if pattern.has_rest_arg? && pattern.has_rest_arg_id # not `*`, but `*rest`
5516 * unless pattern.rest_arg.match?(d[pattern.pre_args_num, rest_num])
5517 * goto match_failed
5518 * end
5519 * end
5520 * end
5521 * pattern.post_args_num.each do |i|
5522 * j = pattern.pre_args_num + i
5523 * j += rest_num
5524 * unless pattern.post_args[i].match?(d[j])
5525 * goto match_failed
5526 * end
5527 * end
5528 * true
5529 * goto fin
5530 * type_error:
5531 * FrozenCore.raise TypeError
5532 * match_failed:
5533 * false
5534 * fin:
5535 */
5536 struct rb_ary_pattern_info *apinfo = node->nd_apinfo;
5537 const NODE *args = apinfo->pre_args;
5538 const int pre_args_num = apinfo->pre_args ? rb_long2int(apinfo->pre_args->nd_alen) : 0;
5539 const int post_args_num = apinfo->post_args ? rb_long2int(apinfo->post_args->nd_alen) : 0;
5540
5541 const int min_argc = pre_args_num + post_args_num;
5542 const int use_rest_num = apinfo->rest_arg && (NODE_NAMED_REST_P(apinfo->rest_arg) ||
5543 (!NODE_NAMED_REST_P(apinfo->rest_arg) && post_args_num > 0));
5544
5545 LABEL *match_failed, *type_error, *fin;
5546 int i;
5547 match_failed = NEW_LABEL(line);
5548 type_error = NEW_LABEL(line);
5549 fin = NEW_LABEL(line);
5550
5551 if (use_rest_num) {
5552 ADD_INSN1(ret, line, putobject, INT2FIX(0)); /* allocate stack for rest_num */
5553 ADD_INSN(ret, line, swap);
5554 }
5555
5556 if (node->nd_pconst) {
5557 ADD_INSN(ret, line, dup);
5558 CHECK(COMPILE(ret, "constant", node->nd_pconst));
5559 ADD_INSN1(ret, line, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE));
5560 ADD_INSNL(ret, line, branchunless, match_failed);
5561 }
5562
5563 ADD_INSN(ret, line, dup);
5564 ADD_INSN1(ret, line, putobject, ID2SYM(rb_intern("deconstruct")));
5565 ADD_SEND(ret, line, idRespond_to, INT2FIX(1));
5566 ADD_INSNL(ret, line, branchunless, match_failed);
5567
5568 ADD_SEND(ret, line, rb_intern("deconstruct"), INT2FIX(0));
5569
5570 ADD_INSN(ret, line, dup);
5571 ADD_INSN1(ret, line, checktype, INT2FIX(T_ARRAY));
5572 ADD_INSNL(ret, line, branchunless, type_error);
5573
5574 ADD_INSN(ret, line, dup);
5575 ADD_SEND(ret, line, idLength, INT2FIX(0));
5576 ADD_INSN1(ret, line, putobject, INT2FIX(min_argc));
5577 ADD_SEND(ret, line, apinfo->rest_arg ? idGE : idEq, INT2FIX(1));
5578 ADD_INSNL(ret, line, branchunless, match_failed);
5579
5580 for (i = 0; i < pre_args_num; i++) {
5581 ADD_INSN(ret, line, dup);
5582 ADD_INSN1(ret, line, putobject, INT2FIX(i));
5583 ADD_SEND(ret, line, idAREF, INT2FIX(1));
5584 iseq_compile_pattern_each(iseq, ret, args->nd_head, in_alt_pattern);
5585 args = args->nd_next;
5586 ADD_INSNL(ret, line, branchunless, match_failed);
5587 }
5588
5589 if (apinfo->rest_arg) {
5590 if (NODE_NAMED_REST_P(apinfo->rest_arg)) {
5591 ADD_INSN(ret, line, dup);
5592 ADD_INSN1(ret, line, putobject, INT2FIX(pre_args_num));
5593 ADD_INSN1(ret, line, topn, INT2FIX(1));
5594 ADD_SEND(ret, line, idLength, INT2FIX(0));
5595 ADD_INSN1(ret, line, putobject, INT2FIX(min_argc));
5596 ADD_SEND(ret, line, idMINUS, INT2FIX(1));
5597 ADD_INSN1(ret, line, setn, INT2FIX(4));
5598 ADD_SEND(ret, line, idAREF, INT2FIX(2));
5599
5600 iseq_compile_pattern_each(iseq, ret, apinfo->rest_arg, in_alt_pattern);
5601 ADD_INSNL(ret, line, branchunless, match_failed);
5602 }
5603 else {
5604 if (post_args_num > 0) {
5605 ADD_INSN(ret, line, dup);
5606 ADD_SEND(ret, line, idLength, INT2FIX(0));
5607 ADD_INSN1(ret, line, putobject, INT2FIX(min_argc));
5608 ADD_SEND(ret, line, idMINUS, INT2FIX(1));
5609 ADD_INSN1(ret, line, setn, INT2FIX(2));
5610 ADD_INSN(ret, line, pop);
5611 }
5612 }
5613 }
5614
5615 args = apinfo->post_args;
5616 for (i = 0; i < post_args_num; i++) {
5617 ADD_INSN(ret, line, dup);
5618
5619 ADD_INSN1(ret, line, putobject, INT2FIX(pre_args_num + i));
5620 ADD_INSN1(ret, line, topn, INT2FIX(3));
5621 ADD_SEND(ret, line, idPLUS, INT2FIX(1));
5622
5623 ADD_SEND(ret, line, idAREF, INT2FIX(1));
5624 iseq_compile_pattern_each(iseq, ret, args->nd_head, in_alt_pattern);
5625 args = args->nd_next;
5626 ADD_INSNL(ret, line, branchunless, match_failed);
5627 }
5628
5629 ADD_INSN(ret, line, pop);
5630 if (use_rest_num) {
5631 ADD_INSN(ret, line, pop);
5632 }
5633 ADD_INSN1(ret, line, putobject, Qtrue);
5634 ADD_INSNL(ret, line, jump, fin);
5635
5636 ADD_LABEL(ret, type_error);
5637 ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
5638 ADD_INSN1(ret, line, putobject, rb_eTypeError);
5639 ADD_INSN1(ret, line, putobject, rb_fstring_lit("deconstruct must return Array"));
5640 ADD_SEND(ret, line, id_core_raise, INT2FIX(2));
5641
5642 ADD_LABEL(ret, match_failed);
5643 ADD_INSN(ret, line, pop);
5644 if (use_rest_num) {
5645 ADD_INSN(ret, line, pop);
5646 }
5647 ADD_INSN1(ret, line, putobject, Qfalse);
5648 ADD_LABEL(ret, fin);
5649
5650 break;
5651 }
5652 case NODE_HSHPTN: {
5653 /*
5654 * keys = nil
5655 * if pattern.has_kw_args_node? && !pattern.has_kw_rest_arg_node?
5656 * keys = pattern.kw_args_node.keys
5657 * end
5658 * if pattern.has_constant_node?
5659 * unless pattern.constant === obj
5660 * goto match_failed
5661 * end
5662 * end
5663 * unless obj.respond_to?(:deconstruct_keys)
5664 * goto match_failed
5665 * end
5666 * d = obj.deconstruct_keys(keys)
5667 * unless Hash === d
5668 * goto type_error
5669 * end
5670 * if pattern.has_kw_rest_arg_node?
5671 * d = d.dup
5672 * end
5673 * if pattern.has_kw_args_node?
5674 * pattern.kw_args_node.each |k,|
5675 * unless d.key?(k)
5676 * goto match_failed
5677 * end
5678 * end
5679 * pattern.kw_args_node.each |k, pat|
5680 * if pattern.has_kw_rest_arg_node?
5681 * unless pat.match?(d.delete(k))
5682 * goto match_failed
5683 * end
5684 * else
5685 * unless pat.match?(d[k])
5686 * goto match_failed
5687 * end
5688 * end
5689 * end
5690 * else
5691 * unless d.empty?
5692 * goto match_failed
5693 * end
5694 * end
5695 * if pattern.has_kw_rest_arg_node?
5696 * if pattern.no_rest_keyword?
5697 * unless d.empty?
5698 * goto match_failed
5699 * end
5700 * else
5701 * unless pattern.kw_rest_arg_node.match?(d)
5702 * goto match_failed
5703 * end
5704 * end
5705 * end
5706 * true
5707 * goto fin
5708 * type_error:
5709 * FrozenCore.raise TypeError
5710 * match_failed:
5711 * false
5712 * fin:
5713 */
5714 LABEL *match_failed, *type_error, *fin;
5715 VALUE keys = Qnil;
5716
5717 match_failed = NEW_LABEL(line);
5718 type_error = NEW_LABEL(line);
5719 fin = NEW_LABEL(line);
5720
5721 if (node->nd_pkwargs && !node->nd_pkwrestarg) {
5722 const NODE *kw_args = node->nd_pkwargs->nd_head;
5723 keys = rb_ary_new_capa(kw_args ? kw_args->nd_alen/2 : 0);
5724 while (kw_args) {
5725 rb_ary_push(keys, kw_args->nd_head->nd_lit);
5726 kw_args = kw_args->nd_next->nd_next;
5727 }
5728 }
5729
5730 if (node->nd_pconst) {
5731 ADD_INSN(ret, line, dup);
5732 CHECK(COMPILE(ret, "constant", node->nd_pconst));
5733 ADD_INSN1(ret, line, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE));
5734 ADD_INSNL(ret, line, branchunless, match_failed);
5735 }
5736
5737 ADD_INSN(ret, line, dup);
5738 ADD_INSN1(ret, line, putobject, ID2SYM(rb_intern("deconstruct_keys")));
5739 ADD_SEND(ret, line, idRespond_to, INT2FIX(1));
5740 ADD_INSNL(ret, line, branchunless, match_failed);
5741
5742 if (NIL_P(keys)) {
5743 ADD_INSN(ret, line, putnil);
5744 }
5745 else {
5746 ADD_INSN1(ret, line, duparray, keys);
5747 RB_OBJ_WRITTEN(iseq, Qundef, rb_obj_hide(keys));
5748 }
5749 ADD_SEND(ret, line, rb_intern("deconstruct_keys"), INT2FIX(1));
5750
5751 ADD_INSN(ret, line, dup);
5752 ADD_INSN1(ret, line, checktype, INT2FIX(T_HASH));
5753 ADD_INSNL(ret, line, branchunless, type_error);
5754
5755 if (node->nd_pkwrestarg) {
5756 ADD_SEND(ret, line, rb_intern("dup"), INT2FIX(0));
5757 }
5758
5759 if (node->nd_pkwargs) {
5760 int i;
5761 int keys_num;
5762 const NODE *args;
5763 args = node->nd_pkwargs->nd_head;
5764 if (args) {
5765 DECL_ANCHOR(match_values);
5766 INIT_ANCHOR(match_values);
5767 keys_num = rb_long2int(args->nd_alen) / 2;
5768 for (i = 0; i < keys_num; i++) {
5769 NODE *key_node = args->nd_head;
5770 NODE *value_node = args->nd_next->nd_head;
5771 VALUE key;
5772
5773 if (nd_type(key_node) != NODE_LIT) {
5774 UNKNOWN_NODE("NODE_IN", key_node, COMPILE_NG);
5775 }
5776 key = key_node->nd_lit;
5777
5778 ADD_INSN(ret, line, dup);
5779 ADD_INSN1(ret, line, putobject, key);
5780 ADD_SEND(ret, line, rb_intern("key?"), INT2FIX(1));
5781 ADD_INSNL(ret, line, branchunless, match_failed);
5782
5783 ADD_INSN(match_values, line, dup);
5784 ADD_INSN1(match_values, line, putobject, key);
5785 ADD_SEND(match_values, line, node->nd_pkwrestarg ? rb_intern("delete") : idAREF, INT2FIX(1));
5786 iseq_compile_pattern_each(iseq, match_values, value_node, in_alt_pattern);
5787 ADD_INSNL(match_values, line, branchunless, match_failed);
5788 args = args->nd_next->nd_next;
5789 }
5790 ADD_SEQ(ret, match_values);
5791 }
5792 }
5793 else {
5794 ADD_INSN(ret, line, dup);
5795 ADD_SEND(ret, line, idEmptyP, INT2FIX(0));
5796 ADD_INSNL(ret, line, branchunless, match_failed);
5797 }
5798
5799 if (node->nd_pkwrestarg) {
5800 if (node->nd_pkwrestarg == NODE_SPECIAL_NO_REST_KEYWORD) {
5801 ADD_INSN(ret, line, dup);
5802 ADD_SEND(ret, line, idEmptyP, INT2FIX(0));
5803 ADD_INSNL(ret, line, branchunless, match_failed);
5804 }
5805 else {
5806 ADD_INSN(ret, line, dup);
5807 iseq_compile_pattern_each(iseq, ret, node->nd_pkwrestarg, in_alt_pattern);
5808 ADD_INSNL(ret, line, branchunless, match_failed);
5809 }
5810 }
5811
5812 ADD_INSN(ret, line, pop);
5813 ADD_INSN1(ret, line, putobject, Qtrue);
5814 ADD_INSNL(ret, line, jump, fin);
5815
5816 ADD_LABEL(ret, type_error);
5817 ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
5818 ADD_INSN1(ret, line, putobject, rb_eTypeError);
5819 ADD_INSN1(ret, line, putobject, rb_fstring_lit("deconstruct_keys must return Hash"));
5820 ADD_SEND(ret, line, id_core_raise, INT2FIX(2));
5821
5822 ADD_LABEL(ret, match_failed);
5823 ADD_INSN(ret, line, pop);
5824 ADD_INSN1(ret, line, putobject, Qfalse);
5825
5826 ADD_LABEL(ret, fin);
5827 break;
5828 }
5829 case NODE_LIT:
5830 case NODE_STR:
5831 case NODE_XSTR:
5832 case NODE_DSTR:
5833 case NODE_DSYM:
5834 case NODE_DREGX:
5835 case NODE_LIST:
5836 case NODE_ZLIST:
5837 case NODE_LAMBDA:
5838 case NODE_DOT2:
5839 case NODE_DOT3:
5840 case NODE_CONST:
5841 case NODE_LVAR:
5842 case NODE_DVAR:
5843 case NODE_TRUE:
5844 case NODE_FALSE:
5845 case NODE_SELF:
5846 case NODE_NIL:
5847 case NODE_COLON2:
5848 case NODE_COLON3:
5849 CHECK(COMPILE(ret, "case in literal", node));
5850 ADD_INSN1(ret, line, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE));
5851 break;
5852 case NODE_LASGN: {
5853 struct rb_iseq_constant_body *const body = iseq->body;
5854 ID id = node->nd_vid;
5855 int idx = body->local_iseq->body->local_table_size - get_local_var_idx(iseq, id);
5856
5857 if (in_alt_pattern) {
5858 const char *name = rb_id2name(id);
5859 if (name && strlen(name) > 0 && name[0] != '_') {
5860 COMPILE_ERROR(ERROR_ARGS "illegal variable in alternative pattern (%"PRIsVALUE")",
5861 rb_id2str(id));
5862 return COMPILE_NG;
5863 }
5864 }
5865
5866 ADD_SETLOCAL(ret, line, idx, get_lvar_level(iseq));
5867 ADD_INSN1(ret, line, putobject, Qtrue);
5868 break;
5869 }
5870 case NODE_DASGN:
5871 case NODE_DASGN_CURR: {
5872 int idx, lv, ls;
5873 ID id = node->nd_vid;
5874
5875 idx = get_dyna_var_idx(iseq, id, &lv, &ls);
5876
5877 if (in_alt_pattern) {
5878 const char *name = rb_id2name(id);
5879 if (name && strlen(name) > 0 && name[0] != '_') {
5880 COMPILE_ERROR(ERROR_ARGS "illegal variable in alternative pattern (%"PRIsVALUE")",
5881 rb_id2str(id));
5882 return COMPILE_NG;
5883 }
5884 }
5885
5886 if (idx < 0) {
5887 COMPILE_ERROR(ERROR_ARGS "NODE_DASGN(_CURR): unknown id (%"PRIsVALUE")",
5888 rb_id2str(id));
5889 return COMPILE_NG;
5890 }
5891 ADD_SETLOCAL(ret, line, ls - idx, lv);
5892 ADD_INSN1(ret, line, putobject, Qtrue);
5893 break;
5894 }
5895 case NODE_IF:
5896 case NODE_UNLESS: {
5897 LABEL *match_failed, *fin;
5898 match_failed = NEW_LABEL(line);
5899 fin = NEW_LABEL(line);
5900 iseq_compile_pattern_each(iseq, ret, node->nd_body, in_alt_pattern);
5901 ADD_INSNL(ret, line, branchunless, match_failed);
5902 CHECK(COMPILE(ret, "case in if", node->nd_cond));
5903 if (nd_type(node) == NODE_IF) {
5904 ADD_INSNL(ret, line, branchunless, match_failed);
5905 }
5906 else {
5907 ADD_INSNL(ret, line, branchif, match_failed);
5908 }
5909 ADD_INSN1(ret, line, putobject, Qtrue);
5910 ADD_INSNL(ret, line, jump, fin);
5911
5912 ADD_LABEL(ret, match_failed);
5913 ADD_INSN1(ret, line, putobject, Qfalse);
5914
5915 ADD_LABEL(ret, fin);
5916 break;
5917 }
5918 case NODE_HASH: {
5919 NODE *n;
5920 LABEL *match_failed, *fin;
5921 match_failed = NEW_LABEL(line);
5922 fin = NEW_LABEL(line);
5923
5924 n = node->nd_head;
5925 if (! (nd_type(n) == NODE_LIST && n->nd_alen == 2)) {
5926 COMPILE_ERROR(ERROR_ARGS "unexpected node");
5927 return COMPILE_NG;
5928 }
5929
5930 ADD_INSN(ret, line, dup);
5931 iseq_compile_pattern_each(iseq, ret, n->nd_head, in_alt_pattern);
5932 ADD_INSNL(ret, line, branchunless, match_failed);
5933 iseq_compile_pattern_each(iseq, ret, n->nd_next->nd_head, in_alt_pattern);
5934 ADD_INSNL(ret, line, jump, fin);
5935
5936 ADD_LABEL(ret, match_failed);
5937 ADD_INSN(ret, line, pop);
5938 ADD_INSN1(ret, line, putobject, Qfalse);
5939
5940 ADD_LABEL(ret, fin);
5941 break;
5942 }
5943 case NODE_OR: {
5944 LABEL *match_succeeded, *fin;
5945 match_succeeded = NEW_LABEL(line);
5946 fin = NEW_LABEL(line);
5947
5948 ADD_INSN(ret, line, dup);
5949 iseq_compile_pattern_each(iseq, ret, node->nd_1st, TRUE);
5950 ADD_INSNL(ret, line, branchif, match_succeeded);
5951 iseq_compile_pattern_each(iseq, ret, node->nd_2nd, TRUE);
5952 ADD_INSNL(ret, line, jump, fin);
5953
5954 ADD_LABEL(ret, match_succeeded);
5955 ADD_INSN(ret, line, pop);
5956 ADD_INSN1(ret, line, putobject, Qtrue);
5957
5958 ADD_LABEL(ret, fin);
5959 break;
5960 }
5961 default:
5962 UNKNOWN_NODE("NODE_IN", node, COMPILE_NG);
5963 }
5964 return COMPILE_OK;
5965 }
5966
5967 static int
5968 compile_case3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
5969 {
5970 const NODE *pattern;
5971 const NODE *node = orig_node;
5972 LABEL *endlabel, *elselabel;
5973 DECL_ANCHOR(head);
5974 DECL_ANCHOR(body_seq);
5975 DECL_ANCHOR(cond_seq);
5976 int line, lineno, column, last_lineno, last_column;
5977 enum node_type type;
5978 VALUE branches = 0;
5979
5980 INIT_ANCHOR(head);
5981 INIT_ANCHOR(body_seq);
5982 INIT_ANCHOR(cond_seq);
5983
5984 CHECK(COMPILE(head, "case base", node->nd_head));
5985
5986 DECL_BRANCH_BASE(branches, nd_first_lineno(node), nd_first_column(node), nd_last_lineno(node), nd_last_column(node), "case");
5987
5988 node = node->nd_body;
5989 EXPECT_NODE("NODE_CASE3", node, NODE_IN, COMPILE_NG);
5990 type = nd_type(node);
5991 line = nd_line(node);
5992 lineno = nd_first_lineno(node);
5993 column = nd_first_column(node);
5994 last_lineno = nd_last_lineno(node);
5995 last_column = nd_last_column(node);
5996
5997 endlabel = NEW_LABEL(line);
5998 elselabel = NEW_LABEL(line);
5999
6000 ADD_SEQ(ret, head); /* case VAL */
6001
6002 while (type == NODE_IN) {
6003 LABEL *l1;
6004
6005 l1 = NEW_LABEL(line);
6006 ADD_LABEL(body_seq, l1);
6007 ADD_INSN(body_seq, line, pop);
6008 ADD_TRACE_BRANCH_COVERAGE(
6009 body_seq,
6010 node->nd_body ? nd_first_lineno(node->nd_body) : lineno,
6011 node->nd_body ? nd_first_column(node->nd_body) : column,
6012 node->nd_body ? nd_last_lineno(node->nd_body) : last_lineno,
6013 node->nd_body ? nd_last_column(node->nd_body) : last_column,
6014 "in",
6015 branches);
6016 CHECK(COMPILE_(body_seq, "in body", node->nd_body, popped));
6017 ADD_INSNL(body_seq, line, jump, endlabel);
6018
6019 pattern = node->nd_head;
6020 if (pattern) {
6021 ADD_INSN (cond_seq, nd_line(pattern), dup);
6022 iseq_compile_pattern_each(iseq, cond_seq, pattern, FALSE);
6023 ADD_INSNL(cond_seq, nd_line(pattern), branchif, l1);
6024 }
6025 else {
6026 COMPILE_ERROR(ERROR_ARGS "unexpected node");
6027 return COMPILE_NG;
6028 }
6029
6030 node = node->nd_next;
6031 if (!node) {
6032 break;
6033 }
6034 type = nd_type(node);
6035 line = nd_line(node);
6036 lineno = nd_first_lineno(node);
6037 column = nd_first_column(node);
6038 last_lineno = nd_last_lineno(node);
6039 last_column = nd_last_column(node);
6040 }
6041 /* else */
6042 if (node) {
6043 ADD_LABEL(cond_seq, elselabel);
6044 ADD_INSN(cond_seq, line, pop);
6045 ADD_TRACE_BRANCH_COVERAGE(cond_seq, nd_first_lineno(node), nd_first_column(node), nd_last_lineno(node), nd_last_column(node), "else", branches);
6046 CHECK(COMPILE_(cond_seq, "else", node, popped));
6047 ADD_INSNL(cond_seq, line, jump, endlabel);
6048 }
6049 else {
6050 debugs("== else (implicit)\n");
6051 ADD_LABEL(cond_seq, elselabel);
6052 ADD_TRACE_BRANCH_COVERAGE(cond_seq, nd_first_lineno(orig_node), nd_first_column(orig_node), nd_last_lineno(orig_node), nd_last_column(orig_node), "else", branches);
6053 ADD_INSN1(cond_seq, nd_line(orig_node), putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
6054 ADD_INSN1(cond_seq, nd_line(orig_node), putobject, rb_eNoMatchingPatternError);
6055 ADD_INSN1(cond_seq, nd_line(orig_node), topn, INT2FIX(2));
6056 ADD_SEND(cond_seq, nd_line(orig_node), id_core_raise, INT2FIX(2));
6057 ADD_INSN(cond_seq, nd_line(orig_node), pop);
6058 ADD_INSN(cond_seq, nd_line(orig_node), pop);
6059 if (!popped) {
6060 ADD_INSN(cond_seq, nd_line(orig_node), putnil);
6061 }
6062 ADD_INSNL(cond_seq, nd_line(orig_node), jump, endlabel);
6063 }
6064
6065 ADD_SEQ(ret, cond_seq);
6066 ADD_SEQ(ret, body_seq);
6067 ADD_LABEL(ret, endlabel);
6068 return COMPILE_OK;
6069 }
6070
6071 static int
6072 compile_loop(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
6073 {
6074 const int line = (int)nd_line(node);
6075 const int lineno = nd_first_lineno(node);
6076 const int column = nd_first_column(node);
6077 const int last_lineno = nd_last_lineno(node);
6078 const int last_column = nd_last_column(node);
6079 LABEL *prev_start_label = ISEQ_COMPILE_DATA(iseq)->start_label;
6080 LABEL *prev_end_label = ISEQ_COMPILE_DATA(iseq)->end_label;
6081 LABEL *prev_redo_label = ISEQ_COMPILE_DATA(iseq)->redo_label;
6082 int prev_loopval_popped = ISEQ_COMPILE_DATA(iseq)->loopval_popped;
6083 VALUE branches = Qfalse;
6084
6085 struct iseq_compile_data_ensure_node_stack enl;
6086
6087 LABEL *next_label = ISEQ_COMPILE_DATA(iseq)->start_label = NEW_LABEL(line); /* next */
6088 LABEL *redo_label = ISEQ_COMPILE_DATA(iseq)->redo_label = NEW_LABEL(line); /* redo */
6089 LABEL *break_label = ISEQ_COMPILE_DATA(iseq)->end_label = NEW_LABEL(line); /* break */
6090 LABEL *end_label = NEW_LABEL(line);
6091 LABEL *adjust_label = NEW_LABEL(line);
6092
6093 LABEL *next_catch_label = NEW_LABEL(line);
6094 LABEL *tmp_label = NULL;
6095
6096 ISEQ_COMPILE_DATA(iseq)->loopval_popped = 0;
6097 push_ensure_entry(iseq, &enl, NULL, NULL);
6098
6099 if (node->nd_state == 1) {
6100 ADD_INSNL(ret, line, jump, next_label);
6101 }
6102 else {
6103 tmp_label = NEW_LABEL(line);
6104 ADD_INSNL(ret, line, jump, tmp_label);
6105 }
6106 ADD_LABEL(ret, adjust_label);
6107 ADD_INSN(ret, line, putnil);
6108 ADD_LABEL(ret, next_catch_label);
6109 ADD_INSN(ret, line, pop);
6110 ADD_INSNL(ret, line, jump, next_label);
6111 if (tmp_label) ADD_LABEL(ret, tmp_label);
6112
6113 ADD_LABEL(ret, redo_label);
6114 DECL_BRANCH_BASE(branches, lineno, column, last_lineno, last_column, type == NODE_WHILE ? "while" : "until");
6115 ADD_TRACE_BRANCH_COVERAGE(
6116 ret,
6117 node->nd_body ? nd_first_lineno(node->nd_body) : lineno,
6118 node->nd_body ? nd_first_column(node->nd_body) : column,
6119 node->nd_body ? nd_last_lineno(node->nd_body) : last_lineno,
6120 node->nd_body ? nd_last_column(node->nd_body) : last_column,
6121 "body",
6122 branches);
6123 CHECK(COMPILE_POPPED(ret, "while body", node->nd_body));
6124 ADD_LABEL(ret, next_label); /* next */
6125
6126 if (type == NODE_WHILE) {
6127 compile_branch_condition(iseq, ret, node->nd_cond,
6128 redo_label, end_label);
6129 }
6130 else {
6131 /* until */
6132 compile_branch_condition(iseq, ret, node->nd_cond,
6133 end_label, redo_label);
6134 }
6135
6136 ADD_LABEL(ret, end_label);
6137 ADD_ADJUST_RESTORE(ret, adjust_label);
6138
6139 if (node->nd_state == Qundef) {
6140 /* ADD_INSN(ret, line, putundef); */
6141 COMPILE_ERROR(ERROR_ARGS "unsupported: putundef");
6142 return COMPILE_NG;
6143 }
6144 else {
6145 ADD_INSN(ret, line, putnil);
6146 }
6147
6148 ADD_LABEL(ret, break_label); /* break */
6149
6150 if (popped) {
6151 ADD_INSN(ret, line, pop);
6152 }
6153
6154 ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, redo_label, break_label, NULL,
6155 break_label);
6156 ADD_CATCH_ENTRY(CATCH_TYPE_NEXT, redo_label, break_label, NULL,
6157 next_catch_label);
6158 ADD_CATCH_ENTRY(CATCH_TYPE_REDO, redo_label, break_label, NULL,
6159 ISEQ_COMPILE_DATA(iseq)->redo_label);
6160
6161 ISEQ_COMPILE_DATA(iseq)->start_label = prev_start_label;
6162 ISEQ_COMPILE_DATA(iseq)->end_label = prev_end_label;
6163 ISEQ_COMPILE_DATA(iseq)->redo_label = prev_redo_label;
6164 ISEQ_COMPILE_DATA(iseq)->loopval_popped = prev_loopval_popped;
6165 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack->prev;
6166 return COMPILE_OK;
6167 }
6168
6169 static int
6170 compile_iter(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
6171 {
6172 const int line = nd_line(node);
6173 const rb_iseq_t *prevblock = ISEQ_COMPILE_DATA(iseq)->current_block;
6174 LABEL *retry_label = NEW_LABEL(line);
6175 LABEL *retry_end_l = NEW_LABEL(line);
6176 const rb_iseq_t *child_iseq;
6177
6178 ADD_LABEL(ret, retry_label);
6179 if (nd_type(node) == NODE_FOR) {
6180 CHECK(COMPILE(ret, "iter caller (for)", node->nd_iter));
6181
6182 ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq =
6183 NEW_CHILD_ISEQ(node->nd_body, make_name_for_block(iseq),
6184 ISEQ_TYPE_BLOCK, line);
6185 ADD_SEND_WITH_BLOCK(ret, line, idEach, INT2FIX(0), child_iseq);
6186 }
6187 else {
6188 ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq =
6189 NEW_CHILD_ISEQ(node->nd_body, make_name_for_block(iseq),
6190 ISEQ_TYPE_BLOCK, line);
6191 CHECK(COMPILE(ret, "iter caller", node->nd_iter));
6192 }
6193 ADD_LABEL(ret, retry_end_l);
6194
6195 if (popped) {
6196 ADD_INSN(ret, line, pop);
6197 }
6198
6199 ISEQ_COMPILE_DATA(iseq)->current_block = prevblock;
6200
6201 ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, retry_label, retry_end_l, child_iseq, retry_end_l);
6202 return COMPILE_OK;
6203 }
6204
6205 static int
6206 compile_for_masgn(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
6207 {
6208 /* massign to var in "for"
6209 * (args.length == 1 && Array.try_convert(args[0])) || args
6210 */
6211 const int line = nd_line(node);
6212 const NODE *var = node->nd_var;
6213 LABEL *not_single = NEW_LABEL(nd_line(var));
6214 LABEL *not_ary = NEW_LABEL(nd_line(var));
6215 CHECK(COMPILE(ret, "for var", var));
6216 ADD_INSN(ret, line, dup);
6217 ADD_CALL(ret, line, idLength, INT2FIX(0));
6218 ADD_INSN1(ret, line, putobject, INT2FIX(1));
6219 ADD_CALL(ret, line, idEq, INT2FIX(1));
6220 ADD_INSNL(ret, line, branchunless, not_single);
6221 ADD_INSN(ret, line, dup);
6222 ADD_INSN1(ret, line, putobject, INT2FIX(0));
6223 ADD_CALL(ret, line, idAREF, INT2FIX(1));
6224 ADD_INSN1(ret, line, putobject, rb_cArray);
6225 ADD_INSN(ret, line, swap);
6226 ADD_CALL(ret, line, rb_intern("try_convert"), INT2FIX(1));
6227 ADD_INSN(ret, line, dup);
6228 ADD_INSNL(ret, line, branchunless, not_ary);
6229 ADD_INSN(ret, line, swap);
6230 ADD_LABEL(ret, not_ary);
6231 ADD_INSN(ret, line, pop);
6232 ADD_LABEL(ret, not_single);
6233 return COMPILE_OK;
6234 }
6235
6236 static int
6237 compile_break(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
6238 {
6239 const int line = nd_line(node);
6240 unsigned long throw_flag = 0;
6241
6242 if (ISEQ_COMPILE_DATA(iseq)->redo_label != 0) {
6243 /* while/until */
6244 LABEL *splabel = NEW_LABEL(0);
6245 ADD_LABEL(ret, splabel);
6246 ADD_ADJUST(ret, line, ISEQ_COMPILE_DATA(iseq)->redo_label);
6247 CHECK(COMPILE_(ret, "break val (while/until)", node->nd_stts,
6248 ISEQ_COMPILE_DATA(iseq)->loopval_popped));
6249 add_ensure_iseq(ret, iseq, 0);
6250 ADD_INSNL(ret, line, jump, ISEQ_COMPILE_DATA(iseq)->end_label);
6251 ADD_ADJUST_RESTORE(ret, splabel);
6252
6253 if (!popped) {
6254 ADD_INSN(ret, line, putnil);
6255 }
6256 }
6257 else if (iseq->body->type == ISEQ_TYPE_BLOCK) {
6258 break_by_insn:
6259 /* escape from block */
6260 CHECK(COMPILE(ret, "break val (block)", node->nd_stts));
6261 ADD_INSN1(ret, line, throw, INT2FIX(throw_flag | TAG_BREAK));
6262 if (popped) {
6263 ADD_INSN(ret, line, pop);
6264 }
6265 }
6266 else if (iseq->body->type == ISEQ_TYPE_EVAL) {
6267 break_in_eval:
6268 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with break");
6269 return COMPILE_NG;
6270 }
6271 else {
6272 const rb_iseq_t *ip = iseq->body->parent_iseq;
6273
6274 while (ip) {
6275 if (!ISEQ_COMPILE_DATA(ip)) {
6276 ip = 0;
6277 break;
6278 }
6279
6280 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
6281 throw_flag = VM_THROW_NO_ESCAPE_FLAG;
6282 goto break_by_insn;
6283 }
6284 else if (ip->body->type == ISEQ_TYPE_BLOCK) {
6285 goto break_by_insn;
6286 }
6287 else if (ip->body->type == ISEQ_TYPE_EVAL) {
6288 goto break_in_eval;
6289 }
6290
6291 ip = ip->body->parent_iseq;
6292 }
6293 COMPILE_ERROR(ERROR_ARGS "Invalid break");
6294 return COMPILE_NG;
6295 }
6296 return COMPILE_OK;
6297 }
6298
6299 static int
6300 compile_next(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
6301 {
6302 const int line = nd_line(node);
6303 unsigned long throw_flag = 0;
6304
6305 if (ISEQ_COMPILE_DATA(iseq)->redo_label != 0) {
6306 LABEL *splabel = NEW_LABEL(0);
6307 debugs("next in while loop\n");
6308 ADD_LABEL(ret, splabel);
6309 CHECK(COMPILE(ret, "next val/valid syntax?", node->nd_stts));
6310 add_ensure_iseq(ret, iseq, 0);
6311 ADD_ADJUST(ret, line, ISEQ_COMPILE_DATA(iseq)->redo_label);
6312 ADD_INSNL(ret, line, jump, ISEQ_COMPILE_DATA(iseq)->start_label);
6313 ADD_ADJUST_RESTORE(ret, splabel);
6314 if (!popped) {
6315 ADD_INSN(ret, line, putnil);
6316 }
6317 }
6318 else if (ISEQ_COMPILE_DATA(iseq)->end_label) {
6319 LABEL *splabel = NEW_LABEL(0);
6320 debugs("next in block\n");
6321 ADD_LABEL(ret, splabel);
6322 ADD_ADJUST(ret, line, ISEQ_COMPILE_DATA(iseq)->start_label);
6323 CHECK(COMPILE(ret, "next val", node->nd_stts));
6324 add_ensure_iseq(ret, iseq, 0);
6325 ADD_INSNL(ret, line, jump, ISEQ_COMPILE_DATA(iseq)->end_label);
6326 ADD_ADJUST_RESTORE(ret, splabel);
6327 splabel->unremovable = FALSE;
6328
6329 if (!popped) {
6330 ADD_INSN(ret, line, putnil);
6331 }
6332 }
6333 else if (iseq->body->type == ISEQ_TYPE_EVAL) {
6334 next_in_eval:
6335 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with next");
6336 return COMPILE_NG;
6337 }
6338 else {
6339 const rb_iseq_t *ip = iseq;
6340
6341 while (ip) {
6342 if (!ISEQ_COMPILE_DATA(ip)) {
6343 ip = 0;
6344 break;
6345 }
6346
6347 throw_flag = VM_THROW_NO_ESCAPE_FLAG;
6348 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
6349 /* while loop */
6350 break;
6351 }
6352 else if (ip->body->type == ISEQ_TYPE_BLOCK) {
6353 break;
6354 }
6355 else if (ip->body->type == ISEQ_TYPE_EVAL) {
6356 goto next_in_eval;
6357 }
6358
6359 ip = ip->body->parent_iseq;
6360 }
6361 if (ip != 0) {
6362 CHECK(COMPILE(ret, "next val", node->nd_stts));
6363 ADD_INSN1(ret, line, throw, INT2FIX(throw_flag | TAG_NEXT));
6364
6365 if (popped) {
6366 ADD_INSN(ret, line, pop);
6367 }
6368 }
6369 else {
6370 COMPILE_ERROR(ERROR_ARGS "Invalid next");
6371 return COMPILE_NG;
6372 }
6373 }
6374 return COMPILE_OK;
6375 }
6376
6377 static int
6378 compile_redo(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
6379 {
6380 const int line = nd_line(node);
6381
6382 if (ISEQ_COMPILE_DATA(iseq)->redo_label) {
6383 LABEL *splabel = NEW_LABEL(0);
6384 debugs("redo in while");
6385 ADD_LABEL(ret, splabel);
6386 ADD_ADJUST(ret, line, ISEQ_COMPILE_DATA(iseq)->redo_label);
6387 add_ensure_iseq(ret, iseq, 0);
6388 ADD_INSNL(ret, line, jump, ISEQ_COMPILE_DATA(iseq)->redo_label);
6389 ADD_ADJUST_RESTORE(ret, splabel);
6390 if (!popped) {
6391 ADD_INSN(ret, line, putnil);
6392 }
6393 }
6394 else if (iseq->body->type == ISEQ_TYPE_EVAL) {
6395 redo_in_eval:
6396 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with redo");
6397 return COMPILE_NG;
6398 }
6399 else if (ISEQ_COMPILE_DATA(iseq)->start_label) {
6400 LABEL *splabel = NEW_LABEL(0);
6401
6402 debugs("redo in block");
6403 ADD_LABEL(ret, splabel);
6404 add_ensure_iseq(ret, iseq, 0);
6405 ADD_ADJUST(ret, line, ISEQ_COMPILE_DATA(iseq)->start_label);
6406 ADD_INSNL(ret, line, jump, ISEQ_COMPILE_DATA(iseq)->start_label);
6407 ADD_ADJUST_RESTORE(ret, splabel);
6408
6409 if (!popped) {
6410 ADD_INSN(ret, line, putnil);
6411 }
6412 }
6413 else {
6414 const rb_iseq_t *ip = iseq;
6415
6416 while (ip) {
6417 if (!ISEQ_COMPILE_DATA(ip)) {
6418 ip = 0;
6419 break;
6420 }
6421
6422 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
6423 break;
6424 }
6425 else if (ip->body->type == ISEQ_TYPE_BLOCK) {
6426 break;
6427 }
6428 else if (ip->body->type == ISEQ_TYPE_EVAL) {
6429 goto redo_in_eval;
6430 }
6431
6432 ip = ip->body->parent_iseq;
6433 }
6434 if (ip != 0) {
6435 ADD_INSN(ret, line, putnil);
6436 ADD_INSN1(ret, line, throw, INT2FIX(VM_THROW_NO_ESCAPE_FLAG | TAG_REDO));
6437
6438 if (popped) {
6439 ADD_INSN(ret, line, pop);
6440 }
6441 }
6442 else {
6443 COMPILE_ERROR(ERROR_ARGS "Invalid redo");
6444 return COMPILE_NG;
6445 }
6446 }
6447 return COMPILE_OK;
6448 }
6449
6450 static int
6451 compile_retry(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
6452 {
6453 const int line = nd_line(node);
6454
6455 if (iseq->body->type == ISEQ_TYPE_RESCUE) {
6456 ADD_INSN(ret, line, putnil);
6457 ADD_INSN1(ret, line, throw, INT2FIX(TAG_RETRY));
6458
6459 if (popped) {
6460 ADD_INSN(ret, line, pop);
6461 }
6462 }
6463 else {
6464 COMPILE_ERROR(ERROR_ARGS "Invalid retry");
6465 return COMPILE_NG;
6466 }
6467 return COMPILE_OK;
6468 }
6469
6470 static int
6471 compile_rescue(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
6472 {
6473 const int line = nd_line(node);
6474 LABEL *lstart = NEW_LABEL(line);
6475 LABEL *lend = NEW_LABEL(line);
6476 LABEL *lcont = NEW_LABEL(line);
6477 const rb_iseq_t *rescue = NEW_CHILD_ISEQ(node->nd_resq,
6478 rb_str_concat(rb_str_new2("rescue in "), iseq->body->location.label),
6479 ISEQ_TYPE_RESCUE, line);
6480
6481 lstart->rescued = LABEL_RESCUE_BEG;
6482 lend->rescued = LABEL_RESCUE_END;
6483 ADD_LABEL(ret, lstart);
6484 CHECK(COMPILE(ret, "rescue head", node->nd_head));
6485 ADD_LABEL(ret, lend);
6486 if (node->nd_else) {
6487 ADD_INSN(ret, line, pop);
6488 CHECK(COMPILE(ret, "rescue else", node->nd_else));
6489 }
6490 ADD_INSN(ret, line, nop);
6491 ADD_LABEL(ret, lcont);
6492
6493 if (popped) {
6494 ADD_INSN(ret, line, pop);
6495 }
6496
6497 /* register catch entry */
6498 ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lcont);
6499 ADD_CATCH_ENTRY(CATCH_TYPE_RETRY, lend, lcont, NULL, lstart);
6500 return COMPILE_OK;
6501 }
6502
6503 static int
6504 compile_resbody(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
6505 {
6506 const int line = nd_line(node);
6507 const NODE *resq = node;
6508 const NODE *narg;
6509 LABEL *label_miss, *label_hit;
6510
6511 while (resq) {
6512 label_miss = NEW_LABEL(line);
6513 label_hit = NEW_LABEL(line);
6514
6515 narg = resq->nd_args;
6516 if (narg) {
6517 switch (nd_type(narg)) {
6518 case NODE_LIST:
6519 while (narg) {
6520 ADD_GETLOCAL(ret, line, LVAR_ERRINFO, 0);
6521 CHECK(COMPILE(ret, "rescue arg", narg->nd_head));
6522 ADD_INSN1(ret, line, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
6523 ADD_INSNL(ret, line, branchif, label_hit);
6524 narg = narg->nd_next;
6525 }
6526 break;
6527 case NODE_SPLAT:
6528 case NODE_ARGSCAT:
6529 case NODE_ARGSPUSH:
6530 ADD_GETLOCAL(ret, line, LVAR_ERRINFO, 0);
6531 CHECK(COMPILE(ret, "rescue/cond splat", narg));
6532 ADD_INSN1(ret, line, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE | VM_CHECKMATCH_ARRAY));
6533 ADD_INSNL(ret, line, branchif, label_hit);
6534 break;
6535 default:
6536 UNKNOWN_NODE("NODE_RESBODY", narg, COMPILE_NG);
6537 }
6538 }
6539 else {
6540 ADD_GETLOCAL(ret, line, LVAR_ERRINFO, 0);
6541 ADD_INSN1(ret, line, putobject, rb_eStandardError);
6542 ADD_INSN1(ret, line, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
6543 ADD_INSNL(ret, line, branchif, label_hit);
6544 }
6545 ADD_INSNL(ret, line, jump, label_miss);
6546 ADD_LABEL(ret, label_hit);
6547 CHECK(COMPILE(ret, "resbody body", resq->nd_body));
6548 if (ISEQ_COMPILE_DATA(iseq)->option->tailcall_optimization) {
6549 ADD_INSN(ret, line, nop);
6550 }
6551 ADD_INSN(ret, line, leave);
6552 ADD_LABEL(ret, label_miss);
6553 resq = resq->nd_head;
6554 }
6555 return COMPILE_OK;
6556 }
6557
6558 static int
6559 compile_ensure(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
6560 {
6561 const int line = nd_line(node);
6562 DECL_ANCHOR(ensr);
6563 const rb_iseq_t *ensure = NEW_CHILD_ISEQ(node->nd_ensr,
6564 rb_str_concat(rb_str_new2 ("ensure in "), iseq->body->location.label),
6565 ISEQ_TYPE_ENSURE, line);
6566 LABEL *lstart = NEW_LABEL(line);
6567 LABEL *lend = NEW_LABEL(line);
6568 LABEL *lcont = NEW_LABEL(line);
6569 LINK_ELEMENT *last;
6570 int last_leave = 0;
6571 struct ensure_range er;
6572 struct iseq_compile_data_ensure_node_stack enl;
6573 struct ensure_range *erange;
6574
6575 INIT_ANCHOR(ensr);
6576 CHECK(COMPILE_POPPED(ensr, "ensure ensr", node->nd_ensr));
6577 last = ensr->last;
6578 last_leave = last && IS_INSN(last) && IS_INSN_ID(last, leave);
6579
6580 er.begin = lstart;
6581 er.end = lend;
6582 er.next = 0;
6583 push_ensure_entry(iseq, &enl, &er, node->nd_ensr);
6584
6585 ADD_LABEL(ret, lstart);
6586 CHECK(COMPILE_(ret, "ensure head", node->nd_head, (popped | last_leave)));
6587 ADD_LABEL(ret, lend);
6588 ADD_SEQ(ret, ensr);
6589 if (!popped && last_leave) ADD_INSN(ret, line, putnil);
6590 ADD_LABEL(ret, lcont);
6591 if (last_leave) ADD_INSN(ret, line, pop);
6592
6593 erange = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack->erange;
6594 if (lstart->link.next != &lend->link) {
6595 while (erange) {
6596 ADD_CATCH_ENTRY(CATCH_TYPE_ENSURE, erange->begin, erange->end,
6597 ensure, lcont);
6598 erange = erange->next;
6599 }
6600 }
6601
6602 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enl.prev;
6603 return COMPILE_OK;
6604 }
6605
6606 static int
6607 compile_return(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
6608 {
6609 const int line = nd_line(node);
6610
6611 if (iseq) {
6612 enum iseq_type type = iseq->body->type;
6613 const rb_iseq_t *is = iseq;
6614 enum iseq_type t = type;
6615 const NODE *retval = node->nd_stts;
6616 LABEL *splabel = 0;
6617
6618 while (t == ISEQ_TYPE_RESCUE || t == ISEQ_TYPE_ENSURE) {
6619 if (!(is = is->body->parent_iseq)) break;
6620 t = is->body->type;
6621 }
6622 switch (t) {
6623 case ISEQ_TYPE_TOP:
6624 case ISEQ_TYPE_MAIN:
6625 if (retval) {
6626 rb_warn("argument of top-level return is ignored");
6627 }
6628 if (is == iseq) {
6629 /* plain top-level, leave directly */
6630 type = ISEQ_TYPE_METHOD;
6631 }
6632 break;
6633 default:
6634 break;
6635 }
6636
6637 if (type == ISEQ_TYPE_METHOD) {
6638 splabel = NEW_LABEL(0);
6639 ADD_LABEL(ret, splabel);
6640 ADD_ADJUST(ret, line, 0);
6641 }
6642
6643 CHECK(COMPILE(ret, "return nd_stts (return val)", retval));
6644
6645 if (type == ISEQ_TYPE_METHOD) {
6646 add_ensure_iseq(ret, iseq, 1);
6647 ADD_TRACE(ret, RUBY_EVENT_RETURN);
6648 ADD_INSN(ret, line, leave);
6649 ADD_ADJUST_RESTORE(ret, splabel);
6650
6651 if (!popped) {
6652 ADD_INSN(ret, line, putnil);
6653 }
6654 }
6655 else {
6656 ADD_INSN1(ret, line, throw, INT2FIX(TAG_RETURN));
6657 if (popped) {
6658 ADD_INSN(ret, line, pop);
6659 }
6660 }
6661 }
6662 return COMPILE_OK;
6663 }
6664
6665 static int
6666 compile_evstr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
6667 {
6668 CHECK(COMPILE_(ret, "nd_body", node, popped));
6669
6670 if (!popped && !all_string_result_p(node)) {
6671 const int line = nd_line(node);
6672 const unsigned int flag = VM_CALL_FCALL;
6673 LABEL *isstr = NEW_LABEL(line);
6674 ADD_INSN(ret, line, dup);
6675 ADD_INSN1(ret, line, checktype, INT2FIX(T_STRING));
6676 ADD_INSNL(ret, line, branchif, isstr);
6677 ADD_INSN(ret, line, dup);
6678 ADD_SEND_R(ret, line, idTo_s, INT2FIX(0), NULL, INT2FIX(flag), NULL);
6679 ADD_INSN(ret, line, tostring);
6680 ADD_LABEL(ret, isstr);
6681 }
6682 return COMPILE_OK;
6683 }
6684
6685 static LABEL *
6686 qcall_branch_start(rb_iseq_t *iseq, LINK_ANCHOR *const recv, VALUE *branches, const NODE *node, int line)
6687 {
6688 LABEL *else_label = NEW_LABEL(line);
6689 const int first_lineno = nd_first_lineno(node), first_column = nd_first_column(node);
6690 const int last_lineno = nd_last_lineno(node), last_column = nd_last_column(node);
6691 VALUE br = 0;
6692
6693 DECL_BRANCH_BASE(br, first_lineno, first_column, last_lineno, last_column, "&.");
6694 *branches = br;
6695 ADD_INSN(recv, line, dup);
6696 ADD_INSNL(recv, line, branchnil, else_label);
6697 ADD_TRACE_BRANCH_COVERAGE(recv, first_lineno, first_column, last_lineno, last_column, "then", br);
6698 return else_label;
6699 }
6700
6701 static void
6702 qcall_branch_end(rb_iseq_t *iseq, LINK_ANCHOR *const ret, LABEL *else_label, VALUE branches, const NODE *node, int line)
6703 {
6704 LABEL *end_label;
6705 if (!else_label) return;
6706 end_label = NEW_LABEL(line);
6707 ADD_INSNL(ret, line, jump, end_label);
6708 ADD_LABEL(ret, else_label);
6709 ADD_TRACE_BRANCH_COVERAGE(ret, nd_first_lineno(node), nd_first_column(node), nd_last_lineno(node), nd_last_column(node),
6710 "else", branches);
6711 ADD_LABEL(ret, end_label);
6712 }
6713
6714 static int
6715 compile_call_precheck_freeze(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int line, int popped)
6716 {
6717 /* optimization shortcut
6718 * "literal".freeze -> opt_str_freeze("literal")
6719 */
6720 if (node->nd_recv && nd_type(node->nd_recv) == NODE_STR &&
6721 (node->nd_mid == idFreeze || node->nd_mid == idUMinus) &&
6722 node->nd_args == NULL &&
6723 ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
6724 ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
6725 VALUE str = rb_fstring(node->nd_recv->nd_lit);
6726 if (node->nd_mid == idUMinus) {
6727 ADD_INSN2(ret, line, opt_str_uminus, str,
6728 new_callinfo(iseq, idUMinus, 0, 0, NULL, FALSE));
6729 }
6730 else {
6731 ADD_INSN2(ret, line, opt_str_freeze, str,
6732 new_callinfo(iseq, idFreeze, 0, 0, NULL, FALSE));
6733 }
6734 RB_OBJ_WRITTEN(iseq, Qundef, str);
6735 if (popped) {
6736 ADD_INSN(ret, line, pop);
6737 }
6738 return TRUE;
6739 }
6740 /* optimization shortcut
6741 * obj["literal"] -> opt_aref_with(obj, "literal")
6742 */
6743 if (node->nd_mid == idAREF && !private_recv_p(node) && node->nd_args &&
6744 nd_type(node->nd_args) == NODE_LIST && node->nd_args->nd_alen == 1 &&
6745 nd_type(node->nd_args->nd_head) == NODE_STR &&
6746 ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
6747 !ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal &&
6748 ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
6749 VALUE str = rb_fstring(node->nd_args->nd_head->nd_lit);
6750 CHECK(COMPILE(ret, "recv", node->nd_recv));
6751 ADD_INSN2(ret, line, opt_aref_with, str,
6752 new_callinfo(iseq, idAREF, 1, 0, NULL, FALSE));
6753 RB_OBJ_WRITTEN(iseq, Qundef, str);
6754 if (popped) {
6755 ADD_INSN(ret, line, pop);
6756 }
6757 return TRUE;
6758 }
6759 return FALSE;
6760 }
6761
6762 static int
6763 iseq_has_builtin_function_table(const rb_iseq_t *iseq)
6764 {
6765 return ISEQ_COMPILE_DATA(iseq)->builtin_function_table != NULL;
6766 }
6767
6768 static const struct rb_builtin_function *
6769 iseq_builtin_function_lookup(const rb_iseq_t *iseq, const char *name)
6770 {
6771 int i;
6772 const struct rb_builtin_function *table = ISEQ_COMPILE_DATA(iseq)->builtin_function_table;
6773 for (i=0; table[i].index != -1; i++) {
6774 if (strcmp(table[i].name, name) == 0) {
6775 return &table[i];
6776 }
6777 }
6778 return NULL;
6779 }
6780
6781 static const char *
6782 iseq_builtin_function_name(ID mid)
6783 {
6784 const char *name = rb_id2name(mid);
6785 static const char prefix[] = "__builtin_";
6786 const size_t prefix_len = sizeof(prefix) - 1;
6787
6788 if (UNLIKELY(strncmp(prefix, name, prefix_len) == 0)) {
6789 return &name[prefix_len];
6790 }
6791 else {
6792 return NULL;
6793 }
6794 }
6795
6796 static int
6797 delegate_call_p(const rb_iseq_t *iseq, unsigned int argc, const LINK_ANCHOR *args, unsigned int *pstart_index)
6798 {
6799
6800 if (argc == 0) {
6801 *pstart_index = 0;
6802 return TRUE;
6803 }
6804 else if (argc <= iseq->body->local_table_size) {
6805 unsigned int start=0;
6806
6807 // local_table: [p1, p2, p3, l1, l2, l3]
6808 // arguments: [p3, l1, l2] -> 2
6809 for (start = 0;
6810 argc + start <= iseq->body->local_table_size;
6811 start++) {
6812 const LINK_ELEMENT *elem = FIRST_ELEMENT(args);
6813
6814 for (unsigned int i=start; i-start<argc; i++) {
6815 if (elem->type == ISEQ_ELEMENT_INSN &&
6816 INSN_OF(elem) == BIN(getlocal)) {
6817 int local_index = FIX2INT(OPERAND_AT(elem, 0));
6818 int local_level = FIX2INT(OPERAND_AT(elem, 1));
6819
6820 if (local_level == 0) {
6821 unsigned int index = iseq->body->local_table_size - (local_index - VM_ENV_DATA_SIZE + 1);
6822 if (0) { // for debug
6823 fprintf(stderr, "lvar:%s (%d), id:%s (%d) local_index:%d, local_size:%d\n",
6824 rb_id2name(iseq->body->local_table[i]), i,
6825 rb_id2name(iseq->body->local_table[index]), index,
6826 local_index, (int)iseq->body->local_table_size);
6827 }
6828 if (i == index) {
6829 elem = elem->next;
6830 continue; /* for */
6831 }
6832 else {
6833 goto next;
6834 }
6835 }
6836 else {
6837 goto fail; // level != 0 is unsupported
6838 }
6839 }
6840 else {
6841 goto fail; // insn is not a getlocal
6842 }
6843 }
6844 goto success;
6845 next:;
6846 }
6847 fail:
6848 return FALSE;
6849 success:
6850 *pstart_index = start;
6851 return TRUE;
6852 }
6853 else {
6854 return FALSE;
6855 }
6856 }
6857
6858 static int
6859 compile_call(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int type, int line, int popped)
6860 {
6861 /* call: obj.method(...)
6862 * fcall: func(...)
6863 * vcall: func
6864 */
6865 DECL_ANCHOR(recv);
6866 DECL_ANCHOR(args);
6867 ID mid = node->nd_mid;
6868 VALUE argc;
6869 unsigned int flag = 0;
6870 struct rb_call_info_kw_arg *keywords = NULL;
6871 const rb_iseq_t *parent_block = ISEQ_COMPILE_DATA(iseq)->current_block;
6872 LABEL *else_label = NULL;
6873 VALUE branches = Qfalse;
6874
6875 ISEQ_COMPILE_DATA(iseq)->current_block = NULL;
6876
6877 INIT_ANCHOR(recv);
6878 INIT_ANCHOR(args);
6879 #if OPT_SUPPORT_JOKE
6880 if (nd_type(node) == NODE_VCALL) {
6881 ID id_bitblt;
6882 ID id_answer;
6883
6884 CONST_ID(id_bitblt, "bitblt");
6885 CONST_ID(id_answer, "the_answer_to_life_the_universe_and_everything");
6886
6887 if (mid == id_bitblt) {
6888 ADD_INSN(ret, line, bitblt);
6889 return COMPILE_OK;
6890 }
6891 else if (mid == id_answer) {
6892 ADD_INSN(ret, line, answer);
6893 return COMPILE_OK;
6894 }
6895 }
6896 /* only joke */
6897 {
6898 ID goto_id;
6899 ID label_id;
6900
6901 CONST_ID(goto_id, "__goto__");
6902 CONST_ID(label_id, "__label__");
6903
6904 if (nd_type(node) == NODE_FCALL &&
6905 (mid == goto_id || mid == label_id)) {
6906 LABEL *label;
6907 st_data_t data;
6908 st_table *labels_table = ISEQ_COMPILE_DATA(iseq)->labels_table;
6909 VALUE label_name;
6910
6911 if (!labels_table) {
6912 labels_table = st_init_numtable();
6913 ISEQ_COMPILE_DATA(iseq)->labels_table = labels_table;
6914 }
6915 if (nd_type(node->nd_args->nd_head) == NODE_LIT &&
6916 SYMBOL_P(node->nd_args->nd_head->nd_lit)) {
6917
6918 label_name = node->nd_args->nd_head->nd_lit;
6919 if (!st_lookup(labels_table, (st_data_t)label_name, &data)) {
6920 label = NEW_LABEL(line);
6921 label->position = line;
6922 st_insert(labels_table, (st_data_t)label_name, (st_data_t)label);
6923 }
6924 else {
6925 label = (LABEL *)data;
6926 }
6927 }
6928 else {
6929 COMPILE_ERROR(ERROR_ARGS "invalid goto/label format");
6930 return COMPILE_NG;
6931 }
6932
6933 if (mid == goto_id) {
6934 ADD_INSNL(ret, line, jump, label);
6935 }
6936 else {
6937 ADD_LABEL(ret, label);
6938 }
6939 return COMPILE_OK;
6940 }
6941 }
6942 #endif
6943 const char *builtin_func;
6944 NODE *args_node = node->nd_args;
6945
6946 if (UNLIKELY(iseq_has_builtin_function_table(iseq)) &&
6947 (builtin_func = iseq_builtin_function_name(mid)) != NULL) {
6948
6949 if (parent_block != NULL) {
6950 COMPILE_ERROR(iseq, line, "should not call builtins here.");
6951 return COMPILE_NG;
6952 }
6953 else {
6954 char inline_func[0x20];
6955 bool cconst = false;
6956 retry:;
6957 const struct rb_builtin_function *bf = iseq_builtin_function_lookup(iseq, builtin_func);
6958
6959 if (bf == NULL) {
6960 if (strcmp("cstmt!", builtin_func) == 0 ||
6961 strcmp("cexpr!", builtin_func) == 0) {
6962 inlinec:;
6963 int inline_index = GET_VM()->builtin_inline_index++;
6964 snprintf(inline_func, 0x20, "_bi%d", inline_index);
6965 builtin_func = inline_func;
6966 args_node = NULL;
6967 goto retry;
6968 }
6969 else if (strcmp("cconst!", builtin_func) == 0) {
6970 cconst = true;
6971 goto inlinec;
6972 }
6973 else if (strcmp("cinit!", builtin_func) == 0) {
6974 // ignore
6975 GET_VM()->builtin_inline_index++;
6976 return COMPILE_OK;
6977 }
6978
6979 if (1) {
6980 rb_bug("can't find builtin function:%s", builtin_func);
6981 }
6982 else {
6983 COMPILE_ERROR(ERROR_ARGS "can't find builtin function:%s", builtin_func);
6984 }
6985 return COMPILE_NG;
6986 }
6987
6988 if (cconst) {
6989 typedef VALUE(*builtin_func0)(void *, VALUE);
6990 VALUE const_val = (*(builtin_func0)bf->func_ptr)(NULL, Qnil);
6991 ADD_INSN1(ret, line, putobject, const_val);
6992 return COMPILE_OK;
6993 }
6994
6995 // fprintf(stderr, "func_name:%s -> %p\n", builtin_func, bf->func_ptr);
6996
6997 argc = setup_args(iseq, args, args_node, &flag, &keywords);
6998
6999 if (FIX2INT(argc) != bf->argc) {
7000 COMPILE_ERROR(ERROR_ARGS "argc is not match for builtin function:%s (expect %d but %d)",
7001 builtin_func, bf->argc, FIX2INT(argc));
7002 return COMPILE_NG;
7003 }
7004
7005 unsigned int start_index;
7006 if (delegate_call_p(iseq, FIX2INT(argc), args, &start_index)) {
7007 ADD_INSN2(ret, line, opt_invokebuiltin_delegate, bf, INT2FIX(start_index));
7008 }
7009 else {
7010 ADD_SEQ(ret, args);
7011 ADD_INSN1(ret,line, invokebuiltin, bf);
7012 }
7013
7014 if (popped) ADD_INSN(ret, line, pop);
7015 return COMPILE_OK;
7016 }
7017 }
7018
7019
7020 /* receiver */
7021 if (type == NODE_CALL || type == NODE_OPCALL || type == NODE_QCALL) {
7022 int idx, level;
7023
7024 if (mid == idCall &&
7025 nd_type(node->nd_recv) == NODE_LVAR &&
7026 iseq_block_param_id_p(iseq, node->nd_recv->nd_vid, &idx, &level)) {
7027 ADD_INSN2(recv, nd_line(node->nd_recv), getblockparamproxy, INT2FIX(idx + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
7028 }
7029 else if (private_recv_p(node)) {
7030 ADD_INSN(recv, nd_line(node), putself);
7031 flag |= VM_CALL_FCALL;
7032 }
7033 else {
7034 CHECK(COMPILE(recv, "recv", node->nd_recv));
7035 }
7036
7037 if (type == NODE_QCALL) {
7038 else_label = qcall_branch_start(iseq, recv, &branches, node, line);
7039 }
7040 }
7041 else if (type == NODE_FCALL || type == NODE_VCALL) {
7042 ADD_CALL_RECEIVER(recv, line);
7043 }
7044
7045 /* args */
7046 if (type != NODE_VCALL) {
7047 argc = setup_args(iseq, args, node->nd_args, &flag, &keywords);
7048 CHECK(!NIL_P(argc));
7049 }
7050 else {
7051 argc = INT2FIX(0);
7052 }
7053
7054 ADD_SEQ(ret, recv);
7055 ADD_SEQ(ret, args);
7056
7057 debugp_param("call args argc", argc);
7058 debugp_param("call method", ID2SYM(mid));
7059
7060 switch ((int)type) {
7061 case NODE_VCALL:
7062 flag |= VM_CALL_VCALL;
7063 /* VCALL is funcall, so fall through */
7064 case NODE_FCALL:
7065 flag |= VM_CALL_FCALL;
7066 }
7067
7068 ADD_SEND_R(ret, line, mid, argc, parent_block, INT2FIX(flag), keywords);
7069
7070 qcall_branch_end(iseq, ret, else_label, branches, node, line);
7071 if (popped) {
7072 ADD_INSN(ret, line, pop);
7073 }
7074 return COMPILE_OK;
7075 }
7076
7077
7078 static int iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int popped);
7086 static int
7087 iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *node, int popped)
7088 {
7089 if (node == 0) {
7090 if (!popped) {
7091 int lineno = ISEQ_COMPILE_DATA(iseq)->last_line;
7092 if (lineno == 0) lineno = FIX2INT(rb_iseq_first_lineno(iseq));
7093 debugs("node: NODE_NIL(implicit)\n");
7094 ADD_INSN(ret, lineno, putnil);
7095 }
7096 return COMPILE_OK;
7097 }
7098 return iseq_compile_each0(iseq, ret, node, popped);
7099 }
7100
7101 static int
7102 check_yield_place(const rb_iseq_t *iseq, int line)
7103 {
7104 VALUE file;
7105 switch (iseq->body->local_iseq->body->type) {
7106 case ISEQ_TYPE_TOP:
7107 case ISEQ_TYPE_MAIN:
7108 return FALSE;
7109 case ISEQ_TYPE_CLASS:
7110 file = rb_iseq_path(iseq);
7111 if (rb_warning_category_enabled_p(RB_WARN_CATEGORY_DEPRECATED)) {
7112 rb_compile_warn(RSTRING_PTR(file), line,
7113 "`yield' in class syntax will not be supported from Ruby 3.0. [Feature #15575]");
7114 }
7115 return TRUE;
7116 default:
7117 return TRUE;
7118 }
7119 }
7120
7121 static int
7122 iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int popped)
7123 {
7124 const int line = (int)nd_line(node);
7125 const enum node_type type = nd_type(node);
7126 struct rb_iseq_constant_body *const body = iseq->body;
7127
7128 if (ISEQ_COMPILE_DATA(iseq)->last_line == line) {
7129 /* ignore */
7130 }
7131 else {
7132 if (node->flags & NODE_FL_NEWLINE) {
7133 int event = RUBY_EVENT_LINE;
7134 ISEQ_COMPILE_DATA(iseq)->last_line = line;
7135 if (ISEQ_COVERAGE(iseq) && ISEQ_LINE_COVERAGE(iseq)) {
7136 event |= RUBY_EVENT_COVERAGE_LINE;
7137 }
7138 ADD_TRACE(ret, event);
7139 }
7140 }
7141
7142 debug_node_start(node);
7143 #undef BEFORE_RETURN
7144 #define BEFORE_RETURN debug_node_end()
7145
7146 switch (type) {
7147 case NODE_BLOCK:{
7148 while (node && nd_type(node) == NODE_BLOCK) {
7149 CHECK(COMPILE_(ret, "BLOCK body", node->nd_head,
7150 (node->nd_next ? 1 : popped)));
7151 node = node->nd_next;
7152 }
7153 if (node) {
7154 CHECK(COMPILE_(ret, "BLOCK next", node->nd_next, popped));
7155 }
7156 break;
7157 }
7158 case NODE_IF:
7159 case NODE_UNLESS:
7160 CHECK(compile_if(iseq, ret, node, popped, type));
7161 break;
7162 case NODE_CASE:
7163 CHECK(compile_case(iseq, ret, node, popped));
7164 break;
7165 case NODE_CASE2:
7166 CHECK(compile_case2(iseq, ret, node, popped));
7167 break;
7168 case NODE_CASE3:
7169 CHECK(compile_case3(iseq, ret, node, popped));
7170 break;
7171 case NODE_WHILE:
7172 case NODE_UNTIL:
7173 CHECK(compile_loop(iseq, ret, node, popped, type));
7174 break;
7175 case NODE_FOR:
7176 case NODE_ITER:
7177 CHECK(compile_iter(iseq, ret, node, popped));
7178 break;
7179 case NODE_FOR_MASGN:
7180 CHECK(compile_for_masgn(iseq, ret, node, popped));
7181 break;
7182 case NODE_BREAK:
7183 CHECK(compile_break(iseq, ret, node, popped));
7184 break;
7185 case NODE_NEXT:
7186 CHECK(compile_next(iseq, ret, node, popped));
7187 break;
7188 case NODE_REDO:
7189 CHECK(compile_redo(iseq, ret, node, popped));
7190 break;
7191 case NODE_RETRY:
7192 CHECK(compile_retry(iseq, ret, node, popped));
7193 break;
7194 case NODE_BEGIN:{
7195 CHECK(COMPILE_(ret, "NODE_BEGIN", node->nd_body, popped));
7196 break;
7197 }
7198 case NODE_RESCUE:
7199 CHECK(compile_rescue(iseq, ret, node, popped));
7200 break;
7201 case NODE_RESBODY:
7202 CHECK(compile_resbody(iseq, ret, node, popped));
7203 break;
7204 case NODE_ENSURE:
7205 CHECK(compile_ensure(iseq, ret, node, popped));
7206 break;
7207
7208 case NODE_AND:
7209 case NODE_OR:{
7210 LABEL *end_label = NEW_LABEL(line);
7211 CHECK(COMPILE(ret, "nd_1st", node->nd_1st));
7212 if (!popped) {
7213 ADD_INSN(ret, line, dup);
7214 }
7215 if (type == NODE_AND) {
7216 ADD_INSNL(ret, line, branchunless, end_label);
7217 }
7218 else {
7219 ADD_INSNL(ret, line, branchif, end_label);
7220 }
7221 if (!popped) {
7222 ADD_INSN(ret, line, pop);
7223 }
7224 CHECK(COMPILE_(ret, "nd_2nd", node->nd_2nd, popped));
7225 ADD_LABEL(ret, end_label);
7226 break;
7227 }
7228
7229 case NODE_MASGN:{
7230 compile_massign(iseq, ret, node, popped);
7231 break;
7232 }
7233
7234 case NODE_LASGN:{
7235 ID id = node->nd_vid;
7236 int idx = body->local_iseq->body->local_table_size - get_local_var_idx(iseq, id);
7237
7238 debugs("lvar: %s idx: %d\n", rb_id2name(id), idx);
7239 CHECK(COMPILE(ret, "rvalue", node->nd_value));
7240
7241 if (!popped) {
7242 ADD_INSN(ret, line, dup);
7243 }
7244 ADD_SETLOCAL(ret, line, idx, get_lvar_level(iseq));
7245 break;
7246 }
7247 case NODE_DASGN:
7248 case NODE_DASGN_CURR:{
7249 int idx, lv, ls;
7250 ID id = node->nd_vid;
7251 CHECK(COMPILE(ret, "dvalue", node->nd_value));
7252 debugi("dassn id", rb_id2str(id) ? id : '*');
7253
7254 if (!popped) {
7255 ADD_INSN(ret, line, dup);
7256 }
7257
7258 idx = get_dyna_var_idx(iseq, id, &lv, &ls);
7259
7260 if (idx < 0) {
7261 COMPILE_ERROR(ERROR_ARGS "NODE_DASGN(_CURR): unknown id (%"PRIsVALUE")",
7262 rb_id2str(id));
7263 goto ng;
7264 }
7265 ADD_SETLOCAL(ret, line, ls - idx, lv);
7266 break;
7267 }
7268 case NODE_GASGN:{
7269 CHECK(COMPILE(ret, "lvalue", node->nd_value));
7270
7271 if (!popped) {
7272 ADD_INSN(ret, line, dup);
7273 }
7274 ADD_INSN1(ret, line, setglobal,
7275 ((VALUE)node->nd_entry | 1));
7276 break;
7277 }
7278 case NODE_IASGN:{
7279 CHECK(COMPILE(ret, "lvalue", node->nd_value));
7280 if (!popped) {
7281 ADD_INSN(ret, line, dup);
7282 }
7283 ADD_INSN2(ret, line, setinstancevariable,
7284 ID2SYM(node->nd_vid),
7285 get_ivar_ic_value(iseq,node->nd_vid));
7286 break;
7287 }
7288 case NODE_CDECL:{
7289 CHECK(COMPILE(ret, "lvalue", node->nd_value));
7290
7291 if (!popped) {
7292 ADD_INSN(ret, line, dup);
7293 }
7294
7295 if (node->nd_vid) {
7296 ADD_INSN1(ret, line, putspecialobject,
7297 INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
7298 ADD_INSN1(ret, line, setconstant, ID2SYM(node->nd_vid));
7299 }
7300 else {
7301 compile_cpath(ret, iseq, node->nd_else);
7302 ADD_INSN1(ret, line, setconstant, ID2SYM(node->nd_else->nd_mid));
7303 }
7304 break;
7305 }
7306 case NODE_CVASGN:{
7307 CHECK(COMPILE(ret, "cvasgn val", node->nd_value));
7308 if (!popped) {
7309 ADD_INSN(ret, line, dup);
7310 }
7311 ADD_INSN1(ret, line, setclassvariable,
7312 ID2SYM(node->nd_vid));
7313 break;
7314 }
7315 case NODE_OP_ASGN1: {
7316 VALUE argc;
7317 unsigned int flag = 0;
7318 int asgnflag = 0;
7319 ID id = node->nd_mid;
7320 int boff = 0;
7321
7322 /*
7323 * a[x] (op)= y
7324 *
7325 * nil # nil
7326 * eval a # nil a
7327 * eval x # nil a x
7328 * dupn 2 # nil a x a x
7329 * send :[] # nil a x a[x]
7330 * eval y # nil a x a[x] y
7331 * send op # nil a x ret
7332 * setn 3 # ret a x ret
7333 * send []= # ret ?
7334 * pop # ret
7335 */
7336
7337 /*
7338 * nd_recv[nd_args->nd_body] (nd_mid)= nd_args->nd_head;
7339 * NODE_OP_ASGN nd_recv
7340 * nd_args->nd_head
7341 * nd_args->nd_body
7342 * nd_mid
7343 */
7344
7345 if (!popped) {
7346 ADD_INSN(ret, line, putnil);
7347 }
7348 asgnflag = COMPILE_RECV(ret, "NODE_OP_ASGN1 recv", node);
7349 CHECK(asgnflag != -1);
7350 switch (nd_type(node->nd_args->nd_head)) {
7351 case NODE_ZLIST:
7352 argc = INT2FIX(0);
7353 break;
7354 case NODE_BLOCK_PASS:
7355 boff = 1;
7356 /* fall through */
7357 default:
7358 argc = setup_args(iseq, ret, node->nd_args->nd_head, &flag, NULL);
7359 CHECK(!NIL_P(argc));
7360 }
7361 ADD_INSN1(ret, line, dupn, FIXNUM_INC(argc, 1 + boff));
7362 flag |= asgnflag;
7363 ADD_SEND_WITH_FLAG(ret, line, idAREF, argc, INT2FIX(flag));
7364
7365 if (id == idOROP || id == idANDOP) {
7366 /* a[x] ||= y or a[x] &&= y
7367
7368 unless/if a[x]
7369 a[x]= y
7370 else
7371 nil
7372 end
7373 */
7374 LABEL *label = NEW_LABEL(line);
7375 LABEL *lfin = NEW_LABEL(line);
7376
7377 ADD_INSN(ret, line, dup);
7378 if (id == idOROP) {
7379 ADD_INSNL(ret, line, branchif, label);
7380 }
7381 else { /* idANDOP */
7382 ADD_INSNL(ret, line, branchunless, label);
7383 }
7384 ADD_INSN(ret, line, pop);
7385
7386 CHECK(COMPILE(ret, "NODE_OP_ASGN1 args->body: ", node->nd_args->nd_body));
7387 if (!popped) {
7388 ADD_INSN1(ret, line, setn, FIXNUM_INC(argc, 2+boff));
7389 }
7390 if (flag & VM_CALL_ARGS_SPLAT) {
7391 ADD_INSN1(ret, line, newarray, INT2FIX(1));
7392 if (boff > 0) {
7393 ADD_INSN1(ret, line, dupn, INT2FIX(3));
7394 ADD_INSN(ret, line, swap);
7395 ADD_INSN(ret, line, pop);
7396 }
7397 ADD_INSN(ret, line, concatarray);
7398 if (boff > 0) {
7399 ADD_INSN1(ret, line, setn, INT2FIX(3));
7400 ADD_INSN(ret, line, pop);
7401 ADD_INSN(ret, line, pop);
7402 }
7403 ADD_SEND_WITH_FLAG(ret, line, idASET, argc, INT2FIX(flag));
7404 }
7405 else {
7406 if (boff > 0)
7407 ADD_INSN(ret, line, swap);
7408 ADD_SEND_WITH_FLAG(ret, line, idASET, FIXNUM_INC(argc, 1), INT2FIX(flag));
7409 }
7410 ADD_INSN(ret, line, pop);
7411 ADD_INSNL(ret, line, jump, lfin);
7412 ADD_LABEL(ret, label);
7413 if (!popped) {
7414 ADD_INSN1(ret, line, setn, FIXNUM_INC(argc, 2+boff));
7415 }
7416 ADD_INSN1(ret, line, adjuststack, FIXNUM_INC(argc, 2+boff));
7417 ADD_LABEL(ret, lfin);
7418 }
7419 else {
7420 CHECK(COMPILE(ret, "NODE_OP_ASGN1 args->body: ", node->nd_args->nd_body));
7421 ADD_SEND(ret, line, id, INT2FIX(1));
7422 if (!popped) {
7423 ADD_INSN1(ret, line, setn, FIXNUM_INC(argc, 2+boff));
7424 }
7425 if (flag & VM_CALL_ARGS_SPLAT) {
7426 ADD_INSN1(ret, line, newarray, INT2FIX(1));
7427 if (boff > 0) {
7428 ADD_INSN1(ret, line, dupn, INT2FIX(3));
7429 ADD_INSN(ret, line, swap);
7430 ADD_INSN(ret, line, pop);
7431 }
7432 ADD_INSN(ret, line, concatarray);
7433 if (boff > 0) {
7434 ADD_INSN1(ret, line, setn, INT2FIX(3));
7435 ADD_INSN(ret, line, pop);
7436 ADD_INSN(ret, line, pop);
7437 }
7438 ADD_SEND_WITH_FLAG(ret, line, idASET, argc, INT2FIX(flag));
7439 }
7440 else {
7441 if (boff > 0)
7442 ADD_INSN(ret, line, swap);
7443 ADD_SEND_WITH_FLAG(ret, line, idASET, FIXNUM_INC(argc, 1), INT2FIX(flag));
7444 }
7445 ADD_INSN(ret, line, pop);
7446 }
7447
7448 break;
7449 }
7450 case NODE_OP_ASGN2:{
7451 ID atype = node->nd_next->nd_mid;
7452 ID vid = node->nd_next->nd_vid, aid = rb_id_attrset(vid);
7453 int asgnflag;
7454 LABEL *lfin = NEW_LABEL(line);
7455 LABEL *lcfin = NEW_LABEL(line);
7456 LABEL *lskip = 0;
7457 /*
7458 class C; attr_accessor :c; end
7459 r = C.new
7460 r.a &&= v # asgn2
7461
7462 eval r # r
7463 dup # r r
7464 eval r.a # r o
7465
7466 # or
7467 dup # r o o
7468 if lcfin # r o
7469 pop # r
7470 eval v # r v
7471 swap # v r
7472 topn 1 # v r v
7473 send a= # v ?
7474 jump lfin # v ?
7475
7476 lcfin: # r o
7477 swap # o r
7478
7479 lfin: # o ?
7480 pop # o
7481
7482 # and
7483 dup # r o o
7484 unless lcfin
7485 pop # r
7486 eval v # r v
7487 swap # v r
7488 topn 1 # v r v
7489 send a= # v ?
7490 jump lfin # v ?
7491
7492 # others
7493 eval v # r o v
7494 send ?? # r w
7495 send a= # w
7496
7497 */
7498
7499 asgnflag = COMPILE_RECV(ret, "NODE_OP_ASGN2#recv", node);
7500 CHECK(asgnflag != -1);
7501 if (node->nd_next->nd_aid) {
7502 lskip = NEW_LABEL(line);
7503 ADD_INSN(ret, line, dup);
7504 ADD_INSNL(ret, line, branchnil, lskip);
7505 }
7506 ADD_INSN(ret, line, dup);
7507 ADD_SEND_WITH_FLAG(ret, line, vid, INT2FIX(0), INT2FIX(asgnflag));
7508
7509 if (atype == idOROP || atype == idANDOP) {
7510 ADD_INSN(ret, line, dup);
7511 if (atype == idOROP) {
7512 ADD_INSNL(ret, line, branchif, lcfin);
7513 }
7514 else { /* idANDOP */
7515 ADD_INSNL(ret, line, branchunless, lcfin);
7516 }
7517 ADD_INSN(ret, line, pop);
7518 CHECK(COMPILE(ret, "NODE_OP_ASGN2 val", node->nd_value));
7519 ADD_INSN(ret, line, swap);
7520 ADD_INSN1(ret, line, topn, INT2FIX(1));
7521 ADD_SEND_WITH_FLAG(ret, line, aid, INT2FIX(1), INT2FIX(asgnflag));
7522 ADD_INSNL(ret, line, jump, lfin);
7523
7524 ADD_LABEL(ret, lcfin);
7525 ADD_INSN(ret, line, swap);
7526
7527 ADD_LABEL(ret, lfin);
7528 ADD_INSN(ret, line, pop);
7529 if (lskip) {
7530 ADD_LABEL(ret, lskip);
7531 }
7532 if (popped) {
7533 /* we can apply more optimize */
7534 ADD_INSN(ret, line, pop);
7535 }
7536 }
7537 else {
7538 CHECK(COMPILE(ret, "NODE_OP_ASGN2 val", node->nd_value));
7539 ADD_SEND(ret, line, atype, INT2FIX(1));
7540 if (!popped) {
7541 ADD_INSN(ret, line, swap);
7542 ADD_INSN1(ret, line, topn, INT2FIX(1));
7543 }
7544 ADD_SEND_WITH_FLAG(ret, line, aid, INT2FIX(1), INT2FIX(asgnflag));
7545 if (lskip && popped) {
7546 ADD_LABEL(ret, lskip);
7547 }
7548 ADD_INSN(ret, line, pop);
7549 if (lskip && !popped) {
7550 ADD_LABEL(ret, lskip);
7551 }
7552 }
7553 break;
7554 }
7555 case NODE_OP_CDECL: {
7556 LABEL *lfin = 0;
7557 LABEL *lassign = 0;
7558 ID mid;
7559
7560 switch (nd_type(node->nd_head)) {
7561 case NODE_COLON3:
7562 ADD_INSN1(ret, line, putobject, rb_cObject);
7563 break;
7564 case NODE_COLON2:
7565 CHECK(COMPILE(ret, "NODE_OP_CDECL/colon2#nd_head", node->nd_head->nd_head));
7566 break;
7567 default:
7568 COMPILE_ERROR(ERROR_ARGS "%s: invalid node in NODE_OP_CDECL",
7569 ruby_node_name(nd_type(node->nd_head)));
7570 goto ng;
7571 }
7572 mid = node->nd_head->nd_mid;
7573 /* cref */
7574 if (node->nd_aid == idOROP) {
7575 lassign = NEW_LABEL(line);
7576 ADD_INSN(ret, line, dup); /* cref cref */
7577 ADD_INSN3(ret, line, defined, INT2FIX(DEFINED_CONST_FROM),
7578 ID2SYM(mid), Qfalse); /* cref bool */
7579 ADD_INSNL(ret, line, branchunless, lassign); /* cref */
7580 }
7581 ADD_INSN(ret, line, dup); /* cref cref */
7582 ADD_INSN1(ret, line, putobject, Qtrue);
7583 ADD_INSN1(ret, line, getconstant, ID2SYM(mid)); /* cref obj */
7584
7585 if (node->nd_aid == idOROP || node->nd_aid == idANDOP) {
7586 lfin = NEW_LABEL(line);
7587 if (!popped) ADD_INSN(ret, line, dup); /* cref [obj] obj */
7588 if (node->nd_aid == idOROP)
7589 ADD_INSNL(ret, line, branchif, lfin);
7590 else /* idANDOP */
7591 ADD_INSNL(ret, line, branchunless, lfin);
7592 /* cref [obj] */
7593 if (!popped) ADD_INSN(ret, line, pop); /* cref */
7594 if (lassign) ADD_LABEL(ret, lassign);
7595 CHECK(COMPILE(ret, "NODE_OP_CDECL#nd_value", node->nd_value));
7596 /* cref value */
7597 if (popped)
7598 ADD_INSN1(ret, line, topn, INT2FIX(1)); /* cref value cref */
7599 else {
7600 ADD_INSN1(ret, line, dupn, INT2FIX(2)); /* cref value cref value */
7601 ADD_INSN(ret, line, swap); /* cref value value cref */
7602 }
7603 ADD_INSN1(ret, line, setconstant, ID2SYM(mid)); /* cref [value] */
7604 ADD_LABEL(ret, lfin); /* cref [value] */
7605 if (!popped) ADD_INSN(ret, line, swap); /* [value] cref */
7606 ADD_INSN(ret, line, pop); /* [value] */
7607 }
7608 else {
7609 CHECK(COMPILE(ret, "NODE_OP_CDECL#nd_value", node->nd_value));
7610 /* cref obj value */
7611 ADD_CALL(ret, line, node->nd_aid, INT2FIX(1));
7612 /* cref value */
7613 ADD_INSN(ret, line, swap); /* value cref */
7614 if (!popped) {
7615 ADD_INSN1(ret, line, topn, INT2FIX(1)); /* value cref value */
7616 ADD_INSN(ret, line, swap); /* value value cref */
7617 }
7618 ADD_INSN1(ret, line, setconstant, ID2SYM(mid));
7619 }
7620 break;
7621 }
7622 case NODE_OP_ASGN_AND:
7623 case NODE_OP_ASGN_OR:{
7624 LABEL *lfin = NEW_LABEL(line);
7625 LABEL *lassign;
7626
7627 if (nd_type(node) == NODE_OP_ASGN_OR) {
7628 LABEL *lfinish[2];
7629 lfinish[0] = lfin;
7630 lfinish[1] = 0;
7631 defined_expr(iseq, ret, node->nd_head, lfinish, Qfalse);
7632 lassign = lfinish[1];
7633 if (!lassign) {
7634 lassign = NEW_LABEL(line);
7635 }
7636 ADD_INSNL(ret, line, branchunless, lassign);
7637 }
7638 else {
7639 lassign = NEW_LABEL(line);
7640 }
7641
7642 CHECK(COMPILE(ret, "NODE_OP_ASGN_AND/OR#nd_head", node->nd_head));
7643 ADD_INSN(ret, line, dup);
7644
7645 if (nd_type(node) == NODE_OP_ASGN_AND) {
7646 ADD_INSNL(ret, line, branchunless, lfin);
7647 }
7648 else {
7649 ADD_INSNL(ret, line, branchif, lfin);
7650 }
7651
7652 ADD_INSN(ret, line, pop);
7653 ADD_LABEL(ret, lassign);
7654 CHECK(COMPILE(ret, "NODE_OP_ASGN_AND/OR#nd_value", node->nd_value));
7655 ADD_LABEL(ret, lfin);
7656
7657 if (popped) {
7658 /* we can apply more optimize */
7659 ADD_INSN(ret, line, pop);
7660 }
7661 break;
7662 }
7663 case NODE_CALL: /* obj.foo */
7664 case NODE_OPCALL: /* foo[] */
7665 if (compile_call_precheck_freeze(iseq, ret, node, line, popped) == TRUE) {
7666 break;
7667 }
7668 case NODE_QCALL: /* obj&.foo */
7669 case NODE_FCALL: /* foo() */
7670 case NODE_VCALL: /* foo (variable or call) */
7671 if (compile_call(iseq, ret, node, type, line, popped) == COMPILE_NG) {
7672 goto ng;
7673 }
7674 break;
7675 case NODE_SUPER:
7676 case NODE_ZSUPER:{
7677 DECL_ANCHOR(args);
7678 int argc;
7679 unsigned int flag = 0;
7680 struct rb_call_info_kw_arg *keywords = NULL;
7681 const rb_iseq_t *parent_block = ISEQ_COMPILE_DATA(iseq)->current_block;
7682
7683 INIT_ANCHOR(args);
7684 ISEQ_COMPILE_DATA(iseq)->current_block = NULL;
7685 if (type == NODE_SUPER) {
7686 VALUE vargc = setup_args(iseq, args, node->nd_args, &flag, &keywords);
7687 CHECK(!NIL_P(vargc));
7688 argc = FIX2INT(vargc);
7689 }
7690 else {
7691 /* NODE_ZSUPER */
7692 int i;
7693 const rb_iseq_t *liseq = body->local_iseq;
7694 const struct rb_iseq_constant_body *const local_body = liseq->body;
7695 const struct rb_iseq_param_keyword *const local_kwd = local_body->param.keyword;
7696 int lvar_level = get_lvar_level(iseq);
7697
7698 argc = local_body->param.lead_num;
7699
7700 /* normal arguments */
7701 for (i = 0; i < local_body->param.lead_num; i++) {
7702 int idx = local_body->local_table_size - i;
7703 ADD_GETLOCAL(args, line, idx, lvar_level);
7704 }
7705
7706 if (local_body->param.flags.has_opt) {
7707 /* optional arguments */
7708 int j;
7709 for (j = 0; j < local_body->param.opt_num; j++) {
7710 int idx = local_body->local_table_size - (i + j);
7711 ADD_GETLOCAL(args, line, idx, lvar_level);
7712 }
7713 i += j;
7714 argc = i;
7715 }
7716 if (local_body->param.flags.has_rest) {
7717 /* rest argument */
7718 int idx = local_body->local_table_size - local_body->param.rest_start;
7719
7720 ADD_GETLOCAL(args, line, idx, lvar_level);
7721 ADD_INSN1(args, line, splatarray, Qfalse);
7722
7723 argc = local_body->param.rest_start + 1;
7724 flag |= VM_CALL_ARGS_SPLAT;
7725 }
7726 if (local_body->param.flags.has_post) {
7727 /* post arguments */
7728 int post_len = local_body->param.post_num;
7729 int post_start = local_body->param.post_start;
7730
7731 if (local_body->param.flags.has_rest) {
7732 int j;
7733 for (j=0; j<post_len; j++) {
7734 int idx = local_body->local_table_size - (post_start + j);
7735 ADD_GETLOCAL(args, line, idx, lvar_level);
7736 }
7737 ADD_INSN1(args, line, newarray, INT2FIX(j));
7738 ADD_INSN (args, line, concatarray);
7739 /* argc is settled at above */
7740 }
7741 else {
7742 int j;
7743 for (j=0; j<post_len; j++) {
7744 int idx = local_body->local_table_size - (post_start + j);
7745 ADD_GETLOCAL(args, line, idx, lvar_level);
7746 }
7747 argc = post_len + post_start;
7748 }
7749 }
7750
7751 if (local_body->param.flags.has_kw) { /* TODO: support keywords */
7752 int local_size = local_body->local_table_size;
7753 argc++;
7754
7755 ADD_INSN1(args, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7756
7757 if (local_body->param.flags.has_kwrest) {
7758 int idx = local_body->local_table_size - local_kwd->rest_start;
7759 ADD_GETLOCAL(args, line, idx, lvar_level);
7760 ADD_SEND (args, line, rb_intern("dup"), INT2FIX(0));
7761 }
7762 else {
7763 ADD_INSN1(args, line, newhash, INT2FIX(0));
7764 }
7765 for (i = 0; i < local_kwd->num; ++i) {
7766 ID id = local_kwd->table[i];
7767 int idx = local_size - get_local_var_idx(liseq, id);
7768 ADD_INSN1(args, line, putobject, ID2SYM(id));
7769 ADD_GETLOCAL(args, line, idx, lvar_level);
7770 }
7771 ADD_SEND(args, line, id_core_hash_merge_ptr, INT2FIX(i * 2 + 1));
7772 if (local_body->param.flags.has_rest) {
7773 ADD_INSN1(args, line, newarray, INT2FIX(1));
7774 ADD_INSN (args, line, concatarray);
7775 --argc;
7776 }
7777 flag |= VM_CALL_KW_SPLAT;
7778 }
7779 else if (local_body->param.flags.has_kwrest) {
7780 int idx = local_body->local_table_size - local_kwd->rest_start;
7781 ADD_GETLOCAL(args, line, idx, lvar_level);
7782
7783 ADD_SEND (args, line, rb_intern("dup"), INT2FIX(0));
7784 if (local_body->param.flags.has_rest) {
7785 ADD_INSN1(args, line, newarray, INT2FIX(1));
7786 ADD_INSN (args, line, concatarray);
7787 }
7788 else {
7789 argc++;
7790 }
7791 flag |= VM_CALL_KW_SPLAT;
7792 }
7793 }
7794
7795 ADD_INSN(ret, line, putself);
7796 ADD_SEQ(ret, args);
7797 ADD_INSN2(ret, line, invokesuper,
7798 new_callinfo(iseq, 0, argc, flag | VM_CALL_SUPER | (type == NODE_ZSUPER ? VM_CALL_ZSUPER : 0) | VM_CALL_FCALL, keywords, parent_block != NULL),
7799 parent_block);
7800
7801 if (popped) {
7802 ADD_INSN(ret, line, pop);
7803 }
7804 break;
7805 }
7806 case NODE_LIST:{
7807 CHECK(compile_array(iseq, ret, node, popped) >= 0);
7808 break;
7809 }
7810 case NODE_ZLIST:{
7811 if (!popped) {
7812 ADD_INSN1(ret, line, newarray, INT2FIX(0));
7813 }
7814 break;
7815 }
7816 case NODE_VALUES:{
7817 const NODE *n = node;
7818 if (popped) {
7819 COMPILE_ERROR(ERROR_ARGS "NODE_VALUES: must not be popped");
7820 }
7821 while (n) {
7822 CHECK(COMPILE(ret, "values item", n->nd_head));
7823 n = n->nd_next;
7824 }
7825 ADD_INSN1(ret, line, newarray, INT2FIX(node->nd_alen));
7826 break;
7827 }
7828 case NODE_HASH:
7829 CHECK(compile_hash(iseq, ret, node, popped) >= 0);
7830 break;
7831 case NODE_RETURN:
7832 CHECK(compile_return(iseq, ret, node, popped));
7833 break;
7834 case NODE_YIELD:{
7835 DECL_ANCHOR(args);
7836 VALUE argc;
7837 unsigned int flag = 0;
7838 struct rb_call_info_kw_arg *keywords = NULL;
7839
7840 INIT_ANCHOR(args);
7841
7842 if (check_yield_place(iseq, line) == FALSE) {
7843 COMPILE_ERROR(ERROR_ARGS "Invalid yield");
7844 goto ng;
7845 }
7846
7847 if (node->nd_head) {
7848 argc = setup_args(iseq, args, node->nd_head, &flag, &keywords);
7849 CHECK(!NIL_P(argc));
7850 }
7851 else {
7852 argc = INT2FIX(0);
7853 }
7854
7855 ADD_SEQ(ret, args);
7856 ADD_INSN1(ret, line, invokeblock, new_callinfo(iseq, 0, FIX2INT(argc), flag, keywords, FALSE));
7857
7858 if (popped) {
7859 ADD_INSN(ret, line, pop);
7860 }
7861 break;
7862 }
7863 case NODE_LVAR:{
7864 if (!popped) {
7865 ID id = node->nd_vid;
7866 int idx = body->local_iseq->body->local_table_size - get_local_var_idx(iseq, id);
7867
7868 debugs("id: %s idx: %d\n", rb_id2name(id), idx);
7869 ADD_GETLOCAL(ret, line, idx, get_lvar_level(iseq));
7870 }
7871 break;
7872 }
7873 case NODE_DVAR:{
7874 int lv, idx, ls;
7875 debugi("nd_vid", node->nd_vid);
7876 if (!popped) {
7877 idx = get_dyna_var_idx(iseq, node->nd_vid, &lv, &ls);
7878 if (idx < 0) {
7879 COMPILE_ERROR(ERROR_ARGS "unknown dvar (%"PRIsVALUE")",
7880 rb_id2str(node->nd_vid));
7881 goto ng;
7882 }
7883 ADD_GETLOCAL(ret, line, ls - idx, lv);
7884 }
7885 break;
7886 }
7887 case NODE_GVAR:{
7888 ADD_INSN1(ret, line, getglobal,
7889 ((VALUE)node->nd_entry | 1));
7890 if (popped) {
7891 ADD_INSN(ret, line, pop);
7892 }
7893 break;
7894 }
7895 case NODE_IVAR:{
7896 debugi("nd_vid", node->nd_vid);
7897 if (!popped) {
7898 ADD_INSN2(ret, line, getinstancevariable,
7899 ID2SYM(node->nd_vid),
7900 get_ivar_ic_value(iseq,node->nd_vid));
7901 }
7902 break;
7903 }
7904 case NODE_CONST:{
7905 debugi("nd_vid", node->nd_vid);
7906
7907 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
7908 LABEL *lend = NEW_LABEL(line);
7909 int ic_index = body->is_size++;
7910
7911 ADD_INSN2(ret, line, opt_getinlinecache, lend, INT2FIX(ic_index));
7912 ADD_INSN1(ret, line, putobject, Qtrue);
7913 ADD_INSN1(ret, line, getconstant, ID2SYM(node->nd_vid));
7914 ADD_INSN1(ret, line, opt_setinlinecache, INT2FIX(ic_index));
7915 ADD_LABEL(ret, lend);
7916 }
7917 else {
7918 ADD_INSN(ret, line, putnil);
7919 ADD_INSN1(ret, line, putobject, Qtrue);
7920 ADD_INSN1(ret, line, getconstant, ID2SYM(node->nd_vid));
7921 }
7922
7923 if (popped) {
7924 ADD_INSN(ret, line, pop);
7925 }
7926 break;
7927 }
7928 case NODE_CVAR:{
7929 if (!popped) {
7930 ADD_INSN1(ret, line, getclassvariable,
7931 ID2SYM(node->nd_vid));
7932 }
7933 break;
7934 }
7935 case NODE_NTH_REF:{
7936 if (!popped) {
7937 if (!node->nd_nth) {
7938 ADD_INSN(ret, line, putnil);
7939 break;
7940 }
7941 ADD_INSN2(ret, line, getspecial, INT2FIX(1) /* '~' */,
7942 INT2FIX(node->nd_nth << 1));
7943 }
7944 break;
7945 }
7946 case NODE_BACK_REF:{
7947 if (!popped) {
7948 ADD_INSN2(ret, line, getspecial, INT2FIX(1) /* '~' */,
7949 INT2FIX(0x01 | (node->nd_nth << 1)));
7950 }
7951 break;
7952 }
7953 case NODE_MATCH:
7954 case NODE_MATCH2:
7955 case NODE_MATCH3:{
7956 DECL_ANCHOR(recv);
7957 DECL_ANCHOR(val);
7958
7959 INIT_ANCHOR(recv);
7960 INIT_ANCHOR(val);
7961 switch (nd_type(node)) {
7962 case NODE_MATCH:
7963 ADD_INSN1(recv, line, putobject, node->nd_lit);
7964 ADD_INSN2(val, line, getspecial, INT2FIX(0),
7965 INT2FIX(0));
7966 break;
7967 case NODE_MATCH2:
7968 CHECK(COMPILE(recv, "receiver", node->nd_recv));
7969 CHECK(COMPILE(val, "value", node->nd_value));
7970 break;
7971 case NODE_MATCH3:
7972 CHECK(COMPILE(recv, "receiver", node->nd_value));
7973 CHECK(COMPILE(val, "value", node->nd_recv));
7974 break;
7975 }
7976
7977 ADD_SEQ(ret, recv);
7978 ADD_SEQ(ret, val);
7979 ADD_SEND(ret, line, idEqTilde, INT2FIX(1));
7980
7981 if (node->nd_args) {
7982 compile_named_capture_assign(iseq, ret, node->nd_args);
7983 }
7984
7985 if (popped) {
7986 ADD_INSN(ret, line, pop);
7987 }
7988 break;
7989 }
7990 case NODE_LIT:{
7991 debugp_param("lit", node->nd_lit);
7992 if (!popped) {
7993 ADD_INSN1(ret, line, putobject, node->nd_lit);
7994 }
7995 break;
7996 }
7997 case NODE_STR:{
7998 debugp_param("nd_lit", node->nd_lit);
7999 if (!popped) {
8000 VALUE lit = node->nd_lit;
8001 if (!ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal) {
8002 lit = rb_fstring(lit);
8003 ADD_INSN1(ret, line, putstring, lit);
8004 RB_OBJ_WRITTEN(iseq, Qundef, lit);
8005 }
8006 else {
8007 if (ISEQ_COMPILE_DATA(iseq)->option->debug_frozen_string_literal || RTEST(ruby_debug)) {
8008 VALUE debug_info = rb_ary_new_from_args(2, rb_iseq_path(iseq), INT2FIX(line));
8009 lit = rb_str_dup(lit);
8010 rb_ivar_set(lit, id_debug_created_info, rb_obj_freeze(debug_info));
8011 lit = rb_str_freeze(lit);
8012 }
8013 else {
8014 lit = rb_fstring(lit);
8015 }
8016 ADD_INSN1(ret, line, putobject, lit);
8017 RB_OBJ_WRITTEN(iseq, Qundef, lit);
8018 }
8019 }
8020 break;
8021 }
8022 case NODE_DSTR:{
8023 compile_dstr(iseq, ret, node);
8024
8025 if (popped) {
8026 ADD_INSN(ret, line, pop);
8027 }
8028 else {
8029 if (ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal) {
8030 VALUE debug_info = Qnil;
8031 if (ISEQ_COMPILE_DATA(iseq)->option->debug_frozen_string_literal || RTEST(ruby_debug)) {
8032 debug_info = rb_ary_new_from_args(2, rb_iseq_path(iseq), INT2FIX(line));
8033 }
8034 ADD_INSN1(ret, line, freezestring, debug_info);
8035 if (!NIL_P(debug_info)) {
8036 RB_OBJ_WRITTEN(iseq, Qundef, rb_obj_freeze(debug_info));
8037 }
8038 }
8039 }
8040 break;
8041 }
8042 case NODE_XSTR:{
8043 ADD_CALL_RECEIVER(ret, line);
8044 VALUE str = rb_fstring(node->nd_lit);
8045 ADD_INSN1(ret, line, putobject, str);
8046 RB_OBJ_WRITTEN(iseq, Qundef, str);
8047 ADD_CALL(ret, line, idBackquote, INT2FIX(1));
8048
8049 if (popped) {
8050 ADD_INSN(ret, line, pop);
8051 }
8052 break;
8053 }
8054 case NODE_DXSTR:{
8055 ADD_CALL_RECEIVER(ret, line);
8056 compile_dstr(iseq, ret, node);
8057 ADD_CALL(ret, line, idBackquote, INT2FIX(1));
8058
8059 if (popped) {
8060 ADD_INSN(ret, line, pop);
8061 }
8062 break;
8063 }
8064 case NODE_EVSTR:
8065 CHECK(compile_evstr(iseq, ret, node->nd_body, popped));
8066 break;
8067 case NODE_DREGX:{
8068 compile_dregx(iseq, ret, node);
8069
8070 if (popped) {
8071 ADD_INSN(ret, line, pop);
8072 }
8073 break;
8074 }
8075 case NODE_ONCE:{
8076 int ic_index = body->is_size++;
8077 const rb_iseq_t *block_iseq;
8078 block_iseq = NEW_CHILD_ISEQ(node->nd_body, make_name_for_block(iseq), ISEQ_TYPE_PLAIN, line);
8079
8080 ADD_INSN2(ret, line, once, block_iseq, INT2FIX(ic_index));
8081 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block_iseq);
8082
8083 if (popped) {
8084 ADD_INSN(ret, line, pop);
8085 }
8086 break;
8087 }
8088 case NODE_ARGSCAT:{
8089 if (popped) {
8090 CHECK(COMPILE(ret, "argscat head", node->nd_head));
8091 ADD_INSN1(ret, line, splatarray, Qfalse);
8092 ADD_INSN(ret, line, pop);
8093 CHECK(COMPILE(ret, "argscat body", node->nd_body));
8094 ADD_INSN1(ret, line, splatarray, Qfalse);
8095 ADD_INSN(ret, line, pop);
8096 }
8097 else {
8098 CHECK(COMPILE(ret, "argscat head", node->nd_head));
8099 CHECK(COMPILE(ret, "argscat body", node->nd_body));
8100 ADD_INSN(ret, line, concatarray);
8101 }
8102 break;
8103 }
8104 case NODE_ARGSPUSH:{
8105 if (popped) {
8106 CHECK(COMPILE(ret, "arsgpush head", node->nd_head));
8107 ADD_INSN1(ret, line, splatarray, Qfalse);
8108 ADD_INSN(ret, line, pop);
8109 CHECK(COMPILE_(ret, "argspush body", node->nd_body, popped));
8110 }
8111 else {
8112 CHECK(COMPILE(ret, "arsgpush head", node->nd_head));
8113 CHECK(COMPILE_(ret, "argspush body", node->nd_body, popped));
8114 ADD_INSN1(ret, line, newarray, INT2FIX(1));
8115 ADD_INSN(ret, line, concatarray);
8116 }
8117 break;
8118 }
8119 case NODE_SPLAT:{
8120 CHECK(COMPILE(ret, "splat", node->nd_head));
8121 ADD_INSN1(ret, line, splatarray, Qtrue);
8122
8123 if (popped) {
8124 ADD_INSN(ret, line, pop);
8125 }
8126 break;
8127 }
8128 case NODE_DEFN:{
8129 ID mid = node->nd_mid;
8130 const rb_iseq_t *method_iseq = NEW_ISEQ(node->nd_defn,
8131 rb_id2str(mid),
8132 ISEQ_TYPE_METHOD, line);
8133
8134 debugp_param("defn/iseq", rb_iseqw_new(method_iseq));
8135 ADD_INSN2(ret, line, definemethod, ID2SYM(mid), method_iseq);
8136 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)method_iseq);
8137
8138 if (!popped) {
8139 ADD_INSN1(ret, line, putobject, ID2SYM(mid));
8140 }
8141
8142 break;
8143 }
8144 case NODE_DEFS:{
8145 ID mid = node->nd_mid;
8146 const rb_iseq_t * singleton_method_iseq = NEW_ISEQ(node->nd_defn,
8147 rb_id2str(mid),
8148 ISEQ_TYPE_METHOD, line);
8149
8150 debugp_param("defs/iseq", rb_iseqw_new(singleton_method_iseq));
8151 CHECK(COMPILE(ret, "defs: recv", node->nd_recv));
8152 ADD_INSN2(ret, line, definesmethod, ID2SYM(mid), singleton_method_iseq);
8153 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)singleton_method_iseq);
8154
8155 if (!popped) {
8156 ADD_INSN1(ret, line, putobject, ID2SYM(mid));
8157 }
8158 break;
8159 }
8160 case NODE_ALIAS:{
8161 ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8162 ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
8163 CHECK(COMPILE(ret, "alias arg1", node->nd_1st));
8164 CHECK(COMPILE(ret, "alias arg2", node->nd_2nd));
8165 ADD_SEND(ret, line, id_core_set_method_alias, INT2FIX(3));
8166
8167 if (popped) {
8168 ADD_INSN(ret, line, pop);
8169 }
8170 break;
8171 }
8172 case NODE_VALIAS:{
8173 ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8174 ADD_INSN1(ret, line, putobject, ID2SYM(node->nd_alias));
8175 ADD_INSN1(ret, line, putobject, ID2SYM(node->nd_orig));
8176 ADD_SEND(ret, line, id_core_set_variable_alias, INT2FIX(2));
8177
8178 if (popped) {
8179 ADD_INSN(ret, line, pop);
8180 }
8181 break;
8182 }
8183 case NODE_UNDEF:{
8184 ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8185 ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
8186 CHECK(COMPILE(ret, "undef arg", node->nd_undef));
8187 ADD_SEND(ret, line, id_core_undef_method, INT2FIX(2));
8188
8189 if (popped) {
8190 ADD_INSN(ret, line, pop);
8191 }
8192 break;
8193 }
8194 case NODE_CLASS:{
8195 const rb_iseq_t *class_iseq = NEW_CHILD_ISEQ(node->nd_body,
8196 rb_sprintf("<class:%"PRIsVALUE">", rb_id2str(node->nd_cpath->nd_mid)),
8197 ISEQ_TYPE_CLASS, line);
8198 const int flags = VM_DEFINECLASS_TYPE_CLASS |
8199 (node->nd_super ? VM_DEFINECLASS_FLAG_HAS_SUPERCLASS : 0) |
8200 compile_cpath(ret, iseq, node->nd_cpath);
8201
8202 CHECK(COMPILE(ret, "super", node->nd_super));
8203 ADD_INSN3(ret, line, defineclass, ID2SYM(node->nd_cpath->nd_mid), class_iseq, INT2FIX(flags));
8204 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)class_iseq);
8205
8206 if (popped) {
8207 ADD_INSN(ret, line, pop);
8208 }
8209 break;
8210 }
8211 case NODE_MODULE:{
8212 const rb_iseq_t *module_iseq = NEW_CHILD_ISEQ(node->nd_body,
8213 rb_sprintf("<module:%"PRIsVALUE">", rb_id2str(node->nd_cpath->nd_mid)),
8214 ISEQ_TYPE_CLASS, line);
8215 const int flags = VM_DEFINECLASS_TYPE_MODULE |
8216 compile_cpath(ret, iseq, node->nd_cpath);
8217
8218 ADD_INSN (ret, line, putnil); /* dummy */
8219 ADD_INSN3(ret, line, defineclass, ID2SYM(node->nd_cpath->nd_mid), module_iseq, INT2FIX(flags));
8220 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)module_iseq);
8221
8222 if (popped) {
8223 ADD_INSN(ret, line, pop);
8224 }
8225 break;
8226 }
8227 case NODE_SCLASS:{
8228 ID singletonclass;
8229 const rb_iseq_t *singleton_class = NEW_ISEQ(node->nd_body, rb_fstring_lit("singleton class"),
8230 ISEQ_TYPE_CLASS, line);
8231
8232 CHECK(COMPILE(ret, "sclass#recv", node->nd_recv));
8233 ADD_INSN (ret, line, putnil);
8234 CONST_ID(singletonclass, "singletonclass");
8235 ADD_INSN3(ret, line, defineclass,
8236 ID2SYM(singletonclass), singleton_class,
8237 INT2FIX(VM_DEFINECLASS_TYPE_SINGLETON_CLASS));
8238 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)singleton_class);
8239
8240 if (popped) {
8241 ADD_INSN(ret, line, pop);
8242 }
8243 break;
8244 }
8245 case NODE_COLON2:{
8246 if (rb_is_const_id(node->nd_mid)) {
8247 /* constant */
8248 LABEL *lend = NEW_LABEL(line);
8249 int ic_index = body->is_size++;
8250
8251 DECL_ANCHOR(pref);
8252 DECL_ANCHOR(body);
8253
8254 INIT_ANCHOR(pref);
8255 INIT_ANCHOR(body);
8256 CHECK(compile_const_prefix(iseq, node, pref, body));
8257 if (LIST_INSN_SIZE_ZERO(pref)) {
8258 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
8259 ADD_INSN2(ret, line, opt_getinlinecache, lend, INT2FIX(ic_index));
8260 }
8261 else {
8262 ADD_INSN(ret, line, putnil);
8263 }
8264
8265 ADD_SEQ(ret, body);
8266
8267 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
8268 ADD_INSN1(ret, line, opt_setinlinecache, INT2FIX(ic_index));
8269 ADD_LABEL(ret, lend);
8270 }
8271 }
8272 else {
8273 ADD_SEQ(ret, pref);
8274 ADD_SEQ(ret, body);
8275 }
8276 }
8277 else {
8278 /* function call */
8279 ADD_CALL_RECEIVER(ret, line);
8280 CHECK(COMPILE(ret, "colon2#nd_head", node->nd_head));
8281 ADD_CALL(ret, line, node->nd_mid, INT2FIX(1));
8282 }
8283 if (popped) {
8284 ADD_INSN(ret, line, pop);
8285 }
8286 break;
8287 }
8288 case NODE_COLON3:{
8289 LABEL *lend = NEW_LABEL(line);
8290 int ic_index = body->is_size++;
8291
8292 debugi("colon3#nd_mid", node->nd_mid);
8293
8294 /* add cache insn */
8295 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
8296 ADD_INSN2(ret, line, opt_getinlinecache, lend, INT2FIX(ic_index));
8297 ADD_INSN(ret, line, pop);
8298 }
8299
8300 ADD_INSN1(ret, line, putobject, rb_cObject);
8301 ADD_INSN1(ret, line, putobject, Qtrue);
8302 ADD_INSN1(ret, line, getconstant, ID2SYM(node->nd_mid));
8303
8304 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
8305 ADD_INSN1(ret, line, opt_setinlinecache, INT2FIX(ic_index));
8306 ADD_LABEL(ret, lend);
8307 }
8308
8309 if (popped) {
8310 ADD_INSN(ret, line, pop);
8311 }
8312 break;
8313 }
8314 case NODE_DOT2:
8315 case NODE_DOT3:{
8316 int excl = type == NODE_DOT3;
8317 VALUE flag = INT2FIX(excl);
8318 const NODE *b = node->nd_beg;
8319 const NODE *e = node->nd_end;
8320 if (number_literal_p(b) && number_literal_p(e)) {
8321 if (!popped) {
8322 VALUE val = rb_range_new(b->nd_lit, e->nd_lit, excl);
8323 ADD_INSN1(ret, line, putobject, val);
8324 RB_OBJ_WRITTEN(iseq, Qundef, val);
8325 }
8326 }
8327 else {
8328 CHECK(COMPILE_(ret, "min", b, popped));
8329 CHECK(COMPILE_(ret, "max", e, popped));
8330 if (!popped) {
8331 ADD_INSN1(ret, line, newrange, flag);
8332 }
8333 }
8334 break;
8335 }
8336 case NODE_FLIP2:
8337 case NODE_FLIP3:{
8338 LABEL *lend = NEW_LABEL(line);
8339 LABEL *ltrue = NEW_LABEL(line);
8340 LABEL *lfalse = NEW_LABEL(line);
8341 CHECK(compile_flip_flop(iseq, ret, node, type == NODE_FLIP2,
8342 ltrue, lfalse));
8343 ADD_LABEL(ret, ltrue);
8344 ADD_INSN1(ret, line, putobject, Qtrue);
8345 ADD_INSNL(ret, line, jump, lend);
8346 ADD_LABEL(ret, lfalse);
8347 ADD_INSN1(ret, line, putobject, Qfalse);
8348 ADD_LABEL(ret, lend);
8349 break;
8350 }
8351 case NODE_SELF:{
8352 if (!popped) {
8353 ADD_INSN(ret, line, putself);
8354 }
8355 break;
8356 }
8357 case NODE_NIL:{
8358 if (!popped) {
8359 ADD_INSN(ret, line, putnil);
8360 }
8361 break;
8362 }
8363 case NODE_TRUE:{
8364 if (!popped) {
8365 ADD_INSN1(ret, line, putobject, Qtrue);
8366 }
8367 break;
8368 }
8369 case NODE_FALSE:{
8370 if (!popped) {
8371 ADD_INSN1(ret, line, putobject, Qfalse);
8372 }
8373 break;
8374 }
8375 case NODE_ERRINFO:{
8376 if (!popped) {
8377 if (body->type == ISEQ_TYPE_RESCUE) {
8378 ADD_GETLOCAL(ret, line, LVAR_ERRINFO, 0);
8379 }
8380 else {
8381 const rb_iseq_t *ip = iseq;
8382 int level = 0;
8383 while (ip) {
8384 if (ip->body->type == ISEQ_TYPE_RESCUE) {
8385 break;
8386 }
8387 ip = ip->body->parent_iseq;
8388 level++;
8389 }
8390 if (ip) {
8391 ADD_GETLOCAL(ret, line, LVAR_ERRINFO, level);
8392 }
8393 else {
8394 ADD_INSN(ret, line, putnil);
8395 }
8396 }
8397 }
8398 break;
8399 }
8400 case NODE_DEFINED:
8401 if (!popped) {
8402 CHECK(compile_defined_expr(iseq, ret, node, Qtrue));
8403 }
8404 break;
8405 case NODE_POSTEXE:{
8406 /* compiled to:
8407 * ONCE{ rb_mRubyVMFrozenCore::core#set_postexe{ ... } }
8408 */
8409 int is_index = body->is_size++;
8410 struct rb_iseq_new_with_callback_callback_func *ifunc =
8411 rb_iseq_new_with_callback_new_callback(build_postexe_iseq, node->nd_body);
8412 const rb_iseq_t *once_iseq =
8413 new_child_iseq_with_callback(iseq, ifunc,
8414 rb_fstring(make_name_for_block(iseq)), iseq, ISEQ_TYPE_BLOCK, line);
8415
8416 ADD_INSN2(ret, line, once, once_iseq, INT2FIX(is_index));
8417 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)once_iseq);
8418
8419 if (popped) {
8420 ADD_INSN(ret, line, pop);
8421 }
8422 break;
8423 }
8424 case NODE_KW_ARG:
8425 {
8426 LABEL *end_label = NEW_LABEL(nd_line(node));
8427 const NODE *default_value = node->nd_body->nd_value;
8428
8429 if (default_value == NODE_SPECIAL_REQUIRED_KEYWORD) {
8430 /* required argument. do nothing */
8431 COMPILE_ERROR(ERROR_ARGS "unreachable");
8432 goto ng;
8433 }
8434 else if (nd_type(default_value) == NODE_LIT ||
8435 nd_type(default_value) == NODE_NIL ||
8436 nd_type(default_value) == NODE_TRUE ||
8437 nd_type(default_value) == NODE_FALSE) {
8438 COMPILE_ERROR(ERROR_ARGS "unreachable");
8439 goto ng;
8440 }
8441 else {
8442 /* if keywordcheck(_kw_bits, nth_keyword)
8443 * kw = default_value
8444 * end
8445 */
8446 int kw_bits_idx = body->local_table_size - body->param.keyword->bits_start;
8447 int keyword_idx = body->param.keyword->num;
8448
8449 ADD_INSN2(ret, line, checkkeyword, INT2FIX(kw_bits_idx + VM_ENV_DATA_SIZE - 1), INT2FIX(keyword_idx));
8450 ADD_INSNL(ret, line, branchif, end_label);
8451 CHECK(COMPILE_POPPED(ret, "keyword default argument", node->nd_body));
8452 ADD_LABEL(ret, end_label);
8453 }
8454
8455 break;
8456 }
8457 case NODE_DSYM:{
8458 compile_dstr(iseq, ret, node);
8459 if (!popped) {
8460 ADD_INSN(ret, line, intern);
8461 }
8462 else {
8463 ADD_INSN(ret, line, pop);
8464 }
8465 break;
8466 }
8467 case NODE_ATTRASGN:{
8468 DECL_ANCHOR(recv);
8469 DECL_ANCHOR(args);
8470 unsigned int flag = 0;
8471 ID mid = node->nd_mid;
8472 VALUE argc;
8473 LABEL *else_label = NULL;
8474 VALUE branches = Qfalse;
8475
8476 /* optimization shortcut
8477 * obj["literal"] = value -> opt_aset_with(obj, "literal", value)
8478 */
8479 if (mid == idASET && !private_recv_p(node) && node->nd_args &&
8480 nd_type(node->nd_args) == NODE_LIST && node->nd_args->nd_alen == 2 &&
8481 nd_type(node->nd_args->nd_head) == NODE_STR &&
8482 ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
8483 !ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal &&
8484 ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction)
8485 {
8486 VALUE str = rb_fstring(node->nd_args->nd_head->nd_lit);
8487 CHECK(COMPILE(ret, "recv", node->nd_recv));
8488 CHECK(COMPILE(ret, "value", node->nd_args->nd_next->nd_head));
8489 if (!popped) {
8490 ADD_INSN(ret, line, swap);
8491 ADD_INSN1(ret, line, topn, INT2FIX(1));
8492 }
8493 ADD_INSN2(ret, line, opt_aset_with, str,
8494 new_callinfo(iseq, idASET, 2, 0, NULL, FALSE));
8495 RB_OBJ_WRITTEN(iseq, Qundef, str);
8496 ADD_INSN(ret, line, pop);
8497 break;
8498 }
8499
8500 INIT_ANCHOR(recv);
8501 INIT_ANCHOR(args);
8502 argc = setup_args(iseq, args, node->nd_args, &flag, NULL);
8503 CHECK(!NIL_P(argc));
8504
8505 int asgnflag = COMPILE_RECV(recv, "recv", node);
8506 CHECK(asgnflag != -1);
8507 flag |= (unsigned int)asgnflag;
8508
8509 debugp_param("argc", argc);
8510 debugp_param("nd_mid", ID2SYM(mid));
8511
8512 if (!rb_is_attrset_id(mid)) {
8513 /* safe nav attr */
8514 mid = rb_id_attrset(mid);
8515 else_label = qcall_branch_start(iseq, recv, &branches, node, line);
8516 }
8517 if (!popped) {
8518 ADD_INSN(ret, line, putnil);
8519 ADD_SEQ(ret, recv);
8520 ADD_SEQ(ret, args);
8521
8522 if (flag & VM_CALL_ARGS_BLOCKARG) {
8523 ADD_INSN1(ret, line, topn, INT2FIX(1));
8524 if (flag & VM_CALL_ARGS_SPLAT) {
8525 ADD_INSN1(ret, line, putobject, INT2FIX(-1));
8526 ADD_SEND_WITH_FLAG(ret, line, idAREF, INT2FIX(1), INT2FIX(asgnflag));
8527 }
8528 ADD_INSN1(ret, line, setn, FIXNUM_INC(argc, 3));
8529 ADD_INSN (ret, line, pop);
8530 }
8531 else if (flag & VM_CALL_ARGS_SPLAT) {
8532 ADD_INSN(ret, line, dup);
8533 ADD_INSN1(ret, line, putobject, INT2FIX(-1));
8534 ADD_SEND_WITH_FLAG(ret, line, idAREF, INT2FIX(1), INT2FIX(asgnflag));
8535 ADD_INSN1(ret, line, setn, FIXNUM_INC(argc, 2));
8536 ADD_INSN (ret, line, pop);
8537 }
8538 else {
8539 ADD_INSN1(ret, line, setn, FIXNUM_INC(argc, 1));
8540 }
8541 }
8542 else {
8543 ADD_SEQ(ret, recv);
8544 ADD_SEQ(ret, args);
8545 }
8546 ADD_SEND_WITH_FLAG(ret, line, mid, argc, INT2FIX(flag));
8547 qcall_branch_end(iseq, ret, else_label, branches, node, line);
8548 ADD_INSN(ret, line, pop);
8549
8550 break;
8551 }
8552 case NODE_LAMBDA:{
8553 /* compile same as lambda{...} */
8554 const rb_iseq_t *block = NEW_CHILD_ISEQ(node->nd_body, make_name_for_block(iseq), ISEQ_TYPE_BLOCK, line);
8555 VALUE argc = INT2FIX(0);
8556
8557 ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8558 ADD_CALL_WITH_BLOCK(ret, line, idLambda, argc, block);
8559 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block);
8560
8561 if (popped) {
8562 ADD_INSN(ret, line, pop);
8563 }
8564 break;
8565 }
8566 default:
8567 UNKNOWN_NODE("iseq_compile_each", node, COMPILE_NG);
8568 ng:
8569 debug_node_end();
8570 return COMPILE_NG;
8571 }
8572
8573 debug_node_end();
8574 return COMPILE_OK;
8575 }
8576
8577 /***************************/
8578 /* instruction information */
8579 /***************************/
8580
8581 static int
8582 insn_data_length(INSN *iobj)
8583 {
8584 return insn_len(iobj->insn_id);
8585 }
8586
8587 static int
8588 calc_sp_depth(int depth, INSN *insn)
8589 {
8590 return comptime_insn_stack_increase(depth, insn->insn_id, insn->operands);
8591 }
8592
8593 static VALUE
8594 opobj_inspect(VALUE obj)
8595 {
8596 struct RBasic *r = (struct RBasic *) obj;
8597 if (!SPECIAL_CONST_P(r) && r->klass == 0) {
8598 switch (BUILTIN_TYPE(r)) {
8599 case T_STRING:
8600 obj = rb_str_new_cstr(RSTRING_PTR(obj));
8601 break;
8602 case T_ARRAY:
8603 obj = rb_ary_dup(obj);
8604 break;
8605 }
8606 }
8607 return rb_inspect(obj);
8608 }
8609
8610
8611
8612 static VALUE
8613 insn_data_to_s_detail(INSN *iobj)
8614 {
8615 VALUE str = rb_sprintf("%-20s ", insn_name(iobj->insn_id));
8616
8617 if (iobj->operands) {
8618 const char *types = insn_op_types(iobj->insn_id);
8619 int j;
8620
8621 for (j = 0; types[j]; j++) {
8622 char type = types[j];
8623
8624 switch (type) {
8625 case TS_OFFSET: /* label(destination position) */
8626 {
8627 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, j);
8628 rb_str_catf(str, LABEL_FORMAT, lobj->label_no);
8629 break;
8630 }
8631 break;
8632 case TS_ISEQ: /* iseq */
8633 {
8634 rb_iseq_t *iseq = (rb_iseq_t *)OPERAND_AT(iobj, j);
8635 VALUE val = Qnil;
8636 if (0 && iseq) { /* TODO: invalidate now */
8637 val = (VALUE)iseq;
8638 }
8639 rb_str_concat(str, opobj_inspect(val));
8640 }
8641 break;
8642 case TS_LINDEX:
8643 case TS_NUM: /* ulong */
8644 case TS_VALUE: /* VALUE */
8645 {
8646 VALUE v = OPERAND_AT(iobj, j);
8647 rb_str_concat(str, opobj_inspect(v));
8648 break;
8649 }
8650 case TS_ID: /* ID */
8651 rb_str_concat(str, opobj_inspect(OPERAND_AT(iobj, j)));
8652 break;
8653 case TS_GENTRY:
8654 {
8655 struct rb_global_entry *entry = (struct rb_global_entry *)
8656 (OPERAND_AT(iobj, j) & (~1));
8657 rb_str_append(str, rb_id2str(entry->id));
8658 break;
8659 }
8660 case TS_IC: /* inline cache */
8661 case TS_IVC: /* inline ivar cache */
8662 case TS_ISE: /* inline storage entry */
8663 rb_str_catf(str, "<ic:%d>", FIX2INT(OPERAND_AT(iobj, j)));
8664 break;
8665 case TS_CALLDATA: /* we store these as call infos at compile time */
8666 {
8667 const struct rb_call_info *ci = (struct rb_call_info *)OPERAND_AT(iobj, j);
8668 rb_str_cat2(str, "<calldata:");
8669 if (ci->mid) rb_str_catf(str, "%"PRIsVALUE, rb_id2str(ci->mid));
8670 rb_str_catf(str, ", %d>", ci->orig_argc);
8671 break;
8672 }
8673 case TS_CDHASH: /* case/when condition cache */
8674 rb_str_cat2(str, "<ch>");
8675 break;
8676 case TS_FUNCPTR:
8677 {
8678 void *func = (void *)OPERAND_AT(iobj, j);
8679 #ifdef HAVE_DLADDR
8680 Dl_info info;
8681 if (dladdr(func, &info) && info.dli_sname) {
8682 rb_str_cat2(str, info.dli_sname);
8683 break;
8684 }
8685 #endif
8686 rb_str_catf(str, "<%p>", func);
8687 }
8688 break;
8689 case TS_BUILTIN:
8690 rb_bug("unsupported: TS_BUILTIN");
8691 break;
8692 default:{
8693 rb_raise(rb_eSyntaxError, "unknown operand type: %c", type);
8694 }
8695 }
8696 if (types[j + 1]) {
8697 rb_str_cat2(str, ", ");
8698 }
8699 }
8700 }
8701 return str;
8702 }
8703
8704 static void
8705 dump_disasm_list(const LINK_ELEMENT *link)
8706 {
8707 dump_disasm_list_with_cursor(link, NULL, NULL);
8708 }
8709
8710 static void
8711 dump_disasm_list_with_cursor(const LINK_ELEMENT *link, const LINK_ELEMENT *curr, const LABEL *dest)
8712 {
8713 int pos = 0;
8714 INSN *iobj;
8715 LABEL *lobj;
8716 VALUE str;
8717
8718 printf("-- raw disasm--------\n");
8719
8720 while (link) {
8721 if (curr) printf(curr == link ? "*" : " ");
8722 switch (link->type) {
8723 case ISEQ_ELEMENT_INSN:
8724 {
8725 iobj = (INSN *)link;
8726 str = insn_data_to_s_detail(iobj);
8727 printf("%04d %-65s(%4u)\n", pos, StringValueCStr(str), iobj->insn_info.line_no);
8728 pos += insn_data_length(iobj);
8729 break;
8730 }
8731 case ISEQ_ELEMENT_LABEL:
8732 {
8733 lobj = (LABEL *)link;
8734 printf(LABEL_FORMAT" [sp: %d]%s\n", lobj->label_no, lobj->sp,
8735 dest == lobj ? " <---" : "");
8736 break;
8737 }
8738 case ISEQ_ELEMENT_TRACE:
8739 {
8740 TRACE *trace = (TRACE *)link;
8741 printf("trace: %0x\n", trace->event);
8742 break;
8743 }
8744 case ISEQ_ELEMENT_ADJUST:
8745 {
8746 ADJUST *adjust = (ADJUST *)link;
8747 printf("adjust: [label: %d]\n", adjust->label ? adjust->label->label_no : -1);
8748 break;
8749 }
8750 default:
8751 /* ignore */
8752 rb_raise(rb_eSyntaxError, "dump_disasm_list error: %ld\n", FIX2LONG(link->type));
8753 }
8754 link = link->next;
8755 }
8756 printf("---------------------\n");
8757 fflush(stdout);
8758 }
8759
8760 const char *
8761 rb_insns_name(int i)
8762 {
8763 return insn_name(i);
8764 }
8765
8766 VALUE
8767 rb_insns_name_array(void)
8768 {
8769 VALUE ary = rb_ary_new_capa(VM_INSTRUCTION_SIZE);
8770 int i;
8771 for (i = 0; i < VM_INSTRUCTION_SIZE; i++) {
8772 rb_ary_push(ary, rb_fstring_cstr(insn_name(i)));
8773 }
8774 return rb_obj_freeze(ary);
8775 }
8776
8777 static LABEL *
8778 register_label(rb_iseq_t *iseq, struct st_table *labels_table, VALUE obj)
8779 {
8780 LABEL *label = 0;
8781 st_data_t tmp;
8782 obj = rb_to_symbol_type(obj);
8783
8784 if (st_lookup(labels_table, obj, &tmp) == 0) {
8785 label = NEW_LABEL(0);
8786 st_insert(labels_table, obj, (st_data_t)label);
8787 }
8788 else {
8789 label = (LABEL *)tmp;
8790 }
8791 LABEL_REF(label);
8792 return label;
8793 }
8794
8795 static VALUE
8796 get_exception_sym2type(VALUE sym)
8797 {
8798 #undef rb_intern
8799 #define rb_intern(str) rb_intern_const(str)
8800 static VALUE symRescue, symEnsure, symRetry;
8801 static VALUE symBreak, symRedo, symNext;
8802
8803 if (symRescue == 0) {
8804 symRescue = ID2SYM(rb_intern("rescue"));
8805 symEnsure = ID2SYM(rb_intern("ensure"));
8806 symRetry = ID2SYM(rb_intern("retry"));
8807 symBreak = ID2SYM(rb_intern("break"));
8808 symRedo = ID2SYM(rb_intern("redo"));
8809 symNext = ID2SYM(rb_intern("next"));
8810 }
8811
8812 if (sym == symRescue) return CATCH_TYPE_RESCUE;
8813 if (sym == symEnsure) return CATCH_TYPE_ENSURE;
8814 if (sym == symRetry) return CATCH_TYPE_RETRY;
8815 if (sym == symBreak) return CATCH_TYPE_BREAK;
8816 if (sym == symRedo) return CATCH_TYPE_REDO;
8817 if (sym == symNext) return CATCH_TYPE_NEXT;
8818 rb_raise(rb_eSyntaxError, "invalid exception symbol: %+"PRIsVALUE, sym);
8819 return 0;
8820 }
8821
8822 static int
8823 iseq_build_from_ary_exception(rb_iseq_t *iseq, struct st_table *labels_table,
8824 VALUE exception)
8825 {
8826 int i;
8827
8828 for (i=0; i<RARRAY_LEN(exception); i++) {
8829 const rb_iseq_t *eiseq;
8830 VALUE v, type;
8831 LABEL *lstart, *lend, *lcont;
8832 unsigned int sp;
8833
8834 v = rb_to_array_type(RARRAY_AREF(exception, i));
8835 if (RARRAY_LEN(v) != 6) {
8836 rb_raise(rb_eSyntaxError, "wrong exception entry");
8837 }
8838 type = get_exception_sym2type(RARRAY_AREF(v, 0));
8839 if (RARRAY_AREF(v, 1) == Qnil) {
8840 eiseq = NULL;
8841 }
8842 else {
8843 eiseq = rb_iseqw_to_iseq(rb_iseq_load(RARRAY_AREF(v, 1), (VALUE)iseq, Qnil));
8844 }
8845
8846 lstart = register_label(iseq, labels_table, RARRAY_AREF(v, 2));
8847 lend = register_label(iseq, labels_table, RARRAY_AREF(v, 3));
8848 lcont = register_label(iseq, labels_table, RARRAY_AREF(v, 4));
8849 sp = NUM2UINT(RARRAY_AREF(v, 5));
8850
8851 /* TODO: Dirty Hack! Fix me */
8852 if (type == CATCH_TYPE_RESCUE ||
8853 type == CATCH_TYPE_BREAK ||
8854 type == CATCH_TYPE_NEXT) {
8855 ++sp;
8856 }
8857
8858 lcont->sp = sp;
8859
8860 ADD_CATCH_ENTRY(type, lstart, lend, eiseq, lcont);
8861
8862 RB_GC_GUARD(v);
8863 }
8864 return COMPILE_OK;
8865 }
8866
8867 static struct st_table *
8868 insn_make_insn_table(void)
8869 {
8870 struct st_table *table;
8871 int i;
8872 table = st_init_numtable_with_size(VM_INSTRUCTION_SIZE);
8873
8874 for (i=0; i<VM_INSTRUCTION_SIZE; i++) {
8875 st_insert(table, ID2SYM(rb_intern(insn_name(i))), i);
8876 }
8877
8878 return table;
8879 }
8880
8881 static const rb_iseq_t *
8882 iseq_build_load_iseq(const rb_iseq_t *iseq, VALUE op)
8883 {
8884 VALUE iseqw;
8885 const rb_iseq_t *loaded_iseq;
8886
8887 if (RB_TYPE_P(op, T_ARRAY)) {
8888 iseqw = rb_iseq_load(op, (VALUE)iseq, Qnil);
8889 }
8890 else if (CLASS_OF(op) == rb_cISeq) {
8891 iseqw = op;
8892 }
8893 else {
8894 rb_raise(rb_eSyntaxError, "ISEQ is required");
8895 }
8896
8897 loaded_iseq = rb_iseqw_to_iseq(iseqw);
8898 return loaded_iseq;
8899 }
8900
8901 static VALUE
8902 iseq_build_callinfo_from_hash(rb_iseq_t *iseq, VALUE op)
8903 {
8904 ID mid = 0;
8905 int orig_argc = 0;
8906 unsigned int flag = 0;
8907 struct rb_call_info_kw_arg *kw_arg = 0;
8908
8909 if (!NIL_P(op)) {
8910 VALUE vmid = rb_hash_aref(op, ID2SYM(rb_intern("mid")));
8911 VALUE vflag = rb_hash_aref(op, ID2SYM(rb_intern("flag")));
8912 VALUE vorig_argc = rb_hash_aref(op, ID2SYM(rb_intern("orig_argc")));
8913 VALUE vkw_arg = rb_hash_aref(op, ID2SYM(rb_intern("kw_arg")));
8914
8915 if (!NIL_P(vmid)) mid = SYM2ID(vmid);
8916 if (!NIL_P(vflag)) flag = NUM2UINT(vflag);
8917 if (!NIL_P(vorig_argc)) orig_argc = FIX2INT(vorig_argc);
8918
8919 if (!NIL_P(vkw_arg)) {
8920 int i;
8921 int len = RARRAY_LENINT(vkw_arg);
8922 size_t n = rb_call_info_kw_arg_bytes(len);
8923
8924 kw_arg = xmalloc(n);
8925 kw_arg->keyword_len = len;
8926 for (i = 0; i < len; i++) {
8927 VALUE kw = RARRAY_AREF(vkw_arg, i);
8928 SYM2ID(kw); /* make immortal */
8929 kw_arg->keywords[i] = kw;
8930 }
8931 }
8932 }
8933
8934 return (VALUE)new_callinfo(iseq, mid, orig_argc, flag, kw_arg, (flag & VM_CALL_ARGS_SIMPLE) == 0);
8935 }
8936
8937 static rb_event_flag_t
8938 event_name_to_flag(VALUE sym)
8939 {
8940 #define CHECK_EVENT(ev) if (sym == ID2SYM(rb_intern(#ev))) return ev;
8941 CHECK_EVENT(RUBY_EVENT_LINE);
8942 CHECK_EVENT(RUBY_EVENT_CLASS);
8943 CHECK_EVENT(RUBY_EVENT_END);
8944 CHECK_EVENT(RUBY_EVENT_CALL);
8945 CHECK_EVENT(RUBY_EVENT_RETURN);
8946 CHECK_EVENT(RUBY_EVENT_B_CALL);
8947 CHECK_EVENT(RUBY_EVENT_B_RETURN);
8948 #undef CHECK_EVENT
8949 return RUBY_EVENT_NONE;
8950 }
8951
8952 static int
8953 iseq_build_from_ary_body(rb_iseq_t *iseq, LINK_ANCHOR *const anchor,
8954 VALUE body, VALUE labels_wrapper)
8955 {
8956 /* TODO: body should be frozen */
8957 long i, len = RARRAY_LEN(body);
8958 struct st_table *labels_table = DATA_PTR(labels_wrapper);
8959 int j;
8960 int line_no = 0;
8961 int ret = COMPILE_OK;
8962
8963 /*
8964 * index -> LABEL *label
8965 */
8966 static struct st_table *insn_table;
8967
8968 if (insn_table == 0) {
8969 insn_table = insn_make_insn_table();
8970 }
8971
8972 for (i=0; i<len; i++) {
8973 VALUE obj = RARRAY_AREF(body, i);
8974
8975 if (SYMBOL_P(obj)) {
8976 rb_event_flag_t event;
8977 if ((event = event_name_to_flag(obj)) != RUBY_EVENT_NONE) {
8978 ADD_TRACE(anchor, event);
8979 }
8980 else {
8981 LABEL *label = register_label(iseq, labels_table, obj);
8982 ADD_LABEL(anchor, label);
8983 }
8984 }
8985 else if (FIXNUM_P(obj)) {
8986 line_no = NUM2INT(obj);
8987 }
8988 else if (RB_TYPE_P(obj, T_ARRAY)) {
8989 VALUE *argv = 0;
8990 int argc = RARRAY_LENINT(obj) - 1;
8991 st_data_t insn_id;
8992 VALUE insn;
8993
8994 insn = (argc < 0) ? Qnil : RARRAY_AREF(obj, 0);
8995 if (st_lookup(insn_table, (st_data_t)insn, &insn_id) == 0) {
8996 /* TODO: exception */
8997 COMPILE_ERROR(iseq, line_no,
8998 "unknown instruction: %+"PRIsVALUE, insn);
8999 ret = COMPILE_NG;
9000 break;
9001 }
9002
9003 if (argc != insn_len((VALUE)insn_id)-1) {
9004 COMPILE_ERROR(iseq, line_no,
9005 "operand size mismatch");
9006 ret = COMPILE_NG;
9007 break;
9008 }
9009
9010 if (argc > 0) {
9011 argv = compile_data_alloc2(iseq, sizeof(VALUE), argc);
9012 for (j=0; j<argc; j++) {
9013 VALUE op = rb_ary_entry(obj, j+1);
9014 switch (insn_op_type((VALUE)insn_id, j)) {
9015 case TS_OFFSET: {
9016 LABEL *label = register_label(iseq, labels_table, op);
9017 argv[j] = (VALUE)label;
9018 break;
9019 }
9020 case TS_LINDEX:
9021 case TS_NUM:
9022 (void)NUM2INT(op);
9023 argv[j] = op;
9024 break;
9025 case TS_VALUE:
9026 argv[j] = op;
9027 RB_OBJ_WRITTEN(iseq, Qundef, op);
9028 break;
9029 case TS_ISEQ:
9030 {
9031 if (op != Qnil) {
9032 VALUE v = (VALUE)iseq_build_load_iseq(iseq, op);
9033 argv[j] = v;
9034 RB_OBJ_WRITTEN(iseq, Qundef, v);
9035 }
9036 else {
9037 argv[j] = 0;
9038 }
9039 }
9040 break;
9041 case TS_GENTRY:
9042 op = rb_to_symbol_type(op);
9043 argv[j] = (VALUE)rb_global_entry(SYM2ID(op));
9044 break;
9045 case TS_ISE:
9046 FL_SET(iseq, ISEQ_MARKABLE_ISEQ);
9047 /* fall through */
9048 case TS_IC:
9049 case TS_IVC: /* inline ivar cache */
9050 argv[j] = op;
9051 if (NUM2UINT(op) >= iseq->body->is_size) {
9052 iseq->body->is_size = NUM2INT(op) + 1;
9053 }
9054 break;
9055 case TS_CALLDATA:
9056 argv[j] = iseq_build_callinfo_from_hash(iseq, op);
9057 break;
9058 case TS_ID:
9059 argv[j] = rb_to_symbol_type(op);
9060 break;
9061 case TS_CDHASH:
9062 {
9063 int i;
9064 VALUE map = rb_hash_new_with_size(RARRAY_LEN(op)/2);
9065
9066 RHASH_TBL_RAW(map)->type = &cdhash_type;
9067 op = rb_to_array_type(op);
9068 for (i=0; i<RARRAY_LEN(op); i+=2) {
9069 VALUE key = RARRAY_AREF(op, i);
9070 VALUE sym = RARRAY_AREF(op, i+1);
9071 LABEL *label =
9072 register_label(iseq, labels_table, sym);
9073 rb_hash_aset(map, key, (VALUE)label | 1);
9074 }
9075 RB_GC_GUARD(op);
9076 argv[j] = map;
9077 RB_OBJ_WRITTEN(iseq, Qundef, map);
9078 }
9079 break;
9080 case TS_FUNCPTR:
9081 {
9082 #if SIZEOF_VALUE <= SIZEOF_LONG
9083 long funcptr = NUM2LONG(op);
9084 #else
9085 LONG_LONG funcptr = NUM2LL(op);
9086 #endif
9087 argv[j] = (VALUE)funcptr;
9088 }
9089 break;
9090 default:
9091 rb_raise(rb_eSyntaxError, "unknown operand: %c", insn_op_type((VALUE)insn_id, j));
9092 }
9093 }
9094 }
9095 ADD_ELEM(anchor,
9096 (LINK_ELEMENT*)new_insn_core(iseq, line_no,
9097 (enum ruby_vminsn_type)insn_id, argc, argv));
9098 }
9099 else {
9100 rb_raise(rb_eTypeError, "unexpected object for instruction");
9101 }
9102 }
9103 DATA_PTR(labels_wrapper) = 0;
9104 validate_labels(iseq, labels_table);
9105 if (!ret) return ret;
9106 return iseq_setup(iseq, anchor);
9107 }
9108
9109 #define CHECK_ARRAY(v) rb_to_array_type(v)
9110 #define CHECK_SYMBOL(v) rb_to_symbol_type(v)
9111
9112 static int
9113 int_param(int *dst, VALUE param, VALUE sym)
9114 {
9115 VALUE val = rb_hash_aref(param, sym);
9116 if (FIXNUM_P(val)) {
9117 *dst = FIX2INT(val);
9118 return TRUE;
9119 }
9120 else if (!NIL_P(val)) {
9121 rb_raise(rb_eTypeError, "invalid %+"PRIsVALUE" Fixnum: %+"PRIsVALUE,
9122 sym, val);
9123 }
9124 return FALSE;
9125 }
9126
9127 static const struct rb_iseq_param_keyword *
9128 iseq_build_kw(rb_iseq_t *iseq, VALUE params, VALUE keywords)
9129 {
9130 int i, j;
9131 int len = RARRAY_LENINT(keywords);
9132 int default_len;
9133 VALUE key, sym, default_val;
9134 VALUE *dvs;
9135 ID *ids;
9136 struct rb_iseq_param_keyword *keyword = ZALLOC(struct rb_iseq_param_keyword);
9137
9138 iseq->body->param.flags.has_kw = TRUE;
9139
9140 keyword->num = len;
9141 #define SYM(s) ID2SYM(rb_intern(#s))
9142 (void)int_param(&keyword->bits_start, params, SYM(kwbits));
9143 i = keyword->bits_start - keyword->num;
9144 ids = (ID *)&iseq->body->local_table[i];
9145 #undef SYM
9146
9147 /* required args */
9148 for (i = 0; i < len; i++) {
9149 VALUE val = RARRAY_AREF(keywords, i);
9150
9151 if (!SYMBOL_P(val)) {
9152 goto default_values;
9153 }
9154 ids[i] = SYM2ID(val);
9155 keyword->required_num++;
9156 }
9157
9158 default_values: /* note: we intentionally preserve `i' from previous loop */
9159 default_len = len - i;
9160 if (default_len == 0) {
9161 keyword->table = ids;
9162 return keyword;
9163 }
9164 else if (default_len < 0) {
9165 UNREACHABLE;
9166 }
9167
9168 dvs = ALLOC_N(VALUE, (unsigned int)default_len);
9169
9170 for (j = 0; i < len; i++, j++) {
9171 key = RARRAY_AREF(keywords, i);
9172 CHECK_ARRAY(key);
9173
9174 switch (RARRAY_LEN(key)) {
9175 case 1:
9176 sym = RARRAY_AREF(key, 0);
9177 default_val = Qundef;
9178 break;
9179 case 2:
9180 sym = RARRAY_AREF(key, 0);
9181 default_val = RARRAY_AREF(key, 1);
9182 break;
9183 default:
9184 rb_raise(rb_eTypeError, "keyword default has unsupported len %+"PRIsVALUE, key);
9185 }
9186 ids[i] = SYM2ID(sym);
9187 dvs[j] = default_val;
9188 }
9189
9190 keyword->table = ids;
9191 keyword->default_values = dvs;
9192
9193 return keyword;
9194 }
9195
9196 void
9197 rb_iseq_mark_insn_storage(struct iseq_compile_data_storage *storage)
9198 {
9199 INSN *iobj = 0;
9200 size_t size = sizeof(INSN);
9201 unsigned int pos = 0;
9202
9203 while (storage) {
9204 #ifdef STRICT_ALIGNMENT
9205 size_t padding = calc_padding((void *)&storage->buff[pos], size);
9206 #else
9207 const size_t padding = 0; /* expected to be optimized by compiler */
9208 #endif /* STRICT_ALIGNMENT */
9209 size_t offset = pos + size + padding;
9210 if (offset > storage->size || offset > storage->pos) {
9211 pos = 0;
9212 storage = storage->next;
9213 }
9214 else {
9215 #ifdef STRICT_ALIGNMENT
9216 pos += (int)padding;
9217 #endif /* STRICT_ALIGNMENT */
9218
9219 iobj = (INSN *)&storage->buff[pos];
9220
9221 if (iobj->operands) {
9222 int j;
9223 const char *types = insn_op_types(iobj->insn_id);
9224
9225 for (j = 0; types[j]; j++) {
9226 char type = types[j];
9227 switch (type) {
9228 case TS_CDHASH:
9229 case TS_ISEQ:
9230 case TS_VALUE:
9231 {
9232 VALUE op = OPERAND_AT(iobj, j);
9233 if (!SPECIAL_CONST_P(op)) {
9234 rb_gc_mark(op);
9235 }
9236 break;
9237 }
9238 default:
9239 break;
9240 }
9241 }
9242 }
9243 pos += (int)size;
9244 }
9245 }
9246 }
9247
9248 void
9249 rb_iseq_build_from_ary(rb_iseq_t *iseq, VALUE misc, VALUE locals, VALUE params,
9250 VALUE exception, VALUE body)
9251 {
9252 #define SYM(s) ID2SYM(rb_intern(#s))
9253 int i, len;
9254 unsigned int arg_size, local_size, stack_max;
9255 ID *tbl;
9256 struct st_table *labels_table = st_init_numtable();
9257 VALUE labels_wrapper = Data_Wrap_Struct(0, rb_mark_set, st_free_table, labels_table);
9258 VALUE arg_opt_labels = rb_hash_aref(params, SYM(opt));
9259 VALUE keywords = rb_hash_aref(params, SYM(keyword));
9260 VALUE sym_arg_rest = ID2SYM(rb_intern("#arg_rest"));
9261 DECL_ANCHOR(anchor);
9262 INIT_ANCHOR(anchor);
9263
9264 len = RARRAY_LENINT(locals);
9265 iseq->body->local_table_size = len;
9266 iseq->body->local_table = tbl = len > 0 ? (ID *)ALLOC_N(ID, iseq->body->local_table_size) : NULL;
9267
9268 for (i = 0; i < len; i++) {
9269 VALUE lv = RARRAY_AREF(locals, i);
9270
9271 if (sym_arg_rest == lv) {
9272 tbl[i] = 0;
9273 }
9274 else {
9275 tbl[i] = FIXNUM_P(lv) ? (ID)FIX2LONG(lv) : SYM2ID(CHECK_SYMBOL(lv));
9276 }
9277 }
9278
9279 #define INT_PARAM(F) int_param(&iseq->body->param.F, params, SYM(F))
9280 if (INT_PARAM(lead_num)) {
9281 iseq->body->param.flags.has_lead = TRUE;
9282 }
9283 if (INT_PARAM(post_num)) iseq->body->param.flags.has_post = TRUE;
9284 if (INT_PARAM(post_start)) iseq->body->param.flags.has_post = TRUE;
9285 if (INT_PARAM(rest_start)) iseq->body->param.flags.has_rest = TRUE;
9286 if (INT_PARAM(block_start)) iseq->body->param.flags.has_block = TRUE;
9287 #undef INT_PARAM
9288 {
9289 #define INT_PARAM(F) F = (int_param(&x, misc, SYM(F)) ? (unsigned int)x : 0)
9290 int x;
9291 INT_PARAM(arg_size);
9292 INT_PARAM(local_size);
9293 INT_PARAM(stack_max);
9294 #undef INT_PARAM
9295 }
9296
9297 if (RB_TYPE_P(arg_opt_labels, T_ARRAY)) {
9298 len = RARRAY_LENINT(arg_opt_labels);
9299 iseq->body->param.flags.has_opt = !!(len - 1 >= 0);
9300
9301 if (iseq->body->param.flags.has_opt) {
9302 VALUE *opt_table = ALLOC_N(VALUE, len);
9303
9304 for (i = 0; i < len; i++) {
9305 VALUE ent = RARRAY_AREF(arg_opt_labels, i);
9306 LABEL *label = register_label(iseq, labels_table, ent);
9307 opt_table[i] = (VALUE)label;
9308 }
9309
9310 iseq->body->param.opt_num = len - 1;
9311 iseq->body->param.opt_table = opt_table;
9312 }
9313 }
9314 else if (!NIL_P(arg_opt_labels)) {
9315 rb_raise(rb_eTypeError, ":opt param is not an array: %+"PRIsVALUE,
9316 arg_opt_labels);
9317 }
9318
9319 if (RB_TYPE_P(keywords, T_ARRAY)) {
9320 iseq->body->param.keyword = iseq_build_kw(iseq, params, keywords);
9321 }
9322 else if (!NIL_P(keywords)) {
9323 rb_raise(rb_eTypeError, ":keywords param is not an array: %+"PRIsVALUE,
9324 keywords);
9325 }
9326
9327 if (Qtrue == rb_hash_aref(params, SYM(ambiguous_param0))) {
9328 iseq->body->param.flags.ambiguous_param0 = TRUE;
9329 }
9330
9331 if (int_param(&i, params, SYM(kwrest))) {
9332 struct rb_iseq_param_keyword *keyword = (struct rb_iseq_param_keyword *)iseq->body->param.keyword;
9333 if (keyword == NULL) {
9334 iseq->body->param.keyword = keyword = ZALLOC(struct rb_iseq_param_keyword);
9335 }
9336 keyword->rest_start = i;
9337 iseq->body->param.flags.has_kwrest = TRUE;
9338 }
9339 #undef SYM
9340 iseq_calc_param_size(iseq);
9341
9342 /* exception */
9343 iseq_build_from_ary_exception(iseq, labels_table, exception);
9344
9345 /* body */
9346 iseq_build_from_ary_body(iseq, anchor, body, labels_wrapper);
9347
9348 iseq->body->param.size = arg_size;
9349 iseq->body->local_table_size = local_size;
9350 iseq->body->stack_max = stack_max;
9351 }
9352
9353 /* for parser */
9354
9355 int
9356 rb_dvar_defined(ID id, const rb_iseq_t *iseq)
9357 {
9358 if (iseq) {
9359 const struct rb_iseq_constant_body *body = iseq->body;
9360 while (body->type == ISEQ_TYPE_BLOCK ||
9361 body->type == ISEQ_TYPE_RESCUE ||
9362 body->type == ISEQ_TYPE_ENSURE ||
9363 body->type == ISEQ_TYPE_EVAL ||
9364 body->type == ISEQ_TYPE_MAIN
9365 ) {
9366 unsigned int i;
9367
9368 for (i = 0; i < body->local_table_size; i++) {
9369 if (body->local_table[i] == id) {
9370 return 1;
9371 }
9372 }
9373 iseq = body->parent_iseq;
9374 body = iseq->body;
9375 }
9376 }
9377 return 0;
9378 }
9379
9380 int
9381 rb_local_defined(ID id, const rb_iseq_t *iseq)
9382 {
9383 if (iseq) {
9384 unsigned int i;
9385 const struct rb_iseq_constant_body *const body = iseq->body->local_iseq->body;
9386
9387 for (i=0; i<body->local_table_size; i++) {
9388 if (body->local_table[i] == id) {
9389 return 1;
9390 }
9391 }
9392 }
9393 return 0;
9394 }
9395
9396 static int
9397 caller_location(VALUE *path, VALUE *realpath)
9398 {
9399 const rb_execution_context_t *ec = GET_EC();
9400 const rb_control_frame_t *const cfp =
9401 rb_vm_get_ruby_level_next_cfp(ec, ec->cfp);
9402
9403 if (cfp) {
9404 int line = rb_vm_get_sourceline(cfp);
9405 *path = rb_iseq_path(cfp->iseq);
9406 *realpath = rb_iseq_realpath(cfp->iseq);
9407 return line;
9408 }
9409 else {
9410 *path = rb_fstring_lit("<compiled>");
9411 *realpath = *path;
9412 return 1;
9413 }
9414 }
9415
9416 typedef struct {
9417 VALUE arg;
9418 rb_insn_func_t func;
9419 int line;
9420 } accessor_args;
9421
9422 static const rb_iseq_t *
9423 method_for_self(VALUE name, VALUE arg, rb_insn_func_t func,
9424 void (*build)(rb_iseq_t *, LINK_ANCHOR *, const void *))
9425 {
9426 VALUE path, realpath;
9427 accessor_args acc;
9428
9429 acc.arg = arg;
9430 acc.func = func;
9431 acc.line = caller_location(&path, &realpath);
9432 struct rb_iseq_new_with_callback_callback_func *ifunc =
9433 rb_iseq_new_with_callback_new_callback(build, &acc);
9434 return rb_iseq_new_with_callback(ifunc,
9435 rb_sym2str(name), path, realpath,
9436 INT2FIX(acc.line), 0, ISEQ_TYPE_METHOD, 0);
9437 }
9438
9439 static void
9440 for_self_aref(rb_iseq_t *iseq, LINK_ANCHOR *ret, const void *a)
9441 {
9442 const accessor_args *const args = (void *)a;
9443 const int line = args->line;
9444 struct rb_iseq_constant_body *const body = iseq->body;
9445
9446 iseq_set_local_table(iseq, 0);
9447 body->param.lead_num = 0;
9448 body->param.size = 0;
9449
9450 ADD_INSN1(ret, line, putobject, args->arg);
9451 ADD_INSN1(ret, line, opt_call_c_function, (VALUE)args->func);
9452 }
9453
9454 static void
9455 for_self_aset(rb_iseq_t *iseq, LINK_ANCHOR *ret, const void *a)
9456 {
9457 const accessor_args *const args = (void *)a;
9458 const int line = args->line;
9459 struct rb_iseq_constant_body *const body = iseq->body;
9460 static const ID vars[] = {1, idUScore};
9461
9462 iseq_set_local_table(iseq, vars);
9463 body->param.lead_num = 1;
9464 body->param.size = 1;
9465
9466 ADD_GETLOCAL(ret, line, numberof(vars)-1, 0);
9467 ADD_INSN1(ret, line, putobject, args->arg);
9468 ADD_INSN1(ret, line, opt_call_c_function, (VALUE)args->func);
9469 ADD_INSN(ret, line, pop);
9470 }
9471
9472 /*
9473 * func (index) -> (value)
9474 */
9475 const rb_iseq_t *
9476 rb_method_for_self_aref(VALUE name, VALUE arg, rb_insn_func_t func)
9477 {
9478 return method_for_self(name, arg, func, for_self_aref);
9479 }
9480
9481 /*
9482 * func (index, value) -> (index, value)
9483 */
9484 const rb_iseq_t *
9485 rb_method_for_self_aset(VALUE name, VALUE arg, rb_insn_func_t func)
9486 {
9487 return method_for_self(name, arg, func, for_self_aset);
9488 }
9489
9490 /* ISeq binary format */
9491
9492 #ifndef IBF_ISEQ_DEBUG
9493 #define IBF_ISEQ_DEBUG 0
9494 #endif
9495
9496 #ifndef IBF_ISEQ_ENABLE_LOCAL_BUFFER
9497 #define IBF_ISEQ_ENABLE_LOCAL_BUFFER 0
9498 #endif
9499
9500 typedef unsigned int ibf_offset_t;
9501 #define IBF_OFFSET(ptr) ((ibf_offset_t)(VALUE)(ptr))
9502
9503 #define IBF_MAJOR_VERSION ISEQ_MAJOR_VERSION
9504 #if RUBY_DEVEL
9505 #define IBF_DEVEL_VERSION 2
9506 #define IBF_MINOR_VERSION (ISEQ_MINOR_VERSION * 10000 + IBF_DEVEL_VERSION)
9507 #else
9508 #define IBF_MINOR_VERSION ISEQ_MINOR_VERSION
9509 #endif
9510
9511 struct ibf_header {
9512 char magic[4]; /* YARB */
9513 unsigned int major_version;
9514 unsigned int minor_version;
9515 unsigned int size;
9516 unsigned int extra_size;
9517
9518 unsigned int iseq_list_size;
9519 unsigned int global_object_list_size;
9520 ibf_offset_t iseq_list_offset;
9521 ibf_offset_t global_object_list_offset;
9522 };
9523
9524 struct ibf_dump_buffer {
9525 VALUE str;
9526 VALUE obj_list; /* [objs] */
9527 };
9528
9529 struct ibf_dump {
9530 VALUE iseq_list; /* [iseqs] */
9531 st_table *iseq_table; /* iseq -> iseq number */
9532 struct ibf_dump_buffer global_buffer;
9533 struct ibf_dump_buffer *current_buffer;
9534 };
9535
9536 rb_iseq_t * iseq_alloc(void);
9537
9538 struct ibf_load_buffer {
9539 const char *buff;
9540 ibf_offset_t size;
9541
9542 VALUE obj_list; /* [obj0, ...] */
9543 unsigned int obj_list_size;
9544 ibf_offset_t obj_list_offset;
9545 };
9546
9547 struct ibf_load {
9548 const struct ibf_header *header;
9549 VALUE iseq_list; /* [iseq0, ...] */
9550 struct ibf_load_buffer global_buffer;
9551 VALUE loader_obj;
9552 rb_iseq_t *iseq;
9553 VALUE str;
9554 struct ibf_load_buffer *current_buffer;
9555 };
9556
9557 static ibf_offset_t
9558 ibf_dump_pos(struct ibf_dump *dump)
9559 {
9560 long pos = RSTRING_LEN(dump->current_buffer->str);
9561 #if SIZEOF_LONG > SIZEOF_INT
9562 if (pos >= UINT_MAX) {
9563 rb_raise(rb_eRuntimeError, "dump size exceeds");
9564 }
9565 #endif
9566 return (unsigned int)pos;
9567 }
9568
9569 static void
9570 ibf_dump_align(struct ibf_dump *dump, size_t align)
9571 {
9572 ibf_offset_t pos = ibf_dump_pos(dump);
9573 if (pos % align) {
9574 static const char padding[sizeof(VALUE)];
9575 size_t size = align - ((size_t)pos % align);
9576 #if SIZEOF_LONG > SIZEOF_INT
9577 if (pos + size >= UINT_MAX) {
9578 rb_raise(rb_eRuntimeError, "dump size exceeds");
9579 }
9580 #endif
9581 for (; size > sizeof(padding); size -= sizeof(padding)) {
9582 rb_str_cat(dump->current_buffer->str, padding, sizeof(padding));
9583 }
9584 rb_str_cat(dump->current_buffer->str, padding, size);
9585 }
9586 }
9587
9588 static ibf_offset_t
9589 ibf_dump_write(struct ibf_dump *dump, const void *buff, unsigned long size)
9590 {
9591 ibf_offset_t pos = ibf_dump_pos(dump);
9592 rb_str_cat(dump->current_buffer->str, (const char *)buff, size);
9593 /* TODO: overflow check */
9594 return pos;
9595 }
9596
9597 static ibf_offset_t
9598 ibf_dump_write_byte(struct ibf_dump *dump, unsigned char byte)
9599 {
9600 return ibf_dump_write(dump, &byte, sizeof(unsigned char));
9601 }
9602
9603 static void
9604 ibf_dump_overwrite(struct ibf_dump *dump, void *buff, unsigned int size, long offset)
9605 {
9606 VALUE str = dump->current_buffer->str;
9607 char *ptr = RSTRING_PTR(str);
9608 if ((unsigned long)(size + offset) > (unsigned long)RSTRING_LEN(str))
9609 rb_bug("ibf_dump_overwrite: overflow");
9610 memcpy(ptr + offset, buff, size);
9611 }
9612
9613 static const void *
9614 ibf_load_ptr(const struct ibf_load *load, ibf_offset_t *offset, int size)
9615 {
9616 ibf_offset_t beg = *offset;
9617 *offset += size;
9618 return load->current_buffer->buff + beg;
9619 }
9620
9621 static void *
9622 ibf_load_alloc(const struct ibf_load *load, ibf_offset_t offset, size_t x, size_t y)
9623 {
9624 void *buff = ruby_xmalloc2(x, y);
9625 size_t size = x * y;
9626 memcpy(buff, load->current_buffer->buff + offset, size);
9627 return buff;
9628 }
9629
9630 #define IBF_W_ALIGN(type) (RUBY_ALIGNOF(type) > 1 ? ibf_dump_align(dump, RUBY_ALIGNOF(type)) : (void)0)
9631
9632 #define IBF_W(b, type, n) (IBF_W_ALIGN(type), (type *)(VALUE)IBF_WP(b, type, n))
9633 #define IBF_WV(variable) ibf_dump_write(dump, &(variable), sizeof(variable))
9634 #define IBF_WP(b, type, n) ibf_dump_write(dump, (b), sizeof(type) * (n))
9635 #define IBF_R(val, type, n) (type *)ibf_load_alloc(load, IBF_OFFSET(val), sizeof(type), (n))
9636 #define IBF_ZERO(variable) memset(&(variable), 0, sizeof(variable))
9637
9638 static int
9639 ibf_table_lookup(struct st_table *table, st_data_t key)
9640 {
9641 st_data_t val;
9642
9643 if (st_lookup(table, key, &val)) {
9644 return (int)val;
9645 }
9646 else {
9647 return -1;
9648 }
9649 }
9650
9651 static int
9652 ibf_table_index(struct st_table *table, st_data_t key)
9653 {
9654 int index = ibf_table_lookup(table, key);
9655
9656 if (index < 0) { /* not found */
9657 index = (int)table->num_entries;
9658 st_insert(table, key, (st_data_t)index);
9659 }
9660
9661 return index;
9662 }
9663
9664 /* dump/load generic */
9665
9666 static void ibf_dump_object_list(struct ibf_dump *dump, ibf_offset_t *obj_list_offset, unsigned int *obj_list_size);
9667
9668 static VALUE ibf_load_object(const struct ibf_load *load, VALUE object_index);
9669 static rb_iseq_t *ibf_load_iseq(const struct ibf_load *load, const rb_iseq_t *index_iseq);
9670
9671 static VALUE
9672 ibf_dump_object_list_new(void)
9673 {
9674 VALUE obj_list = rb_ary_tmp_new(1);
9675 rb_ary_push(obj_list, Qnil); /* 0th is nil */
9676
9677 return obj_list;
9678 }
9679
9680 static VALUE
9681 ibf_dump_object(struct ibf_dump *dump, VALUE obj)
9682 {
9683 VALUE obj_list = dump->current_buffer->obj_list;
9684 long index = RARRAY_LEN(obj_list);
9685 long i;
9686 for (i=0; i<index; i++) {
9687 if (RARRAY_AREF(obj_list, i) == obj) return (VALUE)i; /* dedup */
9688 }
9689 rb_ary_push(obj_list, obj);
9690 return (VALUE)index;
9691 }
9692
9693 static VALUE
9694 ibf_dump_id(struct ibf_dump *dump, ID id)
9695 {
9696 if (id == 0 || rb_id2name(id) == NULL) {
9697 return 0;
9698 }
9699 return ibf_dump_object(dump, rb_id2sym(id));
9700 }
9701
9702 static ID
9703 ibf_load_id(const struct ibf_load *load, const ID id_index)
9704 {
9705 if (id_index == 0) {
9706 return 0;
9707 }
9708 VALUE sym = ibf_load_object(load, id_index);
9709 return rb_sym2id(sym);
9710 }
9711
9712 /* dump/load: code */
9713
9714 static VALUE
9715 ibf_dump_calldata(struct ibf_dump *dump, const struct rb_call_data *cd)
9716 {
9717 return (cd->ci.flag & VM_CALL_KWARG) ? Qtrue : Qfalse;
9718 }
9719
9720 static ibf_offset_t ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq);
9721
9722 static int
9723 ibf_dump_iseq(struct ibf_dump *dump, const rb_iseq_t *iseq)
9724 {
9725 if (iseq == NULL) {
9726 return -1;
9727 }
9728 else {
9729 int iseq_index = ibf_table_lookup(dump->iseq_table, (st_data_t)iseq);
9730 if (iseq_index < 0) {
9731 iseq_index = ibf_table_index(dump->iseq_table, (st_data_t)iseq);
9732 rb_ary_push(dump->iseq_list, (VALUE)iseq);
9733 }
9734 return iseq_index;
9735 }
9736 }
9737
9738 static VALUE
9739 ibf_dump_gentry(struct ibf_dump *dump, const struct rb_global_entry *entry)
9740 {
9741 return (VALUE)ibf_dump_id(dump, entry->id);
9742 }
9743
9744 static VALUE
9745 ibf_load_gentry(const struct ibf_load *load, const struct rb_global_entry *entry)
9746 {
9747 ID gid = ibf_load_id(load, (ID)(VALUE)entry);
9748 return (VALUE)rb_global_entry(gid);
9749 }
9750
9751 static unsigned char
9752 ibf_load_byte(const struct ibf_load *load, ibf_offset_t *offset)
9753 {
9754 if (*offset >= load->current_buffer->size) { rb_raise(rb_eRuntimeError, "invalid bytecode"); }
9755 return (unsigned char)load->current_buffer->buff[(*offset)++];
9756 }
9757
9758 /*
9759 * Small uint serialization
9760 * 0x00000000_00000000 - 0x00000000_0000007f: 1byte | XXXX XXX1 |
9761 * 0x00000000_00000080 - 0x00000000_00003fff: 2byte | XXXX XX10 | XXXX XXXX |
9762 * 0x00000000_00004000 - 0x00000000_001fffff: 3byte | XXXX X100 | XXXX XXXX | XXXX XXXX |
9763 * 0x00000000_00020000 - 0x00000000_0fffffff: 4byte | XXXX 1000 | XXXX XXXX | XXXX XXXX | XXXX XXXX |
9764 * ...
9765 * 0x00010000_00000000 - 0x00ffffff_ffffffff: 8byte | 1000 0000 | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX |
9766 * 0x01000000_00000000 - 0xffffffff_ffffffff: 9byte | 0000 0000 | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX |
9767 */
9768 static void
9769 ibf_dump_write_small_value(struct ibf_dump *dump, VALUE x)
9770 {
9771 if (sizeof(VALUE) > 8 || CHAR_BIT != 8) {
9772 ibf_dump_write(dump, &x, sizeof(VALUE));
9773 }
9774
9775 enum { max_byte_length = sizeof(VALUE) + 1 };
9776
9777 unsigned char bytes[max_byte_length];
9778 ibf_offset_t n;
9779
9780 for (n = 0; n < sizeof(VALUE) && (x >> (7 - n)); n++, x >>= 8) {
9781 bytes[max_byte_length - 1 - n] = (unsigned char)x;
9782 }
9783
9784 x <<= 1;
9785 x |= 1;
9786 x <<= n;
9787 bytes[max_byte_length - 1 - n] = (unsigned char)x;
9788 n++;
9789
9790 ibf_dump_write(dump, bytes + max_byte_length - n, n);
9791 }
9792
9793 static VALUE
9794 ibf_load_small_value(const struct ibf_load *load, ibf_offset_t *offset)
9795 {
9796 if (sizeof(VALUE) > 8 || CHAR_BIT != 8) {
9797 union { char s[sizeof(VALUE)]; VALUE v; } x;
9798
9799 memcpy(x.s, load->current_buffer->buff + *offset, sizeof(VALUE));
9800 *offset += sizeof(VALUE);
9801
9802 return x.v;
9803 }
9804
9805 enum { max_byte_length = sizeof(VALUE) + 1 };
9806
9807 const unsigned char *buffer = (const unsigned char *)load->current_buffer->buff;
9808 const unsigned char c = buffer[*offset];
9809
9810 ibf_offset_t n =
9811 c & 1 ? 1 :
9812 c == 0 ? 9 : ntz_int32(c) + 1;
9813 VALUE x = (VALUE)c >> n;
9814
9815 if (*offset + n > load->current_buffer->size) {
9816 rb_raise(rb_eRuntimeError, "invalid byte sequence");
9817 }
9818
9819 ibf_offset_t i;
9820 for (i = 1; i < n; i++) {
9821 x <<= 8;
9822 x |= (VALUE)buffer[*offset + i];
9823 }
9824
9825 *offset += n;
9826 return x;
9827 }
9828
9829 static void
9830 ibf_dump_builtin(struct ibf_dump *dump, const struct rb_builtin_function *bf)
9831 {
9832 // short: index
9833 // short: name.length
9834 // bytes: name
9835 // // omit argc (only verify with name)
9836 ibf_dump_write_small_value(dump, (VALUE)bf->index);
9837
9838 size_t len = strlen(bf->name);
9839 ibf_dump_write_small_value(dump, (VALUE)len);
9840 ibf_dump_write(dump, bf->name, len);
9841 }
9842
9843 static const struct rb_builtin_function *
9844 ibf_load_builtin(const struct ibf_load *load, ibf_offset_t *offset)
9845 {
9846 int i = (int)ibf_load_small_value(load, offset);
9847 int len = (int)ibf_load_small_value(load, offset);
9848 const char *name = (char *)ibf_load_ptr(load, offset, len);
9849
9850 if (0) {
9851 for (int i=0; i<len; i++) fprintf(stderr, "%c", name[i]);
9852 fprintf(stderr, "!!\n");
9853 }
9854
9855 const struct rb_builtin_function *table = GET_VM()->builtin_function_table;
9856 if (table == NULL) rb_bug("%s: table is not provided.", RUBY_FUNCTION_NAME_STRING);
9857 if (strncmp(table[i].name, name, len) != 0) {
9858 rb_bug("%s: index (%d) mismatch (expect %s but %s).", RUBY_FUNCTION_NAME_STRING, i, name, table[i].name);
9859 }
9860 // fprintf(stderr, "load-builtin: name:%s(%d)\n", table[i].name, table[i].argc);
9861
9862 return &table[i];
9863 }
9864
9865 static ibf_offset_t
9866 ibf_dump_code(struct ibf_dump *dump, const rb_iseq_t *iseq)
9867 {
9868 const struct rb_iseq_constant_body *const body = iseq->body;
9869 const int iseq_size = body->iseq_size;
9870 int code_index;
9871 const VALUE *orig_code = rb_iseq_original_iseq(iseq);
9872
9873 ibf_offset_t offset = ibf_dump_pos(dump);
9874
9875 for (code_index=0; code_index<iseq_size;) {
9876 const VALUE insn = orig_code[code_index++];
9877 const char *types = insn_op_types(insn);
9878 int op_index;
9879
9880 /* opcode */
9881 if (insn >= 0x100) { rb_raise(rb_eRuntimeError, "invalid instruction"); }
9882 ibf_dump_write_small_value(dump, insn);
9883
9884 /* operands */
9885 for (op_index=0; types[op_index]; op_index++, code_index++) {
9886 VALUE op = orig_code[code_index];
9887 VALUE wv;
9888
9889 switch (types[op_index]) {
9890 case TS_CDHASH:
9891 case TS_VALUE:
9892 wv = ibf_dump_object(dump, op);
9893 break;
9894 case TS_ISEQ:
9895 wv = (VALUE)ibf_dump_iseq(dump, (const rb_iseq_t *)op);
9896 break;
9897 case TS_IC:
9898 case TS_IVC:
9899 case TS_ISE:
9900 {
9901 unsigned int i;
9902 for (i=0; i<body->is_size; i++) {
9903 if (op == (VALUE)&body->is_entries[i]) {
9904 break;
9905 }
9906 }
9907 wv = (VALUE)i;
9908 }
9909 break;
9910 case TS_CALLDATA:
9911 {
9912 /* ibf_dump_calldata() always returns either Qtrue or Qfalse */
9913 char c = ibf_dump_calldata(dump, (const struct rb_call_data *)op) == Qtrue; // 1 or 0
9914 ibf_dump_write_byte(dump, c);
9915 goto skip_wv;
9916 }
9917 case TS_ID:
9918 wv = ibf_dump_id(dump, (ID)op);
9919 break;
9920 case TS_GENTRY:
9921 wv = ibf_dump_gentry(dump, (const struct rb_global_entry *)op);
9922 break;
9923 case TS_FUNCPTR:
9924 rb_raise(rb_eRuntimeError, "TS_FUNCPTR is not supported");
9925 goto skip_wv;
9926 case TS_BUILTIN:
9927 ibf_dump_builtin(dump, (const struct rb_builtin_function *)op);
9928 goto skip_wv;
9929 default:
9930 wv = op;
9931 break;
9932 }
9933 ibf_dump_write_small_value(dump, wv);
9934 skip_wv:;
9935 }
9936 assert(insn_len(insn) == op_index+1);
9937 }
9938
9939 return offset;
9940 }
9941
9942 static VALUE *
9943 ibf_load_code(const struct ibf_load *load, const rb_iseq_t *iseq, ibf_offset_t bytecode_offset, ibf_offset_t bytecode_size, unsigned int iseq_size)
9944 {
9945 unsigned int code_index;
9946 ibf_offset_t reading_pos = bytecode_offset;
9947 VALUE *code = ALLOC_N(VALUE, iseq_size);
9948
9949 struct rb_iseq_constant_body *load_body = iseq->body;
9950 struct rb_call_data *cd_entries = load_body->call_data;
9951 struct rb_kwarg_call_data *cd_kw_entries = (struct rb_kwarg_call_data *)&load_body->call_data[load_body->ci_size];
9952 union iseq_inline_storage_entry *is_entries = load_body->is_entries;
9953
9954 for (code_index=0; code_index<iseq_size;) {
9955 /* opcode */
9956 const VALUE insn = code[code_index++] = ibf_load_small_value(load, &reading_pos);
9957 const char *types = insn_op_types(insn);
9958 int op_index;
9959
9960 /* operands */
9961 for (op_index=0; types[op_index]; op_index++, code_index++) {
9962 switch (types[op_index]) {
9963 case TS_CDHASH:
9964 case TS_VALUE:
9965 {
9966 VALUE op = ibf_load_small_value(load, &reading_pos);
9967 VALUE v = ibf_load_object(load, op);
9968 code[code_index] = v;
9969 if (!SPECIAL_CONST_P(v)) {
9970 RB_OBJ_WRITTEN(iseq, Qundef, v);
9971 FL_SET(iseq, ISEQ_MARKABLE_ISEQ);
9972 }
9973 break;
9974 }
9975 case TS_ISEQ:
9976 {
9977 VALUE op = (VALUE)ibf_load_small_value(load, &reading_pos);
9978 VALUE v = (VALUE)ibf_load_iseq(load, (const rb_iseq_t *)op);
9979 code[code_index] = v;
9980 if (!SPECIAL_CONST_P(v)) {
9981 RB_OBJ_WRITTEN(iseq, Qundef, v);
9982 FL_SET(iseq, ISEQ_MARKABLE_ISEQ);
9983 }
9984 break;
9985 }
9986 case TS_ISE:
9987 FL_SET(iseq, ISEQ_MARKABLE_ISEQ);
9988 /* fall through */
9989 case TS_IC:
9990 case TS_IVC:
9991 {
9992 VALUE op = ibf_load_small_value(load, &reading_pos);
9993 code[code_index] = (VALUE)&is_entries[op];
9994 }
9995 break;
9996 case TS_CALLDATA:
9997 {
9998 unsigned char op = ibf_load_byte(load, &reading_pos);
9999 code[code_index] = op ? (VALUE)cd_kw_entries++ : (VALUE)cd_entries++; /* op is 1 (kw) or 0 (!kw) */
10000 }
10001 break;
10002 case TS_ID:
10003 {
10004 VALUE op = ibf_load_small_value(load, &reading_pos);
10005 code[code_index] = ibf_load_id(load, (ID)(VALUE)op);
10006 }
10007 break;
10008 case TS_GENTRY:
10009 {
10010 VALUE op = ibf_load_small_value(load, &reading_pos);
10011 code[code_index] = ibf_load_gentry(load, (const struct rb_global_entry *)(VALUE)op);
10012 }
10013 break;
10014 case TS_FUNCPTR:
10015 rb_raise(rb_eRuntimeError, "TS_FUNCPTR is not supported");
10016 break;
10017 case TS_BUILTIN:
10018 code[code_index] = (VALUE)ibf_load_builtin(load, &reading_pos);
10019 break;
10020 default:
10021 code[code_index] = ibf_load_small_value(load, &reading_pos);
10022 continue;
10023 }
10024 }
10025 if (insn_len(insn) != op_index+1) {
10026 rb_raise(rb_eRuntimeError, "operand size mismatch");
10027 }
10028 }
10029 load_body->iseq_encoded = code;
10030 load_body->iseq_size = code_index;
10031
10032 assert(code_index == iseq_size);
10033 assert(reading_pos == bytecode_offset + bytecode_size);
10034 return code;
10035 }
10036
10037 static ibf_offset_t
10038 ibf_dump_param_opt_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
10039 {
10040 int opt_num = iseq->body->param.opt_num;
10041
10042 if (opt_num > 0) {
10043 IBF_W_ALIGN(VALUE);
10044 return ibf_dump_write(dump, iseq->body->param.opt_table, sizeof(VALUE) * (opt_num + 1));
10045 }
10046 else {
10047 return ibf_dump_pos(dump);
10048 }
10049 }
10050
10051 static VALUE *
10052 ibf_load_param_opt_table(const struct ibf_load *load, ibf_offset_t opt_table_offset, int opt_num)
10053 {
10054 if (opt_num > 0) {
10055 VALUE *table = ALLOC_N(VALUE, opt_num+1);
10056 MEMCPY(table, load->current_buffer->buff + opt_table_offset, VALUE, opt_num+1);
10057 return table;
10058 }
10059 else {
10060 return NULL;
10061 }
10062 }
10063
10064 static ibf_offset_t
10065 ibf_dump_param_keyword(struct ibf_dump *dump, const rb_iseq_t *iseq)
10066 {
10067 const struct rb_iseq_param_keyword *kw = iseq->body->param.keyword;
10068
10069 if (kw) {
10070 struct rb_iseq_param_keyword dump_kw = *kw;
10071 int dv_num = kw->num - kw->required_num;
10072 ID *ids = kw->num > 0 ? ALLOCA_N(ID, kw->num) : NULL;
10073 VALUE *dvs = dv_num > 0 ? ALLOCA_N(VALUE, dv_num) : NULL;
10074 int i;
10075
10076 for (i=0; i<kw->num; i++) ids[i] = (ID)ibf_dump_id(dump, kw->table[i]);
10077 for (i=0; i<dv_num; i++) dvs[i] = (VALUE)ibf_dump_object(dump, kw->default_values[i]);
10078
10079 dump_kw.table = IBF_W(ids, ID, kw->num);
10080 dump_kw.default_values = IBF_W(dvs, VALUE, dv_num);
10081 IBF_W_ALIGN(struct rb_iseq_param_keyword);
10082 return ibf_dump_write(dump, &dump_kw, sizeof(struct rb_iseq_param_keyword) * 1);
10083 }
10084 else {
10085 return 0;
10086 }
10087 }
10088
10089 static const struct rb_iseq_param_keyword *
10090 ibf_load_param_keyword(const struct ibf_load *load, ibf_offset_t param_keyword_offset)
10091 {
10092 if (param_keyword_offset) {
10093 struct rb_iseq_param_keyword *kw = IBF_R(param_keyword_offset, struct rb_iseq_param_keyword, 1);
10094 ID *ids = IBF_R(kw->table, ID, kw->num);
10095 int dv_num = kw->num - kw->required_num;
10096 VALUE *dvs = IBF_R(kw->default_values, VALUE, dv_num);
10097 int i;
10098
10099 for (i=0; i<kw->num; i++) {
10100 ids[i] = ibf_load_id(load, ids[i]);
10101 }
10102 for (i=0; i<dv_num; i++) {
10103 dvs[i] = ibf_load_object(load, dvs[i]);
10104 }
10105
10106 kw->table = ids;
10107 kw->default_values = dvs;
10108 return kw;
10109 }
10110 else {
10111 return NULL;
10112 }
10113 }
10114
10115 static ibf_offset_t
10116 ibf_dump_insns_info_body(struct ibf_dump *dump, const rb_iseq_t *iseq)
10117 {
10118 ibf_offset_t offset = ibf_dump_pos(dump);
10119 const struct iseq_insn_info_entry *entries = iseq->body->insns_info.body;
10120
10121 unsigned int i;
10122 for (i = 0; i < iseq->body->insns_info.size; i++) {
10123 ibf_dump_write_small_value(dump, entries[i].line_no);
10124 ibf_dump_write_small_value(dump, entries[i].events);
10125 }
10126
10127 return offset;
10128 }
10129
10130 static struct iseq_insn_info_entry *
10131 ibf_load_insns_info_body(const struct ibf_load *load, ibf_offset_t body_offset, unsigned int size)
10132 {
10133 ibf_offset_t reading_pos = body_offset;
10134 struct iseq_insn_info_entry *entries = ALLOC_N(struct iseq_insn_info_entry, size);
10135
10136 unsigned int i;
10137 for (i = 0; i < size; i++) {
10138 entries[i].line_no = (int)ibf_load_small_value(load, &reading_pos);
10139 entries[i].events = (rb_event_flag_t)ibf_load_small_value(load, &reading_pos);
10140 }
10141
10142 return entries;
10143 }
10144
10145 static ibf_offset_t
10146 ibf_dump_insns_info_positions(struct ibf_dump *dump, const unsigned int *positions, unsigned int size)
10147 {
10148 ibf_offset_t offset = ibf_dump_pos(dump);
10149
10150 unsigned int last = 0;
10151 unsigned int i;
10152 for (i = 0; i < size; i++) {
10153 ibf_dump_write_small_value(dump, positions[i] - last);
10154 last = positions[i];
10155 }
10156
10157 return offset;
10158 }
10159
10160 static unsigned int *
10161 ibf_load_insns_info_positions(const struct ibf_load *load, ibf_offset_t positions_offset, unsigned int size)
10162 {
10163 ibf_offset_t reading_pos = positions_offset;
10164 unsigned int *positions = ALLOC_N(unsigned int, size);
10165
10166 unsigned int last = 0;
10167 unsigned int i;
10168 for (i = 0; i < size; i++) {
10169 positions[i] = last + (unsigned int)ibf_load_small_value(load, &reading_pos);
10170 last = positions[i];
10171 }
10172
10173 return positions;
10174 }
10175
10176 static ibf_offset_t
10177 ibf_dump_local_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
10178 {
10179 const struct rb_iseq_constant_body *const body = iseq->body;
10180 const int size = body->local_table_size;
10181 ID *table = ALLOCA_N(ID, size);
10182 int i;
10183
10184 for (i=0; i<size; i++) {
10185 table[i] = ibf_dump_id(dump, body->local_table[i]);
10186 }
10187
10188 IBF_W_ALIGN(ID);
10189 return ibf_dump_write(dump, table, sizeof(ID) * size);
10190 }
10191
10192 static ID *
10193 ibf_load_local_table(const struct ibf_load *load, ibf_offset_t local_table_offset, int size)
10194 {
10195 if (size > 0) {
10196 ID *table = IBF_R(local_table_offset, ID, size);
10197 int i;
10198
10199 for (i=0; i<size; i++) {
10200 table[i] = ibf_load_id(load, table[i]);
10201 }
10202 return table;
10203 }
10204 else {
10205 return NULL;
10206 }
10207 }
10208
10209 static ibf_offset_t
10210 ibf_dump_catch_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
10211 {
10212 const struct iseq_catch_table *table = iseq->body->catch_table;
10213
10214 if (table) {
10215 int *iseq_indices = ALLOCA_N(int, table->size);
10216 unsigned int i;
10217
10218 for (i=0; i<table->size; i++) {
10219 iseq_indices[i] = ibf_dump_iseq(dump, table->entries[i].iseq);
10220 }
10221
10222 const ibf_offset_t offset = ibf_dump_pos(dump);
10223
10224 for (i=0; i<table->size; i++) {
10225 ibf_dump_write_small_value(dump, iseq_indices[i]);
10226 ibf_dump_write_small_value(dump, table->entries[i].type);
10227 ibf_dump_write_small_value(dump, table->entries[i].start);
10228 ibf_dump_write_small_value(dump, table->entries[i].end);
10229 ibf_dump_write_small_value(dump, table->entries[i].cont);
10230 ibf_dump_write_small_value(dump, table->entries[i].sp);
10231 }
10232 return offset;
10233 }
10234 else {
10235 return ibf_dump_pos(dump);
10236 }
10237 }
10238
10239 static struct iseq_catch_table *
10240 ibf_load_catch_table(const struct ibf_load *load, ibf_offset_t catch_table_offset, unsigned int size)
10241 {
10242 if (size) {
10243 struct iseq_catch_table *table = ruby_xmalloc(iseq_catch_table_bytes(size));
10244 table->size = size;
10245
10246 ibf_offset_t reading_pos = catch_table_offset;
10247
10248 unsigned int i;
10249 for (i=0; i<table->size; i++) {
10250 int iseq_index = (int)ibf_load_small_value(load, &reading_pos);
10251 table->entries[i].type = (enum catch_type)ibf_load_small_value(load, &reading_pos);
10252 table->entries[i].start = (unsigned int)ibf_load_small_value(load, &reading_pos);
10253 table->entries[i].end = (unsigned int)ibf_load_small_value(load, &reading_pos);
10254 table->entries[i].cont = (unsigned int)ibf_load_small_value(load, &reading_pos);
10255 table->entries[i].sp = (unsigned int)ibf_load_small_value(load, &reading_pos);
10256
10257 table->entries[i].iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)iseq_index);
10258 }
10259 return table;
10260 }
10261 else {
10262 return NULL;
10263 }
10264 }
10265
10266 static ibf_offset_t
10267 ibf_dump_ci_entries(struct ibf_dump *dump, const rb_iseq_t *iseq)
10268 {
10269 const struct rb_iseq_constant_body *const body = iseq->body;
10270 const unsigned int ci_size = body->ci_size;
10271 const unsigned int ci_kw_size = body->ci_kw_size;
10272 const struct rb_call_data *calls = body->call_data;
10273 const struct rb_kwarg_call_data *kw_calls = (const struct rb_kwarg_call_data *)&body->call_data[ci_size];
10274
10275 ibf_offset_t offset = ibf_dump_pos(dump);
10276
10277 unsigned int i;
10278
10279 for (i = 0; i < ci_size; i++) {
10280 VALUE mid = ibf_dump_id(dump, calls[i].ci.mid);
10281
10282 ibf_dump_write_small_value(dump, mid);
10283 ibf_dump_write_small_value(dump, calls[i].ci.flag);
10284 ibf_dump_write_small_value(dump, calls[i].ci.orig_argc);
10285 }
10286
10287 for (i = 0; i < ci_kw_size; i++) {
10288 const struct rb_call_info_kw_arg *kw_arg = kw_calls[i].ci_kw.kw_arg;
10289
10290 VALUE mid = ibf_dump_id(dump, kw_calls[i].ci_kw.ci.mid);
10291
10292 ibf_dump_write_small_value(dump, mid);
10293 ibf_dump_write_small_value(dump, kw_calls[i].ci_kw.ci.flag);
10294 ibf_dump_write_small_value(dump, kw_calls[i].ci_kw.ci.orig_argc);
10295
10296 ibf_dump_write_small_value(dump, kw_arg->keyword_len);
10297
10298 int j;
10299 for (j = 0; j < kw_calls[i].ci_kw.kw_arg->keyword_len; j++) {
10300 VALUE keyword = ibf_dump_object(dump, kw_arg->keywords[j]); /* kw_arg->keywords[n] is Symbol */
10301
10302 ibf_dump_write_small_value(dump, keyword);
10303 }
10304 }
10305
10306 return offset;
10307 }
10308
10309 /* note that we dump out rb_call_info but load back rb_call_data */
10310 static struct rb_call_data *
10311 ibf_load_ci_entries(const struct ibf_load *load,
10312 ibf_offset_t ci_entries_offset,
10313 unsigned int ci_size,
10314 unsigned int ci_kw_size)
10315 {
10316 ibf_offset_t reading_pos = ci_entries_offset;
10317
10318 unsigned int i;
10319
10320 struct rb_call_data *calls =
10321 rb_xcalloc_mul_add_mul(
10322 sizeof(struct rb_call_data), ci_size,
10323 sizeof(struct rb_kwarg_call_data), ci_kw_size);
10324 struct rb_kwarg_call_data *kw_calls = (struct rb_kwarg_call_data *)&calls[ci_size];
10325
10326 for (i = 0; i < ci_size; i++) {
10327 VALUE mid_index = ibf_load_small_value(load, &reading_pos);
10328
10329 calls[i].ci.mid = ibf_load_id(load, mid_index);
10330 calls[i].ci.flag = (unsigned int)ibf_load_small_value(load, &reading_pos);
10331 calls[i].ci.orig_argc = (int)ibf_load_small_value(load, &reading_pos);
10332 }
10333
10334 for (i = 0; i < ci_kw_size; i++) {
10335 VALUE mid_index = ibf_load_small_value(load, &reading_pos);
10336
10337 kw_calls[i].ci_kw.ci.mid = ibf_load_id(load, mid_index);
10338 kw_calls[i].ci_kw.ci.flag = (unsigned int)ibf_load_small_value(load, &reading_pos);
10339 kw_calls[i].ci_kw.ci.orig_argc = (int)ibf_load_small_value(load, &reading_pos);
10340
10341 int keyword_len = (int)ibf_load_small_value(load, &reading_pos);
10342
10343 kw_calls[i].ci_kw.kw_arg =
10344 rb_xmalloc_mul_add(keyword_len - 1, sizeof(VALUE), sizeof(struct rb_call_info_kw_arg));
10345
10346 kw_calls[i].ci_kw.kw_arg->keyword_len = keyword_len;
10347
10348 int j;
10349 for (j = 0; j < kw_calls[i].ci_kw.kw_arg->keyword_len; j++) {
10350 VALUE keyword = ibf_load_small_value(load, &reading_pos);
10351
10352 kw_calls[i].ci_kw.kw_arg->keywords[j] = ibf_load_object(load, keyword);
10353 }
10354 }
10355
10356 return calls;
10357 }
10358
10359 static ibf_offset_t
10360 ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq)
10361 {
10362 assert(dump->current_buffer == &dump->global_buffer);
10363
10364 unsigned int *positions;
10365
10366 const struct rb_iseq_constant_body *body = iseq->body;
10367
10368 const VALUE location_pathobj_index = ibf_dump_object(dump, body->location.pathobj); /* TODO: freeze */
10369 const VALUE location_base_label_index = ibf_dump_object(dump, body->location.base_label);
10370 const VALUE location_label_index = ibf_dump_object(dump, body->location.label);
10371
10372 #if IBF_ISEQ_ENABLE_LOCAL_BUFFER
10373 ibf_offset_t iseq_start = ibf_dump_pos(dump);
10374
10375 struct ibf_dump_buffer *saved_buffer = dump->current_buffer;
10376 struct ibf_dump_buffer buffer;
10377 buffer.str = rb_str_new(0, 0);
10378 buffer.obj_list = ibf_dump_object_list_new();
10379 dump->current_buffer = &buffer;
10380 #endif
10381
10382 const ibf_offset_t bytecode_offset = ibf_dump_code(dump, iseq);
10383 const ibf_offset_t bytecode_size = ibf_dump_pos(dump) - bytecode_offset;
10384 const ibf_offset_t param_opt_table_offset = ibf_dump_param_opt_table(dump, iseq);
10385 const ibf_offset_t param_keyword_offset = ibf_dump_param_keyword(dump, iseq);
10386 const ibf_offset_t insns_info_body_offset = ibf_dump_insns_info_body(dump, iseq);
10387
10388 positions = rb_iseq_insns_info_decode_positions(iseq->body);
10389 const ibf_offset_t insns_info_positions_offset = ibf_dump_insns_info_positions(dump, positions, body->insns_info.size);
10390 ruby_xfree(positions);
10391
10392 const ibf_offset_t local_table_offset = ibf_dump_local_table(dump, iseq);
10393 const unsigned int catch_table_size = body->catch_table ? body->catch_table->size : 0;
10394 const ibf_offset_t catch_table_offset = ibf_dump_catch_table(dump, iseq);
10395 const int parent_iseq_index = ibf_dump_iseq(dump, iseq->body->parent_iseq);
10396 const int local_iseq_index = ibf_dump_iseq(dump, iseq->body->local_iseq);
10397 const ibf_offset_t ci_entries_offset = ibf_dump_ci_entries(dump, iseq);
10398
10399 #if IBF_ISEQ_ENABLE_LOCAL_BUFFER
10400 ibf_offset_t local_obj_list_offset;
10401 unsigned int local_obj_list_size;
10402
10403 ibf_dump_object_list(dump, &local_obj_list_offset, &local_obj_list_size);
10404 #endif
10405
10406 ibf_offset_t body_offset = ibf_dump_pos(dump);
10407
10408 /* dump the constant body */
10409 unsigned int param_flags =
10410 (body->param.flags.has_lead << 0) |
10411 (body->param.flags.has_opt << 1) |
10412 (body->param.flags.has_rest << 2) |
10413 (body->param.flags.has_post << 3) |
10414 (body->param.flags.has_kw << 4) |
10415 (body->param.flags.has_kwrest << 5) |
10416 (body->param.flags.has_block << 6) |
10417 (body->param.flags.ambiguous_param0 << 7) |
10418 (body->param.flags.accepts_no_kwarg << 8) |
10419 (body->param.flags.ruby2_keywords << 9);
10420
10421 #if IBF_ISEQ_ENABLE_LOCAL_BUFFER
10422 # define IBF_BODY_OFFSET(x) (x)
10423 #else
10424 # define IBF_BODY_OFFSET(x) (body_offset - (x))
10425 #endif
10426
10427 ibf_dump_write_small_value(dump, body->type);
10428 ibf_dump_write_small_value(dump, body->iseq_size);
10429 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(bytecode_offset));
10430 ibf_dump_write_small_value(dump, bytecode_size);
10431 ibf_dump_write_small_value(dump, param_flags);
10432 ibf_dump_write_small_value(dump, body->param.size);
10433 ibf_dump_write_small_value(dump, body->param.lead_num);
10434 ibf_dump_write_small_value(dump, body->param.opt_num);
10435 ibf_dump_write_small_value(dump, body->param.rest_start);
10436 ibf_dump_write_small_value(dump, body->param.post_start);
10437 ibf_dump_write_small_value(dump, body->param.post_num);
10438 ibf_dump_write_small_value(dump, body->param.block_start);
10439 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(param_opt_table_offset));
10440 ibf_dump_write_small_value(dump, param_keyword_offset);
10441 ibf_dump_write_small_value(dump, location_pathobj_index);
10442 ibf_dump_write_small_value(dump, location_base_label_index);
10443 ibf_dump_write_small_value(dump, location_label_index);
10444 ibf_dump_write_small_value(dump, body->location.first_lineno);
10445 ibf_dump_write_small_value(dump, body->location.node_id);
10446 ibf_dump_write_small_value(dump, body->location.code_location.beg_pos.lineno);
10447 ibf_dump_write_small_value(dump, body->location.code_location.beg_pos.column);
10448 ibf_dump_write_small_value(dump, body->location.code_location.end_pos.lineno);
10449 ibf_dump_write_small_value(dump, body->location.code_location.end_pos.column);
10450 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(insns_info_body_offset));
10451 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(insns_info_positions_offset));
10452 ibf_dump_write_small_value(dump, body->insns_info.size);
10453 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(local_table_offset));
10454 ibf_dump_write_small_value(dump, catch_table_size);
10455 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(catch_table_offset));
10456 ibf_dump_write_small_value(dump, parent_iseq_index);
10457 ibf_dump_write_small_value(dump, local_iseq_index);
10458 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(ci_entries_offset));
10459 ibf_dump_write_small_value(dump, body->variable.flip_count);
10460 ibf_dump_write_small_value(dump, body->local_table_size);
10461 ibf_dump_write_small_value(dump, body->is_size);
10462 ibf_dump_write_small_value(dump, body->ci_size);
10463 ibf_dump_write_small_value(dump, body->ci_kw_size);
10464 ibf_dump_write_small_value(dump, body->stack_max);
10465 ibf_dump_write_small_value(dump, body->catch_except_p);
10466
10467 #undef IBF_BODY_OFFSET
10468
10469 #if IBF_ISEQ_ENABLE_LOCAL_BUFFER
10470 ibf_offset_t iseq_length_bytes = ibf_dump_pos(dump);
10471
10472 dump->current_buffer = saved_buffer;
10473 ibf_dump_write(dump, RSTRING_PTR(buffer.str), iseq_length_bytes);
10474
10475 ibf_offset_t offset = ibf_dump_pos(dump);
10476 ibf_dump_write_small_value(dump, iseq_start);
10477 ibf_dump_write_small_value(dump, iseq_length_bytes);
10478 ibf_dump_write_small_value(dump, body_offset);
10479
10480 ibf_dump_write_small_value(dump, local_obj_list_offset);
10481 ibf_dump_write_small_value(dump, local_obj_list_size);
10482
10483 return offset;
10484 #else
10485 return body_offset;
10486 #endif
10487 }
10488
10489 static VALUE
10490 ibf_load_location_str(const struct ibf_load *load, VALUE str_index)
10491 {
10492 VALUE str = ibf_load_object(load, str_index);
10493 if (str != Qnil) {
10494 str = rb_fstring(str);
10495 }
10496 return str;
10497 }
10498
10499 static void
10500 ibf_load_iseq_each(struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t offset)
10501 {
10502 struct rb_iseq_constant_body *load_body = iseq->body = rb_iseq_constant_body_alloc();
10503
10504 ibf_offset_t reading_pos = offset;
10505
10506 #if IBF_ISEQ_ENABLE_LOCAL_BUFFER
10507 struct ibf_load_buffer *saved_buffer = load->current_buffer;
10508 load->current_buffer = &load->global_buffer;
10509
10510 const ibf_offset_t iseq_start = ibf_load_small_value(load, &reading_pos);
10511 const ibf_offset_t iseq_length_bytes = ibf_load_small_value(load, &reading_pos);
10512 const ibf_offset_t body_offset = ibf_load_small_value(load, &reading_pos);
10513
10514 struct ibf_load_buffer buffer;
10515 buffer.buff = load->global_buffer.buff + iseq_start;
10516 buffer.size = iseq_length_bytes;
10517 buffer.obj_list_offset = ibf_load_small_value(load, &reading_pos);
10518 buffer.obj_list_size = ibf_load_small_value(load, &reading_pos);
10519 buffer.obj_list = rb_ary_tmp_new(buffer.obj_list_size);
10520 rb_ary_resize(buffer.obj_list, buffer.obj_list_size);
10521
10522 load->current_buffer = &buffer;
10523 reading_pos = body_offset;
10524 #endif
10525
10526 #if IBF_ISEQ_ENABLE_LOCAL_BUFFER
10527 # define IBF_BODY_OFFSET(x) (x)
10528 #else
10529 # define IBF_BODY_OFFSET(x) (offset - (x))
10530 #endif
10531
10532 const unsigned int type = (unsigned int)ibf_load_small_value(load, &reading_pos);
10533 const unsigned int iseq_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
10534 const ibf_offset_t bytecode_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
10535 const ibf_offset_t bytecode_size = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
10536 const unsigned int param_flags = (unsigned int)ibf_load_small_value(load, &reading_pos);
10537 const unsigned int param_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
10538 const int param_lead_num = (int)ibf_load_small_value(load, &reading_pos);
10539 const int param_opt_num = (int)ibf_load_small_value(load, &reading_pos);
10540 const int param_rest_start = (int)ibf_load_small_value(load, &reading_pos);
10541 const int param_post_start = (int)ibf_load_small_value(load, &reading_pos);
10542 const int param_post_num = (int)ibf_load_small_value(load, &reading_pos);
10543 const int param_block_start = (int)ibf_load_small_value(load, &reading_pos);
10544 const ibf_offset_t param_opt_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
10545 const ibf_offset_t param_keyword_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
10546 const VALUE location_pathobj_index = ibf_load_small_value(load, &reading_pos);
10547 const VALUE location_base_label_index = ibf_load_small_value(load, &reading_pos);
10548 const VALUE location_label_index = ibf_load_small_value(load, &reading_pos);
10549 const VALUE location_first_lineno = ibf_load_small_value(load, &reading_pos);
10550 const int location_node_id = (int)ibf_load_small_value(load, &reading_pos);
10551 const int location_code_location_beg_pos_lineno = (int)ibf_load_small_value(load, &reading_pos);
10552 const int location_code_location_beg_pos_column = (int)ibf_load_small_value(load, &reading_pos);
10553 const int location_code_location_end_pos_lineno = (int)ibf_load_small_value(load, &reading_pos);
10554 const int location_code_location_end_pos_column = (int)ibf_load_small_value(load, &reading_pos);
10555 const ibf_offset_t insns_info_body_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
10556 const ibf_offset_t insns_info_positions_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
10557 const unsigned int insns_info_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
10558 const ibf_offset_t local_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
10559 const unsigned int catch_table_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
10560 const ibf_offset_t catch_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
10561 const int parent_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
10562 const int local_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
10563 const ibf_offset_t ci_entries_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
10564 const rb_snum_t variable_flip_count = (rb_snum_t)ibf_load_small_value(load, &reading_pos);
10565 const unsigned int local_table_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
10566 const unsigned int is_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
10567 const unsigned int ci_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
10568 const unsigned int ci_kw_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
10569 const unsigned int stack_max = (unsigned int)ibf_load_small_value(load, &reading_pos);
10570 const char catch_except_p = (char)ibf_load_small_value(load, &reading_pos);
10571
10572 #undef IBF_BODY_OFFSET
10573
10574 load_body->type = type;
10575 load_body->stack_max = stack_max;
10576 load_body->param.flags.has_lead = (param_flags >> 0) & 1;
10577 load_body->param.flags.has_opt = (param_flags >> 1) & 1;
10578 load_body->param.flags.has_rest = (param_flags >> 2) & 1;
10579 load_body->param.flags.has_post = (param_flags >> 3) & 1;
10580 load_body->param.flags.has_kw = FALSE;
10581 load_body->param.flags.has_kwrest = (param_flags >> 5) & 1;
10582 load_body->param.flags.has_block = (param_flags >> 6) & 1;
10583 load_body->param.flags.ambiguous_param0 = (param_flags >> 7) & 1;
10584 load_body->param.flags.accepts_no_kwarg = (param_flags >> 8) & 1;
10585 load_body->param.flags.ruby2_keywords = (param_flags >> 9) & 1;
10586 load_body->param.size = param_size;
10587 load_body->param.lead_num = param_lead_num;
10588 load_body->param.opt_num = param_opt_num;
10589 load_body->param.rest_start = param_rest_start;
10590 load_body->param.post_start = param_post_start;
10591 load_body->param.post_num = param_post_num;
10592 load_body->param.block_start = param_block_start;
10593 load_body->local_table_size = local_table_size;
10594 load_body->is_size = is_size;
10595 load_body->ci_size = ci_size;
10596 load_body->ci_kw_size = ci_kw_size;
10597 load_body->insns_info.size = insns_info_size;
10598
10599 ISEQ_COVERAGE_SET(iseq, Qnil);
10600 ISEQ_ORIGINAL_ISEQ_CLEAR(iseq);
10601 iseq->body->variable.flip_count = variable_flip_count;
10602
10603 load_body->location.first_lineno = location_first_lineno;
10604 load_body->location.node_id = location_node_id;
10605 load_body->location.code_location.beg_pos.lineno = location_code_location_beg_pos_lineno;
10606 load_body->location.code_location.beg_pos.column = location_code_location_beg_pos_column;
10607 load_body->location.code_location.end_pos.lineno = location_code_location_end_pos_lineno;
10608 load_body->location.code_location.end_pos.column = location_code_location_end_pos_column;
10609 load_body->catch_except_p = catch_except_p;
10610
10611 load_body->is_entries = ZALLOC_N(union iseq_inline_storage_entry, is_size);
10612 load_body->call_data = ibf_load_ci_entries(load, ci_entries_offset, ci_size, ci_kw_size);
10613 load_body->param.opt_table = ibf_load_param_opt_table(load, param_opt_table_offset, param_opt_num);
10614 load_body->param.keyword = ibf_load_param_keyword(load, param_keyword_offset);
10615 load_body->param.flags.has_kw = (param_flags >> 4) & 1;
10616 load_body->insns_info.body = ibf_load_insns_info_body(load, insns_info_body_offset, insns_info_size);
10617 load_body->insns_info.positions = ibf_load_insns_info_positions(load, insns_info_positions_offset, insns_info_size);
10618 load_body->local_table = ibf_load_local_table(load, local_table_offset, local_table_size);
10619 load_body->catch_table = ibf_load_catch_table(load, catch_table_offset, catch_table_size);
10620 load_body->parent_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)parent_iseq_index);
10621 load_body->local_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)local_iseq_index);
10622
10623 ibf_load_code(load, iseq, bytecode_offset, bytecode_size, iseq_size);
10624 #if VM_INSN_INFO_TABLE_IMPL == 2
10625 rb_iseq_insns_info_encode_positions(iseq);
10626 #endif
10627
10628 rb_iseq_translate_threaded_code(iseq);
10629
10630 #if IBF_ISEQ_ENABLE_LOCAL_BUFFER
10631 load->current_buffer = &load->global_buffer;
10632 #endif
10633
10634 {
10635 VALUE realpath = Qnil, path = ibf_load_object(load, location_pathobj_index);
10636 if (RB_TYPE_P(path, T_STRING)) {
10637 realpath = path = rb_fstring(path);
10638 }
10639 else if (RB_TYPE_P(path, T_ARRAY)) {
10640 VALUE pathobj = path;
10641 if (RARRAY_LEN(pathobj) != 2) {
10642 rb_raise(rb_eRuntimeError, "path object size mismatch");
10643 }
10644 path = rb_fstring(RARRAY_AREF(pathobj, 0));
10645 realpath = RARRAY_AREF(pathobj, 1);
10646 if (!NIL_P(realpath)) {
10647 if (!RB_TYPE_P(realpath, T_STRING)) {
10648 rb_raise(rb_eArgError, "unexpected realpath %"PRIxVALUE
10649 "(%x), path=%+"PRIsVALUE,
10650 realpath, TYPE(realpath), path);
10651 }
10652 realpath = rb_fstring(realpath);
10653 }
10654 }
10655 else {
10656 rb_raise(rb_eRuntimeError, "unexpected path object");
10657 }
10658 rb_iseq_pathobj_set(iseq, path, realpath);
10659 }
10660
10661 RB_OBJ_WRITE(iseq, &load_body->location.base_label, ibf_load_location_str(load, location_base_label_index));
10662 RB_OBJ_WRITE(iseq, &load_body->location.label, ibf_load_location_str(load, location_label_index));
10663
10664 #if IBF_ISEQ_ENABLE_LOCAL_BUFFER
10665 load->current_buffer = saved_buffer;
10666 #endif
10667 verify_call_cache(iseq);
10668 }
10669
10670 static void
10671 ibf_dump_iseq_list(struct ibf_dump *dump, struct ibf_header *header)
10672 {
10673 VALUE list = rb_ary_tmp_new(RARRAY_LEN(dump->iseq_list));
10674 long i;
10675
10676 for (i = 0; i < RARRAY_LEN(dump->iseq_list); i++) {
10677 ibf_offset_t offset = ibf_dump_iseq_each(dump, (rb_iseq_t *)RARRAY_AREF(dump->iseq_list, i));
10678 rb_ary_push(list, UINT2NUM(offset));
10679 }
10680
10681 long size = RARRAY_LEN(dump->iseq_list);
10682 ibf_offset_t *offsets = ALLOCA_N(ibf_offset_t, size);
10683
10684 for (i = 0; i < size; i++) {
10685 offsets[i] = NUM2UINT(RARRAY_AREF(list, i));
10686 }
10687
10688 ibf_dump_align(dump, sizeof(ibf_offset_t));
10689 header->iseq_list_offset = ibf_dump_write(dump, offsets, sizeof(ibf_offset_t) * size);
10690 header->iseq_list_size = (unsigned int)size;
10691 }
10692
10693 #define IBF_OBJECT_INTERNAL FL_PROMOTED0
10694
10695 /*
10696 * Binary format
10697 * - ibf_object_header
10698 * - ibf_object_xxx (xxx is type)
10699 */
10700
10701 struct ibf_object_header {
10702 unsigned int type: 5;
10703 unsigned int special_const: 1;
10704 unsigned int frozen: 1;
10705 unsigned int internal: 1;
10706 };
10707
10708 enum ibf_object_class_index {
10709 IBF_OBJECT_CLASS_OBJECT,
10710 IBF_OBJECT_CLASS_ARRAY,
10711 IBF_OBJECT_CLASS_STANDARD_ERROR,
10712 IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR,
10713 IBF_OBJECT_CLASS_TYPE_ERROR,
10714 };
10715
10716 struct ibf_object_regexp {
10717 long srcstr;
10718 char option;
10719 };
10720
10721 struct ibf_object_hash {
10722 long len;
10723 long keyval[FLEX_ARY_LEN];
10724 };
10725
10726 struct ibf_object_struct_range {
10727 long class_index;
10728 long len;
10729 long beg;
10730 long end;
10731 int excl;
10732 };
10733
10734 struct ibf_object_bignum {
10735 ssize_t slen;
10736 BDIGIT digits[FLEX_ARY_LEN];
10737 };
10738
10739 enum ibf_object_data_type {
10740 IBF_OBJECT_DATA_ENCODING,
10741 };
10742
10743 struct ibf_object_complex_rational {
10744 long a, b;
10745 };
10746
10747 struct ibf_object_symbol {
10748 long str;
10749 };
10750
10751 #define IBF_ALIGNED_OFFSET(align, offset) /* offset > 0 */ \
10752 ((((offset) - 1) / (align) + 1) * (align))
10753 #define IBF_OBJBODY(type, offset) (const type *)\
10754 ibf_load_check_offset(load, IBF_ALIGNED_OFFSET(RUBY_ALIGNOF(type), offset))
10755
10756 static const void *
10757 ibf_load_check_offset(const struct ibf_load *load, size_t offset)
10758 {
10759 if (offset >= load->current_buffer->size) {
10760 rb_raise(rb_eIndexError, "object offset out of range: %"PRIdSIZE, offset);
10761 }
10762 return load->current_buffer->buff + offset;
10763 }
10764
10765 NORETURN(static void ibf_dump_object_unsupported(struct ibf_dump *dump, VALUE obj));
10766
10767 static void
10768 ibf_dump_object_unsupported(struct ibf_dump *dump, VALUE obj)
10769 {
10770 char buff[0x100];
10771 rb_raw_obj_info(buff, sizeof(buff), obj);
10772 rb_raise(rb_eNotImpError, "ibf_dump_object_unsupported: %s", buff);
10773 }
10774
10775 static VALUE
10776 ibf_load_object_unsupported(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
10777 {
10778 rb_raise(rb_eArgError, "unsupported");
10779 return Qnil;
10780 }
10781
10782 static void
10783 ibf_dump_object_class(struct ibf_dump *dump, VALUE obj)
10784 {
10785 enum ibf_object_class_index cindex;
10786 if (obj == rb_cObject) {
10787 cindex = IBF_OBJECT_CLASS_OBJECT;
10788 }
10789 else if (obj == rb_cArray) {
10790 cindex = IBF_OBJECT_CLASS_ARRAY;
10791 }
10792 else if (obj == rb_eStandardError) {
10793 cindex = IBF_OBJECT_CLASS_STANDARD_ERROR;
10794 }
10795 else if (obj == rb_eNoMatchingPatternError) {
10796 cindex = IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR;
10797 }
10798 else if (obj == rb_eTypeError) {
10799 cindex = IBF_OBJECT_CLASS_TYPE_ERROR;
10800 }
10801 else {
10802 rb_obj_info_dump(obj);
10803 rb_p(obj);
10804 rb_bug("unsupported class");
10805 }
10806 ibf_dump_write_small_value(dump, (VALUE)cindex);
10807 }
10808
10809 static VALUE
10810 ibf_load_object_class(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
10811 {
10812 enum ibf_object_class_index cindex = (enum ibf_object_class_index)ibf_load_small_value(load, &offset);
10813
10814 switch (cindex) {
10815 case IBF_OBJECT_CLASS_OBJECT:
10816 return rb_cObject;
10817 case IBF_OBJECT_CLASS_ARRAY:
10818 return rb_cArray;
10819 case IBF_OBJECT_CLASS_STANDARD_ERROR:
10820 return rb_eStandardError;
10821 case IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR:
10822 return rb_eNoMatchingPatternError;
10823 case IBF_OBJECT_CLASS_TYPE_ERROR:
10824 return rb_eTypeError;
10825 }
10826
10827 rb_raise(rb_eArgError, "ibf_load_object_class: unknown class (%d)", (int)cindex);
10828 }
10829
10830
10831 static void
10832 ibf_dump_object_float(struct ibf_dump *dump, VALUE obj)
10833 {
10834 double dbl = RFLOAT_VALUE(obj);
10835 (void)IBF_W(&dbl, double, 1);
10836 }
10837
10838 static VALUE
10839 ibf_load_object_float(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
10840 {
10841 const double *dblp = IBF_OBJBODY(double, offset);
10842 return DBL2NUM(*dblp);
10843 }
10844
10845 static void
10846 ibf_dump_object_string(struct ibf_dump *dump, VALUE obj)
10847 {
10848 long encindex = (long)rb_enc_get_index(obj);
10849 long len = RSTRING_LEN(obj);
10850 const char *ptr = RSTRING_PTR(obj);
10851
10852 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
10853 rb_encoding *enc = rb_enc_from_index((int)encindex);
10854 const char *enc_name = rb_enc_name(enc);
10855 encindex = RUBY_ENCINDEX_BUILTIN_MAX + ibf_dump_object(dump, rb_str_new2(enc_name));
10856 }
10857
10858 ibf_dump_write_small_value(dump, encindex);
10859 ibf_dump_write_small_value(dump, len);
10860 IBF_WP(ptr, char, len);
10861 }
10862
10863 static VALUE
10864 ibf_load_object_string(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
10865 {
10866 ibf_offset_t reading_pos = offset;
10867
10868 int encindex = (int)ibf_load_small_value(load, &reading_pos);
10869 const long len = (long)ibf_load_small_value(load, &reading_pos);
10870 const char *ptr = load->current_buffer->buff + reading_pos;
10871
10872 VALUE str = rb_str_new(ptr, len);
10873
10874 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
10875 VALUE enc_name_str = ibf_load_object(load, encindex - RUBY_ENCINDEX_BUILTIN_MAX);
10876 encindex = rb_enc_find_index(RSTRING_PTR(enc_name_str));
10877 }
10878 rb_enc_associate_index(str, encindex);
10879
10880 if (header->internal) rb_obj_hide(str);
10881 if (header->frozen) str = rb_fstring(str);
10882
10883 return str;
10884 }
10885
10886 static void
10887 ibf_dump_object_regexp(struct ibf_dump *dump, VALUE obj)
10888 {
10889 VALUE srcstr = RREGEXP_SRC(obj);
10890 struct ibf_object_regexp regexp;
10891 regexp.option = (char)rb_reg_options(obj);
10892 regexp.srcstr = (long)ibf_dump_object(dump, srcstr);
10893
10894 ibf_dump_write_byte(dump, (unsigned char)regexp.option);
10895 ibf_dump_write_small_value(dump, regexp.srcstr);
10896 }
10897
10898 static VALUE
10899 ibf_load_object_regexp(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
10900 {
10901 struct ibf_object_regexp regexp;
10902 regexp.option = ibf_load_byte(load, &offset);
10903 regexp.srcstr = ibf_load_small_value(load, &offset);
10904
10905 VALUE srcstr = ibf_load_object(load, regexp.srcstr);
10906 VALUE reg = rb_reg_compile(srcstr, (int)regexp.option, NULL, 0);
10907
10908 if (header->internal) rb_obj_hide(reg);
10909 if (header->frozen) rb_obj_freeze(reg);
10910
10911 return reg;
10912 }
10913
10914 static void
10915 ibf_dump_object_array(struct ibf_dump *dump, VALUE obj)
10916 {
10917 long i, len = RARRAY_LEN(obj);
10918 ibf_dump_write_small_value(dump, len);
10919 for (i=0; i<len; i++) {
10920 long index = (long)ibf_dump_object(dump, RARRAY_AREF(obj, i));
10921 ibf_dump_write_small_value(dump, index);
10922 }
10923 }
10924
10925 static VALUE
10926 ibf_load_object_array(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
10927 {
10928 ibf_offset_t reading_pos = offset;
10929
10930 const long len = (long)ibf_load_small_value(load, &reading_pos);
10931
10932 VALUE ary = rb_ary_new_capa(len);
10933 int i;
10934
10935 for (i=0; i<len; i++) {
10936 const VALUE index = ibf_load_small_value(load, &reading_pos);
10937 rb_ary_push(ary, ibf_load_object(load, index));
10938 }
10939
10940 if (header->internal) rb_obj_hide(ary);
10941 if (header->frozen) rb_obj_freeze(ary);
10942
10943 return ary;
10944 }
10945
10946 static int
10947 ibf_dump_object_hash_i(st_data_t key, st_data_t val, st_data_t ptr)
10948 {
10949 struct ibf_dump *dump = (struct ibf_dump *)ptr;
10950
10951 VALUE key_index = ibf_dump_object(dump, (VALUE)key);
10952 VALUE val_index = ibf_dump_object(dump, (VALUE)val);
10953
10954 ibf_dump_write_small_value(dump, key_index);
10955 ibf_dump_write_small_value(dump, val_index);
10956 return ST_CONTINUE;
10957 }
10958
10959 static void
10960 ibf_dump_object_hash(struct ibf_dump *dump, VALUE obj)
10961 {
10962 long len = RHASH_SIZE(obj);
10963 ibf_dump_write_small_value(dump, (VALUE)len);
10964
10965 if (len > 0) rb_hash_foreach(obj, ibf_dump_object_hash_i, (VALUE)dump);
10966 }
10967
10968 static VALUE
10969 ibf_load_object_hash(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
10970 {
10971 long len = (long)ibf_load_small_value(load, &offset);
10972 VALUE obj = rb_hash_new_with_size(len);
10973 int i;
10974
10975 for (i = 0; i < len; i++) {
10976 VALUE key_index = ibf_load_small_value(load, &offset);
10977 VALUE val_index = ibf_load_small_value(load, &offset);
10978
10979 VALUE key = ibf_load_object(load, key_index);
10980 VALUE val = ibf_load_object(load, val_index);
10981 rb_hash_aset(obj, key, val);
10982 }
10983 rb_hash_rehash(obj);
10984
10985 if (header->internal) rb_obj_hide(obj);
10986 if (header->frozen) rb_obj_freeze(obj);
10987
10988 return obj;
10989 }
10990
10991 static void
10992 ibf_dump_object_struct(struct ibf_dump *dump, VALUE obj)
10993 {
10994 if (rb_obj_is_kind_of(obj, rb_cRange)) {
10995 struct ibf_object_struct_range range;
10996 VALUE beg, end;
10997 IBF_ZERO(range);
10998 range.len = 3;
10999 range.class_index = 0;
11000
11001 rb_range_values(obj, &beg, &end, &range.excl);
11002 range.beg = (long)ibf_dump_object(dump, beg);
11003 range.end = (long)ibf_dump_object(dump, end);
11004
11005 IBF_W_ALIGN(struct ibf_object_struct_range);
11006 IBF_WV(range);
11007 }
11008 else {
11009 rb_raise(rb_eNotImpError, "ibf_dump_object_struct: unsupported class %"PRIsVALUE,
11010 rb_class_name(CLASS_OF(obj)));
11011 }
11012 }
11013
11014 static VALUE
11015 ibf_load_object_struct(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
11016 {
11017 const struct ibf_object_struct_range *range = IBF_OBJBODY(struct ibf_object_struct_range, offset);
11018 VALUE beg = ibf_load_object(load, range->beg);
11019 VALUE end = ibf_load_object(load, range->end);
11020 VALUE obj = rb_range_new(beg, end, range->excl);
11021 if (header->internal) rb_obj_hide(obj);
11022 if (header->frozen) rb_obj_freeze(obj);
11023 return obj;
11024 }
11025
11026 static void
11027 ibf_dump_object_bignum(struct ibf_dump *dump, VALUE obj)
11028 {
11029 ssize_t len = BIGNUM_LEN(obj);
11030 ssize_t slen = BIGNUM_SIGN(obj) > 0 ? len : len * -1;
11031 BDIGIT *d = BIGNUM_DIGITS(obj);
11032
11033 (void)IBF_W(&slen, ssize_t, 1);
11034 IBF_WP(d, BDIGIT, len);
11035 }
11036
11037 static VALUE
11038 ibf_load_object_bignum(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
11039 {
11040 const struct ibf_object_bignum *bignum = IBF_OBJBODY(struct ibf_object_bignum, offset);
11041 int sign = bignum->slen > 0;
11042 ssize_t len = sign > 0 ? bignum->slen : -1 * bignum->slen;
11043 VALUE obj = rb_integer_unpack(bignum->digits, len * 2, 2, 0,
11044 INTEGER_PACK_LITTLE_ENDIAN | (sign == 0 ? INTEGER_PACK_NEGATIVE : 0));
11045 if (header->internal) rb_obj_hide(obj);
11046 if (header->frozen) rb_obj_freeze(obj);
11047 return obj;
11048 }
11049
11050 static void
11051 ibf_dump_object_data(struct ibf_dump *dump, VALUE obj)
11052 {
11053 if (rb_data_is_encoding(obj)) {
11054 rb_encoding *enc = rb_to_encoding(obj);
11055 const char *name = rb_enc_name(enc);
11056 long len = strlen(name) + 1;
11057 long data[2];
11058 data[0] = IBF_OBJECT_DATA_ENCODING;
11059 data[1] = len;
11060 (void)IBF_W(data, long, 2);
11061 IBF_WP(name, char, len);
11062 }
11063 else {
11064 ibf_dump_object_unsupported(dump, obj);
11065 }
11066 }
11067
11068 static VALUE
11069 ibf_load_object_data(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
11070 {
11071 const long *body = IBF_OBJBODY(long, offset);
11072 const enum ibf_object_data_type type = (enum ibf_object_data_type)body[0];
11073 /* const long len = body[1]; */
11074 const char *data = (const char *)&body[2];
11075
11076 switch (type) {
11077 case IBF_OBJECT_DATA_ENCODING:
11078 {
11079 VALUE encobj = rb_enc_from_encoding(rb_enc_find(data));
11080 return encobj;
11081 }
11082 }
11083
11084 return ibf_load_object_unsupported(load, header, offset);
11085 }
11086
11087 static void
11088 ibf_dump_object_complex_rational(struct ibf_dump *dump, VALUE obj)
11089 {
11090 long data[2];
11091 data[0] = (long)ibf_dump_object(dump, RCOMPLEX(obj)->real);
11092 data[1] = (long)ibf_dump_object(dump, RCOMPLEX(obj)->imag);
11093
11094 (void)IBF_W(data, long, 2);
11095 }
11096
11097 static VALUE
11098 ibf_load_object_complex_rational(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
11099 {
11100 const struct ibf_object_complex_rational *nums = IBF_OBJBODY(struct ibf_object_complex_rational, offset);
11101 VALUE a = ibf_load_object(load, nums->a);
11102 VALUE b = ibf_load_object(load, nums->b);
11103 VALUE obj = header->type == T_COMPLEX ?
11104 rb_complex_new(a, b) : rb_rational_new(a, b);
11105
11106 if (header->internal) rb_obj_hide(obj);
11107 if (header->frozen) rb_obj_freeze(obj);
11108 return obj;
11109 }
11110
11111 static void
11112 ibf_dump_object_symbol(struct ibf_dump *dump, VALUE obj)
11113 {
11114 VALUE str = rb_sym2str(obj);
11115 VALUE str_index = ibf_dump_object(dump, str);
11116
11117 ibf_dump_write_small_value(dump, str_index);
11118 }
11119
11120 static VALUE
11121 ibf_load_object_symbol(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
11122 {
11123 VALUE str_index = ibf_load_small_value(load, &offset);
11124 VALUE str = ibf_load_object(load, str_index);
11125 ID id = rb_intern_str(str);
11126 return ID2SYM(id);
11127 }
11128
11129 typedef void (*ibf_dump_object_function)(struct ibf_dump *dump, VALUE obj);
11130 static ibf_dump_object_function dump_object_functions[RUBY_T_MASK+1] = {
11131 ibf_dump_object_unsupported, /* T_NONE */
11132 ibf_dump_object_unsupported, /* T_OBJECT */
11133 ibf_dump_object_class, /* T_CLASS */
11134 ibf_dump_object_unsupported, /* T_MODULE */
11135 ibf_dump_object_float, /* T_FLOAT */
11136 ibf_dump_object_string, /* T_STRING */
11137 ibf_dump_object_regexp, /* T_REGEXP */
11138 ibf_dump_object_array, /* T_ARRAY */
11139 ibf_dump_object_hash, /* T_HASH */
11140 ibf_dump_object_struct, /* T_STRUCT */
11141 ibf_dump_object_bignum, /* T_BIGNUM */
11142 ibf_dump_object_unsupported, /* T_FILE */
11143 ibf_dump_object_data, /* T_DATA */
11144 ibf_dump_object_unsupported, /* T_MATCH */
11145 ibf_dump_object_complex_rational, /* T_COMPLEX */
11146 ibf_dump_object_complex_rational, /* T_RATIONAL */
11147 ibf_dump_object_unsupported, /* 0x10 */
11148 ibf_dump_object_unsupported, /* 0x11 T_NIL */
11149 ibf_dump_object_unsupported, /* 0x12 T_TRUE */
11150 ibf_dump_object_unsupported, /* 0x13 T_FALSE */
11151 ibf_dump_object_symbol, /* 0x14 T_SYMBOL */
11152 ibf_dump_object_unsupported, /* T_FIXNUM */
11153 ibf_dump_object_unsupported, /* T_UNDEF */
11154 ibf_dump_object_unsupported, /* 0x17 */
11155 ibf_dump_object_unsupported, /* 0x18 */
11156 ibf_dump_object_unsupported, /* 0x19 */
11157 ibf_dump_object_unsupported, /* T_IMEMO 0x1a */
11158 ibf_dump_object_unsupported, /* T_NODE 0x1b */
11159 ibf_dump_object_unsupported, /* T_ICLASS 0x1c */
11160 ibf_dump_object_unsupported, /* T_ZOMBIE 0x1d */
11161 ibf_dump_object_unsupported, /* 0x1e */
11162 ibf_dump_object_unsupported, /* 0x1f */
11163 };
11164
11165 static void
11166 ibf_dump_object_object_header(struct ibf_dump *dump, const struct ibf_object_header header)
11167 {
11168 unsigned char byte =
11169 (header.type << 0) |
11170 (header.special_const << 5) |
11171 (header.frozen << 6) |
11172 (header.internal << 7);
11173
11174 IBF_WV(byte);
11175 }
11176
11177 static struct ibf_object_header
11178 ibf_load_object_object_header(const struct ibf_load *load, ibf_offset_t *offset)
11179 {
11180 unsigned char byte = ibf_load_byte(load, offset);
11181
11182 struct ibf_object_header header;
11183 header.type = (byte >> 0) & 0x1f;
11184 header.special_const = (byte >> 5) & 0x01;
11185 header.frozen = (byte >> 6) & 0x01;
11186 header.internal = (byte >> 7) & 0x01;
11187
11188 return header;
11189 }
11190
11191 static ibf_offset_t
11192 ibf_dump_object_object(struct ibf_dump *dump, VALUE obj_list, VALUE obj)
11193 {
11194 struct ibf_object_header obj_header;
11195 ibf_offset_t current_offset;
11196 IBF_ZERO(obj_header);
11197 obj_header.type = TYPE(obj);
11198
11199 IBF_W_ALIGN(ibf_offset_t);
11200 current_offset = ibf_dump_pos(dump);
11201
11202 if (SPECIAL_CONST_P(obj)) {
11203 if (RB_TYPE_P(obj, T_SYMBOL) ||
11204 RB_TYPE_P(obj, T_FLOAT)) {
11205 obj_header.internal = FALSE;
11206 goto dump_object;
11207 }
11208 obj_header.special_const = TRUE;
11209 obj_header.frozen = TRUE;
11210 obj_header.internal = TRUE;
11211 ibf_dump_object_object_header(dump, obj_header);
11212 ibf_dump_write_small_value(dump, obj);
11213 }
11214 else {
11215 obj_header.internal = (RBASIC_CLASS(obj) == 0) ? TRUE : FALSE;
11216 dump_object:
11217 obj_header.special_const = FALSE;
11218 obj_header.frozen = FL_TEST(obj, FL_FREEZE) ? TRUE : FALSE;
11219 ibf_dump_object_object_header(dump, obj_header);
11220 (*dump_object_functions[obj_header.type])(dump, obj);
11221 }
11222
11223 return current_offset;
11224 }
11225
11226 typedef VALUE (*ibf_load_object_function)(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset);
11227 static ibf_load_object_function load_object_functions[RUBY_T_MASK+1] = {
11228 ibf_load_object_unsupported, /* T_NONE */
11229 ibf_load_object_unsupported, /* T_OBJECT */
11230 ibf_load_object_class, /* T_CLASS */
11231 ibf_load_object_unsupported, /* T_MODULE */
11232 ibf_load_object_float, /* T_FLOAT */
11233 ibf_load_object_string, /* T_STRING */
11234 ibf_load_object_regexp, /* T_REGEXP */
11235 ibf_load_object_array, /* T_ARRAY */
11236 ibf_load_object_hash, /* T_HASH */
11237 ibf_load_object_struct, /* T_STRUCT */
11238 ibf_load_object_bignum, /* T_BIGNUM */
11239 ibf_load_object_unsupported, /* T_FILE */
11240 ibf_load_object_data, /* T_DATA */
11241 ibf_load_object_unsupported, /* T_MATCH */
11242 ibf_load_object_complex_rational, /* T_COMPLEX */
11243 ibf_load_object_complex_rational, /* T_RATIONAL */
11244 ibf_load_object_unsupported, /* 0x10 */
11245 ibf_load_object_unsupported, /* T_NIL */
11246 ibf_load_object_unsupported, /* T_TRUE */
11247 ibf_load_object_unsupported, /* T_FALSE */
11248 ibf_load_object_symbol,
11249 ibf_load_object_unsupported, /* T_FIXNUM */
11250 ibf_load_object_unsupported, /* T_UNDEF */
11251 ibf_load_object_unsupported, /* 0x17 */
11252 ibf_load_object_unsupported, /* 0x18 */
11253 ibf_load_object_unsupported, /* 0x19 */
11254 ibf_load_object_unsupported, /* T_IMEMO 0x1a */
11255 ibf_load_object_unsupported, /* T_NODE 0x1b */
11256 ibf_load_object_unsupported, /* T_ICLASS 0x1c */
11257 ibf_load_object_unsupported, /* T_ZOMBIE 0x1d */
11258 ibf_load_object_unsupported, /* 0x1e */
11259 ibf_load_object_unsupported, /* 0x1f */
11260 };
11261
11262 static VALUE
11263 ibf_load_object(const struct ibf_load *load, VALUE object_index)
11264 {
11265 if (object_index == 0) {
11266 return Qnil;
11267 }
11268 else if (object_index >= (VALUE)RARRAY_LEN(load->current_buffer->obj_list)) {
11269 rb_raise(rb_eIndexError, "object index out of range: %"PRIdVALUE, object_index);
11270 }
11271 else {
11272 VALUE obj = rb_ary_entry(load->current_buffer->obj_list, (long)object_index);
11273 if (obj == Qnil) { /* TODO: avoid multiple Qnil load */
11274 ibf_offset_t *offsets = (ibf_offset_t *)(load->current_buffer->obj_list_offset + load->current_buffer->buff);
11275 ibf_offset_t offset = offsets[object_index];
11276 const struct ibf_object_header header = ibf_load_object_object_header(load, &offset);
11277
11278 #if IBF_ISEQ_DEBUG
11279 fprintf(stderr, "ibf_load_object: list=%#x offsets=%p offset=%#x\n",
11280 load->current_buffer->obj_list_offset, (void *)offsets, offset);
11281 fprintf(stderr, "ibf_load_object: type=%#x special=%d frozen=%d internal=%d\n",
11282 header.type, header.special_const, header.frozen, header.internal);
11283 #endif
11284 if (offset >= load->current_buffer->size) {
11285 rb_raise(rb_eIndexError, "object offset out of range: %u", offset);
11286 }
11287
11288 if (header.special_const) {
11289 ibf_offset_t reading_pos = offset;
11290
11291 obj = ibf_load_small_value(load, &reading_pos);
11292 }
11293 else {
11294 obj = (*load_object_functions[header.type])(load, &header, offset);
11295 }
11296
11297 rb_ary_store(load->current_buffer->obj_list, (long)object_index, obj);
11298 }
11299 #if IBF_ISEQ_DEBUG
11300 fprintf(stderr, "ibf_load_object: index=%#"PRIxVALUE" obj=%#"PRIxVALUE"\n",
11301 object_index, obj);
11302 #endif
11303 return obj;
11304 }
11305 }
11306
11307 static void
11308 ibf_dump_object_list(struct ibf_dump *dump, ibf_offset_t *obj_list_offset, unsigned int *obj_list_size)
11309 {
11310 VALUE obj_list = dump->current_buffer->obj_list;
11311 VALUE list = rb_ary_tmp_new(RARRAY_LEN(obj_list));
11312 int i, size;
11313
11314 for (i=0; i<RARRAY_LEN(obj_list); i++) {
11315 VALUE obj = RARRAY_AREF(obj_list, i);
11316 ibf_offset_t offset = ibf_dump_object_object(dump, obj_list, obj);
11317 rb_ary_push(list, UINT2NUM(offset));
11318 }
11319 size = i;
11320 IBF_W_ALIGN(ibf_offset_t);
11321 *obj_list_offset = ibf_dump_pos(dump);
11322
11323 for (i=0; i<size; i++) {
11324 ibf_offset_t offset = NUM2UINT(RARRAY_AREF(list, i));
11325 IBF_WV(offset);
11326 }
11327
11328 *obj_list_size = size;
11329 }
11330
11331 static void
11332 ibf_dump_mark(void *ptr)
11333 {
11334 struct ibf_dump *dump = (struct ibf_dump *)ptr;
11335 rb_gc_mark(dump->global_buffer.str);
11336 rb_gc_mark(dump->global_buffer.obj_list);
11337 rb_gc_mark(dump->iseq_list);
11338 }
11339
11340 static void
11341 ibf_dump_free(void *ptr)
11342 {
11343 struct ibf_dump *dump = (struct ibf_dump *)ptr;
11344 if (dump->iseq_table) {
11345 st_free_table(dump->iseq_table);
11346 dump->iseq_table = 0;
11347 }
11348 ruby_xfree(dump);
11349 }
11350
11351 static size_t
11352 ibf_dump_memsize(const void *ptr)
11353 {
11354 struct ibf_dump *dump = (struct ibf_dump *)ptr;
11355 size_t size = sizeof(*dump);
11356 if (dump->iseq_table) size += st_memsize(dump->iseq_table);
11357 return size;
11358 }
11359
11360 static const rb_data_type_t ibf_dump_type = {
11361 "ibf_dump",
11362 {ibf_dump_mark, ibf_dump_free, ibf_dump_memsize,},
11363 0, 0, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY
11364 };
11365
11366 static void
11367 ibf_dump_setup(struct ibf_dump *dump, VALUE dumper_obj)
11368 {
11369 RB_OBJ_WRITE(dumper_obj, &dump->iseq_list, rb_ary_tmp_new(0));
11370 RB_OBJ_WRITE(dumper_obj, &dump->global_buffer.obj_list, ibf_dump_object_list_new());
11371 RB_OBJ_WRITE(dumper_obj, &dump->global_buffer.str, rb_str_new(0, 0));
11372 dump->iseq_table = st_init_numtable(); /* need free */
11373
11374 dump->current_buffer = &dump->global_buffer;
11375 }
11376
11377 VALUE
11378 rb_iseq_ibf_dump(const rb_iseq_t *iseq, VALUE opt)
11379 {
11380 struct ibf_dump *dump;
11381 struct ibf_header header = {{0}};
11382 VALUE dump_obj;
11383 VALUE str;
11384
11385 if (iseq->body->parent_iseq != NULL ||
11386 iseq->body->local_iseq != iseq) {
11387 rb_raise(rb_eRuntimeError, "should be top of iseq");
11388 }
11389 if (RTEST(ISEQ_COVERAGE(iseq))) {
11390 rb_raise(rb_eRuntimeError, "should not compile with coverage");
11391 }
11392
11393 dump_obj = TypedData_Make_Struct(0, struct ibf_dump, &ibf_dump_type, dump);
11394 ibf_dump_setup(dump, dump_obj);
11395
11396 ibf_dump_write(dump, &header, sizeof(header));
11397 ibf_dump_write(dump, RUBY_PLATFORM, strlen(RUBY_PLATFORM) + 1);
11398 ibf_dump_iseq(dump, iseq);
11399
11400 header.magic[0] = 'Y'; /* YARB */
11401 header.magic[1] = 'A';
11402 header.magic[2] = 'R';
11403 header.magic[3] = 'B';
11404 header.major_version = IBF_MAJOR_VERSION;
11405 header.minor_version = IBF_MINOR_VERSION;
11406 ibf_dump_iseq_list(dump, &header);
11407 ibf_dump_object_list(dump, &header.global_object_list_offset, &header.global_object_list_size);
11408 header.size = ibf_dump_pos(dump);
11409
11410 if (RTEST(opt)) {
11411 VALUE opt_str = opt;
11412 const char *ptr = StringValuePtr(opt_str);
11413 header.extra_size = RSTRING_LENINT(opt_str);
11414 ibf_dump_write(dump, ptr, header.extra_size);
11415 }
11416 else {
11417 header.extra_size = 0;
11418 }
11419
11420 ibf_dump_overwrite(dump, &header, sizeof(header), 0);
11421
11422 str = dump->global_buffer.str;
11423 ibf_dump_free(dump);
11424 DATA_PTR(dump_obj) = NULL;
11425 RB_GC_GUARD(dump_obj);
11426 return str;
11427 }
11428
11429 static const ibf_offset_t *
11430 ibf_iseq_list(const struct ibf_load *load)
11431 {
11432 return (const ibf_offset_t *)(load->global_buffer.buff + load->header->iseq_list_offset);
11433 }
11434
11435 void
11436 rb_ibf_load_iseq_complete(rb_iseq_t *iseq)
11437 {
11438 struct ibf_load *load = RTYPEDDATA_DATA(iseq->aux.loader.obj);
11439 rb_iseq_t *prev_src_iseq = load->iseq;
11440 ibf_offset_t offset = ibf_iseq_list(load)[iseq->aux.loader.index];
11441 load->iseq = iseq;
11442 #if IBF_ISEQ_DEBUG
11443 fprintf(stderr, "rb_ibf_load_iseq_complete: index=%#x offset=%#x size=%#x\n",
11444 iseq->aux.loader.index, offset,
11445 load->header->size);
11446 #endif
11447 ibf_load_iseq_each(load, iseq, offset);
11448 ISEQ_COMPILE_DATA_CLEAR(iseq);
11449 FL_UNSET(iseq, ISEQ_NOT_LOADED_YET);
11450 rb_iseq_init_trace(iseq);
11451 load->iseq = prev_src_iseq;
11452 }
11453
11454 #if USE_LAZY_LOAD
11455 MJIT_FUNC_EXPORTED const rb_iseq_t *
11456 rb_iseq_complete(const rb_iseq_t *iseq)
11457 {
11458 rb_ibf_load_iseq_complete((rb_iseq_t *)iseq);
11459 return iseq;
11460 }
11461 #endif
11462
11463 static rb_iseq_t *
11464 ibf_load_iseq(const struct ibf_load *load, const rb_iseq_t *index_iseq)
11465 {
11466 int iseq_index = (int)(VALUE)index_iseq;
11467
11468 #if IBF_ISEQ_DEBUG
11469 fprintf(stderr, "ibf_load_iseq: index_iseq=%p iseq_list=%p\n",
11470 (void *)index_iseq, (void *)load->iseq_list);
11471 #endif
11472 if (iseq_index == -1) {
11473 return NULL;
11474 }
11475 else {
11476 VALUE iseqv = rb_ary_entry(load->iseq_list, iseq_index);
11477
11478 #if IBF_ISEQ_DEBUG
11479 fprintf(stderr, "ibf_load_iseq: iseqv=%p\n", (void *)iseqv);
11480 #endif
11481 if (iseqv != Qnil) {
11482 return (rb_iseq_t *)iseqv;
11483 }
11484 else {
11485 rb_iseq_t *iseq = iseq_imemo_alloc();
11486 #if IBF_ISEQ_DEBUG
11487 fprintf(stderr, "ibf_load_iseq: new iseq=%p\n", (void *)iseq);
11488 #endif
11489 FL_SET(iseq, ISEQ_NOT_LOADED_YET);
11490 iseq->aux.loader.obj = load->loader_obj;
11491 iseq->aux.loader.index = iseq_index;
11492 #if IBF_ISEQ_DEBUG
11493 fprintf(stderr, "ibf_load_iseq: iseq=%p loader_obj=%p index=%d\n",
11494 (void *)iseq, (void *)load->loader_obj, iseq_index);
11495 #endif
11496 rb_ary_store(load->iseq_list, iseq_index, (VALUE)iseq);
11497
11498 #if !USE_LAZY_LOAD
11499 #if IBF_ISEQ_DEBUG
11500 fprintf(stderr, "ibf_load_iseq: loading iseq=%p\n", (void *)iseq);
11501 #endif
11502 rb_ibf_load_iseq_complete(iseq);
11503 #else
11504 if (GET_VM()->builtin_function_table) {
11505 rb_ibf_load_iseq_complete(iseq);
11506 }
11507 #endif /* !USE_LAZY_LOAD */
11508
11509 #if IBF_ISEQ_DEBUG
11510 fprintf(stderr, "ibf_load_iseq: iseq=%p loaded %p\n",
11511 (void *)iseq, (void *)load->iseq);
11512 #endif
11513 return iseq;
11514 }
11515 }
11516 }
11517
11518 static void
11519 ibf_load_setup_bytes(struct ibf_load *load, VALUE loader_obj, const char *bytes, size_t size)
11520 {
11521 load->loader_obj = loader_obj;
11522 load->global_buffer.buff = bytes;
11523 load->header = (struct ibf_header *)load->global_buffer.buff;
11524 load->global_buffer.size = load->header->size;
11525 load->global_buffer.obj_list_offset = load->header->global_object_list_offset;
11526 load->global_buffer.obj_list_size = load->header->global_object_list_size;
11527 RB_OBJ_WRITE(loader_obj, &load->iseq_list, rb_ary_tmp_new(0));
11528 RB_OBJ_WRITE(loader_obj, &load->global_buffer.obj_list, rb_ary_tmp_new(load->global_buffer.obj_list_size));
11529 rb_ary_resize(load->global_buffer.obj_list, load->global_buffer.obj_list_size);
11530 load->iseq = NULL;
11531
11532 load->current_buffer = &load->global_buffer;
11533
11534 if (size < load->header->size) {
11535 rb_raise(rb_eRuntimeError, "broken binary format");
11536 }
11537 if (strncmp(load->header->magic, "YARB", 4) != 0) {
11538 rb_raise(rb_eRuntimeError, "unknown binary format");
11539 }
11540 if (load->header->major_version != IBF_MAJOR_VERSION ||
11541 load->header->minor_version != IBF_MINOR_VERSION) {
11542 rb_raise(rb_eRuntimeError, "unmatched version file (%u.%u for %u.%u)",
11543 load->header->major_version, load->header->minor_version, IBF_MAJOR_VERSION, IBF_MINOR_VERSION);
11544 }
11545 if (strcmp(load->global_buffer.buff + sizeof(struct ibf_header), RUBY_PLATFORM) != 0) {
11546 rb_raise(rb_eRuntimeError, "unmatched platform");
11547 }
11548 if (load->header->iseq_list_offset % RUBY_ALIGNOF(ibf_offset_t)) {
11549 rb_raise(rb_eArgError, "unaligned iseq list offset: %u",
11550 load->header->iseq_list_offset);
11551 }
11552 if (load->global_buffer.obj_list_offset % RUBY_ALIGNOF(ibf_offset_t)) {
11553 rb_raise(rb_eArgError, "unaligned object list offset: %u",
11554 load->global_buffer.obj_list_offset);
11555 }
11556 }
11557
11558 static void
11559 ibf_load_setup(struct ibf_load *load, VALUE loader_obj, VALUE str)
11560 {
11561 if (RSTRING_LENINT(str) < (int)sizeof(struct ibf_header)) {
11562 rb_raise(rb_eRuntimeError, "broken binary format");
11563 }
11564
11565 #if USE_LAZY_LOAD
11566 str = rb_str_new(RSTRING_PTR(str), RSTRING_LEN(str));
11567 #endif
11568
11569 ibf_load_setup_bytes(load, loader_obj, StringValuePtr(str), RSTRING_LEN(str));
11570 RB_OBJ_WRITE(loader_obj, &load->str, str);
11571 }
11572
11573 static void
11574 ibf_loader_mark(void *ptr)
11575 {
11576 struct ibf_load *load = (struct ibf_load *)ptr;
11577 rb_gc_mark(load->str);
11578 rb_gc_mark(load->iseq_list);
11579 rb_gc_mark(load->global_buffer.obj_list);
11580 }
11581
11582 static void
11583 ibf_loader_free(void *ptr)
11584 {
11585 struct ibf_load *load = (struct ibf_load *)ptr;
11586 ruby_xfree(load);
11587 }
11588
11589 static size_t
11590 ibf_loader_memsize(const void *ptr)
11591 {
11592 return sizeof(struct ibf_load);
11593 }
11594
11595 static const rb_data_type_t ibf_load_type = {
11596 "ibf_loader",
11597 {ibf_loader_mark, ibf_loader_free, ibf_loader_memsize,},
11598 0, 0, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY
11599 };
11600
11601 const rb_iseq_t *
11602 rb_iseq_ibf_load(VALUE str)
11603 {
11604 struct ibf_load *load;
11605 rb_iseq_t *iseq;
11606 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
11607
11608 ibf_load_setup(load, loader_obj, str);
11609 iseq = ibf_load_iseq(load, 0);
11610
11611 RB_GC_GUARD(loader_obj);
11612 return iseq;
11613 }
11614
11615 const rb_iseq_t *
11616 rb_iseq_ibf_load_bytes(const char *bytes, size_t size)
11617 {
11618 struct ibf_load *load;
11619 rb_iseq_t *iseq;
11620 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
11621
11622 ibf_load_setup_bytes(load, loader_obj, bytes, size);
11623 iseq = ibf_load_iseq(load, 0);
11624
11625 RB_GC_GUARD(loader_obj);
11626 return iseq;
11627 }
11628
11629 VALUE
11630 rb_iseq_ibf_load_extra_data(VALUE str)
11631 {
11632 struct ibf_load *load;
11633 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
11634 VALUE extra_str;
11635
11636 ibf_load_setup(load, loader_obj, str);
11637 extra_str = rb_str_new(load->global_buffer.buff + load->header->size, load->header->extra_size);
11638 RB_GC_GUARD(loader_obj);
11639 return extra_str;
11640 }
rb_cArray
VALUE rb_cArray
Definition: array.c:27
NODE_NEXT
@ NODE_NEXT
Definition: node.h:47
ibf_object_struct_range::class_index
long class_index
Definition: compile.c:10727
idNot
@ idNot
Definition: id.h:99
rb_iseq_realpath
VALUE rb_iseq_realpath(const rb_iseq_t *iseq)
Definition: iseq.c:1033
LABEL
struct iseq_label_data LABEL
rb_ary_new_capa
VALUE rb_ary_new_capa(long capa)
Definition: array.c:717
NODE_COLON3
@ NODE_COLON3
Definition: node.h:119
rb_kwarg_call_data
Definition: vm_core.h:257
NODE_FL_NEWLINE
#define NODE_FL_NEWLINE
Definition: node.h:183
iseq_insn_data::insn_id
enum ruby_vminsn_type insn_id
Definition: compile.c:76
BADINSN_DUMP
#define BADINSN_DUMP(anchor, list, dest)
Definition: compile.c:1885
VM_DEFINECLASS_TYPE_SINGLETON_CLASS
@ VM_DEFINECLASS_TYPE_SINGLETON_CLASS
Definition: vm_core.h:995
IBF_BODY_OFFSET
#define IBF_BODY_OFFSET(x)
UNLIKELY
#define UNLIKELY(x)
Definition: ffi_common.h:126
NODE_NIL
@ NODE_NIL
Definition: node.h:125
ID
unsigned long ID
Definition: ruby.h:103
ruby_xfree
void ruby_xfree(void *x)
Definition: gc.c:10150
rb_str_concat
VALUE rb_str_concat(VALUE, VALUE)
Definition: string.c:3065
BIGNUM_DIGITS
#define BIGNUM_DIGITS(b)
Definition: internal.h:780
ruby_node_name
const char * ruby_node_name(int node)
Definition: iseq.c:2534
ibf_header::global_object_list_offset
ibf_offset_t global_object_list_offset
Definition: compile.c:9521
rb_raw_obj_info
const char * rb_raw_obj_info(char *buff, const int buff_size, VALUE obj)
Definition: gc.c:11419
void
void
Definition: rb_mjit_min_header-2.7.0.h:13273
rb_id2name
const char * rb_id2name(ID)
Definition: symbol.c:801
rb_is_const_id
int rb_is_const_id(ID id)
Definition: symbol.c:854
rb_fstring
VALUE rb_fstring(VALUE)
Definition: string.c:312
RUBY_EVENT_NONE
#define RUBY_EVENT_NONE
Definition: ruby.h:2241
TypedData_Make_Struct
#define TypedData_Make_Struct(klass, type, data_type, sval)
Definition: ruby.h:1244
idTo_s
@ idTo_s
Definition: rb_mjit_min_header-2.7.0.h:8721
idEq
@ idEq
Definition: id.h:96
rb_xcalloc_mul_add_mul
void * rb_xcalloc_mul_add_mul(size_t x, size_t y, size_t z, size_t w)
Definition: gc.c:10177
TRUE
#define TRUE
Definition: nkf.h:175
iseq_link_anchor::anchor
LINK_ELEMENT anchor
Definition: compile.c:51
iseq_compile_data_ensure_node_stack::ensure_node
const NODE * ensure_node
Definition: compile.c:105
NODE_ATTRASGN
@ NODE_ATTRASGN
Definition: node.h:132
iseq_link_element::ISEQ_ELEMENT_TRACE
@ ISEQ_ELEMENT_TRACE
Definition: compile.c:44
rb_str_freeze
VALUE rb_str_freeze(VALUE)
Definition: string.c:2616
rb_iseq_load
VALUE rb_iseq_load(VALUE data, VALUE parent, VALUE opt)
Definition: iseq.c:972
iseq_insn_data
Definition: compile.c:74
DEFINED_FUNC
@ DEFINED_FUNC
Definition: iseq.h:301
T_FLOAT
#define T_FLOAT
Definition: ruby.h:527
idANDOP
@ idANDOP
Definition: id.h:108
rb_iseq_first_lineno
VALUE rb_iseq_first_lineno(const rb_iseq_t *iseq)
Definition: iseq.c:1057
idMax
@ idMax
Definition: rb_mjit_min_header-2.7.0.h:8685
ibf_header::iseq_list_size
unsigned int iseq_list_size
Definition: compile.c:9518
INSERT_AFTER_INSN1
#define INSERT_AFTER_INSN1(prev, line, insn, op1)
Definition: compile.c:226
NODE_DSYM
@ NODE_DSYM
Definition: node.h:131
rb_str_new2
#define rb_str_new2
Definition: intern.h:903
LINK_ELEMENT
struct iseq_link_element LINK_ELEMENT
ibf_object_struct_range::len
long len
Definition: compile.c:10728
vars
const VALUE int int int int int int VALUE * vars[]
Definition: rb_mjit_min_header-2.7.0.h:6462
ibf_load_buffer::obj_list
VALUE obj_list
Definition: compile.c:9542
rb_obj_hide
VALUE rb_obj_hide(VALUE obj)
Make the object invisible from Ruby code.
Definition: object.c:78
NODE_HSHPTN
@ NODE_HSHPTN
Definition: node.h:135
rb_enc_name
#define rb_enc_name(enc)
Definition: encoding.h:177
assert
#define assert(x)
Definition: dlmalloc.c:1176
rb_str_hash
st_index_t rb_str_hash(VALUE)
Definition: string.c:3163
ADD_INSNL
#define ADD_INSNL(seq, line, insn, label)
Definition: compile.c:233
INTEGER_PACK_NEGATIVE
#define INTEGER_PACK_NEGATIVE
Definition: intern.h:160
NODE_RESCUE
@ NODE_RESCUE
Definition: node.h:51
iseq_catch_table_entry::iseq
rb_iseq_t * iseq
Definition: iseq.h:247
range
#define range(low, item, hi)
Definition: date_strftime.c:21
rb_builtin_function
Definition: builtin.h:6
IBF_MAJOR_VERSION
#define IBF_MAJOR_VERSION
Definition: compile.c:9503
id
const int id
Definition: nkf.c:209
ibf_dump_object_function
void(* ibf_dump_object_function)(struct ibf_dump *dump, VALUE obj)
Definition: compile.c:11129
st_table::num_entries
st_index_t num_entries
Definition: st.h:86
idEach
@ idEach
Definition: rb_mjit_min_header-2.7.0.h:8703
NODE_OP_ASGN1
@ NODE_OP_ASGN1
Definition: node.h:64
FIX2INT
#define FIX2INT(x)
Definition: ruby.h:717
idNilP
@ idNilP
Definition: id.h:112
rb_ary_pattern_info::pre_args
NODE * pre_args
Definition: node.h:454
rb_iseq_struct
Definition: vm_core.h:456
va_arg
#define va_arg(v, l)
Definition: rb_mjit_min_header-2.7.0.h:3980
rb_hash_new
VALUE rb_hash_new(void)
Definition: hash.c:1501
path
VALUE path
Definition: rb_mjit_min_header-2.7.0.h:7351
NODE_TRUE
@ NODE_TRUE
Definition: node.h:126
rb_iseq_new_with_callback_callback_func
Definition: vm_core.h:1018
compile_debug
#define compile_debug
Definition: compile.c:130
rb_warn
void rb_warn(const char *fmt,...)
Definition: error.c:313
iseq_compile_data_storage::buff
char buff[FLEX_ARY_LEN]
Definition: iseq.h:278
NODE_MATCH3
@ NODE_MATCH3
Definition: node.h:92
rb_local_defined
int rb_local_defined(ID id, const rb_iseq_t *iseq)
Definition: compile.c:9381
idOr
@ idOr
Definition: id.h:101
NODE_NTH_REF
@ NODE_NTH_REF
Definition: node.h:88
NODE_ZLIST
@ NODE_ZLIST
Definition: node.h:77
ibf_header
Definition: compile.c:9511
NODE_SPECIAL_EXCESSIVE_COMMA
#define NODE_SPECIAL_EXCESSIVE_COMMA
Definition: node.h:385
NODE_DREGX
@ NODE_DREGX
Definition: node.h:99
rb_iseq_constant_body::insns_info
struct rb_iseq_constant_body::iseq_insn_info insns_info
iseq_label_data::label_no
int label_no
Definition: compile.c:64
size_t
long unsigned int size_t
Definition: rb_mjit_min_header-2.7.0.h:666
gc.h
rb_insns_name_array
VALUE rb_insns_name_array(void)
Definition: compile.c:8767
ADD_SEND_WITH_BLOCK
#define ADD_SEND_WITH_BLOCK(seq, line, id, argc, block)
Definition: compile.c:250
NODE_OR
@ NODE_OR
Definition: node.h:55
rb_iseq_disasm
VALUE rb_iseq_disasm(const rb_iseq_t *iseq)
Definition: iseq.c:2278
rb_cNumeric
RUBY_EXTERN VALUE rb_cNumeric
Definition: ruby.h:2037
NODE_ARYPTN
@ NODE_ARYPTN
Definition: node.h:134
ibf_object_header::type
unsigned int type
Definition: compile.c:10702
IS_ADJUST
#define IS_ADJUST(link)
Definition: compile.c:366
RBASIC_CLEAR_CLASS
#define RBASIC_CLEAR_CLASS(obj)
Definition: internal.h:1981
ibf_header::size
unsigned int size
Definition: compile.c:9515
id_core_raise
@ id_core_raise
Definition: id.h:128
rb_ary_new_from_args
#define rb_ary_new_from_args(n,...)
Definition: rb_mjit_min_header-2.7.0.h:7214
rb_iseq_constant_body::table
const ID * table
Definition: vm_core.h:394
NODE_OP_ASGN_OR
@ NODE_OP_ASGN_OR
Definition: node.h:67
VM_CALL_TAILCALL
#define VM_CALL_TAILCALL
Definition: vm_core.h:1109
iseq_insn_info_entry
Definition: iseq.h:220
iseq_trace_data
Definition: compile.c:92
INT2FIX
#define INT2FIX(i)
Definition: ruby.h:263
rb_call_info_kw_arg::keywords
VALUE keywords[1]
Definition: vm_core.h:242
snprintf
int snprintf(char *__restrict, size_t, const char *__restrict,...) __attribute__((__format__(__printf__
VM_CALL_ZSUPER
#define VM_CALL_ZSUPER
Definition: vm_core.h:1111
cdhash_set_label_struct::hash
VALUE hash
Definition: compile.c:1851
param_size
rb_control_frame_t struct rb_calling_info const rb_callable_method_entry_t int int param_size
Definition: rb_mjit_min_header-2.7.0.h:14544
INSN
struct iseq_insn_data INSN
NODE_HASH
@ NODE_HASH
Definition: node.h:79
rb_to_symbol_type
VALUE rb_to_symbol_type(VALUE obj)
Definition: symbol.c:1044
PRIxVALUE
#define PRIxVALUE
Definition: ruby.h:164
ruby_xmalloc
void * ruby_xmalloc(size_t size)
Definition: gc.c:11950
iseq_label_data::refcnt
int refcnt
Definition: compile.c:68
IS_LABEL
#define IS_LABEL(link)
Definition: compile.c:365
OBJ_BUILTIN_TYPE
#define OBJ_BUILTIN_TYPE(obj)
Definition: internal.h:2597
NODE_CONST
@ NODE_CONST
Definition: node.h:86
rb_num_t
unsigned long rb_num_t
Definition: vm_core.h:181
iseq_catch_table_entry::cont
unsigned int cont
Definition: iseq.h:251
rb_warning_category_enabled_p
MJIT_FUNC_EXPORTED bool rb_warning_category_enabled_p(rb_warning_category_t category)
Definition: error.c:164
IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR
@ IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR
Definition: compile.c:10712
RSTRING_PTR
#define RSTRING_PTR(str)
Definition: ruby.h:1009
re.h
COMPILE_ERROR
#define COMPILE_ERROR
Definition: compile.c:413
rb_dbl2big
VALUE rb_dbl2big(double d)
Definition: bignum.c:5249
idMINUS
@ idMINUS
Definition: id.h:86
div
void div_t div(int __numer, int __denom)
idGT
@ idGT
Definition: id.h:94
NODE_LASGN
@ NODE_LASGN
Definition: node.h:57
iseq_adjust_data::link
LINK_ELEMENT link
Definition: compile.c:87
idUMinus
@ idUMinus
Definition: id.h:82
NUM2LONG
#define NUM2LONG(x)
Definition: ruby.h:679
LONG_LONG
#define LONG_LONG
Definition: rb_mjit_min_header-2.7.0.h:3939
iseq_link_anchor
Definition: compile.c:50
ibf_object_complex_rational::b
long b
Definition: compile.c:10744
rb_iseq_constant_body::rest_start
int rest_start
Definition: vm_core.h:369
rb_hash_aref
VALUE rb_hash_aref(VALUE hash, VALUE key)
Definition: hash.c:1964
st_init_numtable
st_table * st_init_numtable(void)
Definition: st.c:653
ne
#define ne(x, y)
Definition: time.c:82
NODE_ARGSPUSH
@ NODE_ARGSPUSH
Definition: node.h:107
NODE_FLIP2
@ NODE_FLIP2
Definition: node.h:122
NODE_FOR
@ NODE_FOR
Definition: node.h:44
ibf_object_class_index
ibf_object_class_index
Definition: compile.c:10708
FL_FREEZE
#define FL_FREEZE
Definition: ruby.h:1287
ERROR_ARGS
#define ERROR_ARGS
Definition: compile.c:416
ibf_offset_t
unsigned int ibf_offset_t
Definition: compile.c:9500
VALUE
unsigned long VALUE
Definition: ruby.h:102
NODE_CASE
@ NODE_CASE
Definition: node.h:36
index
int index
Definition: rb_mjit_min_header-2.7.0.h:11246
rb_id_attrset
ID rb_id_attrset(ID)
Definition: symbol.c:98
GET_VM
#define GET_VM()
Definition: vm_core.h:1764
rb_eArgError
VALUE rb_eArgError
Definition: error.c:923
rb_ast_body_struct
Definition: node.h:394
rb_iseq_location_struct::code_location
rb_code_location_t code_location
Definition: vm_core.h:278
encoding.h
DECL_BRANCH_BASE
#define DECL_BRANCH_BASE(branches, first_line, first_column, last_line, last_column, type)
Definition: compile.c:271
ZALLOC
#define ZALLOC(type)
Definition: ruby.h:1666
rb_ary_store
void rb_ary_store(VALUE ary, long idx, VALUE val)
Definition: array.c:1079
offsetof
#define offsetof(p_type, field)
Definition: addrinfo.h:186
COMPILE_POPPED
#define COMPILE_POPPED(anchor, desc, node)
Definition: compile.c:344
NODE_OP_ASGN2
@ NODE_OP_ASGN2
Definition: node.h:65
NODE_ARGSCAT
@ NODE_ARGSCAT
Definition: node.h:106
LABEL_REF
#define LABEL_REF(label)
Definition: compile.c:230
rb_eSyntaxError
VALUE rb_eSyntaxError
Definition: error.c:938
RB_TYPE_P
#define RB_TYPE_P(obj, type)
Definition: ruby.h:560
iseq_insn_data::operands
VALUE * operands
Definition: compile.c:79
rb_xmalloc_mul_add
void * rb_xmalloc_mul_add(size_t x, size_t y, size_t z)
Definition: gc.c:10156
iseq_catch_table_entry
Definition: iseq.h:225
TYPE
#define TYPE(x)
Definition: ruby.h:554
idEqTilde
@ idEqTilde
Definition: id.h:103
ISEQ_NOT_LOADED_YET
#define ISEQ_NOT_LOADED_YET
Definition: iseq.h:85
CPDEBUG
#define CPDEBUG
debug function(macro) interface depend on CPDEBUG if it is less than 0, runtime option is in effect.
Definition: compile.c:126
rb_args_info::pre_args_num
int pre_args_num
Definition: node.h:435
nd_last_lineno
#define nd_last_lineno(n)
Definition: node.h:207
NODE_DOT2
@ NODE_DOT2
Definition: node.h:120
NODE_EVSTR
@ NODE_EVSTR
Definition: node.h:98
debug_node_start
#define debug_node_start(node)
Definition: compile.c:174
idSucc
@ idSucc
Definition: rb_mjit_min_header-2.7.0.h:8702
ibf_object_bignum::slen
ssize_t slen
Definition: compile.c:10735
RUBY_EVENT_END
#define RUBY_EVENT_END
Definition: ruby.h:2244
VM_ENV_DATA_SIZE
#define VM_ENV_DATA_SIZE
Definition: vm_core.h:1191
RSTRING_LENINT
#define RSTRING_LENINT(str)
Definition: ruby.h:1017
ibf_object_symbol::str
long str
Definition: compile.c:10748
DEFINED_REF
@ DEFINED_REF
Definition: iseq.h:300
int
__inline__ int
Definition: rb_mjit_min_header-2.7.0.h:2839
IS_TRACE
#define IS_TRACE(link)
Definition: compile.c:367
iseq_catch_table_entry::end
unsigned int end
Definition: iseq.h:250
rb_args_info::kw_rest_arg
NODE * kw_rest_arg
Definition: node.h:444
cdhash_set_label_struct::len
int len
Definition: compile.c:1853
FIXNUM_INC
#define FIXNUM_INC(n, i)
Definition: compile.c:35
iseq_compile_data_ensure_node_stack
Definition: compile.c:104
rb_to_array_type
VALUE rb_to_array_type(VALUE ary)
Definition: array.c:902
rb_iseq_path
VALUE rb_iseq_path(const rb_iseq_t *iseq)
Definition: iseq.c:1027
rb_iseq_struct::loader
struct rb_iseq_struct::@181::@182 loader
rb_iseq_constant_body::ISEQ_TYPE_EVAL
@ ISEQ_TYPE_EVAL
Definition: vm_core.h:319
INTEGER_PACK_LITTLE_ENDIAN
#define INTEGER_PACK_LITTLE_ENDIAN
Definition: intern.h:162
debug_list
#define debug_list(anc)
Definition: compile.c:1093
INSERT_BEFORE_INSN
#define INSERT_BEFORE_INSN(next, line, insn)
Definition: compile.c:208
NODE_UNTIL
@ NODE_UNTIL
Definition: node.h:42
rb_args_info::post_init
NODE * post_init
Definition: node.h:433
UINT2NUM
#define UINT2NUM(x)
Definition: ruby.h:1610
ADD_INSN2
#define ADD_INSN2(seq, line, insn, op1, op2)
Definition: compile.c:235
rb_iseq_constant_body::location
rb_iseq_location_t location
Definition: vm_core.h:399
rb_inspect
VALUE rb_inspect(VALUE)
Convenient wrapper of Object::inspect.
Definition: object.c:551
NODE_CVASGN
@ NODE_CVASGN
Definition: node.h:63
NODE_AND
@ NODE_AND
Definition: node.h:54
EXPECT_NODE_NONULL
#define EXPECT_NODE_NONULL(prefix, parent, ndtype, errval)
Definition: compile.c:430
rb_code_position_struct::lineno
int lineno
Definition: node.h:131
NODE_LIT
@ NODE_LIT
Definition: node.h:93
iseq_label_data::sp
int sp
Definition: compile.c:67
rb_id_table
Definition: id_table.c:40
rb_iseq_ibf_load_bytes
const rb_iseq_t * rb_iseq_ibf_load_bytes(const char *bytes, size_t size)
Definition: compile.c:11616
rb_iseq_constant_body::keyword
const struct rb_iseq_constant_body::@178::rb_iseq_param_keyword * keyword
INVALID_ISEQ_TYPE
#define INVALID_ISEQ_TYPE(type)
rb_iseq_constant_body::local_iseq
struct rb_iseq_struct * local_iseq
Definition: vm_core.h:418
rb_id_table_insert
int rb_id_table_insert(struct rb_id_table *tbl, ID id, VALUE val)
Definition: id_table.c:256
rb_str_dup
VALUE rb_str_dup(VALUE)
Definition: string.c:1516
accessor_args::arg
VALUE arg
Definition: compile.c:9417
rb_eIndexError
VALUE rb_eIndexError
Definition: error.c:924
RUBY_EVENT_B_RETURN
#define RUBY_EVENT_B_RETURN
Definition: ruby.h:2254
NODE_MASGN
@ NODE_MASGN
Definition: node.h:56
rb_iseq_location_struct::first_lineno
VALUE first_lineno
Definition: vm_core.h:276
rb_str_cat2
#define rb_str_cat2
Definition: intern.h:912
ibf_object_complex_rational::a
long a
Definition: compile.c:10744
ibf_object_hash::len
long len
Definition: compile.c:10722
BIN
#define BIN(n)
Definition: rb_mjit_min_header-2.7.0.h:11968
ci
rb_control_frame_t struct rb_calling_info const struct rb_call_info * ci
Definition: rb_mjit_min_header-2.7.0.h:15146
Qundef
#define Qundef
Definition: ruby.h:470
ibf_header::minor_version
unsigned int minor_version
Definition: compile.c:9514
NODE_DXSTR
@ NODE_DXSTR
Definition: node.h:97
CHAR_BIT
#define CHAR_BIT
Definition: ruby.h:227
NODE_OPCALL
@ NODE_OPCALL
Definition: node.h:70
DEFINED_YIELD
@ DEFINED_YIELD
Definition: iseq.h:292
NODE_SPECIAL_REQUIRED_KEYWORD
#define NODE_SPECIAL_REQUIRED_KEYWORD
Definition: node.h:381
GET_EC
#define GET_EC()
Definition: vm_core.h:1766
rb_long2int
#define rb_long2int(n)
Definition: ruby.h:350
Data_Wrap_Struct
#define Data_Wrap_Struct(klass, mark, free, sval)
Definition: ruby.h:1211
ensure_range
Definition: compile.c:98
iseq_label_data::rescued
unsigned int rescued
Definition: compile.c:70
iseq_link_element::type
enum iseq_link_element::@1 type
idLE
@ idLE
Definition: id.h:93
ptr
struct RIMemo * ptr
Definition: debug.c:74
idUPlus
@ idUPlus
Definition: id.h:81
NODE_SPECIAL_NO_REST_KEYWORD
#define NODE_SPECIAL_NO_REST_KEYWORD
Definition: node.h:386
rb_call_info_kw_arg::keyword_len
int keyword_len
Definition: vm_core.h:241
Qfalse
#define Qfalse
Definition: ruby.h:467
idCall
@ idCall
Definition: rb_mjit_min_header-2.7.0.h:8727
ibf_load
Definition: compile.c:9547
iseq_insn_data::sc_state
int sc_state
Definition: compile.c:78
debugp_param
#define debugp_param(header, value)
Definition: compile.c:173
DBL2NUM
#define DBL2NUM(dbl)
Definition: ruby.h:967
iseq_link_element::next
struct iseq_link_element * next
Definition: compile.c:46
RNode::flags
VALUE flags
Definition: node.h:150
ssize_t
_ssize_t ssize_t
Definition: rb_mjit_min_header-2.7.0.h:1329
NODE_OP_ASGN_AND
@ NODE_OP_ASGN_AND
Definition: node.h:66
LABEL_RESCUE_BEG
@ LABEL_RESCUE_BEG
Definition: compile.c:57
iseq_link_element::prev
struct iseq_link_element * prev
Definition: compile.c:47
RARRAY_ASET
#define RARRAY_ASET(a, i, v)
Definition: ruby.h:1102
APPEND_LABEL
#define APPEND_LABEL(seq, before, label)
Definition: compile.c:315
CHECK_EVENT
#define CHECK_EVENT(ev)
rb_id2str
#define rb_id2str(id)
Definition: vm_backtrace.c:30
iseq_adjust_data::label
LABEL * label
Definition: compile.c:88
ibf_object_complex_rational
Definition: compile.c:10743
LABEL_RESCUE_NONE
@ LABEL_RESCUE_NONE
Definition: compile.c:56
rb_builtin_function::index
const int index
Definition: builtin.h:12
rb_iseq_constant_body::parent_iseq
const struct rb_iseq_struct * parent_iseq
Definition: vm_core.h:417
NODE_DASGN
@ NODE_DASGN
Definition: node.h:58
ADD_TRACE_BRANCH_COVERAGE
#define ADD_TRACE_BRANCH_COVERAGE(seq, first_line, first_column, last_line, last_column, type, branches)
Definition: compile.c:286
rb_iseq_struct::aux
union rb_iseq_struct::@181 aux
RUBY_ALIGNOF
#define RUBY_ALIGNOF(type)
Definition: defines.h:517
SPECIAL_CONST_P
#define SPECIAL_CONST_P(x)
Definition: ruby.h:1313
printf
int int int printf(const char *__restrict,...) __attribute__((__format__(__printf__
NODE_BLOCK
@ NODE_BLOCK
Definition: node.h:33
VM_CALL_KWARG
#define VM_CALL_KWARG
Definition: vm_core.h:1107
id_core_undef_method
@ id_core_undef_method
Definition: id.h:122
local_size
rb_control_frame_t struct rb_calling_info const rb_callable_method_entry_t int int int local_size
Definition: rb_mjit_min_header-2.7.0.h:14544
ADD_INSN1
#define ADD_INSN1(seq, line, insn, op1)
Definition: compile.c:216
rb_vm_insn_addr2insn
int rb_vm_insn_addr2insn(const void *)
Definition: iseq.c:3111
rb_ibf_load_iseq_complete
void rb_ibf_load_iseq_complete(rb_iseq_t *iseq)
Definition: compile.c:11436
ADD_CATCH_ENTRY
#define ADD_CATCH_ENTRY(type, ls, le, iseqv, lc)
Definition: compile.c:326
NUM2LL
#define NUM2LL(x)
NULL
#define NULL
Definition: _sdbm.c:101
ibf_object_struct_range::excl
int excl
Definition: compile.c:10731
T_COMPLEX
#define T_COMPLEX
Definition: ruby.h:542
ISEQ_PC2BRANCHINDEX
#define ISEQ_PC2BRANCHINDEX(iseq)
Definition: iseq.h:39
iseq_catch_table_entry::CATCH_TYPE_REDO
@ CATCH_TYPE_REDO
Definition: iseq.h:231
NODE_ERRINFO
@ NODE_ERRINFO
Definition: node.h:128
rb_args_info::first_post_arg
ID first_post_arg
Definition: node.h:438
DEFINED_TRUE
@ DEFINED_TRUE
Definition: iseq.h:295
FL_TEST
#define FL_TEST(x, f)
Definition: ruby.h:1353
vm_debug.h
IBF_OBJECT_DATA_ENCODING
@ IBF_OBJECT_DATA_ENCODING
Definition: compile.c:10740
ibf_load::str
VALUE str
Definition: compile.c:9553
DEFINED_FALSE
@ DEFINED_FALSE
Definition: iseq.h:296
OPERAND_AT
#define OPERAND_AT(insn, idx)
Definition: compile.c:358
rb_method_for_self_aref
const rb_iseq_t * rb_method_for_self_aref(VALUE name, VALUE arg, rb_insn_func_t func)
Definition: compile.c:9476
PRIsVALUE
#define PRIsVALUE
Definition: ruby.h:166
ensure_range::next
struct ensure_range * next
Definition: compile.c:101
RUBY_EVENT_CALL
#define RUBY_EVENT_CALL
Definition: ruby.h:2245
RUBY_T_MASK
@ RUBY_T_MASK
Definition: ruby.h:518
rb_enc_from_encoding
VALUE rb_enc_from_encoding(rb_encoding *encoding)
Definition: encoding.c:116
rb_is_attrset_id
int rb_is_attrset_id(ID id)
Definition: symbol.c:878
CHECK_ARRAY
#define CHECK_ARRAY(v)
Definition: compile.c:9109
last
unsigned int last
Definition: nkf.c:4324
NODE_KW_ARG
@ NODE_KW_ARG
Definition: node.h:104
NODE_DSTR
@ NODE_DSTR
Definition: node.h:95
FL_SET
#define FL_SET(x, f)
Definition: ruby.h:1359
DEFINED_CVAR
@ DEFINED_CVAR
Definition: iseq.h:289
VM_CHECKMATCH_TYPE_WHEN
@ VM_CHECKMATCH_TYPE_WHEN
Definition: vm_core.h:1077
ibf_header::major_version
unsigned int major_version
Definition: compile.c:9513
ibf_load_buffer::buff
const char * buff
Definition: compile.c:9539
st_insert
int st_insert(st_table *tab, st_data_t key, st_data_t value)
Definition: st.c:1171
FIX2LONG
#define FIX2LONG(x)
Definition: ruby.h:394
ID2SYM
#define ID2SYM(x)
Definition: ruby.h:414
strlen
size_t strlen(const char *)
iseq_catch_table::size
unsigned int size
Definition: rb_mjit_min_header-2.7.0.h:10860
id_core_hash_merge_kwd
@ id_core_hash_merge_kwd
Definition: id.h:127
OBJ_FREEZE
#define OBJ_FREEZE(x)
Definition: ruby.h:1377
T_SYMBOL
#define T_SYMBOL
Definition: ruby.h:540
NODE_SPLAT
@ NODE_SPLAT
Definition: node.h:108
INIT_ANCHOR
#define INIT_ANCHOR(name)
Definition: compile.c:456
NODE_ITER
@ NODE_ITER
Definition: node.h:43
rb_mark_set
void rb_mark_set(st_table *tbl)
Definition: gc.c:4798
rb_call_info::orig_argc
int orig_argc
Definition: internal.h:2391
NODE_CDECL
@ NODE_CDECL
Definition: node.h:62
rb_iseq_constant_body
Definition: vm_core.h:311
strncmp
int strncmp(const char *, const char *, size_t)
rb_iseq_constant_body::opt_table
const VALUE * opt_table
Definition: vm_core.h:374
rb_args_info::kw_args
NODE * kw_args
Definition: node.h:443
ibf_object_data_type
ibf_object_data_type
Definition: compile.c:10739
FLUSH_CHUNK
#define FLUSH_CHUNK(newarrayinsn)
rb_big_hash
VALUE rb_big_hash(VALUE x)
Definition: bignum.c:6726
iseq_compile_data_storage
Definition: iseq.h:274
idLT
@ idLT
Definition: id.h:92
NODE_CVAR
@ NODE_CVAR
Definition: node.h:87
rb_snum_t
signed long rb_snum_t
Definition: vm_core.h:182
rb_eNoMatchingPatternError
VALUE rb_eNoMatchingPatternError
Definition: error.c:935
rb_hash_new_with_size
MJIT_FUNC_EXPORTED VALUE rb_hash_new_with_size(st_index_t size)
Definition: hash.c:1507
rb_iseq_constant_body_alloc
struct rb_iseq_constant_body * rb_iseq_constant_body_alloc(void)
Definition: iseq.c:433
RARRAY_LENINT
#define RARRAY_LENINT(ary)
Definition: ruby.h:1071
v
int VALUE v
Definition: rb_mjit_min_header-2.7.0.h:12332
rb_cRange
RUBY_EXTERN VALUE rb_cRange
Definition: ruby.h:2040
iseq_link_element::ISEQ_ELEMENT_INSN
@ ISEQ_ELEMENT_INSN
Definition: compile.c:42
rb_args_info::pre_init
NODE * pre_init
Definition: node.h:432
ALLOC_N
#define ALLOC_N(type, n)
Definition: ruby.h:1663
cdhash_set_label_struct
Definition: compile.c:1850
rb_kwarg_call_data::ci_kw
struct rb_call_info_with_kwarg ci_kw
Definition: vm_core.h:259
NODE_IN
@ NODE_IN
Definition: node.h:40
ADD_SEND
#define ADD_SEND(seq, line, id, argc)
Definition: compile.c:244
rb_ast_body_struct::compile_option
VALUE compile_option
Definition: node.h:396
cc
const struct rb_call_cache * cc
Definition: rb_mjit_min_header-2.7.0.h:13228
NODE_ZSUPER
@ NODE_ZSUPER
Definition: node.h:75
rb_call_info_kw_arg
Definition: vm_core.h:240
rb_iseq_original_iseq
VALUE * rb_iseq_original_iseq(const rb_iseq_t *iseq)
Definition: compile.c:778
NODE_SUPER
@ NODE_SUPER
Definition: node.h:74
NODE_LAMBDA
@ NODE_LAMBDA
Definition: node.h:133
DECL_ANCHOR
#define DECL_ANCHOR(name)
Definition: compile.c:454
ibf_load_buffer::obj_list_offset
ibf_offset_t obj_list_offset
Definition: compile.c:9544
TRACE
struct iseq_trace_data TRACE
rb_raise
void rb_raise(VALUE exc, const char *fmt,...)
Definition: error.c:2669
rb_str_hash_cmp
int rb_str_hash_cmp(VALUE, VALUE)
Definition: string.c:3173
NODE_VCALL
@ NODE_VCALL
Definition: node.h:72
const
#define const
Definition: strftime.c:103
rb_reg_compile
VALUE rb_reg_compile(VALUE str, int options, const char *sourcefile, int sourceline)
Definition: re.c:2952
NODE_VALIAS
@ NODE_VALIAS
Definition: node.h:113
rb_ary_entry
VALUE rb_ary_entry(VALUE ary, long offset)
Definition: array.c:1512
debug_compile
#define debug_compile(msg, v)
Definition: compile.c:184
rb_call_cache
Definition: internal.h:2355
INSERT_BEFORE_INSN1
#define INSERT_BEFORE_INSN1(next, line, insn, op1)
Definition: compile.c:221
rb_execution_context_struct::cfp
rb_control_frame_t * cfp
Definition: vm_core.h:847
rb_iseq_constant_body::local_table
const ID * local_table
Definition: vm_core.h:411
ADD_SETLOCAL
#define ADD_SETLOCAL(seq, line, idx, level)
Definition: compile.c:309
NUM2UINT
#define NUM2UINT(x)
Definition: ruby.h:716
ibf_object_symbol
Definition: compile.c:10747
if
if((ID)(DISPID) nameid !=nameid)
Definition: win32ole.c:357
NODE_DEFS
@ NODE_DEFS
Definition: node.h:111
ibf_object_struct_range::beg
long beg
Definition: compile.c:10729
VM_DEFINECLASS_FLAG_SCOPED
#define VM_DEFINECLASS_FLAG_SCOPED
Definition: vm_core.h:1002
obj
const VALUE VALUE obj
Definition: rb_mjit_min_header-2.7.0.h:5742
ibf_dump_buffer::obj_list
VALUE obj_list
Definition: compile.c:9526
NODE_UNLESS
@ NODE_UNLESS
Definition: node.h:35
ibf_dump::current_buffer
struct ibf_dump_buffer * current_buffer
Definition: compile.c:9533
ge
#define ge(x, y)
Definition: time.c:86
gt
#define gt(x, y)
Definition: time.c:84
ADD_INSN3
#define ADD_INSN3(seq, line, insn, op1, op2, op3)
Definition: compile.c:239
iseq_label_data::link
LINK_ELEMENT link
Definition: compile.c:63
rb_fstring_cstr
#define rb_fstring_cstr(str)
Definition: rb_mjit_min_header-2.7.0.h:7718
rb_intern
#define rb_intern(str)
rb_enc_get_index
int rb_enc_get_index(VALUE obj)
Definition: encoding.c:779
ISEQ_TRANSLATED
#define ISEQ_TRANSLATED
Definition: iseq.h:87
rb_global_entry::id
ID id
Definition: internal.h:1352
id_core_set_method_alias
@ id_core_set_method_alias
Definition: id.h:120
memcpy
void * memcpy(void *__restrict, const void *__restrict, size_t)
rb_iseq_constant_body::param
struct rb_iseq_constant_body::@178 param
parameter information
iseq_trace_data::event
rb_event_flag_t event
Definition: compile.c:94
ADD_CALL_RECEIVER
#define ADD_CALL_RECEIVER(seq, line)
Definition: compile.c:253
EXPECT_NODE
#define EXPECT_NODE(prefix, node, ndtype, errval)
Definition: compile.c:418
IBF_OBJECT_CLASS_OBJECT
@ IBF_OBJECT_CLASS_OBJECT
Definition: compile.c:10709
NODE_DEFN
@ NODE_DEFN
Definition: node.h:110
idASET
@ idASET
Definition: id.h:106
rb_args_info::opt_args
NODE * opt_args
Definition: node.h:446
rb_iseq_constant_body::ISEQ_TYPE_BLOCK
@ ISEQ_TYPE_BLOCK
Definition: vm_core.h:315
VM_DEFINECLASS_FLAG_HAS_SUPERCLASS
#define VM_DEFINECLASS_FLAG_HAS_SUPERCLASS
Definition: vm_core.h:1003
rb_iseq_constant_body::lead_num
int lead_num
Definition: vm_core.h:367
ISEQ_BRANCH_COVERAGE
#define ISEQ_BRANCH_COVERAGE(iseq)
Definition: iseq.h:37
RUBY_EVENT_COVERAGE_LINE
#define RUBY_EVENT_COVERAGE_LINE
Definition: vm_core.h:1956
rb_iseqw_to_iseq
const rb_iseq_t * rb_iseqw_to_iseq(VALUE iseqw)
Definition: iseq.c:1350
idMULT
@ idMULT
Definition: id.h:87
DATA_PTR
#define DATA_PTR(dta)
Definition: ruby.h:1175
fprintf
int fprintf(FILE *__restrict, const char *__restrict,...) __attribute__((__format__(__printf__
rb_args_info
Definition: node.h:431
rb_hash_rehash
VALUE rb_hash_rehash(VALUE hash)
Definition: hash.c:1885
ibf_dump::global_buffer
struct ibf_dump_buffer global_buffer
Definition: compile.c:9532
TAG_REDO
#define TAG_REDO
Definition: vm_core.h:202
ibf_object_header::frozen
unsigned int frozen
Definition: compile.c:10704
rb_ary_pattern_info::post_args
NODE * post_args
Definition: node.h:456
rb_encoding
const typedef OnigEncodingType rb_encoding
Definition: encoding.h:115
ensure_range::end
LABEL * end
Definition: compile.c:100
idLTLT
@ idLTLT
Definition: id.h:90
RHASH_SIZE
#define RHASH_SIZE(hsh)
Definition: fbuffer.h:8
idAREF
@ idAREF
Definition: id.h:105
rb_iseqw_new
VALUE rb_iseqw_new(const rb_iseq_t *)
Definition: iseq.c:1157
rb_ary_pattern_info::rest_arg
NODE * rest_arg
Definition: node.h:455
rb_iseq_init_trace
void rb_iseq_init_trace(rb_iseq_t *iseq)
Definition: iseq.c:623
ibf_dump::iseq_table
st_table * iseq_table
Definition: compile.c:9531
iseq_label_data::sc_state
int sc_state
Definition: compile.c:66
rb_iseq_mark_insn_storage
void rb_iseq_mark_insn_storage(struct iseq_compile_data_storage *storage)
Definition: compile.c:9197
st_init_numtable_with_size
st_table * st_init_numtable_with_size(st_index_t size)
Definition: st.c:660
VM_CALL_KW_SPLAT
#define VM_CALL_KW_SPLAT
Definition: vm_core.h:1108
VM_SPECIAL_OBJECT_CBASE
@ VM_SPECIAL_OBJECT_CBASE
Definition: vm_core.h:1116
iseq.h
idNeq
@ idNeq
Definition: id.h:98
LABEL_FORMAT
#define LABEL_FORMAT
Definition: compile.c:191
rb_vm_get_insns_address_table
const void ** rb_vm_get_insns_address_table(void)
Definition: vm_exec.c:126
rb_iseq_location_struct::label
VALUE label
Definition: vm_core.h:275
rb_big_cmp
VALUE rb_big_cmp(VALUE x, VALUE y)
Definition: bignum.c:5419
rb_insn_func_t
rb_control_frame_t *FUNC_FASTCALL rb_insn_func_t(rb_execution_context_t *, rb_control_frame_t *)
Definition: vm_core.h:1143
rb_enc_from_index
rb_encoding * rb_enc_from_index(int index)
Definition: encoding.c:609
ISEQ_ARG_DECLARE
#define ISEQ_ARG_DECLARE
Definition: compile.c:478
ADD_GETLOCAL
#define ADD_GETLOCAL(seq, line, idx, level)
Definition: compile.c:308
rb_iseq_constant_body::local_table_size
unsigned int local_table_size
Definition: vm_core.h:435
rb_iseq_constant_body::is_entries
union iseq_inline_storage_entry * is_entries
Definition: vm_core.h:420
rb_ary_cat
VALUE rb_ary_cat(VALUE ary, const VALUE *argv, long len)
Definition: array.c:1208
ensure_range::begin
LABEL * begin
Definition: compile.c:99
rb_args_info::ruby2_keywords
unsigned int ruby2_keywords
Definition: node.h:448
SP_INSN
#define SP_INSN(opt)
rb_global_entry
struct rb_global_entry * rb_global_entry(ID)
Definition: variable.c:326
rb_ary_tmp_new
VALUE rb_ary_tmp_new(long capa)
Definition: array.c:768
COVERAGE_TARGET_ONESHOT_LINES
#define COVERAGE_TARGET_ONESHOT_LINES
Definition: internal.h:2216
i
uint32_t i
Definition: rb_mjit_min_header-2.7.0.h:5464
METHOD
Definition: proc.c:33
NODE_CLASS
@ NODE_CLASS
Definition: node.h:115
VM_CALL_VCALL
#define VM_CALL_VCALL
Definition: vm_core.h:1104
idEmptyP
@ idEmptyP
Definition: id.h:114
RB_OBJ_WRITTEN
#define RB_OBJ_WRITTEN(a, oldv, b)
Definition: ruby.h:1509
rb_method_for_self_aset
const rb_iseq_t * rb_method_for_self_aset(VALUE name, VALUE arg, rb_insn_func_t func)
Definition: compile.c:9485
NODE_IF
@ NODE_IF
Definition: node.h:34
rb_id2sym
VALUE rb_id2sym(ID)
Definition: symbol.c:776
NODE_ENSURE
@ NODE_ENSURE
Definition: node.h:53
ibf_header::magic
char magic[4]
Definition: compile.c:9512
sym
#define sym(x)
Definition: date_core.c:3716
COMPILE
#define COMPILE(anchor, desc, node)
Definition: compile.c:339
rb_iseq_defined_string
VALUE rb_iseq_defined_string(enum defined_type type)
Definition: iseq.c:3033
rb_builtin_type_name
const char * rb_builtin_type_name(int t)
Definition: error.c:761
rb_iseq_build_from_ary
void rb_iseq_build_from_ary(rb_iseq_t *iseq, VALUE misc, VALUE locals, VALUE params, VALUE exception, VALUE body)
Definition: compile.c:9249
NODE_MATCH2
@ NODE_MATCH2
Definition: node.h:91
rb_iseq_constant_body::ci_size
unsigned int ci_size
Definition: vm_core.h:437
INT_MAX
#define INT_MAX
Definition: rb_mjit_min_header-2.7.0.h:4052
VM_THROW_NO_ESCAPE_FLAG
@ VM_THROW_NO_ESCAPE_FLAG
Definition: vm_core.h:209
rb_iseq_constant_body::variable
struct rb_iseq_constant_body::@179 variable
rb_node_case_when_optimizable_literal
VALUE rb_node_case_when_optimizable_literal(const NODE *const node)
Definition: compile.c:4288
long
#define long
Definition: rb_mjit_min_header-2.7.0.h:2880
iseq_inline_cache_entry
Definition: vm_core.h:220
rb_p
void rb_p(VALUE)
Definition: io.c:7798
rb_iseq_constant_body::size
unsigned int size
Definition: vm_core.h:365
FL_UNSET
#define FL_UNSET(x, f)
Definition: ruby.h:1361
LINK_ANCHOR
struct iseq_link_anchor LINK_ANCHOR
rb_hash_lookup
VALUE rb_hash_lookup(VALUE hash, VALUE key)
Definition: hash.c:1990
ADD_ADJUST_RESTORE
#define ADD_ADJUST_RESTORE(seq, label)
Definition: compile.c:321
IBF_W
#define IBF_W(b, type, n)
Definition: compile.c:9632
rb_ary_push
VALUE rb_ary_push(VALUE ary, VALUE item)
Definition: array.c:1195
rb_call_info_with_kwarg::kw_arg
struct rb_call_info_kw_arg * kw_arg
Definition: vm_core.h:247
rb_code_position_struct::column
int column
Definition: node.h:132
st_index_t
st_data_t st_index_t
Definition: st.h:50
iseq_insn_data::line_no
int line_no
Definition: compile.c:81
NODE_CASE3
@ NODE_CASE3
Definition: node.h:38
st_hash_type
Definition: st.h:61
rb_iseq_constant_body::catch_table
struct iseq_catch_table * catch_table
Definition: vm_core.h:414
rb_complex_new
VALUE rb_complex_new(VALUE x, VALUE y)
Definition: complex.c:1527
DEFINED_GVAR
@ DEFINED_GVAR
Definition: iseq.h:288
va_end
#define va_end(v)
Definition: rb_mjit_min_header-2.7.0.h:3979
cnt
rb_atomic_t cnt[RUBY_NSIG]
Definition: signal.c:503
idGE
@ idGE
Definition: id.h:95
rb_obj_freeze
VALUE rb_obj_freeze(VALUE)
Make the object unmodifiable.
Definition: object.c:1080
idSize
@ idSize
Definition: rb_mjit_min_header-2.7.0.h:8700
iseq_insn_data::operand_size
int operand_size
Definition: compile.c:77
vm_core.h
stderr
#define stderr
Definition: rb_mjit_min_header-2.7.0.h:1485
fflush
int fflush(FILE *)
rb_hash_bulk_insert
void rb_hash_bulk_insert(long argc, const VALUE *argv, VALUE hash)
Definition: hash.c:4515
min_argc
const rb_iseq_t const int const int min_argc
Definition: rb_mjit_min_header-2.7.0.h:13505
rb_iseq_constant_body::type
enum rb_iseq_constant_body::iseq_type type
CHECK
#define CHECK(sub)
Definition: compile.c:448
NODE_DASGN_CURR
@ NODE_DASGN_CURR
Definition: node.h:59
rb_call_data::cc
struct rb_call_cache cc
Definition: internal.h:2394
rb_eTypeError
VALUE rb_eTypeError
Definition: error.c:922
IBF_WV
#define IBF_WV(variable)
Definition: compile.c:9633
RBASIC_CLASS
#define RBASIC_CLASS(obj)
Definition: ruby.h:906
NODE_COLON2
@ NODE_COLON2
Definition: node.h:118
NODE_DOT3
@ NODE_DOT3
Definition: node.h:121
SYM
#define SYM(s)
idPLUS
@ idPLUS
Definition: id.h:85
node_type
node_type
Definition: node.h:22
rb_call_info::mid
ID mid
Definition: internal.h:2389
LVAR_ERRINFO
#define LVAR_ERRINFO
Definition: compile.c:187
entries
struct iseq_catch_table_entry entries[]
Definition: rb_mjit_min_header-2.7.0.h:10827
rb_ary_set_len
void rb_ary_set_len(VALUE ary, long len)
Definition: array.c:1932
rb_integer_unpack
VALUE rb_integer_unpack(const void *words, size_t numwords, size_t wordsize, size_t nails, int flags)
Definition: bignum.c:3633
iseq_trace_data::data
long data
Definition: compile.c:95
rb_iseq_compile_node
VALUE rb_iseq_compile_node(rb_iseq_t *iseq, const NODE *node)
Definition: compile.c:644
IBF_MINOR_VERSION
#define IBF_MINOR_VERSION
Definition: compile.c:9508
ibf_load::iseq
rb_iseq_t * iseq
Definition: compile.c:9552
NODE_BREAK
@ NODE_BREAK
Definition: node.h:46
rb_eRuntimeError
VALUE rb_eRuntimeError
Definition: error.c:920
NODE_GVAR
@ NODE_GVAR
Definition: node.h:84
ALLOCA_N
#define ALLOCA_N(type, n)
Definition: ruby.h:1684
rb_size_mul_or_raise
size_t rb_size_mul_or_raise(size_t x, size_t y, VALUE exc)
Definition: gc.c:192
LABEL_RESCUE_TYPE_MAX
@ LABEL_RESCUE_TYPE_MAX
Definition: compile.c:59
VM_SPECIAL_OBJECT_VMCORE
@ VM_SPECIAL_OBJECT_VMCORE
Definition: vm_core.h:1115
mod
#define mod(x, y)
Definition: date_strftime.c:28
RARRAY_AREF
#define RARRAY_AREF(a, i)
Definition: ruby.h:1101
rb_control_frame_struct
Definition: vm_core.h:760
NODE_XSTR
@ NODE_XSTR
Definition: node.h:96
RTYPEDDATA_DATA
#define RTYPEDDATA_DATA(v)
Definition: ruby.h:1179
StringValuePtr
#define StringValuePtr(v)
Definition: ruby.h:603
IBF_ZERO
#define IBF_ZERO(variable)
Definition: compile.c:9636
VM_CALL_SUPER
#define VM_CALL_SUPER
Definition: vm_core.h:1110
ADD_TRACE
#define ADD_TRACE(seq, event)
Definition: compile.c:265
size
int size
Definition: encoding.c:58
rb_iseq_constant_body::block_start
int block_start
Definition: vm_core.h:372
ADD_LABEL
#define ADD_LABEL(seq, label)
Definition: compile.c:312
FALSE
#define FALSE
Definition: nkf.h:174
ibf_object_regexp
Definition: compile.c:10716
rb_ast_body_struct::line_count
int line_count
Definition: node.h:397
rb_iseq_constant_body::iseq_insn_info::body
const struct iseq_insn_info_entry * body
Definition: vm_core.h:403
rb_ary_resize
VALUE rb_ary_resize(VALUE ary, long len)
expands or shrinks ary to len elements.
Definition: array.c:1955
FIXNUM_P
#define FIXNUM_P(f)
Definition: ruby.h:396
idUScore
@ idUScore
Definition: rb_mjit_min_header-2.7.0.h:8740
LABEL_RESCUE_END
@ LABEL_RESCUE_END
Definition: compile.c:58
NODE_ARGS
@ NODE_ARGS
Definition: node.h:101
VM_DEFINECLASS_TYPE_CLASS
@ VM_DEFINECLASS_TYPE_CLASS
Definition: vm_core.h:994
ibf_load::loader_obj
VALUE loader_obj
Definition: compile.c:9551
id_core_set_postexe
@ id_core_set_postexe
Definition: id.h:125
TAG_RETRY
#define TAG_RETRY
Definition: vm_core.h:201
accessor_args::func
rb_insn_func_t func
Definition: compile.c:9418
nd_first_column
#define nd_first_column(n)
Definition: node.h:198
ruby_xmalloc2
void * ruby_xmalloc2(size_t n, size_t size)
Definition: gc.c:11960
IBF_W_ALIGN
#define IBF_W_ALIGN(type)
Definition: compile.c:9630
NODE_DVAR
@ NODE_DVAR
Definition: node.h:83
rb_iseq_constant_body::flags
struct rb_iseq_constant_body::@178::@180 flags
rb_hash_foreach
void rb_hash_foreach(VALUE hash, rb_foreach_func *func, VALUE farg)
Definition: hash.c:1461
list
struct rb_encoding_entry * list
Definition: encoding.c:56
BADINSN_ERROR
#define BADINSN_ERROR
Definition: compile.c:1888
MEMZERO
#define MEMZERO(p, type, n)
Definition: ruby.h:1752
COMPILE_NG
#define COMPILE_NG
Definition: compile.c:446
memcmp
int memcmp(const void *s1, const void *s2, size_t len)
Definition: memcmp.c:7
rb_str_new_cstr
#define rb_str_new_cstr(str)
Definition: rb_mjit_min_header-2.7.0.h:6117
ibf_header::iseq_list_offset
ibf_offset_t iseq_list_offset
Definition: compile.c:9520
rb_syntax_error_append
VALUE rb_syntax_error_append(VALUE exc, VALUE file, int line, int column, rb_encoding *enc, const char *fmt, va_list args)
Definition: error.c:104
iseq_catch_table_entry::type
enum iseq_catch_table_entry::catch_type type
rb_iseq_location_struct::pathobj
VALUE pathobj
Definition: vm_core.h:273
iseq_insn_data::link
LINK_ELEMENT link
Definition: compile.c:75
IS_NEXT_INSN_ID
#define IS_NEXT_INSN_ID(link, insn)
Definition: compile.c:369
NODE_ALIAS
@ NODE_ALIAS
Definition: node.h:112
RB_OBJ_WRITE
#define RB_OBJ_WRITE(a, slot, b)
Definition: ruby.h:1508
rb_args_info::post_args_num
int post_args_num
Definition: node.h:436
VM_CALL_ARGS_BLOCKARG
#define VM_CALL_ARGS_BLOCKARG
Definition: vm_core.h:1102
rb_iseq_new_with_callback_callback_func::data
const void * data
Definition: vm_core.h:1022
iseq_link_anchor::last
LINK_ELEMENT * last
Definition: compile.c:52
CONST_ID
#define CONST_ID(var, str)
Definition: ruby.h:1841
iseq_compile_data_storage::size
unsigned int size
Definition: iseq.h:277
RREGEXP_SRC
#define RREGEXP_SRC(r)
Definition: ruby.h:1119
StringValueCStr
#define StringValueCStr(v)
Definition: ruby.h:604
ADD_SEQ
#define ADD_SEQ(seq1, seq2)
Definition: compile.c:200
NODE_OP_CDECL
@ NODE_OP_CDECL
Definition: node.h:68
IBF_OBJECT_CLASS_STANDARD_ERROR
@ IBF_OBJECT_CLASS_STANDARD_ERROR
Definition: compile.c:10711
link
int link(const char *, const char *)
Definition: win32.c:4931
key
key
Definition: openssl_missing.h:181
T_HASH
#define T_HASH
Definition: ruby.h:531
rb_builtin_function::func_ptr
const void *const func_ptr
Definition: builtin.h:8
ADJUST
struct iseq_adjust_data ADJUST
iseq_catch_table_entry::CATCH_TYPE_BREAK
@ CATCH_TYPE_BREAK
Definition: iseq.h:230
NODE_POSTARG
@ NODE_POSTARG
Definition: node.h:105
le
#define le(x, y)
Definition: time.c:85
NODE_SELF
@ NODE_SELF
Definition: node.h:124
ibf_header::extra_size
unsigned int extra_size
Definition: compile.c:9516
rb_args_info::no_kwarg
unsigned int no_kwarg
Definition: node.h:447
rb_cISeq
VALUE rb_cISeq
Definition: iseq.c:32
NODE_LVAR
@ NODE_LVAR
Definition: node.h:82
ZALLOC_N
#define ZALLOC_N(type, n)
Definition: ruby.h:1665
rb_report_bug_valist
void rb_report_bug_valist(VALUE file, int line, const char *fmt, va_list args)
Definition: error.c:710
VM_CALL_ARGS_SIMPLE
#define VM_CALL_ARGS_SIMPLE
Definition: vm_core.h:1105
rb_ary_clear
VALUE rb_ary_clear(VALUE ary)
Definition: array.c:3862
UNKNOWN_NODE
#define UNKNOWN_NODE(prefix, node, errval)
Definition: compile.c:437
rb_eNotImpError
VALUE rb_eNotImpError
Definition: error.c:932
NODE_STR
@ NODE_STR
Definition: node.h:94
CLASS_OF
#define CLASS_OF(v)
Definition: ruby.h:484
ADD_SEND_R
#define ADD_SEND_R(seq, line, id, argc, block, flag, keywords)
Definition: compile.c:262
fmt
const VALUE int int int int int int VALUE char * fmt
Definition: rb_mjit_min_header-2.7.0.h:6462
va_init_list
#define va_init_list(a, b)
Definition: win32ole.h:34
strcmp
int strcmp(const char *, const char *)
RCOMPLEX
#define RCOMPLEX(obj)
Definition: internal.h:811
DEFINED_NOT_DEFINED
@ DEFINED_NOT_DEFINED
Definition: iseq.h:284
INSN_OF
#define INSN_OF(insn)
Definition: compile.c:361
VM_SPECIAL_OBJECT_CONST_BASE
@ VM_SPECIAL_OBJECT_CONST_BASE
Definition: vm_core.h:1117
RARRAY_LEN
#define RARRAY_LEN(a)
Definition: ruby.h:1070
st_foreach
int st_foreach(st_table *tab, st_foreach_callback_func *func, st_data_t arg)
Definition: st.c:1718
rb_rational_new
VALUE rb_rational_new(VALUE, VALUE)
Definition: rational.c:1945
ibf_dump_buffer::str
VALUE str
Definition: compile.c:9525
iseq_label_data
Definition: compile.c:62
rb_reg_options
int rb_reg_options(VALUE)
Definition: re.c:3578
NODE_IVAR
@ NODE_IVAR
Definition: node.h:85
char
#define char
Definition: rb_mjit_min_header-2.7.0.h:2876
IBF_WP
#define IBF_WP(b, type, n)
Definition: compile.c:9634
DEFINED_SELF
@ DEFINED_SELF
Definition: iseq.h:294
rb_cObject
RUBY_EXTERN VALUE rb_cObject
Definition: ruby.h:2010
ibf_dump_buffer
Definition: compile.c:9524
rb_event_flag_t
uint32_t rb_event_flag_t
Definition: ruby.h:2278
VM_CHECKMATCH_ARRAY
#define VM_CHECKMATCH_ARRAY
Definition: vm_core.h:1083
RUBY_PLATFORM
#define RUBY_PLATFORM
Definition: defines.h:460
nd_last_column
#define nd_last_column(n)
Definition: node.h:205
n
const char size_t n
Definition: rb_mjit_min_header-2.7.0.h:5456
ISEQ_COVERAGE_SET
#define ISEQ_COVERAGE_SET(iseq, cov)
Definition: iseq.h:35
debug_node_end
#define debug_node_end()
Definition: compile.c:175
T_BIGNUM
#define T_BIGNUM
Definition: ruby.h:533
NODE_BEGIN
@ NODE_BEGIN
Definition: node.h:50
iseq_compile_data_storage::pos
unsigned int pos
Definition: iseq.h:276
COMPILE_
#define COMPILE_(anchor, desc, node, popped)
Definition: compile.c:349
rb_str_append
VALUE rb_str_append(VALUE, VALUE)
Definition: string.c:2965
IBF_OBJECT_CLASS_ARRAY
@ IBF_OBJECT_CLASS_ARRAY
Definition: compile.c:10710
NODE_POSTEXE
@ NODE_POSTEXE
Definition: node.h:130
rb_iseq_new_with_callback_callback_func::func
void(* func)(rb_iseq_t *, struct iseq_link_anchor *, const void *)
Definition: vm_core.h:1021
NODE_RESBODY
@ NODE_RESBODY
Definition: node.h:52
NEW_CHILD_ISEQ
#define NEW_CHILD_ISEQ(node, name, type, line_no)
Definition: compile.c:196
rb_bug
void rb_bug(const char *fmt,...)
Definition: error.c:634
NODE_RETURN
@ NODE_RETURN
Definition: node.h:80
internal.h
idAnd
@ idAnd
Definition: id.h:100
rb_to_encoding
rb_encoding * rb_to_encoding(VALUE enc)
Definition: encoding.c:245
NODE_FALSE
@ NODE_FALSE
Definition: node.h:127
T_ARRAY
#define T_ARRAY
Definition: ruby.h:530
arg
VALUE arg
Definition: rb_mjit_min_header-2.7.0.h:5601
argv
char ** argv
Definition: ruby.c:223
abort
void abort(void) __attribute__((__noreturn__))
iseq_trace_data::link
LINK_ELEMENT link
Definition: compile.c:93
NODE_ONCE
@ NODE_ONCE
Definition: node.h:100
rb_set_errinfo
void rb_set_errinfo(VALUE err)
Sets the current exception ($!) to the given value.
Definition: eval.c:1895
idOROP
@ idOROP
Definition: id.h:109
ibf_load::current_buffer
struct ibf_load_buffer * current_buffer
Definition: compile.c:9554
iseq_alloc
rb_iseq_t * iseq_alloc(void)
stdout
#define stdout
Definition: rb_mjit_min_header-2.7.0.h:1484
ST_CONTINUE
@ ST_CONTINUE
Definition: st.h:99
ibf_load::header
const struct ibf_header * header
Definition: compile.c:9548
rb_iseq_constant_body::iseq_encoded
VALUE * iseq_encoded
Definition: vm_core.h:325
NODE_IASGN
@ NODE_IASGN
Definition: node.h:61
xmalloc
#define xmalloc
Definition: defines.h:211
ibf_object_header
Definition: compile.c:10701
ibf_object_regexp::option
char option
Definition: compile.c:10718
iseq_catch_table::entries
struct iseq_catch_table_entry entries[]
Definition: rb_mjit_min_header-2.7.0.h:10860
UNREACHABLE
#define UNREACHABLE
Definition: ruby.h:63
rb_vm_get_ruby_level_next_cfp
MJIT_FUNC_EXPORTED rb_control_frame_t * rb_vm_get_ruby_level_next_cfp(const rb_execution_context_t *ec, const rb_control_frame_t *cfp)
Definition: vm.c:553
idLength
@ idLength
Definition: rb_mjit_min_header-2.7.0.h:8699
rb_sprintf
VALUE rb_sprintf(const char *format,...)
Definition: sprintf.c:1197
FIX2UINT
#define FIX2UINT(x)
Definition: ruby.h:718
rb_enc_find
rb_encoding * rb_enc_find(const char *name)
Definition: encoding.c:728
st_data_t
unsigned long st_data_t
Definition: rb_mjit_min_header-2.7.0.h:5363
DEFINED_NIL
@ DEFINED_NIL
Definition: iseq.h:285
DEFINED_CONST_FROM
@ DEFINED_CONST_FROM
Definition: iseq.h:302
T_NIL
#define T_NIL
Definition: ruby.h:522
BDIGIT
#define BDIGIT
Definition: bigdecimal.h:48
idFreeze
@ idFreeze
Definition: rb_mjit_min_header-2.7.0.h:8687
LABEL_RESCUE_TYPE
LABEL_RESCUE_TYPE
Definition: compile.c:55
NODE_NAMED_REST_P
#define NODE_NAMED_REST_P(node)
Definition: node.h:384
rb_iseq_insns_info_encode_positions
void rb_iseq_insns_info_encode_positions(const rb_iseq_t *iseq)
Definition: iseq.c:595
str
char str[HTML_ESCAPE_MAX_LEN+1]
Definition: escape.c:18
lt
#define lt(x, y)
Definition: time.c:83
cdhash_set_label_struct::pos
int pos
Definition: compile.c:1852
rb_iseq_constant_body::opt_num
int opt_num
Definition: vm_core.h:368
LABEL_UNREMOVABLE
#define LABEL_UNREMOVABLE(label)
Definition: compile.c:324
nd_first_lineno
#define nd_first_lineno(n)
Definition: node.h:200
BIGNUM_SIGN
#define BIGNUM_SIGN(b)
Definition: internal.h:761
modf
double modf(double, double *)
iseq_adjust_data::line_no
int line_no
Definition: compile.c:89
ibf_dump
Definition: compile.c:9529
id_core_set_variable_alias
@ id_core_set_variable_alias
Definition: id.h:121
rb_enc_find_index
int rb_enc_find_index(const char *name)
Definition: encoding.c:693
rb_range_new
VALUE rb_range_new(VALUE, VALUE, int)
Definition: range.c:52
NODE_WHEN
@ NODE_WHEN
Definition: node.h:39
NODE_BLOCK_PASS
@ NODE_BLOCK_PASS
Definition: node.h:109
rb_control_frame_struct::iseq
const rb_iseq_t * iseq
Definition: vm_core.h:763
NODE_MATCH
@ NODE_MATCH
Definition: node.h:90
VM_CALL_FCALL
#define VM_CALL_FCALL
Definition: vm_core.h:1103
RUBY_TYPED_FREE_IMMEDIATELY
#define RUBY_TYPED_FREE_IMMEDIATELY
Definition: ruby.h:1207
CHECK_SYMBOL
#define CHECK_SYMBOL(v)
Definition: compile.c:9110
ibf_object_struct_range
Definition: compile.c:10726
accessor_args::line
int line
Definition: compile.c:9419
keys
const rb_iseq_t const char const VALUE keys
Definition: rb_mjit_min_header-2.7.0.h:13506
MEMCPY
#define MEMCPY(p1, p2, type, n)
Definition: ruby.h:1753
iseq_insn_info_entry::events
rb_event_flag_t events
Definition: iseq.h:222
rb_iseq_constant_body::ISEQ_TYPE_RESCUE
@ ISEQ_TYPE_RESCUE
Definition: vm_core.h:317
types
enum imemo_type types
Definition: debug.c:72
ibf_object_bignum
Definition: compile.c:10734
rb_hash_aset
VALUE rb_hash_aset(VALUE hash, VALUE key, VALUE val)
Definition: hash.c:2779
iseq_catch_table_entry::CATCH_TYPE_NEXT
@ CATCH_TYPE_NEXT
Definition: iseq.h:232
rb_iseq_constant_body::ISEQ_TYPE_ENSURE
@ ISEQ_TYPE_ENSURE
Definition: vm_core.h:318
NODE_CALL
@ NODE_CALL
Definition: node.h:69
rb_iseq_constant_body::post_num
int post_num
Definition: vm_core.h:371
rb_obj_info_dump
void rb_obj_info_dump(VALUE obj)
Definition: gc.c:11661
NIL_P
#define NIL_P(v)
Definition: ruby.h:482
PRIdSIZE
#define PRIdSIZE
Definition: ruby.h:205
ISEQ_MARKABLE_ISEQ
#define ISEQ_MARKABLE_ISEQ
Definition: iseq.h:88
fail
#define fail()
Definition: date_strptime.c:123
iseq_adjust_data
Definition: compile.c:86
iseq_label_data::set
unsigned int set
Definition: compile.c:69
VM_CHECKMATCH_TYPE_RESCUE
@ VM_CHECKMATCH_TYPE_RESCUE
Definition: vm_core.h:1079
IS_INSN
#define IS_INSN(link)
Definition: compile.c:364
rb_id_table_create
struct rb_id_table * rb_id_table_create(size_t capa)
Definition: id_table.c:95
NODE_CASE2
@ NODE_CASE2
Definition: node.h:37
rb_iseq_constant_body::post_start
int post_start
Definition: vm_core.h:370
argc
int argc
Definition: ruby.c:222
IS_INSN_ID
#define IS_INSN_ID(iobj, insn)
Definition: compile.c:368
NORETURN
NORETURN(static void ibf_dump_object_unsupported(struct ibf_dump *dump, VALUE obj))
id_core_hash_merge_ptr
@ id_core_hash_merge_ptr
Definition: id.h:126
ISEQ_COVERAGE
#define ISEQ_COVERAGE(iseq)
Definition: iseq.h:34
VM_CALL_ARGS_SPLAT
#define VM_CALL_ARGS_SPLAT
Definition: vm_core.h:1101
rb_iseq_shared_exc_local_tbl
const ID rb_iseq_shared_exc_local_tbl[]
Definition: compile.c:110
ADD_SEND_WITH_FLAG
#define ADD_SEND_WITH_FLAG(seq, line, id, argc, flag)
Definition: compile.c:247
RUBY_ENCINDEX_BUILTIN_MAX
@ RUBY_ENCINDEX_BUILTIN_MAX
Definition: encindex.h:48
REALLOC_N
#define REALLOC_N(var, type, n)
Definition: ruby.h:1667
rb_code_location_struct::beg_pos
rb_code_position_t beg_pos
Definition: node.h:136
idBackquote
@ idBackquote
Definition: id.h:102
VM_DEFINECLASS_TYPE_MODULE
@ VM_DEFINECLASS_TYPE_MODULE
Definition: vm_core.h:996
INSERT_AFTER_INSN
#define INSERT_AFTER_INSN(prev, line, insn)
Definition: compile.c:212
iseq_compile_data_ensure_node_stack::prev
struct iseq_compile_data_ensure_node_stack * prev
Definition: compile.c:106
ibf_header::global_object_list_size
unsigned int global_object_list_size
Definition: compile.c:9519
IBF_OBJECT_CLASS_TYPE_ERROR
@ IBF_OBJECT_CLASS_TYPE_ERROR
Definition: compile.c:10713
ruby_debug
#define ruby_debug
Definition: ruby.h:1926
err
int err
Definition: win32.c:135
debugi
#define debugi(header, id)
Definition: compile.c:169
RUBY_EVENT_B_CALL
#define RUBY_EVENT_B_CALL
Definition: ruby.h:2253
encindex.h
ADD_INSN
#define ADD_INSN(seq, line, insn)
Definition: compile.c:204
rb_call_info::flag
unsigned int flag
Definition: internal.h:2390
rb_get_coverage_mode
int rb_get_coverage_mode(void)
Definition: thread.c:5483
rb_data_type_struct
Definition: ruby.h:1148
BUILTIN_TYPE
#define BUILTIN_TYPE(x)
Definition: ruby.h:551
RFLOAT_VALUE
#define RFLOAT_VALUE(v)
Definition: ruby.h:966
rb_iseq_new_with_opt
rb_iseq_t * rb_iseq_new_with_opt(const rb_ast_body_t *ast, VALUE name, VALUE path, VALUE realpath, VALUE first_lineno, const rb_iseq_t *parent, enum iseq_type type, const rb_compile_option_t *option)
Definition: iseq.c:807
xfree
#define xfree
Definition: defines.h:216
iseq_insn_data::events
rb_event_flag_t events
Definition: compile.c:82
rb_call_data::ci
struct rb_call_info ci
Definition: internal.h:2395
DEFINED_EXPR
@ DEFINED_EXPR
Definition: iseq.h:298
NODE_FCALL
@ NODE_FCALL
Definition: node.h:71
rb_str_new
#define rb_str_new(str, len)
Definition: rb_mjit_min_header-2.7.0.h:6116
NEW_LABEL
#define NEW_LABEL(l)
Definition: compile.c:190
rb_sym2id
ID rb_sym2id(VALUE)
Definition: symbol.c:748
idERROR_INFO
@ idERROR_INFO
Definition: rb_mjit_min_header-2.7.0.h:8754
IBF_OBJBODY
#define IBF_OBJBODY(type, offset)
Definition: compile.c:10753
COMPILE_OK
#define COMPILE_OK
Definition: compile.c:445
rb_gc_mark
void rb_gc_mark(VALUE ptr)
Definition: gc.c:5212
VM_CHECKMATCH_TYPE_CASE
@ VM_CHECKMATCH_TYPE_CASE
Definition: vm_core.h:1078
MJIT_FUNC_EXPORTED
#define MJIT_FUNC_EXPORTED
Definition: defines.h:396
rb_iseq_location_struct::node_id
int node_id
Definition: vm_core.h:277
TAG_NEXT
#define TAG_NEXT
Definition: vm_core.h:200
rb_range_values
int rb_range_values(VALUE range, VALUE *begp, VALUE *endp, int *exclp)
Definition: range.c:1243
count
int count
Definition: encoding.c:57
rb_compile_warn
void rb_compile_warn(const char *file, int line, const char *fmt,...)
Definition: error.c:270
st_memsize
size_t st_memsize(const st_table *tab)
Definition: st.c:719
iseq_link_element::ISEQ_ELEMENT_ADJUST
@ ISEQ_ELEMENT_ADJUST
Definition: compile.c:43
NODE_YIELD
@ NODE_YIELD
Definition: node.h:81
rb_iseq_new_with_callback
rb_iseq_t * rb_iseq_new_with_callback(const struct rb_iseq_new_with_callback_callback_func *ifunc, VALUE name, VALUE path, VALUE realpath, VALUE first_lineno, const rb_iseq_t *parent, enum iseq_type type, const rb_compile_option_t *option)
Definition: iseq.c:828
ADD_CALL_WITH_BLOCK
#define ADD_CALL_WITH_BLOCK(seq, line, id, argc, block)
Definition: compile.c:259
Qtrue
#define Qtrue
Definition: ruby.h:468
rb_str_catf
VALUE rb_str_catf(VALUE str, const char *format,...)
Definition: sprintf.c:1237
rb_iseq_ibf_load_extra_data
VALUE rb_iseq_ibf_load_extra_data(VALUE str)
Definition: compile.c:11630
rb_iseq_constant_body::iseq_insn_info::size
unsigned int size
Definition: vm_core.h:405
VM_INSTRUCTION_SIZE
@ VM_INSTRUCTION_SIZE
Definition: rb_mjit_min_header-2.7.0.h:12176
DEFINED_CONST
@ DEFINED_CONST
Definition: iseq.h:290
rb_class_name
VALUE rb_class_name(VALUE)
Definition: variable.c:274
IC
struct iseq_inline_cache_entry * IC
Definition: vm_core.h:1129
rb_iseq_pathobj_set
void rb_iseq_pathobj_set(const rb_iseq_t *iseq, VALUE path, VALUE realpath)
Definition: iseq.c:469
len
uint8_t len
Definition: escape.c:17
SYMBOL_P
#define SYMBOL_P(x)
Definition: ruby.h:413
ibf_load_buffer
Definition: compile.c:9538
ibf_object_header::special_const
unsigned int special_const
Definition: compile.c:10703
iseq_label_data::unremovable
unsigned int unremovable
Definition: compile.c:71
intptr_t
int intptr_t
Definition: win32.h:90
rb_builtin_function::argc
const int argc
Definition: builtin.h:9
rb_memerror
void rb_memerror(void)
Definition: gc.c:9578
PRIdVALUE
#define PRIdVALUE
Definition: ruby.h:161
UINT_MAX
#define UINT_MAX
Definition: rb_mjit_min_header-2.7.0.h:4054
rb_iseq_struct::body
struct rb_iseq_constant_body * body
Definition: vm_core.h:460
iseq_catch_table_entry::sp
unsigned int sp
Definition: iseq.h:252
rb_ary_dup
VALUE rb_ary_dup(VALUE ary)
Definition: array.c:2238
defined_type
defined_type
Definition: iseq.h:283
ruby_vminsn_type
ruby_vminsn_type
Definition: rb_mjit_min_header-2.7.0.h:11969
NODE_UNDEF
@ NODE_UNDEF
Definition: node.h:114
FLEX_ARY_LEN
#define FLEX_ARY_LEN
Definition: internal.h:2620
idBACKREF
@ idBACKREF
Definition: rb_mjit_min_header-2.7.0.h:8753
rb_iseq_ibf_load
const rb_iseq_t * rb_iseq_ibf_load(VALUE str)
Definition: compile.c:11602
LONG2FIX
#define LONG2FIX(i)
Definition: ruby.h:265
va_start
#define va_start(v, l)
Definition: rb_mjit_min_header-2.7.0.h:3978
rb_ivar_set
VALUE rb_ivar_set(VALUE, ID, VALUE)
Definition: variable.c:1300
RUBY_EVENT_RETURN
#define RUBY_EVENT_RETURN
Definition: ruby.h:2246
rb_iseq_constant_body::iseq_size
unsigned int iseq_size
Definition: vm_core.h:324
NODE_BACK_REF
@ NODE_BACK_REF
Definition: node.h:89
nd_line
#define nd_line(n)
Definition: node.h:194
rb_exc_fatal
void rb_exc_fatal(VALUE mesg)
Raises a fatal error in the current thread.
Definition: eval.c:683
rb_intern_str
#define rb_intern_str(string)
Definition: generator.h:16
VM_SVAR_FLIPFLOP_START
@ VM_SVAR_FLIPFLOP_START
Definition: vm_core.h:1125
T_STRING
#define T_STRING
Definition: ruby.h:528
NODE_DEFINED
@ NODE_DEFINED
Definition: node.h:129
rb_data_is_encoding
int rb_data_is_encoding(VALUE obj)
Definition: encoding.c:89
ibf_load::global_buffer
struct ibf_load_buffer global_buffer
Definition: compile.c:9550
iseq_insn_data::insn_info
struct iseq_insn_data::@2 insn_info
TAG_BREAK
#define TAG_BREAK
Definition: vm_core.h:199
rb_sym2str
VALUE rb_sym2str(VALUE)
Definition: symbol.c:784
iseq_link_element::ISEQ_ELEMENT_LABEL
@ ISEQ_ELEMENT_LABEL
Definition: compile.c:41
idRespond_to
@ idRespond_to
Definition: id.h:116
va_list
__gnuc_va_list va_list
Definition: rb_mjit_min_header-2.7.0.h:836
RHASH_TBL_RAW
#define RHASH_TBL_RAW(h)
Definition: internal.h:1689
rb_args_info::block_arg
ID block_arg
Definition: node.h:441
rb_iseq_constant_body::ci_kw_size
unsigned int ci_kw_size
Definition: vm_core.h:438
ibf_object_hash
Definition: compile.c:10721
ibf_object_regexp::srcstr
long srcstr
Definition: compile.c:10717
iseq
const rb_iseq_t * iseq
Definition: rb_mjit_min_header-2.7.0.h:13504
rb_iseq_constant_body::catch_except_p
char catch_except_p
Definition: vm_core.h:441
FIXABLE
#define FIXABLE(f)
Definition: ruby.h:399
iseq_label_data::position
int position
Definition: compile.c:65
rb_call_info
Definition: internal.h:2387
RB_INTEGER_TYPE_P
#define RB_INTEGER_TYPE_P(obj)
Definition: ruby_missing.h:15
NODE_VALUES
@ NODE_VALUES
Definition: node.h:78
NODE_FLIP3
@ NODE_FLIP3
Definition: node.h:123
nd_type
#define nd_type(n)
Definition: node.h:188
DEFINED_IVAR
@ DEFINED_IVAR
Definition: iseq.h:286
rb_iseq_constant_body::iseq_insn_info::positions
unsigned int * positions
Definition: vm_core.h:404
RARRAY_CONST_PTR_TRANSIENT
#define RARRAY_CONST_PTR_TRANSIENT(a)
Definition: ruby.h:1073
iseq_compile_data_ensure_node_stack::erange
struct ensure_range * erange
Definition: compile.c:107
ibf_load_object_function
VALUE(* ibf_load_object_function)(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
Definition: compile.c:11226
rb_code_location_struct::end_pos
rb_code_position_t end_pos
Definition: node.h:137
RB_WARN_CATEGORY_DEPRECATED
@ RB_WARN_CATEGORY_DEPRECATED
Definition: internal.h:1560
rb_vm_get_sourceline
int rb_vm_get_sourceline(const rb_control_frame_t *cfp)
Definition: vm_backtrace.c:68
builtin.h
rb_ast_body_struct::root
const NODE * root
Definition: node.h:395
NUM2INT
#define NUM2INT(x)
Definition: ruby.h:715
Qnil
#define Qnil
Definition: ruby.h:469
realpath
char * realpath(const char *__restrict path, char *__restrict resolved_path)
RUBY_EVENT_COVERAGE_BRANCH
#define RUBY_EVENT_COVERAGE_BRANCH
Definition: vm_core.h:1957
rb_call_info_with_kwarg::ci
struct rb_call_info ci
Definition: vm_core.h:246
rb_fstring_lit
#define rb_fstring_lit(str)
Definition: internal.h:2123
debugs
#define debugs
Definition: compile.c:183
ibf_load_buffer::size
ibf_offset_t size
Definition: compile.c:9540
PADDING_SIZE_MAX
#define PADDING_SIZE_MAX
Definition: compile.c:826
rb_insns_name
const char * rb_insns_name(int i)
Definition: compile.c:8761
rb_id_table_lookup
int rb_id_table_lookup(struct rb_id_table *tbl, ID id, VALUE *valp)
Definition: id_table.c:226
ibf_load_buffer::obj_list_size
unsigned int obj_list_size
Definition: compile.c:9543
rb_iseq_ibf_dump
VALUE rb_iseq_ibf_dump(const rb_iseq_t *iseq, VALUE opt)
Definition: compile.c:11378
NODE_REDO
@ NODE_REDO
Definition: node.h:48
ibf_load::iseq_list
VALUE iseq_list
Definition: compile.c:9549
ADD_CALL
#define ADD_CALL(seq, line, id, argc)
Definition: compile.c:256
st_lookup
int st_lookup(st_table *tab, st_data_t key, st_data_t *value)
Definition: st.c:1101
util.h
rb_ary_pattern_info
Definition: node.h:453
DEFINED_ZSUPER
@ DEFINED_ZSUPER
Definition: iseq.h:293
UNALIGNED_MEMBER_PTR
#define UNALIGNED_MEMBER_PTR(ptr, mem)
Definition: internal.h:2685
iseq_catch_table
Definition: rb_mjit_min_header-2.7.0.h:10860
BIGNUM_LEN
#define BIGNUM_LEN(b)
Definition: internal.h:774
ibf_object_hash::keyval
long keyval[FLEX_ARY_LEN]
Definition: compile.c:10723
rb_iseq_constant_body::call_data
struct rb_call_data * call_data
Definition: vm_core.h:421
COMPILE_RECV
#define COMPILE_RECV(anchor, desc, node)
Definition: compile.c:353
rb_eStandardError
VALUE rb_eStandardError
Definition: error.c:919
NODE_MODULE
@ NODE_MODULE
Definition: node.h:116
RB_GC_GUARD
#define RB_GC_GUARD(v)
Definition: ruby.h:585
numberof
#define numberof(array)
Definition: etc.c:618
DEFINED_ASGN
@ DEFINED_ASGN
Definition: iseq.h:297
MEMORY
#define MEMORY(v)
UNREACHABLE_RETURN
#define UNREACHABLE_RETURN(val)
Definition: ruby.h:59
rb_str_tmp_new
VALUE rb_str_tmp_new(long)
Definition: string.c:1343
RNode::id
ID id
Definition: node.h:153
idDIV
@ idDIV
Definition: id.h:88
rb_call_data
Definition: internal.h:2393
rb_iseq_constant_body::is_size
unsigned int is_size
Definition: vm_core.h:436
RSTRING_LEN
#define RSTRING_LEN(str)
Definition: ruby.h:1005
st_free_table
void st_free_table(st_table *tab)
Definition: st.c:709
st_table
Definition: st.h:79
RUBY_FUNCTION_NAME_STRING
#define RUBY_FUNCTION_NAME_STRING
Definition: rb_mjit_min_header-2.7.0.h:190
ADD_ADJUST
#define ADD_ADJUST(seq, line, label)
Definition: compile.c:318
DEFINED_METHOD
@ DEFINED_METHOD
Definition: iseq.h:291
rb_call_info_with_kwarg
Definition: vm_core.h:245
rb_args_info::rest_arg
ID rest_arg
Definition: node.h:440
iseq_catch_table_entry::start
unsigned int start
Definition: iseq.h:249
idMOD
@ idMOD
Definition: id.h:89
NODE_QCALL
@ NODE_QCALL
Definition: node.h:73
id_debug_created_info
@ id_debug_created_info
Definition: id.h:129
iseq_compile_data_storage::next
struct iseq_compile_data_storage * next
Definition: iseq.h:275
DEFINED_LVAR
@ DEFINED_LVAR
Definition: iseq.h:287
NODE_SCOPE
@ NODE_SCOPE
Definition: node.h:32
idLambda
@ idLambda
Definition: rb_mjit_min_header-2.7.0.h:8705
ibf_object_struct_range::end
long end
Definition: compile.c:10730
NODE_RETRY
@ NODE_RETRY
Definition: node.h:49
ibf_object_header::internal
unsigned int internal
Definition: compile.c:10705
NODE_LIST
@ NODE_LIST
Definition: node.h:76
ibf_object_bignum::digits
BDIGIT digits[FLEX_ARY_LEN]
Definition: compile.c:10736
rb_str_cat
VALUE rb_str_cat(VALUE, const char *, long)
Definition: string.c:2812
id_table.h
rb_obj_is_kind_of
VALUE rb_obj_is_kind_of(VALUE, VALUE)
Determines if obj is a kind of c.
Definition: object.c:692
accessor_args
Definition: compile.c:9416
rb_dbl_long_hash
long rb_dbl_long_hash(double d)
Definition: hash.c:160
NO_CHECK
#define NO_CHECK(sub)
Definition: compile.c:449
rb_builtin_function::name
const char *const name
Definition: builtin.h:13
NEW_ISEQ
#define NEW_ISEQ(node, name, type, line_no)
Definition: compile.c:193
RTEST
#define RTEST(v)
Definition: ruby.h:481
imemo_ifunc
@ imemo_ifunc
iterator function
Definition: internal.h:1137
rb_iseq_constant_body::flip_count
rb_snum_t flip_count
Definition: vm_core.h:429
NODE_FOR_MASGN
@ NODE_FOR_MASGN
Definition: node.h:45
rb_iseq_insns_info_decode_positions
unsigned int * rb_iseq_insns_info_decode_positions(const struct rb_iseq_constant_body *body)
Definition: iseq.c:613
ruby::backward::cxxanyargs::type
VALUE type(ANYARGS)
ANYARGS-ed function type.
Definition: cxxanyargs.hpp:39
SYM2ID
#define SYM2ID(x)
Definition: ruby.h:415
ISEQ_LINE_COVERAGE
#define ISEQ_LINE_COVERAGE(iseq)
Definition: iseq.h:36
RNode
Definition: node.h:149
rb_iseq_location_struct::base_label
VALUE base_label
Definition: vm_core.h:274
dup
int dup(int __fildes)
ibf_dump::iseq_list
VALUE iseq_list
Definition: compile.c:9530
rb_iseq_compile_callback
VALUE rb_iseq_compile_callback(rb_iseq_t *iseq, const struct rb_iseq_new_with_callback_callback_func *ifunc)
Definition: compile.c:630
rb_global_entry
Definition: internal.h:1350
TAG_RETURN
#define TAG_RETURN
Definition: vm_core.h:198
RUBY_TYPED_WB_PROTECTED
#define RUBY_TYPED_WB_PROTECTED
Definition: ruby.h:1208
rb_float_cmp
int rb_float_cmp(VALUE x, VALUE y)
Definition: numeric.c:1487
RUBY_EVENT_LINE
#define RUBY_EVENT_LINE
Definition: ruby.h:2242
RUBY_ASSERT
#define RUBY_ASSERT(expr)
Definition: assert.h:32
rb_enc_associate_index
VALUE rb_enc_associate_index(VALUE obj, int idx)
Definition: encoding.c:838
rb_iseq_constant_body::stack_max
unsigned int stack_max
Definition: vm_core.h:439
iseq_link_element::ISEQ_ELEMENT_ANCHOR
@ ISEQ_ELEMENT_ANCHOR
Definition: compile.c:40
RUBY_EVENT_CLASS
#define RUBY_EVENT_CLASS
Definition: ruby.h:2243
iseq_insn_info_entry::line_no
int line_no
Definition: iseq.h:221
rb_dvar_defined
int rb_dvar_defined(ID id, const rb_iseq_t *iseq)
Definition: compile.c:9356
INT_PARAM
#define INT_PARAM(F)
NODE_WHILE
@ NODE_WHILE
Definition: node.h:41
NODE_SCLASS
@ NODE_SCLASS
Definition: node.h:117
cfp
rb_control_frame_t * cfp
Definition: rb_mjit_min_header-2.7.0.h:14544
iseq_link_element
Definition: compile.c:38
rb_iseq_constant_body::ISEQ_TYPE_MAIN
@ ISEQ_TYPE_MAIN
Definition: vm_core.h:320
iseq_inline_storage_entry
Definition: vm_core.h:231
idMin
@ idMin
Definition: rb_mjit_min_header-2.7.0.h:8686
name
const char * name
Definition: nkf.c:208
NODE_GASGN
@ NODE_GASGN
Definition: node.h:60
rb_execution_context_struct
Definition: vm_core.h:843
ISEQ_LAST_LINE
#define ISEQ_LAST_LINE(iseq)
Definition: compile.c:605
IBF_R
#define IBF_R(val, type, n)
Definition: compile.c:9635