예제 #1
0
파일: 6model.c 프로젝트: danaj/MoarVM
/* Locates a method by name. Returns the method if it exists, or throws an
 * exception if it can not be found. */
void MVM_6model_find_method(MVMThreadContext *tc, MVMObject *obj, MVMString *name, MVMRegister *res) {
    MVMObject *cache, *HOW, *find_method, *code;

    if (MVM_is_null(tc, obj))
        MVM_exception_throw_adhoc(tc,
            "Cannot call method '%s' on a null object",
             MVM_string_utf8_encode_C_string(tc, name));

    /* First try to find it in the cache. If we find it, we have a result.
     * If we don't find it, but the cache is authoritative, then error. */
    cache = STABLE(obj)->method_cache;
    if (cache && IS_CONCRETE(cache)) {
        MVMObject *meth = MVM_repr_at_key_o(tc, cache, name);
        if (!MVM_is_null(tc, meth)) {
            res->o = meth;
            return;
        }
        if (STABLE(obj)->mode_flags & MVM_METHOD_CACHE_AUTHORITATIVE) {
            MVMObject *handler = MVM_hll_current(tc)->method_not_found_error;
            if (!MVM_is_null(tc, handler)) {
                handler = MVM_frame_find_invokee(tc, handler, NULL);
                MVM_args_setup_thunk(tc, NULL, MVM_RETURN_VOID, &mnfe_callsite);
                tc->cur_frame->args[0].o = obj;
                tc->cur_frame->args[1].s = name;
                STABLE(handler)->invoke(tc, handler, &mnfe_callsite, tc->cur_frame->args);
                return;
            }
            else {
                MVM_exception_throw_adhoc(tc,
                    "Cannot find method '%s'",
                    MVM_string_utf8_encode_C_string(tc, name));
            }
        }
    }

    /* Otherwise, need to call the find_method method. We make the assumption
     * that the invocant's meta-object's type is composed. */
    HOW = STABLE(obj)->HOW;
    find_method = MVM_6model_find_method_cache_only(tc, HOW,
        tc->instance->str_consts.find_method);
    if (MVM_is_null(tc, find_method))
        MVM_exception_throw_adhoc(tc,
            "Cannot find method '%s': no method cache and no .^find_method",
             MVM_string_utf8_encode_C_string(tc, name));

    /* Set up the call, using the result register as the target. */
    code = MVM_frame_find_invokee(tc, find_method, NULL);
    MVM_args_setup_thunk(tc, res, MVM_RETURN_OBJ, &fm_callsite);
    tc->cur_frame->args[0].o = HOW;
    tc->cur_frame->args[1].o = obj;
    tc->cur_frame->args[2].s = name;
    STABLE(code)->invoke(tc, code, &fm_callsite, tc->cur_frame->args);
}
예제 #2
0
파일: 6model.c 프로젝트: MattOates/MoarVM
void MVM_6model_can_method(MVMThreadContext *tc, MVMObject *obj, MVMString *name, MVMRegister *res) {
    MVMObject *HOW, *find_method, *code;
    MVMCallsite *findmeth_callsite;

    MVMint64 can_cached = MVM_6model_can_method_cache_only(tc, obj, name);

    if (can_cached == 0 || can_cached == 1) {
        res->i64 = can_cached;
        return;
    }

    /* If no method in cache and the cache is not authoritative, need to make
     * a late-bound call to find_method. */
    HOW = MVM_6model_get_how(tc, STABLE(obj));
    find_method = MVM_6model_find_method_cache_only(tc, HOW,
        tc->instance->str_consts.find_method);
    if (MVM_is_null(tc, find_method)) {
        /* This'll count as a "no"... */
        res->i64 = 0;
        return;
    }

    /* Set up the call, using the result register as the target. A little bad
     * as we're really talking about     */
    code = MVM_frame_find_invokee(tc, find_method, NULL);
    findmeth_callsite = MVM_callsite_get_common(tc, MVM_CALLSITE_ID_FIND_METHOD);
    MVM_args_setup_thunk(tc, res, MVM_RETURN_OBJ, findmeth_callsite);
    tc->cur_frame->special_return      = late_bound_can_return;
    tc->cur_frame->special_return_data = res;
    tc->cur_frame->args[0].o = HOW;
    tc->cur_frame->args[1].o = obj;
    tc->cur_frame->args[2].s = name;
    STABLE(code)->invoke(tc, code, findmeth_callsite, tc->cur_frame->args);
}
예제 #3
0
static void code_pair_fetch_internal(MVMThreadContext *tc, MVMObject *cont, MVMRegister *res, MVMReturnType res_type) {
    CodePairContData        *data = (CodePairContData *)STABLE(cont)->container_data;
    MVMObject               *code = MVM_frame_find_invokee(tc, data->fetch_code, NULL);
    MVMCallsite *inv_arg_callsite = MVM_callsite_get_common(tc, MVM_CALLSITE_ID_INV_ARG);
    MVM_args_setup_thunk(tc, res, res_type, inv_arg_callsite);
    tc->cur_frame->args[0].o      = cont;
    STABLE(code)->invoke(tc, code, inv_arg_callsite, tc->cur_frame->args);
}
예제 #4
0
static void code_pair_store_internal(MVMThreadContext *tc, MVMObject *cont, MVMRegister value, MVMCallsite *cs) {
    CodePairContData         *data = (CodePairContData *)STABLE(cont)->container_data;
    MVMObject                *code = MVM_frame_find_invokee(tc, data->store_code, NULL);
    MVM_args_setup_thunk(tc, NULL, MVM_RETURN_VOID, cs);
    tc->cur_frame->args[0].o       = cont;
    tc->cur_frame->args[1]         = value;
    STABLE(code)->invoke(tc, code, cs, tc->cur_frame->args);
}
예제 #5
0
static void code_pair_fetch(MVMThreadContext *tc, MVMObject *cont, MVMRegister *res) {
    CodePairContData      *data   = (CodePairContData *)STABLE(cont)->container_data;
    MVMObject             *code   = MVM_frame_find_invokee(tc, data->fetch_code, NULL);

    MVM_args_setup_thunk(tc, res, MVM_RETURN_OBJ, &fetch_arg_callsite);
    tc->cur_frame->args[0].o      = cont;

    STABLE(code)->invoke(tc, code, &fetch_arg_callsite, tc->cur_frame->args);
}
예제 #6
0
파일: container.c 프로젝트: FCO/rakudo
static void rakudo_scalar_store(MVMThreadContext *tc, MVMObject *cont, MVMObject *value) {
    RakudoContData *data = (RakudoContData *)STABLE(cont)->container_data;
    MVMObject *code = MVM_frame_find_invokee(tc, data->store, NULL);
    MVMCallsite *cs = MVM_callsite_get_common(tc, MVM_CALLSITE_ID_TWO_OBJ);
    MVM_args_setup_thunk(tc, NULL, MVM_RETURN_VOID, cs);
    tc->cur_frame->args[0].o = cont;
    tc->cur_frame->args[1].o = value;
    STABLE(code)->invoke(tc, code, cs, tc->cur_frame->args);
}
예제 #7
0
static void code_pair_store(MVMThreadContext *tc, MVMObject *cont, MVMObject *obj) {
    CodePairContData      *data   = (CodePairContData *)STABLE(cont)->container_data;
    MVMObject             *code   = MVM_frame_find_invokee(tc, data->store_code, NULL);

    MVM_args_setup_thunk(tc, NULL, MVM_RETURN_VOID, &store_arg_callsite);
    tc->cur_frame->args[0].o      = cont;
    tc->cur_frame->args[1].o      = obj;

    STABLE(code)->invoke(tc, code, &store_arg_callsite, tc->cur_frame->args);
}
예제 #8
0
static void code_pair_fetch(MVMThreadContext *tc, MVMObject *cont, MVMRegister *res) {
    CodePairContData      *data   = (CodePairContData *)STABLE(cont)->container_data;
    MVMObject             *code   = MVM_frame_find_invokee(tc, data->fetch_code);

    tc->cur_frame->return_value   = res;
    tc->cur_frame->return_type    = MVM_RETURN_OBJ;
    tc->cur_frame->return_address = *(tc->interp_cur_op);
    tc->cur_frame->args[0].o      = cont;

    STABLE(code)->invoke(tc, code, &fetch_arg_callsite, tc->cur_frame->args);
}
예제 #9
0
static void run_handler(MVMThreadContext *tc, LocatedHandler lh, MVMObject *ex_obj, MVMuint32 category) {
    switch (lh.handler->action) {
    case MVM_EX_ACTION_GOTO:
        if (lh.jit_handler) {
            void **labels = lh.frame->spesh_cand->jitcode->labels;
            MVMuint8  *pc = lh.frame->spesh_cand->jitcode->bytecode;
            lh.frame->jit_entry_label = labels[lh.jit_handler->goto_label];
            MVM_frame_unwind_to(tc, lh.frame, pc, 0, NULL);
        } else {
            MVM_frame_unwind_to(tc, lh.frame, NULL, lh.handler->goto_offset, NULL);
        }
        break;

    case MVM_EX_ACTION_INVOKE: {
        /* Create active handler record. */
        MVMActiveHandler *ah = MVM_malloc(sizeof(MVMActiveHandler));
        MVMFrame *cur_frame = tc->cur_frame;
        MVMObject *handler_code;

        /* Ensure we have an exception object. */
        if (ex_obj == NULL) {
            ex_obj = MVM_repr_alloc_init(tc, tc->instance->boot_types.BOOTException);
            ((MVMException *)ex_obj)->body.category = category;
        }

        /* Find frame to invoke. */
        handler_code = MVM_frame_find_invokee(tc, lh.frame->work[lh.handler->block_reg].o, NULL);

        /* Install active handler record. */
        ah->frame           = MVM_frame_inc_ref(tc, lh.frame);
        ah->handler         = lh.handler;
        ah->jit_handler     = lh.jit_handler;
        ah->ex_obj          = ex_obj;
        ah->next_handler    = tc->active_handlers;
        tc->active_handlers = ah;

        /* Set up special return to unwinding after running the
         * handler. */
        cur_frame->return_value        = (MVMRegister *)&tc->last_handler_result;
        cur_frame->return_type         = MVM_RETURN_OBJ;
        cur_frame->special_return      = unwind_after_handler;
        cur_frame->special_unwind      = cleanup_active_handler;
        cur_frame->special_return_data = ah;

        /* Invoke the handler frame and return to runloop. */
        STABLE(handler_code)->invoke(tc, handler_code, MVM_callsite_get_common(tc, MVM_CALLSITE_ID_NULL_ARGS),
                                     cur_frame->args);
        break;
    }
    default:
        MVM_panic(1, "Unimplemented handler action");
    }
}
예제 #10
0
static void code_pair_store(MVMThreadContext *tc, MVMObject *cont, MVMObject *obj) {
    CodePairContData      *data   = (CodePairContData *)STABLE(cont)->container_data;
    MVMObject             *code   = MVM_frame_find_invokee(tc, data->store_code);

    tc->cur_frame->return_value   = NULL;
    tc->cur_frame->return_type    = MVM_RETURN_VOID;
    tc->cur_frame->return_address = *(tc->interp_cur_op);
    tc->cur_frame->args[0].o      = cont;
    tc->cur_frame->args[1].o      = obj;

    STABLE(code)->invoke(tc, code, &store_arg_callsite, tc->cur_frame->args);
}
예제 #11
0
파일: 6model.c 프로젝트: MattOates/MoarVM
void MVM_6model_find_method(MVMThreadContext *tc, MVMObject *obj, MVMString *name, MVMRegister *res) {
    MVMObject *cache, *HOW, *find_method, *code;
    MVMCallsite *findmeth_callsite;

    if (MVM_is_null(tc, obj))
        MVM_exception_throw_adhoc(tc,
            "Cannot call method '%s' on a null object",
             MVM_string_utf8_encode_C_string(tc, name));

    /* First try to find it in the cache. If we find it, we have a result.
     * If we don't find it, but the cache is authoritative, then error. */
    cache = get_method_cache(tc, STABLE(obj));
    if (cache && IS_CONCRETE(cache)) {
        MVMObject *meth = MVM_repr_at_key_o(tc, cache, name);
        if (!MVM_is_null(tc, meth)) {
            res->o = meth;
            return;
        }
        if (STABLE(obj)->mode_flags & MVM_METHOD_CACHE_AUTHORITATIVE) {
            die_over_missing_method(tc, obj, name);
            return;
        }
    }

    /* Otherwise, need to call the find_method method. We make the assumption
     * that the invocant's meta-object's type is composed. */
    HOW = MVM_6model_get_how(tc, STABLE(obj));
    find_method = MVM_6model_find_method_cache_only(tc, HOW,
        tc->instance->str_consts.find_method);
    if (MVM_is_null(tc, find_method))
        MVM_exception_throw_adhoc(tc,
            "Cannot find method '%s': no method cache and no .^find_method",
             MVM_string_utf8_encode_C_string(tc, name));

    /* Set up the call, using the result register as the target. */
    code = MVM_frame_find_invokee(tc, find_method, NULL);
    findmeth_callsite = MVM_callsite_get_common(tc, MVM_CALLSITE_ID_FIND_METHOD);
    MVM_args_setup_thunk(tc, res, MVM_RETURN_OBJ, findmeth_callsite);
    {
        FindMethodSRData *fm = MVM_malloc(sizeof(FindMethodSRData));
        fm->obj  = obj;
        fm->name = name;
        fm->res  = res;
        tc->cur_frame->special_return           = late_bound_find_method_return;
        tc->cur_frame->special_return_data      = fm;
        tc->cur_frame->mark_special_return_data = mark_find_method_sr_data;
    }
    tc->cur_frame->args[0].o = HOW;
    tc->cur_frame->args[1].o = obj;
    tc->cur_frame->args[2].s = name;
    STABLE(code)->invoke(tc, code, findmeth_callsite, tc->cur_frame->args);
}
예제 #12
0
/* Sets the passed thread context's thread up so that we'll run a finalize
 * handler on it in the near future. */
