Skip to content
Permalink
Browse files

Add direct marking on iseq operands

Directly marking iseq operands allows us to eliminate the "mark array"
stored on ISEQ objects, which will reduce the amount of memory ISEQ
objects consume.  This patch changes the iseq mark function to:

* Directly marks ISEQ operands
* Iterate over and mark child ISEQs

It also introduces two flags on the ISEQ object.  In order to mark
instruction operands, we have to disassemble the instructions and find
the instruction parameters and types.  Instructions may also be
translated to jump addresses.  Instruction sequences may get marked by
the GC *while* they're mid flight (being compiled).  The
`ISEQ_TRANSLATED` flag is used to indicate whether or not the
instructions have been translated to jump addresses so that when we
decode the instructions we know whether or not we need to go from jump
location back to original instruction or not.

Not all ISEQ objects have any markable objects embedded in their
instructions.  We can detect whether or not an ISEQ has markable objects
in the instructions at compile time.  If the instructions contain
markable objects, we set a flag `ISEQ_MARKABLE_ISEQ` on the ISEQ object.
This means that during the mark phase, we can skip decompilation if the
flag is *not* set.  In other words, we can avoid decompilation of we
know in advance there is nothing to mark.

`once` instructions have an operand that contains the result of a
one-time compilation of a regex.  Before this patch, that operand was
called an "inline cache", even though the struct was actually an "inline
storage".  This patch changes the operand to be an "inline storage" so
that we can differentiate between caches that need marking (the inline
storage) and caches that don't need marking (inline cache).

[ruby-core:84909]

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@62706 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
  • Loading branch information...
tenderlove committed Mar 9, 2018
1 parent 2dafe8d commit 89529649768798d495f97e5439e18864a0259a31
Showing with 171 additions and 72 deletions.
  1. +31 −28 compile.c
  2. +2 −2 insns.def
  3. +118 −9 iseq.c
  4. +10 −28 iseq.h
  5. +1 −0 tool/ruby_vm/models/typemap.rb
  6. +6 −1 vm_core.h
  7. +3 −4 vm_insnhelper.c
@@ -562,15 +562,6 @@ APPEND_ELEM(ISEQ_ARG_DECLARE LINK_ANCHOR *const anchor, LINK_ELEMENT *before, LI
#define APPEND_ELEM(anchor, before, elem) APPEND_ELEM(iseq, (anchor), (before), (elem))
#endif

static int
iseq_add_mark_object(const rb_iseq_t *iseq, VALUE v)
{
if (!SPECIAL_CONST_P(v)) {
rb_iseq_add_mark_object(iseq, v);
}
return COMPILE_OK;
}

static int
iseq_add_mark_object_compile_time(const rb_iseq_t *iseq, VALUE v)
{
@@ -749,6 +740,7 @@ rb_iseq_translate_threaded_code(rb_iseq_t *iseq)
encoded[i] = (VALUE)table[insn];
i += len;
}
FL_SET(iseq, ISEQ_TRANSLATED);
#endif
return COMPILE_OK;
}
@@ -1235,7 +1227,7 @@ new_child_iseq(rb_iseq_t *iseq, const NODE *const node,
rb_iseq_path(iseq), rb_iseq_realpath(iseq),
INT2FIX(line_no), parent, type, ISEQ_COMPILE_DATA(iseq)->option);
debugs("[new_child_iseq]< ---------------------------------------\n");
iseq_add_mark_object(iseq, (VALUE)ret_iseq);
iseq_add_mark_object_compile_time(iseq, (VALUE)ret_iseq);
return ret_iseq;
}

@@ -1250,7 +1242,7 @@ new_child_iseq_ifunc(rb_iseq_t *iseq, const struct vm_ifunc *ifunc,
rb_iseq_path(iseq), rb_iseq_realpath(iseq),
INT2FIX(line_no), parent, type, ISEQ_COMPILE_DATA(iseq)->option);
debugs("[new_child_iseq_ifunc]< ---------------------------------------\n");
iseq_add_mark_object(iseq, (VALUE)ret_iseq);
iseq_add_mark_object_compile_time(iseq, (VALUE)ret_iseq);
return ret_iseq;
}

