Bug 775186 - Part 1: Add PolyInlineDispatch instruction. (r=jandem)
authorKannan Vijayan <kvijayan@mozilla.com>
Wed, 18 Jul 2012 15:14:16 -0400
changeset 106562 787e00928fef52745d4cca6b567e54de463900f3
parent 106561 bef02b378666624c29ef59b0790374b28a725d2b
child 106563 02af560a8cc486670c985ebc497b9001f8b11375
push id23447
push userdanderson@mozilla.com
push dateTue, 11 Sep 2012 17:34:27 +0000
treeherdermozilla-central@fdfaef738a00 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjandem
bugs775186
milestone16.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 775186 - Part 1: Add PolyInlineDispatch instruction. (r=jandem)
js/src/ion/CodeGenerator.cpp
js/src/ion/CodeGenerator.h
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
--- a/js/src/ion/CodeGenerator.cpp
+++ b/js/src/ion/CodeGenerator.cpp
@@ -196,16 +196,35 @@ CodeGenerator::visitTestVAndBranch(LTest
 bool
 CodeGenerator::visitInlineFunctionGuard(LInlineFunctionGuard *lir)
 {
     Register inputReg = ToRegister(lir->input());
     masm.cmpPtr(inputReg, ImmGCPtr(lir->function()));
     emitBranch(Assembler::Equal, lir->functionBlock(), lir->fallbackBlock());
     return true;
 }
+ 
+bool
+CodeGenerator::visitPolyInlineDispatch(LPolyInlineDispatch *lir)
+{
+    MPolyInlineDispatch *mir = lir->mir();
+    Register inputReg = ToRegister(lir->input());
+
+    for (size_t i = 0; i < mir->numCallees(); i++) {
+        JSFunction *func = mir->getFunctionConstant(i)->value().toObject().toFunction();
+        LBlock *target = mir->getSuccessor(i)->lir();
+        if (i < mir->numCallees() - 1) {
+            masm.branchPtr(Assembler::Equal, inputReg, ImmGCPtr(func), target->label());
+        } else {
+            // Don't generate guard for final case
+            masm.jump(target->label());
+        }
+    }
+    return true;
+}
 
 bool
 CodeGenerator::visitIntToString(LIntToString *lir)
 {
     typedef JSFixedString *(*pf)(JSContext *, int);
     static const VMFunction IntToStringInfo = FunctionInfo<pf>(Int32ToString);
 
     pushArg(ToRegister(lir->input()));
--- a/js/src/ion/CodeGenerator.h
+++ b/js/src/ion/CodeGenerator.h
@@ -88,16 +88,17 @@ class CodeGenerator : public CodeGenerat
     bool visitOsrEntry(LOsrEntry *lir);
     bool visitOsrScopeChain(LOsrScopeChain *lir);
     bool visitStackArg(LStackArg *lir);
     bool visitValueToInt32(LValueToInt32 *lir);
     bool visitValueToDouble(LValueToDouble *lir);
     bool visitInt32ToDouble(LInt32ToDouble *lir);
     bool visitTestVAndBranch(LTestVAndBranch *lir);
     bool visitInlineFunctionGuard(LInlineFunctionGuard *lir);
+    bool visitPolyInlineDispatch(LPolyInlineDispatch *lir);
     bool visitIntToString(LIntToString *lir);
     bool visitInteger(LInteger *lir);
     bool visitRegExp(LRegExp *lir);
     bool visitLambda(LLambda *lir);
     bool visitLambdaForSingleton(LLambdaForSingleton *lir);
     bool visitPointer(LPointer *lir);
     bool visitSlots(LSlots *lir);
     bool visitStoreSlotV(LStoreSlotV *store);
--- a/js/src/ion/LIR-Common.h
+++ b/js/src/ion/LIR-Common.h
@@ -800,16 +800,36 @@ class LInlineFunctionGuard : public LIns
     JSFunction *function() const {
         return func_;
     }
     const LAllocation *input() {
         return getOperand(0);
     }
 };
 
+class LPolyInlineDispatch : public LInstructionHelper<0, 1, 0>
+{
+  // Accesses function/block table from MIR instruction.
+  public:
+    LIR_HEADER(PolyInlineDispatch);
+
+    LPolyInlineDispatch(const LAllocation &in) {
+        setOperand(0, in);
+    }
+
+    const LAllocation *input() {
+        return getOperand(0);
+    }
+
+    MPolyInlineDispatch *mir() {
+        return mir_->toPolyInlineDispatch();
+    }
+};
+
+
 // Compares two integral values of the same JS type, either integer or object.
 // For objects, both operands are in registers.
 class LCompare : public LInstructionHelper<1, 2, 0>
 {
     JSOp jsop_;
 
   public:
     LIR_HEADER(Compare);
--- a/js/src/ion/LOpcodes.h
+++ b/js/src/ion/LOpcodes.h
@@ -77,16 +77,17 @@
     _(ShiftOp)                      \
     _(Return)                       \
     _(Throw)                        \
     _(Phi)                          \
     _(TestIAndBranch)               \
     _(TestDAndBranch)               \
     _(TestVAndBranch)               \
     _(InlineFunctionGuard)          \
+    _(PolyInlineDispatch)           \
     _(Compare)                      \
     _(CompareD)                     \
     _(CompareS)                     \
     _(CompareV)                     \
     _(CompareAndBranch)             \
     _(CompareDAndBranch)            \
     _(CompareB)                     \
     _(CompareBAndBranch)            \
--- a/js/src/ion/Lowering.cpp
+++ b/js/src/ion/Lowering.cpp
@@ -424,16 +424,23 @@ bool
 LIRGenerator::visitInlineFunctionGuard(MInlineFunctionGuard *ins)
 {
     LInlineFunctionGuard *lir =
         new LInlineFunctionGuard(useRegister(ins->input()),
             ins->function(), ins->functionBlock(), ins->fallbackBlock());
     return add(lir);
 }
 
+bool
+LIRGenerator::visitPolyInlineDispatch(MPolyInlineDispatch *ins)
+{
+    LPolyInlineDispatch *lir = new LPolyInlineDispatch(useRegister(ins->input()));
+    return add(lir, ins);
+}
+
 static inline bool
 CanEmitCompareAtUses(MInstruction *ins)
 {
     if (!ins->canEmitAtUses())
         return false;
 
     bool foundTest = false;
     for (MUseIterator iter(ins->usesBegin()); iter != ins->usesEnd(); iter++) {
--- a/js/src/ion/Lowering.h
+++ b/js/src/ion/Lowering.h
@@ -121,16 +121,17 @@ class LIRGenerator : public LIRGenerator
     bool visitPrepareCall(MPrepareCall *ins);
     bool visitPassArg(MPassArg *arg);
     bool visitCreateThis(MCreateThis *ins);
     bool visitReturnFromCtor(MReturnFromCtor *ins);
     bool visitCall(MCall *call);
     bool visitApplyArgs(MApplyArgs *apply);
     bool visitTest(MTest *test);
     bool visitInlineFunctionGuard(MInlineFunctionGuard *test);
+    bool visitPolyInlineDispatch(MPolyInlineDispatch *ins);
     bool visitCompare(MCompare *comp);
     bool visitTypeOf(MTypeOf *ins);
     bool visitToId(MToId *ins);
     bool visitBitNot(MBitNot *ins);
     bool visitBitAnd(MBitAnd *ins);
     bool visitBitOr(MBitOr *ins);
     bool visitBitXor(MBitXor *ins);
     bool visitLsh(MLsh *ins);
--- a/js/src/ion/MIR.h
+++ b/js/src/ion/MIR.h
@@ -978,16 +978,98 @@ class MInlineFunctionGuard : public MAry
         return setSuccessor(1, fallback);
     }
 
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 };
 
+// Represents a polymorphic dispatch to one or more functions.
+class MPolyInlineDispatch : public MControlInstruction, public SingleObjectPolicy
+{
+    // A table to map JSFunctions to the blocks that execute them.
+    struct Entry {
+        MConstant *funcConst;
+        MBasicBlock *block;
+        Entry(MConstant *funcConst, MBasicBlock *block)
+            : funcConst(funcConst), block(block) {}
+    };
+    Vector<Entry, 4, IonAllocPolicy> dispatchTable_;
+
+    MDefinition *operand_;
+
+    MPolyInlineDispatch(MDefinition *ins)
+      : dispatchTable_(), operand_(NULL)
+    {
+        initOperand(0, ins);
+    }
+
+  protected:
+    virtual void setOperand(size_t index, MDefinition *operand) {
+        JS_ASSERT(index == 0);
+        operand_ = operand;
+    }
+
+  public:
+    INSTRUCTION_HEADER(PolyInlineDispatch);
+
+    virtual MDefinition *getOperand(size_t index) const {
+        JS_ASSERT(index == 0);
+        return operand_;
+    }
+
+    virtual size_t numOperands() const { return 1; }
+    virtual size_t numSuccessors() const { return dispatchTable_.length(); }
+
+    virtual void replaceSuccessor(size_t i, MBasicBlock *successor) {
+        JS_ASSERT(i < dispatchTable_.length());
+        dispatchTable_[i].block = successor;
+    }
+
+    static MPolyInlineDispatch *New(MDefinition *ins) {
+        return new MPolyInlineDispatch(ins);
+    }
+
+    size_t numCallees() const {
+        return dispatchTable_.length();
+    }
+
+    void addCallee(MConstant *funcConst, MBasicBlock *block) {
+        dispatchTable_.append(Entry(funcConst, block));
+    }
+
+    MConstant *getFunctionConstant(size_t i) const {
+        JS_ASSERT(i < numCallees());
+        return dispatchTable_[i].funcConst;
+    }
+
+    JSFunction *getFunction(size_t i) const {
+        return getFunctionConstant(i)->value().toObject().toFunction();
+    }
+
+    void setSuccessor(size_t i, MBasicBlock *successor) {
+        JS_ASSERT(i < numCallees());
+        dispatchTable_[i].block = successor;
+    }
+
+    MBasicBlock *getSuccessor(size_t i) const {
+        JS_ASSERT(i < numCallees());
+        return dispatchTable_[i].block;
+    }
+
+    MDefinition *input() const {
+        return getOperand(0);
+    }
+
+    TypePolicy *typePolicy() {
+        return this;
+    }
+};
+
 
 // Returns from this function to the previous caller.
 class MReturn
   : public MAryControlInstruction<1, 0>,
     public BoxInputsPolicy
 {
     MReturn(MDefinition *ins) {
         initOperand(0, ins);
--- a/js/src/ion/MOpcodes.h
+++ b/js/src/ion/MOpcodes.h
@@ -49,16 +49,17 @@ namespace ion {
 #define MIR_OPCODE_LIST(_)                                                  \
     _(Constant)                                                             \
     _(Parameter)                                                            \
     _(Callee)                                                               \
     _(TableSwitch)                                                          \
     _(Goto)                                                                 \
     _(Test)                                                                 \
     _(InlineFunctionGuard)                                                  \
+    _(PolyInlineDispatch)                                                   \
     _(Compare)                                                              \
     _(Phi)                                                                  \
     _(Beta)                                                                 \
     _(OsrValue)                                                             \
     _(OsrScopeChain)                                                        \
     _(ReturnFromCtor)                                                       \
     _(CheckOverRecursed)                                                    \
     _(RecompileCheck)                                                       \