Ejemplo n.º 1
0
/* This callback handles starting execution of a thread. */
static void start_thread(void *data) {
    ThreadStart *ts = (ThreadStart *)data;
    MVMThreadContext *tc = ts->tc;

    /* Set the current frame in the thread to be the initial caller;
     * the ref count for this was incremented in the original thread. */
    tc->cur_frame = ts->caller;

    /* wait for the GC to finish if it's not finished stealing us. */
    MVM_gc_mark_thread_unblocked(tc);
    tc->thread_obj->body.stage = MVM_thread_stage_started;

    /* Enter the interpreter, to run code. */
    MVM_interp_run(tc, &thread_initial_invoke, ts);

    /* mark as exited, so the GC will know to clear our stuff. */
    tc->thread_obj->body.stage = MVM_thread_stage_exited;

    /* Now we're done, decrement the reference count of the caller. */
    MVM_frame_dec_ref(tc, ts->caller);

    /* Mark ourselves as dying, so that another thread will take care
     * of GC-ing our objects and cleaning up our thread context. */
    MVM_gc_mark_thread_blocked(tc);

    /* hopefully pop the ts->thread_obj temp */
    MVM_gc_root_temp_pop(tc);
    free(ts);

    /* Exit the thread, now it's completed. */
    MVM_platform_thread_exit(NULL);
}
Ejemplo n.º 2
0
/* Loads bytecode from the specified file name and runs it. */
void MVM_vm_run_file(MVMInstance *instance, const char *filename) {
    MVMStaticFrame *start_frame;

    /* Map the compilation unit into memory and dissect it. */
    MVMThreadContext *tc = instance->main_thread;
    MVMCompUnit      *cu = MVM_cu_map_from_file(tc, filename);

    cu->body.filename = MVM_string_utf8_decode(tc, instance->VMString, filename, strlen(filename));

    /* Run deserialization frame, if there is one. */
    if (cu->body.deserialize_frame) {
        MVMROOT(tc, cu, {
            MVM_interp_run(tc, &toplevel_initial_invoke, cu->body.deserialize_frame);
        });
Ejemplo n.º 3
0
/* Loads bytecode from the specified file name and runs it. */
void MVM_vm_run_file(MVMInstance *instance, const char *filename) {
    /* Map the compilation unit into memory and dissect it. */
    MVMThreadContext *tc = instance->main_thread;
    MVMCompUnit      *cu = MVM_cu_map_from_file(tc, filename);

    MVMROOT(tc, cu, {
        /* The call to MVM_string_utf8_decode() may allocate, invalidating the
           location cu->body.filename */
        MVMString *const str = MVM_string_utf8_c8_decode(tc, instance->VMString, filename, strlen(filename));
        cu->body.filename = str;

        /* Run deserialization frame, if there is one. */
        if (cu->body.deserialize_frame) {
            MVM_interp_run(tc, toplevel_initial_invoke, cu->body.deserialize_frame);
        }
    });
Ejemplo n.º 4
0
static char callback_handler(DCCallback *cb, DCArgs *cb_args, DCValue *cb_result, MVMNativeCallback *data) {
    CallbackInvokeData cid;
    MVMint32 num_roots, i;
    MVMRegister res;

    /* Build a callsite and arguments buffer. */
    MVMThreadContext *tc = data->tc;
    MVMRegister *args = MVM_malloc(data->num_types * sizeof(MVMRegister));
    num_roots = 0;
    for (i = 1; i < data->num_types; i++) {
        MVMObject *type     = data->types[i];
        MVMint16   typeinfo = data->typeinfos[i];
        switch (typeinfo & MVM_NATIVECALL_ARG_TYPE_MASK) {
            case MVM_NATIVECALL_ARG_CHAR:
                args[i - 1].i64 = dcbArgChar(cb_args);
                break;
            case MVM_NATIVECALL_ARG_SHORT:
                args[i - 1].i64 = dcbArgShort(cb_args);
                break;
            case MVM_NATIVECALL_ARG_INT:
                args[i - 1].i64 = dcbArgInt(cb_args);
                break;
            case MVM_NATIVECALL_ARG_LONG:
                args[i - 1].i64 = dcbArgLong(cb_args);
                break;
            case MVM_NATIVECALL_ARG_LONGLONG:
                args[i - 1].i64 = dcbArgLongLong(cb_args);
                break;
            case MVM_NATIVECALL_ARG_FLOAT:
                args[i - 1].n64 = dcbArgFloat(cb_args);
                break;
            case MVM_NATIVECALL_ARG_DOUBLE:
                args[i - 1].n64 = dcbArgDouble(cb_args);
                break;
            case MVM_NATIVECALL_ARG_ASCIISTR:
            case MVM_NATIVECALL_ARG_UTF8STR:
            case MVM_NATIVECALL_ARG_UTF16STR:
                args[i - 1].o = MVM_nativecall_make_str(tc, type, typeinfo,
                    (char *)dcbArgPointer(cb_args));
                MVM_gc_root_temp_push(tc, (MVMCollectable **)&(args[i - 1].o));
                num_roots++;
                break;
            case MVM_NATIVECALL_ARG_CSTRUCT:
                args[i - 1].o = MVM_nativecall_make_cstruct(tc, type,
                    dcbArgPointer(cb_args));
                MVM_gc_root_temp_push(tc, (MVMCollectable **)&(args[i - 1].o));
                num_roots++;
                break;
            case MVM_NATIVECALL_ARG_CPOINTER:
                args[i - 1].o = MVM_nativecall_make_cpointer(tc, type,
                    dcbArgPointer(cb_args));
                MVM_gc_root_temp_push(tc, (MVMCollectable **)&(args[i - 1].o));
                num_roots++;
                break;
            case MVM_NATIVECALL_ARG_CARRAY:
                args[i - 1].o = MVM_nativecall_make_carray(tc, type,
                    dcbArgPointer(cb_args));
                MVM_gc_root_temp_push(tc, (MVMCollectable **)&(args[i - 1].o));
                num_roots++;
                break;
            case MVM_NATIVECALL_ARG_CUNION:
                args[i - 1].o = MVM_nativecall_make_cunion(tc, type,
                    dcbArgPointer(cb_args));
                MVM_gc_root_temp_push(tc, (MVMCollectable **)&(args[i - 1].o));
                num_roots++;
                break;
            case MVM_NATIVECALL_ARG_CALLBACK:
                /* TODO: A callback -return- value means that we have a C method
                * that needs to be wrapped similarly to a is native(...) Perl 6
                * sub. */
                dcbArgPointer(cb_args);
                args[i - 1].o = type;
                MVM_gc_root_temp_push(tc, (MVMCollectable **)&(args[i - 1].o));
                num_roots++;
            case MVM_NATIVECALL_ARG_UCHAR:
                args[i - 1].i64 = dcbArgUChar(cb_args);
                break;
            case MVM_NATIVECALL_ARG_USHORT:
                args[i - 1].i64 = dcbArgUShort(cb_args);
                break;
            case MVM_NATIVECALL_ARG_UINT:
                args[i - 1].i64 = dcbArgUInt(cb_args);
                break;
            case MVM_NATIVECALL_ARG_ULONG:
                args[i - 1].i64 = dcbArgULong(cb_args);
                break;
            case MVM_NATIVECALL_ARG_ULONGLONG:
                args[i - 1].i64 = dcbArgULongLong(cb_args);
                break;
            default:
                MVM_exception_throw_adhoc(tc,
                    "Internal error: unhandled dyncall callback argument type");
        }
    }

    /* Call into a nested interpreter (since we already are in one). Need to
     * save a bunch of state around each side of this. */
    cid.invokee = data->target;
    cid.args    = args;
    cid.cs      = data->cs;
    {
        MVMuint8 **backup_interp_cur_op         = tc->interp_cur_op;
        MVMuint8 **backup_interp_bytecode_start = tc->interp_bytecode_start;
        MVMRegister **backup_interp_reg_base    = tc->interp_reg_base;
        MVMCompUnit **backup_interp_cu          = tc->interp_cu;
        MVMFrame *backup_cur_frame              = tc->cur_frame;
        MVMFrame *backup_thread_entry_frame     = tc->thread_entry_frame;
        MVMuint32 backup_mark                   = MVM_gc_root_temp_mark(tc);
        jmp_buf backup_interp_jump;
        memcpy(backup_interp_jump, tc->interp_jump, sizeof(jmp_buf));

        tc->cur_frame->return_value = &res;
        tc->cur_frame->return_type  = MVM_RETURN_OBJ;
        MVM_interp_run(tc, &callback_invoke, &cid);

        tc->interp_cur_op         = backup_interp_cur_op;
        tc->interp_bytecode_start = backup_interp_bytecode_start;
        tc->interp_reg_base       = backup_interp_reg_base;
        tc->interp_cu             = backup_interp_cu;
        tc->cur_frame             = backup_cur_frame;
        tc->thread_entry_frame    = backup_thread_entry_frame;
        memcpy(tc->interp_jump, backup_interp_jump, sizeof(jmp_buf));
        MVM_gc_root_temp_mark_reset(tc, backup_mark);
    }

    /* Handle return value. */
    if (res.o) {
        MVMContainerSpec const *contspec = STABLE(res.o)->container_spec;
        if (contspec && contspec->fetch_never_invokes)
            contspec->fetch(data->tc, res.o, &res);
    }
    switch (data->typeinfos[0] & MVM_NATIVECALL_ARG_TYPE_MASK) {
        case MVM_NATIVECALL_ARG_VOID:
            break;
        case MVM_NATIVECALL_ARG_CHAR:
            cb_result->c = MVM_nativecall_unmarshal_char(data->tc, res.o);
            break;
        case MVM_NATIVECALL_ARG_SHORT:
            cb_result->s = MVM_nativecall_unmarshal_short(data->tc, res.o);
            break;
        case MVM_NATIVECALL_ARG_INT:
            cb_result->i = MVM_nativecall_unmarshal_int(data->tc, res.o);
            break;
        case MVM_NATIVECALL_ARG_LONG:
            cb_result->j = MVM_nativecall_unmarshal_long(data->tc, res.o);
            break;
        case MVM_NATIVECALL_ARG_LONGLONG:
            cb_result->l = MVM_nativecall_unmarshal_longlong(data->tc, res.o);
            break;
        case MVM_NATIVECALL_ARG_FLOAT:
            cb_result->f = MVM_nativecall_unmarshal_float(data->tc, res.o);
            break;
        case MVM_NATIVECALL_ARG_DOUBLE:
            cb_result->d = MVM_nativecall_unmarshal_double(data->tc, res.o);
            break;
        case MVM_NATIVECALL_ARG_ASCIISTR:
        case MVM_NATIVECALL_ARG_UTF8STR:
        case MVM_NATIVECALL_ARG_UTF16STR:
            cb_result->Z = MVM_nativecall_unmarshal_string(data->tc, res.o, data->typeinfos[0], NULL);
            break;
        case MVM_NATIVECALL_ARG_CSTRUCT:
            cb_result->p = MVM_nativecall_unmarshal_cstruct(data->tc, res.o);
            break;
        case MVM_NATIVECALL_ARG_CPOINTER:
            cb_result->p = MVM_nativecall_unmarshal_cpointer(data->tc, res.o);
            break;
        case MVM_NATIVECALL_ARG_CARRAY:
            cb_result->p = MVM_nativecall_unmarshal_carray(data->tc, res.o);
            break;
        case MVM_NATIVECALL_ARG_CUNION:
            cb_result->p = MVM_nativecall_unmarshal_cunion(data->tc, res.o);
            break;
        case MVM_NATIVECALL_ARG_VMARRAY:
            cb_result->p = MVM_nativecall_unmarshal_vmarray(data->tc, res.o);
            break;
        case MVM_NATIVECALL_ARG_CALLBACK:
            cb_result->p = unmarshal_callback(data->tc, res.o, data->types[0]);
            break;
        case MVM_NATIVECALL_ARG_UCHAR:
            cb_result->c = MVM_nativecall_unmarshal_uchar(data->tc, res.o);
            break;
        case MVM_NATIVECALL_ARG_USHORT:
            cb_result->s = MVM_nativecall_unmarshal_ushort(data->tc, res.o);
            break;
        case MVM_NATIVECALL_ARG_UINT:
            cb_result->i = MVM_nativecall_unmarshal_uint(data->tc, res.o);
            break;
        case MVM_NATIVECALL_ARG_ULONG:
            cb_result->j = MVM_nativecall_unmarshal_ulong(data->tc, res.o);
            break;
        case MVM_NATIVECALL_ARG_ULONGLONG:
            cb_result->l = MVM_nativecall_unmarshal_ulonglong(data->tc, res.o);
            break;
        default:
            MVM_exception_throw_adhoc(data->tc,
                "Internal error: unhandled dyncall callback return type");
    }

    /* Clean up. */
    MVM_gc_root_temp_pop_n(tc, num_roots);
    MVM_free(args);

    /* Indicate what we're producing as a result. */
    return get_signature_char(data->typeinfos[0]);
}
Ejemplo n.º 5
0
static void callback_handler(ffi_cif *cif, void *cb_result, void **cb_args, void *cb_data) {
    CallbackInvokeData cid;
    MVMint32 num_roots, i;
    MVMRegister res;
    MVMRegister *args;
    MVMNativeCallback *data = (MVMNativeCallback *)cb_data;
    void           **values = MVM_malloc(sizeof(void *) * (data->cs->arg_count ? data->cs->arg_count : 1));
    unsigned int interval_id;

    /* Locate the MoarVM thread this callback is being run on. */
    MVMThreadContext *tc = MVM_nativecall_find_thread_context(data->instance);

    /* Unblock GC if needed, so this thread can do work. */
    MVMint32 was_blocked = MVM_gc_is_thread_blocked(tc);
    if (was_blocked)
        MVM_gc_mark_thread_unblocked(tc);

    interval_id = MVM_telemetry_interval_start(tc, "nativecall callback handler");

    /* Build a callsite and arguments buffer. */
    args = MVM_malloc(data->num_types * sizeof(MVMRegister));
    num_roots = 0;
    for (i = 1; i < data->num_types; i++) {
        MVMObject *type     = data->types[i];
        MVMint16   typeinfo = data->typeinfos[i];
        switch (typeinfo & MVM_NATIVECALL_ARG_TYPE_MASK) {
            case MVM_NATIVECALL_ARG_CHAR:
                args[i - 1].i64 = *(signed char *)cb_args[i - 1];
                break;
            case MVM_NATIVECALL_ARG_SHORT:
                args[i - 1].i64 = *(signed short *)cb_args[i - 1];
                break;
            case MVM_NATIVECALL_ARG_INT:
                args[i - 1].i64 = *(signed int *)cb_args[i - 1];
                break;
            case MVM_NATIVECALL_ARG_LONG:
                args[i - 1].i64 = *(signed long *)cb_args[i - 1];
                break;
            case MVM_NATIVECALL_ARG_LONGLONG:
                args[i - 1].i64 = *(signed long long *)cb_args[i - 1];
                break;
            case MVM_NATIVECALL_ARG_FLOAT:
                args[i - 1].n64 = *(float *)cb_args[i - 1];
                break;
            case MVM_NATIVECALL_ARG_DOUBLE:
                args[i - 1].n64 = *(double *)cb_args[i - 1];
                break;
            case MVM_NATIVECALL_ARG_ASCIISTR:
            case MVM_NATIVECALL_ARG_UTF8STR:
            case MVM_NATIVECALL_ARG_UTF16STR:
                args[i - 1].o = MVM_nativecall_make_str(tc, type, typeinfo, *(char **)cb_args[i - 1]);
                MVM_gc_root_temp_push(tc, (MVMCollectable **)&(args[i - 1].o));
                num_roots++;
                break;
            case MVM_NATIVECALL_ARG_CSTRUCT:
                args[i - 1].o = MVM_nativecall_make_cstruct(tc, type, *(void **)cb_args[i - 1]);
                MVM_gc_root_temp_push(tc, (MVMCollectable **)&(args[i - 1].o));
                num_roots++;
                break;
            case MVM_NATIVECALL_ARG_CPPSTRUCT:
                args[i - 1].o = MVM_nativecall_make_cppstruct(tc, type, *(void **)cb_args[i - 1]);
                MVM_gc_root_temp_push(tc, (MVMCollectable **)&(args[i - 1].o));
                num_roots++;
                break;
            case MVM_NATIVECALL_ARG_CPOINTER:
                args[i - 1].o = MVM_nativecall_make_cpointer(tc, type, *(void **)cb_args[i - 1]);
                MVM_gc_root_temp_push(tc, (MVMCollectable **)&(args[i - 1].o));
                num_roots++;
                break;
            case MVM_NATIVECALL_ARG_CARRAY:
                args[i - 1].o = MVM_nativecall_make_carray(tc, type, *(void **)cb_args[i - 1]);
                MVM_gc_root_temp_push(tc, (MVMCollectable **)&(args[i - 1].o));
                num_roots++;
                break;
            case MVM_NATIVECALL_ARG_CUNION:
                args[i - 1].o = MVM_nativecall_make_cunion(tc, type, *(void **)cb_args[i - 1]);
                MVM_gc_root_temp_push(tc, (MVMCollectable **)&(args[i - 1].o));
                num_roots++;
                break;
            case MVM_NATIVECALL_ARG_CALLBACK:
                /* TODO: A callback -return- value means that we have a C method
                * that needs to be wrapped similarly to a is native(...) Perl 6
                * sub. */
                /* XXX do something with the function pointer: *(void **)cb_args[i - 1] */
                args[i - 1].o = type;
                MVM_gc_root_temp_push(tc, (MVMCollectable **)&(args[i - 1].o));
                num_roots++;
            case MVM_NATIVECALL_ARG_UCHAR:
                args[i - 1].i64 = *(unsigned char *)cb_args[i - 1];
                break;
            case MVM_NATIVECALL_ARG_USHORT:
                args[i - 1].i64 = *(unsigned short *)cb_args[i - 1];
                break;
            case MVM_NATIVECALL_ARG_UINT:
                args[i - 1].i64 = *(unsigned int *)cb_args[i - 1];
                break;
            case MVM_NATIVECALL_ARG_ULONG:
                args[i - 1].i64 = *(unsigned long *)cb_args[i - 1];
                break;
            case MVM_NATIVECALL_ARG_ULONGLONG:
                args[i - 1].i64 = *(unsigned long long *)cb_args[i - 1];
                break;
            default:
                MVM_telemetry_interval_stop(tc, interval_id, "nativecall callback handler failed");
                MVM_exception_throw_adhoc(tc,
                    "Internal error: unhandled libffi callback argument type");
        }
    }

    /* Call into a nested interpreter (since we already are in one). Need to
     * save a bunch of state around each side of this. */
    cid.invokee = data->target;
    cid.args    = args;
    cid.cs      = data->cs;
    {
        MVMuint8 **backup_interp_cur_op         = tc->interp_cur_op;
        MVMuint8 **backup_interp_bytecode_start = tc->interp_bytecode_start;
        MVMRegister **backup_interp_reg_base    = tc->interp_reg_base;
        MVMCompUnit **backup_interp_cu          = tc->interp_cu;
        MVMFrame *backup_cur_frame              = MVM_frame_force_to_heap(tc, tc->cur_frame);
        MVMFrame *backup_thread_entry_frame     = tc->thread_entry_frame;
        void **backup_jit_return_address        = tc->jit_return_address;
        tc->jit_return_address                  = NULL;

        MVMROOT2(tc, backup_cur_frame, backup_thread_entry_frame, {
            MVMuint32 backup_mark                   = MVM_gc_root_temp_mark(tc);
            jmp_buf backup_interp_jump;
            memcpy(backup_interp_jump, tc->interp_jump, sizeof(jmp_buf));

            tc->cur_frame->return_value = &res;
            tc->cur_frame->return_type  = MVM_RETURN_OBJ;
            MVM_interp_run(tc, callback_invoke, &cid);

            tc->interp_cur_op         = backup_interp_cur_op;
            tc->interp_bytecode_start = backup_interp_bytecode_start;
            tc->interp_reg_base       = backup_interp_reg_base;
            tc->interp_cu             = backup_interp_cu;
            tc->cur_frame             = backup_cur_frame;
            tc->current_frame_nr      = backup_cur_frame->sequence_nr;
            tc->thread_entry_frame    = backup_thread_entry_frame;
            tc->jit_return_address    = backup_jit_return_address;
            memcpy(tc->interp_jump, backup_interp_jump, sizeof(jmp_buf));
            MVM_gc_root_temp_mark_reset(tc, backup_mark);
        });
    }