static void finalize_handler_caller(MVMThreadContext *tc, void *sr_data) {
    MVMObject *handler = MVM_hll_current(tc)->finalize_handler;
    if (handler) {
        /* Drain the finalizing queue to an array. */
        MVMObject *drain = MVM_repr_alloc_init(tc, tc->instance->boot_types.BOOTArray);
        while (tc->num_finalizing > 0)
            MVM_repr_push_o(tc, drain, tc->finalizing[--tc->num_finalizing]);

        /* Invoke the handler. */
        handler = MVM_frame_find_invokee(tc, handler, NULL);
        MVM_args_setup_thunk(tc, NULL, MVM_RETURN_VOID, MVM_callsite_get_common(tc, MVM_CALLSITE_ID_INV_ARG));
        tc->cur_frame->args[0].o = drain;
        STABLE(handler)->invoke(tc, handler, MVM_callsite_get_common(tc, MVM_CALLSITE_ID_INV_ARG), tc->cur_frame->args);
    }
}
예제 #13
0
파일: frame.c 프로젝트: mj41/MoarVM
void MVM_frame_unwind_to(MVMThreadContext *tc, MVMFrame *frame, MVMuint8 *abs_addr,
                         MVMuint32 rel_addr, MVMObject *return_value) {
    while (tc->cur_frame != frame) {
        if (tc->cur_frame->static_info->body.has_exit_handler &&
                !(tc->cur_frame->flags & MVM_FRAME_FLAG_EXIT_HAND_RUN)) {
            /* We're unwinding a frame with an exit handler. Thus we need to
             * pause the unwind, run the exit handler, and keep enough info
             * around in order to finish up the unwind afterwards. */
            MVMFrame     *caller = tc->cur_frame->caller;
            MVMHLLConfig *hll    = MVM_hll_current(tc);
            MVMObject    *handler;

            if (!caller)
                MVM_exception_throw_adhoc(tc, "Entry point frame cannot have an exit handler");
            if (tc->cur_frame == tc->thread_entry_frame)
                MVM_exception_throw_adhoc(tc, "Thread entry point frame cannot have an exit handler");

            MVM_args_setup_thunk(tc, NULL, MVM_RETURN_VOID, &exit_arg_callsite);
            tc->cur_frame->args[0].o = tc->cur_frame->code_ref;
            tc->cur_frame->args[1].o = NULL;
            tc->cur_frame->special_return = continue_unwind;
            {
                MVMUnwindData *ud = malloc(sizeof(MVMUnwindData));
                ud->frame = frame;
                ud->abs_addr = abs_addr;
                ud->rel_addr = rel_addr;
                if (return_value)
                    MVM_exception_throw_adhoc(tc, "return_value + exit_handler case NYI");
                tc->cur_frame->special_return_data = ud;
            }
            tc->cur_frame->flags |= MVM_FRAME_FLAG_EXIT_HAND_RUN;
            handler = MVM_frame_find_invokee(tc, hll->exit_handler, NULL);
            STABLE(handler)->invoke(tc, handler, &exit_arg_callsite, tc->cur_frame->args);
            return;
        }
        else {
            /* No exit handler, so just remove the frame. */
            if (!remove_one_frame(tc, 1))
                MVM_panic(1, "Internal error: Unwound entire stack and missed handler");
        }
    }
    if (abs_addr)
        *tc->interp_cur_op = abs_addr;
    else if (rel_addr)
        *tc->interp_cur_op = *tc->interp_bytecode_start + rel_addr;
    if (return_value)
        MVM_args_set_result_obj(tc, return_value, 1);
}
예제 #14
0
파일: 6model.c 프로젝트: cono/MoarVM
static void die_over_missing_method(MVMThreadContext *tc, MVMObject *obj, MVMString *name) {
    MVMObject *handler = MVM_hll_current(tc)->method_not_found_error;
    if (!MVM_is_null(tc, handler)) {
        handler = MVM_frame_find_invokee(tc, handler, NULL);
        MVM_args_setup_thunk(tc, NULL, MVM_RETURN_VOID, &mnfe_callsite);
        tc->cur_frame->args[0].o = obj;
        tc->cur_frame->args[1].s = name;
        STABLE(handler)->invoke(tc, handler, &mnfe_callsite, tc->cur_frame->args);
        return;
    }
    else {
        MVM_exception_throw_adhoc(tc,
            "Cannot find method '%s'",
            MVM_string_utf8_encode_C_string(tc, name));
    }
}
예제 #15
0
파일: frame.c 프로젝트: mj41/MoarVM
MVMuint64 MVM_frame_try_return(MVMThreadContext *tc) {
    if (tc->cur_frame->static_info->body.has_exit_handler &&
            !(tc->cur_frame->flags & MVM_FRAME_FLAG_EXIT_HAND_RUN)) {
        /* Set us up to run exit handler, and make it so we'll really exit the
         * frame when that has been done. */
        MVMFrame     *caller = tc->cur_frame->caller;
        MVMHLLConfig *hll    = MVM_hll_current(tc);
        MVMObject    *handler;
        MVMObject    *result;

        if (!caller)
            MVM_exception_throw_adhoc(tc, "Entry point frame cannot have an exit handler");
        if (tc->cur_frame == tc->thread_entry_frame)
            MVM_exception_throw_adhoc(tc, "Thread entry point frame cannot have an exit handler");

        switch (caller->return_type) {
            case MVM_RETURN_OBJ:
                result = caller->return_value->o;
                break;
            case MVM_RETURN_INT:
                result = MVM_repr_box_int(tc, hll->int_box_type, caller->return_value->i64);
                break;
            case MVM_RETURN_NUM:
                result = MVM_repr_box_num(tc, hll->num_box_type, caller->return_value->n64);
                break;
            case MVM_RETURN_STR:
                result = MVM_repr_box_str(tc, hll->str_box_type, caller->return_value->s);
                break;
            default:
                result = NULL;
        }

        MVM_args_setup_thunk(tc, NULL, MVM_RETURN_VOID, &exit_arg_callsite);
        tc->cur_frame->args[0].o = tc->cur_frame->code_ref;
        tc->cur_frame->args[1].o = result;
        tc->cur_frame->special_return = remove_after_handler;
        tc->cur_frame->flags |= MVM_FRAME_FLAG_EXIT_HAND_RUN;
        handler = MVM_frame_find_invokee(tc, hll->exit_handler, NULL);
        STABLE(handler)->invoke(tc, handler, &exit_arg_callsite, tc->cur_frame->args);
        return 1;
    }
    else {
        /* No exit handler, so a straight return. */
        return remove_one_frame(tc, 0);
    }
}
예제 #16
0
파일: coerce.c 프로젝트: krunen/MoarVM
void MVM_coerce_smart_stringify(MVMThreadContext *tc, MVMObject *obj, MVMRegister *res_reg) {
    MVMObject *strmeth;
    const MVMStorageSpec *ss;

    /* Handle null case. */
    if (MVM_is_null(tc, obj)) {
        res_reg->s = tc->instance->str_consts.empty;
        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. */
    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);
        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");
    }
}
예제 #17
0
파일: coerce.c 프로젝트: krunen/MoarVM
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. */
    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);
        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_MVMArray)
            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");
    }
}
예제 #18
0
파일: 6model.c 프로젝트: mj41/MoarVM
void MVM_6model_can_method(MVMThreadContext *tc, MVMObject *obj, MVMString *name, MVMRegister *res) {
    MVMObject *cache, *HOW, *find_method, *code;

    if (!obj)
        MVM_exception_throw_adhoc(tc,
            "Cannot look for method '%s' on a null object",
             MVM_string_utf8_encode_C_string(tc, name));

    /* First consider method cache. */
    cache = STABLE(obj)->method_cache;
    if (cache && IS_CONCRETE(cache)) {
        MVMObject *meth = MVM_repr_at_key_o(tc, cache, name);
        if (meth) {
            res->i64 = 1;
            return;
        }
        if (STABLE(obj)->mode_flags & MVM_METHOD_CACHE_AUTHORITATIVE) {
            res->i64 = 0;
            return;
        }
    }

    /* If no method in cache and the cache is not authoritative, need to make
     * a late-bound call to find_method. */
    HOW = STABLE(obj)->HOW;
    find_method = MVM_6model_find_method_cache_only(tc, HOW,
        tc->instance->str_consts.find_method);
    if (find_method == NULL) {
        /* This'll count as a "no"... */
        res->i64 = 0;
        return;
    }

    /* Set up the call, using the result register as the target. A little bad
     * as we're really talking about     */
    code = MVM_frame_find_invokee(tc, find_method, NULL);
    MVM_args_setup_thunk(tc, res, MVM_RETURN_OBJ, &fm_callsite);
    tc->cur_frame->special_return      = late_bound_can_return;
    tc->cur_frame->special_return_data = res;
    tc->cur_frame->args[0].o = HOW;
    tc->cur_frame->args[1].o = obj;
    tc->cur_frame->args[2].s = name;
    STABLE(code)->invoke(tc, code, &fm_callsite, tc->cur_frame->args);
}
예제 #19
0
파일: 6model.c 프로젝트: cono/MoarVM
/* Checks if an object has a given type, delegating to the type_check or
 * accepts_type methods as needed. */
