Skip to content

Instantly share code, notes, and snippets.

@MasterDuke17
Last active January 24, 2019 02:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save MasterDuke17/a618b3e46db4f7ea9fac78d984af2d3e to your computer and use it in GitHub Desktop.
Save MasterDuke17/a618b3e46db4f7ea9fac78d984af2d3e to your computer and use it in GitHub Desktop.
diff --git a/src/core/coerce.c b/src/core/coerce.c
index 813e913b2..85d990702 100644
--- a/src/core/coerce.c
+++ b/src/core/coerce.c
@@ -285,146 +285,149 @@ void MVM_coerce_smart_stringify(MVMThreadContext *tc, MVMObject *obj, MVMRegiste
return;
}
/* If it can unbox as a string, that wins right off. */
ss = REPR(obj)->get_storage_spec(tc, STABLE(obj));
if (ss->can_box & MVM_STORAGE_SPEC_CAN_BOX_STR && IS_CONCRETE(obj)) {
res_reg->s = REPR(obj)->box_funcs.get_str(tc, STABLE(obj), obj, OBJECT_BODY(obj));
return;
}
/* Check if there is a Str method. */
MVMROOT(tc, obj, {
strmeth = MVM_6model_find_method_cache_only(tc, obj,
tc->instance->str_consts.Str);
});
if (!MVM_is_null(tc, strmeth)) {
/* We need to do the invocation; just set it up with our result reg as
* the one for the call. */
MVMObject *code = MVM_frame_find_invokee(tc, strmeth, NULL);
MVMCallsite *inv_arg_callsite = MVM_callsite_get_common(tc, MVM_CALLSITE_ID_INV_ARG);
MVM_args_setup_thunk(tc, res_reg, MVM_RETURN_STR, inv_arg_callsite);
tc->cur_frame->args[0].o = obj;
STABLE(code)->invoke(tc, code, inv_arg_callsite, tc->cur_frame->args);
+ //fprintf(stderr, ".Str method called on '%s'\n", MVM_6model_get_debug_name(tc, obj));
return;
}
/* Otherwise, guess something appropriate. */
if (!IS_CONCRETE(obj))
res_reg->s = tc->instance->str_consts.empty;
else {
if (REPR(obj)->ID == MVM_REPR_ID_MVMException)
res_reg->s = ((MVMException *)obj)->body.message;
else if (ss->can_box & MVM_STORAGE_SPEC_CAN_BOX_INT)
res_reg->s = MVM_coerce_i_s(tc, REPR(obj)->box_funcs.get_int(tc, STABLE(obj), obj, OBJECT_BODY(obj)));
else if (ss->can_box & MVM_STORAGE_SPEC_CAN_BOX_NUM)
res_reg->s = MVM_coerce_n_s(tc, REPR(obj)->box_funcs.get_num(tc, STABLE(obj), obj, OBJECT_BODY(obj)));
else
MVM_exception_throw_adhoc(tc, "cannot stringify this");
}
}
MVMint64 MVM_coerce_s_i(MVMThreadContext *tc, MVMString *s) {
char *enc = MVM_string_ascii_encode(tc, s, NULL, 0);
MVMint64 i = strtoll(enc, NULL, 10);
MVM_free(enc);
return i;
}
void MVM_coerce_smart_numify(MVMThreadContext *tc, MVMObject *obj, MVMRegister *res_reg) {
MVMObject *nummeth;
/* Handle null case. */
if (MVM_is_null(tc, obj)) {
res_reg->n64 = 0.0;
return;
}
/* Check if there is a Num method. */
MVMROOT(tc, obj, {
nummeth = MVM_6model_find_method_cache_only(tc, obj,
tc->instance->str_consts.Num);
});
if (!MVM_is_null(tc, nummeth)) {
/* We need to do the invocation; just set it up with our result reg as
* the one for the call. */
MVMObject *code = MVM_frame_find_invokee(tc, nummeth, NULL);
MVMCallsite *inv_arg_callsite = MVM_callsite_get_common(tc, MVM_CALLSITE_ID_INV_ARG);
MVM_args_setup_thunk(tc, res_reg, MVM_RETURN_NUM, inv_arg_callsite);
tc->cur_frame->args[0].o = obj;
STABLE(code)->invoke(tc, code, inv_arg_callsite, tc->cur_frame->args);
+ //fprintf(stderr, ".Num method called on '%s'\n", MVM_6model_get_debug_name(tc, obj));
return;
}
/* Otherwise, guess something appropriate. */
if (!IS_CONCRETE(obj)) {
res_reg->n64 = 0.0;
}
else {
const MVMStorageSpec *ss = REPR(obj)->get_storage_spec(tc, STABLE(obj));
if (ss->can_box & MVM_STORAGE_SPEC_CAN_BOX_INT)
res_reg->n64 = (MVMnum64)REPR(obj)->box_funcs.get_int(tc, STABLE(obj), obj, OBJECT_BODY(obj));
else if (ss->can_box & MVM_STORAGE_SPEC_CAN_BOX_NUM)
res_reg->n64 = REPR(obj)->box_funcs.get_num(tc, STABLE(obj), obj, OBJECT_BODY(obj));
else if (ss->can_box & MVM_STORAGE_SPEC_CAN_BOX_STR)
res_reg->n64 = MVM_coerce_s_n(tc, REPR(obj)->box_funcs.get_str(tc, STABLE(obj), obj, OBJECT_BODY(obj)));
else if (REPR(obj)->ID == MVM_REPR_ID_VMArray)
res_reg->n64 = (MVMnum64)REPR(obj)->elems(tc, STABLE(obj), obj, OBJECT_BODY(obj));
else if (REPR(obj)->ID == MVM_REPR_ID_MVMHash)
res_reg->n64 = (MVMnum64)REPR(obj)->elems(tc, STABLE(obj), obj, OBJECT_BODY(obj));
else
MVM_exception_throw_adhoc(tc, "cannot numify this");
}
}
void MVM_coerce_smart_intify(MVMThreadContext *tc, MVMObject *obj, MVMRegister *res_reg) {
MVMObject *intmeth;
/* Handle null case. */
if (MVM_is_null(tc, obj)) {
res_reg->i64 = 0;
}
/* Check if there is an Int method. */
MVMROOT(tc, obj, {
intmeth = MVM_6model_find_method_cache_only(tc, obj,
tc->instance->str_consts.Int);
});
if (!MVM_is_null(tc, intmeth)) {
/* We need to do the invocation; just set it up with our result reg as
* the one for the call. */
MVMObject *code = MVM_frame_find_invokee(tc, intmeth, NULL);
MVMCallsite *inv_arg_callsite = MVM_callsite_get_common(tc, MVM_CALLSITE_ID_INV_ARG);
MVM_args_setup_thunk(tc, res_reg, MVM_RETURN_INT, inv_arg_callsite);
tc->cur_frame->args[0].o = obj;
STABLE(code)->invoke(tc, code, inv_arg_callsite, tc->cur_frame->args);
+ //fprintf(stderr, ".Int method called on '%s'\n", MVM_6model_get_debug_name(tc, obj));
return;
}
else {
res_reg->i64 = MVM_coerce_simple_intify(tc, obj);
}
}
MVMint64 MVM_coerce_simple_intify(MVMThreadContext *tc, MVMObject *obj) {
/* Handle null and non-concrete case. */
if (MVM_is_null(tc, obj) || !IS_CONCRETE(obj)) {
return 0;
}
/* Otherwise, guess something appropriate. */
else {
const MVMStorageSpec *ss = REPR(obj)->get_storage_spec(tc, STABLE(obj));
if (ss->can_box & MVM_STORAGE_SPEC_CAN_BOX_INT)
return REPR(obj)->box_funcs.get_int(tc, STABLE(obj), obj, OBJECT_BODY(obj));
else if (ss->can_box & MVM_STORAGE_SPEC_CAN_BOX_NUM)
return (MVMint64)REPR(obj)->box_funcs.get_num(tc, STABLE(obj), obj, OBJECT_BODY(obj));
else if (ss->can_box & MVM_STORAGE_SPEC_CAN_BOX_STR)
return MVM_coerce_s_i(tc, REPR(obj)->box_funcs.get_str(tc, STABLE(obj), obj, OBJECT_BODY(obj)));
else if (REPR(obj)->ID == MVM_REPR_ID_VMArray)
return REPR(obj)->elems(tc, STABLE(obj), obj, OBJECT_BODY(obj));
else if (REPR(obj)->ID == MVM_REPR_ID_MVMHash)
diff --git a/src/spesh/optimize.c b/src/spesh/optimize.c
index 9f55fa598..1bac5406a 100644
--- a/src/spesh/optimize.c
+++ b/src/spesh/optimize.c
@@ -907,87 +907,101 @@ static void optimize_coerce(MVMThreadContext *tc, MVMSpeshGraph *g, MVMSpeshBB *
ins->info = MVM_op_get_op(MVM_OP_const_n64);
ins->operands[1].lit_n64 = result;
result_facts->flags |= MVM_SPESH_FACT_KNOWN_VALUE;
result_facts->value.n = result;
}
}
/* If we know the type of a significant operand, we might try to specialize by
* representation. */
static void optimize_repr_op(MVMThreadContext *tc, MVMSpeshGraph *g, MVMSpeshBB *bb,
MVMSpeshIns *ins, MVMint32 type_operand) {
/* Immediately mark guards as used, as the JIT would like to devirtualize
* repr ops later and we don't want guards to be thrown out before that */
MVMSpeshFacts *facts = MVM_spesh_get_and_use_facts(tc, g, ins->operands[type_operand]);
if (facts->flags & MVM_SPESH_FACT_KNOWN_TYPE && facts->type)
if (REPR(facts->type)->spesh) {
REPR(facts->type)->spesh(tc, STABLE(facts->type), g, bb, ins);
MVM_spesh_use_facts(tc, g, facts);
}
}
/* smrt_strify and smrt_numify can turn into unboxes, but at least
* for smrt_numify it's "complicated". Also, later when we know how
* to put new invocations into spesh'd code, we could make direct
- * invoke calls to the .Str and .Num methods. */
+ * invoke calls to the .Str, .Num, and .Int methods. */
static void optimize_smart_coerce(MVMThreadContext *tc, MVMSpeshGraph *g, MVMSpeshBB *bb, MVMSpeshIns *ins) {
MVMSpeshFacts *facts = MVM_spesh_get_facts(tc, g, ins->operands[1]);
MVMuint16 is_strify = ins->info->opcode == MVM_OP_smrt_strify;
+ MVMuint16 is_numify = ins->info->opcode == MVM_OP_smrt_numify;
+ MVMuint16 is_intify = ins->info->opcode == MVM_OP_smrt_intify;
if (facts->flags & (MVM_SPESH_FACT_KNOWN_TYPE | MVM_SPESH_FACT_CONCRETE) && facts->type) {
const MVMStorageSpec *ss;
MVMint64 can_result;
ss = REPR(facts->type)->get_storage_spec(tc, STABLE(facts->type));
if (is_strify && ss->can_box & MVM_STORAGE_SPEC_CAN_BOX_STR) {
MVM_spesh_use_facts(tc, g, facts);
ins->info = MVM_op_get_op(MVM_OP_unbox_s);
/* And now that we have a repr op, we can try to optimize
* it even further. */
optimize_repr_op(tc, g, bb, ins, 1);
return;
}
+ else if (is_intify && ss->can_box & MVM_STORAGE_SPEC_CAN_BOX_INT) {
+ MVM_spesh_use_facts(tc, g, facts);
+
+ ins->info = MVM_op_get_op(MVM_OP_unbox_i);
+ /* And now that we have a repr op, we can try to optimize
+ * it even further. */
+ optimize_repr_op(tc, g, bb, ins, 1);
+
+ return;
+ }
/* We cheat a little, since we have full control over the boot
* types. XXX is it a fair DIHWIDT if the user adds stuff to those? */
if (facts->type == tc->instance->boot_types.BOOTInt
|| facts->type == tc->instance->boot_types.BOOTNum
|| facts->type == tc->instance->boot_types.BOOTStr) {
can_result = 0;
}
else {
can_result = MVM_spesh_try_can_method(tc, facts->type,
- is_strify ? tc->instance->str_consts.Str : tc->instance->str_consts.Num);
+ is_strify ? tc->instance->str_consts.Str :
+ is_intify ? tc->instance->str_consts.Int :
+ tc->instance->str_consts.Num);
}
if (can_result == -1) {
- /* Couldn't safely figure out if the type has a Str method or not. */
- MVM_spesh_graph_add_comment(tc, g, ins, "Couldn't safely determine whether %s can .Str/.Num",
+ /* Couldn't safely figure out if the type has a Str/Num/Int method or not. */
+ MVM_spesh_graph_add_comment(tc, g, ins, "Couldn't safely determine whether %s can .Str/.Num/.Int",
MVM_6model_get_debug_name(tc, facts->type));
return;
} else if (can_result == 0) {
MVM_spesh_use_facts(tc, g, facts);
/* We can't .Str this object, so we'll duplicate the "guessing"
* logic from smrt_strify here to remove indirection. */
if (is_strify && REPR(facts->type)->ID == MVM_REPR_ID_MVMException) {
MVMSpeshOperand *operands = MVM_spesh_alloc(tc, g, sizeof( MVMSpeshOperand ) * 3);
MVMSpeshOperand *old_opers = ins->operands;
MVM_spesh_graph_add_comment(tc, g, ins, "specialized from %s", ins->info->name);
ins->info = MVM_op_get_op(MVM_OP_sp_get_s);
ins->operands = operands;
operands[0] = old_opers[0];
operands[1] = old_opers[1];
operands[2].lit_i16 = offsetof( MVMException, body.message );
} else if(ss->can_box & (MVM_STORAGE_SPEC_CAN_BOX_NUM | MVM_STORAGE_SPEC_CAN_BOX_INT)) {
MVMuint16 register_type =
ss->can_box & MVM_STORAGE_SPEC_CAN_BOX_INT ? MVM_reg_int64 : MVM_reg_num64;
MVMSpeshIns *new_ins = MVM_spesh_alloc(tc, g, sizeof( MVMSpeshIns ));
MVMSpeshOperand *operands = MVM_spesh_alloc(tc, g, sizeof( MVMSpeshOperand ) * 2);
@@ -999,82 +1013,88 @@ static void optimize_smart_coerce(MVMThreadContext *tc, MVMSpeshGraph *g, MVMSpe
if (is_strify)
new_ins->info = MVM_op_get_op(register_type == MVM_reg_num64 ? MVM_OP_coerce_ns : MVM_OP_coerce_is);
else
new_ins->info = MVM_op_get_op(register_type == MVM_reg_num64 ? MVM_OP_set : MVM_OP_coerce_in);
new_ins->operands = operands;
operands[0] = ins->operands[0];
operands[1] = temp;
/* We can directly "eliminate" a set instruction here. */
if (new_ins->info->opcode != MVM_OP_set) {
ins->operands[0] = temp;
MVM_spesh_manipulate_insert_ins(tc, bb, ins, new_ins);
MVM_spesh_usages_add_by_reg(tc, g, temp, new_ins);
get_facts_direct(tc, g, temp)->writer = ins;
get_facts_direct(tc, g, operands[0])->writer = new_ins;
}
/* Finally, let's try to optimize the unboxing REPROp. */
optimize_repr_op(tc, g, bb, ins, 1);
/* And as a last clean-up step, we release the temporary register. */
MVM_spesh_manipulate_release_temp_reg(tc, g, temp);
return;
- } else if (!is_strify && (REPR(facts->type)->ID == MVM_REPR_ID_VMArray ||
+ } else if (is_numify && (REPR(facts->type)->ID == MVM_REPR_ID_VMArray ||
(REPR(facts->type)->ID == MVM_REPR_ID_MVMHash))) {
- /* A smrt_numify on an array or hash can be replaced by an
- * elems operation, that can then be optimized by our
- * versatile and dilligent friend optimize_repr_op. */
+ /* A smrt_numify or smrt_intify on an array or hash can be
+ * replaced by an elems operation, that can then be optimized
+ * by our versatile and dilligent friend optimize_repr_op. */
MVMSpeshIns *new_ins = MVM_spesh_alloc(tc, g, sizeof( MVMSpeshIns ));
MVMSpeshOperand *operands = MVM_spesh_alloc(tc, g, sizeof( MVMSpeshOperand ) * 2);
MVMSpeshOperand temp = MVM_spesh_manipulate_get_temp_reg(tc, g, MVM_reg_int64);
MVMSpeshOperand orig_dst = ins->operands[0];
-
+fprintf(stderr, "in numify branch\n");
MVM_spesh_graph_add_comment(tc, g, ins, "specialized from %s", ins->info->name);
ins->info = MVM_op_get_op(MVM_OP_elems);
ins->operands[0] = temp;
MVM_spesh_get_facts(tc, g, temp)->writer = ins;
new_ins->info = MVM_op_get_op(MVM_OP_coerce_in);
new_ins->operands = operands;
operands[0] = orig_dst;
operands[1] = temp;
MVM_spesh_get_facts(tc, g, orig_dst)->writer = new_ins;
MVM_spesh_manipulate_insert_ins(tc, bb, ins, new_ins);
optimize_repr_op(tc, g, bb, ins, 1);
MVM_spesh_usages_add_by_reg(tc, g, temp, new_ins);
MVM_spesh_manipulate_release_temp_reg(tc, g, temp);
return;
+ } else if (is_intify && (REPR(facts->type)->ID == MVM_REPR_ID_VMArray ||
+ (REPR(facts->type)->ID == MVM_REPR_ID_MVMHash))) {
+fprintf(stderr, "in intify branch\n");
+ ins->info = MVM_op_get_op(MVM_OP_elems);
+ optimize_repr_op(tc, g, bb, ins, 1);
+ return;
}
} else if (can_result == 1) {
/* When we know how to generate additional callsites, we could
* make an invocation to .Str or .Num here and perhaps have it
* in-lined. */
}
}
}
/* Optimize string equality if one param is the empty string */
static void optimize_string_equality(MVMThreadContext *tc, MVMSpeshGraph *g, MVMSpeshBB *bb, MVMSpeshIns *ins) {
MVMSpeshFacts *a_facts = MVM_spesh_get_facts(tc, g, ins->operands[1]);
MVMSpeshFacts *b_facts = MVM_spesh_get_facts(tc, g, ins->operands[2]);
MVMuint8 was_eq = 0;
return;
if (ins->info->opcode == MVM_OP_eq_s)
was_eq = 1;
if (a_facts->flags & MVM_SPESH_FACT_KNOWN_VALUE && b_facts->flags & MVM_SPESH_FACT_KNOWN_VALUE) {
/* Cool, we can constant-fold this. */
MVMSpeshFacts *target_facts = MVM_spesh_get_facts(tc, g, ins->operands[0]);
MVM_spesh_usages_delete(tc, g, a_facts, ins);
@@ -2653,50 +2673,51 @@ static void optimize_bb_switch(MVMThreadContext *tc, MVMSpeshGraph *g, MVMSpeshB
case MVM_OP_arg_s:
case MVM_OP_arg_o: {
MVMint16 idx = ins->operands[0].lit_i16;
if (idx < MAX_ARGS_FOR_OPT) {
arg_info.arg_is_const[idx] = 0;
arg_info.arg_facts[idx] = MVM_spesh_get_and_use_facts(tc, g, ins->operands[1]);
arg_info.arg_ins[idx] = ins;
}
break;
}
case MVM_OP_argconst_i:
case MVM_OP_argconst_n:
case MVM_OP_argconst_s: {
MVMint16 idx = ins->operands[0].lit_i16;
if (idx < MAX_ARGS_FOR_OPT) {
arg_info.arg_is_const[idx] = 1;
arg_info.arg_ins[idx] = ins;
}
break;
}
case MVM_OP_coerce_in:
optimize_coerce(tc, g, bb, ins);
break;
case MVM_OP_smrt_numify:
case MVM_OP_smrt_strify:
+ case MVM_OP_smrt_intify:
optimize_smart_coerce(tc, g, bb, ins);
break;
case MVM_OP_invoke_v:
optimize_call(tc, g, bb, ins, p, 0, &arg_info);
break;
case MVM_OP_invoke_i:
case MVM_OP_invoke_n:
case MVM_OP_invoke_s:
case MVM_OP_invoke_o:
optimize_call(tc, g, bb, ins, p, 1, &arg_info);
break;
case MVM_OP_getarg_i:
optimize_getarg(tc, g, bb, ins);
break;
case MVM_OP_speshresolve:
if (p) {
/* Rewriting spesh plugins will insert a bunch of instructions
* in front of the generated code, which would be skipped by
* our loop, so we skip to before the prepargs that belongs to
* it so that we run across the new instructions, too. */
MVMSpeshIns *prepargs = ins->prev;
do {
prepargs = prepargs->prev;
} while (prepargs && prepargs->info->opcode != MVM_OP_prepargs);
optimize_plugin(tc, g, bb, ins, p);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment