Exemplo n.º 1
0
bool
AllocationIntegrityState::checkSafepointAllocation(LInstruction* ins,
                                                   uint32_t vreg, LAllocation alloc,
                                                   bool populateSafepoints)
{
    LSafepoint* safepoint = ins->safepoint();
    MOZ_ASSERT(safepoint);

    if (ins->isCall() && alloc.isRegister())
        return true;

    if (alloc.isRegister()) {
        AnyRegister reg = alloc.toRegister();
        if (populateSafepoints)
            safepoint->addLiveRegister(reg);

        MOZ_ASSERT(safepoint->liveRegs().has(reg));
    }

    // The |this| argument slot is implicitly included in all safepoints.
    if (alloc.isArgument() && alloc.toArgument()->index() < THIS_FRAME_ARGSLOT + sizeof(Value))
        return true;

    LDefinition::Type type = virtualRegisters[vreg]
                             ? virtualRegisters[vreg]->type()
                             : LDefinition::GENERAL;

    switch (type) {
      case LDefinition::OBJECT:
        if (populateSafepoints) {
            JitSpew(JitSpew_RegAlloc, "Safepoint object v%u i%u %s",
                    vreg, ins->id(), alloc.toString());
            if (!safepoint->addGcPointer(alloc))
                return false;
        }
        MOZ_ASSERT(safepoint->hasGcPointer(alloc));
        break;
      case LDefinition::SLOTS:
        if (populateSafepoints) {
            JitSpew(JitSpew_RegAlloc, "Safepoint slots v%u i%u %s",
                    vreg, ins->id(), alloc.toString());
            if (!safepoint->addSlotsOrElementsPointer(alloc))
                return false;
        }
        MOZ_ASSERT(safepoint->hasSlotsOrElementsPointer(alloc));
        break;
#ifdef JS_NUNBOX32
      // Do not assert that safepoint information for nunbox types is complete,
      // as if a vreg for a value's components are copied in multiple places
      // then the safepoint information may not reflect all copies. All copies
      // of payloads must be reflected, however, for generational GC.
      case LDefinition::TYPE:
        if (populateSafepoints) {
            JitSpew(JitSpew_RegAlloc, "Safepoint type v%u i%u %s",
                    vreg, ins->id(), alloc.toString());
            if (!safepoint->addNunboxType(vreg, alloc))
                return false;
        }
        break;
      case LDefinition::PAYLOAD:
        if (populateSafepoints) {
            JitSpew(JitSpew_RegAlloc, "Safepoint payload v%u i%u %s",
                    vreg, ins->id(), alloc.toString());
            if (!safepoint->addNunboxPayload(vreg, alloc))
                return false;
        }
        MOZ_ASSERT(safepoint->hasNunboxPayload(alloc));
        break;
#else
      case LDefinition::BOX:
        if (populateSafepoints) {
            JitSpew(JitSpew_RegAlloc, "Safepoint boxed value v%u i%u %s",
                    vreg, ins->id(), alloc.toString());
            if (!safepoint->addBoxedValue(alloc))
                return false;
        }
        MOZ_ASSERT(safepoint->hasBoxedValue(alloc));
        break;
#endif
      default:
        break;
    }

    return true;
}
Exemplo n.º 2
0
bool
AllocationIntegrityState::check(bool populateSafepoints)
{
    MOZ_ASSERT(!instructions.empty());

#ifdef DEBUG
    if (JitSpewEnabled(JitSpew_RegAlloc))
        dump();

    for (size_t blockIndex = 0; blockIndex < graph.numBlocks(); blockIndex++) {
        LBlock* block = graph.getBlock(blockIndex);

        // Check that all instruction inputs and outputs have been assigned an allocation.
        for (LInstructionIterator iter = block->begin(); iter != block->end(); iter++) {
            LInstruction* ins = *iter;

            for (LInstruction::InputIterator alloc(*ins); alloc.more(); alloc.next())
                MOZ_ASSERT(!alloc->isUse());

            for (size_t i = 0; i < ins->numDefs(); i++) {
                LDefinition* def = ins->getDef(i);
                MOZ_ASSERT(!def->output()->isUse());

                LDefinition oldDef = instructions[ins->id()].outputs[i];
                MOZ_ASSERT_IF(oldDef.policy() == LDefinition::MUST_REUSE_INPUT,
                              *def->output() == *ins->getOperand(oldDef.getReusedInput()));
            }

            for (size_t i = 0; i < ins->numTemps(); i++) {
                LDefinition* temp = ins->getTemp(i);
                MOZ_ASSERT_IF(!temp->isBogusTemp(), temp->output()->isRegister());

                LDefinition oldTemp = instructions[ins->id()].temps[i];
                MOZ_ASSERT_IF(oldTemp.policy() == LDefinition::MUST_REUSE_INPUT,
                              *temp->output() == *ins->getOperand(oldTemp.getReusedInput()));
            }
        }
    }
#endif

    // Check that the register assignment and move groups preserve the original
    // semantics of the virtual registers. Each virtual register has a single
    // write (owing to the SSA representation), but the allocation may move the
    // written value around between registers and memory locations along
    // different paths through the script.
    //
    // For each use of an allocation, follow the physical value which is read
    // backward through the script, along all paths to the value's virtual
    // register's definition.
    for (size_t blockIndex = 0; blockIndex < graph.numBlocks(); blockIndex++) {
        LBlock* block = graph.getBlock(blockIndex);
        for (LInstructionIterator iter = block->begin(); iter != block->end(); iter++) {
            LInstruction* ins = *iter;
            const InstructionInfo& info = instructions[ins->id()];

            LSafepoint* safepoint = ins->safepoint();
            if (safepoint) {
                for (size_t i = 0; i < ins->numTemps(); i++) {
                    if (ins->getTemp(i)->isBogusTemp())
                        continue;
                    uint32_t vreg = info.temps[i].virtualRegister();
                    LAllocation* alloc = ins->getTemp(i)->output();
                    if (!checkSafepointAllocation(ins, vreg, *alloc, populateSafepoints))
                        return false;
                }
                MOZ_ASSERT_IF(ins->isCall() && !populateSafepoints,
                              safepoint->liveRegs().emptyFloat() &&
                              safepoint->liveRegs().emptyGeneral());
            }

            size_t inputIndex = 0;
            for (LInstruction::InputIterator alloc(*ins); alloc.more(); alloc.next()) {
                LAllocation oldInput = info.inputs[inputIndex++];
                if (!oldInput.isUse())
                    continue;

                uint32_t vreg = oldInput.toUse()->virtualRegister();

                if (safepoint && !oldInput.toUse()->usedAtStart()) {
                    if (!checkSafepointAllocation(ins, vreg, **alloc, populateSafepoints))
                        return false;
                }

                // Start checking at the previous instruction, in case this
                // instruction reuses its input register for an output.
                LInstructionReverseIterator riter = block->rbegin(ins);
                riter++;
                checkIntegrity(block, *riter, vreg, **alloc, populateSafepoints);

                while (!worklist.empty()) {
                    IntegrityItem item = worklist.popCopy();
                    checkIntegrity(item.block, *item.block->rbegin(), item.vreg, item.alloc, populateSafepoints);
                }
            }
        }
    }

    return true;
}
Exemplo n.º 3
0
bool
AllocationIntegrityState::checkSafepointAllocation(LInstruction *ins,
                                                   uint32_t vreg, LAllocation alloc,
                                                   bool populateSafepoints)
{
    LSafepoint *safepoint = ins->safepoint();
    JS_ASSERT(safepoint);

    if (ins->isCall() && alloc.isRegister())
        return true;

    if (alloc.isRegister()) {
        AnyRegister reg = alloc.toRegister();
        if (populateSafepoints)
            safepoint->addLiveRegister(reg);
        JS_ASSERT(safepoint->liveRegs().has(reg));
    }

    LDefinition::Type type = virtualRegisters[vreg]
                             ? virtualRegisters[vreg]->type()
                             : LDefinition::GENERAL;

    switch (type) {
      case LDefinition::OBJECT:
        if (populateSafepoints) {
            IonSpew(IonSpew_RegAlloc, "Safepoint object v%u i%u %s",
                    vreg, ins->id(), alloc.toString());
            if (!safepoint->addGcPointer(alloc))
                return false;
        }
        JS_ASSERT(safepoint->hasGcPointer(alloc));
        break;
#ifdef JS_NUNBOX32
      // Do not assert that safepoint information for nunboxes is complete,
      // as if a vreg for a value's components are copied in multiple places
      // then the safepoint information may not reflect all copies.
      // See SafepointWriter::writeNunboxParts.
      case LDefinition::TYPE:
        if (populateSafepoints) {
            IonSpew(IonSpew_RegAlloc, "Safepoint type v%u i%u %s",
                    vreg, ins->id(), alloc.toString());
            if (!safepoint->addNunboxType(vreg, alloc))
                return false;
        }
        break;
      case LDefinition::PAYLOAD:
        if (populateSafepoints) {
            IonSpew(IonSpew_RegAlloc, "Safepoint payload v%u i%u %s",
                    vreg, ins->id(), alloc.toString());
            if (!safepoint->addNunboxPayload(vreg, alloc))
                return false;
        }
        break;
#else
      case LDefinition::BOX:
        if (populateSafepoints) {
            IonSpew(IonSpew_RegAlloc, "Safepoint boxed value v%u i%u %s",
                    vreg, ins->id(), alloc.toString());
            if (!safepoint->addBoxedValue(alloc))
                return false;
        }
        JS_ASSERT(safepoint->hasBoxedValue(alloc));
        break;
#endif
      default:
        break;
    }

    return true;
}