mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-13 21:35:39 +00:00
Bug 1073033 part 3 - Recover MLambda on bailouts. r=shu
This commit is contained in:
parent
efa6d4d979
commit
e925e5f0da
53
js/src/jit-test/tests/ion/recover-lambdas.js
Normal file
53
js/src/jit-test/tests/ion/recover-lambdas.js
Normal 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);
|
||||
}
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user