diff options
author | Koichi Sasada <[email protected]> | 2020-01-08 08:20:36 +0900 |
---|---|---|
committer | Koichi Sasada <[email protected]> | 2020-02-22 09:58:59 +0900 |
commit | f2286925f08406bc857f7b03ad6779a5d61443ae (patch) | |
tree | 62d056c0a8c253f17fccd4a506ddb6cbf1f7bed5 /compile.c | |
parent | a1eb1fabef1bca0696449cd358d93f5a644d5914 (diff) |
VALUE size packed callinfo (ci).
Now, rb_call_info contains how to call the method with tuple of
(mid, orig_argc, flags, kwarg). Most of cases, kwarg == NULL and
mid+argc+flags only requires 64bits. So this patch packed
rb_call_info to VALUE (1 word) on such cases. If we can not
represent it in VALUE, then use imemo_callinfo which contains
conventional callinfo (rb_callinfo, renamed from rb_call_info).
iseq->body->ci_kw_size is removed because all of callinfo is VALUE
size (packed ci or a pointer to imemo_callinfo).
To access ci information, we need to use these functions:
vm_ci_mid(ci), _flag(ci), _argc(ci), _kwarg(ci).
struct rb_call_info_kw_arg is renamed to rb_callinfo_kwarg.
rb_funcallv_with_cc() and rb_method_basic_definition_p_with_cc()
is temporary removed because cd->ci should be marked.
Notes
Notes:
Merged: https://github.com/ruby/ruby/pull/2888
Diffstat (limited to 'compile.c')
-rw-r--r-- | compile.c | 342 |
1 files changed, 165 insertions, 177 deletions
@@ -36,6 +36,7 @@ #include "ruby/re.h" #include "ruby/util.h" #include "vm_core.h" +#include "vm_callinfo.h" #include "vm_debug.h" #include "builtin.h" @@ -919,6 +920,15 @@ compile_data_alloc2(rb_iseq_t *iseq, size_t x, size_t y) return compile_data_alloc(iseq, size); } +static inline void * +compile_data_calloc2(rb_iseq_t *iseq, size_t x, size_t y) +{ + size_t size = rb_size_mul_or_raise(x, y, rb_eRuntimeError); + void *p = compile_data_alloc(iseq, size); + memset(p, 0, size); + return p; +} + static INSN * compile_data_alloc_insn(rb_iseq_t *iseq) { @@ -1187,38 +1197,31 @@ new_insn_body(rb_iseq_t *iseq, int line_no, enum ruby_vminsn_type insn_id, int a return new_insn_core(iseq, line_no, insn_id, argc, operands); } -static struct rb_call_info * -new_callinfo(rb_iseq_t *iseq, ID mid, int argc, unsigned int flag, struct rb_call_info_kw_arg *kw_arg, int has_blockiseq) +static const struct rb_callinfo * +new_callinfo(rb_iseq_t *iseq, ID mid, int argc, unsigned int flag, struct rb_callinfo_kwarg *kw_arg, int has_blockiseq) { - size_t size = kw_arg != NULL ? sizeof(struct rb_call_info_with_kwarg) : sizeof(struct rb_call_info); - struct rb_call_info *ci = (struct rb_call_info *)compile_data_alloc(iseq, size); - struct rb_call_info_with_kwarg *ci_kw = (struct rb_call_info_with_kwarg *)ci; + VM_ASSERT(argc >= 0); - ci->mid = mid; - ci->flag = flag; - ci->orig_argc = argc; + if (!(flag & (VM_CALL_ARGS_SPLAT | VM_CALL_ARGS_BLOCKARG | VM_CALL_KW_SPLAT)) && + kw_arg == NULL && !has_blockiseq) { + flag |= VM_CALL_ARGS_SIMPLE; + } if (kw_arg) { - ci->flag |= VM_CALL_KWARG; - ci_kw->kw_arg = kw_arg; - ci->orig_argc += kw_arg->keyword_len; - iseq->body->ci_kw_size++; - } - else { - iseq->body->ci_size++; + flag |= VM_CALL_KWARG; + argc += kw_arg->keyword_len; } - if (!(ci->flag & (VM_CALL_ARGS_SPLAT | VM_CALL_ARGS_BLOCKARG | VM_CALL_KW_SPLAT)) && - kw_arg == NULL && !has_blockiseq) { - ci->flag |= VM_CALL_ARGS_SIMPLE; - } + iseq->body->ci_size++; + const struct rb_callinfo *ci = vm_ci_new(mid, flag, argc, kw_arg); + RB_OBJ_WRITTEN(iseq, Qundef, ci); return ci; } static INSN * -new_insn_send(rb_iseq_t *iseq, int line_no, ID id, VALUE argc, const rb_iseq_t *blockiseq, VALUE flag, struct rb_call_info_kw_arg *keywords) +new_insn_send(rb_iseq_t *iseq, int line_no, ID id, VALUE argc, const rb_iseq_t *blockiseq, VALUE flag, struct rb_callinfo_kwarg *keywords) { - VALUE *operands = compile_data_alloc2(iseq, sizeof(VALUE), 2); + VALUE *operands = compile_data_calloc2(iseq, sizeof(VALUE), 2); operands[0] = (VALUE)new_callinfo(iseq, id, FIX2INT(argc), FIX2INT(flag), keywords, blockiseq != NULL); operands[1] = (VALUE)blockiseq; return new_insn_core(iseq, line_no, BIN(send), 2, operands); @@ -2129,11 +2132,8 @@ iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor) insns_info = ALLOC_N(struct iseq_insn_info_entry, insn_num); positions = ALLOC_N(unsigned int, insn_num); body->is_entries = ZALLOC_N(union iseq_inline_storage_entry, body->is_size); - body->call_data = - rb_xcalloc_mul_add_mul( - sizeof(struct rb_call_data), body->ci_size, - sizeof(struct rb_kwarg_call_data), body->ci_kw_size); - ISEQ_COMPILE_DATA(iseq)->ci_index = ISEQ_COMPILE_DATA(iseq)->ci_kw_index = 0; + body->call_data = ZALLOC_N(struct rb_call_data, body->ci_size); + ISEQ_COMPILE_DATA(iseq)->ci_index = 0; list = FIRST_ELEMENT(anchor); insns_info_index = code_index = sp = 0; @@ -2201,7 +2201,7 @@ iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor) } case TS_ISE: /* inline storage entry */ /* Treated as an IC, but may contain a markable VALUE */ - FL_SET(iseq, ISEQ_MARKABLE_ISEQ); + FL_SET(iseq, ISEQ_MARKABLE_ISEQ); /* fall through */ case TS_IC: /* inline cache */ case TS_IVC: /* inline ivar cache */ @@ -2219,22 +2219,10 @@ iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor) } case TS_CALLDATA: { - struct rb_call_info *source_ci = (struct rb_call_info *)operands[j]; - struct rb_call_data *cd; - - if (source_ci->flag & VM_CALL_KWARG) { - struct rb_kwarg_call_data *kw_calls = (struct rb_kwarg_call_data *)&body->call_data[body->ci_size]; - struct rb_kwarg_call_data *cd_kw = &kw_calls[ISEQ_COMPILE_DATA(iseq)->ci_kw_index++]; - cd_kw->ci_kw = *((struct rb_call_info_with_kwarg *)source_ci); - cd = (struct rb_call_data *)cd_kw; - assert(ISEQ_COMPILE_DATA(iseq)->ci_kw_index <= body->ci_kw_size); - } - else { - cd = &body->call_data[ISEQ_COMPILE_DATA(iseq)->ci_index++]; - cd->ci = *source_ci; - assert(ISEQ_COMPILE_DATA(iseq)->ci_index <= body->ci_size); - } - + const struct rb_callinfo *source_ci = (const struct rb_callinfo *)operands[j]; + struct rb_call_data *cd = &body->call_data[ISEQ_COMPILE_DATA(iseq)->ci_index++]; + assert(ISEQ_COMPILE_DATA(iseq)->ci_index <= body->ci_size); + cd->ci = source_ci; generated_iseq[code_index + 1 + j] = (VALUE)cd; break; } @@ -2565,10 +2553,7 @@ remove_unreachable_chunk(rb_iseq_t *iseq, LINK_ELEMENT *i) unref_destination((INSN *)i, pos); break; case TS_CALLDATA: - if (((struct rb_call_info *)OPERAND_AT(i, pos))->flag & VM_CALL_KWARG) - --(body->ci_kw_size); - else - --(body->ci_size); + --(body->ci_size); break; } } @@ -2709,6 +2694,28 @@ optimize_checktype(rb_iseq_t *iseq, INSN *iobj) return TRUE; } +static const struct rb_callinfo * +ci_flag_set(const rb_iseq_t *iseq, const struct rb_callinfo *ci, unsigned int add) +{ + const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci), + vm_ci_flag(ci) | add, + vm_ci_argc(ci), + vm_ci_kwarg(ci)); + RB_OBJ_WRITTEN(iseq, ci, nci); + return nci; +} + +static const struct rb_callinfo * +ci_argc_set(const rb_iseq_t *iseq, const struct rb_callinfo *ci, int argc) +{ + const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci), + vm_ci_flag(ci), + argc, + vm_ci_kwarg(ci)); + RB_OBJ_WRITTEN(iseq, ci, nci); + return nci; +} + static int iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcallopt) { @@ -3150,16 +3157,17 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal NIL_P(OPERAND_AT(iobj, 0)) && IS_NEXT_INSN_ID(&iobj->link, send)) { INSN *niobj = (INSN *)iobj->link.next; - struct rb_call_info *ci = (struct rb_call_info *)OPERAND_AT(niobj, 0); - /* + const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(niobj, 0); + + /* * freezestring nil # no debug_info * send <:+@, 0, ARG_SIMPLE> # :-@, too * => * send <:+@, 0, ARG_SIMPLE> # :-@, too */ - if ((ci->mid == idUPlus || ci->mid == idUMinus) && - (ci->flag & VM_CALL_ARGS_SIMPLE) && - ci->orig_argc == 0) { + if ((vm_ci_mid(ci) == idUPlus || vm_ci_mid(ci) == idUMinus) && + (vm_ci_flag(ci) & VM_CALL_ARGS_SIMPLE) && + vm_ci_argc(ci) == 0) { ELEM_REMOVE(list); return COMPILE_OK; } @@ -3207,14 +3215,19 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal } if (piobj) { - struct rb_call_info *ci = (struct rb_call_info *)OPERAND_AT(piobj, 0); - if (IS_INSN_ID(piobj, send) || IS_INSN_ID(piobj, invokesuper)) { + const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(piobj, 0); + if (IS_INSN_ID(piobj, send) || + IS_INSN_ID(piobj, invokesuper)) { if (OPERAND_AT(piobj, 1) == 0) { /* no blockiseq */ - ci->flag |= VM_CALL_TAILCALL; + ci = ci_flag_set(iseq, ci, VM_CALL_TAILCALL); + OPERAND_AT(piobj, 0) = (VALUE)ci; + RB_OBJ_WRITTEN(iseq, Qundef, ci); } } else { - ci->flag |= VM_CALL_TAILCALL; + ci = ci_flag_set(iseq, ci, VM_CALL_TAILCALL); + OPERAND_AT(piobj, 0) = (VALUE)ci; + RB_OBJ_WRITTEN(iseq, Qundef, ci); } } } @@ -3277,7 +3290,7 @@ insn_set_specialized_instruction(rb_iseq_t *iseq, INSN *iobj, int insn_id) if (insn_id == BIN(opt_neq)) { VALUE *old_operands = iobj->operands; iobj->operand_size = 2; - iobj->operands = compile_data_alloc2(iseq, iobj->operand_size, sizeof(VALUE)); + iobj->operands = compile_data_calloc2(iseq, iobj->operand_size, sizeof(VALUE)); iobj->operands[0] = (VALUE)new_callinfo(iseq, idEq, 1, 0, NULL, FALSE); iobj->operands[1] = old_operands[0]; } @@ -3295,9 +3308,9 @@ iseq_specialized_instruction(rb_iseq_t *iseq, INSN *iobj) */ INSN *niobj = (INSN *)iobj->link.next; if (IS_INSN_ID(niobj, send)) { - struct rb_call_info *ci = (struct rb_call_info *)OPERAND_AT(niobj, 0); - if ((ci->flag & VM_CALL_ARGS_SIMPLE) && ci->orig_argc == 0) { - switch (ci->mid) { + const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(niobj, 0); + if ((vm_ci_flag(ci) & VM_CALL_ARGS_SIMPLE) && vm_ci_argc(ci) == 0) { + switch (vm_ci_mid(ci)) { case idMax: iobj->insn_id = BIN(opt_newarray_max); ELEM_REMOVE(&niobj->link); @@ -3312,14 +3325,14 @@ iseq_specialized_instruction(rb_iseq_t *iseq, INSN *iobj) } if (IS_INSN_ID(iobj, send)) { - struct rb_call_info *ci = (struct rb_call_info *)OPERAND_AT(iobj, 0); + const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, 0); const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(iobj, 1); #define SP_INSN(opt) insn_set_specialized_instruction(iseq, iobj, BIN(opt_##opt)) - if (ci->flag & VM_CALL_ARGS_SIMPLE) { - switch (ci->orig_argc) { + if (vm_ci_flag(ci) & VM_CALL_ARGS_SIMPLE) { + switch (vm_ci_argc(ci)) { case 0: - switch (ci->mid) { + switch (vm_ci_mid(ci)) { case idLength: SP_INSN(length); return COMPILE_OK; case idSize: SP_INSN(size); return COMPILE_OK; case idEmptyP: SP_INSN(empty_p);return COMPILE_OK; @@ -3329,7 +3342,7 @@ iseq_specialized_instruction(rb_iseq_t *iseq, INSN *iobj) } break; case 1: - switch (ci->mid) { + switch (vm_ci_mid(ci)) { case idPLUS: SP_INSN(plus); return COMPILE_OK; case idMINUS: SP_INSN(minus); return COMPILE_OK; case idMULT: SP_INSN(mult); return COMPILE_OK; @@ -3349,14 +3362,14 @@ iseq_specialized_instruction(rb_iseq_t *iseq, INSN *iobj) } break; case 2: - switch (ci->mid) { + switch (vm_ci_mid(ci)) { case idASET: SP_INSN(aset); return COMPILE_OK; } break; } } - if ((ci->flag & VM_CALL_ARGS_BLOCKARG) == 0 && blockiseq == NULL) { + if ((vm_ci_flag(ci) & VM_CALL_ARGS_BLOCKARG) == 0 && blockiseq == NULL) { iobj->insn_id = BIN(opt_send_without_block); iobj->operand_size = insn_len(iobj->insn_id) - 1; } @@ -3444,8 +3457,7 @@ new_unified_insn(rb_iseq_t *iseq, } if (argc > 0) { - ptr = operands = - compile_data_alloc2(iseq, sizeof(VALUE), argc); + ptr = operands = compile_data_alloc2(iseq, sizeof(VALUE), argc); } /* copy operands */ @@ -3870,7 +3882,7 @@ keyword_node_p(const NODE *const node) static int compile_keyword_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const root_node, - struct rb_call_info_kw_arg **const kw_arg_ptr, + struct rb_callinfo_kwarg **const kw_arg_ptr, unsigned int *flag) { if (kw_arg_ptr == NULL) return FALSE; @@ -3901,8 +3913,8 @@ compile_keyword_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, node = root_node->nd_head; { int len = (int)node->nd_alen / 2; - struct rb_call_info_kw_arg *kw_arg = - rb_xmalloc_mul_add(len - 1, sizeof(VALUE), sizeof(struct rb_call_info_kw_arg)); + struct rb_callinfo_kwarg *kw_arg = + rb_xmalloc_mul_add(len - 1, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg)); VALUE *keywords = kw_arg->keywords; int i = 0; kw_arg->keyword_len = len; @@ -3924,7 +3936,7 @@ compile_keyword_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, static int compile_args(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, - struct rb_call_info_kw_arg **keywords_ptr, unsigned int *flag) + struct rb_callinfo_kwarg **keywords_ptr, unsigned int *flag) { int len = 0; @@ -4407,21 +4419,26 @@ compile_massign_lhs(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const n switch (nd_type(node)) { case NODE_ATTRASGN: { INSN *iobj; - struct rb_call_info *ci; VALUE dupidx; int line = nd_line(node); CHECK(COMPILE_POPPED(ret, "masgn lhs (NODE_ATTRASGN)", node)); iobj = (INSN *)get_prev_insn((INSN *)LAST_ELEMENT(ret)); /* send insn */ - ci = (struct rb_call_info *)OPERAND_AT(iobj, 0); - ci->orig_argc += 1; - dupidx = INT2FIX(ci->orig_argc); + const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, 0); + int argc = vm_ci_argc(ci) + 1; + ci = ci_argc_set(iseq, ci, argc); + OPERAND_AT(iobj, 0) = (VALUE)ci; + RB_OBJ_WRITTEN(iseq, Qundef, ci); + dupidx = INT2FIX(argc); INSERT_BEFORE_INSN1(iobj, line, topn, dupidx); - if (ci->flag & VM_CALL_ARGS_SPLAT) { - --ci->orig_argc; - INSERT_BEFORE_INSN1(iobj, line, newarray, INT2FIX(1)); + if (vm_ci_flag(ci) & VM_CALL_ARGS_SPLAT) { + int argc = vm_ci_argc(ci); + ci = ci_argc_set(iseq, ci, argc - 1); + OPERAND_AT(iobj, 0) = (VALUE)ci; + RB_OBJ_WRITTEN(iseq, Qundef, iobj); + INSERT_BEFORE_INSN1(iobj, line, newarray, INT2FIX(1)); INSERT_BEFORE_INSN(iobj, line, concatarray); } ADD_INSN(ret, line, pop); /* result */ @@ -5017,7 +5034,7 @@ check_keyword(const NODE *node) static VALUE setup_args_core(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn, - int dup_rest, unsigned int *flag, struct rb_call_info_kw_arg **keywords) + int dup_rest, unsigned int *flag, struct rb_callinfo_kwarg **keywords) { if (argn) { switch (nd_type(argn)) { @@ -5077,7 +5094,7 @@ setup_args_core(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn, static VALUE setup_args(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn, - unsigned int *flag, struct rb_call_info_kw_arg **keywords) + unsigned int *flag, struct rb_callinfo_kwarg **keywords) { VALUE ret; if (argn && nd_type(argn) == NODE_BLOCK_PASS) { @@ -5209,7 +5226,7 @@ compile_if(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int DECL_ANCHOR(else_seq); LABEL *then_label, *else_label, *end_label; VALUE branches = Qfalse; - int ci_size, ci_kw_size; + int ci_size; VALUE catch_table = ISEQ_COMPILE_DATA(iseq)->catch_table_ary; long catch_table_size = NIL_P(catch_table) ? 0 : RARRAY_LEN(catch_table); @@ -5224,12 +5241,10 @@ compile_if(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int then_label, else_label); ci_size = body->ci_size; - ci_kw_size = body->ci_kw_size; CHECK(COMPILE_(then_seq, "then", node_body, popped)); catch_table = ISEQ_COMPILE_DATA(iseq)->catch_table_ary; if (!then_label->refcnt) { body->ci_size = ci_size; - body->ci_kw_size = ci_kw_size; if (!NIL_P(catch_table)) rb_ary_set_len(catch_table, catch_table_size); } else { @@ -5237,12 +5252,10 @@ compile_if(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int } ci_size = body->ci_size; - ci_kw_size = body->ci_kw_size; CHECK(COMPILE_(else_seq, "else", node_else, popped)); catch_table = ISEQ_COMPILE_DATA(iseq)->catch_table_ary; if (!else_label->refcnt) { body->ci_size = ci_size; - body->ci_kw_size = ci_kw_size; if (!NIL_P(catch_table)) rb_ary_set_len(catch_table, catch_table_size); } else { @@ -6873,7 +6886,7 @@ compile_call(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, in ID mid = node->nd_mid; VALUE argc; unsigned int flag = 0; - struct rb_call_info_kw_arg *keywords = NULL; + struct rb_callinfo_kwarg *keywords = NULL; const rb_iseq_t *parent_block = ISEQ_COMPILE_DATA(iseq)->current_block; LABEL *else_label = NULL; VALUE branches = Qfalse; @@ -7676,7 +7689,7 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, in DECL_ANCHOR(args); int argc; unsigned int flag = 0; - struct rb_call_info_kw_arg *keywords = NULL; + struct rb_callinfo_kwarg *keywords = NULL; const rb_iseq_t *parent_block = ISEQ_COMPILE_DATA(iseq)->current_block; INIT_ANCHOR(args); @@ -7834,7 +7847,7 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, in DECL_ANCHOR(args); VALUE argc; unsigned int flag = 0; - struct rb_call_info_kw_arg *keywords = NULL; + struct rb_callinfo_kwarg *keywords = NULL; INIT_ANCHOR(args); @@ -8665,10 +8678,10 @@ insn_data_to_s_detail(INSN *iobj) break; case TS_CALLDATA: /* we store these as call infos at compile time */ { - const struct rb_call_info *ci = (struct rb_call_info *)OPERAND_AT(iobj, j); + const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, j); rb_str_cat2(str, "<calldata:"); - if (ci->mid) rb_str_catf(str, "%"PRIsVALUE, rb_id2str(ci->mid)); - rb_str_catf(str, ", %d>", ci->orig_argc); + if (vm_ci_mid(ci)) rb_str_catf(str, "%"PRIsVALUE, rb_id2str(vm_ci_mid(ci))); + rb_str_catf(str, ", %d>", vm_ci_argc(ci)); break; } case TS_CDHASH: /* case/when condition cache */ @@ -8905,7 +8918,7 @@ iseq_build_callinfo_from_hash(rb_iseq_t *iseq, VALUE op) ID mid = 0; int orig_argc = 0; unsigned int flag = 0; - struct rb_call_info_kw_arg *kw_arg = 0; + struct rb_callinfo_kwarg *kw_arg = 0; if (!NIL_P(op)) { VALUE vmid = rb_hash_aref(op, ID2SYM(rb_intern("mid"))); @@ -8920,7 +8933,7 @@ iseq_build_callinfo_from_hash(rb_iseq_t *iseq, VALUE op) if (!NIL_P(vkw_arg)) { int i; int len = RARRAY_LENINT(vkw_arg); - size_t n = rb_call_info_kw_arg_bytes(len); + size_t n = rb_callinfo_kwarg_bytes(len); kw_arg = xmalloc(n); kw_arg->keyword_len = len; @@ -8932,7 +8945,9 @@ iseq_build_callinfo_from_hash(rb_iseq_t *iseq, VALUE op) } } - return (VALUE)new_callinfo(iseq, mid, orig_argc, flag, kw_arg, (flag & VM_CALL_ARGS_SIMPLE) == 0); + const struct rb_callinfo *ci = new_callinfo(iseq, mid, orig_argc, flag, kw_arg, (flag & VM_CALL_ARGS_SIMPLE) == 0); + RB_OBJ_WRITTEN(iseq, Qundef, ci); + return (VALUE)ci; } static rb_event_flag_t @@ -9009,7 +9024,13 @@ iseq_build_from_ary_body(rb_iseq_t *iseq, LINK_ANCHOR *const anchor, } if (argc > 0) { - argv = compile_data_alloc2(iseq, sizeof(VALUE), argc); + argv = compile_data_calloc2(iseq, sizeof(VALUE), argc); + + // add element before operand setup to make GC root + ADD_ELEM(anchor, + (LINK_ELEMENT*)new_insn_core(iseq, line_no, + (enum ruby_vminsn_type)insn_id, argc, argv)); + for (j=0; j<argc; j++) { VALUE op = rb_ary_entry(obj, j+1); switch (insn_op_type((VALUE)insn_id, j)) { @@ -9093,9 +9114,11 @@ iseq_build_from_ary_body(rb_iseq_t *iseq, LINK_ANCHOR *const anchor, } } } - ADD_ELEM(anchor, - (LINK_ELEMENT*)new_insn_core(iseq, line_no, - (enum ruby_vminsn_type)insn_id, argc, argv)); + else { + ADD_ELEM(anchor, + (LINK_ELEMENT*)new_insn_core(iseq, line_no, + (enum ruby_vminsn_type)insn_id, argc, NULL)); + } } else { rb_raise(rb_eTypeError, "unexpected object for instruction"); @@ -9229,13 +9252,15 @@ rb_iseq_mark_insn_storage(struct iseq_compile_data_storage *storage) case TS_CDHASH: case TS_ISEQ: case TS_VALUE: + case TS_CALLDATA: // ci is stored. { VALUE op = OPERAND_AT(iobj, j); + if (!SPECIAL_CONST_P(op)) { rb_gc_mark(op); } - break; } + break; default: break; } @@ -9704,12 +9729,6 @@ ibf_load_id(const struct ibf_load *load, const ID id_index) /* dump/load: code */ -static VALUE -ibf_dump_calldata(struct ibf_dump *dump, const struct rb_call_data *cd) -{ - return (cd->ci.flag & VM_CALL_KWARG) ? Qtrue : Qfalse; -} - static ibf_offset_t ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq); static int @@ -9898,9 +9917,6 @@ ibf_dump_code(struct ibf_dump *dump, const rb_iseq_t *iseq) break; case TS_CALLDATA: { - /* ibf_dump_calldata() always returns either Qtrue or Qfalse */ - char c = ibf_dump_calldata(dump, (const struct rb_call_data *)op) == Qtrue; // 1 or 0 - ibf_dump_write_byte(dump, c); goto skip_wv; } case TS_ID: @@ -9937,7 +9953,6 @@ ibf_load_code(const struct ibf_load *load, const rb_iseq_t *iseq, ibf_offset_t b struct rb_iseq_constant_body *load_body = iseq->body; struct rb_call_data *cd_entries = load_body->call_data; - struct rb_kwarg_call_data *cd_kw_entries = (struct rb_kwarg_call_data *)&load_body->call_data[load_body->ci_size]; union iseq_inline_storage_entry *is_entries = load_body->is_entries; for (code_index=0; code_index<iseq_size;) { @@ -9984,8 +9999,7 @@ ibf_load_code(const struct ibf_load *load, const rb_iseq_t *iseq, ibf_offset_t b break; case TS_CALLDATA: { - unsigned char op = ibf_load_byte(load, &reading_pos); - code[code_index] = op ? (VALUE)cd_kw_entries++ : (VALUE)cd_entries++; /* op is 1 (kw) or 0 (!kw) */ + code[code_index] = (VALUE)cd_entries++; } break; case TS_ID: @@ -10257,38 +10271,29 @@ ibf_dump_ci_entries(struct ibf_dump *dump, const rb_iseq_t *iseq) { const struct rb_iseq_constant_body *const body = iseq->body; const unsigned int ci_size = body->ci_size; - const unsigned int ci_kw_size = body->ci_kw_size; - const struct rb_call_data *calls = body->call_data; - const struct rb_kwarg_call_data *kw_calls = (const struct rb_kwarg_call_data *)&body->call_data[ci_size]; + const struct rb_call_data *cds = body->call_data; ibf_offset_t offset = ibf_dump_pos(dump); unsigned int i; for (i = 0; i < ci_size; i++) { - VALUE mid = ibf_dump_id(dump, calls[i].ci.mid); - - ibf_dump_write_small_value(dump, mid); - ibf_dump_write_small_value(dump, calls[i].ci.flag); - ibf_dump_write_small_value(dump, calls[i].ci.orig_argc); - } - - for (i = 0; i < ci_kw_size; i++) { - const struct rb_call_info_kw_arg *kw_arg = kw_calls[i].ci_kw.kw_arg; - - VALUE mid = ibf_dump_id(dump, kw_calls[i].ci_kw.ci.mid); - - ibf_dump_write_small_value(dump, mid); - ibf_dump_write_small_value(dump, kw_calls[i].ci_kw.ci.flag); - ibf_dump_write_small_value(dump, kw_calls[i].ci_kw.ci.orig_argc); - - ibf_dump_write_small_value(dump, kw_arg->keyword_len); - - int j; - for (j = 0; j < kw_calls[i].ci_kw.kw_arg->keyword_len; j++) { - VALUE keyword = ibf_dump_object(dump, kw_arg->keywords[j]); /* kw_arg->keywords[n] is Symbol */ - - ibf_dump_write_small_value(dump, keyword); + const struct rb_callinfo *ci = cds[i].ci; + ibf_dump_write_small_value(dump, ibf_dump_id(dump, vm_ci_mid(ci))); + ibf_dump_write_small_value(dump, vm_ci_flag(ci)); + ibf_dump_write_small_value(dump, vm_ci_argc(ci)); + + const struct rb_callinfo_kwarg *kwarg = vm_ci_kwarg(ci); + if (kwarg) { + int len = kwarg->keyword_len; + ibf_dump_write_small_value(dump, len); + for (int j=0; j<len; j++) { + VALUE keyword = ibf_dump_object(dump, kwarg->keywords[j]); + ibf_dump_write_small_value(dump, keyword); + } + } + else { + ibf_dump_write_small_value(dump, 0); } } @@ -10299,51 +10304,37 @@ ibf_dump_ci_entries(struct ibf_dump *dump, const rb_iseq_t *iseq) static struct rb_call_data * ibf_load_ci_entries(const struct ibf_load *load, ibf_offset_t ci_entries_offset, - unsigned int ci_size, - unsigned int ci_kw_size) + unsigned int ci_size) { ibf_offset_t reading_pos = ci_entries_offset; unsigned int i; - struct rb_call_data *calls = - rb_xcalloc_mul_add_mul( - sizeof(struct rb_call_data), ci_size, - sizeof(struct rb_kwarg_call_data), ci_kw_size); - struct rb_kwarg_call_data *kw_calls = (struct rb_kwarg_call_data *)&calls[ci_size]; + struct rb_call_data *cds = ZALLOC_N(struct rb_call_data, ci_size); for (i = 0; i < ci_size; i++) { VALUE mid_index = ibf_load_small_value(load, &reading_pos); - - calls[i].ci.mid = ibf_load_id(load, mid_index); - calls[i].ci.flag = (unsigned int)ibf_load_small_value(load, &reading_pos); - calls[i].ci.orig_argc = (int)ibf_load_small_value(load, &reading_pos); - } - - for (i = 0; i < ci_kw_size; i++) { - VALUE mid_index = ibf_load_small_value(load, &reading_pos); - - kw_calls[i].ci_kw.ci.mid = ibf_load_id(load, mid_index); - kw_calls[i].ci_kw.ci.flag = (unsigned int)ibf_load_small_value(load, &reading_pos); - kw_calls[i].ci_kw.ci.orig_argc = (int)ibf_load_small_value(load, &reading_pos); - - int keyword_len = (int)ibf_load_small_value(load, &reading_pos); - - kw_calls[i].ci_kw.kw_arg = - rb_xmalloc_mul_add(keyword_len - 1, sizeof(VALUE), sizeof(struct rb_call_info_kw_arg)); - - kw_calls[i].ci_kw.kw_arg->keyword_len = keyword_len; - - int j; - for (j = 0; j < kw_calls[i].ci_kw.kw_arg->keyword_len; j++) { - VALUE keyword = ibf_load_small_value(load, &reading_pos); - - kw_calls[i].ci_kw.kw_arg->keywords[j] = ibf_load_object(load, keyword); + ID mid = ibf_load_id(load, mid_index); + unsigned int flag = (unsigned int)ibf_load_small_value(load, &reading_pos); + unsigned int argc = (unsigned int)ibf_load_small_value(load, &reading_pos); + + struct rb_callinfo_kwarg *kwarg = NULL; + int kwlen = (int)ibf_load_small_value(load, &reading_pos); + if (kwlen > 0) { + kwarg = rb_xmalloc_mul_add(kwlen - 1, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));; + kwarg->keyword_len = kwlen; + for (int j=0; j<kwlen; j++) { + VALUE keyword = ibf_load_small_value(load, &reading_pos); + kwarg->keywords[j] = ibf_load_object(load, keyword); + } } + + cds[i].ci = vm_ci_new(mid, flag, argc, kwarg); + RB_OBJ_WRITTEN(load->iseq, Qundef, cds[i].ci); } - return calls; -} + return cds; +} static ibf_offset_t ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq) @@ -10449,7 +10440,6 @@ ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq) ibf_dump_write_small_value(dump, body->local_table_size); ibf_dump_write_small_value(dump, body->is_size); ibf_dump_write_small_value(dump, body->ci_size); - ibf_dump_write_small_value(dump, body->ci_kw_size); ibf_dump_write_small_value(dump, body->stack_max); ibf_dump_write_small_value(dump, body->catch_except_p); @@ -10556,7 +10546,6 @@ ibf_load_iseq_each(struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t offset) const unsigned int local_table_size = (unsigned int)ibf_load_small_value(load, &reading_pos); const unsigned int is_size = (unsigned int)ibf_load_small_value(load, &reading_pos); const unsigned int ci_size = (unsigned int)ibf_load_small_value(load, &reading_pos); - const unsigned int ci_kw_size = (unsigned int)ibf_load_small_value(load, &reading_pos); const unsigned int stack_max = (unsigned int)ibf_load_small_value(load, &reading_pos); const char catch_except_p = (char)ibf_load_small_value(load, &reading_pos); @@ -10584,7 +10573,6 @@ ibf_load_iseq_each(struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t offset) load_body->local_table_size = local_table_size; load_body->is_size = is_size; load_body->ci_size = ci_size; - load_body->ci_kw_size = ci_kw_size; load_body->insns_info.size = insns_info_size; ISEQ_COVERAGE_SET(iseq, Qnil); @@ -10600,7 +10588,7 @@ ibf_load_iseq_each(struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t offset) load_body->catch_except_p = catch_except_p; load_body->is_entries = ZALLOC_N(union iseq_inline_storage_entry, is_size); - load_body->call_data = ibf_load_ci_entries(load, ci_entries_offset, ci_size, ci_kw_size); + load_body->call_data = ibf_load_ci_entries(load, ci_entries_offset, ci_size); load_body->param.opt_table = ibf_load_param_opt_table(load, param_opt_table_offset, param_opt_num); load_body->param.keyword = ibf_load_param_keyword(load, param_keyword_offset); load_body->param.flags.has_kw = (param_flags >> 4) & 1; |