Bug 749358 - Inline MUse storage. r=luke

This commit is contained in:
Sean Stangl 2013-01-28 15:30:50 -08:00
parent 78a045cb78
commit fcd36f671b
10 changed files with 394 additions and 200 deletions

View File

@ -406,6 +406,9 @@ class Vector : private AllocPolicy
/* Clears and releases any heap-allocated storage. */
void clearAndFree();
/* If true, appending |needed| elements will not call realloc(). */
bool canAppendWithoutRealloc(size_t needed) const;
/*
* Potentially fallible append operations.
*
@ -772,6 +775,13 @@ Vector<T,N,AP>::clearAndFree()
#endif
}
template <class T, size_t N, class AP>
inline bool
Vector<T,N,AP>::canAppendWithoutRealloc(size_t needed) const
{
return mLength + needed <= mCapacity;
}
template <class T, size_t N, class AP>
template <class U>
JS_ALWAYS_INLINE bool

View File

@ -55,10 +55,10 @@ EdgeCaseAnalysis::AllUsesTruncate(MInstruction *m)
int ret = 1;
for (MUseIterator use = m->usesBegin(); use != m->usesEnd(); use++) {
// See #809485 why this is allowed
if (use->node()->isResumePoint())
if (use->consumer()->isResumePoint())
continue;
MDefinition *def = use->node()->toDefinition();
MDefinition *def = use->consumer()->toDefinition();
if (def->isTruncateToInt32())
continue;
if (def->isBitAnd())

View File

@ -103,11 +103,11 @@ ion::EliminateDeadResumePointOperands(MIRGenerator *mir, MIRGraph &graph)
// Walk the uses a second time, removing any in resume points after
// the last use in a definition.
for (MUseIterator uses(ins->usesBegin()); uses != ins->usesEnd(); ) {
if (uses->node()->isDefinition()) {
if (uses->consumer()->isDefinition()) {
uses++;
continue;
}
MResumePoint *mrp = uses->node()->toResumePoint();
MResumePoint *mrp = uses->consumer()->toResumePoint();
if (mrp->block() != *block ||
!mrp->instruction() ||
mrp->instruction() == *ins ||
@ -188,8 +188,8 @@ IsPhiObservable(MPhi *phi, Observability observe)
case ConservativeObservability:
for (MUseIterator iter(phi->usesBegin()); iter != phi->usesEnd(); iter++) {
if (!iter->node()->isDefinition() ||
!iter->node()->toDefinition()->isPhi())
if (!iter->consumer()->isDefinition() ||
!iter->consumer()->toDefinition()->isPhi())
return true;
}
break;
@ -879,16 +879,30 @@ CheckPredecessorImpliesSuccessor(MBasicBlock *A, MBasicBlock *B)
}
static bool
CheckMarkedAsUse(MInstruction *ins, MDefinition *operand)
CheckOperandImpliesUse(MInstruction *ins, MDefinition *operand)
{
for (MUseIterator i = operand->usesBegin(); i != operand->usesEnd(); i++) {
if (i->node()->isDefinition()) {
if (ins == i->node()->toDefinition())
return true;
}
if (i->consumer()->isDefinition() && i->consumer()->toDefinition() == ins)
return true;
}
return false;
}
static bool
CheckUseImpliesOperand(MInstruction *ins, MUse *use)
{
MNode *consumer = use->consumer();
uint32_t index = use->index();
if (consumer->isDefinition()) {
MDefinition *def = consumer->toDefinition();
return (def->getOperand(index) == ins);
}
JS_ASSERT(consumer->isResumePoint());
MResumePoint *res = consumer->toResumePoint();
return (res->getOperand(index) == ins);
}
#endif // DEBUG
#ifdef DEBUG
@ -926,9 +940,14 @@ ion::AssertGraphCoherency(MIRGraph &graph)
for (size_t i = 0; i < block->numPredecessors(); i++)
JS_ASSERT(CheckPredecessorImpliesSuccessor(*block, block->getPredecessor(i)));
// Assert that use chains are valid for this instruction.
for (MInstructionIterator ins = block->begin(); ins != block->end(); ins++) {
for (uint32_t i = 0; i < ins->numOperands(); i++)
JS_ASSERT(CheckMarkedAsUse(*ins, ins->getOperand(i)));
JS_ASSERT(CheckOperandImpliesUse(*ins, ins->getOperand(i)));
}
for (MInstructionIterator ins = block->begin(); ins != block->end(); ins++) {
for (MUseIterator i(ins->usesBegin()); i != ins->usesEnd(); i++)
JS_ASSERT(CheckUseImpliesOperand(*ins, *i));
}
}

View File

@ -2957,14 +2957,16 @@ IonBuilder::patchInlinedReturns(CallInfo &callInfo, MIRGraphExits &exits, MBasic
// would have been returned.
JS_ASSERT(exits.length() > 0);
MPhi *retDef = NULL;
// In the case of a single return, no phi is necessary.
MPhi *phi = NULL;
if (exits.length() > 1) {
retDef = MPhi::New(bottom->stackDepth());
bottom->addPhi(retDef);
phi = MPhi::New(bottom->stackDepth());
phi->initLength(exits.length());
bottom->addPhi(phi);
}
for (MBasicBlock **it = exits.begin(), **end = exits.end(); it != end; ++it) {
MBasicBlock *exitBlock = *it;
for (size_t i = 0; i < exits.length(); i++) {
MBasicBlock *exitBlock = exits[i];
MDefinition *rval = exitBlock->lastIns()->toReturn()->getOperand(0);
exitBlock->discardLastIns();
@ -2988,10 +2990,10 @@ IonBuilder::patchInlinedReturns(CallInfo &callInfo, MIRGraphExits &exits, MBasic
if (exits.length() == 1)
return rval;
retDef->addInput(rval);
phi->setOperand(i, rval);
}
return retDef;
return phi;
}
bool
@ -3529,11 +3531,16 @@ IonBuilder::inlineScriptedCalls(AutoObjectVector &targets, AutoObjectVector &ori
MPhi *phi = MPhi::New(inlineBottom->stackDepth() - callInfo.argc() - 2);
inlineBottom->addPhi(phi);
if (!phi->initLength(retvalDefns.length()))
return false;
size_t index = 0;
MDefinition **it = retvalDefns.begin(), **end = retvalDefns.end();
for (; it != end; ++it) {
if (!phi->addInput(*it))
return false;
}
for (; it != end; it++, index++)
phi->setOperand(index, *it);
JS_ASSERT(index == retvalDefns.length());
// retvalDefns should become a singleton vector of 'phi'
retvalDefns.clear();
if (!retvalDefns.append(phi))
@ -3578,10 +3585,16 @@ IonBuilder::inlineScriptedCalls(AutoObjectVector &targets, AutoObjectVector &ori
MPhi *phi = MPhi::New(bottom->stackDepth());
bottom->addPhi(phi);
for (MDefinition **it = retvalDefns.begin(), **end = retvalDefns.end(); it != end; ++it) {
if (!phi->addInput(*it))
return false;
}
if (!phi->initLength(retvalDefns.length()))
return false;
size_t index = 0;
MDefinition **it = retvalDefns.begin(), **end = retvalDefns.end();
for (; it != end; it++, index++)
phi->setOperand(index, *it);
JS_ASSERT(index == retvalDefns.length());
retvalDefn = phi;
} else {
retvalDefn = retvalDefns.back();
@ -4216,10 +4229,13 @@ IonBuilder::makeCallHelper(HandleFunction target, CallInfo &callInfo,
return NULL;
}
MPassArg *newThis = MPassArg::New(create);
// Unwrap the MPassArg before discarding: it may have been captured by an MResumePoint.
thisArg->replaceAllUsesWith(thisArg->getArgument());
thisArg->block()->discard(thisArg);
MPassArg *newThis = MPassArg::New(create);
current->add(newThis);
thisArg = newThis;
}

View File

@ -551,7 +551,7 @@ CanEmitCompareAtUses(MInstruction *ins)
bool foundTest = false;
for (MUseIterator iter(ins->usesBegin()); iter != ins->usesEnd(); iter++) {
MNode *node = iter->node();
MNode *node = iter->consumer();
if (!node->isDefinition())
return false;
if (!node->toDefinition()->isTest())

View File

@ -248,43 +248,70 @@ MDefinition::removeUse(MUseIterator use)
}
MUseIterator
MNode::replaceOperand(MUseIterator use, MDefinition *ins)
MNode::replaceOperand(MUseIterator use, MDefinition *def)
{
MDefinition *used = getOperand(use->index());
if (used == ins)
JS_ASSERT(def != NULL);
uint32_t index = use->index();
MDefinition *prev = use->producer();
JS_ASSERT(use->index() < numOperands());
JS_ASSERT(use->producer() == getOperand(index));
JS_ASSERT(use->consumer() == this);
if (prev == def)
return use;
MUse *save = *use;
MUseIterator result(used->removeUse(use));
if (ins) {
setOperand(save->index(), ins);
ins->linkUse(save);
}
MUseIterator result(prev->removeUse(use));
setOperand(index, def);
return result;
}
void
MNode::replaceOperand(size_t index, MDefinition *def)
{
MDefinition *d = getOperand(index);
for (MUseIterator i(d->usesBegin()); i != d->usesEnd(); i++) {
if (i->index() == index && i->node() == this) {
replaceOperand(i, def);
return;
}
}
JS_ASSERT(def != NULL);
MUse *use = getUseFor(index);
MDefinition *prev = use->producer();
JS_NOT_REACHED("could not find use");
JS_ASSERT(use->index() == index);
JS_ASSERT(use->index() < numOperands());
JS_ASSERT(use->producer() == getOperand(index));
JS_ASSERT(use->consumer() == this);
if (prev == def)
return;
prev->removeUse(use);
setOperand(index, def);
}
void
MNode::discardOperand(size_t index)
{
MUse *use = getUseFor(index);
JS_ASSERT(use->index() == index);
JS_ASSERT(use->producer() == getOperand(index));
JS_ASSERT(use->consumer() == this);
use->producer()->removeUse(use);
#ifdef DEBUG
// Causes any producer/consumer lookups to trip asserts.
use->set(NULL, NULL, index);
#endif
}
void
MDefinition::replaceAllUsesWith(MDefinition *dom)
{
for (MUseIterator i(uses_.begin()); i != uses_.end(); ) {
MUse *use = *i;
i = uses_.removeAt(i);
use->node()->setOperand(use->index(), dom);
dom->linkUse(use);
JS_ASSERT(dom != NULL);
if (dom == this)
return;
for (MUseIterator i(usesBegin()); i != usesEnd(); ) {
JS_ASSERT(i->producer() == this);
i = i->consumer()->replaceOperand(i, dom);
}
}
@ -474,18 +501,27 @@ MPhi::New(uint32_t slot)
void
MPhi::removeOperand(size_t index)
{
MUse *use = getUseFor(index);
JS_ASSERT(index < inputs_.length());
JS_ASSERT(inputs_.length() > 1);
JS_ASSERT(use->index() == index);
JS_ASSERT(use->producer() == getOperand(index));
JS_ASSERT(use->consumer() == this);
// Remove use from producer's use chain.
use->producer()->removeUse(use);
// If we have phi(..., a, b, c, d, ..., z) and we plan
// on removing a, then first shift downward so that we have
// phi(..., b, c, d, ..., z, z):
size_t length = inputs_.length();
for (size_t i = index + 1; i < length; i++)
replaceOperand(i - 1, getOperand(i));
// remove the final operand that now appears twice:
replaceOperand(length - 1, NULL);
for (size_t i = index; i < length - 1; i++) {
MUse *next = MPhi::getUseFor(i + 1);
next->producer()->removeUse(next);
MPhi::setOperand(i, next->producer());
}
// truncate the inputs_ list:
inputs_.shrinkBy(1);
@ -523,17 +559,56 @@ MPhi::congruentTo(MDefinition *const &ins) const
}
bool
MPhi::addInput(MDefinition *ins)
MPhi::initLength(size_t length)
{
ins->addUse(this, inputs_.length());
return inputs_.append(ins);
// Initializes a new MPhi to have an Operand vector of at least the given
// length. This permits use of setOperand() instead of addInputSlow(), the
// latter of which may call realloc().
JS_ASSERT(numOperands() == 0);
return inputs_.resizeUninitialized(length);
}
bool
MPhi::addInputSlow(MDefinition *ins)
{
// The list of inputs to an MPhi is given as a vector of MUse nodes,
// each of which is in the list of the producer MDefinition.
// Because appending to a vector may reallocate the vector, it is possible
// that this operation may cause the producers' linked lists to reference
// invalid memory. Therefore, in the event of moving reallocation, each
// MUse must be removed and reinserted from/into its producer's use chain.
uint32_t index = inputs_.length();
bool performingRealloc = !inputs_.canAppendWithoutRealloc(1);
// Remove all MUses from all use lists, in case realloc() moves.
if (performingRealloc) {
for (uint32_t i = 0; i < index; i++) {
MUse *use = &inputs_[i];
use->producer()->removeUse(use);
}
}
// Insert the new input.
if (!inputs_.append(MUse()))
return false;
MPhi::setOperand(index, ins);
// Add all previously-removed MUses back.
if (performingRealloc) {
for (uint32_t i = 0; i < index; i++) {
MUse *use = &inputs_[i];
use->producer()->addUse(use);
}
}
return true;
}
uint32_t
MPrepareCall::argc() const
{
JS_ASSERT(useCount() == 1);
MCall *call = usesBegin()->node()->toDefinition()->toCall();
MCall *call = usesBegin()->consumer()->toDefinition()->toCall();
return call->numStackArgs();
}
@ -555,7 +630,7 @@ MCall::addArg(size_t argnum, MPassArg *arg)
// The operand vector is initialized in reverse order by the IonBuilder.
// It cannot be checked for consistency until all arguments are added.
arg->setArgnum(argnum);
MNode::initOperand(argnum + NumNonArgumentOperands, arg->toDefinition());
setOperand(argnum + NumNonArgumentOperands, arg->toDefinition());
}
void
@ -647,10 +722,10 @@ NeedNegativeZeroCheck(MDefinition *def)
{
// Test if all uses have the same semantics for -0 and 0
for (MUseIterator use = def->usesBegin(); use != def->usesEnd(); use++) {
if (use->node()->isResumePoint())
if (use->consumer()->isResumePoint())
continue;
MDefinition *use_def = use->node()->toDefinition();
MDefinition *use_def = use->consumer()->toDefinition();
switch (use_def->op()) {
case MDefinition::Op_Add: {
// If add is truncating -0 and 0 are observed as the same.
@ -1427,7 +1502,7 @@ MResumePoint *
MResumePoint::New(MBasicBlock *block, jsbytecode *pc, MResumePoint *parent, Mode mode)
{
MResumePoint *resume = new MResumePoint(block, pc, parent, mode);
if (!resume->init(block))
if (!resume->init())
return NULL;
resume->inherit(block);
return resume;
@ -1444,15 +1519,6 @@ MResumePoint::MResumePoint(MBasicBlock *block, jsbytecode *pc, MResumePoint *cal
{
}
bool
MResumePoint::init(MBasicBlock *block)
{
operands_ = block->graph().allocate<MDefinition *>(stackDepth());
if (!operands_)
return false;
return true;
}
void
MResumePoint::inherit(MBasicBlock *block)
{
@ -1462,7 +1528,7 @@ MResumePoint::inherit(MBasicBlock *block)
// and LStackArg does not define a value.
if (def->isPassArg())
def = def->toPassArg()->getArgument();
initOperand(i, def);
setOperand(i, def);
}
}

View File

@ -67,32 +67,51 @@ class MResumePoint;
static inline bool isOSRLikeValue (MDefinition *def);
// Represents a use of a node.
class MUse : public TempObject, public InlineForwardListNode<MUse>
class MUse : public TempObject, public InlineListNode<MUse>
{
friend class MDefinition;
MNode *node_; // The node that is using this operand.
uint32_t index_; // The index of this operand in its owner.
MDefinition *producer_; // MDefinition that is being used.
MNode *consumer_; // The node that is using this operand.
uint32_t index_; // The index of this operand in its consumer.
MUse(MNode *owner, uint32_t index)
: node_(owner),
MUse(MDefinition *producer, MNode *consumer, uint32_t index)
: producer_(producer),
consumer_(consumer),
index_(index)
{ }
public:
static inline MUse *New(MNode *owner, uint32_t index) {
return new MUse(owner, index);
// Default constructor for use in vectors.
MUse()
: producer_(NULL), consumer_(NULL), index_(0)
{ }
static inline MUse *New(MDefinition *producer, MNode *consumer, uint32_t index) {
return new MUse(producer, consumer, index);
}
MNode *node() const {
return node_;
// Set data inside the MUse.
void set(MDefinition *producer, MNode *consumer, uint32_t index) {
producer_ = producer;
consumer_ = consumer;
index_ = index;
}
MDefinition *producer() const {
JS_ASSERT(producer_ != NULL);
return producer_;
}
MNode *consumer() const {
JS_ASSERT(consumer_ != NULL);
return consumer_;
}
uint32_t index() const {
return index_;
}
};
typedef InlineForwardList<MUse>::iterator MUseIterator;
typedef InlineList<MUse>::iterator MUseIterator;
// A node is an entry in the MIR graph. It has two kinds:
// MInstruction: an instruction which appears in the IR stream.
@ -114,9 +133,12 @@ class MNode : public TempObject
ResumePoint
};
MNode() : block_(NULL)
MNode()
: block_(NULL)
{ }
MNode(MBasicBlock *block) : block_(block)
MNode(MBasicBlock *block)
: block_(block)
{ }
virtual Kind kind() const = 0;
@ -141,20 +163,25 @@ class MNode : public TempObject
return NULL;
}
// Replaces an operand, taking care to update use chains. No memory is
// allocated; the existing data structures are re-linked.
// Replaces an already-set operand during iteration over a use chain.
MUseIterator replaceOperand(MUseIterator use, MDefinition *ins);
// Replaces an already-set operand, updating use information.
void replaceOperand(size_t index, MDefinition *ins);
// Resets the operand to an uninitialized state, breaking the link
// with the previous operand's producer.
void discardOperand(size_t index);
inline MDefinition *toDefinition();
inline MResumePoint *toResumePoint();
protected:
// Sets a raw operand, ignoring updating use information.
// Sets an unset operand, updating use information.
virtual void setOperand(size_t index, MDefinition *operand) = 0;
// Initializes an operand for the first time.
inline void initOperand(size_t index, MDefinition *ins);
// Gets the MUse corresponding to given operand.
virtual MUse *getUseFor(size_t index) = 0;
};
class AliasSet {
@ -230,8 +257,8 @@ class MDefinition : public MNode
};
private:
InlineForwardList<MUse> uses_; // Use chain.
uint32_t id_; // Instruction ID, which after block re-ordering
InlineList<MUse> uses_; // Use chain.
uint32_t id_; // Instruction ID, which after block re-ordering
// is sorted within a basic block.
ValueNumberData *valueNumber_; // The instruction's value number (see GVN for details in use)
Range *range_; // Any computed range for this def.
@ -377,6 +404,9 @@ class MDefinition : public MNode
// Removes a use at the given position
MUseIterator removeUse(MUseIterator use);
void removeUse(MUse *use) {
uses_.remove(use);
}
// Number of uses of this instruction.
size_t useCount() const;
@ -389,8 +419,8 @@ class MDefinition : public MNode
return false;
}
void addUse(MNode *node, size_t index) {
uses_.pushFront(MUse::New(node, index));
void addUse(MUse *use) {
uses_.pushFront(use);
}
void replaceAllUsesWith(MDefinition *dom);
@ -406,13 +436,6 @@ class MDefinition : public MNode
return true;
}
// Adds a use from a node that is being recycled during operand
// replacement.
void linkUse(MUse *use) {
JS_ASSERT(use->node()->getOperand(use->index()) == this);
uses_.pushFront(use);
}
void setVirtualRegister(uint32_t vreg) {
virtualRegister_ = vreg;
#ifdef DEBUG
@ -494,7 +517,7 @@ class MUseDefIterator
MUseIterator search(MUseIterator start) {
MUseIterator i(start);
for (; i != def_->usesEnd(); i++) {
if (i->node()->isDefinition())
if (i->consumer()->isDefinition())
return i;
}
return def_->usesEnd();
@ -504,8 +527,7 @@ class MUseDefIterator
MUseDefIterator(MDefinition *def)
: def_(def),
current_(search(def->usesBegin()))
{
}
{ }
operator bool() const {
return current_ != def_->usesEnd();
@ -521,7 +543,7 @@ class MUseDefIterator
return *current_;
}
MDefinition *def() const {
return current_->node()->toDefinition();
return current_->consumer()->toDefinition();
}
size_t index() const {
return current_->index();
@ -564,15 +586,20 @@ template <size_t Arity>
class MAryInstruction : public MInstruction
{
protected:
FixedArityList<MDefinition*, Arity> operands_;
FixedArityList<MUse, Arity> operands_;
void setOperand(size_t index, MDefinition *operand) {
operands_[index] = operand;
operands_[index].set(operand, this, index);
operand->addUse(&operands_[index]);
}
MUse *getUseFor(size_t index) {
return &operands_[index];
}
public:
MDefinition *getOperand(size_t index) const {
return operands_[index];
return operands_[index].producer();
}
size_t numOperands() const {
return Arity;
@ -758,7 +785,7 @@ class MTableSwitch
// Contains the blocks/cases that still need to get build
Vector<MBasicBlock*, 0, IonAllocPolicy> blocks_;
MDefinition *operand_;
MUse operand_;
int32_t low_;
int32_t high_;
@ -768,13 +795,19 @@ class MTableSwitch
low_(low),
high_(high)
{
initOperand(0, ins);
setOperand(0, ins);
}
protected:
void setOperand(size_t index, MDefinition *operand) {
JS_ASSERT(index == 0);
operand_ = operand;
operand_.set(operand, this, index);
operand->addUse(&operand_);
}
MUse *getUseFor(size_t index) {
JS_ASSERT(index == 0);
return &operand_;
}
public:
@ -846,7 +879,7 @@ class MTableSwitch
MDefinition *getOperand(size_t index) const {
JS_ASSERT(index == 0);
return operand_;
return operand_.producer();
}
size_t numOperands() const {
@ -857,20 +890,25 @@ class MTableSwitch
template <size_t Arity, size_t Successors>
class MAryControlInstruction : public MControlInstruction
{
FixedArityList<MDefinition *, Arity> operands_;
FixedArityList<MUse, Arity> operands_;
FixedArityList<MBasicBlock *, Successors> successors_;
protected:
void setOperand(size_t index, MDefinition *operand) {
operands_[index] = operand;
operands_[index].set(operand, this, index);
operand->addUse(&operands_[index]);
}
void setSuccessor(size_t index, MBasicBlock *successor) {
successors_[index] = successor;
}
MUse *getUseFor(size_t index) {
return &operands_[index];
}
public:
MDefinition *getOperand(size_t index) const {
return operands_[index];
return operands_[index].producer();
}
size_t numOperands() const {
return Arity;
@ -927,7 +965,7 @@ class MTest
MTest(MDefinition *ins, MBasicBlock *if_true, MBasicBlock *if_false)
: operandMightEmulateUndefined_(true)
{
initOperand(0, ins);
setOperand(0, ins);
setSuccessor(0, if_true);
setSuccessor(1, if_false);
}
@ -970,7 +1008,7 @@ class MReturn
public BoxInputsPolicy
{
MReturn(MDefinition *ins) {
initOperand(0, ins);
setOperand(0, ins);
}
public:
@ -992,7 +1030,7 @@ class MThrow
public BoxInputsPolicy
{
MThrow(MDefinition *ins) {
initOperand(0, ins);
setOperand(0, ins);
}
public:
@ -1093,8 +1131,8 @@ class MInitProp
MInitProp(MDefinition *obj, HandlePropertyName name, MDefinition *value)
: name_(name)
{
initOperand(0, obj);
initOperand(1, value);
setOperand(0, obj);
setOperand(1, value);
setResultType(MIRType_None);
}
@ -1141,7 +1179,7 @@ class MPrepareCall : public MNullaryInstruction
class MVariadicInstruction : public MInstruction
{
FixedList<MDefinition *> operands_;
FixedList<MUse> operands_;
protected:
bool init(size_t length) {
@ -1151,13 +1189,18 @@ class MVariadicInstruction : public MInstruction
public:
// Will assert if called before initialization.
MDefinition *getOperand(size_t index) const {
return operands_[index];
return operands_[index].producer();
}
size_t numOperands() const {
return operands_.length();
}
void setOperand(size_t index, MDefinition *operand) {
operands_[index] = operand;
operands_[index].set(operand, this, index);
operand->addUse(&operands_[index]);
}
MUse *getUseFor(size_t index) {
return &operands_[index];
}
};
@ -1199,11 +1242,11 @@ class MCall
void initPrepareCall(MDefinition *start) {
JS_ASSERT(start->isPrepareCall());
return initOperand(PrepareCallOperandIndex, start);
return setOperand(PrepareCallOperandIndex, start);
}
void initFunction(MDefinition *func) {
JS_ASSERT(!func->isPassArg());
return initOperand(FunctionOperandIndex, func);
return setOperand(FunctionOperandIndex, func);
}
MDefinition *getFunction() const {
@ -1264,9 +1307,9 @@ class MApplyArgs
MApplyArgs(JSFunction *target, MDefinition *fun, MDefinition *argc, MDefinition *self)
: target_(target)
{
initOperand(0, fun);
initOperand(1, argc);
initOperand(2, self);
setOperand(0, fun);
setOperand(1, argc);
setOperand(2, self);
setResultType(MIRType_Value);
}
@ -1301,7 +1344,7 @@ class MUnaryInstruction : public MAryInstruction<1>
protected:
MUnaryInstruction(MDefinition *ins)
{
initOperand(0, ins);
setOperand(0, ins);
}
};
@ -1310,8 +1353,8 @@ class MBinaryInstruction : public MAryInstruction<2>
protected:
MBinaryInstruction(MDefinition *left, MDefinition *right)
{
initOperand(0, left);
initOperand(1, right);
setOperand(0, left);
setOperand(1, right);
}
public:
@ -1375,9 +1418,9 @@ class MTernaryInstruction : public MAryInstruction<3>
protected:
MTernaryInstruction(MDefinition *first, MDefinition *second, MDefinition *third)
{
initOperand(0, first);
initOperand(1, second);
initOperand(2, third);
setOperand(0, first);
setOperand(1, second);
setOperand(2, third);
}
protected:
@ -1778,8 +1821,8 @@ class MReturnFromCtor
public MixPolicy<BoxPolicy<0>, ObjectPolicy<1> >
{
MReturnFromCtor(MDefinition *value, MDefinition *object) {
initOperand(0, value);
initOperand(1, object);
setOperand(0, value);
setOperand(1, object);
setResultType(MIRType_Object);
}
@ -2932,10 +2975,12 @@ class MFromCharCode
class MPhi : public MDefinition, public InlineForwardListNode<MPhi>
{
js::Vector<MDefinition *, 2, IonAllocPolicy> inputs_;
js::Vector<MUse, 2, IonAllocPolicy> inputs_;
uint32_t slot_;
bool triedToSpecialize_;
bool isIterator_;
MPhi(uint32_t slot)
: slot_(slot),
triedToSpecialize_(false),
@ -2945,18 +2990,25 @@ class MPhi : public MDefinition, public InlineForwardListNode<MPhi>
}
protected:
void setOperand(size_t index, MDefinition *operand) {
inputs_[index] = operand;
MUse *getUseFor(size_t index) {
return &inputs_[index];
}
public:
INSTRUCTION_HEADER(Phi)
static MPhi *New(uint32_t slot);
// Unsafe to use unless space has already been reserved via initLength().
void setOperand(size_t index, MDefinition *operand) {
JS_ASSERT(index < numOperands());
inputs_[index].set(operand, this, index);
operand->addUse(&inputs_[index]);
}
void removeOperand(size_t index);
MDefinition *getOperand(size_t index) const {
return inputs_[index];
return inputs_[index].producer();
}
size_t numOperands() const {
return inputs_.length();
@ -2971,7 +3023,14 @@ class MPhi : public MDefinition, public InlineForwardListNode<MPhi>
triedToSpecialize_ = true;
setResultType(type);
}
bool addInput(MDefinition *ins);
// Initializes the operands vector to the given length,
// permitting use of setOperand() instead of addInputSlow().
bool initLength(size_t length);
// Appends a new input to the input vector. May call realloc().
// Prefer initLength() and setOperand() instead, where possible.
bool addInputSlow(MDefinition *ins);
MDefinition *foldsTo(bool useValueNumbers);
@ -3476,8 +3535,8 @@ class MSetInitializedLength
{
MSetInitializedLength(MDefinition *elements, MDefinition *index)
{
initOperand(0, elements);
initOperand(1, index);
setOperand(0, elements);
setOperand(1, index);
}
public:
@ -3855,9 +3914,9 @@ class MStoreElement
bool needsHoleCheck_;
MStoreElement(MDefinition *elements, MDefinition *index, MDefinition *value, bool needsHoleCheck) {
initOperand(0, elements);
initOperand(1, index);
initOperand(2, value);
setOperand(0, elements);
setOperand(1, index);
setOperand(2, value);
needsHoleCheck_ = needsHoleCheck;
JS_ASSERT(elements->type() == MIRType_Elements);
JS_ASSERT(index->type() == MIRType_Int32);
@ -3904,10 +3963,10 @@ class MStoreElementHole
{
MStoreElementHole(MDefinition *object, MDefinition *elements,
MDefinition *index, MDefinition *value) {
initOperand(0, object);
initOperand(1, elements);
initOperand(2, index);
initOperand(3, value);
setOperand(0, object);
setOperand(1, elements);
setOperand(2, index);
setOperand(3, value);
JS_ASSERT(elements->type() == MIRType_Elements);
JS_ASSERT(index->type() == MIRType_Int32);
}
@ -4517,39 +4576,45 @@ class MPolyInlineDispatch : public MControlInstruction, public SingleObjectPolic
};
Vector<Entry, 4, IonAllocPolicy> dispatchTable_;
MDefinition *operand_;
MUse operand_;
InlinePropertyTable *inlinePropertyTable_;
MBasicBlock *fallbackPrepBlock_;
MBasicBlock *fallbackMidBlock_;
MBasicBlock *fallbackEndBlock_;
MPolyInlineDispatch(MDefinition *ins)
: dispatchTable_(), operand_(NULL),
: dispatchTable_(),
inlinePropertyTable_(NULL),
fallbackPrepBlock_(NULL),
fallbackMidBlock_(NULL),
fallbackEndBlock_(NULL)
{
initOperand(0, ins);
setOperand(0, ins);
}
MPolyInlineDispatch(MDefinition *ins, InlinePropertyTable *inlinePropertyTable,
MBasicBlock *fallbackPrepBlock,
MBasicBlock *fallbackMidBlock,
MBasicBlock *fallbackEndBlock)
: dispatchTable_(), operand_(NULL),
: dispatchTable_(),
inlinePropertyTable_(inlinePropertyTable),
fallbackPrepBlock_(fallbackPrepBlock),
fallbackMidBlock_(fallbackMidBlock),
fallbackEndBlock_(fallbackEndBlock)
{
initOperand(0, ins);
setOperand(0, ins);
}
protected:
virtual void setOperand(size_t index, MDefinition *operand) {
JS_ASSERT(index == 0);
operand_ = operand;
operand_.set(operand, this, index);
operand->addUse(&operand_);
}
MUse *getUseFor(size_t index) {
JS_ASSERT(index == 0);
return &operand_;
}
void setSuccessor(size_t i, MBasicBlock *successor) {
@ -4565,7 +4630,7 @@ class MPolyInlineDispatch : public MControlInstruction, public SingleObjectPolic
virtual MDefinition *getOperand(size_t index) const {
JS_ASSERT(index == 0);
return operand_;
return operand_.producer();
}
virtual size_t numOperands() const {
@ -5247,9 +5312,9 @@ class MCallSetElement
public CallSetElementPolicy
{
MCallSetElement(MDefinition *object, MDefinition *index, MDefinition *value) {
initOperand(0, object);
initOperand(1, index);
initOperand(2, value);
setOperand(0, object);
setOperand(1, index);
setOperand(2, value);
}
public:
@ -5282,8 +5347,8 @@ class MSetDOMProperty
MSetDOMProperty(const JSJitPropertyOp func, MDefinition *obj, MDefinition *val)
: func_(func)
{
initOperand(0, obj);
initOperand(1, val);
setOperand(0, obj);
setOperand(1, val);
}
public:
@ -5323,10 +5388,10 @@ class MGetDOMProperty
{
JS_ASSERT(jitinfo);
initOperand(0, obj);
setOperand(0, obj);
// Pin the guard as an operand if we want to hoist later
initOperand(1, guard);
setOperand(1, guard);
// We are movable iff the jitinfo says we can be.
if (jitinfo->isConstant)
@ -6023,7 +6088,7 @@ class MResumePoint : public MNode
private:
friend class MBasicBlock;
MDefinition **operands_;
FixedList<MUse> operands_;
uint32_t stackDepth_;
jsbytecode *pc_;
MResumePoint *caller_;
@ -6031,14 +6096,24 @@ class MResumePoint : public MNode
Mode mode_;
MResumePoint(MBasicBlock *block, jsbytecode *pc, MResumePoint *parent, Mode mode);
bool init(MBasicBlock *state);
void inherit(MBasicBlock *state);
protected:
// Initializes operands_ to an empty array of a fixed length.
// The array may then be filled in by inherit().
bool init() {
return operands_.init(stackDepth_);
}
// Overwrites an operand without updating its Uses.
void setOperand(size_t index, MDefinition *operand) {
JS_ASSERT(index < stackDepth_);
operands_[index] = operand;
operands_[index].set(operand, this, index);
operand->addUse(&operands_[index]);
}
MUse *getUseFor(size_t index) {
return &operands_[index];
}
public:
@ -6052,7 +6127,7 @@ class MResumePoint : public MNode
}
MDefinition *getOperand(size_t index) const {
JS_ASSERT(index < stackDepth_);
return operands_[index];
return operands_[index].producer();
}
jsbytecode *pc() const {
return pc_;
@ -6151,11 +6226,6 @@ MInstruction *MDefinition::toInstruction()
return (MInstruction *)this;
}
void MNode::initOperand(size_t index, MDefinition *ins)
{
setOperand(index, ins);
ins->addUse(this, index);
}
static inline bool isOSRLikeValue (MDefinition *def) {
if (def->isOsrValue())
return true;

View File

@ -194,7 +194,7 @@ MBasicBlock::inherit(MBasicBlock *pred, uint32_t popped)
// Create a resume point using our initial stack state.
entryResumePoint_ = new MResumePoint(this, pc(), callerResumePoint, MResumePoint::ResumeAt);
if (!entryResumePoint_->init(this))
if (!entryResumePoint_->init())
return false;
if (pred) {
@ -204,15 +204,16 @@ MBasicBlock::inherit(MBasicBlock *pred, uint32_t popped)
if (kind_ == PENDING_LOOP_HEADER) {
for (size_t i = 0; i < stackDepth(); i++) {
MPhi *phi = MPhi::New(i);
if (!phi->addInput(pred->getSlot(i)))
if (!phi->initLength(1))
return false;
phi->setOperand(0, pred->getSlot(i));
addPhi(phi);
setSlot(i, phi);
entryResumePoint()->initOperand(i, phi);
entryResumePoint()->setOperand(i, phi);
}
} else {
for (size_t i = 0; i < stackDepth(); i++)
entryResumePoint()->initOperand(i, getSlot(i));
entryResumePoint()->setOperand(i, getSlot(i));
}
}
@ -265,7 +266,7 @@ void
MBasicBlock::initSlot(uint32_t slot, MDefinition *ins)
{
slots_[slot] = ins;
entryResumePoint()->initOperand(slot, ins);
entryResumePoint()->setOperand(slot, ins);
}
void
@ -464,11 +465,22 @@ MBasicBlock::moveBefore(MInstruction *at, MInstruction *ins)
at->block()->insertBefore(at, ins);
}
static inline void
AssertSafelyDiscardable(MDefinition *def)
{
#ifdef DEBUG
// Instructions captured by resume points cannot be safely discarded, since
// they are necessary for interpreter frame reconstruction in case of bailout.
JS_ASSERT(def->useCount() == 0);
#endif
}
void
MBasicBlock::discard(MInstruction *ins)
{
AssertSafelyDiscardable(ins);
for (size_t i = 0; i < ins->numOperands(); i++)
ins->replaceOperand(i, NULL);
ins->discardOperand(i);
instructions_.remove(ins);
}
@ -476,8 +488,9 @@ MBasicBlock::discard(MInstruction *ins)
MInstructionIterator
MBasicBlock::discardAt(MInstructionIterator &iter)
{
AssertSafelyDiscardable(*iter);
for (size_t i = 0; i < iter->numOperands(); i++)
iter->replaceOperand(i, NULL);
iter->discardOperand(i);
return instructions_.removeAt(iter);
}
@ -485,8 +498,9 @@ MBasicBlock::discardAt(MInstructionIterator &iter)
MInstructionReverseIterator
MBasicBlock::discardAt(MInstructionReverseIterator &iter)
{
AssertSafelyDiscardable(*iter);
for (size_t i = 0; i < iter->numOperands(); i++)
iter->replaceOperand(i, NULL);
iter->discardOperand(i);
return instructions_.removeAt(iter);
}
@ -555,7 +569,7 @@ MBasicBlock::discardPhiAt(MPhiIterator &at)
JS_ASSERT(!phis_.empty());
for (size_t i = 0; i < at->numOperands(); i++)
at->replaceOperand(i, NULL);
at->discardOperand(i);
MPhiIterator result = phis_.removeAt(at);
@ -587,33 +601,32 @@ MBasicBlock::addPredecessorPopN(MBasicBlock *pred, uint32_t popped)
MDefinition *other = pred->getSlot(i);
if (mine != other) {
MPhi *phi;
// If the current instruction is a phi, and it was created in this
// basic block, then we have already placed this phi and should
// instead append to its operands.
if (mine->isPhi() && mine->block() == this) {
JS_ASSERT(predecessors_.length());
phi = mine->toPhi();
if (!mine->toPhi()->addInputSlow(other))
return false;
} else {
// Otherwise, create a new phi node.
phi = MPhi::New(i);
MPhi *phi = MPhi::New(i);
addPhi(phi);
// Prime the phi for each predecessor, so input(x) comes from
// predecessor(x).
if (!phi->initLength(predecessors_.length() + 1))
return false;
for (size_t j = 0; j < predecessors_.length(); j++) {
JS_ASSERT(predecessors_[j]->getSlot(i) == mine);
if (!phi->addInput(mine))
return false;
phi->setOperand(j, mine);
}
phi->setOperand(predecessors_.length(), other);
setSlot(i, phi);
entryResumePoint()->replaceOperand(i, phi);
}
if (!phi->addInput(other))
return false;
}
}
@ -639,8 +652,8 @@ MBasicBlock::assertUsesAreNotWithin(MUseIterator use, MUseIterator end)
{
#ifdef DEBUG
for (; use != end; use++) {
JS_ASSERT_IF(use->node()->isDefinition(),
use->node()->toDefinition()->block()->id() < id());
JS_ASSERT_IF(use->consumer()->isDefinition(),
use->consumer()->toDefinition()->block()->id() < id());
}
#endif
}
@ -683,7 +696,7 @@ MBasicBlock::setBackedge(MBasicBlock *pred)
exitDef = entryDef->getOperand(0);
}
if (!entryDef->addInput(exitDef))
if (!entryDef->addInputSlow(exitDef))
return false;
JS_ASSERT(entryDef->slot() < pred->stackDepth());

View File

@ -83,7 +83,7 @@ RangeAnalysis::RangeAnalysis(MIRGraph &graph)
static bool
IsDominatedUse(MBasicBlock *block, MUse *use)
{
MNode *n = use->node();
MNode *n = use->consumer();
bool isPhi = n->isDefinition() && n->toDefinition()->isPhi();
if (isPhi)
@ -110,8 +110,8 @@ RangeAnalysis::replaceDominatedUsesWith(MDefinition *orig, MDefinition *dom,
MBasicBlock *block)
{
for (MUseIterator i(orig->usesBegin()); i != orig->usesEnd(); ) {
if (i->node() != dom && IsDominatedUse(block, *i))
i = i->node()->replaceOperand(i, dom);
if (i->consumer() != dom && IsDominatedUse(block, *i))
i = i->consumer()->replaceOperand(i, dom);
else
i++;
}

View File

@ -112,7 +112,7 @@ void
UnreachableCodeElimination::removeUsesFromUnmarkedBlocks(MDefinition *instr)
{
for (MUseIterator iter(instr->usesBegin()); iter != instr->usesEnd(); ) {
if (!iter->node()->block()->isMarked())
if (!iter->consumer()->block()->isMarked())
iter = instr->removeUse(iter);
else
iter++;