@@ -1550,7 +1542,6 @@ iseq_set_arguments_keywords(rb_iseq_t *iseq, LINK_ANCHOR *const optargs,
switch (nd_type(val_node)) {
case NODE_LIT:
dv = val_node->nd_lit;
iseq_add_mark_object(iseq, dv);
break;
case NODE_NIL:
dv = Qnil;
@@ -2076,6 +2067,7 @@ iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
rb_hash_rehash(map);
freeze_hide_obj(map);
generated_iseq[code_index + 1 + j] = map;
FL_SET(iseq, ISEQ_MARKABLE_ISEQ);
break;
}
case TS_LINDEX:
@@ -2086,14 +2078,19 @@ iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
{
VALUE v = operands[j];
generated_iseq[code_index + 1 + j] = v;
if (!SPECIAL_CONST_P(v)) {
FL_SET(iseq, ISEQ_MARKABLE_ISEQ);
}
break;
}
case TS_VALUE: /* VALUE */
{
VALUE v = operands[j];
generated_iseq[code_index + 1 + j] = v;
/* to mark ruby object */
iseq_add_mark_object(iseq, v);
if (!SPECIAL_CONST_P(v)) {
FL_SET(iseq, ISEQ_MARKABLE_ISEQ);
}
break;
}
case TS_IC: /* inline cache */
@@ -2106,6 +2103,17 @@ iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
generated_iseq[code_index + 1 + j] = (VALUE)ic;
break;
}
case TS_ISE: /* inline storage entry */
{
unsigned int ic_index = FIX2UINT(operands[j]);
IC ic = (IC)&iseq->body->is_entries[ic_index];
if (UNLIKELY(ic_index >= iseq->body->is_size)) {
rb_bug("iseq_set_sequence: ic_index overflow: index: %d, size: %d", ic_index, iseq->body->is_size);
}
generated_iseq[code_index + 1 + j] = (VALUE)ic;
FL_SET(iseq, ISEQ_MARKABLE_ISEQ);
break;
}
case TS_CALLINFO: /* call info */
{
struct rb_call_info *base_ci = (struct rb_call_info *)operands[j];
@@ -2258,11 +2266,6 @@ iseq_set_exception_table(rb_iseq_t *iseq)
entry->end = label_get_position((LABEL *)(ptr[2] & ~1));
entry->iseq = (rb_iseq_t *)ptr[3];

/* register iseq as mark object */
if (entry->iseq != 0) {
iseq_add_mark_object(iseq, (VALUE)entry->iseq);
}

/* stack depth */
if (ptr[4]) {
LABEL *lobj = (LABEL *)(ptr[4] & ~1);
@@ -4877,7 +4880,7 @@ compile_case(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_nod
}

if (only_special_literals) {
iseq_add_mark_object(iseq, literals);
iseq_add_mark_object_compile_time(iseq, literals);

ADD_INSN(ret, nd_line(orig_node), dup);
ADD_INSN2(ret, nd_line(orig_node), opt_case_dispatch, literals, elselabel);
@@ -7354,6 +7357,7 @@ insn_data_to_s_detail(INSN *iobj)
break;
}
case TS_IC: /* inline cache */
case TS_ISE: /* inline storage entry */
rb_str_catf(str, "<ic:%d>", FIX2INT(OPERAND_AT(iobj, j)));
break;
case TS_CALLINFO: /* call info */
@@ -7593,7 +7597,6 @@ iseq_build_load_iseq(const rb_iseq_t *iseq, VALUE op)
}

loaded_iseq = rb_iseqw_to_iseq(iseqw);
iseq_add_mark_object(iseq, (VALUE)loaded_iseq);
return loaded_iseq;
}

