Skip to content

Commit

Permalink
Null non-auto-viv P6opaque object slots at init
Browse files Browse the repository at this point in the history
And when we specialize the `create`, then spit out instructions to
initialize the slots to VMNull. This in turn means we can get rid of the
NULL checks on attribute access, so it can JIT into something far
simpler.
  • Loading branch information
jnthn committed Jun 4, 2019
1 parent 504835a commit 9638d3a
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 25 deletions.
72 changes: 69 additions & 3 deletions src/6model/reprs/P6opaque.c
Expand Up @@ -77,6 +77,9 @@ static void initialize(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, voi
st->REPR->initialize(tc, st, root, (char *)data + offset);
break;
}
case MVM_P6O_SETUP_VMNULL:
set_obj_at_offset(tc, root, data, offset, tc->instance->VMNull);
break;
default:
MVM_panic(1, "P6opaque: corrupt setup kind");
}
Expand Down Expand Up @@ -849,12 +852,21 @@ static void compose(MVMThreadContext *tc, MVMSTable *st, MVMObject *info_hash) {
/* Attribute will live at the current position in the object. */
repr_data->attribute_offsets[cur_slot] = cur_alloc_addr;

/* Handle object attributes, which need marking and may have auto-viv needs. */
/* Handle object attributes, which need marking and may have setup or
* auto-viv needs. */
if (!inlined) {
repr_data->gc_obj_mark_offsets[cur_obj_attr] = cur_alloc_addr;
if (MVM_repr_exists_key(tc, attr_info, str_avc))
if (MVM_repr_exists_key(tc, attr_info, str_avc)) {
/* It wants to be vivified on first touch. */
MVM_ASSIGN_REF(tc, &(st->header), repr_data->auto_viv_values[cur_slot],
MVM_repr_at_key_o(tc, attr_info, str_avc));
}
else {
/* We'll initialize it to VMNull at creation. */
repr_data->setups[cur_setup].kind = MVM_P6O_SETUP_VMNULL;
repr_data->setups[cur_setup].slot = cur_slot;
cur_setup++;
}
cur_obj_attr++;
}

Expand Down Expand Up @@ -1103,6 +1115,13 @@ static void deserialize_repr_data(MVMThreadContext *tc, MVMSTable *st, MVMSerial
repr_data->gc_obj_mark_offsets[repr_data->gc_obj_mark_offsets_count] = cur_offset;
repr_data->gc_obj_mark_offsets_count++;

/* If it has no auto-viv, it needs to be set up null. */
if (!repr_data->auto_viv_values || !repr_data->auto_viv_values[i]) {
repr_data->setups[cur_setup].kind = MVM_P6O_SETUP_VMNULL;
repr_data->setups[cur_setup].slot = i;
cur_setup++;
}

/* Increment by pointer size. */
cur_offset += sizeof(MVMObject *);
}
Expand Down Expand Up @@ -1457,6 +1476,50 @@ static MVMint32 has_initializations(MVMThreadContext *tc, MVMP6opaqueREPRData *r
return 1;
return 0;
}
static void emit_setups(MVMThreadContext *tc, MVMSpeshGraph *g, MVMSpeshBB *bb,
MVMSpeshIns *create_ins, MVMP6opaqueREPRData *repr_data) {
MVMSpeshOperand null_reg;
MVMint32 have_null_reg = 0;
MVMSpeshIns *after = create_ins;
MVMint32 i;
for (i = 0; i < repr_data->num_setups; i++) {
switch (repr_data->setups[i].kind) {
case MVM_P6O_SETUP_VMNULL: {
MVMuint16 slot = repr_data->setups[i].slot;
MVMint64 offset = repr_data->attribute_offsets[slot];
MVMSpeshIns *setup = MVM_spesh_alloc(tc, g, sizeof(MVMSpeshIns));
/* TODO Add a no write barrier variant of this. */
setup->info = MVM_op_get_op(MVM_OP_sp_bind_o);
setup->operands = MVM_spesh_alloc(tc, g, 3 * sizeof(MVMSpeshOperand));
setup->operands[0] = create_ins->operands[0];
setup->operands[1].lit_i16 = sizeof(MVMObject) + offset;
if (!have_null_reg) {
/* We produce one null instruction to share over all the
* attributes we might need to set up. */
MVMSpeshIns *null_ins = MVM_spesh_alloc(tc, g, sizeof(MVMSpeshIns));
null_ins->info = MVM_op_get_op(MVM_OP_null);
null_ins->operands = MVM_spesh_alloc(tc, g, 1 * sizeof(MVMSpeshOperand));
null_reg = null_ins->operands[0] = MVM_spesh_manipulate_get_temp_reg(tc,
g, MVM_reg_obj);
MVM_spesh_get_facts(tc, g, null_reg)->writer = null_ins;
MVM_spesh_manipulate_insert_ins(tc, bb, after, null_ins);
after = null_ins;
have_null_reg = 1;
}
setup->operands[2] = null_reg;
MVM_spesh_usages_add_by_reg(tc, g, setup->operands[0], setup);
MVM_spesh_usages_add_by_reg(tc, g, setup->operands[2], setup);
MVM_spesh_manipulate_insert_ins(tc, bb, after, setup);
after = setup;
break;
}
default:
MVM_panic(1, "P6opaque: unsupported setup kind in create lowering");
}
}
if (have_null_reg)
MVM_spesh_manipulate_release_temp_reg(tc, g, null_reg);
}
static void spesh(MVMThreadContext *tc, MVMSTable *st, MVMSpeshGraph *g, MVMSpeshBB *bb, MVMSpeshIns *ins) {
MVMP6opaqueREPRData * repr_data = (MVMP6opaqueREPRData *)st->REPR_data;
MVMuint16 opcode = ins->info->opcode;
Expand All @@ -1471,17 +1534,20 @@ static void spesh(MVMThreadContext *tc, MVMSTable *st, MVMSpeshGraph *g, MVMSpes
MVMSpeshOperand type = ins->operands[1];
MVMSpeshFacts *tgt_facts = MVM_spesh_get_facts(tc, g, target);

/* Emit the allocation instruction. */
ins->info = MVM_op_get_op(MVM_OP_sp_fastcreate);
ins->operands = MVM_spesh_alloc(tc, g, 3 * sizeof(MVMSpeshOperand));
ins->operands[0] = target;
ins->operands[1].lit_i16 = st->size;
ins->operands[2].lit_i16 = MVM_spesh_add_spesh_slot(tc, g, (MVMCollectable *)st);
MVM_spesh_usages_delete_by_reg(tc, g, type, ins);

MVM_spesh_graph_add_comment(tc, g, ins, "%s of a %s",
ins->info->name,
MVM_6model_get_stable_debug_name(tc, st));

/* Emit any attribute setups. */
emit_setups(tc, g, bb, ins, repr_data);

tgt_facts->flags |= MVM_SPESH_FACT_KNOWN_TYPE | MVM_SPESH_FACT_CONCRETE;
tgt_facts->type = st->WHAT;
}
Expand Down
8 changes: 3 additions & 5 deletions src/core/interp.c
Expand Up @@ -5913,8 +5913,7 @@ void MVM_interp_run(MVMThreadContext *tc, void (*initial_invoke)(MVMThreadContex
cur_op += 6;
goto NEXT;
OP(sp_get_o): {
MVMObject *val = *((MVMObject **)((char *)GET_REG(cur_op, 2).o + GET_UI16(cur_op, 4)));
GET_REG(cur_op, 0).o = val ? val : tc->instance->VMNull;
GET_REG(cur_op, 0).o = *((MVMObject **)((char *)GET_REG(cur_op, 2).o + GET_UI16(cur_op, 4)));
cur_op += 6;
goto NEXT;
}
Expand Down Expand Up @@ -5994,9 +5993,8 @@ void MVM_interp_run(MVMThreadContext *tc, void (*initial_invoke)(MVMThreadContex
goto NEXT;
}
OP(sp_p6oget_o): {
MVMObject *o = GET_REG(cur_op, 2).o;
MVMObject *val = MVM_p6opaque_read_object(tc, o, GET_UI16(cur_op, 4));
GET_REG(cur_op, 0).o = val ? val : tc->instance->VMNull;
MVMObject *o = GET_REG(cur_op, 2).o;
GET_REG(cur_op, 0).o = MVM_p6opaque_read_object(tc, o, GET_UI16(cur_op, 4));
cur_op += 6;
goto NEXT;
}
Expand Down
5 changes: 1 addition & 4 deletions src/jit/core_templates.expr
Expand Up @@ -2613,10 +2613,7 @@
(store \$0 $block ptr_sz)))

(template: sp_p6oget_o
(let: (($val (load (add (^p6obody $1) $2) ptr_sz)))
(if (nz $val)
$val
(^vmnull))))
(load (add (^p6obody $1) $2) ptr_sz))

(template: sp_p6ogetvt_o
(let: (($addr (add (^p6obody $1) $2))
Expand Down
14 changes: 1 addition & 13 deletions src/jit/x64/emit.dasc
Expand Up @@ -710,15 +710,7 @@ void MVM_jit_emit_primitive(MVMThreadContext *tc, MVMJitCompiler *compiler, MVMJ
| cmovnz TMP2, TMP5;
}
/* TMP2 now contains address of item */
if (op == MVM_OP_sp_p6oget_o) {
| mov TMP3, [TMP2];
| test TMP3, TMP3;
/* Check if object doesn't point to NULL */
| jnz >3;
/* Otherwise load VMNull */
| get_vmnull TMP3;
|3:
} else if (op == MVM_OP_sp_p6ogetvt_o || op == MVM_OP_sp_getvt_o) {
if (op == MVM_OP_sp_p6ogetvt_o || op == MVM_OP_sp_getvt_o) {
/* vivify as type object */
MVMint16 spesh_idx = ins->operands[3].lit_i16;
MVMCollectable *spesh_value = jg->sg->spesh_slots[spesh_idx];
Expand Down Expand Up @@ -839,10 +831,6 @@ void MVM_jit_emit_primitive(MVMThreadContext *tc, MVMJitCompiler *compiler, MVMJ
MVMint16 offset = ins->operands[2].lit_i16;
| mov TMP1, WORK[obj]; // object
| mov TMP2, qword [TMP1+offset]; // get value from body
| test TMP2, TMP2;
| jnz >1;
| get_vmnull TMP2;
|1:
| mov WORK[dst], TMP2;
break;
}
Expand Down

0 comments on commit 9638d3a

Please sign in to comment.