Skip to content

Commit

Permalink
Support passing unboxed strings to native routines
Browse files Browse the repository at this point in the history
  • Loading branch information
niner committed Oct 17, 2021
1 parent ca182dd commit eed60cc
Show file tree
Hide file tree
Showing 5 changed files with 118 additions and 0 deletions.
38 changes: 38 additions & 0 deletions src/core/nativecall_dyncall.c
Expand Up @@ -990,6 +990,12 @@ MVMObject * MVM_nativecall_dispatch(MVMThreadContext *tc, MVMObject *res_type,
case MVM_NATIVECALL_ARG_CPOINTER:
dcArgPointer(vm, (void*)value);
break;
/* for undefined strings we'll get a literal 0 */
case MVM_NATIVECALL_ARG_ASCIISTR:
case MVM_NATIVECALL_ARG_UTF8STR:
case MVM_NATIVECALL_ARG_UTF16STR:
dcArgPointer(vm, (void*)value);
break;
default:
MVM_telemetry_interval_stop(tc, interval_id, "nativecall invoke failed");
MVM_exception_throw_adhoc(tc, "Internal error: unhandled dyncall argument type");
Expand All @@ -1009,6 +1015,38 @@ MVMObject * MVM_nativecall_dispatch(MVMThreadContext *tc, MVMObject *res_type,
MVM_exception_throw_adhoc(tc, "Internal error: unhandled dyncall argument type");
}
}
else if (args.callsite->arg_flags[i + 1] & MVM_CALLSITE_ARG_STR) {
MVMString *value = args.source[args.map[i + 1]].s;
switch (arg_types[i] & MVM_NATIVECALL_ARG_TYPE_MASK) {
case MVM_NATIVECALL_ARG_ASCIISTR:
case MVM_NATIVECALL_ARG_UTF8STR:
case MVM_NATIVECALL_ARG_UTF16STR:
{
char *str;
switch (arg_types[i] & MVM_NATIVECALL_ARG_TYPE_MASK) {
case MVM_NATIVECALL_ARG_ASCIISTR:
str = MVM_string_ascii_encode_any(tc, value);
break;
case MVM_NATIVECALL_ARG_UTF16STR:
str = MVM_string_utf16_encode(tc, value, 0);
break;
default:
str = MVM_string_utf8_encode_C_string(tc, value);
}
if (arg_types[i] & MVM_NATIVECALL_ARG_FREE_STR_MASK) {
if (!free_strs)
free_strs = (char**)MVM_malloc(num_args * sizeof(char *));
free_strs[num_strs] = str;
num_strs++;
}
dcArgPointer(vm, str);
}
break;
default:
MVM_telemetry_interval_stop(tc, interval_id, "nativecall invoke failed");
MVM_oops(tc, "Internal error: unhandled dyncall argument type for str %d", arg_types[i] & MVM_NATIVECALL_ARG_TYPE_MASK);
}
}
else {
MVM_telemetry_interval_stop(tc, interval_id, "nativecall invoke failed");
MVM_exception_throw_adhoc(tc, "Internal error: unhandled dyncall argument type");
Expand Down
1 change: 1 addition & 0 deletions src/disp/labels.h
Expand Up @@ -41,6 +41,7 @@ static const void * const LABELS[] = {
&&MVMDispOpcodeLoadAttributeStr,
&&MVMDispOpcodeLoadHOW,
&&MVMDispOpcodeUnboxInt,
&&MVMDispOpcodeUnboxStr,
&&MVMDispOpcodeLookup,
&&MVMDispOpcodeSet,
&&MVMDispOpcodeResultValueObj,
Expand Down
59 changes: 59 additions & 0 deletions src/disp/program.c
Expand Up @@ -847,6 +847,28 @@ static MVMuint32 value_index_unbox_int(MVMThreadContext *tc, MVMDispProgramRecor
return MVM_VECTOR_ELEMS(rec->values) - 1;
}

/* Ensures we have a values used entry for the specified unboxed str. */
static MVMuint32 value_index_unbox_str(MVMThreadContext *tc, MVMDispProgramRecording *rec,
MVMuint32 from_value) {
/* Look for an existing such value. */
MVMuint32 i;
for (i = 0; i < MVM_VECTOR_ELEMS(rec->values); i++) {
MVMDispProgramRecordingValue *v = &(rec->values[i]);
if (v->source == MVMDispProgramRecordingUnboxValue &&
v->how.from_value == from_value)
return i;
}

/* Otherwise, we need to create the value entry. */
MVMDispProgramRecordingValue new_value;
memset(&new_value, 0, sizeof(MVMDispProgramRecordingValue));
new_value.source = MVMDispProgramRecordingUnboxValue;
new_value.unbox.from_value = from_value;
new_value.unbox.kind = MVM_CALLSITE_ARG_STR;
MVM_VECTOR_PUSH(rec->values, new_value);
return MVM_VECTOR_ELEMS(rec->values) - 1;
}

/* Ensures we have a values used entry for the specified lookup table read. */
static MVMuint32 value_index_lookup(MVMThreadContext *tc, MVMDispProgramRecording *rec,
MVMuint32 lookup_index, MVMuint32 key_index) {
Expand Down Expand Up @@ -1070,6 +1092,36 @@ MVMObject * MVM_disp_program_record_track_unbox_int(MVMThreadContext *tc, MVMObj
return record->rec.values[result_value_index].tracked;
}

MVMObject * MVM_disp_program_record_track_unbox_str(MVMThreadContext *tc, MVMObject *tracked_in) {
/* Ensure the tracked value is an object type. */
if (((MVMTracked *)tracked_in)->body.kind != MVM_CALLSITE_ARG_OBJ)
MVM_oops(tc, "Can only use dispatcher-track-unbox-str on a tracked object");

/* Resolve the tracked value. */
MVMCallStackDispatchRecord *record = MVM_callstack_find_topmost_dispatch_recording(tc);
MVMuint32 value_index = find_tracked_value_index(tc, &(record->rec), tracked_in);

/* Obtain the object and ensure it is a concrete P6opaque; also track its
* type and concreteness since unboxing safety depends on this. */
MVMObject *read_from = ((MVMTracked *)tracked_in)->body.value.o;
if (!IS_CONCRETE(read_from))
MVM_exception_throw_adhoc(tc, "Can only use dispatcher-track-unbox-str on a concrete object");
record->rec.values[value_index].guard_type = 1;
record->rec.values[value_index].guard_concreteness = 1;

/* Read the value. */
MVMRegister attr_value;
attr_value.s = MVM_repr_get_str(tc, read_from);

/* Ensure that we have this value read in the values table, and make
* a tracked object if not. */
MVMuint32 result_value_index = value_index_unbox_str(tc, &(record->rec), value_index);
if (!record->rec.values[result_value_index].tracked)
record->rec.values[result_value_index].tracked = MVM_tracked_create(tc,
attr_value, MVM_CALLSITE_ARG_STR);
return record->rec.values[result_value_index].tracked;
}

/* Start tracking the HOW of the input tracked object. This does not guard on
* the type of the incoming tracked object, otherwise we'd not need this at
* all (since that behavior can be obtained by doing a guard, calling .HOW,
Expand Down Expand Up @@ -1983,6 +2035,9 @@ static MVMuint32 get_temp_holding_value(MVMThreadContext *tc, compile_state *cs,
case MVM_CALLSITE_ARG_INT:
op.code = MVMDispOpcodeUnboxInt;
break;
case MVM_CALLSITE_ARG_STR:
op.code = MVMDispOpcodeUnboxStr;
break;
default:
MVM_oops(tc, "Unhandled kind of unbox in recorded dispatch: %d", v->attribute.kind);
}
Expand Down Expand Up @@ -3234,6 +3289,10 @@ MVMint64 MVM_disp_program_run(MVMThreadContext *tc, MVMDispProgram *dp,
record->temps[op.load.temp].i64 = MVM_repr_get_int(tc, record->temps[op.load.idx].o);
NEXT;
}
OP(MVMDispOpcodeUnboxStr): {
record->temps[op.load.temp].s = MVM_repr_get_str(tc, record->temps[op.load.idx].o);
NEXT;
}
OP(MVMDispOpcodeLookup):
record->temps[op.load.temp].o = MVM_repr_at_key_o(tc,
record->temps[op.load.temp].o,
Expand Down
3 changes: 3 additions & 0 deletions src/disp/program.h
Expand Up @@ -459,6 +459,8 @@ typedef enum {
MVMDispOpcodeLoadHOW,
/* Unbox an int from an object into a temporary. */
MVMDispOpcodeUnboxInt,
/* Unbox a str from an object into a temporary. */
MVMDispOpcodeUnboxStr,
/* Do a lookup in a hash table and put the result into a temporary if it is
* found. */
MVMDispOpcodeLookup,
Expand Down Expand Up @@ -626,6 +628,7 @@ MVMObject * MVM_disp_program_record_track_arg(MVMThreadContext *tc, MVMObject *c
MVMObject * MVM_disp_program_record_track_attr(MVMThreadContext *tc, MVMObject *tracked,
MVMObject *class_handle, MVMString *name);
MVMObject * MVM_disp_program_record_track_unbox_int(MVMThreadContext *tc, MVMObject *tracked);
MVMObject * MVM_disp_program_record_track_unbox_str(MVMThreadContext *tc, MVMObject *tracked);
MVMObject * MVM_disp_program_record_track_how(MVMThreadContext *tc, MVMObject *tracked);
void MVM_disp_program_record_guard_type(MVMThreadContext *tc, MVMObject *tracked);
void MVM_disp_program_record_guard_concreteness(MVMThreadContext *tc, MVMObject *tracked);
Expand Down
17 changes: 17 additions & 0 deletions src/disp/syscall.c
Expand Up @@ -97,6 +97,22 @@ static MVMDispSysCall dispatcher_track_unbox_int = {
.expected_concrete = { 1 }
};

/* dispatcher-track-unbox-str */
static void dispatcher_track_unbox_str_impl(MVMThreadContext *tc, MVMArgs arg_info) {
MVMObject *tracked_in = get_obj_arg(arg_info, 0);
MVMObject *tracked_out = MVM_disp_program_record_track_unbox_str(tc, tracked_in);
MVM_args_set_result_obj(tc, tracked_out, MVM_RETURN_CURRENT_FRAME);
}
static MVMDispSysCall dispatcher_track_unbox_str = {
.c_name = "dispatcher-track-unbox-str",
.implementation = dispatcher_track_unbox_str_impl,
.min_args = 1,
.max_args = 1,
.expected_kinds = { MVM_CALLSITE_ARG_OBJ },
.expected_reprs = { MVM_REPR_ID_MVMTracked },
.expected_concrete = { 1 }
};

/* dispatcher-track-how */
static void dispatcher_track_how_impl(MVMThreadContext *tc, MVMArgs arg_info) {
MVMObject *tracked_in = get_obj_arg(arg_info, 0);
Expand Down Expand Up @@ -1121,6 +1137,7 @@ void MVM_disp_syscall_setup(MVMThreadContext *tc) {
add_to_hash(tc, &dispatcher_track_arg);
add_to_hash(tc, &dispatcher_track_attr);
add_to_hash(tc, &dispatcher_track_unbox_int);
add_to_hash(tc, &dispatcher_track_unbox_str);
add_to_hash(tc, &dispatcher_track_how);
add_to_hash(tc, &dispatcher_drop_arg);
add_to_hash(tc, &dispatcher_drop_n_args);
Expand Down

0 comments on commit eed60cc

Please sign in to comment.