@@ -7724,7 +7727,6 @@ iseq_build_from_ary_body(rb_iseq_t *iseq, LINK_ANCHOR *const anchor,
break;
case TS_VALUE:
argv[j] = op;
iseq_add_mark_object(iseq, op);
break;
case TS_ISEQ:
{
@@ -7741,6 +7743,7 @@ iseq_build_from_ary_body(rb_iseq_t *iseq, LINK_ANCHOR *const anchor,
argv[j] = (VALUE)rb_global_entry(SYM2ID(op));
break;
case TS_IC:
case TS_ISE:
argv[j] = op;
if (NUM2UINT(op) >= iseq->body->is_size) {
iseq->body->is_size = NUM2INT(op) + 1;
@@ -7771,7 +7774,6 @@ iseq_build_from_ary_body(rb_iseq_t *iseq, LINK_ANCHOR *const anchor,
}
RB_GC_GUARD(op);
argv[j] = map;
rb_iseq_add_mark_object(iseq, map);
}
break;
case TS_FUNCPTR:
@@ -8347,6 +8349,7 @@ ibf_dump_code(struct ibf_dump *dump, const rb_iseq_t *iseq)
code[code_index] = (VALUE)ibf_dump_iseq(dump, (const rb_iseq_t *)op);
break;
case TS_IC:
case TS_ISE:
{
unsigned int i;
for (i=0; i<iseq->body->is_size; i++) {
@@ -8412,6 +8415,7 @@ ibf_load_code(const struct ibf_load *load, const rb_iseq_t *iseq, const struct r
code[code_index] = (VALUE)ibf_load_iseq(load, (const rb_iseq_t *)op);
break;
case TS_IC:
case TS_ISE:
code[code_index] = (VALUE)&is_entries[(int)op];
break;
case TS_CALLINFO:
@@ -8712,7 +8716,8 @@ ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq)
dump_body.is_entries = NULL;
dump_body.ci_entries = ibf_dump_ci_entries(dump, iseq);
dump_body.cc_entries = NULL;
dump_body.mark_ary = ISEQ_FLIP_CNT(iseq);
dump_body.variable.coverage = Qnil;
dump_body.variable.original_iseq = Qnil;

return ibf_dump_write(dump, &dump_body, sizeof(dump_body));
}
@@ -8744,7 +8749,9 @@ ibf_load_iseq_each(const struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t of
load_body->ci_kw_size = body->ci_kw_size;
load_body->insns_info.size = body->insns_info.size;

RB_OBJ_WRITE(iseq, &load_body->mark_ary, iseq_mark_ary_create((int)body->mark_ary));
ISEQ_COVERAGE_SET(iseq, Qnil);
ISEQ_ORIGINAL_ISEQ_CLEAR(iseq);
iseq->body->variable.flip_count = (int)body->variable.flip_count;

{
VALUE realpath = Qnil, path = ibf_load_object(load, body->location.pathobj);
@@ -9376,7 +9383,6 @@ ibf_load_object(const struct ibf_load *load, VALUE object_index)

rb_ary_store(load->obj_list, (long)object_index, obj);
}
iseq_add_mark_object(load->iseq, obj);
return obj;
}
}
@@ -9561,9 +9567,6 @@ ibf_load_iseq(const struct ibf_load *load, const rb_iseq_t *index_iseq)
ibf_load_iseq_complete(iseq);
#endif /* !USE_LAZY_LOAD */

if (load->iseq) {
iseq_add_mark_object(load->iseq, (VALUE)iseq);
}
return iseq;
}
}
@@ -972,11 +972,11 @@ setinlinecache
/* run iseq only once */
DEFINE_INSN
once
(ISEQ iseq, IC ic)
(ISEQ iseq, ISE ise)
()
(VALUE val)
{
val = vm_once_dispatch(ec, iseq, ic);
val = vm_once_dispatch(ec, iseq, ise);
}

/* case dispatcher, jump by table if possible */

0 comments on commit 8952964

Please sign in to comment.
You can’t perform that action at this time.