blob: a6249f4c8e63f8606bf00b278461df04c3ceffaa [file] [log] [blame]
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "jit/LIR.h"
#include "jit/MIR.h"
#include "jit/MIRGraph.h"
#include "Lowering-shared.h"
#include "Lowering-shared-inl.h"
using namespace js;
using namespace jit;
bool
LIRGeneratorShared::visitConstant(MConstant *ins)
{
const Value &v = ins->value();
switch (ins->type()) {
case MIRType_Boolean:
return define(new LInteger(v.toBoolean()), ins);
case MIRType_Int32:
return define(new LInteger(v.toInt32()), ins);
case MIRType_String:
return define(new LPointer(v.toString()), ins);
case MIRType_Object:
return define(new LPointer(&v.toObject()), ins);
default:
// Constants of special types (undefined, null) should never flow into
// here directly. Operations blindly consuming them require a Box.
JS_ASSERT(!"unexpected constant type");
return false;
}
}
bool
LIRGeneratorShared::defineTypedPhi(MPhi *phi, size_t lirIndex)
{
LPhi *lir = current->getPhi(lirIndex);
uint32_t vreg = getVirtualRegister();
if (vreg >= MAX_VIRTUAL_REGISTERS)
return false;
phi->setVirtualRegister(vreg);
lir->setDef(0, LDefinition(vreg, LDefinition::TypeFrom(phi->type())));
annotate(lir);
return true;
}
void
LIRGeneratorShared::lowerTypedPhiInput(MPhi *phi, uint32_t inputPosition, LBlock *block, size_t lirIndex)
{
MDefinition *operand = phi->getOperand(inputPosition);
LPhi *lir = block->getPhi(lirIndex);
lir->setOperand(inputPosition, LUse(operand->virtualRegister(), LUse::ANY));
}
#ifdef JS_NUNBOX32
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 *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());
// Guards should never be eliminated.
JS_ASSERT_IF(ins->isUnused(), !ins->isGuard());
// 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 {
if (!ensureDefined(ins))
return NULL;
*type = useType(ins, LUse::KEEPALIVE);
*payload = usePayload(ins, LUse::KEEPALIVE);
}
}
}
return snapshot;
}
#elif JS_PUNBOX64
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;
}
#endif
bool
LIRGeneratorShared::assignSnapshot(LInstruction *ins, BailoutKind kind)
{
// assignSnapshot must be called before define/add, since
// it may add new instructions for emitted-at-use operands.
JS_ASSERT(ins->id() == 0);
LSnapshot *snapshot = buildSnapshot(ins, lastResumePoint_, kind);
if (!snapshot)
return false;
ins->assignSnapshot(snapshot);
return true;
}
bool
LIRGeneratorShared::assignSafepoint(LInstruction *ins, MInstruction *mir)
{
JS_ASSERT(!osiPoint_);
JS_ASSERT(!ins->safepoint());
ins->initSafepoint();
MResumePoint *mrp = mir->resumePoint() ? mir->resumePoint() : lastResumePoint_;
LSnapshot *postSnapshot = buildSnapshot(ins, mrp, Bailout_Normal);
if (!postSnapshot)
return false;
osiPoint_ = new LOsiPoint(ins->safepoint(), postSnapshot);
return lirGraph_.noteNeedsSafepoint(ins);
}