Ruby  2.7.2p137(2020-10-01revision5445e0435260b449decf2ac16f9d09bae3cafe72)
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 {
45  } type;
49 
50 typedef struct iseq_link_anchor {
54 
55 typedef enum {
61 
62 typedef struct iseq_label_data {
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;
73 
74 typedef struct iseq_insn_data {
78  int sc_state;
80  struct {
81  int line_no;
84 } INSN;
85 
86 typedef struct iseq_adjust_data {
89  int line_no;
91 
92 typedef struct iseq_trace_data {
95  long data;
97 
98 struct ensure_range {
102 };
103 
108 };
109 
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);
391  }
392  else if (!err_info) {
393  RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->err_info, Qtrue);
394  }
395  if (compile_debug) {
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);
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
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
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 
674  ADD_LABEL(ret, start);
675  CHECK(COMPILE(ret, "block body", node->nd_body));
676  ADD_LABEL(ret, end);
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  {
688  CHECK(COMPILE(ret, "scoped node", node->nd_body));
690  ISEQ_COMPILE_DATA(iseq)->last_line = nd_line(node);
691  break;
692  }
693  case ISEQ_TYPE_METHOD:
694  {
696  CHECK(COMPILE(ret, "scoped node", node->nd_body));
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) {
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  }
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 +
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 {
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
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;
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;
1191  iseq->body->ci_kw_size++;
1192  }
1193  else {
1194  iseq->body->ci_size++;
1195  }
1196 
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,
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,
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 =
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) {
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 {
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) {
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  }
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 
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);
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);
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);
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) &&
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  }
2070  while (RARRAY_LEN(ISEQ_PC2BRANCHINDEX(iseq)) <= code_index) {
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 =
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);
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)) {
2185  }
2186  break;
2187  }
2188  case TS_ISE: /* inline storage entry */
2189  /* Treated as an IC, but may contain a markable VALUE */
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);
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:
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(&diobj->link) &&
2723  IS_INSN_ID(diobj, jump) &&
2724  OPERAND_AT(iobj, 0) != OPERAND_AT(diobj, 0)) {
2725  /*
2726  * useless jump elimination:
2727  * jump LABEL1
2728  * ...
2729  * LABEL1:
2730  * jump LABEL2
2731  *
2732  * => in this case, first jump instruction should jump to
2733  * LABEL2 directly
2734  */
2735  replace_destination(iobj, diobj);
2736  remove_unreachable_chunk(iseq, iobj->link.next);
2737  goto again;
2738  }
2739  else if (IS_INSN_ID(diobj, leave)) {
2740  INSN *pop;
2741  /*
2742  * jump LABEL
2743  * ...
2744  * LABEL:
2745  * leave
2746  * =>
2747  * leave
2748  * pop
2749  * ...
2750  * LABEL:
2751  * leave
2752  */
2753  /* replace */
2754  unref_destination(iobj, 0);
2755  iobj->insn_id = BIN(leave);
2756  iobj->operand_size = 0;
2757  iobj->insn_info = diobj->insn_info;
2758  /* adjust stack depth */
2759  pop = new_insn_body(iseq, diobj->insn_info.line_no, BIN(pop), 0);
2760  ELEM_INSERT_NEXT(&iobj->link, &pop->link);
2761  goto again;
2762  }
2763  else if (IS_INSN(iobj->link.prev) &&
2764  (piobj = (INSN *)iobj->link.prev) &&
2765  (IS_INSN_ID(piobj, branchif) ||
2766  IS_INSN_ID(piobj, branchunless))) {
2767  INSN *pdiobj = (INSN *)get_destination_insn(piobj);
2768  if (niobj == pdiobj) {
2769  int refcnt = IS_LABEL(piobj->link.next) ?
2770  ((LABEL *)piobj->link.next)->refcnt : 0;
2771  /*
2772  * useless jump elimination (if/unless destination):
2773  * if L1
2774  * jump L2
2775  * L1:
2776  * ...
2777  * L2:
2778  *
2779  * ==>
2780  * unless L2
2781  * L1:
2782  * ...
2783  * L2:
2784  */
2785  piobj->insn_id = (IS_INSN_ID(piobj, branchif))
2786  ? BIN(branchunless) : BIN(branchif);
2787  replace_destination(piobj, iobj);
2788  if (refcnt <= 1) {
2789  ELEM_REMOVE(&iobj->link);
2790  }
2791  else {
2792  /* TODO: replace other branch destinations too */
2793  }
2794  return COMPILE_OK;
2795  }
2796  else if (diobj == pdiobj) {
2797  /*
2798  * useless jump elimination (if/unless before jump):
2799  * L1:
2800  * ...
2801  * if L1
2802  * jump L1
2803  *
2804  * ==>
2805  * L1:
2806  * ...
2807  * pop
2808  * jump L1
2809  */
2810  INSN *popiobj = new_insn_core(iseq, iobj->insn_info.line_no,
2811  BIN(pop), 0, 0);
2812  ELEM_REPLACE(&piobj->link, &popiobj->link);
2813  }
2814  }
2815  if (remove_unreachable_chunk(iseq, iobj->link.next)) {
2816  goto again;
2817  }
2818  }
2819 
2820  /*
2821  * putstring "beg"
2822  * putstring "end"
2823  * newrange excl
2824  *
2825  * ==>
2826  *
2827  * putobject "beg".."end"
2828  */
2829  if (IS_INSN_ID(iobj, checkmatch)) {
2830  INSN *range = (INSN *)get_prev_insn(iobj);
2831  INSN *beg, *end;
2832  VALUE str_beg, str_end;
2833 
2834  if (range && IS_INSN_ID(range, newrange) &&
2835  (end = (INSN *)get_prev_insn(range)) != 0 &&
2836  is_frozen_putstring(end, &str_end) &&
2837  (beg = (INSN *)get_prev_insn(end)) != 0 &&
2838  is_frozen_putstring(beg, &str_beg)) {
2839  int excl = FIX2INT(OPERAND_AT(range, 0));
2840  VALUE lit_range = rb_range_new(str_beg, str_end, excl);
2841 
2842  ELEM_REMOVE(&beg->link);
2843  ELEM_REMOVE(&end->link);
2844  range->insn_id = BIN(putobject);
2845  OPERAND_AT(range, 0) = lit_range;
2846  RB_OBJ_WRITTEN(iseq, Qundef, lit_range);
2847  }
2848  }
2849 
2850  if (IS_INSN_ID(iobj, leave)) {
2851  remove_unreachable_chunk(iseq, iobj->link.next);
2852  }
2853 
2854  if (IS_INSN_ID(iobj, branchif) ||
2855  IS_INSN_ID(iobj, branchnil) ||
2856  IS_INSN_ID(iobj, branchunless)) {
2857  /*
2858  * if L1
2859  * ...
2860  * L1:
2861  * jump L2
2862  * =>
2863  * if L2
2864  */
2865  INSN *nobj = (INSN *)get_destination_insn(iobj);
2866 
2867  /* This is super nasty hack!!!
2868  *
2869  * This jump-jump optimization may ignore event flags of the jump
2870  * instruction being skipped. Actually, Line 2 TracePoint event
2871  * is never fired in the following code:
2872  *
2873  * 1: raise if 1 == 2
2874  * 2: while true
2875  * 3: break
2876  * 4: end
2877  *
2878  * This is critical for coverage measurement. [Bug #15980]
2879  *
2880  * This is a stopgap measure: stop the jump-jump optimization if
2881  * coverage measurement is enabled and if the skipped instruction
2882  * has any event flag.
2883  *
2884  * Note that, still, TracePoint Line event does not occur on Line 2.
2885  * This should be fixed in future.
2886  */
2887  int stop_optimization =
2889  nobj->insn_info.events;
2890  if (!stop_optimization) {
2891  INSN *pobj = (INSN *)iobj->link.prev;
2892  int prev_dup = 0;
2893  if (pobj) {
2894  if (!IS_INSN(&pobj->link))
2895  pobj = 0;
2896  else if (IS_INSN_ID(pobj, dup))
2897  prev_dup = 1;
2898  }
2899 
2900  for (;;) {
2901  if (IS_INSN(&nobj->link) && IS_INSN_ID(nobj, jump)) {
2902  replace_destination(iobj, nobj);
2903  }
2904  else if (prev_dup && IS_INSN_ID(nobj, dup) &&
2905  !!(nobj = (INSN *)nobj->link.next) &&
2906  /* basic blocks, with no labels in the middle */
2907  nobj->insn_id == iobj->insn_id) {
2908  /*
2909  * dup
2910  * if L1
2911  * ...
2912  * L1:
2913  * dup
2914  * if L2
2915  * =>
2916  * dup
2917  * if L2
2918  * ...
2919  * L1:
2920  * dup
2921  * if L2
2922  */
2923  replace_destination(iobj, nobj);
2924  }
2925  else if (pobj) {
2926  /*
2927  * putnil
2928  * if L1
2929  * =>
2930  * # nothing
2931  *
2932  * putobject true
2933  * if L1
2934  * =>
2935  * jump L1
2936  *
2937  * putstring ".."
2938  * if L1
2939  * =>
2940  * jump L1
2941  *
2942  * putstring ".."
2943  * dup
2944  * if L1
2945  * =>
2946  * putstring ".."
2947  * jump L1
2948  *
2949  */
2950  int cond;
2951  if (prev_dup && IS_INSN(pobj->link.prev)) {
2952  pobj = (INSN *)pobj->link.prev;
2953  }
2954  if (IS_INSN_ID(pobj, putobject)) {
2955  cond = (IS_INSN_ID(iobj, branchif) ?
2956  OPERAND_AT(pobj, 0) != Qfalse :
2957  IS_INSN_ID(iobj, branchunless) ?
2958  OPERAND_AT(pobj, 0) == Qfalse :
2959  FALSE);
2960  }
2961  else if (IS_INSN_ID(pobj, putstring) ||
2962  IS_INSN_ID(pobj, duparray) ||
2963  IS_INSN_ID(pobj, newarray)) {
2964  cond = IS_INSN_ID(iobj, branchif);
2965  }
2966  else if (IS_INSN_ID(pobj, putnil)) {
2967  cond = !IS_INSN_ID(iobj, branchif);
2968  }
2969  else break;
2970  if (prev_dup || !IS_INSN_ID(pobj, newarray)) {
2971  ELEM_REMOVE(iobj->link.prev);
2972  }
2973  else if (!iseq_pop_newarray(iseq, pobj)) {
2974  pobj = new_insn_core(iseq, pobj->insn_info.line_no, BIN(pop), 0, NULL);
2975  ELEM_INSERT_PREV(&iobj->link, &pobj->link);
2976  }
2977  if (cond) {
2978  if (prev_dup) {
2979  pobj = new_insn_core(iseq, pobj->insn_info.line_no, BIN(putnil), 0, NULL);
2980  ELEM_INSERT_NEXT(&iobj->link, &pobj->link);
2981  }
2982  iobj->insn_id = BIN(jump);
2983  goto again;
2984  }
2985  else {
2986  unref_destination(iobj, 0);
2987  ELEM_REMOVE(&iobj->link);
2988  }
2989  break;
2990  }
2991  else break;
2992  nobj = (INSN *)get_destination_insn(nobj);
2993  }
2994  }
2995  }
2996 
2997  if (IS_INSN_ID(iobj, pop)) {
2998  /*
2999  * putself / putnil / putobject obj / putstring "..."
3000  * pop
3001  * =>
3002  * # do nothing
3003  */
3004  LINK_ELEMENT *prev = iobj->link.prev;
3005  if (IS_INSN(prev)) {
3006  enum ruby_vminsn_type previ = ((INSN *)prev)->insn_id;
3007  if (previ == BIN(putobject) || previ == BIN(putnil) ||
3008  previ == BIN(putself) || previ == BIN(putstring) ||
3009  previ == BIN(dup) ||
3010  previ == BIN(getlocal) ||
3011  previ == BIN(getblockparam) ||
3012  previ == BIN(getblockparamproxy) ||
3013  /* getinstancevariable may issue a warning */
3014  previ == BIN(duparray)) {
3015  /* just push operand or static value and pop soon, no
3016  * side effects */
3017  ELEM_REMOVE(prev);
3018  ELEM_REMOVE(&iobj->link);
3019  }
3020  else if (previ == BIN(newarray) && iseq_pop_newarray(iseq, (INSN*)prev)) {
3021  ELEM_REMOVE(&iobj->link);
3022  }
3023  else if (previ == BIN(concatarray)) {
3024  INSN *piobj = (INSN *)prev;
3025  INSERT_BEFORE_INSN1(piobj, piobj->insn_info.line_no, splatarray, Qfalse);
3026  INSN_OF(piobj) = BIN(pop);
3027  }
3028  else if (previ == BIN(concatstrings)) {
3029  if (OPERAND_AT(prev, 0) == INT2FIX(1)) {
3030  ELEM_REMOVE(prev);
3031  }
3032  else {
3033  ELEM_REMOVE(&iobj->link);
3034  INSN_OF(prev) = BIN(adjuststack);
3035  }
3036  }
3037  }
3038  }
3039 
3040  if (IS_INSN_ID(iobj, newarray) ||
3041  IS_INSN_ID(iobj, duparray) ||
3042  IS_INSN_ID(iobj, expandarray) ||
3043  IS_INSN_ID(iobj, concatarray) ||
3044  IS_INSN_ID(iobj, splatarray) ||
3045  0) {
3046  /*
3047  * newarray N
3048  * splatarray
3049  * =>
3050  * newarray N
3051  * newarray always puts an array
3052  */
3053  LINK_ELEMENT *next = iobj->link.next;
3054  if (IS_INSN(next) && IS_INSN_ID(next, splatarray)) {
3055  /* remove splatarray following always-array insn */
3056  ELEM_REMOVE(next);
3057  }
3058  }
3059 
3060  if (IS_INSN_ID(iobj, tostring)) {
3061  LINK_ELEMENT *next = iobj->link.next;
3062  /*
3063  * tostring
3064  * concatstrings 1
3065  * =>
3066  * tostring
3067  */
3068  if (IS_INSN(next) && IS_INSN_ID(next, concatstrings) &&
3069  OPERAND_AT(next, 0) == INT2FIX(1)) {
3070  ELEM_REMOVE(next);
3071  }
3072  }
3073 
3074  if (IS_INSN_ID(iobj, putstring) ||
3075  (IS_INSN_ID(iobj, putobject) && RB_TYPE_P(OPERAND_AT(iobj, 0), T_STRING))) {
3076  /*
3077  * putstring ""
3078  * concatstrings N
3079  * =>
3080  * concatstrings N-1
3081  */
3082  if (IS_NEXT_INSN_ID(&iobj->link, concatstrings) &&
3083  RSTRING_LEN(OPERAND_AT(iobj, 0)) == 0) {
3084  INSN *next = (INSN *)iobj->link.next;
3085  if ((OPERAND_AT(next, 0) = FIXNUM_INC(OPERAND_AT(next, 0), -1)) == INT2FIX(1)) {
3086  ELEM_REMOVE(&next->link);
3087  }
3088  ELEM_REMOVE(&iobj->link);
3089  }
3090  }
3091 
3092  if (IS_INSN_ID(iobj, concatstrings)) {
3093  /*
3094  * concatstrings N
3095  * concatstrings M
3096  * =>
3097  * concatstrings N+M-1
3098  */
3099  LINK_ELEMENT *next = iobj->link.next, *freeze = 0;
3100  INSN *jump = 0;
3101  if (IS_INSN(next) && IS_INSN_ID(next, freezestring))
3102  next = (freeze = next)->next;
3103  if (IS_INSN(next) && IS_INSN_ID(next, jump))
3104  next = get_destination_insn(jump = (INSN *)next);
3105  if (IS_INSN(next) && IS_INSN_ID(next, concatstrings)) {
3106  int n = FIX2INT(OPERAND_AT(iobj, 0)) + FIX2INT(OPERAND_AT(next, 0)) - 1;
3107  OPERAND_AT(iobj, 0) = INT2FIX(n);
3108  if (jump) {
3109  LABEL *label = ((LABEL *)OPERAND_AT(jump, 0));
3110  if (!--label->refcnt) {
3111  ELEM_REMOVE(&label->link);
3112  }
3113  else {
3114  label = NEW_LABEL(0);
3115  OPERAND_AT(jump, 0) = (VALUE)label;
3116  }
3117  label->refcnt++;
3118  if (freeze && IS_NEXT_INSN_ID(next, freezestring)) {
3119  if (same_debug_pos_p(freeze, next->next)) {
3120  ELEM_REMOVE(freeze);
3121  }
3122  else {
3123  next = next->next;
3124  }
3125  }
3126  ELEM_INSERT_NEXT(next, &label->link);
3127  CHECK(iseq_peephole_optimize(iseq, get_next_insn(jump), do_tailcallopt));
3128  }
3129  else {
3130  if (freeze) ELEM_REMOVE(freeze);
3131  ELEM_REMOVE(next);
3132  }
3133  }
3134  }
3135 
3136  if (IS_INSN_ID(iobj, freezestring) &&
3137  NIL_P(OPERAND_AT(iobj, 0)) &&
3138  IS_NEXT_INSN_ID(&iobj->link, send)) {
3139  INSN *niobj = (INSN *)iobj->link.next;
3140  struct rb_call_info *ci = (struct rb_call_info *)OPERAND_AT(niobj, 0);
3141  /*
3142  * freezestring nil # no debug_info
3143  * send <:+@, 0, ARG_SIMPLE> # :-@, too
3144  * =>
3145  * send <:+@, 0, ARG_SIMPLE> # :-@, too
3146  */
3147  if ((ci->mid == idUPlus || ci->mid == idUMinus) &&
3148  (ci->flag & VM_CALL_ARGS_SIMPLE) &&
3149  ci->orig_argc == 0) {
3150  ELEM_REMOVE(list);
3151  return COMPILE_OK;
3152  }
3153  }
3154 
3155  if (do_tailcallopt &&
3156  (IS_INSN_ID(iobj, send) ||
3157  IS_INSN_ID(iobj, opt_aref_with) ||
3158  IS_INSN_ID(iobj, opt_aset_with) ||
3159  IS_INSN_ID(iobj, invokesuper))) {
3160  /*
3161  * send ...
3162  * leave
3163  * =>
3164  * send ..., ... | VM_CALL_TAILCALL, ...
3165  * leave # unreachable
3166  */
3167  INSN *piobj = NULL;
3168  if (iobj->link.next) {
3169  LINK_ELEMENT *next = iobj->link.next;
3170  do {
3171  if (!IS_INSN(next)) {
3172  next = next->next;
3173  continue;
3174  }
3175  switch (INSN_OF(next)) {
3176  case BIN(nop):
3177  next = next->next;
3178  break;
3179  case BIN(jump):
3180  /* if cond
3181  * return tailcall
3182  * end
3183  */
3184  next = get_destination_insn((INSN *)next);
3185  break;
3186  case BIN(leave):
3187  piobj = iobj;
3188  /* fall through */
3189  default:
3190  next = NULL;
3191  break;
3192  }
3193  } while (next);
3194  }
3195 
3196  if (piobj) {
3197  struct rb_call_info *ci = (struct rb_call_info *)OPERAND_AT(piobj, 0);
3198  if (IS_INSN_ID(piobj, send) || IS_INSN_ID(piobj, invokesuper)) {
3199  if (OPERAND_AT(piobj, 1) == 0) { /* no blockiseq */
3200  ci->flag |= VM_CALL_TAILCALL;
3201  }
3202  }
3203  else {
3204  ci->flag |= VM_CALL_TAILCALL;
3205  }
3206  }
3207  }
3208 
3209  if (IS_INSN_ID(iobj, dup)) {
3210  if (IS_NEXT_INSN_ID(&iobj->link, setlocal)) {
3211  LINK_ELEMENT *set1 = iobj->link.next, *set2 = NULL;
3212  if (IS_NEXT_INSN_ID(set1, setlocal)) {
3213  set2 = set1->next;
3214  if (OPERAND_AT(set1, 0) == OPERAND_AT(set2, 0) &&
3215  OPERAND_AT(set1, 1) == OPERAND_AT(set2, 1)) {
3216  ELEM_REMOVE(set1);
3217  ELEM_REMOVE(&iobj->link);
3218  }
3219  }
3220  else if (IS_NEXT_INSN_ID(set1, dup) &&
3221  IS_NEXT_INSN_ID(set1->next, setlocal)) {
3222  set2 = set1->next->next;
3223  if (OPERAND_AT(set1, 0) == OPERAND_AT(set2, 0) &&
3224  OPERAND_AT(set1, 1) == OPERAND_AT(set2, 1)) {
3225  ELEM_REMOVE(set1->next);
3226  ELEM_REMOVE(set2);
3227  }
3228  }
3229  }
3230  }
3231 
3232  if (IS_INSN_ID(iobj, getlocal)) {
3233  LINK_ELEMENT *niobj = &iobj->link;
3234  if (IS_NEXT_INSN_ID(niobj, dup)) {
3235  niobj = niobj->next;
3236  }
3237  if (IS_NEXT_INSN_ID(niobj, setlocal)) {
3238  LINK_ELEMENT *set1 = niobj->next;
3239  if (OPERAND_AT(iobj, 0) == OPERAND_AT(set1, 0) &&
3240  OPERAND_AT(iobj, 1) == OPERAND_AT(set1, 1)) {
3241  ELEM_REMOVE(set1);
3242  ELEM_REMOVE(niobj);
3243  }
3244  }
3245  }
3246 
3247  if (IS_INSN_ID(iobj, opt_invokebuiltin_delegate)) {
3248  if (IS_TRACE(iobj->link.next)) {
3249  if (IS_NEXT_INSN_ID(iobj->link.next, leave)) {
3250  iobj->insn_id = BIN(opt_invokebuiltin_delegate_leave);
3251  }
3252  }
3253  }
3254 
3255  return COMPILE_OK;
3256 }
3257 
3258 static int
3259 insn_set_specialized_instruction(rb_iseq_t *iseq, INSN *iobj, int insn_id)
3260 {
3261  iobj->insn_id = insn_id;
3262  iobj->operand_size = insn_len(insn_id) - 1;
3263 
3264  if (insn_id == BIN(opt_neq)) {
3265  VALUE *old_operands = iobj->operands;
3266  iobj->operand_size = 2;
3267  iobj->operands = compile_data_alloc2(iseq, iobj->operand_size, sizeof(VALUE));
3268  iobj->operands[0] = (VALUE)new_callinfo(iseq, idEq, 1, 0, NULL, FALSE);
3269  iobj->operands[1] = old_operands[0];
3270  }
3271 
3272  return COMPILE_OK;
3273 }
3274 
3275 static int
3276 iseq_specialized_instruction(rb_iseq_t *iseq, INSN *iobj)
3277 {
3278  if (IS_INSN_ID(iobj, newarray) && iobj->link.next &&
3279  IS_INSN(iobj->link.next)) {
3280  /*
3281  * [a, b, ...].max/min -> a, b, c, opt_newarray_max/min
3282  */
3283  INSN *niobj = (INSN *)iobj->link.next;
3284  if (IS_INSN_ID(niobj, send)) {
3285  struct rb_call_info *ci = (struct rb_call_info *)OPERAND_AT(niobj, 0);
3286  if ((ci->flag & VM_CALL_ARGS_SIMPLE) && ci->orig_argc == 0) {
3287  switch (ci->mid) {
3288  case idMax:
3289  iobj->insn_id = BIN(opt_newarray_max);
3290  ELEM_REMOVE(&niobj->link);
3291  return COMPILE_OK;
3292  case idMin:
3293  iobj->insn_id = BIN(opt_newarray_min);
3294  ELEM_REMOVE(&niobj->link);
3295  return COMPILE_OK;
3296  }
3297  }
3298  }
3299  }
3300 
3301  if (IS_INSN_ID(iobj, send)) {
3302  struct rb_call_info *ci = (struct rb_call_info *)OPERAND_AT(iobj, 0);
3303  const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(iobj, 1);
3304 
3305 #define SP_INSN(opt) insn_set_specialized_instruction(iseq, iobj, BIN(opt_##opt))
3306  if (ci->flag & VM_CALL_ARGS_SIMPLE) {
3307  switch (ci->orig_argc) {
3308  case 0:
3309  switch (ci->mid) {
3310  case idLength: SP_INSN(length); return COMPILE_OK;
3311  case idSize: SP_INSN(size); return COMPILE_OK;
3312  case idEmptyP: SP_INSN(empty_p);return COMPILE_OK;
3313  case idNilP: SP_INSN(nil_p); return COMPILE_OK;
3314  case idSucc: SP_INSN(succ); return COMPILE_OK;
3315  case idNot: SP_INSN(not); return COMPILE_OK;
3316  }
3317  break;
3318  case 1:
3319  switch (ci->mid) {
3320  case idPLUS: SP_INSN(plus); return COMPILE_OK;
3321  case idMINUS: SP_INSN(minus); return COMPILE_OK;
3322  case idMULT: SP_INSN(mult); return COMPILE_OK;
3323  case idDIV: SP_INSN(div); return COMPILE_OK;
3324  case idMOD: SP_INSN(mod); return COMPILE_OK;
3325  case idEq: SP_INSN(eq); return COMPILE_OK;
3326  case idNeq: SP_INSN(neq); return COMPILE_OK;
3327  case idEqTilde:SP_INSN(regexpmatch2);return COMPILE_OK;
3328  case idLT: SP_INSN(lt); return COMPILE_OK;
3329  case idLE: SP_INSN(le); return COMPILE_OK;
3330  case idGT: SP_INSN(gt); return COMPILE_OK;
3331  case idGE: SP_INSN(ge); return COMPILE_OK;
3332  case idLTLT: SP_INSN(ltlt); return COMPILE_OK;
3333  case idAREF: SP_INSN(aref); return COMPILE_OK;
3334  case idAnd: SP_INSN(and); return COMPILE_OK;
3335  case idOr: SP_INSN(or); return COMPILE_OK;
3336  }
3337  break;
3338  case 2:
3339  switch (ci->mid) {
3340  case idASET: SP_INSN(aset); return COMPILE_OK;
3341  }
3342  break;
3343  }
3344  }
3345 
3346  if ((ci->flag & VM_CALL_ARGS_BLOCKARG) == 0 && blockiseq == NULL) {
3347  iobj->insn_id = BIN(opt_send_without_block);
3348  iobj->operand_size = insn_len(iobj->insn_id) - 1;
3349  }
3350  }
3351 #undef SP_INSN
3352 
3353  return COMPILE_OK;
3354 }
3355 
3356 static inline int
3357 tailcallable_p(rb_iseq_t *iseq)
3358 {
3359  switch (iseq->body->type) {
3360  case ISEQ_TYPE_TOP:
3361  case ISEQ_TYPE_EVAL:
3362  case ISEQ_TYPE_MAIN:
3363  /* not tail callable because cfp will be over popped */
3364  case ISEQ_TYPE_RESCUE:
3365  case ISEQ_TYPE_ENSURE:
3366  /* rescue block can't tail call because of errinfo */
3367  return FALSE;
3368  default:
3369  return TRUE;
3370  }
3371 }
3372 
3373 static int
3374 iseq_optimize(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
3375 {
3376  LINK_ELEMENT *list;
3377  const int do_peepholeopt = ISEQ_COMPILE_DATA(iseq)->option->peephole_optimization;
3378  const int do_tailcallopt = tailcallable_p(iseq) &&
3379  ISEQ_COMPILE_DATA(iseq)->option->tailcall_optimization;
3380  const int do_si = ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction;
3381  const int do_ou = ISEQ_COMPILE_DATA(iseq)->option->operands_unification;
3382  int rescue_level = 0;
3383  int tailcallopt = do_tailcallopt;
3384 
3385  list = FIRST_ELEMENT(anchor);
3386 
3387  while (list) {
3388  if (IS_INSN(list)) {
3389  if (do_peepholeopt) {
3390  iseq_peephole_optimize(iseq, list, tailcallopt);
3391  }
3392  if (do_si) {
3393  iseq_specialized_instruction(iseq, (INSN *)list);
3394  }
3395  if (do_ou) {
3396  insn_operands_unification((INSN *)list);
3397  }
3398  }
3399  if (IS_LABEL(list)) {
3400  switch (((LABEL *)list)->rescued) {
3401  case LABEL_RESCUE_BEG:
3402  rescue_level++;
3403  tailcallopt = FALSE;
3404  break;
3405  case LABEL_RESCUE_END:
3406  if (!--rescue_level) tailcallopt = do_tailcallopt;
3407  break;
3408  }
3409  }
3410  list = list->next;
3411  }
3412  return COMPILE_OK;
3413 }
3414 
3415 #if OPT_INSTRUCTIONS_UNIFICATION
3416 static INSN *
3417 new_unified_insn(rb_iseq_t *iseq,
3418  int insn_id, int size, LINK_ELEMENT *seq_list)
3419 {
3420  INSN *iobj = 0;
3421  LINK_ELEMENT *list = seq_list;
3422  int i, argc = 0;
3423  VALUE *operands = 0, *ptr = 0;
3424 
3425 
3426  /* count argc */
3427  for (i = 0; i < size; i++) {
3428  iobj = (INSN *)list;
3429  argc += iobj->operand_size;
3430  list = list->next;
3431  }
3432 
3433  if (argc > 0) {
3434  ptr = operands =
3435  compile_data_alloc2(iseq, sizeof(VALUE), argc);
3436  }
3437 
3438  /* copy operands */
3439  list = seq_list;
3440  for (i = 0; i < size; i++) {
3441  iobj = (INSN *)list;
3442  MEMCPY(ptr, iobj->operands, VALUE, iobj->operand_size);
3443  ptr += iobj->operand_size;
3444  list = list->next;
3445  }
3446 
3447  return new_insn_core(iseq, iobj->insn_info.line_no, insn_id, argc, operands);
3448 }
3449 #endif
3450 
3451 /*
3452  * This scheme can get more performance if do this optimize with
3453  * label address resolving.
3454  * It's future work (if compile time was bottle neck).
3455  */
3456 static int
3457 iseq_insns_unification(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
3458 {
3459 #if OPT_INSTRUCTIONS_UNIFICATION
3460  LINK_ELEMENT *list;
3461  INSN *iobj, *niobj;
3462  int id, k;
3463  intptr_t j;
3464 
3465  list = FIRST_ELEMENT(anchor);
3466  while (list) {
3467  if (IS_INSN(list)) {
3468  iobj = (INSN *)list;
3469  id = iobj->insn_id;
3470  if (unified_insns_data[id] != 0) {
3471  const int *const *entry = unified_insns_data[id];
3472  for (j = 1; j < (intptr_t)entry[0]; j++) {
3473  const int *unified = entry[j];
3474  LINK_ELEMENT *li = list->next;
3475  for (k = 2; k < unified[1]; k++) {
3476  if (!IS_INSN(li) ||
3477  ((INSN *)li)->insn_id != unified[k]) {
3478  goto miss;
3479  }
3480  li = li->next;
3481  }
3482  /* matched */
3483  niobj =
3484  new_unified_insn(iseq, unified[0], unified[1] - 1,
3485  list);
3486 
3487  /* insert to list */
3488  niobj->link.prev = (LINK_ELEMENT *)iobj->link.prev;
3489  niobj->link.next = li;
3490  if (li) {
3491  li->prev = (LINK_ELEMENT *)niobj;
3492  }
3493 
3494  list->prev->next = (LINK_ELEMENT *)niobj;
3495  list = (LINK_ELEMENT *)niobj;
3496  break;
3497  miss:;
3498  }
3499  }
3500  }
3501  list = list->next;
3502  }
3503 #endif
3504  return COMPILE_OK;
3505 }
3506 
3507 #if OPT_STACK_CACHING
3508 
3509 #define SC_INSN(insn, stat) sc_insn_info[(insn)][(stat)]
3510 #define SC_NEXT(insn) sc_insn_next[(insn)]
3511 
3512 #include "opt_sc.inc"
3513 
3514 static int
3515 insn_set_sc_state(rb_iseq_t *iseq, const LINK_ELEMENT *anchor, INSN *iobj, int state)
3516 {
3517  int nstate;
3518  int insn_id;
3519 
3520  insn_id = iobj->insn_id;
3521  iobj->insn_id = SC_INSN(insn_id, state);
3522  nstate = SC_NEXT(iobj->insn_id);
3523 
3524  if (insn_id == BIN(jump) ||
3525  insn_id == BIN(branchif) || insn_id == BIN(branchunless)) {
3526  LABEL *lobj = (LABEL *)OPERAND_AT(iobj, 0);
3527 
3528  if (lobj->sc_state != 0) {
3529  if (lobj->sc_state != nstate) {
3530  BADINSN_DUMP(anchor, iobj, lobj);
3532  "insn_set_sc_state error: %d at "LABEL_FORMAT
3533  ", %d expected\n",
3534  lobj->sc_state, lobj->label_no, nstate);
3535  return COMPILE_NG;
3536  }
3537  }
3538  else {
3539  lobj->sc_state = nstate;
3540  }
3541  if (insn_id == BIN(jump)) {
3542  nstate = SCS_XX;
3543  }
3544  }
3545  else if (insn_id == BIN(leave)) {
3546  nstate = SCS_XX;
3547  }
3548 
3549  return nstate;
3550 }
3551 
3552 static int
3553 label_set_sc_state(LABEL *lobj, int state)
3554 {
3555  if (lobj->sc_state != 0) {
3556  if (lobj->sc_state != state) {
3557  state = lobj->sc_state;
3558  }
3559  }
3560  else {
3561  lobj->sc_state = state;
3562  }
3563 
3564  return state;
3565 }
3566 
3567 
3568 #endif
3569 
3570 static int
3571 iseq_set_sequence_stackcaching(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
3572 {
3573 #if OPT_STACK_CACHING
3574  LINK_ELEMENT *list;
3575  int state, insn_id;
3576 
3577  /* initialize */
3578  state = SCS_XX;
3579  list = FIRST_ELEMENT(anchor);
3580  /* dump_disasm_list(list); */
3581 
3582  /* for each list element */
3583  while (list) {
3584  redo_point:
3585  switch (list->type) {
3586  case ISEQ_ELEMENT_INSN:
3587  {
3588  INSN *iobj = (INSN *)list;
3589  insn_id = iobj->insn_id;
3590 
3591  /* dump_disasm_list(list); */
3592 
3593  switch (insn_id) {
3594  case BIN(nop):
3595  {
3596  /* exception merge point */
3597  if (state != SCS_AX) {
3598  INSN *rpobj =
3599  new_insn_body(iseq, 0, BIN(reput), 0);
3600 
3601  /* replace this insn */
3602  ELEM_REPLACE(list, (LINK_ELEMENT *)rpobj);
3603  list = (LINK_ELEMENT *)rpobj;
3604  goto redo_point;
3605  }
3606  break;
3607  }
3608  case BIN(swap):
3609  {
3610  if (state == SCS_AB || state == SCS_BA) {
3611  state = (state == SCS_AB ? SCS_BA : SCS_AB);
3612 
3613  ELEM_REMOVE(list);
3614  list = list->next;
3615  goto redo_point;
3616  }
3617  break;
3618  }
3619  case BIN(pop):
3620  {
3621  switch (state) {
3622  case SCS_AX:
3623  case SCS_BX:
3624  state = SCS_XX;
3625  break;
3626  case SCS_AB:
3627  state = SCS_AX;
3628  break;
3629  case SCS_BA:
3630  state = SCS_BX;
3631  break;
3632  case SCS_XX:
3633  goto normal_insn;
3634  default:
3636  "unreachable");
3637  return COMPILE_NG;
3638  }
3639  /* remove useless pop */
3640  ELEM_REMOVE(list);
3641  list = list->next;
3642  goto redo_point;
3643  }
3644  default:;
3645  /* none */
3646  } /* end of switch */
3647  normal_insn:
3648  state = insn_set_sc_state(iseq, anchor, iobj, state);
3649  break;
3650  }
3651  case ISEQ_ELEMENT_LABEL:
3652  {
3653  LABEL *lobj;
3654  lobj = (LABEL *)list;
3655 
3656  state = label_set_sc_state(lobj, state);
3657  }
3658  default:
3659  break;
3660  }
3661  list = list->next;
3662  }
3663 #endif
3664  return COMPILE_OK;
3665 }
3666 
3667 static int
3668 all_string_result_p(const NODE *node)
3669 {
3670  if (!node) return FALSE;
3671  switch (nd_type(node)) {
3672  case NODE_STR: case NODE_DSTR:
3673  return TRUE;
3674  case NODE_IF: case NODE_UNLESS:
3675  if (!node->nd_body || !node->nd_else) return FALSE;
3676  if (all_string_result_p(node->nd_body))
3677  return all_string_result_p(node->nd_else);
3678  return FALSE;
3679  case NODE_AND: case NODE_OR:
3680  if (!node->nd_2nd)
3681  return all_string_result_p(node->nd_1st);
3682  if (!all_string_result_p(node->nd_1st))
3683  return FALSE;
3684  return all_string_result_p(node->nd_2nd);
3685  default:
3686  return FALSE;
3687  }
3688 }
3689 
3690 static int
3691 compile_dstr_fragments(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int *cntp)
3692 {
3693  const NODE *list = node->nd_next;
3694  VALUE lit = node->nd_lit;
3695  LINK_ELEMENT *first_lit = 0;
3696  int cnt = 0;
3697 
3698  debugp_param("nd_lit", lit);
3699  if (!NIL_P(lit)) {
3700  cnt++;
3701  if (!RB_TYPE_P(lit, T_STRING)) {
3702  COMPILE_ERROR(ERROR_ARGS "dstr: must be string: %s",
3703  rb_builtin_type_name(TYPE(lit)));
3704  return COMPILE_NG;
3705  }
3706  lit = rb_fstring(lit);
3707  ADD_INSN1(ret, nd_line(node), putobject, lit);
3708  RB_OBJ_WRITTEN(iseq, Qundef, lit);
3709  if (RSTRING_LEN(lit) == 0) first_lit = LAST_ELEMENT(ret);
3710  }
3711 
3712  while (list) {
3713  const NODE *const head = list->nd_head;
3714  if (nd_type(head) == NODE_STR) {
3715  lit = rb_fstring(head->nd_lit);
3716  ADD_INSN1(ret, nd_line(head), putobject, lit);
3717  RB_OBJ_WRITTEN(iseq, Qundef, lit);
3718  lit = Qnil;
3719  }
3720  else {
3721  CHECK(COMPILE(ret, "each string", head));
3722  }
3723  cnt++;
3724  list = list->nd_next;
3725  }
3726  if (NIL_P(lit) && first_lit) {
3727  ELEM_REMOVE(first_lit);
3728  --cnt;
3729  }
3730  *cntp = cnt;
3731 
3732  return COMPILE_OK;
3733 }
3734 
3735 static int
3736 compile_dstr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node)
3737 {
3738  int cnt;
3739  CHECK(compile_dstr_fragments(iseq, ret, node, &cnt));
3740  ADD_INSN1(ret, nd_line(node), concatstrings, INT2FIX(cnt));
3741  return COMPILE_OK;
3742 }
3743 
3744 static int
3745 compile_dregx(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node)
3746 {
3747  int cnt;
3748  CHECK(compile_dstr_fragments(iseq, ret, node, &cnt));
3749  ADD_INSN2(ret, nd_line(node), toregexp, INT2FIX(node->nd_cflag), INT2FIX(cnt));
3750  return COMPILE_OK;
3751 }
3752 
3753 static int
3754 compile_flip_flop(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int again,
3755  LABEL *then_label, LABEL *else_label)
3756 {
3757  const int line = nd_line(node);
3758  LABEL *lend = NEW_LABEL(line);
3759  rb_num_t cnt = ISEQ_FLIP_CNT_INCREMENT(iseq->body->local_iseq)
3761  VALUE key = INT2FIX(cnt);
3762 
3763  ADD_INSN2(ret, line, getspecial, key, INT2FIX(0));
3764  ADD_INSNL(ret, line, branchif, lend);
3765 
3766  /* *flip == 0 */
3767  CHECK(COMPILE(ret, "flip2 beg", node->nd_beg));
3768  ADD_INSNL(ret, line, branchunless, else_label);
3769  ADD_INSN1(ret, line, putobject, Qtrue);
3770  ADD_INSN1(ret, line, setspecial, key);
3771  if (!again) {
3772  ADD_INSNL(ret, line, jump, then_label);
3773  }
3774 
3775  /* *flip == 1 */
3776  ADD_LABEL(ret, lend);
3777  CHECK(COMPILE(ret, "flip2 end", node->nd_end));
3778  ADD_INSNL(ret, line, branchunless, then_label);
3779  ADD_INSN1(ret, line, putobject, Qfalse);
3780  ADD_INSN1(ret, line, setspecial, key);
3781  ADD_INSNL(ret, line, jump, then_label);
3782 
3783  return COMPILE_OK;
3784 }
3785 
3786 static int
3787 compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *cond,
3788  LABEL *then_label, LABEL *else_label)
3789 {
3790  again:
3791  switch (nd_type(cond)) {
3792  case NODE_AND:
3793  {
3794  LABEL *label = NEW_LABEL(nd_line(cond));
3795  CHECK(compile_branch_condition(iseq, ret, cond->nd_1st, label,
3796  else_label));
3797  if (!label->refcnt) break;
3798  ADD_LABEL(ret, label);
3799  cond = cond->nd_2nd;
3800  goto again;
3801  }
3802  case NODE_OR:
3803  {
3804  LABEL *label = NEW_LABEL(nd_line(cond));
3805  CHECK(compile_branch_condition(iseq, ret, cond->nd_1st, then_label,
3806  label));
3807  if (!label->refcnt) break;
3808  ADD_LABEL(ret, label);
3809  cond = cond->nd_2nd;
3810  goto again;
3811  }
3812  case NODE_LIT: /* NODE_LIT is always true */
3813  case NODE_TRUE:
3814  case NODE_STR:
3815  case NODE_ZLIST:
3816  case NODE_LAMBDA:
3817  /* printf("useless condition eliminate (%s)\n", ruby_node_name(nd_type(cond))); */
3818  ADD_INSNL(ret, nd_line(cond), jump, then_label);
3819  break;
3820  case NODE_FALSE:
3821  case NODE_NIL:
3822  /* printf("useless condition eliminate (%s)\n", ruby_node_name(nd_type(cond))); */
3823  ADD_INSNL(ret, nd_line(cond), jump, else_label);
3824  break;
3825  case NODE_LIST:
3826  case NODE_ARGSCAT:
3827  case NODE_DREGX:
3828  case NODE_DSTR:
3829  CHECK(COMPILE_POPPED(ret, "branch condition", cond));
3830  ADD_INSNL(ret, nd_line(cond), jump, then_label);
3831  break;
3832  case NODE_FLIP2:
3833  CHECK(compile_flip_flop(iseq, ret, cond, TRUE, then_label, else_label));
3834  break;
3835  case NODE_FLIP3:
3836  CHECK(compile_flip_flop(iseq, ret, cond, FALSE, then_label, else_label));
3837  break;
3838  case NODE_DEFINED:
3839  CHECK(compile_defined_expr(iseq, ret, cond, Qfalse));
3840  goto branch;
3841  default:
3842  CHECK(COMPILE(ret, "branch condition", cond));
3843  branch:
3844  ADD_INSNL(ret, nd_line(cond), branchunless, else_label);
3845  ADD_INSNL(ret, nd_line(cond), jump, then_label);
3846  break;
3847  }
3848  return COMPILE_OK;
3849 }
3850 
3851 static int
3852 keyword_node_p(const NODE *const node)
3853 {
3854  return nd_type(node) == NODE_HASH && node->nd_brace == FALSE;
3855 }
3856 
3857 static int
3858 compile_keyword_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
3859  const NODE *const root_node,
3860  struct rb_call_info_kw_arg **const kw_arg_ptr,
3861  unsigned int *flag)
3862 {
3863  if (kw_arg_ptr == NULL) return FALSE;
3864 
3865  if (keyword_node_p(root_node) && root_node->nd_head && nd_type(root_node->nd_head) == NODE_LIST) {
3866  const NODE *node = root_node->nd_head;
3867 
3868  while (node) {
3869  const NODE *key_node = node->nd_head;
3870 
3871  assert(nd_type(node) == NODE_LIST);
3872  if (!key_node) {
3873  if (flag) *flag |= VM_CALL_KW_SPLAT;
3874  return FALSE;
3875  }
3876  else if (nd_type(key_node) == NODE_LIT && RB_TYPE_P(key_node->nd_lit, T_SYMBOL)) {
3877  /* can be keywords */
3878  }
3879  else {
3880  if (flag) *flag |= VM_CALL_KW_SPLAT;
3881  return FALSE;
3882  }
3883  node = node->nd_next; /* skip value node */
3884  node = node->nd_next;
3885  }
3886 
3887  /* may be keywords */
3888  node = root_node->nd_head;
3889  {
3890  int len = (int)node->nd_alen / 2;
3891  struct rb_call_info_kw_arg *kw_arg =
3892  rb_xmalloc_mul_add(len - 1, sizeof(VALUE), sizeof(struct rb_call_info_kw_arg));
3893  VALUE *keywords = kw_arg->keywords;
3894  int i = 0;
3895  kw_arg->keyword_len = len;
3896 
3897  *kw_arg_ptr = kw_arg;
3898 
3899  for (i=0; node != NULL; i++, node = node->nd_next->nd_next) {
3900  const NODE *key_node = node->nd_head;
3901  const NODE *val_node = node->nd_next->nd_head;
3902  keywords[i] = key_node->nd_lit;
3903  NO_CHECK(COMPILE(ret, "keyword values", val_node));
3904  }
3905  assert(i == len);
3906  return TRUE;
3907  }
3908  }
3909  return FALSE;
3910 }
3911 
3912 static int
3913 compile_args(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node,
3914  struct rb_call_info_kw_arg **keywords_ptr, unsigned int *flag)
3915 {
3916  int len = 0;
3917 
3918  for (; node; len++, node = node->nd_next) {
3919  if (CPDEBUG > 0) {
3920  EXPECT_NODE("compile_args", node, NODE_LIST, -1);
3921  }
3922 
3923  if (node->nd_next == NULL /* last node */ &&
3924  compile_keyword_arg(iseq, ret, node->nd_head, keywords_ptr, flag)) {
3925  len--;
3926  }
3927  else {
3928  NO_CHECK(COMPILE_(ret, "array element", node->nd_head, FALSE));
3929  }
3930  }
3931 
3932  return len;
3933 }
3934 
3935 static inline int
3936 static_literal_node_p(const NODE *node, const rb_iseq_t *iseq)
3937 {
3938  node = node->nd_head;
3939  switch (nd_type(node)) {
3940  case NODE_LIT:
3941  case NODE_NIL:
3942  case NODE_TRUE:
3943  case NODE_FALSE:
3944  return TRUE;
3945  case NODE_STR:
3946  return ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal;
3947  default:
3948  return FALSE;
3949  }
3950 }
3951 
3952 static inline VALUE
3953 static_literal_value(const NODE *node, rb_iseq_t *iseq)
3954 {
3955  node = node->nd_head;
3956  switch (nd_type(node)) {
3957  case NODE_NIL:
3958  return Qnil;
3959  case NODE_TRUE:
3960  return Qtrue;
3961  case NODE_FALSE:
3962  return Qfalse;
3963  case NODE_STR:
3964  if (ISEQ_COMPILE_DATA(iseq)->option->debug_frozen_string_literal || RTEST(ruby_debug)) {
3965  VALUE lit;
3966  VALUE debug_info = rb_ary_new_from_args(2, rb_iseq_path(iseq), INT2FIX((int)nd_line(node)));
3967  lit = rb_str_dup(node->nd_lit);
3968  rb_ivar_set(lit, id_debug_created_info, rb_obj_freeze(debug_info));
3969  return rb_str_freeze(lit);
3970  }
3971  else {
3972  return rb_fstring(node->nd_lit);
3973  }
3974  default:
3975  return node->nd_lit;
3976  }
3977 }
3978 
3979 static int
3980 compile_array(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int popped)
3981 {
3982  int line = (int)nd_line(node);
3983 
3984  if (nd_type(node) == NODE_ZLIST) {
3985  if (!popped) {
3986  ADD_INSN1(ret, line, newarray, INT2FIX(0));
3987  }
3988  return 0;
3989  }
3990 
3991  EXPECT_NODE("compile_array", node, NODE_LIST, -1);
3992 
3993  if (popped) {
3994  for (; node; node = node->nd_next) {
3995  NO_CHECK(COMPILE_(ret, "array element", node->nd_head, popped));
3996  }
3997  return 1;
3998  }
3999 
4000  /* Compilation of an array literal.
4001  * The following code is essentially the same as:
4002  *
4003  * for (int count = 0; node; count++; node->nd_next) {
4004  * compile(node->nd_head);
4005  * }
4006  * ADD_INSN(newarray, count);
4007  *
4008  * However, there are three points.
4009  *
4010  * - The code above causes stack overflow for a big string literal.
4011  * The following limits the stack length up to max_stack_len.
4012  *
4013  * [x1,x2,...,x10000] =>
4014  * push x1 ; push x2 ; ...; push x256; newarray 256;
4015  * push x257; push x258; ...; push x512; newarray 256; concatarray;
4016  * push x513; push x514; ...; push x768; newarray 256; concatarray;
4017  * ...
4018  *
4019  * - Long subarray can be optimized by pre-allocating a hidden array.
4020  *
4021  * [1,2,3,...,100] =>
4022  * duparray [1,2,3,...,100]
4023  *
4024  * [x, 1,2,3,...,100, z] =>
4025  * push x; newarray 1;
4026  * putobject [1,2,3,...,100] (<- hidden array); concatarray;
4027  * push z; newarray 1; concatarray
4028  *
4029  * - If the last element is a keyword, newarraykwsplat should be emitted
4030  * to check and remove empty keyword arguments hash from array.
4031  * (Note: a keyword is NODE_HASH which is not static_literal_node_p.)
4032  *
4033  * [1,2,3,**kw] =>
4034  * putobject 1; putobject 2; putobject 3; push kw; newarraykwsplat
4035  */
4036 
4037  const int max_stack_len = 0x100;
4038  const int min_tmp_ary_len = 0x40;
4039  int stack_len = 0;
4040  int first_chunk = 1;
4041 
4042  /* Convert pushed elements to an array, and concatarray if needed */
4043 #define FLUSH_CHUNK(newarrayinsn) \
4044  if (stack_len) { \
4045  ADD_INSN1(ret, line, newarrayinsn, INT2FIX(stack_len)); \
4046  if (!first_chunk) ADD_INSN(ret, line, concatarray); \
4047  first_chunk = stack_len = 0; \
4048  }
4049 
4050  while (node) {
4051  int count = 1;
4052 
4053  /* pre-allocation check (this branch can be omittable) */
4054  if (static_literal_node_p(node, iseq)) {
4055  /* count the elements that are optimizable */
4056  const NODE *node_tmp = node->nd_next;
4057  for (; node_tmp && static_literal_node_p(node_tmp, iseq); node_tmp = node_tmp->nd_next)
4058  count++;
4059 
4060  if ((first_chunk && stack_len == 0 && !node_tmp) || count >= min_tmp_ary_len) {
4061  /* The literal contains only optimizable elements, or the subarray is long enough */
4062  VALUE ary = rb_ary_tmp_new(count);
4063 
4064  /* Create a hidden array */
4065  for (; count; count--, node = node->nd_next)
4066  rb_ary_push(ary, static_literal_value(node, iseq));
4067  OBJ_FREEZE(ary);
4068 
4069  /* Emit optimized code */
4070  FLUSH_CHUNK(newarray);
4071  if (first_chunk) {
4072  ADD_INSN1(ret, line, duparray, ary);
4073  first_chunk = 0;
4074  }
4075  else {
4076  ADD_INSN1(ret, line, putobject, ary);
4077  ADD_INSN(ret, line, concatarray);
4078  }
4079  RB_OBJ_WRITTEN(iseq, Qundef, ary);
4080  }
4081  }
4082 
4083  /* Base case: Compile "count" elements */
4084  for (; count; count--, node = node->nd_next) {
4085  if (CPDEBUG > 0) {
4086  EXPECT_NODE("compile_array", node, NODE_LIST, -1);
4087  }
4088 
4089  NO_CHECK(COMPILE_(ret, "array element", node->nd_head, 0));
4090  stack_len++;
4091 
4092  if (!node->nd_next && keyword_node_p(node->nd_head)) {
4093  /* Reached the end, and the last element is a keyword */
4094  FLUSH_CHUNK(newarraykwsplat);
4095  return 1;
4096  }
4097 
4098  /* If there are many pushed elements, flush them to avoid stack overflow */
4099  if (stack_len >= max_stack_len) FLUSH_CHUNK(newarray);
4100  }
4101  }
4102 
4103  FLUSH_CHUNK(newarray);
4104 #undef FLUSH_CHUNK
4105  return 1;
4106 }
4107 
4108 static inline int
4109 static_literal_node_pair_p(const NODE *node, const rb_iseq_t *iseq)
4110 {
4111  return node->nd_head && static_literal_node_p(node, iseq) && static_literal_node_p(node->nd_next, iseq);
4112 }
4113 
4114 static int
4115 compile_hash(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int popped)
4116 {
4117  int line = (int)nd_line(node);
4118 
4119  node = node->nd_head;
4120 
4121  if (!node || nd_type(node) == NODE_ZLIST) {
4122  if (!popped) {
4123  ADD_INSN1(ret, line, newhash, INT2FIX(0));
4124  }
4125  return 0;
4126  }
4127 
4128  EXPECT_NODE("compile_hash", node, NODE_LIST, -1);
4129 
4130  if (popped) {
4131  for (; node; node = node->nd_next) {
4132  NO_CHECK(COMPILE_(ret, "hash element", node->nd_head, popped));
4133  }
4134  return 1;
4135  }
4136 
4137  /* Compilation of a hash literal (or keyword arguments).
4138  * This is very similar to compile_array, but there are some differences:
4139  *
4140  * - It contains key-value pairs. So we need to take every two elements.
4141  * We can assume that the length is always even.
4142  *
4143  * - Merging is done by a method call (id_core_hash_merge_ptr).
4144  * Sometimes we need to insert the receiver, so "anchor" is needed.
4145  * In addition, a method call is much slower than concatarray.
4146  * So it pays only when the subsequence is really long.
4147  * (min_tmp_hash_len must be much larger than min_tmp_ary_len.)
4148  *
4149  * - We need to handle keyword splat: **kw.
4150  * For **kw, the key part (node->nd_head) is NULL, and the value part
4151  * (node->nd_next->nd_head) is "kw".
4152  * The code is a bit difficult to avoid hash allocation for **{}.
4153  */
4154 
4155  const int max_stack_len = 0x100;
4156  const int min_tmp_hash_len = 0x800;
4157  int stack_len = 0;
4158  int first_chunk = 1;
4159  DECL_ANCHOR(anchor);
4160  INIT_ANCHOR(anchor);
4161 
4162  /* Convert pushed elements to a hash, and merge if needed */
4163 #define FLUSH_CHUNK() \
4164  if (stack_len) { \
4165  if (first_chunk) { \
4166  APPEND_LIST(ret, anchor); \
4167  ADD_INSN1(ret, line, newhash, INT2FIX(stack_len)); \
4168  } \
4169  else { \
4170  ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE)); \
4171  ADD_INSN(ret, line, swap); \
4172  APPEND_LIST(ret, anchor); \
4173  ADD_SEND(ret, line, id_core_hash_merge_ptr, INT2FIX(stack_len + 1)); \
4174  } \
4175  INIT_ANCHOR(anchor); \
4176  first_chunk = stack_len = 0; \
4177  }
4178 
4179  while (node) {
4180  int count = 1;
4181 
4182  /* pre-allocation check (this branch can be omittable) */
4183  if (static_literal_node_pair_p(node, iseq)) {
4184  /* count the elements that are optimizable */
4185  const NODE *node_tmp = node->nd_next->nd_next;
4186  for (; node_tmp && static_literal_node_pair_p(node_tmp, iseq); node_tmp = node_tmp->nd_next->nd_next)
4187  count++;
4188 
4189  if ((first_chunk && stack_len == 0 && !node_tmp) || count >= min_tmp_hash_len) {
4190  /* The literal contains only optimizable elements, or the subsequence is long enough */
4191  VALUE ary = rb_ary_tmp_new(count);
4192 
4193  /* Create a hidden hash */
4194  for (; count; count--, node = node->nd_next->nd_next) {
4195  VALUE elem[2];
4196  elem[0] = static_literal_value(node, iseq);
4197  elem[1] = static_literal_value(node->nd_next, iseq);
4198  rb_ary_cat(ary, elem, 2);
4199  }
4200  VALUE hash = rb_hash_new_with_size(RARRAY_LEN(ary) / 2);
4202  hash = rb_obj_hide(hash);
4203  OBJ_FREEZE(hash);
4204 
4205  /* Emit optimized code */
4206  FLUSH_CHUNK();
4207  if (first_chunk) {
4208  ADD_INSN1(ret, line, duphash, hash);
4209  first_chunk = 0;
4210  }
4211  else {
4212  ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
4213  ADD_INSN(ret, line, swap);
4214 
4215  ADD_INSN1(ret, line, putobject, hash);
4216 
4217  ADD_SEND(ret, line, id_core_hash_merge_kwd, INT2FIX(2));
4218  }
4219  RB_OBJ_WRITTEN(iseq, Qundef, hash);
4220  }
4221  }
4222 
4223  /* Base case: Compile "count" elements */
4224  for (; count; count--, node = node->nd_next->nd_next) {
4225 
4226  if (CPDEBUG > 0) {
4227  EXPECT_NODE("compile_hash", node, NODE_LIST, -1);
4228  }
4229 
4230  if (node->nd_head) {
4231  /* Normal key-value pair */
4232  NO_CHECK(COMPILE_(anchor, "hash key element", node->nd_head, 0));
4233  NO_CHECK(COMPILE_(anchor, "hash value element", node->nd_next->nd_head, 0));
4234  stack_len += 2;
4235 
4236  /* If there are many pushed elements, flush them to avoid stack overflow */
4237  if (stack_len >= max_stack_len) FLUSH_CHUNK();
4238  }
4239  else {
4240  /* kwsplat case: foo(..., **kw, ...) */
4241  FLUSH_CHUNK();
4242 
4243  const NODE *kw = node->nd_next->nd_head;
4244  int empty_kw = nd_type(kw) == NODE_LIT && RB_TYPE_P(kw->nd_lit, T_HASH); /* foo( ..., **{}, ...) */
4245  int first_kw = first_chunk && stack_len == 0; /* foo(1,2,3, **kw, ...) */
4246  int last_kw = !node->nd_next->nd_next; /* foo( ..., **kw) */
4247  int only_kw = last_kw && first_kw; /* foo(1,2,3, **kw) */
4248 
4249  if (empty_kw) {
4250  if (only_kw) {
4251  /* **{} appears at the last, so it won't be modified.
4252  * kw is a special NODE_LIT that contains a special empty hash,
4253  * so this emits: putobject {}
4254  */
4255  NO_CHECK(COMPILE(ret, "keyword splat", kw));
4256  }
4257  else if (first_kw) {
4258  /* **{} appears at the first, so it may be modified.
4259  * We need to create a fresh hash object.
4260  */
4261  ADD_INSN1(ret, line, newhash, INT2FIX(0));
4262  }
4263  }
4264  else {
4265  /* This is not empty hash: **{k:1}.
4266  * We need to clone the hash (if first), or merge the hash to
4267  * the accumulated hash (if not first).
4268  */
4269  ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
4270  if (first_kw) ADD_INSN1(ret, line, newhash, INT2FIX(0));
4271  else ADD_INSN(ret, line, swap);
4272 
4273  NO_CHECK(COMPILE(ret, "keyword splat", kw));
4274 
4275  ADD_SEND(ret, line, id_core_hash_merge_kwd, INT2FIX(2));
4276  }
4277 
4278  first_chunk = 0;
4279  }
4280  }
4281  }
4282 
4283  FLUSH_CHUNK();
4284 #undef FLUSH_CHUNK
4285  return 1;
4286 }
4287 
4288 VALUE
4290 {
4291  switch (nd_type(node)) {
4292  case NODE_LIT: {
4293  VALUE v = node->nd_lit;
4294  double ival;
4295  if (RB_TYPE_P(v, T_FLOAT) &&
4296  modf(RFLOAT_VALUE(v), &ival) == 0.0) {
4297  return FIXABLE(ival) ? LONG2FIX((long)ival) : rb_dbl2big(ival);
4298  }
4300  return v;
4301  }
4302  break;
4303  }
4304  case NODE_NIL:
4305  return Qnil;
4306  case NODE_TRUE:
4307  return Qtrue;
4308  case NODE_FALSE:
4309  return Qfalse;
4310  case NODE_STR:
4311  return rb_fstring(node->nd_lit);
4312  }
4313  return Qundef;
4314 }
4315 
4316 static int
4317 when_vals(rb_iseq_t *iseq, LINK_ANCHOR *const cond_seq, const NODE *vals,
4318  LABEL *l1, int only_special_literals, VALUE literals)
4319 {
4320  while (vals) {
4321  const NODE *val = vals->nd_head;
4323 
4324  if (lit == Qundef) {
4325  only_special_literals = 0;
4326  }
4327  else if (NIL_P(rb_hash_lookup(literals, lit))) {
4328  rb_hash_aset(literals, lit, (VALUE)(l1) | 1);
4329  }
4330 
4331  ADD_INSN(cond_seq, nd_line(val), dup); /* dup target */
4332 
4333  if (nd_type(val) == NODE_STR) {
4334  debugp_param("nd_lit", val->nd_lit);
4335  lit = rb_fstring(val->nd_lit);
4336  ADD_INSN1(cond_seq, nd_line(val), putobject, lit);
4337  RB_OBJ_WRITTEN(iseq, Qundef, lit);
4338  }
4339  else {
4340  if (!COMPILE(cond_seq, "when cond", val)) return -1;
4341  }
4342 
4343  ADD_INSN1(cond_seq, nd_line(vals), checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE));
4344  ADD_INSNL(cond_seq, nd_line(val), branchif, l1);
4345  vals = vals->nd_next;
4346  }
4347  return only_special_literals;
4348 }
4349 
4350 static int
4351 when_splat_vals(rb_iseq_t *iseq, LINK_ANCHOR *const cond_seq, const NODE *vals,
4352  LABEL *l1, int only_special_literals, VALUE literals)
4353 {
4354  const int line = nd_line(vals);
4355 
4356  switch (nd_type(vals)) {
4357  case NODE_LIST:
4358  if (when_vals(iseq, cond_seq, vals, l1, only_special_literals, literals) < 0)
4359  return COMPILE_NG;
4360  break;
4361  case NODE_SPLAT:
4362  ADD_INSN (cond_seq, line, dup);
4363  CHECK(COMPILE(cond_seq, "when splat", vals->nd_head));
4364  ADD_INSN1(cond_seq, line, splatarray, Qfalse);
4365  ADD_INSN1(cond_seq, line, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE | VM_CHECKMATCH_ARRAY));
4366  ADD_INSNL(cond_seq, line, branchif, l1);
4367  break;
4368  case NODE_ARGSCAT:
4369  CHECK(when_splat_vals(iseq, cond_seq, vals->nd_head, l1, only_special_literals, literals));
4370  CHECK(when_splat_vals(iseq, cond_seq, vals->nd_body, l1, only_special_literals, literals));
4371  break;
4372  case NODE_ARGSPUSH:
4373  CHECK(when_splat_vals(iseq, cond_seq, vals->nd_head, l1, only_special_literals, literals));
4374  ADD_INSN (cond_seq, line, dup);
4375  CHECK(COMPILE(cond_seq, "when argspush body", vals->nd_body));
4376  ADD_INSN1(cond_seq, line, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE));
4377  ADD_INSNL(cond_seq, line, branchif, l1);
4378  break;
4379  default:
4380  ADD_INSN (cond_seq, line, dup);
4381  CHECK(COMPILE(cond_seq, "when val", vals));
4382  ADD_INSN1(cond_seq, line, splatarray, Qfalse);
4383  ADD_INSN1(cond_seq, line, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE | VM_CHECKMATCH_ARRAY));
4384  ADD_INSNL(cond_seq, line, branchif, l1);
4385  break;
4386  }
4387  return COMPILE_OK;
4388 }
4389 
4390 
4391 static int
4392 compile_massign_lhs(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node)
4393 {
4394  switch (nd_type(node)) {
4395  case NODE_ATTRASGN: {
4396  INSN *iobj;
4397  struct rb_call_info *ci;
4398  VALUE dupidx;
4399  int line = nd_line(node);
4400 
4401  CHECK(COMPILE_POPPED(ret, "masgn lhs (NODE_ATTRASGN)", node));
4402 
4403  iobj = (INSN *)get_prev_insn((INSN *)LAST_ELEMENT(ret)); /* send insn */
4404  ci = (struct rb_call_info *)OPERAND_AT(iobj, 0);
4405  ci->orig_argc += 1;
4406  dupidx = INT2FIX(ci->orig_argc);
4407 
4408  INSERT_BEFORE_INSN1(iobj, line, topn, dupidx);
4409  if (ci->flag & VM_CALL_ARGS_SPLAT) {
4410  --ci->orig_argc;
4411  INSERT_BEFORE_INSN1(iobj, line, newarray, INT2FIX(1));
4412  INSERT_BEFORE_INSN(iobj, line, concatarray);
4413  }
4414  ADD_INSN(ret, line, pop); /* result */
4415  break;
4416  }
4417  case NODE_MASGN: {
4418  DECL_ANCHOR(anchor);
4419  INIT_ANCHOR(anchor);
4420  CHECK(COMPILE_POPPED(anchor, "nest masgn lhs", node));
4421  ELEM_REMOVE(FIRST_ELEMENT(anchor));
4422  ADD_SEQ(ret, anchor);
4423  break;
4424  }
4425  default: {
4426  DECL_ANCHOR(anchor);
4427  INIT_ANCHOR(anchor);
4428  CHECK(COMPILE_POPPED(anchor, "masgn lhs", node));
4429  ELEM_REMOVE(FIRST_ELEMENT(anchor));
4430  ADD_SEQ(ret, anchor);
4431  }
4432  }
4433 
4434  return COMPILE_OK;
4435 }
4436 
4437 static int
4438 compile_massign_opt_lhs(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *lhsn)
4439 {
4440  if (lhsn) {
4441  CHECK(compile_massign_opt_lhs(iseq, ret, lhsn->nd_next));
4442  CHECK(compile_massign_lhs(iseq, ret, lhsn->nd_head));
4443  }
4444  return COMPILE_OK;
4445 }
4446 
4447 static int
4448 compile_massign_opt(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
4449  const NODE *rhsn, const NODE *orig_lhsn)
4450 {
4451  VALUE mem[64];
4452  const int memsize = numberof(mem);
4453  int memindex = 0;
4454  int llen = 0, rlen = 0;
4455  int i;
4456  const NODE *lhsn = orig_lhsn;
4457 
4458 #define MEMORY(v) { \
4459  int i; \
4460  if (memindex == memsize) return 0; \
4461  for (i=0; i<memindex; i++) { \
4462  if (mem[i] == (v)) return 0; \
4463  } \
4464  mem[memindex++] = (v); \
4465 }
4466 
4467  if (rhsn == 0 || nd_type(rhsn) != NODE_LIST) {
4468  return 0;
4469  }
4470 
4471  while (lhsn) {
4472  const NODE *ln = lhsn->nd_head;
4473  switch (nd_type(ln)) {
4474  case NODE_LASGN:
4475  MEMORY(ln->nd_vid);
4476  break;
4477  case NODE_DASGN:
4478  case NODE_DASGN_CURR:
4479  case NODE_IASGN:
4480  case NODE_CVASGN:
4481  MEMORY(ln->nd_vid);
4482  break;
4483  default:
4484  return 0;
4485  }
4486  lhsn = lhsn->nd_next;
4487  llen++;
4488  }
4489 
4490  while (rhsn) {
4491  if (llen <= rlen) {
4492  NO_CHECK(COMPILE_POPPED(ret, "masgn val (popped)", rhsn->nd_head));
4493  }
4494  else {
4495  NO_CHECK(COMPILE(ret, "masgn val", rhsn->nd_head));
4496  }
4497  rhsn = rhsn->nd_next;
4498  rlen++;
4499  }
4500 
4501  if (llen > rlen) {
4502  for (i=0; i<llen-rlen; i++) {
4503  ADD_INSN(ret, nd_line(orig_lhsn), putnil);
4504  }
4505  }
4506 
4507  compile_massign_opt_lhs(iseq, ret, orig_lhsn);
4508  return 1;
4509 }
4510 
4511 static void
4512 adjust_stack(rb_iseq_t *iseq, LINK_ANCHOR *const ret, int line, int rlen, int llen)
4513 {
4514  if (rlen < llen) {
4515  do {ADD_INSN(ret, line, putnil);} while (++rlen < llen);
4516  }
4517  else if (rlen > llen) {
4518  do {ADD_INSN(ret, line, pop);} while (--rlen > llen);
4519  }
4520 }
4521 
4522 static int
4523 compile_massign(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
4524 {
4525  const NODE *rhsn = node->nd_value;
4526  const NODE *splatn = node->nd_args;
4527  const NODE *lhsn = node->nd_head;
4528  int lhs_splat = (splatn && NODE_NAMED_REST_P(splatn)) ? 1 : 0;
4529 
4530  if (!popped || splatn || !compile_massign_opt(iseq, ret, rhsn, lhsn)) {
4531  int llen = 0;
4532  int expand = 1;
4533  DECL_ANCHOR(lhsseq);
4534 
4535  INIT_ANCHOR(lhsseq);
4536 
4537  while (lhsn) {
4538  CHECK(compile_massign_lhs(iseq, lhsseq, lhsn->nd_head));
4539  llen += 1;
4540  lhsn = lhsn->nd_next;
4541  }
4542 
4543  NO_CHECK(COMPILE(ret, "normal masgn rhs", rhsn));
4544 
4545  if (!popped) {
4546  ADD_INSN(ret, nd_line(node), dup);
4547  }
4548  else if (!lhs_splat) {
4549  INSN *last = (INSN*)ret->last;
4550  if (IS_INSN(&last->link) &&
4551  IS_INSN_ID(last, newarray) &&
4552  last->operand_size == 1) {
4553  int rlen = FIX2INT(OPERAND_AT(last, 0));
4554  /* special case: assign to aset or attrset */
4555  if (llen == 2) {
4556  POP_ELEMENT(ret);
4557  adjust_stack(iseq, ret, nd_line(node), rlen, llen);
4558  ADD_INSN(ret, nd_line(node), swap);
4559  expand = 0;
4560  }
4561  else if (llen > 2 && llen != rlen) {
4562  POP_ELEMENT(ret);
4563  adjust_stack(iseq, ret, nd_line(node), rlen, llen);
4564  ADD_INSN1(ret, nd_line(node), reverse, INT2FIX(llen));
4565  expand = 0;
4566  }
4567  else if (llen > 2) {
4568  last->insn_id = BIN(reverse);
4569  expand = 0;
4570  }
4571  }
4572  }
4573  if (expand) {
4574  ADD_INSN2(ret, nd_line(node), expandarray,
4575  INT2FIX(llen), INT2FIX(lhs_splat));
4576  }
4577  ADD_SEQ(ret, lhsseq);
4578 
4579  if (lhs_splat) {
4580  if (nd_type(splatn) == NODE_POSTARG) {
4581  /*a, b, *r, p1, p2 */
4582  const NODE *postn = splatn->nd_2nd;
4583  const NODE *restn = splatn->nd_1st;
4584  int num = (int)postn->nd_alen;
4585  int flag = 0x02 | (NODE_NAMED_REST_P(restn) ? 0x01 : 0x00);
4586 
4587  ADD_INSN2(ret, nd_line(splatn), expandarray,
4588  INT2FIX(num), INT2FIX(flag));
4589 
4590  if (NODE_NAMED_REST_P(restn)) {
4591  CHECK(compile_massign_lhs(iseq, ret, restn));
4592  }
4593  while (postn) {
4594  CHECK(compile_massign_lhs(iseq, ret, postn->nd_head));
4595  postn = postn->nd_next;
4596  }
4597  }
4598  else {
4599  /* a, b, *r */
4600  CHECK(compile_massign_lhs(iseq, ret, splatn));
4601  }
4602  }
4603  }
4604  return COMPILE_OK;
4605 }
4606 
4607 static int
4608 compile_const_prefix(rb_iseq_t *iseq, const NODE *const node,
4609  LINK_ANCHOR *const pref, LINK_ANCHOR *const body)
4610 {
4611  switch (nd_type(node)) {
4612  case NODE_CONST:
4613  debugi("compile_const_prefix - colon", node->nd_vid);
4614  ADD_INSN1(body, nd_line(node), putobject, Qtrue);
4615  ADD_INSN1(body, nd_line(node), getconstant, ID2SYM(node->nd_vid));
4616  break;
4617  case NODE_COLON3:
4618  debugi("compile_const_prefix - colon3", node->nd_mid);
4619  ADD_INSN(body, nd_line(node), pop);
4620  ADD_INSN1(body, nd_line(node), putobject, rb_cObject);
4621  ADD_INSN1(body, nd_line(node), putobject, Qtrue);
4622  ADD_INSN1(body, nd_line(node), getconstant, ID2SYM(node->nd_mid));
4623  break;
4624  case NODE_COLON2:
4625  CHECK(compile_const_prefix(iseq, node->nd_head, pref, body));
4626  debugi("compile_const_prefix - colon2", node->nd_mid);
4627  ADD_INSN1(body, nd_line(node), putobject, Qfalse);
4628  ADD_INSN1(body, nd_line(node), getconstant, ID2SYM(node->nd_mid));
4629  break;
4630  default:
4631  CHECK(COMPILE(pref, "const colon2 prefix", node));
4632  break;
4633  }
4634  return COMPILE_OK;
4635 }
4636 
4637 static int
4638 compile_cpath(LINK_ANCHOR *const ret, rb_iseq_t *iseq, const NODE *cpath)
4639 {
4640  if (nd_type(cpath) == NODE_COLON3) {
4641  /* toplevel class ::Foo */
4642  ADD_INSN1(ret, nd_line(cpath), putobject, rb_cObject);
4644  }
4645  else if (cpath->nd_head) {
4646  /* Bar::Foo */
4647  NO_CHECK(COMPILE(ret, "nd_else->nd_head", cpath->nd_head));
4649  }
4650  else {
4651  /* class at cbase Foo */
4652  ADD_INSN1(ret, nd_line(cpath), putspecialobject,
4654  return 0;
4655  }
4656 }
4657 
4658 static inline int
4659 private_recv_p(const NODE *node)
4660 {
4661  if (nd_type(node->nd_recv) == NODE_SELF) {
4662  NODE *self = node->nd_recv;
4663  return self->nd_state != 0;
4664  }
4665  return 0;
4666 }
4667 
4668 static void
4669 defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
4670  const NODE *const node, LABEL **lfinish, VALUE needstr);
4671 
4672 static void
4673 defined_expr0(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
4674  const NODE *const node, LABEL **lfinish, VALUE needstr)
4675 {
4676  enum defined_type expr_type = DEFINED_NOT_DEFINED;
4677  enum node_type type;
4678  const int line = nd_line(node);
4679 
4680  switch (type = nd_type(node)) {
4681 
4682  /* easy literals */
4683  case NODE_NIL:
4684  expr_type = DEFINED_NIL;
4685  break;
4686  case NODE_SELF:
4687  expr_type = DEFINED_SELF;
4688  break;
4689  case NODE_TRUE:
4690  expr_type = DEFINED_TRUE;
4691  break;
4692  case NODE_FALSE:
4693  expr_type = DEFINED_FALSE;
4694  break;
4695 
4696  case NODE_LIST:{
4697  const NODE *vals = node;
4698 
4699  do {
4700  defined_expr0(iseq, ret, vals->nd_head, lfinish, Qfalse);
4701 
4702  if (!lfinish[1]) {
4703  lfinish[1] = NEW_LABEL(line);
4704  }
4705  ADD_INSNL(ret, line, branchunless, lfinish[1]);
4706  } while ((vals = vals->nd_next) != NULL);
4707  }
4708  /* fall through */
4709  case NODE_STR:
4710  case NODE_LIT:
4711  case NODE_ZLIST:
4712  case NODE_AND:
4713  case NODE_OR:
4714  default:
4715  expr_type = DEFINED_EXPR;
4716  break;
4717 
4718  /* variables */
4719  case NODE_LVAR:
4720  case NODE_DVAR:
4721  expr_type = DEFINED_LVAR;
4722  break;
4723 
4724  case NODE_IVAR:
4725  ADD_INSN(ret, line, putnil);
4726  ADD_INSN3(ret, line, defined, INT2FIX(DEFINED_IVAR),
4727  ID2SYM(node->nd_vid), needstr);
4728  return;
4729 
4730  case NODE_GVAR:
4731  ADD_INSN(ret, line, putnil);
4732  ADD_INSN3(ret, line, defined, INT2FIX(DEFINED_GVAR),
4733  ID2SYM(node->nd_entry->id), needstr);
4734  return;
4735 
4736  case NODE_CVAR:
4737  ADD_INSN(ret, line, putnil);
4738  ADD_INSN3(ret, line, defined, INT2FIX(DEFINED_CVAR),
4739  ID2SYM(node->nd_vid), needstr);
4740  return;
4741 
4742  case NODE_CONST:
4743  ADD_INSN(ret, line, putnil);
4744  ADD_INSN3(ret, line, defined, INT2FIX(DEFINED_CONST),
4745  ID2SYM(node->nd_vid), needstr);
4746  return;
4747  case NODE_COLON2:
4748  if (!lfinish[1]) {
4749  lfinish[1] = NEW_LABEL(line);
4750  }
4751  defined_expr0(iseq, ret, node->nd_head, lfinish, Qfalse);
4752  ADD_INSNL(ret, line, branchunless, lfinish[1]);
4753  NO_CHECK(COMPILE(ret, "defined/colon2#nd_head", node->nd_head));
4754 
4755  ADD_INSN3(ret, line, defined,
4756  (rb_is_const_id(node->nd_mid) ?
4758  ID2SYM(node->nd_mid), needstr);
4759  return;
4760  case NODE_COLON3:
4761  ADD_INSN1(ret, line, putobject, rb_cObject);
4762  ADD_INSN3(ret, line, defined,
4763  INT2FIX(DEFINED_CONST_FROM), ID2SYM(node->nd_mid), needstr);
4764  return;
4765 
4766  /* method dispatch */
4767  case NODE_CALL:
4768  case NODE_OPCALL:
4769  case NODE_VCALL:
4770  case NODE_FCALL:
4771  case NODE_ATTRASGN:{
4772  const int explicit_receiver =
4773  (type == NODE_CALL || type == NODE_OPCALL ||
4774  (type == NODE_ATTRASGN && !private_recv_p(node)));
4775 
4776  if (!lfinish[1] && (node->nd_args || explicit_receiver)) {
4777  lfinish[1] = NEW_LABEL(line);
4778  }
4779  if (node->nd_args) {
4780  defined_expr0(iseq, ret, node->nd_args, lfinish, Qfalse);
4781  ADD_INSNL(ret, line, branchunless, lfinish[1]);
4782  }
4783  if (explicit_receiver) {
4784  defined_expr0(iseq, ret, node->nd_recv, lfinish, Qfalse);
4785  ADD_INSNL(ret, line, branchunless, lfinish[1]);
4786  NO_CHECK(COMPILE(ret, "defined/recv", node->nd_recv));
4787  ADD_INSN3(ret, line, defined, INT2FIX(DEFINED_METHOD),
4788  ID2SYM(node->nd_mid), needstr);
4789  }
4790  else {
4791  ADD_INSN(ret, line, putself);
4792  ADD_INSN3(ret, line, defined, INT2FIX(DEFINED_FUNC),
4793  ID2SYM(node->nd_mid), needstr);
4794  }
4795  return;
4796  }
4797 
4798  case NODE_YIELD:
4799  ADD_INSN(ret, line, putnil);
4800  ADD_INSN3(ret, line, defined, INT2FIX(DEFINED_YIELD), 0,
4801  needstr);
4802  return;
4803 
4804  case NODE_BACK_REF:
4805  case NODE_NTH_REF:
4806  ADD_INSN(ret, line, putnil);
4807  ADD_INSN3(ret, line, defined, INT2FIX(DEFINED_REF),
4808  INT2FIX((node->nd_nth << 1) | (type == NODE_BACK_REF)),
4809  needstr);
4810  return;
4811 
4812  case NODE_SUPER:
4813  case NODE_ZSUPER:
4814  ADD_INSN(ret, line, putnil);
4815  ADD_INSN3(ret, line, defined, INT2FIX(DEFINED_ZSUPER), 0,
4816  needstr);
4817  return;
4818 
4819  case NODE_OP_ASGN1:
4820  case NODE_OP_ASGN2:
4821  case NODE_OP_ASGN_OR:
4822  case NODE_OP_ASGN_AND:
4823  case NODE_MASGN:
4824  case NODE_LASGN:
4825  case NODE_DASGN:
4826  case NODE_DASGN_CURR:
4827  case NODE_GASGN:
4828  case NODE_IASGN:
4829  case NODE_CDECL:
4830  case NODE_CVASGN:
4831  expr_type = DEFINED_ASGN;
4832  break;
4833  }
4834 
4835  assert(expr_type != DEFINED_NOT_DEFINED);
4836 
4837  if (needstr != Qfalse) {
4838  VALUE str = rb_iseq_defined_string(expr_type);
4839  ADD_INSN1(ret, line, putobject, str);
4840  }
4841  else {
4842  ADD_INSN1(ret, line, putobject, Qtrue);
4843  }
4844 }
4845 
4846 static void
4847 build_defined_rescue_iseq(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const void *unused)
4848 {
4849  ADD_INSN(ret, 0, putnil);
4850  iseq_set_exception_local_table(iseq);
4851 }
4852 
4853 static void
4854 defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
4855  const NODE *const node, LABEL **lfinish, VALUE needstr)
4856 {
4857  LINK_ELEMENT *lcur = ret->last;
4858  defined_expr0(iseq, ret, node, lfinish, needstr);
4859  if (lfinish[1]) {
4860  int line = nd_line(node);
4861  LABEL *lstart = NEW_LABEL(line);
4862  LABEL *lend = NEW_LABEL(line);
4863  const rb_iseq_t *rescue;
4865  rb_iseq_new_with_callback_new_callback(build_defined_rescue_iseq, NULL);
4866  rescue = new_child_iseq_with_callback(iseq, ifunc,
4867  rb_str_concat(rb_str_new2("defined guard in "),
4868  iseq->body->location.label),
4869  iseq, ISEQ_TYPE_RESCUE, 0);
4870  lstart->rescued = LABEL_RESCUE_BEG;
4871  lend->rescued = LABEL_RESCUE_END;
4872  APPEND_LABEL(ret, lcur, lstart);
4873  ADD_LABEL(ret, lend);
4874  ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lfinish[1]);
4875  }
4876 }
4877 
4878 static int
4879 compile_defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE needstr)
4880 {
4881  const int line = nd_line(node);
4882  if (!node->nd_head) {
4884  ADD_INSN1(ret, line, putobject, str);
4885  }
4886  else {
4887  LABEL *lfinish[2];
4888  LINK_ELEMENT *last = ret->last;
4889  lfinish[0] = NEW_LABEL(line);
4890  lfinish[1] = 0;
4891  defined_expr(iseq, ret, node->nd_head, lfinish, needstr);
4892  if (lfinish[1]) {
4893  ELEM_INSERT_NEXT(last, &new_insn_body(iseq, line, BIN(putnil), 0)->link);
4894  ADD_INSN(ret, line, swap);
4895  ADD_INSN(ret, line, pop);
4896  ADD_LABEL(ret, lfinish[1]);
4897  }
4898  ADD_LABEL(ret, lfinish[0]);
4899  }
4900  return COMPILE_OK;
4901 }
4902 
4903 static VALUE
4904 make_name_for_block(const rb_iseq_t *orig_iseq)
4905 {
4906  int level = 1;
4907  const rb_iseq_t *iseq = orig_iseq;
4908 
4909  if (orig_iseq->body->parent_iseq != 0) {
4910  while (orig_iseq->body->local_iseq != iseq) {
4911  if (iseq->body->type == ISEQ_TYPE_BLOCK) {
4912  level++;
4913  }
4914  iseq = iseq->body->parent_iseq;
4915  }
4916  }
4917 
4918  if (level == 1) {
4919  return rb_sprintf("block in %"PRIsVALUE, iseq->body->location.label);
4920  }
4921  else {
4922  return rb_sprintf("block (%d levels) in %"PRIsVALUE, level, iseq->body->location.label);
4923  }
4924 }
4925 
4926 static void
4927 push_ensure_entry(rb_iseq_t *iseq,
4929  struct ensure_range *er, const NODE *const node)
4930 {
4931  enl->ensure_node = node;
4932  enl->prev = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack; /* prev */
4933  enl->erange = er;
4934  ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enl;
4935 }
4936 
4937 static void
4938 add_ensure_range(rb_iseq_t *iseq, struct ensure_range *erange,
4939  LABEL *lstart, LABEL *lend)
4940 {
4941  struct ensure_range *ne =
4942  compile_data_alloc(iseq, sizeof(struct ensure_range));
4943 
4944  while (erange->next != 0) {
4945  erange = erange->next;
4946  }
4947  ne->next = 0;
4948  ne->begin = lend;
4949  ne->end = erange->end;
4950  erange->end = lstart;
4951 
4952  erange->next = ne;
4953 }
4954 
4955 static void
4956 add_ensure_iseq(LINK_ANCHOR *const ret, rb_iseq_t *iseq, int is_return)
4957 {
4959  ISEQ_COMPILE_DATA(iseq)->ensure_node_stack;
4960  struct iseq_compile_data_ensure_node_stack *prev_enlp = enlp;
4961  DECL_ANCHOR(ensure);
4962 
4963  INIT_ANCHOR(ensure);
4964  while (enlp) {
4965  if (enlp->erange != NULL) {
4966  DECL_ANCHOR(ensure_part);
4967  LABEL *lstart = NEW_LABEL(0);
4968  LABEL *lend = NEW_LABEL(0);
4969  INIT_ANCHOR(ensure_part);
4970 
4971  add_ensure_range(iseq, enlp->erange, lstart, lend);
4972 
4973  ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enlp->prev;
4974  ADD_LABEL(ensure_part, lstart);
4975  NO_CHECK(COMPILE_POPPED(ensure_part, "ensure part", enlp->ensure_node));
4976  ADD_LABEL(ensure_part, lend);
4977  ADD_SEQ(ensure, ensure_part);
4978  }
4979  else {
4980  if (!is_return) {
4981  break;
4982  }
4983  }
4984  enlp = enlp->prev;
4985  }
4986  ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = prev_enlp;
4987  ADD_SEQ(ret, ensure);
4988 }
4989 
4990 static int
4991 check_keyword(const NODE *node)
4992 {
4993  /* This check is essentially a code clone of compile_keyword_arg. */
4994 
4995  if (nd_type(node) == NODE_LIST) {
4996  while (node->nd_next) {
4997  node = node->nd_next;
4998  }
4999  node = node->nd_head;
5000  }
5001 
5002  return keyword_node_p(node);
5003 }
5004 
5005 static VALUE
5006 setup_args_core(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
5007  int dup_rest, unsigned int *flag, struct rb_call_info_kw_arg **keywords)
5008 {
5009  if (argn) {
5010  switch (nd_type(argn)) {
5011  case NODE_SPLAT: {
5012  NO_CHECK(COMPILE(args, "args (splat)", argn->nd_head));
5013  ADD_INSN1(args, nd_line(argn), splatarray, dup_rest ? Qtrue : Qfalse);
5014  if (flag) *flag |= VM_CALL_ARGS_SPLAT;
5015  return INT2FIX(1);
5016  }
5017  case NODE_ARGSCAT:
5018  case NODE_ARGSPUSH: {
5019  int next_is_list = (nd_type(argn->nd_head) == NODE_LIST);
5020  VALUE argc = setup_args_core(iseq, args, argn->nd_head, 1, NULL, NULL);
5021  if (nd_type(argn->nd_body) == NODE_LIST) {
5022  /* This branch is needed to avoid "newarraykwsplat" [Bug #16442] */
5023  int rest_len = compile_args(iseq, args, argn->nd_body, NULL, NULL);
5024  ADD_INSN1(args, nd_line(argn), newarray, INT2FIX(rest_len));
5025  }
5026  else {
5027  NO_CHECK(COMPILE(args, "args (cat: splat)", argn->nd_body));
5028  }
5029  if (flag) {
5030  *flag |= VM_CALL_ARGS_SPLAT;
5031  /* This is a dirty hack. It traverses the AST twice.
5032  * In a long term, it should be fixed by a redesign of keyword arguments */
5033  if (check_keyword(argn->nd_body))
5034  *flag |= VM_CALL_KW_SPLAT;
5035  }
5036  if (nd_type(argn) == NODE_ARGSCAT) {
5037  if (next_is_list) {
5038  ADD_INSN1(args, nd_line(argn), splatarray, Qtrue);
5039  return INT2FIX(FIX2INT(argc) + 1);
5040  }
5041  else {
5042  ADD_INSN1(args, nd_line(argn), splatarray, Qfalse);
5043  ADD_INSN(args, nd_line(argn), concatarray);
5044  return argc;
5045  }
5046  }
5047  else {
5048  ADD_INSN1(args, nd_line(argn), newarray, INT2FIX(1));
5049  ADD_INSN(args, nd_line(argn), concatarray);
5050  return argc;
5051  }
5052  }
5053  case NODE_LIST: {
5054  int len = compile_args(iseq, args, argn, keywords, flag);
5055  return INT2FIX(len);
5056  }
5057  default: {
5058  UNKNOWN_NODE("setup_arg", argn, Qnil);
5059  }
5060  }
5061  }
5062  return INT2FIX(0);
5063 }
5064 
5065 static VALUE
5066 setup_args(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
5067  unsigned int *flag, struct rb_call_info_kw_arg **keywords)
5068 {
5069  VALUE ret;
5070  if (argn && nd_type(argn) == NODE_BLOCK_PASS) {
5071  DECL_ANCHOR(arg_block);
5072  INIT_ANCHOR(arg_block);
5073  NO_CHECK(COMPILE(arg_block, "block", argn->nd_body));
5074 
5075  *flag |= VM_CALL_ARGS_BLOCKARG;
5076  ret = setup_args_core(iseq, args, argn->nd_head, 0, flag, keywords);
5077 
5078  if (LIST_INSN_SIZE_ONE(arg_block)) {
5079  LINK_ELEMENT *elem = FIRST_ELEMENT(arg_block);
5080  if (elem->type == ISEQ_ELEMENT_INSN) {
5081  INSN *iobj = (INSN *)elem;
5082  if (iobj->insn_id == BIN(getblockparam)) {
5083  iobj->insn_id = BIN(getblockparamproxy);
5084  }
5085  }
5086  }
5087  ADD_SEQ(args, arg_block);
5088  }
5089  else {
5090  ret = setup_args_core(iseq, args, argn, 0, flag, keywords);
5091  }
5092  return ret;
5093 }
5094 
5095 static void
5096 build_postexe_iseq(rb_iseq_t *iseq, LINK_ANCHOR *ret, const void *ptr)
5097 {
5098  const NODE *body = ptr;
5099  int line = nd_line(body);
5100  VALUE argc = INT2FIX(0);
5101  const rb_iseq_t *block = NEW_CHILD_ISEQ(body, make_name_for_block(iseq->body->parent_iseq), ISEQ_TYPE_BLOCK, line);
5102 
5103  ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
5104  ADD_CALL_WITH_BLOCK(ret, line, id_core_set_postexe, argc, block);
5105  RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block);
5106  iseq_set_local_table(iseq, 0);
5107 }
5108 
5109 static void
5110 compile_named_capture_assign(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node)
5111 {
5112  const NODE *vars;
5113  LINK_ELEMENT *last;
5114  int line = nd_line(node);
5115  LABEL *fail_label = NEW_LABEL(line), *end_label = NEW_LABEL(line);
5116 
5117 #if !(defined(NAMED_CAPTURE_BY_SVAR) && NAMED_CAPTURE_BY_SVAR-0)
5118  ADD_INSN1(ret, line, getglobal, ((VALUE)rb_global_entry(idBACKREF) | 1));
5119 #else
5120  ADD_INSN2(ret, line, getspecial, INT2FIX(1) /* '~' */, INT2FIX(0));
5121 #endif
5122  ADD_INSN(ret, line, dup);
5123  ADD_INSNL(ret, line, branchunless, fail_label);
5124 
5125  for (vars = node; vars; vars = vars->nd_next) {
5126  INSN *cap;
5127  if (vars->nd_next) {
5128  ADD_INSN(ret, line, dup);
5129  }
5130  last = ret->last;
5131  NO_CHECK(COMPILE_POPPED(ret, "capture", vars->nd_head));
5132  last = last->next; /* putobject :var */
5133  cap = new_insn_send(iseq, line, idAREF, INT2FIX(1),
5134  NULL, INT2FIX(0), NULL);
5135  ELEM_INSERT_PREV(last->next, (LINK_ELEMENT *)cap);
5136 #if !defined(NAMED_CAPTURE_SINGLE_OPT) || NAMED_CAPTURE_SINGLE_OPT-0
5137  if (!vars->nd_next && vars == node) {
5138  /* only one name */
5139  DECL_ANCHOR(nom);
5140 
5141  INIT_ANCHOR(nom);
5142  ADD_INSNL(nom, line, jump, end_label);
5143  ADD_LABEL(nom, fail_label);
5144 # if 0 /* $~ must be MatchData or nil */
5145  ADD_INSN(nom, line, pop);
5146  ADD_INSN(nom, line, putnil);
5147 # endif
5148  ADD_LABEL(nom, end_label);
5149  (nom->last->next = cap->link.next)->prev = nom->last;
5150  (cap->link.next = nom->anchor.next)->prev = &cap->link;
5151  return;
5152  }
5153 #endif
5154  }
5155  ADD_INSNL(ret, line, jump, end_label);
5156  ADD_LABEL(ret, fail_label);
5157  ADD_INSN(ret, line, pop);
5158  for (vars = node; vars; vars = vars->nd_next) {
5159  last = ret->last;
5160  NO_CHECK(COMPILE_POPPED(ret, "capture", vars->nd_head));
5161  last = last->next; /* putobject :var */
5162  ((INSN*)last)->insn_id = BIN(putnil);
5163  ((INSN*)last)->operand_size = 0;
5164  }
5165  ADD_LABEL(ret, end_label);
5166 }
5167 
5168 static int
5169 number_literal_p(const NODE *n)
5170 {
5171  return (n && nd_type(n) == NODE_LIT && RB_INTEGER_TYPE_P(n->nd_lit));
5172 }
5173 
5174 static int
5175 compile_if(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
5176 {
5177  struct rb_iseq_constant_body *const body = iseq->body;
5178  const NODE *const node_body = type == NODE_IF ? node->nd_body : node->nd_else;
5179  const NODE *const node_else = type == NODE_IF ? node->nd_else : node->nd_body;
5180 
5181  const int line = nd_line(node);
5182  const int lineno = nd_first_lineno(node);
5183  const int column = nd_first_column(node);
5184  const int last_lineno = nd_last_lineno(node);
5185  const int last_column = nd_last_column(node);
5186  DECL_ANCHOR(cond_seq);
5187  DECL_ANCHOR(then_seq);
5188  DECL_ANCHOR(else_seq);
5189  LABEL *then_label, *else_label, *end_label;
5190  VALUE branches = Qfalse;
5191  int ci_size, ci_kw_size;
5192  VALUE catch_table = ISEQ_COMPILE_DATA(iseq)->catch_table_ary;
5193  long catch_table_size = NIL_P(catch_table) ? 0 : RARRAY_LEN(catch_table);
5194 
5195  INIT_ANCHOR(cond_seq);
5196  INIT_ANCHOR(then_seq);
5197  INIT_ANCHOR(else_seq);
5198  then_label = NEW_LABEL(line);
5199  else_label = NEW_LABEL(line);
5200  end_label = 0;
5201 
5202  compile_branch_condition(iseq, cond_seq, node->nd_cond,
5203  then_label, else_label);
5204 
5205  ci_size = body->ci_size;
5206  ci_kw_size = body->ci_kw_size;
5207  CHECK(COMPILE_(then_seq, "then", node_body, popped));
5208  catch_table = ISEQ_COMPILE_DATA(iseq)->catch_table_ary;
5209  if (!then_label->refcnt) {
5210  body->ci_size = ci_size;
5211  body->ci_kw_size = ci_kw_size;
5212  if (!NIL_P(catch_table)) rb_ary_set_len(catch_table, catch_table_size);
5213  }
5214  else {
5215  if (!NIL_P(catch_table)) catch_table_size = RARRAY_LEN(catch_table);
5216  }
5217 
5218  ci_size = body->ci_size;
5219  ci_kw_size = body->ci_kw_size;
5220  CHECK(COMPILE_(else_seq, "else", node_else, popped));
5221  catch_table = ISEQ_COMPILE_DATA(iseq)->catch_table_ary;
5222  if (!else_label->refcnt) {
5223  body->ci_size = ci_size;
5224  body->ci_kw_size = ci_kw_size;
5225  if (!NIL_P(catch_table)) rb_ary_set_len(catch_table, catch_table_size);
5226  }
5227  else {
5228  if (!NIL_P(catch_table)) catch_table_size = RARRAY_LEN(catch_table);
5229  }
5230 
5231  ADD_SEQ(ret, cond_seq);
5232 
5233  if (then_label->refcnt && else_label->refcnt) {
5234  DECL_BRANCH_BASE(branches, lineno, column, last_lineno, last_column, type == NODE_IF ? "if" : "unless");
5235  }
5236 
5237  if (then_label->refcnt) {
5238  ADD_LABEL(ret, then_label);
5239  if (else_label->refcnt) {
5241  ret,
5242  node_body ? nd_first_lineno(node_body) : lineno,
5243  node_body ? nd_first_column(node_body) : column,
5244  node_body ? nd_last_lineno(node_body) : last_lineno,
5245  node_body ? nd_last_column(node_body) : last_column,
5246  type == NODE_IF ? "then" : "else",
5247  branches);
5248  end_label = NEW_LABEL(line);
5249  ADD_INSNL(then_seq, line, jump, end_label);
5250  }
5251  ADD_SEQ(ret, then_seq);
5252  }
5253 
5254  if (else_label->refcnt) {
5255  ADD_LABEL(ret, else_label);
5256  if (then_label->refcnt) {
5258  ret,
5259  node_else ? nd_first_lineno(node_else) : lineno,
5260  node_else ? nd_first_column(node_else) : column,
5261  node_else ? nd_last_lineno(node_else) : last_lineno,
5262  node_else ? nd_last_column(node_else) : last_column,
5263  type == NODE_IF ? "else" : "then",
5264  branches);
5265  }
5266  ADD_SEQ(ret, else_seq);
5267  }
5268 
5269  if (end_label) {
5270  ADD_LABEL(ret, end_label);
5271  }
5272 
5273  return COMPILE_OK;
5274 }
5275 
5276 static int
5277 compile_case(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
5278 {
5279  const NODE *vals;
5280  const NODE *node = orig_node;
5281  LABEL *endlabel, *elselabel;
5282  DECL_ANCHOR(head);
5283  DECL_ANCHOR(body_seq);
5284  DECL_ANCHOR(cond_seq);
5285  int only_special_literals = 1;
5286  VALUE literals = rb_hash_new();
5287  int line, lineno, column, last_lineno, last_column;
5288  enum node_type type;
5289  VALUE branches = Qfalse;
5290 
5291  INIT_ANCHOR(head);
5292  INIT_ANCHOR(body_seq);
5293  INIT_ANCHOR(cond_seq);
5294 
5295  RHASH_TBL_RAW(literals)->type = &cdhash_type;
5296 
5297  CHECK(COMPILE(head, "case base", node->nd_head));
5298 
5299  DECL_BRANCH_BASE(branches, nd_first_lineno(node), nd_first_column(node), nd_last_lineno(node), nd_last_column(node), "case");
5300 
5301  node = node->nd_body;
5302  EXPECT_NODE("NODE_CASE", node, NODE_WHEN, COMPILE_NG);
5303  type = nd_type(node);
5304  line = nd_line(node);
5305  lineno = nd_first_lineno(node);
5306  column = nd_first_column(node);
5307  last_lineno = nd_last_lineno(node);
5308  last_column = nd_last_column(node);
5309 
5310  endlabel = NEW_LABEL(line);
5311  elselabel = NEW_LABEL(line);
5312 
5313  ADD_SEQ(ret, head); /* case VAL */
5314 
5315  while (type == NODE_WHEN) {
5316  LABEL *l1;
5317 
5318  l1 = NEW_LABEL(line);
5319  ADD_LABEL(body_seq, l1);
5320  ADD_INSN(body_seq, line, pop);
5322  body_seq,
5323  node->nd_body ? nd_first_lineno(node->nd_body) : lineno,
5324  node->nd_body ? nd_first_column(node->nd_body) : column,
5325  node->nd_body ? nd_last_lineno(node->nd_body) : last_lineno,
5326  node->nd_body ? nd_last_column(node->nd_body) : last_column,
5327  "when",
5328  branches);
5329  CHECK(COMPILE_(body_seq, "when body", node->nd_body, popped));
5330  ADD_INSNL(body_seq, line, jump, endlabel);
5331 
5332  vals = node->nd_head;
5333  if (vals) {
5334  switch (nd_type(vals)) {
5335  case NODE_LIST:
5336  only_special_literals = when_vals(iseq, cond_seq, vals, l1, only_special_literals, literals);
5337  if (only_special_literals < 0) return COMPILE_NG;
5338  break;
5339  case NODE_SPLAT:
5340  case NODE_ARGSCAT:
5341  case NODE_ARGSPUSH:
5342  only_special_literals = 0;
5343  CHECK(when_splat_vals(iseq, cond_seq, vals, l1, only_special_literals, literals));
5344  break;
5345  default:
5346  UNKNOWN_NODE("NODE_CASE", vals, COMPILE_NG);
5347  }
5348  }
5349  else {
5350  EXPECT_NODE_NONULL("NODE_CASE", node, NODE_LIST, COMPILE_NG);
5351  }
5352 
5353  node = node->nd_next;
5354  if (!node) {
5355  break;
5356  }
5357  type = nd_type(node);
5358  line = nd_line(node);
5359  lineno = nd_first_lineno(node);
5360  column = nd_first_column(node);
5361  last_lineno = nd_last_lineno(node);
5362  last_column = nd_last_column(node);
5363  }
5364  /* else */
5365  if (node) {
5366  ADD_LABEL(cond_seq, elselabel);
5367  ADD_INSN(cond_seq, line, pop);
5368  ADD_TRACE_BRANCH_COVERAGE(cond_seq, nd_first_lineno(node), nd_first_column(node), nd_last_lineno(node), nd_last_column(node), "else", branches);
5369  CHECK(COMPILE_(cond_seq, "else", node, popped));
5370  ADD_INSNL(cond_seq, line, jump, endlabel);
5371  }
5372  else {
5373  debugs("== else (implicit)\n");
5374  ADD_LABEL(cond_seq, elselabel);
5375  ADD_INSN(cond_seq, nd_line(orig_node), pop);
5376  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);
5377  if (!popped) {
5378  ADD_INSN(cond_seq, nd_line(orig_node), putnil);
5379  }
5380  ADD_INSNL(cond_seq, nd_line(orig_node), jump, endlabel);
5381  }
5382 
5383  if (only_special_literals && ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
5384  ADD_INSN(ret, nd_line(orig_node), dup);
5385  ADD_INSN2(ret, nd_line(orig_node), opt_case_dispatch, literals, elselabel);
5386  RB_OBJ_WRITTEN(iseq, Qundef, literals);
5387  LABEL_REF(elselabel);
5388  }
5389 
5390  ADD_SEQ(ret, cond_seq);
5391  ADD_SEQ(ret, body_seq);
5392  ADD_LABEL(ret, endlabel);
5393  return COMPILE_OK;
5394 }
5395 
5396 static int
5397 compile_case2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
5398 {
5399  const NODE *vals;
5400  const NODE *val;
5401  const NODE *node = orig_node->nd_body;
5402  LABEL *endlabel;
5403  DECL_ANCHOR(body_seq);
5404  VALUE branches = Qfalse;
5405 
5406  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");
5407 
5408  INIT_ANCHOR(body_seq);
5409  endlabel = NEW_LABEL(nd_line(node));
5410 
5411  while (node && nd_type(node) == NODE_WHEN) {
5412  const int line = nd_line(node);
5413  const int lineno = nd_first_lineno(node);
5414  const int column = nd_first_column(node);
5415  const int last_lineno = nd_last_lineno(node);
5416  const int last_column = nd_last_column(node);
5417  LABEL *l1 = NEW_LABEL(line);
5418  ADD_LABEL(body_seq, l1);
5420  body_seq,
5421  node->nd_body ? nd_first_lineno(node->nd_body) : lineno,
5422  node->nd_body ? nd_first_column(node->nd_body) : column,
5423  node->nd_body ? nd_last_lineno(node->nd_body) : last_lineno,
5424  node->nd_body ? nd_last_column(node->nd_body) : last_column,
5425  "when",
5426  branches);
5427  CHECK(COMPILE_(body_seq, "when", node->nd_body, popped));
5428  ADD_INSNL(body_seq, line, jump, endlabel);
5429 
5430  vals = node->nd_head;
5431  if (!vals) {
5432  EXPECT_NODE_NONULL("NODE_WHEN", node, NODE_LIST, COMPILE_NG);
5433  }
5434  switch (nd_type(vals)) {
5435  case NODE_LIST:
5436  while (vals) {
5437  LABEL *lnext;
5438  val = vals->nd_head;
5439  lnext = NEW_LABEL(nd_line(val));
5440  debug_compile("== when2\n", (void)0);
5441  CHECK(compile_branch_condition(iseq, ret, val, l1, lnext));
5442  ADD_LABEL(ret, lnext);
5443  vals = vals->nd_next;
5444  }
5445  break;
5446  case NODE_SPLAT:
5447  case NODE_ARGSCAT:
5448  case NODE_ARGSPUSH:
5449  ADD_INSN(ret, nd_line(vals), putnil);
5450  CHECK(COMPILE(ret, "when2/cond splat", vals));
5452  ADD_INSNL(ret, nd_line(vals), branchif, l1);
5453  break;
5454  default:
5455  UNKNOWN_NODE("NODE_WHEN", vals, COMPILE_NG);
5456  }
5457  node = node->nd_next;
5458  }
5459  /* else */
5461  ret,
5462  node ? nd_first_lineno(node) : nd_first_lineno(orig_node),
5463  node ? nd_first_column(node) : nd_first_column(orig_node),
5464  node ? nd_last_lineno(node) : nd_last_lineno(orig_node),
5465  node ? nd_last_column(node) : nd_last_column(orig_node),
5466  "else",
5467  branches);
5468  CHECK(COMPILE_(ret, "else", node, popped));
5469  ADD_INSNL(ret, nd_line(orig_node), jump, endlabel);
5470 
5471  ADD_SEQ(ret, body_seq);
5472  ADD_LABEL(ret, endlabel);
5473  return COMPILE_OK;
5474 }
5475 
5476 static int
5477 iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int in_alt_pattern)
5478 {
5479  const int line = nd_line(node);
5480 
5481  switch (nd_type(node)) {
5482  case NODE_ARYPTN: {
5483  /*
5484  * if pattern.use_rest_num?
5485  * rest_num = 0
5486  * end
5487  * if pattern.has_constant_node?
5488  * unless pattern.constant === obj
5489  * goto match_failed
5490  * end
5491  * end
5492  * unless obj.respond_to?(:deconstruct)
5493  * goto match_failed
5494  * end
5495  * d = obj.deconstruct
5496  * unless Array === d
5497  * goto type_error
5498  * end
5499  * min_argc = pattern.pre_args_num + pattern.post_args_num
5500  * if pattern.has_rest_arg?
5501  * unless d.length >= min_argc
5502  * goto match_failed
5503  * end
5504  * else
5505  * unless d.length == min_argc
5506  * goto match_failed
5507  * end
5508  * end
5509  * pattern.pre_args_num.each do |i|
5510  * unless pattern.pre_args[i].match?(d[i])
5511  * goto match_failed
5512  * end
5513  * end
5514  * if pattern.use_rest_num?
5515  * rest_num = d.length - min_argc
5516  * if pattern.has_rest_arg? && pattern.has_rest_arg_id # not `*`, but `*rest`
5517  * unless pattern.rest_arg.match?(d[pattern.pre_args_num, rest_num])
5518  * goto match_failed
5519  * end
5520  * end
5521  * end
5522  * pattern.post_args_num.each do |i|
5523  * j = pattern.pre_args_num + i
5524  * j += rest_num
5525  * unless pattern.post_args[i].match?(d[j])
5526  * goto match_failed
5527  * end
5528  * end
5529  * true
5530  * goto fin
5531  * type_error:
5532  * FrozenCore.raise TypeError
5533  * match_failed:
5534  * false
5535  * fin:
5536  */
5537  struct rb_ary_pattern_info *apinfo = node->nd_apinfo;
5538  const NODE *args = apinfo->pre_args;
5539  const int pre_args_num = apinfo->pre_args ? rb_long2int(apinfo->pre_args->nd_alen) : 0;
5540  const int post_args_num = apinfo->post_args ? rb_long2int(apinfo->post_args->nd_alen) : 0;
5541 
5542  const int min_argc = pre_args_num + post_args_num;
5543  const int use_rest_num = apinfo->rest_arg && (NODE_NAMED_REST_P(apinfo->rest_arg) ||
5544  (!NODE_NAMED_REST_P(apinfo->rest_arg) && post_args_num > 0));
5545 
5546  LABEL *match_failed, *type_error, *fin;
5547  int i;
5548  match_failed = NEW_LABEL(line);
5549  type_error = NEW_LABEL(line);
5550  fin = NEW_LABEL(line);
5551 
5552  if (use_rest_num) {
5553  ADD_INSN1(ret, line, putobject, INT2FIX(0)); /* allocate stack for rest_num */
5554  ADD_INSN(ret, line, swap);
5555  }
5556 
5557  if (node->nd_pconst) {
5558  ADD_INSN(ret, line, dup);
5559  CHECK(COMPILE(ret, "constant", node->nd_pconst));
5560  ADD_INSN1(ret, line, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE));
5561  ADD_INSNL(ret, line, branchunless, match_failed);
5562  }
5563 
5564  ADD_INSN(ret, line, dup);
5565  ADD_INSN1(ret, line, putobject, ID2SYM(rb_intern("deconstruct")));
5566  ADD_SEND(ret, line, idRespond_to, INT2FIX(1));
5567  ADD_INSNL(ret, line, branchunless, match_failed);
5568 
5569  ADD_SEND(ret, line, rb_intern("deconstruct"), INT2FIX(0));
5570 
5571  ADD_INSN(ret, line, dup);
5572  ADD_INSN1(ret, line, checktype, INT2FIX(T_ARRAY));
5573  ADD_INSNL(ret, line, branchunless, type_error);
5574 
5575  ADD_INSN(ret, line, dup);
5576  ADD_SEND(ret, line, idLength, INT2FIX(0));
5577  ADD_INSN1(ret, line, putobject, INT2FIX(min_argc));
5578  ADD_SEND(ret, line, apinfo->rest_arg ? idGE : idEq, INT2FIX(1));
5579  ADD_INSNL(ret, line, branchunless, match_failed);
5580 
5581  for (i = 0; i < pre_args_num; i++) {
5582  ADD_INSN(ret, line, dup);
5583  ADD_INSN1(ret, line, putobject, INT2FIX(i));
5584  ADD_SEND(ret, line, idAREF, INT2FIX(1));
5585  iseq_compile_pattern_each(iseq, ret, args->nd_head, in_alt_pattern);
5586  args = args->nd_next;
5587  ADD_INSNL(ret, line, branchunless, match_failed);
5588  }
5589 
5590  if (apinfo->rest_arg) {
5591  if (NODE_NAMED_REST_P(apinfo->rest_arg)) {
5592  ADD_INSN(ret, line, dup);
5593  ADD_INSN1(ret, line, putobject, INT2FIX(pre_args_num));
5594  ADD_INSN1(ret, line, topn, INT2FIX(1));
5595  ADD_SEND(ret, line, idLength, INT2FIX(0));
5596  ADD_INSN1(ret, line, putobject, INT2FIX(min_argc));
5597  ADD_SEND(ret, line, idMINUS, INT2FIX(1));
5598  ADD_INSN1(ret, line, setn, INT2FIX(4));
5599  ADD_SEND(ret, line, idAREF, INT2FIX(2));
5600 
5601  iseq_compile_pattern_each(iseq, ret, apinfo->rest_arg, in_alt_pattern);
5602  ADD_INSNL(ret, line, branchunless, match_failed);
5603  }
5604  else {
5605  if (post_args_num > 0) {
5606  ADD_INSN(ret, line, dup);
5607  ADD_SEND(ret, line, idLength, INT2FIX(0));
5608  ADD_INSN1(ret, line, putobject, INT2FIX(min_argc));
5609  ADD_SEND(ret, line, idMINUS, INT2FIX(1));
5610  ADD_INSN1(ret, line, setn, INT2FIX(2));
5611  ADD_INSN(ret, line, pop);
5612  }
5613  }
5614  }
5615 
5616  args = apinfo->post_args;
5617  for (i = 0; i < post_args_num; i++) {
5618  ADD_INSN(ret, line, dup);
5619 
5620  ADD_INSN1(ret, line, putobject, INT2FIX(pre_args_num + i));
5621  ADD_INSN1(ret, line, topn, INT2FIX(3));
5622  ADD_SEND(ret, line, idPLUS, INT2FIX(1));
5623 
5624  ADD_SEND(ret, line, idAREF, INT2FIX(1));
5625  iseq_compile_pattern_each(iseq, ret, args->nd_head, in_alt_pattern);
5626  args = args->nd_next;
5627  ADD_INSNL(ret, line, branchunless, match_failed);
5628  }
5629 
5630  ADD_INSN(ret, line, pop);
5631  if (use_rest_num) {
5632  ADD_INSN(ret, line, pop);
5633  }
5634  ADD_INSN1(ret, line, putobject, Qtrue);
5635  ADD_INSNL(ret, line, jump, fin);
5636 
5637  ADD_LABEL(ret, type_error);
5638  ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
5639  ADD_INSN1(ret, line, putobject, rb_eTypeError);
5640  ADD_INSN1(ret, line, putobject, rb_fstring_lit("deconstruct must return Array"));
5641  ADD_SEND(ret, line, id_core_raise, INT2FIX(2));
5642 
5643  ADD_LABEL(ret, match_failed);
5644  ADD_INSN(ret, line, pop);
5645  if (use_rest_num) {
5646  ADD_INSN(ret, line, pop);
5647  }
5648  ADD_INSN1(ret, line, putobject, Qfalse);
5649  ADD_LABEL(ret, fin);
5650 
5651  break;
5652  }
5653  case NODE_HSHPTN: {
5654  /*
5655  * keys = nil
5656  * if pattern.has_kw_args_node? && !pattern.has_kw_rest_arg_node?
5657  * keys = pattern.kw_args_node.keys
5658  * end
5659  * if pattern.has_constant_node?
5660  * unless pattern.constant === obj
5661  * goto match_failed
5662  * end
5663  * end
5664  * unless obj.respond_to?(:deconstruct_keys)
5665  * goto match_failed
5666  * end
5667  * d = obj.deconstruct_keys(keys)
5668  * unless Hash === d
5669  * goto type_error
5670  * end
5671  * if pattern.has_kw_rest_arg_node?
5672  * d = d.dup
5673  * end
5674  * if pattern.has_kw_args_node?
5675  * pattern.kw_args_node.each |k,|
5676  * unless d.key?(k)
5677  * goto match_failed
5678  * end
5679  * end
5680  * pattern.kw_args_node.each |k, pat|
5681  * if pattern.has_kw_rest_arg_node?
5682  * unless pat.match?(d.delete(k))
5683  * goto match_failed
5684  * end
5685  * else
5686  * unless pat.match?(d[k])
5687  * goto match_failed
5688  * end
5689  * end
5690  * end
5691  * else
5692  * unless d.empty?
5693  * goto match_failed
5694  * end
5695  * end
5696  * if pattern.has_kw_rest_arg_node?
5697  * if pattern.no_rest_keyword?
5698  * unless d.empty?
5699  * goto match_failed
5700  * end
5701  * else
5702  * unless pattern.kw_rest_arg_node.match?(d)
5703  * goto match_failed
5704  * end
5705  * end
5706  * end
5707  * true
5708  * goto fin
5709  * type_error:
5710  * FrozenCore.raise TypeError
5711  * match_failed:
5712  * false
5713  * fin:
5714  */
5715  LABEL *match_failed, *type_error, *fin;
5716  VALUE keys = Qnil;
5717 
5718  match_failed = NEW_LABEL(line);
5719  type_error = NEW_LABEL(line);
5720  fin = NEW_LABEL(line);
5721 
5722  if (node->nd_pkwargs && !node->nd_pkwrestarg) {
5723  const NODE *kw_args = node->nd_pkwargs->nd_head;
5724  keys = rb_ary_new_capa(kw_args ? kw_args->nd_alen/2 : 0);
5725  while (kw_args) {
5726  rb_ary_push(keys, kw_args->nd_head->nd_lit);
5727  kw_args = kw_args->nd_next->nd_next;
5728  }
5729  }
5730 
5731  if (node->nd_pconst) {
5732  ADD_INSN(ret, line, dup);
5733  CHECK(COMPILE(ret, "constant", node->nd_pconst));
5734  ADD_INSN1(ret, line, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE));
5735  ADD_INSNL(ret, line, branchunless, match_failed);
5736  }
5737 
5738  ADD_INSN(ret, line, dup);
5739  ADD_INSN1(ret, line, putobject, ID2SYM(rb_intern("deconstruct_keys")));
5740  ADD_SEND(ret, line, idRespond_to, INT2FIX(1));
5741  ADD_INSNL(ret, line, branchunless, match_failed);
5742 
5743  if (NIL_P(keys)) {
5744  ADD_INSN(ret, line, putnil);
5745  }
5746  else {
5747  ADD_INSN1(ret, line, duparray, keys);
5749  }
5750  ADD_SEND(ret, line, rb_intern("deconstruct_keys"), INT2FIX(1));
5751 
5752  ADD_INSN(ret, line, dup);
5753  ADD_INSN1(ret, line, checktype, INT2FIX(T_HASH));
5754  ADD_INSNL(ret, line, branchunless, type_error);
5755 
5756  if (node->nd_pkwrestarg) {
5757  ADD_SEND(ret, line, rb_intern("dup"), INT2FIX(0));
5758  }
5759 
5760  if (node->nd_pkwargs) {
5761  int i;
5762  int keys_num;
5763  const NODE *args;
5764  args = node->nd_pkwargs->nd_head;
5765  if (args) {
5766  DECL_ANCHOR(match_values);
5767  INIT_ANCHOR(match_values);
5768  keys_num = rb_long2int(args->nd_alen) / 2;
5769  for (i = 0; i < keys_num; i++) {
5770  NODE *key_node = args->nd_head;
5771  NODE *value_node = args->nd_next->nd_head;
5772  VALUE key;
5773 
5774  if (nd_type(key_node) != NODE_LIT) {
5775  UNKNOWN_NODE("NODE_IN", key_node, COMPILE_NG);
5776  }
5777  key = key_node->nd_lit;
5778 
5779  ADD_INSN(ret, line, dup);
5780  ADD_INSN1(ret, line, putobject, key);
5781  ADD_SEND(ret, line, rb_intern("key?"), INT2FIX(1));
5782  ADD_INSNL(ret, line, branchunless, match_failed);
5783 
5784  ADD_INSN(match_values, line, dup);
5785  ADD_INSN1(match_values, line, putobject, key);
5786  ADD_SEND(match_values, line, node->nd_pkwrestarg ? rb_intern("delete") : idAREF, INT2FIX(1));
5787  iseq_compile_pattern_each(iseq, match_values, value_node, in_alt_pattern);
5788  ADD_INSNL(match_values, line, branchunless, match_failed);
5789  args = args->nd_next->nd_next;
5790  }
5791  ADD_SEQ(ret, match_values);
5792  }
5793  }
5794  else {
5795  ADD_INSN(ret, line, dup);
5796  ADD_SEND(ret, line, idEmptyP, INT2FIX(0));
5797  ADD_INSNL(ret, line, branchunless, match_failed);
5798  }
5799 
5800  if (node->nd_pkwrestarg) {
5801  if (node->nd_pkwrestarg == NODE_SPECIAL_NO_REST_KEYWORD) {
5802  ADD_INSN(ret, line, dup);
5803  ADD_SEND(ret, line, idEmptyP, INT2FIX(0));
5804  ADD_INSNL(ret, line, branchunless, match_failed);
5805  }
5806  else {
5807  ADD_INSN(ret, line, dup);
5808  iseq_compile_pattern_each(iseq, ret, node->nd_pkwrestarg, in_alt_pattern);
5809  ADD_INSNL(ret, line, branchunless, match_failed);
5810  }
5811  }
5812 
5813  ADD_INSN(ret, line, pop);
5814  ADD_INSN1(ret, line, putobject, Qtrue);
5815  ADD_INSNL(ret, line, jump, fin);
5816 
5817  ADD_LABEL(ret, type_error);
5818  ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
5819  ADD_INSN1(ret, line, putobject, rb_eTypeError);
5820  ADD_INSN1(ret, line, putobject, rb_fstring_lit("deconstruct_keys must return Hash"));
5821  ADD_SEND(ret, line, id_core_raise, INT2FIX(2));
5822 
5823  ADD_LABEL(ret, match_failed);
5824  ADD_INSN(ret, line, pop);
5825  ADD_INSN1(ret, line, putobject, Qfalse);
5826 
5827  ADD_LABEL(ret, fin);
5828  break;
5829  }
5830  case NODE_LIT:
5831  case NODE_STR:
5832  case NODE_XSTR:
5833  case NODE_DSTR:
5834  case NODE_DSYM:
5835  case NODE_DREGX:
5836  case NODE_LIST:
5837  case NODE_ZLIST:
5838  case NODE_LAMBDA:
5839  case NODE_DOT2:
5840  case NODE_DOT3:
5841  case NODE_CONST:
5842  case NODE_LVAR:
5843  case NODE_DVAR:
5844  case NODE_TRUE:
5845  case NODE_FALSE:
5846  case NODE_SELF:
5847  case NODE_NIL:
5848  case NODE_COLON2:
5849  case NODE_COLON3:
5850  CHECK(COMPILE(ret, "case in literal", node));
5851  ADD_INSN1(ret, line, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE));
5852  break;
5853  case NODE_LASGN: {
5854  struct rb_iseq_constant_body *const body = iseq->body;
5855  ID id = node->nd_vid;
5856  int idx = body->local_iseq->body->local_table_size - get_local_var_idx(iseq, id);
5857 
5858  if (in_alt_pattern) {
5859  const char *name = rb_id2name(id);
5860  if (name && strlen(name) > 0 && name[0] != '_') {
5861  COMPILE_ERROR(ERROR_ARGS "illegal variable in alternative pattern (%"PRIsVALUE")",
5862  rb_id2str(id));
5863  return COMPILE_NG;
5864  }
5865  }
5866 
5867  ADD_SETLOCAL(ret, line, idx, get_lvar_level(iseq));
5868  ADD_INSN1(ret, line, putobject, Qtrue);
5869  break;
5870  }
5871  case NODE_DASGN:
5872  case NODE_DASGN_CURR: {
5873  int idx, lv, ls;
5874  ID id = node->nd_vid;
5875 
5876  idx = get_dyna_var_idx(iseq, id, &lv, &ls);
5877 
5878  if (in_alt_pattern) {
5879  const char *name = rb_id2name(id);
5880  if (name && strlen(name) > 0 && name[0] != '_') {
5881  COMPILE_ERROR(ERROR_ARGS "illegal variable in alternative pattern (%"PRIsVALUE")",
5882  rb_id2str(id));
5883  return COMPILE_NG;
5884  }
5885  }
5886 
5887  if (idx < 0) {
5888  COMPILE_ERROR(ERROR_ARGS "NODE_DASGN(_CURR): unknown id (%"PRIsVALUE")",
5889  rb_id2str(id));
5890  return COMPILE_NG;
5891  }
5892  ADD_SETLOCAL(ret, line, ls - idx, lv);
5893  ADD_INSN1(ret, line, putobject, Qtrue);
5894  break;
5895  }
5896  case NODE_IF:
5897  case NODE_UNLESS: {
5898  LABEL *match_failed, *fin;
5899  match_failed = NEW_LABEL(line);
5900  fin = NEW_LABEL(line);
5901  iseq_compile_pattern_each(iseq, ret, node->nd_body, in_alt_pattern);
5902  ADD_INSNL(ret, line, branchunless, match_failed);
5903  CHECK(COMPILE(ret, "case in if", node->nd_cond));
5904  if (nd_type(node) == NODE_IF) {
5905  ADD_INSNL(ret, line, branchunless, match_failed);
5906  }
5907  else {
5908  ADD_INSNL(ret, line, branchif, match_failed);
5909  }
5910  ADD_INSN1(ret, line, putobject, Qtrue);
5911  ADD_INSNL(ret, line, jump, fin);
5912 
5913  ADD_LABEL(ret, match_failed);
5914  ADD_INSN1(ret, line, putobject, Qfalse);
5915 
5916  ADD_LABEL(ret, fin);
5917  break;
5918  }
5919  case NODE_HASH: {
5920  NODE *n;
5921  LABEL *match_failed, *fin;
5922  match_failed = NEW_LABEL(line);
5923  fin = NEW_LABEL(line);
5924 
5925  n = node->nd_head;
5926  if (! (nd_type(n) == NODE_LIST && n->nd_alen == 2)) {
5927  COMPILE_ERROR(ERROR_ARGS "unexpected node");
5928  return COMPILE_NG;
5929  }
5930 
5931  ADD_INSN(ret, line, dup);
5932  iseq_compile_pattern_each(iseq, ret, n->nd_head, in_alt_pattern);
5933  ADD_INSNL(ret, line, branchunless, match_failed);
5934  iseq_compile_pattern_each(iseq, ret, n->nd_next->nd_head, in_alt_pattern);
5935  ADD_INSNL(ret, line, jump, fin);
5936 
5937  ADD_LABEL(ret, match_failed);
5938  ADD_INSN(ret, line, pop);
5939  ADD_INSN1(ret, line, putobject, Qfalse);
5940 
5941  ADD_LABEL(ret, fin);
5942  break;
5943  }
5944  case NODE_OR: {
5945  LABEL *match_succeeded, *fin;
5946  match_succeeded = NEW_LABEL(line);
5947  fin = NEW_LABEL(line);
5948 
5949  ADD_INSN(ret, line, dup);
5950  iseq_compile_pattern_each(iseq, ret, node->nd_1st, TRUE);
5951  ADD_INSNL(ret, line, branchif, match_succeeded);
5952  iseq_compile_pattern_each(iseq, ret, node->nd_2nd, TRUE);
5953  ADD_INSNL(ret, line, jump, fin);
5954 
5955  ADD_LABEL(ret, match_succeeded);
5956  ADD_INSN(ret, line, pop);
5957  ADD_INSN1(ret, line, putobject, Qtrue);
5958 
5959  ADD_LABEL(ret, fin);
5960  break;
5961  }
5962  default:
5963  UNKNOWN_NODE("NODE_IN", node, COMPILE_NG);
5964  }
5965  return COMPILE_OK;
5966 }
5967 
5968 static int
5969 compile_case3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
5970 {
5971  const NODE *pattern;
5972  const NODE *node = orig_node;
5973  LABEL *endlabel, *elselabel;
5974  DECL_ANCHOR(head);
5975  DECL_ANCHOR(body_seq);
5976  DECL_ANCHOR(cond_seq);
5977  int line, lineno, column, last_lineno, last_column;
5978  enum node_type type;
5979  VALUE branches = 0;
5980 
5981  INIT_ANCHOR(head);
5982  INIT_ANCHOR(body_seq);
5983  INIT_ANCHOR(cond_seq);
5984 
5985  CHECK(COMPILE(head, "case base", node->nd_head));
5986 
5987  DECL_BRANCH_BASE(branches, nd_first_lineno(node), nd_first_column(node), nd_last_lineno(node), nd_last_column(node), "case");
5988 
5989  node = node->nd_body;
5990  EXPECT_NODE("NODE_CASE3", node, NODE_IN, COMPILE_NG);
5991  type = nd_type(node);
5992  line = nd_line(node);
5993  lineno = nd_first_lineno(node);
5994  column = nd_first_column(node);
5995  last_lineno = nd_last_lineno(node);
5996  last_column = nd_last_column(node);
5997 
5998  endlabel = NEW_LABEL(line);
5999  elselabel = NEW_LABEL(line);
6000 
6001  ADD_SEQ(ret, head); /* case VAL */
6002 
6003  while (type == NODE_IN) {
6004  LABEL *l1;
6005 
6006  l1 = NEW_LABEL(line);
6007  ADD_LABEL(body_seq, l1);
6008  ADD_INSN(body_seq, line, pop);
6010  body_seq,
6011  node->nd_body ? nd_first_lineno(node->nd_body) : lineno,
6012  node->nd_body ? nd_first_column(node->nd_body) : column,
6013  node->nd_body ? nd_last_lineno(node->nd_body) : last_lineno,
6014  node->nd_body ? nd_last_column(node->nd_body) : last_column,
6015  "in",
6016  branches);
6017  CHECK(COMPILE_(body_seq, "in body", node->nd_body, popped));
6018  ADD_INSNL(body_seq, line, jump, endlabel);
6019 
6020  pattern = node->nd_head;
6021  if (pattern) {
6022  ADD_INSN (cond_seq, nd_line(pattern), dup);
6023  iseq_compile_pattern_each(iseq, cond_seq, pattern, FALSE);
6024  ADD_INSNL(cond_seq, nd_line(pattern), branchif, l1);
6025  }
6026  else {
6027  COMPILE_ERROR(ERROR_ARGS "unexpected node");
6028  return COMPILE_NG;
6029  }
6030 
6031  node = node->nd_next;
6032  if (!node) {
6033  break;
6034  }
6035  type = nd_type(node);
6036  line = nd_line(node);
6037  lineno = nd_first_lineno(node);
6038  column = nd_first_column(node);
6039  last_lineno = nd_last_lineno(node);
6040  last_column = nd_last_column(node);
6041  }
6042  /* else */
6043  if (node) {
6044  ADD_LABEL(cond_seq, elselabel);
6045  ADD_INSN(cond_seq, line, pop);
6046  ADD_TRACE_BRANCH_COVERAGE(cond_seq, nd_first_lineno(node), nd_first_column(node), nd_last_lineno(node), nd_last_column(node), "else", branches);
6047  CHECK(COMPILE_(cond_seq, "else", node, popped));
6048  ADD_INSNL(cond_seq, line, jump, endlabel);
6049  }
6050  else {
6051  debugs("== else (implicit)\n");
6052  ADD_LABEL(cond_seq, elselabel);
6053  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);
6054  ADD_INSN1(cond_seq, nd_line(orig_node), putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
6055  ADD_INSN1(cond_seq, nd_line(orig_node), putobject, rb_eNoMatchingPatternError);
6056  ADD_INSN1(cond_seq, nd_line(orig_node), topn, INT2FIX(2));
6057  ADD_SEND(cond_seq, nd_line(orig_node), id_core_raise, INT2FIX(2));
6058  ADD_INSN(cond_seq, nd_line(orig_node), pop);
6059  ADD_INSN(cond_seq, nd_line(orig_node), pop);
6060  if (!popped) {
6061  ADD_INSN(cond_seq, nd_line(orig_node), putnil);
6062  }
6063  ADD_INSNL(cond_seq, nd_line(orig_node), jump, endlabel);
6064  }
6065 
6066  ADD_SEQ(ret, cond_seq);
6067  ADD_SEQ(ret, body_seq);
6068  ADD_LABEL(ret, endlabel);
6069  return COMPILE_OK;
6070 }
6071 
6072 static int
6073 compile_loop(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
6074 {
6075  const int line = (int)nd_line(node);
6076  const int lineno = nd_first_lineno(node);
6077  const int column = nd_first_column(node);
6078  const int last_lineno = nd_last_lineno(node);
6079  const int last_column = nd_last_column(node);
6080  LABEL *prev_start_label = ISEQ_COMPILE_DATA(iseq)->start_label;
6081  LABEL *prev_end_label = ISEQ_COMPILE_DATA(iseq)->end_label;
6082  LABEL *prev_redo_label = ISEQ_COMPILE_DATA(iseq)->redo_label;
6083  int prev_loopval_popped = ISEQ_COMPILE_DATA(iseq)->loopval_popped;
6084  VALUE branches = Qfalse;
6085 
6087 
6088  LABEL *next_label = ISEQ_COMPILE_DATA(iseq)->start_label = NEW_LABEL(line); /* next */
6089  LABEL *redo_label = ISEQ_COMPILE_DATA(iseq)->redo_label = NEW_LABEL(line); /* redo */
6090  LABEL *break_label = ISEQ_COMPILE_DATA(iseq)->end_label = NEW_LABEL(line); /* break */
6091  LABEL *end_label = NEW_LABEL(line);
6092  LABEL *adjust_label = NEW_LABEL(line);
6093 
6094  LABEL *next_catch_label = NEW_LABEL(line);
6095  LABEL *tmp_label = NULL;
6096 
6097  ISEQ_COMPILE_DATA(iseq)->loopval_popped = 0;
6098  push_ensure_entry(iseq, &enl, NULL, NULL);
6099 
6100  if (node->nd_state == 1) {
6101  ADD_INSNL(ret, line, jump, next_label);
6102  }
6103  else {
6104  tmp_label = NEW_LABEL(line);
6105  ADD_INSNL(ret, line, jump, tmp_label);
6106  }
6107  ADD_LABEL(ret, adjust_label);
6108  ADD_INSN(ret, line, putnil);
6109  ADD_LABEL(ret, next_catch_label);
6110  ADD_INSN(ret, line, pop);
6111  ADD_INSNL(ret, line, jump, next_label);
6112  if (tmp_label) ADD_LABEL(ret, tmp_label);
6113 
6114  ADD_LABEL(ret, redo_label);
6115  DECL_BRANCH_BASE(branches, lineno, column, last_lineno, last_column, type == NODE_WHILE ? "while" : "until");
6117  ret,
6118  node->nd_body ? nd_first_lineno(node->nd_body) : lineno,
6119  node->nd_body ? nd_first_column(node->nd_body) : column,
6120  node->nd_body ? nd_last_lineno(node->nd_body) : last_lineno,
6121  node->nd_body ? nd_last_column(node->nd_body) : last_column,
6122  "body",
6123  branches);
6124  CHECK(COMPILE_POPPED(ret, "while body", node->nd_body));
6125  ADD_LABEL(ret, next_label); /* next */
6126 
6127  if (type == NODE_WHILE) {
6128  compile_branch_condition(iseq, ret, node->nd_cond,
6129  redo_label, end_label);
6130  }
6131  else {
6132  /* until */
6133  compile_branch_condition(iseq, ret, node->nd_cond,
6134  end_label, redo_label);
6135  }
6136 
6137  ADD_LABEL(ret, end_label);
6138  ADD_ADJUST_RESTORE(ret, adjust_label);
6139 
6140  if (node->nd_state == Qundef) {
6141  /* ADD_INSN(ret, line, putundef); */
6142  COMPILE_ERROR(ERROR_ARGS "unsupported: putundef");
6143  return COMPILE_NG;
6144  }
6145  else {
6146  ADD_INSN(ret, line, putnil);
6147  }
6148 
6149  ADD_LABEL(ret, break_label); /* break */
6150 
6151  if (popped) {
6152  ADD_INSN(ret, line, pop);
6153  }
6154 
6155  ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, redo_label, break_label, NULL,
6156  break_label);
6157  ADD_CATCH_ENTRY(CATCH_TYPE_NEXT, redo_label, break_label, NULL,
6158  next_catch_label);
6159  ADD_CATCH_ENTRY(CATCH_TYPE_REDO, redo_label, break_label, NULL,
6160  ISEQ_COMPILE_DATA(iseq)->redo_label);
6161 
6162  ISEQ_COMPILE_DATA(iseq)->start_label = prev_start_label;
6163  ISEQ_COMPILE_DATA(iseq)->end_label = prev_end_label;
6164  ISEQ_COMPILE_DATA(iseq)->redo_label = prev_redo_label;
6165  ISEQ_COMPILE_DATA(iseq)->loopval_popped = prev_loopval_popped;
6166  ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack->prev;
6167  return COMPILE_OK;
6168 }
6169 
6170 static int
6171 compile_iter(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
6172 {
6173  const int line = nd_line(node);
6174  const rb_iseq_t *prevblock = ISEQ_COMPILE_DATA(iseq)->current_block;
6175  LABEL *retry_label = NEW_LABEL(line);
6176  LABEL *retry_end_l = NEW_LABEL(line);
6177  const rb_iseq_t *child_iseq;
6178 
6179  ADD_LABEL(ret, retry_label);
6180  if (nd_type(node) == NODE_FOR) {
6181  CHECK(COMPILE(ret, "iter caller (for)", node->nd_iter));
6182 
6183  ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq =
6184  NEW_CHILD_ISEQ(node->nd_body, make_name_for_block(iseq),
6185  ISEQ_TYPE_BLOCK, line);
6186  ADD_SEND_WITH_BLOCK(ret, line, idEach, INT2FIX(0), child_iseq);
6187  }
6188  else {
6189  ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq =
6190  NEW_CHILD_ISEQ(node->nd_body, make_name_for_block(iseq),
6191  ISEQ_TYPE_BLOCK, line);
6192  CHECK(COMPILE(ret, "iter caller", node->nd_iter));
6193  }
6194  ADD_LABEL(ret, retry_end_l);
6195 
6196  if (popped) {
6197  ADD_INSN(ret, line, pop);
6198  }
6199 
6200  ISEQ_COMPILE_DATA(iseq)->current_block = prevblock;
6201 
6202  ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, retry_label, retry_end_l, child_iseq, retry_end_l);
6203  return COMPILE_OK;
6204 }
6205 
6206 static int
6207 compile_for_masgn(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
6208 {
6209  /* massign to var in "for"
6210  * (args.length == 1 && Array.try_convert(args[0])) || args
6211  */
6212  const int line = nd_line(node);
6213  const NODE *var = node->nd_var;
6214  LABEL *not_single = NEW_LABEL(nd_line(var));
6215  LABEL *not_ary = NEW_LABEL(nd_line(var));
6216  CHECK(COMPILE(ret, "for var", var));
6217  ADD_INSN(ret, line, dup);
6218  ADD_CALL(ret, line, idLength, INT2FIX(0));
6219  ADD_INSN1(ret, line, putobject, INT2FIX(1));
6220  ADD_CALL(ret, line, idEq, INT2FIX(1));
6221  ADD_INSNL(ret, line, branchunless, not_single);
6222  ADD_INSN(ret, line, dup);
6223  ADD_INSN1(ret, line, putobject, INT2FIX(0));
6224  ADD_CALL(ret, line, idAREF, INT2FIX(1));
6225  ADD_INSN1(ret, line, putobject, rb_cArray);
6226  ADD_INSN(ret, line, swap);
6227  ADD_CALL(ret, line, rb_intern("try_convert"), INT2FIX(1));
6228  ADD_INSN(ret, line, dup);
6229  ADD_INSNL(ret, line, branchunless, not_ary);
6230  ADD_INSN(ret, line, swap);
6231  ADD_LABEL(ret, not_ary);
6232  ADD_INSN(ret, line, pop);
6233  ADD_LABEL(ret, not_single);
6234  return COMPILE_OK;
6235 }
6236 
6237 static int
6238 compile_break(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
6239 {
6240  const int line = nd_line(node);
6241  unsigned long throw_flag = 0;
6242 
6243  if (ISEQ_COMPILE_DATA(iseq)->redo_label != 0) {
6244  /* while/until */
6245  LABEL *splabel = NEW_LABEL(0);
6246  ADD_LABEL(ret, splabel);
6247  ADD_ADJUST(ret, line, ISEQ_COMPILE_DATA(iseq)->redo_label);
6248  CHECK(COMPILE_(ret, "break val (while/until)", node->nd_stts,
6249  ISEQ_COMPILE_DATA(iseq)->loopval_popped));
6250  add_ensure_iseq(ret, iseq, 0);
6251  ADD_INSNL(ret, line, jump, ISEQ_COMPILE_DATA(iseq)->end_label);
6252  ADD_ADJUST_RESTORE(ret, splabel);
6253 
6254  if (!popped) {
6255  ADD_INSN(ret, line, putnil);
6256  }
6257  }
6258  else if (iseq->body->type == ISEQ_TYPE_BLOCK) {
6259  break_by_insn:
6260  /* escape from block */
6261  CHECK(COMPILE(ret, "break val (block)", node->nd_stts));
6262  ADD_INSN1(ret, line, throw, INT2FIX(throw_flag | TAG_BREAK));
6263  if (popped) {
6264  ADD_INSN(ret, line, pop);
6265  }
6266  }
6267  else if (iseq->body->type == ISEQ_TYPE_EVAL) {
6268  break_in_eval:
6269  COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with break");
6270  return COMPILE_NG;
6271  }
6272  else {
6273  const rb_iseq_t *ip = iseq->body->parent_iseq;
6274 
6275  while (ip) {
6276  if (!ISEQ_COMPILE_DATA(ip)) {
6277  ip = 0;
6278  break;
6279  }
6280 
6281  if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
6282  throw_flag = VM_THROW_NO_ESCAPE_FLAG;
6283  goto break_by_insn;
6284  }
6285  else if (ip->body->type == ISEQ_TYPE_BLOCK) {
6286  goto break_by_insn;
6287  }
6288  else if (ip->body->type == ISEQ_TYPE_EVAL) {
6289  goto break_in_eval;
6290  }
6291 
6292  ip = ip->body->parent_iseq;
6293  }
6294  COMPILE_ERROR(ERROR_ARGS "Invalid break");
6295  return COMPILE_NG;
6296  }
6297  return COMPILE_OK;
6298 }
6299 
6300 static int
6301 compile_next(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
6302 {
6303  const int line = nd_line(node);
6304  unsigned long throw_flag = 0;
6305 
6306  if (ISEQ_COMPILE_DATA(iseq)->redo_label != 0) {
6307  LABEL *splabel = NEW_LABEL(0);
6308  debugs("next in while loop\n");
6309  ADD_LABEL(ret, splabel);
6310  CHECK(COMPILE(ret, "next val/valid syntax?", node->nd_stts));
6311  add_ensure_iseq(ret, iseq, 0);
6312  ADD_ADJUST(ret, line, ISEQ_COMPILE_DATA(iseq)->redo_label);
6313  ADD_INSNL(ret, line, jump, ISEQ_COMPILE_DATA(iseq)->start_label);
6314  ADD_ADJUST_RESTORE(ret, splabel);
6315  if (!popped) {
6316  ADD_INSN(ret, line, putnil);
6317  }
6318  }
6319  else if (ISEQ_COMPILE_DATA(iseq)->end_label) {
6320  LABEL *splabel = NEW_LABEL(0);
6321  debugs("next in block\n");
6322  ADD_LABEL(ret, splabel);
6323  ADD_ADJUST(ret, line, ISEQ_COMPILE_DATA(iseq)->start_label);
6324  CHECK(COMPILE(ret, "next val", node->nd_stts));
6325  add_ensure_iseq(ret, iseq, 0);
6326  ADD_INSNL(ret, line, jump, ISEQ_COMPILE_DATA(iseq)->end_label);
6327  ADD_ADJUST_RESTORE(ret, splabel);
6328  splabel->unremovable = FALSE;
6329 
6330  if (!popped) {
6331  ADD_INSN(ret, line, putnil);
6332  }
6333  }
6334  else if (iseq->body->type == ISEQ_TYPE_EVAL) {
6335  next_in_eval:
6336  COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with next");
6337  return COMPILE_NG;
6338  }
6339  else {
6340  const rb_iseq_t *ip = iseq;
6341 
6342  while (ip) {
6343  if (!ISEQ_COMPILE_DATA(ip)) {
6344  ip = 0;
6345  break;
6346  }
6347 
6348  throw_flag = VM_THROW_NO_ESCAPE_FLAG;
6349  if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
6350  /* while loop */
6351  break;
6352  }
6353  else if (ip->body->type == ISEQ_TYPE_BLOCK) {
6354  break;
6355  }
6356  else if (ip->body->type == ISEQ_TYPE_EVAL) {
6357  goto next_in_eval;
6358  }
6359 
6360  ip = ip->body->parent_iseq;
6361  }
6362  if (ip != 0) {
6363  CHECK(COMPILE(ret, "next val", node->nd_stts));
6364  ADD_INSN1(ret, line, throw, INT2FIX(throw_flag | TAG_NEXT));
6365 
6366  if (popped) {
6367  ADD_INSN(ret, line, pop);
6368  }
6369  }
6370  else {
6371  COMPILE_ERROR(ERROR_ARGS "Invalid next");
6372  return COMPILE_NG;
6373  }
6374  }
6375  return COMPILE_OK;
6376 }
6377 
6378 static int
6379 compile_redo(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
6380 {
6381  const int line = nd_line(node);
6382 
6383  if (ISEQ_COMPILE_DATA(iseq)->redo_label) {
6384  LABEL *splabel = NEW_LABEL(0);
6385  debugs("redo in while");
6386  ADD_LABEL(ret, splabel);
6387  ADD_ADJUST(ret, line, ISEQ_COMPILE_DATA(iseq)->redo_label);
6388  add_ensure_iseq(ret, iseq, 0);
6389  ADD_INSNL(ret, line, jump, ISEQ_COMPILE_DATA(iseq)->redo_label);
6390  ADD_ADJUST_RESTORE(ret, splabel);
6391  if (!popped) {
6392  ADD_INSN(ret, line, putnil);
6393  }
6394  }
6395  else if (iseq->body->type == ISEQ_TYPE_EVAL) {
6396  redo_in_eval:
6397  COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with redo");
6398  return COMPILE_NG;
6399  }
6400  else if (ISEQ_COMPILE_DATA(iseq)->start_label) {
6401  LABEL *splabel = NEW_LABEL(0);
6402 
6403  debugs("redo in block");
6404  ADD_LABEL(ret, splabel);
6405  add_ensure_iseq(ret, iseq, 0);
6406  ADD_ADJUST(ret, line, ISEQ_COMPILE_DATA(iseq)->start_label);
6407  ADD_INSNL(ret, line, jump, ISEQ_COMPILE_DATA(iseq)->start_label);
6408  ADD_ADJUST_RESTORE(ret, splabel);
6409 
6410  if (!popped) {
6411  ADD_INSN(ret, line, putnil);
6412  }
6413  }
6414  else {
6415  const rb_iseq_t *ip = iseq;
6416 
6417  while (ip) {
6418  if (!ISEQ_COMPILE_DATA(ip)) {
6419  ip = 0;
6420  break;
6421  }
6422 
6423  if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
6424  break;
6425  }
6426  else if (ip->body->type == ISEQ_TYPE_BLOCK) {
6427  break;
6428  }
6429  else if (ip->body->type == ISEQ_TYPE_EVAL) {
6430  goto redo_in_eval;
6431  }
6432 
6433  ip = ip->body->parent_iseq;
6434  }
6435  if (ip != 0) {
6436  ADD_INSN(ret, line, putnil);
6437  ADD_INSN1(ret, line, throw, INT2FIX(VM_THROW_NO_ESCAPE_FLAG | TAG_REDO));
6438 
6439  if (popped) {
6440  ADD_INSN(ret, line, pop);
6441  }
6442  }
6443  else {
6444  COMPILE_ERROR(ERROR_ARGS "Invalid redo");
6445  return COMPILE_NG;
6446  }
6447  }
6448  return COMPILE_OK;
6449 }
6450 
6451 static int
6452 compile_retry(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
6453 {
6454  const int line = nd_line(node);
6455 
6456  if (iseq->body->type == ISEQ_TYPE_RESCUE) {
6457  ADD_INSN(ret, line, putnil);
6458  ADD_INSN1(ret, line, throw, INT2FIX(TAG_RETRY));
6459 
6460  if (popped) {
6461  ADD_INSN(ret, line, pop);
6462  }
6463  }
6464  else {
6465  COMPILE_ERROR(ERROR_ARGS "Invalid retry");
6466  return COMPILE_NG;
6467  }
6468  return COMPILE_OK;
6469 }
6470 
6471 static int
6472 compile_rescue(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
6473 {
6474  const int line = nd_line(node);
6475  LABEL *lstart = NEW_LABEL(line);
6476  LABEL *lend = NEW_LABEL(line);
6477  LABEL *lcont = NEW_LABEL(line);
6478  const rb_iseq_t *rescue = NEW_CHILD_ISEQ(node->nd_resq,
6479  rb_str_concat(rb_str_new2("rescue in "), iseq->body->location.label),
6480  ISEQ_TYPE_RESCUE, line);
6481 
6482  lstart->rescued = LABEL_RESCUE_BEG;
6483  lend->rescued = LABEL_RESCUE_END;
6484  ADD_LABEL(ret, lstart);
6485  CHECK(COMPILE(ret, "rescue head", node->nd_head));
6486  ADD_LABEL(ret, lend);
6487  if (node->nd_else) {
6488  ADD_INSN(ret, line, pop);
6489  CHECK(COMPILE(ret, "rescue else", node->nd_else));
6490  }
6491  ADD_INSN(ret, line, nop);
6492  ADD_LABEL(ret, lcont);
6493 
6494  if (popped) {
6495  ADD_INSN(ret, line, pop);
6496  }
6497 
6498  /* register catch entry */
6499  ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lcont);
6500  ADD_CATCH_ENTRY(CATCH_TYPE_RETRY, lend, lcont, NULL, lstart);
6501  return COMPILE_OK;
6502 }
6503 
6504 static int
6505 compile_resbody(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
6506 {
6507  const int line = nd_line(node);
6508  const NODE *resq = node;
6509  const NODE *narg;
6510  LABEL *label_miss, *label_hit;
6511 
6512  while (resq) {
6513  label_miss = NEW_LABEL(line);
6514  label_hit = NEW_LABEL(line);
6515 
6516  narg = resq->nd_args;
6517  if (narg) {
6518  switch (nd_type(narg)) {
6519  case NODE_LIST:
6520  while (narg) {
6521  ADD_GETLOCAL(ret, line, LVAR_ERRINFO, 0);
6522  CHECK(COMPILE(ret, "rescue arg", narg->nd_head));
6523  ADD_INSN1(ret, line, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
6524  ADD_INSNL(ret, line, branchif, label_hit);
6525  narg = narg->nd_next;
6526  }
6527  break;
6528  case NODE_SPLAT:
6529  case NODE_ARGSCAT:
6530  case NODE_ARGSPUSH:
6531  ADD_GETLOCAL(ret, line, LVAR_ERRINFO, 0);
6532  CHECK(COMPILE(ret, "rescue/cond splat", narg));
6534  ADD_INSNL(ret, line, branchif, label_hit);
6535  break;
6536  default:
6537  UNKNOWN_NODE("NODE_RESBODY", narg, COMPILE_NG);
6538  }
6539  }
6540  else {
6541  ADD_GETLOCAL(ret, line, LVAR_ERRINFO, 0);
6542  ADD_INSN1(ret, line, putobject, rb_eStandardError);
6543  ADD_INSN1(ret, line, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
6544  ADD_INSNL(ret, line, branchif, label_hit);
6545  }
6546  ADD_INSNL(ret, line, jump, label_miss);
6547  ADD_LABEL(ret, label_hit);
6548  CHECK(COMPILE(ret, "resbody body", resq->nd_body));
6549  if (ISEQ_COMPILE_DATA(iseq)->option->tailcall_optimization) {
6550  ADD_INSN(ret, line, nop);
6551  }
6552  ADD_INSN(ret, line, leave);
6553  ADD_LABEL(ret, label_miss);
6554  resq = resq->nd_head;
6555  }
6556  return COMPILE_OK;
6557 }
6558 
6559 static int
6560 compile_ensure(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
6561 {
6562  const int line = nd_line(node);
6563  DECL_ANCHOR(ensr);
6564  const rb_iseq_t *ensure = NEW_CHILD_ISEQ(node->nd_ensr,
6565  rb_str_concat(rb_str_new2 ("ensure in "), iseq->body->location.label),
6566  ISEQ_TYPE_ENSURE, line);
6567  LABEL *lstart = NEW_LABEL(line);
6568  LABEL *lend = NEW_LABEL(line);
6569  LABEL *lcont = NEW_LABEL(line);
6570  LINK_ELEMENT *last;
6571  int last_leave = 0;
6572  struct ensure_range er;
6574  struct ensure_range *erange;
6575 
6576  INIT_ANCHOR(ensr);
6577  CHECK(COMPILE_POPPED(ensr, "ensure ensr", node->nd_ensr));
6578  last = ensr->last;
6579  last_leave = last && IS_INSN(last) && IS_INSN_ID(last, leave);
6580 
6581  er.begin = lstart;
6582  er.end = lend;
6583  er.next = 0;
6584  push_ensure_entry(iseq, &enl, &er, node->nd_ensr);
6585 
6586  ADD_LABEL(ret, lstart);
6587  CHECK(COMPILE_(ret, "ensure head", node->nd_head, (popped | last_leave)));
6588  ADD_LABEL(ret, lend);
6589  ADD_SEQ(ret, ensr);
6590  if (!popped && last_leave) ADD_INSN(ret, line, putnil);
6591  ADD_LABEL(ret, lcont);
6592  if (last_leave) ADD_INSN(ret, line, pop);
6593 
6594  erange = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack->erange;
6595  if (lstart->link.next != &lend->link) {
6596  while (erange) {
6597  ADD_CATCH_ENTRY(CATCH_TYPE_ENSURE, erange->begin, erange->end,
6598  ensure, lcont);
6599  erange = erange->next;
6600  }
6601  }
6602 
6603  ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enl.prev;
6604  return COMPILE_OK;
6605 }
6606 
6607 static int
6608 compile_return(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
6609 {
6610  const int line = nd_line(node);
6611 
6612  if (iseq) {
6613  enum iseq_type type = iseq->body->type;
6614  const rb_iseq_t *is = iseq;
6615  enum iseq_type t = type;
6616  const NODE *retval = node->nd_stts;
6617  LABEL *splabel = 0;
6618 
6619  while (t == ISEQ_TYPE_RESCUE || t == ISEQ_TYPE_ENSURE) {
6620  if (!(is = is->body->parent_iseq)) break;
6621  t = is->body->type;
6622  }
6623  switch (t) {
6624  case ISEQ_TYPE_TOP:
6625  case ISEQ_TYPE_MAIN:
6626  if (retval) {
6627  rb_warn("argument of top-level return is ignored");
6628  }
6629  if (is == iseq) {
6630  /* plain top-level, leave directly */
6631  type = ISEQ_TYPE_METHOD;
6632  }
6633  break;
6634  default:
6635  break;
6636  }
6637 
6638  if (type == ISEQ_TYPE_METHOD) {
6639  splabel = NEW_LABEL(0);
6640  ADD_LABEL(ret, splabel);
6641  ADD_ADJUST(ret, line, 0);
6642  }
6643 
6644  CHECK(COMPILE(ret, "return nd_stts (return val)", retval));
6645 
6646  if (type == ISEQ_TYPE_METHOD) {
6647  add_ensure_iseq(ret, iseq, 1);
6649  ADD_INSN(ret, line, leave);
6650  ADD_ADJUST_RESTORE(ret, splabel);
6651 
6652  if (!popped) {
6653  ADD_INSN(ret, line, putnil);
6654  }
6655  }
6656  else {
6657  ADD_INSN1(ret, line, throw, INT2FIX(TAG_RETURN));
6658  if (popped) {
6659  ADD_INSN(ret, line, pop);
6660  }
6661  }
6662  }
6663  return COMPILE_OK;
6664 }
6665 
6666 static int
6667 compile_evstr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
6668 {
6669  CHECK(COMPILE_(ret, "nd_body", node, popped));
6670 
6671  if (!popped && !all_string_result_p(node)) {
6672  const int line = nd_line(node);
6673  const unsigned int flag = VM_CALL_FCALL;
6674  LABEL *isstr = NEW_LABEL(line);
6675  ADD_INSN(ret, line, dup);
6676  ADD_INSN1(ret, line, checktype, INT2FIX(T_STRING));
6677  ADD_INSNL(ret, line, branchif, isstr);
6678  ADD_INSN(ret, line, dup);
6679  ADD_SEND_R(ret, line, idTo_s, INT2FIX(0), NULL, INT2FIX(flag), NULL);
6680  ADD_INSN(ret, line, tostring);
6681  ADD_LABEL(ret, isstr);
6682  }
6683  return COMPILE_OK;
6684 }
6685 
6686 static LABEL *
6687 qcall_branch_start(rb_iseq_t *iseq, LINK_ANCHOR *const recv, VALUE *branches, const NODE *node, int line)
6688 {
6689  LABEL *else_label = NEW_LABEL(line);
6690  const int first_lineno = nd_first_lineno(node), first_column = nd_first_column(node);
6691  const int last_lineno = nd_last_lineno(node), last_column = nd_last_column(node);
6692  VALUE br = 0;
6693 
6694  DECL_BRANCH_BASE(br, first_lineno, first_column, last_lineno, last_column, "&.");
6695  *branches = br;
6696  ADD_INSN(recv, line, dup);
6697  ADD_INSNL(recv, line, branchnil, else_label);
6698  ADD_TRACE_BRANCH_COVERAGE(recv, first_lineno, first_column, last_lineno, last_column, "then", br);
6699  return else_label;
6700 }
6701 
6702 static void
6703 qcall_branch_end(rb_iseq_t *iseq, LINK_ANCHOR *const ret, LABEL *else_label, VALUE branches, const NODE *node, int line)
6704 {
6705  LABEL *end_label;
6706  if (!else_label) return;
6707  end_label = NEW_LABEL(line);
6708  ADD_INSNL(ret, line, jump, end_label);
6709  ADD_LABEL(ret, else_label);
6711  "else", branches);
6712  ADD_LABEL(ret, end_label);
6713 }
6714 
6715 static int
6716 compile_call_precheck_freeze(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int line, int popped)
6717 {
6718  /* optimization shortcut
6719  * "literal".freeze -> opt_str_freeze("literal")
6720  */
6721  if (node->nd_recv && nd_type(node->nd_recv) == NODE_STR &&
6722  (node->nd_mid == idFreeze || node->nd_mid == idUMinus) &&
6723  node->nd_args == NULL &&
6724  ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
6725  ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
6726  VALUE str = rb_fstring(node->nd_recv->nd_lit);
6727  if (node->nd_mid == idUMinus) {
6728  ADD_INSN2(ret, line, opt_str_uminus, str,
6729  new_callinfo(iseq, idUMinus, 0, 0, NULL, FALSE));
6730  }
6731  else {
6732  ADD_INSN2(ret, line, opt_str_freeze, str,
6733  new_callinfo(iseq, idFreeze, 0, 0, NULL, FALSE));
6734  }
6736  if (popped) {
6737  ADD_INSN(ret, line, pop);
6738  }
6739  return TRUE;
6740  }
6741  /* optimization shortcut
6742  * obj["literal"] -> opt_aref_with(obj, "literal")
6743  */
6744  if (node->nd_mid == idAREF && !private_recv_p(node) && node->nd_args &&
6745  nd_type(node->nd_args) == NODE_LIST && node->nd_args->nd_alen == 1 &&
6746  nd_type(node->nd_args->nd_head) == NODE_STR &&
6747  ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
6748  !ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal &&
6749  ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
6750  VALUE str = rb_fstring(node->nd_args->nd_head->nd_lit);
6751  CHECK(COMPILE(ret, "recv", node->nd_recv));
6752  ADD_INSN2(ret, line, opt_aref_with, str,
6753  new_callinfo(iseq, idAREF, 1, 0, NULL, FALSE));
6755  if (popped) {
6756  ADD_INSN(ret, line, pop);
6757  }
6758  return TRUE;
6759  }
6760  return FALSE;
6761 }
6762 
6763 static int
6764 iseq_has_builtin_function_table(const rb_iseq_t *iseq)
6765 {
6766  return ISEQ_COMPILE_DATA(iseq)->builtin_function_table != NULL;
6767 }
6768 
6769 static const struct rb_builtin_function *
6770 iseq_builtin_function_lookup(const rb_iseq_t *iseq, const char *name)
6771 {
6772  int i;
6773  const struct rb_builtin_function *table = ISEQ_COMPILE_DATA(iseq)->builtin_function_table;
6774  for (i=0; table[i].index != -1; i++) {
6775  if (strcmp(table[i].name, name) == 0) {
6776  return &table[i];
6777  }
6778  }
6779  return NULL;
6780 }
6781 
6782 static const char *
6783 iseq_builtin_function_name(ID mid)
6784 {
6785  const char *name = rb_id2name(mid);
6786  static const char prefix[] = "__builtin_";
6787  const size_t prefix_len = sizeof(prefix) - 1;
6788 
6789  if (UNLIKELY(strncmp(prefix, name, prefix_len) == 0)) {
6790  return &name[prefix_len];
6791  }
6792  else {
6793  return NULL;
6794  }
6795 }
6796 
6797 static int
6798 delegate_call_p(const rb_iseq_t *iseq, unsigned int argc, const LINK_ANCHOR *args, unsigned int *pstart_index)
6799 {
6800 
6801  if (argc == 0) {
6802  *pstart_index = 0;
6803  return TRUE;
6804  }
6805  else if (argc <= iseq->body->local_table_size) {
6806  unsigned int start=0;
6807 
6808  // local_table: [p1, p2, p3, l1, l2, l3]
6809  // arguments: [p3, l1, l2] -> 2
6810  for (start = 0;
6811  argc + start <= iseq->body->local_table_size;
6812  start++) {
6813  const LINK_ELEMENT *elem = FIRST_ELEMENT(args);
6814 
6815  for (unsigned int i=start; i-start<argc; i++) {
6816  if (elem->type == ISEQ_ELEMENT_INSN &&
6817  INSN_OF(elem) == BIN(getlocal)) {
6818  int local_index = FIX2INT(OPERAND_AT(elem, 0));
6819  int local_level = FIX2INT(OPERAND_AT(elem, 1));
6820 
6821  if (local_level == 0) {
6822  unsigned int index = iseq->body->local_table_size - (local_index - VM_ENV_DATA_SIZE + 1);
6823  if (0) { // for debug
6824  fprintf(stderr, "lvar:%s (%d), id:%s (%d) local_index:%d, local_size:%d\n",
6827  local_index, (int)iseq->body->local_table_size);
6828  }
6829  if (i == index) {
6830  elem = elem->next;
6831  continue; /* for */
6832  }
6833  else {
6834  goto next;
6835  }
6836  }
6837  else {
6838  goto fail; // level != 0 is unsupported
6839  }
6840  }
6841  else {
6842  goto fail; // insn is not a getlocal
6843  }
6844  }
6845  goto success;
6846  next:;
6847  }
6848  fail:
6849  return FALSE;
6850  success:
6851  *pstart_index = start;
6852  return TRUE;
6853  }
6854  else {
6855  return FALSE;
6856  }
6857 }
6858 
6859 static int
6860 compile_call(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int type, int line, int popped)
6861 {
6862  /* call: obj.method(...)
6863  * fcall: func(...)
6864  * vcall: func
6865  */
6866  DECL_ANCHOR(recv);
6867  DECL_ANCHOR(args);
6868  ID mid = node->nd_mid;
6869  VALUE argc;
6870  unsigned int flag = 0;
6871  struct rb_call_info_kw_arg *keywords = NULL;
6872  const rb_iseq_t *parent_block = ISEQ_COMPILE_DATA(iseq)->current_block;
6873  LABEL *else_label = NULL;
6874  VALUE branches = Qfalse;
6875 
6876  ISEQ_COMPILE_DATA(iseq)->current_block = NULL;
6877 
6878  INIT_ANCHOR(recv);
6879  INIT_ANCHOR(args);
6880 #if OPT_SUPPORT_JOKE
6881  if (nd_type(node) == NODE_VCALL) {
6882  ID id_bitblt;
6883  ID id_answer;
6884 
6885  CONST_ID(id_bitblt, "bitblt");
6886  CONST_ID(id_answer, "the_answer_to_life_the_universe_and_everything");
6887 
6888  if (mid == id_bitblt) {
6889  ADD_INSN(ret, line, bitblt);
6890  return COMPILE_OK;
6891  }
6892  else if (mid == id_answer) {
6893  ADD_INSN(ret, line, answer);
6894  return COMPILE_OK;
6895  }
6896  }
6897  /* only joke */
6898  {
6899  ID goto_id;
6900  ID label_id;
6901 
6902  CONST_ID(goto_id, "__goto__");
6903  CONST_ID(label_id, "__label__");
6904 
6905  if (nd_type(node) == NODE_FCALL &&
6906  (mid == goto_id || mid == label_id)) {
6907  LABEL *label;
6908  st_data_t data;
6909  st_table *labels_table = ISEQ_COMPILE_DATA(iseq)->labels_table;
6910  VALUE label_name;
6911 
6912  if (!labels_table) {
6913  labels_table = st_init_numtable();
6914  ISEQ_COMPILE_DATA(iseq)->labels_table = labels_table;
6915  }
6916  if (nd_type(node->nd_args->nd_head) == NODE_LIT &&
6917  SYMBOL_P(node->nd_args->nd_head->nd_lit)) {
6918 
6919  label_name = node->nd_args->nd_head->nd_lit;
6920  if (!st_lookup(labels_table, (st_data_t)label_name, &data)) {
6921  label = NEW_LABEL(line);
6922  label->position = line;
6923  st_insert(labels_table, (st_data_t)label_name, (st_data_t)label);
6924  }
6925  else {
6926  label = (LABEL *)data;
6927  }
6928  }
6929  else {
6930  COMPILE_ERROR(ERROR_ARGS "invalid goto/label format");
6931  return COMPILE_NG;
6932  }
6933 
6934  if (mid == goto_id) {
6935  ADD_INSNL(ret, line, jump, label);
6936  }
6937  else {
6938  ADD_LABEL(ret, label);
6939  }
6940  return COMPILE_OK;
6941  }
6942  }
6943 #endif
6944  const char *builtin_func;
6945  NODE *args_node = node->nd_args;
6946 
6947  if (UNLIKELY(iseq_has_builtin_function_table(iseq)) &&
6948  (builtin_func = iseq_builtin_function_name(mid)) != NULL) {
6949 
6950  if (parent_block != NULL) {
6951  COMPILE_ERROR(iseq, line, "should not call builtins here.");
6952  return COMPILE_NG;
6953  }
6954  else {
6955  char inline_func[0x20];
6956  bool cconst = false;
6957  retry:;
6958  const struct rb_builtin_function *bf = iseq_builtin_function_lookup(iseq, builtin_func);
6959 
6960  if (bf == NULL) {
6961  if (strcmp("cstmt!", builtin_func) == 0 ||
6962  strcmp("cexpr!", builtin_func) == 0) {
6963  inlinec:;
6964  int inline_index = GET_VM()->builtin_inline_index++;
6965  snprintf(inline_func, 0x20, "_bi%d", inline_index);
6966  builtin_func = inline_func;
6967  args_node = NULL;
6968  goto retry;
6969  }
6970  else if (strcmp("cconst!", builtin_func) == 0) {
6971  cconst = true;
6972  goto inlinec;
6973  }
6974  else if (strcmp("cinit!", builtin_func) == 0) {
6975  // ignore
6976  GET_VM()->builtin_inline_index++;
6977  return COMPILE_OK;
6978  }
6979 
6980  if (1) {
6981  rb_bug("can't find builtin function:%s", builtin_func);
6982  }
6983  else {
6984  COMPILE_ERROR(ERROR_ARGS "can't find builtin function:%s", builtin_func);
6985  }
6986  return COMPILE_NG;
6987  }
6988 
6989  if (cconst) {
6990  typedef VALUE(*builtin_func0)(void *, VALUE);
6991  VALUE const_val = (*(builtin_func0)bf->func_ptr)(NULL, Qnil);
6992  ADD_INSN1(ret, line, putobject, const_val);
6993  return COMPILE_OK;
6994  }
6995 
6996  // fprintf(stderr, "func_name:%s -> %p\n", builtin_func, bf->func_ptr);
6997 
6998  argc = setup_args(iseq, args, args_node, &flag, &keywords);
6999 
7000  if (FIX2INT(argc) != bf->argc) {
7001  COMPILE_ERROR(ERROR_ARGS "argc is not match for builtin function:%s (expect %d but %d)",
7002  builtin_func, bf->argc, FIX2INT(argc));
7003  return COMPILE_NG;
7004  }
7005 
7006  unsigned int start_index;
7007  if (delegate_call_p(iseq, FIX2INT(argc), args, &start_index)) {
7008  ADD_INSN2(ret, line, opt_invokebuiltin_delegate, bf, INT2FIX(start_index));
7009  }
7010  else {
7011  ADD_SEQ(ret, args);
7012  ADD_INSN1(ret,line, invokebuiltin, bf);
7013  }
7014 
7015  if (popped) ADD_INSN(ret, line, pop);
7016  return COMPILE_OK;
7017  }
7018  }
7019 
7020 
7021  /* receiver */
7022  if (type == NODE_CALL || type == NODE_OPCALL || type == NODE_QCALL) {
7023  int idx, level;
7024 
7025  if (mid == idCall &&
7026  nd_type(node->nd_recv) == NODE_LVAR &&
7027  iseq_block_param_id_p(iseq, node->nd_recv->nd_vid, &idx, &level)) {
7028  ADD_INSN2(recv, nd_line(node->nd_recv), getblockparamproxy, INT2FIX(idx + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
7029  }
7030  else if (private_recv_p(node)) {
7031  ADD_INSN(recv, nd_line(node), putself);
7032  flag |= VM_CALL_FCALL;
7033  }
7034  else {
7035  CHECK(COMPILE(recv, "recv", node->nd_recv));
7036  }
7037 
7038  if (type == NODE_QCALL) {
7039  else_label = qcall_branch_start(iseq, recv, &branches, node, line);
7040  }
7041  }
7042  else if (type == NODE_FCALL || type == NODE_VCALL) {
7043  ADD_CALL_RECEIVER(recv, line);
7044  }
7045 
7046  /* args */
7047  if (type != NODE_VCALL) {
7048  argc = setup_args(iseq, args, node->nd_args, &flag, &keywords);
7049  CHECK(!NIL_P(argc));
7050  }
7051  else {
7052  argc = INT2FIX(0);
7053  }
7054 
7055  ADD_SEQ(ret, recv);
7056  ADD_SEQ(ret, args);
7057 
7058  debugp_param("call args argc", argc);
7059  debugp_param("call method", ID2SYM(mid));
7060 
7061  switch ((int)type) {
7062  case NODE_VCALL:
7063  flag |= VM_CALL_VCALL;
7064  /* VCALL is funcall, so fall through */
7065  case NODE_FCALL:
7066  flag |= VM_CALL_FCALL;
7067  }
7068 
7069  ADD_SEND_R(ret, line, mid, argc, parent_block, INT2FIX(flag), keywords);
7070 
7071  qcall_branch_end(iseq, ret, else_label, branches, node, line);
7072  if (popped) {
7073  ADD_INSN(ret, line, pop);
7074  }
7075  return COMPILE_OK;
7076 }
7077 
7078 
7079 static int iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int popped);
7087 static int
7088 iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *node, int popped)
7089 {
7090  if (node == 0) {
7091  if (!popped) {
7092  int lineno = ISEQ_COMPILE_DATA(iseq)->last_line;
7093  if (lineno == 0) lineno = FIX2INT(rb_iseq_first_lineno(iseq));
7094  debugs("node: NODE_NIL(implicit)\n");
7095  ADD_INSN(ret, lineno, putnil);
7096  }
7097  return COMPILE_OK;
7098  }
7099  return iseq_compile_each0(iseq, ret, node, popped);
7100 }
7101 
7102 static int
7103 check_yield_place(const rb_iseq_t *iseq, int line)
7104 {
7105  VALUE file;
7106  switch (iseq->body->local_iseq->body->type) {
7107  case ISEQ_TYPE_TOP:
7108  case ISEQ_TYPE_MAIN:
7109  return FALSE;
7110  case ISEQ_TYPE_CLASS:
7111  file = rb_iseq_path(iseq);
7113  rb_compile_warn(RSTRING_PTR(file), line,
7114  "`yield' in class syntax will not be supported from Ruby 3.0. [Feature #15575]");
7115  }
7116  return TRUE;
7117  default:
7118  return TRUE;
7119  }
7120 }
7121 
7122 static int
7123 iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int popped)
7124 {
7125  const int line = (int)nd_line(node);
7126  const enum node_type type = nd_type(node);
7127  struct rb_iseq_constant_body *const body = iseq->body;
7128 
7129  if (ISEQ_COMPILE_DATA(iseq)->last_line == line) {
7130  /* ignore */
7131  }
7132  else {
7133  if (node->flags & NODE_FL_NEWLINE) {
7134  int event = RUBY_EVENT_LINE;
7135  ISEQ_COMPILE_DATA(iseq)->last_line = line;
7137  event |= RUBY_EVENT_COVERAGE_LINE;
7138  }
7139  ADD_TRACE(ret, event);
7140  }
7141  }
7142 
7143  debug_node_start(node);
7144 #undef BEFORE_RETURN
7145 #define BEFORE_RETURN debug_node_end()
7146 
7147  switch (type) {
7148  case NODE_BLOCK:{
7149  while (node && nd_type(node) == NODE_BLOCK) {
7150  CHECK(COMPILE_(ret, "BLOCK body", node->nd_head,
7151  (node->nd_next ? 1 : popped)));
7152  node = node->nd_next;
7153  }
7154  if (node) {
7155  CHECK(COMPILE_(ret, "BLOCK next", node->nd_next, popped));
7156  }
7157  break;
7158  }
7159  case NODE_IF:
7160  case NODE_UNLESS:
7161  CHECK(compile_if(iseq, ret, node, popped, type));
7162  break;
7163  case NODE_CASE:
7164  CHECK(compile_case(iseq, ret, node, popped));
7165  break;
7166  case NODE_CASE2:
7167  CHECK(compile_case2(iseq, ret, node, popped));
7168  break;
7169  case NODE_CASE3:
7170  CHECK(compile_case3(iseq, ret, node, popped));
7171  break;
7172  case NODE_WHILE:
7173  case NODE_UNTIL:
7174  CHECK(compile_loop(iseq, ret, node, popped, type));
7175  break;
7176  case NODE_FOR:
7177  case NODE_ITER:
7178  CHECK(compile_iter(iseq, ret, node, popped));
7179  break;
7180  case NODE_FOR_MASGN:
7181  CHECK(compile_for_masgn(iseq, ret, node, popped));
7182  break;
7183  case NODE_BREAK:
7184  CHECK(compile_break(iseq, ret, node, popped));
7185  break;
7186  case NODE_NEXT:
7187  CHECK(compile_next(iseq, ret, node, popped));
7188  break;
7189  case NODE_REDO:
7190  CHECK(compile_redo(iseq, ret, node, popped));
7191  break;
7192  case NODE_RETRY:
7193  CHECK(compile_retry(iseq, ret, node, popped));
7194  break;
7195  case NODE_BEGIN:{
7196  CHECK(COMPILE_(ret, "NODE_BEGIN", node->nd_body, popped));
7197  break;
7198  }
7199  case NODE_RESCUE:
7200  CHECK(compile_rescue(iseq, ret, node, popped));
7201  break;
7202  case NODE_RESBODY:
7203  CHECK(compile_resbody(iseq, ret, node, popped));
7204  break;
7205  case NODE_ENSURE:
7206  CHECK(compile_ensure(iseq, ret, node, popped));
7207  break;
7208 
7209  case NODE_AND:
7210  case NODE_OR:{
7211  LABEL *end_label = NEW_LABEL(line);
7212  CHECK(COMPILE(ret, "nd_1st", node->nd_1st));
7213  if (!popped) {
7214  ADD_INSN(ret, line, dup);
7215  }
7216  if (type == NODE_AND) {
7217  ADD_INSNL(ret, line, branchunless, end_label);
7218  }
7219  else {
7220  ADD_INSNL(ret, line, branchif, end_label);
7221  }
7222  if (!popped) {
7223  ADD_INSN(ret, line, pop);
7224  }
7225  CHECK(COMPILE_(ret, "nd_2nd", node->nd_2nd, popped));
7226  ADD_LABEL(ret, end_label);
7227  break;
7228  }
7229 
7230  case NODE_MASGN:{
7231  compile_massign(iseq, ret, node, popped);
7232  break;
7233  }
7234 
7235  case NODE_LASGN:{
7236  ID id = node->nd_vid;
7237  int idx = body->local_iseq->body->local_table_size - get_local_var_idx(iseq, id);
7238 
7239  debugs("lvar: %s idx: %d\n", rb_id2name(id), idx);
7240  CHECK(COMPILE(ret, "rvalue", node->nd_value));
7241 
7242  if (!popped) {
7243  ADD_INSN(ret, line, dup);
7244  }
7245  ADD_SETLOCAL(ret, line, idx, get_lvar_level(iseq));
7246  break;
7247  }
7248  case NODE_DASGN:
7249  case NODE_DASGN_CURR:{
7250  int idx, lv, ls;
7251  ID id = node->nd_vid;
7252  CHECK(COMPILE(ret, "dvalue", node->nd_value));
7253  debugi("dassn id", rb_id2str(id) ? id : '*');
7254 
7255  if (!popped) {
7256  ADD_INSN(ret, line, dup);
7257  }
7258 
7259  idx = get_dyna_var_idx(iseq, id, &lv, &ls);
7260 
7261  if (idx < 0) {
7262  COMPILE_ERROR(ERROR_ARGS "NODE_DASGN(_CURR): unknown id (%"PRIsVALUE")",
7263  rb_id2str(id));
7264  goto ng;
7265  }
7266  ADD_SETLOCAL(ret, line, ls - idx, lv);
7267  break;
7268  }
7269  case NODE_GASGN:{
7270  CHECK(COMPILE(ret, "lvalue", node->nd_value));
7271 
7272  if (!popped) {
7273  ADD_INSN(ret, line, dup);
7274  }
7275  ADD_INSN1(ret, line, setglobal,
7276  ((VALUE)node->nd_entry | 1));
7277  break;
7278  }
7279  case NODE_IASGN:{
7280  CHECK(COMPILE(ret, "lvalue", node->nd_value));
7281  if (!popped) {
7282  ADD_INSN(ret, line, dup);
7283  }
7284  ADD_INSN2(ret, line, setinstancevariable,
7285  ID2SYM(node->nd_vid),
7286  get_ivar_ic_value(iseq,node->nd_vid));
7287  break;
7288  }
7289  case NODE_CDECL:{
7290  CHECK(COMPILE(ret, "lvalue", node->nd_value));
7291 
7292  if (!popped) {
7293  ADD_INSN(ret, line, dup);
7294  }
7295 
7296  if (node->nd_vid) {
7297  ADD_INSN1(ret, line, putspecialobject,
7299  ADD_INSN1(ret, line, setconstant, ID2SYM(node->nd_vid));
7300  }
7301  else {
7302  compile_cpath(ret, iseq, node->nd_else);
7303  ADD_INSN1(ret, line, setconstant, ID2SYM(node->nd_else->nd_mid));
7304  }
7305  break;
7306  }
7307  case NODE_CVASGN:{
7308  CHECK(COMPILE(ret, "cvasgn val", node->nd_value));
7309  if (!popped) {
7310  ADD_INSN(ret, line, dup);
7311  }
7312  ADD_INSN1(ret, line, setclassvariable,
7313  ID2SYM(node->nd_vid));
7314  break;
7315  }
7316  case NODE_OP_ASGN1: {
7317  VALUE argc;
7318  unsigned int flag = 0;
7319  int asgnflag = 0;
7320  ID id = node->nd_mid;
7321  int boff = 0;
7322 
7323  /*
7324  * a[x] (op)= y
7325  *
7326  * nil # nil
7327  * eval a # nil a
7328  * eval x # nil a x
7329  * dupn 2 # nil a x a x
7330  * send :[] # nil a x a[x]
7331  * eval y # nil a x a[x] y
7332  * send op # nil a x ret
7333  * setn 3 # ret a x ret
7334  * send []= # ret ?
7335  * pop # ret
7336  */
7337 
7338  /*
7339  * nd_recv[nd_args->nd_body] (nd_mid)= nd_args->nd_head;
7340  * NODE_OP_ASGN nd_recv
7341  * nd_args->nd_head
7342  * nd_args->nd_body
7343  * nd_mid
7344  */
7345 
7346  if (!popped) {
7347  ADD_INSN(ret, line, putnil);
7348  }
7349  asgnflag = COMPILE_RECV(ret, "NODE_OP_ASGN1 recv", node);
7350  CHECK(asgnflag != -1);
7351  switch (nd_type(node->nd_args->nd_head)) {
7352  case NODE_ZLIST:
7353  argc = INT2FIX(0);
7354  break;
7355  case NODE_BLOCK_PASS:
7356  boff = 1;
7357  /* fall through */
7358  default:
7359  argc = setup_args(iseq, ret, node->nd_args->nd_head, &flag, NULL);
7360  CHECK(!NIL_P(argc));
7361  }
7362  ADD_INSN1(ret, line, dupn, FIXNUM_INC(argc, 1 + boff));
7363  flag |= asgnflag;
7364  ADD_SEND_WITH_FLAG(ret, line, idAREF, argc, INT2FIX(flag));
7365 
7366  if (id == idOROP || id == idANDOP) {
7367  /* a[x] ||= y or a[x] &&= y
7368 
7369  unless/if a[x]
7370  a[x]= y
7371  else
7372  nil
7373  end
7374  */
7375  LABEL *label = NEW_LABEL(line);
7376  LABEL *lfin = NEW_LABEL(line);
7377 
7378  ADD_INSN(ret, line, dup);
7379  if (id == idOROP) {
7380  ADD_INSNL(ret, line, branchif, label);
7381  }
7382  else { /* idANDOP */
7383  ADD_INSNL(ret, line, branchunless, label);
7384  }
7385  ADD_INSN(ret, line, pop);
7386 
7387  CHECK(COMPILE(ret, "NODE_OP_ASGN1 args->body: ", node->nd_args->nd_body));
7388  if (!popped) {
7389  ADD_INSN1(ret, line, setn, FIXNUM_INC(argc, 2+boff));
7390  }
7391  if (flag & VM_CALL_ARGS_SPLAT) {
7392  ADD_INSN1(ret, line, newarray, INT2FIX(1));
7393  if (boff > 0) {
7394  ADD_INSN1(ret, line, dupn, INT2FIX(3));
7395  ADD_INSN(ret, line, swap);
7396  ADD_INSN(ret, line, pop);
7397  }
7398  ADD_INSN(ret, line, concatarray);
7399  if (boff > 0) {
7400  ADD_INSN1(ret, line, setn, INT2FIX(3));
7401  ADD_INSN(ret, line, pop);
7402  ADD_INSN(ret, line, pop);
7403  }
7404  ADD_SEND_WITH_FLAG(ret, line, idASET, argc, INT2FIX(flag));
7405  }
7406  else {
7407  if (boff > 0)
7408  ADD_INSN(ret, line, swap);
7409  ADD_SEND_WITH_FLAG(ret, line, idASET, FIXNUM_INC(argc, 1), INT2FIX(flag));
7410  }
7411  ADD_INSN(ret, line, pop);
7412  ADD_INSNL(ret, line, jump, lfin);
7413  ADD_LABEL(ret, label);
7414  if (!popped) {
7415  ADD_INSN1(ret, line, setn, FIXNUM_INC(argc, 2+boff));
7416  }
7417  ADD_INSN1(ret, line, adjuststack, FIXNUM_INC(argc, 2+boff));
7418  ADD_LABEL(ret, lfin);
7419  }
7420  else {
7421  CHECK(COMPILE(ret, "NODE_OP_ASGN1 args->body: ", node->nd_args->nd_body));
7422  ADD_SEND(ret, line, id, INT2FIX(1));
7423  if (!popped) {
7424  ADD_INSN1(ret, line, setn, FIXNUM_INC(argc, 2+boff));
7425  }
7426  if (flag & VM_CALL_ARGS_SPLAT) {
7427  ADD_INSN1(ret, line, newarray, INT2FIX(1));
7428  if (boff > 0) {
7429  ADD_INSN1(ret, line, dupn, INT2FIX(3));
7430  ADD_INSN(ret, line, swap);
7431  ADD_INSN(ret, line, pop);
7432  }
7433  ADD_INSN(ret, line, concatarray);
7434  if (boff > 0) {
7435  ADD_INSN1(ret, line, setn, INT2FIX(3));
7436  ADD_INSN(ret, line, pop);
7437  ADD_INSN(ret, line, pop);
7438  }
7439  ADD_SEND_WITH_FLAG(ret, line, idASET, argc, INT2FIX(flag));
7440  }
7441  else {
7442  if (boff > 0)
7443  ADD_INSN(ret, line, swap);
7444  ADD_SEND_WITH_FLAG(ret, line, idASET, FIXNUM_INC(argc, 1), INT2FIX(flag));
7445  }
7446  ADD_INSN(ret, line, pop);
7447  }
7448 
7449  break;
7450  }
7451  case NODE_OP_ASGN2:{
7452  ID atype = node->nd_next->nd_mid;
7453  ID vid = node->nd_next->nd_vid, aid = rb_id_attrset(vid);
7454  int asgnflag;
7455  LABEL *lfin = NEW_LABEL(line);
7456  LABEL *lcfin = NEW_LABEL(line);
7457  LABEL *lskip = 0;
7458  /*
7459  class C; attr_accessor :c; end
7460  r = C.new
7461  r.a &&= v # asgn2
7462 
7463  eval r # r
7464  dup # r r
7465  eval r.a # r o
7466 
7467  # or
7468  dup # r o o
7469  if lcfin # r o
7470  pop # r
7471  eval v # r v
7472  swap # v r
7473  topn 1 # v r v
7474  send a= # v ?
7475  jump lfin # v ?
7476 
7477  lcfin: # r o
7478  swap # o r
7479 
7480  lfin: # o ?
7481  pop # o
7482 
7483  # and
7484  dup # r o o
7485  unless lcfin
7486  pop # r
7487  eval v # r v
7488  swap # v r
7489  topn 1 # v r v
7490  send a= # v ?
7491  jump lfin # v ?
7492 
7493  # others
7494  eval v # r o v
7495  send ?? # r w
7496  send a= # w
7497 
7498  */
7499 
7500  asgnflag = COMPILE_RECV(ret, "NODE_OP_ASGN2#recv", node);
7501  CHECK(asgnflag != -1);
7502  if (node->nd_next->nd_aid) {
7503  lskip = NEW_LABEL(line);
7504  ADD_INSN(ret, line, dup);
7505  ADD_INSNL(ret, line, branchnil, lskip);
7506  }
7507  ADD_INSN(ret, line, dup);
7508  ADD_SEND_WITH_FLAG(ret, line, vid, INT2FIX(0), INT2FIX(asgnflag));
7509 
7510  if (atype == idOROP || atype == idANDOP) {
7511  ADD_INSN(ret, line, dup);
7512  if (atype == idOROP) {
7513  ADD_INSNL(ret, line, branchif, lcfin);
7514  }
7515  else { /* idANDOP */
7516  ADD_INSNL(ret, line, branchunless, lcfin);
7517  }
7518  ADD_INSN(ret, line, pop);
7519  CHECK(COMPILE(ret, "NODE_OP_ASGN2 val", node->nd_value));
7520  ADD_INSN(ret, line, swap);
7521  ADD_INSN1(ret, line, topn, INT2FIX(1));
7522  ADD_SEND_WITH_FLAG(ret, line, aid, INT2FIX(1), INT2FIX(asgnflag));
7523  ADD_INSNL(ret, line, jump, lfin);
7524 
7525  ADD_LABEL(ret, lcfin);
7526  ADD_INSN(ret, line, swap);
7527 
7528  ADD_LABEL(ret, lfin);
7529  ADD_INSN(ret, line, pop);
7530  if (lskip) {
7531  ADD_LABEL(ret, lskip);
7532  }
7533  if (popped) {
7534  /* we can apply more optimize */
7535  ADD_INSN(ret, line, pop);
7536  }
7537  }
7538  else {
7539  CHECK(COMPILE(ret, "NODE_OP_ASGN2 val", node->nd_value));
7540  ADD_SEND(ret, line, atype, INT2FIX(1));
7541  if (!popped) {
7542  ADD_INSN(ret, line, swap);
7543  ADD_INSN1(ret, line, topn, INT2FIX(1));
7544  }
7545  ADD_SEND_WITH_FLAG(ret, line, aid, INT2FIX(1), INT2FIX(asgnflag));
7546  if (lskip && popped) {
7547  ADD_LABEL(ret, lskip);
7548  }
7549  ADD_INSN(ret, line, pop);
7550  if (lskip && !popped) {
7551  ADD_LABEL(ret, lskip);
7552  }
7553  }
7554  break;
7555  }
7556  case NODE_OP_CDECL: {
7557  LABEL *lfin = 0;
7558  LABEL *lassign = 0;
7559  ID mid;
7560 
7561  switch (nd_type(node->nd_head)) {
7562  case NODE_COLON3:
7563  ADD_INSN1(ret, line, putobject, rb_cObject);
7564  break;
7565  case NODE_COLON2:
7566  CHECK(COMPILE(ret, "NODE_OP_CDECL/colon2#nd_head", node->nd_head->nd_head));
7567  break;
7568  default:
7569  COMPILE_ERROR(ERROR_ARGS "%s: invalid node in NODE_OP_CDECL",
7570  ruby_node_name(nd_type(node->nd_head)));
7571  goto ng;
7572  }
7573  mid = node->nd_head->nd_mid;
7574  /* cref */
7575  if (node->nd_aid == idOROP) {
7576  lassign = NEW_LABEL(line);
7577  ADD_INSN(ret, line, dup); /* cref cref */
7578  ADD_INSN3(ret, line, defined, INT2FIX(DEFINED_CONST_FROM),
7579  ID2SYM(mid), Qfalse); /* cref bool */
7580  ADD_INSNL(ret, line, branchunless, lassign); /* cref */
7581  }
7582  ADD_INSN(ret, line, dup); /* cref cref */
7583  ADD_INSN1(ret, line, putobject, Qtrue);
7584  ADD_INSN1(ret, line, getconstant, ID2SYM(mid)); /* cref obj */
7585 
7586  if (node->nd_aid == idOROP || node->nd_aid == idANDOP) {
7587  lfin = NEW_LABEL(line);
7588  if (!popped) ADD_INSN(ret, line, dup); /* cref [obj] obj */
7589  if (node->nd_aid == idOROP)
7590  ADD_INSNL(ret, line, branchif, lfin);
7591  else /* idANDOP */
7592  ADD_INSNL(ret, line, branchunless, lfin);
7593  /* cref [obj] */
7594  if (!popped) ADD_INSN(ret, line, pop); /* cref */
7595  if (lassign) ADD_LABEL(ret, lassign);
7596  CHECK(COMPILE(ret, "NODE_OP_CDECL#nd_value", node->nd_value));
7597  /* cref value */
7598  if (popped)
7599  ADD_INSN1(ret, line, topn, INT2FIX(1)); /* cref value cref */
7600  else {
7601  ADD_INSN1(ret, line, dupn, INT2FIX(2)); /* cref value cref value */
7602  ADD_INSN(ret, line, swap); /* cref value value cref */
7603  }
7604  ADD_INSN1(ret, line, setconstant, ID2SYM(mid)); /* cref [value] */
7605  ADD_LABEL(ret, lfin); /* cref [value] */
7606  if (!popped) ADD_INSN(ret, line, swap); /* [value] cref */
7607  ADD_INSN(ret, line, pop); /* [value] */
7608  }
7609  else {
7610  CHECK(COMPILE(ret, "NODE_OP_CDECL#nd_value", node->nd_value));
7611  /* cref obj value */
7612  ADD_CALL(ret, line, node->nd_aid, INT2FIX(1));
7613  /* cref value */
7614  ADD_INSN(ret, line, swap); /* value cref */
7615  if (!popped) {
7616  ADD_INSN1(ret, line, topn, INT2FIX(1)); /* value cref value */
7617  ADD_INSN(ret, line, swap); /* value value cref */
7618  }
7619  ADD_INSN1(ret, line, setconstant, ID2SYM(mid));
7620  }
7621  break;
7622  }
7623  case NODE_OP_ASGN_AND:
7624  case NODE_OP_ASGN_OR:{
7625  LABEL *lfin = NEW_LABEL(line);
7626  LABEL *lassign;
7627 
7628  if (nd_type(node) == NODE_OP_ASGN_OR) {
7629  LABEL *lfinish[2];
7630  lfinish[0] = lfin;
7631  lfinish[1] = 0;
7632  defined_expr(iseq, ret, node->nd_head, lfinish, Qfalse);
7633  lassign = lfinish[1];
7634  if (!lassign) {
7635  lassign = NEW_LABEL(line);
7636  }
7637  ADD_INSNL(ret, line, branchunless, lassign);
7638  }
7639  else {
7640  lassign = NEW_LABEL(line);
7641  }
7642 
7643  CHECK(COMPILE(ret, "NODE_OP_ASGN_AND/OR#nd_head", node->nd_head));
7644  ADD_INSN(ret, line, dup);
7645 
7646  if (nd_type(node) == NODE_OP_ASGN_AND) {
7647  ADD_INSNL(ret, line, branchunless, lfin);
7648  }
7649  else {
7650  ADD_INSNL(ret, line, branchif, lfin);
7651  }
7652 
7653  ADD_INSN(ret, line, pop);
7654  ADD_LABEL(ret, lassign);
7655  CHECK(COMPILE(ret, "NODE_OP_ASGN_AND/OR#nd_value", node->nd_value));
7656  ADD_LABEL(ret, lfin);
7657 
7658  if (popped) {
7659  /* we can apply more optimize */
7660  ADD_INSN(ret, line, pop);
7661  }
7662  break;
7663  }
7664  case NODE_CALL: /* obj.foo */
7665  case NODE_OPCALL: /* foo[] */
7666  if (compile_call_precheck_freeze(iseq, ret, node, line, popped) == TRUE) {
7667  break;
7668  }
7669  case NODE_QCALL: /* obj&.foo */
7670  case NODE_FCALL: /* foo() */
7671  case NODE_VCALL: /* foo (variable or call) */
7672  if (compile_call(iseq, ret, node, type, line, popped) == COMPILE_NG) {
7673  goto ng;
7674  }
7675  break;
7676  case NODE_SUPER:
7677  case NODE_ZSUPER:{
7678  DECL_ANCHOR(args);
7679  int argc;
7680  unsigned int flag = 0;
7681  struct rb_call_info_kw_arg *keywords = NULL;
7682  const rb_iseq_t *parent_block = ISEQ_COMPILE_DATA(iseq)->current_block;
7683 
7684  INIT_ANCHOR(args);
7685  ISEQ_COMPILE_DATA(iseq)->current_block = NULL;
7686  if (type == NODE_SUPER) {
7687  VALUE vargc = setup_args(iseq, args, node->nd_args, &flag, &keywords);
7688  CHECK(!NIL_P(vargc));
7689  argc = FIX2INT(vargc);
7690  }
7691  else {
7692  /* NODE_ZSUPER */
7693  int i;
7694  const rb_iseq_t *liseq = body->local_iseq;
7695  const struct rb_iseq_constant_body *const local_body = liseq->body;
7696  const struct rb_iseq_param_keyword *const local_kwd = local_body->param.keyword;
7697  int lvar_level = get_lvar_level(iseq);
7698 
7699  argc = local_body->param.lead_num;
7700 
7701  /* normal arguments */
7702  for (i = 0; i < local_body->param.lead_num; i++) {
7703  int idx = local_body->local_table_size - i;
7704  ADD_GETLOCAL(args, line, idx, lvar_level);
7705  }
7706 
7707  if (local_body->param.flags.has_opt) {
7708  /* optional arguments */
7709  int j;
7710  for (j = 0; j < local_body->param.opt_num; j++) {
7711  int idx = local_body->local_table_size - (i + j);
7712  ADD_GETLOCAL(args, line, idx, lvar_level);
7713  }
7714  i += j;
7715  argc = i;
7716  }
7717  if (local_body->param.flags.has_rest) {
7718  /* rest argument */
7719  int idx = local_body->local_table_size - local_body->param.rest_start;
7720 
7721  ADD_GETLOCAL(args, line, idx, lvar_level);
7722  ADD_INSN1(args, line, splatarray, Qfalse);
7723 
7724  argc = local_body->param.rest_start + 1;
7725  flag |= VM_CALL_ARGS_SPLAT;
7726  }
7727  if (local_body->param.flags.has_post) {
7728  /* post arguments */
7729  int post_len = local_body->param.post_num;
7730  int post_start = local_body->param.post_start;
7731 
7732  if (local_body->param.flags.has_rest) {
7733  int j;
7734  for (j=0; j<post_len; j++) {
7735  int idx = local_body->local_table_size - (post_start + j);
7736  ADD_GETLOCAL(args, line, idx, lvar_level);
7737  }
7738  ADD_INSN1(args, line, newarray, INT2FIX(j));
7739  ADD_INSN (args, line, concatarray);
7740  /* argc is settled at above */
7741  }
7742  else {
7743  int j;
7744  for (j=0; j<post_len; j++) {
7745  int idx = local_body->local_table_size - (post_start + j);
7746  ADD_GETLOCAL(args, line, idx, lvar_level);
7747  }
7748  argc = post_len + post_start;
7749  }
7750  }
7751 
7752  if (local_body->param.flags.has_kw) { /* TODO: support keywords */
7753  int local_size = local_body->local_table_size;
7754  argc++;
7755 
7756  ADD_INSN1(args, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7757 
7758  if (local_body->param.flags.has_kwrest) {
7759  int idx = local_body->local_table_size - local_kwd->rest_start;
7760  ADD_GETLOCAL(args, line, idx, lvar_level);
7761  ADD_SEND (args, line, rb_intern("dup"), INT2FIX(0));
7762  }
7763  else {
7764  ADD_INSN1(args, line, newhash, INT2FIX(0));
7765  }
7766  for (i = 0; i < local_kwd->num; ++i) {
7767  ID id = local_kwd->table[i];
7768  int idx = local_size - get_local_var_idx(liseq, id);
7769  ADD_INSN1(args, line, putobject, ID2SYM(id));
7770  ADD_GETLOCAL(args, line, idx, lvar_level);
7771  }
7772  ADD_SEND(args, line, id_core_hash_merge_ptr, INT2FIX(i * 2 + 1));
7773  if (local_body->param.flags.has_rest) {
7774  ADD_INSN1(args, line, newarray, INT2FIX(1));
7775  ADD_INSN (args, line, concatarray);
7776  --argc;
7777  }
7778  flag |= VM_CALL_KW_SPLAT;
7779  }
7780  else if (local_body->param.flags.has_kwrest) {
7781  int idx = local_body->local_table_size - local_kwd->rest_start;
7782  ADD_GETLOCAL(args, line, idx, lvar_level);
7783 
7784  ADD_SEND (args, line, rb_intern("dup"), INT2FIX(0));
7785  if (local_body->param.flags.has_rest) {
7786  ADD_INSN1(args, line, newarray, INT2FIX(1));
7787  ADD_INSN (args, line, concatarray);
7788  }
7789  else {
7790  argc++;
7791  }
7792  flag |= VM_CALL_KW_SPLAT;
7793  }
7794  }
7795 
7796  ADD_INSN(ret, line, putself);
7797  ADD_SEQ(ret, args);
7798  ADD_INSN2(ret, line, invokesuper,
7799  new_callinfo(iseq, 0, argc, flag | VM_CALL_SUPER | (type == NODE_ZSUPER ? VM_CALL_ZSUPER : 0) | VM_CALL_FCALL, keywords, parent_block != NULL),
7800  parent_block);
7801 
7802  if (popped) {
7803  ADD_INSN(ret, line, pop);
7804  }
7805  break;
7806  }
7807  case NODE_LIST:{
7808  CHECK(compile_array(iseq, ret, node, popped) >= 0);
7809  break;
7810  }
7811  case NODE_ZLIST:{
7812  if (!popped) {
7813  ADD_INSN1(ret, line, newarray, INT2FIX(0));
7814  }
7815  break;
7816  }
7817  case NODE_VALUES:{
7818  const NODE *n = node;
7819  if (popped) {
7820  COMPILE_ERROR(ERROR_ARGS "NODE_VALUES: must not be popped");
7821  }
7822  while (n) {
7823  CHECK(COMPILE(ret, "values item", n->nd_head));
7824  n = n->nd_next;
7825  }
7826  ADD_INSN1(ret, line, newarray, INT2FIX(node->nd_alen));
7827  break;
7828  }
7829  case NODE_HASH:
7830  CHECK(compile_hash(iseq, ret, node, popped) >= 0);
7831  break;
7832  case NODE_RETURN:
7833  CHECK(compile_return(iseq, ret, node, popped));
7834  break;
7835  case NODE_YIELD:{
7836  DECL_ANCHOR(args);
7837  VALUE argc;
7838  unsigned int flag = 0;
7839  struct rb_call_info_kw_arg *keywords = NULL;
7840 
7841  INIT_ANCHOR(args);
7842 
7843  if (check_yield_place(iseq, line) == FALSE) {
7844  COMPILE_ERROR(ERROR_ARGS "Invalid yield");
7845  goto ng;
7846  }
7847 
7848  if (node->nd_head) {
7849  argc = setup_args(iseq, args, node->nd_head, &flag, &keywords);
7850  CHECK(!NIL_P(argc));
7851  }
7852  else {
7853  argc = INT2FIX(0);
7854  }
7855 
7856  ADD_SEQ(ret, args);
7857  ADD_INSN1(ret, line, invokeblock, new_callinfo(iseq, 0, FIX2INT(argc), flag, keywords, FALSE));
7858 
7859  if (popped) {
7860  ADD_INSN(ret, line, pop);
7861  }
7862  break;
7863  }
7864  case NODE_LVAR:{
7865  if (!popped) {
7866  ID id = node->nd_vid;
7867  int idx = body->local_iseq->body->local_table_size - get_local_var_idx(iseq, id);
7868 
7869  debugs("id: %s idx: %d\n", rb_id2name(id), idx);
7870  ADD_GETLOCAL(ret, line, idx, get_lvar_level(iseq));
7871  }
7872  break;
7873  }
7874  case NODE_DVAR:{
7875  int lv, idx, ls;
7876  debugi("nd_vid", node->nd_vid);
7877  if (!popped) {
7878  idx = get_dyna_var_idx(iseq, node->nd_vid, &lv, &ls);
7879  if (idx < 0) {
7880  COMPILE_ERROR(ERROR_ARGS "unknown dvar (%"PRIsVALUE")",
7881  rb_id2str(node->nd_vid));
7882  goto ng;
7883  }
7884  ADD_GETLOCAL(ret, line, ls - idx, lv);
7885  }
7886  break;
7887  }
7888  case NODE_GVAR:{
7889  ADD_INSN1(ret, line, getglobal,
7890  ((VALUE)node->nd_entry | 1));
7891  if (popped) {
7892  ADD_INSN(ret, line, pop);
7893  }
7894  break;
7895  }
7896  case NODE_IVAR:{
7897  debugi("nd_vid", node->nd_vid);
7898  if (!popped) {
7899  ADD_INSN2(ret, line, getinstancevariable,
7900  ID2SYM(node->nd_vid),
7901  get_ivar_ic_value(iseq,node->nd_vid));
7902  }
7903  break;
7904  }
7905  case NODE_CONST:{
7906  debugi("nd_vid", node->nd_vid);
7907 
7908  if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
7909  LABEL *lend = NEW_LABEL(line);
7910  int ic_index = body->is_size++;
7911 
7912  ADD_INSN2(ret, line, opt_getinlinecache, lend, INT2FIX(ic_index));
7913  ADD_INSN1(ret, line, putobject, Qtrue);
7914  ADD_INSN1(ret, line, getconstant, ID2SYM(node->nd_vid));
7915  ADD_INSN1(ret, line, opt_setinlinecache, INT2FIX(ic_index));
7916  ADD_LABEL(ret, lend);
7917  }
7918  else {
7919  ADD_INSN(ret, line, putnil);
7920  ADD_INSN1(ret, line, putobject, Qtrue);
7921  ADD_INSN1(ret, line, getconstant, ID2SYM(node->nd_vid));
7922  }
7923 
7924  if (popped) {
7925  ADD_INSN(ret, line, pop);
7926  }
7927  break;
7928  }
7929  case NODE_CVAR:{
7930  if (!popped) {
7931  ADD_INSN1(ret, line, getclassvariable,
7932  ID2SYM(node->nd_vid));
7933  }
7934  break;
7935  }
7936  case NODE_NTH_REF:{
7937  if (!popped) {
7938  if (!node->nd_nth) {
7939  ADD_INSN(ret, line, putnil);
7940  break;
7941  }
7942  ADD_INSN2(ret, line, getspecial, INT2FIX(1) /* '~' */,
7943  INT2FIX(node->nd_nth << 1));
7944  }
7945  break;
7946  }
7947  case NODE_BACK_REF:{
7948  if (!popped) {
7949  ADD_INSN2(ret, line, getspecial, INT2FIX(1) /* '~' */,
7950  INT2FIX(0x01 | (node->nd_nth << 1)));
7951  }
7952  break;
7953  }
7954  case NODE_MATCH:
7955  case NODE_MATCH2:
7956  case NODE_MATCH3:{
7957  DECL_ANCHOR(recv);
7958  DECL_ANCHOR(val);
7959 
7960  INIT_ANCHOR(recv);
7961  INIT_ANCHOR(val);
7962  switch (nd_type(node)) {
7963  case NODE_MATCH:
7964  ADD_INSN1(recv, line, putobject, node->nd_lit);
7965  ADD_INSN2(val, line, getspecial, INT2FIX(0),
7966  INT2FIX(0));
7967  break;
7968  case NODE_MATCH2:
7969  CHECK(COMPILE(recv, "receiver", node->nd_recv));
7970  CHECK(COMPILE(val, "value", node->nd_value));
7971  break;
7972  case NODE_MATCH3:
7973  CHECK(COMPILE(recv, "receiver", node->nd_value));
7974  CHECK(COMPILE(val, "value", node->nd_recv));
7975  break;
7976  }
7977 
7978  ADD_SEQ(ret, recv);
7979  ADD_SEQ(ret, val);
7980  ADD_SEND(ret, line, idEqTilde, INT2FIX(1));
7981 
7982  if (node->nd_args) {
7983  compile_named_capture_assign(iseq, ret, node->nd_args);
7984  }
7985 
7986  if (popped) {
7987  ADD_INSN(ret, line, pop);
7988  }
7989  break;
7990  }
7991  case NODE_LIT:{
7992  debugp_param("lit", node->nd_lit);
7993  if (!popped) {
7994  ADD_INSN1(ret, line, putobject, node->nd_lit);
7995  }
7996  break;
7997  }
7998  case NODE_STR:{
7999  debugp_param("nd_lit", node->nd_lit);
8000  if (!popped) {
8001  VALUE lit = node->nd_lit;
8002  if (!ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal) {
8003  lit = rb_fstring(lit);
8004  ADD_INSN1(ret, line, putstring, lit);
8005  RB_OBJ_WRITTEN(iseq, Qundef, lit);
8006  }
8007  else {
8008  if (ISEQ_COMPILE_DATA(iseq)->option->debug_frozen_string_literal || RTEST(ruby_debug)) {
8009  VALUE debug_info = rb_ary_new_from_args(2, rb_iseq_path(iseq), INT2FIX(line));
8010  lit = rb_str_dup(lit);
8011  rb_ivar_set(lit, id_debug_created_info, rb_obj_freeze(debug_info));
8012  lit = rb_str_freeze(lit);
8013  }
8014  else {
8015  lit = rb_fstring(lit);
8016  }
8017  ADD_INSN1(ret, line, putobject, lit);
8018  RB_OBJ_WRITTEN(iseq, Qundef, lit);
8019  }
8020  }
8021  break;
8022  }
8023  case NODE_DSTR:{
8024  compile_dstr(iseq, ret, node);
8025 
8026  if (popped) {
8027  ADD_INSN(ret, line, pop);
8028  }
8029  else {
8030  if (ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal) {
8031  VALUE debug_info = Qnil;
8032  if (ISEQ_COMPILE_DATA(iseq)->option->debug_frozen_string_literal || RTEST(ruby_debug)) {
8033  debug_info = rb_ary_new_from_args(2, rb_iseq_path(iseq), INT2FIX(line));
8034  }
8035  ADD_INSN1(ret, line, freezestring, debug_info);
8036  if (!NIL_P(debug_info)) {
8037  RB_OBJ_WRITTEN(iseq, Qundef, rb_obj_freeze(debug_info));
8038  }
8039  }
8040  }
8041  break;
8042  }
8043  case NODE_XSTR:{
8044  ADD_CALL_RECEIVER(ret, line);
8045  VALUE str = rb_fstring(node->nd_lit);
8046  ADD_INSN1(ret, line, putobject, str);
8048  ADD_CALL(ret, line, idBackquote, INT2FIX(1));
8049 
8050  if (popped) {
8051  ADD_INSN(ret, line, pop);
8052  }
8053  break;
8054  }
8055  case NODE_DXSTR:{
8056  ADD_CALL_RECEIVER(ret, line);
8057  compile_dstr(iseq, ret, node);
8058  ADD_CALL(ret, line, idBackquote, INT2FIX(1));
8059 
8060  if (popped) {
8061  ADD_INSN(ret, line, pop);
8062  }
8063  break;
8064  }
8065  case NODE_EVSTR:
8066  CHECK(compile_evstr(iseq, ret, node->nd_body, popped));
8067  break;
8068  case NODE_DREGX:{
8069  compile_dregx(iseq, ret, node);
8070 
8071  if (popped) {
8072  ADD_INSN(ret, line, pop);
8073  }
8074  break;
8075  }
8076  case NODE_ONCE:{
8077  int ic_index = body->is_size++;
8078  const rb_iseq_t *block_iseq;
8079  block_iseq = NEW_CHILD_ISEQ(node->nd_body, make_name_for_block(iseq), ISEQ_TYPE_PLAIN, line);
8080 
8081  ADD_INSN2(ret, line, once, block_iseq, INT2FIX(ic_index));
8082  RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block_iseq);
8083 
8084  if (popped) {
8085  ADD_INSN(ret, line, pop);
8086  }
8087  break;
8088  }
8089  case NODE_ARGSCAT:{
8090  if (popped) {
8091  CHECK(COMPILE(ret, "argscat head", node->nd_head));
8092  ADD_INSN1(ret, line, splatarray, Qfalse);
8093  ADD_INSN(ret, line, pop);
8094  CHECK(COMPILE(ret, "argscat body", node->nd_body));
8095  ADD_INSN1(ret, line, splatarray, Qfalse);
8096  ADD_INSN(ret, line, pop);
8097  }
8098  else {
8099  CHECK(COMPILE(ret, "argscat head", node->nd_head));
8100  CHECK(COMPILE(ret, "argscat body", node->nd_body));
8101  ADD_INSN(ret, line, concatarray);
8102  }
8103  break;
8104  }
8105  case NODE_ARGSPUSH:{
8106  if (popped) {
8107  CHECK(COMPILE(ret, "arsgpush head", node->nd_head));
8108  ADD_INSN1(ret, line, splatarray, Qfalse);
8109  ADD_INSN(ret, line, pop);
8110  CHECK(COMPILE_(ret, "argspush body", node->nd_body, popped));
8111  }
8112  else {
8113  CHECK(COMPILE(ret, "arsgpush head", node->nd_head));
8114  CHECK(COMPILE_(ret, "argspush body", node->nd_body, popped));
8115  ADD_INSN1(ret, line, newarray, INT2FIX(1));
8116  ADD_INSN(ret, line, concatarray);
8117  }
8118  break;
8119  }
8120  case NODE_SPLAT:{
8121  CHECK(COMPILE(ret, "splat", node->nd_head));
8122  ADD_INSN1(ret, line, splatarray, Qtrue);
8123 
8124  if (popped) {
8125  ADD_INSN(ret, line, pop);
8126  }
8127  break;
8128  }
8129  case NODE_DEFN:{
8130  ID mid = node->nd_mid;
8131  const rb_iseq_t *method_iseq = NEW_ISEQ(node->nd_defn,
8132  rb_id2str(mid),
8133  ISEQ_TYPE_METHOD, line);
8134 
8135  debugp_param("defn/iseq", rb_iseqw_new(method_iseq));
8136  ADD_INSN2(ret, line, definemethod, ID2SYM(mid), method_iseq);
8137  RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)method_iseq);
8138 
8139  if (!popped) {
8140  ADD_INSN1(ret, line, putobject, ID2SYM(mid));
8141  }
8142 
8143  break;
8144  }
8145  case NODE_DEFS:{
8146  ID mid = node->nd_mid;
8147  const rb_iseq_t * singleton_method_iseq = NEW_ISEQ(node->nd_defn,
8148  rb_id2str(mid),
8149  ISEQ_TYPE_METHOD, line);
8150 
8151  debugp_param("defs/iseq", rb_iseqw_new(singleton_method_iseq));
8152  CHECK(COMPILE(ret, "defs: recv", node->nd_recv));
8153  ADD_INSN2(ret, line, definesmethod, ID2SYM(mid), singleton_method_iseq);
8154  RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)singleton_method_iseq);
8155 
8156  if (!popped) {
8157  ADD_INSN1(ret, line, putobject, ID2SYM(mid));
8158  }
8159  break;
8160  }
8161  case NODE_ALIAS:{
8162  ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8163  ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
8164  CHECK(COMPILE(ret, "alias arg1", node->nd_1st));
8165  CHECK(COMPILE(ret, "alias arg2", node->nd_2nd));
8166  ADD_SEND(ret, line, id_core_set_method_alias, INT2FIX(3));
8167 
8168  if (popped) {
8169  ADD_INSN(ret, line, pop);
8170  }
8171  break;
8172  }
8173  case NODE_VALIAS:{
8174  ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8175  ADD_INSN1(ret, line, putobject, ID2SYM(node->nd_alias));
8176  ADD_INSN1(ret, line, putobject, ID2SYM(node->nd_orig));
8178 
8179  if (popped) {
8180  ADD_INSN(ret, line, pop);
8181  }
8182  break;
8183  }
8184  case NODE_UNDEF:{
8185  ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8186  ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
8187  CHECK(COMPILE(ret, "undef arg", node->nd_undef));
8188  ADD_SEND(ret, line, id_core_undef_method, INT2FIX(2));
8189 
8190  if (popped) {
8191  ADD_INSN(ret, line, pop);
8192  }
8193  break;
8194  }
8195  case NODE_CLASS:{
8196  const rb_iseq_t *class_iseq = NEW_CHILD_ISEQ(node->nd_body,
8197  rb_sprintf("<class:%"PRIsVALUE">", rb_id2str(node->nd_cpath->nd_mid)),
8198  ISEQ_TYPE_CLASS, line);
8199  const int flags = VM_DEFINECLASS_TYPE_CLASS |
8200  (node->nd_super ? VM_DEFINECLASS_FLAG_HAS_SUPERCLASS : 0) |
8201  compile_cpath(ret, iseq, node->nd_cpath);
8202 
8203  CHECK(COMPILE(ret, "super", node->nd_super));
8204  ADD_INSN3(ret, line, defineclass, ID2SYM(node->nd_cpath->nd_mid), class_iseq, INT2FIX(flags));
8205  RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)class_iseq);
8206 
8207  if (popped) {
8208  ADD_INSN(ret, line, pop);
8209  }
8210  break;
8211  }
8212  case NODE_MODULE:{
8213  const rb_iseq_t *module_iseq = NEW_CHILD_ISEQ(node->nd_body,
8214  rb_sprintf("<module:%"PRIsVALUE">", rb_id2str(node->nd_cpath->nd_mid)),
8215  ISEQ_TYPE_CLASS, line);
8216  const int flags = VM_DEFINECLASS_TYPE_MODULE |
8217  compile_cpath(ret, iseq, node->nd_cpath);
8218 
8219  ADD_INSN (ret, line, putnil); /* dummy */
8220  ADD_INSN3(ret, line, defineclass, ID2SYM(node->nd_cpath->nd_mid), module_iseq, INT2FIX(flags));
8221  RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)module_iseq);
8222 
8223  if (popped) {
8224  ADD_INSN(ret, line, pop);
8225  }
8226  break;
8227  }
8228  case NODE_SCLASS:{
8229  ID singletonclass;
8230  const rb_iseq_t *singleton_class = NEW_ISEQ(node->nd_body, rb_fstring_lit("singleton class"),
8231  ISEQ_TYPE_CLASS, line);
8232 
8233  CHECK(COMPILE(ret, "sclass#recv", node->nd_recv));
8234  ADD_INSN (ret, line, putnil);
8235  CONST_ID(singletonclass, "singletonclass");
8236  ADD_INSN3(ret, line, defineclass,
8237  ID2SYM(singletonclass), singleton_class,
8239  RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)singleton_class);
8240 
8241  if (popped) {
8242  ADD_INSN(ret, line, pop);
8243  }
8244  break;
8245  }
8246  case NODE_COLON2:{
8247  if (rb_is_const_id(node->nd_mid)) {
8248  /* constant */
8249  LABEL *lend = NEW_LABEL(line);
8250  int ic_index = body->is_size++;
8251 
8252  DECL_ANCHOR(pref);
8253  DECL_ANCHOR(body);
8254 
8255  INIT_ANCHOR(pref);
8256  INIT_ANCHOR(body);
8257  CHECK(compile_const_prefix(iseq, node, pref, body));
8258  if (LIST_INSN_SIZE_ZERO(pref)) {
8259  if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
8260  ADD_INSN2(ret, line, opt_getinlinecache, lend, INT2FIX(ic_index));
8261  }
8262  else {
8263  ADD_INSN(ret, line, putnil);
8264  }
8265 
8266  ADD_SEQ(ret, body);
8267 
8268  if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
8269  ADD_INSN1(ret, line, opt_setinlinecache, INT2FIX(ic_index));
8270  ADD_LABEL(ret, lend);
8271  }
8272  }
8273  else {
8274  ADD_SEQ(ret, pref);
8275  ADD_SEQ(ret, body);
8276  }
8277  }
8278  else {
8279  /* function call */
8280  ADD_CALL_RECEIVER(ret, line);
8281  CHECK(COMPILE(ret, "colon2#nd_head", node->nd_head));
8282  ADD_CALL(ret, line, node->nd_mid, INT2FIX(1));
8283  }
8284  if (popped) {
8285  ADD_INSN(ret, line, pop);
8286  }
8287  break;
8288  }
8289  case NODE_COLON3:{
8290  LABEL *lend = NEW_LABEL(line);
8291  int ic_index = body->is_size++;
8292 
8293  debugi("colon3#nd_mid", node->nd_mid);
8294 
8295  /* add cache insn */
8296  if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
8297  ADD_INSN2(ret, line, opt_getinlinecache, lend, INT2FIX(ic_index));
8298  ADD_INSN(ret, line, pop);
8299  }
8300 
8301  ADD_INSN1(ret, line, putobject, rb_cObject);
8302  ADD_INSN1(ret, line, putobject, Qtrue);
8303  ADD_INSN1(ret, line, getconstant, ID2SYM(node->nd_mid));
8304 
8305  if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
8306  ADD_INSN1(ret, line, opt_setinlinecache, INT2FIX(ic_index));
8307  ADD_LABEL(ret, lend);
8308  }
8309 
8310  if (popped) {
8311  ADD_INSN(ret, line, pop);
8312  }
8313  break;
8314  }
8315  case NODE_DOT2:
8316  case NODE_DOT3:{
8317  int excl = type == NODE_DOT3;
8318  VALUE flag = INT2FIX(excl);
8319  const NODE *b = node->nd_beg;
8320  const NODE *e = node->nd_end;
8321  if (number_literal_p(b) && number_literal_p(e)) {
8322  if (!popped) {
8323  VALUE val = rb_range_new(b->nd_lit, e->nd_lit, excl);
8324  ADD_INSN1(ret, line, putobject, val);
8325  RB_OBJ_WRITTEN(iseq, Qundef, val);
8326  }
8327  }
8328  else {
8329  CHECK(COMPILE_(ret, "min", b, popped));
8330  CHECK(COMPILE_(ret, "max", e, popped));
8331  if (!popped) {
8332  ADD_INSN1(ret, line, newrange, flag);
8333  }
8334  }
8335  break;
8336  }
8337  case NODE_FLIP2:
8338  case NODE_FLIP3:{
8339  LABEL *lend = NEW_LABEL(line);
8340  LABEL *ltrue = NEW_LABEL(line);
8341  LABEL *lfalse = NEW_LABEL(line);
8342  CHECK(compile_flip_flop(iseq, ret, node, type == NODE_FLIP2,
8343  ltrue, lfalse));
8344  ADD_LABEL(ret, ltrue);
8345  ADD_INSN1(ret, line, putobject, Qtrue);
8346  ADD_INSNL(ret, line, jump, lend);
8347  ADD_LABEL(ret, lfalse);
8348  ADD_INSN1(ret, line, putobject, Qfalse);
8349  ADD_LABEL(ret, lend);
8350  break;
8351  }
8352  case NODE_SELF:{
8353  if (!popped) {
8354  ADD_INSN(ret, line, putself);
8355  }
8356  break;
8357  }
8358  case NODE_NIL:{
8359  if (!popped) {
8360  ADD_INSN(ret, line, putnil);
8361  }
8362  break;
8363  }
8364  case NODE_TRUE:{
8365  if (!popped) {
8366  ADD_INSN1(ret, line, putobject, Qtrue);
8367  }
8368  break;
8369  }
8370  case NODE_FALSE:{
8371  if (!popped) {
8372  ADD_INSN1(ret, line, putobject, Qfalse);
8373  }
8374  break;
8375  }
8376  case NODE_ERRINFO:{
8377  if (!popped) {
8378  if (body->type == ISEQ_TYPE_RESCUE) {
8379  ADD_GETLOCAL(ret, line, LVAR_ERRINFO, 0);
8380  }
8381  else {
8382  const rb_iseq_t *ip = iseq;
8383  int level = 0;
8384  while (ip) {
8385  if (ip->body->type == ISEQ_TYPE_RESCUE) {
8386  break;
8387  }
8388  ip = ip->body->parent_iseq;
8389  level++;
8390  }
8391  if (ip) {
8392  ADD_GETLOCAL(ret, line, LVAR_ERRINFO, level);
8393  }
8394  else {
8395  ADD_INSN(ret, line, putnil);
8396  }
8397  }
8398  }
8399  break;
8400  }
8401  case NODE_DEFINED:
8402  if (!popped) {
8403  CHECK(compile_defined_expr(iseq, ret, node, Qtrue));
8404  }
8405  break;
8406  case NODE_POSTEXE:{
8407  /* compiled to:
8408  * ONCE{ rb_mRubyVMFrozenCore::core#set_postexe{ ... } }
8409  */
8410  int is_index = body->is_size++;
8412  rb_iseq_new_with_callback_new_callback(build_postexe_iseq, node->nd_body);
8413  const rb_iseq_t *once_iseq =
8414  new_child_iseq_with_callback(iseq, ifunc,
8415  rb_fstring(make_name_for_block(iseq)), iseq, ISEQ_TYPE_BLOCK, line);
8416 
8417  ADD_INSN2(ret, line, once, once_iseq, INT2FIX(is_index));
8418  RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)once_iseq);
8419 
8420  if (popped) {
8421  ADD_INSN(ret, line, pop);
8422  }
8423  break;
8424  }
8425  case NODE_KW_ARG:
8426  {
8427  LABEL *end_label = NEW_LABEL(nd_line(node));
8428  const NODE *default_value = node->nd_body->nd_value;
8429 
8430  if (default_value == NODE_SPECIAL_REQUIRED_KEYWORD) {
8431  /* required argument. do nothing */
8432  COMPILE_ERROR(ERROR_ARGS "unreachable");
8433  goto ng;
8434  }
8435  else if (nd_type(default_value) == NODE_LIT ||
8436  nd_type(default_value) == NODE_NIL ||
8437  nd_type(default_value) == NODE_TRUE ||
8438  nd_type(default_value) == NODE_FALSE) {
8439  COMPILE_ERROR(ERROR_ARGS "unreachable");
8440  goto ng;
8441  }
8442  else {
8443  /* if keywordcheck(_kw_bits, nth_keyword)
8444  * kw = default_value
8445  * end
8446  */
8447  int kw_bits_idx = body->local_table_size - body->param.keyword->bits_start;
8448  int keyword_idx = body->param.keyword->num;
8449 
8450  ADD_INSN2(ret, line, checkkeyword, INT2FIX(kw_bits_idx + VM_ENV_DATA_SIZE - 1), INT2FIX(keyword_idx));
8451  ADD_INSNL(ret, line, branchif, end_label);
8452  CHECK(COMPILE_POPPED(ret, "keyword default argument", node->nd_body));
8453  ADD_LABEL(ret, end_label);
8454  }
8455 
8456  break;
8457  }
8458  case NODE_DSYM:{
8459  compile_dstr(iseq, ret, node);
8460  if (!popped) {
8461  ADD_INSN(ret, line, intern);
8462  }
8463  else {
8464  ADD_INSN(ret, line, pop);
8465  }
8466  break;
8467  }
8468  case NODE_ATTRASGN:{
8469  DECL_ANCHOR(recv);
8470  DECL_ANCHOR(args);
8471  unsigned int flag = 0;
8472  ID mid = node->nd_mid;
8473  VALUE argc;
8474  LABEL *else_label = NULL;
8475  VALUE branches = Qfalse;
8476 
8477  /* optimization shortcut
8478  * obj["literal"] = value -> opt_aset_with(obj, "literal", value)
8479  */
8480  if (mid == idASET && !private_recv_p(node) && node->nd_args &&
8481  nd_type(node->nd_args) == NODE_LIST && node->nd_args->nd_alen == 2 &&
8482  nd_type(node->nd_args->nd_head) == NODE_STR &&
8483  ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
8484  !ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal &&
8485  ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction)
8486  {
8487  VALUE str = rb_fstring(node->nd_args->nd_head->nd_lit);
8488  CHECK(COMPILE(ret, "recv", node->nd_recv));
8489  CHECK(COMPILE(ret, "value", node->nd_args->nd_next->nd_head));
8490  if (!popped) {
8491  ADD_INSN(ret, line, swap);
8492  ADD_INSN1(ret, line, topn, INT2FIX(1));
8493  }
8494  ADD_INSN2(ret, line, opt_aset_with, str,
8495  new_callinfo(iseq, idASET, 2, 0, NULL, FALSE));
8497  ADD_INSN(ret, line, pop);
8498  break;
8499  }
8500 
8501  INIT_ANCHOR(recv);
8502  INIT_ANCHOR(args);
8503  argc = setup_args(iseq, args, node->nd_args, &flag, NULL);
8504  CHECK(!NIL_P(argc));
8505 
8506  int asgnflag = COMPILE_RECV(recv, "recv", node);
8507  CHECK(asgnflag != -1);
8508  flag |= (unsigned int)asgnflag;
8509 
8510  debugp_param("argc", argc);
8511  debugp_param("nd_mid", ID2SYM(mid));
8512 
8513  if (!rb_is_attrset_id(mid)) {
8514  /* safe nav attr */
8515  mid = rb_id_attrset(mid);
8516  else_label = qcall_branch_start(iseq, recv, &branches, node, line);
8517  }
8518  if (!popped) {
8519  ADD_INSN(ret, line, putnil);
8520  ADD_SEQ(ret, recv);
8521  ADD_SEQ(ret, args);
8522 
8523  if (flag & VM_CALL_ARGS_BLOCKARG) {
8524  ADD_INSN1(ret, line, topn, INT2FIX(1));
8525  if (flag & VM_CALL_ARGS_SPLAT) {
8526  ADD_INSN1(ret, line, putobject, INT2FIX(-1));
8527  ADD_SEND_WITH_FLAG(ret, line, idAREF, INT2FIX(1), INT2FIX(asgnflag));
8528  }
8529  ADD_INSN1(ret, line, setn, FIXNUM_INC(argc, 3));
8530  ADD_INSN (ret, line, pop);
8531  }
8532  else if (flag & VM_CALL_ARGS_SPLAT) {
8533  ADD_INSN(ret, line, dup);
8534  ADD_INSN1(ret, line, putobject, INT2FIX(-1));
8535  ADD_SEND_WITH_FLAG(ret, line, idAREF, INT2FIX(1), INT2FIX(asgnflag));
8536  ADD_INSN1(ret, line, setn, FIXNUM_INC(argc, 2));
8537  ADD_INSN (ret, line, pop);
8538  }
8539  else {
8540  ADD_INSN1(ret, line, setn, FIXNUM_INC(argc, 1));
8541  }
8542  }
8543  else {
8544  ADD_SEQ(ret, recv);
8545  ADD_SEQ(ret, args);
8546  }
8547  ADD_SEND_WITH_FLAG(ret, line, mid, argc, INT2FIX(flag));
8548  qcall_branch_end(iseq, ret, else_label, branches, node, line);
8549  ADD_INSN(ret, line, pop);
8550 
8551  break;
8552  }
8553  case NODE_LAMBDA:{
8554  /* compile same as lambda{...} */
8555  const rb_iseq_t *block = NEW_CHILD_ISEQ(node->nd_body, make_name_for_block(iseq), ISEQ_TYPE_BLOCK, line);
8556  VALUE argc = INT2FIX(0);
8557 
8558  ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8559  ADD_CALL_WITH_BLOCK(ret, line, idLambda, argc, block);
8560  RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block);
8561 
8562  if (popped) {
8563  ADD_INSN(ret, line, pop);
8564  }
8565  break;
8566  }
8567  default:
8568  UNKNOWN_NODE("iseq_compile_each", node, COMPILE_NG);
8569  ng:
8570  debug_node_end();
8571  return COMPILE_NG;
8572  }
8573 
8574  debug_node_end();
8575  return COMPILE_OK;
8576 }
8577 
8578 /***************************/
8579 /* instruction information */
8580 /***************************/
8581 
8582 static int
8583 insn_data_length(INSN *iobj)
8584 {
8585  return insn_len(iobj->insn_id);
8586 }
8587 
8588 static int
8589 calc_sp_depth(int depth, INSN *insn)
8590 {
8591  return comptime_insn_stack_increase(depth, insn->insn_id, insn->operands);
8592 }
8593 
8594 static VALUE
8595 opobj_inspect(VALUE obj)
8596 {
8597  struct RBasic *r = (struct RBasic *) obj;
8598  if (!SPECIAL_CONST_P(r) && r->klass == 0) {
8599  switch (BUILTIN_TYPE(r)) {
8600  case T_STRING:
8602  break;
8603  case T_ARRAY:
8604  obj = rb_ary_dup(obj);
8605  break;
8606  }
8607  }
8608  return rb_inspect(obj);
8609 }
8610 
8611 
8612 
8613 static VALUE
8614 insn_data_to_s_detail(INSN *iobj)
8615 {
8616  VALUE str = rb_sprintf("%-20s ", insn_name(iobj->insn_id));
8617 
8618  if (iobj->operands) {
8619  const char *types = insn_op_types(iobj->insn_id);
8620  int j;
8621 
8622  for (j = 0; types[j]; j++) {
8623  char type = types[j];
8624 
8625  switch (type) {
8626  case TS_OFFSET: /* label(destination position) */
8627  {
8628  LABEL *lobj = (LABEL *)OPERAND_AT(iobj, j);
8630  break;
8631  }
8632  break;
8633  case TS_ISEQ: /* iseq */
8634  {
8635  rb_iseq_t *iseq = (rb_iseq_t *)OPERAND_AT(iobj, j);
8636  VALUE val = Qnil;
8637  if (0 && iseq) { /* TODO: invalidate now */
8638  val = (VALUE)iseq;
8639  }
8640  rb_str_concat(str, opobj_inspect(val));
8641  }
8642  break;
8643  case TS_LINDEX:
8644  case TS_NUM: /* ulong */
8645  case TS_VALUE: /* VALUE */
8646  {
8647  VALUE v = OPERAND_AT(iobj, j);
8648  rb_str_concat(str, opobj_inspect(v));
8649  break;
8650  }
8651  case TS_ID: /* ID */
8652  rb_str_concat(str, opobj_inspect(OPERAND_AT(iobj, j)));
8653  break;
8654  case TS_GENTRY:
8655  {
8656  struct rb_global_entry *entry = (struct rb_global_entry *)
8657  (OPERAND_AT(iobj, j) & (~1));
8658  rb_str_append(str, rb_id2str(entry->id));
8659  break;
8660  }
8661  case TS_IC: /* inline cache */
8662  case TS_IVC: /* inline ivar cache */
8663  case TS_ISE: /* inline storage entry */
8664  rb_str_catf(str, "<ic:%d>", FIX2INT(OPERAND_AT(iobj, j)));
8665  break;
8666  case TS_CALLDATA: /* we store these as call infos at compile time */
8667  {
8668  const struct rb_call_info *ci = (struct rb_call_info *)OPERAND_AT(iobj, j);
8669  rb_str_cat2(str, "<calldata:");
8670  if (ci->mid) rb_str_catf(str, "%"PRIsVALUE, rb_id2str(ci->mid));
8671  rb_str_catf(str, ", %d>", ci->orig_argc);
8672  break;
8673  }
8674  case TS_CDHASH: /* case/when condition cache */
8675  rb_str_cat2(str, "<ch>");
8676  break;
8677  case TS_FUNCPTR:
8678  {
8679  void *func = (void *)OPERAND_AT(iobj, j);
8680 #ifdef HAVE_DLADDR
8681  Dl_info info;
8682  if (dladdr(func, &info) && info.dli_sname) {
8683  rb_str_cat2(str, info.dli_sname);
8684  break;
8685  }
8686 #endif
8687  rb_str_catf(str, "<%p>", func);
8688  }
8689  break;
8690  case TS_BUILTIN:
8691  rb_bug("unsupported: TS_BUILTIN");
8692  break;
8693  default:{
8694  rb_raise(rb_eSyntaxError, "unknown operand type: %c", type);
8695  }
8696  }
8697  if (types[j + 1]) {
8698  rb_str_cat2(str, ", ");
8699  }
8700  }
8701  }
8702  return str;
8703 }
8704 
8705 static void
8706 dump_disasm_list(const LINK_ELEMENT *link)
8707 {
8708  dump_disasm_list_with_cursor(link, NULL, NULL);
8709 }
8710 
8711 static void
8712 dump_disasm_list_with_cursor(const LINK_ELEMENT *link, const LINK_ELEMENT *curr, const LABEL *dest)
8713 {
8714  int pos = 0;
8715  INSN *iobj;
8716  LABEL *lobj;
8717  VALUE str;
8718 
8719  printf("-- raw disasm--------\n");
8720 
8721  while (link) {
8722  if (curr) printf(curr == link ? "*" : " ");
8723  switch (link->type) {
8724  case ISEQ_ELEMENT_INSN:
8725  {
8726  iobj = (INSN *)link;
8727  str = insn_data_to_s_detail(iobj);
8728  printf("%04d %-65s(%4u)\n", pos, StringValueCStr(str), iobj->insn_info.line_no);
8729  pos += insn_data_length(iobj);
8730  break;
8731  }
8732  case ISEQ_ELEMENT_LABEL:
8733  {
8734  lobj = (LABEL *)link;
8735  printf(LABEL_FORMAT" [sp: %d]%s\n", lobj->label_no, lobj->sp,
8736  dest == lobj ? " <---" : "");
8737  break;
8738  }
8739  case ISEQ_ELEMENT_TRACE:
8740  {
8741  TRACE *trace = (TRACE *)link;
8742  printf("trace: %0x\n", trace->event);
8743  break;
8744  }
8745  case ISEQ_ELEMENT_ADJUST:
8746  {
8747  ADJUST *adjust = (ADJUST *)link;
8748  printf("adjust: [label: %d]\n", adjust->label ? adjust->label->label_no : -1);
8749  break;
8750  }
8751  default:
8752  /* ignore */
8753  rb_raise(rb_eSyntaxError, "dump_disasm_list error: %ld\n", FIX2LONG(link->type));
8754  }
8755  link = link->next;
8756  }
8757  printf("---------------------\n");
8758  fflush(stdout);
8759 }
8760 
8761 const char *
8763 {
8764  return insn_name(i);
8765 }
8766 
8767 VALUE
8769 {
8771  int i;
8772  for (i = 0; i < VM_INSTRUCTION_SIZE; i++) {
8773  rb_ary_push(ary, rb_fstring_cstr(insn_name(i)));
8774  }
8775  return rb_obj_freeze(ary);
8776 }
8777 
8778 static LABEL *
8779 register_label(rb_iseq_t *iseq, struct st_table *labels_table, VALUE obj)
8780 {
8781  LABEL *label = 0;
8782  st_data_t tmp;
8784 
8785  if (st_lookup(labels_table, obj, &tmp) == 0) {
8786  label = NEW_LABEL(0);
8787  st_insert(labels_table, obj, (st_data_t)label);
8788  }
8789  else {
8790  label = (LABEL *)tmp;
8791  }
8792  LABEL_REF(label);
8793  return label;
8794 }
8795 
8796 static VALUE
8797 get_exception_sym2type(VALUE sym)
8798 {
8799 #undef rb_intern
8800 #define rb_intern(str) rb_intern_const(str)
8801  static VALUE symRescue, symEnsure, symRetry;
8802  static VALUE symBreak, symRedo, symNext;
8803 
8804  if (symRescue == 0) {
8805  symRescue = ID2SYM(rb_intern("rescue"));
8806  symEnsure = ID2SYM(rb_intern("ensure"));
8807  symRetry = ID2SYM(rb_intern("retry"));
8808  symBreak = ID2SYM(rb_intern("break"));
8809  symRedo = ID2SYM(rb_intern("redo"));
8810  symNext = ID2SYM(rb_intern("next"));
8811  }
8812 
8813  if (sym == symRescue) return CATCH_TYPE_RESCUE;
8814  if (sym == symEnsure) return CATCH_TYPE_ENSURE;
8815  if (sym == symRetry) return CATCH_TYPE_RETRY;
8816  if (sym == symBreak) return CATCH_TYPE_BREAK;
8817  if (sym == symRedo) return CATCH_TYPE_REDO;
8818  if (sym == symNext) return CATCH_TYPE_NEXT;
8819  rb_raise(rb_eSyntaxError, "invalid exception symbol: %+"PRIsVALUE, sym);
8820  return 0;
8821 }
8822 
8823 static int
8824 iseq_build_from_ary_exception(rb_iseq_t *iseq, struct st_table *labels_table,
8825  VALUE exception)
8826 {
8827  int i;
8828 
8829  for (i=0; i<RARRAY_LEN(exception); i++) {
8830  const rb_iseq_t *eiseq;
8831  VALUE v, type;
8832  LABEL *lstart, *lend, *lcont;
8833  unsigned int sp;
8834 
8835  v = rb_to_array_type(RARRAY_AREF(exception, i));
8836  if (RARRAY_LEN(v) != 6) {
8837  rb_raise(rb_eSyntaxError, "wrong exception entry");
8838  }
8839  type = get_exception_sym2type(RARRAY_AREF(v, 0));
8840  if (RARRAY_AREF(v, 1) == Qnil) {
8841  eiseq = NULL;
8842  }
8843  else {
8845  }
8846 
8847  lstart = register_label(iseq, labels_table, RARRAY_AREF(v, 2));
8848  lend = register_label(iseq, labels_table, RARRAY_AREF(v, 3));
8849  lcont = register_label(iseq, labels_table, RARRAY_AREF(v, 4));
8850  sp = NUM2UINT(RARRAY_AREF(v, 5));
8851 
8852  /* TODO: Dirty Hack! Fix me */
8853  if (type == CATCH_TYPE_RESCUE ||
8854  type == CATCH_TYPE_BREAK ||
8855  type == CATCH_TYPE_NEXT) {
8856  ++sp;
8857  }
8858 
8859  lcont->sp = sp;
8860 
8861  ADD_CATCH_ENTRY(type, lstart, lend, eiseq, lcont);
8862 
8863  RB_GC_GUARD(v);
8864  }
8865  return COMPILE_OK;
8866 }
8867 
8868 static struct st_table *
8869 insn_make_insn_table(void)
8870 {
8871  struct st_table *table;
8872  int i;
8874 
8875  for (i=0; i<VM_INSTRUCTION_SIZE; i++) {
8876  st_insert(table, ID2SYM(rb_intern(insn_name(i))), i);
8877  }
8878 
8879  return table;
8880 }
8881 
8882 static const rb_iseq_t *
8883 iseq_build_load_iseq(const rb_iseq_t *iseq, VALUE op)
8884 {
8885  VALUE iseqw;
8886  const rb_iseq_t *loaded_iseq;
8887 
8888  if (RB_TYPE_P(op, T_ARRAY)) {
8889  iseqw = rb_iseq_load(op, (VALUE)iseq, Qnil);
8890  }
8891  else if (CLASS_OF(op) == rb_cISeq) {
8892  iseqw = op;
8893  }
8894  else {
8895  rb_raise(rb_eSyntaxError, "ISEQ is required");
8896  }
8897 
8898  loaded_iseq = rb_iseqw_to_iseq(iseqw);
8899  return loaded_iseq;
8900 }
8901 
8902 static VALUE
8903 iseq_build_callinfo_from_hash(rb_iseq_t *iseq, VALUE op)
8904 {
8905  ID mid = 0;
8906  int orig_argc = 0;
8907  unsigned int flag = 0;
8908  struct rb_call_info_kw_arg *kw_arg = 0;
8909 
8910  if (!NIL_P(op)) {
8911  VALUE vmid = rb_hash_aref(op, ID2SYM(rb_intern("mid")));
8912  VALUE vflag = rb_hash_aref(op, ID2SYM(rb_intern("flag")));
8913  VALUE vorig_argc = rb_hash_aref(op, ID2SYM(rb_intern("orig_argc")));
8914  VALUE vkw_arg = rb_hash_aref(op, ID2SYM(rb_intern("kw_arg")));
8915 
8916  if (!NIL_P(vmid)) mid = SYM2ID(vmid);
8917  if (!NIL_P(vflag)) flag = NUM2UINT(vflag);
8918  if (!NIL_P(vorig_argc)) orig_argc = FIX2INT(vorig_argc);
8919 
8920  if (!NIL_P(vkw_arg)) {
8921  int i;
8922  int len = RARRAY_LENINT(vkw_arg);
8923  size_t n = rb_call_info_kw_arg_bytes(len);
8924 
8925  kw_arg = xmalloc(n);
8926  kw_arg->keyword_len = len;
8927  for (i = 0; i < len; i++) {
8928  VALUE kw = RARRAY_AREF(vkw_arg, i);
8929  SYM2ID(kw); /* make immortal */
8930  kw_arg->keywords[i] = kw;
8931  }
8932  }
8933  }
8934 
8935  return (VALUE)new_callinfo(iseq, mid, orig_argc, flag, kw_arg, (flag & VM_CALL_ARGS_SIMPLE) == 0);
8936 }
8937 
8938 static rb_event_flag_t
8939 event_name_to_flag(VALUE sym)
8940 {
8941 #define CHECK_EVENT(ev) if (sym == ID2SYM(rb_intern(#ev))) return ev;
8949 #undef CHECK_EVENT
8950  return RUBY_EVENT_NONE;
8951 }
8952 
8953 static int
8954 iseq_build_from_ary_body(rb_iseq_t *iseq, LINK_ANCHOR *const anchor,
8955  VALUE body, VALUE labels_wrapper)
8956 {
8957  /* TODO: body should be frozen */
8958  long i, len = RARRAY_LEN(body);
8959  struct st_table *labels_table = DATA_PTR(labels_wrapper);
8960  int j;
8961  int line_no = 0;
8962  int ret = COMPILE_OK;
8963 
8964  /*
8965  * index -> LABEL *label
8966  */
8967  static struct st_table *insn_table;
8968 
8969  if (insn_table == 0) {
8970  insn_table = insn_make_insn_table();
8971  }
8972 
8973  for (i=0; i<len; i++) {
8974  VALUE obj = RARRAY_AREF(body, i);
8975 
8976  if (SYMBOL_P(obj)) {
8977  rb_event_flag_t event;
8978  if ((event = event_name_to_flag(obj)) != RUBY_EVENT_NONE) {
8979  ADD_TRACE(anchor, event);
8980  }
8981  else {
8982  LABEL *label = register_label(iseq, labels_table, obj);
8983  ADD_LABEL(anchor, label);
8984  }
8985  }
8986  else if (FIXNUM_P(obj)) {
8987  line_no = NUM2INT(obj);
8988  }
8989  else if (RB_TYPE_P(obj, T_ARRAY)) {
8990  VALUE *argv = 0;
8991  int argc = RARRAY_LENINT(obj) - 1;
8992  st_data_t insn_id;
8993  VALUE insn;
8994 
8995  insn = (argc < 0) ? Qnil : RARRAY_AREF(obj, 0);
8996  if (st_lookup(insn_table, (st_data_t)insn, &insn_id) == 0) {
8997  /* TODO: exception */
8998  COMPILE_ERROR(iseq, line_no,
8999  "unknown instruction: %+"PRIsVALUE, insn);
9000  ret = COMPILE_NG;
9001  break;
9002  }
9003 
9004  if (argc != insn_len((VALUE)insn_id)-1) {
9005  COMPILE_ERROR(iseq, line_no,
9006  "operand size mismatch");
9007  ret = COMPILE_NG;
9008  break;
9009  }
9010 
9011  if (argc > 0) {
9012  argv = compile_data_alloc2(iseq, sizeof(VALUE), argc);
9013  for (j=0; j<argc; j++) {
9014  VALUE op = rb_ary_entry(obj, j+1);
9015  switch (insn_op_type((VALUE)insn_id, j)) {
9016  case TS_OFFSET: {
9017  LABEL *label = register_label(iseq, labels_table, op);
9018  argv[j] = (VALUE)label;
9019  break;
9020  }
9021  case TS_LINDEX:
9022  case TS_NUM:
9023  (void)NUM2INT(op);
9024  argv[j] = op;
9025  break;
9026  case TS_VALUE:
9027  argv[j] = op;
9028  RB_OBJ_WRITTEN(iseq, Qundef, op);
9029  break;
9030  case TS_ISEQ:
9031  {
9032  if (op != Qnil) {
9033  VALUE v = (VALUE)iseq_build_load_iseq(iseq, op);
9034  argv[j] = v;
9036  }
9037  else {
9038  argv[j] = 0;
9039  }
9040  }
9041  break;
9042  case TS_GENTRY:
9043  op = rb_to_symbol_type(op);
9044  argv[j] = (VALUE)rb_global_entry(SYM2ID(op));
9045  break;
9046  case TS_ISE:
9048  /* fall through */
9049  case TS_IC:
9050  case TS_IVC: /* inline ivar cache */
9051  argv[j] = op;
9052  if (NUM2UINT(op) >= iseq->body->is_size) {
9053  iseq->body->is_size = NUM2INT(op) + 1;
9054  }
9055  break;
9056  case TS_CALLDATA:
9057  argv[j] = iseq_build_callinfo_from_hash(iseq, op);
9058  break;
9059  case TS_ID:
9060  argv[j] = rb_to_symbol_type(op);
9061  break;
9062  case TS_CDHASH:
9063  {
9064  int i;
9065  VALUE map = rb_hash_new_with_size(RARRAY_LEN(op)/2);
9066 
9067  RHASH_TBL_RAW(map)->type = &cdhash_type;
9068  op = rb_to_array_type(op);
9069  for (i=0; i<RARRAY_LEN(op); i+=2) {
9070  VALUE key = RARRAY_AREF(op, i);
9071  VALUE sym = RARRAY_AREF(op, i+1);
9072  LABEL *label =
9073  register_label(iseq, labels_table, sym);
9074  rb_hash_aset(map, key, (VALUE)label | 1);
9075  }
9076  RB_GC_GUARD(op);
9077  argv[j] = map;
9078  RB_OBJ_WRITTEN(iseq, Qundef, map);
9079  }
9080  break;
9081  case TS_FUNCPTR:
9082  {
9083 #if SIZEOF_VALUE <= SIZEOF_LONG
9084  long funcptr = NUM2LONG(op);
9085 #else
9086  LONG_LONG funcptr = NUM2LL(op);
9087 #endif
9088  argv[j] = (VALUE)funcptr;
9089  }
9090  break;
9091  default:
9092  rb_raise(rb_eSyntaxError, "unknown operand: %c", insn_op_type((VALUE)insn_id, j));
9093  }
9094  }
9095  }
9096  ADD_ELEM(anchor,
9097  (LINK_ELEMENT*)new_insn_core(iseq, line_no,
9098  (enum ruby_vminsn_type)insn_id, argc, argv));
9099  }
9100  else {
9101  rb_raise(rb_eTypeError, "unexpected object for instruction");
9102  }
9103  }
9104  DATA_PTR(labels_wrapper) = 0;
9105  validate_labels(iseq, labels_table);
9106  if (!ret) return ret;
9107  return iseq_setup(iseq, anchor);
9108 }
9109 
9110 #define CHECK_ARRAY(v) rb_to_array_type(v)
9111 #define CHECK_SYMBOL(v) rb_to_symbol_type(v)
9112 
9113 static int
9114 int_param(int *dst, VALUE param, VALUE sym)
9115 {
9116  VALUE val = rb_hash_aref(param, sym);
9117  if (FIXNUM_P(val)) {
9118  *dst = FIX2INT(val);
9119  return TRUE;
9120  }
9121  else if (!NIL_P(val)) {
9122  rb_raise(rb_eTypeError, "invalid %+"PRIsVALUE" Fixnum: %+"PRIsVALUE,
9123  sym, val);
9124  }
9125  return FALSE;
9126 }
9127 
9128 static const struct rb_iseq_param_keyword *
9129 iseq_build_kw(rb_iseq_t *iseq, VALUE params, VALUE keywords)
9130 {
9131  int i, j;
9132  int len = RARRAY_LENINT(keywords);
9133  int default_len;
9134  VALUE key, sym, default_val;
9135  VALUE *dvs;
9136  ID *ids;
9137  struct rb_iseq_param_keyword *keyword = ZALLOC(struct rb_iseq_param_keyword);
9138 
9139  iseq->body->param.flags.has_kw = TRUE;
9140 
9141  keyword->num = len;
9142 #define SYM(s) ID2SYM(rb_intern(#s))
9143  (void)int_param(&keyword->bits_start, params, SYM(kwbits));
9144  i = keyword->bits_start - keyword->num;
9145  ids = (ID *)&iseq->body->local_table[i];
9146 #undef SYM
9147 
9148  /* required args */
9149  for (i = 0; i < len; i++) {
9150  VALUE val = RARRAY_AREF(keywords, i);
9151 
9152  if (!SYMBOL_P(val)) {
9153  goto default_values;
9154  }
9155  ids[i] = SYM2ID(val);
9156  keyword->required_num++;
9157  }
9158 
9159  default_values: /* note: we intentionally preserve `i' from previous loop */
9160  default_len = len - i;
9161  if (default_len == 0) {
9162  keyword->table = ids;
9163  return keyword;
9164  }
9165  else if (default_len < 0) {
9166  UNREACHABLE;
9167  }
9168 
9169  dvs = ALLOC_N(VALUE, (unsigned int)default_len);
9170 
9171  for (j = 0; i < len; i++, j++) {
9172  key = RARRAY_AREF(keywords, i);
9173  CHECK_ARRAY(key);
9174 
9175  switch (RARRAY_LEN(key)) {
9176  case 1:
9177  sym = RARRAY_AREF(key, 0);
9178  default_val = Qundef;
9179  break;
9180  case 2:
9181  sym = RARRAY_AREF(key, 0);
9182  default_val = RARRAY_AREF(key, 1);
9183  break;
9184  default:
9185  rb_raise(rb_eTypeError, "keyword default has unsupported len %+"PRIsVALUE, key);
9186  }
9187  ids[i] = SYM2ID(sym);
9188  dvs[j] = default_val;
9189  }
9190 
9191  keyword->table = ids;
9192  keyword->default_values = dvs;
9193 
9194  return keyword;
9195 }
9196 
9197 void
9199 {
9200  INSN *iobj = 0;
9201  size_t size = sizeof(INSN);
9202  unsigned int pos = 0;
9203 
9204  while (storage) {
9205 #ifdef STRICT_ALIGNMENT
9206  size_t padding = calc_padding((void *)&storage->buff[pos], size);
9207 #else
9208  const size_t padding = 0; /* expected to be optimized by compiler */
9209 #endif /* STRICT_ALIGNMENT */
9210  size_t offset = pos + size + padding;
9211  if (offset > storage->size || offset > storage->pos) {
9212  pos = 0;
9213  storage = storage->next;
9214  }
9215  else {
9216 #ifdef STRICT_ALIGNMENT
9217  pos += (int)padding;
9218 #endif /* STRICT_ALIGNMENT */
9219 
9220  iobj = (INSN *)&storage->buff[pos];
9221 
9222  if (iobj->operands) {
9223  int j;
9224  const char *types = insn_op_types(iobj->insn_id);
9225 
9226  for (j = 0; types[j]; j++) {
9227  char type = types[j];
9228  switch (type) {
9229  case TS_CDHASH:
9230  case TS_ISEQ:
9231  case TS_VALUE:
9232  {
9233  VALUE op = OPERAND_AT(iobj, j);
9234  if (!SPECIAL_CONST_P(op)) {
9235  rb_gc_mark(op);
9236  }
9237  break;
9238  }
9239  default:
9240  break;
9241  }
9242  }
9243  }
9244  pos += (int)size;
9245  }
9246  }
9247 }
9248 
9249 void
9251  VALUE exception, VALUE body)
9252 {
9253 #define SYM(s) ID2SYM(rb_intern(#s))
9254  int i, len;
9255  unsigned int arg_size, local_size, stack_max;
9256  ID *tbl;
9257  struct st_table *labels_table = st_init_numtable();
9258  VALUE labels_wrapper = Data_Wrap_Struct(0, rb_mark_set, st_free_table, labels_table);
9259  VALUE arg_opt_labels = rb_hash_aref(params, SYM(opt));
9260  VALUE keywords = rb_hash_aref(params, SYM(keyword));
9261  VALUE sym_arg_rest = ID2SYM(rb_intern("#arg_rest"));
9262  DECL_ANCHOR(anchor);
9263  INIT_ANCHOR(anchor);
9264 
9265  len = RARRAY_LENINT(locals);
9267  iseq->body->local_table = tbl = len > 0 ? (ID *)ALLOC_N(ID, iseq->body->local_table_size) : NULL;
9268 
9269  for (i = 0; i < len; i++) {
9270  VALUE lv = RARRAY_AREF(locals, i);
9271 
9272  if (sym_arg_rest == lv) {
9273  tbl[i] = 0;
9274  }
9275  else {
9276  tbl[i] = FIXNUM_P(lv) ? (ID)FIX2LONG(lv) : SYM2ID(CHECK_SYMBOL(lv));
9277  }
9278  }
9279 
9280 #define INT_PARAM(F) int_param(&iseq->body->param.F, params, SYM(F))
9281  if (INT_PARAM(lead_num)) {
9282  iseq->body->param.flags.has_lead = TRUE;
9283  }
9284  if (INT_PARAM(post_num)) iseq->body->param.flags.has_post = TRUE;
9285  if (INT_PARAM(post_start)) iseq->body->param.flags.has_post = TRUE;
9286  if (INT_PARAM(rest_start)) iseq->body->param.flags.has_rest = TRUE;
9287  if (INT_PARAM(block_start)) iseq->body->param.flags.has_block = TRUE;
9288 #undef INT_PARAM
9289  {
9290 #define INT_PARAM(F) F = (int_param(&x, misc, SYM(F)) ? (unsigned int)x : 0)
9291  int x;
9292  INT_PARAM(arg_size);
9294  INT_PARAM(stack_max);
9295 #undef INT_PARAM
9296  }
9297 
9298  if (RB_TYPE_P(arg_opt_labels, T_ARRAY)) {
9299  len = RARRAY_LENINT(arg_opt_labels);
9300  iseq->body->param.flags.has_opt = !!(len - 1 >= 0);
9301 
9302  if (iseq->body->param.flags.has_opt) {
9303  VALUE *opt_table = ALLOC_N(VALUE, len);
9304 
9305  for (i = 0; i < len; i++) {
9306  VALUE ent = RARRAY_AREF(arg_opt_labels, i);
9307  LABEL *label = register_label(iseq, labels_table, ent);
9308  opt_table[i] = (VALUE)label;
9309  }
9310 
9311  iseq->body->param.opt_num = len - 1;
9312  iseq->body->param.opt_table = opt_table;
9313  }
9314  }
9315  else if (!NIL_P(arg_opt_labels)) {
9316  rb_raise(rb_eTypeError, ":opt param is not an array: %+"PRIsVALUE,
9317  arg_opt_labels);
9318  }
9319 
9320  if (RB_TYPE_P(keywords, T_ARRAY)) {
9321  iseq->body->param.keyword = iseq_build_kw(iseq, params, keywords);
9322  }
9323  else if (!NIL_P(keywords)) {
9324  rb_raise(rb_eTypeError, ":keywords param is not an array: %+"PRIsVALUE,
9325  keywords);
9326  }
9327 
9328  if (Qtrue == rb_hash_aref(params, SYM(ambiguous_param0))) {
9329  iseq->body->param.flags.ambiguous_param0 = TRUE;
9330  }
9331 
9332  if (int_param(&i, params, SYM(kwrest))) {
9333  struct rb_iseq_param_keyword *keyword = (struct rb_iseq_param_keyword *)iseq->body->param.keyword;
9334  if (keyword == NULL) {
9335  iseq->body->param.keyword = keyword = ZALLOC(struct rb_iseq_param_keyword);
9336  }
9337  keyword->rest_start = i;
9338  iseq->body->param.flags.has_kwrest = TRUE;
9339  }
9340 #undef SYM
9341  iseq_calc_param_size(iseq);
9342 
9343  /* exception */
9344  iseq_build_from_ary_exception(iseq, labels_table, exception);
9345 
9346  /* body */
9347  iseq_build_from_ary_body(iseq, anchor, body, labels_wrapper);
9348 
9349  iseq->body->param.size = arg_size;
9351  iseq->body->stack_max = stack_max;
9352 }
9353 
9354 /* for parser */
9355 
9356 int
9358 {
9359  if (iseq) {
9360  const struct rb_iseq_constant_body *body = iseq->body;
9361  while (body->type == ISEQ_TYPE_BLOCK ||
9362  body->type == ISEQ_TYPE_RESCUE ||
9363  body->type == ISEQ_TYPE_ENSURE ||
9364  body->type == ISEQ_TYPE_EVAL ||
9365  body->type == ISEQ_TYPE_MAIN
9366  ) {
9367  unsigned int i;
9368 
9369  for (i = 0; i < body->local_table_size; i++) {
9370  if (body->local_table[i] == id) {
9371  return 1;
9372  }
9373  }
9374  iseq = body->parent_iseq;
9375  body = iseq->body;
9376  }
9377  }
9378  return 0;
9379 }
9380 
9381 int
9383 {
9384  if (iseq) {
9385  unsigned int i;
9386  const struct rb_iseq_constant_body *const body = iseq->body->local_iseq->body;
9387 
9388  for (i=0; i<body->local_table_size; i++) {
9389  if (body->local_table[i] == id) {
9390  return 1;
9391  }
9392  }
9393  }
9394  return 0;
9395 }
9396 
9397 static int
9398 caller_location(VALUE *path, VALUE *realpath)
9399 {
9400  const rb_execution_context_t *ec = GET_EC();
9401  const rb_control_frame_t *const cfp =
9403 
9404  if (cfp) {
9405  int line = rb_vm_get_sourceline(cfp);
9406  *path = rb_iseq_path(cfp->iseq);
9408  return line;
9409  }
9410  else {
9411  *path = rb_fstring_lit("<compiled>");
9412  *realpath = *path;
9413  return 1;
9414  }
9415 }
9416 
9417 typedef struct {
9420  int line;
9421 } accessor_args;
9422 
9423 static const rb_iseq_t *
9424 method_for_self(VALUE name, VALUE arg, rb_insn_func_t func,
9425  void (*build)(rb_iseq_t *, LINK_ANCHOR *, const void *))
9426 {
9427  VALUE path, realpath;
9428  accessor_args acc;
9429 
9430  acc.arg = arg;
9431  acc.func = func;
9432  acc.line = caller_location(&path, &realpath);
9434  rb_iseq_new_with_callback_new_callback(build, &acc);
9435  return rb_iseq_new_with_callback(ifunc,
9437  INT2FIX(acc.line), 0, ISEQ_TYPE_METHOD, 0);
9438 }
9439 
9440 static void
9441 for_self_aref(rb_iseq_t *iseq, LINK_ANCHOR *ret, const void *a)
9442 {
9443  const accessor_args *const args = (void *)a;
9444  const int line = args->line;
9445  struct rb_iseq_constant_body *const body = iseq->body;
9446 
9447  iseq_set_local_table(iseq, 0);
9448  body->param.lead_num = 0;
9449  body->param.size = 0;
9450 
9451  ADD_INSN1(ret, line, putobject, args->arg);
9452  ADD_INSN1(ret, line, opt_call_c_function, (VALUE)args->func);
9453 }
9454 
9455 static void
9456 for_self_aset(rb_iseq_t *iseq, LINK_ANCHOR *ret, const void *a)
9457 {
9458  const accessor_args *const args = (void *)a;
9459  const int line = args->line;
9460  struct rb_iseq_constant_body *const body = iseq->body;
9461  static const ID vars[] = {1, idUScore};
9462 
9463  iseq_set_local_table(iseq, vars);
9464  body->param.lead_num = 1;
9465  body->param.size = 1;
9466 
9467  ADD_GETLOCAL(ret, line, numberof(vars)-1, 0);
9468  ADD_INSN1(ret, line, putobject, args->arg);
9469  ADD_INSN1(ret, line, opt_call_c_function, (VALUE)args->func);
9470  ADD_INSN(ret, line, pop);
9471 }
9472 
9473 /*
9474  * func (index) -> (value)
9475  */
9476 const rb_iseq_t *
9478 {
9479  return method_for_self(name, arg, func, for_self_aref);
9480 }
9481 
9482 /*
9483  * func (index, value) -> (index, value)
9484  */
9485 const rb_iseq_t *
9487 {
9488  return method_for_self(name, arg, func, for_self_aset);
9489 }
9490 
9491 /* ISeq binary format */
9492 
9493 #ifndef IBF_ISEQ_DEBUG
9494 #define IBF_ISEQ_DEBUG 0
9495 #endif
9496 
9497 #ifndef IBF_ISEQ_ENABLE_LOCAL_BUFFER
9498 #define IBF_ISEQ_ENABLE_LOCAL_BUFFER 0
9499 #endif
9500 
9501 typedef unsigned int ibf_offset_t;
9502 #define IBF_OFFSET(ptr) ((ibf_offset_t)(VALUE)(ptr))
9503 
9504 #define IBF_MAJOR_VERSION ISEQ_MAJOR_VERSION
9505 #if RUBY_DEVEL
9506 #define IBF_DEVEL_VERSION 2
9507 #define IBF_MINOR_VERSION (ISEQ_MINOR_VERSION * 10000 + IBF_DEVEL_VERSION)
9508 #else
9509 #define IBF_MINOR_VERSION ISEQ_MINOR_VERSION
9510 #endif
9511 
9512 struct ibf_header {
9513  char magic[4]; /* YARB */
9514  unsigned int major_version;
9515  unsigned int minor_version;
9516  unsigned int size;
9517  unsigned int extra_size;
9518 
9519  unsigned int iseq_list_size;
9523 };
9524 
9527  VALUE obj_list; /* [objs] */
9528 };
9529 
9530 struct ibf_dump {
9531  VALUE iseq_list; /* [iseqs] */
9532  st_table *iseq_table; /* iseq -> iseq number */
9535 };
9536 
9538 
9540  const char *buff;
9542 
9543  VALUE obj_list; /* [obj0, ...] */
9544  unsigned int obj_list_size;
9546 };
9547 
9548 struct ibf_load {
9549  const struct ibf_header *header;
9550  VALUE iseq_list; /* [iseq0, ...] */
9556 };
9557 
9558 static ibf_offset_t
9559 ibf_dump_pos(struct ibf_dump *dump)
9560 {
9561  long pos = RSTRING_LEN(dump->current_buffer->str);
9562 #if SIZEOF_LONG > SIZEOF_INT
9563  if (pos >= UINT_MAX) {
9564  rb_raise(rb_eRuntimeError, "dump size exceeds");
9565  }
9566 #endif
9567  return (unsigned int)pos;
9568 }
9569 
9570 static void
9571 ibf_dump_align(struct ibf_dump *dump, size_t align)
9572 {
9573  ibf_offset_t pos = ibf_dump_pos(dump);
9574  if (pos % align) {
9575  static const char padding[sizeof(VALUE)];
9576  size_t size = align - ((size_t)pos % align);
9577 #if SIZEOF_LONG > SIZEOF_INT
9578  if (pos + size >= UINT_MAX) {
9579  rb_raise(rb_eRuntimeError, "dump size exceeds");
9580  }
9581 #endif
9582  for (; size > sizeof(padding); size -= sizeof(padding)) {
9583  rb_str_cat(dump->current_buffer->str, padding, sizeof(padding));
9584  }
9585  rb_str_cat(dump->current_buffer->str, padding, size);
9586  }
9587 }
9588 
9589 static ibf_offset_t
9590 ibf_dump_write(struct ibf_dump *dump, const void *buff, unsigned long size)
9591 {
9592  ibf_offset_t pos = ibf_dump_pos(dump);
9593  rb_str_cat(dump->current_buffer->str, (const char *)buff, size);
9594  /* TODO: overflow check */
9595  return pos;
9596 }
9597 
9598 static ibf_offset_t
9599 ibf_dump_write_byte(struct ibf_dump *dump, unsigned char byte)
9600 {
9601  return ibf_dump_write(dump, &byte, sizeof(unsigned char));
9602 }
9603 
9604 static void
9605 ibf_dump_overwrite(struct ibf_dump *dump, void *buff, unsigned int size, long offset)
9606 {
9607  VALUE str = dump->current_buffer->str;
9608  char *ptr = RSTRING_PTR(str);
9609  if ((unsigned long)(size + offset) > (unsigned long)RSTRING_LEN(str))
9610  rb_bug("ibf_dump_overwrite: overflow");
9611  memcpy(ptr + offset, buff, size);
9612 }
9613 
9614 static const void *
9615 ibf_load_ptr(const struct ibf_load *load, ibf_offset_t *offset, int size)
9616 {
9617  ibf_offset_t beg = *offset;
9618  *offset += size;
9619  return load->current_buffer->buff + beg;
9620 }
9621 
9622 static void *
9623 ibf_load_alloc(const struct ibf_load *load, ibf_offset_t offset, size_t x, size_t y)
9624 {
9625  void *buff = ruby_xmalloc2(x, y);
9626  size_t size = x * y;
9627  memcpy(buff, load->current_buffer->buff + offset, size);
9628  return buff;
9629 }
9630 
9631 #define IBF_W_ALIGN(type) (RUBY_ALIGNOF(type) > 1 ? ibf_dump_align(dump, RUBY_ALIGNOF(type)) : (void)0)
9632 
9633 #define IBF_W(b, type, n) (IBF_W_ALIGN(type), (type *)(VALUE)IBF_WP(b, type, n))
9634 #define IBF_WV(variable) ibf_dump_write(dump, &(variable), sizeof(variable))
9635 #define IBF_WP(b, type, n) ibf_dump_write(dump, (b), sizeof(type) * (n))
9636 #define IBF_R(val, type, n) (type *)ibf_load_alloc(load, IBF_OFFSET(val), sizeof(type), (n))
9637 #define IBF_ZERO(variable) memset(&(variable), 0, sizeof(variable))
9638 
9639 static int
9640 ibf_table_lookup(struct st_table *table, st_data_t key)
9641 {
9642  st_data_t val;
9643 
9644  if (st_lookup(table, key, &val)) {
9645  return (int)val;
9646  }
9647  else {
9648  return -1;
9649  }
9650 }
9651 
9652 static int
9653 ibf_table_index(struct st_table *table, st_data_t key)
9654 {
9655  int index = ibf_table_lookup(table, key);
9656 
9657  if (index < 0) { /* not found */
9658  index = (int)table->num_entries;
9659  st_insert(table, key, (st_data_t)index);
9660  }
9661 
9662  return index;
9663 }
9664 
9665 /* dump/load generic */
9666 
9667 static void ibf_dump_object_list(struct ibf_dump *dump, ibf_offset_t *obj_list_offset, unsigned int *obj_list_size);
9668 
9669 static VALUE ibf_load_object(const struct ibf_load *load, VALUE object_index);
9670 static rb_iseq_t *ibf_load_iseq(const struct ibf_load *load, const rb_iseq_t *index_iseq);
9671 
9672 static VALUE
9673 ibf_dump_object_list_new(void)
9674 {
9676  rb_ary_push(obj_list, Qnil); /* 0th is nil */
9677 
9678  return obj_list;
9679 }
9680 
9681 static VALUE
9682 ibf_dump_object(struct ibf_dump *dump, VALUE obj)
9683 {
9685  long index = RARRAY_LEN(obj_list);
9686  long i;
9687  for (i=0; i<index; i++) {
9688  if (RARRAY_AREF(obj_list, i) == obj) return (VALUE)i; /* dedup */
9689  }
9691  return (VALUE)index;
9692 }
9693 
9694 static VALUE
9695 ibf_dump_id(struct ibf_dump *dump, ID id)
9696 {
9697  if (id == 0 || rb_id2name(id) == NULL) {
9698  return 0;
9699  }
9700  return ibf_dump_object(dump, rb_id2sym(id));
9701 }
9702 
9703 static ID
9704 ibf_load_id(const struct ibf_load *load, const ID id_index)
9705 {
9706  if (id_index == 0) {
9707  return 0;
9708  }
9709  VALUE sym = ibf_load_object(load, id_index);
9710  return rb_sym2id(sym);
9711 }
9712 
9713 /* dump/load: code */
9714 
9715 static VALUE
9716 ibf_dump_calldata(struct ibf_dump *dump, const struct rb_call_data *cd)
9717 {
9718  return (cd->ci.flag & VM_CALL_KWARG) ? Qtrue : Qfalse;
9719 }
9720 
9721 static ibf_offset_t ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq);
9722 
9723 static int
9724 ibf_dump_iseq(struct ibf_dump *dump, const rb_iseq_t *iseq)
9725 {
9726  if (iseq == NULL) {
9727  return -1;
9728  }
9729  else {
9730  int iseq_index = ibf_table_lookup(dump->iseq_table, (st_data_t)iseq);
9731  if (iseq_index < 0) {
9732  iseq_index = ibf_table_index(dump->iseq_table, (st_data_t)iseq);
9733  rb_ary_push(dump->iseq_list, (VALUE)iseq);
9734  }
9735  return iseq_index;
9736  }
9737 }
9738 
9739 static VALUE
9740 ibf_dump_gentry(struct ibf_dump *dump, const struct rb_global_entry *entry)
9741 {
9742  return (VALUE)ibf_dump_id(dump, entry->id);
9743 }
9744 
9745 static VALUE
9746 ibf_load_gentry(const struct ibf_load *load, const struct rb_global_entry *entry)
9747 {
9748  ID gid = ibf_load_id(load, (ID)(VALUE)entry);
9749  return (VALUE)rb_global_entry(gid);
9750 }
9751 
9752 static unsigned char
9753 ibf_load_byte(const struct ibf_load *load, ibf_offset_t *offset)
9754 {
9755  if (*offset >= load->current_buffer->size) { rb_raise(rb_eRuntimeError, "invalid bytecode"); }
9756  return (unsigned char)load->current_buffer->buff[(*offset)++];
9757 }
9758 
9759 /*
9760  * Small uint serialization
9761  * 0x00000000_00000000 - 0x00000000_0000007f: 1byte | XXXX XXX1 |
9762  * 0x00000000_00000080 - 0x00000000_00003fff: 2byte | XXXX XX10 | XXXX XXXX |
9763  * 0x00000000_00004000 - 0x00000000_001fffff: 3byte | XXXX X100 | XXXX XXXX | XXXX XXXX |
9764  * 0x00000000_00020000 - 0x00000000_0fffffff: 4byte | XXXX 1000 | XXXX XXXX | XXXX XXXX | XXXX XXXX |
9765  * ...
9766  * 0x00010000_00000000 - 0x00ffffff_ffffffff: 8byte | 1000 0000 | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX |
9767  * 0x01000000_00000000 - 0xffffffff_ffffffff: 9byte | 0000 0000 | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX |
9768  */
9769 static void
9770 ibf_dump_write_small_value(struct ibf_dump *dump, VALUE x)
9771 {
9772  if (sizeof(VALUE) > 8 || CHAR_BIT != 8) {
9773  ibf_dump_write(dump, &x, sizeof(VALUE));
9774  }
9775 
9776  enum { max_byte_length = sizeof(VALUE) + 1 };
9777 
9778  unsigned char bytes[max_byte_length];
9779  ibf_offset_t n;
9780 
9781  for (n = 0; n < sizeof(VALUE) && (x >> (7 - n)); n++, x >>= 8) {
9782  bytes[max_byte_length - 1 - n] = (unsigned char)x;
9783  }
9784 
9785  x <<= 1;
9786  x |= 1;
9787  x <<= n;
9788  bytes[max_byte_length - 1 - n] = (unsigned char)x;
9789  n++;
9790 
9791  ibf_dump_write(dump, bytes + max_byte_length - n, n);
9792 }
9793 
9794 static VALUE
9795 ibf_load_small_value(const struct ibf_load *load, ibf_offset_t *offset)
9796 {
9797  if (sizeof(VALUE) > 8 || CHAR_BIT != 8) {
9798  union { char s[sizeof(VALUE)]; VALUE v; } x;
9799 
9800  memcpy(x.s, load->current_buffer->buff + *offset, sizeof(VALUE));
9801  *offset += sizeof(VALUE);
9802 
9803  return x.v;
9804  }
9805 
9806  enum { max_byte_length = sizeof(VALUE) + 1 };
9807 
9808  const unsigned char *buffer = (const unsigned char *)load->current_buffer->buff;
9809  const unsigned char c = buffer[*offset];
9810 
9811  ibf_offset_t n =
9812  c & 1 ? 1 :
9813  c == 0 ? 9 : ntz_int32(c) + 1;
9814  VALUE x = (VALUE)c >> n;
9815 
9816  if (*offset + n > load->current_buffer->size) {
9817  rb_raise(rb_eRuntimeError, "invalid byte sequence");
9818  }
9819 
9820  ibf_offset_t i;
9821  for (i = 1; i < n; i++) {
9822  x <<= 8;
9823  x |= (VALUE)buffer[*offset + i];
9824  }
9825 
9826  *offset += n;
9827  return x;
9828 }
9829 
9830 static void
9831 ibf_dump_builtin(struct ibf_dump *dump, const struct rb_builtin_function *bf)
9832 {
9833  // short: index
9834  // short: name.length
9835  // bytes: name
9836  // // omit argc (only verify with name)
9837  ibf_dump_write_small_value(dump, (VALUE)bf->index);
9838 
9839  size_t len = strlen(bf->name);
9840  ibf_dump_write_small_value(dump, (VALUE)len);
9841  ibf_dump_write(dump, bf->name, len);
9842 }
9843 
9844 static const struct rb_builtin_function *
9845 ibf_load_builtin(const struct ibf_load *load, ibf_offset_t *offset)
9846 {
9847  int i = (int)ibf_load_small_value(load, offset);
9848  int len = (int)ibf_load_small_value(load, offset);
9849  const char *name = (char *)ibf_load_ptr(load, offset, len);
9850 
9851  if (0) {
9852  for (int i=0; i<len; i++) fprintf(stderr, "%c", name[i]);
9853  fprintf(stderr, "!!\n");
9854  }
9855 
9856  const struct rb_builtin_function *table = GET_VM()->builtin_function_table;
9857  if (table == NULL) rb_bug("%s: table is not provided.", RUBY_FUNCTION_NAME_STRING);
9858  if (strncmp(table[i].name, name, len) != 0) {
9859  rb_bug("%s: index (%d) mismatch (expect %s but %s).", RUBY_FUNCTION_NAME_STRING, i, name, table[i].name);
9860  }
9861  // fprintf(stderr, "load-builtin: name:%s(%d)\n", table[i].name, table[i].argc);
9862 
9863  return &table[i];
9864 }
9865 
9866 static ibf_offset_t
9867 ibf_dump_code(struct ibf_dump *dump, const rb_iseq_t *iseq)
9868 {
9869  const struct rb_iseq_constant_body *const body = iseq->body;
9870  const int iseq_size = body->iseq_size;
9871  int code_index;
9872  const VALUE *orig_code = rb_iseq_original_iseq(iseq);
9873 
9874  ibf_offset_t offset = ibf_dump_pos(dump);
9875 
9876  for (code_index=0; code_index<iseq_size;) {
9877  const VALUE insn = orig_code[code_index++];
9878  const char *types = insn_op_types(insn);
9879  int op_index;
9880 
9881  /* opcode */
9882  if (insn >= 0x100) { rb_raise(rb_eRuntimeError, "invalid instruction"); }
9883  ibf_dump_write_small_value(dump, insn);
9884 
9885  /* operands */
9886  for (op_index=0; types[op_index]; op_index++, code_index++) {
9887  VALUE op = orig_code[code_index];
9888  VALUE wv;
9889 
9890  switch (types[op_index]) {
9891  case TS_CDHASH:
9892  case TS_VALUE:
9893  wv = ibf_dump_object(dump, op);
9894  break;
9895  case TS_ISEQ:
9896  wv = (VALUE)ibf_dump_iseq(dump, (const rb_iseq_t *)op);
9897  break;
9898  case TS_IC:
9899  case TS_IVC:
9900  case TS_ISE:
9901  {
9902  unsigned int i;
9903  for (i=0; i<body->is_size; i++) {
9904  if (op == (VALUE)&body->is_entries[i]) {
9905  break;
9906  }
9907  }
9908  wv = (VALUE)i;
9909  }
9910  break;
9911  case TS_CALLDATA:
9912  {
9913  /* ibf_dump_calldata() always returns either Qtrue or Qfalse */
9914  char c = ibf_dump_calldata(dump, (const struct rb_call_data *)op) == Qtrue; // 1 or 0
9915  ibf_dump_write_byte(dump, c);
9916  goto skip_wv;
9917  }
9918  case TS_ID:
9919  wv = ibf_dump_id(dump, (ID)op);
9920  break;
9921  case TS_GENTRY:
9922  wv = ibf_dump_gentry(dump, (const struct rb_global_entry *)op);
9923  break;
9924  case TS_FUNCPTR:
9925  rb_raise(rb_eRuntimeError, "TS_FUNCPTR is not supported");
9926  goto skip_wv;
9927  case TS_BUILTIN:
9928  ibf_dump_builtin(dump, (const struct rb_builtin_function *)op);
9929  goto skip_wv;
9930  default:
9931  wv = op;
9932  break;
9933  }
9934  ibf_dump_write_small_value(dump, wv);
9935  skip_wv:;
9936  }
9937  assert(insn_len(insn) == op_index+1);
9938  }
9939 
9940  return offset;
9941 }
9942 
9943 static VALUE *
9944 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)
9945 {
9946  unsigned int code_index;
9947  ibf_offset_t reading_pos = bytecode_offset;
9948  VALUE *code = ALLOC_N(VALUE, iseq_size);
9949 
9950  struct rb_iseq_constant_body *load_body = iseq->body;
9951  struct rb_call_data *cd_entries = load_body->call_data;
9952  struct rb_kwarg_call_data *cd_kw_entries = (struct rb_kwarg_call_data *)&load_body->call_data[load_body->ci_size];
9953  union iseq_inline_storage_entry *is_entries = load_body->is_entries;
9954 
9955  for (code_index=0; code_index<iseq_size;) {
9956  /* opcode */
9957  const VALUE insn = code[code_index++] = ibf_load_small_value(load, &reading_pos);
9958  const char *types = insn_op_types(insn);
9959  int op_index;
9960 
9961  /* operands */
9962  for (op_index=0; types[op_index]; op_index++, code_index++) {
9963  switch (types[op_index]) {
9964  case TS_CDHASH:
9965  case TS_VALUE:
9966  {
9967  VALUE op = ibf_load_small_value(load, &reading_pos);
9968  VALUE v = ibf_load_object(load, op);
9969  code[code_index] = v;
9970  if (!SPECIAL_CONST_P(v)) {
9973  }
9974  break;
9975  }
9976  case TS_ISEQ:
9977  {
9978  VALUE op = (VALUE)ibf_load_small_value(load, &reading_pos);
9979  VALUE v = (VALUE)ibf_load_iseq(load, (const rb_iseq_t *)op);
9980  code[code_index] = v;
9981  if (!SPECIAL_CONST_P(v)) {
9984  }
9985  break;
9986  }
9987  case TS_ISE:
9989  /* fall through */
9990  case TS_IC:
9991  case TS_IVC:
9992  {
9993  VALUE op = ibf_load_small_value(load, &reading_pos);
9994  code[code_index] = (VALUE)&is_entries[op];
9995  }
9996  break;
9997  case TS_CALLDATA:
9998  {
9999  unsigned char op = ibf_load_byte(load, &reading_pos);
10000  code[code_index] = op ? (VALUE)cd_kw_entries++ : (VALUE)cd_entries++; /* op is 1 (kw) or 0 (!kw) */
10001  }
10002  break;
10003  case TS_ID:
10004  {
10005  VALUE op = ibf_load_small_value(load, &reading_pos);
10006  code[code_index] = ibf_load_id(load, (ID)(VALUE)op);
10007  }
10008  break;
10009  case TS_GENTRY:
10010  {
10011  VALUE op = ibf_load_small_value(load, &reading_pos);
10012  code[code_index] = ibf_load_gentry(load, (const struct rb_global_entry *)(VALUE)op);
10013  }
10014  break;
10015  case TS_FUNCPTR:
10016  rb_raise(rb_eRuntimeError, "TS_FUNCPTR is not supported");
10017  break;
10018  case TS_BUILTIN:
10019  code[code_index] = (VALUE)ibf_load_builtin(load, &reading_pos);
10020  break;
10021  default:
10022  code[code_index] = ibf_load_small_value(load, &reading_pos);
10023  continue;
10024  }
10025  }
10026  if (insn_len(insn) != op_index+1) {
10027  rb_raise(rb_eRuntimeError, "operand size mismatch");
10028  }
10029  }
10030  load_body->iseq_encoded = code;
10031  load_body->iseq_size = code_index;
10032 
10033  assert(code_index == iseq_size);
10034  assert(reading_pos == bytecode_offset + bytecode_size);
10035  return code;
10036 }
10037 
10038 static ibf_offset_t
10039 ibf_dump_param_opt_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
10040 {
10041  int opt_num = iseq->body->param.opt_num;
10042 
10043  if (opt_num > 0) {
10044  IBF_W_ALIGN(VALUE);
10045  return ibf_dump_write(dump, iseq->body->param.opt_table, sizeof(VALUE) * (opt_num + 1));
10046  }
10047  else {
10048  return ibf_dump_pos(dump);
10049  }
10050 }
10051 
10052 static VALUE *
10053 ibf_load_param_opt_table(const struct ibf_load *load, ibf_offset_t opt_table_offset, int opt_num)
10054 {
10055  if (opt_num > 0) {
10056  VALUE *table = ALLOC_N(VALUE, opt_num+1);
10057  MEMCPY(table, load->current_buffer->buff + opt_table_offset, VALUE, opt_num+1);
10058  return table;
10059  }
10060  else {
10061  return NULL;
10062  }
10063 }
10064 
10065 static ibf_offset_t
10066 ibf_dump_param_keyword(struct ibf_dump *dump, const rb_iseq_t *iseq)
10067 {
10068  const struct rb_iseq_param_keyword *kw = iseq->body->param.keyword;
10069 
10070  if (kw) {
10071  struct rb_iseq_param_keyword dump_kw = *kw;
10072  int dv_num = kw->num - kw->required_num;
10073  ID *ids = kw->num > 0 ? ALLOCA_N(ID, kw->num) : NULL;
10074  VALUE *dvs = dv_num > 0 ? ALLOCA_N(VALUE, dv_num) : NULL;
10075  int i;
10076 
10077  for (i=0; i<kw->num; i++) ids[i] = (ID)ibf_dump_id(dump, kw->table[i]);
10078  for (i=0; i<dv_num; i++) dvs[i] = (VALUE)ibf_dump_object(dump, kw->default_values[i]);
10079 
10080  dump_kw.table = IBF_W(ids, ID, kw->num);
10081  dump_kw.default_values = IBF_W(dvs, VALUE, dv_num);
10082  IBF_W_ALIGN(struct rb_iseq_param_keyword);
10083  return ibf_dump_write(dump, &dump_kw, sizeof(struct rb_iseq_param_keyword) * 1);
10084  }
10085  else {
10086  return 0;
10087  }
10088 }
10089 
10090 static const struct rb_iseq_param_keyword *
10091 ibf_load_param_keyword(const struct ibf_load *load, ibf_offset_t param_keyword_offset)
10092 {
10093  if (param_keyword_offset) {
10094  struct rb_iseq_param_keyword *kw = IBF_R(param_keyword_offset, struct rb_iseq_param_keyword, 1);
10095  ID *ids = IBF_R(kw->table, ID, kw->num);
10096  int dv_num = kw->num - kw->required_num;
10097  VALUE *dvs = IBF_R(kw->default_values, VALUE, dv_num);
10098  int i;
10099 
10100  for (i=0; i<kw->num; i++) {
10101  ids[i] = ibf_load_id(load, ids[i]);
10102  }
10103  for (i=0; i<dv_num; i++) {
10104  dvs[i] = ibf_load_object(load, dvs[i]);
10105  }
10106 
10107  kw->table = ids;
10108  kw->default_values = dvs;
10109  return kw;
10110  }
10111  else {
10112  return NULL;
10113  }
10114 }
10115 
10116 static ibf_offset_t
10117 ibf_dump_insns_info_body(struct ibf_dump *dump, const rb_iseq_t *iseq)
10118 {
10119  ibf_offset_t offset = ibf_dump_pos(dump);
10121 
10122  unsigned int i;
10123  for (i = 0; i < iseq->body->insns_info.size; i++) {
10124  ibf_dump_write_small_value(dump, entries[i].line_no);
10125  ibf_dump_write_small_value(dump, entries[i].events);
10126  }
10127 
10128  return offset;
10129 }
10130 
10131 static struct iseq_insn_info_entry *
10132 ibf_load_insns_info_body(const struct ibf_load *load, ibf_offset_t body_offset, unsigned int size)
10133 {
10134  ibf_offset_t reading_pos = body_offset;
10136 
10137  unsigned int i;
10138  for (i = 0; i < size; i++) {
10139  entries[i].line_no = (int)ibf_load_small_value(load, &reading_pos);
10140  entries[i].events = (rb_event_flag_t)ibf_load_small_value(load, &reading_pos);
10141  }
10142 
10143  return entries;
10144 }
10145 
10146 static ibf_offset_t
10147 ibf_dump_insns_info_positions(struct ibf_dump *dump, const unsigned int *positions, unsigned int size)
10148 {
10149  ibf_offset_t offset = ibf_dump_pos(dump);
10150 
10151  unsigned int last = 0;
10152  unsigned int i;
10153  for (i = 0; i < size; i++) {
10154  ibf_dump_write_small_value(dump, positions[i] - last);
10155  last = positions[i];
10156  }
10157 
10158  return offset;
10159 }
10160 
10161 static unsigned int *
10162 ibf_load_insns_info_positions(const struct ibf_load *load, ibf_offset_t positions_offset, unsigned int size)
10163 {
10164  ibf_offset_t reading_pos = positions_offset;
10165  unsigned int *positions = ALLOC_N(unsigned int, size);
10166 
10167  unsigned int last = 0;
10168  unsigned int i;
10169  for (i = 0; i < size; i++) {
10170  positions[i] = last + (unsigned int)ibf_load_small_value(load, &reading_pos);
10171  last = positions[i];
10172  }
10173 
10174  return positions;
10175 }
10176 
10177 static ibf_offset_t
10178 ibf_dump_local_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
10179 {
10180  const struct rb_iseq_constant_body *const body = iseq->body;
10181  const int size = body->local_table_size;
10182  ID *table = ALLOCA_N(ID, size);
10183  int i;
10184 
10185  for (i=0; i<size; i++) {
10186  table[i] = ibf_dump_id(dump, body->local_table[i]);
10187  }
10188 
10189  IBF_W_ALIGN(ID);
10190  return ibf_dump_write(dump, table, sizeof(ID) * size);
10191 }
10192 
10193 static ID *
10194 ibf_load_local_table(const struct ibf_load *load, ibf_offset_t local_table_offset, int size)
10195 {
10196  if (size > 0) {
10197  ID *table = IBF_R(local_table_offset, ID, size);
10198  int i;
10199 
10200  for (i=0; i<size; i++) {
10201  table[i] = ibf_load_id(load, table[i]);
10202  }
10203  return table;
10204  }
10205  else {
10206  return NULL;
10207  }
10208 }
10209 
10210 static ibf_offset_t
10211 ibf_dump_catch_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
10212 {
10213  const struct iseq_catch_table *table = iseq->body->catch_table;
10214 
10215  if (table) {
10216  int *iseq_indices = ALLOCA_N(int, table->size);
10217  unsigned int i;
10218 
10219  for (i=0; i<table->size; i++) {
10220  iseq_indices[i] = ibf_dump_iseq(dump, table->entries[i].iseq);
10221  }
10222 
10223  const ibf_offset_t offset = ibf_dump_pos(dump);
10224 
10225  for (i=0; i<table->size; i++) {
10226  ibf_dump_write_small_value(dump, iseq_indices[i]);
10227  ibf_dump_write_small_value(dump, table->entries[i].type);
10228  ibf_dump_write_small_value(dump, table->entries[i].start);
10229  ibf_dump_write_small_value(dump, table->entries[i].end);
10230  ibf_dump_write_small_value(dump, table->entries[i].cont);
10231  ibf_dump_write_small_value(dump, table->entries[i].sp);
10232  }
10233  return offset;
10234  }
10235  else {
10236  return ibf_dump_pos(dump);
10237  }
10238 }
10239 
10240 static struct iseq_catch_table *
10241 ibf_load_catch_table(const struct ibf_load *load, ibf_offset_t catch_table_offset, unsigned int size)
10242 {
10243  if (size) {
10244  struct iseq_catch_table *table = ruby_xmalloc(iseq_catch_table_bytes(size));
10245  table->size = size;
10246 
10247  ibf_offset_t reading_pos = catch_table_offset;
10248 
10249  unsigned int i;
10250  for (i=0; i<table->size; i++) {
10251  int iseq_index = (int)ibf_load_small_value(load, &reading_pos);
10252  table->entries[i].type = (enum catch_type)ibf_load_small_value(load, &reading_pos);
10253  table->entries[i].start = (unsigned int)ibf_load_small_value(load, &reading_pos);
10254  table->entries[i].end = (unsigned int)ibf_load_small_value(load, &reading_pos);
10255  table->entries[i].cont = (unsigned int)ibf_load_small_value(load, &reading_pos);
10256  table->entries[i].sp = (unsigned int)ibf_load_small_value(load, &reading_pos);
10257 
10258  table->entries[i].iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)iseq_index);
10259  }
10260  return table;
10261  }
10262  else {
10263  return NULL;
10264  }
10265 }
10266 
10267 static ibf_offset_t
10268 ibf_dump_ci_entries(struct ibf_dump *dump, const rb_iseq_t *iseq)
10269 {
10270  const struct rb_iseq_constant_body *const body = iseq->body;
10271  const unsigned int ci_size = body->ci_size;
10272  const unsigned int ci_kw_size = body->ci_kw_size;
10273  const struct rb_call_data *calls = body->call_data;
10274  const struct rb_kwarg_call_data *kw_calls = (const struct rb_kwarg_call_data *)&body->call_data[ci_size];
10275 
10276  ibf_offset_t offset = ibf_dump_pos(dump);
10277 
10278  unsigned int i;
10279 
10280  for (i = 0; i < ci_size; i++) {
10281  VALUE mid = ibf_dump_id(dump, calls[i].ci.mid);
10282 
10283  ibf_dump_write_small_value(dump, mid);
10284  ibf_dump_write_small_value(dump, calls[i].ci.flag);
10285  ibf_dump_write_small_value(dump, calls[i].ci.orig_argc);
10286  }
10287 
10288  for (i = 0; i < ci_kw_size; i++) {
10289  const struct rb_call_info_kw_arg *kw_arg = kw_calls[i].ci_kw.kw_arg;
10290 
10291  VALUE mid = ibf_dump_id(dump, kw_calls[i].ci_kw.ci.mid);
10292 
10293  ibf_dump_write_small_value(dump, mid);
10294  ibf_dump_write_small_value(dump, kw_calls[i].ci_kw.ci.flag);
10295  ibf_dump_write_small_value(dump, kw_calls[i].ci_kw.ci.orig_argc);
10296 
10297  ibf_dump_write_small_value(dump, kw_arg->keyword_len);
10298 
10299  int j;
10300  for (j = 0; j < kw_calls[i].ci_kw.kw_arg->keyword_len; j++) {
10301  VALUE keyword = ibf_dump_object(dump, kw_arg->keywords[j]); /* kw_arg->keywords[n] is Symbol */
10302 
10303  ibf_dump_write_small_value(dump, keyword);
10304  }
10305  }
10306 
10307  return offset;
10308 }
10309 
10310 /* note that we dump out rb_call_info but load back rb_call_data */
10311 static struct rb_call_data *
10312 ibf_load_ci_entries(const struct ibf_load *load,
10313  ibf_offset_t ci_entries_offset,
10314  unsigned int ci_size,
10315  unsigned int ci_kw_size)
10316 {
10317  ibf_offset_t reading_pos = ci_entries_offset;
10318 
10319  unsigned int i;
10320 
10321  struct rb_call_data *calls =
10323  sizeof(struct rb_call_data), ci_size,
10324  sizeof(struct rb_kwarg_call_data), ci_kw_size);
10325  struct rb_kwarg_call_data *kw_calls = (struct rb_kwarg_call_data *)&calls[ci_size];
10326 
10327  for (i = 0; i < ci_size; i++) {
10328  VALUE mid_index = ibf_load_small_value(load, &reading_pos);
10329 
10330  calls[i].ci.mid = ibf_load_id(load, mid_index);
10331  calls[i].ci.flag = (unsigned int)ibf_load_small_value(load, &reading_pos);
10332  calls[i].ci.orig_argc = (int)ibf_load_small_value(load, &reading_pos);
10333  }
10334 
10335  for (i = 0; i < ci_kw_size; i++) {
10336  VALUE mid_index = ibf_load_small_value(load, &reading_pos);
10337 
10338  kw_calls[i].ci_kw.ci.mid = ibf_load_id(load, mid_index);
10339  kw_calls[i].ci_kw.ci.flag = (unsigned int)ibf_load_small_value(load, &reading_pos);
10340  kw_calls[i].ci_kw.ci.orig_argc = (int)ibf_load_small_value(load, &reading_pos);
10341 
10342  int keyword_len = (int)ibf_load_small_value(load, &reading_pos);
10343 
10344  kw_calls[i].ci_kw.kw_arg =
10345  rb_xmalloc_mul_add(keyword_len - 1, sizeof(VALUE), sizeof(struct rb_call_info_kw_arg));
10346 
10347  kw_calls[i].ci_kw.kw_arg->keyword_len = keyword_len;
10348 
10349  int j;
10350  for (j = 0; j < kw_calls[i].ci_kw.kw_arg->keyword_len; j++) {
10351  VALUE keyword = ibf_load_small_value(load, &reading_pos);
10352 
10353  kw_calls[i].ci_kw.kw_arg->keywords[j] = ibf_load_object(load, keyword);
10354  }
10355  }
10356 
10357  return calls;
10358 }
10359 
10360 static ibf_offset_t
10361 ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq)
10362 {
10363  assert(dump->current_buffer == &dump->global_buffer);
10364 
10365  unsigned int *positions;
10366 
10367  const struct rb_iseq_constant_body *body = iseq->body;
10368 
10369  const VALUE location_pathobj_index = ibf_dump_object(dump, body->location.pathobj); /* TODO: freeze */
10370  const VALUE location_base_label_index = ibf_dump_object(dump, body->location.base_label);
10371  const VALUE location_label_index = ibf_dump_object(dump, body->location.label);
10372 
10373 #if IBF_ISEQ_ENABLE_LOCAL_BUFFER
10374  ibf_offset_t iseq_start = ibf_dump_pos(dump);
10375 
10376  struct ibf_dump_buffer *saved_buffer = dump->current_buffer;
10377  struct ibf_dump_buffer buffer;
10378  buffer.str = rb_str_new(0, 0);
10379  buffer.obj_list = ibf_dump_object_list_new();
10380  dump->current_buffer = &buffer;
10381 #endif
10382 
10383  const ibf_offset_t bytecode_offset = ibf_dump_code(dump, iseq);
10384  const ibf_offset_t bytecode_size = ibf_dump_pos(dump) - bytecode_offset;
10385  const ibf_offset_t param_opt_table_offset = ibf_dump_param_opt_table(dump, iseq);
10386  const ibf_offset_t param_keyword_offset = ibf_dump_param_keyword(dump, iseq);
10387  const ibf_offset_t insns_info_body_offset = ibf_dump_insns_info_body(dump, iseq);
10388 
10390  const ibf_offset_t insns_info_positions_offset = ibf_dump_insns_info_positions(dump, positions, body->insns_info.size);
10391  ruby_xfree(positions);
10392 
10393  const ibf_offset_t local_table_offset = ibf_dump_local_table(dump, iseq);
10394  const unsigned int catch_table_size = body->catch_table ? body->catch_table->size : 0;
10395  const ibf_offset_t catch_table_offset = ibf_dump_catch_table(dump, iseq);
10396  const int parent_iseq_index = ibf_dump_iseq(dump, iseq->body->parent_iseq);
10397  const int local_iseq_index = ibf_dump_iseq(dump, iseq->body->local_iseq);
10398  const ibf_offset_t ci_entries_offset = ibf_dump_ci_entries(dump, iseq);
10399 
10400 #if IBF_ISEQ_ENABLE_LOCAL_BUFFER
10401  ibf_offset_t local_obj_list_offset;
10402  unsigned int local_obj_list_size;
10403 
10404  ibf_dump_object_list(dump, &local_obj_list_offset, &local_obj_list_size);
10405 #endif
10406 
10407  ibf_offset_t body_offset = ibf_dump_pos(dump);
10408 
10409  /* dump the constant body */
10410  unsigned int param_flags =
10411  (body->param.flags.has_lead << 0) |
10412  (body->param.flags.has_opt << 1) |
10413  (body->param.flags.has_rest << 2) |
10414  (body->param.flags.has_post << 3) |
10415  (body->param.flags.has_kw << 4) |
10416  (body->param.flags.has_kwrest << 5) |
10417  (body->param.flags.has_block << 6) |
10418  (body->param.flags.ambiguous_param0 << 7) |
10419  (body->param.flags.accepts_no_kwarg << 8) |
10420  (body->param.flags.ruby2_keywords << 9);
10421 
10422 #if IBF_ISEQ_ENABLE_LOCAL_BUFFER
10423 # define IBF_BODY_OFFSET(x) (x)
10424 #else
10425 # define IBF_BODY_OFFSET(x) (body_offset - (x))
10426 #endif
10427 
10428  ibf_dump_write_small_value(dump, body->type);
10429  ibf_dump_write_small_value(dump, body->iseq_size);
10430  ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(bytecode_offset));
10431  ibf_dump_write_small_value(dump, bytecode_size);
10432  ibf_dump_write_small_value(dump, param_flags);
10433  ibf_dump_write_small_value(dump, body->param.size);
10434  ibf_dump_write_small_value(dump, body->param.lead_num);
10435  ibf_dump_write_small_value(dump, body->param.opt_num);
10436  ibf_dump_write_small_value(dump, body->param.rest_start);
10437  ibf_dump_write_small_value(dump, body->param.post_start);
10438  ibf_dump_write_small_value(dump, body->param.post_num);
10439  ibf_dump_write_small_value(dump, body->param.block_start);
10440  ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(param_opt_table_offset));
10441  ibf_dump_write_small_value(dump, param_keyword_offset);
10442  ibf_dump_write_small_value(dump, location_pathobj_index);
10443  ibf_dump_write_small_value(dump, location_base_label_index);
10444  ibf_dump_write_small_value(dump, location_label_index);
10445  ibf_dump_write_small_value(dump, body->location.first_lineno);
10446  ibf_dump_write_small_value(dump, body->location.node_id);
10447  ibf_dump_write_small_value(dump, body->location.code_location.beg_pos.lineno);
10448  ibf_dump_write_small_value(dump, body->location.code_location.beg_pos.column);
10449  ibf_dump_write_small_value(dump, body->location.code_location.end_pos.lineno);
10450  ibf_dump_write_small_value(dump, body->location.code_location.end_pos.column);
10451  ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(insns_info_body_offset));
10452  ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(insns_info_positions_offset));
10453  ibf_dump_write_small_value(dump, body->insns_info.size);
10454  ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(local_table_offset));
10455  ibf_dump_write_small_value(dump, catch_table_size);
10456  ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(catch_table_offset));
10457  ibf_dump_write_small_value(dump, parent_iseq_index);
10458  ibf_dump_write_small_value(dump, local_iseq_index);
10459  ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(ci_entries_offset));
10460  ibf_dump_write_small_value(dump, body->variable.flip_count);
10461  ibf_dump_write_small_value(dump, body->local_table_size);
10462  ibf_dump_write_small_value(dump, body->is_size);
10463  ibf_dump_write_small_value(dump, body->ci_size);
10464  ibf_dump_write_small_value(dump, body->ci_kw_size);
10465  ibf_dump_write_small_value(dump, body->stack_max);
10466  ibf_dump_write_small_value(dump, body->catch_except_p);
10467 
10468 #undef IBF_BODY_OFFSET
10469 
10470 #if IBF_ISEQ_ENABLE_LOCAL_BUFFER
10471  ibf_offset_t iseq_length_bytes = ibf_dump_pos(dump);
10472 
10473  dump->current_buffer = saved_buffer;
10474  ibf_dump_write(dump, RSTRING_PTR(buffer.str), iseq_length_bytes);
10475 
10476  ibf_offset_t offset = ibf_dump_pos(dump);
10477  ibf_dump_write_small_value(dump, iseq_start);
10478  ibf_dump_write_small_value(dump, iseq_length_bytes);
10479  ibf_dump_write_small_value(dump, body_offset);
10480 
10481  ibf_dump_write_small_value(dump, local_obj_list_offset);
10482  ibf_dump_write_small_value(dump, local_obj_list_size);
10483 
10484  return offset;
10485 #else
10486  return body_offset;
10487 #endif
10488 }
10489 
10490 static VALUE
10491 ibf_load_location_str(const struct ibf_load *load, VALUE str_index)
10492 {
10493  VALUE str = ibf_load_object(load, str_index);
10494  if (str != Qnil) {
10495  str = rb_fstring(str);
10496  }
10497  return str;
10498 }
10499 
10500 static void
10501 ibf_load_iseq_each(struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t offset)
10502 {
10504 
10505  ibf_offset_t reading_pos = offset;
10506 
10507 #if IBF_ISEQ_ENABLE_LOCAL_BUFFER
10508  struct ibf_load_buffer *saved_buffer = load->current_buffer;
10509  load->current_buffer = &load->global_buffer;
10510 
10511  const ibf_offset_t iseq_start = ibf_load_small_value(load, &reading_pos);
10512  const ibf_offset_t iseq_length_bytes = ibf_load_small_value(load, &reading_pos);
10513  const ibf_offset_t body_offset = ibf_load_small_value(load, &reading_pos);
10514 
10515  struct ibf_load_buffer buffer;
10516  buffer.buff = load->global_buffer.buff + iseq_start;
10517  buffer.size = iseq_length_bytes;
10518  buffer.obj_list_offset = ibf_load_small_value(load, &reading_pos);
10519  buffer.obj_list_size = ibf_load_small_value(load, &reading_pos);
10520  buffer.obj_list = rb_ary_tmp_new(buffer.obj_list_size);
10521  rb_ary_resize(buffer.obj_list, buffer.obj_list_size);
10522 
10523  load->current_buffer = &buffer;
10524  reading_pos = body_offset;
10525 #endif
10526 
10527 #if IBF_ISEQ_ENABLE_LOCAL_BUFFER
10528 # define IBF_BODY_OFFSET(x) (x)
10529 #else
10530 # define IBF_BODY_OFFSET(x) (offset - (x))
10531 #endif
10532 
10533  const unsigned int type = (unsigned int)ibf_load_small_value(load, &reading_pos);
10534  const unsigned int iseq_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
10535  const ibf_offset_t bytecode_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
10536  const ibf_offset_t bytecode_size = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
10537  const unsigned int param_flags = (unsigned int)ibf_load_small_value(load, &reading_pos);
10538  const unsigned int param_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
10539  const int param_lead_num = (int)ibf_load_small_value(load, &reading_pos);
10540  const int param_opt_num = (int)ibf_load_small_value(load, &reading_pos);
10541  const int param_rest_start = (int)ibf_load_small_value(load, &reading_pos);
10542  const int param_post_start = (int)ibf_load_small_value(load, &reading_pos);
10543  const int param_post_num = (int)ibf_load_small_value(load, &reading_pos);
10544  const int param_block_start = (int)ibf_load_small_value(load, &reading_pos);
10545  const ibf_offset_t param_opt_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
10546  const ibf_offset_t param_keyword_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
10547  const VALUE location_pathobj_index = ibf_load_small_value(load, &reading_pos);
10548  const VALUE location_base_label_index = ibf_load_small_value(load, &reading_pos);
10549  const VALUE location_label_index = ibf_load_small_value(load, &reading_pos);
10550  const VALUE location_first_lineno = ibf_load_small_value(load, &reading_pos);
10551  const int location_node_id = (int)ibf_load_small_value(load, &reading_pos);
10552  const int location_code_location_beg_pos_lineno = (int)ibf_load_small_value(load, &reading_pos);
10553  const int location_code_location_beg_pos_column = (int)ibf_load_small_value(load, &reading_pos);
10554  const int location_code_location_end_pos_lineno = (int)ibf_load_small_value(load, &reading_pos);
10555  const int location_code_location_end_pos_column = (int)ibf_load_small_value(load, &reading_pos);
10556  const ibf_offset_t insns_info_body_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
10557  const ibf_offset_t insns_info_positions_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
10558  const unsigned int insns_info_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
10559  const ibf_offset_t local_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
10560  const unsigned int catch_table_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
10561  const ibf_offset_t catch_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
10562  const int parent_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
10563  const int local_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
10564  const ibf_offset_t ci_entries_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
10565  const rb_snum_t variable_flip_count = (rb_snum_t)ibf_load_small_value(load, &reading_pos);
10566  const unsigned int local_table_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
10567  const unsigned int is_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
10568  const unsigned int ci_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
10569  const unsigned int ci_kw_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
10570  const unsigned int stack_max = (unsigned int)ibf_load_small_value(load, &reading_pos);
10571  const char catch_except_p = (char)ibf_load_small_value(load, &reading_pos);
10572 
10573 #undef IBF_BODY_OFFSET
10574 
10575  load_body->type = type;
10576  load_body->stack_max = stack_max;
10577  load_body->param.flags.has_lead = (param_flags >> 0) & 1;
10578  load_body->param.flags.has_opt = (param_flags >> 1) & 1;
10579  load_body->param.flags.has_rest = (param_flags >> 2) & 1;
10580  load_body->param.flags.has_post = (param_flags >> 3) & 1;
10581  load_body->param.flags.has_kw = FALSE;
10582  load_body->param.flags.has_kwrest = (param_flags >> 5) & 1;
10583  load_body->param.flags.has_block = (param_flags >> 6) & 1;
10584  load_body->param.flags.ambiguous_param0 = (param_flags >> 7) & 1;
10585  load_body->param.flags.accepts_no_kwarg = (param_flags >> 8) & 1;
10586  load_body->param.flags.ruby2_keywords = (param_flags >> 9) & 1;
10587  load_body->param.size = param_size;
10588  load_body->param.lead_num = param_lead_num;
10589  load_body->param.opt_num = param_opt_num;
10590  load_body->param.rest_start = param_rest_start;
10591  load_body->param.post_start = param_post_start;
10592  load_body->param.post_num = param_post_num;
10593  load_body->param.block_start = param_block_start;
10594  load_body->local_table_size = local_table_size;
10595  load_body->is_size = is_size;
10596  load_body->ci_size = ci_size;
10597  load_body->ci_kw_size = ci_kw_size;
10598  load_body->insns_info.size = insns_info_size;
10599 
10601  ISEQ_ORIGINAL_ISEQ_CLEAR(iseq);
10602  iseq->body->variable.flip_count = variable_flip_count;
10603 
10604  load_body->location.first_lineno = location_first_lineno;
10605  load_body->location.node_id = location_node_id;
10606  load_body->location.code_location.beg_pos.lineno = location_code_location_beg_pos_lineno;
10607  load_body->location.code_location.beg_pos.column = location_code_location_beg_pos_column;
10608  load_body->location.code_location.end_pos.lineno = location_code_location_end_pos_lineno;
10609  load_body->location.code_location.end_pos.column = location_code_location_end_pos_column;
10610  load_body->catch_except_p = catch_except_p;
10611 
10612  load_body->is_entries = ZALLOC_N(union iseq_inline_storage_entry, is_size);
10613  load_body->call_data = ibf_load_ci_entries(load, ci_entries_offset, ci_size, ci_kw_size);
10614  load_body->param.opt_table = ibf_load_param_opt_table(load, param_opt_table_offset, param_opt_num);
10615  load_body->param.keyword = ibf_load_param_keyword(load, param_keyword_offset);
10616  load_body->param.flags.has_kw = (param_flags >> 4) & 1;
10617  load_body->insns_info.body = ibf_load_insns_info_body(load, insns_info_body_offset, insns_info_size);
10618  load_body->insns_info.positions = ibf_load_insns_info_positions(load, insns_info_positions_offset, insns_info_size);
10619  load_body->local_table = ibf_load_local_table(load, local_table_offset, local_table_size);
10620  load_body->catch_table = ibf_load_catch_table(load, catch_table_offset, catch_table_size);
10621  load_body->parent_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)parent_iseq_index);
10622  load_body->local_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)local_iseq_index);
10623 
10624  ibf_load_code(load, iseq, bytecode_offset, bytecode_size, iseq_size);
10625 #if VM_INSN_INFO_TABLE_IMPL == 2
10627 #endif
10628 
10629  rb_iseq_translate_threaded_code(iseq);
10630 
10631 #if IBF_ISEQ_ENABLE_LOCAL_BUFFER
10632  load->current_buffer = &load->global_buffer;
10633 #endif
10634 
10635  {
10636  VALUE realpath = Qnil, path = ibf_load_object(load, location_pathobj_index);
10637  if (RB_TYPE_P(path, T_STRING)) {
10639  }
10640  else if (RB_TYPE_P(path, T_ARRAY)) {
10641  VALUE pathobj = path;
10642  if (RARRAY_LEN(pathobj) != 2) {
10643  rb_raise(rb_eRuntimeError, "path object size mismatch");
10644  }
10645  path = rb_fstring(RARRAY_AREF(pathobj, 0));
10646  realpath = RARRAY_AREF(pathobj, 1);
10647  if (!NIL_P(realpath)) {
10648  if (!RB_TYPE_P(realpath, T_STRING)) {
10649  rb_raise(rb_eArgError, "unexpected realpath %"PRIxVALUE
10650  "(%x), path=%+"PRIsVALUE,
10651  realpath, TYPE(realpath), path);
10652  }
10654  }
10655  }
10656  else {
10657  rb_raise(rb_eRuntimeError, "unexpected path object");
10658  }
10660  }
10661 
10662  RB_OBJ_WRITE(iseq, &load_body->location.base_label, ibf_load_location_str(load, location_base_label_index));
10663  RB_OBJ_WRITE(iseq, &load_body->location.label, ibf_load_location_str(load, location_label_index));
10664 
10665 #if IBF_ISEQ_ENABLE_LOCAL_BUFFER
10666  load->current_buffer = saved_buffer;
10667 #endif
10668  verify_call_cache(iseq);
10669 }
10670 
10671 static void
10672 ibf_dump_iseq_list(struct ibf_dump *dump, struct ibf_header *header)
10673 {
10675  long i;
10676 
10677  for (i = 0; i < RARRAY_LEN(dump->iseq_list); i++) {
10678  ibf_offset_t offset = ibf_dump_iseq_each(dump, (rb_iseq_t *)RARRAY_AREF(dump->iseq_list, i));
10679  rb_ary_push(list, UINT2NUM(offset));
10680  }
10681 
10682  long size = RARRAY_LEN(dump->iseq_list);
10683  ibf_offset_t *offsets = ALLOCA_N(ibf_offset_t, size);
10684 
10685  for (i = 0; i < size; i++) {
10686  offsets[i] = NUM2UINT(RARRAY_AREF(list, i));
10687  }
10688 
10689  ibf_dump_align(dump, sizeof(ibf_offset_t));
10690  header->iseq_list_offset = ibf_dump_write(dump, offsets, sizeof(ibf_offset_t) * size);
10691  header->iseq_list_size = (unsigned int)size;
10692 }
10693 
10694 #define IBF_OBJECT_INTERNAL FL_PROMOTED0
10695 
10696 /*
10697  * Binary format
10698  * - ibf_object_header
10699  * - ibf_object_xxx (xxx is type)
10700  */
10701 
10703  unsigned int type: 5;
10704  unsigned int special_const: 1;
10705  unsigned int frozen: 1;
10706  unsigned int internal: 1;
10707 };
10708 
10715 };
10716 
10718  long srcstr;
10719  char option;
10720 };
10721 
10723  long len;
10725 };
10726 
10729  long len;
10730  long beg;
10731  long end;
10732  int excl;
10733 };
10734 
10738 };
10739 
10742 };
10743 
10745  long a, b;
10746 };
10747 
10749  long str;
10750 };
10751 
10752 #define IBF_ALIGNED_OFFSET(align, offset) /* offset > 0 */ \
10753  ((((offset) - 1) / (align) + 1) * (align))
10754 #define IBF_OBJBODY(type, offset) (const type *)\
10755  ibf_load_check_offset(load, IBF_ALIGNED_OFFSET(RUBY_ALIGNOF(type), offset))
10756 
10757 static const void *
10758 ibf_load_check_offset(const struct ibf_load *load, size_t offset)
10759 {
10760  if (offset >= load->current_buffer->size) {
10761  rb_raise(rb_eIndexError, "object offset out of range: %"PRIdSIZE, offset);
10762  }
10763  return load->current_buffer->buff + offset;
10764 }
10765 
10766 NORETURN(static void ibf_dump_object_unsupported(struct ibf_dump *dump, VALUE obj));
10767 
10768 static void
10769 ibf_dump_object_unsupported(struct ibf_dump *dump, VALUE obj)
10770 {
10771  char buff[0x100];
10772  rb_raw_obj_info(buff, sizeof(buff), obj);
10773  rb_raise(rb_eNotImpError, "ibf_dump_object_unsupported: %s", buff);
10774 }
10775 
10776 static VALUE
10777 ibf_load_object_unsupported(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
10778 {
10779  rb_raise(rb_eArgError, "unsupported");
10780  return Qnil;
10781 }
10782 
10783 static void
10784 ibf_dump_object_class(struct ibf_dump *dump, VALUE obj)
10785 {
10786  enum ibf_object_class_index cindex;
10787  if (obj == rb_cObject) {
10788  cindex = IBF_OBJECT_CLASS_OBJECT;
10789  }
10790  else if (obj == rb_cArray) {
10791  cindex = IBF_OBJECT_CLASS_ARRAY;
10792  }
10793  else if (obj == rb_eStandardError) {
10795  }
10796  else if (obj == rb_eNoMatchingPatternError) {
10798  }
10799  else if (obj == rb_eTypeError) {
10800  cindex = IBF_OBJECT_CLASS_TYPE_ERROR;
10801  }
10802  else {
10804  rb_p(obj);
10805  rb_bug("unsupported class");
10806  }
10807  ibf_dump_write_small_value(dump, (VALUE)cindex);
10808 }
10809 
10810 static VALUE
10811 ibf_load_object_class(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
10812 {
10813  enum ibf_object_class_index cindex = (enum ibf_object_class_index)ibf_load_small_value(load, &offset);
10814 
10815  switch (cindex) {
10817  return rb_cObject;
10819  return rb_cArray;
10821  return rb_eStandardError;
10825  return rb_eTypeError;
10826  }
10827 
10828  rb_raise(rb_eArgError, "ibf_load_object_class: unknown class (%d)", (int)cindex);
10829 }
10830 
10831 
10832 static void
10833 ibf_dump_object_float(struct ibf_dump *dump, VALUE obj)
10834 {
10835  double dbl = RFLOAT_VALUE(obj);
10836  (void)IBF_W(&dbl, double, 1);
10837 }
10838 
10839 static VALUE
10840 ibf_load_object_float(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
10841 {
10842  const double *dblp = IBF_OBJBODY(double, offset);
10843  return DBL2NUM(*dblp);
10844 }
10845 
10846 static void
10847 ibf_dump_object_string(struct ibf_dump *dump, VALUE obj)
10848 {
10849  long encindex = (long)rb_enc_get_index(obj);
10850  long len = RSTRING_LEN(obj);
10851  const char *ptr = RSTRING_PTR(obj);
10852 
10853  if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
10854  rb_encoding *enc = rb_enc_from_index((int)encindex);
10855  const char *enc_name = rb_enc_name(enc);
10856  encindex = RUBY_ENCINDEX_BUILTIN_MAX + ibf_dump_object(dump, rb_str_new2(enc_name));
10857  }
10858 
10859  ibf_dump_write_small_value(dump, encindex);
10860  ibf_dump_write_small_value(dump, len);
10861  IBF_WP(ptr, char, len);
10862 }
10863 
10864 static VALUE
10865 ibf_load_object_string(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
10866 {
10867  ibf_offset_t reading_pos = offset;
10868 
10869  int encindex = (int)ibf_load_small_value(load, &reading_pos);
10870  const long len = (long)ibf_load_small_value(load, &reading_pos);
10871  const char *ptr = load->current_buffer->buff + reading_pos;
10872 
10873  VALUE str = rb_str_new(ptr, len);
10874 
10875  if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
10876  VALUE enc_name_str = ibf_load_object(load, encindex - RUBY_ENCINDEX_BUILTIN_MAX);
10877  encindex = rb_enc_find_index(RSTRING_PTR(enc_name_str));
10878  }
10879  rb_enc_associate_index(str, encindex);
10880 
10881  if (header->internal) rb_obj_hide(str);
10882  if (header->frozen) str = rb_fstring(str);
10883 
10884  return str;
10885 }
10886 
10887 static void
10888 ibf_dump_object_regexp(struct ibf_dump *dump, VALUE obj)
10889 {
10890  VALUE srcstr = RREGEXP_SRC(obj);
10891  struct ibf_object_regexp regexp;
10892  regexp.option = (char)rb_reg_options(obj);
10893  regexp.srcstr = (long)ibf_dump_object(dump, srcstr);
10894 
10895  ibf_dump_write_byte(dump, (unsigned char)regexp.option);
10896  ibf_dump_write_small_value(dump, regexp.srcstr);
10897 }
10898 
10899 static VALUE
10900 ibf_load_object_regexp(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
10901 {
10902  struct ibf_object_regexp regexp;
10903  regexp.option = ibf_load_byte(load, &offset);
10904  regexp.srcstr = ibf_load_small_value(load, &offset);
10905 
10906  VALUE srcstr = ibf_load_object(load, regexp.srcstr);
10907  VALUE reg = rb_reg_compile(srcstr, (int)regexp.option, NULL, 0);
10908 
10909  if (header->internal) rb_obj_hide(reg);
10910  if (header->frozen) rb_obj_freeze(reg);
10911 
10912  return reg;
10913 }
10914 
10915 static void
10916 ibf_dump_object_array(struct ibf_dump *dump, VALUE obj)
10917 {
10918  long i, len = RARRAY_LEN(obj);
10919  ibf_dump_write_small_value(dump, len);
10920  for (i=0; i<len; i++) {
10921  long index = (long)ibf_dump_object(dump, RARRAY_AREF(obj, i));
10922  ibf_dump_write_small_value(dump, index);
10923  }
10924 }
10925 
10926 static VALUE
10927 ibf_load_object_array(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
10928 {
10929  ibf_offset_t reading_pos = offset;
10930 
10931  const long len = (long)ibf_load_small_value(load, &reading_pos);
10932 
10933  VALUE ary = rb_ary_new_capa(len);
10934  int i;
10935 
10936  for (i=0; i<len; i++) {
10937  const VALUE index = ibf_load_small_value(load, &reading_pos);
10938  rb_ary_push(ary, ibf_load_object(load, index));
10939  }
10940 
10941  if (header->internal) rb_obj_hide(ary);
10942  if (header->frozen) rb_obj_freeze(ary);
10943 
10944  return ary;
10945 }
10946 
10947 static int
10948 ibf_dump_object_hash_i(st_data_t key, st_data_t val, st_data_t ptr)
10949 {
10950  struct ibf_dump *dump = (struct ibf_dump *)ptr;
10951 
10952  VALUE key_index = ibf_dump_object(dump, (VALUE)key);
10953  VALUE val_index = ibf_dump_object(dump, (VALUE)val);
10954 
10955  ibf_dump_write_small_value(dump, key_index);
10956  ibf_dump_write_small_value(dump, val_index);
10957  return ST_CONTINUE;
10958 }
10959 
10960 static void
10961 ibf_dump_object_hash(struct ibf_dump *dump, VALUE obj)
10962 {
10963  long len = RHASH_SIZE(obj);
10964  ibf_dump_write_small_value(dump, (VALUE)len);
10965 
10966  if (len > 0) rb_hash_foreach(obj, ibf_dump_object_hash_i, (VALUE)dump);
10967 }
10968 
10969 static VALUE
10970 ibf_load_object_hash(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
10971 {
10972  long len = (long)ibf_load_small_value(load, &offset);
10974  int i;
10975 
10976  for (i = 0; i < len; i++) {
10977  VALUE key_index = ibf_load_small_value(load, &offset);
10978  VALUE val_index = ibf_load_small_value(load, &offset);
10979 
10980  VALUE key = ibf_load_object(load, key_index);
10981  VALUE val = ibf_load_object(load, val_index);
10982  rb_hash_aset(obj, key, val);
10983  }
10985 
10986  if (header->internal) rb_obj_hide(obj);
10987  if (header->frozen) rb_obj_freeze(obj);
10988 
10989  return obj;
10990 }
10991 
10992 static void
10993 ibf_dump_object_struct(struct ibf_dump *dump, VALUE obj)
10994 {
10997  VALUE beg, end;
10998  IBF_ZERO(range);
10999  range.len = 3;
11000  range.class_index = 0;
11001 
11002  rb_range_values(obj, &beg, &end, &range.excl);
11003  range.beg = (long)ibf_dump_object(dump, beg);
11004  range.end = (long)ibf_dump_object(dump, end);
11005 
11007  IBF_WV(range);
11008  }
11009  else {
11010  rb_raise(rb_eNotImpError, "ibf_dump_object_struct: unsupported class %"PRIsVALUE,
11012  }
11013 }
11014 
11015 static VALUE
11016 ibf_load_object_struct(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
11017 {
11018  const struct ibf_object_struct_range *range = IBF_OBJBODY(struct ibf_object_struct_range, offset);
11019  VALUE beg = ibf_load_object(load, range->beg);
11020  VALUE end = ibf_load_object(load, range->end);
11021  VALUE obj = rb_range_new(beg, end, range->excl);
11022  if (header->internal) rb_obj_hide(obj);
11023  if (header->frozen) rb_obj_freeze(obj);
11024  return obj;
11025 }
11026 
11027 static void
11028 ibf_dump_object_bignum(struct ibf_dump *dump, VALUE obj)
11029 {
11031  ssize_t slen = BIGNUM_SIGN(obj) > 0 ? len : len * -1;
11032  BDIGIT *d = BIGNUM_DIGITS(obj);
11033 
11034  (void)IBF_W(&slen, ssize_t, 1);
11035  IBF_WP(d, BDIGIT, len);
11036 }
11037 
11038 static VALUE
11039 ibf_load_object_bignum(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
11040 {
11041  const struct ibf_object_bignum *bignum = IBF_OBJBODY(struct ibf_object_bignum, offset);
11042  int sign = bignum->slen > 0;
11043  ssize_t len = sign > 0 ? bignum->slen : -1 * bignum->slen;
11044  VALUE obj = rb_integer_unpack(bignum->digits, len * 2, 2, 0,
11046  if (header->internal) rb_obj_hide(obj);
11047  if (header->frozen) rb_obj_freeze(obj);
11048  return obj;
11049 }
11050 
11051 static void
11052 ibf_dump_object_data(struct ibf_dump *dump, VALUE obj)
11053 {
11054  if (rb_data_is_encoding(obj)) {
11055  rb_encoding *enc = rb_to_encoding(obj);
11056  const char *name = rb_enc_name(enc);
11057  long len = strlen(name) + 1;
11058  long data[2];
11059  data[0] = IBF_OBJECT_DATA_ENCODING;
11060  data[1] = len;
11061  (void)IBF_W(data, long, 2);
11062  IBF_WP(name, char, len);
11063  }
11064  else {
11065  ibf_dump_object_unsupported(dump, obj);
11066  }
11067 }
11068 
11069 static VALUE
11070 ibf_load_object_data(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
11071 {
11072  const long *body = IBF_OBJBODY(long, offset);
11073  const enum ibf_object_data_type type = (enum ibf_object_data_type)body[0];
11074  /* const long len = body[1]; */
11075  const char *data = (const char *)&body[2];
11076 
11077  switch (type) {
11079  {
11080  VALUE encobj = rb_enc_from_encoding(rb_enc_find(data));
11081  return encobj;
11082  }
11083  }
11084 
11085  return ibf_load_object_unsupported(load, header, offset);
11086 }
11087 
11088 static void
11089 ibf_dump_object_complex_rational(struct ibf_dump *dump, VALUE obj)
11090 {
11091  long data[2];
11092  data[0] = (long)ibf_dump_object(dump, RCOMPLEX(obj)->real);
11093  data[1] = (long)ibf_dump_object(dump, RCOMPLEX(obj)->imag);
11094 
11095  (void)IBF_W(data, long, 2);
11096 }
11097 
11098 static VALUE
11099 ibf_load_object_complex_rational(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
11100 {
11101  const struct ibf_object_complex_rational *nums = IBF_OBJBODY(struct ibf_object_complex_rational, offset);
11102  VALUE a = ibf_load_object(load, nums->a);
11103  VALUE b = ibf_load_object(load, nums->b);
11104  VALUE obj = header->type == T_COMPLEX ?
11106 
11107  if (header->internal) rb_obj_hide(obj);
11108  if (header->frozen) rb_obj_freeze(obj);
11109  return obj;
11110 }
11111 
11112 static void
11113 ibf_dump_object_symbol(struct ibf_dump *dump, VALUE obj)
11114 {
11115  VALUE str = rb_sym2str(obj);
11116  VALUE str_index = ibf_dump_object(dump, str);
11117 
11118  ibf_dump_write_small_value(dump, str_index);
11119 }
11120 
11121 static VALUE
11122 ibf_load_object_symbol(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
11123 {
11124  VALUE str_index = ibf_load_small_value(load, &offset);
11125  VALUE str = ibf_load_object(load, str_index);
11126  ID id = rb_intern_str(str);
11127  return ID2SYM(id);
11128 }
11129 
11130 typedef void (*ibf_dump_object_function)(struct ibf_dump *dump, VALUE obj);
11131 static ibf_dump_object_function dump_object_functions[RUBY_T_MASK+1] = {
11132  ibf_dump_object_unsupported, /* T_NONE */
11133  ibf_dump_object_unsupported, /* T_OBJECT */
11134  ibf_dump_object_class, /* T_CLASS */
11135  ibf_dump_object_unsupported, /* T_MODULE */
11136  ibf_dump_object_float, /* T_FLOAT */
11137  ibf_dump_object_string, /* T_STRING */
11138  ibf_dump_object_regexp, /* T_REGEXP */
11139  ibf_dump_object_array, /* T_ARRAY */
11140  ibf_dump_object_hash, /* T_HASH */
11141  ibf_dump_object_struct, /* T_STRUCT */
11142  ibf_dump_object_bignum, /* T_BIGNUM */
11143  ibf_dump_object_unsupported, /* T_FILE */
11144  ibf_dump_object_data, /* T_DATA */
11145  ibf_dump_object_unsupported, /* T_MATCH */
11146  ibf_dump_object_complex_rational, /* T_COMPLEX */
11147  ibf_dump_object_complex_rational, /* T_RATIONAL */
11148  ibf_dump_object_unsupported, /* 0x10 */
11149  ibf_dump_object_unsupported, /* 0x11 T_NIL */
11150  ibf_dump_object_unsupported, /* 0x12 T_TRUE */
11151  ibf_dump_object_unsupported, /* 0x13 T_FALSE */
11152  ibf_dump_object_symbol, /* 0x14 T_SYMBOL */
11153  ibf_dump_object_unsupported, /* T_FIXNUM */
11154  ibf_dump_object_unsupported, /* T_UNDEF */
11155  ibf_dump_object_unsupported, /* 0x17 */
11156  ibf_dump_object_unsupported, /* 0x18 */
11157  ibf_dump_object_unsupported, /* 0x19 */
11158  ibf_dump_object_unsupported, /* T_IMEMO 0x1a */
11159  ibf_dump_object_unsupported, /* T_NODE 0x1b */
11160  ibf_dump_object_unsupported, /* T_ICLASS 0x1c */
11161  ibf_dump_object_unsupported, /* T_ZOMBIE 0x1d */
11162  ibf_dump_object_unsupported, /* 0x1e */
11163  ibf_dump_object_unsupported, /* 0x1f */
11164 };
11165 
11166 static void
11167 ibf_dump_object_object_header(struct ibf_dump *dump, const struct ibf_object_header header)
11168 {
11169  unsigned char byte =
11170  (header.type << 0) |
11171  (header.special_const << 5) |
11172  (header.frozen << 6) |
11173  (header.internal << 7);
11174 
11175  IBF_WV(byte);
11176 }
11177 
11178 static struct ibf_object_header
11179 ibf_load_object_object_header(const struct ibf_load *load, ibf_offset_t *offset)
11180 {
11181  unsigned char byte = ibf_load_byte(load, offset);
11182 
11183  struct ibf_object_header header;
11184  header.type = (byte >> 0) & 0x1f;
11185  header.special_const = (byte >> 5) & 0x01;
11186  header.frozen = (byte >> 6) & 0x01;
11187  header.internal = (byte >> 7) & 0x01;
11188 
11189  return header;
11190 }
11191 
11192 static ibf_offset_t
11193 ibf_dump_object_object(struct ibf_dump *dump, VALUE obj_list, VALUE obj)
11194 {
11195  struct ibf_object_header obj_header;
11196  ibf_offset_t current_offset;
11197  IBF_ZERO(obj_header);
11198  obj_header.type = TYPE(obj);
11199 
11201  current_offset = ibf_dump_pos(dump);
11202 
11203  if (SPECIAL_CONST_P(obj)) {
11204  if (RB_TYPE_P(obj, T_SYMBOL) ||
11205  RB_TYPE_P(obj, T_FLOAT)) {
11206  obj_header.internal = FALSE;
11207  goto dump_object;
11208  }
11209  obj_header.special_const = TRUE;
11210  obj_header.frozen = TRUE;
11211  obj_header.internal = TRUE;
11212  ibf_dump_object_object_header(dump, obj_header);
11213  ibf_dump_write_small_value(dump, obj);
11214  }
11215  else {
11216  obj_header.internal = (RBASIC_CLASS(obj) == 0) ? TRUE : FALSE;
11217  dump_object:
11218  obj_header.special_const = FALSE;
11219  obj_header.frozen = FL_TEST(obj, FL_FREEZE) ? TRUE : FALSE;
11220  ibf_dump_object_object_header(dump, obj_header);
11221  (*dump_object_functions[obj_header.type])(dump, obj);
11222  }
11223 
11224  return current_offset;
11225 }
11226 
11227 typedef VALUE (*ibf_load_object_function)(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset);
11228 static ibf_load_object_function load_object_functions[RUBY_T_MASK+1] = {
11229  ibf_load_object_unsupported, /* T_NONE */
11230  ibf_load_object_unsupported, /* T_OBJECT */
11231  ibf_load_object_class, /* T_CLASS */
11232  ibf_load_object_unsupported, /* T_MODULE */
11233  ibf_load_object_float, /* T_FLOAT */
11234  ibf_load_object_string, /* T_STRING */
11235  ibf_load_object_regexp, /* T_REGEXP */
11236  ibf_load_object_array, /* T_ARRAY */
11237  ibf_load_object_hash, /* T_HASH */
11238  ibf_load_object_struct, /* T_STRUCT */
11239  ibf_load_object_bignum, /* T_BIGNUM */
11240  ibf_load_object_unsupported, /* T_FILE */
11241  ibf_load_object_data, /* T_DATA */
11242  ibf_load_object_unsupported, /* T_MATCH */
11243  ibf_load_object_complex_rational, /* T_COMPLEX */
11244  ibf_load_object_complex_rational, /* T_RATIONAL */
11245  ibf_load_object_unsupported, /* 0x10 */
11246  ibf_load_object_unsupported, /* T_NIL */
11247  ibf_load_object_unsupported, /* T_TRUE */
11248  ibf_load_object_unsupported, /* T_FALSE */
11249  ibf_load_object_symbol,
11250  ibf_load_object_unsupported, /* T_FIXNUM */
11251  ibf_load_object_unsupported, /* T_UNDEF */
11252  ibf_load_object_unsupported, /* 0x17 */
11253  ibf_load_object_unsupported, /* 0x18 */
11254  ibf_load_object_unsupported, /* 0x19 */
11255  ibf_load_object_unsupported, /* T_IMEMO 0x1a */
11256  ibf_load_object_unsupported, /* T_NODE 0x1b */
11257  ibf_load_object_unsupported, /* T_ICLASS 0x1c */
11258  ibf_load_object_unsupported, /* T_ZOMBIE 0x1d */
11259  ibf_load_object_unsupported, /* 0x1e */
11260  ibf_load_object_unsupported, /* 0x1f */
11261 };
11262 
11263 static VALUE
11264 ibf_load_object(const struct ibf_load *load, VALUE object_index)
11265 {
11266  if (object_index == 0) {
11267  return Qnil;
11268  }
11269  else if (object_index >= (VALUE)RARRAY_LEN(load->current_buffer->obj_list)) {
11270  rb_raise(rb_eIndexError, "object index out of range: %"PRIdVALUE, object_index);
11271  }
11272  else {
11273  VALUE obj = rb_ary_entry(load->current_buffer->obj_list, (long)object_index);
11274  if (obj == Qnil) { /* TODO: avoid multiple Qnil load */
11276  ibf_offset_t offset = offsets[object_index];
11277  const struct ibf_object_header header = ibf_load_object_object_header(load, &offset);
11278 
11279 #if IBF_ISEQ_DEBUG
11280  fprintf(stderr, "ibf_load_object: list=%#x offsets=%p offset=%#x\n",
11281  load->current_buffer->obj_list_offset, (void *)offsets, offset);
11282  fprintf(stderr, "ibf_load_object: type=%#x special=%d frozen=%d internal=%d\n",
11283  header.type, header.special_const, header.frozen, header.internal);
11284 #endif
11285  if (offset >= load->current_buffer->size) {
11286  rb_raise(rb_eIndexError, "object offset out of range: %u", offset);
11287  }
11288 
11289  if (header.special_const) {
11290  ibf_offset_t reading_pos = offset;
11291 
11292  obj = ibf_load_small_value(load, &reading_pos);
11293  }
11294  else {
11295  obj = (*load_object_functions[header.type])(load, &header, offset);
11296  }
11297 
11298  rb_ary_store(load->current_buffer->obj_list, (long)object_index, obj);
11299  }
11300 #if IBF_ISEQ_DEBUG
11301  fprintf(stderr, "ibf_load_object: index=%#"PRIxVALUE" obj=%#"PRIxVALUE"\n",
11302  object_index, obj);
11303 #endif
11304  return obj;
11305  }
11306 }
11307 
11308 static void
11309 ibf_dump_object_list(struct ibf_dump *dump, ibf_offset_t *obj_list_offset, unsigned int *obj_list_size)
11310 {
11311  VALUE obj_list = dump->current_buffer->obj_list;
11312  VALUE list = rb_ary_tmp_new(RARRAY_LEN(obj_list));
11313  int i, size;
11314 
11315  for (i=0; i<RARRAY_LEN(obj_list); i++) {
11316  VALUE obj = RARRAY_AREF(obj_list, i);
11317  ibf_offset_t offset = ibf_dump_object_object(dump, obj_list, obj);
11318  rb_ary_push(list, UINT2NUM(offset));
11319  }
11320  size = i;
11322  *obj_list_offset = ibf_dump_pos(dump);
11323 
11324  for (i=0; i<size; i++) {
11325  ibf_offset_t offset = NUM2UINT(RARRAY_AREF(list, i));
11326  IBF_WV(offset);
11327  }
11328 
11329  *obj_list_size = size;
11330 }
11331 
11332 static void
11333 ibf_dump_mark(void *ptr)
11334 {
11335  struct ibf_dump *dump = (struct ibf_dump *)ptr;
11336  rb_gc_mark(dump->global_buffer.str);
11338  rb_gc_mark(dump->iseq_list);
11339 }
11340 
11341 static void
11342 ibf_dump_free(void *ptr)
11343 {
11344  struct ibf_dump *dump = (struct ibf_dump *)ptr;
11345  if (dump->iseq_table) {
11346  st_free_table(dump->iseq_table);
11347  dump->iseq_table = 0;
11348  }
11349  ruby_xfree(dump);
11350 }
11351 
11352 static size_t
11353 ibf_dump_memsize(const void *ptr)
11354 {
11355  struct ibf_dump *dump = (struct ibf_dump *)ptr;
11356  size_t size = sizeof(*dump);
11357  if (dump->iseq_table) size += st_memsize(dump->iseq_table);
11358  return size;
11359 }
11360 
11361 static const rb_data_type_t ibf_dump_type = {
11362  "ibf_dump",
11363  {ibf_dump_mark, ibf_dump_free, ibf_dump_memsize,},
11365 };
11366 
11367 static void
11368 ibf_dump_setup(struct ibf_dump *dump, VALUE dumper_obj)
11369 {
11370  RB_OBJ_WRITE(dumper_obj, &dump->iseq_list, rb_ary_tmp_new(0));
11371  RB_OBJ_WRITE(dumper_obj, &dump->global_buffer.obj_list, ibf_dump_object_list_new());
11372  RB_OBJ_WRITE(dumper_obj, &dump->global_buffer.str, rb_str_new(0, 0));
11373  dump->iseq_table = st_init_numtable(); /* need free */
11374 
11375  dump->current_buffer = &dump->global_buffer;
11376 }
11377 
11378 VALUE
11380 {
11381  struct ibf_dump *dump;
11382  struct ibf_header header = {{0}};
11383  VALUE dump_obj;
11384  VALUE str;
11385 
11386  if (iseq->body->parent_iseq != NULL ||
11387  iseq->body->local_iseq != iseq) {
11388  rb_raise(rb_eRuntimeError, "should be top of iseq");
11389  }
11390  if (RTEST(ISEQ_COVERAGE(iseq))) {
11391  rb_raise(rb_eRuntimeError, "should not compile with coverage");
11392  }
11393 
11394  dump_obj = TypedData_Make_Struct(0, struct ibf_dump, &ibf_dump_type, dump);
11395  ibf_dump_setup(dump, dump_obj);
11396 
11397  ibf_dump_write(dump, &header, sizeof(header));
11398  ibf_dump_write(dump, RUBY_PLATFORM, strlen(RUBY_PLATFORM) + 1);
11399  ibf_dump_iseq(dump, iseq);
11400 
11401  header.magic[0] = 'Y'; /* YARB */
11402  header.magic[1] = 'A';
11403  header.magic[2] = 'R';
11404  header.magic[3] = 'B';
11407  ibf_dump_iseq_list(dump, &header);
11408  ibf_dump_object_list(dump, &header.global_object_list_offset, &header.global_object_list_size);
11409  header.size = ibf_dump_pos(dump);
11410 
11411  if (RTEST(opt)) {
11412  VALUE opt_str = opt;
11413  const char *ptr = StringValuePtr(opt_str);
11414  header.extra_size = RSTRING_LENINT(opt_str);
11415  ibf_dump_write(dump, ptr, header.extra_size);
11416  }
11417  else {
11418  header.extra_size = 0;
11419  }
11420 
11421  ibf_dump_overwrite(dump, &header, sizeof(header), 0);
11422 
11423  str = dump->global_buffer.str;
11424  ibf_dump_free(dump);
11425  DATA_PTR(dump_obj) = NULL;
11426  RB_GC_GUARD(dump_obj);
11427  return str;
11428 }
11429 
11430 static const ibf_offset_t *
11431 ibf_iseq_list(const struct ibf_load *load)
11432 {
11433  return (const ibf_offset_t *)(load->global_buffer.buff + load->header->iseq_list_offset);
11434 }
11435 
11436 void
11438 {
11439  struct ibf_load *load = RTYPEDDATA_DATA(iseq->aux.loader.obj);
11440  rb_iseq_t *prev_src_iseq = load->iseq;
11441  ibf_offset_t offset = ibf_iseq_list(load)[iseq->aux.loader.index];
11442  load->iseq = iseq;
11443 #if IBF_ISEQ_DEBUG
11444  fprintf(stderr, "rb_ibf_load_iseq_complete: index=%#x offset=%#x size=%#x\n",
11445  iseq->aux.loader.index, offset,
11446  load->header->size);
11447 #endif
11448  ibf_load_iseq_each(load, iseq, offset);
11449  ISEQ_COMPILE_DATA_CLEAR(iseq);
11452  load->iseq = prev_src_iseq;
11453 }
11454 
11455 #if USE_LAZY_LOAD
11457 rb_iseq_complete(const rb_iseq_t *iseq)
11458 {
11460  return iseq;
11461 }
11462 #endif
11463 
11464 static rb_iseq_t *
11465 ibf_load_iseq(const struct ibf_load *load, const rb_iseq_t *index_iseq)
11466 {
11467  int iseq_index = (int)(VALUE)index_iseq;
11468 
11469 #if IBF_ISEQ_DEBUG
11470  fprintf(stderr, "ibf_load_iseq: index_iseq=%p iseq_list=%p\n",
11471  (void *)index_iseq, (void *)load->iseq_list);
11472 #endif
11473  if (iseq_index == -1) {
11474  return NULL;
11475  }
11476  else {
11477  VALUE iseqv = rb_ary_entry(load->iseq_list, iseq_index);
11478 
11479 #if IBF_ISEQ_DEBUG
11480  fprintf(stderr, "ibf_load_iseq: iseqv=%p\n", (void *)iseqv);
11481 #endif
11482  if (iseqv != Qnil) {
11483  return (rb_iseq_t *)iseqv;
11484  }
11485  else {
11486  rb_iseq_t *iseq = iseq_imemo_alloc();
11487 #if IBF_ISEQ_DEBUG
11488  fprintf(stderr, "ibf_load_iseq: new iseq=%p\n", (void *)iseq);
11489 #endif
11491  iseq->aux.loader.obj = load->loader_obj;
11492  iseq->aux.loader.index = iseq_index;
11493 #if IBF_ISEQ_DEBUG
11494  fprintf(stderr, "ibf_load_iseq: iseq=%p loader_obj=%p index=%d\n",
11495  (void *)iseq, (void *)load->loader_obj, iseq_index);
11496 #endif
11497  rb_ary_store(load->iseq_list, iseq_index, (VALUE)iseq);
11498 
11499 #if !USE_LAZY_LOAD
11500 #if IBF_ISEQ_DEBUG
11501  fprintf(stderr, "ibf_load_iseq: loading iseq=%p\n", (void *)iseq);
11502 #endif
11504 #else
11505  if (GET_VM()->builtin_function_table) {
11507  }
11508 #endif /* !USE_LAZY_LOAD */
11509 
11510 #if IBF_ISEQ_DEBUG
11511  fprintf(stderr, "ibf_load_iseq: iseq=%p loaded %p\n",
11512  (void *)iseq, (void *)load->iseq);
11513 #endif
11514  return iseq;
11515  }
11516  }
11517 }
11518 
11519 static void
11520 ibf_load_setup_bytes(struct ibf_load *load, VALUE loader_obj, const char *bytes, size_t size)
11521 {
11522  load->loader_obj = loader_obj;
11523  load->global_buffer.buff = bytes;
11524  load->header = (struct ibf_header *)load->global_buffer.buff;
11525  load->global_buffer.size = load->header->size;
11528  RB_OBJ_WRITE(loader_obj, &load->iseq_list, rb_ary_tmp_new(0));
11531  load->iseq = NULL;
11532 
11533  load->current_buffer = &load->global_buffer;
11534 
11535  if (size < load->header->size) {
11536  rb_raise(rb_eRuntimeError, "broken binary format");
11537  }
11538  if (strncmp(load->header->magic, "YARB", 4) != 0) {
11539  rb_raise(rb_eRuntimeError, "unknown binary format");
11540  }
11541  if (load->header->major_version != IBF_MAJOR_VERSION ||
11543  rb_raise(rb_eRuntimeError, "unmatched version file (%u.%u for %u.%u)",
11545  }
11546  if (strcmp(load->global_buffer.buff + sizeof(struct ibf_header), RUBY_PLATFORM) != 0) {
11547  rb_raise(rb_eRuntimeError, "unmatched platform");
11548  }
11550  rb_raise(rb_eArgError, "unaligned iseq list offset: %u",
11551  load->header->iseq_list_offset);
11552  }
11554  rb_raise(rb_eArgError, "unaligned object list offset: %u",
11556  }
11557 }
11558 
11559 static void
11560 ibf_load_setup(struct ibf_load *load, VALUE loader_obj, VALUE str)
11561 {
11562  if (RSTRING_LENINT(str) < (int)sizeof(struct ibf_header)) {
11563  rb_raise(rb_eRuntimeError, "broken binary format");
11564  }
11565 
11566 #if USE_LAZY_LOAD
11568 #endif
11569 
11570  ibf_load_setup_bytes(load, loader_obj, StringValuePtr(str), RSTRING_LEN(str));
11571  RB_OBJ_WRITE(loader_obj, &load->str, str);
11572 }
11573 
11574 static void
11575 ibf_loader_mark(void *ptr)
11576 {
11577  struct ibf_load *load = (struct ibf_load *)ptr;
11578  rb_gc_mark(load->str);
11579  rb_gc_mark(load->iseq_list);
11581 }
11582 
11583 static void
11584 ibf_loader_free(void *ptr)
11585 {
11586  struct ibf_load *load = (struct ibf_load *)ptr;
11587  ruby_xfree(load);
11588 }
11589 
11590 static size_t
11591 ibf_loader_memsize(const void *ptr)
11592 {
11593  return sizeof(struct ibf_load);
11594 }
11595 
11596 static const rb_data_type_t ibf_load_type = {
11597  "ibf_loader",
11598  {ibf_loader_mark, ibf_loader_free, ibf_loader_memsize,},
11600 };
11601 
11602 const rb_iseq_t *
11604 {
11605  struct ibf_load *load;
11606  rb_iseq_t *iseq;
11607  VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
11608 
11609  ibf_load_setup(load, loader_obj, str);
11610  iseq = ibf_load_iseq(load, 0);
11611 
11613  return iseq;
11614 }
11615 
11616 const rb_iseq_t *
11617 rb_iseq_ibf_load_bytes(const char *bytes, size_t size)
11618 {
11619  struct ibf_load *load;
11620  rb_iseq_t *iseq;
11621  VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
11622 
11623  ibf_load_setup_bytes(load, loader_obj, bytes, size);
11624  iseq = ibf_load_iseq(load, 0);
11625 
11627  return iseq;
11628 }
11629 
11630 VALUE
11632 {
11633  struct ibf_load *load;
11634  VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
11635  VALUE extra_str;
11636 
11637  ibf_load_setup(load, loader_obj, str);
11638  extra_str = rb_str_new(load->global_buffer.buff + load->header->size, load->header->extra_size);
11640  return extra_str;
11641 }
rb_cArray
VALUE rb_cArray
Definition: array.c:27
NODE_NEXT
@ NODE_NEXT
Definition: node.h:38
ibf_object_struct_range::class_index
long class_index
Definition: compile.c:10728
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
strncmp
int strncmp(const char *, const char *, size_t)
va_end
#define va_end(v)
Definition: rb_mjit_min_header-2.7.2.h:3982
rb_ary_new_capa
VALUE rb_ary_new_capa(long capa)
Definition: array.c:717
NODE_COLON3
@ NODE_COLON3
Definition: node.h:110
abort
void abort(void) __attribute__((__noreturn__))
rb_kwarg_call_data
Definition: vm_core.h:257
NODE_FL_NEWLINE
#define NODE_FL_NEWLINE
Definition: node.h:183
min_argc
const rb_iseq_t const int const int min_argc
Definition: rb_mjit_min_header-2.7.2.h:13470
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:116
ID
unsigned long ID
Definition: ruby.h:103
ruby_xfree
void ruby_xfree(void *x)
Definition: gc.c:10170
rb_str_concat
VALUE rb_str_concat(VALUE, VALUE)
Definition: string.c:3065
BIGNUM_DIGITS
#define BIGNUM_DIGITS(b)
Definition: internal.h:780
idSucc
@ idSucc
Definition: rb_mjit_min_header-2.7.2.h:8666
rb_iseq_constant_body::variable
struct rb_iseq_constant_body::@4 variable
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:9522
rb_raw_obj_info
const char * rb_raw_obj_info(char *buff, const int buff_size, VALUE obj)
Definition: gc.c:11447
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
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:10197
TRUE
#define TRUE
Definition: nkf.h:175
iseq_compile_data_ensure_node_stack::ensure_node
const NODE * ensure_node
Definition: compile.c:105
NODE_ATTRASGN
@ NODE_ATTRASGN
Definition: node.h:123
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
ibf_header::iseq_list_size
unsigned int iseq_list_size
Definition: compile.c:9519
INSERT_AFTER_INSN1
#define INSERT_AFTER_INSN1(prev, line, insn, op1)
Definition: compile.c:226
NODE_DSYM
@ NODE_DSYM
Definition: node.h:122
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:10729
ibf_load_buffer::obj_list
VALUE obj_list
Definition: compile.c:9543
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:126
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:42
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:9504
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:11130
st_table::num_entries
st_index_t num_entries
Definition: st.h:86
iseq_insn_data::insn_info
struct iseq_insn_data::@1 insn_info
NODE_OP_ASGN1
@ NODE_OP_ASGN1
Definition: node.h:55
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:455
rb_iseq_struct
Definition: vm_core.h:456
rb_hash_new
VALUE rb_hash_new(void)
Definition: hash.c:1523
NODE_TRUE
@ NODE_TRUE
Definition: node.h:117
cfp
rb_control_frame_t * cfp
Definition: rb_mjit_min_header-2.7.2.h:14524
rb_iseq_new_with_callback_callback_func
Definition: vm_core.h:1018
idERROR_INFO
@ idERROR_INFO
Definition: rb_mjit_min_header-2.7.2.h:8718
compile_debug
#define compile_debug
Definition: compile.c:130
rb_warn
void rb_warn(const char *fmt,...)
Definition: error.c:315
iseq_compile_data_storage::buff
char buff[FLEX_ARY_LEN]
Definition: iseq.h:278
NODE_MATCH3
@ NODE_MATCH3
Definition: node.h:83
rb_local_defined
int rb_local_defined(ID id, const rb_iseq_t *iseq)
Definition: compile.c:9382
idOr
@ idOr
Definition: id.h:101
NODE_NTH_REF
@ NODE_NTH_REF
Definition: node.h:79
NODE_ZLIST
@ NODE_ZLIST
Definition: node.h:68
ibf_header
Definition: compile.c:9512
NODE_SPECIAL_EXCESSIVE_COMMA
#define NODE_SPECIAL_EXCESSIVE_COMMA
Definition: node.h:385
NODE_DREGX
@ NODE_DREGX
Definition: node.h:90
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
gc.h
rb_insns_name_array
VALUE rb_insns_name_array(void)
Definition: compile.c:8768
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:46
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
int
__inline__ int
Definition: rb_mjit_min_header-2.7.2.h:2845
NODE_ARYPTN
@ NODE_ARYPTN
Definition: node.h:125
ibf_object_header::type
unsigned int type
Definition: compile.c:10703
IS_ADJUST
#define IS_ADJUST(link)
Definition: compile.c:366
RBASIC_CLEAR_CLASS
#define RBASIC_CLEAR_CLASS(obj)
Definition: internal.h:1987
ibf_header::size
unsigned int size
Definition: compile.c:9516
id_core_raise
@ id_core_raise
Definition: id.h:128
rb_iseq_constant_body::table
const ID * table
Definition: vm_core.h:394
NODE_OP_ASGN_OR
@ NODE_OP_ASGN_OR
Definition: node.h:58
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
VM_CALL_ZSUPER
#define VM_CALL_ZSUPER
Definition: vm_core.h:1111
cdhash_set_label_struct::hash
VALUE hash
Definition: compile.c:1851
INSN
struct iseq_insn_data INSN
NODE_HASH
@ NODE_HASH
Definition: node.h:70
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:11978
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:2603
NODE_CONST
@ NODE_CONST
Definition: node.h:77
rb_num_t
unsigned long rb_num_t
Definition: vm_core.h:181
RHASH_SIZE
#define RHASH_SIZE(h)
Definition: ruby.h:1130
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:166
IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR
@ IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR
Definition: compile.c:10713
RSTRING_PTR
#define RSTRING_PTR(str)
Definition: ruby.h:1009
re.h
COMPILE_ERROR
#define COMPILE_ERROR
Definition: compile.c:413
i
uint32_t i
Definition: rb_mjit_min_header-2.7.2.h:5460
rb_dbl2big
VALUE rb_dbl2big(double d)
Definition: bignum.c:5249
idMINUS
@ idMINUS
Definition: id.h:86
idGT
@ idGT
Definition: id.h:94
NODE_LASGN
@ NODE_LASGN
Definition: node.h:48
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
ibf_object_complex_rational::b
long b
Definition: compile.c:10745
ci
rb_control_frame_t struct rb_calling_info const struct rb_call_info * ci
Definition: rb_mjit_min_header-2.7.2.h:15126
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:2037
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:98
NODE_FLIP2
@ NODE_FLIP2
Definition: node.h:113
NODE_FOR
@ NODE_FOR
Definition: node.h:35
ibf_object_class_index
ibf_object_class_index
Definition: compile.c:10709
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:9501
VALUE
unsigned long VALUE
Definition: ruby.h:102
NODE_CASE
@ NODE_CASE
Definition: node.h:27
long
#define long
Definition: rb_mjit_min_header-2.7.2.h:2889
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:925
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
va_list
__gnuc_va_list va_list
Definition: rb_mjit_min_header-2.7.2.h:834
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:56
NODE_ARGSCAT
@ NODE_ARGSCAT
Definition: node.h:97
LABEL_REF
#define LABEL_REF(label)
Definition: compile.c:230
rb_eSyntaxError
VALUE rb_eSyntaxError
Definition: error.c:940
RB_TYPE_P
#define RB_TYPE_P(obj, type)
Definition: ruby.h:560
iseq_insn_data::operands
VALUE * operands
Definition: compile.c:79
rb_iseq_constant_body::keyword
const struct rb_iseq_constant_body::@3::rb_iseq_param_keyword * keyword
rb_xmalloc_mul_add
void * rb_xmalloc_mul_add(size_t x, size_t y, size_t z)
Definition: gc.c:10176
idFreeze
@ idFreeze
Definition: rb_mjit_min_header-2.7.2.h:8651
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:436
nd_last_lineno
#define nd_last_lineno(n)
Definition: node.h:207
NODE_DOT2
@ NODE_DOT2
Definition: node.h:111
NODE_EVSTR
@ NODE_EVSTR
Definition: node.h:89
debug_node_start
#define debug_node_start(node)
Definition: compile.c:174
ibf_object_bignum::slen
ssize_t slen
Definition: compile.c:10736
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:10749
DEFINED_REF
@ DEFINED_REF
Definition: iseq.h:300
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:445
NUM2LL
#define NUM2LL(x)
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_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
entries
struct iseq_catch_table_entry entries[]
INSERT_BEFORE_INSN
#define INSERT_BEFORE_INSN(next, line, insn)
Definition: compile.c:208
NODE_UNTIL
@ NODE_UNTIL
Definition: node.h:33
rb_args_info::post_init
NODE * post_init
Definition: node.h:434
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:54
NODE_AND
@ NODE_AND
Definition: node.h:45
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:84
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:11617
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:9418
rb_eIndexError
VALUE rb_eIndexError
Definition: error.c:926
RUBY_EVENT_B_RETURN
#define RUBY_EVENT_B_RETURN
Definition: ruby.h:2254
NODE_MASGN
@ NODE_MASGN
Definition: node.h:47
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:10745
ibf_object_hash::len
long len
Definition: compile.c:10723
Qundef
#define Qundef
Definition: ruby.h:470
ibf_header::minor_version
unsigned int minor_version
Definition: compile.c:9515
NODE_DXSTR
@ NODE_DXSTR
Definition: node.h:88
CHAR_BIT
#define CHAR_BIT
Definition: ruby.h:227
NODE_OPCALL
@ NODE_OPCALL
Definition: node.h:61
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
idLE
@ idLE
Definition: id.h:93
ptr
struct RIMemo * ptr
Definition: debug.c:65
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
ibf_load
Definition: compile.c:9548
rb_iseq_constant_body::param
struct rb_iseq_constant_body::@3 param
parameter information
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
RNode::flags
VALUE flags
Definition: node.h:150
NODE_OP_ASGN_AND
@ NODE_OP_ASGN_AND
Definition: node.h:57
LABEL_RESCUE_BEG
@ LABEL_RESCUE_BEG
Definition: compile.c:57
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:10744
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
VM_INSTRUCTION_SIZE
@ VM_INSTRUCTION_SIZE
Definition: rb_mjit_min_header-2.7.2.h:12144
NODE_DASGN
@ NODE_DASGN
Definition: node.h:49
ADD_TRACE_BRANCH_COVERAGE
#define ADD_TRACE_BRANCH_COVERAGE(seq, first_line, first_column, last_line, last_column, type, branches)
Definition: compile.c:286
RUBY_ALIGNOF
#define RUBY_ALIGNOF(type)
Definition: defines.h:517
SPECIAL_CONST_P
#define SPECIAL_CONST_P(x)
Definition: ruby.h:1313
NODE_BLOCK
@ NODE_BLOCK
Definition: node.h:24
VM_CALL_KWARG
#define VM_CALL_KWARG
Definition: vm_core.h:1107
id_core_undef_method
@ id_core_undef_method
Definition: id.h:122
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:3115
rb_ibf_load_iseq_complete
void rb_ibf_load_iseq_complete(rb_iseq_t *iseq)
Definition: compile.c:11437
ADD_CATCH_ENTRY
#define ADD_CATCH_ENTRY(type, ls, le, iseqv, lc)
Definition: compile.c:326
NULL
#define NULL
Definition: _sdbm.c:101
ibf_object_struct_range::excl
int excl
Definition: compile.c:10732
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:119
rb_args_info::first_post_arg
ID first_post_arg
Definition: node.h:439
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:10741
ibf_load::str
VALUE str
Definition: compile.c:9554
DEFINED_FALSE
@ DEFINED_FALSE
Definition: iseq.h:296
rb_iseq_struct::loader
struct rb_iseq_struct::@6::@7 loader
OPERAND_AT
#define OPERAND_AT(insn, idx)
Definition: compile.c:358
fmt
const VALUE int int int int int int VALUE char * fmt
Definition: rb_mjit_min_header-2.7.2.h:6458
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:9477
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:9110
last
unsigned int last
Definition: nkf.c:4324
NODE_KW_ARG
@ NODE_KW_ARG
Definition: node.h:95
NODE_DSTR
@ NODE_DSTR
Definition: node.h:86
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:9514
ibf_load_buffer::buff
const char * buff
Definition: compile.c:9540
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.2.h:10828
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:99
INIT_ANCHOR
#define INIT_ANCHOR(name)
Definition: compile.c:456
NODE_ITER
@ NODE_ITER
Definition: node.h:34
rb_mark_set
void rb_mark_set(st_table *tbl)
Definition: gc.c:4801
rb_call_info::orig_argc
int orig_argc
Definition: internal.h:2397
NODE_CDECL
@ NODE_CDECL
Definition: node.h:53
rb_iseq_constant_body
Definition: vm_core.h:311
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:444
ibf_object_data_type
ibf_object_data_type
Definition: compile.c:10740
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:78
rb_snum_t
signed long rb_snum_t
Definition: vm_core.h:182
rb_eNoMatchingPatternError
VALUE rb_eNoMatchingPatternError
Definition: error.c:937
rb_hash_new_with_size
MJIT_FUNC_EXPORTED VALUE rb_hash_new_with_size(st_index_t size)
Definition: hash.c:1529
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
rb_cRange
RUBY_EXTERN VALUE rb_cRange
Definition: ruby.h:2040
rb_args_info::pre_init
NODE * pre_init
Definition: node.h:433
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:31
ADD_SEND
#define ADD_SEND(seq, line, id, argc)
Definition: compile.c:244
void
void
Definition: rb_mjit_min_header-2.7.2.h:13241
rb_ast_body_struct::compile_option
VALUE compile_option
Definition: node.h:396
NODE_ZSUPER
@ NODE_ZSUPER
Definition: node.h:66
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:65
NODE_LAMBDA
@ NODE_LAMBDA
Definition: node.h:124
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:9545
TRACE
struct iseq_trace_data TRACE
rb_raise
void rb_raise(VALUE exc, const char *fmt,...)
Definition: error.c:2671
rb_str_hash_cmp
int rb_str_hash_cmp(VALUE, VALUE)
Definition: string.c:3173
NODE_VCALL
@ NODE_VCALL
Definition: node.h:63
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:2953
NODE_VALIAS
@ NODE_VALIAS
Definition: node.h:104
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:2361
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:10748
if
if((ID)(DISPID) nameid !=nameid)
Definition: win32ole.c:357
NODE_DEFS
@ NODE_DEFS
Definition: node.h:102
ibf_object_struct_range::beg
long beg
Definition: compile.c:10730
VM_DEFINECLASS_FLAG_SCOPED
#define VM_DEFINECLASS_FLAG_SCOPED
Definition: vm_core.h:1002
ibf_dump_buffer::obj_list
VALUE obj_list
Definition: compile.c:9527
NODE_UNLESS
@ NODE_UNLESS
Definition: node.h:26
ibf_dump::current_buffer
struct ibf_dump_buffer * current_buffer
Definition: compile.c:9534
ge
#define ge(x, y)
Definition: time.c:86
gt
#define gt(x, y)
Definition: time.c:84
idTo_s
@ idTo_s
Definition: rb_mjit_min_header-2.7.2.h:8685
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_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
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:10710
NODE_DEFN
@ NODE_DEFN
Definition: node.h:101
idASET
@ idASET
Definition: id.h:106
rb_args_info::opt_args
NODE * opt_args
Definition: node.h:447
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
stdout
#define stdout
Definition: rb_mjit_min_header-2.7.2.h:1515
snprintf
int snprintf(char *__restrict, size_t, const char *__restrict,...) __attribute__((__format__(__printf__
keys
const rb_iseq_t const char const VALUE keys
Definition: rb_mjit_min_header-2.7.2.h:13471
rb_iseq_constant_body::lead_num
int lead_num
Definition: vm_core.h:367
idBACKREF
@ idBACKREF
Definition: rb_mjit_min_header-2.7.2.h:8717
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
rb_args_info
Definition: node.h:432
rb_hash_rehash
VALUE rb_hash_rehash(VALUE hash)
Definition: hash.c:1958
ibf_dump::global_buffer
struct ibf_dump_buffer global_buffer
Definition: compile.c:9533
TAG_REDO
#define TAG_REDO
Definition: vm_core.h:202
ibf_object_header::frozen
unsigned int frozen
Definition: compile.c:10705
rb_ary_pattern_info::post_args
NODE * post_args
Definition: node.h:457
ensure_range::end
LABEL * end
Definition: compile.c:100
idLTLT
@ idLTLT
Definition: id.h:90
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:456
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:9532
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:9198
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:449
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:2222
METHOD
Definition: proc.c:33
RUBY_FUNCTION_NAME_STRING
#define RUBY_FUNCTION_NAME_STRING
Definition: rb_mjit_min_header-2.7.2.h:190
NODE_CLASS
@ NODE_CLASS
Definition: node.h:106
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:9486
NODE_IF
@ NODE_IF
Definition: node.h:25
rb_id2sym
VALUE rb_id2sym(ID)
Definition: symbol.c:776
NODE_ENSURE
@ NODE_ENSURE
Definition: node.h:44
ibf_header::magic
char magic[4]
Definition: compile.c:9513
OnigEncodingTypeST
Definition: onigmo.h:160
idUScore
@ idUScore
Definition: rb_mjit_min_header-2.7.2.h:8704
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:763
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:9250
NODE_MATCH2
@ NODE_MATCH2
Definition: node.h:82
rb_iseq_constant_body::ci_size
unsigned int ci_size
Definition: vm_core.h:437
VM_THROW_NO_ESCAPE_FLAG
@ VM_THROW_NO_ESCAPE_FLAG
Definition: vm_core.h:209
rb_node_case_when_optimizable_literal
VALUE rb_node_case_when_optimizable_literal(const NODE *const node)
Definition: compile.c:4289
rb_fstring_cstr
#define rb_fstring_cstr(str)
Definition: rb_mjit_min_header-2.7.2.h:7681
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:2063
ADD_ADJUST_RESTORE
#define ADD_ADJUST_RESTORE(seq, label)
Definition: compile.c:321
IBF_W
#define IBF_W(b, type, n)
Definition: compile.c:9633
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:29
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
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
RARRAY_AREF
#define RARRAY_AREF(a, i)
Definition: psych_emitter.c:7
iseq_insn_data::operand_size
int operand_size
Definition: compile.c:77
vm_core.h
rb_hash_bulk_insert
void rb_hash_bulk_insert(long argc, const VALUE *argv, VALUE hash)
Definition: hash.c:4590
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:50
rb_call_data::cc
struct rb_call_cache cc
Definition: internal.h:2400
rb_eTypeError
VALUE rb_eTypeError
Definition: error.c:924
IBF_WV
#define IBF_WV(variable)
Definition: compile.c:9634
RBASIC_CLASS
#define RBASIC_CLASS(obj)
Definition: ruby.h:906
NODE_COLON2
@ NODE_COLON2
Definition: node.h:109
NODE_DOT3
@ NODE_DOT3
Definition: node.h:112
SYM
#define SYM(s)
idPLUS
@ idPLUS
Definition: id.h:85
node_type
node_type
Definition: node.h:22
vars
const VALUE int int int int int int VALUE * vars[]
Definition: rb_mjit_min_header-2.7.2.h:6458
rb_call_info::mid
ID mid
Definition: internal.h:2395
LVAR_ERRINFO
#define LVAR_ERRINFO
Definition: compile.c:187
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
idMin
@ idMin
Definition: rb_mjit_min_header-2.7.2.h:8650
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:9509
idCall
@ idCall
Definition: rb_mjit_min_header-2.7.2.h:8691
ibf_load::iseq
rb_iseq_t * iseq
Definition: compile.c:9553
NODE_BREAK
@ NODE_BREAK
Definition: node.h:37
rb_eRuntimeError
VALUE rb_eRuntimeError
Definition: error.c:922
NODE_GVAR
@ NODE_GVAR
Definition: node.h:75
va_arg
#define va_arg(v, l)
Definition: rb_mjit_min_header-2.7.2.h:3983
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
rb_control_frame_struct
Definition: vm_core.h:760
NODE_XSTR
@ NODE_XSTR
Definition: node.h:87
BIN
#define BIN(n)
Definition: rb_mjit_min_header-2.7.2.h:11936
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:9637
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:10717
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
LABEL_RESCUE_END
@ LABEL_RESCUE_END
Definition: compile.c:58
NODE_ARGS
@ NODE_ARGS
Definition: node.h:92
VM_DEFINECLASS_TYPE_CLASS
@ VM_DEFINECLASS_TYPE_CLASS
Definition: vm_core.h:994
ibf_load::loader_obj
VALUE loader_obj
Definition: compile.c:9552
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:9419
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:11988
arg
VALUE arg
Definition: rb_mjit_min_header-2.7.2.h:5597
IBF_W_ALIGN
#define IBF_W_ALIGN(type)
Definition: compile.c:9631
NODE_DVAR
@ NODE_DVAR
Definition: node.h:74
rb_hash_foreach
void rb_hash_foreach(VALUE hash, rb_foreach_func *func, VALUE farg)
Definition: hash.c:1483
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
ibf_header::iseq_list_offset
ibf_offset_t iseq_list_offset
Definition: compile.c:9521
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:103
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:437
VM_CALL_ARGS_BLOCKARG
#define VM_CALL_ARGS_BLOCKARG
Definition: vm_core.h:1102
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.2.h:14524
rb_iseq_new_with_callback_callback_func::data
const void * data
Definition: vm_core.h:1022
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:59
IBF_OBJECT_CLASS_STANDARD_ERROR
@ IBF_OBJECT_CLASS_STANDARD_ERROR
Definition: compile.c:10712
realpath
char * realpath(const char *__restrict path, char *__restrict resolved_path)
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:96
le
#define le(x, y)
Definition: time.c:85
NODE_SELF
@ NODE_SELF
Definition: node.h:115
ibf_header::extra_size
unsigned int extra_size
Definition: compile.c:9517
rb_args_info::no_kwarg
unsigned int no_kwarg
Definition: node.h:448
rb_cISeq
VALUE rb_cISeq
Definition: iseq.c:32
NODE_LVAR
@ NODE_LVAR
Definition: node.h:73
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:712
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:934
NODE_STR
@ NODE_STR
Definition: node.h:85
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
va_init_list
#define va_init_list(a, b)
Definition: win32ole.h:34
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
dup
int dup(int __fildes)
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:9526
iseq_label_data
Definition: compile.c:62
rb_reg_options
int rb_reg_options(VALUE)
Definition: re.c:3579
NODE_IVAR
@ NODE_IVAR
Definition: node.h:76
IBF_WP
#define IBF_WP(b, type, n)
Definition: compile.c:9635
DEFINED_SELF
@ DEFINED_SELF
Definition: iseq.h:294
LONG_LONG
#define LONG_LONG
Definition: rb_mjit_min_header-2.7.2.h:3942
rb_cObject
RUBY_EXTERN VALUE rb_cObject
Definition: ruby.h:2010
ibf_dump_buffer
Definition: compile.c:9525
div
void div_t div(int __numer, int __denom)
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
ISEQ_COVERAGE_SET
#define ISEQ_COVERAGE_SET(iseq, cov)
Definition: iseq.h:35
debug_node_end
#define debug_node_end()
Definition: compile.c:175
obj
const VALUE VALUE obj
Definition: rb_mjit_min_header-2.7.2.h:5738
T_BIGNUM
#define T_BIGNUM
Definition: ruby.h:533
NODE_BEGIN
@ NODE_BEGIN
Definition: node.h:41
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:10711
NODE_POSTEXE
@ NODE_POSTEXE
Definition: node.h:121
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:43
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:636
NODE_RETURN
@ NODE_RETURN
Definition: node.h:71
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:118
T_ARRAY
#define T_ARRAY
Definition: ruby.h:530
argv
char ** argv
Definition: ruby.c:223
iseq_trace_data::link
LINK_ELEMENT link
Definition: compile.c:93
NODE_ONCE
@ NODE_ONCE
Definition: node.h:91
rb_set_errinfo
void rb_set_errinfo(VALUE err)
Sets the current exception ($!) to the given value.
Definition: eval.c:1896
idOROP
@ idOROP
Definition: id.h:109
ibf_load::current_buffer
struct ibf_load_buffer * current_buffer
Definition: compile.c:9555
iseq_alloc
rb_iseq_t * iseq_alloc(void)
ST_CONTINUE
@ ST_CONTINUE
Definition: st.h:99
ibf_load::header
const struct ibf_header * header
Definition: compile.c:9549
rb_iseq_constant_body::iseq_encoded
VALUE * iseq_encoded
Definition: vm_core.h:325
NODE_IASGN
@ NODE_IASGN
Definition: node.h:52
idLambda
@ idLambda
Definition: rb_mjit_min_header-2.7.2.h:8669
xmalloc
#define xmalloc
Definition: defines.h:211
ibf_object_header
Definition: compile.c:10702
ibf_object_regexp::option
char option
Definition: compile.c:10719
iseq_catch_table::entries
struct iseq_catch_table_entry entries[]
Definition: rb_mjit_min_header-2.7.2.h:10828
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
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
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
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
iseq_adjust_data::line_no
int line_no
Definition: compile.c:89
ibf_dump
Definition: compile.c:9530
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:54
NODE_WHEN
@ NODE_WHEN
Definition: node.h:30
NODE_BLOCK_PASS
@ NODE_BLOCK_PASS
Definition: node.h:100
rb_control_frame_struct::iseq
const rb_iseq_t * iseq
Definition: vm_core.h:763
NODE_MATCH
@ NODE_MATCH
Definition: node.h:81
memcpy
void * memcpy(void *__restrict, const void *__restrict, size_t)
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:9111
ibf_object_struct_range
Definition: compile.c:10727
accessor_args::line
int line
Definition: compile.c:9420
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:63
ibf_object_bignum
Definition: compile.c:10735
path
VALUE path
Definition: rb_mjit_min_header-2.7.2.h:7336
rb_hash_aset
VALUE rb_hash_aset(VALUE hash, VALUE key, VALUE val)
Definition: hash.c:2852
ssize_t
_ssize_t ssize_t
Definition: rb_mjit_min_header-2.7.2.h:1327
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:60
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:11689
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
va_start
#define va_start(v, l)
Definition: rb_mjit_min_header-2.7.2.h:3981
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:28
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
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.2.h:14524
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:39
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:9520
IBF_OBJECT_CLASS_TYPE_ERROR
@ IBF_OBJECT_CLASS_TYPE_ERROR
Definition: compile.c:10714
ruby_debug
#define ruby_debug
Definition: ruby.h:1926
err
int err
Definition: win32.c:135
idEach
@ idEach
Definition: rb_mjit_min_header-2.7.2.h:8667
debugi
#define debugi(header, id)
Definition: compile.c:169
RUBY_EVENT_B_CALL
#define RUBY_EVENT_B_CALL
Definition: ruby.h:2253
rb_iseq_constant_body::flags
struct rb_iseq_constant_body::@3::@5 flags
idSize
@ idSize
Definition: rb_mjit_min_header-2.7.2.h:8664
encindex.h
ADD_INSN
#define ADD_INSN(seq, line, insn)
Definition: compile.c:204
rb_call_info::flag
unsigned int flag
Definition: internal.h:2396
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
st_data_t
unsigned long st_data_t
Definition: rb_mjit_min_header-2.7.2.h:5359
rb_call_data::ci
struct rb_call_info ci
Definition: internal.h:2401
DEFINED_EXPR
@ DEFINED_EXPR
Definition: iseq.h:298
printf
int int int printf(const char *__restrict,...) __attribute__((__format__(__printf__
size_t
unsigned int size_t
Definition: rb_mjit_min_header-2.7.2.h:663
NODE_FCALL
@ NODE_FCALL
Definition: node.h:62
NEW_LABEL
#define NEW_LABEL(l)
Definition: compile.c:190
modf
double modf(double, double *)
rb_sym2id
ID rb_sym2id(VALUE)
Definition: symbol.c:748
rb_iseq_struct::aux
union rb_iseq_struct::@6 aux
IBF_OBJBODY
#define IBF_OBJBODY(type, offset)
Definition: compile.c:10754
COMPILE_OK
#define COMPILE_OK
Definition: compile.c:445
rb_gc_mark
void rb_gc_mark(VALUE ptr)
Definition: gc.c:5215
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_ary_new_from_args
#define rb_ary_new_from_args(n,...)
Definition: rb_mjit_min_header-2.7.2.h:7196
rb_iseq_location_struct::node_id
int node_id
Definition: vm_core.h:277
TAG_NEXT
#define TAG_NEXT
Definition: vm_core.h:200
INT_MAX
#define INT_MAX
Definition: rb_mjit_min_header-2.7.2.h:4055
rb_range_values
int rb_range_values(VALUE range, VALUE *begp, VALUE *endp, int *exclp)
Definition: range.c:1248
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:272
st_memsize
size_t st_memsize(const st_table *tab)
Definition: st.c:719
NODE_YIELD
@ NODE_YIELD
Definition: node.h:72
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:11631
rb_iseq_constant_body::iseq_insn_info::size
unsigned int size
Definition: vm_core.h:405
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
v
int VALUE v
Definition: rb_mjit_min_header-2.7.2.h:12300
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:9539
ibf_object_header::special_const
unsigned int special_const
Definition: compile.c:10704
iseq_label_data::unremovable
unsigned int unremovable
Definition: compile.c:71
intptr_t
int intptr_t
Definition: win32.h:90
cc
const struct rb_call_cache * cc
Definition: rb_mjit_min_header-2.7.2.h:13196
rb_builtin_function::argc
const int argc
Definition: builtin.h:9
rb_memerror
void rb_memerror(void)
Definition: gc.c:9598
PRIdVALUE
#define PRIdVALUE
Definition: ruby.h:161
rb_iseq_struct::body
struct rb_iseq_constant_body * body
Definition: vm_core.h:460
fflush
int fflush(FILE *)
iseq_catch_table_entry::sp
unsigned int sp
Definition: iseq.h:252
stderr
#define stderr
Definition: rb_mjit_min_header-2.7.2.h:1516
rb_ary_dup
VALUE rb_ary_dup(VALUE ary)
Definition: array.c:2238
defined_type
defined_type
Definition: iseq.h:283
NODE_UNDEF
@ NODE_UNDEF
Definition: node.h:105
FLEX_ARY_LEN
#define FLEX_ARY_LEN
Definition: internal.h:2626
rb_iseq_ibf_load
const rb_iseq_t * rb_iseq_ibf_load(VALUE str)
Definition: compile.c:11603
LONG2FIX
#define LONG2FIX(i)
Definition: ruby.h:265
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:80
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:684
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:120
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:9551
TAG_BREAK
#define TAG_BREAK
Definition: vm_core.h:199
rb_sym2str
VALUE rb_sym2str(VALUE)
Definition: symbol.c:784
idRespond_to
@ idRespond_to
Definition: id.h:116
index
int index
Definition: rb_mjit_min_header-2.7.2.h:11214
RHASH_TBL_RAW
#define RHASH_TBL_RAW(h)
Definition: internal.h:1695
rb_args_info::block_arg
ID block_arg
Definition: node.h:442
rb_iseq_constant_body::ci_kw_size
unsigned int ci_kw_size
Definition: vm_core.h:438
ibf_object_hash
Definition: compile.c:10722
ibf_object_regexp::srcstr
long srcstr
Definition: compile.c:10718
rb_str_new_cstr
#define rb_str_new_cstr(str)
Definition: rb_mjit_min_header-2.7.2.h:6113
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:2393
RB_INTEGER_TYPE_P
#define RB_INTEGER_TYPE_P(obj)
Definition: ruby_missing.h:15
NODE_VALUES
@ NODE_VALUES
Definition: node.h:69
NODE_FLIP3
@ NODE_FLIP3
Definition: node.h:114
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:11227
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:1562
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
RUBY_EVENT_COVERAGE_BRANCH
#define RUBY_EVENT_COVERAGE_BRANCH
Definition: vm_core.h:1957
rb_str_new
#define rb_str_new(str, len)
Definition: rb_mjit_min_header-2.7.2.h:6112
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:2129
debugs
#define debugs
Definition: compile.c:183
ibf_load_buffer::size
ibf_offset_t size
Definition: compile.c:9541
PADDING_SIZE_MAX
#define PADDING_SIZE_MAX
Definition: compile.c:826
rb_insns_name
const char * rb_insns_name(int i)
Definition: compile.c:8762
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:9544
rb_iseq_ibf_dump
VALUE rb_iseq_ibf_dump(const rb_iseq_t *iseq, VALUE opt)
Definition: compile.c:11379
NODE_REDO
@ NODE_REDO
Definition: node.h:39
ibf_load::iseq_list
VALUE iseq_list
Definition: compile.c:9550
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:454
DEFINED_ZSUPER
@ DEFINED_ZSUPER
Definition: iseq.h:293
UNALIGNED_MEMBER_PTR
#define UNALIGNED_MEMBER_PTR(ptr, mem)
Definition: internal.h:2691
iseq_catch_table
Definition: rb_mjit_min_header-2.7.2.h:10828
BIGNUM_LEN
#define BIGNUM_LEN(b)
Definition: internal.h:774
ibf_object_hash::keyval
long keyval[FLEX_ARY_LEN]
Definition: compile.c:10724
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:921
NODE_MODULE
@ NODE_MODULE
Definition: node.h:107
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
fprintf
int fprintf(FILE *__restrict, const char *__restrict,...) __attribute__((__format__(__printf__
RNode::id
ID id
Definition: node.h:153
idDIV
@ idDIV
Definition: id.h:88
rb_call_data
Definition: internal.h:2399
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
char
#define char
Definition: rb_mjit_min_header-2.7.2.h:2884
st_free_table
void st_free_table(st_table *tab)
Definition: st.c:709
st_table
Definition: st.h:79
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:441
UINT_MAX
#define UINT_MAX
Definition: rb_mjit_min_header-2.7.2.h:4057
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:64
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:23
ruby_vminsn_type
ruby_vminsn_type
Definition: rb_mjit_min_header-2.7.2.h:11937
ibf_object_struct_range::end
long end
Definition: compile.c:10731
NODE_RETRY
@ NODE_RETRY
Definition: node.h:40
ibf_object_header::internal
unsigned int internal
Definition: compile.c:10706
NODE_LIST
@ NODE_LIST
Definition: node.h:67
idMax
@ idMax
Definition: rb_mjit_min_header-2.7.2.h:8649
ibf_object_bignum::digits
BDIGIT digits[FLEX_ARY_LEN]
Definition: compile.c:10737
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:9417
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:36
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
strcmp
int strcmp(const char *, const char *)
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
ibf_dump::iseq_list
VALUE iseq_list
Definition: compile.c:9531
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
iseq
const rb_iseq_t * iseq
Definition: rb_mjit_min_header-2.7.2.h:13469
TAG_RETURN
#define TAG_RETURN
Definition: vm_core.h:198
idLength
@ idLength
Definition: rb_mjit_min_header-2.7.2.h:8663
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
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:9357
INT_PARAM
#define INT_PARAM(F)
NODE_WHILE
@ NODE_WHILE
Definition: node.h:32
NODE_SCLASS
@ NODE_SCLASS
Definition: node.h:108
rb_iseq_constant_body::ISEQ_TYPE_MAIN
@ ISEQ_TYPE_MAIN
Definition: vm_core.h:320
iseq_inline_storage_entry
Definition: vm_core.h:231
name
const char * name
Definition: nkf.c:208
NODE_GASGN
@ NODE_GASGN
Definition: node.h:51
rb_execution_context_struct
Definition: vm_core.h:843
ISEQ_LAST_LINE
#define ISEQ_LAST_LINE(iseq)
Definition: compile.c:605
n
const char size_t n
Definition: rb_mjit_min_header-2.7.2.h:5452
IBF_R
#define IBF_R(val, type, n)
Definition: compile.c:9636