Ejemplo n.º 1
0
bool
TypeInferenceOracle::analyzeTypesForInlinableCallees(JSContext *cx, JSScript *script,
                                                     Vector<JSScript*> &seen)
{
    // Don't analyze scripts which will not be inlined (but always analyze the first script).
    if (seen.length() > 0 && script->getUseCount() < js_IonOptions.usesBeforeInlining())
        return true;

    for (size_t i = 0; i < seen.length(); i++) {
        if (seen[i] == script)
            return true;
    }
    if (!seen.append(script))
        return false;

    if (!script->ensureRanInference(cx))
        return false;

    ScriptAnalysis *analysis = script->analysis();
    JS_ASSERT(analysis->ranInference());

    for (jsbytecode *pc = script->code;
         pc < script->code + script->length;
         pc += GetBytecodeLength(pc))
    {
        if (!(js_CodeSpec[*pc].format & JOF_INVOKE))
            continue;

        if (!analysis->maybeCode(pc))
            continue;

        uint32_t argc = GET_ARGC(pc);

        StackTypeSet *calleeTypes = analysis->poppedTypes(pc, argc + 1);
        if (!analyzeTypesForInlinableCallees(cx, calleeTypes, seen))
            return false;

        // For foo.call() and foo.apply(), also look for any callees in the
        // 'this' types of the call, which might be inlined by Ion.
        if (*pc == JSOP_FUNCALL || *pc == JSOP_FUNAPPLY) {
            StackTypeSet *thisTypes = analysis->poppedTypes(pc, argc);
            if (!analyzeTypesForInlinableCallees(cx, thisTypes, seen))
                return false;
        }
    }

    return true;
}
Ejemplo n.º 2
0
bool
TypeInferenceOracle::getOsrTypes(jsbytecode *osrPc, Vector<MIRType> &slotTypes)
{
    JS_ASSERT(JSOp(*osrPc) == JSOP_LOOPENTRY);
    JS_ASSERT(script()->code < osrPc);
    JS_ASSERT(osrPc < script()->code + script()->length);

    Vector<types::StackTypeSet *> slotTypeSets(cx);
    if (!slotTypeSets.resize(TotalSlots(script())))
        return false;

    for (uint32_t slot = ThisSlot(); slot < TotalSlots(script()); slot++)
        slotTypeSets[slot] = TypeScript::SlotTypes(script(), slot);

    jsbytecode *pc = script()->code;
    ScriptAnalysis *analysis = script()->analysis();

    // To determine the slot types at the OSR pc, we have to do a forward walk
    // over the bytecode to reconstruct the types.
    for (;;) {
        Bytecode *opinfo = analysis->maybeCode(pc);
        if (opinfo) {
            if (opinfo->jumpTarget) {
                // Update variable types for all new values at this bytecode.
                if (const SlotValue *newv = analysis->newValues(pc)) {
                    while (newv->slot) {
                        if (newv->slot < TotalSlots(script()))
                            slotTypeSets[newv->slot] = analysis->getValueTypes(newv->value);
                        newv++;
                    }
                }
            }

            if (BytecodeUpdatesSlot(JSOp(*pc))) {
                uint32_t slot = GetBytecodeSlot(script(), pc);
                if (analysis->trackSlot(slot))
                    slotTypeSets[slot] = analysis->pushedTypes(pc, 0);
            }
        }

        if (pc == osrPc)
            break;

        pc += GetBytecodeLength(pc);
    }

    JS_ASSERT(pc == osrPc);

    // TI always includes the |this| slot, but Ion only does so for function
    // scripts. This means we have to subtract 1 for global/eval scripts.
    JS_ASSERT(ThisSlot() == 1);
    JS_ASSERT(ArgSlot(0) == 2);

#ifdef DEBUG
    uint32_t stackDepth = analysis->getCode(osrPc).stackDepth;
#endif

    if (script()->function()) {
        JS_ASSERT(slotTypes.length() == TotalSlots(script()) + stackDepth);

        for (size_t i = ThisSlot(); i < TotalSlots(script()); i++)
            slotTypes[i] = getMIRType(slotTypeSets[i]);
    } else {
        JS_ASSERT(slotTypes.length() == TotalSlots(script()) + stackDepth - 1);

        for (size_t i = ArgSlot(0); i < TotalSlots(script()); i++)
            slotTypes[i - 1] = getMIRType(slotTypeSets[i]);
    }

    return true;
}