Bug 893038 - Re-enable heavyweight function and cloned lambda inlining. r=nbp
authorKannan Vijayan <kvijayan@mozilla.com>
Wed, 31 Jul 2013 17:36:09 -0400
changeset 153106 133bde40e6bcac97ac71cbb8697c18c826f25b6c
parent 153105 eab74a7144c07514013857e399d0c2526eefd418
child 153107 bd49d8389a9b6b9e12fd068b92809ec13e847c23
push id2859
push userakeybl@mozilla.com
push dateMon, 16 Sep 2013 19:14:59 +0000
treeherdermozilla-beta@87d3c51cd2bf [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnbp
bugs893038
milestone25.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 893038 - Re-enable heavyweight function and cloned lambda inlining. r=nbp
js/src/ion/CodeGenerator.cpp
js/src/ion/CodeGenerator.h
js/src/ion/IonBuilder.cpp
js/src/ion/LIR-Common.h
js/src/ion/LOpcodes.h
js/src/ion/Lowering.cpp
js/src/ion/Lowering.h
js/src/ion/MIR.h
js/src/ion/MOpcodes.h
js/src/ion/ParallelSafetyAnalysis.cpp
--- a/js/src/ion/CodeGenerator.cpp
+++ b/js/src/ion/CodeGenerator.cpp
@@ -838,16 +838,28 @@ CodeGenerator::visitCallee(LCallee *lir)
     Address ptr(StackPointer, frameSize() + IonJSFrameLayout::offsetOfCalleeToken());
 
     masm.loadPtr(ptr, callee);
     masm.clearCalleeTag(callee, gen->info().executionMode());
     return true;
 }
 
 bool
+CodeGenerator::visitForceUseV(LForceUseV *lir)
+{
+    return true;
+}
+
+bool
+CodeGenerator::visitForceUseT(LForceUseT *lir)
+{
+    return true;
+}
+
+bool
 CodeGenerator::visitStart(LStart *lir)
 {
     return true;
 }
 
 bool
 CodeGenerator::visitReturn(LReturn *lir)
 {
--- a/js/src/ion/CodeGenerator.h
+++ b/js/src/ion/CodeGenerator.h
@@ -54,16 +54,18 @@ class CodeGenerator : public CodeGenerat
     bool visitLabel(LLabel *lir);
     bool visitNop(LNop *lir);
     bool visitOsiPoint(LOsiPoint *lir);
     bool visitGoto(LGoto *lir);
     bool visitTableSwitch(LTableSwitch *ins);
     bool visitTableSwitchV(LTableSwitchV *ins);
     bool visitParameter(LParameter *lir);
     bool visitCallee(LCallee *lir);
+    bool visitForceUseV(LForceUseV *lir);
+    bool visitForceUseT(LForceUseT *lir);
     bool visitStart(LStart *lir);
     bool visitReturn(LReturn *ret);
     bool visitDefVar(LDefVar *lir);
     bool visitDefFun(LDefFun *lir);
     bool visitOsrEntry(LOsrEntry *lir);
     bool visitOsrScopeChain(LOsrScopeChain *lir);
     bool visitStackArgT(LStackArgT *lir);
     bool visitStackArgV(LStackArgV *lir);
--- a/js/src/ion/IonBuilder.cpp
+++ b/js/src/ion/IonBuilder.cpp
@@ -189,33 +189,28 @@ IonBuilder::getPolyCallTargets(types::St
             if (obj->as<JSFunction>().isInterpreted() &&
                 !obj->as<JSFunction>().getOrCreateScript(cx))
             {
                 return false;
             }
             DebugOnly<bool> appendOk = targets.append(obj);
             JS_ASSERT(appendOk);
         } else {
-            /* Temporarily disable heavyweight-function inlining. */
-            targets.clear();
-            return true;
-#if 0
             types::TypeObject *typeObj = calleeTypes->getTypeObject(i);
             JS_ASSERT(typeObj);
             if (!typeObj->isFunction() || !typeObj->interpretedFunction) {
                 targets.clear();
                 return true;
             }
             if (!typeObj->interpretedFunction->getOrCreateScript(cx))
                 return false;
             DebugOnly<bool> appendOk = targets.append(typeObj->interpretedFunction);
             JS_ASSERT(appendOk);
 
             *gotLambda = true;
-#endif
         }
     }
 
     // For now, only inline "singleton" lambda calls
     if (*gotLambda && targets.length() > 1)
         targets.clear();
 
     return true;
