LSnapshot * LIRGeneratorShared::buildSnapshot(LInstruction *ins, MResumePoint *rp, BailoutKind kind) { LSnapshot *snapshot = LSnapshot::New(gen, rp, kind); if (!snapshot) return NULL; FlattenedMResumePointIter iter(rp); if (!iter.init()) return NULL; size_t i = 0; for (MResumePoint **it = iter.begin(), **end = iter.end(); it != end; ++it) { MResumePoint *mir = *it; for (size_t j = 0; j < mir->numOperands(); ++i, ++j) { MDefinition *def = mir->getOperand(j); if (def->isPassArg()) def = def->toPassArg()->getArgument(); LAllocation *a = snapshot->getEntry(i); if (def->isUnused()) { *a = LConstantIndex::Bogus(); continue; } *a = useKeepaliveOrConstant(def); } } return snapshot; }
LSnapshot * LIRGeneratorShared::buildSnapshot(LInstruction *ins, MResumePoint *rp, BailoutKind kind) { LRecoverInfo *recoverInfo = getRecoverInfo(rp); if (!recoverInfo) return nullptr; LSnapshot *snapshot = LSnapshot::New(gen, recoverInfo, kind); if (!snapshot) return nullptr; size_t index = 0; LRecoverInfo::OperandIter it(recoverInfo->begin()); LRecoverInfo::OperandIter end(recoverInfo->end()); for (; it != end; ++it) { // Check that optimized out operands are in eliminable slots. MOZ_ASSERT(it.canOptimizeOutIfUnused()); MDefinition *ins = *it; if (ins->isRecoveredOnBailout()) continue; LAllocation *type = snapshot->typeOfSlot(index); LAllocation *payload = snapshot->payloadOfSlot(index); ++index; if (ins->isBox()) ins = ins->toBox()->getOperand(0); // Guards should never be eliminated. MOZ_ASSERT_IF(ins->isUnused(), !ins->isGuard()); // Snapshot operands other than constants should never be // emitted-at-uses. Try-catch support depends on there being no // code between an instruction and the LOsiPoint that follows it. MOZ_ASSERT_IF(!ins->isConstant(), !ins->isEmittedAtUses()); // The register allocation will fill these fields in with actual // register/stack assignments. During code generation, we can restore // interpreter state with the given information. Note that for // constants, including known types, we record a dummy placeholder, // since we can recover the same information, much cleaner, from MIR. if (ins->isConstant() || ins->isUnused()) { *type = LConstantIndex::Bogus(); *payload = LConstantIndex::Bogus(); } else if (ins->type() != MIRType_Value) { *type = LConstantIndex::Bogus(); *payload = use(ins, LUse(LUse::KEEPALIVE)); } else { *type = useType(ins, LUse::KEEPALIVE); *payload = usePayload(ins, LUse::KEEPALIVE); } } return snapshot; }
LSnapshot * LIRGeneratorShared::buildSnapshot(LInstruction *ins, MResumePoint *rp, BailoutKind kind) { LSnapshot *snapshot = LSnapshot::New(gen, rp, kind); if (!snapshot) return NULL; FlattenedMResumePointIter iter(rp); if (!iter.init()) return NULL; size_t i = 0; for (MResumePoint **it = iter.begin(), **end = iter.end(); it != end; ++it) { MResumePoint *mir = *it; for (size_t j = 0, e = mir->numOperands(); j < e; ++i, ++j) { MDefinition *ins = mir->getOperand(j); LAllocation *type = snapshot->typeOfSlot(i); LAllocation *payload = snapshot->payloadOfSlot(i); if (ins->isPassArg()) ins = ins->toPassArg()->getArgument(); JS_ASSERT(!ins->isPassArg()); if (ins->isBox()) ins = ins->toBox()->getOperand(0); // Guards should never be eliminated. JS_ASSERT_IF(ins->isUnused(), !ins->isGuard()); // Snapshot operands other than constants should never be // emitted-at-uses. Try-catch support depends on there being no // code between an instruction and the LOsiPoint that follows it. JS_ASSERT_IF(!ins->isConstant(), !ins->isEmittedAtUses()); // The register allocation will fill these fields in with actual // register/stack assignments. During code generation, we can restore // interpreter state with the given information. Note that for // constants, including known types, we record a dummy placeholder, // since we can recover the same information, much cleaner, from MIR. if (ins->isConstant() || ins->isUnused()) { *type = LConstantIndex::Bogus(); *payload = LConstantIndex::Bogus(); } else if (ins->type() != MIRType_Value) { *type = LConstantIndex::Bogus(); *payload = use(ins, LUse::KEEPALIVE); } else { *type = useType(ins, LUse::KEEPALIVE); *payload = usePayload(ins, LUse::KEEPALIVE); } } } return snapshot; }
LSnapshot * LSnapshot::New(MIRGenerator *gen, MResumePoint *mir, BailoutKind kind) { LSnapshot *snapshot = new LSnapshot(mir, kind); if (!snapshot->init(gen)) return NULL; IonSpew(IonSpew_Snapshots, "Generating LIR snapshot %p from MIR (%p)", (void *)snapshot, (void *)mir); return snapshot; }
LSnapshot * LSnapshot::New(MIRGenerator *gen, LRecoverInfo *recover, BailoutKind kind) { LSnapshot *snapshot = new(gen->alloc()) LSnapshot(recover, kind); if (!snapshot || !snapshot->init(gen)) return nullptr; IonSpew(IonSpew_Snapshots, "Generating LIR snapshot %p from recover (%p)", (void *)snapshot, (void *)recover); return snapshot; }
LSnapshot * LIRGeneratorShared::buildSnapshot(LInstruction *ins, MResumePoint *rp, BailoutKind kind) { LRecoverInfo *recoverInfo = getRecoverInfo(rp); if (!recoverInfo) return nullptr; LSnapshot *snapshot = LSnapshot::New(gen, recoverInfo, kind); if (!snapshot) return nullptr; size_t index = 0; LRecoverInfo::OperandIter it(recoverInfo->begin()); LRecoverInfo::OperandIter end(recoverInfo->end()); for (; it != end; ++it) { // Check that optimized out operands are in eliminable slots. MOZ_ASSERT(it.canOptimizeOutIfUnused()); MDefinition *def = *it; if (def->isRecoveredOnBailout()) continue; if (def->isBox()) def = def->toBox()->getOperand(0); // Guards should never be eliminated. MOZ_ASSERT_IF(def->isUnused(), !def->isGuard()); // Snapshot operands other than constants should never be // emitted-at-uses. Try-catch support depends on there being no // code between an instruction and the LOsiPoint that follows it. MOZ_ASSERT_IF(!def->isConstant(), !def->isEmittedAtUses()); LAllocation *a = snapshot->getEntry(index++); if (def->isUnused()) { *a = LConstantIndex::Bogus(); continue; } *a = useKeepaliveOrConstant(def); } return snapshot; }
LSnapshot * LIRGeneratorShared::buildSnapshot(LInstruction *ins, MResumePoint *rp, BailoutKind kind) { LSnapshot *snapshot = LSnapshot::New(gen, rp, kind); if (!snapshot) return NULL; FlattenedMResumePointIter iter(rp); if (!iter.init()) return NULL; size_t i = 0; for (MResumePoint **it = iter.begin(), **end = iter.end(); it != end; ++it) { MResumePoint *mir = *it; for (size_t j = 0, e = mir->numOperands(); j < e; ++i, ++j) { MDefinition *def = mir->getOperand(j); if (def->isPassArg()) def = def->toPassArg()->getArgument(); JS_ASSERT(!def->isPassArg()); if (def->isBox()) def = def->toBox()->getOperand(0); // Guards should never be eliminated. JS_ASSERT_IF(def->isUnused(), !def->isGuard()); // Snapshot operands other than constants should never be // emitted-at-uses. Try-catch support depends on there being no // code between an instruction and the LOsiPoint that follows it. JS_ASSERT_IF(!def->isConstant(), !def->isEmittedAtUses()); LAllocation *a = snapshot->getEntry(i); if (def->isUnused()) { *a = LConstantIndex::Bogus(); continue; } *a = useKeepaliveOrConstant(def); } } return snapshot; }
void GreedyAllocator::informSnapshot(LInstruction *ins) { LSnapshot *snapshot = ins->snapshot(); for (size_t i = 0; i < snapshot->numEntries(); i++) { LAllocation *a = snapshot->getEntry(i); if (!a->isUse()) continue; // Every definition in a snapshot gets a stack slot. This // simplification means we can treat normal snapshots and LOsiPoint // snapshots (which follow calls) the same, without adding a special // exception to note that registers are spilled at the LOsiPoint. VirtualRegister *vr = getVirtualRegister(a->toUse()); allocateStack(vr); *a = vr->backingStack(); } }