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