diff --git a/src/core/nativecall_dyncall.c b/src/core/nativecall_dyncall.c index 5290b5cca4..d3135a4019 100644 --- a/src/core/nativecall_dyncall.c +++ b/src/core/nativecall_dyncall.c @@ -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"); @@ -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"); diff --git a/src/disp/labels.h b/src/disp/labels.h index caeee28317..e118b6513e 100644 --- a/src/disp/labels.h +++ b/src/disp/labels.h @@ -41,6 +41,7 @@ static const void * const LABELS[] = { &&MVMDispOpcodeLoadAttributeStr, &&MVMDispOpcodeLoadHOW, &&MVMDispOpcodeUnboxInt, + &&MVMDispOpcodeUnboxStr, &&MVMDispOpcodeLookup, &&MVMDispOpcodeSet, &&MVMDispOpcodeResultValueObj, diff --git a/src/disp/program.c b/src/disp/program.c index bcdd2bc77b..b33c4bb948 100644 --- a/src/disp/program.c +++ b/src/disp/program.c @@ -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) { @@ -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, @@ -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); } @@ -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, diff --git a/src/disp/program.h b/src/disp/program.h index 0a091f29ff..5a36e60da8 100644 --- a/src/disp/program.h +++ b/src/disp/program.h @@ -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, @@ -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); diff --git a/src/disp/syscall.c b/src/disp/syscall.c index 0d44fee6c9..5f9f2dbcd4 100644 --- a/src/disp/syscall.c +++ b/src/disp/syscall.c @@ -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); @@ -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);