Bug 1073033 part 3 - Recover MLambda on bailouts. r=shu

This commit is contained in:
Nicolas B. Pierron 2014-12-19 15:28:30 +01:00
parent efa6d4d979
commit e925e5f0da
6 changed files with 121 additions and 7 deletions

View File

@ -0,0 +1,53 @@
var max = 40;
setJitCompilerOption("ion.warmup.trigger", max - 10);
// This function is used to escape "g" which is a non-escaped inner function.
// As it is not escaped within "f", the lambda for "g" would be computed on the
// bailout path. Resolving the first ".caller" implies that we have to recover
// the lambda. Resolving the second ".caller" is needed such as we can build the
// test case without explicitly escaping "g", which would prevent this
// optimization.
function return_f(i) {
if (i != max - 1)
return f;
// return_f.caller == g
// return_f.caller.caller == f
return return_f.caller.caller;
}
function f(i) {
function g() {
return return_f(i);
}
return g();
}
// This function is used to cause an invalidation after having removed a branch.
// These functions are used to check if we correctly recover the lambda
// and its environment during a bailout.
var uceFault = function (i) {
if (i == max - 1)
uceFault = function (i) { return true; };
return false;
};
var uceFault_lambdaCall = eval(uneval(uceFault).replace('uceFault', 'uceFault_lambdaCall'));
function lambdaCall(i) {
function g() {
return i;
}
if (uceFault_lambdaCall(i) || uceFault_lambdaCall(i))
assertEq(g(), i);
};
for (var i = 0; i < max; i++) {
assertEq(f(i), f);
lambdaCall(i);
}

View File

@ -10623,7 +10623,9 @@ IonBuilder::jsop_lambda(JSFunction *fun)
if (fun->isNative() && IsAsmJSModuleNative(fun->native()))
return abort("asm.js module function");
MLambda *ins = MLambda::New(alloc(), constraints(), current->scopeChain(), fun);
MConstant *cst = MConstant::NewConstraintlessObject(alloc(), fun);
current->add(cst);
MLambda *ins = MLambda::New(alloc(), constraints(), current->scopeChain(), cst);
current->add(ins);
current->push(ins);

View File

@ -7040,33 +7040,40 @@ struct LambdaFunctionInfo
};
class MLambda
: public MUnaryInstruction,
: public MBinaryInstruction,
public SingleObjectPolicy::Data
{
LambdaFunctionInfo info_;
MLambda(types::CompilerConstraintList *constraints, MDefinition *scopeChain, JSFunction *fun)
: MUnaryInstruction(scopeChain), info_(fun)
MLambda(types::CompilerConstraintList *constraints, MDefinition *scopeChain, MConstant *cst)
: MBinaryInstruction(scopeChain, cst), info_(&cst->value().toObject().as<JSFunction>())
{
setResultType(MIRType_Object);
if (!fun->hasSingletonType() && !types::UseNewTypeForClone(fun))
setResultTypeSet(MakeSingletonTypeSet(constraints, fun));
if (!info().fun->hasSingletonType() && !types::UseNewTypeForClone(info().fun))
setResultTypeSet(MakeSingletonTypeSet(constraints, info().fun));
}
public:
INSTRUCTION_HEADER(Lambda)
static MLambda *New(TempAllocator &alloc, types::CompilerConstraintList *constraints,
MDefinition *scopeChain, JSFunction *fun)
MDefinition *scopeChain, MConstant *fun)
{
return new(alloc) MLambda(constraints, scopeChain, fun);
}
MDefinition *scopeChain() const {
return getOperand(0);
}
MConstant *functionOperand() const {
return getOperand(1)->toConstant();
}
const LambdaFunctionInfo &info() const {
return info_;
}
bool writeRecoverData(CompactBufferWriter &writer) const;
bool canRecoverOnBailout() const {
return true;
}
};
class MLambdaArrow

View File

@ -1218,6 +1218,34 @@ RCreateThisWithTemplate::recover(JSContext *cx, SnapshotIterator &iter) const
return true;
}
bool
MLambda::writeRecoverData(CompactBufferWriter &writer) const
{
MOZ_ASSERT(canRecoverOnBailout());
writer.writeUnsigned(uint32_t(RInstruction::Recover_Lambda));
return true;
}
RLambda::RLambda(CompactBufferReader &reader)
{
}
bool
RLambda::recover(JSContext *cx, SnapshotIterator &iter) const
{
RootedObject scopeChain(cx, &iter.read().toObject());
RootedFunction fun(cx, &iter.read().toObject().as<JSFunction>());
JSObject *resultObject = js::Lambda(cx, fun, scopeChain);
if (!resultObject)
return false;
RootedValue result(cx);
result.setObject(*resultObject);
iter.storeInstructionResult(result);
return true;
}
bool
MObjectState::writeRecoverData(CompactBufferWriter &writer) const
{

View File

@ -60,6 +60,7 @@ namespace jit {
_(NewArray) \
_(NewDerivedTypedObject) \
_(CreateThisWithTemplate) \
_(Lambda) \
_(ObjectState) \
_(ArrayState)
@ -641,6 +642,18 @@ class RCreateThisWithTemplate MOZ_FINAL : public RInstruction
bool recover(JSContext *cx, SnapshotIterator &iter) const;
};
class RLambda MOZ_FINAL : public RInstruction
{
public:
RINSTRUCTION_HEADER_(Lambda)
virtual uint32_t numOperands() const {
return 2;
}
bool recover(JSContext *cx, SnapshotIterator &iter) const;
};
class RObjectState MOZ_FINAL : public RInstruction
{
private:

View File

@ -307,6 +307,17 @@ CodeGeneratorShared::encodeAllocation(LSnapshot *snapshot, MDefinition *mir,
// This MDefinition is recovered, thus it should be listed in the
// LRecoverInfo.
MOZ_ASSERT(it != end && mir == *it);
// Lambda should have a default value readable for iterating over the
// inner frames.
if (mir->isLambda()) {
MConstant *constant = mir->toLambda()->functionOperand();
uint32_t cstIndex;
masm.propagateOOM(graph.addConstantToPool(constant->value(), &cstIndex));
alloc = RValueAllocation::RecoverInstruction(index, cstIndex);
break;
}
alloc = RValueAllocation::RecoverInstruction(index);
break;
}