Beispiel #1
0
/* Looks through the handlers of a particular scope, and sees if one will
 * match what we're looking for. Returns 1 to it if so; if not,
 * returns 0. */
static MVMint32 search_frame_handlers(MVMThreadContext *tc, MVMFrame *f,
                                      MVMuint8 mode, MVMuint32 cat,
                                      MVMObject *payload, LocatedHandler *lh) {
    MVMuint32  i;
    if (f->spesh_cand && f->spesh_cand->jitcode && f->jit_entry_label) {
        MVMJitHandler    *jhs = f->spesh_cand->jitcode->handlers;
        MVMFrameHandler  *fhs = f->effective_handlers;
        MVMint32 num_handlers = f->spesh_cand->jitcode->num_handlers;
        void         **labels = f->spesh_cand->jitcode->labels;
        void       *cur_label = f->jit_entry_label;
        for (i = 0; i < num_handlers; i++) {
            if (mode == MVM_EX_THROW_LEX && fhs[i].inlined_and_not_lexical)
                continue;
            if (!handler_can_handle(f, &fhs[i], cat, payload))
                continue;
            if (cur_label >= labels[jhs[i].start_label] &&
                cur_label <= labels[jhs[i].end_label] &&
                !in_handler_stack(tc, &fhs[i], f)) {
                lh->handler     = &fhs[i];
                lh->jit_handler = &jhs[i];
                return 1;
            }
        }
    } else {
        MVMint32 num_handlers = f->spesh_cand
            ? f->spesh_cand->num_handlers
            : f->static_info->body.num_handlers;
        MVMint32 pc;
        if (f == tc->cur_frame)
            pc = (MVMuint32)(*tc->interp_cur_op - *tc->interp_bytecode_start);
        else
            pc = (MVMuint32)(f->return_address - f->effective_bytecode);
        for (i = 0; i < num_handlers; i++) {
            MVMFrameHandler  *fh = &f->effective_handlers[i];
            if (mode == MVM_EX_THROW_LEX && fh->inlined_and_not_lexical)
                continue;
            if (!handler_can_handle(f, fh, cat, payload))
                continue;
            if (pc >= fh->start_offset && pc <= fh->end_offset && !in_handler_stack(tc, fh, f)) {
                lh->handler = fh;
                return 1;
            }
        }
    }
    return 0;
}
Beispiel #2
0
/* Looks through the handlers of a particular frame, including inlines in
 * dynamic scope, and sees if one will match what we're looking for. Returns
 * 1 to it if so, and 0 if not; in the case 1 is returned the *lh will be
 * populated with details of the located handler. Since upon inlining, the
 * dynamic scope becomes lexical so far as the optimized bytecode is
 * concerned, then this just needs a scan of the table without any further
 * checks being needed. */
static MVMint32 search_frame_handlers_dyn(MVMThreadContext *tc, MVMFrame *f,
                                          MVMuint32 cat, MVMObject *payload,
                                          LocatedHandler *lh) {
    MVMuint32  i;
    if (f->spesh_cand && f->spesh_cand->jitcode && f->jit_entry_label) {
        MVMJitCode *jitcode = f->spesh_cand->jitcode;
        void *current_position = MVM_jit_code_get_current_position(tc, jitcode, f);
        MVMJitHandler    *jhs = f->spesh_cand->jitcode->handlers;
        MVMFrameHandler  *fhs = MVM_frame_effective_handlers(f);
        for (i = MVM_jit_code_get_active_handlers(tc, jitcode, current_position, 0);
             i < jitcode->num_handlers;
             i = MVM_jit_code_get_active_handlers(tc, jitcode, current_position, i+1)) {
            if (handler_can_handle(f, &fhs[i], cat, payload) &&
                !in_handler_stack(tc, &fhs[i], f)) {
                lh->handler     = &fhs[i];
                lh->jit_handler = &jhs[i];
                return 1;
            }
        }
    } else {
        MVMint32 num_handlers = f->spesh_cand
            ? f->spesh_cand->num_handlers
            : f->static_info->body.num_handlers;
        MVMint32 pc;
        if (f == tc->cur_frame)
            pc = (MVMuint32)(*tc->interp_cur_op - *tc->interp_bytecode_start);
        else
            pc = (MVMuint32)(f->return_address - MVM_frame_effective_bytecode(f));
        for (i = 0; i < num_handlers; i++) {
            MVMFrameHandler  *fh = &(MVM_frame_effective_handlers(f)[i]);
            if (!handler_can_handle(f, fh, cat, payload))
                continue;
            if (pc >= fh->start_offset && pc <= fh->end_offset && !in_handler_stack(tc, fh, f)) {
                lh->handler = fh;
                return 1;
            }
        }
    }
    return 0;
}
Beispiel #3
0
/* Looks for lexically applicable handlers in the current frame, accounting
 * for any inlines. The skip_first_inlinee flag indicates that we should skip
 * looking until we have encountered an inline boundary indicator saying that
 * we have crossed from an inlinee to its inliner's handlers; this is used to
 * handle the THROW_LEX_CALLER mode. If we never encounter an inline boundary
 * when skip_first_inlinee is true then we'll always return 0.
 *
 * If skip_first_inlinee is false or we already saw an inline boundary, then
 * we start looking for a matching handler. If one is found before seeing
 * another inline boundary, then it is applicable; the data pointed to by lh
 * will be updated with the frame handler details and 1 will be returned.
 *
 * Upon reaching an (or, in the case of skip_first_inlinee, a second) inline
 * boundary indicator, there are two cases that apply. We take the inline
 * that we are leaving, and look up the code ref using the code_ref_reg in
 * the inline. We know that we can never inline a frame that was closed over
 * (due to capturelex or takeclosure being marked :noinline). Thus, either:
 * 1. The outer of the inlinee is actually the current frame f. In this case,
 *    we skip all inlined handlers and just consider those of f itself.
 * 2. The next frame we should search in is the ->outer of the inlinee, and
 *    thus all the rest of the handlers in this frame should be ignored. In
 *    this case, the MVMFrame **next_outer will be populated with a pointer
 *    to that frame.
 *
 * The skip_all_inlinees flag is set once we are below the frame on the stack
 * to where the search started. Again, this is because a frame that did a
 * lexical capture may not be inlined, so we only need to consider the topmost
 * frame's handlers, not anything it might have inlined into it.
 */
