Feature #11786 ยป 0001-micro-optimize-case-dispatch-even-harder.patch
| benchmark/bm_vm2_case_small.rb | ||
|---|---|---|
|
i = 0
|
||
|
while i<6_000_000 # while loop 2
|
||
|
case :foo
|
||
|
when :foo
|
||
|
i += 1
|
||
|
else
|
||
|
raise
|
||
|
end
|
||
|
end
|
||
| compile.c | ||
|---|---|---|
|
};
|
||
|
struct cdhash_set_label_struct {
|
||
|
VALUE hash;
|
||
|
st_table *cdh;
|
||
|
int pos;
|
||
|
int len;
|
||
|
};
|
||
|
static int
|
||
|
cdhash_set_label_i(VALUE key, VALUE val, void *ptr)
|
||
|
cdhash_set_label_i(VALUE key, long val, void *ptr)
|
||
|
{
|
||
|
struct cdhash_set_label_struct *data = (struct cdhash_set_label_struct *)ptr;
|
||
|
struct cdhash_set_label_struct *d = (struct cdhash_set_label_struct *)ptr;
|
||
|
LABEL *lobj = (LABEL *)(val & ~1);
|
||
|
rb_hash_aset(data->hash, key, INT2FIX(lobj->position - (data->pos+data->len)));
|
||
|
st_insert(d->cdh, key, lobj->position - (d->pos + d->len));
|
||
|
return ST_CONTINUE;
|
||
|
}
|
||
| ... | ... | |
|
}
|
||
|
case TS_CDHASH:
|
||
|
{
|
||
|
VALUE map = operands[j];
|
||
|
struct cdhash_set_label_struct data;
|
||
|
data.hash = map;
|
||
|
data.pos = code_index;
|
||
|
data.len = len;
|
||
|
rb_hash_foreach(map, cdhash_set_label_i, (VALUE)&data);
|
||
|
freeze_hide_obj(map);
|
||
|
generated_iseq[code_index + 1 + j] = map;
|
||
|
st_table *cdh = (st_table *)operands[j];
|
||
|
struct cdhash_set_label_struct d;
|
||
|
d.cdh = cdh;
|
||
|
d.pos = code_index;
|
||
|
d.len = len;
|
||
|
st_foreach(cdh, cdhash_set_label_i, (st_data_t)&d);
|
||
|
generated_iseq[code_index + 1 + j] = (VALUE)cdh;
|
||
|
break;
|
||
|
}
|
||
|
case TS_LINDEX:
|
||
| ... | ... | |
|
}
|
||
|
static int
|
||
|
when_vals(rb_iseq_t *iseq, LINK_ANCHOR *cond_seq, NODE *vals, LABEL *l1, int only_special_literals, VALUE literals)
|
||
|
when_vals(rb_iseq_t *iseq, LINK_ANCHOR *cond_seq, NODE *vals, LABEL *l1,
|
||
|
int only_special_literals, st_table *literals)
|
||
|
{
|
||
|
while (vals) {
|
||
|
NODE* val = vals->nd_head;
|
||
| ... | ... | |
|
only_special_literals = 0;
|
||
|
}
|
||
|
else {
|
||
|
if (rb_hash_lookup(literals, lit) != Qnil) {
|
||
|
if (st_lookup(literals, lit, 0)) {
|
||
|
rb_compile_warning(ruby_sourcefile, nd_line(val), "duplicated when clause is ignored");
|
||
|
}
|
||
|
else {
|
||
|
rb_hash_aset(literals, lit, (VALUE)(l1) | 1);
|
||
|
st_add_direct(literals, lit, (VALUE)(l1) | 1);
|
||
|
}
|
||
|
}
|
||
| ... | ... | |
|
DECL_ANCHOR(body_seq);
|
||
|
DECL_ANCHOR(cond_seq);
|
||
|
int only_special_literals = 1;
|
||
|
VALUE literals = rb_hash_new();
|
||
|
st_table *literals = st_init_table(&cdhash_type);
|
||
|
INIT_ANCHOR(head);
|
||
|
INIT_ANCHOR(body_seq);
|
||
|
INIT_ANCHOR(cond_seq);
|
||
|
rb_hash_tbl_raw(literals)->type = &cdhash_type;
|
||
|
if (node->nd_head == 0) {
|
||
|
COMPILE_(ret, "when", node->nd_body, poped);
|
||
|
break;
|
||
| ... | ... | |
|
}
|
||
|
if (only_special_literals) {
|
||
|
iseq_add_mark_object(iseq, literals);
|
||
|
ADD_INSN(ret, nd_line(tempnode), dup);
|
||
|
ADD_INSN2(ret, nd_line(tempnode), opt_case_dispatch, literals, elselabel);
|
||
|
LABEL_REF(elselabel);
|
||
|
}
|
||
|
else {
|
||
|
st_free_table(literals);
|
||
|
}
|
||
|
ADD_SEQ(ret, cond_seq);
|
||
|
ADD_SEQ(ret, body_seq);
|
||
| ... | ... | |
|
case TS_CDHASH:
|
||
|
{
|
||
|
int i;
|
||
|
VALUE map = rb_hash_new();
|
||
|
st_table *literals = st_init_table(&cdhash_type);
|
||
|
rb_hash_tbl_raw(map)->type = &cdhash_type;
|
||
|
op = rb_convert_type(op, T_ARRAY, "Array", "to_ary");
|
||
|
op = rb_ary_dup(op);
|
||
|
for (i=0; i<RARRAY_LEN(op); i+=2) {
|
||
| ... | ... | |
|
VALUE sym = RARRAY_AREF(op, i+1);
|
||
|
LABEL *label =
|
||
|
register_label(iseq, labels_table, sym);
|
||
|
rb_hash_aset(map, key, (VALUE)label | 1);
|
||
|
st_add_direct(literals, key, (VALUE)label | 1);
|
||
|
}
|
||
|
RB_GC_GUARD(op);
|
||
|
argv[j] = map;
|
||
|
rb_iseq_add_mark_object(iseq, map);
|
||
|
argv[j] = (VALUE)literals;
|
||
|
}
|
||
|
break;
|
||
|
case TS_FUNCPTR:
|
||
| insns.def | ||
|---|---|---|
|
*/
|
||
|
DEFINE_INSN
|
||
|
opt_case_dispatch
|
||
|
(CDHASH hash, OFFSET else_offset)
|
||
|
(CDHASH cdh, OFFSET else_offset)
|
||
|
(..., VALUE key)
|
||
|
() // inc += -1;
|
||
|
{
|
||
| ... | ... | |
|
FALSE_REDEFINED_OP_FLAG |
|
||
|
STRING_REDEFINED_OP_FLAG)) {
|
||
|
st_data_t val;
|
||
|
if (st_lookup(RHASH_TBL_RAW(hash), key, &val)) {
|
||
|
JUMP(FIX2INT((VALUE)val));
|
||
|
if (st_lookup(cdh, key, &val)) {
|
||
|
JUMP(val);
|
||
|
}
|
||
|
else {
|
||
|
JUMP(else_offset);
|
||
| iseq.c | ||
|---|---|---|
|
cdhash_each(VALUE key, VALUE value, VALUE ary)
|
||
|
{
|
||
|
rb_ary_push(ary, obj_resurrect(key));
|
||
|
rb_ary_push(ary, value);
|
||
|
rb_ary_push(ary, INT2FIX(value));
|
||
|
return ST_CONTINUE;
|
||
|
}
|
||
| ... | ... | |
|
break;
|
||
|
case TS_CDHASH:
|
||
|
{
|
||
|
VALUE hash = *seq;
|
||
|
st_table *cdh = (st_table *)*seq;
|
||
|
VALUE val = rb_ary_new();
|
||
|
int i;
|
||
|
rb_hash_foreach(hash, cdhash_each, val);
|
||
|
st_foreach(cdh, cdhash_each, val);
|
||
|
for (i=0; i<RARRAY_LEN(val); i+=2) {
|
||
|
VALUE pos = FIX2INT(rb_ary_entry(val, i+1));
|
||
| vm_core.h | ||
|---|---|---|
|
void rb_vm_change_state(void);
|
||
|
typedef VALUE CDHASH;
|
||
|
typedef st_table * CDHASH;
|
||
|
#ifndef FUNC_FASTCALL
|
||
|
#define FUNC_FASTCALL(x) x
|
||
|
-
|
||