@@ -3522,16 +3517,21 @@ IonBuilder::inlineScriptedCall(CallInfo 
     // When profiling add Inline_Exit instruction to indicate end of inlined function.
     if (instrumentedProfiling())
         returnBlock->add(MFunctionBoundary::New(NULL, MFunctionBoundary::Inline_Exit));
 
     // Inherit the slots from current and pop |fun|.
     returnBlock->inheritSlots(current);
     returnBlock->pop();
 
+    // If callee is not a constant, add an MForceUse with the callee to make sure that
+    // it gets kept alive across the inlined body.
+    if (!callInfo.fun()->isConstant())
+        returnBlock->add(MForceUse::New(callInfo.fun()));
+
     // Accumulate return values.
     MIRGraphExits &exits = *inlineBuilder.graph().exitAccumulator();
     if (exits.length() == 0) {
         // Inlining of functions that have no exit is not supported.
         calleeScript->analysis()->setIonUninlineable();
         abortReason_ = AbortReason_Inlining;
         return false;
     }
--- a/js/src/ion/LIR-Common.h
+++ b/js/src/ion/LIR-Common.h
@@ -214,16 +214,33 @@ class LParameter : public LInstructionHe
 
 // Stack offset for a word-sized immutable input value to a frame.
 class LCallee : public LInstructionHelper<1, 0, 0>
 {
   public:
     LIR_HEADER(Callee)
 };
 
+class LForceUseV : public LInstructionHelper<0, BOX_PIECES, 0>
+{
+  public:
+    LIR_HEADER(ForceUseV)
+};
+
+class LForceUseT : public LInstructionHelper<0, 1, 0>
+{
+  public:
+    LIR_HEADER(ForceUseT)
+
+    LForceUseT(const LAllocation &value)
+    {
+        setOperand(0, value);
+    }
+};
+
 // Base class for control instructions (goto, branch, etc.)
 template <size_t Succs, size_t Operands, size_t Temps>
 class LControlInstructionHelper : public LInstructionHelper<0, Operands, Temps> {
 
     MBasicBlock *successors_[Succs];
 
   public:
     virtual size_t numSuccessors() const MOZ_FINAL MOZ_OVERRIDE { return Succs; }
--- a/js/src/ion/LOpcodes.h
+++ b/js/src/ion/LOpcodes.h
@@ -13,16 +13,18 @@
     _(OsiPoint)                     \
     _(MoveGroup)                    \
     _(Integer)                      \
     _(Pointer)                      \
     _(Double)                       \
     _(Value)                        \
     _(Parameter)                    \
     _(Callee)                       \
+    _(ForceUseV)                    \
+    _(ForceUseT)                    \
     _(TableSwitch)                  \
     _(TableSwitchV)                 \
     _(Goto)                         \
     _(NewParallelArray)             \
     _(NewArray)                     \
     _(NewObject)                    \
     _(NewSlots)                     \
     _(NewDeclEnvObject)             \
--- a/js/src/ion/Lowering.cpp
+++ b/js/src/ion/Lowering.cpp
@@ -56,16 +56,30 @@ LIRGenerator::visitParameter(MParameter 
 
 bool
 LIRGenerator::visitCallee(MCallee *ins)
 {
     return define(new LCallee(), ins);
 }
 
 bool
+LIRGenerator::visitForceUse(MForceUse *ins)
+{
+    if (ins->input()->type() == MIRType_Value) {
+        LForceUseV *lir = new LForceUseV();
+        if (!useBox(lir, 0, ins->input()));
+            return false;
+        return add(lir);
+    }
+
+    LForceUseT *lir = new LForceUseT(useAnyOrConstant(ins->input()));
+    return add(lir);
+}
+
+bool
 LIRGenerator::visitGoto(MGoto *ins)
 {
     return add(new LGoto(ins->target()));
 }
 
 bool
 LIRGenerator::visitTableSwitch(MTableSwitch *tableswitch)
 {
--- a/js/src/ion/Lowering.h
+++ b/js/src/ion/Lowering.h
@@ -75,16 +75,17 @@ class LIRGenerator : public LIRGenerator
   public:
     bool visitInstruction(MInstruction *ins);
     bool visitBlock(MBasicBlock *block);
 
     // Visitor hooks are explicit, to give CPU-specific versions a chance to
     // intercept without a bunch of explicit gunk in the .cpp.
     bool visitParameter(MParameter *param);
     bool visitCallee(MCallee *callee);
+    bool visitForceUse(MForceUse *forceUse);
     bool visitGoto(MGoto *ins);
     bool visitTableSwitch(MTableSwitch *tableswitch);
     bool visitNewSlots(MNewSlots *ins);
     bool visitNewParallelArray(MNewParallelArray *ins);
     bool visitNewArray(MNewArray *ins);
     bool visitNewObject(MNewObject *ins);
     bool visitNewDeclEnvObject(MNewDeclEnvObject *ins);
     bool visitNewCallObject(MNewCallObject *ins);
--- a/js/src/ion/MIR.h
+++ b/js/src/ion/MIR.h
@@ -991,16 +991,44 @@ class MCallee : public MNullaryInstructi
     static MCallee *New() {
         return new MCallee();
     }
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 };
 
+// MForceUse exists to force the use of a resumePoint-recorded
+// instruction at a later point in time, so that the contents don't get
+// discarded when inlining.
+class MForceUse : public MUnaryInstruction
+{
+  public:
+    MForceUse(MDefinition *input)
+      : MUnaryInstruction(input)
+    {
+        setGuard();
+        setResultType(MIRType_None);
+    }
+
+  public:
+    INSTRUCTION_HEADER(ForceUse)
+
+    bool congruentTo(MDefinition * const &ins) const {
+        return false;
+    }
+
+    static MForceUse *New(MDefinition *input) {
+        return new MForceUse(input);
+    }
+    AliasSet getAliasSet() const {
+        return AliasSet::None();
+    }
+};
+
 class MControlInstruction : public MInstruction
 {
   public:
     MControlInstruction()
     { }
 
     virtual size_t numSuccessors() const = 0;
     virtual MBasicBlock *getSuccessor(size_t i) const = 0;
--- a/js/src/ion/MOpcodes.h
+++ b/js/src/ion/MOpcodes.h
@@ -9,16 +9,17 @@
 
 namespace js {
 namespace ion {
 
 #define MIR_OPCODE_LIST(_)                                                  \
     _(Constant)                                                             \
     _(Parameter)                                                            \
     _(Callee)                                                               \
+    _(ForceUse)                                                             \
     _(TableSwitch)                                                          \
     _(Goto)                                                                 \
     _(Test)                                                                 \
     _(TypeObjectDispatch)                                                   \
     _(FunctionDispatch)                                                     \
     _(PolyInlineDispatch)                                                   \
     _(Compare)                                                              \
     _(Phi)                                                                  \
--- a/js/src/ion/ParallelSafetyAnalysis.cpp
+++ b/js/src/ion/ParallelSafetyAnalysis.cpp
@@ -106,16 +106,17 @@ class ParallelSafetyVisitor : public MIn
     bool convertToBailout(MBasicBlock *block, MInstruction *ins);
 
     // I am taking the policy of blacklisting everything that's not
     // obviously safe for now.  We can loosen as we need.
 
     SAFE_OP(Constant)
     SAFE_OP(Parameter)
     SAFE_OP(Callee)
+    SAFE_OP(ForceUse)
     SAFE_OP(TableSwitch)
     SAFE_OP(Goto)
     SAFE_OP(Test)
     SAFE_OP(Compare)
     SAFE_OP(Phi)
     SAFE_OP(Beta)
     UNSAFE_OP(OsrValue)
     UNSAFE_OP(OsrScopeChain)