static MVMint32 search_frame_handlers_lex(MVMThreadContext *tc, MVMFrame *f,
                                          MVMuint32 cat, MVMObject *payload,
                                          LocatedHandler *lh,
                                          MVMuint32 *skip_first_inlinee,
                                          MVMuint32 skip_all_inlinees,
                                          MVMFrame **next_outer) {
    MVMuint32 i;
    MVMuint32 skipping = *skip_first_inlinee;
    MVMFrameHandler *fhs = MVM_frame_effective_handlers(f);
    if (f->spesh_cand && f->spesh_cand->jitcode && f->jit_entry_label) {
        MVMJitCode *jitcode = f->spesh_cand->jitcode;
        void *current_position = MVM_jit_code_get_current_position(tc, jitcode, f);
        MVMJitHandler    *jhs = jitcode->handlers;
        for (i = MVM_jit_code_get_active_handlers(tc, jitcode, current_position, 0);
             i < jitcode->num_handlers;
             i = MVM_jit_code_get_active_handlers(tc, jitcode, current_position, i+1)) {
            MVMFrameHandler *fh = &(fhs[i]);
            if (skip_all_inlinees && fh->inlinee >= 0)
                continue;
            if (fh->category_mask == MVM_EX_INLINE_BOUNDARY) {
                if (skipping) {
                    skipping = 0;
                    *skip_first_inlinee = 0;
                }
                else {
                    MVMuint16 cr_reg = f->spesh_cand->inlines[fh->inlinee].code_ref_reg;
                    MVMFrame *inline_outer = ((MVMCode *)f->work[cr_reg].o)->body.outer;
                    if (inline_outer == f) {
                        skip_all_inlinees = 1;
                    }
                    else {
                        *next_outer = inline_outer;
                        return 0;
                    }
                }
            }
            if (skipping || !handler_can_handle(f, fh, cat, payload))
                continue;
            if (!in_handler_stack(tc, fh, f)) {
                if (skipping && f->static_info->body.is_thunk)
                    return 0;
                lh->handler     = fh;
                lh->jit_handler = &jhs[i];
                return 1;
            }
        }
    }
    else {
        MVMint32 num_handlers = f->spesh_cand
            ? f->spesh_cand->num_handlers
            : f->static_info->body.num_handlers;
        MVMint32 pc;
        if (f == tc->cur_frame)
            pc = (MVMuint32)(*tc->interp_cur_op - *tc->interp_bytecode_start);
        else
            pc = (MVMuint32)(f->return_address - MVM_frame_effective_bytecode(f));
        for (i = 0; i < num_handlers; i++) {
            MVMFrameHandler *fh = &(fhs[i]);
            if (skip_all_inlinees && fh->inlinee >= 0)
                continue;
            if (fh->category_mask == MVM_EX_INLINE_BOUNDARY) {
                if (pc >= fh->start_offset && pc <= fh->end_offset) {
                    if (skipping) {
                        skipping = 0;
                        *skip_first_inlinee = 0;
                    }
                    else {
                        MVMuint16 cr_reg = f->spesh_cand->inlines[fh->inlinee].code_ref_reg;
                        MVMFrame *inline_outer = ((MVMCode *)f->work[cr_reg].o)->body.outer;
                        if (inline_outer == f) {
                            skip_all_inlinees = 1;
                        }
                        else {
                            *next_outer = inline_outer;
                            return 0;
                        }
                    }
                }
                continue;
            }
            if (skipping || !handler_can_handle(f, fh, cat, payload))
                continue;
            if (pc >= fh->start_offset &&
                    pc <= fh->end_offset &&
                    !in_handler_stack(tc, fh, f)) {
                if (skipping && f->static_info->body.is_thunk)
                    return 0;
                lh->handler = fh;
                return 1;
            }
        }
    }
    return 0;
}