static void do_accepts_type_check(MVMThreadContext *tc, MVMObject *obj, MVMObject *type, MVMRegister *res) {
    MVMObject *HOW = MVM_6model_get_how(tc, STABLE(type));
    MVMObject *meth = MVM_6model_find_method_cache_only(tc, HOW,
        tc->instance->str_consts.accepts_type);
    if (!MVM_is_null(tc, meth)) {
        /* Set up the call, using the result register as the target. */
        MVMObject *code = MVM_frame_find_invokee(tc, meth, NULL);
        MVM_args_setup_thunk(tc, res, MVM_RETURN_INT, &tc_callsite);
        tc->cur_frame->args[0].o = HOW;
        tc->cur_frame->args[1].o = type;
        tc->cur_frame->args[2].o = obj;
        STABLE(code)->invoke(tc, code, &tc_callsite, tc->cur_frame->args);
        return;
    }
    else {
        MVM_exception_throw_adhoc(tc,
            "Expected 'accepts_type' method, but none found in meta-object");
    }
}
예제 #20
0
static void run_handler(MVMThreadContext *tc, LocatedHandler lh, MVMObject *ex_obj) {
    switch (lh.handler->action) {
        case MVM_EX_ACTION_GOTO:
            unwind_to_frame(tc, lh.frame);
            *tc->interp_cur_op = *tc->interp_bytecode_start + lh.handler->goto_offset;
            break;
        case MVM_EX_ACTION_INVOKE: {
            /* Create active handler record. */
            MVMActiveHandler *ah = malloc(sizeof(MVMActiveHandler));
            
            /* Find frame to invoke. */
            MVMObject *handler_code = MVM_frame_find_invokee(tc,
                lh.frame->work[lh.handler->block_reg].o);
            
            /* Ensure we have an exception object. */
            /* TODO: Can make one up. */
            if (ex_obj == NULL)
                MVM_panic(1, "Exception object creation NYI");
            
            /* Install active handler record. */
            ah->frame = lh.frame;
            ah->handler = lh.handler;
            ah->ex_obj = ex_obj;
            ah->next_handler = tc->active_handlers;
            tc->active_handlers = ah;
            
            /* Set up special return to unwinding after running the
             * handler. */
            tc->cur_frame->return_value        = NULL;
            tc->cur_frame->return_type         = MVM_RETURN_VOID;
            tc->cur_frame->special_return      = unwind_after_handler;
            tc->cur_frame->special_return_data = ah;
            
            /* Inovke the handler frame and return to runloop. */
            STABLE(handler_code)->invoke(tc, handler_code, &no_arg_callsite,
                tc->cur_frame->args);
            break;
        }
        default:
            MVM_panic(1, "Unimplemented handler action");
    }
}
예제 #21
0
void MVM_coerce_smart_stringify(MVMThreadContext *tc, MVMObject *obj, MVMRegister *res_reg) {
    MVMObject *strmeth;

    /* Handle null case. */
    if (!obj) {
        res_reg->s = tc->instance->str_consts->empty;
        return;
    }

    /* Check if there is a Str method. */
    strmeth = MVM_6model_find_method_cache_only(tc, obj,
              tc->instance->str_consts->Str);
    if (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);
        tc->cur_frame->return_value   = res_reg;
        tc->cur_frame->return_type    = MVM_RETURN_STR;
        tc->cur_frame->return_address = *(tc->interp_cur_op);
        tc->cur_frame->args[0].o = obj;
        STABLE(code)->invoke(tc, code, get_inv_callsite(), tc->cur_frame->args);
        return;
    }

    /* Otherwise, guess something appropriate. */
    if (!IS_CONCRETE(obj))
        res_reg->s = tc->instance->str_consts->empty;
    else {
        MVMStorageSpec ss = REPR(obj)->get_storage_spec(tc, STABLE(obj));
        if (REPR(obj)->ID == MVM_REPR_ID_MVMString)
            res_reg->s = (MVMString *)obj;
        else if (ss.can_box & MVM_STORAGE_SPEC_CAN_BOX_STR)
            res_reg->s = REPR(obj)->box_funcs->get_str(tc, STABLE(obj), obj, OBJECT_BODY(obj));
        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");
    }
}
예제 #22
0
void MVM_continuation_reset(MVMThreadContext *tc, MVMObject *tag, 
                            MVMObject *code, MVMRegister *res_reg) {
    /* Save the tag. */
    MVMContinuationTag *tag_record = MVM_malloc(sizeof(MVMContinuationTag));
    tag_record->tag = tag;
    tag_record->active_handlers = tc->active_handlers;
    tag_record->next = tc->cur_frame->continuation_tags;
    tc->cur_frame->continuation_tags = tag_record;

    /* Were we passed code or a continuation? */
    if (REPR(code)->ID == MVM_REPR_ID_MVMContinuation) {
        /* Continuation; invoke it. */
        MVM_continuation_invoke(tc, (MVMContinuation *)code, NULL, res_reg);
    }
    else {
        /* Run the passed code. */
        MVMCallsite *null_args_callsite = MVM_callsite_get_common(tc, MVM_CALLSITE_ID_NULL_ARGS);
        code = MVM_frame_find_invokee(tc, code, NULL);
        MVM_args_setup_thunk(tc, res_reg, MVM_RETURN_OBJ, null_args_callsite);
        tc->cur_frame->special_return = clear_tag;
        tc->cur_frame->special_return_data = tag_record;
        STABLE(code)->invoke(tc, code, null_args_callsite, tc->cur_frame->args);
    }
}
예제 #23
0
파일: 6model.c 프로젝트: MattOates/MoarVM
void MVM_6model_istype(MVMThreadContext *tc, MVMObject *obj, MVMObject *type, MVMRegister *res) {
    MVMObject **cache;
    MVMSTable  *st;
    MVMint64    mode;

    /* Null never type-checks. */
    if (MVM_is_null(tc, obj)) {
        res->i64 = 0;
        return;
    }

    st    = STABLE(obj);
    mode  = STABLE(type)->mode_flags & MVM_TYPE_CHECK_CACHE_FLAG_MASK;
    cache = st->type_check_cache;
    if (cache) {
        /* We have the cache, so just look for the type object we
         * want to be in there. */
        MVMint64 elems = STABLE(obj)->type_check_cache_length;
        MVMint64 i;
        for (i = 0; i < elems; i++) {
            if (cache[i] == type) {
                res->i64 = 1;
                return;
            }
        }

        /* If the type check cache is definitive, we're done. */
        if ((mode & MVM_TYPE_CHECK_CACHE_THEN_METHOD) == 0 &&
            (mode & MVM_TYPE_CHECK_NEEDS_ACCEPTS) == 0) {
            res->i64 = 0;
            return;
        }
    }

    /* If we get here, need to call .^type_check on the value we're
     * checking, unless it's an accepts check. */
    if (!cache || (mode & MVM_TYPE_CHECK_CACHE_THEN_METHOD)) {
        MVMObject *HOW = MVM_6model_get_how(tc, st);
        MVMObject *meth = MVM_6model_find_method_cache_only(tc, HOW,
            tc->instance->str_consts.type_check);
        if (!MVM_is_null(tc, meth)) {
            /* Set up the call, using the result register as the target. */
            MVMObject *code = MVM_frame_find_invokee(tc, meth, NULL);
            MVMCallsite *typecheck_callsite = MVM_callsite_get_common(tc, MVM_CALLSITE_ID_TYPECHECK);

            MVM_args_setup_thunk(tc, res, MVM_RETURN_INT, typecheck_callsite);
            tc->cur_frame->args[0].o = HOW;
            tc->cur_frame->args[1].o = obj;
            tc->cur_frame->args[2].o = type;
            if (mode & MVM_TYPE_CHECK_NEEDS_ACCEPTS) {
                AcceptsTypeSRData *atd = MVM_malloc(sizeof(AcceptsTypeSRData));
                atd->obj = obj;
                atd->type = type;
                atd->res = res;
                tc->cur_frame->special_return           = accepts_type_sr;
                tc->cur_frame->special_return_data      = atd;
                tc->cur_frame->mark_special_return_data = mark_sr_data;
            }
            STABLE(code)->invoke(tc, code, typecheck_callsite, tc->cur_frame->args);
            return;
        }
    }

    /* If the flag to call .accepts_type on the target value is set, do so. */
    if (mode & MVM_TYPE_CHECK_NEEDS_ACCEPTS) {
        do_accepts_type_check(tc, obj, type, res);
    }
    else {
        /* If all else fails... */
        res->i64 = 0;
    }
}
예제 #24
0
static void * unmarshal_callback(MVMThreadContext *tc, MVMObject *callback, MVMObject *sig_info) {
    MVMNativeCallbackCacheHead *callback_data_head = NULL;
    MVMNativeCallback **callback_data_handle;
    MVMString          *cuid;

    if (!IS_CONCRETE(callback))
        return NULL;

    /* Try to locate existing cached callback info. */
    callback = MVM_frame_find_invokee(tc, callback, NULL);
    cuid     = ((MVMCode *)callback)->body.sf->body.cuuid;
    MVM_string_flatten(tc, cuid);
    MVM_HASH_GET(tc, tc->native_callback_cache, cuid, callback_data_head);

    if (!callback_data_head) {
        callback_data_head = MVM_malloc(sizeof(MVMNativeCallbackCacheHead));
        callback_data_head->head = NULL;

        MVM_HASH_BIND(tc, tc->native_callback_cache, cuid, callback_data_head);
    }

    callback_data_handle = &(callback_data_head->head);

    while (*callback_data_handle) {
        if ((*callback_data_handle)->target == callback) /* found it, break */
            break;

        callback_data_handle = &((*callback_data_handle)->next);
    }

    if (!*callback_data_handle) {
        /* First, build the MVMNativeCallback */
        MVMCallsite *cs;
        char        *signature;
        MVMObject   *typehash;
        MVMint64     num_info, i;
        MVMNativeCallback *callback_data;

        num_info                 = MVM_repr_elems(tc, sig_info);
        callback_data            = MVM_malloc(sizeof(MVMNativeCallback));
        callback_data->num_types = num_info;
        callback_data->typeinfos = MVM_malloc(num_info * sizeof(MVMint16));
        callback_data->types     = MVM_malloc(num_info * sizeof(MVMObject *));
        callback_data->next      = NULL;

        /* A dyncall signature looks like this: xxx)x
        * Argument types before the ) and return type after it. Thus,
        * num_info+1 must be NULL (zero-terminated string) and num_info-1
        * must be the ).
        */
        signature = MVM_malloc(num_info + 2);
        signature[num_info + 1] = '\0';
        signature[num_info - 1] = ')';

        /* We'll also build up a MoarVM callsite as we go. */
        cs                 = MVM_malloc(sizeof(MVMCallsite));
        cs->arg_flags      = MVM_malloc(num_info * sizeof(MVMCallsiteEntry));
        cs->arg_count      = num_info - 1;
        cs->num_pos        = num_info - 1;
        cs->has_flattening = 0;
        cs->is_interned    = 0;
        cs->with_invocant  = NULL;

        typehash = MVM_repr_at_pos_o(tc, sig_info, 0);
        callback_data->types[0] = MVM_repr_at_key_o(tc, typehash,
            tc->instance->str_consts.typeobj);
        callback_data->typeinfos[0] = MVM_nativecall_get_arg_type(tc, typehash, 1);
        signature[num_info] = get_signature_char(callback_data->typeinfos[0]);
        for (i = 1; i < num_info; i++) {
            typehash = MVM_repr_at_pos_o(tc, sig_info, i);
            callback_data->types[i] = MVM_repr_at_key_o(tc, typehash,
                tc->instance->str_consts.typeobj);
            callback_data->typeinfos[i] = MVM_nativecall_get_arg_type(tc, typehash, 0) & ~MVM_NATIVECALL_ARG_FREE_STR;
            signature[i - 1] = get_signature_char(callback_data->typeinfos[i]);
            switch (callback_data->typeinfos[i] & MVM_NATIVECALL_ARG_TYPE_MASK) {
                case MVM_NATIVECALL_ARG_CHAR:
                case MVM_NATIVECALL_ARG_SHORT:
                case MVM_NATIVECALL_ARG_INT:
                case MVM_NATIVECALL_ARG_LONG:
                case MVM_NATIVECALL_ARG_LONGLONG:
                    cs->arg_flags[i - 1] = MVM_CALLSITE_ARG_INT;
                    break;
                case MVM_NATIVECALL_ARG_UCHAR:
                case MVM_NATIVECALL_ARG_USHORT:
                case MVM_NATIVECALL_ARG_UINT:
                case MVM_NATIVECALL_ARG_ULONG:
                case MVM_NATIVECALL_ARG_ULONGLONG:
                    /* TODO: should probably be UINT, when we can support that. */
                    cs->arg_flags[i - 1] = MVM_CALLSITE_ARG_INT;
                    break;
                case MVM_NATIVECALL_ARG_FLOAT:
                case MVM_NATIVECALL_ARG_DOUBLE:
                    cs->arg_flags[i - 1] = MVM_CALLSITE_ARG_NUM;
                    break;
                default:
                    cs->arg_flags[i - 1] = MVM_CALLSITE_ARG_OBJ;
                    break;
            }
        }

        MVM_callsite_try_intern(tc, &cs);

        callback_data->tc        = tc;
        callback_data->cs        = cs;
        callback_data->target    = callback;
        callback_data->cb        = dcbNewCallback(signature, (DCCallbackHandler *)&callback_handler, callback_data);

        /* Now insert the MVMCallback into the linked list. */
        *callback_data_handle = callback_data;
        MVM_free(signature);
    }

    return (*callback_data_handle)->cb;
}
예제 #25
0
void MVM_coerce_istrue(MVMThreadContext *tc, MVMObject *obj, MVMRegister *res_reg,
                       MVMuint8 *true_addr, MVMuint8 *false_addr, MVMuint8 flip) {
    MVMint64 result;
    if (obj == NULL) {
        result = 0;
    }
    else {
        MVMBoolificationSpec *bs = obj->st->boolification_spec;
        switch (bs == NULL ? MVM_BOOL_MODE_NOT_TYPE_OBJECT : bs->mode) {
        case MVM_BOOL_MODE_CALL_METHOD:
            if (res_reg) {
                /* We need to do the invocation, and set this register
                 * the result. Then we just do the call. For the flip
                 * case, just set up special return handler to flip
                 * the register. */
                MVMObject *code = MVM_frame_find_invokee(tc, bs->method);
                tc->cur_frame->return_value   = res_reg;
                tc->cur_frame->return_type    = MVM_RETURN_INT;
                tc->cur_frame->return_address = *(tc->interp_cur_op);
                tc->cur_frame->args[0].o = obj;
                if (flip) {
                    tc->cur_frame->special_return      = flip_return;
                    tc->cur_frame->special_return_data = res_reg;
                }
                STABLE(code)->invoke(tc, code, get_inv_callsite(), tc->cur_frame->args);
            }
            else {
                /* Need to set up special return hook. */
                MVMObject *code = MVM_frame_find_invokee(tc, bs->method);
                BoolMethReturnData *data = malloc(sizeof(BoolMethReturnData));
                data->true_addr  = true_addr;
                data->false_addr = false_addr;
                data->flip       = flip;
                tc->cur_frame->special_return      = boolify_return;
                tc->cur_frame->special_return_data = data;
                tc->cur_frame->return_value        = &data->res_reg;
                tc->cur_frame->return_type         = MVM_RETURN_INT;
                tc->cur_frame->return_address      = *(tc->interp_cur_op);
                tc->cur_frame->args[0].o = obj;
                STABLE(code)->invoke(tc, code, get_inv_callsite(), tc->cur_frame->args);
                return;
            }
            break;
        case MVM_BOOL_MODE_UNBOX_INT:
            result = !IS_CONCRETE(obj) || REPR(obj)->box_funcs->get_int(tc, STABLE(obj), obj, OBJECT_BODY(obj)) == 0 ? 0 : 1;
            break;
        case MVM_BOOL_MODE_UNBOX_NUM:
            result = !IS_CONCRETE(obj) || REPR(obj)->box_funcs->get_num(tc, STABLE(obj), obj, OBJECT_BODY(obj)) == 0.0 ? 0 : 1;
            break;
        case MVM_BOOL_MODE_UNBOX_STR_NOT_EMPTY:
            result = !IS_CONCRETE(obj) || NUM_GRAPHS(REPR(obj)->box_funcs->get_str(tc, STABLE(obj), obj, OBJECT_BODY(obj))) == 0 ? 0 : 1;
            break;
        case MVM_BOOL_MODE_UNBOX_STR_NOT_EMPTY_OR_ZERO: {
            MVMString *str;
            if (!IS_CONCRETE(obj)) {
                result = 0;
                break;
            }
            str = REPR(obj)->box_funcs->get_str(tc, STABLE(obj), obj, OBJECT_BODY(obj));
            result = MVM_coerce_istrue_s(tc, str);
            break;
        }
        case MVM_BOOL_MODE_NOT_TYPE_OBJECT:
            result = !IS_CONCRETE(obj) ? 0 : 1;
            break;
        case MVM_BOOL_MODE_ITER:
            result = IS_CONCRETE(obj) ? MVM_iter_istrue(tc, (MVMIter *)obj) : 0;
            break;
        case MVM_BOOL_MODE_HAS_ELEMS:
            result = IS_CONCRETE(obj) ? MVM_repr_elems(tc, obj) != 0 : 0;
            break;
        default:
            MVM_exception_throw_adhoc(tc, "Invalid boolification spec mode used");
        }
    }

    if (flip)
        result = result ? 0 : 1;

    if (res_reg) {
        res_reg->i64 = result;
    }
    else {
        if (result)
            *(tc->interp_cur_op) = true_addr;
        else
            *(tc->interp_cur_op) = false_addr;
    }
}
예제 #26
0
파일: coerce.c 프로젝트: niner/MoarVM
void MVM_coerce_istrue(MVMThreadContext *tc, MVMObject *obj, MVMRegister *res_reg,
        MVMuint8 *true_addr, MVMuint8 *false_addr, MVMuint8 flip) {
    MVMint64 result = 0;
    if (!MVM_is_null(tc, obj)) {
        MVMBoolificationSpec *bs = obj->st->boolification_spec;
        switch (bs == NULL ? MVM_BOOL_MODE_NOT_TYPE_OBJECT : bs->mode) {
            case MVM_BOOL_MODE_CALL_METHOD: {
                MVMObject *code = MVM_frame_find_invokee(tc, bs->method, NULL);
                MVMCallsite *inv_arg_callsite = MVM_callsite_get_common(tc, MVM_CALLSITE_ID_INV_ARG);
                if (res_reg) {
                    /* We need to do the invocation, and set this register
                     * the result. Then we just do the call. For the flip
                     * case, just set up special return handler to flip
                     * the register. */
                    MVM_args_setup_thunk(tc, res_reg, MVM_RETURN_INT, inv_arg_callsite);
                    tc->cur_frame->args[0].o = obj;
                    if (flip) {
                        tc->cur_frame->special_return      = flip_return;
                        tc->cur_frame->special_return_data = res_reg;
                    }
                    STABLE(code)->invoke(tc, code, inv_arg_callsite, tc->cur_frame->args);
                }
                else {
                    /* Need to set up special return hook. */
                    BoolMethReturnData *data = MVM_malloc(sizeof(BoolMethReturnData));
                    data->true_addr  = true_addr;
                    data->false_addr = false_addr;
                    data->flip       = flip;
                    tc->cur_frame->special_return      = boolify_return;
                    tc->cur_frame->special_return_data = data;
                    MVM_args_setup_thunk(tc, &data->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);
                }
                return;
            }
            case MVM_BOOL_MODE_UNBOX_INT:
                result = !IS_CONCRETE(obj) || REPR(obj)->box_funcs.get_int(tc, STABLE(obj), obj, OBJECT_BODY(obj)) == 0 ? 0 : 1;
                break;
            case MVM_BOOL_MODE_UNBOX_NUM:
                result = !IS_CONCRETE(obj) || REPR(obj)->box_funcs.get_num(tc, STABLE(obj), obj, OBJECT_BODY(obj)) == 0.0 ? 0 : 1;
                break;
            case MVM_BOOL_MODE_UNBOX_STR_NOT_EMPTY: {
                MVMString *str;
                if (!IS_CONCRETE(obj)) {
                    result = 0;
                    break;
                }
                str = REPR(obj)->box_funcs.get_str(tc, STABLE(obj), obj, OBJECT_BODY(obj));
                result = MVM_coerce_istrue_s(tc, str);
                break;
            }
            case MVM_BOOL_MODE_UNBOX_STR_NOT_EMPTY_OR_ZERO: {
                MVMString *str;
                MVMint64 chars;
                if (!IS_CONCRETE(obj)) {
                    result = 0;
                    break;
                }
                str = REPR(obj)->box_funcs.get_str(tc, STABLE(obj), obj, OBJECT_BODY(obj));

                if (str == NULL || !IS_CONCRETE(str)) {
                    result = 0;
                    break;
                }

                chars = MVM_string_graphs(tc, str);

                result = chars == 0 ||
                        (chars == 1 && MVM_string_get_grapheme_at_nocheck(tc, str, 0) == 48)
                        ? 0 : 1;
                break;
            }
            case MVM_BOOL_MODE_NOT_TYPE_OBJECT:
                result = !IS_CONCRETE(obj) ? 0 : 1;
                break;
            case MVM_BOOL_MODE_BIGINT:
                result = IS_CONCRETE(obj) ? MVM_bigint_bool(tc, obj) : 0;
                break;
            case MVM_BOOL_MODE_ITER:
                result = IS_CONCRETE(obj) ? MVM_iter_istrue(tc, (MVMIter *)obj) : 0;
                break;
            case MVM_BOOL_MODE_HAS_ELEMS:
                result = IS_CONCRETE(obj) ? MVM_repr_elems(tc, obj) != 0 : 0;
                break;
            default:
                MVM_exception_throw_adhoc(tc, "Invalid boolification spec mode used");
        }
    }

    if (flip)
        result = result ? 0 : 1;

    if (res_reg) {
        res_reg->i64 = result;
    }
    else {
        if (result)
            *(tc->interp_cur_op) = true_addr;
        else
            *(tc->interp_cur_op) = false_addr;
    }
}
예제 #27
0
static void * unmarshal_callback(MVMThreadContext *tc, MVMObject *callback, MVMObject *sig_info) {
    MVMNativeCallbackCacheHead *callback_data_head = NULL;
    MVMNativeCallback **callback_data_handle;
    MVMString          *cuid;

    if (!IS_CONCRETE(callback))
        return NULL;

    /* Try to locate existing cached callback info. */
    callback = MVM_frame_find_invokee(tc, callback, NULL);
    cuid     = ((MVMCode *)callback)->body.sf->body.cuuid;
    MVM_HASH_GET(tc, tc->native_callback_cache, cuid, callback_data_head);

    if (!callback_data_head) {
        callback_data_head = MVM_malloc(sizeof(MVMNativeCallbackCacheHead));
        callback_data_head->head = NULL;

        MVM_HASH_BIND(tc, tc->native_callback_cache, cuid, callback_data_head);
    }

    callback_data_handle = &(callback_data_head->head);

    while (*callback_data_handle) {
        if ((*callback_data_handle)->target == callback) /* found it, break */
            break;

        callback_data_handle = &((*callback_data_handle)->next);
    }

    if (!*callback_data_handle) {
        /* First, build the MVMNativeCallback */
        MVMCallsite *cs;
        MVMObject   *typehash;
        MVMint64     num_info, i;
        MVMNativeCallback *callback_data;
        /* cb is a piece of executable memory we obtain from libffi. */
        void *cb;
        ffi_cif *cif;
        ffi_closure *closure;
        ffi_status status;

        num_info = MVM_repr_elems(tc, sig_info);

        /* We'll also build up a MoarVM callsite as we go. */
        cs                 = MVM_calloc(1, sizeof(MVMCallsite));
        cs->flag_count     = num_info - 1;
        cs->arg_flags      = MVM_malloc(cs->flag_count * sizeof(MVMCallsiteEntry));
        cs->arg_count      = num_info - 1;
        cs->num_pos        = num_info - 1;
        cs->has_flattening = 0;
        cs->is_interned    = 0;
        cs->with_invocant  = NULL;

        callback_data                = MVM_malloc(sizeof(MVMNativeCallback));
        callback_data->num_types     = num_info;
        callback_data->typeinfos     = MVM_malloc(num_info * sizeof(MVMint16));
        callback_data->types         = MVM_malloc(num_info * sizeof(MVMObject *));
        callback_data->next          = NULL;
        cif                          = (ffi_cif *)MVM_malloc(sizeof(ffi_cif));
        callback_data->convention    = FFI_DEFAULT_ABI;
        callback_data->ffi_arg_types = MVM_malloc(sizeof(ffi_type *) * (cs->arg_count ? cs->arg_count : 1));

        /* Collect information about the return type. */
        typehash                    = MVM_repr_at_pos_o(tc, sig_info, 0);
        callback_data->types[0]     = MVM_repr_at_key_o(tc, typehash, tc->instance->str_consts.typeobj);
        callback_data->typeinfos[0] = MVM_nativecall_get_arg_type(tc, typehash, 1);
        callback_data->ffi_ret_type = MVM_nativecall_get_ffi_type(tc, callback_data->typeinfos[0]);

        for (i = 1; i < num_info; i++) {
            typehash = MVM_repr_at_pos_o(tc, sig_info, i);
            callback_data->types[i]             = MVM_repr_at_key_o(tc, typehash, tc->instance->str_consts.typeobj);
            callback_data->typeinfos[i]         = MVM_nativecall_get_arg_type(tc, typehash, 0) & ~MVM_NATIVECALL_ARG_FREE_STR;
            callback_data->ffi_arg_types[i - 1] = MVM_nativecall_get_ffi_type(tc, callback_data->typeinfos[i]);
            switch (callback_data->typeinfos[i] & MVM_NATIVECALL_ARG_TYPE_MASK) {
                case MVM_NATIVECALL_ARG_CHAR:
                case MVM_NATIVECALL_ARG_SHORT:
                case MVM_NATIVECALL_ARG_INT:
                case MVM_NATIVECALL_ARG_LONG:
                case MVM_NATIVECALL_ARG_LONGLONG:
                    cs->arg_flags[i - 1] = MVM_CALLSITE_ARG_INT;
                    break;
                case MVM_NATIVECALL_ARG_UCHAR:
                case MVM_NATIVECALL_ARG_USHORT:
                case MVM_NATIVECALL_ARG_UINT:
                case MVM_NATIVECALL_ARG_ULONG:
                case MVM_NATIVECALL_ARG_ULONGLONG:
                    /* TODO: should probably be UINT, when we can support that. */
                    cs->arg_flags[i - 1] = MVM_CALLSITE_ARG_INT;
                    break;
                case MVM_NATIVECALL_ARG_FLOAT:
                case MVM_NATIVECALL_ARG_DOUBLE:
                    cs->arg_flags[i - 1] = MVM_CALLSITE_ARG_NUM;
                    break;
                default:
                    cs->arg_flags[i - 1] = MVM_CALLSITE_ARG_OBJ;
                    break;
            }
        }

        MVM_callsite_try_intern(tc, &cs);

        callback_data->instance  = tc->instance;
        callback_data->cs        = cs;
        callback_data->target    = callback;
        status                   = ffi_prep_cif(cif, callback_data->convention, (unsigned int)cs->arg_count,
            callback_data->ffi_ret_type, callback_data->ffi_arg_types);

        closure                  = ffi_closure_alloc(sizeof(ffi_closure), &cb);
        if (!closure)
            MVM_panic(1, "Unable to allocate memory for callback closure");
        ffi_prep_closure_loc(closure, cif, callback_handler, callback_data, cb);
        callback_data->cb        = cb;

        /* Now insert the MVMCallback into the linked list. */
        *callback_data_handle    = callback_data;
    }

    return (*callback_data_handle)->cb;
}