Ruby  3.4.0dev (2024-12-06 revision 892c46283a5ea4179500d951c9d4866c0051f27b)
compile.c (892c46283a5ea4179500d951c9d4866c0051f27b)
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/internal/config.h"
13 #include <math.h>
14 
15 #ifdef HAVE_DLADDR
16 # include <dlfcn.h>
17 #endif
18 
19 #include "encindex.h"
20 #include "id_table.h"
21 #include "internal.h"
22 #include "internal/array.h"
23 #include "internal/compile.h"
24 #include "internal/complex.h"
25 #include "internal/encoding.h"
26 #include "internal/error.h"
27 #include "internal/gc.h"
28 #include "internal/hash.h"
29 #include "internal/io.h"
30 #include "internal/numeric.h"
31 #include "internal/object.h"
32 #include "internal/rational.h"
33 #include "internal/re.h"
34 #include "internal/ruby_parser.h"
35 #include "internal/symbol.h"
36 #include "internal/thread.h"
37 #include "internal/variable.h"
38 #include "iseq.h"
39 #include "ruby/ractor.h"
40 #include "ruby/re.h"
41 #include "ruby/util.h"
42 #include "vm_core.h"
43 #include "vm_callinfo.h"
44 #include "vm_debug.h"
45 #include "yjit.h"
46 
47 #include "builtin.h"
48 #include "insns.inc"
49 #include "insns_info.inc"
50 
51 #define FIXNUM_INC(n, i) ((n)+(INT2FIX(i)&~FIXNUM_FLAG))
52 #define FIXNUM_OR(n, i) ((n)|INT2FIX(i))
53 
54 typedef struct iseq_link_element {
55  enum {
56  ISEQ_ELEMENT_ANCHOR,
57  ISEQ_ELEMENT_LABEL,
58  ISEQ_ELEMENT_INSN,
59  ISEQ_ELEMENT_ADJUST,
60  ISEQ_ELEMENT_TRACE,
61  } type;
62  struct iseq_link_element *next;
63  struct iseq_link_element *prev;
64 } LINK_ELEMENT;
65 
66 typedef struct iseq_link_anchor {
67  LINK_ELEMENT anchor;
68  LINK_ELEMENT *last;
69 } LINK_ANCHOR;
70 
71 typedef enum {
72  LABEL_RESCUE_NONE,
73  LABEL_RESCUE_BEG,
74  LABEL_RESCUE_END,
75  LABEL_RESCUE_TYPE_MAX
76 } LABEL_RESCUE_TYPE;
77 
78 typedef struct iseq_label_data {
79  LINK_ELEMENT link;
80  int label_no;
81  int position;
82  int sc_state;
83  int sp;
84  int refcnt;
85  unsigned int set: 1;
86  unsigned int rescued: 2;
87  unsigned int unremovable: 1;
88 } LABEL;
89 
90 typedef struct iseq_insn_data {
91  LINK_ELEMENT link;
92  enum ruby_vminsn_type insn_id;
93  int operand_size;
94  int sc_state;
95  VALUE *operands;
96  struct {
97  int line_no;
98  int node_id;
99  rb_event_flag_t events;
100  } insn_info;
101 } INSN;
102 
103 typedef struct iseq_adjust_data {
104  LINK_ELEMENT link;
105  LABEL *label;
106  int line_no;
107 } ADJUST;
108 
109 typedef struct iseq_trace_data {
110  LINK_ELEMENT link;
111  rb_event_flag_t event;
112  long data;
113 } TRACE;
114 
115 struct ensure_range {
116  LABEL *begin;
117  LABEL *end;
118  struct ensure_range *next;
119 };
120 
122  const void *ensure_node;
124  struct ensure_range *erange;
125 };
126 
127 const ID rb_iseq_shared_exc_local_tbl[] = {idERROR_INFO};
128 
142 #ifndef CPDEBUG
143 #define CPDEBUG 0
144 #endif
145 
146 #if CPDEBUG >= 0
147 #define compile_debug CPDEBUG
148 #else
149 #define compile_debug ISEQ_COMPILE_DATA(iseq)->option->debug_level
150 #endif
151 
152 #if CPDEBUG
153 
154 #define compile_debug_print_indent(level) \
155  ruby_debug_print_indent((level), compile_debug, gl_node_level * 2)
156 
157 #define debugp(header, value) (void) \
158  (compile_debug_print_indent(1) && \
159  ruby_debug_print_value(1, compile_debug, (header), (value)))
160 
161 #define debugi(header, id) (void) \
162  (compile_debug_print_indent(1) && \
163  ruby_debug_print_id(1, compile_debug, (header), (id)))
164 
165 #define debugp_param(header, value) (void) \
166  (compile_debug_print_indent(1) && \
167  ruby_debug_print_value(1, compile_debug, (header), (value)))
168 
169 #define debugp_verbose(header, value) (void) \
170  (compile_debug_print_indent(2) && \
171  ruby_debug_print_value(2, compile_debug, (header), (value)))
172 
173 #define debugp_verbose_node(header, value) (void) \
174  (compile_debug_print_indent(10) && \
175  ruby_debug_print_value(10, compile_debug, (header), (value)))
176 
177 #define debug_node_start(node) ((void) \
178  (compile_debug_print_indent(1) && \
179  (ruby_debug_print_node(1, CPDEBUG, "", (const NODE *)(node)), gl_node_level)), \
180  gl_node_level++)
181 
182 #define debug_node_end() gl_node_level --
183 
184 #else
185 
186 #define debugi(header, id) ((void)0)
187 #define debugp(header, value) ((void)0)
188 #define debugp_verbose(header, value) ((void)0)
189 #define debugp_verbose_node(header, value) ((void)0)
190 #define debugp_param(header, value) ((void)0)
191 #define debug_node_start(node) ((void)0)
192 #define debug_node_end() ((void)0)
193 #endif
194 
195 #if CPDEBUG > 1 || CPDEBUG < 0
196 #undef printf
197 #define printf ruby_debug_printf
198 #define debugs if (compile_debug_print_indent(1)) ruby_debug_printf
199 #define debug_compile(msg, v) ((void)(compile_debug_print_indent(1) && fputs((msg), stderr)), (v))
200 #else
201 #define debugs if(0)printf
202 #define debug_compile(msg, v) (v)
203 #endif
204 
205 #define LVAR_ERRINFO (1)
206 
207 /* create new label */
208 #define NEW_LABEL(l) new_label_body(iseq, (l))
209 #define LABEL_FORMAT "<L%03d>"
210 
211 #define NEW_ISEQ(node, name, type, line_no) \
212  new_child_iseq(iseq, (node), rb_fstring(name), 0, (type), (line_no))
213 
214 #define NEW_CHILD_ISEQ(node, name, type, line_no) \
215  new_child_iseq(iseq, (node), rb_fstring(name), iseq, (type), (line_no))
216 
217 /* add instructions */
218 #define ADD_SEQ(seq1, seq2) \
219  APPEND_LIST((seq1), (seq2))
220 
221 /* add an instruction */
222 #define ADD_INSN(seq, line_node, insn) \
223  ADD_ELEM((seq), (LINK_ELEMENT *) new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(insn), 0))
224 
225 /* add an instruction with the given line number and node id */
226 #define ADD_SYNTHETIC_INSN(seq, line_no, node_id, insn) \
227  ADD_ELEM((seq), (LINK_ELEMENT *) new_insn_body(iseq, (line_no), (node_id), BIN(insn), 0))
228 
229 /* insert an instruction before next */
230 #define INSERT_BEFORE_INSN(next, line_no, node_id, insn) \
231  ELEM_INSERT_PREV(&(next)->link, (LINK_ELEMENT *) new_insn_body(iseq, line_no, node_id, BIN(insn), 0))
232 
233 /* insert an instruction after prev */
234 #define INSERT_AFTER_INSN(prev, line_no, node_id, insn) \
235  ELEM_INSERT_NEXT(&(prev)->link, (LINK_ELEMENT *) new_insn_body(iseq, line_no, node_id, BIN(insn), 0))
236 
237 /* add an instruction with some operands (1, 2, 3, 5) */
238 #define ADD_INSN1(seq, line_node, insn, op1) \
239  ADD_ELEM((seq), (LINK_ELEMENT *) \
240  new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(insn), 1, (VALUE)(op1)))
241 
242 /* insert an instruction with some operands (1, 2, 3, 5) before next */
243 #define INSERT_BEFORE_INSN1(next, line_no, node_id, insn, op1) \
244  ELEM_INSERT_PREV(&(next)->link, (LINK_ELEMENT *) \
245  new_insn_body(iseq, line_no, node_id, BIN(insn), 1, (VALUE)(op1)))
246 
247 /* insert an instruction with some operands (1, 2, 3, 5) after prev */
248 #define INSERT_AFTER_INSN1(prev, line_no, node_id, insn, op1) \
249  ELEM_INSERT_NEXT(&(prev)->link, (LINK_ELEMENT *) \
250  new_insn_body(iseq, line_no, node_id, BIN(insn), 1, (VALUE)(op1)))
251 
252 #define LABEL_REF(label) ((label)->refcnt++)
253 
254 /* add an instruction with label operand (alias of ADD_INSN1) */
255 #define ADD_INSNL(seq, line_node, insn, label) (ADD_INSN1(seq, line_node, insn, label), LABEL_REF(label))
256 
257 #define ADD_INSN2(seq, line_node, insn, op1, op2) \
258  ADD_ELEM((seq), (LINK_ELEMENT *) \
259  new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(insn), 2, (VALUE)(op1), (VALUE)(op2)))
260 
261 #define ADD_INSN3(seq, line_node, insn, op1, op2, op3) \
262  ADD_ELEM((seq), (LINK_ELEMENT *) \
263  new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(insn), 3, (VALUE)(op1), (VALUE)(op2), (VALUE)(op3)))
264 
265 /* Specific Insn factory */
266 #define ADD_SEND(seq, line_node, id, argc) \
267  ADD_SEND_R((seq), (line_node), (id), (argc), NULL, (VALUE)INT2FIX(0), NULL)
268 
269 #define ADD_SEND_WITH_FLAG(seq, line_node, id, argc, flag) \
270  ADD_SEND_R((seq), (line_node), (id), (argc), NULL, (VALUE)(flag), NULL)
271 
272 #define ADD_SEND_WITH_BLOCK(seq, line_node, id, argc, block) \
273  ADD_SEND_R((seq), (line_node), (id), (argc), (block), (VALUE)INT2FIX(0), NULL)
274 
275 #define ADD_CALL_RECEIVER(seq, line_node) \
276  ADD_INSN((seq), (line_node), putself)
277 
278 #define ADD_CALL(seq, line_node, id, argc) \
279  ADD_SEND_R((seq), (line_node), (id), (argc), NULL, (VALUE)INT2FIX(VM_CALL_FCALL), NULL)
280 
281 #define ADD_CALL_WITH_BLOCK(seq, line_node, id, argc, block) \
282  ADD_SEND_R((seq), (line_node), (id), (argc), (block), (VALUE)INT2FIX(VM_CALL_FCALL), NULL)
283 
284 #define ADD_SEND_R(seq, line_node, id, argc, block, flag, keywords) \
285  ADD_ELEM((seq), (LINK_ELEMENT *) new_insn_send(iseq, nd_line(line_node), nd_node_id(line_node), (id), (VALUE)(argc), (block), (VALUE)(flag), (keywords)))
286 
287 #define ADD_TRACE(seq, event) \
288  ADD_ELEM((seq), (LINK_ELEMENT *)new_trace_body(iseq, (event), 0))
289 #define ADD_TRACE_WITH_DATA(seq, event, data) \
290  ADD_ELEM((seq), (LINK_ELEMENT *)new_trace_body(iseq, (event), (data)))
291 
292 static void iseq_add_getlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NODE *const line_node, int idx, int level);
293 static void iseq_add_setlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NODE *const line_node, int idx, int level);
294 
295 #define ADD_GETLOCAL(seq, line_node, idx, level) iseq_add_getlocal(iseq, (seq), (line_node), (idx), (level))
296 #define ADD_SETLOCAL(seq, line_node, idx, level) iseq_add_setlocal(iseq, (seq), (line_node), (idx), (level))
297 
298 /* add label */
299 #define ADD_LABEL(seq, label) \
300  ADD_ELEM((seq), (LINK_ELEMENT *) (label))
301 
302 #define APPEND_LABEL(seq, before, label) \
303  APPEND_ELEM((seq), (before), (LINK_ELEMENT *) (label))
304 
305 #define ADD_ADJUST(seq, line_node, label) \
306  ADD_ELEM((seq), (LINK_ELEMENT *) new_adjust_body(iseq, (label), nd_line(line_node)))
307 
308 #define ADD_ADJUST_RESTORE(seq, label) \
309  ADD_ELEM((seq), (LINK_ELEMENT *) new_adjust_body(iseq, (label), -1))
310 
311 #define LABEL_UNREMOVABLE(label) \
312  ((label) ? (LABEL_REF(label), (label)->unremovable=1) : 0)
313 #define ADD_CATCH_ENTRY(type, ls, le, iseqv, lc) do { \
314  VALUE _e = rb_ary_new3(5, (type), \
315  (VALUE)(ls) | 1, (VALUE)(le) | 1, \
316  (VALUE)(iseqv), (VALUE)(lc) | 1); \
317  LABEL_UNREMOVABLE(ls); \
318  LABEL_REF(le); \
319  LABEL_REF(lc); \
320  if (NIL_P(ISEQ_COMPILE_DATA(iseq)->catch_table_ary)) \
321  RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->catch_table_ary, rb_ary_hidden_new(3)); \
322  rb_ary_push(ISEQ_COMPILE_DATA(iseq)->catch_table_ary, freeze_hide_obj(_e)); \
323 } while (0)
324 
325 /* compile node */
326 #define COMPILE(anchor, desc, node) \
327  (debug_compile("== " desc "\n", \
328  iseq_compile_each(iseq, (anchor), (node), 0)))
329 
330 /* compile node, this node's value will be popped */
331 #define COMPILE_POPPED(anchor, desc, node) \
332  (debug_compile("== " desc "\n", \
333  iseq_compile_each(iseq, (anchor), (node), 1)))
334 
335 /* compile node, which is popped when 'popped' is true */
336 #define COMPILE_(anchor, desc, node, popped) \
337  (debug_compile("== " desc "\n", \
338  iseq_compile_each(iseq, (anchor), (node), (popped))))
339 
340 #define COMPILE_RECV(anchor, desc, node, recv) \
341  (private_recv_p(node) ? \
342  (ADD_INSN(anchor, node, putself), VM_CALL_FCALL) : \
343  COMPILE(anchor, desc, recv) ? 0 : -1)
344 
345 #define OPERAND_AT(insn, idx) \
346  (((INSN*)(insn))->operands[(idx)])
347 
348 #define INSN_OF(insn) \
349  (((INSN*)(insn))->insn_id)
350 
351 #define IS_INSN(link) ((link)->type == ISEQ_ELEMENT_INSN)
352 #define IS_LABEL(link) ((link)->type == ISEQ_ELEMENT_LABEL)
353 #define IS_ADJUST(link) ((link)->type == ISEQ_ELEMENT_ADJUST)
354 #define IS_TRACE(link) ((link)->type == ISEQ_ELEMENT_TRACE)
355 #define IS_INSN_ID(iobj, insn) (INSN_OF(iobj) == BIN(insn))
356 #define IS_NEXT_INSN_ID(link, insn) \
357  ((link)->next && IS_INSN((link)->next) && IS_INSN_ID((link)->next, insn))
358 
359 /* error */
360 #if CPDEBUG > 0
362 #endif
363 RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 3, 4)
364 static void
365 append_compile_error(const rb_iseq_t *iseq, int line, const char *fmt, ...)
366 {
367  VALUE err_info = ISEQ_COMPILE_DATA(iseq)->err_info;
368  VALUE file = rb_iseq_path(iseq);
369  VALUE err = err_info == Qtrue ? Qfalse : err_info;
370  va_list args;
371 
372  va_start(args, fmt);
373  err = rb_syntax_error_append(err, file, line, -1, NULL, fmt, args);
374  va_end(args);
375  if (NIL_P(err_info)) {
376  RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->err_info, err);
377  rb_set_errinfo(err);
378  }
379  else if (!err_info) {
380  RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->err_info, Qtrue);
381  }
382  if (compile_debug) {
383  if (SPECIAL_CONST_P(err)) err = rb_eSyntaxError;
384  rb_exc_fatal(err);
385  }
386 }
387 
388 #if 0
389 static void
390 compile_bug(rb_iseq_t *iseq, int line, const char *fmt, ...)
391 {
392  va_list args;
393  va_start(args, fmt);
394  rb_report_bug_valist(rb_iseq_path(iseq), line, fmt, args);
395  va_end(args);
396  abort();
397 }
398 #endif
399 
400 #define COMPILE_ERROR append_compile_error
401 
402 #define ERROR_ARGS_AT(n) iseq, nd_line(n),
403 #define ERROR_ARGS ERROR_ARGS_AT(node)
404 
405 #define EXPECT_NODE(prefix, node, ndtype, errval) \
406 do { \
407  const NODE *error_node = (node); \
408  enum node_type error_type = nd_type(error_node); \
409  if (error_type != (ndtype)) { \
410  COMPILE_ERROR(ERROR_ARGS_AT(error_node) \
411  prefix ": " #ndtype " is expected, but %s", \
412  ruby_node_name(error_type)); \
413  return errval; \
414  } \
415 } while (0)
416 
417 #define EXPECT_NODE_NONULL(prefix, parent, ndtype, errval) \
418 do { \
419  COMPILE_ERROR(ERROR_ARGS_AT(parent) \
420  prefix ": must be " #ndtype ", but 0"); \
421  return errval; \
422 } while (0)
423 
424 #define UNKNOWN_NODE(prefix, node, errval) \
425 do { \
426  const NODE *error_node = (node); \
427  COMPILE_ERROR(ERROR_ARGS_AT(error_node) prefix ": unknown node (%s)", \
428  ruby_node_name(nd_type(error_node))); \
429  return errval; \
430 } while (0)
431 
432 #define COMPILE_OK 1
433 #define COMPILE_NG 0
434 
435 #define CHECK(sub) if (!(sub)) {BEFORE_RETURN;return COMPILE_NG;}
436 #define NO_CHECK(sub) (void)(sub)
437 #define BEFORE_RETURN
438 
439 #define DECL_ANCHOR(name) \
440  LINK_ANCHOR name[1] = {{{ISEQ_ELEMENT_ANCHOR,},&name[0].anchor}}
441 #define INIT_ANCHOR(name) \
442  ((name->last = &name->anchor)->next = NULL) /* re-initialize */
443 
444 static inline VALUE
445 freeze_hide_obj(VALUE obj)
446 {
447  OBJ_FREEZE(obj);
448  RBASIC_CLEAR_CLASS(obj);
449  return obj;
450 }
451 
452 #include "optinsn.inc"
453 #if OPT_INSTRUCTIONS_UNIFICATION
454 #include "optunifs.inc"
455 #endif
456 
457 /* for debug */
458 #if CPDEBUG < 0
459 #define ISEQ_ARG iseq,
460 #define ISEQ_ARG_DECLARE rb_iseq_t *iseq,
461 #else
462 #define ISEQ_ARG
463 #define ISEQ_ARG_DECLARE
464 #endif
465 
466 #if CPDEBUG
467 #define gl_node_level ISEQ_COMPILE_DATA(iseq)->node_level
468 #endif
469 
470 static void dump_disasm_list_with_cursor(const LINK_ELEMENT *link, const LINK_ELEMENT *curr, const LABEL *dest);
471 static void dump_disasm_list(const LINK_ELEMENT *elem);
472 
473 static int insn_data_length(INSN *iobj);
474 static int calc_sp_depth(int depth, INSN *iobj);
475 
476 static INSN *new_insn_body(rb_iseq_t *iseq, int line_no, int node_id, enum ruby_vminsn_type insn_id, int argc, ...);
477 static LABEL *new_label_body(rb_iseq_t *iseq, long line);
478 static ADJUST *new_adjust_body(rb_iseq_t *iseq, LABEL *label, int line);
479 static TRACE *new_trace_body(rb_iseq_t *iseq, rb_event_flag_t event, long data);
480 
481 
482 static int iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *anchor, const NODE *n, int);
483 static int iseq_setup(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
484 static int iseq_setup_insn(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
485 static int iseq_optimize(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
486 static int iseq_insns_unification(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
487 
488 static int iseq_set_local_table(rb_iseq_t *iseq, const rb_ast_id_table_t *tbl, const NODE *const node_args);
489 static int iseq_set_exception_local_table(rb_iseq_t *iseq);
490 static int iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *const anchor, const NODE *const node);
491 
492 static int iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
493 static int iseq_set_exception_table(rb_iseq_t *iseq);
494 static int iseq_set_optargs_table(rb_iseq_t *iseq);
495 
496 static int compile_defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE needstr, bool ignore);
497 static int compile_hash(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int method_call_keywords, int popped);
498 
499 /*
500  * To make Array to LinkedList, use link_anchor
501  */
502 
503 static void
504 verify_list(ISEQ_ARG_DECLARE const char *info, LINK_ANCHOR *const anchor)
505 {
506 #if CPDEBUG
507  int flag = 0;
508  LINK_ELEMENT *list, *plist;
509 
510  if (!compile_debug) return;
511 
512  list = anchor->anchor.next;
513  plist = &anchor->anchor;
514  while (list) {
515  if (plist != list->prev) {
516  flag += 1;
517  }
518  plist = list;
519  list = list->next;
520  }
521 
522  if (anchor->last != plist && anchor->last != 0) {
523  flag |= 0x70000;
524  }
525 
526  if (flag != 0) {
527  rb_bug("list verify error: %08x (%s)", flag, info);
528  }
529 #endif
530 }
531 #if CPDEBUG < 0
532 #define verify_list(info, anchor) verify_list(iseq, (info), (anchor))
533 #endif
534 
535 static void
536 verify_call_cache(rb_iseq_t *iseq)
537 {
538 #if CPDEBUG
539  VALUE *original = rb_iseq_original_iseq(iseq);
540  size_t i = 0;
541  while (i < ISEQ_BODY(iseq)->iseq_size) {
542  VALUE insn = original[i];
543  const char *types = insn_op_types(insn);
544 
545  for (int j=0; types[j]; j++) {
546  if (types[j] == TS_CALLDATA) {
547  struct rb_call_data *cd = (struct rb_call_data *)original[i+j+1];
548  const struct rb_callinfo *ci = cd->ci;
549  const struct rb_callcache *cc = cd->cc;
550  if (cc != vm_cc_empty()) {
551  vm_ci_dump(ci);
552  rb_bug("call cache is not initialized by vm_cc_empty()");
553  }
554  }
555  }
556  i += insn_len(insn);
557  }
558 
559  for (unsigned int i=0; i<ISEQ_BODY(iseq)->ci_size; i++) {
560  struct rb_call_data *cd = &ISEQ_BODY(iseq)->call_data[i];
561  const struct rb_callinfo *ci = cd->ci;
562  const struct rb_callcache *cc = cd->cc;
563  if (cc != NULL && cc != vm_cc_empty()) {
564  vm_ci_dump(ci);
565  rb_bug("call cache is not initialized by vm_cc_empty()");
566  }
567  }
568 #endif
569 }
570 
571 /*
572  * elem1, elem2 => elem1, elem2, elem
573  */
574 static void
575 ADD_ELEM(ISEQ_ARG_DECLARE LINK_ANCHOR *const anchor, LINK_ELEMENT *elem)
576 {
577  elem->prev = anchor->last;
578  anchor->last->next = elem;
579  anchor->last = elem;
580  verify_list("add", anchor);
581 }
582 
583 /*
584  * elem1, before, elem2 => elem1, before, elem, elem2
585  */
586 static void
587 APPEND_ELEM(ISEQ_ARG_DECLARE LINK_ANCHOR *const anchor, LINK_ELEMENT *before, LINK_ELEMENT *elem)
588 {
589  elem->prev = before;
590  elem->next = before->next;
591  elem->next->prev = elem;
592  before->next = elem;
593  if (before == anchor->last) anchor->last = elem;
594  verify_list("add", anchor);
595 }
596 #if CPDEBUG < 0
597 #define ADD_ELEM(anchor, elem) ADD_ELEM(iseq, (anchor), (elem))
598 #define APPEND_ELEM(anchor, before, elem) APPEND_ELEM(iseq, (anchor), (before), (elem))
599 #endif
600 
601 static int
602 branch_coverage_valid_p(rb_iseq_t *iseq, int first_line)
603 {
604  if (!ISEQ_COVERAGE(iseq)) return 0;
605  if (!ISEQ_BRANCH_COVERAGE(iseq)) return 0;
606  if (first_line <= 0) return 0;
607  return 1;
608 }
609 
610 #define PTR2NUM(x) (rb_int2inum((intptr_t)(void *)(x)))
611 
612 static VALUE
613 setup_branch(const rb_code_location_t *loc, const char *type, VALUE structure, VALUE key)
614 {
615  const int first_lineno = loc->beg_pos.lineno, first_column = loc->beg_pos.column;
616  const int last_lineno = loc->end_pos.lineno, last_column = loc->end_pos.column;
617  VALUE branch = rb_ary_hidden_new(6);
618 
619  rb_hash_aset(structure, key, branch);
620  rb_ary_push(branch, ID2SYM(rb_intern(type)));
621  rb_ary_push(branch, INT2FIX(first_lineno));
622  rb_ary_push(branch, INT2FIX(first_column));
623  rb_ary_push(branch, INT2FIX(last_lineno));
624  rb_ary_push(branch, INT2FIX(last_column));
625  return branch;
626 }
627 
628 static VALUE
629 decl_branch_base(rb_iseq_t *iseq, VALUE key, const rb_code_location_t *loc, const char *type)
630 {
631  if (!branch_coverage_valid_p(iseq, loc->beg_pos.lineno)) return Qundef;
632 
633  /*
634  * if !structure[node]
635  * structure[node] = [type, first_lineno, first_column, last_lineno, last_column, branches = {}]
636  * else
637  * branches = structure[node][5]
638  * end
639  */
640 
641  VALUE structure = RARRAY_AREF(ISEQ_BRANCH_COVERAGE(iseq), 0);
642  VALUE branch_base = rb_hash_aref(structure, key);
643  VALUE branches;
644 
645  if (NIL_P(branch_base)) {
646  branch_base = setup_branch(loc, type, structure, key);
647  branches = rb_hash_new();
648  rb_obj_hide(branches);
649  rb_ary_push(branch_base, branches);
650  }
651  else {
652  branches = RARRAY_AREF(branch_base, 5);
653  }
654 
655  return branches;
656 }
657 
658 static NODE
659 generate_dummy_line_node(int lineno, int node_id)
660 {
661  NODE dummy = { 0 };
662  nd_set_line(&dummy, lineno);
663  nd_set_node_id(&dummy, node_id);
664  return dummy;
665 }
666 
667 static void
668 add_trace_branch_coverage(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const rb_code_location_t *loc, int node_id, int branch_id, const char *type, VALUE branches)
669 {
670  if (!branch_coverage_valid_p(iseq, loc->beg_pos.lineno)) return;
671 
672  /*
673  * if !branches[branch_id]
674  * branches[branch_id] = [type, first_lineno, first_column, last_lineno, last_column, counter_idx]
675  * else
676  * counter_idx= branches[branch_id][5]
677  * end
678  */
679 
680  VALUE key = INT2FIX(branch_id);
681  VALUE branch = rb_hash_aref(branches, key);
682  long counter_idx;
683 
684  if (NIL_P(branch)) {
685  branch = setup_branch(loc, type, branches, key);
686  VALUE counters = RARRAY_AREF(ISEQ_BRANCH_COVERAGE(iseq), 1);
687  counter_idx = RARRAY_LEN(counters);
688  rb_ary_push(branch, LONG2FIX(counter_idx));
689  rb_ary_push(counters, INT2FIX(0));
690  }
691  else {
692  counter_idx = FIX2LONG(RARRAY_AREF(branch, 5));
693  }
694 
695  ADD_TRACE_WITH_DATA(seq, RUBY_EVENT_COVERAGE_BRANCH, counter_idx);
696  ADD_SYNTHETIC_INSN(seq, loc->end_pos.lineno, node_id, nop);
697 }
698 
699 #define ISEQ_LAST_LINE(iseq) (ISEQ_COMPILE_DATA(iseq)->last_line)
700 
701 static int
702 validate_label(st_data_t name, st_data_t label, st_data_t arg)
703 {
704  rb_iseq_t *iseq = (rb_iseq_t *)arg;
705  LABEL *lobj = (LABEL *)label;
706  if (!lobj->link.next) {
707  do {
708  COMPILE_ERROR(iseq, lobj->position,
709  "%"PRIsVALUE": undefined label",
710  rb_sym2str((VALUE)name));
711  } while (0);
712  }
713  return ST_CONTINUE;
714 }
715 
716 static void
717 validate_labels(rb_iseq_t *iseq, st_table *labels_table)
718 {
719  st_foreach(labels_table, validate_label, (st_data_t)iseq);
720  st_free_table(labels_table);
721 }
722 
723 static NODE *
724 get_nd_recv(const NODE *node)
725 {
726  switch (nd_type(node)) {
727  case NODE_CALL:
728  return RNODE_CALL(node)->nd_recv;
729  case NODE_OPCALL:
730  return RNODE_OPCALL(node)->nd_recv;
731  case NODE_FCALL:
732  return 0;
733  case NODE_QCALL:
734  return RNODE_QCALL(node)->nd_recv;
735  case NODE_VCALL:
736  return 0;
737  case NODE_ATTRASGN:
738  return RNODE_ATTRASGN(node)->nd_recv;
739  case NODE_OP_ASGN1:
740  return RNODE_OP_ASGN1(node)->nd_recv;
741  case NODE_OP_ASGN2:
742  return RNODE_OP_ASGN2(node)->nd_recv;
743  default:
744  rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
745  }
746 }
747 
748 static ID
749 get_node_call_nd_mid(const NODE *node)
750 {
751  switch (nd_type(node)) {
752  case NODE_CALL:
753  return RNODE_CALL(node)->nd_mid;
754  case NODE_OPCALL:
755  return RNODE_OPCALL(node)->nd_mid;
756  case NODE_FCALL:
757  return RNODE_FCALL(node)->nd_mid;
758  case NODE_QCALL:
759  return RNODE_QCALL(node)->nd_mid;
760  case NODE_VCALL:
761  return RNODE_VCALL(node)->nd_mid;
762  case NODE_ATTRASGN:
763  return RNODE_ATTRASGN(node)->nd_mid;
764  default:
765  rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
766  }
767 }
768 
769 static NODE *
770 get_nd_args(const NODE *node)
771 {
772  switch (nd_type(node)) {
773  case NODE_CALL:
774  return RNODE_CALL(node)->nd_args;
775  case NODE_OPCALL:
776  return RNODE_OPCALL(node)->nd_args;
777  case NODE_FCALL:
778  return RNODE_FCALL(node)->nd_args;
779  case NODE_QCALL:
780  return RNODE_QCALL(node)->nd_args;
781  case NODE_VCALL:
782  return 0;
783  case NODE_ATTRASGN:
784  return RNODE_ATTRASGN(node)->nd_args;
785  default:
786  rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
787  }
788 }
789 
790 static ID
791 get_node_colon_nd_mid(const NODE *node)
792 {
793  switch (nd_type(node)) {
794  case NODE_COLON2:
795  return RNODE_COLON2(node)->nd_mid;
796  case NODE_COLON3:
797  return RNODE_COLON3(node)->nd_mid;
798  default:
799  rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
800  }
801 }
802 
803 static ID
804 get_nd_vid(const NODE *node)
805 {
806  switch (nd_type(node)) {
807  case NODE_LASGN:
808  return RNODE_LASGN(node)->nd_vid;
809  case NODE_DASGN:
810  return RNODE_DASGN(node)->nd_vid;
811  case NODE_IASGN:
812  return RNODE_IASGN(node)->nd_vid;
813  case NODE_CVASGN:
814  return RNODE_CVASGN(node)->nd_vid;
815  default:
816  rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
817  }
818 }
819 
820 static NODE *
821 get_nd_value(const NODE *node)
822 {
823  switch (nd_type(node)) {
824  case NODE_LASGN:
825  return RNODE_LASGN(node)->nd_value;
826  case NODE_DASGN:
827  return RNODE_DASGN(node)->nd_value;
828  default:
829  rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
830  }
831 }
832 
833 static VALUE
834 get_string_value(const NODE *node)
835 {
836  switch (nd_type(node)) {
837  case NODE_STR:
838  return rb_node_str_string_val(node);
839  case NODE_FILE:
840  return rb_node_file_path_val(node);
841  default:
842  rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
843  }
844 }
845 
846 VALUE
847 rb_iseq_compile_callback(rb_iseq_t *iseq, const struct rb_iseq_new_with_callback_callback_func * ifunc)
848 {
849  DECL_ANCHOR(ret);
850  INIT_ANCHOR(ret);
851 
852  (*ifunc->func)(iseq, ret, ifunc->data);
853 
854  ADD_SYNTHETIC_INSN(ret, ISEQ_COMPILE_DATA(iseq)->last_line, -1, leave);
855 
856  CHECK(iseq_setup_insn(iseq, ret));
857  return iseq_setup(iseq, ret);
858 }
859 
860 static bool drop_unreachable_return(LINK_ANCHOR *ret);
861 
862 VALUE
863 rb_iseq_compile_node(rb_iseq_t *iseq, const NODE *node)
864 {
865  DECL_ANCHOR(ret);
866  INIT_ANCHOR(ret);
867 
868  if (node == 0) {
869  NO_CHECK(COMPILE(ret, "nil", node));
870  iseq_set_local_table(iseq, 0, 0);
871  }
872  /* assume node is T_NODE */
873  else if (nd_type_p(node, NODE_SCOPE)) {
874  /* iseq type of top, method, class, block */
875  iseq_set_local_table(iseq, RNODE_SCOPE(node)->nd_tbl, (NODE *)RNODE_SCOPE(node)->nd_args);
876  iseq_set_arguments(iseq, ret, (NODE *)RNODE_SCOPE(node)->nd_args);
877 
878  switch (ISEQ_BODY(iseq)->type) {
879  case ISEQ_TYPE_BLOCK:
880  {
881  LABEL *start = ISEQ_COMPILE_DATA(iseq)->start_label = NEW_LABEL(0);
882  LABEL *end = ISEQ_COMPILE_DATA(iseq)->end_label = NEW_LABEL(0);
883 
884  start->rescued = LABEL_RESCUE_BEG;
885  end->rescued = LABEL_RESCUE_END;
886 
887  ADD_TRACE(ret, RUBY_EVENT_B_CALL);
888  ADD_SYNTHETIC_INSN(ret, ISEQ_BODY(iseq)->location.first_lineno, -1, nop);
889  ADD_LABEL(ret, start);
890  CHECK(COMPILE(ret, "block body", RNODE_SCOPE(node)->nd_body));
891  ADD_LABEL(ret, end);
892  ADD_TRACE(ret, RUBY_EVENT_B_RETURN);
893  ISEQ_COMPILE_DATA(iseq)->last_line = ISEQ_BODY(iseq)->location.code_location.end_pos.lineno;
894 
895  /* wide range catch handler must put at last */
896  ADD_CATCH_ENTRY(CATCH_TYPE_REDO, start, end, NULL, start);
897  ADD_CATCH_ENTRY(CATCH_TYPE_NEXT, start, end, NULL, end);
898  break;
899  }
900  case ISEQ_TYPE_CLASS:
901  {
902  ADD_TRACE(ret, RUBY_EVENT_CLASS);
903  CHECK(COMPILE(ret, "scoped node", RNODE_SCOPE(node)->nd_body));
904  ADD_TRACE(ret, RUBY_EVENT_END);
905  ISEQ_COMPILE_DATA(iseq)->last_line = nd_line(node);
906  break;
907  }
908  case ISEQ_TYPE_METHOD:
909  {
910  ISEQ_COMPILE_DATA(iseq)->root_node = RNODE_SCOPE(node)->nd_body;
911  ADD_TRACE(ret, RUBY_EVENT_CALL);
912  CHECK(COMPILE(ret, "scoped node", RNODE_SCOPE(node)->nd_body));
913  ISEQ_COMPILE_DATA(iseq)->root_node = RNODE_SCOPE(node)->nd_body;
914  ADD_TRACE(ret, RUBY_EVENT_RETURN);
915  ISEQ_COMPILE_DATA(iseq)->last_line = nd_line(node);
916  break;
917  }
918  default: {
919  CHECK(COMPILE(ret, "scoped node", RNODE_SCOPE(node)->nd_body));
920  break;
921  }
922  }
923  }
924  else {
925  const char *m;
926 #define INVALID_ISEQ_TYPE(type) \
927  ISEQ_TYPE_##type: m = #type; goto invalid_iseq_type
928  switch (ISEQ_BODY(iseq)->type) {
929  case INVALID_ISEQ_TYPE(METHOD);
930  case INVALID_ISEQ_TYPE(CLASS);
931  case INVALID_ISEQ_TYPE(BLOCK);
932  case INVALID_ISEQ_TYPE(EVAL);
933  case INVALID_ISEQ_TYPE(MAIN);
934  case INVALID_ISEQ_TYPE(TOP);
935 #undef INVALID_ISEQ_TYPE /* invalid iseq types end */
936  case ISEQ_TYPE_RESCUE:
937  iseq_set_exception_local_table(iseq);
938  CHECK(COMPILE(ret, "rescue", node));
939  break;
940  case ISEQ_TYPE_ENSURE:
941  iseq_set_exception_local_table(iseq);
942  CHECK(COMPILE_POPPED(ret, "ensure", node));
943  break;
944  case ISEQ_TYPE_PLAIN:
945  CHECK(COMPILE(ret, "ensure", node));
946  break;
947  default:
948  COMPILE_ERROR(ERROR_ARGS "unknown scope: %d", ISEQ_BODY(iseq)->type);
949  return COMPILE_NG;
950  invalid_iseq_type:
951  COMPILE_ERROR(ERROR_ARGS "compile/ISEQ_TYPE_%s should not be reached", m);
952  return COMPILE_NG;
953  }
954  }
955 
956  if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_RESCUE || ISEQ_BODY(iseq)->type == ISEQ_TYPE_ENSURE) {
957  NODE dummy_line_node = generate_dummy_line_node(0, -1);
958  ADD_GETLOCAL(ret, &dummy_line_node, LVAR_ERRINFO, 0);
959  ADD_INSN1(ret, &dummy_line_node, throw, INT2FIX(0) /* continue throw */ );
960  }
961  else if (!drop_unreachable_return(ret)) {
962  ADD_SYNTHETIC_INSN(ret, ISEQ_COMPILE_DATA(iseq)->last_line, -1, leave);
963  }
964 
965 #if OPT_SUPPORT_JOKE
966  if (ISEQ_COMPILE_DATA(iseq)->labels_table) {
967  st_table *labels_table = ISEQ_COMPILE_DATA(iseq)->labels_table;
968  ISEQ_COMPILE_DATA(iseq)->labels_table = 0;
969  validate_labels(iseq, labels_table);
970  }
971 #endif
972  CHECK(iseq_setup_insn(iseq, ret));
973  return iseq_setup(iseq, ret);
974 }
975 
976 static int
977 rb_iseq_translate_threaded_code(rb_iseq_t *iseq)
978 {
979 #if OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE
980  const void * const *table = rb_vm_get_insns_address_table();
981  unsigned int i;
982  VALUE *encoded = (VALUE *)ISEQ_BODY(iseq)->iseq_encoded;
983 
984  for (i = 0; i < ISEQ_BODY(iseq)->iseq_size; /* */ ) {
985  int insn = (int)ISEQ_BODY(iseq)->iseq_encoded[i];
986  int len = insn_len(insn);
987  encoded[i] = (VALUE)table[insn];
988  i += len;
989  }
990  FL_SET((VALUE)iseq, ISEQ_TRANSLATED);
991 #endif
992 
993 #if USE_YJIT
994  rb_yjit_live_iseq_count++;
995  rb_yjit_iseq_alloc_count++;
996 #endif
997 
998  return COMPILE_OK;
999 }
1000 
1001 VALUE *
1002 rb_iseq_original_iseq(const rb_iseq_t *iseq) /* cold path */
1003 {
1004  VALUE *original_code;
1005 
1006  if (ISEQ_ORIGINAL_ISEQ(iseq)) return ISEQ_ORIGINAL_ISEQ(iseq);
1007  original_code = ISEQ_ORIGINAL_ISEQ_ALLOC(iseq, ISEQ_BODY(iseq)->iseq_size);
1008  MEMCPY(original_code, ISEQ_BODY(iseq)->iseq_encoded, VALUE, ISEQ_BODY(iseq)->iseq_size);
1009 
1010 #if OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE
1011  {
1012  unsigned int i;
1013 
1014  for (i = 0; i < ISEQ_BODY(iseq)->iseq_size; /* */ ) {
1015  const void *addr = (const void *)original_code[i];
1016  const int insn = rb_vm_insn_addr2insn(addr);
1017 
1018  original_code[i] = insn;
1019  i += insn_len(insn);
1020  }
1021  }
1022 #endif
1023  return original_code;
1024 }
1025 
1026 /*********************************************/
1027 /* definition of data structure for compiler */
1028 /*********************************************/
1029 
1030 /*
1031  * On 32-bit SPARC, GCC by default generates SPARC V7 code that may require
1032  * 8-byte word alignment. On the other hand, Oracle Solaris Studio seems to
1033  * generate SPARCV8PLUS code with unaligned memory access instructions.
1034  * That is why the STRICT_ALIGNMENT is defined only with GCC.
1035  */
1036 #if defined(__sparc) && SIZEOF_VOIDP == 4 && defined(__GNUC__)
1037  #define STRICT_ALIGNMENT
1038 #endif
1039 
1040 /*
1041  * Some OpenBSD platforms (including sparc64) require strict alignment.
1042  */
1043 #if defined(__OpenBSD__)
1044  #include <sys/endian.h>
1045  #ifdef __STRICT_ALIGNMENT
1046  #define STRICT_ALIGNMENT
1047  #endif
1048 #endif
1049 
1050 #ifdef STRICT_ALIGNMENT
1051  #if defined(HAVE_TRUE_LONG_LONG) && SIZEOF_LONG_LONG > SIZEOF_VALUE
1052  #define ALIGNMENT_SIZE SIZEOF_LONG_LONG
1053  #else
1054  #define ALIGNMENT_SIZE SIZEOF_VALUE
1055  #endif
1056  #define PADDING_SIZE_MAX ((size_t)((ALIGNMENT_SIZE) - 1))
1057  #define ALIGNMENT_SIZE_MASK PADDING_SIZE_MAX
1058  /* Note: ALIGNMENT_SIZE == (2 ** N) is expected. */
1059 #else
1060  #define PADDING_SIZE_MAX 0
1061 #endif /* STRICT_ALIGNMENT */
1062 
1063 #ifdef STRICT_ALIGNMENT
1064 /* calculate padding size for aligned memory access */
1065 static size_t
1066 calc_padding(void *ptr, size_t size)
1067 {
1068  size_t mis;
1069  size_t padding = 0;
1070 
1071  mis = (size_t)ptr & ALIGNMENT_SIZE_MASK;
1072  if (mis > 0) {
1073  padding = ALIGNMENT_SIZE - mis;
1074  }
1075 /*
1076  * On 32-bit sparc or equivalents, when a single VALUE is requested
1077  * and padding == sizeof(VALUE), it is clear that no padding is needed.
1078  */
1079 #if ALIGNMENT_SIZE > SIZEOF_VALUE
1080  if (size == sizeof(VALUE) && padding == sizeof(VALUE)) {
1081  padding = 0;
1082  }
1083 #endif
1084 
1085  return padding;
1086 }
1087 #endif /* STRICT_ALIGNMENT */
1088 
1089 static void *
1090 compile_data_alloc_with_arena(struct iseq_compile_data_storage **arena, size_t size)
1091 {
1092  void *ptr = 0;
1093  struct iseq_compile_data_storage *storage = *arena;
1094 #ifdef STRICT_ALIGNMENT
1095  size_t padding = calc_padding((void *)&storage->buff[storage->pos], size);
1096 #else
1097  const size_t padding = 0; /* expected to be optimized by compiler */
1098 #endif /* STRICT_ALIGNMENT */
1099 
1100  if (size >= INT_MAX - padding) rb_memerror();
1101  if (storage->pos + size + padding > storage->size) {
1102  unsigned int alloc_size = storage->size;
1103 
1104  while (alloc_size < size + PADDING_SIZE_MAX) {
1105  if (alloc_size >= INT_MAX / 2) rb_memerror();
1106  alloc_size *= 2;
1107  }
1108  storage->next = (void *)ALLOC_N(char, alloc_size +
1109  offsetof(struct iseq_compile_data_storage, buff));
1110  storage = *arena = storage->next;
1111  storage->next = 0;
1112  storage->pos = 0;
1113  storage->size = alloc_size;
1114 #ifdef STRICT_ALIGNMENT
1115  padding = calc_padding((void *)&storage->buff[storage->pos], size);
1116 #endif /* STRICT_ALIGNMENT */
1117  }
1118 
1119 #ifdef STRICT_ALIGNMENT
1120  storage->pos += (int)padding;
1121 #endif /* STRICT_ALIGNMENT */
1122 
1123  ptr = (void *)&storage->buff[storage->pos];
1124  storage->pos += (int)size;
1125  return ptr;
1126 }
1127 
1128 static void *
1129 compile_data_alloc(rb_iseq_t *iseq, size_t size)
1130 {
1131  struct iseq_compile_data_storage ** arena = &ISEQ_COMPILE_DATA(iseq)->node.storage_current;
1132  return compile_data_alloc_with_arena(arena, size);
1133 }
1134 
1135 static inline void *
1136 compile_data_alloc2(rb_iseq_t *iseq, size_t x, size_t y)
1137 {
1138  size_t size = rb_size_mul_or_raise(x, y, rb_eRuntimeError);
1139  return compile_data_alloc(iseq, size);
1140 }
1141 
1142 static inline void *
1143 compile_data_calloc2(rb_iseq_t *iseq, size_t x, size_t y)
1144 {
1145  size_t size = rb_size_mul_or_raise(x, y, rb_eRuntimeError);
1146  void *p = compile_data_alloc(iseq, size);
1147  memset(p, 0, size);
1148  return p;
1149 }
1150 
1151 static INSN *
1152 compile_data_alloc_insn(rb_iseq_t *iseq)
1153 {
1154  struct iseq_compile_data_storage ** arena = &ISEQ_COMPILE_DATA(iseq)->insn.storage_current;
1155  return (INSN *)compile_data_alloc_with_arena(arena, sizeof(INSN));
1156 }
1157 
1158 static LABEL *
1159 compile_data_alloc_label(rb_iseq_t *iseq)
1160 {
1161  return (LABEL *)compile_data_alloc(iseq, sizeof(LABEL));
1162 }
1163 
1164 static ADJUST *
1165 compile_data_alloc_adjust(rb_iseq_t *iseq)
1166 {
1167  return (ADJUST *)compile_data_alloc(iseq, sizeof(ADJUST));
1168 }
1169 
1170 static TRACE *
1171 compile_data_alloc_trace(rb_iseq_t *iseq)
1172 {
1173  return (TRACE *)compile_data_alloc(iseq, sizeof(TRACE));
1174 }
1175 
1176 /*
1177  * elem1, elemX => elem1, elem2, elemX
1178  */
1179 static void
1180 ELEM_INSERT_NEXT(LINK_ELEMENT *elem1, LINK_ELEMENT *elem2)
1181 {
1182  elem2->next = elem1->next;
1183  elem2->prev = elem1;
1184  elem1->next = elem2;
1185  if (elem2->next) {
1186  elem2->next->prev = elem2;
1187  }
1188 }
1189 
1190 /*
1191  * elem1, elemX => elemX, elem2, elem1
1192  */
1193 static void
1194 ELEM_INSERT_PREV(LINK_ELEMENT *elem1, LINK_ELEMENT *elem2)
1195 {
1196  elem2->prev = elem1->prev;
1197  elem2->next = elem1;
1198  elem1->prev = elem2;
1199  if (elem2->prev) {
1200  elem2->prev->next = elem2;
1201  }
1202 }
1203 
1204 /*
1205  * elemX, elem1, elemY => elemX, elem2, elemY
1206  */
1207 static void
1208 ELEM_REPLACE(LINK_ELEMENT *elem1, LINK_ELEMENT *elem2)
1209 {
1210  elem2->prev = elem1->prev;
1211  elem2->next = elem1->next;
1212  if (elem1->prev) {
1213  elem1->prev->next = elem2;
1214  }
1215  if (elem1->next) {
1216  elem1->next->prev = elem2;
1217  }
1218 }
1219 
1220 static void
1221 ELEM_REMOVE(LINK_ELEMENT *elem)
1222 {
1223  elem->prev->next = elem->next;
1224  if (elem->next) {
1225  elem->next->prev = elem->prev;
1226  }
1227 }
1228 
1229 static LINK_ELEMENT *
1230 FIRST_ELEMENT(const LINK_ANCHOR *const anchor)
1231 {
1232  return anchor->anchor.next;
1233 }
1234 
1235 static LINK_ELEMENT *
1236 LAST_ELEMENT(LINK_ANCHOR *const anchor)
1237 {
1238  return anchor->last;
1239 }
1240 
1241 static LINK_ELEMENT *
1242 ELEM_FIRST_INSN(LINK_ELEMENT *elem)
1243 {
1244  while (elem) {
1245  switch (elem->type) {
1246  case ISEQ_ELEMENT_INSN:
1247  case ISEQ_ELEMENT_ADJUST:
1248  return elem;
1249  default:
1250  elem = elem->next;
1251  }
1252  }
1253  return NULL;
1254 }
1255 
1256 static int
1257 LIST_INSN_SIZE_ONE(const LINK_ANCHOR *const anchor)
1258 {
1259  LINK_ELEMENT *first_insn = ELEM_FIRST_INSN(FIRST_ELEMENT(anchor));
1260  if (first_insn != NULL &&
1261  ELEM_FIRST_INSN(first_insn->next) == NULL) {
1262  return TRUE;
1263  }
1264  else {
1265  return FALSE;
1266  }
1267 }
1268 
1269 static int
1270 LIST_INSN_SIZE_ZERO(const LINK_ANCHOR *const anchor)
1271 {
1272  if (ELEM_FIRST_INSN(FIRST_ELEMENT(anchor)) == NULL) {
1273  return TRUE;
1274  }
1275  else {
1276  return FALSE;
1277  }
1278 }
1279 
1280 /*
1281  * anc1: e1, e2, e3
1282  * anc2: e4, e5
1283  *#=>
1284  * anc1: e1, e2, e3, e4, e5
1285  * anc2: e4, e5 (broken)
1286  */
1287 static void
1288 APPEND_LIST(ISEQ_ARG_DECLARE LINK_ANCHOR *const anc1, LINK_ANCHOR *const anc2)
1289 {
1290  if (anc2->anchor.next) {
1291  /* LINK_ANCHOR must not loop */
1292  RUBY_ASSERT(anc2->last != &anc2->anchor);
1293  anc1->last->next = anc2->anchor.next;
1294  anc2->anchor.next->prev = anc1->last;
1295  anc1->last = anc2->last;
1296  }
1297  else {
1298  RUBY_ASSERT(anc2->last == &anc2->anchor);
1299  }
1300  verify_list("append", anc1);
1301 }
1302 #if CPDEBUG < 0
1303 #define APPEND_LIST(anc1, anc2) APPEND_LIST(iseq, (anc1), (anc2))
1304 #endif
1305 
1306 #if CPDEBUG && 0
1307 static void
1308 debug_list(ISEQ_ARG_DECLARE LINK_ANCHOR *const anchor, LINK_ELEMENT *cur)
1309 {
1310  LINK_ELEMENT *list = FIRST_ELEMENT(anchor);
1311  printf("----\n");
1312  printf("anch: %p, frst: %p, last: %p\n", (void *)&anchor->anchor,
1313  (void *)anchor->anchor.next, (void *)anchor->last);
1314  while (list) {
1315  printf("curr: %p, next: %p, prev: %p, type: %d\n", (void *)list, (void *)list->next,
1316  (void *)list->prev, (int)list->type);
1317  list = list->next;
1318  }
1319  printf("----\n");
1320 
1321  dump_disasm_list_with_cursor(anchor->anchor.next, cur, 0);
1322  verify_list("debug list", anchor);
1323 }
1324 #if CPDEBUG < 0
1325 #define debug_list(anc, cur) debug_list(iseq, (anc), (cur))
1326 #endif
1327 #else
1328 #define debug_list(anc, cur) ((void)0)
1329 #endif
1330 
1331 static TRACE *
1332 new_trace_body(rb_iseq_t *iseq, rb_event_flag_t event, long data)
1333 {
1334  TRACE *trace = compile_data_alloc_trace(iseq);
1335 
1336  trace->link.type = ISEQ_ELEMENT_TRACE;
1337  trace->link.next = NULL;
1338  trace->event = event;
1339  trace->data = data;
1340 
1341  return trace;
1342 }
1343 
1344 static LABEL *
1345 new_label_body(rb_iseq_t *iseq, long line)
1346 {
1347  LABEL *labelobj = compile_data_alloc_label(iseq);
1348 
1349  labelobj->link.type = ISEQ_ELEMENT_LABEL;
1350  labelobj->link.next = 0;
1351 
1352  labelobj->label_no = ISEQ_COMPILE_DATA(iseq)->label_no++;
1353  labelobj->sc_state = 0;
1354  labelobj->sp = -1;
1355  labelobj->refcnt = 0;
1356  labelobj->set = 0;
1357  labelobj->rescued = LABEL_RESCUE_NONE;
1358  labelobj->unremovable = 0;
1359  labelobj->position = -1;
1360  return labelobj;
1361 }
1362 
1363 static ADJUST *
1364 new_adjust_body(rb_iseq_t *iseq, LABEL *label, int line)
1365 {
1366  ADJUST *adjust = compile_data_alloc_adjust(iseq);
1367  adjust->link.type = ISEQ_ELEMENT_ADJUST;
1368  adjust->link.next = 0;
1369  adjust->label = label;
1370  adjust->line_no = line;
1371  LABEL_UNREMOVABLE(label);
1372  return adjust;
1373 }
1374 
1375 static void
1376 iseq_insn_each_markable_object(INSN *insn, void (*func)(VALUE, VALUE), VALUE data)
1377 {
1378  const char *types = insn_op_types(insn->insn_id);
1379  for (int j = 0; types[j]; j++) {
1380  char type = types[j];
1381  switch (type) {
1382  case TS_CDHASH:
1383  case TS_ISEQ:
1384  case TS_VALUE:
1385  case TS_IC: // constant path array
1386  case TS_CALLDATA: // ci is stored.
1387  func(OPERAND_AT(insn, j), data);
1388  break;
1389  default:
1390  break;
1391  }
1392  }
1393 }
1394 
1395 static void
1396 iseq_insn_each_object_write_barrier(VALUE obj, VALUE iseq)
1397 {
1398  RB_OBJ_WRITTEN(iseq, Qundef, obj);
1399 }
1400 
1401 static INSN *
1402 new_insn_core(rb_iseq_t *iseq, int line_no, int node_id, int insn_id, int argc, VALUE *argv)
1403 {
1404  INSN *iobj = compile_data_alloc_insn(iseq);
1405 
1406  /* printf("insn_id: %d, line: %d\n", insn_id, nd_line(line_node)); */
1407 
1408  iobj->link.type = ISEQ_ELEMENT_INSN;
1409  iobj->link.next = 0;
1410  iobj->insn_id = insn_id;
1411  iobj->insn_info.line_no = line_no;
1412  iobj->insn_info.node_id = node_id;
1413  iobj->insn_info.events = 0;
1414  iobj->operands = argv;
1415  iobj->operand_size = argc;
1416  iobj->sc_state = 0;
1417 
1418  iseq_insn_each_markable_object(iobj, iseq_insn_each_object_write_barrier, (VALUE)iseq);
1419 
1420  return iobj;
1421 }
1422 
1423 static INSN *
1424 new_insn_body(rb_iseq_t *iseq, int line_no, int node_id, enum ruby_vminsn_type insn_id, int argc, ...)
1425 {
1426  VALUE *operands = 0;
1427  va_list argv;
1428  if (argc > 0) {
1429  int i;
1430  va_start(argv, argc);
1431  operands = compile_data_alloc2(iseq, sizeof(VALUE), argc);
1432  for (i = 0; i < argc; i++) {
1433  VALUE v = va_arg(argv, VALUE);
1434  operands[i] = v;
1435  }
1436  va_end(argv);
1437  }
1438  return new_insn_core(iseq, line_no, node_id, insn_id, argc, operands);
1439 }
1440 
1441 static const struct rb_callinfo *
1442 new_callinfo(rb_iseq_t *iseq, ID mid, int argc, unsigned int flag, struct rb_callinfo_kwarg *kw_arg, int has_blockiseq)
1443 {
1444  VM_ASSERT(argc >= 0);
1445 
1446  if (kw_arg) {
1447  flag |= VM_CALL_KWARG;
1448  argc += kw_arg->keyword_len;
1449  }
1450 
1451  if (!(flag & (VM_CALL_ARGS_SPLAT | VM_CALL_ARGS_BLOCKARG | VM_CALL_KWARG | VM_CALL_KW_SPLAT | VM_CALL_FORWARDING))
1452  && !has_blockiseq) {
1453  flag |= VM_CALL_ARGS_SIMPLE;
1454  }
1455 
1456  ISEQ_BODY(iseq)->ci_size++;
1457  const struct rb_callinfo *ci = vm_ci_new(mid, flag, argc, kw_arg);
1458  RB_OBJ_WRITTEN(iseq, Qundef, ci);
1459  return ci;
1460 }
1461 
1462 static INSN *
1463 new_insn_send(rb_iseq_t *iseq, int line_no, int node_id, ID id, VALUE argc, const rb_iseq_t *blockiseq, VALUE flag, struct rb_callinfo_kwarg *keywords)
1464 {
1465  VALUE *operands = compile_data_calloc2(iseq, sizeof(VALUE), 2);
1466  VALUE ci = (VALUE)new_callinfo(iseq, id, FIX2INT(argc), FIX2INT(flag), keywords, blockiseq != NULL);
1467  operands[0] = ci;
1468  operands[1] = (VALUE)blockiseq;
1469  if (blockiseq) {
1470  RB_OBJ_WRITTEN(iseq, Qundef, blockiseq);
1471  }
1472 
1473  INSN *insn;
1474 
1475  if (vm_ci_flag((struct rb_callinfo *)ci) & VM_CALL_FORWARDING) {
1476  insn = new_insn_core(iseq, line_no, node_id, BIN(sendforward), 2, operands);
1477  }
1478  else {
1479  insn = new_insn_core(iseq, line_no, node_id, BIN(send), 2, operands);
1480  }
1481 
1482  RB_OBJ_WRITTEN(iseq, Qundef, ci);
1483  RB_GC_GUARD(ci);
1484  return insn;
1485 }
1486 
1487 static rb_iseq_t *
1488 new_child_iseq(rb_iseq_t *iseq, const NODE *const node,
1489  VALUE name, const rb_iseq_t *parent, enum rb_iseq_type type, int line_no)
1490 {
1491  rb_iseq_t *ret_iseq;
1492  VALUE ast_value = rb_ruby_ast_new(node);
1493 
1494  debugs("[new_child_iseq]> ---------------------------------------\n");
1495  int isolated_depth = ISEQ_COMPILE_DATA(iseq)->isolated_depth;
1496  ret_iseq = rb_iseq_new_with_opt(ast_value, name,
1497  rb_iseq_path(iseq), rb_iseq_realpath(iseq),
1498  line_no, parent,
1499  isolated_depth ? isolated_depth + 1 : 0,
1500  type, ISEQ_COMPILE_DATA(iseq)->option,
1501  ISEQ_BODY(iseq)->variable.script_lines);
1502  debugs("[new_child_iseq]< ---------------------------------------\n");
1503  return ret_iseq;
1504 }
1505 
1506 static rb_iseq_t *
1507 new_child_iseq_with_callback(rb_iseq_t *iseq, const struct rb_iseq_new_with_callback_callback_func *ifunc,
1508  VALUE name, const rb_iseq_t *parent, enum rb_iseq_type type, int line_no)
1509 {
1510  rb_iseq_t *ret_iseq;
1511 
1512  debugs("[new_child_iseq_with_callback]> ---------------------------------------\n");
1513  ret_iseq = rb_iseq_new_with_callback(ifunc, name,
1514  rb_iseq_path(iseq), rb_iseq_realpath(iseq),
1515  line_no, parent, type, ISEQ_COMPILE_DATA(iseq)->option);
1516  debugs("[new_child_iseq_with_callback]< ---------------------------------------\n");
1517  return ret_iseq;
1518 }
1519 
1520 static void
1521 set_catch_except_p(rb_iseq_t *iseq)
1522 {
1523  RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
1524  ISEQ_COMPILE_DATA(iseq)->catch_except_p = true;
1525  if (ISEQ_BODY(iseq)->parent_iseq != NULL) {
1526  if (ISEQ_COMPILE_DATA(ISEQ_BODY(iseq)->parent_iseq)) {
1527  set_catch_except_p((rb_iseq_t *) ISEQ_BODY(iseq)->parent_iseq);
1528  }
1529  }
1530 }
1531 
1532 /* Set body->catch_except_p to true if the ISeq may catch an exception. If it is false,
1533  JIT-ed code may be optimized. If we are extremely conservative, we should set true
1534  if catch table exists. But we want to optimize while loop, which always has catch
1535  table entries for break/next/redo.
1536 
1537  So this function sets true for limited ISeqs with break/next/redo catch table entries
1538  whose child ISeq would really raise an exception. */
1539 static void
1540 update_catch_except_flags(rb_iseq_t *iseq, struct rb_iseq_constant_body *body)
1541 {
1542  unsigned int pos;
1543  size_t i;
1544  int insn;
1545  const struct iseq_catch_table *ct = body->catch_table;
1546 
1547  /* This assumes that a block has parent_iseq which may catch an exception from the block, and that
1548  BREAK/NEXT/REDO catch table entries are used only when `throw` insn is used in the block. */
1549  pos = 0;
1550  while (pos < body->iseq_size) {
1551  insn = rb_vm_insn_decode(body->iseq_encoded[pos]);
1552  if (insn == BIN(throw)) {
1553  set_catch_except_p(iseq);
1554  break;
1555  }
1556  pos += insn_len(insn);
1557  }
1558 
1559  if (ct == NULL)
1560  return;
1561 
1562  for (i = 0; i < ct->size; i++) {
1563  const struct iseq_catch_table_entry *entry =
1564  UNALIGNED_MEMBER_PTR(ct, entries[i]);
1565  if (entry->type != CATCH_TYPE_BREAK
1566  && entry->type != CATCH_TYPE_NEXT
1567  && entry->type != CATCH_TYPE_REDO) {
1568  RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
1569  ISEQ_COMPILE_DATA(iseq)->catch_except_p = true;
1570  break;
1571  }
1572  }
1573 }
1574 
1575 static void
1576 iseq_insert_nop_between_end_and_cont(rb_iseq_t *iseq)
1577 {
1578  VALUE catch_table_ary = ISEQ_COMPILE_DATA(iseq)->catch_table_ary;
1579  if (NIL_P(catch_table_ary)) return;
1580  unsigned int i, tlen = (unsigned int)RARRAY_LEN(catch_table_ary);
1581  const VALUE *tptr = RARRAY_CONST_PTR(catch_table_ary);
1582  for (i = 0; i < tlen; i++) {
1583  const VALUE *ptr = RARRAY_CONST_PTR(tptr[i]);
1584  LINK_ELEMENT *end = (LINK_ELEMENT *)(ptr[2] & ~1);
1585  LINK_ELEMENT *cont = (LINK_ELEMENT *)(ptr[4] & ~1);
1586  LINK_ELEMENT *e;
1587 
1588  enum rb_catch_type ct = (enum rb_catch_type)(ptr[0] & 0xffff);
1589 
1590  if (ct != CATCH_TYPE_BREAK
1591  && ct != CATCH_TYPE_NEXT
1592  && ct != CATCH_TYPE_REDO) {
1593 
1594  for (e = end; e && (IS_LABEL(e) || IS_TRACE(e)); e = e->next) {
1595  if (e == cont) {
1596  INSN *nop = new_insn_core(iseq, 0, -1, BIN(nop), 0, 0);
1597  ELEM_INSERT_NEXT(end, &nop->link);
1598  break;
1599  }
1600  }
1601  }
1602  }
1603 
1604  RB_GC_GUARD(catch_table_ary);
1605 }
1606 
1607 static int
1608 iseq_setup_insn(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
1609 {
1610  if (RTEST(ISEQ_COMPILE_DATA(iseq)->err_info))
1611  return COMPILE_NG;
1612 
1613  /* debugs("[compile step 2] (iseq_array_to_linkedlist)\n"); */
1614 
1615  if (compile_debug > 5)
1616  dump_disasm_list(FIRST_ELEMENT(anchor));
1617 
1618  debugs("[compile step 3.1 (iseq_optimize)]\n");
1619  iseq_optimize(iseq, anchor);
1620 
1621  if (compile_debug > 5)
1622  dump_disasm_list(FIRST_ELEMENT(anchor));
1623 
1624  if (ISEQ_COMPILE_DATA(iseq)->option->instructions_unification) {
1625  debugs("[compile step 3.2 (iseq_insns_unification)]\n");
1626  iseq_insns_unification(iseq, anchor);
1627  if (compile_debug > 5)
1628  dump_disasm_list(FIRST_ELEMENT(anchor));
1629  }
1630 
1631  debugs("[compile step 3.4 (iseq_insert_nop_between_end_and_cont)]\n");
1632  iseq_insert_nop_between_end_and_cont(iseq);
1633  if (compile_debug > 5)
1634  dump_disasm_list(FIRST_ELEMENT(anchor));
1635 
1636  return COMPILE_OK;
1637 }
1638 
1639 static int
1640 iseq_setup(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
1641 {
1642  if (RTEST(ISEQ_COMPILE_DATA(iseq)->err_info))
1643  return COMPILE_NG;
1644 
1645  debugs("[compile step 4.1 (iseq_set_sequence)]\n");
1646  if (!iseq_set_sequence(iseq, anchor)) return COMPILE_NG;
1647  if (compile_debug > 5)
1648  dump_disasm_list(FIRST_ELEMENT(anchor));
1649 
1650  debugs("[compile step 4.2 (iseq_set_exception_table)]\n");
1651  if (!iseq_set_exception_table(iseq)) return COMPILE_NG;
1652 
1653  debugs("[compile step 4.3 (set_optargs_table)] \n");
1654  if (!iseq_set_optargs_table(iseq)) return COMPILE_NG;
1655 
1656  debugs("[compile step 5 (iseq_translate_threaded_code)] \n");
1657  if (!rb_iseq_translate_threaded_code(iseq)) return COMPILE_NG;
1658 
1659  debugs("[compile step 6 (update_catch_except_flags)] \n");
1660  RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
1661  update_catch_except_flags(iseq, ISEQ_BODY(iseq));
1662 
1663  debugs("[compile step 6.1 (remove unused catch tables)] \n");
1664  RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
1665  if (!ISEQ_COMPILE_DATA(iseq)->catch_except_p && ISEQ_BODY(iseq)->catch_table) {
1666  xfree(ISEQ_BODY(iseq)->catch_table);
1667  ISEQ_BODY(iseq)->catch_table = NULL;
1668  }
1669 
1670 #if VM_INSN_INFO_TABLE_IMPL == 2
1671  if (ISEQ_BODY(iseq)->insns_info.succ_index_table == NULL) {
1672  debugs("[compile step 7 (rb_iseq_insns_info_encode_positions)] \n");
1673  rb_iseq_insns_info_encode_positions(iseq);
1674  }
1675 #endif
1676 
1677  if (compile_debug > 1) {
1678  VALUE str = rb_iseq_disasm(iseq);
1679  printf("%s\n", StringValueCStr(str));
1680  }
1681  verify_call_cache(iseq);
1682  debugs("[compile step: finish]\n");
1683 
1684  return COMPILE_OK;
1685 }
1686 
1687 static int
1688 iseq_set_exception_local_table(rb_iseq_t *iseq)
1689 {
1690  ISEQ_BODY(iseq)->local_table_size = numberof(rb_iseq_shared_exc_local_tbl);
1691  ISEQ_BODY(iseq)->local_table = rb_iseq_shared_exc_local_tbl;
1692  return COMPILE_OK;
1693 }
1694 
1695 static int
1696 get_lvar_level(const rb_iseq_t *iseq)
1697 {
1698  int lev = 0;
1699  while (iseq != ISEQ_BODY(iseq)->local_iseq) {
1700  lev++;
1701  iseq = ISEQ_BODY(iseq)->parent_iseq;
1702  }
1703  return lev;
1704 }
1705 
1706 static int
1707 get_dyna_var_idx_at_raw(const rb_iseq_t *iseq, ID id)
1708 {
1709  unsigned int i;
1710 
1711  for (i = 0; i < ISEQ_BODY(iseq)->local_table_size; i++) {
1712  if (ISEQ_BODY(iseq)->local_table[i] == id) {
1713  return (int)i;
1714  }
1715  }
1716  return -1;
1717 }
1718 
1719 static int
1720 get_local_var_idx(const rb_iseq_t *iseq, ID id)
1721 {
1722  int idx = get_dyna_var_idx_at_raw(ISEQ_BODY(iseq)->local_iseq, id);
1723 
1724  if (idx < 0) {
1725  COMPILE_ERROR(iseq, ISEQ_LAST_LINE(iseq),
1726  "get_local_var_idx: %d", idx);
1727  }
1728 
1729  return idx;
1730 }
1731 
1732 static int
1733 get_dyna_var_idx(const rb_iseq_t *iseq, ID id, int *level, int *ls)
1734 {
1735  int lv = 0, idx = -1;
1736  const rb_iseq_t *const topmost_iseq = iseq;
1737 
1738  while (iseq) {
1739  idx = get_dyna_var_idx_at_raw(iseq, id);
1740  if (idx >= 0) {
1741  break;
1742  }
1743  iseq = ISEQ_BODY(iseq)->parent_iseq;
1744  lv++;
1745  }
1746 
1747  if (idx < 0) {
1748  COMPILE_ERROR(topmost_iseq, ISEQ_LAST_LINE(topmost_iseq),
1749  "get_dyna_var_idx: -1");
1750  }
1751 
1752  *level = lv;
1753  *ls = ISEQ_BODY(iseq)->local_table_size;
1754  return idx;
1755 }
1756 
1757 static int
1758 iseq_local_block_param_p(const rb_iseq_t *iseq, unsigned int idx, unsigned int level)
1759 {
1760  const struct rb_iseq_constant_body *body;
1761  while (level > 0) {
1762  iseq = ISEQ_BODY(iseq)->parent_iseq;
1763  level--;
1764  }
1765  body = ISEQ_BODY(iseq);
1766  if (body->local_iseq == iseq && /* local variables */
1767  body->param.flags.has_block &&
1768  body->local_table_size - body->param.block_start == idx) {
1769  return TRUE;
1770  }
1771  else {
1772  return FALSE;
1773  }
1774 }
1775 
1776 static int
1777 iseq_block_param_id_p(const rb_iseq_t *iseq, ID id, int *pidx, int *plevel)
1778 {
1779  int level, ls;
1780  int idx = get_dyna_var_idx(iseq, id, &level, &ls);
1781  if (iseq_local_block_param_p(iseq, ls - idx, level)) {
1782  *pidx = ls - idx;
1783  *plevel = level;
1784  return TRUE;
1785  }
1786  else {
1787  return FALSE;
1788  }
1789 }
1790 
1791 static void
1792 access_outer_variables(const rb_iseq_t *iseq, int level, ID id, bool write)
1793 {
1794  int isolated_depth = ISEQ_COMPILE_DATA(iseq)->isolated_depth;
1795 
1796  if (isolated_depth && level >= isolated_depth) {
1797  if (id == rb_intern("yield")) {
1798  COMPILE_ERROR(iseq, ISEQ_LAST_LINE(iseq), "can not yield from isolated Proc");
1799  }
1800  else {
1801  COMPILE_ERROR(iseq, ISEQ_LAST_LINE(iseq), "can not access variable '%s' from isolated Proc", rb_id2name(id));
1802  }
1803  }
1804 
1805  for (int i=0; i<level; i++) {
1806  VALUE val;
1807  struct rb_id_table *ovs = ISEQ_BODY(iseq)->outer_variables;
1808 
1809  if (!ovs) {
1810  ovs = ISEQ_BODY(iseq)->outer_variables = rb_id_table_create(8);
1811  }
1812 
1813  if (rb_id_table_lookup(ISEQ_BODY(iseq)->outer_variables, id, &val)) {
1814  if (write && !val) {
1815  rb_id_table_insert(ISEQ_BODY(iseq)->outer_variables, id, Qtrue);
1816  }
1817  }
1818  else {
1819  rb_id_table_insert(ISEQ_BODY(iseq)->outer_variables, id, RBOOL(write));
1820  }
1821 
1822  iseq = ISEQ_BODY(iseq)->parent_iseq;
1823  }
1824 }
1825 
1826 static ID
1827 iseq_lvar_id(const rb_iseq_t *iseq, int idx, int level)
1828 {
1829  for (int i=0; i<level; i++) {
1830  iseq = ISEQ_BODY(iseq)->parent_iseq;
1831  }
1832 
1833  ID id = ISEQ_BODY(iseq)->local_table[ISEQ_BODY(iseq)->local_table_size - idx];
1834  // fprintf(stderr, "idx:%d level:%d ID:%s\n", idx, level, rb_id2name(id));
1835  return id;
1836 }
1837 
1838 static void
1839 iseq_add_getlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NODE *const line_node, int idx, int level)
1840 {
1841  if (iseq_local_block_param_p(iseq, idx, level)) {
1842  ADD_INSN2(seq, line_node, getblockparam, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1843  }
1844  else {
1845  ADD_INSN2(seq, line_node, getlocal, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1846  }
1847  if (level > 0) access_outer_variables(iseq, level, iseq_lvar_id(iseq, idx, level), Qfalse);
1848 }
1849 
1850 static void
1851 iseq_add_setlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NODE *const line_node, int idx, int level)
1852 {
1853  if (iseq_local_block_param_p(iseq, idx, level)) {
1854  ADD_INSN2(seq, line_node, setblockparam, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1855  }
1856  else {
1857  ADD_INSN2(seq, line_node, setlocal, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1858  }
1859  if (level > 0) access_outer_variables(iseq, level, iseq_lvar_id(iseq, idx, level), Qtrue);
1860 }
1861 
1862 
1863 
1864 static void
1865 iseq_calc_param_size(rb_iseq_t *iseq)
1866 {
1867  struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
1868  if (body->param.flags.has_opt ||
1869  body->param.flags.has_post ||
1870  body->param.flags.has_rest ||
1871  body->param.flags.has_block ||
1872  body->param.flags.has_kw ||
1873  body->param.flags.has_kwrest) {
1874 
1875  if (body->param.flags.has_block) {
1876  body->param.size = body->param.block_start + 1;
1877  }
1878  else if (body->param.flags.has_kwrest) {
1879  body->param.size = body->param.keyword->rest_start + 1;
1880  }
1881  else if (body->param.flags.has_kw) {
1882  body->param.size = body->param.keyword->bits_start + 1;
1883  }
1884  else if (body->param.flags.has_post) {
1885  body->param.size = body->param.post_start + body->param.post_num;
1886  }
1887  else if (body->param.flags.has_rest) {
1888  body->param.size = body->param.rest_start + 1;
1889  }
1890  else if (body->param.flags.has_opt) {
1891  body->param.size = body->param.lead_num + body->param.opt_num;
1892  }
1893  else {
1894  UNREACHABLE;
1895  }
1896  }
1897  else {
1898  body->param.size = body->param.lead_num;
1899  }
1900 }
1901 
1902 static int
1903 iseq_set_arguments_keywords(rb_iseq_t *iseq, LINK_ANCHOR *const optargs,
1904  const struct rb_args_info *args, int arg_size)
1905 {
1906  const rb_node_kw_arg_t *node = args->kw_args;
1907  struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
1908  struct rb_iseq_param_keyword *keyword;
1909  const VALUE default_values = rb_ary_hidden_new(1);
1910  const VALUE complex_mark = rb_str_tmp_new(0);
1911  int kw = 0, rkw = 0, di = 0, i;
1912 
1913  body->param.flags.has_kw = TRUE;
1914  body->param.keyword = keyword = ZALLOC_N(struct rb_iseq_param_keyword, 1);
1915 
1916  while (node) {
1917  kw++;
1918  node = node->nd_next;
1919  }
1920  arg_size += kw;
1921  keyword->bits_start = arg_size++;
1922 
1923  node = args->kw_args;
1924  while (node) {
1925  const NODE *val_node = get_nd_value(node->nd_body);
1926  VALUE dv;
1927 
1928  if (val_node == NODE_SPECIAL_REQUIRED_KEYWORD) {
1929  ++rkw;
1930  }
1931  else {
1932  switch (nd_type(val_node)) {
1933  case NODE_SYM:
1934  dv = rb_node_sym_string_val(val_node);
1935  break;
1936  case NODE_REGX:
1937  dv = rb_node_regx_string_val(val_node);
1938  break;
1939  case NODE_LINE:
1940  dv = rb_node_line_lineno_val(val_node);
1941  break;
1942  case NODE_INTEGER:
1943  dv = rb_node_integer_literal_val(val_node);
1944  break;
1945  case NODE_FLOAT:
1946  dv = rb_node_float_literal_val(val_node);
1947  break;
1948  case NODE_RATIONAL:
1949  dv = rb_node_rational_literal_val(val_node);
1950  break;
1951  case NODE_IMAGINARY:
1952  dv = rb_node_imaginary_literal_val(val_node);
1953  break;
1954  case NODE_ENCODING:
1955  dv = rb_node_encoding_val(val_node);
1956  break;
1957  case NODE_NIL:
1958  dv = Qnil;
1959  break;
1960  case NODE_TRUE:
1961  dv = Qtrue;
1962  break;
1963  case NODE_FALSE:
1964  dv = Qfalse;
1965  break;
1966  default:
1967  NO_CHECK(COMPILE_POPPED(optargs, "kwarg", RNODE(node))); /* nd_type_p(node, NODE_KW_ARG) */
1968  dv = complex_mark;
1969  }
1970 
1971  keyword->num = ++di;
1972  rb_ary_push(default_values, dv);
1973  }
1974 
1975  node = node->nd_next;
1976  }
1977 
1978  keyword->num = kw;
1979 
1980  if (RNODE_DVAR(args->kw_rest_arg)->nd_vid != 0) {
1981  ID kw_id = iseq->body->local_table[arg_size];
1982  keyword->rest_start = arg_size++;
1983  body->param.flags.has_kwrest = TRUE;
1984 
1985  if (kw_id == idPow) body->param.flags.anon_kwrest = TRUE;
1986  }
1987  keyword->required_num = rkw;
1988  keyword->table = &body->local_table[keyword->bits_start - keyword->num];
1989 
1990  if (RARRAY_LEN(default_values)) {
1991  VALUE *dvs = ALLOC_N(VALUE, RARRAY_LEN(default_values));
1992 
1993  for (i = 0; i < RARRAY_LEN(default_values); i++) {
1994  VALUE dv = RARRAY_AREF(default_values, i);
1995  if (dv == complex_mark) dv = Qundef;
1996  RB_OBJ_WRITE(iseq, &dvs[i], dv);
1997  }
1998 
1999  keyword->default_values = dvs;
2000  }
2001  return arg_size;
2002 }
2003 
2004 static void
2005 iseq_set_use_block(rb_iseq_t *iseq)
2006 {
2007  struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
2008  if (!body->param.flags.use_block) {
2009  body->param.flags.use_block = 1;
2010 
2011  rb_vm_t *vm = GET_VM();
2012 
2013  if (!rb_warning_category_enabled_p(RB_WARN_CATEGORY_STRICT_UNUSED_BLOCK)) {
2014  st_data_t key = (st_data_t)rb_intern_str(body->location.label); // String -> ID
2015  st_insert(vm->unused_block_warning_table, key, 1);
2016  }
2017  }
2018 }
2019 
2020 static int
2021 iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *const optargs, const NODE *const node_args)
2022 {
2023  debugs("iseq_set_arguments: %s\n", node_args ? "" : "0");
2024 
2025  if (node_args) {
2026  struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
2027  struct rb_args_info *args = &RNODE_ARGS(node_args)->nd_ainfo;
2028  ID rest_id = 0;
2029  int last_comma = 0;
2030  ID block_id = 0;
2031  int arg_size;
2032 
2033  EXPECT_NODE("iseq_set_arguments", node_args, NODE_ARGS, COMPILE_NG);
2034 
2035  body->param.flags.ruby2_keywords = args->ruby2_keywords;
2036  body->param.lead_num = arg_size = (int)args->pre_args_num;
2037  if (body->param.lead_num > 0) body->param.flags.has_lead = TRUE;
2038  debugs(" - argc: %d\n", body->param.lead_num);
2039 
2040  rest_id = args->rest_arg;
2041  if (rest_id == NODE_SPECIAL_EXCESSIVE_COMMA) {
2042  last_comma = 1;
2043  rest_id = 0;
2044  }
2045  block_id = args->block_arg;
2046 
2047  bool optimized_forward = (args->forwarding && args->pre_args_num == 0 && !args->opt_args);
2048 
2049  if (optimized_forward) {
2050  rest_id = 0;
2051  block_id = 0;
2052  }
2053 
2054  if (args->opt_args) {
2055  const rb_node_opt_arg_t *node = args->opt_args;
2056  LABEL *label;
2057  VALUE labels = rb_ary_hidden_new(1);
2058  VALUE *opt_table;
2059  int i = 0, j;
2060 
2061  while (node) {
2062  label = NEW_LABEL(nd_line(RNODE(node)));
2063  rb_ary_push(labels, (VALUE)label | 1);
2064  ADD_LABEL(optargs, label);
2065  NO_CHECK(COMPILE_POPPED(optargs, "optarg", node->nd_body));
2066  node = node->nd_next;
2067  i += 1;
2068  }
2069 
2070  /* last label */
2071  label = NEW_LABEL(nd_line(node_args));
2072  rb_ary_push(labels, (VALUE)label | 1);
2073  ADD_LABEL(optargs, label);
2074 
2075  opt_table = ALLOC_N(VALUE, i+1);
2076 
2077  MEMCPY(opt_table, RARRAY_CONST_PTR(labels), VALUE, i+1);
2078  for (j = 0; j < i+1; j++) {
2079  opt_table[j] &= ~1;
2080  }
2081  rb_ary_clear(labels);
2082 
2083  body->param.flags.has_opt = TRUE;
2084  body->param.opt_num = i;
2085  body->param.opt_table = opt_table;
2086  arg_size += i;
2087  }
2088 
2089  if (rest_id) {
2090  body->param.rest_start = arg_size++;
2091  body->param.flags.has_rest = TRUE;
2092  if (rest_id == '*') body->param.flags.anon_rest = TRUE;
2093  RUBY_ASSERT(body->param.rest_start != -1);
2094  }
2095 
2096  if (args->first_post_arg) {
2097  body->param.post_start = arg_size;
2098  body->param.post_num = args->post_args_num;
2099  body->param.flags.has_post = TRUE;
2100  arg_size += args->post_args_num;
2101 
2102  if (body->param.flags.has_rest) { /* TODO: why that? */
2103  body->param.post_start = body->param.rest_start + 1;
2104  }
2105  }
2106 
2107  if (args->kw_args) {
2108  arg_size = iseq_set_arguments_keywords(iseq, optargs, args, arg_size);
2109  }
2110  else if (args->kw_rest_arg && !optimized_forward) {
2111  ID kw_id = iseq->body->local_table[arg_size];
2112  struct rb_iseq_param_keyword *keyword = ZALLOC_N(struct rb_iseq_param_keyword, 1);
2113  keyword->rest_start = arg_size++;
2114  body->param.keyword = keyword;
2115  body->param.flags.has_kwrest = TRUE;
2116 
2117  static ID anon_kwrest = 0;
2118  if (!anon_kwrest) anon_kwrest = rb_intern("**");
2119  if (kw_id == anon_kwrest) body->param.flags.anon_kwrest = TRUE;
2120  }
2121  else if (args->no_kwarg) {
2122  body->param.flags.accepts_no_kwarg = TRUE;
2123  }
2124 
2125  if (block_id) {
2126  body->param.block_start = arg_size++;
2127  body->param.flags.has_block = TRUE;
2128  iseq_set_use_block(iseq);
2129  }
2130 
2131  // Only optimize specifically methods like this: `foo(...)`
2132  if (optimized_forward) {
2133  body->param.flags.use_block = 1;
2134  body->param.flags.forwardable = TRUE;
2135  arg_size = 1;
2136  }
2137 
2138  iseq_calc_param_size(iseq);
2139  body->param.size = arg_size;
2140 
2141  if (args->pre_init) { /* m_init */
2142  NO_CHECK(COMPILE_POPPED(optargs, "init arguments (m)", args->pre_init));
2143  }
2144  if (args->post_init) { /* p_init */
2145  NO_CHECK(COMPILE_POPPED(optargs, "init arguments (p)", args->post_init));
2146  }
2147 
2148  if (body->type == ISEQ_TYPE_BLOCK) {
2149  if (body->param.flags.has_opt == FALSE &&
2150  body->param.flags.has_post == FALSE &&
2151  body->param.flags.has_rest == FALSE &&
2152  body->param.flags.has_kw == FALSE &&
2153  body->param.flags.has_kwrest == FALSE) {
2154 
2155  if (body->param.lead_num == 1 && last_comma == 0) {
2156  /* {|a|} */
2157  body->param.flags.ambiguous_param0 = TRUE;
2158  }
2159  }
2160  }
2161  }
2162 
2163  return COMPILE_OK;
2164 }
2165 
2166 static int
2167 iseq_set_local_table(rb_iseq_t *iseq, const rb_ast_id_table_t *tbl, const NODE *const node_args)
2168 {
2169  unsigned int size = tbl ? tbl->size : 0;
2170  unsigned int offset = 0;
2171 
2172  if (node_args) {
2173  struct rb_args_info *args = &RNODE_ARGS(node_args)->nd_ainfo;
2174 
2175  // If we have a function that only has `...` as the parameter,
2176  // then its local table should only be `...`
2177  // FIXME: I think this should be fixed in the AST rather than special case here.
2178  if (args->forwarding && args->pre_args_num == 0 && !args->opt_args) {
2179  size -= 3;
2180  offset += 3;
2181  }
2182  }
2183 
2184  if (size > 0) {
2185  ID *ids = (ID *)ALLOC_N(ID, size);
2186  MEMCPY(ids, tbl->ids + offset, ID, size);
2187  ISEQ_BODY(iseq)->local_table = ids;
2188  }
2189  ISEQ_BODY(iseq)->local_table_size = size;
2190 
2191  debugs("iseq_set_local_table: %u\n", ISEQ_BODY(iseq)->local_table_size);
2192  return COMPILE_OK;
2193 }
2194 
2195 int
2196 rb_iseq_cdhash_cmp(VALUE val, VALUE lit)
2197 {
2198  int tval, tlit;
2199 
2200  if (val == lit) {
2201  return 0;
2202  }
2203  else if ((tlit = OBJ_BUILTIN_TYPE(lit)) == -1) {
2204  return val != lit;
2205  }
2206  else if ((tval = OBJ_BUILTIN_TYPE(val)) == -1) {
2207  return -1;
2208  }
2209  else if (tlit != tval) {
2210  return -1;
2211  }
2212  else if (tlit == T_SYMBOL) {
2213  return val != lit;
2214  }
2215  else if (tlit == T_STRING) {
2216  return rb_str_hash_cmp(lit, val);
2217  }
2218  else if (tlit == T_BIGNUM) {
2219  long x = FIX2LONG(rb_big_cmp(lit, val));
2220 
2221  /* Given lit and val are both Bignum, x must be -1, 0, 1.
2222  * There is no need to call rb_fix2int here. */
2223  RUBY_ASSERT((x == 1) || (x == 0) || (x == -1));
2224  return (int)x;
2225  }
2226  else if (tlit == T_FLOAT) {
2227  return rb_float_cmp(lit, val);
2228  }
2229  else if (tlit == T_RATIONAL) {
2230  const struct RRational *rat1 = RRATIONAL(val);
2231  const struct RRational *rat2 = RRATIONAL(lit);
2232  return rb_iseq_cdhash_cmp(rat1->num, rat2->num) || rb_iseq_cdhash_cmp(rat1->den, rat2->den);
2233  }
2234  else if (tlit == T_COMPLEX) {
2235  const struct RComplex *comp1 = RCOMPLEX(val);
2236  const struct RComplex *comp2 = RCOMPLEX(lit);
2237  return rb_iseq_cdhash_cmp(comp1->real, comp2->real) || rb_iseq_cdhash_cmp(comp1->imag, comp2->imag);
2238  }
2239  else if (tlit == T_REGEXP) {
2240  return rb_reg_equal(val, lit) ? 0 : -1;
2241  }
2242  else {
2243  UNREACHABLE_RETURN(-1);
2244  }
2245 }
2246 
2247 st_index_t
2248 rb_iseq_cdhash_hash(VALUE a)
2249 {
2250  switch (OBJ_BUILTIN_TYPE(a)) {
2251  case -1:
2252  case T_SYMBOL:
2253  return (st_index_t)a;
2254  case T_STRING:
2255  return rb_str_hash(a);
2256  case T_BIGNUM:
2257  return FIX2LONG(rb_big_hash(a));
2258  case T_FLOAT:
2259  return rb_dbl_long_hash(RFLOAT_VALUE(a));
2260  case T_RATIONAL:
2261  return rb_rational_hash(a);
2262  case T_COMPLEX:
2263  return rb_complex_hash(a);
2264  case T_REGEXP:
2265  return NUM2LONG(rb_reg_hash(a));
2266  default:
2267  UNREACHABLE_RETURN(0);
2268  }
2269 }
2270 
2271 static const struct st_hash_type cdhash_type = {
2272  rb_iseq_cdhash_cmp,
2273  rb_iseq_cdhash_hash,
2274 };
2275 
2277  VALUE hash;
2278  int pos;
2279  int len;
2280 };
2281 
2282 static int
2283 cdhash_set_label_i(VALUE key, VALUE val, VALUE ptr)
2284 {
2285  struct cdhash_set_label_struct *data = (struct cdhash_set_label_struct *)ptr;
2286  LABEL *lobj = (LABEL *)(val & ~1);
2287  rb_hash_aset(data->hash, key, INT2FIX(lobj->position - (data->pos+data->len)));
2288  return ST_CONTINUE;
2289 }
2290 
2291 
2292 static inline VALUE
2293 get_ivar_ic_value(rb_iseq_t *iseq,ID id)
2294 {
2295  return INT2FIX(ISEQ_BODY(iseq)->ivc_size++);
2296 }
2297 
2298 static inline VALUE
2299 get_cvar_ic_value(rb_iseq_t *iseq,ID id)
2300 {
2301  VALUE val;
2302  struct rb_id_table *tbl = ISEQ_COMPILE_DATA(iseq)->ivar_cache_table;
2303  if (tbl) {
2304  if (rb_id_table_lookup(tbl,id,&val)) {
2305  return val;
2306  }
2307  }
2308  else {
2309  tbl = rb_id_table_create(1);
2310  ISEQ_COMPILE_DATA(iseq)->ivar_cache_table = tbl;
2311  }
2312  val = INT2FIX(ISEQ_BODY(iseq)->icvarc_size++);
2313  rb_id_table_insert(tbl,id,val);
2314  return val;
2315 }
2316 
2317 #define BADINSN_DUMP(anchor, list, dest) \
2318  dump_disasm_list_with_cursor(FIRST_ELEMENT(anchor), list, dest)
2319 
2320 #define BADINSN_ERROR \
2321  (xfree(generated_iseq), \
2322  xfree(insns_info), \
2323  BADINSN_DUMP(anchor, list, NULL), \
2324  COMPILE_ERROR)
2325 
2326 static int
2327 fix_sp_depth(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
2328 {
2329  int stack_max = 0, sp = 0, line = 0;
2330  LINK_ELEMENT *list;
2331 
2332  for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
2333  if (IS_LABEL(list)) {
2334  LABEL *lobj = (LABEL *)list;
2335  lobj->set = TRUE;
2336  }
2337  }
2338 
2339  for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
2340  switch (list->type) {
2341  case ISEQ_ELEMENT_INSN:
2342  {
2343  int j, len, insn;
2344  const char *types;
2345  VALUE *operands;
2346  INSN *iobj = (INSN *)list;
2347 
2348  /* update sp */
2349  sp = calc_sp_depth(sp, iobj);
2350  if (sp < 0) {
2351  BADINSN_DUMP(anchor, list, NULL);
2352  COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2353  "argument stack underflow (%d)", sp);
2354  return -1;
2355  }
2356  if (sp > stack_max) {
2357  stack_max = sp;
2358  }
2359 
2360  line = iobj->insn_info.line_no;
2361  /* fprintf(stderr, "insn: %-16s, sp: %d\n", insn_name(iobj->insn_id), sp); */
2362  operands = iobj->operands;
2363  insn = iobj->insn_id;
2364  types = insn_op_types(insn);
2365  len = insn_len(insn);
2366 
2367  /* operand check */
2368  if (iobj->operand_size != len - 1) {
2369  /* printf("operand size miss! (%d, %d)\n", iobj->operand_size, len); */
2370  BADINSN_DUMP(anchor, list, NULL);
2371  COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2372  "operand size miss! (%d for %d)",
2373  iobj->operand_size, len - 1);
2374  return -1;
2375  }
2376 
2377  for (j = 0; types[j]; j++) {
2378  if (types[j] == TS_OFFSET) {
2379  /* label(destination position) */
2380  LABEL *lobj = (LABEL *)operands[j];
2381  if (!lobj->set) {
2382  BADINSN_DUMP(anchor, list, NULL);
2383  COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2384  "unknown label: "LABEL_FORMAT, lobj->label_no);
2385  return -1;
2386  }
2387  if (lobj->sp == -1) {
2388  lobj->sp = sp;
2389  }
2390  else if (lobj->sp != sp) {
2391  debugs("%s:%d: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2392  RSTRING_PTR(rb_iseq_path(iseq)), line,
2393  lobj->label_no, lobj->sp, sp);
2394  }
2395  }
2396  }
2397  break;
2398  }
2399  case ISEQ_ELEMENT_LABEL:
2400  {
2401  LABEL *lobj = (LABEL *)list;
2402  if (lobj->sp == -1) {
2403  lobj->sp = sp;
2404  }
2405  else {
2406  if (lobj->sp != sp) {
2407  debugs("%s:%d: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2408  RSTRING_PTR(rb_iseq_path(iseq)), line,
2409  lobj->label_no, lobj->sp, sp);
2410  }
2411  sp = lobj->sp;
2412  }
2413  break;
2414  }
2415  case ISEQ_ELEMENT_TRACE:
2416  {
2417  /* ignore */
2418  break;
2419  }
2420  case ISEQ_ELEMENT_ADJUST:
2421  {
2422  ADJUST *adjust = (ADJUST *)list;
2423  int orig_sp = sp;
2424 
2425  sp = adjust->label ? adjust->label->sp : 0;
2426  if (adjust->line_no != -1 && orig_sp - sp < 0) {
2427  BADINSN_DUMP(anchor, list, NULL);
2428  COMPILE_ERROR(iseq, adjust->line_no,
2429  "iseq_set_sequence: adjust bug %d < %d",
2430  orig_sp, sp);
2431  return -1;
2432  }
2433  break;
2434  }
2435  default:
2436  BADINSN_DUMP(anchor, list, NULL);
2437  COMPILE_ERROR(iseq, line, "unknown list type: %d", list->type);
2438  return -1;
2439  }
2440  }
2441  return stack_max;
2442 }
2443 
2444 static int
2445 add_insn_info(struct iseq_insn_info_entry *insns_info, unsigned int *positions,
2446  int insns_info_index, int code_index, const INSN *iobj)
2447 {
2448  if (insns_info_index == 0 ||
2449  insns_info[insns_info_index-1].line_no != iobj->insn_info.line_no ||
2450 #ifdef USE_ISEQ_NODE_ID
2451  insns_info[insns_info_index-1].node_id != iobj->insn_info.node_id ||
2452 #endif
2453  insns_info[insns_info_index-1].events != iobj->insn_info.events) {
2454  insns_info[insns_info_index].line_no = iobj->insn_info.line_no;
2455 #ifdef USE_ISEQ_NODE_ID
2456  insns_info[insns_info_index].node_id = iobj->insn_info.node_id;
2457 #endif
2458  insns_info[insns_info_index].events = iobj->insn_info.events;
2459  positions[insns_info_index] = code_index;
2460  return TRUE;
2461  }
2462  return FALSE;
2463 }
2464 
2465 static int
2466 add_adjust_info(struct iseq_insn_info_entry *insns_info, unsigned int *positions,
2467  int insns_info_index, int code_index, const ADJUST *adjust)
2468 {
2469  insns_info[insns_info_index].line_no = adjust->line_no;
2470  insns_info[insns_info_index].node_id = -1;
2471  insns_info[insns_info_index].events = 0;
2472  positions[insns_info_index] = code_index;
2473  return TRUE;
2474 }
2475 
2476 static ID *
2477 array_to_idlist(VALUE arr)
2478 {
2479  RUBY_ASSERT(RB_TYPE_P(arr, T_ARRAY));
2480  long size = RARRAY_LEN(arr);
2481  ID *ids = (ID *)ALLOC_N(ID, size + 1);
2482  for (int i = 0; i < size; i++) {
2483  VALUE sym = RARRAY_AREF(arr, i);
2484  ids[i] = SYM2ID(sym);
2485  }
2486  ids[size] = 0;
2487  return ids;
2488 }
2489 
2490 static VALUE
2491 idlist_to_array(const ID *ids)
2492 {
2493  VALUE arr = rb_ary_new();
2494  while (*ids) {
2495  rb_ary_push(arr, ID2SYM(*ids++));
2496  }
2497  return arr;
2498 }
2499 
2503 static int
2504 iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
2505 {
2506  struct iseq_insn_info_entry *insns_info;
2507  struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
2508  unsigned int *positions;
2509  LINK_ELEMENT *list;
2510  VALUE *generated_iseq;
2511  rb_event_flag_t events = 0;
2512  long data = 0;
2513 
2514  int insn_num, code_index, insns_info_index, sp = 0;
2515  int stack_max = fix_sp_depth(iseq, anchor);
2516 
2517  if (stack_max < 0) return COMPILE_NG;
2518 
2519  /* fix label position */
2520  insn_num = code_index = 0;
2521  for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
2522  switch (list->type) {
2523  case ISEQ_ELEMENT_INSN:
2524  {
2525  INSN *iobj = (INSN *)list;
2526  /* update sp */
2527  sp = calc_sp_depth(sp, iobj);
2528  insn_num++;
2529  events = iobj->insn_info.events |= events;
2530  if (ISEQ_COVERAGE(iseq)) {
2531  if (ISEQ_LINE_COVERAGE(iseq) && (events & RUBY_EVENT_COVERAGE_LINE) &&
2532  !(rb_get_coverage_mode() & COVERAGE_TARGET_ONESHOT_LINES)) {
2533  int line = iobj->insn_info.line_no - 1;
2534  if (line >= 0 && line < RARRAY_LEN(ISEQ_LINE_COVERAGE(iseq))) {
2535  RARRAY_ASET(ISEQ_LINE_COVERAGE(iseq), line, INT2FIX(0));
2536  }
2537  }
2538  if (ISEQ_BRANCH_COVERAGE(iseq) && (events & RUBY_EVENT_COVERAGE_BRANCH)) {
2539  while (RARRAY_LEN(ISEQ_PC2BRANCHINDEX(iseq)) <= code_index) {
2540  rb_ary_push(ISEQ_PC2BRANCHINDEX(iseq), Qnil);
2541  }
2542  RARRAY_ASET(ISEQ_PC2BRANCHINDEX(iseq), code_index, INT2FIX(data));
2543  }
2544  }
2545  code_index += insn_data_length(iobj);
2546  events = 0;
2547  data = 0;
2548  break;
2549  }
2550  case ISEQ_ELEMENT_LABEL:
2551  {
2552  LABEL *lobj = (LABEL *)list;
2553  lobj->position = code_index;
2554  if (lobj->sp != sp) {
2555  debugs("%s: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2556  RSTRING_PTR(rb_iseq_path(iseq)),
2557  lobj->label_no, lobj->sp, sp);
2558  }
2559  sp = lobj->sp;
2560  break;
2561  }
2562  case ISEQ_ELEMENT_TRACE:
2563  {
2564  TRACE *trace = (TRACE *)list;
2565  events |= trace->event;
2566  if (trace->event & RUBY_EVENT_COVERAGE_BRANCH) data = trace->data;
2567  break;
2568  }
2569  case ISEQ_ELEMENT_ADJUST:
2570  {
2571  ADJUST *adjust = (ADJUST *)list;
2572  if (adjust->line_no != -1) {
2573  int orig_sp = sp;
2574  sp = adjust->label ? adjust->label->sp : 0;
2575  if (orig_sp - sp > 0) {
2576  if (orig_sp - sp > 1) code_index++; /* 1 operand */
2577  code_index++; /* insn */
2578  insn_num++;
2579  }
2580  }
2581  break;
2582  }
2583  default: break;
2584  }
2585  }
2586 
2587  /* make instruction sequence */
2588  generated_iseq = ALLOC_N(VALUE, code_index);
2589  insns_info = ALLOC_N(struct iseq_insn_info_entry, insn_num);
2590  positions = ALLOC_N(unsigned int, insn_num);
2591  if (ISEQ_IS_SIZE(body)) {
2592  body->is_entries = ZALLOC_N(union iseq_inline_storage_entry, ISEQ_IS_SIZE(body));
2593  }
2594  else {
2595  body->is_entries = NULL;
2596  }
2597  body->call_data = ZALLOC_N(struct rb_call_data, body->ci_size);
2598  ISEQ_COMPILE_DATA(iseq)->ci_index = 0;
2599 
2600  // Calculate the bitmask buffer size.
2601  // Round the generated_iseq size up to the nearest multiple
2602  // of the number of bits in an unsigned long.
2603 
2604  // Allocate enough room for the bitmask list
2605  iseq_bits_t * mark_offset_bits;
2606  int code_size = code_index;
2607 
2608  iseq_bits_t tmp[1] = {0};
2609  bool needs_bitmap = false;
2610 
2611  if (ISEQ_MBITS_BUFLEN(code_index) == 1) {
2612  mark_offset_bits = tmp;
2613  }
2614  else {
2615  mark_offset_bits = ZALLOC_N(iseq_bits_t, ISEQ_MBITS_BUFLEN(code_index));
2616  }
2617 
2618  list = FIRST_ELEMENT(anchor);
2619  insns_info_index = code_index = sp = 0;
2620 
2621  while (list) {
2622  switch (list->type) {
2623  case ISEQ_ELEMENT_INSN:
2624  {
2625  int j, len, insn;
2626  const char *types;
2627  VALUE *operands;
2628  INSN *iobj = (INSN *)list;
2629 
2630  /* update sp */
2631  sp = calc_sp_depth(sp, iobj);
2632  /* fprintf(stderr, "insn: %-16s, sp: %d\n", insn_name(iobj->insn_id), sp); */
2633  operands = iobj->operands;
2634  insn = iobj->insn_id;
2635  generated_iseq[code_index] = insn;
2636  types = insn_op_types(insn);
2637  len = insn_len(insn);
2638 
2639  for (j = 0; types[j]; j++) {
2640  char type = types[j];
2641 
2642  /* printf("--> [%c - (%d-%d)]\n", type, k, j); */
2643  switch (type) {
2644  case TS_OFFSET:
2645  {
2646  /* label(destination position) */
2647  LABEL *lobj = (LABEL *)operands[j];
2648  generated_iseq[code_index + 1 + j] = lobj->position - (code_index + len);
2649  break;
2650  }
2651  case TS_CDHASH:
2652  {
2653  VALUE map = operands[j];
2654  struct cdhash_set_label_struct data;
2655  data.hash = map;
2656  data.pos = code_index;
2657  data.len = len;
2658  rb_hash_foreach(map, cdhash_set_label_i, (VALUE)&data);
2659 
2660  rb_hash_rehash(map);
2661  freeze_hide_obj(map);
2662  generated_iseq[code_index + 1 + j] = map;
2663  ISEQ_MBITS_SET(mark_offset_bits, code_index + 1 + j);
2664  RB_OBJ_WRITTEN(iseq, Qundef, map);
2665  needs_bitmap = true;
2666  break;
2667  }
2668  case TS_LINDEX:
2669  case TS_NUM: /* ulong */
2670  generated_iseq[code_index + 1 + j] = FIX2INT(operands[j]);
2671  break;
2672  case TS_ISEQ: /* iseq */
2673  case TS_VALUE: /* VALUE */
2674  {
2675  VALUE v = operands[j];
2676  generated_iseq[code_index + 1 + j] = v;
2677  /* to mark ruby object */
2678  if (!SPECIAL_CONST_P(v)) {
2679  RB_OBJ_WRITTEN(iseq, Qundef, v);
2680  ISEQ_MBITS_SET(mark_offset_bits, code_index + 1 + j);
2681  needs_bitmap = true;
2682  }
2683  break;
2684  }
2685  /* [ TS_IVC | TS_ICVARC | TS_ISE | TS_IC ] */
2686  case TS_IC: /* inline cache: constants */
2687  {
2688  unsigned int ic_index = ISEQ_COMPILE_DATA(iseq)->ic_index++;
2689  IC ic = &ISEQ_IS_ENTRY_START(body, type)[ic_index].ic_cache;
2690  if (UNLIKELY(ic_index >= body->ic_size)) {
2691  BADINSN_DUMP(anchor, &iobj->link, 0);
2692  COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2693  "iseq_set_sequence: ic_index overflow: index: %d, size: %d",
2694  ic_index, ISEQ_IS_SIZE(body));
2695  }
2696 
2697  ic->segments = array_to_idlist(operands[j]);
2698 
2699  generated_iseq[code_index + 1 + j] = (VALUE)ic;
2700  }
2701  break;
2702  case TS_IVC: /* inline ivar cache */
2703  {
2704  unsigned int ic_index = FIX2UINT(operands[j]);
2705 
2706  IVC cache = ((IVC)&body->is_entries[ic_index]);
2707 
2708  if (insn == BIN(setinstancevariable)) {
2709  cache->iv_set_name = SYM2ID(operands[j - 1]);
2710  }
2711  else {
2712  cache->iv_set_name = 0;
2713  }
2714 
2715  vm_ic_attr_index_initialize(cache, INVALID_SHAPE_ID);
2716  }
2717  case TS_ISE: /* inline storage entry: `once` insn */
2718  case TS_ICVARC: /* inline cvar cache */
2719  {
2720  unsigned int ic_index = FIX2UINT(operands[j]);
2721  IC ic = &ISEQ_IS_ENTRY_START(body, type)[ic_index].ic_cache;
2722  if (UNLIKELY(ic_index >= ISEQ_IS_SIZE(body))) {
2723  BADINSN_DUMP(anchor, &iobj->link, 0);
2724  COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2725  "iseq_set_sequence: ic_index overflow: index: %d, size: %d",
2726  ic_index, ISEQ_IS_SIZE(body));
2727  }
2728  generated_iseq[code_index + 1 + j] = (VALUE)ic;
2729 
2730  break;
2731  }
2732  case TS_CALLDATA:
2733  {
2734  const struct rb_callinfo *source_ci = (const struct rb_callinfo *)operands[j];
2735  RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq)->ci_index <= body->ci_size);
2736  struct rb_call_data *cd = &body->call_data[ISEQ_COMPILE_DATA(iseq)->ci_index++];
2737  cd->ci = source_ci;
2738  cd->cc = vm_cc_empty();
2739  generated_iseq[code_index + 1 + j] = (VALUE)cd;
2740  break;
2741  }
2742  case TS_ID: /* ID */
2743  generated_iseq[code_index + 1 + j] = SYM2ID(operands[j]);
2744  break;
2745  case TS_FUNCPTR:
2746  generated_iseq[code_index + 1 + j] = operands[j];
2747  break;
2748  case TS_BUILTIN:
2749  generated_iseq[code_index + 1 + j] = operands[j];
2750  break;
2751  default:
2752  BADINSN_ERROR(iseq, iobj->insn_info.line_no,
2753  "unknown operand type: %c", type);
2754  return COMPILE_NG;
2755  }
2756  }
2757  if (add_insn_info(insns_info, positions, insns_info_index, code_index, iobj)) insns_info_index++;
2758  code_index += len;
2759  break;
2760  }
2761  case ISEQ_ELEMENT_LABEL:
2762  {
2763  LABEL *lobj = (LABEL *)list;
2764  if (lobj->sp != sp) {
2765  debugs("%s: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2766  RSTRING_PTR(rb_iseq_path(iseq)),
2767  lobj->label_no, lobj->sp, sp);
2768  }
2769  sp = lobj->sp;
2770  break;
2771  }
2772  case ISEQ_ELEMENT_ADJUST:
2773  {
2774  ADJUST *adjust = (ADJUST *)list;
2775  int orig_sp = sp;
2776 
2777  if (adjust->label) {
2778  sp = adjust->label->sp;
2779  }
2780  else {
2781  sp = 0;
2782  }
2783 
2784  if (adjust->line_no != -1) {
2785  const int diff = orig_sp - sp;
2786  if (diff > 0) {
2787  if (insns_info_index == 0) {
2788  COMPILE_ERROR(iseq, adjust->line_no,
2789  "iseq_set_sequence: adjust bug (ISEQ_ELEMENT_ADJUST must not be the first in iseq)");
2790  }
2791  if (add_adjust_info(insns_info, positions, insns_info_index, code_index, adjust)) insns_info_index++;
2792  }
2793  if (diff > 1) {
2794  generated_iseq[code_index++] = BIN(adjuststack);
2795  generated_iseq[code_index++] = orig_sp - sp;
2796  }
2797  else if (diff == 1) {
2798  generated_iseq[code_index++] = BIN(pop);
2799  }
2800  else if (diff < 0) {
2801  int label_no = adjust->label ? adjust->label->label_no : -1;
2802  xfree(generated_iseq);
2803  xfree(insns_info);
2804  xfree(positions);
2805  if (ISEQ_MBITS_BUFLEN(code_size) > 1) {
2806  xfree(mark_offset_bits);
2807  }
2808  debug_list(anchor, list);
2809  COMPILE_ERROR(iseq, adjust->line_no,
2810  "iseq_set_sequence: adjust bug to %d %d < %d",
2811  label_no, orig_sp, sp);
2812  return COMPILE_NG;
2813  }
2814  }
2815  break;
2816  }
2817  default:
2818  /* ignore */
2819  break;
2820  }
2821  list = list->next;
2822  }
2823 
2824  body->iseq_encoded = (void *)generated_iseq;
2825  body->iseq_size = code_index;
2826  body->stack_max = stack_max;
2827 
2828  if (ISEQ_MBITS_BUFLEN(body->iseq_size) == 1) {
2829  body->mark_bits.single = mark_offset_bits[0];
2830  }
2831  else {
2832  if (needs_bitmap) {
2833  body->mark_bits.list = mark_offset_bits;
2834  }
2835  else {
2836  body->mark_bits.list = 0;
2837  ruby_xfree(mark_offset_bits);
2838  }
2839  }
2840 
2841  /* get rid of memory leak when REALLOC failed */
2842  body->insns_info.body = insns_info;
2843  body->insns_info.positions = positions;
2844 
2845  REALLOC_N(insns_info, struct iseq_insn_info_entry, insns_info_index);
2846  body->insns_info.body = insns_info;
2847  REALLOC_N(positions, unsigned int, insns_info_index);
2848  body->insns_info.positions = positions;
2849  body->insns_info.size = insns_info_index;
2850 
2851  return COMPILE_OK;
2852 }
2853 
2854 static int
2855 label_get_position(LABEL *lobj)
2856 {
2857  return lobj->position;
2858 }
2859 
2860 static int
2861 label_get_sp(LABEL *lobj)
2862 {
2863  return lobj->sp;
2864 }
2865 
2866 static int
2867 iseq_set_exception_table(rb_iseq_t *iseq)
2868 {
2869  const VALUE *tptr, *ptr;
2870  unsigned int tlen, i;
2871  struct iseq_catch_table_entry *entry;
2872 
2873  ISEQ_BODY(iseq)->catch_table = NULL;
2874 
2875  VALUE catch_table_ary = ISEQ_COMPILE_DATA(iseq)->catch_table_ary;
2876  if (NIL_P(catch_table_ary)) return COMPILE_OK;
2877  tlen = (int)RARRAY_LEN(catch_table_ary);
2878  tptr = RARRAY_CONST_PTR(catch_table_ary);
2879 
2880  if (tlen > 0) {
2881  struct iseq_catch_table *table = xmalloc(iseq_catch_table_bytes(tlen));
2882  table->size = tlen;
2883 
2884  for (i = 0; i < table->size; i++) {
2885  int pos;
2886  ptr = RARRAY_CONST_PTR(tptr[i]);
2887  entry = UNALIGNED_MEMBER_PTR(table, entries[i]);
2888  entry->type = (enum rb_catch_type)(ptr[0] & 0xffff);
2889  pos = label_get_position((LABEL *)(ptr[1] & ~1));
2890  RUBY_ASSERT(pos >= 0);
2891  entry->start = (unsigned int)pos;
2892  pos = label_get_position((LABEL *)(ptr[2] & ~1));
2893  RUBY_ASSERT(pos >= 0);
2894  entry->end = (unsigned int)pos;
2895  entry->iseq = (rb_iseq_t *)ptr[3];
2896  RB_OBJ_WRITTEN(iseq, Qundef, entry->iseq);
2897 
2898  /* stack depth */
2899  if (ptr[4]) {
2900  LABEL *lobj = (LABEL *)(ptr[4] & ~1);
2901  entry->cont = label_get_position(lobj);
2902  entry->sp = label_get_sp(lobj);
2903 
2904  /* TODO: Dirty Hack! Fix me */
2905  if (entry->type == CATCH_TYPE_RESCUE ||
2906  entry->type == CATCH_TYPE_BREAK ||
2907  entry->type == CATCH_TYPE_NEXT) {
2908  RUBY_ASSERT(entry->sp > 0);
2909  entry->sp--;
2910  }
2911  }
2912  else {
2913  entry->cont = 0;
2914  }
2915  }
2916  ISEQ_BODY(iseq)->catch_table = table;
2917  RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->catch_table_ary, 0); /* free */
2918  }
2919 
2920  RB_GC_GUARD(catch_table_ary);
2921 
2922  return COMPILE_OK;
2923 }
2924 
2925 /*
2926  * set optional argument table
2927  * def foo(a, b=expr1, c=expr2)
2928  * =>
2929  * b:
2930  * expr1
2931  * c:
2932  * expr2
2933  */
2934 static int
2935 iseq_set_optargs_table(rb_iseq_t *iseq)
2936 {
2937  int i;
2938  VALUE *opt_table = (VALUE *)ISEQ_BODY(iseq)->param.opt_table;
2939 
2940  if (ISEQ_BODY(iseq)->param.flags.has_opt) {
2941  for (i = 0; i < ISEQ_BODY(iseq)->param.opt_num + 1; i++) {
2942  opt_table[i] = label_get_position((LABEL *)opt_table[i]);
2943  }
2944  }
2945  return COMPILE_OK;
2946 }
2947 
2948 static LINK_ELEMENT *
2949 get_destination_insn(INSN *iobj)
2950 {
2951  LABEL *lobj = (LABEL *)OPERAND_AT(iobj, 0);
2952  LINK_ELEMENT *list;
2953  rb_event_flag_t events = 0;
2954 
2955  list = lobj->link.next;
2956  while (list) {
2957  switch (list->type) {
2958  case ISEQ_ELEMENT_INSN:
2959  case ISEQ_ELEMENT_ADJUST:
2960  goto found;
2961  case ISEQ_ELEMENT_LABEL:
2962  /* ignore */
2963  break;
2964  case ISEQ_ELEMENT_TRACE:
2965  {
2966  TRACE *trace = (TRACE *)list;
2967  events |= trace->event;
2968  }
2969  break;
2970  default: break;
2971  }
2972  list = list->next;
2973  }
2974  found:
2975  if (list && IS_INSN(list)) {
2976  INSN *iobj = (INSN *)list;
2977  iobj->insn_info.events |= events;
2978  }
2979  return list;
2980 }
2981 
2982 static LINK_ELEMENT *
2983 get_next_insn(INSN *iobj)
2984 {
2985  LINK_ELEMENT *list = iobj->link.next;
2986 
2987  while (list) {
2988  if (IS_INSN(list) || IS_ADJUST(list)) {
2989  return list;
2990  }
2991  list = list->next;
2992  }
2993  return 0;
2994 }
2995 
2996 static LINK_ELEMENT *
2997 get_prev_insn(INSN *iobj)
2998 {
2999  LINK_ELEMENT *list = iobj->link.prev;
3000 
3001  while (list) {
3002  if (IS_INSN(list) || IS_ADJUST(list)) {
3003  return list;
3004  }
3005  list = list->prev;
3006  }
3007  return 0;
3008 }
3009 
3010 static void
3011 unref_destination(INSN *iobj, int pos)
3012 {
3013  LABEL *lobj = (LABEL *)OPERAND_AT(iobj, pos);
3014  --lobj->refcnt;
3015  if (!lobj->refcnt) ELEM_REMOVE(&lobj->link);
3016 }
3017 
3018 static bool
3019 replace_destination(INSN *dobj, INSN *nobj)
3020 {
3021  VALUE n = OPERAND_AT(nobj, 0);
3022  LABEL *dl = (LABEL *)OPERAND_AT(dobj, 0);
3023  LABEL *nl = (LABEL *)n;
3024  if (dl == nl) return false;
3025  --dl->refcnt;
3026  ++nl->refcnt;
3027  OPERAND_AT(dobj, 0) = n;
3028  if (!dl->refcnt) ELEM_REMOVE(&dl->link);
3029  return true;
3030 }
3031 
3032 static LABEL*
3033 find_destination(INSN *i)
3034 {
3035  int pos, len = insn_len(i->insn_id);
3036  for (pos = 0; pos < len; ++pos) {
3037  if (insn_op_types(i->insn_id)[pos] == TS_OFFSET) {
3038  return (LABEL *)OPERAND_AT(i, pos);
3039  }
3040  }
3041  return 0;
3042 }
3043 
3044 static int
3045 remove_unreachable_chunk(rb_iseq_t *iseq, LINK_ELEMENT *i)
3046 {
3047  LINK_ELEMENT *first = i, *end;
3048  int *unref_counts = 0, nlabels = ISEQ_COMPILE_DATA(iseq)->label_no;
3049 
3050  if (!i) return 0;
3051  unref_counts = ALLOCA_N(int, nlabels);
3052  MEMZERO(unref_counts, int, nlabels);
3053  end = i;
3054  do {
3055  LABEL *lab;
3056  if (IS_INSN(i)) {
3057  if (IS_INSN_ID(i, leave)) {
3058  end = i;
3059  break;
3060  }
3061  else if ((lab = find_destination((INSN *)i)) != 0) {
3062  unref_counts[lab->label_no]++;
3063  }
3064  }
3065  else if (IS_LABEL(i)) {
3066  lab = (LABEL *)i;
3067  if (lab->unremovable) return 0;
3068  if (lab->refcnt > unref_counts[lab->label_no]) {
3069  if (i == first) return 0;
3070  break;
3071  }
3072  continue;
3073  }
3074  else if (IS_TRACE(i)) {
3075  /* do nothing */
3076  }
3077  else if (IS_ADJUST(i)) {
3078  return 0;
3079  }
3080  end = i;
3081  } while ((i = i->next) != 0);
3082  i = first;
3083  do {
3084  if (IS_INSN(i)) {
3085  struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
3086  VALUE insn = INSN_OF(i);
3087  int pos, len = insn_len(insn);
3088  for (pos = 0; pos < len; ++pos) {
3089  switch (insn_op_types(insn)[pos]) {
3090  case TS_OFFSET:
3091  unref_destination((INSN *)i, pos);
3092  break;
3093  case TS_CALLDATA:
3094  --(body->ci_size);
3095  break;
3096  }
3097  }
3098  }
3099  ELEM_REMOVE(i);
3100  } while ((i != end) && (i = i->next) != 0);
3101  return 1;
3102 }
3103 
3104 static int
3105 iseq_pop_newarray(rb_iseq_t *iseq, INSN *iobj)
3106 {
3107  switch (OPERAND_AT(iobj, 0)) {
3108  case INT2FIX(0): /* empty array */
3109  ELEM_REMOVE(&iobj->link);
3110  return TRUE;
3111  case INT2FIX(1): /* single element array */
3112  ELEM_REMOVE(&iobj->link);
3113  return FALSE;
3114  default:
3115  iobj->insn_id = BIN(adjuststack);
3116  return TRUE;
3117  }
3118 }
3119 
3120 static int
3121 is_frozen_putstring(INSN *insn, VALUE *op)
3122 {
3123  if (IS_INSN_ID(insn, putstring) || IS_INSN_ID(insn, putchilledstring)) {
3124  *op = OPERAND_AT(insn, 0);
3125  return 1;
3126  }
3127  else if (IS_INSN_ID(insn, putobject)) { /* frozen_string_literal */
3128  *op = OPERAND_AT(insn, 0);
3129  return RB_TYPE_P(*op, T_STRING);
3130  }
3131  return 0;
3132 }
3133 
3134 static int
3135 optimize_checktype(rb_iseq_t *iseq, INSN *iobj)
3136 {
3137  /*
3138  * putobject obj
3139  * dup
3140  * checktype T_XXX
3141  * branchif l1
3142  * l2:
3143  * ...
3144  * l1:
3145  *
3146  * => obj is a T_XXX
3147  *
3148  * putobject obj (T_XXX)
3149  * jump L1
3150  * L1:
3151  *
3152  * => obj is not a T_XXX
3153  *
3154  * putobject obj (T_XXX)
3155  * jump L2
3156  * L2:
3157  */
3158  int line, node_id;
3159  INSN *niobj, *ciobj, *dup = 0;
3160  LABEL *dest = 0;
3161  VALUE type;
3162 
3163  switch (INSN_OF(iobj)) {
3164  case BIN(putstring):
3165  case BIN(putchilledstring):
3166  type = INT2FIX(T_STRING);
3167  break;
3168  case BIN(putnil):
3169  type = INT2FIX(T_NIL);
3170  break;
3171  case BIN(putobject):
3172  type = INT2FIX(TYPE(OPERAND_AT(iobj, 0)));
3173  break;
3174  default: return FALSE;
3175  }
3176 
3177  ciobj = (INSN *)get_next_insn(iobj);
3178  if (IS_INSN_ID(ciobj, jump)) {
3179  ciobj = (INSN *)get_next_insn((INSN*)OPERAND_AT(ciobj, 0));
3180  }
3181  if (IS_INSN_ID(ciobj, dup)) {
3182  ciobj = (INSN *)get_next_insn(dup = ciobj);
3183  }
3184  if (!ciobj || !IS_INSN_ID(ciobj, checktype)) return FALSE;
3185  niobj = (INSN *)get_next_insn(ciobj);
3186  if (!niobj) {
3187  /* TODO: putobject true/false */
3188  return FALSE;
3189  }
3190  switch (INSN_OF(niobj)) {
3191  case BIN(branchif):
3192  if (OPERAND_AT(ciobj, 0) == type) {
3193  dest = (LABEL *)OPERAND_AT(niobj, 0);
3194  }
3195  break;
3196  case BIN(branchunless):
3197  if (OPERAND_AT(ciobj, 0) != type) {
3198  dest = (LABEL *)OPERAND_AT(niobj, 0);
3199  }
3200  break;
3201  default:
3202  return FALSE;
3203  }
3204  line = ciobj->insn_info.line_no;
3205  node_id = ciobj->insn_info.node_id;
3206  if (!dest) {
3207  if (niobj->link.next && IS_LABEL(niobj->link.next)) {
3208  dest = (LABEL *)niobj->link.next; /* reuse label */
3209  }
3210  else {
3211  dest = NEW_LABEL(line);
3212  ELEM_INSERT_NEXT(&niobj->link, &dest->link);
3213  }
3214  }
3215  INSERT_AFTER_INSN1(iobj, line, node_id, jump, dest);
3216  LABEL_REF(dest);
3217  if (!dup) INSERT_AFTER_INSN(iobj, line, node_id, pop);
3218  return TRUE;
3219 }
3220 
3221 static const struct rb_callinfo *
3222 ci_flag_set(const rb_iseq_t *iseq, const struct rb_callinfo *ci, unsigned int add)
3223 {
3224  const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci),
3225  vm_ci_flag(ci) | add,
3226  vm_ci_argc(ci),
3227  vm_ci_kwarg(ci));
3228  RB_OBJ_WRITTEN(iseq, ci, nci);
3229  return nci;
3230 }
3231 
3232 static const struct rb_callinfo *
3233 ci_argc_set(const rb_iseq_t *iseq, const struct rb_callinfo *ci, int argc)
3234 {
3235  const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci),
3236  vm_ci_flag(ci),
3237  argc,
3238  vm_ci_kwarg(ci));
3239  RB_OBJ_WRITTEN(iseq, ci, nci);
3240  return nci;
3241 }
3242 
3243 #define vm_ci_simple(ci) (vm_ci_flag(ci) & VM_CALL_ARGS_SIMPLE)
3244 
3245 static int
3246 iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcallopt)
3247 {
3248  INSN *const iobj = (INSN *)list;
3249 
3250  again:
3251  optimize_checktype(iseq, iobj);
3252 
3253  if (IS_INSN_ID(iobj, jump)) {
3254  INSN *niobj, *diobj, *piobj;
3255  diobj = (INSN *)get_destination_insn(iobj);
3256  niobj = (INSN *)get_next_insn(iobj);
3257 
3258  if (diobj == niobj) {
3259  /*
3260  * jump LABEL
3261  * LABEL:
3262  * =>
3263  * LABEL:
3264  */
3265  unref_destination(iobj, 0);
3266  ELEM_REMOVE(&iobj->link);
3267  return COMPILE_OK;
3268  }
3269  else if (iobj != diobj && IS_INSN(&diobj->link) &&
3270  IS_INSN_ID(diobj, jump) &&
3271  OPERAND_AT(iobj, 0) != OPERAND_AT(diobj, 0) &&
3272  diobj->insn_info.events == 0) {
3273  /*
3274  * useless jump elimination:
3275  * jump LABEL1
3276  * ...
3277  * LABEL1:
3278  * jump LABEL2
3279  *
3280  * => in this case, first jump instruction should jump to
3281  * LABEL2 directly
3282  */
3283  if (replace_destination(iobj, diobj)) {
3284  remove_unreachable_chunk(iseq, iobj->link.next);
3285  goto again;
3286  }
3287  }
3288  else if (IS_INSN_ID(diobj, leave)) {
3289  /*
3290  * jump LABEL
3291  * ...
3292  * LABEL:
3293  * leave
3294  * =>
3295  * leave
3296  * ...
3297  * LABEL:
3298  * leave
3299  */
3300  /* replace */
3301  unref_destination(iobj, 0);
3302  iobj->insn_id = BIN(leave);
3303  iobj->operand_size = 0;
3304  iobj->insn_info = diobj->insn_info;
3305  goto again;
3306  }
3307  else if (IS_INSN(iobj->link.prev) &&
3308  (piobj = (INSN *)iobj->link.prev) &&
3309  (IS_INSN_ID(piobj, branchif) ||
3310  IS_INSN_ID(piobj, branchunless))) {
3311  INSN *pdiobj = (INSN *)get_destination_insn(piobj);
3312  if (niobj == pdiobj) {
3313  int refcnt = IS_LABEL(piobj->link.next) ?
3314  ((LABEL *)piobj->link.next)->refcnt : 0;
3315  /*
3316  * useless jump elimination (if/unless destination):
3317  * if L1
3318  * jump L2
3319  * L1:
3320  * ...
3321  * L2:
3322  *
3323  * ==>
3324  * unless L2
3325  * L1:
3326  * ...
3327  * L2:
3328  */
3329  piobj->insn_id = (IS_INSN_ID(piobj, branchif))
3330  ? BIN(branchunless) : BIN(branchif);
3331  if (replace_destination(piobj, iobj) && refcnt <= 1) {
3332  ELEM_REMOVE(&iobj->link);
3333  }
3334  else {
3335  /* TODO: replace other branch destinations too */
3336  }
3337  return COMPILE_OK;
3338  }
3339  else if (diobj == pdiobj) {
3340  /*
3341  * useless jump elimination (if/unless before jump):
3342  * L1:
3343  * ...
3344  * if L1
3345  * jump L1
3346  *
3347  * ==>
3348  * L1:
3349  * ...
3350  * pop
3351  * jump L1
3352  */
3353  INSN *popiobj = new_insn_core(iseq, iobj->insn_info.line_no, iobj->insn_info.node_id, BIN(pop), 0, 0);
3354  ELEM_REPLACE(&piobj->link, &popiobj->link);
3355  }
3356  }
3357  if (remove_unreachable_chunk(iseq, iobj->link.next)) {
3358  goto again;
3359  }
3360  }
3361 
3362  /*
3363  * putstring "beg"
3364  * putstring "end"
3365  * newrange excl
3366  *
3367  * ==>
3368  *
3369  * putobject "beg".."end"
3370  */
3371  if (IS_INSN_ID(iobj, newrange)) {
3372  INSN *const range = iobj;
3373  INSN *beg, *end;
3374  VALUE str_beg, str_end;
3375 
3376  if ((end = (INSN *)get_prev_insn(range)) != 0 &&
3377  is_frozen_putstring(end, &str_end) &&
3378  (beg = (INSN *)get_prev_insn(end)) != 0 &&
3379  is_frozen_putstring(beg, &str_beg)) {
3380  int excl = FIX2INT(OPERAND_AT(range, 0));
3381  VALUE lit_range = rb_range_new(str_beg, str_end, excl);
3382 
3383  ELEM_REMOVE(&beg->link);
3384  ELEM_REMOVE(&end->link);
3385  range->insn_id = BIN(putobject);
3386  OPERAND_AT(range, 0) = lit_range;
3387  RB_OBJ_WRITTEN(iseq, Qundef, lit_range);
3388  }
3389  }
3390 
3391  if (IS_INSN_ID(iobj, leave)) {
3392  remove_unreachable_chunk(iseq, iobj->link.next);
3393  }
3394 
3395  /*
3396  * ...
3397  * duparray [...]
3398  * concatarray | concattoarray
3399  * =>
3400  * ...
3401  * putobject [...]
3402  * concatarray | concattoarray
3403  */
3404  if (IS_INSN_ID(iobj, duparray)) {
3405  LINK_ELEMENT *next = iobj->link.next;
3406  if (IS_INSN(next) && (IS_INSN_ID(next, concatarray) || IS_INSN_ID(next, concattoarray))) {
3407  iobj->insn_id = BIN(putobject);
3408  }
3409  }
3410 
3411  /*
3412  * duparray [...]
3413  * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
3414  * =>
3415  * opt_ary_freeze [...], <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
3416  */
3417  if (IS_INSN_ID(iobj, duparray)) {
3418  LINK_ELEMENT *next = iobj->link.next;
3419  if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3420  const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
3421  const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3422 
3423  if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3424  VALUE ary = iobj->operands[0];
3425  rb_obj_reveal(ary, rb_cArray);
3426 
3427  iobj->insn_id = BIN(opt_ary_freeze);
3428  iobj->operand_size = 2;
3429  iobj->operands = compile_data_calloc2(iseq, iobj->operand_size, sizeof(VALUE));
3430  iobj->operands[0] = ary;
3431  iobj->operands[1] = (VALUE)ci;
3432  ELEM_REMOVE(next);
3433  }
3434  }
3435  }
3436 
3437  /*
3438  * duphash {...}
3439  * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
3440  * =>
3441  * opt_hash_freeze {...}, <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
3442  */
3443  if (IS_INSN_ID(iobj, duphash)) {
3444  LINK_ELEMENT *next = iobj->link.next;
3445  if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3446  const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
3447  const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3448 
3449  if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3450  VALUE hash = iobj->operands[0];
3451  rb_obj_reveal(hash, rb_cHash);
3452 
3453  iobj->insn_id = BIN(opt_hash_freeze);
3454  iobj->operand_size = 2;
3455  iobj->operands = compile_data_calloc2(iseq, iobj->operand_size, sizeof(VALUE));
3456  iobj->operands[0] = hash;
3457  iobj->operands[1] = (VALUE)ci;
3458  ELEM_REMOVE(next);
3459  }
3460  }
3461  }
3462 
3463  /*
3464  * newarray 0
3465  * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
3466  * =>
3467  * opt_ary_freeze [], <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
3468  */
3469  if (IS_INSN_ID(iobj, newarray) && iobj->operands[0] == INT2FIX(0)) {
3470  LINK_ELEMENT *next = iobj->link.next;
3471  if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3472  const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
3473  const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3474 
3475  if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3476  iobj->insn_id = BIN(opt_ary_freeze);
3477  iobj->operand_size = 2;
3478  iobj->operands = compile_data_calloc2(iseq, iobj->operand_size, sizeof(VALUE));
3479  iobj->operands[0] = rb_cArray_empty_frozen;
3480  iobj->operands[1] = (VALUE)ci;
3481  ELEM_REMOVE(next);
3482  }
3483  }
3484  }
3485 
3486  /*
3487  * newhash 0
3488  * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
3489  * =>
3490  * opt_hash_freeze {}, <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
3491  */
3492  if (IS_INSN_ID(iobj, newhash) && iobj->operands[0] == INT2FIX(0)) {
3493  LINK_ELEMENT *next = iobj->link.next;
3494  if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3495  const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
3496  const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3497 
3498  if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3499  iobj->insn_id = BIN(opt_hash_freeze);
3500  iobj->operand_size = 2;
3501  iobj->operands = compile_data_calloc2(iseq, iobj->operand_size, sizeof(VALUE));
3502  iobj->operands[0] = rb_cHash_empty_frozen;
3503  iobj->operands[1] = (VALUE)ci;
3504  ELEM_REMOVE(next);
3505  }
3506  }
3507  }
3508 
3509  if (IS_INSN_ID(iobj, branchif) ||
3510  IS_INSN_ID(iobj, branchnil) ||
3511  IS_INSN_ID(iobj, branchunless)) {
3512  /*
3513  * if L1
3514  * ...
3515  * L1:
3516  * jump L2
3517  * =>
3518  * if L2
3519  */
3520  INSN *nobj = (INSN *)get_destination_insn(iobj);
3521 
3522  /* This is super nasty hack!!!
3523  *
3524  * This jump-jump optimization may ignore event flags of the jump
3525  * instruction being skipped. Actually, Line 2 TracePoint event
3526  * is never fired in the following code:
3527  *
3528  * 1: raise if 1 == 2
3529  * 2: while true
3530  * 3: break
3531  * 4: end
3532  *
3533  * This is critical for coverage measurement. [Bug #15980]
3534  *
3535  * This is a stopgap measure: stop the jump-jump optimization if
3536  * coverage measurement is enabled and if the skipped instruction
3537  * has any event flag.
3538  *
3539  * Note that, still, TracePoint Line event does not occur on Line 2.
3540  * This should be fixed in future.
3541  */
3542  int stop_optimization =
3543  ISEQ_COVERAGE(iseq) && ISEQ_LINE_COVERAGE(iseq) &&
3544  nobj->link.type == ISEQ_ELEMENT_INSN &&
3545  nobj->insn_info.events;
3546  if (!stop_optimization) {
3547  INSN *pobj = (INSN *)iobj->link.prev;
3548  int prev_dup = 0;
3549  if (pobj) {
3550  if (!IS_INSN(&pobj->link))
3551  pobj = 0;
3552  else if (IS_INSN_ID(pobj, dup))
3553  prev_dup = 1;
3554  }
3555 
3556  for (;;) {
3557  if (IS_INSN(&nobj->link) && IS_INSN_ID(nobj, jump)) {
3558  if (!replace_destination(iobj, nobj)) break;
3559  }
3560  else if (prev_dup && IS_INSN_ID(nobj, dup) &&
3561  !!(nobj = (INSN *)nobj->link.next) &&
3562  /* basic blocks, with no labels in the middle */
3563  nobj->insn_id == iobj->insn_id) {
3564  /*
3565  * dup
3566  * if L1
3567  * ...
3568  * L1:
3569  * dup
3570  * if L2
3571  * =>
3572  * dup
3573  * if L2
3574  * ...
3575  * L1:
3576  * dup
3577  * if L2
3578  */
3579  if (!replace_destination(iobj, nobj)) break;
3580  }
3581  else if (pobj) {
3582  /*
3583  * putnil
3584  * if L1
3585  * =>
3586  * # nothing
3587  *
3588  * putobject true
3589  * if L1
3590  * =>
3591  * jump L1
3592  *
3593  * putstring ".."
3594  * if L1
3595  * =>
3596  * jump L1
3597  *
3598  * putstring ".."
3599  * dup
3600  * if L1
3601  * =>
3602  * putstring ".."
3603  * jump L1
3604  *
3605  */
3606  int cond;
3607  if (prev_dup && IS_INSN(pobj->link.prev)) {
3608  pobj = (INSN *)pobj->link.prev;
3609  }
3610  if (IS_INSN_ID(pobj, putobject)) {
3611  cond = (IS_INSN_ID(iobj, branchif) ?
3612  OPERAND_AT(pobj, 0) != Qfalse :
3613  IS_INSN_ID(iobj, branchunless) ?
3614  OPERAND_AT(pobj, 0) == Qfalse :
3615  FALSE);
3616  }
3617  else if (IS_INSN_ID(pobj, putstring) ||
3618  IS_INSN_ID(pobj, duparray) ||
3619  IS_INSN_ID(pobj, newarray)) {
3620  cond = IS_INSN_ID(iobj, branchif);
3621  }
3622  else if (IS_INSN_ID(pobj, putnil)) {
3623  cond = !IS_INSN_ID(iobj, branchif);
3624  }
3625  else break;
3626  if (prev_dup || !IS_INSN_ID(pobj, newarray)) {
3627  ELEM_REMOVE(iobj->link.prev);
3628  }
3629  else if (!iseq_pop_newarray(iseq, pobj)) {
3630  pobj = new_insn_core(iseq, pobj->insn_info.line_no, pobj->insn_info.node_id, BIN(pop), 0, NULL);
3631  ELEM_INSERT_PREV(&iobj->link, &pobj->link);
3632  }
3633  if (cond) {
3634  if (prev_dup) {
3635  pobj = new_insn_core(iseq, pobj->insn_info.line_no, pobj->insn_info.node_id, BIN(putnil), 0, NULL);
3636  ELEM_INSERT_NEXT(&iobj->link, &pobj->link);
3637  }
3638  iobj->insn_id = BIN(jump);
3639  goto again;
3640  }
3641  else {
3642  unref_destination(iobj, 0);
3643  ELEM_REMOVE(&iobj->link);
3644  }
3645  break;
3646  }
3647  else break;
3648  nobj = (INSN *)get_destination_insn(nobj);
3649  }
3650  }
3651  }
3652 
3653  if (IS_INSN_ID(iobj, pop)) {
3654  /*
3655  * putself / putnil / putobject obj / putstring "..."
3656  * pop
3657  * =>
3658  * # do nothing
3659  */
3660  LINK_ELEMENT *prev = iobj->link.prev;
3661  if (IS_INSN(prev)) {
3662  enum ruby_vminsn_type previ = ((INSN *)prev)->insn_id;
3663  if (previ == BIN(putobject) || previ == BIN(putnil) ||
3664  previ == BIN(putself) || previ == BIN(putstring) ||
3665  previ == BIN(putchilledstring) ||
3666  previ == BIN(dup) ||
3667  previ == BIN(getlocal) ||
3668  previ == BIN(getblockparam) ||
3669  previ == BIN(getblockparamproxy) ||
3670  previ == BIN(getinstancevariable) ||
3671  previ == BIN(duparray)) {
3672  /* just push operand or static value and pop soon, no
3673  * side effects */
3674  ELEM_REMOVE(prev);
3675  ELEM_REMOVE(&iobj->link);
3676  }
3677  else if (previ == BIN(newarray) && iseq_pop_newarray(iseq, (INSN*)prev)) {
3678  ELEM_REMOVE(&iobj->link);
3679  }
3680  else if (previ == BIN(concatarray)) {
3681  INSN *piobj = (INSN *)prev;
3682  INSERT_BEFORE_INSN1(piobj, piobj->insn_info.line_no, piobj->insn_info.node_id, splatarray, Qfalse);
3683  INSN_OF(piobj) = BIN(pop);
3684  }
3685  else if (previ == BIN(concatstrings)) {
3686  if (OPERAND_AT(prev, 0) == INT2FIX(1)) {
3687  ELEM_REMOVE(prev);
3688  }
3689  else {
3690  ELEM_REMOVE(&iobj->link);
3691  INSN_OF(prev) = BIN(adjuststack);
3692  }
3693  }
3694  }
3695  }
3696 
3697  if (IS_INSN_ID(iobj, newarray) ||
3698  IS_INSN_ID(iobj, duparray) ||
3699  IS_INSN_ID(iobj, concatarray) ||
3700  IS_INSN_ID(iobj, splatarray) ||
3701  0) {
3702  /*
3703  * newarray N
3704  * splatarray
3705  * =>
3706  * newarray N
3707  * newarray always puts an array
3708  */
3709  LINK_ELEMENT *next = iobj->link.next;
3710  if (IS_INSN(next) && IS_INSN_ID(next, splatarray)) {
3711  /* remove splatarray following always-array insn */
3712  ELEM_REMOVE(next);
3713  }
3714  }
3715 
3716  if (IS_INSN_ID(iobj, newarray)) {
3717  LINK_ELEMENT *next = iobj->link.next;
3718  if (IS_INSN(next) && IS_INSN_ID(next, expandarray) &&
3719  OPERAND_AT(next, 1) == INT2FIX(0)) {
3720  VALUE op1, op2;
3721  op1 = OPERAND_AT(iobj, 0);
3722  op2 = OPERAND_AT(next, 0);
3723  ELEM_REMOVE(next);
3724 
3725  if (op1 == op2) {
3726  /*
3727  * newarray 2
3728  * expandarray 2, 0
3729  * =>
3730  * swap
3731  */
3732  if (op1 == INT2FIX(2)) {
3733  INSN_OF(iobj) = BIN(swap);
3734  iobj->operand_size = 0;
3735  }
3736  /*
3737  * newarray X
3738  * expandarray X, 0
3739  * =>
3740  * opt_reverse X
3741  */
3742  else {
3743  INSN_OF(iobj) = BIN(opt_reverse);
3744  }
3745  }
3746  else {
3747  long diff = FIX2LONG(op1) - FIX2LONG(op2);
3748  INSN_OF(iobj) = BIN(opt_reverse);
3749  OPERAND_AT(iobj, 0) = OPERAND_AT(next, 0);
3750 
3751  if (op1 > op2) {
3752  /* X > Y
3753  * newarray X
3754  * expandarray Y, 0
3755  * =>
3756  * pop * (Y-X)
3757  * opt_reverse Y
3758  */
3759  for (; diff > 0; diff--) {
3760  INSERT_BEFORE_INSN(iobj, iobj->insn_info.line_no, iobj->insn_info.node_id, pop);
3761  }
3762  }
3763  else { /* (op1 < op2) */
3764  /* X < Y
3765  * newarray X
3766  * expandarray Y, 0
3767  * =>
3768  * putnil * (Y-X)
3769  * opt_reverse Y
3770  */
3771  for (; diff < 0; diff++) {
3772  INSERT_BEFORE_INSN(iobj, iobj->insn_info.line_no, iobj->insn_info.node_id, putnil);
3773  }
3774  }
3775  }
3776  }
3777  }
3778 
3779  if (IS_INSN_ID(iobj, duparray)) {
3780  LINK_ELEMENT *next = iobj->link.next;
3781  /*
3782  * duparray obj
3783  * expandarray X, 0
3784  * =>
3785  * putobject obj
3786  * expandarray X, 0
3787  */
3788  if (IS_INSN(next) && IS_INSN_ID(next, expandarray)) {
3789  INSN_OF(iobj) = BIN(putobject);
3790  }
3791  }
3792 
3793  if (IS_INSN_ID(iobj, anytostring)) {
3794  LINK_ELEMENT *next = iobj->link.next;
3795  /*
3796  * anytostring
3797  * concatstrings 1
3798  * =>
3799  * anytostring
3800  */
3801  if (IS_INSN(next) && IS_INSN_ID(next, concatstrings) &&
3802  OPERAND_AT(next, 0) == INT2FIX(1)) {
3803  ELEM_REMOVE(next);
3804  }
3805  }
3806 
3807  if (IS_INSN_ID(iobj, putstring) || IS_INSN_ID(iobj, putchilledstring) ||
3808  (IS_INSN_ID(iobj, putobject) && RB_TYPE_P(OPERAND_AT(iobj, 0), T_STRING))) {
3809  /*
3810  * putstring ""
3811  * concatstrings N
3812  * =>
3813  * concatstrings N-1
3814  */
3815  if (IS_NEXT_INSN_ID(&iobj->link, concatstrings) &&
3816  RSTRING_LEN(OPERAND_AT(iobj, 0)) == 0) {
3817  INSN *next = (INSN *)iobj->link.next;
3818  if ((OPERAND_AT(next, 0) = FIXNUM_INC(OPERAND_AT(next, 0), -1)) == INT2FIX(1)) {
3819  ELEM_REMOVE(&next->link);
3820  }
3821  ELEM_REMOVE(&iobj->link);
3822  }
3823  }
3824 
3825  if (IS_INSN_ID(iobj, concatstrings)) {
3826  /*
3827  * concatstrings N
3828  * concatstrings M
3829  * =>
3830  * concatstrings N+M-1
3831  */
3832  LINK_ELEMENT *next = iobj->link.next;
3833  INSN *jump = 0;
3834  if (IS_INSN(next) && IS_INSN_ID(next, jump))
3835  next = get_destination_insn(jump = (INSN *)next);
3836  if (IS_INSN(next) && IS_INSN_ID(next, concatstrings)) {
3837  int n = FIX2INT(OPERAND_AT(iobj, 0)) + FIX2INT(OPERAND_AT(next, 0)) - 1;
3838  OPERAND_AT(iobj, 0) = INT2FIX(n);
3839  if (jump) {
3840  LABEL *label = ((LABEL *)OPERAND_AT(jump, 0));
3841  if (!--label->refcnt) {
3842  ELEM_REMOVE(&label->link);
3843  }
3844  else {
3845  label = NEW_LABEL(0);
3846  OPERAND_AT(jump, 0) = (VALUE)label;
3847  }
3848  label->refcnt++;
3849  ELEM_INSERT_NEXT(next, &label->link);
3850  CHECK(iseq_peephole_optimize(iseq, get_next_insn(jump), do_tailcallopt));
3851  }
3852  else {
3853  ELEM_REMOVE(next);
3854  }
3855  }
3856  }
3857 
3858  if (do_tailcallopt &&
3859  (IS_INSN_ID(iobj, send) ||
3860  IS_INSN_ID(iobj, opt_aref_with) ||
3861  IS_INSN_ID(iobj, opt_aset_with) ||
3862  IS_INSN_ID(iobj, invokesuper))) {
3863  /*
3864  * send ...
3865  * leave
3866  * =>
3867  * send ..., ... | VM_CALL_TAILCALL, ...
3868  * leave # unreachable
3869  */
3870  INSN *piobj = NULL;
3871  if (iobj->link.next) {
3872  LINK_ELEMENT *next = iobj->link.next;
3873  do {
3874  if (!IS_INSN(next)) {
3875  next = next->next;
3876  continue;
3877  }
3878  switch (INSN_OF(next)) {
3879  case BIN(nop):
3880  next = next->next;
3881  break;
3882  case BIN(jump):
3883  /* if cond
3884  * return tailcall
3885  * end
3886  */
3887  next = get_destination_insn((INSN *)next);
3888  break;
3889  case BIN(leave):
3890  piobj = iobj;
3891  /* fall through */
3892  default:
3893  next = NULL;
3894  break;
3895  }
3896  } while (next);
3897  }
3898 
3899  if (piobj) {
3900  const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(piobj, 0);
3901  if (IS_INSN_ID(piobj, send) ||
3902  IS_INSN_ID(piobj, invokesuper)) {
3903  if (OPERAND_AT(piobj, 1) == 0) { /* no blockiseq */
3904  ci = ci_flag_set(iseq, ci, VM_CALL_TAILCALL);
3905  OPERAND_AT(piobj, 0) = (VALUE)ci;
3906  RB_OBJ_WRITTEN(iseq, Qundef, ci);
3907  }
3908  }
3909  else {
3910  ci = ci_flag_set(iseq, ci, VM_CALL_TAILCALL);
3911  OPERAND_AT(piobj, 0) = (VALUE)ci;
3912  RB_OBJ_WRITTEN(iseq, Qundef, ci);
3913  }
3914  }
3915  }
3916 
3917  if (IS_INSN_ID(iobj, dup)) {
3918  if (IS_NEXT_INSN_ID(&iobj->link, setlocal)) {
3919  LINK_ELEMENT *set1 = iobj->link.next, *set2 = NULL;
3920 
3921  /*
3922  * dup
3923  * setlocal x, y
3924  * setlocal x, y
3925  * =>
3926  * dup
3927  * setlocal x, y
3928  */
3929  if (IS_NEXT_INSN_ID(set1, setlocal)) {
3930  set2 = set1->next;
3931  if (OPERAND_AT(set1, 0) == OPERAND_AT(set2, 0) &&
3932  OPERAND_AT(set1, 1) == OPERAND_AT(set2, 1)) {
3933  ELEM_REMOVE(set1);
3934  ELEM_REMOVE(&iobj->link);
3935  }
3936  }
3937 
3938  /*
3939  * dup
3940  * setlocal x, y
3941  * dup
3942  * setlocal x, y
3943  * =>
3944  * dup
3945  * setlocal x, y
3946  */
3947  else if (IS_NEXT_INSN_ID(set1, dup) &&
3948  IS_NEXT_INSN_ID(set1->next, setlocal)) {
3949  set2 = set1->next->next;
3950  if (OPERAND_AT(set1, 0) == OPERAND_AT(set2, 0) &&
3951  OPERAND_AT(set1, 1) == OPERAND_AT(set2, 1)) {
3952  ELEM_REMOVE(set1->next);
3953  ELEM_REMOVE(set2);
3954  }
3955  }
3956  }
3957  }
3958 
3959  /*
3960  * getlocal x, y
3961  * dup
3962  * setlocal x, y
3963  * =>
3964  * dup
3965  */
3966  if (IS_INSN_ID(iobj, getlocal)) {
3967  LINK_ELEMENT *niobj = &iobj->link;
3968  if (IS_NEXT_INSN_ID(niobj, dup)) {
3969  niobj = niobj->next;
3970  }
3971  if (IS_NEXT_INSN_ID(niobj, setlocal)) {
3972  LINK_ELEMENT *set1 = niobj->next;
3973  if (OPERAND_AT(iobj, 0) == OPERAND_AT(set1, 0) &&
3974  OPERAND_AT(iobj, 1) == OPERAND_AT(set1, 1)) {
3975  ELEM_REMOVE(set1);
3976  ELEM_REMOVE(niobj);
3977  }
3978  }
3979  }
3980 
3981  /*
3982  * opt_invokebuiltin_delegate
3983  * trace
3984  * leave
3985  * =>
3986  * opt_invokebuiltin_delegate_leave
3987  * trace
3988  * leave
3989  */
3990  if (IS_INSN_ID(iobj, opt_invokebuiltin_delegate)) {
3991  if (IS_TRACE(iobj->link.next)) {
3992  if (IS_NEXT_INSN_ID(iobj->link.next, leave)) {
3993  iobj->insn_id = BIN(opt_invokebuiltin_delegate_leave);
3994  const struct rb_builtin_function *bf = (const struct rb_builtin_function *)iobj->operands[0];
3995  if (iobj == (INSN *)list && bf->argc == 0 && (iseq->body->builtin_attrs & BUILTIN_ATTR_LEAF)) {
3996  iseq->body->builtin_attrs |= BUILTIN_ATTR_SINGLE_NOARG_LEAF;
3997  }
3998  }
3999  }
4000  }
4001 
4002  /*
4003  * getblockparam
4004  * branchif / branchunless
4005  * =>
4006  * getblockparamproxy
4007  * branchif / branchunless
4008  */
4009  if (IS_INSN_ID(iobj, getblockparam)) {
4010  if (IS_NEXT_INSN_ID(&iobj->link, branchif) || IS_NEXT_INSN_ID(&iobj->link, branchunless)) {
4011  iobj->insn_id = BIN(getblockparamproxy);
4012  }
4013  }
4014 
4015  if (IS_INSN_ID(iobj, splatarray) && OPERAND_AT(iobj, 0) == false) {
4016  LINK_ELEMENT *niobj = &iobj->link;
4017  if (IS_NEXT_INSN_ID(niobj, duphash)) {
4018  niobj = niobj->next;
4019  LINK_ELEMENT *siobj;
4020  unsigned int set_flags = 0, unset_flags = 0;
4021 
4022  /*
4023  * Eliminate hash allocation for f(*a, kw: 1)
4024  *
4025  * splatarray false
4026  * duphash
4027  * send ARGS_SPLAT|KW_SPLAT|KW_SPLAT_MUT and not ARGS_BLOCKARG
4028  * =>
4029  * splatarray false
4030  * putobject
4031  * send ARGS_SPLAT|KW_SPLAT
4032  */
4033  if (IS_NEXT_INSN_ID(niobj, send)) {
4034  siobj = niobj->next;
4035  set_flags = VM_CALL_ARGS_SPLAT|VM_CALL_KW_SPLAT|VM_CALL_KW_SPLAT_MUT;
4036  unset_flags = VM_CALL_ARGS_BLOCKARG;
4037  }
4038  /*
4039  * Eliminate hash allocation for f(*a, kw: 1, &{arg,lvar,@iv})
4040  *
4041  * splatarray false
4042  * duphash
4043  * getlocal / getinstancevariable / getblockparamproxy
4044  * send ARGS_SPLAT|KW_SPLAT|KW_SPLAT_MUT|ARGS_BLOCKARG
4045  * =>
4046  * splatarray false
4047  * putobject
4048  * getlocal / getinstancevariable / getblockparamproxy
4049  * send ARGS_SPLAT|KW_SPLAT|ARGS_BLOCKARG
4050  */
4051  else if ((IS_NEXT_INSN_ID(niobj, getlocal) || IS_NEXT_INSN_ID(niobj, getinstancevariable) ||
4052  IS_NEXT_INSN_ID(niobj, getblockparamproxy)) && (IS_NEXT_INSN_ID(niobj->next, send))) {
4053  siobj = niobj->next->next;
4054  set_flags = VM_CALL_ARGS_SPLAT|VM_CALL_KW_SPLAT|VM_CALL_KW_SPLAT_MUT|VM_CALL_ARGS_BLOCKARG;
4055  }
4056 
4057  if (set_flags) {
4058  const struct rb_callinfo *ci = (const struct rb_callinfo *)OPERAND_AT(siobj, 0);
4059  unsigned int flags = vm_ci_flag(ci);
4060  if ((flags & set_flags) == set_flags && !(flags & unset_flags)) {
4061  ((INSN*)niobj)->insn_id = BIN(putobject);
4062  OPERAND_AT(niobj, 0) = rb_hash_freeze(rb_hash_resurrect(OPERAND_AT(niobj, 0)));
4063 
4064  const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci),
4065  flags & ~VM_CALL_KW_SPLAT_MUT, vm_ci_argc(ci), vm_ci_kwarg(ci));
4066  RB_OBJ_WRITTEN(iseq, ci, nci);
4067  OPERAND_AT(siobj, 0) = (VALUE)nci;
4068  }
4069  }
4070  }
4071  }
4072 
4073  return COMPILE_OK;
4074 }
4075 
4076 static int
4077 insn_set_specialized_instruction(rb_iseq_t *iseq, INSN *iobj, int insn_id)
4078 {
4079  iobj->insn_id = insn_id;
4080  iobj->operand_size = insn_len(insn_id) - 1;
4081  iobj->insn_info.events |= RUBY_EVENT_C_CALL | RUBY_EVENT_C_RETURN;
4082 
4083  if (insn_id == BIN(opt_neq)) {
4084  VALUE original_ci = iobj->operands[0];
4085  iobj->operand_size = 2;
4086  iobj->operands = compile_data_calloc2(iseq, iobj->operand_size, sizeof(VALUE));
4087  iobj->operands[0] = (VALUE)new_callinfo(iseq, idEq, 1, 0, NULL, FALSE);
4088  iobj->operands[1] = original_ci;
4089  }
4090 
4091  return COMPILE_OK;
4092 }
4093 
4094 static int
4095 iseq_specialized_instruction(rb_iseq_t *iseq, INSN *iobj)
4096 {
4097  if (IS_INSN_ID(iobj, newarray) && iobj->link.next &&
4098  IS_INSN(iobj->link.next)) {
4099  /*
4100  * [a, b, ...].max/min -> a, b, c, opt_newarray_send max/min
4101  */
4102  INSN *niobj = (INSN *)iobj->link.next;
4103  if (IS_INSN_ID(niobj, send)) {
4104  const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(niobj, 0);
4105  if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0) {
4106  VALUE method = INT2FIX(0);
4107  switch (vm_ci_mid(ci)) {
4108  case idMax:
4109  method = INT2FIX(VM_OPT_NEWARRAY_SEND_MAX);
4110  break;
4111  case idMin:
4112  method = INT2FIX(VM_OPT_NEWARRAY_SEND_MIN);
4113  break;
4114  case idHash:
4115  method = INT2FIX(VM_OPT_NEWARRAY_SEND_HASH);
4116  break;
4117  }
4118 
4119  if (method != INT2FIX(0)) {
4120  VALUE num = iobj->operands[0];
4121  int operand_len = insn_len(BIN(opt_newarray_send)) - 1;
4122  iobj->insn_id = BIN(opt_newarray_send);
4123  iobj->operands = compile_data_calloc2(iseq, operand_len, sizeof(VALUE));
4124  iobj->operands[0] = num;
4125  iobj->operands[1] = method;
4126  iobj->operand_size = operand_len;
4127  ELEM_REMOVE(&niobj->link);
4128  return COMPILE_OK;
4129  }
4130  }
4131  }
4132  else if ((IS_INSN_ID(niobj, putstring) || IS_INSN_ID(niobj, putchilledstring) ||
4133  (IS_INSN_ID(niobj, putobject) && RB_TYPE_P(OPERAND_AT(niobj, 0), T_STRING))) &&
4134  IS_NEXT_INSN_ID(&niobj->link, send)) {
4135  const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT((INSN *)niobj->link.next, 0);
4136  if (vm_ci_simple(ci) && vm_ci_argc(ci) == 1 && vm_ci_mid(ci) == idPack) {
4137  VALUE num = iobj->operands[0];
4138  int operand_len = insn_len(BIN(opt_newarray_send)) - 1;
4139  iobj->insn_id = BIN(opt_newarray_send);
4140  iobj->operands = compile_data_calloc2(iseq, operand_len, sizeof(VALUE));
4141  iobj->operands[0] = FIXNUM_INC(num, 1);
4142  iobj->operands[1] = INT2FIX(VM_OPT_NEWARRAY_SEND_PACK);
4143  iobj->operand_size = operand_len;
4144  ELEM_REMOVE(&iobj->link);
4145  ELEM_REMOVE(niobj->link.next);
4146  ELEM_INSERT_NEXT(&niobj->link, &iobj->link);
4147  return COMPILE_OK;
4148  }
4149  }
4150  // newarray n, putchilledstring "E", getlocal b, send :pack with {buffer: b}
4151  // -> putchilledstring "E", getlocal b, opt_newarray_send n+2, :pack, :buffer
4152  else if ((IS_INSN_ID(niobj, putstring) || IS_INSN_ID(niobj, putchilledstring) ||
4153  (IS_INSN_ID(niobj, putobject) && RB_TYPE_P(OPERAND_AT(niobj, 0), T_STRING))) &&
4154  IS_NEXT_INSN_ID(&niobj->link, getlocal) &&
4155  (niobj->link.next && IS_NEXT_INSN_ID(niobj->link.next, send))) {
4156  const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT((INSN *)(niobj->link.next)->next, 0);
4157  const struct rb_callinfo_kwarg *kwarg = vm_ci_kwarg(ci);
4158  if (vm_ci_mid(ci) == idPack && vm_ci_argc(ci) == 2 &&
4159  (kwarg && kwarg->keyword_len == 1 && kwarg->keywords[0] == rb_id2sym(idBuffer))) {
4160  VALUE num = iobj->operands[0];
4161  int operand_len = insn_len(BIN(opt_newarray_send)) - 1;
4162  iobj->insn_id = BIN(opt_newarray_send);
4163  iobj->operands = compile_data_calloc2(iseq, operand_len, sizeof(VALUE));
4164  iobj->operands[0] = FIXNUM_INC(num, 2);
4165  iobj->operands[1] = INT2FIX(VM_OPT_NEWARRAY_SEND_PACK_BUFFER);
4166  iobj->operand_size = operand_len;
4167  // Remove the "send" insn.
4168  ELEM_REMOVE((niobj->link.next)->next);
4169  // Remove the modified insn from its original "newarray" position...
4170  ELEM_REMOVE(&iobj->link);
4171  // and insert it after the buffer insn.
4172  ELEM_INSERT_NEXT(niobj->link.next, &iobj->link);
4173  return COMPILE_OK;
4174  }
4175  }
4176 
4177  // Break the "else if" chain since some prior checks abort after sub-ifs.
4178  // We already found "newarray". To match `[...].include?(arg)` we look for
4179  // the instruction(s) representing the argument followed by a "send".
4180  if ((IS_INSN_ID(niobj, putstring) || IS_INSN_ID(niobj, putchilledstring) ||
4181  IS_INSN_ID(niobj, putobject) ||
4182  IS_INSN_ID(niobj, putself) ||
4183  IS_INSN_ID(niobj, getlocal) ||
4184  IS_INSN_ID(niobj, getinstancevariable)) &&
4185  IS_NEXT_INSN_ID(&niobj->link, send)) {
4186 
4187  LINK_ELEMENT *sendobj = &(niobj->link); // Below we call ->next;
4188  const struct rb_callinfo *ci;
4189  // Allow any number (0 or more) of simple method calls on the argument
4190  // (as in `[...].include?(arg.method1.method2)`.
4191  do {
4192  sendobj = sendobj->next;
4193  ci = (struct rb_callinfo *)OPERAND_AT(sendobj, 0);
4194  } while (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && IS_NEXT_INSN_ID(sendobj, send));
4195 
4196  // If this send is for .include? with one arg we can do our opt.
4197  if (vm_ci_simple(ci) && vm_ci_argc(ci) == 1 && vm_ci_mid(ci) == idIncludeP) {
4198  VALUE num = iobj->operands[0];
4199  INSN *sendins = (INSN *)sendobj;
4200  sendins->insn_id = BIN(opt_newarray_send);
4201  sendins->operand_size = insn_len(sendins->insn_id) - 1;
4202  sendins->operands = compile_data_calloc2(iseq, sendins->operand_size, sizeof(VALUE));
4203  sendins->operands[0] = FIXNUM_INC(num, 1);
4204  sendins->operands[1] = INT2FIX(VM_OPT_NEWARRAY_SEND_INCLUDE_P);
4205  // Remove the original "newarray" insn.
4206  ELEM_REMOVE(&iobj->link);
4207  return COMPILE_OK;
4208  }
4209  }
4210  }
4211 
4212  /*
4213  * duparray [...]
4214  * some insn for the arg...
4215  * send <calldata!mid:include?, argc:1, ARGS_SIMPLE>, nil
4216  * =>
4217  * arg insn...
4218  * opt_duparray_send [...], :include?, 1
4219  */
4220  if (IS_INSN_ID(iobj, duparray) && iobj->link.next && IS_INSN(iobj->link.next)) {
4221  INSN *niobj = (INSN *)iobj->link.next;
4222  if ((IS_INSN_ID(niobj, getlocal) ||
4223  IS_INSN_ID(niobj, getinstancevariable) ||
4224  IS_INSN_ID(niobj, putself)) &&
4225  IS_NEXT_INSN_ID(&niobj->link, send)) {
4226 
4227  LINK_ELEMENT *sendobj = &(niobj->link); // Below we call ->next;
4228  const struct rb_callinfo *ci;
4229  // Allow any number (0 or more) of simple method calls on the argument
4230  // (as in `[...].include?(arg.method1.method2)`.
4231  do {
4232  sendobj = sendobj->next;
4233  ci = (struct rb_callinfo *)OPERAND_AT(sendobj, 0);
4234  } while (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && IS_NEXT_INSN_ID(sendobj, send));
4235 
4236  if (vm_ci_simple(ci) && vm_ci_argc(ci) == 1 && vm_ci_mid(ci) == idIncludeP) {
4237  // Move the array arg from duparray to opt_duparray_send.
4238  VALUE ary = iobj->operands[0];
4239  rb_obj_reveal(ary, rb_cArray);
4240 
4241  INSN *sendins = (INSN *)sendobj;
4242  sendins->insn_id = BIN(opt_duparray_send);
4243  sendins->operand_size = insn_len(sendins->insn_id) - 1;;
4244  sendins->operands = compile_data_calloc2(iseq, sendins->operand_size, sizeof(VALUE));
4245  sendins->operands[0] = ary;
4246  sendins->operands[1] = rb_id2sym(idIncludeP);
4247  sendins->operands[2] = INT2FIX(1);
4248 
4249  // Remove the duparray insn.
4250  ELEM_REMOVE(&iobj->link);
4251  return COMPILE_OK;
4252  }
4253  }
4254  }
4255 
4256 
4257  if (IS_INSN_ID(iobj, send)) {
4258  const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, 0);
4259  const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(iobj, 1);
4260 
4261 #define SP_INSN(opt) insn_set_specialized_instruction(iseq, iobj, BIN(opt_##opt))
4262  if (vm_ci_simple(ci)) {
4263  switch (vm_ci_argc(ci)) {
4264  case 0:
4265  switch (vm_ci_mid(ci)) {
4266  case idLength: SP_INSN(length); return COMPILE_OK;
4267  case idSize: SP_INSN(size); return COMPILE_OK;
4268  case idEmptyP: SP_INSN(empty_p);return COMPILE_OK;
4269  case idNilP: SP_INSN(nil_p); return COMPILE_OK;
4270  case idSucc: SP_INSN(succ); return COMPILE_OK;
4271  case idNot: SP_INSN(not); return COMPILE_OK;
4272  }
4273  break;
4274  case 1:
4275  switch (vm_ci_mid(ci)) {
4276  case idPLUS: SP_INSN(plus); return COMPILE_OK;
4277  case idMINUS: SP_INSN(minus); return COMPILE_OK;
4278  case idMULT: SP_INSN(mult); return COMPILE_OK;
4279  case idDIV: SP_INSN(div); return COMPILE_OK;
4280  case idMOD: SP_INSN(mod); return COMPILE_OK;
4281  case idEq: SP_INSN(eq); return COMPILE_OK;
4282  case idNeq: SP_INSN(neq); return COMPILE_OK;
4283  case idEqTilde:SP_INSN(regexpmatch2);return COMPILE_OK;
4284  case idLT: SP_INSN(lt); return COMPILE_OK;
4285  case idLE: SP_INSN(le); return COMPILE_OK;
4286  case idGT: SP_INSN(gt); return COMPILE_OK;
4287  case idGE: SP_INSN(ge); return COMPILE_OK;
4288  case idLTLT: SP_INSN(ltlt); return COMPILE_OK;
4289  case idAREF: SP_INSN(aref); return COMPILE_OK;
4290  case idAnd: SP_INSN(and); return COMPILE_OK;
4291  case idOr: SP_INSN(or); return COMPILE_OK;
4292  }
4293  break;
4294  case 2:
4295  switch (vm_ci_mid(ci)) {
4296  case idASET: SP_INSN(aset); return COMPILE_OK;
4297  }
4298  break;
4299  }
4300  }
4301 
4302  if ((vm_ci_flag(ci) & (VM_CALL_ARGS_BLOCKARG | VM_CALL_FORWARDING)) == 0 && blockiseq == NULL) {
4303  iobj->insn_id = BIN(opt_send_without_block);
4304  iobj->operand_size = insn_len(iobj->insn_id) - 1;
4305  }
4306  }
4307 #undef SP_INSN
4308 
4309  return COMPILE_OK;
4310 }
4311 
4312 static inline int
4313 tailcallable_p(rb_iseq_t *iseq)
4314 {
4315  switch (ISEQ_BODY(iseq)->type) {
4316  case ISEQ_TYPE_TOP:
4317  case ISEQ_TYPE_EVAL:
4318  case ISEQ_TYPE_MAIN:
4319  /* not tail callable because cfp will be over popped */
4320  case ISEQ_TYPE_RESCUE:
4321  case ISEQ_TYPE_ENSURE:
4322  /* rescue block can't tail call because of errinfo */
4323  return FALSE;
4324  default:
4325  return TRUE;
4326  }
4327 }
4328 
4329 static int
4330 iseq_optimize(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
4331 {
4332  LINK_ELEMENT *list;
4333  const int do_peepholeopt = ISEQ_COMPILE_DATA(iseq)->option->peephole_optimization;
4334  const int do_tailcallopt = tailcallable_p(iseq) &&
4335  ISEQ_COMPILE_DATA(iseq)->option->tailcall_optimization;
4336  const int do_si = ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction;
4337  const int do_ou = ISEQ_COMPILE_DATA(iseq)->option->operands_unification;
4338  int rescue_level = 0;
4339  int tailcallopt = do_tailcallopt;
4340 
4341  list = FIRST_ELEMENT(anchor);
4342 
4343  int do_block_optimization = 0;
4344 
4345  if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_BLOCK && !ISEQ_COMPILE_DATA(iseq)->catch_except_p) {
4346  do_block_optimization = 1;
4347  }
4348 
4349  while (list) {
4350  if (IS_INSN(list)) {
4351  if (do_peepholeopt) {
4352  iseq_peephole_optimize(iseq, list, tailcallopt);
4353  }
4354  if (do_si) {
4355  iseq_specialized_instruction(iseq, (INSN *)list);
4356  }
4357  if (do_ou) {
4358  insn_operands_unification((INSN *)list);
4359  }
4360 
4361  if (do_block_optimization) {
4362  INSN * item = (INSN *)list;
4363  if (IS_INSN_ID(item, jump)) {
4364  do_block_optimization = 0;
4365  }
4366  }
4367  }
4368  if (IS_LABEL(list)) {
4369  switch (((LABEL *)list)->rescued) {
4370  case LABEL_RESCUE_BEG:
4371  rescue_level++;
4372  tailcallopt = FALSE;
4373  break;
4374  case LABEL_RESCUE_END:
4375  if (!--rescue_level) tailcallopt = do_tailcallopt;
4376  break;
4377  }
4378  }
4379  list = list->next;
4380  }
4381 
4382  if (do_block_optimization) {
4383  LINK_ELEMENT * le = FIRST_ELEMENT(anchor)->next;
4384  if (IS_INSN(le) && IS_INSN_ID((INSN *)le, nop)) {
4385  ELEM_REMOVE(le);
4386  }
4387  }
4388  return COMPILE_OK;
4389 }
4390 
4391 #if OPT_INSTRUCTIONS_UNIFICATION
4392 static INSN *
4393 new_unified_insn(rb_iseq_t *iseq,
4394  int insn_id, int size, LINK_ELEMENT *seq_list)
4395 {
4396  INSN *iobj = 0;
4397  LINK_ELEMENT *list = seq_list;
4398  int i, argc = 0;
4399  VALUE *operands = 0, *ptr = 0;
4400 
4401 
4402  /* count argc */
4403  for (i = 0; i < size; i++) {
4404  iobj = (INSN *)list;
4405  argc += iobj->operand_size;
4406  list = list->next;
4407  }
4408 
4409  if (argc > 0) {
4410  ptr = operands = compile_data_alloc2(iseq, sizeof(VALUE), argc);
4411  }
4412 
4413  /* copy operands */
4414  list = seq_list;
4415  for (i = 0; i < size; i++) {
4416  iobj = (INSN *)list;
4417  MEMCPY(ptr, iobj->operands, VALUE, iobj->operand_size);
4418  ptr += iobj->operand_size;
4419  list = list->next;
4420  }
4421 
4422  return new_insn_core(iseq, iobj->insn_info.line_no, iobj->insn_info.node_id, insn_id, argc, operands);
4423 }
4424 #endif
4425 
4426 /*
4427  * This scheme can get more performance if do this optimize with
4428  * label address resolving.
4429  * It's future work (if compile time was bottle neck).
4430  */
4431 static int
4432 iseq_insns_unification(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
4433 {
4434 #if OPT_INSTRUCTIONS_UNIFICATION
4435  LINK_ELEMENT *list;
4436  INSN *iobj, *niobj;
4437  int id, k;
4438  intptr_t j;
4439 
4440  list = FIRST_ELEMENT(anchor);
4441  while (list) {
4442  if (IS_INSN(list)) {
4443  iobj = (INSN *)list;
4444  id = iobj->insn_id;
4445  if (unified_insns_data[id] != 0) {
4446  const int *const *entry = unified_insns_data[id];
4447  for (j = 1; j < (intptr_t)entry[0]; j++) {
4448  const int *unified = entry[j];
4449  LINK_ELEMENT *li = list->next;
4450  for (k = 2; k < unified[1]; k++) {
4451  if (!IS_INSN(li) ||
4452  ((INSN *)li)->insn_id != unified[k]) {
4453  goto miss;
4454  }
4455  li = li->next;
4456  }
4457  /* matched */
4458  niobj =
4459  new_unified_insn(iseq, unified[0], unified[1] - 1,
4460  list);
4461 
4462  /* insert to list */
4463  niobj->link.prev = (LINK_ELEMENT *)iobj->link.prev;
4464  niobj->link.next = li;
4465  if (li) {
4466  li->prev = (LINK_ELEMENT *)niobj;
4467  }
4468 
4469  list->prev->next = (LINK_ELEMENT *)niobj;
4470  list = (LINK_ELEMENT *)niobj;
4471  break;
4472  miss:;
4473  }
4474  }
4475  }
4476  list = list->next;
4477  }
4478 #endif
4479  return COMPILE_OK;
4480 }
4481 
4482 static int
4483 all_string_result_p(const NODE *node)
4484 {
4485  if (!node) return FALSE;
4486  switch (nd_type(node)) {
4487  case NODE_STR: case NODE_DSTR: case NODE_FILE:
4488  return TRUE;
4489  case NODE_IF: case NODE_UNLESS:
4490  if (!RNODE_IF(node)->nd_body || !RNODE_IF(node)->nd_else) return FALSE;
4491  if (all_string_result_p(RNODE_IF(node)->nd_body))
4492  return all_string_result_p(RNODE_IF(node)->nd_else);
4493  return FALSE;
4494  case NODE_AND: case NODE_OR:
4495  if (!RNODE_AND(node)->nd_2nd)
4496  return all_string_result_p(RNODE_AND(node)->nd_1st);
4497  if (!all_string_result_p(RNODE_AND(node)->nd_1st))
4498  return FALSE;
4499  return all_string_result_p(RNODE_AND(node)->nd_2nd);
4500  default:
4501  return FALSE;
4502  }
4503 }
4504 
4505 static int
4506 compile_dstr_fragments(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int *cntp)
4507 {
4508  const struct RNode_LIST *list = RNODE_DSTR(node)->nd_next;
4509  VALUE lit = rb_node_dstr_string_val(node);
4510  LINK_ELEMENT *first_lit = 0;
4511  int cnt = 0;
4512 
4513  debugp_param("nd_lit", lit);
4514  if (!NIL_P(lit)) {
4515  cnt++;
4516  if (!RB_TYPE_P(lit, T_STRING)) {
4517  COMPILE_ERROR(ERROR_ARGS "dstr: must be string: %s",
4518  rb_builtin_type_name(TYPE(lit)));
4519  return COMPILE_NG;
4520  }
4521  lit = rb_fstring(lit);
4522  ADD_INSN1(ret, node, putobject, lit);
4523  RB_OBJ_WRITTEN(iseq, Qundef, lit);
4524  if (RSTRING_LEN(lit) == 0) first_lit = LAST_ELEMENT(ret);
4525  }
4526 
4527  while (list) {
4528  const NODE *const head = list->nd_head;
4529  if (nd_type_p(head, NODE_STR)) {
4530  lit = rb_node_str_string_val(head);
4531  ADD_INSN1(ret, head, putobject, lit);
4532  RB_OBJ_WRITTEN(iseq, Qundef, lit);
4533  lit = Qnil;
4534  }
4535  else {
4536  CHECK(COMPILE(ret, "each string", head));
4537  }
4538  cnt++;
4539  list = (struct RNode_LIST *)list->nd_next;
4540  }
4541  if (NIL_P(lit) && first_lit) {
4542  ELEM_REMOVE(first_lit);
4543  --cnt;
4544  }
4545  *cntp = cnt;
4546 
4547  return COMPILE_OK;
4548 }
4549 
4550 static int
4551 compile_block(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int popped)
4552 {
4553  while (node && nd_type_p(node, NODE_BLOCK)) {
4554  CHECK(COMPILE_(ret, "BLOCK body", RNODE_BLOCK(node)->nd_head,
4555  (RNODE_BLOCK(node)->nd_next ? 1 : popped)));
4556  node = RNODE_BLOCK(node)->nd_next;
4557  }
4558  if (node) {
4559  CHECK(COMPILE_(ret, "BLOCK next", RNODE_BLOCK(node)->nd_next, popped));
4560  }
4561  return COMPILE_OK;
4562 }
4563 
4564 static int
4565 compile_dstr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node)
4566 {
4567  int cnt;
4568  if (!RNODE_DSTR(node)->nd_next) {
4569  VALUE lit = rb_node_dstr_string_val(node);
4570  ADD_INSN1(ret, node, putstring, lit);
4571  RB_OBJ_WRITTEN(iseq, Qundef, lit);
4572  }
4573  else {
4574  CHECK(compile_dstr_fragments(iseq, ret, node, &cnt));
4575  ADD_INSN1(ret, node, concatstrings, INT2FIX(cnt));
4576  }
4577  return COMPILE_OK;
4578 }
4579 
4580 static int
4581 compile_dregx(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
4582 {
4583  int cnt;
4584  int cflag = (int)RNODE_DREGX(node)->as.nd_cflag;
4585 
4586  if (!RNODE_DREGX(node)->nd_next) {
4587  if (!popped) {
4588  VALUE src = rb_node_dregx_string_val(node);
4589  VALUE match = rb_reg_compile(src, cflag, NULL, 0);
4590  ADD_INSN1(ret, node, putobject, match);
4591  RB_OBJ_WRITTEN(iseq, Qundef, match);
4592  }
4593  return COMPILE_OK;
4594  }
4595 
4596  CHECK(compile_dstr_fragments(iseq, ret, node, &cnt));
4597  ADD_INSN2(ret, node, toregexp, INT2FIX(cflag), INT2FIX(cnt));
4598 
4599  if (popped) {
4600  ADD_INSN(ret, node, pop);
4601  }
4602 
4603  return COMPILE_OK;
4604 }
4605 
4606 static int
4607 compile_flip_flop(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int again,
4608  LABEL *then_label, LABEL *else_label)
4609 {
4610  const int line = nd_line(node);
4611  LABEL *lend = NEW_LABEL(line);
4612  rb_num_t cnt = ISEQ_FLIP_CNT_INCREMENT(ISEQ_BODY(iseq)->local_iseq)
4613  + VM_SVAR_FLIPFLOP_START;
4614  VALUE key = INT2FIX(cnt);
4615 
4616  ADD_INSN2(ret, node, getspecial, key, INT2FIX(0));
4617  ADD_INSNL(ret, node, branchif, lend);
4618 
4619  /* *flip == 0 */
4620  CHECK(COMPILE(ret, "flip2 beg", RNODE_FLIP2(node)->nd_beg));
4621  ADD_INSNL(ret, node, branchunless, else_label);
4622  ADD_INSN1(ret, node, putobject, Qtrue);
4623  ADD_INSN1(ret, node, setspecial, key);
4624  if (!again) {
4625  ADD_INSNL(ret, node, jump, then_label);
4626  }
4627 
4628  /* *flip == 1 */
4629  ADD_LABEL(ret, lend);
4630  CHECK(COMPILE(ret, "flip2 end", RNODE_FLIP2(node)->nd_end));
4631  ADD_INSNL(ret, node, branchunless, then_label);
4632  ADD_INSN1(ret, node, putobject, Qfalse);
4633  ADD_INSN1(ret, node, setspecial, key);
4634  ADD_INSNL(ret, node, jump, then_label);
4635 
4636  return COMPILE_OK;
4637 }
4638 
4639 static int
4640 compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *cond,
4641  LABEL *then_label, LABEL *else_label);
4642 
4643 #define COMPILE_SINGLE 2
4644 static int
4645 compile_logical(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *cond,
4646  LABEL *then_label, LABEL *else_label)
4647 {
4648  DECL_ANCHOR(seq);
4649  INIT_ANCHOR(seq);
4650  LABEL *label = NEW_LABEL(nd_line(cond));
4651  if (!then_label) then_label = label;
4652  else if (!else_label) else_label = label;
4653 
4654  CHECK(compile_branch_condition(iseq, seq, cond, then_label, else_label));
4655 
4656  if (LIST_INSN_SIZE_ONE(seq)) {
4657  INSN *insn = (INSN *)ELEM_FIRST_INSN(FIRST_ELEMENT(seq));
4658  if (insn->insn_id == BIN(jump) && (LABEL *)(insn->operands[0]) == label)
4659  return COMPILE_OK;
4660  }
4661  if (!label->refcnt) {
4662  return COMPILE_SINGLE;
4663  }
4664  ADD_LABEL(seq, label);
4665  ADD_SEQ(ret, seq);
4666  return COMPILE_OK;
4667 }
4668 
4669 static int
4670 compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *cond,
4671  LABEL *then_label, LABEL *else_label)
4672 {
4673  int ok;
4674  DECL_ANCHOR(ignore);
4675 
4676  again:
4677  switch (nd_type(cond)) {
4678  case NODE_AND:
4679  CHECK(ok = compile_logical(iseq, ret, RNODE_AND(cond)->nd_1st, NULL, else_label));
4680  cond = RNODE_AND(cond)->nd_2nd;
4681  if (ok == COMPILE_SINGLE) {
4682  INIT_ANCHOR(ignore);
4683  ret = ignore;
4684  then_label = NEW_LABEL(nd_line(cond));
4685  }
4686  goto again;
4687  case NODE_OR:
4688  CHECK(ok = compile_logical(iseq, ret, RNODE_OR(cond)->nd_1st, then_label, NULL));
4689  cond = RNODE_OR(cond)->nd_2nd;
4690  if (ok == COMPILE_SINGLE) {
4691  INIT_ANCHOR(ignore);
4692  ret = ignore;
4693  else_label = NEW_LABEL(nd_line(cond));
4694  }
4695  goto again;
4696  case NODE_SYM:
4697  case NODE_LINE:
4698  case NODE_FILE:
4699  case NODE_ENCODING:
4700  case NODE_INTEGER: /* NODE_INTEGER is always true */
4701  case NODE_FLOAT: /* NODE_FLOAT is always true */
4702  case NODE_RATIONAL: /* NODE_RATIONAL is always true */
4703  case NODE_IMAGINARY: /* NODE_IMAGINARY is always true */
4704  case NODE_TRUE:
4705  case NODE_STR:
4706  case NODE_REGX:
4707  case NODE_ZLIST:
4708  case NODE_LAMBDA:
4709  /* printf("useless condition eliminate (%s)\n", ruby_node_name(nd_type(cond))); */
4710  ADD_INSNL(ret, cond, jump, then_label);
4711  return COMPILE_OK;
4712  case NODE_FALSE:
4713  case NODE_NIL:
4714  /* printf("useless condition eliminate (%s)\n", ruby_node_name(nd_type(cond))); */
4715  ADD_INSNL(ret, cond, jump, else_label);
4716  return COMPILE_OK;
4717  case NODE_LIST:
4718  case NODE_ARGSCAT:
4719  case NODE_DREGX:
4720  case NODE_DSTR:
4721  CHECK(COMPILE_POPPED(ret, "branch condition", cond));
4722  ADD_INSNL(ret, cond, jump, then_label);
4723  return COMPILE_OK;
4724  case NODE_FLIP2:
4725  CHECK(compile_flip_flop(iseq, ret, cond, TRUE, then_label, else_label));
4726  return COMPILE_OK;
4727  case NODE_FLIP3:
4728  CHECK(compile_flip_flop(iseq, ret, cond, FALSE, then_label, else_label));
4729  return COMPILE_OK;
4730  case NODE_DEFINED:
4731  CHECK(compile_defined_expr(iseq, ret, cond, Qfalse, ret == ignore));
4732  break;
4733  default:
4734  {
4735  DECL_ANCHOR(cond_seq);
4736  INIT_ANCHOR(cond_seq);
4737 
4738  CHECK(COMPILE(cond_seq, "branch condition", cond));
4739 
4740  if (LIST_INSN_SIZE_ONE(cond_seq)) {
4741  INSN *insn = (INSN *)ELEM_FIRST_INSN(FIRST_ELEMENT(cond_seq));
4742  if (insn->insn_id == BIN(putobject)) {
4743  if (RTEST(insn->operands[0])) {
4744  ADD_INSNL(ret, cond, jump, then_label);
4745  // maybe unreachable
4746  return COMPILE_OK;
4747  }
4748  else {
4749  ADD_INSNL(ret, cond, jump, else_label);
4750  return COMPILE_OK;
4751  }
4752  }
4753  }
4754  ADD_SEQ(ret, cond_seq);
4755  }
4756  break;
4757  }
4758 
4759  ADD_INSNL(ret, cond, branchunless, else_label);
4760  ADD_INSNL(ret, cond, jump, then_label);
4761  return COMPILE_OK;
4762 }
4763 
4764 #define HASH_BRACE 1
4765 
4766 static int
4767 keyword_node_p(const NODE *const node)
4768 {
4769  return nd_type_p(node, NODE_HASH) && (RNODE_HASH(node)->nd_brace & HASH_BRACE) != HASH_BRACE;
4770 }
4771 
4772 static VALUE
4773 get_symbol_value(rb_iseq_t *iseq, const NODE *node)
4774 {
4775  switch (nd_type(node)) {
4776  case NODE_SYM:
4777  return rb_node_sym_string_val(node);
4778  default:
4779  UNKNOWN_NODE("get_symbol_value", node, Qnil);
4780  }
4781 }
4782 
4783 static VALUE
4784 node_hash_unique_key_index(rb_iseq_t *iseq, rb_node_hash_t *node_hash, int *count_ptr)
4785 {
4786  NODE *node = node_hash->nd_head;
4787  VALUE hash = rb_hash_new();
4788  VALUE ary = rb_ary_new();
4789 
4790  for (int i = 0; node != NULL; i++, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
4791  VALUE key = get_symbol_value(iseq, RNODE_LIST(node)->nd_head);
4792  VALUE idx = rb_hash_aref(hash, key);
4793  if (!NIL_P(idx)) {
4794  rb_ary_store(ary, FIX2INT(idx), Qfalse);
4795  (*count_ptr)--;
4796  }
4797  rb_hash_aset(hash, key, INT2FIX(i));
4798  rb_ary_store(ary, i, Qtrue);
4799  (*count_ptr)++;
4800  }
4801 
4802  return ary;
4803 }
4804 
4805 static int
4806 compile_keyword_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
4807  const NODE *const root_node,
4808  struct rb_callinfo_kwarg **const kw_arg_ptr,
4809  unsigned int *flag)
4810 {
4811  RUBY_ASSERT(nd_type_p(root_node, NODE_HASH));
4812  RUBY_ASSERT(kw_arg_ptr != NULL);
4813  RUBY_ASSERT(flag != NULL);
4814 
4815  if (RNODE_HASH(root_node)->nd_head && nd_type_p(RNODE_HASH(root_node)->nd_head, NODE_LIST)) {
4816  const NODE *node = RNODE_HASH(root_node)->nd_head;
4817  int seen_nodes = 0;
4818 
4819  while (node) {
4820  const NODE *key_node = RNODE_LIST(node)->nd_head;
4821  seen_nodes++;
4822 
4823  RUBY_ASSERT(nd_type_p(node, NODE_LIST));
4824  if (key_node && nd_type_p(key_node, NODE_SYM)) {
4825  /* can be keywords */
4826  }
4827  else {
4828  if (flag) {
4829  *flag |= VM_CALL_KW_SPLAT;
4830  if (seen_nodes > 1 || RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
4831  /* A new hash will be created for the keyword arguments
4832  * in this case, so mark the method as passing mutable
4833  * keyword splat.
4834  */
4835  *flag |= VM_CALL_KW_SPLAT_MUT;
4836  }
4837  }
4838  return FALSE;
4839  }
4840  node = RNODE_LIST(node)->nd_next; /* skip value node */
4841  node = RNODE_LIST(node)->nd_next;
4842  }
4843 
4844  /* may be keywords */
4845  node = RNODE_HASH(root_node)->nd_head;
4846  {
4847  int len = 0;
4848  VALUE key_index = node_hash_unique_key_index(iseq, RNODE_HASH(root_node), &len);
4849  struct rb_callinfo_kwarg *kw_arg =
4850  rb_xmalloc_mul_add(len, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
4851  VALUE *keywords = kw_arg->keywords;
4852  int i = 0;
4853  int j = 0;
4854  kw_arg->references = 0;
4855  kw_arg->keyword_len = len;
4856 
4857  *kw_arg_ptr = kw_arg;
4858 
4859  for (i=0; node != NULL; i++, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
4860  const NODE *key_node = RNODE_LIST(node)->nd_head;
4861  const NODE *val_node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head;
4862  int popped = TRUE;
4863  if (rb_ary_entry(key_index, i)) {
4864  keywords[j] = get_symbol_value(iseq, key_node);
4865  j++;
4866  popped = FALSE;
4867  }
4868  NO_CHECK(COMPILE_(ret, "keyword values", val_node, popped));
4869  }
4870  RUBY_ASSERT(j == len);
4871  return TRUE;
4872  }
4873  }
4874  return FALSE;
4875 }
4876 
4877 static int
4878 compile_args(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, NODE **kwnode_ptr)
4879 {
4880  int len = 0;
4881 
4882  for (; node; len++, node = RNODE_LIST(node)->nd_next) {
4883  if (CPDEBUG > 0) {
4884  EXPECT_NODE("compile_args", node, NODE_LIST, -1);
4885  }
4886 
4887  if (RNODE_LIST(node)->nd_next == NULL && keyword_node_p(RNODE_LIST(node)->nd_head)) { /* last node is kwnode */
4888  *kwnode_ptr = RNODE_LIST(node)->nd_head;
4889  }
4890  else {
4891  RUBY_ASSERT(!keyword_node_p(RNODE_LIST(node)->nd_head));
4892  NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, FALSE));
4893  }
4894  }
4895 
4896  return len;
4897 }
4898 
4899 static inline bool
4900 frozen_string_literal_p(const rb_iseq_t *iseq)
4901 {
4902  return ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal > 0;
4903 }
4904 
4905 static inline bool
4906 static_literal_node_p(const NODE *node, const rb_iseq_t *iseq, bool hash_key)
4907 {
4908  switch (nd_type(node)) {
4909  case NODE_SYM:
4910  case NODE_REGX:
4911  case NODE_LINE:
4912  case NODE_ENCODING:
4913  case NODE_INTEGER:
4914  case NODE_FLOAT:
4915  case NODE_RATIONAL:
4916  case NODE_IMAGINARY:
4917  case NODE_NIL:
4918  case NODE_TRUE:
4919  case NODE_FALSE:
4920  return TRUE;
4921  case NODE_STR:
4922  case NODE_FILE:
4923  return hash_key || frozen_string_literal_p(iseq);
4924  default:
4925  return FALSE;
4926  }
4927 }
4928 
4929 static inline VALUE
4930 static_literal_value(const NODE *node, rb_iseq_t *iseq)
4931 {
4932  switch (nd_type(node)) {
4933  case NODE_INTEGER:
4934  return rb_node_integer_literal_val(node);
4935  case NODE_FLOAT:
4936  return rb_node_float_literal_val(node);
4937  case NODE_RATIONAL:
4938  return rb_node_rational_literal_val(node);
4939  case NODE_IMAGINARY:
4940  return rb_node_imaginary_literal_val(node);
4941  case NODE_NIL:
4942  return Qnil;
4943  case NODE_TRUE:
4944  return Qtrue;
4945  case NODE_FALSE:
4946  return Qfalse;
4947  case NODE_SYM:
4948  return rb_node_sym_string_val(node);
4949  case NODE_REGX:
4950  return rb_node_regx_string_val(node);
4951  case NODE_LINE:
4952  return rb_node_line_lineno_val(node);
4953  case NODE_ENCODING:
4954  return rb_node_encoding_val(node);
4955  case NODE_FILE:
4956  case NODE_STR:
4957  if (ISEQ_COMPILE_DATA(iseq)->option->debug_frozen_string_literal || RTEST(ruby_debug)) {
4958  VALUE lit = get_string_value(node);
4959  return rb_str_with_debug_created_info(lit, rb_iseq_path(iseq), (int)nd_line(node));
4960  }
4961  else {
4962  return get_string_value(node);
4963  }
4964  default:
4965  rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
4966  }
4967 }
4968 
4969 static int
4970 compile_array(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int popped, bool first_chunk)
4971 {
4972  const NODE *line_node = node;
4973 
4974  if (nd_type_p(node, NODE_ZLIST)) {
4975  if (!popped) {
4976  ADD_INSN1(ret, line_node, newarray, INT2FIX(0));
4977  }
4978  return 0;
4979  }
4980 
4981  EXPECT_NODE("compile_array", node, NODE_LIST, -1);
4982 
4983  if (popped) {
4984  for (; node; node = RNODE_LIST(node)->nd_next) {
4985  NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, popped));
4986  }
4987  return 1;
4988  }
4989 
4990  /* Compilation of an array literal.
4991  * The following code is essentially the same as:
4992  *
4993  * for (int count = 0; node; count++; node->nd_next) {
4994  * compile(node->nd_head);
4995  * }
4996  * ADD_INSN(newarray, count);
4997  *
4998  * However, there are three points.
4999  *
5000  * - The code above causes stack overflow for a big string literal.
5001  * The following limits the stack length up to max_stack_len.
5002  *
5003  * [x1,x2,...,x10000] =>
5004  * push x1 ; push x2 ; ...; push x256; newarray 256;
5005  * push x257; push x258; ...; push x512; pushtoarray 256;
5006  * push x513; push x514; ...; push x768; pushtoarray 256;
5007  * ...
5008  *
5009  * - Long subarray can be optimized by pre-allocating a hidden array.
5010  *
5011  * [1,2,3,...,100] =>
5012  * duparray [1,2,3,...,100]
5013  *
5014  * [x, 1,2,3,...,100, z] =>
5015  * push x; newarray 1;
5016  * putobject [1,2,3,...,100] (<- hidden array); concattoarray;
5017  * push z; pushtoarray 1;
5018  *
5019  * - If the last element is a keyword, pushtoarraykwsplat should be emitted
5020  * to only push it onto the array if it is not empty
5021  * (Note: a keyword is NODE_HASH which is not static_literal_node_p.)
5022  *
5023  * [1,2,3,**kw] =>
5024  * putobject 1; putobject 2; putobject 3; newarray 3; ...; pushtoarraykwsplat kw
5025  */
5026 
5027  const int max_stack_len = 0x100;
5028  const int min_tmp_ary_len = 0x40;
5029  int stack_len = 0;
5030 
5031  /* Either create a new array, or push to the existing array */
5032 #define FLUSH_CHUNK \
5033  if (stack_len) { \
5034  if (first_chunk) ADD_INSN1(ret, line_node, newarray, INT2FIX(stack_len)); \
5035  else ADD_INSN1(ret, line_node, pushtoarray, INT2FIX(stack_len)); \
5036  first_chunk = FALSE; \
5037  stack_len = 0; \
5038  }
5039 
5040  while (node) {
5041  int count = 1;
5042 
5043  /* pre-allocation check (this branch can be omittable) */
5044  if (static_literal_node_p(RNODE_LIST(node)->nd_head, iseq, false)) {
5045  /* count the elements that are optimizable */
5046  const NODE *node_tmp = RNODE_LIST(node)->nd_next;
5047  for (; node_tmp && static_literal_node_p(RNODE_LIST(node_tmp)->nd_head, iseq, false); node_tmp = RNODE_LIST(node_tmp)->nd_next)
5048  count++;
5049 
5050  if ((first_chunk && stack_len == 0 && !node_tmp) || count >= min_tmp_ary_len) {
5051  /* The literal contains only optimizable elements, or the subarray is long enough */
5052  VALUE ary = rb_ary_hidden_new(count);
5053 
5054  /* Create a hidden array */
5055  for (; count; count--, node = RNODE_LIST(node)->nd_next)
5056  rb_ary_push(ary, static_literal_value(RNODE_LIST(node)->nd_head, iseq));
5057  OBJ_FREEZE(ary);
5058 
5059  /* Emit optimized code */
5060  FLUSH_CHUNK;
5061  if (first_chunk) {
5062  ADD_INSN1(ret, line_node, duparray, ary);
5063  first_chunk = FALSE;
5064  }
5065  else {
5066  ADD_INSN1(ret, line_node, putobject, ary);
5067  ADD_INSN(ret, line_node, concattoarray);
5068  }
5069  RB_OBJ_WRITTEN(iseq, Qundef, ary);
5070  }
5071  }
5072 
5073  /* Base case: Compile "count" elements */
5074  for (; count; count--, node = RNODE_LIST(node)->nd_next) {
5075  if (CPDEBUG > 0) {
5076  EXPECT_NODE("compile_array", node, NODE_LIST, -1);
5077  }
5078 
5079  if (!RNODE_LIST(node)->nd_next && keyword_node_p(RNODE_LIST(node)->nd_head)) {
5080  /* Create array or push existing non-keyword elements onto array */
5081  if (stack_len == 0 && first_chunk) {
5082  ADD_INSN1(ret, line_node, newarray, INT2FIX(0));
5083  }
5084  else {
5085  FLUSH_CHUNK;
5086  }
5087  NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, 0));
5088  ADD_INSN(ret, line_node, pushtoarraykwsplat);
5089  return 1;
5090  }
5091  else {
5092  NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, 0));
5093  stack_len++;
5094  }
5095 
5096  /* If there are many pushed elements, flush them to avoid stack overflow */
5097  if (stack_len >= max_stack_len) FLUSH_CHUNK;
5098  }
5099  }
5100 
5101  FLUSH_CHUNK;
5102 #undef FLUSH_CHUNK
5103  return 1;
5104 }
5105 
5106 static inline int
5107 static_literal_node_pair_p(const NODE *node, const rb_iseq_t *iseq)
5108 {
5109  return RNODE_LIST(node)->nd_head && static_literal_node_p(RNODE_LIST(node)->nd_head, iseq, true) && static_literal_node_p(RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head, iseq, false);
5110 }
5111 
5112 static int
5113 compile_hash(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int method_call_keywords, int popped)
5114 {
5115  const NODE *line_node = node;
5116 
5117  node = RNODE_HASH(node)->nd_head;
5118 
5119  if (!node || nd_type_p(node, NODE_ZLIST)) {
5120  if (!popped) {
5121  ADD_INSN1(ret, line_node, newhash, INT2FIX(0));
5122  }
5123  return 0;
5124  }
5125 
5126  EXPECT_NODE("compile_hash", node, NODE_LIST, -1);
5127 
5128  if (popped) {
5129  for (; node; node = RNODE_LIST(node)->nd_next) {
5130  NO_CHECK(COMPILE_(ret, "hash element", RNODE_LIST(node)->nd_head, popped));
5131  }
5132  return 1;
5133  }
5134 
5135  /* Compilation of a hash literal (or keyword arguments).
5136  * This is very similar to compile_array, but there are some differences:
5137  *
5138  * - It contains key-value pairs. So we need to take every two elements.
5139  * We can assume that the length is always even.
5140  *
5141  * - Merging is done by a method call (id_core_hash_merge_ptr).
5142  * Sometimes we need to insert the receiver, so "anchor" is needed.
5143  * In addition, a method call is much slower than concatarray.
5144  * So it pays only when the subsequence is really long.
5145  * (min_tmp_hash_len must be much larger than min_tmp_ary_len.)
5146  *
5147  * - We need to handle keyword splat: **kw.
5148  * For **kw, the key part (node->nd_head) is NULL, and the value part
5149  * (node->nd_next->nd_head) is "kw".
5150  * The code is a bit difficult to avoid hash allocation for **{}.
5151  */
5152 
5153  const int max_stack_len = 0x100;
5154  const int min_tmp_hash_len = 0x800;
5155  int stack_len = 0;
5156  int first_chunk = 1;
5157  DECL_ANCHOR(anchor);
5158  INIT_ANCHOR(anchor);
5159 
5160  /* Convert pushed elements to a hash, and merge if needed */
5161 #define FLUSH_CHUNK() \
5162  if (stack_len) { \
5163  if (first_chunk) { \
5164  APPEND_LIST(ret, anchor); \
5165  ADD_INSN1(ret, line_node, newhash, INT2FIX(stack_len)); \
5166  } \
5167  else { \
5168  ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE)); \
5169  ADD_INSN(ret, line_node, swap); \
5170  APPEND_LIST(ret, anchor); \
5171  ADD_SEND(ret, line_node, id_core_hash_merge_ptr, INT2FIX(stack_len + 1)); \
5172  } \
5173  INIT_ANCHOR(anchor); \
5174  first_chunk = stack_len = 0; \
5175  }
5176 
5177  while (node) {
5178  int count = 1;
5179 
5180  /* pre-allocation check (this branch can be omittable) */
5181  if (static_literal_node_pair_p(node, iseq)) {
5182  /* count the elements that are optimizable */
5183  const NODE *node_tmp = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next;
5184  for (; node_tmp && static_literal_node_pair_p(node_tmp, iseq); node_tmp = RNODE_LIST(RNODE_LIST(node_tmp)->nd_next)->nd_next)
5185  count++;
5186 
5187  if ((first_chunk && stack_len == 0 && !node_tmp) || count >= min_tmp_hash_len) {
5188  /* The literal contains only optimizable elements, or the subsequence is long enough */
5189  VALUE ary = rb_ary_hidden_new(count);
5190 
5191  /* Create a hidden hash */
5192  for (; count; count--, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
5193  VALUE elem[2];
5194  elem[0] = static_literal_value(RNODE_LIST(node)->nd_head, iseq);
5195  elem[1] = static_literal_value(RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head, iseq);
5196  rb_ary_cat(ary, elem, 2);
5197  }
5198  VALUE hash = rb_hash_new_with_size(RARRAY_LEN(ary) / 2);
5200  hash = rb_obj_hide(hash);
5201  OBJ_FREEZE(hash);
5202 
5203  /* Emit optimized code */
5204  FLUSH_CHUNK();
5205  if (first_chunk) {
5206  ADD_INSN1(ret, line_node, duphash, hash);
5207  first_chunk = 0;
5208  }
5209  else {
5210  ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
5211  ADD_INSN(ret, line_node, swap);
5212 
5213  ADD_INSN1(ret, line_node, putobject, hash);
5214 
5215  ADD_SEND(ret, line_node, id_core_hash_merge_kwd, INT2FIX(2));
5216  }
5217  RB_OBJ_WRITTEN(iseq, Qundef, hash);
5218  }
5219  }
5220 
5221  /* Base case: Compile "count" elements */
5222  for (; count; count--, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
5223 
5224  if (CPDEBUG > 0) {
5225  EXPECT_NODE("compile_hash", node, NODE_LIST, -1);
5226  }
5227 
5228  if (RNODE_LIST(node)->nd_head) {
5229  /* Normal key-value pair */
5230  NO_CHECK(COMPILE_(anchor, "hash key element", RNODE_LIST(node)->nd_head, 0));
5231  NO_CHECK(COMPILE_(anchor, "hash value element", RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head, 0));
5232  stack_len += 2;
5233 
5234  /* If there are many pushed elements, flush them to avoid stack overflow */
5235  if (stack_len >= max_stack_len) FLUSH_CHUNK();
5236  }
5237  else {
5238  /* kwsplat case: foo(..., **kw, ...) */
5239  FLUSH_CHUNK();
5240 
5241  const NODE *kw = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head;
5242  int empty_kw = nd_type_p(kw, NODE_HASH) && (!RNODE_HASH(kw)->nd_head); /* foo( ..., **{}, ...) */
5243  int first_kw = first_chunk && stack_len == 0; /* foo(1,2,3, **kw, ...) */
5244  int last_kw = !RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next; /* foo( ..., **kw) */
5245  int only_kw = last_kw && first_kw; /* foo(1,2,3, **kw) */
5246 
5247  empty_kw = empty_kw || nd_type_p(kw, NODE_NIL); /* foo( ..., **nil, ...) */
5248  if (empty_kw) {
5249  if (only_kw && method_call_keywords) {
5250  /* **{} appears at the only keyword argument in method call,
5251  * so it won't be modified.
5252  * kw is a special NODE_LIT that contains a special empty hash,
5253  * so this emits: putobject {}.
5254  * This is only done for method calls and not for literal hashes,
5255  * because literal hashes should always result in a new hash.
5256  */
5257  NO_CHECK(COMPILE(ret, "keyword splat", kw));
5258  }
5259  else if (first_kw) {
5260  /* **{} appears as the first keyword argument, so it may be modified.
5261  * We need to create a fresh hash object.
5262  */
5263  ADD_INSN1(ret, line_node, newhash, INT2FIX(0));
5264  }
5265  /* Any empty keyword splats that are not the first can be ignored.
5266  * since merging an empty hash into the existing hash is the same
5267  * as not merging it. */
5268  }
5269  else {
5270  if (only_kw && method_call_keywords) {
5271  /* **kw is only keyword argument in method call.
5272  * Use directly. This will be not be flagged as mutable.
5273  * This is only done for method calls and not for literal hashes,
5274  * because literal hashes should always result in a new hash.
5275  */
5276  NO_CHECK(COMPILE(ret, "keyword splat", kw));
5277  }
5278  else {
5279  /* There is more than one keyword argument, or this is not a method
5280  * call. In that case, we need to add an empty hash (if first keyword),
5281  * or merge the hash to the accumulated hash (if not the first keyword).
5282  */
5283  ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
5284  if (first_kw) ADD_INSN1(ret, line_node, newhash, INT2FIX(0));
5285  else ADD_INSN(ret, line_node, swap);
5286 
5287  NO_CHECK(COMPILE(ret, "keyword splat", kw));
5288 
5289  ADD_SEND(ret, line_node, id_core_hash_merge_kwd, INT2FIX(2));
5290  }
5291  }
5292 
5293  first_chunk = 0;
5294  }
5295  }
5296  }
5297 
5298  FLUSH_CHUNK();
5299 #undef FLUSH_CHUNK
5300  return 1;
5301 }
5302 
5303 VALUE
5304 rb_node_case_when_optimizable_literal(const NODE *const node)
5305 {
5306  switch (nd_type(node)) {
5307  case NODE_INTEGER:
5308  return rb_node_integer_literal_val(node);
5309  case NODE_FLOAT: {
5310  VALUE v = rb_node_float_literal_val(node);
5311  double ival;
5312 
5313  if (modf(RFLOAT_VALUE(v), &ival) == 0.0) {
5314  return FIXABLE(ival) ? LONG2FIX((long)ival) : rb_dbl2big(ival);
5315  }
5316  return v;
5317  }
5318  case NODE_RATIONAL:
5319  case NODE_IMAGINARY:
5320  return Qundef;
5321  case NODE_NIL:
5322  return Qnil;
5323  case NODE_TRUE:
5324  return Qtrue;
5325  case NODE_FALSE:
5326  return Qfalse;
5327  case NODE_SYM:
5328  return rb_node_sym_string_val(node);
5329  case NODE_LINE:
5330  return rb_node_line_lineno_val(node);
5331  case NODE_STR:
5332  return rb_node_str_string_val(node);
5333  case NODE_FILE:
5334  return rb_node_file_path_val(node);
5335  }
5336  return Qundef;
5337 }
5338 
5339 static int
5340 when_vals(rb_iseq_t *iseq, LINK_ANCHOR *const cond_seq, const NODE *vals,
5341  LABEL *l1, int only_special_literals, VALUE literals)
5342 {
5343  while (vals) {
5344  const NODE *val = RNODE_LIST(vals)->nd_head;
5345  VALUE lit = rb_node_case_when_optimizable_literal(val);
5346 
5347  if (UNDEF_P(lit)) {
5348  only_special_literals = 0;
5349  }
5350  else if (NIL_P(rb_hash_lookup(literals, lit))) {
5351  rb_hash_aset(literals, lit, (VALUE)(l1) | 1);
5352  }
5353 
5354  if (nd_type_p(val, NODE_STR) || nd_type_p(val, NODE_FILE)) {
5355  debugp_param("nd_lit", get_string_value(val));
5356  lit = get_string_value(val);
5357  ADD_INSN1(cond_seq, val, putobject, lit);
5358  RB_OBJ_WRITTEN(iseq, Qundef, lit);
5359  }
5360  else {
5361  if (!COMPILE(cond_seq, "when cond", val)) return -1;
5362  }
5363 
5364  // Emit pattern === target
5365  ADD_INSN1(cond_seq, vals, topn, INT2FIX(1));
5366  ADD_CALL(cond_seq, vals, idEqq, INT2FIX(1));
5367  ADD_INSNL(cond_seq, val, branchif, l1);
5368  vals = RNODE_LIST(vals)->nd_next;
5369  }
5370  return only_special_literals;
5371 }
5372 
5373 static int
5374 when_splat_vals(rb_iseq_t *iseq, LINK_ANCHOR *const cond_seq, const NODE *vals,
5375  LABEL *l1, int only_special_literals, VALUE literals)
5376 {
5377  const NODE *line_node = vals;
5378 
5379  switch (nd_type(vals)) {
5380  case NODE_LIST:
5381  if (when_vals(iseq, cond_seq, vals, l1, only_special_literals, literals) < 0)
5382  return COMPILE_NG;
5383  break;
5384  case NODE_SPLAT:
5385  ADD_INSN (cond_seq, line_node, dup);
5386  CHECK(COMPILE(cond_seq, "when splat", RNODE_SPLAT(vals)->nd_head));
5387  ADD_INSN1(cond_seq, line_node, splatarray, Qfalse);
5388  ADD_INSN1(cond_seq, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE | VM_CHECKMATCH_ARRAY));
5389  ADD_INSNL(cond_seq, line_node, branchif, l1);
5390  break;
5391  case NODE_ARGSCAT:
5392  CHECK(when_splat_vals(iseq, cond_seq, RNODE_ARGSCAT(vals)->nd_head, l1, only_special_literals, literals));
5393  CHECK(when_splat_vals(iseq, cond_seq, RNODE_ARGSCAT(vals)->nd_body, l1, only_special_literals, literals));
5394  break;
5395  case NODE_ARGSPUSH:
5396  CHECK(when_splat_vals(iseq, cond_seq, RNODE_ARGSPUSH(vals)->nd_head, l1, only_special_literals, literals));
5397  ADD_INSN (cond_seq, line_node, dup);
5398  CHECK(COMPILE(cond_seq, "when argspush body", RNODE_ARGSPUSH(vals)->nd_body));
5399  ADD_INSN1(cond_seq, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE));
5400  ADD_INSNL(cond_seq, line_node, branchif, l1);
5401  break;
5402  default:
5403  ADD_INSN (cond_seq, line_node, dup);
5404  CHECK(COMPILE(cond_seq, "when val", vals));
5405  ADD_INSN1(cond_seq, line_node, splatarray, Qfalse);
5406  ADD_INSN1(cond_seq, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE | VM_CHECKMATCH_ARRAY));
5407  ADD_INSNL(cond_seq, line_node, branchif, l1);
5408  break;
5409  }
5410  return COMPILE_OK;
5411 }
5412 
5413 /* Multiple Assignment Handling
5414  *
5415  * In order to handle evaluation of multiple assignment such that the left hand side
5416  * is evaluated before the right hand side, we need to process the left hand side
5417  * and see if there are any attributes that need to be assigned, or constants set
5418  * on explicit objects. If so, we add instructions to evaluate the receiver of
5419  * any assigned attributes or constants before we process the right hand side.
5420  *
5421  * For a multiple assignment such as:
5422  *
5423  * l1.m1, l2[0] = r3, r4
5424  *
5425  * We start off evaluating l1 and l2, then we evaluate r3 and r4, then we
5426  * assign the result of r3 to l1.m1, and then the result of r4 to l2.m2.
5427  * On the VM stack, this looks like:
5428  *
5429  * self # putself
5430  * l1 # send
5431  * l1, self # putself
5432  * l1, l2 # send
5433  * l1, l2, 0 # putobject 0
5434  * l1, l2, 0, [r3, r4] # after evaluation of RHS
5435  * l1, l2, 0, [r3, r4], r4, r3 # expandarray
5436  * l1, l2, 0, [r3, r4], r4, r3, l1 # topn 5
5437  * l1, l2, 0, [r3, r4], r4, l1, r3 # swap
5438  * l1, l2, 0, [r3, r4], r4, m1= # send
5439  * l1, l2, 0, [r3, r4], r4 # pop
5440  * l1, l2, 0, [r3, r4], r4, l2 # topn 3
5441  * l1, l2, 0, [r3, r4], r4, l2, 0 # topn 3
5442  * l1, l2, 0, [r3, r4], r4, l2, 0, r4 # topn 2
5443  * l1, l2, 0, [r3, r4], r4, []= # send
5444  * l1, l2, 0, [r3, r4], r4 # pop
5445  * l1, l2, 0, [r3, r4] # pop
5446  * [r3, r4], l2, 0, [r3, r4] # setn 3
5447  * [r3, r4], l2, 0 # pop
5448  * [r3, r4], l2 # pop
5449  * [r3, r4] # pop
5450  *
5451  * This is made more complex when you have to handle splats, post args,
5452  * and arbitrary levels of nesting. You need to keep track of the total
5453  * number of attributes to set, and for each attribute, how many entries
5454  * are on the stack before the final attribute, in order to correctly
5455  * calculate the topn value to use to get the receiver of the attribute
5456  * setter method.
5457  *
5458  * A brief description of the VM stack for simple multiple assignment
5459  * with no splat (rhs_array will not be present if the return value of
5460  * the multiple assignment is not needed):
5461  *
5462  * lhs_attr1, lhs_attr2, ..., rhs_array, ..., rhs_arg2, rhs_arg1
5463  *
5464  * For multiple assignment with splats, while processing the part before
5465  * the splat (splat+post here is an array of the splat and the post arguments):
5466  *
5467  * lhs_attr1, lhs_attr2, ..., rhs_array, splat+post, ..., rhs_arg2, rhs_arg1
5468  *
5469  * When processing the splat and post arguments:
5470  *
5471  * lhs_attr1, lhs_attr2, ..., rhs_array, ..., post_arg2, post_arg1, splat
5472  *
5473  * When processing nested multiple assignment, existing values on the stack
5474  * are kept. So for:
5475  *
5476  * (l1.m1, l2.m2), l3.m3, l4* = [r1, r2], r3, r4
5477  *
5478  * The stack layout would be the following before processing the nested
5479  * multiple assignment:
5480  *
5481  * l1, l2, [[r1, r2], r3, r4], [r4], r3, [r1, r2]
5482  *
5483  * In order to handle this correctly, we need to keep track of the nesting
5484  * level for each attribute assignment, as well as the attribute number
5485  * (left hand side attributes are processed left to right) and number of
5486  * arguments to pass to the setter method. struct masgn_lhs_node tracks
5487  * this information.
5488  *
5489  * We also need to track information for the entire multiple assignment, such
5490  * as the total number of arguments, and the current nesting level, to
5491  * handle both nested multiple assignment as well as cases where the
5492  * rhs is not needed. We also need to keep track of all attribute
5493  * assignments in this, which we do using a linked listed. struct masgn_state
5494  * tracks this information.
5495  */
5496 
5498  INSN *before_insn;
5499  struct masgn_lhs_node *next;
5500  const NODE *line_node;
5501  int argn;
5502  int num_args;
5503  int lhs_pos;
5504 };
5505 
5506 struct masgn_state {
5507  struct masgn_lhs_node *first_memo;
5508  struct masgn_lhs_node *last_memo;
5509  int lhs_level;
5510  int num_args;
5511  bool nested;
5512 };
5513 
5514 static int
5515 add_masgn_lhs_node(struct masgn_state *state, int lhs_pos, const NODE *line_node, int argc, INSN *before_insn)
5516 {
5517  if (!state) {
5518  rb_bug("no masgn_state");
5519  }
5520 
5521  struct masgn_lhs_node *memo;
5522  memo = malloc(sizeof(struct masgn_lhs_node));
5523  if (!memo) {
5524  return COMPILE_NG;
5525  }
5526 
5527  memo->before_insn = before_insn;
5528  memo->line_node = line_node;
5529  memo->argn = state->num_args + 1;
5530  memo->num_args = argc;
5531  state->num_args += argc;
5532  memo->lhs_pos = lhs_pos;
5533  memo->next = NULL;
5534  if (!state->first_memo) {
5535  state->first_memo = memo;
5536  }
5537  else {
5538  state->last_memo->next = memo;
5539  }
5540  state->last_memo = memo;
5541 
5542  return COMPILE_OK;
5543 }
5544 
5545 static int compile_massign0(rb_iseq_t *iseq, LINK_ANCHOR *const pre, LINK_ANCHOR *const rhs, LINK_ANCHOR *const lhs, LINK_ANCHOR *const post, const NODE *const node, struct masgn_state *state, int popped);
5546 
5547 static int
5548 compile_massign_lhs(rb_iseq_t *iseq, LINK_ANCHOR *const pre, LINK_ANCHOR *const rhs, LINK_ANCHOR *const lhs, LINK_ANCHOR *const post, const NODE *const node, struct masgn_state *state, int lhs_pos)
5549 {
5550  switch (nd_type(node)) {
5551  case NODE_ATTRASGN: {
5552  INSN *iobj;
5553  const NODE *line_node = node;
5554 
5555  CHECK(COMPILE_POPPED(pre, "masgn lhs (NODE_ATTRASGN)", node));
5556 
5557  bool safenav_call = false;
5558  LINK_ELEMENT *insn_element = LAST_ELEMENT(pre);
5559  iobj = (INSN *)get_prev_insn((INSN *)insn_element); /* send insn */
5560  ASSUME(iobj);
5561  ELEM_REMOVE(insn_element);
5562  if (!IS_INSN_ID(iobj, send)) {
5563  safenav_call = true;
5564  iobj = (INSN *)get_prev_insn(iobj);
5565  ELEM_INSERT_NEXT(&iobj->link, insn_element);
5566  }
5567  (pre->last = iobj->link.prev)->next = 0;
5568 
5569  const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, 0);
5570  int argc = vm_ci_argc(ci) + 1;
5571  ci = ci_argc_set(iseq, ci, argc);
5572  OPERAND_AT(iobj, 0) = (VALUE)ci;
5573  RB_OBJ_WRITTEN(iseq, Qundef, ci);
5574 
5575  if (argc == 1) {
5576  ADD_INSN(lhs, line_node, swap);
5577  }
5578  else {
5579  ADD_INSN1(lhs, line_node, topn, INT2FIX(argc));
5580  }
5581 
5582  if (!add_masgn_lhs_node(state, lhs_pos, line_node, argc, (INSN *)LAST_ELEMENT(lhs))) {
5583  return COMPILE_NG;
5584  }
5585 
5586  iobj->link.prev = lhs->last;
5587  lhs->last->next = &iobj->link;
5588  for (lhs->last = &iobj->link; lhs->last->next; lhs->last = lhs->last->next);
5589  if (vm_ci_flag(ci) & VM_CALL_ARGS_SPLAT) {
5590  int argc = vm_ci_argc(ci);
5591  bool dupsplat = false;
5592  ci = ci_argc_set(iseq, ci, argc - 1);
5593  if (!(vm_ci_flag(ci) & VM_CALL_ARGS_SPLAT_MUT)) {
5594  /* Given h[*a], _ = ary
5595  * setup_args sets VM_CALL_ARGS_SPLAT and not VM_CALL_ARGS_SPLAT_MUT
5596  * `a` must be dupped, because it will be appended with ary[0]
5597  * Since you are dupping `a`, you can set VM_CALL_ARGS_SPLAT_MUT
5598  */
5599  dupsplat = true;
5600  ci = ci_flag_set(iseq, ci, VM_CALL_ARGS_SPLAT_MUT);
5601  }
5602  OPERAND_AT(iobj, 0) = (VALUE)ci;
5603  RB_OBJ_WRITTEN(iseq, Qundef, iobj);
5604 
5605  /* Given: h[*a], h[*b, 1] = ary
5606  * h[*a] uses splatarray false and does not set VM_CALL_ARGS_SPLAT_MUT,
5607  * so this uses splatarray true on a to dup it before using pushtoarray
5608  * h[*b, 1] uses splatarray true and sets VM_CALL_ARGS_SPLAT_MUT,
5609  * so you can use pushtoarray directly
5610  */
5611  int line_no = nd_line(line_node);
5612  int node_id = nd_node_id(line_node);
5613 
5614  if (dupsplat) {
5615  INSERT_BEFORE_INSN(iobj, line_no, node_id, swap);
5616  INSERT_BEFORE_INSN1(iobj, line_no, node_id, splatarray, Qtrue);
5617  INSERT_BEFORE_INSN(iobj, line_no, node_id, swap);
5618  }
5619  INSERT_BEFORE_INSN1(iobj, line_no, node_id, pushtoarray, INT2FIX(1));
5620  }
5621  if (!safenav_call) {
5622  ADD_INSN(lhs, line_node, pop);
5623  if (argc != 1) {
5624  ADD_INSN(lhs, line_node, pop);
5625  }
5626  }
5627  for (int i=0; i < argc; i++) {
5628  ADD_INSN(post, line_node, pop);
5629  }
5630  break;
5631  }
5632  case NODE_MASGN: {
5633  DECL_ANCHOR(nest_rhs);
5634  INIT_ANCHOR(nest_rhs);
5635  DECL_ANCHOR(nest_lhs);
5636  INIT_ANCHOR(nest_lhs);
5637 
5638  int prev_level = state->lhs_level;
5639  bool prev_nested = state->nested;
5640  state->nested = 1;
5641  state->lhs_level = lhs_pos - 1;
5642  CHECK(compile_massign0(iseq, pre, nest_rhs, nest_lhs, post, node, state, 1));
5643  state->lhs_level = prev_level;
5644  state->nested = prev_nested;
5645 
5646  ADD_SEQ(lhs, nest_rhs);
5647  ADD_SEQ(lhs, nest_lhs);
5648  break;
5649  }
5650  case NODE_CDECL:
5651  if (!RNODE_CDECL(node)->nd_vid) {
5652  /* Special handling only needed for expr::C, not for C */
5653  INSN *iobj;
5654 
5655  CHECK(COMPILE_POPPED(pre, "masgn lhs (NODE_CDECL)", node));
5656 
5657  LINK_ELEMENT *insn_element = LAST_ELEMENT(pre);
5658  iobj = (INSN *)insn_element; /* setconstant insn */
5659  ELEM_REMOVE((LINK_ELEMENT *)get_prev_insn((INSN *)get_prev_insn(iobj)));
5660  ELEM_REMOVE((LINK_ELEMENT *)get_prev_insn(iobj));
5661  ELEM_REMOVE(insn_element);
5662  pre->last = iobj->link.prev;
5663  ADD_ELEM(lhs, (LINK_ELEMENT *)iobj);
5664 
5665  if (!add_masgn_lhs_node(state, lhs_pos, node, 1, (INSN *)LAST_ELEMENT(lhs))) {
5666  return COMPILE_NG;
5667  }
5668 
5669  ADD_INSN(post, node, pop);
5670  break;
5671  }
5672  /* Fallthrough */
5673  default: {
5674  DECL_ANCHOR(anchor);
5675  INIT_ANCHOR(anchor);
5676  CHECK(COMPILE_POPPED(anchor, "masgn lhs", node));
5677  ELEM_REMOVE(FIRST_ELEMENT(anchor));
5678  ADD_SEQ(lhs, anchor);
5679  }
5680  }
5681 
5682  return COMPILE_OK;
5683 }
5684 
5685 static int
5686 compile_massign_opt_lhs(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *lhsn)
5687 {
5688  if (lhsn) {
5689  CHECK(compile_massign_opt_lhs(iseq, ret, RNODE_LIST(lhsn)->nd_next));
5690  CHECK(compile_massign_lhs(iseq, ret, ret, ret, ret, RNODE_LIST(lhsn)->nd_head, NULL, 0));
5691  }
5692  return COMPILE_OK;
5693 }
5694 
5695 static int
5696 compile_massign_opt(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
5697  const NODE *rhsn, const NODE *orig_lhsn)
5698 {
5699  VALUE mem[64];
5700  const int memsize = numberof(mem);
5701  int memindex = 0;
5702  int llen = 0, rlen = 0;
5703  int i;
5704  const NODE *lhsn = orig_lhsn;
5705 
5706 #define MEMORY(v) { \
5707  int i; \
5708  if (memindex == memsize) return 0; \
5709  for (i=0; i<memindex; i++) { \
5710  if (mem[i] == (v)) return 0; \
5711  } \
5712  mem[memindex++] = (v); \
5713 }
5714 
5715  if (rhsn == 0 || !nd_type_p(rhsn, NODE_LIST)) {
5716  return 0;
5717  }
5718 
5719  while (lhsn) {
5720  const NODE *ln = RNODE_LIST(lhsn)->nd_head;
5721  switch (nd_type(ln)) {
5722  case NODE_LASGN:
5723  case NODE_DASGN:
5724  case NODE_IASGN:
5725  case NODE_CVASGN:
5726  MEMORY(get_nd_vid(ln));
5727  break;
5728  default:
5729  return 0;
5730  }
5731  lhsn = RNODE_LIST(lhsn)->nd_next;
5732  llen++;
5733  }
5734 
5735  while (rhsn) {
5736  if (llen <= rlen) {
5737  NO_CHECK(COMPILE_POPPED(ret, "masgn val (popped)", RNODE_LIST(rhsn)->nd_head));
5738  }
5739  else {
5740  NO_CHECK(COMPILE(ret, "masgn val", RNODE_LIST(rhsn)->nd_head));
5741  }
5742  rhsn = RNODE_LIST(rhsn)->nd_next;
5743  rlen++;
5744  }
5745 
5746  if (llen > rlen) {
5747  for (i=0; i<llen-rlen; i++) {
5748  ADD_INSN(ret, orig_lhsn, putnil);
5749  }
5750  }
5751 
5752  compile_massign_opt_lhs(iseq, ret, orig_lhsn);
5753  return 1;
5754 }
5755 
5756 static int
5757 compile_massign0(rb_iseq_t *iseq, LINK_ANCHOR *const pre, LINK_ANCHOR *const rhs, LINK_ANCHOR *const lhs, LINK_ANCHOR *const post, const NODE *const node, struct masgn_state *state, int popped)
5758 {
5759  const NODE *rhsn = RNODE_MASGN(node)->nd_value;
5760  const NODE *splatn = RNODE_MASGN(node)->nd_args;
5761  const NODE *lhsn = RNODE_MASGN(node)->nd_head;
5762  const NODE *lhsn_count = lhsn;
5763  int lhs_splat = (splatn && NODE_NAMED_REST_P(splatn)) ? 1 : 0;
5764 
5765  int llen = 0;
5766  int lpos = 0;
5767 
5768  while (lhsn_count) {
5769  llen++;
5770  lhsn_count = RNODE_LIST(lhsn_count)->nd_next;
5771  }
5772  while (lhsn) {
5773  CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, RNODE_LIST(lhsn)->nd_head, state, (llen - lpos) + lhs_splat + state->lhs_level));
5774  lpos++;
5775  lhsn = RNODE_LIST(lhsn)->nd_next;
5776  }
5777 
5778  if (lhs_splat) {
5779  if (nd_type_p(splatn, NODE_POSTARG)) {
5780  /*a, b, *r, p1, p2 */
5781  const NODE *postn = RNODE_POSTARG(splatn)->nd_2nd;
5782  const NODE *restn = RNODE_POSTARG(splatn)->nd_1st;
5783  int plen = (int)RNODE_LIST(postn)->as.nd_alen;
5784  int ppos = 0;
5785  int flag = 0x02 | (NODE_NAMED_REST_P(restn) ? 0x01 : 0x00);
5786 
5787  ADD_INSN2(lhs, splatn, expandarray, INT2FIX(plen), INT2FIX(flag));
5788 
5789  if (NODE_NAMED_REST_P(restn)) {
5790  CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, restn, state, 1 + plen + state->lhs_level));
5791  }
5792  while (postn) {
5793  CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, RNODE_LIST(postn)->nd_head, state, (plen - ppos) + state->lhs_level));
5794  ppos++;
5795  postn = RNODE_LIST(postn)->nd_next;
5796  }
5797  }
5798  else {
5799  /* a, b, *r */
5800  CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, splatn, state, 1 + state->lhs_level));
5801  }
5802  }
5803 
5804  if (!state->nested) {
5805  NO_CHECK(COMPILE(rhs, "normal masgn rhs", rhsn));
5806  }
5807 
5808  if (!popped) {
5809  ADD_INSN(rhs, node, dup);
5810  }
5811  ADD_INSN2(rhs, node, expandarray, INT2FIX(llen), INT2FIX(lhs_splat));
5812  return COMPILE_OK;
5813 }
5814 
5815 static int
5816 compile_massign(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
5817 {
5818  if (!popped || RNODE_MASGN(node)->nd_args || !compile_massign_opt(iseq, ret, RNODE_MASGN(node)->nd_value, RNODE_MASGN(node)->nd_head)) {
5819  struct masgn_state state;
5820  state.lhs_level = popped ? 0 : 1;
5821  state.nested = 0;
5822  state.num_args = 0;
5823  state.first_memo = NULL;
5824  state.last_memo = NULL;
5825 
5826  DECL_ANCHOR(pre);
5827  INIT_ANCHOR(pre);
5828  DECL_ANCHOR(rhs);
5829  INIT_ANCHOR(rhs);
5830  DECL_ANCHOR(lhs);
5831  INIT_ANCHOR(lhs);
5832  DECL_ANCHOR(post);
5833  INIT_ANCHOR(post);
5834  int ok = compile_massign0(iseq, pre, rhs, lhs, post, node, &state, popped);
5835 
5836  struct masgn_lhs_node *memo = state.first_memo, *tmp_memo;
5837  while (memo) {
5838  VALUE topn_arg = INT2FIX((state.num_args - memo->argn) + memo->lhs_pos);
5839  for (int i = 0; i < memo->num_args; i++) {
5840  INSERT_BEFORE_INSN1(memo->before_insn, nd_line(memo->line_node), nd_node_id(memo->line_node), topn, topn_arg);
5841  }
5842  tmp_memo = memo->next;
5843  free(memo);
5844  memo = tmp_memo;
5845  }
5846  CHECK(ok);
5847 
5848  ADD_SEQ(ret, pre);
5849  ADD_SEQ(ret, rhs);
5850  ADD_SEQ(ret, lhs);
5851  if (!popped && state.num_args >= 1) {
5852  /* make sure rhs array is returned before popping */
5853  ADD_INSN1(ret, node, setn, INT2FIX(state.num_args));
5854  }
5855  ADD_SEQ(ret, post);
5856  }
5857  return COMPILE_OK;
5858 }
5859 
5860 static VALUE
5861 collect_const_segments(rb_iseq_t *iseq, const NODE *node)
5862 {
5863  VALUE arr = rb_ary_new();
5864  for (;;) {
5865  switch (nd_type(node)) {
5866  case NODE_CONST:
5867  rb_ary_unshift(arr, ID2SYM(RNODE_CONST(node)->nd_vid));
5868  return arr;
5869  case NODE_COLON3:
5870  rb_ary_unshift(arr, ID2SYM(RNODE_COLON3(node)->nd_mid));
5871  rb_ary_unshift(arr, ID2SYM(idNULL));
5872  return arr;
5873  case NODE_COLON2:
5874  rb_ary_unshift(arr, ID2SYM(RNODE_COLON2(node)->nd_mid));
5875  node = RNODE_COLON2(node)->nd_head;
5876  break;
5877  default:
5878  return Qfalse;
5879  }
5880  }
5881 }
5882 
5883 static int
5884 compile_const_prefix(rb_iseq_t *iseq, const NODE *const node,
5885  LINK_ANCHOR *const pref, LINK_ANCHOR *const body)
5886 {
5887  switch (nd_type(node)) {
5888  case NODE_CONST:
5889  debugi("compile_const_prefix - colon", RNODE_CONST(node)->nd_vid);
5890  ADD_INSN1(body, node, putobject, Qtrue);
5891  ADD_INSN1(body, node, getconstant, ID2SYM(RNODE_CONST(node)->nd_vid));
5892  break;
5893  case NODE_COLON3:
5894  debugi("compile_const_prefix - colon3", RNODE_COLON3(node)->nd_mid);
5895  ADD_INSN(body, node, pop);
5896  ADD_INSN1(body, node, putobject, rb_cObject);
5897  ADD_INSN1(body, node, putobject, Qtrue);
5898  ADD_INSN1(body, node, getconstant, ID2SYM(RNODE_COLON3(node)->nd_mid));
5899  break;
5900  case NODE_COLON2:
5901  CHECK(compile_const_prefix(iseq, RNODE_COLON2(node)->nd_head, pref, body));
5902  debugi("compile_const_prefix - colon2", RNODE_COLON2(node)->nd_mid);
5903  ADD_INSN1(body, node, putobject, Qfalse);
5904  ADD_INSN1(body, node, getconstant, ID2SYM(RNODE_COLON2(node)->nd_mid));
5905  break;
5906  default:
5907  CHECK(COMPILE(pref, "const colon2 prefix", node));
5908  break;
5909  }
5910  return COMPILE_OK;
5911 }
5912 
5913 static int
5914 compile_cpath(LINK_ANCHOR *const ret, rb_iseq_t *iseq, const NODE *cpath)
5915 {
5916  if (nd_type_p(cpath, NODE_COLON3)) {
5917  /* toplevel class ::Foo */
5918  ADD_INSN1(ret, cpath, putobject, rb_cObject);
5919  return VM_DEFINECLASS_FLAG_SCOPED;
5920  }
5921  else if (nd_type_p(cpath, NODE_COLON2) && RNODE_COLON2(cpath)->nd_head) {
5922  /* Bar::Foo */
5923  NO_CHECK(COMPILE(ret, "nd_else->nd_head", RNODE_COLON2(cpath)->nd_head));
5924  return VM_DEFINECLASS_FLAG_SCOPED;
5925  }
5926  else {
5927  /* class at cbase Foo */
5928  ADD_INSN1(ret, cpath, putspecialobject,
5929  INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
5930  return 0;
5931  }
5932 }
5933 
5934 static inline int
5935 private_recv_p(const NODE *node)
5936 {
5937  NODE *recv = get_nd_recv(node);
5938  if (recv && nd_type_p(recv, NODE_SELF)) {
5939  return RNODE_SELF(recv)->nd_state != 0;
5940  }
5941  return 0;
5942 }
5943 
5944 static void
5945 defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
5946  const NODE *const node, LABEL **lfinish, VALUE needstr, bool ignore);
5947 
5948 static int
5949 compile_call(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, const enum node_type type, const NODE *const line_node, int popped, bool assume_receiver);
5950 
5951 static void
5952 defined_expr0(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
5953  const NODE *const node, LABEL **lfinish, VALUE needstr,
5954  bool keep_result)
5955 {
5956  enum defined_type expr_type = DEFINED_NOT_DEFINED;
5957  enum node_type type;
5958  const int line = nd_line(node);
5959  const NODE *line_node = node;
5960 
5961  switch (type = nd_type(node)) {
5962 
5963  /* easy literals */
5964  case NODE_NIL:
5965  expr_type = DEFINED_NIL;
5966  break;
5967  case NODE_SELF:
5968  expr_type = DEFINED_SELF;
5969  break;
5970  case NODE_TRUE:
5971  expr_type = DEFINED_TRUE;
5972  break;
5973  case NODE_FALSE:
5974  expr_type = DEFINED_FALSE;
5975  break;
5976 
5977  case NODE_HASH:
5978  case NODE_LIST:{
5979  const NODE *vals = (nd_type(node) == NODE_HASH) ? RNODE_HASH(node)->nd_head : node;
5980 
5981  if (vals) {
5982  do {
5983  if (RNODE_LIST(vals)->nd_head) {
5984  defined_expr0(iseq, ret, RNODE_LIST(vals)->nd_head, lfinish, Qfalse, false);
5985 
5986  if (!lfinish[1]) {
5987  lfinish[1] = NEW_LABEL(line);
5988  }
5989  ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
5990  }
5991  } while ((vals = RNODE_LIST(vals)->nd_next) != NULL);
5992  }
5993  }
5994  /* fall through */
5995  case NODE_STR:
5996  case NODE_SYM:
5997  case NODE_REGX:
5998  case NODE_LINE:
5999  case NODE_FILE:
6000  case NODE_ENCODING:
6001  case NODE_INTEGER:
6002  case NODE_FLOAT:
6003  case NODE_RATIONAL:
6004  case NODE_IMAGINARY:
6005  case NODE_ZLIST:
6006  case NODE_AND:
6007  case NODE_OR:
6008  default:
6009  expr_type = DEFINED_EXPR;
6010  break;
6011 
6012  case NODE_SPLAT:
6013  defined_expr0(iseq, ret, RNODE_LIST(node)->nd_head, lfinish, Qfalse, false);
6014  if (!lfinish[1]) {
6015  lfinish[1] = NEW_LABEL(line);
6016  }
6017  ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6018  expr_type = DEFINED_EXPR;
6019  break;
6020 
6021  /* variables */
6022  case NODE_LVAR:
6023  case NODE_DVAR:
6024  expr_type = DEFINED_LVAR;
6025  break;
6026 
6027 #define PUSH_VAL(type) (needstr == Qfalse ? Qtrue : rb_iseq_defined_string(type))
6028  case NODE_IVAR:
6029  ADD_INSN3(ret, line_node, definedivar,
6030  ID2SYM(RNODE_IVAR(node)->nd_vid), get_ivar_ic_value(iseq,RNODE_IVAR(node)->nd_vid), PUSH_VAL(DEFINED_IVAR));
6031  return;
6032 
6033  case NODE_GVAR:
6034  ADD_INSN(ret, line_node, putnil);
6035  ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_GVAR),
6036  ID2SYM(RNODE_GVAR(node)->nd_vid), PUSH_VAL(DEFINED_GVAR));
6037  return;
6038 
6039  case NODE_CVAR:
6040  ADD_INSN(ret, line_node, putnil);
6041  ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CVAR),
6042  ID2SYM(RNODE_CVAR(node)->nd_vid), PUSH_VAL(DEFINED_CVAR));
6043  return;
6044 
6045  case NODE_CONST:
6046  ADD_INSN(ret, line_node, putnil);
6047  ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CONST),
6048  ID2SYM(RNODE_CONST(node)->nd_vid), PUSH_VAL(DEFINED_CONST));
6049  return;
6050  case NODE_COLON2:
6051  if (!lfinish[1]) {
6052  lfinish[1] = NEW_LABEL(line);
6053  }
6054  defined_expr0(iseq, ret, RNODE_COLON2(node)->nd_head, lfinish, Qfalse, false);
6055  ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6056  NO_CHECK(COMPILE(ret, "defined/colon2#nd_head", RNODE_COLON2(node)->nd_head));
6057 
6058  if (rb_is_const_id(RNODE_COLON2(node)->nd_mid)) {
6059  ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CONST_FROM),
6060  ID2SYM(RNODE_COLON2(node)->nd_mid), PUSH_VAL(DEFINED_CONST));
6061  }
6062  else {
6063  ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_METHOD),
6064  ID2SYM(RNODE_COLON2(node)->nd_mid), PUSH_VAL(DEFINED_METHOD));
6065  }
6066  return;
6067  case NODE_COLON3:
6068  ADD_INSN1(ret, line_node, putobject, rb_cObject);
6069  ADD_INSN3(ret, line_node, defined,
6070  INT2FIX(DEFINED_CONST_FROM), ID2SYM(RNODE_COLON3(node)->nd_mid), PUSH_VAL(DEFINED_CONST));
6071  return;
6072 
6073  /* method dispatch */
6074  case NODE_CALL:
6075  case NODE_OPCALL:
6076  case NODE_VCALL:
6077  case NODE_FCALL:
6078  case NODE_ATTRASGN:{
6079  const int explicit_receiver =
6080  (type == NODE_CALL || type == NODE_OPCALL ||
6081  (type == NODE_ATTRASGN && !private_recv_p(node)));
6082 
6083  if (get_nd_args(node) || explicit_receiver) {
6084  if (!lfinish[1]) {
6085  lfinish[1] = NEW_LABEL(line);
6086  }
6087  if (!lfinish[2]) {
6088  lfinish[2] = NEW_LABEL(line);
6089  }
6090  }
6091  if (get_nd_args(node)) {
6092  defined_expr0(iseq, ret, get_nd_args(node), lfinish, Qfalse, false);
6093  ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6094  }
6095  if (explicit_receiver) {
6096  defined_expr0(iseq, ret, get_nd_recv(node), lfinish, Qfalse, true);
6097  switch (nd_type(get_nd_recv(node))) {
6098  case NODE_CALL:
6099  case NODE_OPCALL:
6100  case NODE_VCALL:
6101  case NODE_FCALL:
6102  case NODE_ATTRASGN:
6103  ADD_INSNL(ret, line_node, branchunless, lfinish[2]);
6104  compile_call(iseq, ret, get_nd_recv(node), nd_type(get_nd_recv(node)), line_node, 0, true);
6105  break;
6106  default:
6107  ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6108  NO_CHECK(COMPILE(ret, "defined/recv", get_nd_recv(node)));
6109  break;
6110  }
6111  if (keep_result) {
6112  ADD_INSN(ret, line_node, dup);
6113  }
6114  ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_METHOD),
6115  ID2SYM(get_node_call_nd_mid(node)), PUSH_VAL(DEFINED_METHOD));
6116  }
6117  else {
6118  ADD_INSN(ret, line_node, putself);
6119  if (keep_result) {
6120  ADD_INSN(ret, line_node, dup);
6121  }
6122  ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_FUNC),
6123  ID2SYM(get_node_call_nd_mid(node)), PUSH_VAL(DEFINED_METHOD));
6124  }
6125  return;
6126  }
6127 
6128  case NODE_YIELD:
6129  ADD_INSN(ret, line_node, putnil);
6130  ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_YIELD), 0,
6131  PUSH_VAL(DEFINED_YIELD));
6132  iseq_set_use_block(ISEQ_BODY(iseq)->local_iseq);
6133  return;
6134 
6135  case NODE_BACK_REF:
6136  case NODE_NTH_REF:
6137  ADD_INSN(ret, line_node, putnil);
6138  ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_REF),
6139  INT2FIX((RNODE_BACK_REF(node)->nd_nth << 1) | (type == NODE_BACK_REF)),
6140  PUSH_VAL(DEFINED_GVAR));
6141  return;
6142 
6143  case NODE_SUPER:
6144  case NODE_ZSUPER:
6145  ADD_INSN(ret, line_node, putnil);
6146  ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_ZSUPER), 0,
6147  PUSH_VAL(DEFINED_ZSUPER));
6148  return;
6149 
6150 #undef PUSH_VAL
6151  case NODE_OP_ASGN1:
6152  case NODE_OP_ASGN2:
6153  case NODE_OP_ASGN_OR:
6154  case NODE_OP_ASGN_AND:
6155  case NODE_MASGN:
6156  case NODE_LASGN:
6157  case NODE_DASGN:
6158  case NODE_GASGN:
6159  case NODE_IASGN:
6160  case NODE_CDECL:
6161  case NODE_CVASGN:
6162  case NODE_OP_CDECL:
6163  expr_type = DEFINED_ASGN;
6164  break;
6165  }
6166 
6167  RUBY_ASSERT(expr_type != DEFINED_NOT_DEFINED);
6168 
6169  if (needstr != Qfalse) {
6170  VALUE str = rb_iseq_defined_string(expr_type);
6171  ADD_INSN1(ret, line_node, putobject, str);
6172  }
6173  else {
6174  ADD_INSN1(ret, line_node, putobject, Qtrue);
6175  }
6176 }
6177 
6178 static void
6179 build_defined_rescue_iseq(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const void *unused)
6180 {
6181  ADD_SYNTHETIC_INSN(ret, 0, -1, putnil);
6182  iseq_set_exception_local_table(iseq);
6183 }
6184 
6185 static void
6186 defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
6187  const NODE *const node, LABEL **lfinish, VALUE needstr, bool ignore)
6188 {
6189  LINK_ELEMENT *lcur = ret->last;
6190  defined_expr0(iseq, ret, node, lfinish, needstr, false);
6191  if (lfinish[1]) {
6192  int line = nd_line(node);
6193  LABEL *lstart = NEW_LABEL(line);
6194  LABEL *lend = NEW_LABEL(line);
6195  const rb_iseq_t *rescue;
6197  rb_iseq_new_with_callback_new_callback(build_defined_rescue_iseq, NULL);
6198  rescue = new_child_iseq_with_callback(iseq, ifunc,
6199  rb_str_concat(rb_str_new2("defined guard in "),
6200  ISEQ_BODY(iseq)->location.label),
6201  iseq, ISEQ_TYPE_RESCUE, 0);
6202  lstart->rescued = LABEL_RESCUE_BEG;
6203  lend->rescued = LABEL_RESCUE_END;
6204  APPEND_LABEL(ret, lcur, lstart);
6205  ADD_LABEL(ret, lend);
6206  if (!ignore) {
6207  ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lfinish[1]);
6208  }
6209  }
6210 }
6211 
6212 static int
6213 compile_defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE needstr, bool ignore)
6214 {
6215  const int line = nd_line(node);
6216  const NODE *line_node = node;
6217  if (!RNODE_DEFINED(node)->nd_head) {
6218  VALUE str = rb_iseq_defined_string(DEFINED_NIL);
6219  ADD_INSN1(ret, line_node, putobject, str);
6220  }
6221  else {
6222  LABEL *lfinish[3];
6223  LINK_ELEMENT *last = ret->last;
6224  lfinish[0] = NEW_LABEL(line);
6225  lfinish[1] = 0;
6226  lfinish[2] = 0;
6227  defined_expr(iseq, ret, RNODE_DEFINED(node)->nd_head, lfinish, needstr, ignore);
6228  if (lfinish[1]) {
6229  ELEM_INSERT_NEXT(last, &new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(putnil), 0)->link);
6230  ADD_INSN(ret, line_node, swap);
6231  if (lfinish[2]) {
6232  ADD_LABEL(ret, lfinish[2]);
6233  }
6234  ADD_INSN(ret, line_node, pop);
6235  ADD_LABEL(ret, lfinish[1]);
6236  }
6237  ADD_LABEL(ret, lfinish[0]);
6238  }
6239  return COMPILE_OK;
6240 }
6241 
6242 static VALUE
6243 make_name_for_block(const rb_iseq_t *orig_iseq)
6244 {
6245  int level = 1;
6246  const rb_iseq_t *iseq = orig_iseq;
6247 
6248  if (ISEQ_BODY(orig_iseq)->parent_iseq != 0) {
6249  while (ISEQ_BODY(orig_iseq)->local_iseq != iseq) {
6250  if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_BLOCK) {
6251  level++;
6252  }
6253  iseq = ISEQ_BODY(iseq)->parent_iseq;
6254  }
6255  }
6256 
6257  if (level == 1) {
6258  return rb_sprintf("block in %"PRIsVALUE, ISEQ_BODY(iseq)->location.label);
6259  }
6260  else {
6261  return rb_sprintf("block (%d levels) in %"PRIsVALUE, level, ISEQ_BODY(iseq)->location.label);
6262  }
6263 }
6264 
6265 static void
6266 push_ensure_entry(rb_iseq_t *iseq,
6268  struct ensure_range *er, const void *const node)
6269 {
6270  enl->ensure_node = node;
6271  enl->prev = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack; /* prev */
6272  enl->erange = er;
6273  ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enl;
6274 }
6275 
6276 static void
6277 add_ensure_range(rb_iseq_t *iseq, struct ensure_range *erange,
6278  LABEL *lstart, LABEL *lend)
6279 {
6280  struct ensure_range *ne =
6281  compile_data_alloc(iseq, sizeof(struct ensure_range));
6282 
6283  while (erange->next != 0) {
6284  erange = erange->next;
6285  }
6286  ne->next = 0;
6287  ne->begin = lend;
6288  ne->end = erange->end;
6289  erange->end = lstart;
6290 
6291  erange->next = ne;
6292 }
6293 
6294 static bool
6295 can_add_ensure_iseq(const rb_iseq_t *iseq)
6296 {
6298  if (ISEQ_COMPILE_DATA(iseq)->in_rescue && (e = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack) != NULL) {
6299  while (e) {
6300  if (e->ensure_node) return false;
6301  e = e->prev;
6302  }
6303  }
6304  return true;
6305 }
6306 
6307 static void
6308 add_ensure_iseq(LINK_ANCHOR *const ret, rb_iseq_t *iseq, int is_return)
6309 {
6310  RUBY_ASSERT(can_add_ensure_iseq(iseq));
6311 
6313  ISEQ_COMPILE_DATA(iseq)->ensure_node_stack;
6314  struct iseq_compile_data_ensure_node_stack *prev_enlp = enlp;
6315  DECL_ANCHOR(ensure);
6316 
6317  INIT_ANCHOR(ensure);
6318  while (enlp) {
6319  if (enlp->erange != NULL) {
6320  DECL_ANCHOR(ensure_part);
6321  LABEL *lstart = NEW_LABEL(0);
6322  LABEL *lend = NEW_LABEL(0);
6323  INIT_ANCHOR(ensure_part);
6324 
6325  add_ensure_range(iseq, enlp->erange, lstart, lend);
6326 
6327  ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enlp->prev;
6328  ADD_LABEL(ensure_part, lstart);
6329  NO_CHECK(COMPILE_POPPED(ensure_part, "ensure part", enlp->ensure_node));
6330  ADD_LABEL(ensure_part, lend);
6331  ADD_SEQ(ensure, ensure_part);
6332  }
6333  else {
6334  if (!is_return) {
6335  break;
6336  }
6337  }
6338  enlp = enlp->prev;
6339  }
6340  ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = prev_enlp;
6341  ADD_SEQ(ret, ensure);
6342 }
6343 
6344 #if RUBY_DEBUG
6345 static int
6346 check_keyword(const NODE *node)
6347 {
6348  /* This check is essentially a code clone of compile_keyword_arg. */
6349 
6350  if (nd_type_p(node, NODE_LIST)) {
6351  while (RNODE_LIST(node)->nd_next) {
6352  node = RNODE_LIST(node)->nd_next;
6353  }
6354  node = RNODE_LIST(node)->nd_head;
6355  }
6356 
6357  return keyword_node_p(node);
6358 }
6359 #endif
6360 
6361 static bool
6362 keyword_node_single_splat_p(NODE *kwnode)
6363 {
6364  RUBY_ASSERT(keyword_node_p(kwnode));
6365 
6366  NODE *node = RNODE_HASH(kwnode)->nd_head;
6367  return RNODE_LIST(node)->nd_head == NULL &&
6368  RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next == NULL;
6369 }
6370 
6371 static void
6372 compile_single_keyword_splat_mutable(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
6373  NODE *kwnode, unsigned int *flag_ptr)
6374 {
6375  *flag_ptr |= VM_CALL_KW_SPLAT_MUT;
6376  ADD_INSN1(args, argn, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
6377  ADD_INSN1(args, argn, newhash, INT2FIX(0));
6378  compile_hash(iseq, args, kwnode, TRUE, FALSE);
6379  ADD_SEND(args, argn, id_core_hash_merge_kwd, INT2FIX(2));
6380 }
6381 
6382 #define SPLATARRAY_FALSE 0
6383 #define SPLATARRAY_TRUE 1
6384 #define DUP_SINGLE_KW_SPLAT 2
6385 
6386 static int
6387 setup_args_core(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
6388  unsigned int *dup_rest, unsigned int *flag_ptr, struct rb_callinfo_kwarg **kwarg_ptr)
6389 {
6390  if (!argn) return 0;
6391 
6392  NODE *kwnode = NULL;
6393 
6394  switch (nd_type(argn)) {
6395  case NODE_LIST: {
6396  // f(x, y, z)
6397  int len = compile_args(iseq, args, argn, &kwnode);
6398  RUBY_ASSERT(flag_ptr == NULL || (*flag_ptr & VM_CALL_ARGS_SPLAT) == 0);
6399 
6400  if (kwnode) {
6401  if (compile_keyword_arg(iseq, args, kwnode, kwarg_ptr, flag_ptr)) {
6402  len -= 1;
6403  }
6404  else {
6405  if (keyword_node_single_splat_p(kwnode) && (*dup_rest & DUP_SINGLE_KW_SPLAT)) {
6406  compile_single_keyword_splat_mutable(iseq, args, argn, kwnode, flag_ptr);
6407  }
6408  else {
6409  compile_hash(iseq, args, kwnode, TRUE, FALSE);
6410  }
6411  }
6412  }
6413 
6414  return len;
6415  }
6416  case NODE_SPLAT: {
6417  // f(*a)
6418  NO_CHECK(COMPILE(args, "args (splat)", RNODE_SPLAT(argn)->nd_head));
6419  ADD_INSN1(args, argn, splatarray, RBOOL(*dup_rest & SPLATARRAY_TRUE));
6420  if (*dup_rest & SPLATARRAY_TRUE) *dup_rest &= ~SPLATARRAY_TRUE;
6421  if (flag_ptr) *flag_ptr |= VM_CALL_ARGS_SPLAT;
6422  RUBY_ASSERT(flag_ptr == NULL || (*flag_ptr & VM_CALL_KW_SPLAT) == 0);
6423  return 1;
6424  }
6425  case NODE_ARGSCAT: {
6426  if (flag_ptr) *flag_ptr |= VM_CALL_ARGS_SPLAT;
6427  int argc = setup_args_core(iseq, args, RNODE_ARGSCAT(argn)->nd_head, dup_rest, NULL, NULL);
6428  bool args_pushed = false;
6429 
6430  if (nd_type_p(RNODE_ARGSCAT(argn)->nd_body, NODE_LIST)) {
6431  int rest_len = compile_args(iseq, args, RNODE_ARGSCAT(argn)->nd_body, &kwnode);
6432  if (kwnode) rest_len--;
6433  ADD_INSN1(args, argn, pushtoarray, INT2FIX(rest_len));
6434  args_pushed = true;
6435  }
6436  else {
6437  RUBY_ASSERT(!check_keyword(RNODE_ARGSCAT(argn)->nd_body));
6438  NO_CHECK(COMPILE(args, "args (cat: splat)", RNODE_ARGSCAT(argn)->nd_body));
6439  }
6440 
6441  if (nd_type_p(RNODE_ARGSCAT(argn)->nd_head, NODE_LIST)) {
6442  ADD_INSN1(args, argn, splatarray, RBOOL(*dup_rest & SPLATARRAY_TRUE));
6443  if (*dup_rest & SPLATARRAY_TRUE) *dup_rest &= ~SPLATARRAY_TRUE;
6444  argc += 1;
6445  }
6446  else if (!args_pushed) {
6447  ADD_INSN(args, argn, concattoarray);
6448  }
6449 
6450  // f(..., *a, ..., k1:1, ...) #=> f(..., *[*a, ...], **{k1:1, ...})
6451  if (kwnode) {
6452  // kwsplat
6453  *flag_ptr |= VM_CALL_KW_SPLAT;
6454  compile_hash(iseq, args, kwnode, TRUE, FALSE);
6455  argc += 1;
6456  }
6457 
6458  return argc;
6459  }
6460  case NODE_ARGSPUSH: {
6461  if (flag_ptr) *flag_ptr |= VM_CALL_ARGS_SPLAT;
6462  int argc = setup_args_core(iseq, args, RNODE_ARGSPUSH(argn)->nd_head, dup_rest, NULL, NULL);
6463 
6464  if (nd_type_p(RNODE_ARGSPUSH(argn)->nd_body, NODE_LIST)) {
6465  int rest_len = compile_args(iseq, args, RNODE_ARGSPUSH(argn)->nd_body, &kwnode);
6466  if (kwnode) rest_len--;
6467  ADD_INSN1(args, argn, newarray, INT2FIX(rest_len));
6468  ADD_INSN1(args, argn, pushtoarray, INT2FIX(1));
6469  }
6470  else {
6471  if (keyword_node_p(RNODE_ARGSPUSH(argn)->nd_body)) {
6472  kwnode = RNODE_ARGSPUSH(argn)->nd_body;
6473  }
6474  else {
6475  NO_CHECK(COMPILE(args, "args (cat: splat)", RNODE_ARGSPUSH(argn)->nd_body));
6476  ADD_INSN1(args, argn, pushtoarray, INT2FIX(1));
6477  }
6478  }
6479 
6480  if (kwnode) {
6481  // f(*a, k:1)
6482  *flag_ptr |= VM_CALL_KW_SPLAT;
6483  if (!keyword_node_single_splat_p(kwnode)) {
6484  *flag_ptr |= VM_CALL_KW_SPLAT_MUT;
6485  compile_hash(iseq, args, kwnode, TRUE, FALSE);
6486  }
6487  else if (*dup_rest & DUP_SINGLE_KW_SPLAT) {
6488  compile_single_keyword_splat_mutable(iseq, args, argn, kwnode, flag_ptr);
6489  }
6490  else {
6491  compile_hash(iseq, args, kwnode, TRUE, FALSE);
6492  }
6493  argc += 1;
6494  }
6495 
6496  return argc;
6497  }
6498  default: {
6499  UNKNOWN_NODE("setup_arg", argn, Qnil);
6500  }
6501  }
6502 }
6503 
6504 static void
6505 setup_args_splat_mut(unsigned int *flag, int dup_rest, int initial_dup_rest)
6506 {
6507  if ((*flag & VM_CALL_ARGS_SPLAT) && dup_rest != initial_dup_rest) {
6508  *flag |= VM_CALL_ARGS_SPLAT_MUT;
6509  }
6510 }
6511 
6512 static bool
6513 setup_args_dup_rest_p(const NODE *argn)
6514 {
6515  switch(nd_type(argn)) {
6516  case NODE_LVAR:
6517  case NODE_DVAR:
6518  case NODE_GVAR:
6519  case NODE_IVAR:
6520  case NODE_CVAR:
6521  case NODE_CONST:
6522  case NODE_COLON3:
6523  case NODE_INTEGER:
6524  case NODE_FLOAT:
6525  case NODE_RATIONAL:
6526  case NODE_IMAGINARY:
6527  case NODE_STR:
6528  case NODE_SYM:
6529  case NODE_REGX:
6530  case NODE_SELF:
6531  case NODE_NIL:
6532  case NODE_TRUE:
6533  case NODE_FALSE:
6534  case NODE_LAMBDA:
6535  case NODE_NTH_REF:
6536  case NODE_BACK_REF:
6537  return false;
6538  case NODE_COLON2:
6539  return setup_args_dup_rest_p(RNODE_COLON2(argn)->nd_head);
6540  default:
6541  return true;
6542  }
6543 }
6544 
6545 static VALUE
6546 setup_args(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
6547  unsigned int *flag, struct rb_callinfo_kwarg **keywords)
6548 {
6549  VALUE ret;
6550  unsigned int dup_rest = SPLATARRAY_TRUE, initial_dup_rest;
6551 
6552  if (argn) {
6553  const NODE *check_arg = nd_type_p(argn, NODE_BLOCK_PASS) ?
6554  RNODE_BLOCK_PASS(argn)->nd_head : argn;
6555 
6556  if (check_arg) {
6557  switch(nd_type(check_arg)) {
6558  case(NODE_SPLAT):
6559  // avoid caller side array allocation for f(*arg)
6560  dup_rest = SPLATARRAY_FALSE;
6561  break;
6562  case(NODE_ARGSCAT):
6563  // avoid caller side array allocation for f(1, *arg)
6564  dup_rest = !nd_type_p(RNODE_ARGSCAT(check_arg)->nd_head, NODE_LIST);
6565  break;
6566  case(NODE_ARGSPUSH):
6567  // avoid caller side array allocation for f(*arg, **hash) and f(1, *arg, **hash)
6568  dup_rest = !((nd_type_p(RNODE_ARGSPUSH(check_arg)->nd_head, NODE_SPLAT) ||
6569  (nd_type_p(RNODE_ARGSPUSH(check_arg)->nd_head, NODE_ARGSCAT) &&
6570  nd_type_p(RNODE_ARGSCAT(RNODE_ARGSPUSH(check_arg)->nd_head)->nd_head, NODE_LIST))) &&
6571  nd_type_p(RNODE_ARGSPUSH(check_arg)->nd_body, NODE_HASH) &&
6572  !RNODE_HASH(RNODE_ARGSPUSH(check_arg)->nd_body)->nd_brace);
6573 
6574  if (dup_rest == SPLATARRAY_FALSE) {
6575  // require allocation for keyword key/value/splat that may modify splatted argument
6576  NODE *node = RNODE_HASH(RNODE_ARGSPUSH(check_arg)->nd_body)->nd_head;
6577  while (node) {
6578  NODE *key_node = RNODE_LIST(node)->nd_head;
6579  if (key_node && setup_args_dup_rest_p(key_node)) {
6580  dup_rest = SPLATARRAY_TRUE;
6581  break;
6582  }
6583 
6584  node = RNODE_LIST(node)->nd_next;
6585  NODE *value_node = RNODE_LIST(node)->nd_head;
6586  if (setup_args_dup_rest_p(value_node)) {
6587  dup_rest = SPLATARRAY_TRUE;
6588  break;
6589  }
6590 
6591  node = RNODE_LIST(node)->nd_next;
6592  }
6593  }
6594  break;
6595  default:
6596  break;
6597  }
6598  }
6599 
6600  if (check_arg != argn && setup_args_dup_rest_p(RNODE_BLOCK_PASS(argn)->nd_body)) {
6601  // for block pass that may modify splatted argument, dup rest and kwrest if given
6602  dup_rest = SPLATARRAY_TRUE | DUP_SINGLE_KW_SPLAT;
6603  }
6604  }
6605  initial_dup_rest = dup_rest;
6606 
6607  if (argn && nd_type_p(argn, NODE_BLOCK_PASS)) {
6608  DECL_ANCHOR(arg_block);
6609  INIT_ANCHOR(arg_block);
6610 
6611  if (RNODE_BLOCK_PASS(argn)->forwarding && ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->param.flags.forwardable) {
6612  int idx = ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->local_table_size;// - get_local_var_idx(iseq, idDot3);
6613 
6614  RUBY_ASSERT(nd_type_p(RNODE_BLOCK_PASS(argn)->nd_head, NODE_ARGSPUSH));
6615  const NODE * arg_node =
6616  RNODE_ARGSPUSH(RNODE_BLOCK_PASS(argn)->nd_head)->nd_head;
6617 
6618  int argc = 0;
6619 
6620  // Only compile leading args:
6621  // foo(x, y, ...)
6622  // ^^^^
6623  if (nd_type_p(arg_node, NODE_ARGSCAT)) {
6624  argc += setup_args_core(iseq, args, RNODE_ARGSCAT(arg_node)->nd_head, &dup_rest, flag, keywords);
6625  }
6626 
6627  *flag |= VM_CALL_FORWARDING;
6628 
6629  ADD_GETLOCAL(args, argn, idx, get_lvar_level(iseq));
6630  setup_args_splat_mut(flag, dup_rest, initial_dup_rest);
6631  return INT2FIX(argc);
6632  }
6633  else {
6634  *flag |= VM_CALL_ARGS_BLOCKARG;
6635 
6636  NO_CHECK(COMPILE(arg_block, "block", RNODE_BLOCK_PASS(argn)->nd_body));
6637  }
6638 
6639  if (LIST_INSN_SIZE_ONE(arg_block)) {
6640  LINK_ELEMENT *elem = FIRST_ELEMENT(arg_block);
6641  if (IS_INSN(elem)) {
6642  INSN *iobj = (INSN *)elem;
6643  if (iobj->insn_id == BIN(getblockparam)) {
6644  iobj->insn_id = BIN(getblockparamproxy);
6645  }
6646  }
6647  }
6648  ret = INT2FIX(setup_args_core(iseq, args, RNODE_BLOCK_PASS(argn)->nd_head, &dup_rest, flag, keywords));
6649  ADD_SEQ(args, arg_block);
6650  }
6651  else {
6652  ret = INT2FIX(setup_args_core(iseq, args, argn, &dup_rest, flag, keywords));
6653  }
6654  setup_args_splat_mut(flag, dup_rest, initial_dup_rest);
6655  return ret;
6656 }
6657 
6658 static void
6659 build_postexe_iseq(rb_iseq_t *iseq, LINK_ANCHOR *ret, const void *ptr)
6660 {
6661  const NODE *body = ptr;
6662  int line = nd_line(body);
6663  VALUE argc = INT2FIX(0);
6664  const rb_iseq_t *block = NEW_CHILD_ISEQ(body, make_name_for_block(ISEQ_BODY(iseq)->parent_iseq), ISEQ_TYPE_BLOCK, line);
6665 
6666  ADD_INSN1(ret, body, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
6667  ADD_CALL_WITH_BLOCK(ret, body, id_core_set_postexe, argc, block);
6668  RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block);
6669  iseq_set_local_table(iseq, 0, 0);
6670 }
6671 
6672 static void
6673 compile_named_capture_assign(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node)
6674 {
6675  const NODE *vars;
6676  LINK_ELEMENT *last;
6677  int line = nd_line(node);
6678  const NODE *line_node = node;
6679  LABEL *fail_label = NEW_LABEL(line), *end_label = NEW_LABEL(line);
6680 
6681 #if !(defined(NAMED_CAPTURE_BY_SVAR) && NAMED_CAPTURE_BY_SVAR-0)
6682  ADD_INSN1(ret, line_node, getglobal, ID2SYM(idBACKREF));
6683 #else
6684  ADD_INSN2(ret, line_node, getspecial, INT2FIX(1) /* '~' */, INT2FIX(0));
6685 #endif
6686  ADD_INSN(ret, line_node, dup);
6687  ADD_INSNL(ret, line_node, branchunless, fail_label);
6688 
6689  for (vars = node; vars; vars = RNODE_BLOCK(vars)->nd_next) {
6690  INSN *cap;
6691  if (RNODE_BLOCK(vars)->nd_next) {
6692  ADD_INSN(ret, line_node, dup);
6693  }
6694  last = ret->last;
6695  NO_CHECK(COMPILE_POPPED(ret, "capture", RNODE_BLOCK(vars)->nd_head));
6696  last = last->next; /* putobject :var */
6697  cap = new_insn_send(iseq, nd_line(line_node), nd_node_id(line_node), idAREF, INT2FIX(1),
6698  NULL, INT2FIX(0), NULL);
6699  ELEM_INSERT_PREV(last->next, (LINK_ELEMENT *)cap);
6700 #if !defined(NAMED_CAPTURE_SINGLE_OPT) || NAMED_CAPTURE_SINGLE_OPT-0
6701  if (!RNODE_BLOCK(vars)->nd_next && vars == node) {
6702  /* only one name */
6703  DECL_ANCHOR(nom);
6704 
6705  INIT_ANCHOR(nom);
6706  ADD_INSNL(nom, line_node, jump, end_label);
6707  ADD_LABEL(nom, fail_label);
6708 # if 0 /* $~ must be MatchData or nil */
6709  ADD_INSN(nom, line_node, pop);
6710  ADD_INSN(nom, line_node, putnil);
6711 # endif
6712  ADD_LABEL(nom, end_label);
6713  (nom->last->next = cap->link.next)->prev = nom->last;
6714  (cap->link.next = nom->anchor.next)->prev = &cap->link;
6715  return;
6716  }
6717 #endif
6718  }
6719  ADD_INSNL(ret, line_node, jump, end_label);
6720  ADD_LABEL(ret, fail_label);
6721  ADD_INSN(ret, line_node, pop);
6722  for (vars = node; vars; vars = RNODE_BLOCK(vars)->nd_next) {
6723  last = ret->last;
6724  NO_CHECK(COMPILE_POPPED(ret, "capture", RNODE_BLOCK(vars)->nd_head));
6725  last = last->next; /* putobject :var */
6726  ((INSN*)last)->insn_id = BIN(putnil);
6727  ((INSN*)last)->operand_size = 0;
6728  }
6729  ADD_LABEL(ret, end_label);
6730 }
6731 
6732 static int
6733 optimizable_range_item_p(const NODE *n)
6734 {
6735  if (!n) return FALSE;
6736  switch (nd_type(n)) {
6737  case NODE_LINE:
6738  return TRUE;
6739  case NODE_INTEGER:
6740  return TRUE;
6741  case NODE_NIL:
6742  return TRUE;
6743  default:
6744  return FALSE;
6745  }
6746 }
6747 
6748 static VALUE
6749 optimized_range_item(const NODE *n)
6750 {
6751  switch (nd_type(n)) {
6752  case NODE_LINE:
6753  return rb_node_line_lineno_val(n);
6754  case NODE_INTEGER:
6755  return rb_node_integer_literal_val(n);
6756  case NODE_FLOAT:
6757  return rb_node_float_literal_val(n);
6758  case NODE_RATIONAL:
6759  return rb_node_rational_literal_val(n);
6760  case NODE_IMAGINARY:
6761  return rb_node_imaginary_literal_val(n);
6762  case NODE_NIL:
6763  return Qnil;
6764  default:
6765  rb_bug("unexpected node: %s", ruby_node_name(nd_type(n)));
6766  }
6767 }
6768 
6769 static int
6770 compile_if(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
6771 {
6772  const NODE *const node_body = type == NODE_IF ? RNODE_IF(node)->nd_body : RNODE_UNLESS(node)->nd_else;
6773  const NODE *const node_else = type == NODE_IF ? RNODE_IF(node)->nd_else : RNODE_UNLESS(node)->nd_body;
6774 
6775  const int line = nd_line(node);
6776  const NODE *line_node = node;
6777  DECL_ANCHOR(cond_seq);
6778  LABEL *then_label, *else_label, *end_label;
6779  VALUE branches = Qfalse;
6780 
6781  INIT_ANCHOR(cond_seq);
6782  then_label = NEW_LABEL(line);
6783  else_label = NEW_LABEL(line);
6784  end_label = 0;
6785 
6786  NODE *cond = RNODE_IF(node)->nd_cond;
6787  if (nd_type(cond) == NODE_BLOCK) {
6788  cond = RNODE_BLOCK(cond)->nd_head;
6789  }
6790 
6791  CHECK(compile_branch_condition(iseq, cond_seq, cond, then_label, else_label));
6792  ADD_SEQ(ret, cond_seq);
6793 
6794  if (then_label->refcnt && else_label->refcnt) {
6795  branches = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), type == NODE_IF ? "if" : "unless");
6796  }
6797 
6798  if (then_label->refcnt) {
6799  ADD_LABEL(ret, then_label);
6800 
6801  DECL_ANCHOR(then_seq);
6802  INIT_ANCHOR(then_seq);
6803  CHECK(COMPILE_(then_seq, "then", node_body, popped));
6804 
6805  if (else_label->refcnt) {
6806  const NODE *const coverage_node = node_body ? node_body : node;
6807  add_trace_branch_coverage(
6808  iseq,
6809  ret,
6810  nd_code_loc(coverage_node),
6811  nd_node_id(coverage_node),
6812  0,
6813  type == NODE_IF ? "then" : "else",
6814  branches);
6815  end_label = NEW_LABEL(line);
6816  ADD_INSNL(then_seq, line_node, jump, end_label);
6817  if (!popped) {
6818  ADD_INSN(then_seq, line_node, pop);
6819  }
6820  }
6821  ADD_SEQ(ret, then_seq);
6822  }
6823 
6824  if (else_label->refcnt) {
6825  ADD_LABEL(ret, else_label);
6826 
6827  DECL_ANCHOR(else_seq);
6828  INIT_ANCHOR(else_seq);
6829  CHECK(COMPILE_(else_seq, "else", node_else, popped));
6830 
6831  if (then_label->refcnt) {
6832  const NODE *const coverage_node = node_else ? node_else : node;
6833  add_trace_branch_coverage(
6834  iseq,
6835  ret,
6836  nd_code_loc(coverage_node),
6837  nd_node_id(coverage_node),
6838  1,
6839  type == NODE_IF ? "else" : "then",
6840  branches);
6841  }
6842  ADD_SEQ(ret, else_seq);
6843  }
6844 
6845  if (end_label) {
6846  ADD_LABEL(ret, end_label);
6847  }
6848 
6849  return COMPILE_OK;
6850 }
6851 
6852 static int
6853 compile_case(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
6854 {
6855  const NODE *vals;
6856  const NODE *node = orig_node;
6857  LABEL *endlabel, *elselabel;
6858  DECL_ANCHOR(head);
6859  DECL_ANCHOR(body_seq);
6860  DECL_ANCHOR(cond_seq);
6861  int only_special_literals = 1;
6862  VALUE literals = rb_hash_new();
6863  int line;
6864  enum node_type type;
6865  const NODE *line_node;
6866  VALUE branches = Qfalse;
6867  int branch_id = 0;
6868 
6869  INIT_ANCHOR(head);
6870  INIT_ANCHOR(body_seq);
6871  INIT_ANCHOR(cond_seq);
6872 
6873  RHASH_TBL_RAW(literals)->type = &cdhash_type;
6874 
6875  CHECK(COMPILE(head, "case base", RNODE_CASE(node)->nd_head));
6876 
6877  branches = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), "case");
6878 
6879  node = RNODE_CASE(node)->nd_body;
6880  EXPECT_NODE("NODE_CASE", node, NODE_WHEN, COMPILE_NG);
6881  type = nd_type(node);
6882  line = nd_line(node);
6883  line_node = node;
6884 
6885  endlabel = NEW_LABEL(line);
6886  elselabel = NEW_LABEL(line);
6887 
6888  ADD_SEQ(ret, head); /* case VAL */
6889 
6890  while (type == NODE_WHEN) {
6891  LABEL *l1;
6892 
6893  l1 = NEW_LABEL(line);
6894  ADD_LABEL(body_seq, l1);
6895  ADD_INSN(body_seq, line_node, pop);
6896 
6897  const NODE *const coverage_node = RNODE_WHEN(node)->nd_body ? RNODE_WHEN(node)->nd_body : node;
6898  add_trace_branch_coverage(
6899  iseq,
6900  body_seq,
6901  nd_code_loc(coverage_node),
6902  nd_node_id(coverage_node),
6903  branch_id++,
6904  "when",
6905  branches);
6906 
6907  CHECK(COMPILE_(body_seq, "when body", RNODE_WHEN(node)->nd_body, popped));
6908  ADD_INSNL(body_seq, line_node, jump, endlabel);
6909 
6910  vals = RNODE_WHEN(node)->nd_head;
6911  if (vals) {
6912  switch (nd_type(vals)) {
6913  case NODE_LIST:
6914  only_special_literals = when_vals(iseq, cond_seq, vals, l1, only_special_literals, literals);
6915  if (only_special_literals < 0) return COMPILE_NG;
6916  break;
6917  case NODE_SPLAT:
6918  case NODE_ARGSCAT:
6919  case NODE_ARGSPUSH:
6920  only_special_literals = 0;
6921  CHECK(when_splat_vals(iseq, cond_seq, vals, l1, only_special_literals, literals));
6922  break;
6923  default:
6924  UNKNOWN_NODE("NODE_CASE", vals, COMPILE_NG);
6925  }
6926  }
6927  else {
6928  EXPECT_NODE_NONULL("NODE_CASE", node, NODE_LIST, COMPILE_NG);
6929  }
6930 
6931  node = RNODE_WHEN(node)->nd_next;
6932  if (!node) {
6933  break;
6934  }
6935  type = nd_type(node);
6936  line = nd_line(node);
6937  line_node = node;
6938  }
6939  /* else */
6940  if (node) {
6941  ADD_LABEL(cond_seq, elselabel);
6942  ADD_INSN(cond_seq, line_node, pop);
6943  add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(node), nd_node_id(node), branch_id, "else", branches);
6944  CHECK(COMPILE_(cond_seq, "else", node, popped));
6945  ADD_INSNL(cond_seq, line_node, jump, endlabel);
6946  }
6947  else {
6948  debugs("== else (implicit)\n");
6949  ADD_LABEL(cond_seq, elselabel);
6950  ADD_INSN(cond_seq, orig_node, pop);
6951  add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(orig_node), nd_node_id(orig_node), branch_id, "else", branches);
6952  if (!popped) {
6953  ADD_INSN(cond_seq, orig_node, putnil);
6954  }
6955  ADD_INSNL(cond_seq, orig_node, jump, endlabel);
6956  }
6957 
6958  if (only_special_literals && ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
6959  ADD_INSN(ret, orig_node, dup);
6960  ADD_INSN2(ret, orig_node, opt_case_dispatch, literals, elselabel);
6961  RB_OBJ_WRITTEN(iseq, Qundef, literals);
6962  LABEL_REF(elselabel);
6963  }
6964 
6965  ADD_SEQ(ret, cond_seq);
6966  ADD_SEQ(ret, body_seq);
6967  ADD_LABEL(ret, endlabel);
6968  return COMPILE_OK;
6969 }
6970 
6971 static int
6972 compile_case2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
6973 {
6974  const NODE *vals;
6975  const NODE *val;
6976  const NODE *node = RNODE_CASE2(orig_node)->nd_body;
6977  LABEL *endlabel;
6978  DECL_ANCHOR(body_seq);
6979  VALUE branches = Qfalse;
6980  int branch_id = 0;
6981 
6982  branches = decl_branch_base(iseq, PTR2NUM(orig_node), nd_code_loc(orig_node), "case");
6983 
6984  INIT_ANCHOR(body_seq);
6985  endlabel = NEW_LABEL(nd_line(node));
6986 
6987  while (node && nd_type_p(node, NODE_WHEN)) {
6988  const int line = nd_line(node);
6989  LABEL *l1 = NEW_LABEL(line);
6990  ADD_LABEL(body_seq, l1);
6991 
6992  const NODE *const coverage_node = RNODE_WHEN(node)->nd_body ? RNODE_WHEN(node)->nd_body : node;
6993  add_trace_branch_coverage(
6994  iseq,
6995  body_seq,
6996  nd_code_loc(coverage_node),
6997  nd_node_id(coverage_node),
6998  branch_id++,
6999  "when",
7000  branches);
7001 
7002  CHECK(COMPILE_(body_seq, "when", RNODE_WHEN(node)->nd_body, popped));
7003  ADD_INSNL(body_seq, node, jump, endlabel);
7004 
7005  vals = RNODE_WHEN(node)->nd_head;
7006  if (!vals) {
7007  EXPECT_NODE_NONULL("NODE_WHEN", node, NODE_LIST, COMPILE_NG);
7008  }
7009  switch (nd_type(vals)) {
7010  case NODE_LIST:
7011  while (vals) {
7012  LABEL *lnext;
7013  val = RNODE_LIST(vals)->nd_head;
7014  lnext = NEW_LABEL(nd_line(val));
7015  debug_compile("== when2\n", (void)0);
7016  CHECK(compile_branch_condition(iseq, ret, val, l1, lnext));
7017  ADD_LABEL(ret, lnext);
7018  vals = RNODE_LIST(vals)->nd_next;
7019  }
7020  break;
7021  case NODE_SPLAT:
7022  case NODE_ARGSCAT:
7023  case NODE_ARGSPUSH:
7024  ADD_INSN(ret, vals, putnil);
7025  CHECK(COMPILE(ret, "when2/cond splat", vals));
7026  ADD_INSN1(ret, vals, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_WHEN | VM_CHECKMATCH_ARRAY));
7027  ADD_INSNL(ret, vals, branchif, l1);
7028  break;
7029  default:
7030  UNKNOWN_NODE("NODE_WHEN", vals, COMPILE_NG);
7031  }
7032  node = RNODE_WHEN(node)->nd_next;
7033  }
7034  /* else */
7035  const NODE *const coverage_node = node ? node : orig_node;
7036  add_trace_branch_coverage(
7037  iseq,
7038  ret,
7039  nd_code_loc(coverage_node),
7040  nd_node_id(coverage_node),
7041  branch_id,
7042  "else",
7043  branches);
7044  CHECK(COMPILE_(ret, "else", node, popped));
7045  ADD_INSNL(ret, orig_node, jump, endlabel);
7046 
7047  ADD_SEQ(ret, body_seq);
7048  ADD_LABEL(ret, endlabel);
7049  return COMPILE_OK;
7050 }
7051 
7052 static int iseq_compile_pattern_match(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, LABEL *unmatched, bool in_single_pattern, bool in_alt_pattern, int base_index, bool use_deconstructed_cache);
7053 
7054 static int iseq_compile_pattern_constant(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, LABEL *match_failed, bool in_single_pattern, int base_index);
7055 static int iseq_compile_array_deconstruct(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, LABEL *deconstruct, LABEL *deconstructed, LABEL *match_failed, LABEL *type_error, bool in_single_pattern, int base_index, bool use_deconstructed_cache);
7056 static int iseq_compile_pattern_set_general_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE errmsg, int base_index);
7057 static int iseq_compile_pattern_set_length_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE errmsg, VALUE pattern_length, int base_index);
7058 static int iseq_compile_pattern_set_eqq_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int base_index);
7059 
7060 #define CASE3_BI_OFFSET_DECONSTRUCTED_CACHE 0
7061 #define CASE3_BI_OFFSET_ERROR_STRING 1
7062 #define CASE3_BI_OFFSET_KEY_ERROR_P 2
7063 #define CASE3_BI_OFFSET_KEY_ERROR_MATCHEE 3
7064 #define CASE3_BI_OFFSET_KEY_ERROR_KEY 4
7065 
7066 static int
7067 iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, LABEL *matched, LABEL *unmatched, bool in_single_pattern, bool in_alt_pattern, int base_index, bool use_deconstructed_cache)
7068 {
7069  const int line = nd_line(node);
7070  const NODE *line_node = node;
7071 
7072  switch (nd_type(node)) {
7073  case NODE_ARYPTN: {
7074  /*
7075  * if pattern.use_rest_num?
7076  * rest_num = 0
7077  * end
7078  * if pattern.has_constant_node?
7079  * unless pattern.constant === obj
7080  * goto match_failed
7081  * end
7082  * end
7083  * unless obj.respond_to?(:deconstruct)
7084  * goto match_failed
7085  * end
7086  * d = obj.deconstruct
7087  * unless Array === d
7088  * goto type_error
7089  * end
7090  * min_argc = pattern.pre_args_num + pattern.post_args_num
7091  * if pattern.has_rest_arg?
7092  * unless d.length >= min_argc
7093  * goto match_failed
7094  * end
7095  * else
7096  * unless d.length == min_argc
7097  * goto match_failed
7098  * end
7099  * end
7100  * pattern.pre_args_num.each do |i|
7101  * unless pattern.pre_args[i].match?(d[i])
7102  * goto match_failed
7103  * end
7104  * end
7105  * if pattern.use_rest_num?
7106  * rest_num = d.length - min_argc
7107  * if pattern.has_rest_arg? && pattern.has_rest_arg_id # not `*`, but `*rest`
7108  * unless pattern.rest_arg.match?(d[pattern.pre_args_num, rest_num])
7109  * goto match_failed
7110  * end
7111  * end
7112  * end
7113  * pattern.post_args_num.each do |i|
7114  * j = pattern.pre_args_num + i
7115  * j += rest_num
7116  * unless pattern.post_args[i].match?(d[j])
7117  * goto match_failed
7118  * end
7119  * end
7120  * goto matched
7121  * type_error:
7122  * FrozenCore.raise TypeError
7123  * match_failed:
7124  * goto unmatched
7125  */
7126  const NODE *args = RNODE_ARYPTN(node)->pre_args;
7127  const int pre_args_num = RNODE_ARYPTN(node)->pre_args ? rb_long2int(RNODE_LIST(RNODE_ARYPTN(node)->pre_args)->as.nd_alen) : 0;
7128  const int post_args_num = RNODE_ARYPTN(node)->post_args ? rb_long2int(RNODE_LIST(RNODE_ARYPTN(node)->post_args)->as.nd_alen) : 0;
7129 
7130  const int min_argc = pre_args_num + post_args_num;
7131  const int use_rest_num = RNODE_ARYPTN(node)->rest_arg && (NODE_NAMED_REST_P(RNODE_ARYPTN(node)->rest_arg) ||
7132  (!NODE_NAMED_REST_P(RNODE_ARYPTN(node)->rest_arg) && post_args_num > 0));
7133 
7134  LABEL *match_failed, *type_error, *deconstruct, *deconstructed;
7135  int i;
7136  match_failed = NEW_LABEL(line);
7137  type_error = NEW_LABEL(line);
7138  deconstruct = NEW_LABEL(line);
7139  deconstructed = NEW_LABEL(line);
7140 
7141  if (use_rest_num) {
7142  ADD_INSN1(ret, line_node, putobject, INT2FIX(0)); /* allocate stack for rest_num */
7143  ADD_INSN(ret, line_node, swap);
7144  if (base_index) {
7145  base_index++;
7146  }
7147  }
7148 
7149  CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
7150 
7151  CHECK(iseq_compile_array_deconstruct(iseq, ret, node, deconstruct, deconstructed, match_failed, type_error, in_single_pattern, base_index, use_deconstructed_cache));
7152 
7153  ADD_INSN(ret, line_node, dup);
7154  ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7155  ADD_INSN1(ret, line_node, putobject, INT2FIX(min_argc));
7156  ADD_SEND(ret, line_node, RNODE_ARYPTN(node)->rest_arg ? idGE : idEq, INT2FIX(1)); // (1)
7157  if (in_single_pattern) {
7158  CHECK(iseq_compile_pattern_set_length_errmsg(iseq, ret, node,
7159  RNODE_ARYPTN(node)->rest_arg ? rb_fstring_lit("%p length mismatch (given %p, expected %p+)") :
7160  rb_fstring_lit("%p length mismatch (given %p, expected %p)"),
7161  INT2FIX(min_argc), base_index + 1 /* (1) */));
7162  }
7163  ADD_INSNL(ret, line_node, branchunless, match_failed);
7164 
7165  for (i = 0; i < pre_args_num; i++) {
7166  ADD_INSN(ret, line_node, dup);
7167  ADD_INSN1(ret, line_node, putobject, INT2FIX(i));
7168  ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (2)
7169  CHECK(iseq_compile_pattern_match(iseq, ret, RNODE_LIST(args)->nd_head, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 /* (2) */, false));
7170  args = RNODE_LIST(args)->nd_next;
7171  }
7172 
7173  if (RNODE_ARYPTN(node)->rest_arg) {
7174  if (NODE_NAMED_REST_P(RNODE_ARYPTN(node)->rest_arg)) {
7175  ADD_INSN(ret, line_node, dup);
7176  ADD_INSN1(ret, line_node, putobject, INT2FIX(pre_args_num));
7177  ADD_INSN1(ret, line_node, topn, INT2FIX(1));
7178  ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7179  ADD_INSN1(ret, line_node, putobject, INT2FIX(min_argc));
7180  ADD_SEND(ret, line_node, idMINUS, INT2FIX(1));
7181  ADD_INSN1(ret, line_node, setn, INT2FIX(4));
7182  ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (3)
7183 
7184  CHECK(iseq_compile_pattern_match(iseq, ret, RNODE_ARYPTN(node)->rest_arg, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 /* (3) */, false));
7185  }
7186  else {
7187  if (post_args_num > 0) {
7188  ADD_INSN(ret, line_node, dup);
7189  ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7190  ADD_INSN1(ret, line_node, putobject, INT2FIX(min_argc));
7191  ADD_SEND(ret, line_node, idMINUS, INT2FIX(1));
7192  ADD_INSN1(ret, line_node, setn, INT2FIX(2));
7193  ADD_INSN(ret, line_node, pop);
7194  }
7195  }
7196  }
7197 
7198  args = RNODE_ARYPTN(node)->post_args;
7199  for (i = 0; i < post_args_num; i++) {
7200  ADD_INSN(ret, line_node, dup);
7201 
7202  ADD_INSN1(ret, line_node, putobject, INT2FIX(pre_args_num + i));
7203  ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7204  ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
7205 
7206  ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (4)
7207  CHECK(iseq_compile_pattern_match(iseq, ret, RNODE_LIST(args)->nd_head, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 /* (4) */, false));
7208  args = RNODE_LIST(args)->nd_next;
7209  }
7210 
7211  ADD_INSN(ret, line_node, pop);
7212  if (use_rest_num) {
7213  ADD_INSN(ret, line_node, pop);
7214  }
7215  ADD_INSNL(ret, line_node, jump, matched);
7216  ADD_INSN(ret, line_node, putnil);
7217  if (use_rest_num) {
7218  ADD_INSN(ret, line_node, putnil);
7219  }
7220 
7221  ADD_LABEL(ret, type_error);
7222  ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7223  ADD_INSN1(ret, line_node, putobject, rb_eTypeError);
7224  ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("deconstruct must return Array"));
7225  ADD_SEND(ret, line_node, id_core_raise, INT2FIX(2));
7226  ADD_INSN(ret, line_node, pop);
7227 
7228  ADD_LABEL(ret, match_failed);
7229  ADD_INSN(ret, line_node, pop);
7230  if (use_rest_num) {
7231  ADD_INSN(ret, line_node, pop);
7232  }
7233  ADD_INSNL(ret, line_node, jump, unmatched);
7234 
7235  break;
7236  }
7237  case NODE_FNDPTN: {
7238  /*
7239  * if pattern.has_constant_node?
7240  * unless pattern.constant === obj
7241  * goto match_failed
7242  * end
7243  * end
7244  * unless obj.respond_to?(:deconstruct)
7245  * goto match_failed
7246  * end
7247  * d = obj.deconstruct
7248  * unless Array === d
7249  * goto type_error
7250  * end
7251  * unless d.length >= pattern.args_num
7252  * goto match_failed
7253  * end
7254  *
7255  * begin
7256  * len = d.length
7257  * limit = d.length - pattern.args_num
7258  * i = 0
7259  * while i <= limit
7260  * if pattern.args_num.times.all? {|j| pattern.args[j].match?(d[i+j]) }
7261  * if pattern.has_pre_rest_arg_id
7262  * unless pattern.pre_rest_arg.match?(d[0, i])
7263  * goto find_failed
7264  * end
7265  * end
7266  * if pattern.has_post_rest_arg_id
7267  * unless pattern.post_rest_arg.match?(d[i+pattern.args_num, len])
7268  * goto find_failed
7269  * end
7270  * end
7271  * goto find_succeeded
7272  * end
7273  * i+=1
7274  * end
7275  * find_failed:
7276  * goto match_failed
7277  * find_succeeded:
7278  * end
7279  *
7280  * goto matched
7281  * type_error:
7282  * FrozenCore.raise TypeError
7283  * match_failed:
7284  * goto unmatched
7285  */
7286  const NODE *args = RNODE_FNDPTN(node)->args;
7287  const int args_num = RNODE_FNDPTN(node)->args ? rb_long2int(RNODE_LIST(RNODE_FNDPTN(node)->args)->as.nd_alen) : 0;
7288 
7289  LABEL *match_failed, *type_error, *deconstruct, *deconstructed;
7290  match_failed = NEW_LABEL(line);
7291  type_error = NEW_LABEL(line);
7292  deconstruct = NEW_LABEL(line);
7293  deconstructed = NEW_LABEL(line);
7294 
7295  CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
7296 
7297  CHECK(iseq_compile_array_deconstruct(iseq, ret, node, deconstruct, deconstructed, match_failed, type_error, in_single_pattern, base_index, use_deconstructed_cache));
7298 
7299  ADD_INSN(ret, line_node, dup);
7300  ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7301  ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num));
7302  ADD_SEND(ret, line_node, idGE, INT2FIX(1)); // (1)
7303  if (in_single_pattern) {
7304  CHECK(iseq_compile_pattern_set_length_errmsg(iseq, ret, node, rb_fstring_lit("%p length mismatch (given %p, expected %p+)"), INT2FIX(args_num), base_index + 1 /* (1) */));
7305  }
7306  ADD_INSNL(ret, line_node, branchunless, match_failed);
7307 
7308  {
7309  LABEL *while_begin = NEW_LABEL(nd_line(node));
7310  LABEL *next_loop = NEW_LABEL(nd_line(node));
7311  LABEL *find_succeeded = NEW_LABEL(line);
7312  LABEL *find_failed = NEW_LABEL(nd_line(node));
7313  int j;
7314 
7315  ADD_INSN(ret, line_node, dup); /* allocate stack for len */
7316  ADD_SEND(ret, line_node, idLength, INT2FIX(0)); // (2)
7317 
7318  ADD_INSN(ret, line_node, dup); /* allocate stack for limit */
7319  ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num));
7320  ADD_SEND(ret, line_node, idMINUS, INT2FIX(1)); // (3)
7321 
7322  ADD_INSN1(ret, line_node, putobject, INT2FIX(0)); /* allocate stack for i */ // (4)
7323 
7324  ADD_LABEL(ret, while_begin);
7325 
7326  ADD_INSN(ret, line_node, dup);
7327  ADD_INSN1(ret, line_node, topn, INT2FIX(2));
7328  ADD_SEND(ret, line_node, idLE, INT2FIX(1));
7329  ADD_INSNL(ret, line_node, branchunless, find_failed);
7330 
7331  for (j = 0; j < args_num; j++) {
7332  ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7333  ADD_INSN1(ret, line_node, topn, INT2FIX(1));
7334  if (j != 0) {
7335  ADD_INSN1(ret, line_node, putobject, INT2FIX(j));
7336  ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
7337  }
7338  ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (5)
7339 
7340  CHECK(iseq_compile_pattern_match(iseq, ret, RNODE_LIST(args)->nd_head, next_loop, in_single_pattern, in_alt_pattern, base_index + 4 /* (2), (3), (4), (5) */, false));
7341  args = RNODE_LIST(args)->nd_next;
7342  }
7343 
7344  if (NODE_NAMED_REST_P(RNODE_FNDPTN(node)->pre_rest_arg)) {
7345  ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7346  ADD_INSN1(ret, line_node, putobject, INT2FIX(0));
7347  ADD_INSN1(ret, line_node, topn, INT2FIX(2));
7348  ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (6)
7349  CHECK(iseq_compile_pattern_match(iseq, ret, RNODE_FNDPTN(node)->pre_rest_arg, find_failed, in_single_pattern, in_alt_pattern, base_index + 4 /* (2), (3), (4), (6) */, false));
7350  }
7351  if (NODE_NAMED_REST_P(RNODE_FNDPTN(node)->post_rest_arg)) {
7352  ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7353  ADD_INSN1(ret, line_node, topn, INT2FIX(1));
7354  ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num));
7355  ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
7356  ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7357  ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (7)
7358  CHECK(iseq_compile_pattern_match(iseq, ret, RNODE_FNDPTN(node)->post_rest_arg, find_failed, in_single_pattern, in_alt_pattern, base_index + 4 /* (2), (3),(4), (7) */, false));
7359  }
7360  ADD_INSNL(ret, line_node, jump, find_succeeded);
7361 
7362  ADD_LABEL(ret, next_loop);
7363  ADD_INSN1(ret, line_node, putobject, INT2FIX(1));
7364  ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
7365  ADD_INSNL(ret, line_node, jump, while_begin);
7366 
7367  ADD_LABEL(ret, find_failed);
7368  ADD_INSN1(ret, line_node, adjuststack, INT2FIX(3));
7369  if (in_single_pattern) {
7370  ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7371  ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("%p does not match to find pattern"));
7372  ADD_INSN1(ret, line_node, topn, INT2FIX(2));
7373  ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(2)); // (8)
7374  ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (8) */)); // (9)
7375 
7376  ADD_INSN1(ret, line_node, putobject, Qfalse);
7377  ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (8), (9) */));
7378 
7379  ADD_INSN(ret, line_node, pop);
7380  ADD_INSN(ret, line_node, pop);
7381  }
7382  ADD_INSNL(ret, line_node, jump, match_failed);
7383  ADD_INSN1(ret, line_node, dupn, INT2FIX(3));
7384 
7385  ADD_LABEL(ret, find_succeeded);
7386  ADD_INSN1(ret, line_node, adjuststack, INT2FIX(3));
7387  }
7388 
7389  ADD_INSN(ret, line_node, pop);
7390  ADD_INSNL(ret, line_node, jump, matched);
7391  ADD_INSN(ret, line_node, putnil);
7392 
7393  ADD_LABEL(ret, type_error);
7394  ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7395  ADD_INSN1(ret, line_node, putobject, rb_eTypeError);
7396  ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("deconstruct must return Array"));
7397  ADD_SEND(ret, line_node, id_core_raise, INT2FIX(2));
7398  ADD_INSN(ret, line_node, pop);
7399 
7400  ADD_LABEL(ret, match_failed);
7401  ADD_INSN(ret, line_node, pop);
7402  ADD_INSNL(ret, line_node, jump, unmatched);
7403 
7404  break;
7405  }
7406  case NODE_HSHPTN: {
7407  /*
7408  * keys = nil
7409  * if pattern.has_kw_args_node? && !pattern.has_kw_rest_arg_node?
7410  * keys = pattern.kw_args_node.keys
7411  * end
7412  * if pattern.has_constant_node?
7413  * unless pattern.constant === obj
7414  * goto match_failed
7415  * end
7416  * end
7417  * unless obj.respond_to?(:deconstruct_keys)
7418  * goto match_failed
7419  * end
7420  * d = obj.deconstruct_keys(keys)
7421  * unless Hash === d
7422  * goto type_error
7423  * end
7424  * if pattern.has_kw_rest_arg_node?
7425  * d = d.dup
7426  * end
7427  * if pattern.has_kw_args_node?
7428  * pattern.kw_args_node.each |k,|
7429  * unless d.key?(k)
7430  * goto match_failed
7431  * end
7432  * end
7433  * pattern.kw_args_node.each |k, pat|
7434  * if pattern.has_kw_rest_arg_node?
7435  * unless pat.match?(d.delete(k))
7436  * goto match_failed
7437  * end
7438  * else
7439  * unless pat.match?(d[k])
7440  * goto match_failed
7441  * end
7442  * end
7443  * end
7444  * else
7445  * unless d.empty?
7446  * goto match_failed
7447  * end
7448  * end
7449  * if pattern.has_kw_rest_arg_node?
7450  * if pattern.no_rest_keyword?
7451  * unless d.empty?
7452  * goto match_failed
7453  * end
7454  * else
7455  * unless pattern.kw_rest_arg_node.match?(d)
7456  * goto match_failed
7457  * end
7458  * end
7459  * end
7460  * goto matched
7461  * type_error:
7462  * FrozenCore.raise TypeError
7463  * match_failed:
7464  * goto unmatched
7465  */
7466  LABEL *match_failed, *type_error;
7467  VALUE keys = Qnil;
7468 
7469  match_failed = NEW_LABEL(line);
7470  type_error = NEW_LABEL(line);
7471 
7472  if (RNODE_HSHPTN(node)->nd_pkwargs && !RNODE_HSHPTN(node)->nd_pkwrestarg) {
7473  const NODE *kw_args = RNODE_HASH(RNODE_HSHPTN(node)->nd_pkwargs)->nd_head;
7474  keys = rb_ary_new_capa(kw_args ? RNODE_LIST(kw_args)->as.nd_alen/2 : 0);
7475  while (kw_args) {
7476  rb_ary_push(keys, get_symbol_value(iseq, RNODE_LIST(kw_args)->nd_head));
7477  kw_args = RNODE_LIST(RNODE_LIST(kw_args)->nd_next)->nd_next;
7478  }
7479  }
7480 
7481  CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
7482 
7483  ADD_INSN(ret, line_node, dup);
7484  ADD_INSN1(ret, line_node, putobject, ID2SYM(rb_intern("deconstruct_keys")));
7485  ADD_SEND(ret, line_node, idRespond_to, INT2FIX(1)); // (1)
7486  if (in_single_pattern) {
7487  CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("%p does not respond to #deconstruct_keys"), base_index + 1 /* (1) */));
7488  }
7489  ADD_INSNL(ret, line_node, branchunless, match_failed);
7490 
7491  if (NIL_P(keys)) {
7492  ADD_INSN(ret, line_node, putnil);
7493  }
7494  else {
7495  ADD_INSN1(ret, line_node, duparray, keys);
7496  RB_OBJ_WRITTEN(iseq, Qundef, rb_obj_hide(keys));
7497  }
7498  ADD_SEND(ret, line_node, rb_intern("deconstruct_keys"), INT2FIX(1)); // (2)
7499 
7500  ADD_INSN(ret, line_node, dup);
7501  ADD_INSN1(ret, line_node, checktype, INT2FIX(T_HASH));
7502  ADD_INSNL(ret, line_node, branchunless, type_error);
7503 
7504  if (RNODE_HSHPTN(node)->nd_pkwrestarg) {
7505  ADD_SEND(ret, line_node, rb_intern("dup"), INT2FIX(0));
7506  }
7507 
7508  if (RNODE_HSHPTN(node)->nd_pkwargs) {
7509  int i;
7510  int keys_num;
7511  const NODE *args;
7512  args = RNODE_HASH(RNODE_HSHPTN(node)->nd_pkwargs)->nd_head;
7513  if (args) {
7514  DECL_ANCHOR(match_values);
7515  INIT_ANCHOR(match_values);
7516  keys_num = rb_long2int(RNODE_LIST(args)->as.nd_alen) / 2;
7517  for (i = 0; i < keys_num; i++) {
7518  NODE *key_node = RNODE_LIST(args)->nd_head;
7519  NODE *value_node = RNODE_LIST(RNODE_LIST(args)->nd_next)->nd_head;
7520  VALUE key = get_symbol_value(iseq, key_node);
7521 
7522  ADD_INSN(ret, line_node, dup);
7523  ADD_INSN1(ret, line_node, putobject, key);
7524  ADD_SEND(ret, line_node, rb_intern("key?"), INT2FIX(1)); // (3)
7525  if (in_single_pattern) {
7526  LABEL *match_succeeded;
7527  match_succeeded = NEW_LABEL(line);
7528 
7529  ADD_INSN(ret, line_node, dup);
7530  ADD_INSNL(ret, line_node, branchif, match_succeeded);
7531 
7532  ADD_INSN1(ret, line_node, putobject, rb_str_freeze(rb_sprintf("key not found: %+"PRIsVALUE, key))); // (4)
7533  ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 2 /* (3), (4) */));
7534  ADD_INSN1(ret, line_node, putobject, Qtrue); // (5)
7535  ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 3 /* (3), (4), (5) */));
7536  ADD_INSN1(ret, line_node, topn, INT2FIX(3)); // (6)
7537  ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_MATCHEE + 4 /* (3), (4), (5), (6) */));
7538  ADD_INSN1(ret, line_node, putobject, key); // (7)
7539  ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_KEY + 5 /* (3), (4), (5), (6), (7) */));
7540 
7541  ADD_INSN1(ret, line_node, adjuststack, INT2FIX(4));
7542 
7543  ADD_LABEL(ret, match_succeeded);
7544  }
7545  ADD_INSNL(ret, line_node, branchunless, match_failed);
7546 
7547  ADD_INSN(match_values, line_node, dup);
7548  ADD_INSN1(match_values, line_node, putobject, key);
7549  ADD_SEND(match_values, line_node, RNODE_HSHPTN(node)->nd_pkwrestarg ? rb_intern("delete") : idAREF, INT2FIX(1)); // (8)
7550  CHECK(iseq_compile_pattern_match(iseq, match_values, value_node, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 /* (8) */, false));
7551  args = RNODE_LIST(RNODE_LIST(args)->nd_next)->nd_next;
7552  }
7553  ADD_SEQ(ret, match_values);
7554  }
7555  }
7556  else {
7557  ADD_INSN(ret, line_node, dup);
7558  ADD_SEND(ret, line_node, idEmptyP, INT2FIX(0)); // (9)
7559  if (in_single_pattern) {
7560  CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("%p is not empty"), base_index + 1 /* (9) */));
7561  }
7562  ADD_INSNL(ret, line_node, branchunless, match_failed);
7563  }
7564 
7565  if (RNODE_HSHPTN(node)->nd_pkwrestarg) {
7566  if (RNODE_HSHPTN(node)->nd_pkwrestarg == NODE_SPECIAL_NO_REST_KEYWORD) {
7567  ADD_INSN(ret, line_node, dup);
7568  ADD_SEND(ret, line_node, idEmptyP, INT2FIX(0)); // (10)
7569  if (in_single_pattern) {
7570  CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("rest of %p is not empty"), base_index + 1 /* (10) */));
7571  }
7572  ADD_INSNL(ret, line_node, branchunless, match_failed);
7573  }
7574  else {
7575  ADD_INSN(ret, line_node, dup); // (11)
7576  CHECK(iseq_compile_pattern_match(iseq, ret, RNODE_HSHPTN(node)->nd_pkwrestarg, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 /* (11) */, false));
7577  }
7578  }
7579 
7580  ADD_INSN(ret, line_node, pop);
7581  ADD_INSNL(ret, line_node, jump, matched);
7582  ADD_INSN(ret, line_node, putnil);
7583 
7584  ADD_LABEL(ret, type_error);
7585  ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7586  ADD_INSN1(ret, line_node, putobject, rb_eTypeError);
7587  ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("deconstruct_keys must return Hash"));
7588  ADD_SEND(ret, line_node, id_core_raise, INT2FIX(2));
7589  ADD_INSN(ret, line_node, pop);
7590 
7591  ADD_LABEL(ret, match_failed);
7592  ADD_INSN(ret, line_node, pop);
7593  ADD_INSNL(ret, line_node, jump, unmatched);
7594  break;
7595  }
7596  case NODE_SYM:
7597  case NODE_REGX:
7598  case NODE_LINE:
7599  case NODE_INTEGER:
7600  case NODE_FLOAT:
7601  case NODE_RATIONAL:
7602  case NODE_IMAGINARY:
7603  case NODE_FILE:
7604  case NODE_ENCODING:
7605  case NODE_STR:
7606  case NODE_XSTR:
7607  case NODE_DSTR:
7608  case NODE_DSYM:
7609  case NODE_DREGX:
7610  case NODE_LIST:
7611  case NODE_ZLIST:
7612  case NODE_LAMBDA:
7613  case NODE_DOT2:
7614  case NODE_DOT3:
7615  case NODE_CONST:
7616  case NODE_LVAR:
7617  case NODE_DVAR:
7618  case NODE_IVAR:
7619  case NODE_CVAR:
7620  case NODE_GVAR:
7621  case NODE_TRUE:
7622  case NODE_FALSE:
7623  case NODE_SELF:
7624  case NODE_NIL:
7625  case NODE_COLON2:
7626  case NODE_COLON3:
7627  case NODE_BEGIN:
7628  case NODE_BLOCK:
7629  case NODE_ONCE:
7630  CHECK(COMPILE(ret, "case in literal", node)); // (1)
7631  if (in_single_pattern) {
7632  ADD_INSN1(ret, line_node, dupn, INT2FIX(2));
7633  }
7634  ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE)); // (2)
7635  if (in_single_pattern) {
7636  CHECK(iseq_compile_pattern_set_eqq_errmsg(iseq, ret, node, base_index + 2 /* (1), (2) */));
7637  }
7638  ADD_INSNL(ret, line_node, branchif, matched);
7639  ADD_INSNL(ret, line_node, jump, unmatched);
7640  break;
7641  case NODE_LASGN: {
7642  struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
7643  ID id = RNODE_LASGN(node)->nd_vid;
7644  int idx = ISEQ_BODY(body->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
7645 
7646  if (in_alt_pattern) {
7647  const char *name = rb_id2name(id);
7648  if (name && strlen(name) > 0 && name[0] != '_') {
7649  COMPILE_ERROR(ERROR_ARGS "illegal variable in alternative pattern (%"PRIsVALUE")",
7650  rb_id2str(id));
7651  return COMPILE_NG;
7652  }
7653  }
7654 
7655  ADD_SETLOCAL(ret, line_node, idx, get_lvar_level(iseq));
7656  ADD_INSNL(ret, line_node, jump, matched);
7657  break;
7658  }
7659  case NODE_DASGN: {
7660  int idx, lv, ls;
7661  ID id = RNODE_DASGN(node)->nd_vid;
7662 
7663  idx = get_dyna_var_idx(iseq, id, &lv, &ls);
7664 
7665  if (in_alt_pattern) {
7666  const char *name = rb_id2name(id);
7667  if (name && strlen(name) > 0 && name[0] != '_') {
7668  COMPILE_ERROR(ERROR_ARGS "illegal variable in alternative pattern (%"PRIsVALUE")",
7669  rb_id2str(id));
7670  return COMPILE_NG;
7671  }
7672  }
7673 
7674  if (idx < 0) {
7675  COMPILE_ERROR(ERROR_ARGS "NODE_DASGN: unknown id (%"PRIsVALUE")",
7676  rb_id2str(id));
7677  return COMPILE_NG;
7678  }
7679  ADD_SETLOCAL(ret, line_node, ls - idx, lv);
7680  ADD_INSNL(ret, line_node, jump, matched);
7681  break;
7682  }
7683  case NODE_IF:
7684  case NODE_UNLESS: {
7685  LABEL *match_failed;
7686  match_failed = unmatched;
7687  CHECK(iseq_compile_pattern_match(iseq, ret, RNODE_IF(node)->nd_body, unmatched, in_single_pattern, in_alt_pattern, base_index, use_deconstructed_cache));
7688  CHECK(COMPILE(ret, "case in if", RNODE_IF(node)->nd_cond));
7689  if (in_single_pattern) {
7690  LABEL *match_succeeded;
7691  match_succeeded = NEW_LABEL(line);
7692 
7693  ADD_INSN(ret, line_node, dup);
7694  if (nd_type_p(node, NODE_IF)) {
7695  ADD_INSNL(ret, line_node, branchif, match_succeeded);
7696  }
7697  else {
7698  ADD_INSNL(ret, line_node, branchunless, match_succeeded);
7699  }
7700 
7701  ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("guard clause does not return true")); // (1)
7702  ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
7703  ADD_INSN1(ret, line_node, putobject, Qfalse);
7704  ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (1), (2) */));
7705 
7706  ADD_INSN(ret, line_node, pop);
7707  ADD_INSN(ret, line_node, pop);
7708 
7709  ADD_LABEL(ret, match_succeeded);
7710  }
7711  if (nd_type_p(node, NODE_IF)) {
7712  ADD_INSNL(ret, line_node, branchunless, match_failed);
7713  }
7714  else {
7715  ADD_INSNL(ret, line_node, branchif, match_failed);
7716  }
7717  ADD_INSNL(ret, line_node, jump, matched);
7718  break;
7719  }
7720  case NODE_HASH: {
7721  NODE *n;
7722  LABEL *match_failed;
7723  match_failed = NEW_LABEL(line);
7724 
7725  n = RNODE_HASH(node)->nd_head;
7726  if (! (nd_type_p(n, NODE_LIST) && RNODE_LIST(n)->as.nd_alen == 2)) {
7727  COMPILE_ERROR(ERROR_ARGS "unexpected node");
7728  return COMPILE_NG;
7729  }
7730 
7731  ADD_INSN(ret, line_node, dup); // (1)
7732  CHECK(iseq_compile_pattern_match(iseq, ret, RNODE_LIST(n)->nd_head, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 /* (1) */, use_deconstructed_cache));
7733  CHECK(iseq_compile_pattern_each(iseq, ret, RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_head, matched, match_failed, in_single_pattern, in_alt_pattern, base_index, false));
7734  ADD_INSN(ret, line_node, putnil);
7735 
7736  ADD_LABEL(ret, match_failed);
7737  ADD_INSN(ret, line_node, pop);
7738  ADD_INSNL(ret, line_node, jump, unmatched);
7739  break;
7740  }
7741  case NODE_OR: {
7742  LABEL *match_succeeded, *fin;
7743  match_succeeded = NEW_LABEL(line);
7744  fin = NEW_LABEL(line);
7745 
7746  ADD_INSN(ret, line_node, dup); // (1)
7747  CHECK(iseq_compile_pattern_each(iseq, ret, RNODE_OR(node)->nd_1st, match_succeeded, fin, in_single_pattern, true, base_index + 1 /* (1) */, use_deconstructed_cache));
7748  ADD_LABEL(ret, match_succeeded);
7749  ADD_INSN(ret, line_node, pop);
7750  ADD_INSNL(ret, line_node, jump, matched);
7751  ADD_INSN(ret, line_node, putnil);
7752  ADD_LABEL(ret, fin);
7753  CHECK(iseq_compile_pattern_each(iseq, ret, RNODE_OR(node)->nd_2nd, matched, unmatched, in_single_pattern, true, base_index, use_deconstructed_cache));
7754  break;
7755  }
7756  default:
7757  UNKNOWN_NODE("NODE_IN", node, COMPILE_NG);
7758  }
7759  return COMPILE_OK;
7760 }
7761 
7762 static int
7763 iseq_compile_pattern_match(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, LABEL *unmatched, bool in_single_pattern, bool in_alt_pattern, int base_index, bool use_deconstructed_cache)
7764 {
7765  LABEL *fin = NEW_LABEL(nd_line(node));
7766  CHECK(iseq_compile_pattern_each(iseq, ret, node, fin, unmatched, in_single_pattern, in_alt_pattern, base_index, use_deconstructed_cache));
7767  ADD_LABEL(ret, fin);
7768  return COMPILE_OK;
7769 }
7770 
7771 static int
7772 iseq_compile_pattern_constant(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, LABEL *match_failed, bool in_single_pattern, int base_index)
7773 {
7774  const NODE *line_node = node;
7775 
7776  if (RNODE_ARYPTN(node)->nd_pconst) {
7777  ADD_INSN(ret, line_node, dup); // (1)
7778  CHECK(COMPILE(ret, "constant", RNODE_ARYPTN(node)->nd_pconst)); // (2)
7779  if (in_single_pattern) {
7780  ADD_INSN1(ret, line_node, dupn, INT2FIX(2));
7781  }
7782  ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE)); // (3)
7783  if (in_single_pattern) {
7784  CHECK(iseq_compile_pattern_set_eqq_errmsg(iseq, ret, node, base_index + 3 /* (1), (2), (3) */));
7785  }
7786  ADD_INSNL(ret, line_node, branchunless, match_failed);
7787  }
7788  return COMPILE_OK;
7789 }
7790 
7791 
7792 static int
7793 iseq_compile_array_deconstruct(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, LABEL *deconstruct, LABEL *deconstructed, LABEL *match_failed, LABEL *type_error, bool in_single_pattern, int base_index, bool use_deconstructed_cache)
7794 {
7795  const NODE *line_node = node;
7796 
7797  // NOTE: this optimization allows us to re-use the #deconstruct value
7798  // (or its absence).
7799  if (use_deconstructed_cache) {
7800  // If value is nil then we haven't tried to deconstruct
7801  ADD_INSN1(ret, line_node, topn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
7802  ADD_INSNL(ret, line_node, branchnil, deconstruct);
7803 
7804  // If false then the value is not deconstructable
7805  ADD_INSN1(ret, line_node, topn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
7806  ADD_INSNL(ret, line_node, branchunless, match_failed);
7807 
7808  // Drop value, add deconstructed to the stack and jump
7809  ADD_INSN(ret, line_node, pop); // (1)
7810  ADD_INSN1(ret, line_node, topn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE - 1 /* (1) */));
7811  ADD_INSNL(ret, line_node, jump, deconstructed);
7812  }
7813  else {
7814  ADD_INSNL(ret, line_node, jump, deconstruct);
7815  }
7816 
7817  ADD_LABEL(ret, deconstruct);
7818  ADD_INSN(ret, line_node, dup);
7819  ADD_INSN1(ret, line_node, putobject, ID2SYM(rb_intern("deconstruct")));
7820  ADD_SEND(ret, line_node, idRespond_to, INT2FIX(1)); // (2)
7821 
7822  // Cache the result of respond_to? (in case it's false is stays there, if true - it's overwritten after #deconstruct)
7823  if (use_deconstructed_cache) {
7824  ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE + 1 /* (2) */));
7825  }
7826 
7827  if (in_single_pattern) {
7828  CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("%p does not respond to #deconstruct"), base_index + 1 /* (2) */));
7829  }
7830 
7831  ADD_INSNL(ret, line_node, branchunless, match_failed);
7832 
7833  ADD_SEND(ret, line_node, rb_intern("deconstruct"), INT2FIX(0));
7834 
7835  // Cache the result (if it's cacheable - currently, only top-level array patterns)
7836  if (use_deconstructed_cache) {
7837  ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
7838  }
7839 
7840  ADD_INSN(ret, line_node, dup);
7841  ADD_INSN1(ret, line_node, checktype, INT2FIX(T_ARRAY));
7842  ADD_INSNL(ret, line_node, branchunless, type_error);
7843 
7844  ADD_LABEL(ret, deconstructed);
7845 
7846  return COMPILE_OK;
7847 }
7848 
7849 static int
7850 iseq_compile_pattern_set_general_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE errmsg, int base_index)
7851 {
7852  /*
7853  * if match_succeeded?
7854  * goto match_succeeded
7855  * end
7856  * error_string = FrozenCore.sprintf(errmsg, matchee)
7857  * key_error_p = false
7858  * match_succeeded:
7859  */
7860  const int line = nd_line(node);
7861  const NODE *line_node = node;
7862  LABEL *match_succeeded = NEW_LABEL(line);
7863 
7864  ADD_INSN(ret, line_node, dup);
7865  ADD_INSNL(ret, line_node, branchif, match_succeeded);
7866 
7867  ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7868  ADD_INSN1(ret, line_node, putobject, errmsg);
7869  ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7870  ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(2)); // (1)
7871  ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
7872 
7873  ADD_INSN1(ret, line_node, putobject, Qfalse);
7874  ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (1), (2) */));
7875 
7876  ADD_INSN(ret, line_node, pop);
7877  ADD_INSN(ret, line_node, pop);
7878  ADD_LABEL(ret, match_succeeded);
7879 
7880  return COMPILE_OK;
7881 }
7882 
7883 static int
7884 iseq_compile_pattern_set_length_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE errmsg, VALUE pattern_length, int base_index)
7885 {
7886  /*
7887  * if match_succeeded?
7888  * goto match_succeeded
7889  * end
7890  * error_string = FrozenCore.sprintf(errmsg, matchee, matchee.length, pat.length)
7891  * key_error_p = false
7892  * match_succeeded:
7893  */
7894  const int line = nd_line(node);
7895  const NODE *line_node = node;
7896  LABEL *match_succeeded = NEW_LABEL(line);
7897 
7898  ADD_INSN(ret, line_node, dup);
7899  ADD_INSNL(ret, line_node, branchif, match_succeeded);
7900 
7901  ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7902  ADD_INSN1(ret, line_node, putobject, errmsg);
7903  ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7904  ADD_INSN(ret, line_node, dup);
7905  ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7906  ADD_INSN1(ret, line_node, putobject, pattern_length);
7907  ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(4)); // (1)
7908  ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
7909 
7910  ADD_INSN1(ret, line_node, putobject, Qfalse);
7911  ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2/* (1), (2) */));
7912 
7913  ADD_INSN(ret, line_node, pop);
7914  ADD_INSN(ret, line_node, pop);
7915  ADD_LABEL(ret, match_succeeded);
7916 
7917  return COMPILE_OK;
7918 }
7919 
7920 static int
7921 iseq_compile_pattern_set_eqq_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int base_index)
7922 {
7923  /*
7924  * if match_succeeded?
7925  * goto match_succeeded
7926  * end
7927  * error_string = FrozenCore.sprintf("%p === %p does not return true", pat, matchee)
7928  * key_error_p = false
7929  * match_succeeded:
7930  */
7931  const int line = nd_line(node);
7932  const NODE *line_node = node;
7933  LABEL *match_succeeded = NEW_LABEL(line);
7934 
7935  ADD_INSN(ret, line_node, dup);
7936  ADD_INSNL(ret, line_node, branchif, match_succeeded);
7937 
7938  ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7939  ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("%p === %p does not return true"));
7940  ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7941  ADD_INSN1(ret, line_node, topn, INT2FIX(5));
7942  ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(3)); // (1)
7943  ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
7944 
7945  ADD_INSN1(ret, line_node, putobject, Qfalse);
7946  ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (1), (2) */));
7947 
7948  ADD_INSN(ret, line_node, pop);
7949  ADD_INSN(ret, line_node, pop);
7950 
7951  ADD_LABEL(ret, match_succeeded);
7952  ADD_INSN1(ret, line_node, setn, INT2FIX(2));
7953  ADD_INSN(ret, line_node, pop);
7954  ADD_INSN(ret, line_node, pop);
7955 
7956  return COMPILE_OK;
7957 }
7958 
7959 static int
7960 compile_case3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
7961 {
7962  const NODE *pattern;
7963  const NODE *node = orig_node;
7964  LABEL *endlabel, *elselabel;
7965  DECL_ANCHOR(head);
7966  DECL_ANCHOR(body_seq);
7967  DECL_ANCHOR(cond_seq);
7968  int line;
7969  enum node_type type;
7970  const NODE *line_node;
7971  VALUE branches = 0;
7972  int branch_id = 0;
7973  bool single_pattern;
7974 
7975  INIT_ANCHOR(head);
7976  INIT_ANCHOR(body_seq);
7977  INIT_ANCHOR(cond_seq);
7978 
7979  branches = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), "case");
7980 
7981  node = RNODE_CASE3(node)->nd_body;
7982  EXPECT_NODE("NODE_CASE3", node, NODE_IN, COMPILE_NG);
7983  type = nd_type(node);
7984  line = nd_line(node);
7985  line_node = node;
7986  single_pattern = !RNODE_IN(node)->nd_next;
7987 
7988  endlabel = NEW_LABEL(line);
7989  elselabel = NEW_LABEL(line);
7990 
7991  if (single_pattern) {
7992  /* allocate stack for ... */
7993  ADD_INSN(head, line_node, putnil); /* key_error_key */
7994  ADD_INSN(head, line_node, putnil); /* key_error_matchee */
7995  ADD_INSN1(head, line_node, putobject, Qfalse); /* key_error_p */
7996  ADD_INSN(head, line_node, putnil); /* error_string */
7997  }
7998  ADD_INSN(head, line_node, putnil); /* allocate stack for cached #deconstruct value */
7999 
8000  CHECK(COMPILE(head, "case base", RNODE_CASE3(orig_node)->nd_head));
8001 
8002  ADD_SEQ(ret, head); /* case VAL */
8003 
8004  while (type == NODE_IN) {
8005  LABEL *l1;
8006 
8007  if (branch_id) {
8008  ADD_INSN(body_seq, line_node, putnil);
8009  }
8010  l1 = NEW_LABEL(line);
8011  ADD_LABEL(body_seq, l1);
8012  ADD_INSN1(body_seq, line_node, adjuststack, INT2FIX(single_pattern ? 6 : 2));
8013 
8014  const NODE *const coverage_node = RNODE_IN(node)->nd_body ? RNODE_IN(node)->nd_body : node;
8015  add_trace_branch_coverage(
8016  iseq,
8017  body_seq,
8018  nd_code_loc(coverage_node),
8019  nd_node_id(coverage_node),
8020  branch_id++,
8021  "in",
8022  branches);
8023 
8024  CHECK(COMPILE_(body_seq, "in body", RNODE_IN(node)->nd_body, popped));
8025  ADD_INSNL(body_seq, line_node, jump, endlabel);
8026 
8027  pattern = RNODE_IN(node)->nd_head;
8028  if (pattern) {
8029  int pat_line = nd_line(pattern);
8030  LABEL *next_pat = NEW_LABEL(pat_line);
8031  ADD_INSN (cond_seq, pattern, dup); /* dup case VAL */
8032  // NOTE: set base_index (it's "under" the matchee value, so it's position is 2)
8033  CHECK(iseq_compile_pattern_each(iseq, cond_seq, pattern, l1, next_pat, single_pattern, false, 2, true));
8034  ADD_LABEL(cond_seq, next_pat);
8035  LABEL_UNREMOVABLE(next_pat);
8036  }
8037  else {
8038  COMPILE_ERROR(ERROR_ARGS "unexpected node");
8039  return COMPILE_NG;
8040  }
8041 
8042  node = RNODE_IN(node)->nd_next;
8043  if (!node) {
8044  break;
8045  }
8046  type = nd_type(node);
8047  line = nd_line(node);
8048  line_node = node;
8049  }
8050  /* else */
8051  if (node) {
8052  ADD_LABEL(cond_seq, elselabel);
8053  ADD_INSN(cond_seq, line_node, pop);
8054  ADD_INSN(cond_seq, line_node, pop); /* discard cached #deconstruct value */
8055  add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(node), nd_node_id(node), branch_id, "else", branches);
8056  CHECK(COMPILE_(cond_seq, "else", node, popped));
8057  ADD_INSNL(cond_seq, line_node, jump, endlabel);
8058  ADD_INSN(cond_seq, line_node, putnil);
8059  if (popped) {
8060  ADD_INSN(cond_seq, line_node, putnil);
8061  }
8062  }
8063  else {
8064  debugs("== else (implicit)\n");
8065  ADD_LABEL(cond_seq, elselabel);
8066  add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(orig_node), nd_node_id(orig_node), branch_id, "else", branches);
8067  ADD_INSN1(cond_seq, orig_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8068 
8069  if (single_pattern) {
8070  /*
8071  * if key_error_p
8072  * FrozenCore.raise NoMatchingPatternKeyError.new(FrozenCore.sprintf("%p: %s", case_val, error_string), matchee: key_error_matchee, key: key_error_key)
8073  * else
8074  * FrozenCore.raise NoMatchingPatternError, FrozenCore.sprintf("%p: %s", case_val, error_string)
8075  * end
8076  */
8077  LABEL *key_error, *fin;
8078  struct rb_callinfo_kwarg *kw_arg;
8079 
8080  key_error = NEW_LABEL(line);
8081  fin = NEW_LABEL(line);
8082 
8083  kw_arg = rb_xmalloc_mul_add(2, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
8084  kw_arg->references = 0;
8085  kw_arg->keyword_len = 2;
8086  kw_arg->keywords[0] = ID2SYM(rb_intern("matchee"));
8087  kw_arg->keywords[1] = ID2SYM(rb_intern("key"));
8088 
8089  ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_P + 2));
8090  ADD_INSNL(cond_seq, orig_node, branchif, key_error);
8091  ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternError);
8092  ADD_INSN1(cond_seq, orig_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8093  ADD_INSN1(cond_seq, orig_node, putobject, rb_fstring_lit("%p: %s"));
8094  ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(4)); /* case VAL */
8095  ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_ERROR_STRING + 6));
8096  ADD_SEND(cond_seq, orig_node, id_core_sprintf, INT2FIX(3));
8097  ADD_SEND(cond_seq, orig_node, id_core_raise, INT2FIX(2));
8098  ADD_INSNL(cond_seq, orig_node, jump, fin);
8099 
8100  ADD_LABEL(cond_seq, key_error);
8101  ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternKeyError);
8102  ADD_INSN1(cond_seq, orig_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8103  ADD_INSN1(cond_seq, orig_node, putobject, rb_fstring_lit("%p: %s"));
8104  ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(4)); /* case VAL */
8105  ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_ERROR_STRING + 6));
8106  ADD_SEND(cond_seq, orig_node, id_core_sprintf, INT2FIX(3));
8107  ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_MATCHEE + 4));
8108  ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_KEY + 5));
8109  ADD_SEND_R(cond_seq, orig_node, rb_intern("new"), INT2FIX(1), NULL, INT2FIX(VM_CALL_KWARG), kw_arg);
8110  ADD_SEND(cond_seq, orig_node, id_core_raise, INT2FIX(1));
8111 
8112  ADD_LABEL(cond_seq, fin);
8113  }
8114  else {
8115  ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternError);
8116  ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(2));
8117  ADD_SEND(cond_seq, orig_node, id_core_raise, INT2FIX(2));
8118  }
8119  ADD_INSN1(cond_seq, orig_node, adjuststack, INT2FIX(single_pattern ? 7 : 3));
8120  if (!popped) {
8121  ADD_INSN(cond_seq, orig_node, putnil);
8122  }
8123  ADD_INSNL(cond_seq, orig_node, jump, endlabel);
8124  ADD_INSN1(cond_seq, orig_node, dupn, INT2FIX(single_pattern ? 5 : 1));
8125  if (popped) {
8126  ADD_INSN(cond_seq, line_node, putnil);
8127  }
8128  }
8129 
8130  ADD_SEQ(ret, cond_seq);
8131  ADD_SEQ(ret, body_seq);
8132  ADD_LABEL(ret, endlabel);
8133  return COMPILE_OK;
8134 }
8135 
8136 #undef CASE3_BI_OFFSET_DECONSTRUCTED_CACHE
8137 #undef CASE3_BI_OFFSET_ERROR_STRING
8138 #undef CASE3_BI_OFFSET_KEY_ERROR_P
8139 #undef CASE3_BI_OFFSET_KEY_ERROR_MATCHEE
8140 #undef CASE3_BI_OFFSET_KEY_ERROR_KEY
8141 
8142 static int
8143 compile_loop(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
8144 {
8145  const int line = (int)nd_line(node);
8146  const NODE *line_node = node;
8147 
8148  LABEL *prev_start_label = ISEQ_COMPILE_DATA(iseq)->start_label;
8149  LABEL *prev_end_label = ISEQ_COMPILE_DATA(iseq)->end_label;
8150  LABEL *prev_redo_label = ISEQ_COMPILE_DATA(iseq)->redo_label;
8151  int prev_loopval_popped = ISEQ_COMPILE_DATA(iseq)->loopval_popped;
8152  VALUE branches = Qfalse;
8153 
8155 
8156  LABEL *next_label = ISEQ_COMPILE_DATA(iseq)->start_label = NEW_LABEL(line); /* next */
8157  LABEL *redo_label = ISEQ_COMPILE_DATA(iseq)->redo_label = NEW_LABEL(line); /* redo */
8158  LABEL *break_label = ISEQ_COMPILE_DATA(iseq)->end_label = NEW_LABEL(line); /* break */
8159  LABEL *end_label = NEW_LABEL(line);
8160  LABEL *adjust_label = NEW_LABEL(line);
8161 
8162  LABEL *next_catch_label = NEW_LABEL(line);
8163  LABEL *tmp_label = NULL;
8164 
8165  ISEQ_COMPILE_DATA(iseq)->loopval_popped = 0;
8166  push_ensure_entry(iseq, &enl, NULL, NULL);
8167 
8168  if (RNODE_WHILE(node)->nd_state == 1) {
8169  ADD_INSNL(ret, line_node, jump, next_label);
8170  }
8171  else {
8172  tmp_label = NEW_LABEL(line);
8173  ADD_INSNL(ret, line_node, jump, tmp_label);
8174  }
8175  ADD_LABEL(ret, adjust_label);
8176  ADD_INSN(ret, line_node, putnil);
8177  ADD_LABEL(ret, next_catch_label);
8178  ADD_INSN(ret, line_node, pop);
8179  ADD_INSNL(ret, line_node, jump, next_label);
8180  if (tmp_label) ADD_LABEL(ret, tmp_label);
8181 
8182  ADD_LABEL(ret, redo_label);
8183  branches = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), type == NODE_WHILE ? "while" : "until");
8184 
8185  const NODE *const coverage_node = RNODE_WHILE(node)->nd_body ? RNODE_WHILE(node)->nd_body : node;
8186  add_trace_branch_coverage(
8187  iseq,
8188  ret,
8189  nd_code_loc(coverage_node),
8190  nd_node_id(coverage_node),
8191  0,
8192  "body",
8193  branches);
8194 
8195  CHECK(COMPILE_POPPED(ret, "while body", RNODE_WHILE(node)->nd_body));
8196  ADD_LABEL(ret, next_label); /* next */
8197 
8198  if (type == NODE_WHILE) {
8199  CHECK(compile_branch_condition(iseq, ret, RNODE_WHILE(node)->nd_cond,
8200  redo_label, end_label));
8201  }
8202  else {
8203  /* until */
8204  CHECK(compile_branch_condition(iseq, ret, RNODE_WHILE(node)->nd_cond,
8205  end_label, redo_label));
8206  }
8207 
8208  ADD_LABEL(ret, end_label);
8209  ADD_ADJUST_RESTORE(ret, adjust_label);
8210 
8211  if (UNDEF_P(RNODE_WHILE(node)->nd_state)) {
8212  /* ADD_INSN(ret, line_node, putundef); */
8213  COMPILE_ERROR(ERROR_ARGS "unsupported: putundef");
8214  return COMPILE_NG;
8215  }
8216  else {
8217  ADD_INSN(ret, line_node, putnil);
8218  }
8219 
8220  ADD_LABEL(ret, break_label); /* break */
8221 
8222  if (popped) {
8223  ADD_INSN(ret, line_node, pop);
8224  }
8225 
8226  ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, redo_label, break_label, NULL,
8227  break_label);
8228  ADD_CATCH_ENTRY(CATCH_TYPE_NEXT, redo_label, break_label, NULL,
8229  next_catch_label);
8230  ADD_CATCH_ENTRY(CATCH_TYPE_REDO, redo_label, break_label, NULL,
8231  ISEQ_COMPILE_DATA(iseq)->redo_label);
8232 
8233  ISEQ_COMPILE_DATA(iseq)->start_label = prev_start_label;
8234  ISEQ_COMPILE_DATA(iseq)->end_label = prev_end_label;
8235  ISEQ_COMPILE_DATA(iseq)->redo_label = prev_redo_label;
8236  ISEQ_COMPILE_DATA(iseq)->loopval_popped = prev_loopval_popped;
8237  ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack->prev;
8238  return COMPILE_OK;
8239 }
8240 
8241 static int
8242 compile_iter(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8243 {
8244  const int line = nd_line(node);
8245  const NODE *line_node = node;
8246  const rb_iseq_t *prevblock = ISEQ_COMPILE_DATA(iseq)->current_block;
8247  LABEL *retry_label = NEW_LABEL(line);
8248  LABEL *retry_end_l = NEW_LABEL(line);
8249  const rb_iseq_t *child_iseq;
8250 
8251  ADD_LABEL(ret, retry_label);
8252  if (nd_type_p(node, NODE_FOR)) {
8253  CHECK(COMPILE(ret, "iter caller (for)", RNODE_FOR(node)->nd_iter));
8254 
8255  ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq =
8256  NEW_CHILD_ISEQ(RNODE_FOR(node)->nd_body, make_name_for_block(iseq),
8257  ISEQ_TYPE_BLOCK, line);
8258  ADD_SEND_WITH_BLOCK(ret, line_node, idEach, INT2FIX(0), child_iseq);
8259  }
8260  else {
8261  ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq =
8262  NEW_CHILD_ISEQ(RNODE_ITER(node)->nd_body, make_name_for_block(iseq),
8263  ISEQ_TYPE_BLOCK, line);
8264  CHECK(COMPILE(ret, "iter caller", RNODE_ITER(node)->nd_iter));
8265  }
8266 
8267  {
8268  // We need to put the label "retry_end_l" immediately after the last "send" instruction.
8269  // This because vm_throw checks if the break cont is equal to the index of next insn of the "send".
8270  // (Otherwise, it is considered "break from proc-closure". See "TAG_BREAK" handling in "vm_throw_start".)
8271  //
8272  // Normally, "send" instruction is at the last.
8273  // However, qcall under branch coverage measurement adds some instructions after the "send".
8274  //
8275  // Note that "invokesuper", "invokesuperforward" appears instead of "send".
8276  INSN *iobj;
8277  LINK_ELEMENT *last_elem = LAST_ELEMENT(ret);
8278  iobj = IS_INSN(last_elem) ? (INSN*) last_elem : (INSN*) get_prev_insn((INSN*) last_elem);
8279  while (!IS_INSN_ID(iobj, send) && !IS_INSN_ID(iobj, invokesuper) && !IS_INSN_ID(iobj, sendforward) && !IS_INSN_ID(iobj, invokesuperforward)) {
8280  iobj = (INSN*) get_prev_insn(iobj);
8281  }
8282  ELEM_INSERT_NEXT(&iobj->link, (LINK_ELEMENT*) retry_end_l);
8283 
8284  // LINK_ANCHOR has a pointer to the last element, but ELEM_INSERT_NEXT does not update it
8285  // even if we add an insn to the last of LINK_ANCHOR. So this updates it manually.
8286  if (&iobj->link == LAST_ELEMENT(ret)) {
8287  ret->last = (LINK_ELEMENT*) retry_end_l;
8288  }
8289  }
8290 
8291  if (popped) {
8292  ADD_INSN(ret, line_node, pop);
8293  }
8294 
8295  ISEQ_COMPILE_DATA(iseq)->current_block = prevblock;
8296 
8297  ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, retry_label, retry_end_l, child_iseq, retry_end_l);
8298  return COMPILE_OK;
8299 }
8300 
8301 static int
8302 compile_for_masgn(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8303 {
8304  /* massign to var in "for"
8305  * (args.length == 1 && Array.try_convert(args[0])) || args
8306  */
8307  const NODE *line_node = node;
8308  const NODE *var = RNODE_FOR_MASGN(node)->nd_var;
8309  LABEL *not_single = NEW_LABEL(nd_line(var));
8310  LABEL *not_ary = NEW_LABEL(nd_line(var));
8311  CHECK(COMPILE(ret, "for var", var));
8312  ADD_INSN(ret, line_node, dup);
8313  ADD_CALL(ret, line_node, idLength, INT2FIX(0));
8314  ADD_INSN1(ret, line_node, putobject, INT2FIX(1));
8315  ADD_CALL(ret, line_node, idEq, INT2FIX(1));
8316  ADD_INSNL(ret, line_node, branchunless, not_single);
8317  ADD_INSN(ret, line_node, dup);
8318  ADD_INSN1(ret, line_node, putobject, INT2FIX(0));
8319  ADD_CALL(ret, line_node, idAREF, INT2FIX(1));
8320  ADD_INSN1(ret, line_node, putobject, rb_cArray);
8321  ADD_INSN(ret, line_node, swap);
8322  ADD_CALL(ret, line_node, rb_intern("try_convert"), INT2FIX(1));
8323  ADD_INSN(ret, line_node, dup);
8324  ADD_INSNL(ret, line_node, branchunless, not_ary);
8325  ADD_INSN(ret, line_node, swap);
8326  ADD_LABEL(ret, not_ary);
8327  ADD_INSN(ret, line_node, pop);
8328  ADD_LABEL(ret, not_single);
8329  return COMPILE_OK;
8330 }
8331 
8332 static int
8333 compile_break(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8334 {
8335  const NODE *line_node = node;
8336  unsigned long throw_flag = 0;
8337 
8338  if (ISEQ_COMPILE_DATA(iseq)->redo_label != 0 && can_add_ensure_iseq(iseq)) {
8339  /* while/until */
8340  LABEL *splabel = NEW_LABEL(0);
8341  ADD_LABEL(ret, splabel);
8342  ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
8343  CHECK(COMPILE_(ret, "break val (while/until)", RNODE_BREAK(node)->nd_stts,
8344  ISEQ_COMPILE_DATA(iseq)->loopval_popped));
8345  add_ensure_iseq(ret, iseq, 0);
8346  ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->end_label);
8347  ADD_ADJUST_RESTORE(ret, splabel);
8348 
8349  if (!popped) {
8350  ADD_INSN(ret, line_node, putnil);
8351  }
8352  }
8353  else {
8354  const rb_iseq_t *ip = iseq;
8355 
8356  while (ip) {
8357  if (!ISEQ_COMPILE_DATA(ip)) {
8358  ip = 0;
8359  break;
8360  }
8361 
8362  if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
8363  throw_flag = VM_THROW_NO_ESCAPE_FLAG;
8364  }
8365  else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
8366  throw_flag = 0;
8367  }
8368  else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
8369  COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with break");
8370  return COMPILE_NG;
8371  }
8372  else {
8373  ip = ISEQ_BODY(ip)->parent_iseq;
8374  continue;
8375  }
8376 
8377  /* escape from block */
8378  CHECK(COMPILE(ret, "break val (block)", RNODE_BREAK(node)->nd_stts));
8379  ADD_INSN1(ret, line_node, throw, INT2FIX(throw_flag | TAG_BREAK));
8380  if (popped) {
8381  ADD_INSN(ret, line_node, pop);
8382  }
8383  return COMPILE_OK;
8384  }
8385  COMPILE_ERROR(ERROR_ARGS "Invalid break");
8386  return COMPILE_NG;
8387  }
8388  return COMPILE_OK;
8389 }
8390 
8391 static int
8392 compile_next(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8393 {
8394  const NODE *line_node = node;
8395  unsigned long throw_flag = 0;
8396 
8397  if (ISEQ_COMPILE_DATA(iseq)->redo_label != 0 && can_add_ensure_iseq(iseq)) {
8398  LABEL *splabel = NEW_LABEL(0);
8399  debugs("next in while loop\n");
8400  ADD_LABEL(ret, splabel);
8401  CHECK(COMPILE(ret, "next val/valid syntax?", RNODE_NEXT(node)->nd_stts));
8402  add_ensure_iseq(ret, iseq, 0);
8403  ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
8404  ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->start_label);
8405  ADD_ADJUST_RESTORE(ret, splabel);
8406  if (!popped) {
8407  ADD_INSN(ret, line_node, putnil);
8408  }
8409  }
8410  else if (ISEQ_COMPILE_DATA(iseq)->end_label && can_add_ensure_iseq(iseq)) {
8411  LABEL *splabel = NEW_LABEL(0);
8412  debugs("next in block\n");
8413  ADD_LABEL(ret, splabel);
8414  ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->start_label);
8415  CHECK(COMPILE(ret, "next val", RNODE_NEXT(node)->nd_stts));
8416  add_ensure_iseq(ret, iseq, 0);
8417  ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->end_label);
8418  ADD_ADJUST_RESTORE(ret, splabel);
8419 
8420  if (!popped) {
8421  ADD_INSN(ret, line_node, putnil);
8422  }
8423  }
8424  else {
8425  const rb_iseq_t *ip = iseq;
8426 
8427  while (ip) {
8428  if (!ISEQ_COMPILE_DATA(ip)) {
8429  ip = 0;
8430  break;
8431  }
8432 
8433  throw_flag = VM_THROW_NO_ESCAPE_FLAG;
8434  if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
8435  /* while loop */
8436  break;
8437  }
8438  else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
8439  break;
8440  }
8441  else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
8442  COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with next");
8443  return COMPILE_NG;
8444  }
8445 
8446  ip = ISEQ_BODY(ip)->parent_iseq;
8447  }
8448  if (ip != 0) {
8449  CHECK(COMPILE(ret, "next val", RNODE_NEXT(node)->nd_stts));
8450  ADD_INSN1(ret, line_node, throw, INT2FIX(throw_flag | TAG_NEXT));
8451 
8452  if (popped) {
8453  ADD_INSN(ret, line_node, pop);
8454  }
8455  }
8456  else {
8457  COMPILE_ERROR(ERROR_ARGS "Invalid next");
8458  return COMPILE_NG;
8459  }
8460  }
8461  return COMPILE_OK;
8462 }
8463 
8464 static int
8465 compile_redo(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8466 {
8467  const NODE *line_node = node;
8468 
8469  if (ISEQ_COMPILE_DATA(iseq)->redo_label && can_add_ensure_iseq(iseq)) {
8470  LABEL *splabel = NEW_LABEL(0);
8471  debugs("redo in while");
8472  ADD_LABEL(ret, splabel);
8473  ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
8474  add_ensure_iseq(ret, iseq, 0);
8475  ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->redo_label);
8476  ADD_ADJUST_RESTORE(ret, splabel);
8477  if (!popped) {
8478  ADD_INSN(ret, line_node, putnil);
8479  }
8480  }
8481  else if (ISEQ_BODY(iseq)->type != ISEQ_TYPE_EVAL && ISEQ_COMPILE_DATA(iseq)->start_label && can_add_ensure_iseq(iseq)) {
8482  LABEL *splabel = NEW_LABEL(0);
8483 
8484  debugs("redo in block");
8485  ADD_LABEL(ret, splabel);
8486  add_ensure_iseq(ret, iseq, 0);
8487  ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->start_label);
8488  ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->start_label);
8489  ADD_ADJUST_RESTORE(ret, splabel);
8490 
8491  if (!popped) {
8492  ADD_INSN(ret, line_node, putnil);
8493  }
8494  }
8495  else {
8496  const rb_iseq_t *ip = iseq;
8497 
8498  while (ip) {
8499  if (!ISEQ_COMPILE_DATA(ip)) {
8500  ip = 0;
8501  break;
8502  }
8503 
8504  if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
8505  break;
8506  }
8507  else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
8508  break;
8509  }
8510  else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
8511  COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with redo");
8512  return COMPILE_NG;
8513  }
8514 
8515  ip = ISEQ_BODY(ip)->parent_iseq;
8516  }
8517  if (ip != 0) {
8518  ADD_INSN(ret, line_node, putnil);
8519  ADD_INSN1(ret, line_node, throw, INT2FIX(VM_THROW_NO_ESCAPE_FLAG | TAG_REDO));
8520 
8521  if (popped) {
8522  ADD_INSN(ret, line_node, pop);
8523  }
8524  }
8525  else {
8526  COMPILE_ERROR(ERROR_ARGS "Invalid redo");
8527  return COMPILE_NG;
8528  }
8529  }
8530  return COMPILE_OK;
8531 }
8532 
8533 static int
8534 compile_retry(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8535 {
8536  const NODE *line_node = node;
8537 
8538  if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_RESCUE) {
8539  ADD_INSN(ret, line_node, putnil);
8540  ADD_INSN1(ret, line_node, throw, INT2FIX(TAG_RETRY));
8541 
8542  if (popped) {
8543  ADD_INSN(ret, line_node, pop);
8544  }
8545  }
8546  else {
8547  COMPILE_ERROR(ERROR_ARGS "Invalid retry");
8548  return COMPILE_NG;
8549  }
8550  return COMPILE_OK;
8551 }
8552 
8553 static int
8554 compile_rescue(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8555 {
8556  const int line = nd_line(node);
8557  const NODE *line_node = node;
8558  LABEL *lstart = NEW_LABEL(line);
8559  LABEL *lend = NEW_LABEL(line);
8560  LABEL *lcont = NEW_LABEL(line);
8561  const rb_iseq_t *rescue = NEW_CHILD_ISEQ(RNODE_RESCUE(node)->nd_resq,
8562  rb_str_concat(rb_str_new2("rescue in "),
8563  ISEQ_BODY(iseq)->location.label),
8564  ISEQ_TYPE_RESCUE, line);
8565 
8566  lstart->rescued = LABEL_RESCUE_BEG;
8567  lend->rescued = LABEL_RESCUE_END;
8568  ADD_LABEL(ret, lstart);
8569 
8570  bool prev_in_rescue = ISEQ_COMPILE_DATA(iseq)->in_rescue;
8571  ISEQ_COMPILE_DATA(iseq)->in_rescue = true;
8572  {
8573  CHECK(COMPILE(ret, "rescue head", RNODE_RESCUE(node)->nd_head));
8574  }
8575  ISEQ_COMPILE_DATA(iseq)->in_rescue = prev_in_rescue;
8576 
8577  ADD_LABEL(ret, lend);
8578  if (RNODE_RESCUE(node)->nd_else) {
8579  ADD_INSN(ret, line_node, pop);
8580  CHECK(COMPILE(ret, "rescue else", RNODE_RESCUE(node)->nd_else));
8581  }
8582  ADD_INSN(ret, line_node, nop);
8583  ADD_LABEL(ret, lcont);
8584 
8585  if (popped) {
8586  ADD_INSN(ret, line_node, pop);
8587  }
8588 
8589  /* register catch entry */
8590  ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lcont);
8591  ADD_CATCH_ENTRY(CATCH_TYPE_RETRY, lend, lcont, NULL, lstart);
8592  return COMPILE_OK;
8593 }
8594 
8595 static int
8596 compile_resbody(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8597 {
8598  const int line = nd_line(node);
8599  const NODE *line_node = node;
8600  const NODE *resq = node;
8601  const NODE *narg;
8602  LABEL *label_miss, *label_hit;
8603 
8604  while (resq) {
8605  label_miss = NEW_LABEL(line);
8606  label_hit = NEW_LABEL(line);
8607 
8608  narg = RNODE_RESBODY(resq)->nd_args;
8609  if (narg) {
8610  switch (nd_type(narg)) {
8611  case NODE_LIST:
8612  while (narg) {
8613  ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
8614  CHECK(COMPILE(ret, "rescue arg", RNODE_LIST(narg)->nd_head));
8615  ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
8616  ADD_INSNL(ret, line_node, branchif, label_hit);
8617  narg = RNODE_LIST(narg)->nd_next;
8618  }
8619  break;
8620  case NODE_SPLAT:
8621  case NODE_ARGSCAT:
8622  case NODE_ARGSPUSH:
8623  ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
8624  CHECK(COMPILE(ret, "rescue/cond splat", narg));
8625  ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE | VM_CHECKMATCH_ARRAY));
8626  ADD_INSNL(ret, line_node, branchif, label_hit);
8627  break;
8628  default:
8629  UNKNOWN_NODE("NODE_RESBODY", narg, COMPILE_NG);
8630  }
8631  }
8632  else {
8633  ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
8634  ADD_INSN1(ret, line_node, putobject, rb_eStandardError);
8635  ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
8636  ADD_INSNL(ret, line_node, branchif, label_hit);
8637  }
8638  ADD_INSNL(ret, line_node, jump, label_miss);
8639  ADD_LABEL(ret, label_hit);
8640  ADD_TRACE(ret, RUBY_EVENT_RESCUE);
8641 
8642  if (RNODE_RESBODY(resq)->nd_exc_var) {
8643  CHECK(COMPILE_POPPED(ret, "resbody exc_var", RNODE_RESBODY(resq)->nd_exc_var));
8644  }
8645 
8646  if (nd_type(RNODE_RESBODY(resq)->nd_body) == NODE_BEGIN && RNODE_BEGIN(RNODE_RESBODY(resq)->nd_body)->nd_body == NULL && !RNODE_RESBODY(resq)->nd_exc_var) {
8647  // empty body
8648  ADD_SYNTHETIC_INSN(ret, nd_line(RNODE_RESBODY(resq)->nd_body), -1, putnil);
8649  }
8650  else {
8651  CHECK(COMPILE(ret, "resbody body", RNODE_RESBODY(resq)->nd_body));
8652  }
8653 
8654  if (ISEQ_COMPILE_DATA(iseq)->option->tailcall_optimization) {
8655  ADD_INSN(ret, line_node, nop);
8656  }
8657  ADD_INSN(ret, line_node, leave);
8658  ADD_LABEL(ret, label_miss);
8659  resq = RNODE_RESBODY(resq)->nd_next;
8660  }
8661  return COMPILE_OK;
8662 }
8663 
8664 static int
8665 compile_ensure(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8666 {
8667  const int line = nd_line(RNODE_ENSURE(node)->nd_ensr);
8668  const NODE *line_node = node;
8669  DECL_ANCHOR(ensr);
8670  const rb_iseq_t *ensure = NEW_CHILD_ISEQ(RNODE_ENSURE(node)->nd_ensr,
8671  rb_str_concat(rb_str_new2 ("ensure in "), ISEQ_BODY(iseq)->location.label),
8672  ISEQ_TYPE_ENSURE, line);
8673  LABEL *lstart = NEW_LABEL(line);
8674  LABEL *lend = NEW_LABEL(line);
8675  LABEL *lcont = NEW_LABEL(line);
8676  LINK_ELEMENT *last;
8677  int last_leave = 0;
8678  struct ensure_range er;
8680  struct ensure_range *erange;
8681 
8682  INIT_ANCHOR(ensr);
8683  CHECK(COMPILE_POPPED(ensr, "ensure ensr", RNODE_ENSURE(node)->nd_ensr));
8684  last = ensr->last;
8685  last_leave = last && IS_INSN(last) && IS_INSN_ID(last, leave);
8686 
8687  er.begin = lstart;
8688  er.end = lend;
8689  er.next = 0;
8690  push_ensure_entry(iseq, &enl, &er, RNODE_ENSURE(node)->nd_ensr);
8691 
8692  ADD_LABEL(ret, lstart);
8693  CHECK(COMPILE_(ret, "ensure head", RNODE_ENSURE(node)->nd_head, (popped | last_leave)));
8694  ADD_LABEL(ret, lend);
8695  ADD_SEQ(ret, ensr);
8696  if (!popped && last_leave) ADD_INSN(ret, line_node, putnil);
8697  ADD_LABEL(ret, lcont);
8698  if (last_leave) ADD_INSN(ret, line_node, pop);
8699 
8700  erange = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack->erange;
8701  if (lstart->link.next != &lend->link) {
8702  while (erange) {
8703  ADD_CATCH_ENTRY(CATCH_TYPE_ENSURE, erange->begin, erange->end,
8704  ensure, lcont);
8705  erange = erange->next;
8706  }
8707  }
8708 
8709  ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enl.prev;
8710  return COMPILE_OK;
8711 }
8712 
8713 static int
8714 compile_return(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8715 {
8716  const NODE *line_node = node;
8717 
8718  if (iseq) {
8719  enum rb_iseq_type type = ISEQ_BODY(iseq)->type;
8720  const rb_iseq_t *is = iseq;
8721  enum rb_iseq_type t = type;
8722  const NODE *retval = RNODE_RETURN(node)->nd_stts;
8723  LABEL *splabel = 0;
8724 
8725  while (t == ISEQ_TYPE_RESCUE || t == ISEQ_TYPE_ENSURE) {
8726  if (!(is = ISEQ_BODY(is)->parent_iseq)) break;
8727  t = ISEQ_BODY(is)->type;
8728  }
8729  switch (t) {
8730  case ISEQ_TYPE_TOP:
8731  case ISEQ_TYPE_MAIN:
8732  if (retval) {
8733  rb_warn("argument of top-level return is ignored");
8734  }
8735  if (is == iseq) {
8736  /* plain top-level, leave directly */
8737  type = ISEQ_TYPE_METHOD;
8738  }
8739  break;
8740  default:
8741  break;
8742  }
8743 
8744  if (type == ISEQ_TYPE_METHOD) {
8745  splabel = NEW_LABEL(0);
8746  ADD_LABEL(ret, splabel);
8747  ADD_ADJUST(ret, line_node, 0);
8748  }
8749 
8750  CHECK(COMPILE(ret, "return nd_stts (return val)", retval));
8751 
8752  if (type == ISEQ_TYPE_METHOD && can_add_ensure_iseq(iseq)) {
8753  add_ensure_iseq(ret, iseq, 1);
8754  ADD_TRACE(ret, RUBY_EVENT_RETURN);
8755  ADD_INSN(ret, line_node, leave);
8756  ADD_ADJUST_RESTORE(ret, splabel);
8757 
8758  if (!popped) {
8759  ADD_INSN(ret, line_node, putnil);
8760  }
8761  }
8762  else {
8763  ADD_INSN1(ret, line_node, throw, INT2FIX(TAG_RETURN));
8764  if (popped) {
8765  ADD_INSN(ret, line_node, pop);
8766  }
8767  }
8768  }
8769  return COMPILE_OK;
8770 }
8771 
8772 static bool
8773 drop_unreachable_return(LINK_ANCHOR *ret)
8774 {
8775  LINK_ELEMENT *i = ret->last, *last;
8776  if (!i) return false;
8777  if (IS_TRACE(i)) i = i->prev;
8778  if (!IS_INSN(i) || !IS_INSN_ID(i, putnil)) return false;
8779  last = i = i->prev;
8780  if (IS_ADJUST(i)) i = i->prev;
8781  if (!IS_INSN(i)) return false;
8782  switch (INSN_OF(i)) {
8783  case BIN(leave):
8784  case BIN(jump):
8785  break;
8786  default:
8787  return false;
8788  }
8789  (ret->last = last->prev)->next = NULL;
8790  return true;
8791 }
8792 
8793 static int
8794 compile_evstr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8795 {
8796  CHECK(COMPILE_(ret, "nd_body", node, popped));
8797 
8798  if (!popped && !all_string_result_p(node)) {
8799  const NODE *line_node = node;
8800  const unsigned int flag = VM_CALL_FCALL;
8801 
8802  // Note, this dup could be removed if we are willing to change anytostring. It pops
8803  // two VALUEs off the stack when it could work by replacing the top most VALUE.
8804  ADD_INSN(ret, line_node, dup);
8805  ADD_INSN1(ret, line_node, objtostring, new_callinfo(iseq, idTo_s, 0, flag, NULL, FALSE));
8806  ADD_INSN(ret, line_node, anytostring);
8807  }
8808  return COMPILE_OK;
8809 }
8810 
8811 static void
8812 compile_lvar(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *line_node, ID id)
8813 {
8814  int idx = ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
8815 
8816  debugs("id: %s idx: %d\n", rb_id2name(id), idx);
8817  ADD_GETLOCAL(ret, line_node, idx, get_lvar_level(iseq));
8818 }
8819 
8820 static LABEL *
8821 qcall_branch_start(rb_iseq_t *iseq, LINK_ANCHOR *const recv, VALUE *branches, const NODE *node, const NODE *line_node)
8822 {
8823  LABEL *else_label = NEW_LABEL(nd_line(line_node));
8824  VALUE br = 0;
8825 
8826  br = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), "&.");
8827  *branches = br;
8828  ADD_INSN(recv, line_node, dup);
8829  ADD_INSNL(recv, line_node, branchnil, else_label);
8830  add_trace_branch_coverage(iseq, recv, nd_code_loc(node), nd_node_id(node), 0, "then", br);
8831  return else_label;
8832 }
8833 
8834 static void
8835 qcall_branch_end(rb_iseq_t *iseq, LINK_ANCHOR *const ret, LABEL *else_label, VALUE branches, const NODE *node, const NODE *line_node)
8836 {
8837  LABEL *end_label;
8838  if (!else_label) return;
8839  end_label = NEW_LABEL(nd_line(line_node));
8840  ADD_INSNL(ret, line_node, jump, end_label);
8841  ADD_LABEL(ret, else_label);
8842  add_trace_branch_coverage(iseq, ret, nd_code_loc(node), nd_node_id(node), 1, "else", branches);
8843  ADD_LABEL(ret, end_label);
8844 }
8845 
8846 static int
8847 compile_call_precheck_freeze(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, const NODE *line_node, int popped)
8848 {
8849  /* optimization shortcut
8850  * "literal".freeze -> opt_str_freeze("literal")
8851  */
8852  if (get_nd_recv(node) &&
8853  (nd_type_p(get_nd_recv(node), NODE_STR) || nd_type_p(get_nd_recv(node), NODE_FILE)) &&
8854  (get_node_call_nd_mid(node) == idFreeze || get_node_call_nd_mid(node) == idUMinus) &&
8855  get_nd_args(node) == NULL &&
8856  ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
8857  ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
8858  VALUE str = get_string_value(get_nd_recv(node));
8859  if (get_node_call_nd_mid(node) == idUMinus) {
8860  ADD_INSN2(ret, line_node, opt_str_uminus, str,
8861  new_callinfo(iseq, idUMinus, 0, 0, NULL, FALSE));
8862  }
8863  else {
8864  ADD_INSN2(ret, line_node, opt_str_freeze, str,
8865  new_callinfo(iseq, idFreeze, 0, 0, NULL, FALSE));
8866  }
8867  RB_OBJ_WRITTEN(iseq, Qundef, str);
8868  if (popped) {
8869  ADD_INSN(ret, line_node, pop);
8870  }
8871  return TRUE;
8872  }
8873  /* optimization shortcut
8874  * obj["literal"] -> opt_aref_with(obj, "literal")
8875  */
8876  if (get_node_call_nd_mid(node) == idAREF && !private_recv_p(node) && get_nd_args(node) &&
8877  nd_type_p(get_nd_args(node), NODE_LIST) && RNODE_LIST(get_nd_args(node))->as.nd_alen == 1 &&
8878  (nd_type_p(RNODE_LIST(get_nd_args(node))->nd_head, NODE_STR) || nd_type_p(RNODE_LIST(get_nd_args(node))->nd_head, NODE_FILE)) &&
8879  ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
8880  !frozen_string_literal_p(iseq) &&
8881  ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
8882  VALUE str = get_string_value(RNODE_LIST(get_nd_args(node))->nd_head);
8883  CHECK(COMPILE(ret, "recv", get_nd_recv(node)));
8884  ADD_INSN2(ret, line_node, opt_aref_with, str,
8885  new_callinfo(iseq, idAREF, 1, 0, NULL, FALSE));
8886  RB_OBJ_WRITTEN(iseq, Qundef, str);
8887  if (popped) {
8888  ADD_INSN(ret, line_node, pop);
8889  }
8890  return TRUE;
8891  }
8892  return FALSE;
8893 }
8894 
8895 static int
8896 iseq_has_builtin_function_table(const rb_iseq_t *iseq)
8897 {
8898  return ISEQ_COMPILE_DATA(iseq)->builtin_function_table != NULL;
8899 }
8900 
8901 static const struct rb_builtin_function *
8902 iseq_builtin_function_lookup(const rb_iseq_t *iseq, const char *name)
8903 {
8904  int i;
8905  const struct rb_builtin_function *table = ISEQ_COMPILE_DATA(iseq)->builtin_function_table;
8906  for (i=0; table[i].index != -1; i++) {
8907  if (strcmp(table[i].name, name) == 0) {
8908  return &table[i];
8909  }
8910  }
8911  return NULL;
8912 }
8913 
8914 static const char *
8915 iseq_builtin_function_name(const enum node_type type, const NODE *recv, ID mid)
8916 {
8917  const char *name = rb_id2name(mid);
8918  static const char prefix[] = "__builtin_";
8919  const size_t prefix_len = sizeof(prefix) - 1;
8920 
8921  switch (type) {
8922  case NODE_CALL:
8923  if (recv) {
8924  switch (nd_type(recv)) {
8925  case NODE_VCALL:
8926  if (RNODE_VCALL(recv)->nd_mid == rb_intern("__builtin")) {
8927  return name;
8928  }
8929  break;
8930  case NODE_CONST:
8931  if (RNODE_CONST(recv)->nd_vid == rb_intern("Primitive")) {
8932  return name;
8933  }
8934  break;
8935  default: break;
8936  }
8937  }
8938  break;
8939  case NODE_VCALL:
8940  case NODE_FCALL:
8941  if (UNLIKELY(strncmp(prefix, name, prefix_len) == 0)) {
8942  return &name[prefix_len];
8943  }
8944  break;
8945  default: break;
8946  }
8947  return NULL;
8948 }
8949 
8950 static int
8951 delegate_call_p(const rb_iseq_t *iseq, unsigned int argc, const LINK_ANCHOR *args, unsigned int *pstart_index)
8952 {
8953 
8954  if (argc == 0) {
8955  *pstart_index = 0;
8956  return TRUE;
8957  }
8958  else if (argc <= ISEQ_BODY(iseq)->local_table_size) {
8959  unsigned int start=0;
8960 
8961  // local_table: [p1, p2, p3, l1, l2, l3]
8962  // arguments: [p3, l1, l2] -> 2
8963  for (start = 0;
8964  argc + start <= ISEQ_BODY(iseq)->local_table_size;
8965  start++) {
8966  const LINK_ELEMENT *elem = FIRST_ELEMENT(args);
8967 
8968  for (unsigned int i=start; i-start<argc; i++) {
8969  if (IS_INSN(elem) &&
8970  INSN_OF(elem) == BIN(getlocal)) {
8971  int local_index = FIX2INT(OPERAND_AT(elem, 0));
8972  int local_level = FIX2INT(OPERAND_AT(elem, 1));
8973 
8974  if (local_level == 0) {
8975  unsigned int index = ISEQ_BODY(iseq)->local_table_size - (local_index - VM_ENV_DATA_SIZE + 1);
8976  if (0) { // for debug
8977  fprintf(stderr, "lvar:%s (%d), id:%s (%d) local_index:%d, local_size:%d\n",
8978  rb_id2name(ISEQ_BODY(iseq)->local_table[i]), i,
8979  rb_id2name(ISEQ_BODY(iseq)->local_table[index]), index,
8980  local_index, (int)ISEQ_BODY(iseq)->local_table_size);
8981  }
8982  if (i == index) {
8983  elem = elem->next;
8984  continue; /* for */
8985  }
8986  else {
8987  goto next;
8988  }
8989  }
8990  else {
8991  goto fail; // level != 0 is unsupported
8992  }
8993  }
8994  else {
8995  goto fail; // insn is not a getlocal
8996  }
8997  }
8998  goto success;
8999  next:;
9000  }
9001  fail:
9002  return FALSE;
9003  success:
9004  *pstart_index = start;
9005  return TRUE;
9006  }
9007  else {
9008  return FALSE;
9009  }
9010 }
9011 
9012 // Compile Primitive.attr! :leaf, ...
9013 static int
9014 compile_builtin_attr(rb_iseq_t *iseq, const NODE *node)
9015 {
9016  VALUE symbol;
9017  VALUE string;
9018  if (!node) goto no_arg;
9019  while (node) {
9020  if (!nd_type_p(node, NODE_LIST)) goto bad_arg;
9021  const NODE *next = RNODE_LIST(node)->nd_next;
9022 
9023  node = RNODE_LIST(node)->nd_head;
9024  if (!node) goto no_arg;
9025  switch (nd_type(node)) {
9026  case NODE_SYM:
9027  symbol = rb_node_sym_string_val(node);
9028  break;
9029  default:
9030  goto bad_arg;
9031  }
9032 
9033  if (!SYMBOL_P(symbol)) goto non_symbol_arg;
9034 
9035  string = rb_sym2str(symbol);
9036  if (strcmp(RSTRING_PTR(string), "leaf") == 0) {
9037  ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_LEAF;
9038  }
9039  else if (strcmp(RSTRING_PTR(string), "inline_block") == 0) {
9040  ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_INLINE_BLOCK;
9041  }
9042  else if (strcmp(RSTRING_PTR(string), "use_block") == 0) {
9043  iseq_set_use_block(iseq);
9044  }
9045  else if (strcmp(RSTRING_PTR(string), "c_trace") == 0) {
9046  // Let the iseq act like a C method in backtraces
9047  ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_C_TRACE;
9048  }
9049  else {
9050  goto unknown_arg;
9051  }
9052  node = next;
9053  }
9054  return COMPILE_OK;
9055  no_arg:
9056  COMPILE_ERROR(ERROR_ARGS "attr!: no argument");
9057  return COMPILE_NG;
9058  non_symbol_arg:
9059  COMPILE_ERROR(ERROR_ARGS "non symbol argument to attr!: %s", rb_builtin_class_name(symbol));
9060  return COMPILE_NG;
9061  unknown_arg:
9062  COMPILE_ERROR(ERROR_ARGS "unknown argument to attr!: %s", RSTRING_PTR(string));
9063  return COMPILE_NG;
9064  bad_arg:
9065  UNKNOWN_NODE("attr!", node, COMPILE_NG);
9066 }
9067 
9068 static int
9069 compile_builtin_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, const NODE *line_node, int popped)
9070 {
9071  VALUE name;
9072 
9073  if (!node) goto no_arg;
9074  if (!nd_type_p(node, NODE_LIST)) goto bad_arg;
9075  if (RNODE_LIST(node)->nd_next) goto too_many_arg;
9076  node = RNODE_LIST(node)->nd_head;
9077  if (!node) goto no_arg;
9078  switch (nd_type(node)) {
9079  case NODE_SYM:
9080  name = rb_node_sym_string_val(node);
9081  break;
9082  default:
9083  goto bad_arg;
9084  }
9085  if (!SYMBOL_P(name)) goto non_symbol_arg;
9086  if (!popped) {
9087  compile_lvar(iseq, ret, line_node, SYM2ID(name));
9088  }
9089  return COMPILE_OK;
9090  no_arg:
9091  COMPILE_ERROR(ERROR_ARGS "arg!: no argument");
9092  return COMPILE_NG;
9093  too_many_arg:
9094  COMPILE_ERROR(ERROR_ARGS "arg!: too many argument");
9095  return COMPILE_NG;
9096  non_symbol_arg:
9097  COMPILE_ERROR(ERROR_ARGS "non symbol argument to arg!: %s",
9098  rb_builtin_class_name(name));
9099  return COMPILE_NG;
9100  bad_arg:
9101  UNKNOWN_NODE("arg!", node, COMPILE_NG);
9102 }
9103 
9104 static NODE *
9105 mandatory_node(const rb_iseq_t *iseq, const NODE *cond_node)
9106 {
9107  const NODE *node = ISEQ_COMPILE_DATA(iseq)->root_node;
9108  if (nd_type(node) == NODE_IF && RNODE_IF(node)->nd_cond == cond_node) {
9109  return RNODE_IF(node)->nd_body;
9110  }
9111  else {
9112  rb_bug("mandatory_node: can't find mandatory node");
9113  }
9114 }
9115 
9116 static int
9117 compile_builtin_mandatory_only_method(rb_iseq_t *iseq, const NODE *node, const NODE *line_node)
9118 {
9119  // arguments
9120  struct rb_args_info args = {
9121  .pre_args_num = ISEQ_BODY(iseq)->param.lead_num,
9122  };
9123  rb_node_args_t args_node;
9124  rb_node_init(RNODE(&args_node), NODE_ARGS);
9125  args_node.nd_ainfo = args;
9126 
9127  // local table without non-mandatory parameters
9128  const int skip_local_size = ISEQ_BODY(iseq)->param.size - ISEQ_BODY(iseq)->param.lead_num;
9129  const int table_size = ISEQ_BODY(iseq)->local_table_size - skip_local_size;
9130 
9131  VALUE idtmp = 0;
9132  rb_ast_id_table_t *tbl = ALLOCV(idtmp, sizeof(rb_ast_id_table_t) + table_size * sizeof(ID));
9133  tbl->size = table_size;
9134 
9135  int i;
9136 
9137  // lead parameters
9138  for (i=0; i<ISEQ_BODY(iseq)->param.lead_num; i++) {
9139  tbl->ids[i] = ISEQ_BODY(iseq)->local_table[i];
9140  }
9141  // local variables
9142  for (; i<table_size; i++) {
9143  tbl->ids[i] = ISEQ_BODY(iseq)->local_table[i + skip_local_size];
9144  }
9145 
9146  rb_node_scope_t scope_node;
9147  rb_node_init(RNODE(&scope_node), NODE_SCOPE);
9148  scope_node.nd_tbl = tbl;
9149  scope_node.nd_body = mandatory_node(iseq, node);
9150  scope_node.nd_args = &args_node;
9151 
9152  VALUE ast_value = rb_ruby_ast_new(RNODE(&scope_node));
9153 
9154  ISEQ_BODY(iseq)->mandatory_only_iseq =
9155  rb_iseq_new_with_opt(ast_value, rb_iseq_base_label(iseq),
9156  rb_iseq_path(iseq), rb_iseq_realpath(iseq),
9157  nd_line(line_node), NULL, 0,
9158  ISEQ_TYPE_METHOD, ISEQ_COMPILE_DATA(iseq)->option,
9159  ISEQ_BODY(iseq)->variable.script_lines);
9160 
9161  ALLOCV_END(idtmp);
9162  return COMPILE_OK;
9163 }
9164 
9165 static int
9166 compile_builtin_function_call(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, const NODE *line_node, int popped,
9167  const rb_iseq_t *parent_block, LINK_ANCHOR *args, const char *builtin_func)
9168 {
9169  NODE *args_node = get_nd_args(node);
9170 
9171  if (parent_block != NULL) {
9172  COMPILE_ERROR(ERROR_ARGS_AT(line_node) "should not call builtins here.");
9173  return COMPILE_NG;
9174  }
9175  else {
9176 # define BUILTIN_INLINE_PREFIX "_bi"
9177  char inline_func[sizeof(BUILTIN_INLINE_PREFIX) + DECIMAL_SIZE_OF(int)];
9178  bool cconst = false;
9179  retry:;
9180  const struct rb_builtin_function *bf = iseq_builtin_function_lookup(iseq, builtin_func);
9181 
9182  if (bf == NULL) {
9183  if (strcmp("cstmt!", builtin_func) == 0 ||
9184  strcmp("cexpr!", builtin_func) == 0) {
9185  // ok
9186  }
9187  else if (strcmp("cconst!", builtin_func) == 0) {
9188  cconst = true;
9189  }
9190  else if (strcmp("cinit!", builtin_func) == 0) {
9191  // ignore
9192  return COMPILE_OK;
9193  }
9194  else if (strcmp("attr!", builtin_func) == 0) {
9195  return compile_builtin_attr(iseq, args_node);
9196  }
9197  else if (strcmp("arg!", builtin_func) == 0) {
9198  return compile_builtin_arg(iseq, ret, args_node, line_node, popped);
9199  }
9200  else if (strcmp("mandatory_only?", builtin_func) == 0) {
9201  if (popped) {
9202  rb_bug("mandatory_only? should be in if condition");
9203  }
9204  else if (!LIST_INSN_SIZE_ZERO(ret)) {
9205  rb_bug("mandatory_only? should be put on top");
9206  }
9207 
9208  ADD_INSN1(ret, line_node, putobject, Qfalse);
9209  return compile_builtin_mandatory_only_method(iseq, node, line_node);
9210  }
9211  else if (1) {
9212  rb_bug("can't find builtin function:%s", builtin_func);
9213  }
9214  else {
9215  COMPILE_ERROR(ERROR_ARGS "can't find builtin function:%s", builtin_func);
9216  return COMPILE_NG;
9217  }
9218 
9219  int inline_index = nd_line(node);
9220  snprintf(inline_func, sizeof(inline_func), BUILTIN_INLINE_PREFIX "%d", inline_index);
9221  builtin_func = inline_func;
9222  args_node = NULL;
9223  goto retry;
9224  }
9225 
9226  if (cconst) {
9227  typedef VALUE(*builtin_func0)(void *, VALUE);
9228  VALUE const_val = (*(builtin_func0)(uintptr_t)bf->func_ptr)(NULL, Qnil);
9229  ADD_INSN1(ret, line_node, putobject, const_val);
9230  return COMPILE_OK;
9231  }
9232 
9233  // fprintf(stderr, "func_name:%s -> %p\n", builtin_func, bf->func_ptr);
9234 
9235  unsigned int flag = 0;
9236  struct rb_callinfo_kwarg *keywords = NULL;
9237  VALUE argc = setup_args(iseq, args, args_node, &flag, &keywords);
9238 
9239  if (FIX2INT(argc) != bf->argc) {
9240  COMPILE_ERROR(ERROR_ARGS "argc is not match for builtin function:%s (expect %d but %d)",
9241  builtin_func, bf->argc, FIX2INT(argc));
9242  return COMPILE_NG;
9243  }
9244 
9245  unsigned int start_index;
9246  if (delegate_call_p(iseq, FIX2INT(argc), args, &start_index)) {
9247  ADD_INSN2(ret, line_node, opt_invokebuiltin_delegate, bf, INT2FIX(start_index));
9248  }
9249  else {
9250  ADD_SEQ(ret, args);
9251  ADD_INSN1(ret, line_node, invokebuiltin, bf);
9252  }
9253 
9254  if (popped) ADD_INSN(ret, line_node, pop);
9255  return COMPILE_OK;
9256  }
9257 }
9258 
9259 static int
9260 compile_call(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, const enum node_type type, const NODE *const line_node, int popped, bool assume_receiver)
9261 {
9262  /* call: obj.method(...)
9263  * fcall: func(...)
9264  * vcall: func
9265  */
9266  DECL_ANCHOR(recv);
9267  DECL_ANCHOR(args);
9268  ID mid = get_node_call_nd_mid(node);
9269  VALUE argc;
9270  unsigned int flag = 0;
9271  struct rb_callinfo_kwarg *keywords = NULL;
9272  const rb_iseq_t *parent_block = ISEQ_COMPILE_DATA(iseq)->current_block;
9273  LABEL *else_label = NULL;
9274  VALUE branches = Qfalse;
9275 
9276  ISEQ_COMPILE_DATA(iseq)->current_block = NULL;
9277 
9278  INIT_ANCHOR(recv);
9279  INIT_ANCHOR(args);
9280 #if OPT_SUPPORT_JOKE
9281  if (nd_type_p(node, NODE_VCALL)) {
9282  ID id_bitblt;
9283  ID id_answer;
9284 
9285  CONST_ID(id_bitblt, "bitblt");
9286  CONST_ID(id_answer, "the_answer_to_life_the_universe_and_everything");
9287 
9288  if (mid == id_bitblt) {
9289  ADD_INSN(ret, line_node, bitblt);
9290  return COMPILE_OK;
9291  }
9292  else if (mid == id_answer) {
9293  ADD_INSN(ret, line_node, answer);
9294  return COMPILE_OK;
9295  }
9296  }
9297  /* only joke */
9298  {
9299  ID goto_id;
9300  ID label_id;
9301 
9302  CONST_ID(goto_id, "__goto__");
9303  CONST_ID(label_id, "__label__");
9304 
9305  if (nd_type_p(node, NODE_FCALL) &&
9306  (mid == goto_id || mid == label_id)) {
9307  LABEL *label;
9308  st_data_t data;
9309  st_table *labels_table = ISEQ_COMPILE_DATA(iseq)->labels_table;
9310  VALUE label_name;
9311 
9312  if (!labels_table) {
9313  labels_table = st_init_numtable();
9314  ISEQ_COMPILE_DATA(iseq)->labels_table = labels_table;
9315  }
9316  {
9317  COMPILE_ERROR(ERROR_ARGS "invalid goto/label format");
9318  return COMPILE_NG;
9319  }
9320 
9321  if (mid == goto_id) {
9322  ADD_INSNL(ret, line_node, jump, label);
9323  }
9324  else {
9325  ADD_LABEL(ret, label);
9326  }
9327  return COMPILE_OK;
9328  }
9329  }
9330 #endif
9331 
9332  const char *builtin_func;
9333  if (UNLIKELY(iseq_has_builtin_function_table(iseq)) &&
9334  (builtin_func = iseq_builtin_function_name(type, get_nd_recv(node), mid)) != NULL) {
9335  return compile_builtin_function_call(iseq, ret, node, line_node, popped, parent_block, args, builtin_func);
9336  }
9337 
9338  /* receiver */
9339  if (!assume_receiver) {
9340  if (type == NODE_CALL || type == NODE_OPCALL || type == NODE_QCALL) {
9341  int idx, level;
9342 
9343  if (mid == idCall &&
9344  nd_type_p(get_nd_recv(node), NODE_LVAR) &&
9345  iseq_block_param_id_p(iseq, RNODE_LVAR(get_nd_recv(node))->nd_vid, &idx, &level)) {
9346  ADD_INSN2(recv, get_nd_recv(node), getblockparamproxy, INT2FIX(idx + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
9347  }
9348  else if (private_recv_p(node)) {
9349  ADD_INSN(recv, node, putself);
9350  flag |= VM_CALL_FCALL;
9351  }
9352  else {
9353  CHECK(COMPILE(recv, "recv", get_nd_recv(node)));
9354  }
9355 
9356  if (type == NODE_QCALL) {
9357  else_label = qcall_branch_start(iseq, recv, &branches, node, line_node);
9358  }
9359  }
9360  else if (type == NODE_FCALL || type == NODE_VCALL) {
9361  ADD_CALL_RECEIVER(recv, line_node);
9362  }
9363  }
9364 
9365  /* args */
9366  if (type != NODE_VCALL) {
9367  argc = setup_args(iseq, args, get_nd_args(node), &flag, &keywords);
9368  CHECK(!NIL_P(argc));
9369  }
9370  else {
9371  argc = INT2FIX(0);
9372  }
9373 
9374  ADD_SEQ(ret, recv);
9375  ADD_SEQ(ret, args);
9376 
9377  debugp_param("call args argc", argc);
9378  debugp_param("call method", ID2SYM(mid));
9379 
9380  switch ((int)type) {
9381  case NODE_VCALL:
9382  flag |= VM_CALL_VCALL;
9383  /* VCALL is funcall, so fall through */
9384  case NODE_FCALL:
9385  flag |= VM_CALL_FCALL;
9386  }
9387 
9388  if ((flag & VM_CALL_ARGS_BLOCKARG) && (flag & VM_CALL_KW_SPLAT) && !(flag & VM_CALL_KW_SPLAT_MUT)) {
9389  ADD_INSN(ret, line_node, splatkw);
9390  }
9391  ADD_SEND_R(ret, line_node, mid, argc, parent_block, INT2FIX(flag), keywords);
9392 
9393  qcall_branch_end(iseq, ret, else_label, branches, node, line_node);
9394  if (popped) {
9395  ADD_INSN(ret, line_node, pop);
9396  }
9397  return COMPILE_OK;
9398 }
9399 
9400 static int
9401 compile_op_asgn1(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9402 {
9403  const int line = nd_line(node);
9404  VALUE argc;
9405  unsigned int flag = 0;
9406  int asgnflag = 0;
9407  ID id = RNODE_OP_ASGN1(node)->nd_mid;
9408 
9409  /*
9410  * a[x] (op)= y
9411  *
9412  * nil # nil
9413  * eval a # nil a
9414  * eval x # nil a x
9415  * dupn 2 # nil a x a x
9416  * send :[] # nil a x a[x]
9417  * eval y # nil a x a[x] y
9418  * send op # nil a x ret
9419  * setn 3 # ret a x ret
9420  * send []= # ret ?
9421  * pop # ret
9422  */
9423 
9424  /*
9425  * nd_recv[nd_args->nd_body] (nd_mid)= nd_args->nd_head;
9426  * NODE_OP_ASGN nd_recv
9427  * nd_args->nd_head
9428  * nd_args->nd_body
9429  * nd_mid
9430  */
9431 
9432  if (!popped) {
9433  ADD_INSN(ret, node, putnil);
9434  }
9435  asgnflag = COMPILE_RECV(ret, "NODE_OP_ASGN1 recv", node, RNODE_OP_ASGN1(node)->nd_recv);
9436  CHECK(asgnflag != -1);
9437  switch (nd_type(RNODE_OP_ASGN1(node)->nd_index)) {
9438  case NODE_ZLIST:
9439  argc = INT2FIX(0);
9440  break;
9441  default:
9442  argc = setup_args(iseq, ret, RNODE_OP_ASGN1(node)->nd_index, &flag, NULL);
9443  CHECK(!NIL_P(argc));
9444  }
9445  int dup_argn = FIX2INT(argc) + 1;
9446  ADD_INSN1(ret, node, dupn, INT2FIX(dup_argn));
9447  flag |= asgnflag;
9448  ADD_SEND_R(ret, node, idAREF, argc, NULL, INT2FIX(flag & ~VM_CALL_ARGS_SPLAT_MUT), NULL);
9449 
9450  if (id == idOROP || id == idANDOP) {
9451  /* a[x] ||= y or a[x] &&= y
9452 
9453  unless/if a[x]
9454  a[x]= y
9455  else
9456  nil
9457  end
9458  */
9459  LABEL *label = NEW_LABEL(line);
9460  LABEL *lfin = NEW_LABEL(line);
9461 
9462  ADD_INSN(ret, node, dup);
9463  if (id == idOROP) {
9464  ADD_INSNL(ret, node, branchif, label);
9465  }
9466  else { /* idANDOP */
9467  ADD_INSNL(ret, node, branchunless, label);
9468  }
9469  ADD_INSN(ret, node, pop);
9470 
9471  CHECK(COMPILE(ret, "NODE_OP_ASGN1 nd_rvalue: ", RNODE_OP_ASGN1(node)->nd_rvalue));
9472  if (!popped) {
9473  ADD_INSN1(ret, node, setn, INT2FIX(dup_argn+1));
9474  }
9475  if (flag & VM_CALL_ARGS_SPLAT) {
9476  if (!(flag & VM_CALL_ARGS_SPLAT_MUT)) {
9477  ADD_INSN(ret, node, swap);
9478  ADD_INSN1(ret, node, splatarray, Qtrue);
9479  ADD_INSN(ret, node, swap);
9480  flag |= VM_CALL_ARGS_SPLAT_MUT;
9481  }
9482  ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
9483  ADD_SEND_R(ret, node, idASET, argc, NULL, INT2FIX(flag), NULL);
9484  }
9485  else {
9486  ADD_SEND_R(ret, node, idASET, FIXNUM_INC(argc, 1), NULL, INT2FIX(flag), NULL);
9487  }
9488  ADD_INSN(ret, node, pop);
9489  ADD_INSNL(ret, node, jump, lfin);
9490  ADD_LABEL(ret, label);
9491  if (!popped) {
9492  ADD_INSN1(ret, node, setn, INT2FIX(dup_argn+1));
9493  }
9494  ADD_INSN1(ret, node, adjuststack, INT2FIX(dup_argn+1));
9495  ADD_LABEL(ret, lfin);
9496  }
9497  else {
9498  CHECK(COMPILE(ret, "NODE_OP_ASGN1 nd_rvalue: ", RNODE_OP_ASGN1(node)->nd_rvalue));
9499  ADD_SEND(ret, node, id, INT2FIX(1));
9500  if (!popped) {
9501  ADD_INSN1(ret, node, setn, INT2FIX(dup_argn+1));
9502  }
9503  if (flag & VM_CALL_ARGS_SPLAT) {
9504  if (flag & VM_CALL_KW_SPLAT) {
9505  ADD_INSN1(ret, node, topn, INT2FIX(2));
9506  if (!(flag & VM_CALL_ARGS_SPLAT_MUT)) {
9507  ADD_INSN1(ret, node, splatarray, Qtrue);
9508  flag |= VM_CALL_ARGS_SPLAT_MUT;
9509  }
9510  ADD_INSN(ret, node, swap);
9511  ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
9512  ADD_INSN1(ret, node, setn, INT2FIX(2));
9513  ADD_INSN(ret, node, pop);
9514  }
9515  else {
9516  if (!(flag & VM_CALL_ARGS_SPLAT_MUT)) {
9517  ADD_INSN(ret, node, swap);
9518  ADD_INSN1(ret, node, splatarray, Qtrue);
9519  ADD_INSN(ret, node, swap);
9520  flag |= VM_CALL_ARGS_SPLAT_MUT;
9521  }
9522  ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
9523  }
9524  ADD_SEND_R(ret, node, idASET, argc, NULL, INT2FIX(flag), NULL);
9525  }
9526  else {
9527  ADD_SEND_R(ret, node, idASET, FIXNUM_INC(argc, 1), NULL, INT2FIX(flag), NULL);
9528  }
9529  ADD_INSN(ret, node, pop);
9530  }
9531  return COMPILE_OK;
9532 }
9533 
9534 static int
9535 compile_op_asgn2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9536 {
9537  const int line = nd_line(node);
9538  ID atype = RNODE_OP_ASGN2(node)->nd_mid;
9539  ID vid = RNODE_OP_ASGN2(node)->nd_vid, aid = rb_id_attrset(vid);
9540  int asgnflag;
9541  LABEL *lfin = NEW_LABEL(line);
9542  LABEL *lcfin = NEW_LABEL(line);
9543  LABEL *lskip = 0;
9544  /*
9545  class C; attr_accessor :c; end
9546  r = C.new
9547  r.a &&= v # asgn2
9548 
9549  eval r # r
9550  dup # r r
9551  eval r.a # r o
9552 
9553  # or
9554  dup # r o o
9555  if lcfin # r o
9556  pop # r
9557  eval v # r v
9558  swap # v r
9559  topn 1 # v r v
9560  send a= # v ?
9561  jump lfin # v ?
9562 
9563  lcfin: # r o
9564  swap # o r
9565 
9566  lfin: # o ?
9567  pop # o
9568 
9569  # or (popped)
9570  if lcfin # r
9571  eval v # r v
9572  send a= # ?
9573  jump lfin # ?
9574 
9575  lcfin: # r
9576 
9577  lfin: # ?
9578  pop #
9579 
9580  # and
9581  dup # r o o
9582  unless lcfin
9583  pop # r
9584  eval v # r v
9585  swap # v r
9586  topn 1 # v r v
9587  send a= # v ?
9588  jump lfin # v ?
9589 
9590  # others
9591  eval v # r o v
9592  send ?? # r w
9593  send a= # w
9594 
9595  */
9596 
9597  asgnflag = COMPILE_RECV(ret, "NODE_OP_ASGN2#recv", node, RNODE_OP_ASGN2(node)->nd_recv);
9598  CHECK(asgnflag != -1);
9599  if (RNODE_OP_ASGN2(node)->nd_aid) {
9600  lskip = NEW_LABEL(line);
9601  ADD_INSN(ret, node, dup);
9602  ADD_INSNL(ret, node, branchnil, lskip);
9603  }
9604  ADD_INSN(ret, node, dup);
9605  ADD_SEND_WITH_FLAG(ret, node, vid, INT2FIX(0), INT2FIX(asgnflag));
9606 
9607  if (atype == idOROP || atype == idANDOP) {
9608  if (!popped) {
9609  ADD_INSN(ret, node, dup);
9610  }
9611  if (atype == idOROP) {
9612  ADD_INSNL(ret, node, branchif, lcfin);
9613  }
9614  else { /* idANDOP */
9615  ADD_INSNL(ret, node, branchunless, lcfin);
9616  }
9617  if (!popped) {
9618  ADD_INSN(ret, node, pop);
9619  }
9620  CHECK(COMPILE(ret, "NODE_OP_ASGN2 val", RNODE_OP_ASGN2(node)->nd_value));
9621  if (!popped) {
9622  ADD_INSN(ret, node, swap);
9623  ADD_INSN1(ret, node, topn, INT2FIX(1));
9624  }
9625  ADD_SEND_WITH_FLAG(ret, node, aid, INT2FIX(1), INT2FIX(asgnflag));
9626  ADD_INSNL(ret, node, jump, lfin);
9627 
9628  ADD_LABEL(ret, lcfin);
9629  if (!popped) {
9630  ADD_INSN(ret, node, swap);
9631  }
9632 
9633  ADD_LABEL(ret, lfin);
9634  }
9635  else {
9636  CHECK(COMPILE(ret, "NODE_OP_ASGN2 val", RNODE_OP_ASGN2(node)->nd_value));
9637  ADD_SEND(ret, node, atype, INT2FIX(1));
9638  if (!popped) {
9639  ADD_INSN(ret, node, swap);
9640  ADD_INSN1(ret, node, topn, INT2FIX(1));
9641  }
9642  ADD_SEND_WITH_FLAG(ret, node, aid, INT2FIX(1), INT2FIX(asgnflag));
9643  }
9644  if (lskip && popped) {
9645  ADD_LABEL(ret, lskip);
9646  }
9647  ADD_INSN(ret, node, pop);
9648  if (lskip && !popped) {
9649  ADD_LABEL(ret, lskip);
9650  }
9651  return COMPILE_OK;
9652 }
9653 
9654 static int compile_shareable_constant_value(rb_iseq_t *iseq, LINK_ANCHOR *ret, enum rb_parser_shareability shareable, const NODE *lhs, const NODE *value);
9655 
9656 static int
9657 compile_op_cdecl(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9658 {
9659  const int line = nd_line(node);
9660  LABEL *lfin = 0;
9661  LABEL *lassign = 0;
9662  ID mid;
9663 
9664  switch (nd_type(RNODE_OP_CDECL(node)->nd_head)) {
9665  case NODE_COLON3:
9666  ADD_INSN1(ret, node, putobject, rb_cObject);
9667  break;
9668  case NODE_COLON2:
9669  CHECK(COMPILE(ret, "NODE_OP_CDECL/colon2#nd_head", RNODE_COLON2(RNODE_OP_CDECL(node)->nd_head)->nd_head));
9670  break;
9671  default:
9672  COMPILE_ERROR(ERROR_ARGS "%s: invalid node in NODE_OP_CDECL",
9673  ruby_node_name(nd_type(RNODE_OP_CDECL(node)->nd_head)));
9674  return COMPILE_NG;
9675  }
9676  mid = get_node_colon_nd_mid(RNODE_OP_CDECL(node)->nd_head);
9677  /* cref */
9678  if (RNODE_OP_CDECL(node)->nd_aid == idOROP) {
9679  lassign = NEW_LABEL(line);
9680  ADD_INSN(ret, node, dup); /* cref cref */
9681  ADD_INSN3(ret, node, defined, INT2FIX(DEFINED_CONST_FROM),
9682  ID2SYM(mid), Qtrue); /* cref bool */
9683  ADD_INSNL(ret, node, branchunless, lassign); /* cref */
9684  }
9685  ADD_INSN(ret, node, dup); /* cref cref */
9686  ADD_INSN1(ret, node, putobject, Qtrue);
9687  ADD_INSN1(ret, node, getconstant, ID2SYM(mid)); /* cref obj */
9688 
9689  if (RNODE_OP_CDECL(node)->nd_aid == idOROP || RNODE_OP_CDECL(node)->nd_aid == idANDOP) {
9690  lfin = NEW_LABEL(line);
9691  if (!popped) ADD_INSN(ret, node, dup); /* cref [obj] obj */
9692  if (RNODE_OP_CDECL(node)->nd_aid == idOROP)
9693  ADD_INSNL(ret, node, branchif, lfin);
9694  else /* idANDOP */
9695  ADD_INSNL(ret, node, branchunless, lfin);
9696  /* cref [obj] */
9697  if (!popped) ADD_INSN(ret, node, pop); /* cref */
9698  if (lassign) ADD_LABEL(ret, lassign);
9699  CHECK(compile_shareable_constant_value(iseq, ret, RNODE_OP_CDECL(node)->shareability, RNODE_OP_CDECL(node)->nd_head, RNODE_OP_CDECL(node)->nd_value));
9700  /* cref value */
9701  if (popped)
9702  ADD_INSN1(ret, node, topn, INT2FIX(1)); /* cref value cref */
9703  else {
9704  ADD_INSN1(ret, node, dupn, INT2FIX(2)); /* cref value cref value */
9705  ADD_INSN(ret, node, swap); /* cref value value cref */
9706  }
9707  ADD_INSN1(ret, node, setconstant, ID2SYM(mid)); /* cref [value] */
9708  ADD_LABEL(ret, lfin); /* cref [value] */
9709  if (!popped) ADD_INSN(ret, node, swap); /* [value] cref */
9710  ADD_INSN(ret, node, pop); /* [value] */
9711  }
9712  else {
9713  CHECK(compile_shareable_constant_value(iseq, ret, RNODE_OP_CDECL(node)->shareability, RNODE_OP_CDECL(node)->nd_head, RNODE_OP_CDECL(node)->nd_value));
9714  /* cref obj value */
9715  ADD_CALL(ret, node, RNODE_OP_CDECL(node)->nd_aid, INT2FIX(1));
9716  /* cref value */
9717  ADD_INSN(ret, node, swap); /* value cref */
9718  if (!popped) {
9719  ADD_INSN1(ret, node, topn, INT2FIX(1)); /* value cref value */
9720  ADD_INSN(ret, node, swap); /* value value cref */
9721  }
9722  ADD_INSN1(ret, node, setconstant, ID2SYM(mid));
9723  }
9724  return COMPILE_OK;
9725 }
9726 
9727 static int
9728 compile_op_log(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
9729 {
9730  const int line = nd_line(node);
9731  LABEL *lfin = NEW_LABEL(line);
9732  LABEL *lassign;
9733 
9734  if (type == NODE_OP_ASGN_OR && !nd_type_p(RNODE_OP_ASGN_OR(node)->nd_head, NODE_IVAR)) {
9735  LABEL *lfinish[2];
9736  lfinish[0] = lfin;
9737  lfinish[1] = 0;
9738  defined_expr(iseq, ret, RNODE_OP_ASGN_OR(node)->nd_head, lfinish, Qfalse, false);
9739  lassign = lfinish[1];
9740  if (!lassign) {
9741  lassign = NEW_LABEL(line);
9742  }
9743  ADD_INSNL(ret, node, branchunless, lassign);
9744  }
9745  else {
9746  lassign = NEW_LABEL(line);
9747  }
9748 
9749  CHECK(COMPILE(ret, "NODE_OP_ASGN_AND/OR#nd_head", RNODE_OP_ASGN_OR(node)->nd_head));
9750 
9751  if (!popped) {
9752  ADD_INSN(ret, node, dup);
9753  }
9754 
9755  if (type == NODE_OP_ASGN_AND) {
9756  ADD_INSNL(ret, node, branchunless, lfin);
9757  }
9758  else {
9759  ADD_INSNL(ret, node, branchif, lfin);
9760  }
9761 
9762  if (!popped) {
9763  ADD_INSN(ret, node, pop);
9764  }
9765 
9766  ADD_LABEL(ret, lassign);
9767  CHECK(COMPILE_(ret, "NODE_OP_ASGN_AND/OR#nd_value", RNODE_OP_ASGN_OR(node)->nd_value, popped));
9768  ADD_LABEL(ret, lfin);
9769  return COMPILE_OK;
9770 }
9771 
9772 static int
9773 compile_super(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
9774 {
9775  struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
9776  DECL_ANCHOR(args);
9777  int argc;
9778  unsigned int flag = 0;
9779  struct rb_callinfo_kwarg *keywords = NULL;
9780  const rb_iseq_t *parent_block = ISEQ_COMPILE_DATA(iseq)->current_block;
9781  int use_block = 1;
9782 
9783  INIT_ANCHOR(args);
9784  ISEQ_COMPILE_DATA(iseq)->current_block = NULL;
9785 
9786  if (type == NODE_SUPER) {
9787  VALUE vargc = setup_args(iseq, args, RNODE_SUPER(node)->nd_args, &flag, &keywords);
9788  CHECK(!NIL_P(vargc));
9789  argc = FIX2INT(vargc);
9790  if ((flag & VM_CALL_ARGS_BLOCKARG) && (flag & VM_CALL_KW_SPLAT) && !(flag & VM_CALL_KW_SPLAT_MUT)) {
9791  ADD_INSN(args, node, splatkw);
9792  }
9793 
9794  if (flag & VM_CALL_ARGS_BLOCKARG) {
9795  use_block = 0;
9796  }
9797  }
9798  else {
9799  /* NODE_ZSUPER */
9800  int i;
9801  const rb_iseq_t *liseq = body->local_iseq;
9802  const struct rb_iseq_constant_body *const local_body = ISEQ_BODY(liseq);
9803  const struct rb_iseq_param_keyword *const local_kwd = local_body->param.keyword;
9804  int lvar_level = get_lvar_level(iseq);
9805 
9806  argc = local_body->param.lead_num;
9807 
9808  /* normal arguments */
9809  for (i = 0; i < local_body->param.lead_num; i++) {
9810  int idx = local_body->local_table_size - i;
9811  ADD_GETLOCAL(args, node, idx, lvar_level);
9812  }
9813 
9814  /* forward ... */
9815  if (local_body->param.flags.forwardable) {
9816  flag |= VM_CALL_FORWARDING;
9817  int idx = local_body->local_table_size - get_local_var_idx(liseq, idDot3);
9818  ADD_GETLOCAL(args, node, idx, lvar_level);
9819  }
9820 
9821  if (local_body->param.flags.has_opt) {
9822  /* optional arguments */
9823  int j;
9824  for (j = 0; j < local_body->param.opt_num; j++) {
9825  int idx = local_body->local_table_size - (i + j);
9826  ADD_GETLOCAL(args, node, idx, lvar_level);
9827  }
9828  i += j;
9829  argc = i;
9830  }
9831  if (local_body->param.flags.has_rest) {
9832  /* rest argument */
9833  int idx = local_body->local_table_size - local_body->param.rest_start;
9834  ADD_GETLOCAL(args, node, idx, lvar_level);
9835  ADD_INSN1(args, node, splatarray, RBOOL(local_body->param.flags.has_post));
9836 
9837  argc = local_body->param.rest_start + 1;
9838  flag |= VM_CALL_ARGS_SPLAT;
9839  }
9840  if (local_body->param.flags.has_post) {
9841  /* post arguments */
9842  int post_len = local_body->param.post_num;
9843  int post_start = local_body->param.post_start;
9844 
9845  if (local_body->param.flags.has_rest) {
9846  int j;
9847  for (j=0; j<post_len; j++) {
9848  int idx = local_body->local_table_size - (post_start + j);
9849  ADD_GETLOCAL(args, node, idx, lvar_level);
9850  }
9851  ADD_INSN1(args, node, pushtoarray, INT2FIX(j));
9852  flag |= VM_CALL_ARGS_SPLAT_MUT;
9853  /* argc is settled at above */
9854  }
9855  else {
9856  int j;
9857  for (j=0; j<post_len; j++) {
9858  int idx = local_body->local_table_size - (post_start + j);
9859  ADD_GETLOCAL(args, node, idx, lvar_level);
9860  }
9861  argc = post_len + post_start;
9862  }
9863  }
9864 
9865  if (local_body->param.flags.has_kw) { /* TODO: support keywords */
9866  int local_size = local_body->local_table_size;
9867  argc++;
9868 
9869  ADD_INSN1(args, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
9870 
9871  if (local_body->param.flags.has_kwrest) {
9872  int idx = local_body->local_table_size - local_kwd->rest_start;
9873  ADD_GETLOCAL(args, node, idx, lvar_level);
9874  RUBY_ASSERT(local_kwd->num > 0);
9875  ADD_SEND (args, node, rb_intern("dup"), INT2FIX(0));
9876  }
9877  else {
9878  ADD_INSN1(args, node, newhash, INT2FIX(0));
9879  }
9880  for (i = 0; i < local_kwd->num; ++i) {
9881  ID id = local_kwd->table[i];
9882  int idx = local_size - get_local_var_idx(liseq, id);
9883  ADD_INSN1(args, node, putobject, ID2SYM(id));
9884  ADD_GETLOCAL(args, node, idx, lvar_level);
9885  }
9886  ADD_SEND(args, node, id_core_hash_merge_ptr, INT2FIX(i * 2 + 1));
9887  flag |= VM_CALL_KW_SPLAT| VM_CALL_KW_SPLAT_MUT;
9888  }
9889  else if (local_body->param.flags.has_kwrest) {
9890  int idx = local_body->local_table_size - local_kwd->rest_start;
9891  ADD_GETLOCAL(args, node, idx, lvar_level);
9892  argc++;
9893  flag |= VM_CALL_KW_SPLAT;
9894  }
9895  }
9896 
9897  if (use_block && parent_block == NULL) {
9898  iseq_set_use_block(ISEQ_BODY(iseq)->local_iseq);
9899  }
9900 
9901  flag |= VM_CALL_SUPER | VM_CALL_FCALL;
9902  if (type == NODE_ZSUPER) flag |= VM_CALL_ZSUPER;
9903  ADD_INSN(ret, node, putself);
9904  ADD_SEQ(ret, args);
9905 
9906  const struct rb_callinfo * ci = new_callinfo(iseq, 0, argc, flag, keywords, parent_block != NULL);
9907 
9908  if (vm_ci_flag(ci) & VM_CALL_FORWARDING) {
9909  ADD_INSN2(ret, node, invokesuperforward, ci, parent_block);
9910  }
9911  else {
9912  ADD_INSN2(ret, node, invokesuper, ci, parent_block);
9913  }
9914 
9915  if (popped) {
9916  ADD_INSN(ret, node, pop);
9917  }
9918  return COMPILE_OK;
9919 }
9920 
9921 static int
9922 compile_yield(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9923 {
9924  DECL_ANCHOR(args);
9925  VALUE argc;
9926  unsigned int flag = 0;
9927  struct rb_callinfo_kwarg *keywords = NULL;
9928 
9929  INIT_ANCHOR(args);
9930 
9931  switch (ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->type) {
9932  case ISEQ_TYPE_TOP:
9933  case ISEQ_TYPE_MAIN:
9934  case ISEQ_TYPE_CLASS:
9935  COMPILE_ERROR(ERROR_ARGS "Invalid yield");
9936  return COMPILE_NG;
9937  default: /* valid */;
9938  }
9939 
9940  if (RNODE_YIELD(node)->nd_head) {
9941  argc = setup_args(iseq, args, RNODE_YIELD(node)->nd_head, &flag, &keywords);
9942  CHECK(!NIL_P(argc));
9943  }
9944  else {
9945  argc = INT2FIX(0);
9946  }
9947 
9948  ADD_SEQ(ret, args);
9949  ADD_INSN1(ret, node, invokeblock, new_callinfo(iseq, 0, FIX2INT(argc), flag, keywords, FALSE));
9950  iseq_set_use_block(ISEQ_BODY(iseq)->local_iseq);
9951 
9952  if (popped) {
9953  ADD_INSN(ret, node, pop);
9954  }
9955 
9956  int level = 0;
9957  const rb_iseq_t *tmp_iseq = iseq;
9958  for (; tmp_iseq != ISEQ_BODY(iseq)->local_iseq; level++ ) {
9959  tmp_iseq = ISEQ_BODY(tmp_iseq)->parent_iseq;
9960  }
9961  if (level > 0) access_outer_variables(iseq, level, rb_intern("yield"), true);
9962 
9963  return COMPILE_OK;
9964 }
9965 
9966 static int
9967 compile_match(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
9968 {
9969  DECL_ANCHOR(recv);
9970  DECL_ANCHOR(val);
9971 
9972  INIT_ANCHOR(recv);
9973  INIT_ANCHOR(val);
9974  switch ((int)type) {
9975  case NODE_MATCH:
9976  ADD_INSN1(recv, node, putobject, rb_node_regx_string_val(node));
9977  ADD_INSN2(val, node, getspecial, INT2FIX(0),
9978  INT2FIX(0));
9979  break;
9980  case NODE_MATCH2:
9981  CHECK(COMPILE(recv, "receiver", RNODE_MATCH2(node)->nd_recv));
9982  CHECK(COMPILE(val, "value", RNODE_MATCH2(node)->nd_value));
9983  break;
9984  case NODE_MATCH3:
9985  CHECK(COMPILE(recv, "receiver", RNODE_MATCH3(node)->nd_value));
9986  CHECK(COMPILE(val, "value", RNODE_MATCH3(node)->nd_recv));
9987  break;
9988  }
9989 
9990  ADD_SEQ(ret, recv);
9991  ADD_SEQ(ret, val);
9992  ADD_SEND(ret, node, idEqTilde, INT2FIX(1));
9993 
9994  if (nd_type_p(node, NODE_MATCH2) && RNODE_MATCH2(node)->nd_args) {
9995  compile_named_capture_assign(iseq, ret, RNODE_MATCH2(node)->nd_args);
9996  }
9997 
9998  if (popped) {
9999  ADD_INSN(ret, node, pop);
10000  }
10001  return COMPILE_OK;
10002 }
10003 
10004 static int
10005 compile_colon2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10006 {
10007  if (rb_is_const_id(RNODE_COLON2(node)->nd_mid)) {
10008  /* constant */
10009  VALUE segments;
10010  if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache &&
10011  (segments = collect_const_segments(iseq, node))) {
10012  ISEQ_BODY(iseq)->ic_size++;
10013  ADD_INSN1(ret, node, opt_getconstant_path, segments);
10014  RB_OBJ_WRITTEN(iseq, Qundef, segments);
10015  }
10016  else {
10017  /* constant */
10018  DECL_ANCHOR(pref);
10019  DECL_ANCHOR(body);
10020 
10021  INIT_ANCHOR(pref);
10022  INIT_ANCHOR(body);
10023  CHECK(compile_const_prefix(iseq, node, pref, body));
10024  if (LIST_INSN_SIZE_ZERO(pref)) {
10025  ADD_INSN(ret, node, putnil);
10026  ADD_SEQ(ret, body);
10027  }
10028  else {
10029  ADD_SEQ(ret, pref);
10030  ADD_SEQ(ret, body);
10031  }
10032  }
10033  }
10034  else {
10035  /* function call */
10036  ADD_CALL_RECEIVER(ret, node);
10037  CHECK(COMPILE(ret, "colon2#nd_head", RNODE_COLON2(node)->nd_head));
10038  ADD_CALL(ret, node, RNODE_COLON2(node)->nd_mid, INT2FIX(1));
10039  }
10040  if (popped) {
10041  ADD_INSN(ret, node, pop);
10042  }
10043  return COMPILE_OK;
10044 }
10045 
10046 static int
10047 compile_colon3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10048 {
10049  debugi("colon3#nd_mid", RNODE_COLON3(node)->nd_mid);
10050 
10051  /* add cache insn */
10052  if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
10053  ISEQ_BODY(iseq)->ic_size++;
10054  VALUE segments = rb_ary_new_from_args(2, ID2SYM(idNULL), ID2SYM(RNODE_COLON3(node)->nd_mid));
10055  ADD_INSN1(ret, node, opt_getconstant_path, segments);
10056  RB_OBJ_WRITTEN(iseq, Qundef, segments);
10057  }
10058  else {
10059  ADD_INSN1(ret, node, putobject, rb_cObject);
10060  ADD_INSN1(ret, node, putobject, Qtrue);
10061  ADD_INSN1(ret, node, getconstant, ID2SYM(RNODE_COLON3(node)->nd_mid));
10062  }
10063 
10064  if (popped) {
10065  ADD_INSN(ret, node, pop);
10066  }
10067  return COMPILE_OK;
10068 }
10069 
10070 static int
10071 compile_dots(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const int excl)
10072 {
10073  VALUE flag = INT2FIX(excl);
10074  const NODE *b = RNODE_DOT2(node)->nd_beg;
10075  const NODE *e = RNODE_DOT2(node)->nd_end;
10076 
10077  if (optimizable_range_item_p(b) && optimizable_range_item_p(e)) {
10078  if (!popped) {
10079  VALUE bv = optimized_range_item(b);
10080  VALUE ev = optimized_range_item(e);
10081  VALUE val = rb_range_new(bv, ev, excl);
10082  ADD_INSN1(ret, node, putobject, val);
10083  RB_OBJ_WRITTEN(iseq, Qundef, val);
10084  }
10085  }
10086  else {
10087  CHECK(COMPILE_(ret, "min", b, popped));
10088  CHECK(COMPILE_(ret, "max", e, popped));
10089  if (!popped) {
10090  ADD_INSN1(ret, node, newrange, flag);
10091  }
10092  }
10093  return COMPILE_OK;
10094 }
10095 
10096 static int
10097 compile_errinfo(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10098 {
10099  if (!popped) {
10100  if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_RESCUE) {
10101  ADD_GETLOCAL(ret, node, LVAR_ERRINFO, 0);
10102  }
10103  else {
10104  const rb_iseq_t *ip = iseq;
10105  int level = 0;
10106  while (ip) {
10107  if (ISEQ_BODY(ip)->type == ISEQ_TYPE_RESCUE) {
10108  break;
10109  }
10110  ip = ISEQ_BODY(ip)->parent_iseq;
10111  level++;
10112  }
10113  if (ip) {
10114  ADD_GETLOCAL(ret, node, LVAR_ERRINFO, level);
10115  }
10116  else {
10117  ADD_INSN(ret, node, putnil);
10118  }
10119  }
10120  }
10121  return COMPILE_OK;
10122 }
10123 
10124 static int
10125 compile_kw_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10126 {
10127  struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
10128  LABEL *end_label = NEW_LABEL(nd_line(node));
10129  const NODE *default_value = get_nd_value(RNODE_KW_ARG(node)->nd_body);
10130 
10131  if (default_value == NODE_SPECIAL_REQUIRED_KEYWORD) {
10132  /* required argument. do nothing */
10133  COMPILE_ERROR(ERROR_ARGS "unreachable");
10134  return COMPILE_NG;
10135  }
10136  else if (nd_type_p(default_value, NODE_SYM) ||
10137  nd_type_p(default_value, NODE_REGX) ||
10138  nd_type_p(default_value, NODE_LINE) ||
10139  nd_type_p(default_value, NODE_INTEGER) ||
10140  nd_type_p(default_value, NODE_FLOAT) ||
10141  nd_type_p(default_value, NODE_RATIONAL) ||
10142  nd_type_p(default_value, NODE_IMAGINARY) ||
10143  nd_type_p(default_value, NODE_NIL) ||
10144  nd_type_p(default_value, NODE_TRUE) ||
10145  nd_type_p(default_value, NODE_FALSE)) {
10146  COMPILE_ERROR(ERROR_ARGS "unreachable");
10147  return COMPILE_NG;
10148  }
10149  else {
10150  /* if keywordcheck(_kw_bits, nth_keyword)
10151  * kw = default_value
10152  * end
10153  */
10154  int kw_bits_idx = body->local_table_size - body->param.keyword->bits_start;
10155  int keyword_idx = body->param.keyword->num;
10156 
10157  ADD_INSN2(ret, node, checkkeyword, INT2FIX(kw_bits_idx + VM_ENV_DATA_SIZE - 1), INT2FIX(keyword_idx));
10158  ADD_INSNL(ret, node, branchif, end_label);
10159  CHECK(COMPILE_POPPED(ret, "keyword default argument", RNODE_KW_ARG(node)->nd_body));
10160  ADD_LABEL(ret, end_label);
10161  }
10162  return COMPILE_OK;
10163 }
10164 
10165 static int
10166 compile_attrasgn(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10167 {
10168  DECL_ANCHOR(recv);
10169  DECL_ANCHOR(args);
10170  unsigned int flag = 0;
10171  ID mid = RNODE_ATTRASGN(node)->nd_mid;
10172  VALUE argc;
10173  LABEL *else_label = NULL;
10174  VALUE branches = Qfalse;
10175 
10176  /* optimization shortcut
10177  * obj["literal"] = value -> opt_aset_with(obj, "literal", value)
10178  */
10179  if (mid == idASET && !private_recv_p(node) && RNODE_ATTRASGN(node)->nd_args &&
10180  nd_type_p(RNODE_ATTRASGN(node)->nd_args, NODE_LIST) && RNODE_LIST(RNODE_ATTRASGN(node)->nd_args)->as.nd_alen == 2 &&
10181  (nd_type_p(RNODE_LIST(RNODE_ATTRASGN(node)->nd_args)->nd_head, NODE_STR) || nd_type_p(RNODE_LIST(RNODE_ATTRASGN(node)->nd_args)->nd_head, NODE_FILE)) &&
10182  ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
10183  !frozen_string_literal_p(iseq) &&
10184  ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction)
10185  {
10186  VALUE str = get_string_value(RNODE_LIST(RNODE_ATTRASGN(node)->nd_args)->nd_head);
10187  CHECK(COMPILE(ret, "recv", RNODE_ATTRASGN(node)->nd_recv));
10188  CHECK(COMPILE(ret, "value", RNODE_LIST(RNODE_LIST(RNODE_ATTRASGN(node)->nd_args)->nd_next)->nd_head));
10189  if (!popped) {
10190  ADD_INSN(ret, node, swap);
10191  ADD_INSN1(ret, node, topn, INT2FIX(1));
10192  }
10193  ADD_INSN2(ret, node, opt_aset_with, str,
10194  new_callinfo(iseq, idASET, 2, 0, NULL, FALSE));
10195  RB_OBJ_WRITTEN(iseq, Qundef, str);
10196  ADD_INSN(ret, node, pop);
10197  return COMPILE_OK;
10198  }
10199 
10200  INIT_ANCHOR(recv);
10201  INIT_ANCHOR(args);
10202  argc = setup_args(iseq, args, RNODE_ATTRASGN(node)->nd_args, &flag, NULL);
10203  CHECK(!NIL_P(argc));
10204 
10205  int asgnflag = COMPILE_RECV(recv, "recv", node, RNODE_ATTRASGN(node)->nd_recv);
10206  CHECK(asgnflag != -1);
10207  flag |= (unsigned int)asgnflag;
10208 
10209  debugp_param("argc", argc);
10210  debugp_param("nd_mid", ID2SYM(mid));
10211 
10212  if (!rb_is_attrset_id(mid)) {
10213  /* safe nav attr */
10214  mid = rb_id_attrset(mid);
10215  else_label = qcall_branch_start(iseq, recv, &branches, node, node);
10216  }
10217  if (!popped) {
10218  ADD_INSN(ret, node, putnil);
10219  ADD_SEQ(ret, recv);
10220  ADD_SEQ(ret, args);
10221 
10222  if (flag & VM_CALL_ARGS_SPLAT) {
10223  ADD_INSN(ret, node, dup);
10224  ADD_INSN1(ret, node, putobject, INT2FIX(-1));
10225  ADD_SEND_WITH_FLAG(ret, node, idAREF, INT2FIX(1), INT2FIX(asgnflag));
10226  ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 2));
10227  ADD_INSN (ret, node, pop);
10228  }
10229  else {
10230  ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 1));
10231  }
10232  }
10233  else {
10234  ADD_SEQ(ret, recv);
10235  ADD_SEQ(ret, args);
10236  }
10237  ADD_SEND_WITH_FLAG(ret, node, mid, argc, INT2FIX(flag));
10238  qcall_branch_end(iseq, ret, else_label, branches, node, node);
10239  ADD_INSN(ret, node, pop);
10240  return COMPILE_OK;
10241 }
10242 
10243 static int
10244 compile_make_shareable_node(rb_iseq_t *iseq, LINK_ANCHOR *ret, LINK_ANCHOR *sub, const NODE *value, bool copy)
10245 {
10246  ADD_INSN1(ret, value, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
10247  ADD_SEQ(ret, sub);
10248 
10249  if (copy) {
10250  /*
10251  * NEW_CALL(fcore, rb_intern("make_shareable_copy"),
10252  * NEW_LIST(value, loc), loc);
10253  */
10254  ADD_SEND_WITH_FLAG(ret, value, rb_intern("make_shareable_copy"), INT2FIX(1), INT2FIX(VM_CALL_ARGS_SIMPLE));
10255  }
10256  else {
10257  /*
10258  * NEW_CALL(fcore, rb_intern("make_shareable"),
10259  * NEW_LIST(value, loc), loc);
10260  */
10261  ADD_SEND_WITH_FLAG(ret, value, rb_intern("make_shareable"), INT2FIX(1), INT2FIX(VM_CALL_ARGS_SIMPLE));
10262  }
10263 
10264  return COMPILE_OK;
10265 }
10266 
10267 static VALUE
10268 node_const_decl_val(const NODE *node)
10269 {
10270  VALUE path;
10271  switch (nd_type(node)) {
10272  case NODE_CDECL:
10273  if (RNODE_CDECL(node)->nd_vid) {
10274  path = rb_id2str(RNODE_CDECL(node)->nd_vid);
10275  goto end;
10276  }
10277  else {
10278  node = RNODE_CDECL(node)->nd_else;
10279  }
10280  break;
10281  case NODE_COLON2:
10282  break;
10283  case NODE_COLON3:
10284  // ::Const
10285  path = rb_str_new_cstr("::");
10286  rb_str_append(path, rb_id2str(RNODE_COLON3(node)->nd_mid));
10287  goto end;
10288  default:
10289  rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
10290  UNREACHABLE_RETURN(0);
10291  }
10292 
10293  path = rb_ary_new();
10294  if (node) {
10295  for (; node && nd_type_p(node, NODE_COLON2); node = RNODE_COLON2(node)->nd_head) {
10296  rb_ary_push(path, rb_id2str(RNODE_COLON2(node)->nd_mid));
10297  }
10298  if (node && nd_type_p(node, NODE_CONST)) {
10299  // Const::Name
10300  rb_ary_push(path, rb_id2str(RNODE_CONST(node)->nd_vid));
10301  }
10302  else if (node && nd_type_p(node, NODE_COLON3)) {
10303  // ::Const::Name
10304  rb_ary_push(path, rb_id2str(RNODE_COLON3(node)->nd_mid));
10305  rb_ary_push(path, rb_str_new(0, 0));
10306  }
10307  else {
10308  // expression::Name
10309  rb_ary_push(path, rb_str_new_cstr("..."));
10310  }
10311  path = rb_ary_join(rb_ary_reverse(path), rb_str_new_cstr("::"));
10312  }
10313  end:
10314  path = rb_fstring(path);
10315  return path;
10316 }
10317 
10318 static VALUE
10319 const_decl_path(NODE *dest)
10320 {
10321  VALUE path = Qnil;
10322  if (!nd_type_p(dest, NODE_CALL)) {
10323  path = node_const_decl_val(dest);
10324  }
10325  return path;
10326 }
10327 
10328 static int
10329 compile_ensure_shareable_node(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE *dest, const NODE *value)
10330 {
10331  /*
10332  *. RubyVM::FrozenCore.ensure_shareable(value, const_decl_path(dest))
10333  */
10334  VALUE path = const_decl_path(dest);
10335  ADD_INSN1(ret, value, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
10336  CHECK(COMPILE(ret, "compile_ensure_shareable_node", value));
10337  ADD_INSN1(ret, value, putobject, path);
10338  RB_OBJ_WRITTEN(iseq, Qundef, path);
10339  ADD_SEND_WITH_FLAG(ret, value, rb_intern("ensure_shareable"), INT2FIX(2), INT2FIX(VM_CALL_ARGS_SIMPLE));
10340 
10341  return COMPILE_OK;
10342 }
10343 
10344 #ifndef SHAREABLE_BARE_EXPRESSION
10345 #define SHAREABLE_BARE_EXPRESSION 1
10346 #endif
10347 
10348 static int
10349 compile_shareable_literal_constant(rb_iseq_t *iseq, LINK_ANCHOR *ret, enum rb_parser_shareability shareable, NODE *dest, const NODE *node, size_t level, VALUE *value_p, int *shareable_literal_p)
10350 {
10351 # define compile_shareable_literal_constant_next(node, anchor, value_p, shareable_literal_p) \
10352  compile_shareable_literal_constant(iseq, anchor, shareable, dest, node, level+1, value_p, shareable_literal_p)
10353  VALUE lit = Qnil;
10354  DECL_ANCHOR(anchor);
10355 
10356  enum node_type type = nd_type(node);
10357  switch (type) {
10358  case NODE_TRUE:
10359  *value_p = Qtrue;
10360  goto compile;
10361  case NODE_FALSE:
10362  *value_p = Qfalse;
10363  goto compile;
10364  case NODE_NIL:
10365  *value_p = Qnil;
10366  goto compile;
10367  case NODE_SYM:
10368  *value_p = rb_node_sym_string_val(node);
10369  goto compile;
10370  case NODE_REGX:
10371  *value_p = rb_node_regx_string_val(node);
10372  goto compile;
10373  case NODE_LINE:
10374  *value_p = rb_node_line_lineno_val(node);
10375  goto compile;
10376  case NODE_INTEGER:
10377  *value_p = rb_node_integer_literal_val(node);
10378  goto compile;
10379  case NODE_FLOAT:
10380  *value_p = rb_node_float_literal_val(node);
10381  goto compile;
10382  case NODE_RATIONAL:
10383  *value_p = rb_node_rational_literal_val(node);
10384  goto compile;
10385  case NODE_IMAGINARY:
10386  *value_p = rb_node_imaginary_literal_val(node);
10387  goto compile;
10388  case NODE_ENCODING:
10389  *value_p = rb_node_encoding_val(node);
10390 
10391  compile:
10392  CHECK(COMPILE(ret, "shareable_literal_constant", node));
10393  *shareable_literal_p = 1;
10394  return COMPILE_OK;
10395 
10396  case NODE_DSTR:
10397  CHECK(COMPILE(ret, "shareable_literal_constant", node));
10398  if (shareable == rb_parser_shareable_literal) {
10399  /*
10400  * NEW_CALL(node, idUMinus, 0, loc);
10401  *
10402  * -"#{var}"
10403  */
10404  ADD_SEND_WITH_FLAG(ret, node, idUMinus, INT2FIX(0), INT2FIX(VM_CALL_ARGS_SIMPLE));
10405  }
10406  *value_p = Qundef;
10407  *shareable_literal_p = 1;
10408  return COMPILE_OK;
10409 
10410  case NODE_STR:{
10411  VALUE lit = rb_node_str_string_val(node);
10412  ADD_INSN1(ret, node, putobject, lit);
10413  RB_OBJ_WRITTEN(iseq, Qundef, lit);
10414  *value_p = lit;
10415  *shareable_literal_p = 1;
10416 
10417  return COMPILE_OK;
10418  }
10419 
10420  case NODE_FILE:{
10421  VALUE lit = rb_node_file_path_val(node);
10422  ADD_INSN1(ret, node, putobject, lit);
10423  RB_OBJ_WRITTEN(iseq, Qundef, lit);
10424  *value_p = lit;
10425  *shareable_literal_p = 1;
10426 
10427  return COMPILE_OK;
10428  }
10429 
10430  case NODE_ZLIST:{
10431  VALUE lit = rb_ary_new();
10432  OBJ_FREEZE(lit);
10433  ADD_INSN1(ret, node, putobject, lit);
10434  RB_OBJ_WRITTEN(iseq, Qundef, lit);
10435  *value_p = lit;
10436  *shareable_literal_p = 1;
10437 
10438  return COMPILE_OK;
10439  }
10440 
10441  case NODE_LIST:{
10442  INIT_ANCHOR(anchor);
10443  lit = rb_ary_new();
10444  for (NODE *n = (NODE *)node; n; n = RNODE_LIST(n)->nd_next) {
10445  VALUE val;
10446  int shareable_literal_p2;
10447  NODE *elt = RNODE_LIST(n)->nd_head;
10448  if (elt) {
10449  CHECK(compile_shareable_literal_constant_next(elt, anchor, &val, &shareable_literal_p2));
10450  if (shareable_literal_p2) {
10451  /* noop */
10452  }
10453  else if (RTEST(lit)) {
10454  rb_ary_clear(lit);
10455  lit = Qfalse;
10456  }
10457  }
10458  if (RTEST(lit)) {
10459  if (!UNDEF_P(val)) {
10460  rb_ary_push(lit, val);
10461  }
10462  else {
10463  rb_ary_clear(lit);
10464  lit = Qnil; /* make shareable at runtime */
10465  }
10466  }
10467  }
10468  break;
10469  }
10470  case NODE_HASH:{
10471  if (!RNODE_HASH(node)->nd_brace) {
10472  *value_p = Qundef;
10473  *shareable_literal_p = 0;
10474  return COMPILE_OK;
10475  }
10476 
10477  INIT_ANCHOR(anchor);
10478  lit = rb_hash_new();
10479  for (NODE *n = RNODE_HASH(node)->nd_head; n; n = RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_next) {
10480  VALUE key_val;
10481  VALUE value_val;
10482  int shareable_literal_p2;
10483  NODE *key = RNODE_LIST(n)->nd_head;
10484  NODE *val = RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_head;
10485  if (key) {
10486  CHECK(compile_shareable_literal_constant_next(key, anchor, &key_val, &shareable_literal_p2));
10487  if (shareable_literal_p2) {
10488  /* noop */
10489  }
10490  else if (RTEST(lit)) {
10491  rb_hash_clear(lit);
10492  lit = Qfalse;
10493  }
10494  }
10495  if (val) {
10496  CHECK(compile_shareable_literal_constant_next(val, anchor, &value_val, &shareable_literal_p2));
10497  if (shareable_literal_p2) {
10498  /* noop */
10499  }
10500  else if (RTEST(lit)) {
10501  rb_hash_clear(lit);
10502  lit = Qfalse;
10503  }
10504  }
10505  if (RTEST(lit)) {
10506  if (!UNDEF_P(key_val) && !UNDEF_P(value_val)) {
10507  rb_hash_aset(lit, key_val, value_val);
10508  }
10509  else {
10510  rb_hash_clear(lit);
10511  lit = Qnil; /* make shareable at runtime */
10512  }
10513  }
10514  }
10515  break;
10516  }
10517 
10518  default:
10519  if (shareable == rb_parser_shareable_literal &&
10520  (SHAREABLE_BARE_EXPRESSION || level > 0)) {
10521  CHECK(compile_ensure_shareable_node(iseq, ret, dest, node));
10522  *value_p = Qundef;
10523  *shareable_literal_p = 1;
10524  return COMPILE_OK;
10525  }
10526  CHECK(COMPILE(ret, "shareable_literal_constant", node));
10527  *value_p = Qundef;
10528  *shareable_literal_p = 0;
10529  return COMPILE_OK;
10530  }
10531 
10532  /* Array or Hash */
10533  if (!lit) {
10534  if (nd_type(node) == NODE_LIST) {
10535  ADD_INSN1(anchor, node, newarray, INT2FIX(RNODE_LIST(node)->as.nd_alen));
10536  }
10537  else if (nd_type(node) == NODE_HASH) {
10538  int len = (int)RNODE_LIST(RNODE_HASH(node)->nd_head)->as.nd_alen;
10539  ADD_INSN1(anchor, node, newhash, INT2FIX(len));
10540  }
10541  *value_p = Qundef;
10542  *shareable_literal_p = 0;
10543  ADD_SEQ(ret, anchor);
10544  return COMPILE_OK;
10545  }
10546  if (NIL_P(lit)) {
10547  // if shareable_literal, all elements should have been ensured
10548  // as shareable
10549  if (nd_type(node) == NODE_LIST) {
10550  ADD_INSN1(anchor, node, newarray, INT2FIX(RNODE_LIST(node)->as.nd_alen));
10551  }
10552  else if (nd_type(node) == NODE_HASH) {
10553  int len = (int)RNODE_LIST(RNODE_HASH(node)->nd_head)->as.nd_alen;
10554  ADD_INSN1(anchor, node, newhash, INT2FIX(len));
10555  }
10556  CHECK(compile_make_shareable_node(iseq, ret, anchor, node, false));
10557  *value_p = Qundef;
10558  *shareable_literal_p = 1;
10559  }
10560  else {
10561  VALUE val = rb_ractor_make_shareable(lit);
10562  ADD_INSN1(ret, node, putobject, val);
10563  RB_OBJ_WRITTEN(iseq, Qundef, val);
10564  *value_p = val;
10565  *shareable_literal_p = 1;
10566  }
10567 
10568  return COMPILE_OK;
10569 }
10570 
10571 static int
10572 compile_shareable_constant_value(rb_iseq_t *iseq, LINK_ANCHOR *ret, enum rb_parser_shareability shareable, const NODE *lhs, const NODE *value)
10573 {
10574  int literal_p = 0;
10575  VALUE val;
10576  DECL_ANCHOR(anchor);
10577  INIT_ANCHOR(anchor);
10578 
10579  switch (shareable) {
10580  case rb_parser_shareable_none:
10581  CHECK(COMPILE(ret, "compile_shareable_constant_value", value));
10582  return COMPILE_OK;
10583 
10584  case rb_parser_shareable_literal:
10585  CHECK(compile_shareable_literal_constant(iseq, anchor, shareable, (NODE *)lhs, value, 0, &val, &literal_p));
10586  ADD_SEQ(ret, anchor);
10587  return COMPILE_OK;
10588 
10589  case rb_parser_shareable_copy:
10590  case rb_parser_shareable_everything:
10591  CHECK(compile_shareable_literal_constant(iseq, anchor, shareable, (NODE *)lhs, value, 0, &val, &literal_p));
10592  if (!literal_p) {
10593  CHECK(compile_make_shareable_node(iseq, ret, anchor, value, shareable == rb_parser_shareable_copy));
10594  }
10595  else {
10596  ADD_SEQ(ret, anchor);
10597  }
10598  return COMPILE_OK;
10599  default:
10600  rb_bug("unexpected rb_parser_shareability: %d", shareable);
10601  }
10602 }
10603 
10604 static int iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped);
10612 static int
10613 iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *node, int popped)
10614 {
10615  if (node == 0) {
10616  if (!popped) {
10617  int lineno = ISEQ_COMPILE_DATA(iseq)->last_line;
10618  if (lineno == 0) lineno = FIX2INT(rb_iseq_first_lineno(iseq));
10619  debugs("node: NODE_NIL(implicit)\n");
10620  ADD_SYNTHETIC_INSN(ret, lineno, -1, putnil);
10621  }
10622  return COMPILE_OK;
10623  }
10624  return iseq_compile_each0(iseq, ret, node, popped);
10625 }
10626 
10627 static int
10628 iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10629 {
10630  const int line = (int)nd_line(node);
10631  const enum node_type type = nd_type(node);
10632  struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
10633 
10634  if (ISEQ_COMPILE_DATA(iseq)->last_line == line) {
10635  /* ignore */
10636  }
10637  else {
10638  if (nd_fl_newline(node)) {
10639  int event = RUBY_EVENT_LINE;
10640  ISEQ_COMPILE_DATA(iseq)->last_line = line;
10641  if (ISEQ_COVERAGE(iseq) && ISEQ_LINE_COVERAGE(iseq)) {
10642  event |= RUBY_EVENT_COVERAGE_LINE;
10643  }
10644  ADD_TRACE(ret, event);
10645  }
10646  }
10647 
10648  debug_node_start(node);
10649 #undef BEFORE_RETURN
10650 #define BEFORE_RETURN debug_node_end()
10651 
10652  switch (type) {
10653  case NODE_BLOCK:
10654  CHECK(compile_block(iseq, ret, node, popped));
10655  break;
10656  case NODE_IF:
10657  case NODE_UNLESS:
10658  CHECK(compile_if(iseq, ret, node, popped, type));
10659  break;
10660  case NODE_CASE:
10661  CHECK(compile_case(iseq, ret, node, popped));
10662  break;
10663  case NODE_CASE2:
10664  CHECK(compile_case2(iseq, ret, node, popped));
10665  break;
10666  case NODE_CASE3:
10667  CHECK(compile_case3(iseq, ret, node, popped));
10668  break;
10669  case NODE_WHILE:
10670  case NODE_UNTIL:
10671  CHECK(compile_loop(iseq, ret, node, popped, type));
10672  break;
10673  case NODE_FOR:
10674  case NODE_ITER:
10675  CHECK(compile_iter(iseq, ret, node, popped));
10676  break;
10677  case NODE_FOR_MASGN:
10678  CHECK(compile_for_masgn(iseq, ret, node, popped));
10679  break;
10680  case NODE_BREAK:
10681  CHECK(compile_break(iseq, ret, node, popped));
10682  break;
10683  case NODE_NEXT:
10684  CHECK(compile_next(iseq, ret, node, popped));
10685  break;
10686  case NODE_REDO:
10687  CHECK(compile_redo(iseq, ret, node, popped));
10688  break;
10689  case NODE_RETRY:
10690  CHECK(compile_retry(iseq, ret, node, popped));
10691  break;
10692  case NODE_BEGIN:{
10693  CHECK(COMPILE_(ret, "NODE_BEGIN", RNODE_BEGIN(node)->nd_body, popped));
10694  break;
10695  }
10696  case NODE_RESCUE:
10697  CHECK(compile_rescue(iseq, ret, node, popped));
10698  break;
10699  case NODE_RESBODY:
10700  CHECK(compile_resbody(iseq, ret, node, popped));
10701  break;
10702  case NODE_ENSURE:
10703  CHECK(compile_ensure(iseq, ret, node, popped));
10704  break;
10705 
10706  case NODE_AND:
10707  case NODE_OR:{
10708  LABEL *end_label = NEW_LABEL(line);
10709  CHECK(COMPILE(ret, "nd_1st", RNODE_OR(node)->nd_1st));
10710  if (!popped) {
10711  ADD_INSN(ret, node, dup);
10712  }
10713  if (type == NODE_AND) {
10714  ADD_INSNL(ret, node, branchunless, end_label);
10715  }
10716  else {
10717  ADD_INSNL(ret, node, branchif, end_label);
10718  }
10719  if (!popped) {
10720  ADD_INSN(ret, node, pop);
10721  }
10722  CHECK(COMPILE_(ret, "nd_2nd", RNODE_OR(node)->nd_2nd, popped));
10723  ADD_LABEL(ret, end_label);
10724  break;
10725  }
10726 
10727  case NODE_MASGN:{
10728  compile_massign(iseq, ret, node, popped);
10729  break;
10730  }
10731 
10732  case NODE_LASGN:{
10733  ID id = RNODE_LASGN(node)->nd_vid;
10734  int idx = ISEQ_BODY(body->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
10735 
10736  debugs("lvar: %s idx: %d\n", rb_id2name(id), idx);
10737  CHECK(COMPILE(ret, "rvalue", RNODE_LASGN(node)->nd_value));
10738 
10739  if (!popped) {
10740  ADD_INSN(ret, node, dup);
10741  }
10742  ADD_SETLOCAL(ret, node, idx, get_lvar_level(iseq));
10743  break;
10744  }
10745  case NODE_DASGN: {
10746  int idx, lv, ls;
10747  ID id = RNODE_DASGN(node)->nd_vid;
10748  CHECK(COMPILE(ret, "dvalue", RNODE_DASGN(node)->nd_value));
10749  debugi("dassn id", rb_id2str(id) ? id : '*');
10750 
10751  if (!popped) {
10752  ADD_INSN(ret, node, dup);
10753  }
10754 
10755  idx = get_dyna_var_idx(iseq, id, &lv, &ls);
10756 
10757  if (idx < 0) {
10758  COMPILE_ERROR(ERROR_ARGS "NODE_DASGN: unknown id (%"PRIsVALUE")",
10759  rb_id2str(id));
10760  goto ng;
10761  }
10762  ADD_SETLOCAL(ret, node, ls - idx, lv);
10763  break;
10764  }
10765  case NODE_GASGN:{
10766  CHECK(COMPILE(ret, "lvalue", RNODE_GASGN(node)->nd_value));
10767 
10768  if (!popped) {
10769  ADD_INSN(ret, node, dup);
10770  }
10771  ADD_INSN1(ret, node, setglobal, ID2SYM(RNODE_GASGN(node)->nd_vid));
10772  break;
10773  }
10774  case NODE_IASGN:{
10775  CHECK(COMPILE(ret, "lvalue", RNODE_IASGN(node)->nd_value));
10776  if (!popped) {
10777  ADD_INSN(ret, node, dup);
10778  }
10779  ADD_INSN2(ret, node, setinstancevariable,
10780  ID2SYM(RNODE_IASGN(node)->nd_vid),
10781  get_ivar_ic_value(iseq,RNODE_IASGN(node)->nd_vid));
10782  break;
10783  }
10784  case NODE_CDECL:{
10785  if (RNODE_CDECL(node)->nd_vid) {
10786  CHECK(compile_shareable_constant_value(iseq, ret, RNODE_CDECL(node)->shareability, node, RNODE_CDECL(node)->nd_value));
10787 
10788  if (!popped) {
10789  ADD_INSN(ret, node, dup);
10790  }
10791 
10792  ADD_INSN1(ret, node, putspecialobject,
10793  INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
10794  ADD_INSN1(ret, node, setconstant, ID2SYM(RNODE_CDECL(node)->nd_vid));
10795  }
10796  else {
10797  compile_cpath(ret, iseq, RNODE_CDECL(node)->nd_else);
10798  CHECK(compile_shareable_constant_value(iseq, ret, RNODE_CDECL(node)->shareability, node, RNODE_CDECL(node)->nd_value));
10799  ADD_INSN(ret, node, swap);
10800 
10801  if (!popped) {
10802  ADD_INSN1(ret, node, topn, INT2FIX(1));
10803  ADD_INSN(ret, node, swap);
10804  }
10805 
10806  ADD_INSN1(ret, node, setconstant, ID2SYM(get_node_colon_nd_mid(RNODE_CDECL(node)->nd_else)));
10807  }
10808  break;
10809  }
10810  case NODE_CVASGN:{
10811  CHECK(COMPILE(ret, "cvasgn val", RNODE_CVASGN(node)->nd_value));
10812  if (!popped) {
10813  ADD_INSN(ret, node, dup);
10814  }
10815  ADD_INSN2(ret, node, setclassvariable,
10816  ID2SYM(RNODE_CVASGN(node)->nd_vid),
10817  get_cvar_ic_value(iseq, RNODE_CVASGN(node)->nd_vid));
10818  break;
10819  }
10820  case NODE_OP_ASGN1:
10821  CHECK(compile_op_asgn1(iseq, ret, node, popped));
10822  break;
10823  case NODE_OP_ASGN2:
10824  CHECK(compile_op_asgn2(iseq, ret, node, popped));
10825  break;
10826  case NODE_OP_CDECL:
10827  CHECK(compile_op_cdecl(iseq, ret, node, popped));
10828  break;
10829  case NODE_OP_ASGN_AND:
10830  case NODE_OP_ASGN_OR:
10831  CHECK(compile_op_log(iseq, ret, node, popped, type));
10832  break;
10833  case NODE_CALL: /* obj.foo */
10834  case NODE_OPCALL: /* foo[] */
10835  if (compile_call_precheck_freeze(iseq, ret, node, node, popped) == TRUE) {
10836  break;
10837  }
10838  case NODE_QCALL: /* obj&.foo */
10839  case NODE_FCALL: /* foo() */
10840  case NODE_VCALL: /* foo (variable or call) */
10841  if (compile_call(iseq, ret, node, type, node, popped, false) == COMPILE_NG) {
10842  goto ng;
10843  }
10844  break;
10845  case NODE_SUPER:
10846  case NODE_ZSUPER:
10847  CHECK(compile_super(iseq, ret, node, popped, type));
10848  break;
10849  case NODE_LIST:{
10850  CHECK(compile_array(iseq, ret, node, popped, TRUE) >= 0);
10851  break;
10852  }
10853  case NODE_ZLIST:{
10854  if (!popped) {
10855  ADD_INSN1(ret, node, newarray, INT2FIX(0));
10856  }
10857  break;
10858  }
10859  case NODE_HASH:
10860  CHECK(compile_hash(iseq, ret, node, FALSE, popped) >= 0);
10861  break;
10862  case NODE_RETURN:
10863  CHECK(compile_return(iseq, ret, node, popped));
10864  break;
10865  case NODE_YIELD:
10866  CHECK(compile_yield(iseq, ret, node, popped));
10867  break;
10868  case NODE_LVAR:{
10869  if (!popped) {
10870  compile_lvar(iseq, ret, node, RNODE_LVAR(node)->nd_vid);
10871  }
10872  break;
10873  }
10874  case NODE_DVAR:{
10875  int lv, idx, ls;
10876  debugi("nd_vid", RNODE_DVAR(node)->nd_vid);
10877  if (!popped) {
10878  idx = get_dyna_var_idx(iseq, RNODE_DVAR(node)->nd_vid, &lv, &ls);
10879  if (idx < 0) {
10880  COMPILE_ERROR(ERROR_ARGS "unknown dvar (%"PRIsVALUE")",
10881  rb_id2str(RNODE_DVAR(node)->nd_vid));
10882  goto ng;
10883  }
10884  ADD_GETLOCAL(ret, node, ls - idx, lv);
10885  }
10886  break;
10887  }
10888  case NODE_GVAR:{
10889  ADD_INSN1(ret, node, getglobal, ID2SYM(RNODE_GVAR(node)->nd_vid));
10890  if (popped) {
10891  ADD_INSN(ret, node, pop);
10892  }
10893  break;
10894  }
10895  case NODE_IVAR:{
10896  debugi("nd_vid", RNODE_IVAR(node)->nd_vid);
10897  if (!popped) {
10898  ADD_INSN2(ret, node, getinstancevariable,
10899  ID2SYM(RNODE_IVAR(node)->nd_vid),
10900  get_ivar_ic_value(iseq, RNODE_IVAR(node)->nd_vid));
10901  }
10902  break;
10903  }
10904  case NODE_CONST:{
10905  debugi("nd_vid", RNODE_CONST(node)->nd_vid);
10906 
10907  if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
10908  body->ic_size++;
10909  VALUE segments = rb_ary_new_from_args(1, ID2SYM(RNODE_CONST(node)->nd_vid));
10910  ADD_INSN1(ret, node, opt_getconstant_path, segments);
10911  RB_OBJ_WRITTEN(iseq, Qundef, segments);
10912  }
10913  else {
10914  ADD_INSN(ret, node, putnil);
10915  ADD_INSN1(ret, node, putobject, Qtrue);
10916  ADD_INSN1(ret, node, getconstant, ID2SYM(RNODE_CONST(node)->nd_vid));
10917  }
10918 
10919  if (popped) {
10920  ADD_INSN(ret, node, pop);
10921  }
10922  break;
10923  }
10924  case NODE_CVAR:{
10925  if (!popped) {
10926  ADD_INSN2(ret, node, getclassvariable,
10927  ID2SYM(RNODE_CVAR(node)->nd_vid),
10928  get_cvar_ic_value(iseq, RNODE_CVAR(node)->nd_vid));
10929  }
10930  break;
10931  }
10932  case NODE_NTH_REF:{
10933  if (!popped) {
10934  if (!RNODE_NTH_REF(node)->nd_nth) {
10935  ADD_INSN(ret, node, putnil);
10936  break;
10937  }
10938  ADD_INSN2(ret, node, getspecial, INT2FIX(1) /* '~' */,
10939  INT2FIX(RNODE_NTH_REF(node)->nd_nth << 1));
10940  }
10941  break;
10942  }
10943  case NODE_BACK_REF:{
10944  if (!popped) {
10945  ADD_INSN2(ret, node, getspecial, INT2FIX(1) /* '~' */,
10946  INT2FIX(0x01 | (RNODE_BACK_REF(node)->nd_nth << 1)));
10947  }
10948  break;
10949  }
10950  case NODE_MATCH:
10951  case NODE_MATCH2:
10952  case NODE_MATCH3:
10953  CHECK(compile_match(iseq, ret, node, popped, type));
10954  break;
10955  case NODE_SYM:{
10956  if (!popped) {
10957  ADD_INSN1(ret, node, putobject, rb_node_sym_string_val(node));
10958  }
10959  break;
10960  }
10961  case NODE_LINE:{
10962  if (!popped) {
10963  ADD_INSN1(ret, node, putobject, rb_node_line_lineno_val(node));
10964  }
10965  break;
10966  }
10967  case NODE_ENCODING:{
10968  if (!popped) {
10969  ADD_INSN1(ret, node, putobject, rb_node_encoding_val(node));
10970  }
10971  break;
10972  }
10973  case NODE_INTEGER:{
10974  VALUE lit = rb_node_integer_literal_val(node);
10975  debugp_param("integer", lit);
10976  if (!popped) {
10977  ADD_INSN1(ret, node, putobject, lit);
10978  RB_OBJ_WRITTEN(iseq, Qundef, lit);
10979  }
10980  break;
10981  }
10982  case NODE_FLOAT:{
10983  VALUE lit = rb_node_float_literal_val(node);
10984  debugp_param("float", lit);
10985  if (!popped) {
10986  ADD_INSN1(ret, node, putobject, lit);
10987  RB_OBJ_WRITTEN(iseq, Qundef, lit);
10988  }
10989  break;
10990  }
10991  case NODE_RATIONAL:{
10992  VALUE lit = rb_node_rational_literal_val(node);
10993  debugp_param("rational", lit);
10994  if (!popped) {
10995  ADD_INSN1(ret, node, putobject, lit);
10996  RB_OBJ_WRITTEN(iseq, Qundef, lit);
10997  }
10998  break;
10999  }
11000  case NODE_IMAGINARY:{
11001  VALUE lit = rb_node_imaginary_literal_val(node);
11002  debugp_param("imaginary", lit);
11003  if (!popped) {
11004  ADD_INSN1(ret, node, putobject, lit);
11005  RB_OBJ_WRITTEN(iseq, Qundef, lit);
11006  }
11007  break;
11008  }
11009  case NODE_FILE:
11010  case NODE_STR:{
11011  debugp_param("nd_lit", get_string_value(node));
11012  if (!popped) {
11013  VALUE lit = get_string_value(node);
11014  const rb_compile_option_t *option = ISEQ_COMPILE_DATA(iseq)->option;
11015  if ((option->debug_frozen_string_literal || RTEST(ruby_debug)) &&
11016  option->frozen_string_literal != ISEQ_FROZEN_STRING_LITERAL_DISABLED) {
11017  lit = rb_str_with_debug_created_info(lit, rb_iseq_path(iseq), line);
11018  }
11019  switch (option->frozen_string_literal) {
11020  case ISEQ_FROZEN_STRING_LITERAL_UNSET:
11021  ADD_INSN1(ret, node, putchilledstring, lit);
11022  break;
11023  case ISEQ_FROZEN_STRING_LITERAL_DISABLED:
11024  ADD_INSN1(ret, node, putstring, lit);
11025  break;
11026  case ISEQ_FROZEN_STRING_LITERAL_ENABLED:
11027  ADD_INSN1(ret, node, putobject, lit);
11028  break;
11029  default:
11030  rb_bug("invalid frozen_string_literal");
11031  }
11032  RB_OBJ_WRITTEN(iseq, Qundef, lit);
11033  }
11034  break;
11035  }
11036  case NODE_DSTR:{
11037  compile_dstr(iseq, ret, node);
11038 
11039  if (popped) {
11040  ADD_INSN(ret, node, pop);
11041  }
11042  break;
11043  }
11044  case NODE_XSTR:{
11045  ADD_CALL_RECEIVER(ret, node);
11046  VALUE str = rb_node_str_string_val(node);
11047  ADD_INSN1(ret, node, putobject, str);
11048  RB_OBJ_WRITTEN(iseq, Qundef, str);
11049  ADD_CALL(ret, node, idBackquote, INT2FIX(1));
11050 
11051  if (popped) {
11052  ADD_INSN(ret, node, pop);
11053  }
11054  break;
11055  }
11056  case NODE_DXSTR:{
11057  ADD_CALL_RECEIVER(ret, node);
11058  compile_dstr(iseq, ret, node);
11059  ADD_CALL(ret, node, idBackquote, INT2FIX(1));
11060 
11061  if (popped) {
11062  ADD_INSN(ret, node, pop);
11063  }
11064  break;
11065  }
11066  case NODE_EVSTR:
11067  CHECK(compile_evstr(iseq, ret, RNODE_EVSTR(node)->nd_body, popped));
11068  break;
11069  case NODE_REGX:{
11070  if (!popped) {
11071  VALUE lit = rb_node_regx_string_val(node);
11072  ADD_INSN1(ret, node, putobject, lit);
11073  RB_OBJ_WRITTEN(iseq, Qundef, lit);
11074  }
11075  break;
11076  }
11077  case NODE_DREGX:
11078  compile_dregx(iseq, ret, node, popped);
11079  break;
11080  case NODE_ONCE:{
11081  int ic_index = body->ise_size++;
11082  const rb_iseq_t *block_iseq;
11083  block_iseq = NEW_CHILD_ISEQ(RNODE_ONCE(node)->nd_body, make_name_for_block(iseq), ISEQ_TYPE_PLAIN, line);
11084 
11085  ADD_INSN2(ret, node, once, block_iseq, INT2FIX(ic_index));
11086  RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block_iseq);
11087 
11088  if (popped) {
11089  ADD_INSN(ret, node, pop);
11090  }
11091  break;
11092  }
11093  case NODE_ARGSCAT:{
11094  if (popped) {
11095  CHECK(COMPILE(ret, "argscat head", RNODE_ARGSCAT(node)->nd_head));
11096  ADD_INSN1(ret, node, splatarray, Qfalse);
11097  ADD_INSN(ret, node, pop);
11098  CHECK(COMPILE(ret, "argscat body", RNODE_ARGSCAT(node)->nd_body));
11099  ADD_INSN1(ret, node, splatarray, Qfalse);
11100  ADD_INSN(ret, node, pop);
11101  }
11102  else {
11103  CHECK(COMPILE(ret, "argscat head", RNODE_ARGSCAT(node)->nd_head));
11104  const NODE *body_node = RNODE_ARGSCAT(node)->nd_body;
11105  if (nd_type_p(body_node, NODE_LIST)) {
11106  CHECK(compile_array(iseq, ret, body_node, popped, FALSE) >= 0);
11107  }
11108  else {
11109  CHECK(COMPILE(ret, "argscat body", body_node));
11110  ADD_INSN(ret, node, concattoarray);
11111  }
11112  }
11113  break;
11114  }
11115  case NODE_ARGSPUSH:{
11116  if (popped) {
11117  CHECK(COMPILE(ret, "argspush head", RNODE_ARGSPUSH(node)->nd_head));
11118  ADD_INSN1(ret, node, splatarray, Qfalse);
11119  ADD_INSN(ret, node, pop);
11120  CHECK(COMPILE_(ret, "argspush body", RNODE_ARGSPUSH(node)->nd_body, popped));
11121  }
11122  else {
11123  CHECK(COMPILE(ret, "argspush head", RNODE_ARGSPUSH(node)->nd_head));
11124  const NODE *body_node = RNODE_ARGSPUSH(node)->nd_body;
11125  if (keyword_node_p(body_node)) {
11126  CHECK(COMPILE_(ret, "array element", body_node, FALSE));
11127  ADD_INSN(ret, node, pushtoarraykwsplat);
11128  }
11129  else if (static_literal_node_p(body_node, iseq, false)) {
11130  ADD_INSN1(ret, body_node, putobject, static_literal_value(body_node, iseq));
11131  ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
11132  }
11133  else {
11134  CHECK(COMPILE_(ret, "array element", body_node, FALSE));
11135  ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
11136  }
11137  }
11138  break;
11139  }
11140  case NODE_SPLAT:{
11141  CHECK(COMPILE(ret, "splat", RNODE_SPLAT(node)->nd_head));
11142  ADD_INSN1(ret, node, splatarray, Qtrue);
11143 
11144  if (popped) {
11145  ADD_INSN(ret, node, pop);
11146  }
11147  break;
11148  }
11149  case NODE_DEFN:{
11150  ID mid = RNODE_DEFN(node)->nd_mid;
11151  const rb_iseq_t *method_iseq = NEW_ISEQ(RNODE_DEFN(node)->nd_defn,
11152  rb_id2str(mid),
11153  ISEQ_TYPE_METHOD, line);
11154 
11155  debugp_param("defn/iseq", rb_iseqw_new(method_iseq));
11156  ADD_INSN2(ret, node, definemethod, ID2SYM(mid), method_iseq);
11157  RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)method_iseq);
11158 
11159  if (!popped) {
11160  ADD_INSN1(ret, node, putobject, ID2SYM(mid));
11161  }
11162 
11163  break;
11164  }
11165  case NODE_DEFS:{
11166  ID mid = RNODE_DEFS(node)->nd_mid;
11167  const rb_iseq_t * singleton_method_iseq = NEW_ISEQ(RNODE_DEFS(node)->nd_defn,
11168  rb_id2str(mid),
11169  ISEQ_TYPE_METHOD, line);
11170 
11171  debugp_param("defs/iseq", rb_iseqw_new(singleton_method_iseq));
11172  CHECK(COMPILE(ret, "defs: recv", RNODE_DEFS(node)->nd_recv));
11173  ADD_INSN2(ret, node, definesmethod, ID2SYM(mid), singleton_method_iseq);
11174  RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)singleton_method_iseq);
11175 
11176  if (!popped) {
11177  ADD_INSN1(ret, node, putobject, ID2SYM(mid));
11178  }
11179  break;
11180  }
11181  case NODE_ALIAS:{
11182  ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11183  ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
11184  CHECK(COMPILE(ret, "alias arg1", RNODE_ALIAS(node)->nd_1st));
11185  CHECK(COMPILE(ret, "alias arg2", RNODE_ALIAS(node)->nd_2nd));
11186  ADD_SEND(ret, node, id_core_set_method_alias, INT2FIX(3));
11187 
11188  if (popped) {
11189  ADD_INSN(ret, node, pop);
11190  }
11191  break;
11192  }
11193  case NODE_VALIAS:{
11194  ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11195  ADD_INSN1(ret, node, putobject, ID2SYM(RNODE_VALIAS(node)->nd_alias));
11196  ADD_INSN1(ret, node, putobject, ID2SYM(RNODE_VALIAS(node)->nd_orig));
11197  ADD_SEND(ret, node, id_core_set_variable_alias, INT2FIX(2));
11198 
11199  if (popped) {
11200  ADD_INSN(ret, node, pop);
11201  }
11202  break;
11203  }
11204  case NODE_UNDEF:{
11205  const rb_parser_ary_t *ary = RNODE_UNDEF(node)->nd_undefs;
11206 
11207  for (long i = 0; i < ary->len; i++) {
11208  ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11209  ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
11210  CHECK(COMPILE(ret, "undef arg", ary->data[i]));
11211  ADD_SEND(ret, node, id_core_undef_method, INT2FIX(2));
11212 
11213  if (i < ary->len - 1) {
11214  ADD_INSN(ret, node, pop);
11215  }
11216  }
11217 
11218  if (popped) {
11219  ADD_INSN(ret, node, pop);
11220  }
11221  break;
11222  }
11223  case NODE_CLASS:{
11224  const rb_iseq_t *class_iseq = NEW_CHILD_ISEQ(RNODE_CLASS(node)->nd_body,
11225  rb_str_freeze(rb_sprintf("<class:%"PRIsVALUE">", rb_id2str(get_node_colon_nd_mid(RNODE_CLASS(node)->nd_cpath)))),
11226  ISEQ_TYPE_CLASS, line);
11227  const int flags = VM_DEFINECLASS_TYPE_CLASS |
11228  (RNODE_CLASS(node)->nd_super ? VM_DEFINECLASS_FLAG_HAS_SUPERCLASS : 0) |
11229  compile_cpath(ret, iseq, RNODE_CLASS(node)->nd_cpath);
11230 
11231  CHECK(COMPILE(ret, "super", RNODE_CLASS(node)->nd_super));
11232  ADD_INSN3(ret, node, defineclass, ID2SYM(get_node_colon_nd_mid(RNODE_CLASS(node)->nd_cpath)), class_iseq, INT2FIX(flags));
11233  RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)class_iseq);
11234 
11235  if (popped) {
11236  ADD_INSN(ret, node, pop);
11237  }
11238  break;
11239  }
11240  case NODE_MODULE:{
11241  const rb_iseq_t *module_iseq = NEW_CHILD_ISEQ(RNODE_MODULE(node)->nd_body,
11242  rb_str_freeze(rb_sprintf("<module:%"PRIsVALUE">", rb_id2str(get_node_colon_nd_mid(RNODE_MODULE(node)->nd_cpath)))),
11243  ISEQ_TYPE_CLASS, line);
11244  const int flags = VM_DEFINECLASS_TYPE_MODULE |
11245  compile_cpath(ret, iseq, RNODE_MODULE(node)->nd_cpath);
11246 
11247  ADD_INSN (ret, node, putnil); /* dummy */
11248  ADD_INSN3(ret, node, defineclass, ID2SYM(get_node_colon_nd_mid(RNODE_MODULE(node)->nd_cpath)), module_iseq, INT2FIX(flags));
11249  RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)module_iseq);
11250 
11251  if (popped) {
11252  ADD_INSN(ret, node, pop);
11253  }
11254  break;
11255  }
11256  case NODE_SCLASS:{
11257  ID singletonclass;
11258  const rb_iseq_t *singleton_class = NEW_ISEQ(RNODE_SCLASS(node)->nd_body, rb_fstring_lit("singleton class"),
11259  ISEQ_TYPE_CLASS, line);
11260 
11261  CHECK(COMPILE(ret, "sclass#recv", RNODE_SCLASS(node)->nd_recv));
11262  ADD_INSN (ret, node, putnil);
11263  CONST_ID(singletonclass, "singletonclass");
11264  ADD_INSN3(ret, node, defineclass,
11265  ID2SYM(singletonclass), singleton_class,
11266  INT2FIX(VM_DEFINECLASS_TYPE_SINGLETON_CLASS));
11267  RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)singleton_class);
11268 
11269  if (popped) {
11270  ADD_INSN(ret, node, pop);
11271  }
11272  break;
11273  }
11274  case NODE_COLON2:
11275  CHECK(compile_colon2(iseq, ret, node, popped));
11276  break;
11277  case NODE_COLON3:
11278  CHECK(compile_colon3(iseq, ret, node, popped));
11279  break;
11280  case NODE_DOT2:
11281  CHECK(compile_dots(iseq, ret, node, popped, FALSE));
11282  break;
11283  case NODE_DOT3:
11284  CHECK(compile_dots(iseq, ret, node, popped, TRUE));
11285  break;
11286  case NODE_FLIP2:
11287  case NODE_FLIP3:{
11288  LABEL *lend = NEW_LABEL(line);
11289  LABEL *ltrue = NEW_LABEL(line);
11290  LABEL *lfalse = NEW_LABEL(line);
11291  CHECK(compile_flip_flop(iseq, ret, node, type == NODE_FLIP2,
11292  ltrue, lfalse));
11293  ADD_LABEL(ret, ltrue);
11294  ADD_INSN1(ret, node, putobject, Qtrue);
11295  ADD_INSNL(ret, node, jump, lend);
11296  ADD_LABEL(ret, lfalse);
11297  ADD_INSN1(ret, node, putobject, Qfalse);
11298  ADD_LABEL(ret, lend);
11299  break;
11300  }
11301  case NODE_SELF:{
11302  if (!popped) {
11303  ADD_INSN(ret, node, putself);
11304  }
11305  break;
11306  }
11307  case NODE_NIL:{
11308  if (!popped) {
11309  ADD_INSN(ret, node, putnil);
11310  }
11311  break;
11312  }
11313  case NODE_TRUE:{
11314  if (!popped) {
11315  ADD_INSN1(ret, node, putobject, Qtrue);
11316  }
11317  break;
11318  }
11319  case NODE_FALSE:{
11320  if (!popped) {
11321  ADD_INSN1(ret, node, putobject, Qfalse);
11322  }
11323  break;
11324  }
11325  case NODE_ERRINFO:
11326  CHECK(compile_errinfo(iseq, ret, node, popped));
11327  break;
11328  case NODE_DEFINED:
11329  if (!popped) {
11330  CHECK(compile_defined_expr(iseq, ret, node, Qtrue, false));
11331  }
11332  break;
11333  case NODE_POSTEXE:{
11334  /* compiled to:
11335  * ONCE{ rb_mRubyVMFrozenCore::core#set_postexe{ ... } }
11336  */
11337  int is_index = body->ise_size++;
11339  rb_iseq_new_with_callback_new_callback(build_postexe_iseq, RNODE_POSTEXE(node)->nd_body);
11340  const rb_iseq_t *once_iseq =
11341  new_child_iseq_with_callback(iseq, ifunc,
11342  rb_fstring(make_name_for_block(iseq)), iseq, ISEQ_TYPE_BLOCK, line);
11343 
11344  ADD_INSN2(ret, node, once, once_iseq, INT2FIX(is_index));
11345  RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)once_iseq);
11346 
11347  if (popped) {
11348  ADD_INSN(ret, node, pop);
11349  }
11350  break;
11351  }
11352  case NODE_KW_ARG:
11353  CHECK(compile_kw_arg(iseq, ret, node, popped));
11354  break;
11355  case NODE_DSYM:{
11356  compile_dstr(iseq, ret, node);
11357  if (!popped) {
11358  ADD_INSN(ret, node, intern);
11359  }
11360  else {
11361  ADD_INSN(ret, node, pop);
11362  }
11363  break;
11364  }
11365  case NODE_ATTRASGN:
11366  CHECK(compile_attrasgn(iseq, ret, node, popped));
11367  break;
11368  case NODE_LAMBDA:{
11369  /* compile same as lambda{...} */
11370  const rb_iseq_t *block = NEW_CHILD_ISEQ(RNODE_LAMBDA(node)->nd_body, make_name_for_block(iseq), ISEQ_TYPE_BLOCK, line);
11371  VALUE argc = INT2FIX(0);
11372 
11373  ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11374  ADD_CALL_WITH_BLOCK(ret, node, idLambda, argc, block);
11375  RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block);
11376 
11377  if (popped) {
11378  ADD_INSN(ret, node, pop);
11379  }
11380  break;
11381  }
11382  default:
11383  UNKNOWN_NODE("iseq_compile_each", node, COMPILE_NG);
11384  ng:
11385  debug_node_end();
11386  return COMPILE_NG;
11387  }
11388 
11389  debug_node_end();
11390  return COMPILE_OK;
11391 }
11392 
11393 /***************************/
11394 /* instruction information */
11395 /***************************/
11396 
11397 static int
11398 insn_data_length(INSN *iobj)
11399 {
11400  return insn_len(iobj->insn_id);
11401 }
11402 
11403 static int
11404 calc_sp_depth(int depth, INSN *insn)
11405 {
11406  return comptime_insn_stack_increase(depth, insn->insn_id, insn->operands);
11407 }
11408 
11409 static VALUE
11410 opobj_inspect(VALUE obj)
11411 {
11412  if (!SPECIAL_CONST_P(obj) && !RBASIC_CLASS(obj)) {
11413  switch (BUILTIN_TYPE(obj)) {
11414  case T_STRING:
11415  obj = rb_str_new_cstr(RSTRING_PTR(obj));
11416  break;
11417  case T_ARRAY:
11418  obj = rb_ary_dup(obj);
11419  break;
11420  default:
11421  break;
11422  }
11423  }
11424  return rb_inspect(obj);
11425 }
11426 
11427 
11428 
11429 static VALUE
11430 insn_data_to_s_detail(INSN *iobj)
11431 {
11432  VALUE str = rb_sprintf("%-20s ", insn_name(iobj->insn_id));
11433 
11434  if (iobj->operands) {
11435  const char *types = insn_op_types(iobj->insn_id);
11436  int j;
11437 
11438  for (j = 0; types[j]; j++) {
11439  char type = types[j];
11440 
11441  switch (type) {
11442  case TS_OFFSET: /* label(destination position) */
11443  {
11444  LABEL *lobj = (LABEL *)OPERAND_AT(iobj, j);
11445  rb_str_catf(str, LABEL_FORMAT, lobj->label_no);
11446  break;
11447  }
11448  break;
11449  case TS_ISEQ: /* iseq */
11450  {
11451  rb_iseq_t *iseq = (rb_iseq_t *)OPERAND_AT(iobj, j);
11452  VALUE val = Qnil;
11453  if (0 && iseq) { /* TODO: invalidate now */
11454  val = (VALUE)iseq;
11455  }
11456  rb_str_concat(str, opobj_inspect(val));
11457  }
11458  break;
11459  case TS_LINDEX:
11460  case TS_NUM: /* ulong */
11461  case TS_VALUE: /* VALUE */
11462  {
11463  VALUE v = OPERAND_AT(iobj, j);
11464  if (!CLASS_OF(v))
11465  rb_str_cat2(str, "<hidden>");
11466  else {
11467  rb_str_concat(str, opobj_inspect(v));
11468  }
11469  break;
11470  }
11471  case TS_ID: /* ID */
11472  rb_str_concat(str, opobj_inspect(OPERAND_AT(iobj, j)));
11473  break;
11474  case TS_IC: /* inline cache */
11475  rb_str_concat(str, opobj_inspect(OPERAND_AT(iobj, j)));
11476  break;
11477  case TS_IVC: /* inline ivar cache */
11478  rb_str_catf(str, "<ivc:%d>", FIX2INT(OPERAND_AT(iobj, j)));
11479  break;
11480  case TS_ICVARC: /* inline cvar cache */
11481  rb_str_catf(str, "<icvarc:%d>", FIX2INT(OPERAND_AT(iobj, j)));
11482  break;
11483  case TS_ISE: /* inline storage entry */
11484  rb_str_catf(str, "<ise:%d>", FIX2INT(OPERAND_AT(iobj, j)));
11485  break;
11486  case TS_CALLDATA: /* we store these as call infos at compile time */
11487  {
11488  const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, j);
11489  rb_str_cat2(str, "<calldata:");
11490  if (vm_ci_mid(ci)) rb_str_catf(str, "%"PRIsVALUE, rb_id2str(vm_ci_mid(ci)));
11491  rb_str_catf(str, ", %d>", vm_ci_argc(ci));
11492  break;
11493  }
11494  case TS_CDHASH: /* case/when condition cache */
11495  rb_str_cat2(str, "<ch>");
11496  break;
11497  case TS_FUNCPTR:
11498  {
11499  void *func = (void *)OPERAND_AT(iobj, j);
11500 #ifdef HAVE_DLADDR
11501  Dl_info info;
11502  if (dladdr(func, &info) && info.dli_sname) {
11503  rb_str_cat2(str, info.dli_sname);
11504  break;
11505  }
11506 #endif
11507  rb_str_catf(str, "<%p>", func);
11508  }
11509  break;
11510  case TS_BUILTIN:
11511  rb_str_cat2(str, "<TS_BUILTIN>");
11512  break;
11513  default:{
11514  rb_raise(rb_eSyntaxError, "unknown operand type: %c", type);
11515  }
11516  }
11517  if (types[j + 1]) {
11518  rb_str_cat2(str, ", ");
11519  }
11520  }
11521  }
11522  return str;
11523 }
11524 
11525 static void
11526 dump_disasm_list(const LINK_ELEMENT *link)
11527 {
11528  dump_disasm_list_with_cursor(link, NULL, NULL);
11529 }
11530 
11531 static void
11532 dump_disasm_list_with_cursor(const LINK_ELEMENT *link, const LINK_ELEMENT *curr, const LABEL *dest)
11533 {
11534  int pos = 0;
11535  INSN *iobj;
11536  LABEL *lobj;
11537  VALUE str;
11538 
11539  printf("-- raw disasm--------\n");
11540 
11541  while (link) {
11542  if (curr) printf(curr == link ? "*" : " ");
11543  switch (link->type) {
11544  case ISEQ_ELEMENT_INSN:
11545  {
11546  iobj = (INSN *)link;
11547  str = insn_data_to_s_detail(iobj);
11548  printf(" %04d %-65s(%4u)\n", pos, StringValueCStr(str), iobj->insn_info.line_no);
11549  pos += insn_data_length(iobj);
11550  break;
11551  }
11552  case ISEQ_ELEMENT_LABEL:
11553  {
11554  lobj = (LABEL *)link;
11555  printf(LABEL_FORMAT" [sp: %d, unremovable: %d, refcnt: %d]%s\n", lobj->label_no, lobj->sp, lobj->unremovable, lobj->refcnt,
11556  dest == lobj ? " <---" : "");
11557  break;
11558  }
11559  case ISEQ_ELEMENT_TRACE:
11560  {
11561  TRACE *trace = (TRACE *)link;
11562  printf(" trace: %0x\n", trace->event);
11563  break;
11564  }
11565  case ISEQ_ELEMENT_ADJUST:
11566  {
11567  ADJUST *adjust = (ADJUST *)link;
11568  printf(" adjust: [label: %d]\n", adjust->label ? adjust->label->label_no : -1);
11569  break;
11570  }
11571  default:
11572  /* ignore */
11573  rb_raise(rb_eSyntaxError, "dump_disasm_list error: %d\n", (int)link->type);
11574  }
11575  link = link->next;
11576  }
11577  printf("---------------------\n");
11578  fflush(stdout);
11579 }
11580 
11581 int
11582 rb_insn_len(VALUE insn)
11583 {
11584  return insn_len(insn);
11585 }
11586 
11587 const char *
11588 rb_insns_name(int i)
11589 {
11590  return insn_name(i);
11591 }
11592 
11593 VALUE
11594 rb_insns_name_array(void)
11595 {
11596  VALUE ary = rb_ary_new_capa(VM_INSTRUCTION_SIZE);
11597  int i;
11598  for (i = 0; i < VM_INSTRUCTION_SIZE; i++) {
11599  rb_ary_push(ary, rb_fstring_cstr(insn_name(i)));
11600  }
11601  return rb_ary_freeze(ary);
11602 }
11603 
11604 static LABEL *
11605 register_label(rb_iseq_t *iseq, struct st_table *labels_table, VALUE obj)
11606 {
11607  LABEL *label = 0;
11608  st_data_t tmp;
11609  obj = rb_to_symbol_type(obj);
11610 
11611  if (st_lookup(labels_table, obj, &tmp) == 0) {
11612  label = NEW_LABEL(0);
11613  st_insert(labels_table, obj, (st_data_t)label);
11614  }
11615  else {
11616  label = (LABEL *)tmp;
11617  }
11618  LABEL_REF(label);
11619  return label;
11620 }
11621 
11622 static VALUE
11623 get_exception_sym2type(VALUE sym)
11624 {
11625  static VALUE symRescue, symEnsure, symRetry;
11626  static VALUE symBreak, symRedo, symNext;
11627 
11628  if (symRescue == 0) {
11629  symRescue = ID2SYM(rb_intern_const("rescue"));
11630  symEnsure = ID2SYM(rb_intern_const("ensure"));
11631  symRetry = ID2SYM(rb_intern_const("retry"));
11632  symBreak = ID2SYM(rb_intern_const("break"));
11633  symRedo = ID2SYM(rb_intern_const("redo"));
11634  symNext = ID2SYM(rb_intern_const("next"));
11635  }
11636 
11637  if (sym == symRescue) return CATCH_TYPE_RESCUE;
11638  if (sym == symEnsure) return CATCH_TYPE_ENSURE;
11639  if (sym == symRetry) return CATCH_TYPE_RETRY;
11640  if (sym == symBreak) return CATCH_TYPE_BREAK;
11641  if (sym == symRedo) return CATCH_TYPE_REDO;
11642  if (sym == symNext) return CATCH_TYPE_NEXT;
11643  rb_raise(rb_eSyntaxError, "invalid exception symbol: %+"PRIsVALUE, sym);
11644  return 0;
11645 }
11646 
11647 static int
11648 iseq_build_from_ary_exception(rb_iseq_t *iseq, struct st_table *labels_table,
11649  VALUE exception)
11650 {
11651  int i;
11652 
11653  for (i=0; i<RARRAY_LEN(exception); i++) {
11654  const rb_iseq_t *eiseq;
11655  VALUE v, type;
11656  LABEL *lstart, *lend, *lcont;
11657  unsigned int sp;
11658 
11659  v = rb_to_array_type(RARRAY_AREF(exception, i));
11660  if (RARRAY_LEN(v) != 6) {
11661  rb_raise(rb_eSyntaxError, "wrong exception entry");
11662  }
11663  type = get_exception_sym2type(RARRAY_AREF(v, 0));
11664  if (NIL_P(RARRAY_AREF(v, 1))) {
11665  eiseq = NULL;
11666  }
11667  else {
11668  eiseq = rb_iseqw_to_iseq(rb_iseq_load(RARRAY_AREF(v, 1), (VALUE)iseq, Qnil));
11669  }
11670 
11671  lstart = register_label(iseq, labels_table, RARRAY_AREF(v, 2));
11672  lend = register_label(iseq, labels_table, RARRAY_AREF(v, 3));
11673  lcont = register_label(iseq, labels_table, RARRAY_AREF(v, 4));
11674  sp = NUM2UINT(RARRAY_AREF(v, 5));
11675 
11676  /* TODO: Dirty Hack! Fix me */
11677  if (type == CATCH_TYPE_RESCUE ||
11678  type == CATCH_TYPE_BREAK ||
11679  type == CATCH_TYPE_NEXT) {
11680  ++sp;
11681  }
11682 
11683  lcont->sp = sp;
11684 
11685  ADD_CATCH_ENTRY(type, lstart, lend, eiseq, lcont);
11686 
11687  RB_GC_GUARD(v);
11688  }
11689  return COMPILE_OK;
11690 }
11691 
11692 static struct st_table *
11693 insn_make_insn_table(void)
11694 {
11695  struct st_table *table;
11696  int i;
11697  table = st_init_numtable_with_size(VM_INSTRUCTION_SIZE);
11698 
11699  for (i=0; i<VM_INSTRUCTION_SIZE; i++) {
11700  st_insert(table, ID2SYM(rb_intern_const(insn_name(i))), i);
11701  }
11702 
11703  return table;
11704 }
11705 
11706 static const rb_iseq_t *
11707 iseq_build_load_iseq(const rb_iseq_t *iseq, VALUE op)
11708 {
11709  VALUE iseqw;
11710  const rb_iseq_t *loaded_iseq;
11711 
11712  if (RB_TYPE_P(op, T_ARRAY)) {
11713  iseqw = rb_iseq_load(op, (VALUE)iseq, Qnil);
11714  }
11715  else if (CLASS_OF(op) == rb_cISeq) {
11716  iseqw = op;
11717  }
11718  else {
11719  rb_raise(rb_eSyntaxError, "ISEQ is required");
11720  }
11721 
11722  loaded_iseq = rb_iseqw_to_iseq(iseqw);
11723  return loaded_iseq;
11724 }
11725 
11726 static VALUE
11727 iseq_build_callinfo_from_hash(rb_iseq_t *iseq, VALUE op)
11728 {
11729  ID mid = 0;
11730  int orig_argc = 0;
11731  unsigned int flag = 0;
11732  struct rb_callinfo_kwarg *kw_arg = 0;
11733 
11734  if (!NIL_P(op)) {
11735  VALUE vmid = rb_hash_aref(op, ID2SYM(rb_intern_const("mid")));
11736  VALUE vflag = rb_hash_aref(op, ID2SYM(rb_intern_const("flag")));
11737  VALUE vorig_argc = rb_hash_aref(op, ID2SYM(rb_intern_const("orig_argc")));
11738  VALUE vkw_arg = rb_hash_aref(op, ID2SYM(rb_intern_const("kw_arg")));
11739 
11740  if (!NIL_P(vmid)) mid = SYM2ID(vmid);
11741  if (!NIL_P(vflag)) flag = NUM2UINT(vflag);
11742  if (!NIL_P(vorig_argc)) orig_argc = FIX2INT(vorig_argc);
11743 
11744  if (!NIL_P(vkw_arg)) {
11745  int i;
11746  int len = RARRAY_LENINT(vkw_arg);
11747  size_t n = rb_callinfo_kwarg_bytes(len);
11748 
11749  kw_arg = xmalloc(n);
11750  kw_arg->references = 0;
11751  kw_arg->keyword_len = len;
11752  for (i = 0; i < len; i++) {
11753  VALUE kw = RARRAY_AREF(vkw_arg, i);
11754  SYM2ID(kw); /* make immortal */
11755  kw_arg->keywords[i] = kw;
11756  }
11757  }
11758  }
11759 
11760  const struct rb_callinfo *ci = new_callinfo(iseq, mid, orig_argc, flag, kw_arg, (flag & VM_CALL_ARGS_SIMPLE) == 0);
11761  RB_OBJ_WRITTEN(iseq, Qundef, ci);
11762  return (VALUE)ci;
11763 }
11764 
11765 static rb_event_flag_t
11766 event_name_to_flag(VALUE sym)
11767 {
11768 #define CHECK_EVENT(ev) if (sym == ID2SYM(rb_intern_const(#ev))) return ev;
11769  CHECK_EVENT(RUBY_EVENT_LINE);
11770  CHECK_EVENT(RUBY_EVENT_CLASS);
11771  CHECK_EVENT(RUBY_EVENT_END);
11772  CHECK_EVENT(RUBY_EVENT_CALL);
11773  CHECK_EVENT(RUBY_EVENT_RETURN);
11774  CHECK_EVENT(RUBY_EVENT_B_CALL);
11775  CHECK_EVENT(RUBY_EVENT_B_RETURN);
11776  CHECK_EVENT(RUBY_EVENT_RESCUE);
11777 #undef CHECK_EVENT
11778  return RUBY_EVENT_NONE;
11779 }
11780 
11781 static int
11782 iseq_build_from_ary_body(rb_iseq_t *iseq, LINK_ANCHOR *const anchor,
11783  VALUE body, VALUE node_ids, VALUE labels_wrapper)
11784 {
11785  /* TODO: body should be frozen */
11786  long i, len = RARRAY_LEN(body);
11787  struct st_table *labels_table = RTYPEDDATA_DATA(labels_wrapper);
11788  int j;
11789  int line_no = 0, node_id = -1, insn_idx = 0;
11790  int ret = COMPILE_OK;
11791 
11792  /*
11793  * index -> LABEL *label
11794  */
11795  static struct st_table *insn_table;
11796 
11797  if (insn_table == 0) {
11798  insn_table = insn_make_insn_table();
11799  }
11800 
11801  for (i=0; i<len; i++) {
11802  VALUE obj = RARRAY_AREF(body, i);
11803 
11804  if (SYMBOL_P(obj)) {
11805  rb_event_flag_t event;
11806  if ((event = event_name_to_flag(obj)) != RUBY_EVENT_NONE) {
11807  ADD_TRACE(anchor, event);
11808  }
11809  else {
11810  LABEL *label = register_label(iseq, labels_table, obj);
11811  ADD_LABEL(anchor, label);
11812  }
11813  }
11814  else if (FIXNUM_P(obj)) {
11815  line_no = NUM2INT(obj);
11816  }
11817  else if (RB_TYPE_P(obj, T_ARRAY)) {
11818  VALUE *argv = 0;
11819  int argc = RARRAY_LENINT(obj) - 1;
11820  st_data_t insn_id;
11821  VALUE insn;
11822 
11823  if (node_ids) {
11824  node_id = NUM2INT(rb_ary_entry(node_ids, insn_idx++));
11825  }
11826 
11827  insn = (argc < 0) ? Qnil : RARRAY_AREF(obj, 0);
11828  if (st_lookup(insn_table, (st_data_t)insn, &insn_id) == 0) {
11829  /* TODO: exception */
11830  COMPILE_ERROR(iseq, line_no,
11831  "unknown instruction: %+"PRIsVALUE, insn);
11832  ret = COMPILE_NG;
11833  break;
11834  }
11835 
11836  if (argc != insn_len((VALUE)insn_id)-1) {
11837  COMPILE_ERROR(iseq, line_no,
11838  "operand size mismatch");
11839  ret = COMPILE_NG;
11840  break;
11841  }
11842 
11843  if (argc > 0) {
11844  argv = compile_data_calloc2(iseq, sizeof(VALUE), argc);
11845 
11846  // add element before operand setup to make GC root
11847  ADD_ELEM(anchor,
11848  (LINK_ELEMENT*)new_insn_core(iseq, line_no, node_id,
11849  (enum ruby_vminsn_type)insn_id, argc, argv));
11850 
11851  for (j=0; j<argc; j++) {
11852  VALUE op = rb_ary_entry(obj, j+1);
11853  switch (insn_op_type((VALUE)insn_id, j)) {
11854  case TS_OFFSET: {
11855  LABEL *label = register_label(iseq, labels_table, op);
11856  argv[j] = (VALUE)label;
11857  break;
11858  }
11859  case TS_LINDEX:
11860  case TS_NUM:
11861  (void)NUM2INT(op);
11862  argv[j] = op;
11863  break;
11864  case TS_VALUE:
11865  argv[j] = op;
11866  RB_OBJ_WRITTEN(iseq, Qundef, op);
11867  break;
11868  case TS_ISEQ:
11869  {
11870  if (op != Qnil) {
11871  VALUE v = (VALUE)iseq_build_load_iseq(iseq, op);
11872  argv[j] = v;
11873  RB_OBJ_WRITTEN(iseq, Qundef, v);
11874  }
11875  else {
11876  argv[j] = 0;
11877  }
11878  }
11879  break;
11880  case TS_ISE:
11881  argv[j] = op;
11882  if (NUM2UINT(op) >= ISEQ_BODY(iseq)->ise_size) {
11883  ISEQ_BODY(iseq)->ise_size = NUM2INT(op) + 1;
11884  }
11885  break;
11886  case TS_IC:
11887  {
11888  VALUE segments = rb_ary_new();
11889  op = rb_to_array_type(op);
11890 
11891  for (int i = 0; i < RARRAY_LEN(op); i++) {
11892  VALUE sym = RARRAY_AREF(op, i);
11893  sym = rb_to_symbol_type(sym);
11894  rb_ary_push(segments, sym);
11895  }
11896 
11897  RB_GC_GUARD(op);
11898  argv[j] = segments;
11899  RB_OBJ_WRITTEN(iseq, Qundef, segments);
11900  ISEQ_BODY(iseq)->ic_size++;
11901  }
11902  break;
11903  case TS_IVC: /* inline ivar cache */
11904  argv[j] = op;
11905  if (NUM2UINT(op) >= ISEQ_BODY(iseq)->ivc_size) {
11906  ISEQ_BODY(iseq)->ivc_size = NUM2INT(op) + 1;
11907  }
11908  break;
11909  case TS_ICVARC: /* inline cvar cache */
11910  argv[j] = op;
11911  if (NUM2UINT(op) >= ISEQ_BODY(iseq)->icvarc_size) {
11912  ISEQ_BODY(iseq)->icvarc_size = NUM2INT(op) + 1;
11913  }
11914  break;
11915  case TS_CALLDATA:
11916  argv[j] = iseq_build_callinfo_from_hash(iseq, op);
11917  break;
11918  case TS_ID:
11919  argv[j] = rb_to_symbol_type(op);
11920  break;
11921  case TS_CDHASH:
11922  {
11923  int i;
11924  VALUE map = rb_hash_new_with_size(RARRAY_LEN(op)/2);
11925 
11926  RHASH_TBL_RAW(map)->type = &cdhash_type;
11927  op = rb_to_array_type(op);
11928  for (i=0; i<RARRAY_LEN(op); i+=2) {
11929  VALUE key = RARRAY_AREF(op, i);
11930  VALUE sym = RARRAY_AREF(op, i+1);
11931  LABEL *label =
11932  register_label(iseq, labels_table, sym);
11933  rb_hash_aset(map, key, (VALUE)label | 1);
11934  }
11935  RB_GC_GUARD(op);
11936  argv[j] = map;
11937  RB_OBJ_WRITTEN(iseq, Qundef, map);
11938  }
11939  break;
11940  case TS_FUNCPTR:
11941  {
11942 #if SIZEOF_VALUE <= SIZEOF_LONG
11943  long funcptr = NUM2LONG(op);
11944 #else
11945  LONG_LONG funcptr = NUM2LL(op);
11946 #endif
11947  argv[j] = (VALUE)funcptr;
11948  }
11949  break;
11950  default:
11951  rb_raise(rb_eSyntaxError, "unknown operand: %c", insn_op_type((VALUE)insn_id, j));
11952  }
11953  }
11954  }
11955  else {
11956  ADD_ELEM(anchor,
11957  (LINK_ELEMENT*)new_insn_core(iseq, line_no, node_id,
11958  (enum ruby_vminsn_type)insn_id, argc, NULL));
11959  }
11960  }
11961  else {
11962  rb_raise(rb_eTypeError, "unexpected object for instruction");
11963  }
11964  }
11965  RTYPEDDATA_DATA(labels_wrapper) = 0;
11966  RB_GC_GUARD(labels_wrapper);
11967  validate_labels(iseq, labels_table);
11968  if (!ret) return ret;
11969  return iseq_setup(iseq, anchor);
11970 }
11971 
11972 #define CHECK_ARRAY(v) rb_to_array_type(v)
11973 #define CHECK_SYMBOL(v) rb_to_symbol_type(v)
11974 
11975 static int
11976 int_param(int *dst, VALUE param, VALUE sym)
11977 {
11978  VALUE val = rb_hash_aref(param, sym);
11979  if (FIXNUM_P(val)) {
11980  *dst = FIX2INT(val);
11981  return TRUE;
11982  }
11983  else if (!NIL_P(val)) {
11984  rb_raise(rb_eTypeError, "invalid %+"PRIsVALUE" Fixnum: %+"PRIsVALUE,
11985  sym, val);
11986  }
11987  return FALSE;
11988 }
11989 
11990 static const struct rb_iseq_param_keyword *
11991 iseq_build_kw(rb_iseq_t *iseq, VALUE params, VALUE keywords)
11992 {
11993  int i, j;
11994  int len = RARRAY_LENINT(keywords);
11995  int default_len;
11996  VALUE key, sym, default_val;
11997  VALUE *dvs;
11998  ID *ids;
11999  struct rb_iseq_param_keyword *keyword = ZALLOC(struct rb_iseq_param_keyword);
12000 
12001  ISEQ_BODY(iseq)->param.flags.has_kw = TRUE;
12002 
12003  keyword->num = len;
12004 #define SYM(s) ID2SYM(rb_intern_const(#s))
12005  (void)int_param(&keyword->bits_start, params, SYM(kwbits));
12006  i = keyword->bits_start - keyword->num;
12007  ids = (ID *)&ISEQ_BODY(iseq)->local_table[i];
12008 #undef SYM
12009 
12010  /* required args */
12011  for (i = 0; i < len; i++) {
12012  VALUE val = RARRAY_AREF(keywords, i);
12013 
12014  if (!SYMBOL_P(val)) {
12015  goto default_values;
12016  }
12017  ids[i] = SYM2ID(val);
12018  keyword->required_num++;
12019  }
12020 
12021  default_values: /* note: we intentionally preserve `i' from previous loop */
12022  default_len = len - i;
12023  if (default_len == 0) {
12024  keyword->table = ids;
12025  return keyword;
12026  }
12027  else if (default_len < 0) {
12028  UNREACHABLE;
12029  }
12030 
12031  dvs = ALLOC_N(VALUE, (unsigned int)default_len);
12032 
12033  for (j = 0; i < len; i++, j++) {
12034  key = RARRAY_AREF(keywords, i);
12035  CHECK_ARRAY(key);
12036 
12037  switch (RARRAY_LEN(key)) {
12038  case 1:
12039  sym = RARRAY_AREF(key, 0);
12040  default_val = Qundef;
12041  break;
12042  case 2:
12043  sym = RARRAY_AREF(key, 0);
12044  default_val = RARRAY_AREF(key, 1);
12045  break;
12046  default:
12047  rb_raise(rb_eTypeError, "keyword default has unsupported len %+"PRIsVALUE, key);
12048  }
12049  ids[i] = SYM2ID(sym);
12050  RB_OBJ_WRITE(iseq, &dvs[j], default_val);
12051  }
12052 
12053  keyword->table = ids;
12054  keyword->default_values = dvs;
12055 
12056  return keyword;
12057 }
12058 
12059 static void
12060 iseq_insn_each_object_mark_and_pin(VALUE obj, VALUE _)
12061 {
12062  rb_gc_mark(obj);
12063 }
12064 
12065 void
12066 rb_iseq_mark_and_pin_insn_storage(struct iseq_compile_data_storage *storage)
12067 {
12068  INSN *iobj = 0;
12069  size_t size = sizeof(INSN);
12070  unsigned int pos = 0;
12071 
12072  while (storage) {
12073 #ifdef STRICT_ALIGNMENT
12074  size_t padding = calc_padding((void *)&storage->buff[pos], size);
12075 #else
12076  const size_t padding = 0; /* expected to be optimized by compiler */
12077 #endif /* STRICT_ALIGNMENT */
12078  size_t offset = pos + size + padding;
12079  if (offset > storage->size || offset > storage->pos) {
12080  pos = 0;
12081  storage = storage->next;
12082  }
12083  else {
12084 #ifdef STRICT_ALIGNMENT
12085  pos += (int)padding;
12086 #endif /* STRICT_ALIGNMENT */
12087 
12088  iobj = (INSN *)&storage->buff[pos];
12089 
12090  if (iobj->operands) {
12091  iseq_insn_each_markable_object(iobj, iseq_insn_each_object_mark_and_pin, (VALUE)0);
12092  }
12093  pos += (int)size;
12094  }
12095  }
12096 }
12097 
12098 static const rb_data_type_t labels_wrapper_type = {
12099  .wrap_struct_name = "compiler/labels_wrapper",
12100  .function = {
12101  .dmark = (RUBY_DATA_FUNC)rb_mark_set,
12102  .dfree = (RUBY_DATA_FUNC)st_free_table,
12103  },
12104  .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
12105 };
12106 
12107 void
12108 rb_iseq_build_from_ary(rb_iseq_t *iseq, VALUE misc, VALUE locals, VALUE params,
12109  VALUE exception, VALUE body)
12110 {
12111 #define SYM(s) ID2SYM(rb_intern_const(#s))
12112  int i, len;
12113  unsigned int arg_size, local_size, stack_max;
12114  ID *tbl;
12115  struct st_table *labels_table = st_init_numtable();
12116  VALUE labels_wrapper = TypedData_Wrap_Struct(0, &labels_wrapper_type, labels_table);
12117  VALUE arg_opt_labels = rb_hash_aref(params, SYM(opt));
12118  VALUE keywords = rb_hash_aref(params, SYM(keyword));
12119  VALUE sym_arg_rest = ID2SYM(rb_intern_const("#arg_rest"));
12120  DECL_ANCHOR(anchor);
12121  INIT_ANCHOR(anchor);
12122 
12123  len = RARRAY_LENINT(locals);
12124  ISEQ_BODY(iseq)->local_table_size = len;
12125  ISEQ_BODY(iseq)->local_table = tbl = len > 0 ? (ID *)ALLOC_N(ID, ISEQ_BODY(iseq)->local_table_size) : NULL;
12126 
12127  for (i = 0; i < len; i++) {
12128  VALUE lv = RARRAY_AREF(locals, i);
12129 
12130  if (sym_arg_rest == lv) {
12131  tbl[i] = 0;
12132  }
12133  else {
12134  tbl[i] = FIXNUM_P(lv) ? (ID)FIX2LONG(lv) : SYM2ID(CHECK_SYMBOL(lv));
12135  }
12136  }
12137 
12138 #define INT_PARAM(F) int_param(&ISEQ_BODY(iseq)->param.F, params, SYM(F))
12139  if (INT_PARAM(lead_num)) {
12140  ISEQ_BODY(iseq)->param.flags.has_lead = TRUE;
12141  }
12142  if (INT_PARAM(post_num)) ISEQ_BODY(iseq)->param.flags.has_post = TRUE;
12143  if (INT_PARAM(post_start)) ISEQ_BODY(iseq)->param.flags.has_post = TRUE;
12144  if (INT_PARAM(rest_start)) ISEQ_BODY(iseq)->param.flags.has_rest = TRUE;
12145  if (INT_PARAM(block_start)) ISEQ_BODY(iseq)->param.flags.has_block = TRUE;
12146 #undef INT_PARAM
12147  {
12148 #define INT_PARAM(F) F = (int_param(&x, misc, SYM(F)) ? (unsigned int)x : 0)
12149  int x;
12150  INT_PARAM(arg_size);
12151  INT_PARAM(local_size);
12152  INT_PARAM(stack_max);
12153 #undef INT_PARAM
12154  }
12155 
12156  VALUE node_ids = Qfalse;
12157 #ifdef USE_ISEQ_NODE_ID
12158  node_ids = rb_hash_aref(misc, ID2SYM(rb_intern("node_ids")));
12159  if (!RB_TYPE_P(node_ids, T_ARRAY)) {
12160  rb_raise(rb_eTypeError, "node_ids is not an array");
12161  }
12162 #endif
12163 
12164  if (RB_TYPE_P(arg_opt_labels, T_ARRAY)) {
12165  len = RARRAY_LENINT(arg_opt_labels);
12166  ISEQ_BODY(iseq)->param.flags.has_opt = !!(len - 1 >= 0);
12167 
12168  if (ISEQ_BODY(iseq)->param.flags.has_opt) {
12169  VALUE *opt_table = ALLOC_N(VALUE, len);
12170 
12171  for (i = 0; i < len; i++) {
12172  VALUE ent = RARRAY_AREF(arg_opt_labels, i);
12173  LABEL *label = register_label(iseq, labels_table, ent);
12174  opt_table[i] = (VALUE)label;
12175  }
12176 
12177  ISEQ_BODY(iseq)->param.opt_num = len - 1;
12178  ISEQ_BODY(iseq)->param.opt_table = opt_table;
12179  }
12180  }
12181  else if (!NIL_P(arg_opt_labels)) {
12182  rb_raise(rb_eTypeError, ":opt param is not an array: %+"PRIsVALUE,
12183  arg_opt_labels);
12184  }
12185 
12186  if (RB_TYPE_P(keywords, T_ARRAY)) {
12187  ISEQ_BODY(iseq)->param.keyword = iseq_build_kw(iseq, params, keywords);
12188  }
12189  else if (!NIL_P(keywords)) {
12190  rb_raise(rb_eTypeError, ":keywords param is not an array: %+"PRIsVALUE,
12191  keywords);
12192  }
12193 
12194  if (Qtrue == rb_hash_aref(params, SYM(ambiguous_param0))) {
12195  ISEQ_BODY(iseq)->param.flags.ambiguous_param0 = TRUE;
12196  }
12197 
12198  if (Qtrue == rb_hash_aref(params, SYM(use_block))) {
12199  ISEQ_BODY(iseq)->param.flags.use_block = TRUE;
12200  }
12201 
12202  if (int_param(&i, params, SYM(kwrest))) {
12203  struct rb_iseq_param_keyword *keyword = (struct rb_iseq_param_keyword *)ISEQ_BODY(iseq)->param.keyword;
12204  if (keyword == NULL) {
12205  ISEQ_BODY(iseq)->param.keyword = keyword = ZALLOC(struct rb_iseq_param_keyword);
12206  }
12207  keyword->rest_start = i;
12208  ISEQ_BODY(iseq)->param.flags.has_kwrest = TRUE;
12209  }
12210 #undef SYM
12211  iseq_calc_param_size(iseq);
12212 
12213  /* exception */
12214  iseq_build_from_ary_exception(iseq, labels_table, exception);
12215 
12216  /* body */
12217  iseq_build_from_ary_body(iseq, anchor, body, node_ids, labels_wrapper);
12218 
12219  ISEQ_BODY(iseq)->param.size = arg_size;
12220  ISEQ_BODY(iseq)->local_table_size = local_size;
12221  ISEQ_BODY(iseq)->stack_max = stack_max;
12222 }
12223 
12224 /* for parser */
12225 
12226 int
12227 rb_dvar_defined(ID id, const rb_iseq_t *iseq)
12228 {
12229  if (iseq) {
12230  const struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
12231  while (body->type == ISEQ_TYPE_BLOCK ||
12232  body->type == ISEQ_TYPE_RESCUE ||
12233  body->type == ISEQ_TYPE_ENSURE ||
12234  body->type == ISEQ_TYPE_EVAL ||
12235  body->type == ISEQ_TYPE_MAIN
12236  ) {
12237  unsigned int i;
12238 
12239  for (i = 0; i < body->local_table_size; i++) {
12240  if (body->local_table[i] == id) {
12241  return 1;
12242  }
12243  }
12244  iseq = body->parent_iseq;
12245  body = ISEQ_BODY(iseq);
12246  }
12247  }
12248  return 0;
12249 }
12250 
12251 int
12252 rb_local_defined(ID id, const rb_iseq_t *iseq)
12253 {
12254  if (iseq) {
12255  unsigned int i;
12256  const struct rb_iseq_constant_body *const body = ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq);
12257 
12258  for (i=0; i<body->local_table_size; i++) {
12259  if (body->local_table[i] == id) {
12260  return 1;
12261  }
12262  }
12263  }
12264  return 0;
12265 }
12266 
12267 /* ISeq binary format */
12268 
12269 #ifndef IBF_ISEQ_DEBUG
12270 #define IBF_ISEQ_DEBUG 0
12271 #endif
12272 
12273 #ifndef IBF_ISEQ_ENABLE_LOCAL_BUFFER
12274 #define IBF_ISEQ_ENABLE_LOCAL_BUFFER 0
12275 #endif
12276 
12277 typedef uint32_t ibf_offset_t;
12278 #define IBF_OFFSET(ptr) ((ibf_offset_t)(VALUE)(ptr))
12279 
12280 #define IBF_MAJOR_VERSION ISEQ_MAJOR_VERSION
12281 #ifdef RUBY_DEVEL
12282 #define IBF_DEVEL_VERSION 4
12283 #define IBF_MINOR_VERSION (ISEQ_MINOR_VERSION * 10000 + IBF_DEVEL_VERSION)
12284 #else
12285 #define IBF_MINOR_VERSION ISEQ_MINOR_VERSION
12286 #endif
12287 
12288 static const char IBF_ENDIAN_MARK =
12289 #ifdef WORDS_BIGENDIAN
12290  'b'
12291 #else
12292  'l'
12293 #endif
12294  ;
12295 
12296 struct ibf_header {
12297  char magic[4]; /* YARB */
12298  uint32_t major_version;
12299  uint32_t minor_version;
12300  uint32_t size;
12301  uint32_t extra_size;
12302 
12303  uint32_t iseq_list_size;
12304  uint32_t global_object_list_size;
12305  ibf_offset_t iseq_list_offset;
12306  ibf_offset_t global_object_list_offset;
12307  uint8_t endian;
12308  uint8_t wordsize; /* assume no 2048-bit CPU */
12309 };
12310 
12312  VALUE str;
12313  st_table *obj_table; /* obj -> obj number */
12314 };
12315 
12316 struct ibf_dump {
12317  st_table *iseq_table; /* iseq -> iseq number */
12318  struct ibf_dump_buffer global_buffer;
12319  struct ibf_dump_buffer *current_buffer;
12320 };
12321 
12323  const char *buff;
12324  ibf_offset_t size;
12325 
12326  VALUE obj_list; /* [obj0, ...] */
12327  unsigned int obj_list_size;
12328  ibf_offset_t obj_list_offset;
12329 };
12330 
12331 struct ibf_load {
12332  const struct ibf_header *header;
12333  VALUE iseq_list; /* [iseq0, ...] */
12334  struct ibf_load_buffer global_buffer;
12335  VALUE loader_obj;
12336  rb_iseq_t *iseq;
12337  VALUE str;
12338  struct ibf_load_buffer *current_buffer;
12339 };
12340 
12341 struct pinned_list {
12342  long size;
12343  VALUE buffer[1];
12344 };
12345 
12346 static void
12347 pinned_list_mark(void *ptr)
12348 {
12349  long i;
12350  struct pinned_list *list = (struct pinned_list *)ptr;
12351  for (i = 0; i < list->size; i++) {
12352  if (list->buffer[i]) {
12353  rb_gc_mark(list->buffer[i]);
12354  }
12355  }
12356 }
12357 
12358 static const rb_data_type_t pinned_list_type = {
12359  "pinned_list",
12360  {
12361  pinned_list_mark,
12363  NULL, // No external memory to report,
12364  },
12365  0, 0, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_EMBEDDABLE
12366 };
12367 
12368 static VALUE
12369 pinned_list_fetch(VALUE list, long offset)
12370 {
12371  struct pinned_list * ptr;
12372 
12373  TypedData_Get_Struct(list, struct pinned_list, &pinned_list_type, ptr);
12374 
12375  if (offset >= ptr->size) {
12376  rb_raise(rb_eIndexError, "object index out of range: %ld", offset);
12377  }
12378 
12379  return ptr->buffer[offset];
12380 }
12381 
12382 static void
12383 pinned_list_store(VALUE list, long offset, VALUE object)
12384 {
12385  struct pinned_list * ptr;
12386 
12387  TypedData_Get_Struct(list, struct pinned_list, &pinned_list_type, ptr);
12388 
12389  if (offset >= ptr->size) {
12390  rb_raise(rb_eIndexError, "object index out of range: %ld", offset);
12391  }
12392 
12393  RB_OBJ_WRITE(list, &ptr->buffer[offset], object);
12394 }
12395 
12396 static VALUE
12397 pinned_list_new(long size)
12398 {
12399  size_t memsize = offsetof(struct pinned_list, buffer) + size * sizeof(VALUE);
12400  VALUE obj_list = rb_data_typed_object_zalloc(0, memsize, &pinned_list_type);
12401  struct pinned_list * ptr = RTYPEDDATA_GET_DATA(obj_list);
12402  ptr->size = size;
12403  return obj_list;
12404 }
12405 
12406 static ibf_offset_t
12407 ibf_dump_pos(struct ibf_dump *dump)
12408 {
12409  long pos = RSTRING_LEN(dump->current_buffer->str);
12410 #if SIZEOF_LONG > SIZEOF_INT
12411  if (pos >= UINT_MAX) {
12412  rb_raise(rb_eRuntimeError, "dump size exceeds");
12413  }
12414 #endif
12415  return (unsigned int)pos;
12416 }
12417 
12418 static void
12419 ibf_dump_align(struct ibf_dump *dump, size_t align)
12420 {
12421  ibf_offset_t pos = ibf_dump_pos(dump);
12422  if (pos % align) {
12423  static const char padding[sizeof(VALUE)];
12424  size_t size = align - ((size_t)pos % align);
12425 #if SIZEOF_LONG > SIZEOF_INT
12426  if (pos + size >= UINT_MAX) {
12427  rb_raise(rb_eRuntimeError, "dump size exceeds");
12428  }
12429 #endif
12430  for (; size > sizeof(padding); size -= sizeof(padding)) {
12431  rb_str_cat(dump->current_buffer->str, padding, sizeof(padding));
12432  }
12433  rb_str_cat(dump->current_buffer->str, padding, size);
12434  }
12435 }
12436 
12437 static ibf_offset_t
12438 ibf_dump_write(struct ibf_dump *dump, const void *buff, unsigned long size)
12439 {
12440  ibf_offset_t pos = ibf_dump_pos(dump);
12441  rb_str_cat(dump->current_buffer->str, (const char *)buff, size);
12442  /* TODO: overflow check */
12443  return pos;
12444 }
12445 
12446 static ibf_offset_t
12447 ibf_dump_write_byte(struct ibf_dump *dump, unsigned char byte)
12448 {
12449  return ibf_dump_write(dump, &byte, sizeof(unsigned char));
12450 }
12451 
12452 static void
12453 ibf_dump_overwrite(struct ibf_dump *dump, void *buff, unsigned int size, long offset)
12454 {
12455  VALUE str = dump->current_buffer->str;
12456  char *ptr = RSTRING_PTR(str);
12457  if ((unsigned long)(size + offset) > (unsigned long)RSTRING_LEN(str))
12458  rb_bug("ibf_dump_overwrite: overflow");
12459  memcpy(ptr + offset, buff, size);
12460 }
12461 
12462 static const void *
12463 ibf_load_ptr(const struct ibf_load *load, ibf_offset_t *offset, int size)
12464 {
12465  ibf_offset_t beg = *offset;
12466  *offset += size;
12467  return load->current_buffer->buff + beg;
12468 }
12469 
12470 static void *
12471 ibf_load_alloc(const struct ibf_load *load, ibf_offset_t offset, size_t x, size_t y)
12472 {
12473  void *buff = ruby_xmalloc2(x, y);
12474  size_t size = x * y;
12475  memcpy(buff, load->current_buffer->buff + offset, size);
12476  return buff;
12477 }
12478 
12479 #define IBF_W_ALIGN(type) (RUBY_ALIGNOF(type) > 1 ? ibf_dump_align(dump, RUBY_ALIGNOF(type)) : (void)0)
12480 
12481 #define IBF_W(b, type, n) (IBF_W_ALIGN(type), (type *)(VALUE)IBF_WP(b, type, n))
12482 #define IBF_WV(variable) ibf_dump_write(dump, &(variable), sizeof(variable))
12483 #define IBF_WP(b, type, n) ibf_dump_write(dump, (b), sizeof(type) * (n))
12484 #define IBF_R(val, type, n) (type *)ibf_load_alloc(load, IBF_OFFSET(val), sizeof(type), (n))
12485 #define IBF_ZERO(variable) memset(&(variable), 0, sizeof(variable))
12486 
12487 static int
12488 ibf_table_lookup(struct st_table *table, st_data_t key)
12489 {
12490  st_data_t val;
12491 
12492  if (st_lookup(table, key, &val)) {
12493  return (int)val;
12494  }
12495  else {
12496  return -1;
12497  }
12498 }
12499 
12500 static int
12501 ibf_table_find_or_insert(struct st_table *table, st_data_t key)
12502 {
12503  int index = ibf_table_lookup(table, key);
12504 
12505  if (index < 0) { /* not found */
12506  index = (int)table->num_entries;
12507  st_insert(table, key, (st_data_t)index);
12508  }
12509 
12510  return index;
12511 }
12512 
12513 /* dump/load generic */
12514 
12515 static void ibf_dump_object_list(struct ibf_dump *dump, ibf_offset_t *obj_list_offset, unsigned int *obj_list_size);
12516 
12517 static VALUE ibf_load_object(const struct ibf_load *load, VALUE object_index);
12518 static rb_iseq_t *ibf_load_iseq(const struct ibf_load *load, const rb_iseq_t *index_iseq);
12519 
12520 static st_table *
12521 ibf_dump_object_table_new(void)
12522 {
12523  st_table *obj_table = st_init_numtable(); /* need free */
12524  st_insert(obj_table, (st_data_t)Qnil, (st_data_t)0); /* 0th is nil */
12525 
12526  return obj_table;
12527 }
12528 
12529 static VALUE
12530 ibf_dump_object(struct ibf_dump *dump, VALUE obj)
12531 {
12532  return ibf_table_find_or_insert(dump->current_buffer->obj_table, (st_data_t)obj);
12533 }
12534 
12535 static VALUE
12536 ibf_dump_id(struct ibf_dump *dump, ID id)
12537 {
12538  if (id == 0 || rb_id2name(id) == NULL) {
12539  return 0;
12540  }
12541  return ibf_dump_object(dump, rb_id2sym(id));
12542 }
12543 
12544 static ID
12545 ibf_load_id(const struct ibf_load *load, const ID id_index)
12546 {
12547  if (id_index == 0) {
12548  return 0;
12549  }
12550  VALUE sym = ibf_load_object(load, id_index);
12551  if (rb_integer_type_p(sym)) {
12552  /* Load hidden local variables as indexes */
12553  return NUM2ULONG(sym);
12554  }
12555  return rb_sym2id(sym);
12556 }
12557 
12558 /* dump/load: code */
12559 
12560 static ibf_offset_t ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq);
12561 
12562 static int
12563 ibf_dump_iseq(struct ibf_dump *dump, const rb_iseq_t *iseq)
12564 {
12565  if (iseq == NULL) {
12566  return -1;
12567  }
12568  else {
12569  return ibf_table_find_or_insert(dump->iseq_table, (st_data_t)iseq);
12570  }
12571 }
12572 
12573 static unsigned char
12574 ibf_load_byte(const struct ibf_load *load, ibf_offset_t *offset)
12575 {
12576  if (*offset >= load->current_buffer->size) { rb_raise(rb_eRuntimeError, "invalid bytecode"); }
12577  return (unsigned char)load->current_buffer->buff[(*offset)++];
12578 }
12579 
12580 /*
12581  * Small uint serialization
12582  * 0x00000000_00000000 - 0x00000000_0000007f: 1byte | XXXX XXX1 |
12583  * 0x00000000_00000080 - 0x00000000_00003fff: 2byte | XXXX XX10 | XXXX XXXX |
12584  * 0x00000000_00004000 - 0x00000000_001fffff: 3byte | XXXX X100 | XXXX XXXX | XXXX XXXX |
12585  * 0x00000000_00020000 - 0x00000000_0fffffff: 4byte | XXXX 1000 | XXXX XXXX | XXXX XXXX | XXXX XXXX |
12586  * ...
12587  * 0x00010000_00000000 - 0x00ffffff_ffffffff: 8byte | 1000 0000 | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX |
12588  * 0x01000000_00000000 - 0xffffffff_ffffffff: 9byte | 0000 0000 | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX |
12589  */
12590 static void
12591 ibf_dump_write_small_value(struct ibf_dump *dump, VALUE x)
12592 {
12593  if (sizeof(VALUE) > 8 || CHAR_BIT != 8) {
12594  ibf_dump_write(dump, &x, sizeof(VALUE));
12595  return;
12596  }
12597 
12598  enum { max_byte_length = sizeof(VALUE) + 1 };
12599 
12600  unsigned char bytes[max_byte_length];
12601  ibf_offset_t n;
12602 
12603  for (n = 0; n < sizeof(VALUE) && (x >> (7 - n)); n++, x >>= 8) {
12604  bytes[max_byte_length - 1 - n] = (unsigned char)x;
12605  }
12606 
12607  x <<= 1;
12608  x |= 1;
12609  x <<= n;
12610  bytes[max_byte_length - 1 - n] = (unsigned char)x;
12611  n++;
12612 
12613  ibf_dump_write(dump, bytes + max_byte_length - n, n);
12614 }
12615 
12616 static VALUE
12617 ibf_load_small_value(const struct ibf_load *load, ibf_offset_t *offset)
12618 {
12619  if (sizeof(VALUE) > 8 || CHAR_BIT != 8) {
12620  union { char s[sizeof(VALUE)]; VALUE v; } x;
12621 
12622  memcpy(x.s, load->current_buffer->buff + *offset, sizeof(VALUE));
12623  *offset += sizeof(VALUE);
12624 
12625  return x.v;
12626  }
12627 
12628  enum { max_byte_length = sizeof(VALUE) + 1 };
12629 
12630  const unsigned char *buffer = (const unsigned char *)load->current_buffer->buff;
12631  const unsigned char c = buffer[*offset];
12632 
12633  ibf_offset_t n =
12634  c & 1 ? 1 :
12635  c == 0 ? 9 : ntz_int32(c) + 1;
12636  VALUE x = (VALUE)c >> n;
12637 
12638  if (*offset + n > load->current_buffer->size) {
12639  rb_raise(rb_eRuntimeError, "invalid byte sequence");
12640  }
12641 
12642  ibf_offset_t i;
12643  for (i = 1; i < n; i++) {
12644  x <<= 8;
12645  x |= (VALUE)buffer[*offset + i];
12646  }
12647 
12648  *offset += n;
12649  return x;
12650 }
12651 
12652 static void
12653 ibf_dump_builtin(struct ibf_dump *dump, const struct rb_builtin_function *bf)
12654 {
12655  // short: index
12656  // short: name.length
12657  // bytes: name
12658  // // omit argc (only verify with name)
12659  ibf_dump_write_small_value(dump, (VALUE)bf->index);
12660 
12661  size_t len = strlen(bf->name);
12662  ibf_dump_write_small_value(dump, (VALUE)len);
12663  ibf_dump_write(dump, bf->name, len);
12664 }
12665 
12666 static const struct rb_builtin_function *
12667 ibf_load_builtin(const struct ibf_load *load, ibf_offset_t *offset)
12668 {
12669  int i = (int)ibf_load_small_value(load, offset);
12670  int len = (int)ibf_load_small_value(load, offset);
12671  const char *name = (char *)ibf_load_ptr(load, offset, len);
12672 
12673  if (0) {
12674  fprintf(stderr, "%.*s!!\n", len, name);
12675  }
12676 
12677  const struct rb_builtin_function *table = GET_VM()->builtin_function_table;
12678  if (table == NULL) rb_raise(rb_eArgError, "builtin function table is not provided");
12679  if (strncmp(table[i].name, name, len) != 0) {
12680  rb_raise(rb_eArgError, "builtin function index (%d) mismatch (expect %s but %s)", i, name, table[i].name);
12681  }
12682  // fprintf(stderr, "load-builtin: name:%s(%d)\n", table[i].name, table[i].argc);
12683 
12684  return &table[i];
12685 }
12686 
12687 static ibf_offset_t
12688 ibf_dump_code(struct ibf_dump *dump, const rb_iseq_t *iseq)
12689 {
12690  const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
12691  const int iseq_size = body->iseq_size;
12692  int code_index;
12693  const VALUE *orig_code = rb_iseq_original_iseq(iseq);
12694 
12695  ibf_offset_t offset = ibf_dump_pos(dump);
12696 
12697  for (code_index=0; code_index<iseq_size;) {
12698  const VALUE insn = orig_code[code_index++];
12699  const char *types = insn_op_types(insn);
12700  int op_index;
12701 
12702  /* opcode */
12703  if (insn >= 0x100) { rb_raise(rb_eRuntimeError, "invalid instruction"); }
12704  ibf_dump_write_small_value(dump, insn);
12705 
12706  /* operands */
12707  for (op_index=0; types[op_index]; op_index++, code_index++) {
12708  VALUE op = orig_code[code_index];
12709  VALUE wv;
12710 
12711  switch (types[op_index]) {
12712  case TS_CDHASH:
12713  case TS_VALUE:
12714  wv = ibf_dump_object(dump, op);
12715  break;
12716  case TS_ISEQ:
12717  wv = (VALUE)ibf_dump_iseq(dump, (const rb_iseq_t *)op);
12718  break;
12719  case TS_IC:
12720  {
12721  IC ic = (IC)op;
12722  VALUE arr = idlist_to_array(ic->segments);
12723  wv = ibf_dump_object(dump, arr);
12724  }
12725  break;
12726  case TS_ISE:
12727  case TS_IVC:
12728  case TS_ICVARC:
12729  {
12730  union iseq_inline_storage_entry *is = (union iseq_inline_storage_entry *)op;
12731  wv = is - ISEQ_IS_ENTRY_START(body, types[op_index]);
12732  }
12733  break;
12734  case TS_CALLDATA:
12735  {
12736  goto skip_wv;
12737  }
12738  case TS_ID:
12739  wv = ibf_dump_id(dump, (ID)op);
12740  break;
12741  case TS_FUNCPTR:
12742  rb_raise(rb_eRuntimeError, "TS_FUNCPTR is not supported");
12743  goto skip_wv;
12744  case TS_BUILTIN:
12745  ibf_dump_builtin(dump, (const struct rb_builtin_function *)op);
12746  goto skip_wv;
12747  default:
12748  wv = op;
12749  break;
12750  }
12751  ibf_dump_write_small_value(dump, wv);
12752  skip_wv:;
12753  }
12754  RUBY_ASSERT(insn_len(insn) == op_index+1);
12755  }
12756 
12757  return offset;
12758 }
12759 
12760 static VALUE *
12761 ibf_load_code(const struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t bytecode_offset, ibf_offset_t bytecode_size, unsigned int iseq_size)
12762 {
12763  VALUE iseqv = (VALUE)iseq;
12764  unsigned int code_index;
12765  ibf_offset_t reading_pos = bytecode_offset;
12766  VALUE *code = ALLOC_N(VALUE, iseq_size);
12767 
12768  struct rb_iseq_constant_body *load_body = ISEQ_BODY(iseq);
12769  struct rb_call_data *cd_entries = load_body->call_data;
12770  int ic_index = 0;
12771 
12772  iseq_bits_t * mark_offset_bits;
12773 
12774  iseq_bits_t tmp[1] = {0};
12775 
12776  if (ISEQ_MBITS_BUFLEN(iseq_size) == 1) {
12777  mark_offset_bits = tmp;
12778  }
12779  else {
12780  mark_offset_bits = ZALLOC_N(iseq_bits_t, ISEQ_MBITS_BUFLEN(iseq_size));
12781  }
12782  bool needs_bitmap = false;
12783 
12784  for (code_index=0; code_index<iseq_size;) {
12785  /* opcode */
12786  const VALUE insn = code[code_index] = ibf_load_small_value(load, &reading_pos);
12787  const char *types = insn_op_types(insn);
12788  int op_index;
12789 
12790  code_index++;
12791 
12792  /* operands */
12793  for (op_index=0; types[op_index]; op_index++, code_index++) {
12794  const char operand_type = types[op_index];
12795  switch (operand_type) {
12796  case TS_VALUE:
12797  {
12798  VALUE op = ibf_load_small_value(load, &reading_pos);
12799  VALUE v = ibf_load_object(load, op);
12800  code[code_index] = v;
12801  if (!SPECIAL_CONST_P(v)) {
12802  RB_OBJ_WRITTEN(iseqv, Qundef, v);
12803  ISEQ_MBITS_SET(mark_offset_bits, code_index);
12804  needs_bitmap = true;
12805  }
12806  break;
12807  }
12808  case TS_CDHASH:
12809  {
12810  VALUE op = ibf_load_small_value(load, &reading_pos);
12811  VALUE v = ibf_load_object(load, op);
12812  v = rb_hash_dup(v); // hash dumped as frozen
12813  RHASH_TBL_RAW(v)->type = &cdhash_type;
12814  rb_hash_rehash(v); // hash function changed
12815  freeze_hide_obj(v);
12816 
12817  // Overwrite the existing hash in the object list. This
12818  // is to keep the object alive during load time.
12819  // [Bug #17984] [ruby-core:104259]
12820  pinned_list_store(load->current_buffer->obj_list, (long)op, v);
12821 
12822  code[code_index] = v;
12823  ISEQ_MBITS_SET(mark_offset_bits, code_index);
12824  RB_OBJ_WRITTEN(iseqv, Qundef, v);
12825  needs_bitmap = true;
12826  break;
12827  }
12828  case TS_ISEQ:
12829  {
12830  VALUE op = (VALUE)ibf_load_small_value(load, &reading_pos);
12831  VALUE v = (VALUE)ibf_load_iseq(load, (const rb_iseq_t *)op);
12832  code[code_index] = v;
12833  if (!SPECIAL_CONST_P(v)) {
12834  RB_OBJ_WRITTEN(iseqv, Qundef, v);
12835  ISEQ_MBITS_SET(mark_offset_bits, code_index);
12836  needs_bitmap = true;
12837  }
12838  break;
12839  }
12840  case TS_IC:
12841  {
12842  VALUE op = ibf_load_small_value(load, &reading_pos);
12843  VALUE arr = ibf_load_object(load, op);
12844 
12845  IC ic = &ISEQ_IS_IC_ENTRY(load_body, ic_index++);
12846  ic->segments = array_to_idlist(arr);
12847 
12848  code[code_index] = (VALUE)ic;
12849  }
12850  break;
12851  case TS_ISE:
12852  case TS_ICVARC:
12853  case TS_IVC:
12854  {
12855  unsigned int op = (unsigned int)ibf_load_small_value(load, &reading_pos);
12856 
12857  ISE ic = ISEQ_IS_ENTRY_START(load_body, operand_type) + op;
12858  code[code_index] = (VALUE)ic;
12859 
12860  if (operand_type == TS_IVC) {
12861  IVC cache = (IVC)ic;
12862 
12863  if (insn == BIN(setinstancevariable)) {
12864  ID iv_name = (ID)code[code_index - 1];
12865  cache->iv_set_name = iv_name;
12866  }
12867  else {
12868  cache->iv_set_name = 0;
12869  }
12870 
12871  vm_ic_attr_index_initialize(cache, INVALID_SHAPE_ID);
12872  }
12873 
12874  }
12875  break;
12876  case TS_CALLDATA:
12877  {
12878  code[code_index] = (VALUE)cd_entries++;
12879  }
12880  break;
12881  case TS_ID:
12882  {
12883  VALUE op = ibf_load_small_value(load, &reading_pos);
12884  code[code_index] = ibf_load_id(load, (ID)(VALUE)op);
12885  }
12886  break;
12887  case TS_FUNCPTR:
12888  rb_raise(rb_eRuntimeError, "TS_FUNCPTR is not supported");
12889  break;
12890  case TS_BUILTIN:
12891  code[code_index] = (VALUE)ibf_load_builtin(load, &reading_pos);
12892  break;
12893  default:
12894  code[code_index] = ibf_load_small_value(load, &reading_pos);
12895  continue;
12896  }
12897  }
12898  if (insn_len(insn) != op_index+1) {
12899  rb_raise(rb_eRuntimeError, "operand size mismatch");
12900  }
12901  }
12902 
12903  load_body->iseq_encoded = code;
12904  load_body->iseq_size = code_index;
12905 
12906  if (ISEQ_MBITS_BUFLEN(load_body->iseq_size) == 1) {
12907  load_body->mark_bits.single = mark_offset_bits[0];
12908  }
12909  else {
12910  if (needs_bitmap) {
12911  load_body->mark_bits.list = mark_offset_bits;
12912  }
12913  else {
12914  load_body->mark_bits.list = 0;
12915  ruby_xfree(mark_offset_bits);
12916  }
12917  }
12918 
12919  RUBY_ASSERT(code_index == iseq_size);
12920  RUBY_ASSERT(reading_pos == bytecode_offset + bytecode_size);
12921  return code;
12922 }
12923 
12924 static ibf_offset_t
12925 ibf_dump_param_opt_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
12926 {
12927  int opt_num = ISEQ_BODY(iseq)->param.opt_num;
12928 
12929  if (opt_num > 0) {
12930  IBF_W_ALIGN(VALUE);
12931  return ibf_dump_write(dump, ISEQ_BODY(iseq)->param.opt_table, sizeof(VALUE) * (opt_num + 1));
12932  }
12933  else {
12934  return ibf_dump_pos(dump);
12935  }
12936 }
12937 
12938 static VALUE *
12939 ibf_load_param_opt_table(const struct ibf_load *load, ibf_offset_t opt_table_offset, int opt_num)
12940 {
12941  if (opt_num > 0) {
12942  VALUE *table = ALLOC_N(VALUE, opt_num+1);
12943  MEMCPY(table, load->current_buffer->buff + opt_table_offset, VALUE, opt_num+1);
12944  return table;
12945  }
12946  else {
12947  return NULL;
12948  }
12949 }
12950 
12951 static ibf_offset_t
12952 ibf_dump_param_keyword(struct ibf_dump *dump, const rb_iseq_t *iseq)
12953 {
12954  const struct rb_iseq_param_keyword *kw = ISEQ_BODY(iseq)->param.keyword;
12955 
12956  if (kw) {
12957  struct rb_iseq_param_keyword dump_kw = *kw;
12958  int dv_num = kw->num - kw->required_num;
12959  ID *ids = kw->num > 0 ? ALLOCA_N(ID, kw->num) : NULL;
12960  VALUE *dvs = dv_num > 0 ? ALLOCA_N(VALUE, dv_num) : NULL;
12961  int i;
12962 
12963  for (i=0; i<kw->num; i++) ids[i] = (ID)ibf_dump_id(dump, kw->table[i]);
12964  for (i=0; i<dv_num; i++) dvs[i] = (VALUE)ibf_dump_object(dump, kw->default_values[i]);
12965 
12966  dump_kw.table = IBF_W(ids, ID, kw->num);
12967  dump_kw.default_values = IBF_W(dvs, VALUE, dv_num);
12968  IBF_W_ALIGN(struct rb_iseq_param_keyword);
12969  return ibf_dump_write(dump, &dump_kw, sizeof(struct rb_iseq_param_keyword) * 1);
12970  }
12971  else {
12972  return 0;
12973  }
12974 }
12975 
12976 static const struct rb_iseq_param_keyword *
12977 ibf_load_param_keyword(const struct ibf_load *load, ibf_offset_t param_keyword_offset)
12978 {
12979  if (param_keyword_offset) {
12980  struct rb_iseq_param_keyword *kw = IBF_R(param_keyword_offset, struct rb_iseq_param_keyword, 1);
12981  int dv_num = kw->num - kw->required_num;
12982  VALUE *dvs = dv_num ? IBF_R(kw->default_values, VALUE, dv_num) : NULL;
12983 
12984  int i;
12985  for (i=0; i<dv_num; i++) {
12986  dvs[i] = ibf_load_object(load, dvs[i]);
12987  }
12988 
12989  // Will be set once the local table is loaded.
12990  kw->table = NULL;
12991 
12992  kw->default_values = dvs;
12993  return kw;
12994  }
12995  else {
12996  return NULL;
12997  }
12998 }
12999 
13000 static ibf_offset_t
13001 ibf_dump_insns_info_body(struct ibf_dump *dump, const rb_iseq_t *iseq)
13002 {
13003  ibf_offset_t offset = ibf_dump_pos(dump);
13004  const struct iseq_insn_info_entry *entries = ISEQ_BODY(iseq)->insns_info.body;
13005 
13006  unsigned int i;
13007  for (i = 0; i < ISEQ_BODY(iseq)->insns_info.size; i++) {
13008  ibf_dump_write_small_value(dump, entries[i].line_no);
13009 #ifdef USE_ISEQ_NODE_ID
13010  ibf_dump_write_small_value(dump, entries[i].node_id);
13011 #endif
13012  ibf_dump_write_small_value(dump, entries[i].events);
13013  }
13014 
13015  return offset;
13016 }
13017 
13018 static struct iseq_insn_info_entry *
13019 ibf_load_insns_info_body(const struct ibf_load *load, ibf_offset_t body_offset, unsigned int size)
13020 {
13021  ibf_offset_t reading_pos = body_offset;
13022  struct iseq_insn_info_entry *entries = ALLOC_N(struct iseq_insn_info_entry, size);
13023 
13024  unsigned int i;
13025  for (i = 0; i < size; i++) {
13026  entries[i].line_no = (int)ibf_load_small_value(load, &reading_pos);
13027 #ifdef USE_ISEQ_NODE_ID
13028  entries[i].node_id = (int)ibf_load_small_value(load, &reading_pos);
13029 #endif
13030  entries[i].events = (rb_event_flag_t)ibf_load_small_value(load, &reading_pos);
13031  }
13032 
13033  return entries;
13034 }
13035 
13036 static ibf_offset_t
13037 ibf_dump_insns_info_positions(struct ibf_dump *dump, const unsigned int *positions, unsigned int size)
13038 {
13039  ibf_offset_t offset = ibf_dump_pos(dump);
13040 
13041  unsigned int last = 0;
13042  unsigned int i;
13043  for (i = 0; i < size; i++) {
13044  ibf_dump_write_small_value(dump, positions[i] - last);
13045  last = positions[i];
13046  }
13047 
13048  return offset;
13049 }
13050 
13051 static unsigned int *
13052 ibf_load_insns_info_positions(const struct ibf_load *load, ibf_offset_t positions_offset, unsigned int size)
13053 {
13054  ibf_offset_t reading_pos = positions_offset;
13055  unsigned int *positions = ALLOC_N(unsigned int, size);
13056 
13057  unsigned int last = 0;
13058  unsigned int i;
13059  for (i = 0; i < size; i++) {
13060  positions[i] = last + (unsigned int)ibf_load_small_value(load, &reading_pos);
13061  last = positions[i];
13062  }
13063 
13064  return positions;
13065 }
13066 
13067 static ibf_offset_t
13068 ibf_dump_local_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
13069 {
13070  const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
13071  const int size = body->local_table_size;
13072  ID *table = ALLOCA_N(ID, size);
13073  int i;
13074 
13075  for (i=0; i<size; i++) {
13076  VALUE v = ibf_dump_id(dump, body->local_table[i]);
13077  if (v == 0) {
13078  /* Dump hidden local variables as indexes, so load_from_binary will work with them */
13079  v = ibf_dump_object(dump, ULONG2NUM(body->local_table[i]));
13080  }
13081  table[i] = v;
13082  }
13083 
13084  IBF_W_ALIGN(ID);
13085  return ibf_dump_write(dump, table, sizeof(ID) * size);
13086 }
13087 
13088 static ID *
13089 ibf_load_local_table(const struct ibf_load *load, ibf_offset_t local_table_offset, int size)
13090 {
13091  if (size > 0) {
13092  ID *table = IBF_R(local_table_offset, ID, size);
13093  int i;
13094 
13095  for (i=0; i<size; i++) {
13096  table[i] = ibf_load_id(load, table[i]);
13097  }
13098  return table;
13099  }
13100  else {
13101  return NULL;
13102  }
13103 }
13104 
13105 static ibf_offset_t
13106 ibf_dump_catch_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
13107 {
13108  const struct iseq_catch_table *table = ISEQ_BODY(iseq)->catch_table;
13109 
13110  if (table) {
13111  int *iseq_indices = ALLOCA_N(int, table->size);
13112  unsigned int i;
13113 
13114  for (i=0; i<table->size; i++) {
13115  iseq_indices[i] = ibf_dump_iseq(dump, table->entries[i].iseq);
13116  }
13117 
13118  const ibf_offset_t offset = ibf_dump_pos(dump);
13119 
13120  for (i=0; i<table->size; i++) {
13121  ibf_dump_write_small_value(dump, iseq_indices[i]);
13122  ibf_dump_write_small_value(dump, table->entries[i].type);
13123  ibf_dump_write_small_value(dump, table->entries[i].start);
13124  ibf_dump_write_small_value(dump, table->entries[i].end);
13125  ibf_dump_write_small_value(dump, table->entries[i].cont);
13126  ibf_dump_write_small_value(dump, table->entries[i].sp);
13127  }
13128  return offset;
13129  }
13130  else {
13131  return ibf_dump_pos(dump);
13132  }
13133 }
13134 
13135 static struct iseq_catch_table *
13136 ibf_load_catch_table(const struct ibf_load *load, ibf_offset_t catch_table_offset, unsigned int size)
13137 {
13138  if (size) {
13139  struct iseq_catch_table *table = ruby_xmalloc(iseq_catch_table_bytes(size));
13140  table->size = size;
13141 
13142  ibf_offset_t reading_pos = catch_table_offset;
13143 
13144  unsigned int i;
13145  for (i=0; i<table->size; i++) {
13146  int iseq_index = (int)ibf_load_small_value(load, &reading_pos);
13147  table->entries[i].type = (enum rb_catch_type)ibf_load_small_value(load, &reading_pos);
13148  table->entries[i].start = (unsigned int)ibf_load_small_value(load, &reading_pos);
13149  table->entries[i].end = (unsigned int)ibf_load_small_value(load, &reading_pos);
13150  table->entries[i].cont = (unsigned int)ibf_load_small_value(load, &reading_pos);
13151  table->entries[i].sp = (unsigned int)ibf_load_small_value(load, &reading_pos);
13152 
13153  table->entries[i].iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)iseq_index);
13154  }
13155  return table;
13156  }
13157  else {
13158  return NULL;
13159  }
13160 }
13161 
13162 static ibf_offset_t
13163 ibf_dump_ci_entries(struct ibf_dump *dump, const rb_iseq_t *iseq)
13164 {
13165  const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
13166  const unsigned int ci_size = body->ci_size;
13167  const struct rb_call_data *cds = body->call_data;
13168 
13169  ibf_offset_t offset = ibf_dump_pos(dump);
13170 
13171  unsigned int i;
13172 
13173  for (i = 0; i < ci_size; i++) {
13174  const struct rb_callinfo *ci = cds[i].ci;
13175  if (ci != NULL) {
13176  ibf_dump_write_small_value(dump, ibf_dump_id(dump, vm_ci_mid(ci)));
13177  ibf_dump_write_small_value(dump, vm_ci_flag(ci));
13178  ibf_dump_write_small_value(dump, vm_ci_argc(ci));
13179 
13180  const struct rb_callinfo_kwarg *kwarg = vm_ci_kwarg(ci);
13181  if (kwarg) {
13182  int len = kwarg->keyword_len;
13183  ibf_dump_write_small_value(dump, len);
13184  for (int j=0; j<len; j++) {
13185  VALUE keyword = ibf_dump_object(dump, kwarg->keywords[j]);
13186  ibf_dump_write_small_value(dump, keyword);
13187  }
13188  }
13189  else {
13190  ibf_dump_write_small_value(dump, 0);
13191  }
13192  }
13193  else {
13194  // TODO: truncate NULL ci from call_data.
13195  ibf_dump_write_small_value(dump, (VALUE)-1);
13196  }
13197  }
13198 
13199  return offset;
13200 }
13201 
13203  ID id;
13204  VALUE name;
13205  VALUE val;
13206 };
13207 
13209  size_t num;
13210  struct outer_variable_pair pairs[1];
13211 };
13212 
13213 static enum rb_id_table_iterator_result
13214 store_outer_variable(ID id, VALUE val, void *dump)
13215 {
13216  struct outer_variable_list *ovlist = dump;
13217  struct outer_variable_pair *pair = &ovlist->pairs[ovlist->num++];
13218  pair->id = id;
13219  pair->name = rb_id2str(id);
13220  pair->val = val;
13221  return ID_TABLE_CONTINUE;
13222 }
13223 
13224 static int
13225 outer_variable_cmp(const void *a, const void *b, void *arg)
13226 {
13227  const struct outer_variable_pair *ap = (const struct outer_variable_pair *)a;
13228  const struct outer_variable_pair *bp = (const struct outer_variable_pair *)b;
13229  return rb_str_cmp(ap->name, bp->name);
13230 }
13231 
13232 static ibf_offset_t
13233 ibf_dump_outer_variables(struct ibf_dump *dump, const rb_iseq_t *iseq)
13234 {
13235  struct rb_id_table * ovs = ISEQ_BODY(iseq)->outer_variables;
13236 
13237  ibf_offset_t offset = ibf_dump_pos(dump);
13238 
13239  size_t size = ovs ? rb_id_table_size(ovs) : 0;
13240  ibf_dump_write_small_value(dump, (VALUE)size);
13241  if (size > 0) {
13242  VALUE buff;
13243  size_t buffsize =
13244  rb_size_mul_add_or_raise(sizeof(struct outer_variable_pair), size,
13245  offsetof(struct outer_variable_list, pairs),
13246  rb_eArgError);
13247  struct outer_variable_list *ovlist = RB_ALLOCV(buff, buffsize);
13248  ovlist->num = 0;
13249  rb_id_table_foreach(ovs, store_outer_variable, ovlist);
13250  ruby_qsort(ovlist->pairs, size, sizeof(struct outer_variable_pair), outer_variable_cmp, NULL);
13251  for (size_t i = 0; i < size; ++i) {
13252  ID id = ovlist->pairs[i].id;
13253  ID val = ovlist->pairs[i].val;
13254  ibf_dump_write_small_value(dump, ibf_dump_id(dump, id));
13255  ibf_dump_write_small_value(dump, val);
13256  }
13257  }
13258 
13259  return offset;
13260 }
13261 
13262 /* note that we dump out rb_call_info but load back rb_call_data */
13263 static void
13264 ibf_load_ci_entries(const struct ibf_load *load,
13265  ibf_offset_t ci_entries_offset,
13266  unsigned int ci_size,
13267  struct rb_call_data **cd_ptr)
13268 {
13269  ibf_offset_t reading_pos = ci_entries_offset;
13270 
13271  unsigned int i;
13272 
13273  struct rb_call_data *cds = ZALLOC_N(struct rb_call_data, ci_size);
13274  *cd_ptr = cds;
13275 
13276  for (i = 0; i < ci_size; i++) {
13277  VALUE mid_index = ibf_load_small_value(load, &reading_pos);
13278  if (mid_index != (VALUE)-1) {
13279  ID mid = ibf_load_id(load, mid_index);
13280  unsigned int flag = (unsigned int)ibf_load_small_value(load, &reading_pos);
13281  unsigned int argc = (unsigned int)ibf_load_small_value(load, &reading_pos);
13282 
13283  struct rb_callinfo_kwarg *kwarg = NULL;
13284  int kwlen = (int)ibf_load_small_value(load, &reading_pos);
13285  if (kwlen > 0) {
13286  kwarg = rb_xmalloc_mul_add(kwlen, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
13287  kwarg->references = 0;
13288  kwarg->keyword_len = kwlen;
13289  for (int j=0; j<kwlen; j++) {
13290  VALUE keyword = ibf_load_small_value(load, &reading_pos);
13291  kwarg->keywords[j] = ibf_load_object(load, keyword);
13292  }
13293  }
13294 
13295  cds[i].ci = vm_ci_new(mid, flag, argc, kwarg);
13296  RB_OBJ_WRITTEN(load->iseq, Qundef, cds[i].ci);
13297  cds[i].cc = vm_cc_empty();
13298  }
13299  else {
13300  // NULL ci
13301  cds[i].ci = NULL;
13302  cds[i].cc = NULL;
13303  }
13304  }
13305 }
13306 
13307 static struct rb_id_table *
13308 ibf_load_outer_variables(const struct ibf_load * load, ibf_offset_t outer_variables_offset)
13309 {
13310  ibf_offset_t reading_pos = outer_variables_offset;
13311 
13312  struct rb_id_table *tbl = NULL;
13313 
13314  size_t table_size = (size_t)ibf_load_small_value(load, &reading_pos);
13315 
13316  if (table_size > 0) {
13317  tbl = rb_id_table_create(table_size);
13318  }
13319 
13320  for (size_t i = 0; i < table_size; i++) {
13321  ID key = ibf_load_id(load, (ID)ibf_load_small_value(load, &reading_pos));
13322  VALUE value = ibf_load_small_value(load, &reading_pos);
13323  if (!key) key = rb_make_temporary_id(i);
13324  rb_id_table_insert(tbl, key, value);
13325  }
13326 
13327  return tbl;
13328 }
13329 
13330 static ibf_offset_t
13331 ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq)
13332 {
13333  RUBY_ASSERT(dump->current_buffer == &dump->global_buffer);
13334 
13335  unsigned int *positions;
13336 
13337  const struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
13338 
13339  const VALUE location_pathobj_index = ibf_dump_object(dump, body->location.pathobj); /* TODO: freeze */
13340  const VALUE location_base_label_index = ibf_dump_object(dump, body->location.base_label);
13341  const VALUE location_label_index = ibf_dump_object(dump, body->location.label);
13342 
13343 #if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13344  ibf_offset_t iseq_start = ibf_dump_pos(dump);
13345 
13346  struct ibf_dump_buffer *saved_buffer = dump->current_buffer;
13347  struct ibf_dump_buffer buffer;
13348  buffer.str = rb_str_new(0, 0);
13349  buffer.obj_table = ibf_dump_object_table_new();
13350  dump->current_buffer = &buffer;
13351 #endif
13352 
13353  const ibf_offset_t bytecode_offset = ibf_dump_code(dump, iseq);
13354  const ibf_offset_t bytecode_size = ibf_dump_pos(dump) - bytecode_offset;
13355  const ibf_offset_t param_opt_table_offset = ibf_dump_param_opt_table(dump, iseq);
13356  const ibf_offset_t param_keyword_offset = ibf_dump_param_keyword(dump, iseq);
13357  const ibf_offset_t insns_info_body_offset = ibf_dump_insns_info_body(dump, iseq);
13358 
13359  positions = rb_iseq_insns_info_decode_positions(ISEQ_BODY(iseq));
13360  const ibf_offset_t insns_info_positions_offset = ibf_dump_insns_info_positions(dump, positions, body->insns_info.size);
13361  ruby_xfree(positions);
13362 
13363  const ibf_offset_t local_table_offset = ibf_dump_local_table(dump, iseq);
13364  const unsigned int catch_table_size = body->catch_table ? body->catch_table->size : 0;
13365  const ibf_offset_t catch_table_offset = ibf_dump_catch_table(dump, iseq);
13366  const int parent_iseq_index = ibf_dump_iseq(dump, ISEQ_BODY(iseq)->parent_iseq);
13367  const int local_iseq_index = ibf_dump_iseq(dump, ISEQ_BODY(iseq)->local_iseq);
13368  const int mandatory_only_iseq_index = ibf_dump_iseq(dump, ISEQ_BODY(iseq)->mandatory_only_iseq);
13369  const ibf_offset_t ci_entries_offset = ibf_dump_ci_entries(dump, iseq);
13370  const ibf_offset_t outer_variables_offset = ibf_dump_outer_variables(dump, iseq);
13371 
13372 #if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13373  ibf_offset_t local_obj_list_offset;
13374  unsigned int local_obj_list_size;
13375 
13376  ibf_dump_object_list(dump, &local_obj_list_offset, &local_obj_list_size);
13377 #endif
13378 
13379  ibf_offset_t body_offset = ibf_dump_pos(dump);
13380 
13381  /* dump the constant body */
13382  unsigned int param_flags =
13383  (body->param.flags.has_lead << 0) |
13384  (body->param.flags.has_opt << 1) |
13385  (body->param.flags.has_rest << 2) |
13386  (body->param.flags.has_post << 3) |
13387  (body->param.flags.has_kw << 4) |
13388  (body->param.flags.has_kwrest << 5) |
13389  (body->param.flags.has_block << 6) |
13390  (body->param.flags.ambiguous_param0 << 7) |
13391  (body->param.flags.accepts_no_kwarg << 8) |
13392  (body->param.flags.ruby2_keywords << 9) |
13393  (body->param.flags.anon_rest << 10) |
13394  (body->param.flags.anon_kwrest << 11) |
13395  (body->param.flags.use_block << 12) |
13396  (body->param.flags.forwardable << 13) ;
13397 
13398 #if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13399 # define IBF_BODY_OFFSET(x) (x)
13400 #else
13401 # define IBF_BODY_OFFSET(x) (body_offset - (x))
13402 #endif
13403 
13404  ibf_dump_write_small_value(dump, body->type);
13405  ibf_dump_write_small_value(dump, body->iseq_size);
13406  ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(bytecode_offset));
13407  ibf_dump_write_small_value(dump, bytecode_size);
13408  ibf_dump_write_small_value(dump, param_flags);
13409  ibf_dump_write_small_value(dump, body->param.size);
13410  ibf_dump_write_small_value(dump, body->param.lead_num);
13411  ibf_dump_write_small_value(dump, body->param.opt_num);
13412  ibf_dump_write_small_value(dump, body->param.rest_start);
13413  ibf_dump_write_small_value(dump, body->param.post_start);
13414  ibf_dump_write_small_value(dump, body->param.post_num);
13415  ibf_dump_write_small_value(dump, body->param.block_start);
13416  ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(param_opt_table_offset));
13417  ibf_dump_write_small_value(dump, param_keyword_offset);
13418  ibf_dump_write_small_value(dump, location_pathobj_index);
13419  ibf_dump_write_small_value(dump, location_base_label_index);
13420  ibf_dump_write_small_value(dump, location_label_index);
13421  ibf_dump_write_small_value(dump, body->location.first_lineno);
13422  ibf_dump_write_small_value(dump, body->location.node_id);
13423  ibf_dump_write_small_value(dump, body->location.code_location.beg_pos.lineno);
13424  ibf_dump_write_small_value(dump, body->location.code_location.beg_pos.column);
13425  ibf_dump_write_small_value(dump, body->location.code_location.end_pos.lineno);
13426  ibf_dump_write_small_value(dump, body->location.code_location.end_pos.column);
13427  ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(insns_info_body_offset));
13428  ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(insns_info_positions_offset));
13429  ibf_dump_write_small_value(dump, body->insns_info.size);
13430  ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(local_table_offset));
13431  ibf_dump_write_small_value(dump, catch_table_size);
13432  ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(catch_table_offset));
13433  ibf_dump_write_small_value(dump, parent_iseq_index);
13434  ibf_dump_write_small_value(dump, local_iseq_index);
13435  ibf_dump_write_small_value(dump, mandatory_only_iseq_index);
13436  ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(ci_entries_offset));
13437  ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(outer_variables_offset));
13438  ibf_dump_write_small_value(dump, body->variable.flip_count);
13439  ibf_dump_write_small_value(dump, body->local_table_size);
13440  ibf_dump_write_small_value(dump, body->ivc_size);
13441  ibf_dump_write_small_value(dump, body->icvarc_size);
13442  ibf_dump_write_small_value(dump, body->ise_size);
13443  ibf_dump_write_small_value(dump, body->ic_size);
13444  ibf_dump_write_small_value(dump, body->ci_size);
13445  ibf_dump_write_small_value(dump, body->stack_max);
13446  ibf_dump_write_small_value(dump, body->builtin_attrs);
13447  ibf_dump_write_small_value(dump, body->prism ? 1 : 0);
13448 
13449 #undef IBF_BODY_OFFSET
13450 
13451 #if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13452  ibf_offset_t iseq_length_bytes = ibf_dump_pos(dump);
13453 
13454  dump->current_buffer = saved_buffer;
13455  ibf_dump_write(dump, RSTRING_PTR(buffer.str), iseq_length_bytes);
13456 
13457  ibf_offset_t offset = ibf_dump_pos(dump);
13458  ibf_dump_write_small_value(dump, iseq_start);
13459  ibf_dump_write_small_value(dump, iseq_length_bytes);
13460  ibf_dump_write_small_value(dump, body_offset);
13461 
13462  ibf_dump_write_small_value(dump, local_obj_list_offset);
13463  ibf_dump_write_small_value(dump, local_obj_list_size);
13464 
13465  st_free_table(buffer.obj_table); // TODO: this leaks in case of exception
13466 
13467  return offset;
13468 #else
13469  return body_offset;
13470 #endif
13471 }
13472 
13473 static VALUE
13474 ibf_load_location_str(const struct ibf_load *load, VALUE str_index)
13475 {
13476  VALUE str = ibf_load_object(load, str_index);
13477  if (str != Qnil) {
13478  str = rb_fstring(str);
13479  }
13480  return str;
13481 }
13482 
13483 static void
13484 ibf_load_iseq_each(struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t offset)
13485 {
13486  struct rb_iseq_constant_body *load_body = ISEQ_BODY(iseq) = rb_iseq_constant_body_alloc();
13487 
13488  ibf_offset_t reading_pos = offset;
13489 
13490 #if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13491  struct ibf_load_buffer *saved_buffer = load->current_buffer;
13492  load->current_buffer = &load->global_buffer;
13493 
13494  const ibf_offset_t iseq_start = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13495  const ibf_offset_t iseq_length_bytes = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13496  const ibf_offset_t body_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13497 
13498  struct ibf_load_buffer buffer;
13499  buffer.buff = load->global_buffer.buff + iseq_start;
13500  buffer.size = iseq_length_bytes;
13501  buffer.obj_list_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13502  buffer.obj_list_size = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13503  buffer.obj_list = pinned_list_new(buffer.obj_list_size);
13504 
13505  load->current_buffer = &buffer;
13506  reading_pos = body_offset;
13507 #endif
13508 
13509 #if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13510 # define IBF_BODY_OFFSET(x) (x)
13511 #else
13512 # define IBF_BODY_OFFSET(x) (offset - (x))
13513 #endif
13514 
13515  const unsigned int type = (unsigned int)ibf_load_small_value(load, &reading_pos);
13516  const unsigned int iseq_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13517  const ibf_offset_t bytecode_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13518  const ibf_offset_t bytecode_size = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13519  const unsigned int param_flags = (unsigned int)ibf_load_small_value(load, &reading_pos);
13520  const unsigned int param_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13521  const int param_lead_num = (int)ibf_load_small_value(load, &reading_pos);
13522  const int param_opt_num = (int)ibf_load_small_value(load, &reading_pos);
13523  const int param_rest_start = (int)ibf_load_small_value(load, &reading_pos);
13524  const int param_post_start = (int)ibf_load_small_value(load, &reading_pos);
13525  const int param_post_num = (int)ibf_load_small_value(load, &reading_pos);
13526  const int param_block_start = (int)ibf_load_small_value(load, &reading_pos);
13527  const ibf_offset_t param_opt_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13528  const ibf_offset_t param_keyword_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13529  const VALUE location_pathobj_index = ibf_load_small_value(load, &reading_pos);
13530  const VALUE location_base_label_index = ibf_load_small_value(load, &reading_pos);
13531  const VALUE location_label_index = ibf_load_small_value(load, &reading_pos);
13532  const int location_first_lineno = (int)ibf_load_small_value(load, &reading_pos);
13533  const int location_node_id = (int)ibf_load_small_value(load, &reading_pos);
13534  const int location_code_location_beg_pos_lineno = (int)ibf_load_small_value(load, &reading_pos);
13535  const int location_code_location_beg_pos_column = (int)ibf_load_small_value(load, &reading_pos);
13536  const int location_code_location_end_pos_lineno = (int)ibf_load_small_value(load, &reading_pos);
13537  const int location_code_location_end_pos_column = (int)ibf_load_small_value(load, &reading_pos);
13538  const ibf_offset_t insns_info_body_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13539  const ibf_offset_t insns_info_positions_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13540  const unsigned int insns_info_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13541  const ibf_offset_t local_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13542  const unsigned int catch_table_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13543  const ibf_offset_t catch_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13544  const int parent_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
13545  const int local_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
13546  const int mandatory_only_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
13547  const ibf_offset_t ci_entries_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13548  const ibf_offset_t outer_variables_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13549  const rb_snum_t variable_flip_count = (rb_snum_t)ibf_load_small_value(load, &reading_pos);
13550  const unsigned int local_table_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13551 
13552  const unsigned int ivc_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13553  const unsigned int icvarc_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13554  const unsigned int ise_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13555  const unsigned int ic_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13556 
13557  const unsigned int ci_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13558  const unsigned int stack_max = (unsigned int)ibf_load_small_value(load, &reading_pos);
13559  const unsigned int builtin_attrs = (unsigned int)ibf_load_small_value(load, &reading_pos);
13560  const bool prism = (bool)ibf_load_small_value(load, &reading_pos);
13561 
13562  // setup fname and dummy frame
13563  VALUE path = ibf_load_object(load, location_pathobj_index);
13564  {
13565  VALUE realpath = Qnil;
13566 
13567  if (RB_TYPE_P(path, T_STRING)) {
13568  realpath = path = rb_fstring(path);
13569  }
13570  else if (RB_TYPE_P(path, T_ARRAY)) {
13571  VALUE pathobj = path;
13572  if (RARRAY_LEN(pathobj) != 2) {
13573  rb_raise(rb_eRuntimeError, "path object size mismatch");
13574  }
13575  path = rb_fstring(RARRAY_AREF(pathobj, 0));
13576  realpath = RARRAY_AREF(pathobj, 1);
13577  if (!NIL_P(realpath)) {
13578  if (!RB_TYPE_P(realpath, T_STRING)) {
13579  rb_raise(rb_eArgError, "unexpected realpath %"PRIxVALUE
13580  "(%x), path=%+"PRIsVALUE,
13581  realpath, TYPE(realpath), path);
13582  }
13583  realpath = rb_fstring(realpath);
13584  }
13585  }
13586  else {
13587  rb_raise(rb_eRuntimeError, "unexpected path object");
13588  }
13589  rb_iseq_pathobj_set(iseq, path, realpath);
13590  }
13591 
13592  // push dummy frame
13593  rb_execution_context_t *ec = GET_EC();
13594  VALUE dummy_frame = rb_vm_push_frame_fname(ec, path);
13595 
13596 #undef IBF_BODY_OFFSET
13597 
13598  load_body->type = type;
13599  load_body->stack_max = stack_max;
13600  load_body->param.flags.has_lead = (param_flags >> 0) & 1;
13601  load_body->param.flags.has_opt = (param_flags >> 1) & 1;
13602  load_body->param.flags.has_rest = (param_flags >> 2) & 1;
13603  load_body->param.flags.has_post = (param_flags >> 3) & 1;
13604  load_body->param.flags.has_kw = FALSE;
13605  load_body->param.flags.has_kwrest = (param_flags >> 5) & 1;
13606  load_body->param.flags.has_block = (param_flags >> 6) & 1;
13607  load_body->param.flags.ambiguous_param0 = (param_flags >> 7) & 1;
13608  load_body->param.flags.accepts_no_kwarg = (param_flags >> 8) & 1;
13609  load_body->param.flags.ruby2_keywords = (param_flags >> 9) & 1;
13610  load_body->param.flags.anon_rest = (param_flags >> 10) & 1;
13611  load_body->param.flags.anon_kwrest = (param_flags >> 11) & 1;
13612  load_body->param.flags.use_block = (param_flags >> 12) & 1;
13613  load_body->param.flags.forwardable = (param_flags >> 13) & 1;
13614  load_body->param.size = param_size;
13615  load_body->param.lead_num = param_lead_num;
13616  load_body->param.opt_num = param_opt_num;
13617  load_body->param.rest_start = param_rest_start;
13618  load_body->param.post_start = param_post_start;
13619  load_body->param.post_num = param_post_num;
13620  load_body->param.block_start = param_block_start;
13621  load_body->local_table_size = local_table_size;
13622  load_body->ci_size = ci_size;
13623  load_body->insns_info.size = insns_info_size;
13624 
13625  ISEQ_COVERAGE_SET(iseq, Qnil);
13626  ISEQ_ORIGINAL_ISEQ_CLEAR(iseq);
13627  load_body->variable.flip_count = variable_flip_count;
13628  load_body->variable.script_lines = Qnil;
13629 
13630  load_body->location.first_lineno = location_first_lineno;
13631  load_body->location.node_id = location_node_id;
13632  load_body->location.code_location.beg_pos.lineno = location_code_location_beg_pos_lineno;
13633  load_body->location.code_location.beg_pos.column = location_code_location_beg_pos_column;
13634  load_body->location.code_location.end_pos.lineno = location_code_location_end_pos_lineno;
13635  load_body->location.code_location.end_pos.column = location_code_location_end_pos_column;
13636  load_body->builtin_attrs = builtin_attrs;
13637  load_body->prism = prism;
13638 
13639  load_body->ivc_size = ivc_size;
13640  load_body->icvarc_size = icvarc_size;
13641  load_body->ise_size = ise_size;
13642  load_body->ic_size = ic_size;
13643 
13644  if (ISEQ_IS_SIZE(load_body)) {
13645  load_body->is_entries = ZALLOC_N(union iseq_inline_storage_entry, ISEQ_IS_SIZE(load_body));
13646  }
13647  else {
13648  load_body->is_entries = NULL;
13649  }
13650  ibf_load_ci_entries(load, ci_entries_offset, ci_size, &load_body->call_data);
13651  load_body->outer_variables = ibf_load_outer_variables(load, outer_variables_offset);
13652  load_body->param.opt_table = ibf_load_param_opt_table(load, param_opt_table_offset, param_opt_num);
13653  load_body->param.keyword = ibf_load_param_keyword(load, param_keyword_offset);
13654  load_body->param.flags.has_kw = (param_flags >> 4) & 1;
13655  load_body->insns_info.body = ibf_load_insns_info_body(load, insns_info_body_offset, insns_info_size);
13656  load_body->insns_info.positions = ibf_load_insns_info_positions(load, insns_info_positions_offset, insns_info_size);
13657  load_body->local_table = ibf_load_local_table(load, local_table_offset, local_table_size);
13658  load_body->catch_table = ibf_load_catch_table(load, catch_table_offset, catch_table_size);
13659  load_body->parent_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)parent_iseq_index);
13660  load_body->local_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)local_iseq_index);
13661  load_body->mandatory_only_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)mandatory_only_iseq_index);
13662 
13663  // This must be done after the local table is loaded.
13664  if (load_body->param.keyword != NULL) {
13665  RUBY_ASSERT(load_body->local_table);
13666  struct rb_iseq_param_keyword *keyword = (struct rb_iseq_param_keyword *) load_body->param.keyword;
13667  keyword->table = &load_body->local_table[keyword->bits_start - keyword->num];
13668  }
13669 
13670  ibf_load_code(load, iseq, bytecode_offset, bytecode_size, iseq_size);
13671 #if VM_INSN_INFO_TABLE_IMPL == 2
13672  rb_iseq_insns_info_encode_positions(iseq);
13673 #endif
13674 
13675  rb_iseq_translate_threaded_code(iseq);
13676 
13677 #if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13678  load->current_buffer = &load->global_buffer;
13679 #endif
13680 
13681  RB_OBJ_WRITE(iseq, &load_body->location.base_label, ibf_load_location_str(load, location_base_label_index));
13682  RB_OBJ_WRITE(iseq, &load_body->location.label, ibf_load_location_str(load, location_label_index));
13683 
13684 #if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13685  load->current_buffer = saved_buffer;
13686 #endif
13687  verify_call_cache(iseq);
13688 
13689  RB_GC_GUARD(dummy_frame);
13690  rb_vm_pop_frame_no_int(ec);
13691 }
13692 
13694 {
13695  struct ibf_dump *dump;
13696  VALUE offset_list;
13697 };
13698 
13699 static int
13700 ibf_dump_iseq_list_i(st_data_t key, st_data_t val, st_data_t ptr)
13701 {
13702  const rb_iseq_t *iseq = (const rb_iseq_t *)key;
13703  struct ibf_dump_iseq_list_arg *args = (struct ibf_dump_iseq_list_arg *)ptr;
13704 
13705  ibf_offset_t offset = ibf_dump_iseq_each(args->dump, iseq);
13706  rb_ary_push(args->offset_list, UINT2NUM(offset));
13707 
13708  return ST_CONTINUE;
13709 }
13710 
13711 static void
13712 ibf_dump_iseq_list(struct ibf_dump *dump, struct ibf_header *header)
13713 {
13714  VALUE offset_list = rb_ary_hidden_new(dump->iseq_table->num_entries);
13715 
13716  struct ibf_dump_iseq_list_arg args;
13717  args.dump = dump;
13718  args.offset_list = offset_list;
13719 
13720  st_foreach(dump->iseq_table, ibf_dump_iseq_list_i, (st_data_t)&args);
13721 
13722  st_index_t i;
13723  st_index_t size = dump->iseq_table->num_entries;
13724  ibf_offset_t *offsets = ALLOCA_N(ibf_offset_t, size);
13725 
13726  for (i = 0; i < size; i++) {
13727  offsets[i] = NUM2UINT(RARRAY_AREF(offset_list, i));
13728  }
13729 
13730  ibf_dump_align(dump, sizeof(ibf_offset_t));
13731  header->iseq_list_offset = ibf_dump_write(dump, offsets, sizeof(ibf_offset_t) * size);
13732  header->iseq_list_size = (unsigned int)size;
13733 }
13734 
13735 #define IBF_OBJECT_INTERNAL FL_PROMOTED0
13736 
13737 /*
13738  * Binary format
13739  * - ibf_object_header
13740  * - ibf_object_xxx (xxx is type)
13741  */
13742 
13744  unsigned int type: 5;
13745  unsigned int special_const: 1;
13746  unsigned int frozen: 1;
13747  unsigned int internal: 1;
13748 };
13749 
13750 enum ibf_object_class_index {
13751  IBF_OBJECT_CLASS_OBJECT,
13752  IBF_OBJECT_CLASS_ARRAY,
13753  IBF_OBJECT_CLASS_STANDARD_ERROR,
13754  IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR,
13755  IBF_OBJECT_CLASS_TYPE_ERROR,
13756  IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR,
13757 };
13758 
13760  long srcstr;
13761  char option;
13762 };
13763 
13765  long len;
13766  long keyval[FLEX_ARY_LEN];
13767 };
13768 
13770  long class_index;
13771  long len;
13772  long beg;
13773  long end;
13774  int excl;
13775 };
13776 
13778  ssize_t slen;
13779  BDIGIT digits[FLEX_ARY_LEN];
13780 };
13781 
13782 enum ibf_object_data_type {
13783  IBF_OBJECT_DATA_ENCODING,
13784 };
13785 
13787  long a, b;
13788 };
13789 
13791  long str;
13792 };
13793 
13794 #define IBF_ALIGNED_OFFSET(align, offset) /* offset > 0 */ \
13795  ((((offset) - 1) / (align) + 1) * (align))
13796 #define IBF_OBJBODY(type, offset) (const type *)\
13797  ibf_load_check_offset(load, IBF_ALIGNED_OFFSET(RUBY_ALIGNOF(type), offset))
13798 
13799 static const void *
13800 ibf_load_check_offset(const struct ibf_load *load, size_t offset)
13801 {
13802  if (offset >= load->current_buffer->size) {
13803  rb_raise(rb_eIndexError, "object offset out of range: %"PRIdSIZE, offset);
13804  }
13805  return load->current_buffer->buff + offset;
13806 }
13807 
13808 NORETURN(static void ibf_dump_object_unsupported(struct ibf_dump *dump, VALUE obj));
13809 
13810 static void
13811 ibf_dump_object_unsupported(struct ibf_dump *dump, VALUE obj)
13812 {
13813  char buff[0x100];
13814  rb_raw_obj_info(buff, sizeof(buff), obj);
13815  rb_raise(rb_eNotImpError, "ibf_dump_object_unsupported: %s", buff);
13816 }
13817 
13818 NORETURN(static VALUE ibf_load_object_unsupported(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset));
13819 
13820 static VALUE
13821 ibf_load_object_unsupported(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
13822 {
13823  rb_raise(rb_eArgError, "unsupported");
13825 }
13826 
13827 static void
13828 ibf_dump_object_class(struct ibf_dump *dump, VALUE obj)
13829 {
13830  enum ibf_object_class_index cindex;
13831  if (obj == rb_cObject) {
13832  cindex = IBF_OBJECT_CLASS_OBJECT;
13833  }
13834  else if (obj == rb_cArray) {
13835  cindex = IBF_OBJECT_CLASS_ARRAY;
13836  }
13837  else if (obj == rb_eStandardError) {
13838  cindex = IBF_OBJECT_CLASS_STANDARD_ERROR;
13839  }
13840  else if (obj == rb_eNoMatchingPatternError) {
13841  cindex = IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR;
13842  }
13843  else if (obj == rb_eTypeError) {
13844  cindex = IBF_OBJECT_CLASS_TYPE_ERROR;
13845  }
13846  else if (obj == rb_eNoMatchingPatternKeyError) {
13847  cindex = IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR;
13848  }
13849  else {
13850  rb_obj_info_dump(obj);
13851  rb_p(obj);
13852  rb_bug("unsupported class");
13853  }
13854  ibf_dump_write_small_value(dump, (VALUE)cindex);
13855 }
13856 
13857 static VALUE
13858 ibf_load_object_class(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
13859 {
13860  enum ibf_object_class_index cindex = (enum ibf_object_class_index)ibf_load_small_value(load, &offset);
13861 
13862  switch (cindex) {
13863  case IBF_OBJECT_CLASS_OBJECT:
13864  return rb_cObject;
13865  case IBF_OBJECT_CLASS_ARRAY:
13866  return rb_cArray;
13867  case IBF_OBJECT_CLASS_STANDARD_ERROR:
13868  return rb_eStandardError;
13869  case IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR:
13871  case IBF_OBJECT_CLASS_TYPE_ERROR:
13872  return rb_eTypeError;
13873  case IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR:
13875  }
13876 
13877  rb_raise(rb_eArgError, "ibf_load_object_class: unknown class (%d)", (int)cindex);
13878 }
13879 
13880 
13881 static void
13882 ibf_dump_object_float(struct ibf_dump *dump, VALUE obj)
13883 {
13884  double dbl = RFLOAT_VALUE(obj);
13885  (void)IBF_W(&dbl, double, 1);
13886 }
13887 
13888 static VALUE
13889 ibf_load_object_float(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
13890 {
13891  const double *dblp = IBF_OBJBODY(double, offset);
13892  return DBL2NUM(*dblp);
13893 }
13894 
13895 static void
13896 ibf_dump_object_string(struct ibf_dump *dump, VALUE obj)
13897 {
13898  long encindex = (long)rb_enc_get_index(obj);
13899  long len = RSTRING_LEN(obj);
13900  const char *ptr = RSTRING_PTR(obj);
13901 
13902  if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
13903  rb_encoding *enc = rb_enc_from_index((int)encindex);
13904  const char *enc_name = rb_enc_name(enc);
13905  encindex = RUBY_ENCINDEX_BUILTIN_MAX + ibf_dump_object(dump, rb_str_new2(enc_name));
13906  }
13907 
13908  ibf_dump_write_small_value(dump, encindex);
13909  ibf_dump_write_small_value(dump, len);
13910  IBF_WP(ptr, char, len);
13911 }
13912 
13913 static VALUE
13914 ibf_load_object_string(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
13915 {
13916  ibf_offset_t reading_pos = offset;
13917 
13918  int encindex = (int)ibf_load_small_value(load, &reading_pos);
13919  const long len = (long)ibf_load_small_value(load, &reading_pos);
13920  const char *ptr = load->current_buffer->buff + reading_pos;
13921 
13922  if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
13923  VALUE enc_name_str = ibf_load_object(load, encindex - RUBY_ENCINDEX_BUILTIN_MAX);
13924  encindex = rb_enc_find_index(RSTRING_PTR(enc_name_str));
13925  }
13926 
13927  VALUE str;
13928  if (header->frozen && !header->internal) {
13929  str = rb_enc_literal_str(ptr, len, rb_enc_from_index(encindex));
13930  }
13931  else {
13932  str = rb_enc_str_new(ptr, len, rb_enc_from_index(encindex));
13933 
13934  if (header->internal) rb_obj_hide(str);
13935  if (header->frozen) str = rb_fstring(str);
13936  }
13937  return str;
13938 }
13939 
13940 static void
13941 ibf_dump_object_regexp(struct ibf_dump *dump, VALUE obj)
13942 {
13943  VALUE srcstr = RREGEXP_SRC(obj);
13944  struct ibf_object_regexp regexp;
13945  regexp.option = (char)rb_reg_options(obj);
13946  regexp.srcstr = (long)ibf_dump_object(dump, srcstr);
13947 
13948  ibf_dump_write_byte(dump, (unsigned char)regexp.option);
13949  ibf_dump_write_small_value(dump, regexp.srcstr);
13950 }
13951 
13952 static VALUE
13953 ibf_load_object_regexp(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
13954 {
13955  struct ibf_object_regexp regexp;
13956  regexp.option = ibf_load_byte(load, &offset);
13957  regexp.srcstr = ibf_load_small_value(load, &offset);
13958 
13959  VALUE srcstr = ibf_load_object(load, regexp.srcstr);
13960  VALUE reg = rb_reg_compile(srcstr, (int)regexp.option, NULL, 0);
13961 
13962  if (header->internal) rb_obj_hide(reg);
13963  if (header->frozen) rb_obj_freeze(reg);
13964 
13965  return reg;
13966 }
13967 
13968 static void
13969 ibf_dump_object_array(struct ibf_dump *dump, VALUE obj)
13970 {
13971  long i, len = RARRAY_LEN(obj);
13972  ibf_dump_write_small_value(dump, len);
13973  for (i=0; i<len; i++) {
13974  long index = (long)ibf_dump_object(dump, RARRAY_AREF(obj, i));
13975  ibf_dump_write_small_value(dump, index);
13976  }
13977 }
13978 
13979 static VALUE
13980 ibf_load_object_array(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
13981 {
13982  ibf_offset_t reading_pos = offset;
13983 
13984  const long len = (long)ibf_load_small_value(load, &reading_pos);
13985 
13986  VALUE ary = header->internal ? rb_ary_hidden_new(len) : rb_ary_new_capa(len);
13987  int i;
13988 
13989  for (i=0; i<len; i++) {
13990  const VALUE index = ibf_load_small_value(load, &reading_pos);
13991  rb_ary_push(ary, ibf_load_object(load, index));
13992  }
13993 
13994  if (header->frozen) rb_ary_freeze(ary);
13995 
13996  return ary;
13997 }
13998 
13999 static int
14000 ibf_dump_object_hash_i(st_data_t key, st_data_t val, st_data_t ptr)
14001 {
14002  struct ibf_dump *dump = (struct ibf_dump *)ptr;
14003 
14004  VALUE key_index = ibf_dump_object(dump, (VALUE)key);
14005  VALUE val_index = ibf_dump_object(dump, (VALUE)val);
14006 
14007  ibf_dump_write_small_value(dump, key_index);
14008  ibf_dump_write_small_value(dump, val_index);
14009  return ST_CONTINUE;
14010 }
14011 
14012 static void
14013 ibf_dump_object_hash(struct ibf_dump *dump, VALUE obj)
14014 {
14015  long len = RHASH_SIZE(obj);
14016  ibf_dump_write_small_value(dump, (VALUE)len);
14017 
14018  if (len > 0) rb_hash_foreach(obj, ibf_dump_object_hash_i, (VALUE)dump);
14019 }
14020 
14021 static VALUE
14022 ibf_load_object_hash(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14023 {
14024  long len = (long)ibf_load_small_value(load, &offset);
14025  VALUE obj = rb_hash_new_with_size(len);
14026  int i;
14027 
14028  for (i = 0; i < len; i++) {
14029  VALUE key_index = ibf_load_small_value(load, &offset);
14030  VALUE val_index = ibf_load_small_value(load, &offset);
14031 
14032  VALUE key = ibf_load_object(load, key_index);
14033  VALUE val = ibf_load_object(load, val_index);
14034  rb_hash_aset(obj, key, val);
14035  }
14036  rb_hash_rehash(obj);
14037 
14038  if (header->internal) rb_obj_hide(obj);
14039  if (header->frozen) rb_obj_freeze(obj);
14040 
14041  return obj;
14042 }
14043 
14044 static void
14045 ibf_dump_object_struct(struct ibf_dump *dump, VALUE obj)
14046 {
14047  if (rb_obj_is_kind_of(obj, rb_cRange)) {
14048  struct ibf_object_struct_range range;
14049  VALUE beg, end;
14050  IBF_ZERO(range);
14051  range.len = 3;
14052  range.class_index = 0;
14053 
14054  rb_range_values(obj, &beg, &end, &range.excl);
14055  range.beg = (long)ibf_dump_object(dump, beg);
14056  range.end = (long)ibf_dump_object(dump, end);
14057 
14058  IBF_W_ALIGN(struct ibf_object_struct_range);
14059  IBF_WV(range);
14060  }
14061  else {
14062  rb_raise(rb_eNotImpError, "ibf_dump_object_struct: unsupported class %"PRIsVALUE,
14063  rb_class_name(CLASS_OF(obj)));
14064  }
14065 }
14066 
14067 static VALUE
14068 ibf_load_object_struct(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14069 {
14070  const struct ibf_object_struct_range *range = IBF_OBJBODY(struct ibf_object_struct_range, offset);
14071  VALUE beg = ibf_load_object(load, range->beg);
14072  VALUE end = ibf_load_object(load, range->end);
14073  VALUE obj = rb_range_new(beg, end, range->excl);
14074  if (header->internal) rb_obj_hide(obj);
14075  if (header->frozen) rb_obj_freeze(obj);
14076  return obj;
14077 }
14078 
14079 static void
14080 ibf_dump_object_bignum(struct ibf_dump *dump, VALUE obj)
14081 {
14082  ssize_t len = BIGNUM_LEN(obj);
14083  ssize_t slen = BIGNUM_SIGN(obj) > 0 ? len : len * -1;
14084  BDIGIT *d = BIGNUM_DIGITS(obj);
14085 
14086  (void)IBF_W(&slen, ssize_t, 1);
14087  IBF_WP(d, BDIGIT, len);
14088 }
14089 
14090 static VALUE
14091 ibf_load_object_bignum(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14092 {
14093  const struct ibf_object_bignum *bignum = IBF_OBJBODY(struct ibf_object_bignum, offset);
14094  int sign = bignum->slen > 0;
14095  ssize_t len = sign > 0 ? bignum->slen : -1 * bignum->slen;
14096  const int big_unpack_flags = /* c.f. rb_big_unpack() */
14099  VALUE obj = rb_integer_unpack(bignum->digits, len, sizeof(BDIGIT), 0,
14100  big_unpack_flags |
14101  (sign == 0 ? INTEGER_PACK_NEGATIVE : 0));
14102  if (header->internal) rb_obj_hide(obj);
14103  if (header->frozen) rb_obj_freeze(obj);
14104  return obj;
14105 }
14106 
14107 static void
14108 ibf_dump_object_data(struct ibf_dump *dump, VALUE obj)
14109 {
14110  if (rb_data_is_encoding(obj)) {
14111  rb_encoding *enc = rb_to_encoding(obj);
14112  const char *name = rb_enc_name(enc);
14113  long len = strlen(name) + 1;
14114  long data[2];
14115  data[0] = IBF_OBJECT_DATA_ENCODING;
14116  data[1] = len;
14117  (void)IBF_W(data, long, 2);
14118  IBF_WP(name, char, len);
14119  }
14120  else {
14121  ibf_dump_object_unsupported(dump, obj);
14122  }
14123 }
14124 
14125 static VALUE
14126 ibf_load_object_data(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14127 {
14128  const long *body = IBF_OBJBODY(long, offset);
14129  const enum ibf_object_data_type type = (enum ibf_object_data_type)body[0];
14130  /* const long len = body[1]; */
14131  const char *data = (const char *)&body[2];
14132 
14133  switch (type) {
14134  case IBF_OBJECT_DATA_ENCODING:
14135  {
14136  VALUE encobj = rb_enc_from_encoding(rb_enc_find(data));
14137  return encobj;
14138  }
14139  }
14140 
14141  return ibf_load_object_unsupported(load, header, offset);
14142 }
14143 
14144 static void
14145 ibf_dump_object_complex_rational(struct ibf_dump *dump, VALUE obj)
14146 {
14147  long data[2];
14148  data[0] = (long)ibf_dump_object(dump, RCOMPLEX(obj)->real);
14149  data[1] = (long)ibf_dump_object(dump, RCOMPLEX(obj)->imag);
14150 
14151  (void)IBF_W(data, long, 2);
14152 }
14153 
14154 static VALUE
14155 ibf_load_object_complex_rational(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14156 {
14157  const struct ibf_object_complex_rational *nums = IBF_OBJBODY(struct ibf_object_complex_rational, offset);
14158  VALUE a = ibf_load_object(load, nums->a);
14159  VALUE b = ibf_load_object(load, nums->b);
14160  VALUE obj = header->type == T_COMPLEX ?
14161  rb_complex_new(a, b) : rb_rational_new(a, b);
14162 
14163  if (header->internal) rb_obj_hide(obj);
14164  if (header->frozen) rb_obj_freeze(obj);
14165  return obj;
14166 }
14167 
14168 static void
14169 ibf_dump_object_symbol(struct ibf_dump *dump, VALUE obj)
14170 {
14171  ibf_dump_object_string(dump, rb_sym2str(obj));
14172 }
14173 
14174 static VALUE
14175 ibf_load_object_symbol(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14176 {
14177  ibf_offset_t reading_pos = offset;
14178 
14179  int encindex = (int)ibf_load_small_value(load, &reading_pos);
14180  const long len = (long)ibf_load_small_value(load, &reading_pos);
14181  const char *ptr = load->current_buffer->buff + reading_pos;
14182 
14183  if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
14184  VALUE enc_name_str = ibf_load_object(load, encindex - RUBY_ENCINDEX_BUILTIN_MAX);
14185  encindex = rb_enc_find_index(RSTRING_PTR(enc_name_str));
14186  }
14187 
14188  ID id = rb_intern3(ptr, len, rb_enc_from_index(encindex));
14189  return ID2SYM(id);
14190 }
14191 
14192 typedef void (*ibf_dump_object_function)(struct ibf_dump *dump, VALUE obj);
14193 static const ibf_dump_object_function dump_object_functions[RUBY_T_MASK+1] = {
14194  ibf_dump_object_unsupported, /* T_NONE */
14195  ibf_dump_object_unsupported, /* T_OBJECT */
14196  ibf_dump_object_class, /* T_CLASS */
14197  ibf_dump_object_unsupported, /* T_MODULE */
14198  ibf_dump_object_float, /* T_FLOAT */
14199  ibf_dump_object_string, /* T_STRING */
14200  ibf_dump_object_regexp, /* T_REGEXP */
14201  ibf_dump_object_array, /* T_ARRAY */
14202  ibf_dump_object_hash, /* T_HASH */
14203  ibf_dump_object_struct, /* T_STRUCT */
14204  ibf_dump_object_bignum, /* T_BIGNUM */
14205  ibf_dump_object_unsupported, /* T_FILE */
14206  ibf_dump_object_data, /* T_DATA */
14207  ibf_dump_object_unsupported, /* T_MATCH */
14208  ibf_dump_object_complex_rational, /* T_COMPLEX */
14209  ibf_dump_object_complex_rational, /* T_RATIONAL */
14210  ibf_dump_object_unsupported, /* 0x10 */
14211  ibf_dump_object_unsupported, /* 0x11 T_NIL */
14212  ibf_dump_object_unsupported, /* 0x12 T_TRUE */
14213  ibf_dump_object_unsupported, /* 0x13 T_FALSE */
14214  ibf_dump_object_symbol, /* 0x14 T_SYMBOL */
14215  ibf_dump_object_unsupported, /* T_FIXNUM */
14216  ibf_dump_object_unsupported, /* T_UNDEF */
14217  ibf_dump_object_unsupported, /* 0x17 */
14218  ibf_dump_object_unsupported, /* 0x18 */
14219  ibf_dump_object_unsupported, /* 0x19 */
14220  ibf_dump_object_unsupported, /* T_IMEMO 0x1a */
14221  ibf_dump_object_unsupported, /* T_NODE 0x1b */
14222  ibf_dump_object_unsupported, /* T_ICLASS 0x1c */
14223  ibf_dump_object_unsupported, /* T_ZOMBIE 0x1d */
14224  ibf_dump_object_unsupported, /* 0x1e */
14225  ibf_dump_object_unsupported, /* 0x1f */
14226 };
14227 
14228 static void
14229 ibf_dump_object_object_header(struct ibf_dump *dump, const struct ibf_object_header header)
14230 {
14231  unsigned char byte =
14232  (header.type << 0) |
14233  (header.special_const << 5) |
14234  (header.frozen << 6) |
14235  (header.internal << 7);
14236 
14237  IBF_WV(byte);
14238 }
14239 
14240 static struct ibf_object_header
14241 ibf_load_object_object_header(const struct ibf_load *load, ibf_offset_t *offset)
14242 {
14243  unsigned char byte = ibf_load_byte(load, offset);
14244 
14245  struct ibf_object_header header;
14246  header.type = (byte >> 0) & 0x1f;
14247  header.special_const = (byte >> 5) & 0x01;
14248  header.frozen = (byte >> 6) & 0x01;
14249  header.internal = (byte >> 7) & 0x01;
14250 
14251  return header;
14252 }
14253 
14254 static ibf_offset_t
14255 ibf_dump_object_object(struct ibf_dump *dump, VALUE obj)
14256 {
14257  struct ibf_object_header obj_header;
14258  ibf_offset_t current_offset;
14259  IBF_ZERO(obj_header);
14260  obj_header.type = TYPE(obj);
14261 
14262  IBF_W_ALIGN(ibf_offset_t);
14263  current_offset = ibf_dump_pos(dump);
14264 
14265  if (SPECIAL_CONST_P(obj) &&
14266  ! (SYMBOL_P(obj) ||
14267  RB_FLOAT_TYPE_P(obj))) {
14268  obj_header.special_const = TRUE;
14269  obj_header.frozen = TRUE;
14270  obj_header.internal = TRUE;
14271  ibf_dump_object_object_header(dump, obj_header);
14272  ibf_dump_write_small_value(dump, obj);
14273  }
14274  else {
14275  obj_header.internal = SPECIAL_CONST_P(obj) ? FALSE : (RBASIC_CLASS(obj) == 0) ? TRUE : FALSE;
14276  obj_header.special_const = FALSE;
14277  obj_header.frozen = FL_TEST(obj, FL_FREEZE) ? TRUE : FALSE;
14278  ibf_dump_object_object_header(dump, obj_header);
14279  (*dump_object_functions[obj_header.type])(dump, obj);
14280  }
14281 
14282  return current_offset;
14283 }
14284 
14285 typedef VALUE (*ibf_load_object_function)(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset);
14286 static const ibf_load_object_function load_object_functions[RUBY_T_MASK+1] = {
14287  ibf_load_object_unsupported, /* T_NONE */
14288  ibf_load_object_unsupported, /* T_OBJECT */
14289  ibf_load_object_class, /* T_CLASS */
14290  ibf_load_object_unsupported, /* T_MODULE */
14291  ibf_load_object_float, /* T_FLOAT */
14292  ibf_load_object_string, /* T_STRING */
14293  ibf_load_object_regexp, /* T_REGEXP */
14294  ibf_load_object_array, /* T_ARRAY */
14295  ibf_load_object_hash, /* T_HASH */
14296  ibf_load_object_struct, /* T_STRUCT */
14297  ibf_load_object_bignum, /* T_BIGNUM */
14298  ibf_load_object_unsupported, /* T_FILE */
14299  ibf_load_object_data, /* T_DATA */
14300  ibf_load_object_unsupported, /* T_MATCH */
14301  ibf_load_object_complex_rational, /* T_COMPLEX */
14302  ibf_load_object_complex_rational, /* T_RATIONAL */
14303  ibf_load_object_unsupported, /* 0x10 */
14304  ibf_load_object_unsupported, /* T_NIL */
14305  ibf_load_object_unsupported, /* T_TRUE */
14306  ibf_load_object_unsupported, /* T_FALSE */
14307  ibf_load_object_symbol,
14308  ibf_load_object_unsupported, /* T_FIXNUM */
14309  ibf_load_object_unsupported, /* T_UNDEF */
14310  ibf_load_object_unsupported, /* 0x17 */
14311  ibf_load_object_unsupported, /* 0x18 */
14312  ibf_load_object_unsupported, /* 0x19 */
14313  ibf_load_object_unsupported, /* T_IMEMO 0x1a */
14314  ibf_load_object_unsupported, /* T_NODE 0x1b */
14315  ibf_load_object_unsupported, /* T_ICLASS 0x1c */
14316  ibf_load_object_unsupported, /* T_ZOMBIE 0x1d */
14317  ibf_load_object_unsupported, /* 0x1e */
14318  ibf_load_object_unsupported, /* 0x1f */
14319 };
14320 
14321 static VALUE
14322 ibf_load_object(const struct ibf_load *load, VALUE object_index)
14323 {
14324  if (object_index == 0) {
14325  return Qnil;
14326  }
14327  else {
14328  VALUE obj = pinned_list_fetch(load->current_buffer->obj_list, (long)object_index);
14329  if (!obj) {
14330  ibf_offset_t *offsets = (ibf_offset_t *)(load->current_buffer->obj_list_offset + load->current_buffer->buff);
14331  ibf_offset_t offset = offsets[object_index];
14332  const struct ibf_object_header header = ibf_load_object_object_header(load, &offset);
14333 
14334 #if IBF_ISEQ_DEBUG
14335  fprintf(stderr, "ibf_load_object: list=%#x offsets=%p offset=%#x\n",
14336  load->current_buffer->obj_list_offset, (void *)offsets, offset);
14337  fprintf(stderr, "ibf_load_object: type=%#x special=%d frozen=%d internal=%d\n",
14338  header.type, header.special_const, header.frozen, header.internal);
14339 #endif
14340  if (offset >= load->current_buffer->size) {
14341  rb_raise(rb_eIndexError, "object offset out of range: %u", offset);
14342  }
14343 
14344  if (header.special_const) {
14345  ibf_offset_t reading_pos = offset;
14346 
14347  obj = ibf_load_small_value(load, &reading_pos);
14348  }
14349  else {
14350  obj = (*load_object_functions[header.type])(load, &header, offset);
14351  }
14352 
14353  pinned_list_store(load->current_buffer->obj_list, (long)object_index, obj);
14354  }
14355 #if IBF_ISEQ_DEBUG
14356  fprintf(stderr, "ibf_load_object: index=%#"PRIxVALUE" obj=%#"PRIxVALUE"\n",
14357  object_index, obj);
14358 #endif
14359  return obj;
14360  }
14361 }
14362 
14364 {
14365  struct ibf_dump *dump;
14366  VALUE offset_list;
14367 };
14368 
14369 static int
14370 ibf_dump_object_list_i(st_data_t key, st_data_t val, st_data_t ptr)
14371 {
14372  VALUE obj = (VALUE)key;
14373  struct ibf_dump_object_list_arg *args = (struct ibf_dump_object_list_arg *)ptr;
14374 
14375  ibf_offset_t offset = ibf_dump_object_object(args->dump, obj);
14376  rb_ary_push(args->offset_list, UINT2NUM(offset));
14377 
14378  return ST_CONTINUE;
14379 }
14380 
14381 static void
14382 ibf_dump_object_list(struct ibf_dump *dump, ibf_offset_t *obj_list_offset, unsigned int *obj_list_size)
14383 {
14384  st_table *obj_table = dump->current_buffer->obj_table;
14385  VALUE offset_list = rb_ary_hidden_new(obj_table->num_entries);
14386 
14387  struct ibf_dump_object_list_arg args;
14388  args.dump = dump;
14389  args.offset_list = offset_list;
14390 
14391  st_foreach(obj_table, ibf_dump_object_list_i, (st_data_t)&args);
14392 
14393  IBF_W_ALIGN(ibf_offset_t);
14394  *obj_list_offset = ibf_dump_pos(dump);
14395 
14396  st_index_t size = obj_table->num_entries;
14397  st_index_t i;
14398 
14399  for (i=0; i<size; i++) {
14400  ibf_offset_t offset = NUM2UINT(RARRAY_AREF(offset_list, i));
14401  IBF_WV(offset);
14402  }
14403 
14404  *obj_list_size = (unsigned int)size;
14405 }
14406 
14407 static void
14408 ibf_dump_mark(void *ptr)
14409 {
14410  struct ibf_dump *dump = (struct ibf_dump *)ptr;
14411  rb_gc_mark(dump->global_buffer.str);
14412 
14413  rb_mark_set(dump->global_buffer.obj_table);
14414  rb_mark_set(dump->iseq_table);
14415 }
14416 
14417 static void
14418 ibf_dump_free(void *ptr)
14419 {
14420  struct ibf_dump *dump = (struct ibf_dump *)ptr;
14421  if (dump->global_buffer.obj_table) {
14422  st_free_table(dump->global_buffer.obj_table);
14423  dump->global_buffer.obj_table = 0;
14424  }
14425  if (dump->iseq_table) {
14426  st_free_table(dump->iseq_table);
14427  dump->iseq_table = 0;
14428  }
14429 }
14430 
14431 static size_t
14432 ibf_dump_memsize(const void *ptr)
14433 {
14434  struct ibf_dump *dump = (struct ibf_dump *)ptr;
14435  size_t size = 0;
14436  if (dump->iseq_table) size += st_memsize(dump->iseq_table);
14437  if (dump->global_buffer.obj_table) size += st_memsize(dump->global_buffer.obj_table);
14438  return size;
14439 }
14440 
14441 static const rb_data_type_t ibf_dump_type = {
14442  "ibf_dump",
14443  {ibf_dump_mark, ibf_dump_free, ibf_dump_memsize,},
14444  0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_EMBEDDABLE
14445 };
14446 
14447 static void
14448 ibf_dump_setup(struct ibf_dump *dump, VALUE dumper_obj)
14449 {
14450  dump->global_buffer.obj_table = NULL; // GC may run before a value is assigned
14451  dump->iseq_table = NULL;
14452 
14453  RB_OBJ_WRITE(dumper_obj, &dump->global_buffer.str, rb_str_new(0, 0));
14454  dump->global_buffer.obj_table = ibf_dump_object_table_new();
14455  dump->iseq_table = st_init_numtable(); /* need free */
14456 
14457  dump->current_buffer = &dump->global_buffer;
14458 }
14459 
14460 VALUE
14461 rb_iseq_ibf_dump(const rb_iseq_t *iseq, VALUE opt)
14462 {
14463  struct ibf_dump *dump;
14464  struct ibf_header header = {{0}};
14465  VALUE dump_obj;
14466  VALUE str;
14467 
14468  if (ISEQ_BODY(iseq)->parent_iseq != NULL ||
14469  ISEQ_BODY(iseq)->local_iseq != iseq) {
14470  rb_raise(rb_eRuntimeError, "should be top of iseq");
14471  }
14472  if (RTEST(ISEQ_COVERAGE(iseq))) {
14473  rb_raise(rb_eRuntimeError, "should not compile with coverage");
14474  }
14475 
14476  dump_obj = TypedData_Make_Struct(0, struct ibf_dump, &ibf_dump_type, dump);
14477  ibf_dump_setup(dump, dump_obj);
14478 
14479  ibf_dump_write(dump, &header, sizeof(header));
14480  ibf_dump_iseq(dump, iseq);
14481 
14482  header.magic[0] = 'Y'; /* YARB */
14483  header.magic[1] = 'A';
14484  header.magic[2] = 'R';
14485  header.magic[3] = 'B';
14486  header.major_version = IBF_MAJOR_VERSION;
14487  header.minor_version = IBF_MINOR_VERSION;
14488  header.endian = IBF_ENDIAN_MARK;
14489  header.wordsize = (uint8_t)SIZEOF_VALUE;
14490  ibf_dump_iseq_list(dump, &header);
14491  ibf_dump_object_list(dump, &header.global_object_list_offset, &header.global_object_list_size);
14492  header.size = ibf_dump_pos(dump);
14493 
14494  if (RTEST(opt)) {
14495  VALUE opt_str = opt;
14496  const char *ptr = StringValuePtr(opt_str);
14497  header.extra_size = RSTRING_LENINT(opt_str);
14498  ibf_dump_write(dump, ptr, header.extra_size);
14499  }
14500  else {
14501  header.extra_size = 0;
14502  }
14503 
14504  ibf_dump_overwrite(dump, &header, sizeof(header), 0);
14505 
14506  str = dump->global_buffer.str;
14507  RB_GC_GUARD(dump_obj);
14508  return str;
14509 }
14510 
14511 static const ibf_offset_t *
14512 ibf_iseq_list(const struct ibf_load *load)
14513 {
14514  return (const ibf_offset_t *)(load->global_buffer.buff + load->header->iseq_list_offset);
14515 }
14516 
14517 void
14518 rb_ibf_load_iseq_complete(rb_iseq_t *iseq)
14519 {
14520  struct ibf_load *load = RTYPEDDATA_DATA(iseq->aux.loader.obj);
14521  rb_iseq_t *prev_src_iseq = load->iseq;
14522  ibf_offset_t offset = ibf_iseq_list(load)[iseq->aux.loader.index];
14523  load->iseq = iseq;
14524 #if IBF_ISEQ_DEBUG
14525  fprintf(stderr, "rb_ibf_load_iseq_complete: index=%#x offset=%#x size=%#x\n",
14526  iseq->aux.loader.index, offset,
14527  load->header->size);
14528 #endif
14529  ibf_load_iseq_each(load, iseq, offset);
14530  ISEQ_COMPILE_DATA_CLEAR(iseq);
14531  FL_UNSET((VALUE)iseq, ISEQ_NOT_LOADED_YET);
14532  rb_iseq_init_trace(iseq);
14533  load->iseq = prev_src_iseq;
14534 }
14535 
14536 #if USE_LAZY_LOAD
14537 const rb_iseq_t *
14538 rb_iseq_complete(const rb_iseq_t *iseq)
14539 {
14540  rb_ibf_load_iseq_complete((rb_iseq_t *)iseq);
14541  return iseq;
14542 }
14543 #endif
14544 
14545 static rb_iseq_t *
14546 ibf_load_iseq(const struct ibf_load *load, const rb_iseq_t *index_iseq)
14547 {
14548  int iseq_index = (int)(VALUE)index_iseq;
14549 
14550 #if IBF_ISEQ_DEBUG
14551  fprintf(stderr, "ibf_load_iseq: index_iseq=%p iseq_list=%p\n",
14552  (void *)index_iseq, (void *)load->iseq_list);
14553 #endif
14554  if (iseq_index == -1) {
14555  return NULL;
14556  }
14557  else {
14558  VALUE iseqv = pinned_list_fetch(load->iseq_list, iseq_index);
14559 
14560 #if IBF_ISEQ_DEBUG
14561  fprintf(stderr, "ibf_load_iseq: iseqv=%p\n", (void *)iseqv);
14562 #endif
14563  if (iseqv) {
14564  return (rb_iseq_t *)iseqv;
14565  }
14566  else {
14567  rb_iseq_t *iseq = iseq_imemo_alloc();
14568 #if IBF_ISEQ_DEBUG
14569  fprintf(stderr, "ibf_load_iseq: new iseq=%p\n", (void *)iseq);
14570 #endif
14571  FL_SET((VALUE)iseq, ISEQ_NOT_LOADED_YET);
14572  iseq->aux.loader.obj = load->loader_obj;
14573  iseq->aux.loader.index = iseq_index;
14574 #if IBF_ISEQ_DEBUG
14575  fprintf(stderr, "ibf_load_iseq: iseq=%p loader_obj=%p index=%d\n",
14576  (void *)iseq, (void *)load->loader_obj, iseq_index);
14577 #endif
14578  pinned_list_store(load->iseq_list, iseq_index, (VALUE)iseq);
14579 
14580  if (!USE_LAZY_LOAD || GET_VM()->builtin_function_table) {
14581 #if IBF_ISEQ_DEBUG
14582  fprintf(stderr, "ibf_load_iseq: loading iseq=%p\n", (void *)iseq);
14583 #endif
14584  rb_ibf_load_iseq_complete(iseq);
14585  }
14586 
14587 #if IBF_ISEQ_DEBUG
14588  fprintf(stderr, "ibf_load_iseq: iseq=%p loaded %p\n",
14589  (void *)iseq, (void *)load->iseq);
14590 #endif
14591  return iseq;
14592  }
14593  }
14594 }
14595 
14596 static void
14597 ibf_load_setup_bytes(struct ibf_load *load, VALUE loader_obj, const char *bytes, size_t size)
14598 {
14599  struct ibf_header *header = (struct ibf_header *)bytes;
14600  load->loader_obj = loader_obj;
14601  load->global_buffer.buff = bytes;
14602  load->header = header;
14603  load->global_buffer.size = header->size;
14604  load->global_buffer.obj_list_offset = header->global_object_list_offset;
14605  load->global_buffer.obj_list_size = header->global_object_list_size;
14606  RB_OBJ_WRITE(loader_obj, &load->iseq_list, pinned_list_new(header->iseq_list_size));
14607  RB_OBJ_WRITE(loader_obj, &load->global_buffer.obj_list, pinned_list_new(load->global_buffer.obj_list_size));
14608  load->iseq = NULL;
14609 
14610  load->current_buffer = &load->global_buffer;
14611 
14612  if (size < header->size) {
14613  rb_raise(rb_eRuntimeError, "broken binary format");
14614  }
14615  if (strncmp(header->magic, "YARB", 4) != 0) {
14616  rb_raise(rb_eRuntimeError, "unknown binary format");
14617  }
14618  if (header->major_version != IBF_MAJOR_VERSION ||
14619  header->minor_version != IBF_MINOR_VERSION) {
14620  rb_raise(rb_eRuntimeError, "unmatched version file (%u.%u for %u.%u)",
14621  header->major_version, header->minor_version, IBF_MAJOR_VERSION, IBF_MINOR_VERSION);
14622  }
14623  if (header->endian != IBF_ENDIAN_MARK) {
14624  rb_raise(rb_eRuntimeError, "unmatched endian: %c", header->endian);
14625  }
14626  if (header->wordsize != SIZEOF_VALUE) {
14627  rb_raise(rb_eRuntimeError, "unmatched word size: %d", header->wordsize);
14628  }
14629  if (header->iseq_list_offset % RUBY_ALIGNOF(ibf_offset_t)) {
14630  rb_raise(rb_eArgError, "unaligned iseq list offset: %u",
14631  header->iseq_list_offset);
14632  }
14633  if (load->global_buffer.obj_list_offset % RUBY_ALIGNOF(ibf_offset_t)) {
14634  rb_raise(rb_eArgError, "unaligned object list offset: %u",
14635  load->global_buffer.obj_list_offset);
14636  }
14637 }
14638 
14639 static void
14640 ibf_load_setup(struct ibf_load *load, VALUE loader_obj, VALUE str)
14641 {
14642  StringValue(str);
14643 
14644  if (RSTRING_LENINT(str) < (int)sizeof(struct ibf_header)) {
14645  rb_raise(rb_eRuntimeError, "broken binary format");
14646  }
14647 
14648  if (USE_LAZY_LOAD) {
14649  str = rb_str_new(RSTRING_PTR(str), RSTRING_LEN(str));
14650  }
14651 
14652  ibf_load_setup_bytes(load, loader_obj, RSTRING_PTR(str), RSTRING_LEN(str));
14653  RB_OBJ_WRITE(loader_obj, &load->str, str);
14654 }
14655 
14656 static void
14657 ibf_loader_mark(void *ptr)
14658 {
14659  struct ibf_load *load = (struct ibf_load *)ptr;
14660  rb_gc_mark(load->str);
14661  rb_gc_mark(load->iseq_list);
14662  rb_gc_mark(load->global_buffer.obj_list);
14663 }
14664 
14665 static void
14666 ibf_loader_free(void *ptr)
14667 {
14668  struct ibf_load *load = (struct ibf_load *)ptr;
14669  ruby_xfree(load);
14670 }
14671 
14672 static size_t
14673 ibf_loader_memsize(const void *ptr)
14674 {
14675  return sizeof(struct ibf_load);
14676 }
14677 
14678 static const rb_data_type_t ibf_load_type = {
14679  "ibf_loader",
14680  {ibf_loader_mark, ibf_loader_free, ibf_loader_memsize,},
14681  0, 0, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY
14682 };
14683 
14684 const rb_iseq_t *
14685 rb_iseq_ibf_load(VALUE str)
14686 {
14687  struct ibf_load *load;
14688  rb_iseq_t *iseq;
14689  VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
14690 
14691  ibf_load_setup(load, loader_obj, str);
14692  iseq = ibf_load_iseq(load, 0);
14693 
14694  RB_GC_GUARD(loader_obj);
14695  return iseq;
14696 }
14697 
14698 const rb_iseq_t *
14699 rb_iseq_ibf_load_bytes(const char *bytes, size_t size)
14700 {
14701  struct ibf_load *load;
14702  rb_iseq_t *iseq;
14703  VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
14704 
14705  ibf_load_setup_bytes(load, loader_obj, bytes, size);
14706  iseq = ibf_load_iseq(load, 0);
14707 
14708  RB_GC_GUARD(loader_obj);
14709  return iseq;
14710 }
14711 
14712 VALUE
14713 rb_iseq_ibf_load_extra_data(VALUE str)
14714 {
14715  struct ibf_load *load;
14716  VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
14717  VALUE extra_str;
14718 
14719  ibf_load_setup(load, loader_obj, str);
14720  extra_str = rb_str_new(load->global_buffer.buff + load->header->size, load->header->extra_size);
14721  RB_GC_GUARD(loader_obj);
14722  return extra_str;
14723 }
14724 
14725 #include "prism_compile.c"
#define RUBY_ASSERT(...)
Asserts that the given expression is truthy if and only if RUBY_DEBUG is truthy.
Definition: assert.h:219
#define LONG_LONG
Definition: long_long.h:38
#define RUBY_ALIGNOF
Wraps (or simulates) alignof.
Definition: stdalign.h:28
#define RUBY_EVENT_END
Encountered an end of a class clause.
Definition: event.h:40
#define RUBY_EVENT_C_CALL
A method, written in C, is called.
Definition: event.h:43
#define RUBY_EVENT_B_RETURN
Encountered a next statement.
Definition: event.h:56
#define RUBY_EVENT_CLASS
Encountered a new class.
Definition: event.h:39
#define RUBY_EVENT_NONE
No events.
Definition: event.h:37
#define RUBY_EVENT_LINE
Encountered a new line.
Definition: event.h:38
#define RUBY_EVENT_RETURN
Encountered a return statement.
Definition: event.h:42
#define RUBY_EVENT_C_RETURN
Return from a method, written in C.
Definition: event.h:44
#define RUBY_EVENT_B_CALL
Encountered an yield statement.
Definition: event.h:55
uint32_t rb_event_flag_t
Represents event(s).
Definition: event.h:108
#define RUBY_EVENT_CALL
A method, written in Ruby, is called.
Definition: event.h:41
#define RUBY_EVENT_RESCUE
Encountered a rescue statement.
Definition: event.h:61
#define RBIMPL_ATTR_FORMAT(x, y, z)
Wraps (or simulates) __attribute__((format))
Definition: format.h:27
#define rb_str_new2
Old name of rb_str_new_cstr.
Definition: string.h:1675
#define T_COMPLEX
Old name of RUBY_T_COMPLEX.
Definition: value_type.h:59
#define TYPE(_)
Old name of rb_type.
Definition: value_type.h:108
#define NUM2ULONG
Old name of RB_NUM2ULONG.
Definition: long.h:52
#define NUM2LL
Old name of RB_NUM2LL.
Definition: long_long.h:34
#define REALLOC_N
Old name of RB_REALLOC_N.
Definition: memory.h:398
#define ALLOCV
Old name of RB_ALLOCV.
Definition: memory.h:399
#define RFLOAT_VALUE
Old name of rb_float_value.
Definition: double.h:28
#define T_STRING
Old name of RUBY_T_STRING.
Definition: value_type.h:78
#define xfree
Old name of ruby_xfree.
Definition: xmalloc.h:58
#define Qundef
Old name of RUBY_Qundef.
#define INT2FIX
Old name of RB_INT2FIX.
Definition: long.h:48
#define T_NIL
Old name of RUBY_T_NIL.
Definition: value_type.h:72
#define UNREACHABLE
Old name of RBIMPL_UNREACHABLE.
Definition: assume.h:28
#define T_FLOAT
Old name of RUBY_T_FLOAT.
Definition: value_type.h:64
#define ID2SYM
Old name of RB_ID2SYM.
Definition: symbol.h:44
#define T_BIGNUM
Old name of RUBY_T_BIGNUM.
Definition: value_type.h:57
#define SPECIAL_CONST_P
Old name of RB_SPECIAL_CONST_P.
#define OBJ_FREEZE
Old name of RB_OBJ_FREEZE.
Definition: fl_type.h:135
#define ULONG2NUM
Old name of RB_ULONG2NUM.
Definition: long.h:60
#define UNREACHABLE_RETURN
Old name of RBIMPL_UNREACHABLE_RETURN.
Definition: assume.h:29
#define SYM2ID
Old name of RB_SYM2ID.
Definition: symbol.h:45
#define FIX2UINT
Old name of RB_FIX2UINT.
Definition: int.h:42
#define ZALLOC
Old name of RB_ZALLOC.
Definition: memory.h:397
#define CLASS_OF
Old name of rb_class_of.
Definition: globals.h:203
#define FIXABLE
Old name of RB_FIXABLE.
Definition: fixnum.h:25
#define xmalloc
Old name of ruby_xmalloc.
Definition: xmalloc.h:53
#define LONG2FIX
Old name of RB_INT2FIX.
Definition: long.h:49
#define FIX2INT
Old name of RB_FIX2INT.
Definition: int.h:41
#define NUM2UINT
Old name of RB_NUM2UINT.
Definition: int.h:45
#define ZALLOC_N
Old name of RB_ZALLOC_N.
Definition: memory.h:396
#define ASSUME
Old name of RBIMPL_ASSUME.
Definition: assume.h:27
#define T_RATIONAL
Old name of RUBY_T_RATIONAL.
Definition: value_type.h:76
#define T_HASH
Old name of RUBY_T_HASH.
Definition: value_type.h:65
#define ALLOC_N
Old name of RB_ALLOC_N.
Definition: memory.h:394
#define FL_SET
Old name of RB_FL_SET.
Definition: fl_type.h:129
#define Qtrue
Old name of RUBY_Qtrue.
#define NUM2INT
Old name of RB_NUM2INT.
Definition: int.h:44
#define Qnil
Old name of RUBY_Qnil.
#define Qfalse
Old name of RUBY_Qfalse.
#define FIX2LONG
Old name of RB_FIX2LONG.
Definition: long.h:46
#define T_ARRAY
Old name of RUBY_T_ARRAY.
Definition: value_type.h:56
#define NIL_P
Old name of RB_NIL_P.
#define T_SYMBOL
Old name of RUBY_T_SYMBOL.
Definition: value_type.h:80
#define DBL2NUM
Old name of rb_float_new.
Definition: double.h:29
#define BUILTIN_TYPE
Old name of RB_BUILTIN_TYPE.
Definition: value_type.h:85
#define FL_TEST
Old name of RB_FL_TEST.
Definition: fl_type.h:131
#define FL_FREEZE
Old name of RUBY_FL_FREEZE.
Definition: fl_type.h:67
#define NUM2LONG
Old name of RB_NUM2LONG.
Definition: long.h:51
#define FL_UNSET
Old name of RB_FL_UNSET.
Definition: fl_type.h:133
#define UINT2NUM
Old name of RB_UINT2NUM.
Definition: int.h:46
#define FIXNUM_P
Old name of RB_FIXNUM_P.
#define CONST_ID
Old name of RUBY_CONST_ID.
Definition: symbol.h:47
#define ALLOCV_END
Old name of RB_ALLOCV_END.
Definition: memory.h:401
#define SYMBOL_P
Old name of RB_SYMBOL_P.
Definition: value_type.h:88
#define T_REGEXP
Old name of RUBY_T_REGEXP.
Definition: value_type.h:77
#define ruby_debug
This variable controls whether the interpreter is in debug mode.
Definition: error.h:486
void rb_raise(VALUE exc_class, const char *fmt,...)
Exception entry point.
Definition: error.c:3635
VALUE rb_eNotImpError
NotImplementedError exception.
Definition: error.c:1418
void rb_bug(const char *fmt,...)
Interpreter panic switch.
Definition: error.c:1089
VALUE rb_eStandardError
StandardError exception.
Definition: error.c:1405
void rb_set_errinfo(VALUE err)
Sets the current exception ($!) to the given value.
Definition: eval.c:1926
VALUE rb_eTypeError
TypeError exception.
Definition: error.c:1408
VALUE rb_eNoMatchingPatternError
NoMatchingPatternError exception.
Definition: error.c:1421
void rb_exc_fatal(VALUE mesg)
Raises a fatal error in the current thread.
Definition: eval.c:689
VALUE rb_eRuntimeError
RuntimeError exception.
Definition: error.c:1406
void rb_warn(const char *fmt,...)
Identical to rb_warning(), except it reports unless $VERBOSE is nil.
Definition: error.c:466
VALUE rb_eNoMatchingPatternKeyError
NoMatchingPatternKeyError exception.
Definition: error.c:1422
VALUE rb_eArgError
ArgumentError exception.
Definition: error.c:1409
VALUE rb_eIndexError
IndexError exception.
Definition: error.c:1410
VALUE rb_eSyntaxError
SyntaxError exception.
Definition: error.c:1425
@ RB_WARN_CATEGORY_STRICT_UNUSED_BLOCK
Warning is for checking unused block strictly.
Definition: error.h:57
VALUE rb_obj_reveal(VALUE obj, VALUE klass)
Make a hidden object visible again.
Definition: object.c:113
VALUE rb_cArray
Array class.
Definition: array.c:40
VALUE rb_obj_hide(VALUE obj)
Make the object invisible from Ruby code.
Definition: object.c:104
VALUE rb_cHash
Hash class.
Definition: hash.c:113
VALUE rb_inspect(VALUE obj)
Generates a human-readable textual representation of the given object.
Definition: object.c:680
VALUE rb_cRange
Range class.
Definition: range.c:31
VALUE rb_obj_is_kind_of(VALUE obj, VALUE klass)
Queries if the given object is an instance (of possibly descendants) of the given class.
Definition: object.c:865
VALUE rb_obj_freeze(VALUE obj)
Just calls rb_obj_freeze_inline() inside.
Definition: object.c:1260
#define RB_OBJ_WRITTEN(old, oldv, young)
Identical to RB_OBJ_WRITE(), except it doesn't write any values, but only a WB declaration.
Definition: gc.h:615
#define RB_OBJ_WRITE(old, slot, young)
Declaration of a "back" pointer.
Definition: gc.h:603
int rb_enc_get_index(VALUE obj)
Queries the index of the encoding of the passed object, if any.
Definition: encoding.c:920
rb_encoding * rb_enc_find(const char *name)
Identical to rb_find_encoding(), except it takes a C's string instead of Ruby's.
Definition: encoding.c:859
rb_encoding * rb_to_encoding(VALUE obj)
Identical to rb_find_encoding(), except it raises an exception instead of returning NULL.
Definition: encoding.c:323
VALUE rb_enc_from_encoding(rb_encoding *enc)
Queries the Ruby-level counterpart instance of rb_cEncoding that corresponds to the passed encoding.
Definition: encoding.c:182
rb_encoding * rb_enc_from_index(int idx)
Identical to rb_find_encoding(), except it takes an encoding index instead of a Ruby object.
Definition: encoding.c:402
static const char * rb_enc_name(rb_encoding *enc)
Queries the (canonical) name of the passed encoding.
Definition: encoding.h:417
int rb_enc_find_index(const char *name)
Queries the index of the encoding.
Definition: encoding.c:824
VALUE rb_enc_str_new(const char *ptr, long len, rb_encoding *enc)
Identical to rb_str_new(), except it additionally takes an encoding.
Definition: string.c:1068
ID rb_intern3(const char *name, long len, rb_encoding *enc)
Identical to rb_intern2(), except it additionally takes an encoding.
Definition: symbol.c:752
void rb_gc_mark(VALUE obj)
Marks an object.
Definition: gc.c:2211
void rb_memerror(void)
Triggers out-of-memory error.
Definition: gc.c:4426
void rb_mark_set(struct st_table *tbl)
Identical to rb_mark_hash(), except it marks only keys of the table and leave their associated values...
Definition: gc.c:2307
VALUE rb_ary_reverse(VALUE ary)
Destructively reverses the passed array in-place.
Definition: array.c:3113
VALUE rb_ary_dup(VALUE ary)
Duplicates an array.
Definition: array.c:2771
VALUE rb_ary_unshift(VALUE ary, VALUE elem)
Destructively prepends the passed item at the beginning of the passed array.
Definition: array.c:1713
VALUE rb_ary_cat(VALUE ary, const VALUE *train, long len)
Destructively appends multiple elements at the end of the array.
Definition: array.c:1391
VALUE rb_ary_new(void)
Allocates a new, empty array.
Definition: array.c:741
VALUE rb_ary_new_capa(long capa)
Identical to rb_ary_new(), except it additionally specifies how many rooms of objects it should alloc...
Definition: array.c:735
VALUE rb_ary_hidden_new(long capa)
Allocates a hidden (no class) empty array.
Definition: array.c:853
VALUE rb_ary_clear(VALUE ary)
Destructively removes everything form an array.
Definition: array.c:4729
VALUE rb_ary_push(VALUE ary, VALUE elem)
Special case of rb_ary_cat() that it adds only one element.
Definition: array.c:1378
VALUE rb_ary_freeze(VALUE obj)
Freeze an array, preventing further modifications.
Definition: array.c:642
VALUE rb_ary_new_from_args(long n,...)
Constructs an array from the passed objects.
Definition: array.c:747
VALUE rb_ary_entry(VALUE ary, long off)
Queries an element of an array.
Definition: array.c:1731
VALUE rb_ary_join(VALUE ary, VALUE sep)
Recursively stringises the elements of the passed array, flattens that result, then joins the sequenc...
Definition: array.c:2885
void rb_ary_store(VALUE ary, long key, VALUE val)
Destructively stores the passed value to the passed array's passed index.
Definition: array.c:1201
#define INTEGER_PACK_NATIVE_BYTE_ORDER
Means either INTEGER_PACK_MSBYTE_FIRST or INTEGER_PACK_LSBYTE_FIRST, depending on the host processor'...
Definition: bignum.h:546
VALUE rb_integer_unpack(const void *words, size_t numwords, size_t wordsize, size_t nails, int flags)
Import an integer from a buffer.
Definition: bignum.c:3674
VALUE rb_big_cmp(VALUE lhs, VALUE rhs)
Compares the passed two bignums.
Definition: bignum.c:5449
VALUE rb_dbl2big(double d)
Converts a C's double into a bignum.
Definition: bignum.c:5285
#define INTEGER_PACK_NEGATIVE
Interprets the input as a signed negative number (unpack only).
Definition: bignum.h:564
#define INTEGER_PACK_LSWORD_FIRST
Stores/interprets the least significant word as the first word.
Definition: bignum.h:528
VALUE rb_complex_new(VALUE real, VALUE imag)
Constructs a Complex, by first multiplying the imaginary part with 1i then adds it to the real part.
Definition: complex.c:1755
void rb_hash_bulk_insert(long argc, const VALUE *argv, VALUE hash)
Inserts a list of key-value pairs into a hash table at once.
Definition: hash.c:4766
void rb_hash_foreach(VALUE hash, int(*func)(VALUE key, VALUE val, VALUE arg), VALUE arg)
Iterates over a hash.
VALUE rb_hash_freeze(VALUE obj)
Just another name of rb_obj_freeze.
Definition: hash.c:108
VALUE rb_hash_aref(VALUE hash, VALUE key)
Queries the given key in the given hash table.
Definition: hash.c:2073
VALUE rb_hash_aset(VALUE hash, VALUE key, VALUE val)
Inserts or replaces ("upsert"s) the objects into the given hash table.
Definition: hash.c:2893
VALUE rb_hash_lookup(VALUE hash, VALUE key)
Identical to rb_hash_aref(), except it always returns RUBY_Qnil for misshits.
Definition: hash.c:2099
VALUE rb_hash_dup(VALUE hash)
Duplicates a hash.
Definition: hash.c:1563
VALUE rb_hash_clear(VALUE hash)
Swipes everything out of the passed hash table.
Definition: hash.c:2820
VALUE rb_hash_new(void)
Creates a new, empty hash object.
Definition: hash.c:1475
int rb_is_const_id(ID id)
Classifies the given ID, then sees if it is a constant.
Definition: symbol.c:1063
ID rb_id_attrset(ID id)
Calculates an ID of attribute writer.
Definition: symbol.c:121
int rb_is_attrset_id(ID id)
Classifies the given ID, then sees if it is an attribute writer.
Definition: symbol.c:1087
int rb_range_values(VALUE range, VALUE *begp, VALUE *endp, int *exclp)
Deconstructs a range into its components.
Definition: range.c:1754
VALUE rb_range_new(VALUE beg, VALUE end, int excl)
Creates a new Range.
Definition: range.c:68
VALUE rb_rational_new(VALUE num, VALUE den)
Constructs a Rational, with reduction.
Definition: rational.c:1974
int rb_reg_options(VALUE re)
Queries the options of the passed regular expression.
Definition: re.c:4198
VALUE rb_str_append(VALUE dst, VALUE src)
Identical to rb_str_buf_append(), except it converts the right hand side before concatenating.
Definition: string.c:3675
VALUE rb_str_tmp_new(long len)
Allocates a "temporary" string.
Definition: string.c:1671
int rb_str_hash_cmp(VALUE str1, VALUE str2)
Compares two strings.
Definition: string.c:4044
VALUE rb_str_cat2(VALUE, const char *)
Just another name of rb_str_cat_cstr.
st_index_t rb_str_hash(VALUE str)
Calculates a hash value of a string.
Definition: string.c:4030
VALUE rb_str_cat(VALUE dst, const char *src, long srclen)
Destructively appends the passed contents to the string.
Definition: string.c:3443
int rb_str_cmp(VALUE lhs, VALUE rhs)
Compares two strings, as in strcmp(3).
Definition: string.c:4100
VALUE rb_str_concat(VALUE dst, VALUE src)
Identical to rb_str_append(), except it also accepts an integer as a codepoint.
Definition: string.c:3917
VALUE rb_str_freeze(VALUE str)
This is the implementation of String#freeze.
Definition: string.c:3176
VALUE rb_str_new(const char *ptr, long len)
Allocates an instance of rb_cString.
Definition: string.c:1050
VALUE rb_str_new_cstr(const char *ptr)
Identical to rb_str_new(), except it assumes the passed pointer is a pointer to a C string.
Definition: string.c:1074
VALUE rb_class_name(VALUE obj)
Queries the name of the given object's class.
Definition: variable.c:412
static ID rb_intern_const(const char *str)
This is a "tiny optimisation" over rb_intern().
Definition: symbol.h:277
VALUE rb_id2sym(ID id)
Allocates an instance of rb_cSymbol that has the given id.
Definition: symbol.c:951
const char * rb_id2name(ID id)
Retrieves the name mapped to the given id.
Definition: symbol.c:992
ID rb_intern(const char *name)
Finds or creates a symbol of the given name.
Definition: symbol.c:823
VALUE rb_sym2str(VALUE symbol)
Obtain a frozen string representation of a symbol (not including the leading colon).
Definition: symbol.c:970
ID rb_sym2id(VALUE obj)
Converts an instance of rb_cSymbol into an ID.
Definition: symbol.c:917
ID rb_intern_str(VALUE str)
Identical to rb_intern(), except it takes an instance of rb_cString.
Definition: symbol.c:829
VALUE rb_id2str(ID id)
Identical to rb_id2name(), except it returns a frozen Ruby String instead of a C String.
Definition: symbol.c:986
RBIMPL_ATTR_NORETURN() void rb_eof_error(void)
Utility function to raise rb_eEOFError.
char * ptr
Pointer to the underlying memory region, of at least capa bytes.
Definition: io.h:2
int len
Length of the buffer.
Definition: io.h:8
VALUE rb_ractor_make_shareable(VALUE obj)
Destructively transforms the passed object so that multiple Ractors can share it.
Definition: ractor.c:3078
#define DECIMAL_SIZE_OF(expr)
An approximation of decimal representation size.
Definition: util.h:48
void ruby_qsort(void *, const size_t, const size_t, int(*)(const void *, const void *, void *), void *)
Reentrant implementation of quick sort.
VALUE rb_sprintf(const char *fmt,...)
Ruby's extended sprintf(3).
Definition: sprintf.c:1217
VALUE rb_str_catf(VALUE dst, const char *fmt,...)
Identical to rb_sprintf(), except it renders the output to the specified object rather than creating ...
Definition: sprintf.c:1240
#define rb_long2int
Just another name of rb_long2int_inline.
Definition: long.h:62
#define MEMCPY(p1, p2, type, n)
Handy macro to call memcpy.
Definition: memory.h:367
#define ALLOCA_N(type, n)
Definition: memory.h:287
#define MEMZERO(p, type, n)
Handy macro to erase a region of memory.
Definition: memory.h:355
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
Definition: memory.h:162
#define RB_ALLOCV(v, n)
Identical to RB_ALLOCV_N(), except that it allocates a number of bytes and returns a void* .
Definition: memory.h:299
VALUE type(ANYARGS)
ANYARGS-ed function type.
Definition: cxxanyargs.hpp:56
int st_foreach(st_table *q, int_type *w, st_data_t e)
Iteration over the given table.
Definition: cxxanyargs.hpp:432
#define RARRAY_LEN
Just another name of rb_array_len.
Definition: rarray.h:51
static int RARRAY_LENINT(VALUE ary)
Identical to rb_array_len(), except it differs for the return type.
Definition: rarray.h:281
static void RARRAY_ASET(VALUE ary, long i, VALUE v)
Assigns an object in an array.
Definition: rarray.h:386
#define RARRAY_AREF(a, i)
Definition: rarray.h:403
#define RARRAY_CONST_PTR
Just another name of rb_array_const_ptr.
Definition: rarray.h:52
static VALUE RBASIC_CLASS(VALUE obj)
Queries the class of an object.
Definition: rbasic.h:150
#define RUBY_DEFAULT_FREE
This is a value you can set to RData::dfree.
Definition: rdata.h:78
void(* RUBY_DATA_FUNC)(void *)
This is the type of callbacks registered to RData.
Definition: rdata.h:104
#define RHASH_SIZE(h)
Queries the size of the hash.
Definition: rhash.h:69
static VALUE RREGEXP_SRC(VALUE rexp)
Convenient getter function.
Definition: rregexp.h:103
#define StringValue(v)
Ensures that the parameter object is a String.
Definition: rstring.h:66
#define StringValuePtr(v)
Identical to StringValue, except it returns a char*.
Definition: rstring.h:76
static char * RSTRING_PTR(VALUE str)
Queries the contents pointer of the string.
Definition: rstring.h:416
static int RSTRING_LENINT(VALUE str)
Identical to RSTRING_LEN(), except it differs for the return type.
Definition: rstring.h:468
static long RSTRING_LEN(VALUE str)
Queries the length of the string.
Definition: rstring.h:367
#define StringValueCStr(v)
Identical to StringValuePtr, except it additionally checks for the contents for viability as a C stri...
Definition: rstring.h:89
#define RTYPEDDATA_DATA(v)
Convenient getter macro.
Definition: rtypeddata.h:102
VALUE rb_data_typed_object_zalloc(VALUE klass, size_t size, const rb_data_type_t *type)
Identical to rb_data_typed_object_wrap(), except it allocates a new data region internally instead of...
Definition: gc.c:1068
#define TypedData_Get_Struct(obj, type, data_type, sval)
Obtains a C struct from inside of a wrapper Ruby object.
Definition: rtypeddata.h:515
#define TypedData_Wrap_Struct(klass, data_type, sval)
Converts sval, a pointer to your struct, into a Ruby object.
Definition: rtypeddata.h:449
#define TypedData_Make_Struct(klass, type, data_type, sval)
Identical to TypedData_Wrap_Struct, except it allocates a new data region internally instead of takin...
Definition: rtypeddata.h:497
void rb_p(VALUE obj)
Inspects an object.
Definition: io.c:9000
#define RTEST
This is an old name of RB_TEST.
#define _(args)
This was a transition path from K&R to ANSI.
Definition: stdarg.h:35
Definition: proc.c:29
Internal header for Complex.
Definition: complex.h:13
Internal header for Rational.
Definition: rational.h:16
Definition: iseq.h:269
const ID * segments
A null-terminated list of ids, used to represent a constant's path idNULL is used to represent the ::...
Definition: vm_core.h:285
Definition: vm_core.h:288
Definition: iseq.h:240
This is the struct that holds necessary info for a struct.
Definition: rtypeddata.h:200
const char * wrap_struct_name
Name of structs of this kind.
Definition: rtypeddata.h:207
struct rb_iseq_constant_body::@154 param
parameter information
Definition: st.h:79
Definition: vm_core.h:297
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
Definition: value.h:52
#define SIZEOF_VALUE
Identical to sizeof(VALUE), except it is a macro that can also be used inside of preprocessor directi...
Definition: value.h:69
uintptr_t VALUE
Type that represents a Ruby object.
Definition: value.h:40
static bool RB_FLOAT_TYPE_P(VALUE obj)
Queries if the object is an instance of rb_cFloat.
Definition: value_type.h:264
static bool rb_integer_type_p(VALUE obj)
Queries if the object is an instance of rb_cInteger.
Definition: value_type.h:204
static bool RB_TYPE_P(VALUE obj, enum ruby_value_type t)
Queries if the given object is of given type.
Definition: value_type.h:376
@ RUBY_T_MASK
Bitmask of ruby_value_type.
Definition: value_type.h:145
void * ruby_xmalloc2(size_t nelems, size_t elemsiz)
Identical to ruby_xmalloc(), except it allocates nelems * elemsiz bytes.
Definition: gc.c:4498
void * ruby_xmalloc(size_t size)
Allocates a storage instance.
Definition: gc.c:4472
void ruby_xfree(void *ptr)
Deallocates a storage instance.
Definition: gc.c:4594