Exemplo n.º 1
0
JS_REQUIRES_STACK AbortableRecordingStatus
TraceRecorder::upRecursion()
{
    JS_ASSERT((JSOp)*cx->fp->down->regs->pc == JSOP_CALL);
    JS_ASSERT(js_CodeSpec[js_GetOpcode(cx, cx->fp->down->script,
              cx->fp->down->regs->pc)].length == JSOP_CALL_LENGTH);

    JS_ASSERT(callDepth == 0);

    /*
     * If some operation involving interpreter frame slurping failed, go to
     * that code right away, and don't bother with emitting the up-recursive
     * guards again.
     */
    if (anchor && (anchor->exitType == RECURSIVE_EMPTY_RP_EXIT ||
        anchor->exitType == RECURSIVE_SLURP_MISMATCH_EXIT ||
        anchor->exitType == RECURSIVE_SLURP_FAIL_EXIT)) {
        return slurpDownFrames(cx->fp->down->regs->pc);
    }

    jsbytecode* return_pc = cx->fp->down->regs->pc;
    jsbytecode* recursive_pc = return_pc + JSOP_CALL_LENGTH;

    /*
     * It is possible that the down frame isn't the same at runtime. It's not
     * enough to guard on the PC, since the typemap could be different as well.
     * To deal with this, guard that the FrameInfo on the callstack is 100%
     * identical.
     *
     * Note that though the counted slots is called "downPostSlots", this is
     * the number of slots after the CALL instruction has theoretically popped
     * callee/this/argv, but before the return value is pushed. This is
     * intended since the FrameInfo pushed by down recursion would not have
     * the return value yet. Instead, when closing the loop, the return value
     * becomes the sole stack type that deduces type stability.
     */
    unsigned totalSlots = NativeStackSlots(cx, 1);
    unsigned downPostSlots = totalSlots - NativeStackSlots(cx, 0);
    FrameInfo* fi = (FrameInfo*)alloca(sizeof(FrameInfo) + totalSlots * sizeof(TraceType));
    fi->block = NULL;
    fi->pc = (jsbytecode*)return_pc;
    fi->imacpc = NULL;

    /*
     * Need to compute this from the down frame, since the stack could have
     * moved on this one.
     */
    fi->spdist = cx->fp->down->regs->sp - cx->fp->down->slots;
    JS_ASSERT(cx->fp->argc == cx->fp->down->argc);
    fi->set_argc(cx->fp->argc, false);
    fi->callerHeight = downPostSlots;
    fi->callerArgc = cx->fp->down->argc;

    if (anchor && anchor->exitType == RECURSIVE_MISMATCH_EXIT) {
        /*
         * Case 0: Anchoring off a RECURSIVE_MISMATCH guard. Guard on this FrameInfo.
         * This is always safe because this point is only reached on simple "call myself"
         * recursive functions.
         */
        #if defined DEBUG
        AssertDownFrameIsConsistent(cx, anchor, fi);
        #endif
        fi = anchor->recursive_down;
    } else if (recursive_pc != fragment->root->ip) {
        /*
         * Case 1: Guess that down-recursion has to started back out, infer types
         * from the down frame.
         */
        CaptureStackTypes(cx, 1, fi->get_typemap());
    } else {
        /* Case 2: Guess that up-recursion is backing out, infer types from our Tree. */
        JS_ASSERT(tree->nStackTypes == downPostSlots + 1);
        TraceType* typeMap = fi->get_typemap();
        for (unsigned i = 0; i < downPostSlots; i++)
            typeMap[i] = tree->typeMap[i];
    }

    fi = traceMonitor->frameCache->memoize(fi);

    /*
     * Guard that there are more recursive frames. If coming from an anchor
     * where this was already computed, don't bother doing it again.
     */
    if (!anchor || anchor->exitType != RECURSIVE_MISMATCH_EXIT) {
        VMSideExit* exit = snapshot(RECURSIVE_EMPTY_RP_EXIT);

        /* Guard that rp >= sr + 1 */
        guard(true,
              lir->ins2(LIR_pge, lirbuf->rp,
                        lir->ins2(LIR_piadd,
                                  lir->insLoad(LIR_ldp, lirbuf->state,
                                               offsetof(InterpState, sor)),
                                  INS_CONSTWORD(sizeof(FrameInfo*)))),
              exit);
    }

    debug_only_printf(LC_TMRecorder, "guardUpRecursive fragment->root=%p fi=%p\n", (void*)fragment->root, (void*)fi);

    /* Guard that the FrameInfo above is the same FrameInfo pointer. */
    VMSideExit* exit = snapshot(RECURSIVE_MISMATCH_EXIT);
    LIns* prev_rp = lir->insLoad(LIR_ldp, lirbuf->rp, -int32_t(sizeof(FrameInfo*)));
    guard(true, lir->ins2(LIR_peq, prev_rp, INS_CONSTPTR(fi)), exit);

    /*
     * Now it's time to try and close the loop. Get a special exit that points
     * at the down frame, after the return has been propagated up.
     */
    exit = downSnapshot(fi);

    LIns* rval_ins = (!anchor || anchor->exitType != RECURSIVE_SLURP_FAIL_EXIT) ?
                     get(&stackval(-1)) :
                     NULL;
    JS_ASSERT(rval_ins != NULL);
    TraceType returnType = exit->stackTypeMap()[downPostSlots];
    if (returnType == TT_INT32) {
        JS_ASSERT(determineSlotType(&stackval(-1)) == TT_INT32);
        JS_ASSERT(isPromoteInt(rval_ins));
        rval_ins = demote(lir, rval_ins);
    }

    UpRecursiveSlotMap slotMap(*this, downPostSlots, rval_ins);
    for (unsigned i = 0; i < downPostSlots; i++)
        slotMap.addSlot(exit->stackType(i));
    slotMap.addSlot(&stackval(-1));
    VisitGlobalSlots(slotMap, cx, *tree->globalSlots);
    if (recursive_pc == (jsbytecode*)fragment->root->ip) {
        debug_only_print0(LC_TMTracer, "Compiling up-recursive loop...\n");
    } else {
        debug_only_print0(LC_TMTracer, "Compiling up-recursive branch...\n");
        exit->exitType = RECURSIVE_UNLINKED_EXIT;
        exit->recursive_pc = recursive_pc;
    }
    JS_ASSERT(tree->recursion != Recursion_Disallowed);
    if (tree->recursion != Recursion_Detected)
        tree->recursion = Recursion_Unwinds;
    return closeLoop(slotMap, exit);
}