michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- michael@0: * vim: set ts=8 sts=4 et sw=4 tw=99: michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "jit/shared/Lowering-shared-inl.h" michael@0: michael@0: #include "jit/LIR.h" michael@0: #include "jit/MIR.h" michael@0: michael@0: using namespace js; michael@0: using namespace jit; michael@0: michael@0: bool michael@0: LIRGeneratorShared::visitConstant(MConstant *ins) michael@0: { michael@0: const Value &v = ins->value(); michael@0: switch (ins->type()) { michael@0: case MIRType_Boolean: michael@0: return define(new(alloc()) LInteger(v.toBoolean()), ins); michael@0: case MIRType_Int32: michael@0: return define(new(alloc()) LInteger(v.toInt32()), ins); michael@0: case MIRType_String: michael@0: return define(new(alloc()) LPointer(v.toString()), ins); michael@0: case MIRType_Object: michael@0: return define(new(alloc()) LPointer(&v.toObject()), ins); michael@0: default: michael@0: // Constants of special types (undefined, null) should never flow into michael@0: // here directly. Operations blindly consuming them require a Box. michael@0: JS_ASSERT(!"unexpected constant type"); michael@0: return false; michael@0: } michael@0: } michael@0: michael@0: bool michael@0: LIRGeneratorShared::defineTypedPhi(MPhi *phi, size_t lirIndex) michael@0: { michael@0: LPhi *lir = current->getPhi(lirIndex); michael@0: michael@0: uint32_t vreg = getVirtualRegister(); michael@0: if (vreg >= MAX_VIRTUAL_REGISTERS) michael@0: return false; michael@0: michael@0: phi->setVirtualRegister(vreg); michael@0: lir->setDef(0, LDefinition(vreg, LDefinition::TypeFrom(phi->type()))); michael@0: annotate(lir); michael@0: return true; michael@0: } michael@0: michael@0: void michael@0: LIRGeneratorShared::lowerTypedPhiInput(MPhi *phi, uint32_t inputPosition, LBlock *block, size_t lirIndex) michael@0: { michael@0: MDefinition *operand = phi->getOperand(inputPosition); michael@0: LPhi *lir = block->getPhi(lirIndex); michael@0: lir->setOperand(inputPosition, LUse(operand->virtualRegister(), LUse::ANY)); michael@0: } michael@0: michael@0: LRecoverInfo * michael@0: LIRGeneratorShared::getRecoverInfo(MResumePoint *rp) michael@0: { michael@0: if (cachedRecoverInfo_ && cachedRecoverInfo_->mir() == rp) michael@0: return cachedRecoverInfo_; michael@0: michael@0: LRecoverInfo *recoverInfo = LRecoverInfo::New(gen, rp); michael@0: if (!recoverInfo) michael@0: return nullptr; michael@0: michael@0: cachedRecoverInfo_ = recoverInfo; michael@0: return recoverInfo; michael@0: } michael@0: michael@0: #ifdef JS_NUNBOX32 michael@0: LSnapshot * michael@0: LIRGeneratorShared::buildSnapshot(LInstruction *ins, MResumePoint *rp, BailoutKind kind) michael@0: { michael@0: LRecoverInfo *recover = getRecoverInfo(rp); michael@0: if (!recover) michael@0: return nullptr; michael@0: michael@0: LSnapshot *snapshot = LSnapshot::New(gen, recover, kind); michael@0: if (!snapshot) michael@0: return nullptr; michael@0: michael@0: size_t i = 0; michael@0: for (MResumePoint **it = recover->begin(), **end = recover->end(); it != end; ++it) { michael@0: MResumePoint *mir = *it; michael@0: for (size_t j = 0, e = mir->numOperands(); j < e; ++i, ++j) { michael@0: MDefinition *ins = mir->getOperand(j); michael@0: michael@0: LAllocation *type = snapshot->typeOfSlot(i); michael@0: LAllocation *payload = snapshot->payloadOfSlot(i); michael@0: michael@0: if (ins->isBox()) michael@0: ins = ins->toBox()->getOperand(0); michael@0: michael@0: // Guards should never be eliminated. michael@0: JS_ASSERT_IF(ins->isUnused(), !ins->isGuard()); michael@0: michael@0: // Snapshot operands other than constants should never be michael@0: // emitted-at-uses. Try-catch support depends on there being no michael@0: // code between an instruction and the LOsiPoint that follows it. michael@0: JS_ASSERT_IF(!ins->isConstant(), !ins->isEmittedAtUses()); michael@0: michael@0: // The register allocation will fill these fields in with actual michael@0: // register/stack assignments. During code generation, we can restore michael@0: // interpreter state with the given information. Note that for michael@0: // constants, including known types, we record a dummy placeholder, michael@0: // since we can recover the same information, much cleaner, from MIR. michael@0: if (ins->isConstant() || ins->isUnused()) { michael@0: *type = LConstantIndex::Bogus(); michael@0: *payload = LConstantIndex::Bogus(); michael@0: } else if (ins->type() != MIRType_Value) { michael@0: *type = LConstantIndex::Bogus(); michael@0: *payload = use(ins, LUse::KEEPALIVE); michael@0: } else { michael@0: *type = useType(ins, LUse::KEEPALIVE); michael@0: *payload = usePayload(ins, LUse::KEEPALIVE); michael@0: } michael@0: } michael@0: } michael@0: michael@0: return snapshot; michael@0: } michael@0: michael@0: #elif JS_PUNBOX64 michael@0: michael@0: LSnapshot * michael@0: LIRGeneratorShared::buildSnapshot(LInstruction *ins, MResumePoint *rp, BailoutKind kind) michael@0: { michael@0: LRecoverInfo *recover = getRecoverInfo(rp); michael@0: if (!recover) michael@0: return nullptr; michael@0: michael@0: LSnapshot *snapshot = LSnapshot::New(gen, recover, kind); michael@0: if (!snapshot) michael@0: return nullptr; michael@0: michael@0: size_t i = 0; michael@0: for (MResumePoint **it = recover->begin(), **end = recover->end(); it != end; ++it) { michael@0: MResumePoint *mir = *it; michael@0: for (size_t j = 0, e = mir->numOperands(); j < e; ++i, ++j) { michael@0: MDefinition *def = mir->getOperand(j); michael@0: michael@0: if (def->isBox()) michael@0: def = def->toBox()->getOperand(0); michael@0: michael@0: // Guards should never be eliminated. michael@0: JS_ASSERT_IF(def->isUnused(), !def->isGuard()); michael@0: michael@0: // Snapshot operands other than constants should never be michael@0: // emitted-at-uses. Try-catch support depends on there being no michael@0: // code between an instruction and the LOsiPoint that follows it. michael@0: JS_ASSERT_IF(!def->isConstant(), !def->isEmittedAtUses()); michael@0: michael@0: LAllocation *a = snapshot->getEntry(i); michael@0: michael@0: if (def->isUnused()) { michael@0: *a = LConstantIndex::Bogus(); michael@0: continue; michael@0: } michael@0: michael@0: *a = useKeepaliveOrConstant(def); michael@0: } michael@0: } michael@0: michael@0: return snapshot; michael@0: } michael@0: #endif michael@0: michael@0: bool michael@0: LIRGeneratorShared::assignSnapshot(LInstruction *ins, BailoutKind kind) michael@0: { michael@0: // assignSnapshot must be called before define/add, since michael@0: // it may add new instructions for emitted-at-use operands. michael@0: JS_ASSERT(ins->id() == 0); michael@0: michael@0: LSnapshot *snapshot = buildSnapshot(ins, lastResumePoint_, kind); michael@0: if (!snapshot) michael@0: return false; michael@0: michael@0: ins->assignSnapshot(snapshot); michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: LIRGeneratorShared::assignSafepoint(LInstruction *ins, MInstruction *mir) michael@0: { michael@0: JS_ASSERT(!osiPoint_); michael@0: JS_ASSERT(!ins->safepoint()); michael@0: michael@0: ins->initSafepoint(alloc()); michael@0: michael@0: MResumePoint *mrp = mir->resumePoint() ? mir->resumePoint() : lastResumePoint_; michael@0: LSnapshot *postSnapshot = buildSnapshot(ins, mrp, Bailout_Normal); michael@0: if (!postSnapshot) michael@0: return false; michael@0: michael@0: osiPoint_ = new(alloc()) LOsiPoint(ins->safepoint(), postSnapshot); michael@0: michael@0: return lirGraph_.noteNeedsSafepoint(ins); michael@0: } michael@0: