Compile JSOP_TOID (bug 727087, r=dvander)
authorJan de Mooij <jdemooij@mozilla.com>
Thu, 16 Feb 2012 11:36:53 +0100
changeset 112705 e3891c579d984be29c0f7cb3c47b532bb7ae4783
parent 112704 c4dc1640324cad5be2b42b7dc1684751bc654804
child 112706 5c6072296e4a12468d204b997aaae3850695b2ab
push id239
push userakeybl@mozilla.com
push dateThu, 03 Jan 2013 21:54:43 +0000
treeherdermozilla-release@3a7b66445659 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdvander
bugs727087
milestone13.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
Compile JSOP_TOID (bug 727087, r=dvander)
js/src/ion/CodeGenerator.cpp
js/src/ion/CodeGenerator.h
js/src/ion/IonBuilder.cpp
js/src/ion/IonBuilder.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
js/src/jit-test/tests/ion/toid.js
--- a/js/src/ion/CodeGenerator.cpp
+++ b/js/src/ion/CodeGenerator.cpp
@@ -1880,16 +1880,27 @@ CodeGenerator::visitOutOfLineTypeOfV(Out
     masm.storeCallResult(ToRegister(ins->output()));
     restoreLive(ins);
 
     masm.jump(ool->rejoin());
     return true;
 }
 
 bool
+CodeGenerator::visitToIdV(LToIdV *lir)
+{
+    typedef bool (*pf)(JSContext *, const Value &, const Value &, Value *);
+    static const VMFunction Info = FunctionInfo<pf>(ToIdOperation);
+
+    pushArg(ToValue(lir, LToIdV::Index));
+    pushArg(ToValue(lir, LToIdV::Object));
+    return callVM(Info, lir);
+}
+
+bool
 CodeGenerator::visitLoadElementV(LLoadElementV *load)
 {
     Register elements = ToRegister(load->elements());
     const ValueOperand out = ToOutValue(load);
 
     if (load->index()->isConstant())
         masm.loadValue(Address(elements, ToInt32(load->index()) * sizeof(Value)), out);
     else
--- a/js/src/ion/CodeGenerator.h
+++ b/js/src/ion/CodeGenerator.h
@@ -123,16 +123,17 @@ class CodeGenerator : public CodeGenerat
     bool visitCallGetProperty(LCallGetProperty *lir);
     bool visitCallGetName(LCallGetName *lir);
     bool visitCallGetNameTypeOf(LCallGetNameTypeOf *lir);
     bool visitCallGetElement(LCallGetElement *lir);
     bool visitCallSetElement(LCallSetElement *lir);
     bool visitThrow(LThrow *lir);
     bool visitTypeOfV(LTypeOfV *lir);
     bool visitOutOfLineTypeOfV(OutOfLineTypeOfV *ool);
+    bool visitToIdV(LToIdV *lir);
     bool visitLoadElementV(LLoadElementV *load);
     bool visitLoadElementHole(LLoadElementHole *lir);
     bool visitStoreElementT(LStoreElementT *lir);
     bool visitStoreElementV(LStoreElementV *lir);
     bool visitStoreElementHoleT(LStoreElementHoleT *lir);
     bool visitStoreElementHoleV(LStoreElementHoleV *lir);
     bool visitCallIteratorStart(LCallIteratorStart *lir);
     bool visitCallIteratorNext(LCallIteratorNext *lir);
--- a/js/src/ion/IonBuilder.cpp
+++ b/js/src/ion/IonBuilder.cpp
@@ -790,16 +790,19 @@ IonBuilder::inspectOpcode(JSOp op)
         return jsop_regexp(info().getRegExp(pc));
 
       case JSOP_OBJECT:
         return jsop_object(info().getObject(pc));
 
       case JSOP_TYPEOF:
         return jsop_typeof();
 
+      case JSOP_TOID:
+        return jsop_toid();
+
       case JSOP_LAMBDA:
         return jsop_lambda(info().getFunction(pc));
 
       case JSOP_DEFLOCALFUN:
         return jsop_deflocalfun(GET_SLOTNO(pc), info().getFunction(pc + SLOTNO_LEN));
 
       case JSOP_ITER:
         return jsop_iter(GET_INT8(pc));
@@ -3673,16 +3676,33 @@ IonBuilder::jsop_typeof()
     current->push(ins);
 
     if (ins->isEffectful() && !resumeAfter(ins))
         return false;
     return true;
 }
 
 bool
+IonBuilder::jsop_toid()
+{
+    // No-op if the index is an integer.
+    TypeOracle::Unary unary = oracle->unaryOp(script, pc);
+    if (unary.ival == MIRType_Int32)
+        return true;
+
+    MDefinition *index = current->pop();
+    MToId *ins = MToId::New(current->peek(-1), index);
+
+    current->add(ins);
+    current->push(ins);
+
+    return resumeAfter(ins);
+}
+
+bool
 IonBuilder::jsop_iter(uint8 flags)
 {
     MDefinition *obj = current->pop();
     MInstruction *ins = MIteratorStart::New(obj, flags);
 
     current->add(ins);
     current->push(ins);
 
--- a/js/src/ion/IonBuilder.h
+++ b/js/src/ion/IonBuilder.h
@@ -309,16 +309,17 @@ class IonBuilder : public MIRGenerator
     bool jsop_setprop(JSAtom *atom);
     bool jsop_newarray(uint32 count);
     bool jsop_regexp(RegExpObject *reobj);
     bool jsop_object(JSObject *obj);
     bool jsop_lambda(JSFunction *fun);
     bool jsop_deflocalfun(uint32 local, JSFunction *fun);
     bool jsop_this();
     bool jsop_typeof();
+    bool jsop_toid();
     bool jsop_iter(uint8 flags);
     bool jsop_iternext(uint8 depth);
     bool jsop_itermore();
     bool jsop_iterend();
 
     // Replace generic calls to native function by instructions which can be
     // specialized and which can enable GVN & LICM on these native calls.
     void discardCallArgs(uint32 argc, MDefinition **argv);
--- a/js/src/ion/LIR-Common.h
+++ b/js/src/ion/LIR-Common.h
@@ -260,16 +260,25 @@ class LTypeOfV : public LInstructionHelp
     MTypeOf *mir() const {
         return mir_->toTypeOf();
     }
     const LDefinition *output() {
         return getDef(0);
     }
 };
 
+class LToIdV : public LCallInstructionHelper<BOX_PIECES, 2 * BOX_PIECES, 0>
+{
+  public:
+    LIR_HEADER(ToIdV);
+
+    static const size_t Object = 0;
+    static const size_t Index = BOX_PIECES;
+};
+
 // Writes an argument for a function call to the frame's argument vector.
 class LStackArg : public LInstructionHelper<0, BOX_PIECES, 0>
 {
     uint32 argslot_; // Index into frame-scope argument vector.
 
   public:
     LIR_HEADER(StackArg);
 
--- a/js/src/ion/LOpcodes.h
+++ b/js/src/ion/LOpcodes.h
@@ -142,16 +142,17 @@
     _(SetPropertyCacheT)            \
     _(CallIteratorStart)            \
     _(CallIteratorNext)             \
     _(CallIteratorMore)             \
     _(CallIteratorEnd)              \
     _(ArrayLength)                  \
     _(StringLength)                 \
     _(TypeOfV)                      \
+    _(ToIdV)                        \
     _(Round)
 
 #if defined(JS_CPU_X86)
 # include "x86/LOpcodes-x86.h"
 #elif defined(JS_CPU_X64)
 # include "x64/LOpcodes-x64.h"
 #elif defined(JS_CPU_ARM)
 # include "arm/LOpcodes-arm.h"
--- a/js/src/ion/Lowering.cpp
+++ b/js/src/ion/Lowering.cpp
@@ -357,16 +357,29 @@ LIRGenerator::visitTypeOf(MTypeOf *ins)
 
     LTypeOfV *lir = new LTypeOfV();
     if (!useBox(lir, LTypeOfV::Input, opd))
         return false;
     return define(lir, ins) && assignSafepoint(lir, ins);
 }
 
 bool
+LIRGenerator::visitToId(MToId *ins)
+{
+    LToIdV *lir = new LToIdV();
+    if (!useBox(lir, LToIdV::Object, ins->lhs()))
+        return false;
+    if (!useBox(lir, LToIdV::Index, ins->rhs()))
+        return false;
+    if (!defineVMReturn(lir, ins))
+        return false;
+    return assignSafepoint(lir, ins);
+}
+
+bool
 LIRGenerator::visitBitNot(MBitNot *ins)
 {
     MDefinition *input = ins->getOperand(0);
 
     if (input->type() == MIRType_Int32)
         return lowerForALU(new LBitNotI(), ins, input);
 
     LBitNotV *lir = new LBitNotV;
--- a/js/src/ion/Lowering.h
+++ b/js/src/ion/Lowering.h
@@ -117,16 +117,17 @@ class LIRGenerator : public LIRGenerator
     bool visitNewArray(MNewArray *ins);
     bool visitCheckOverRecursed(MCheckOverRecursed *ins);
     bool visitPrepareCall(MPrepareCall *ins);
     bool visitPassArg(MPassArg *arg);
     bool visitCall(MCall *call);
     bool visitTest(MTest *test);
     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);
     bool visitRsh(MRsh *ins);
     bool visitUrsh(MUrsh *ins);
     bool visitRound(MRound *ins);
--- a/js/src/ion/MIR.h
+++ b/js/src/ion/MIR.h
@@ -1588,16 +1588,38 @@ class MTypeOf
         if (inputType_ <= MIRType_String)
             return AliasSet::None();
 
         // For objects, typeof may invoke an effectful typeof hook.
         return AliasSet::Store(AliasSet::Any);
     }
 };
 
+class MToId
+  : public MBinaryInstruction,
+    public BoxInputsPolicy
+{
+    MToId(MDefinition *object, MDefinition *index)
+      : MBinaryInstruction(object, index)
+    {
+        setResultType(MIRType_Value);
+    }
+
+  public:
+    INSTRUCTION_HEADER(ToId);
+
+    static MToId *New(MDefinition *object, MDefinition *index) {
+        return new MToId(object, index);
+    }
+
+    TypePolicy *typePolicy() {
+        return this;
+    }
+};
+
 class MBinaryBitwiseInstruction
   : public MBinaryInstruction,
     public BitwisePolicy
 {
   protected:
     MBinaryBitwiseInstruction(MDefinition *left, MDefinition *right)
       : MBinaryInstruction(left, right)
     {
--- a/js/src/ion/MOpcodes.h
+++ b/js/src/ion/MOpcodes.h
@@ -59,16 +59,17 @@ namespace ion {
     _(OsrScopeChain)                                                        \
     _(CheckOverRecursed)                                                    \
     _(RecompileCheck)                                                       \
     _(PrepareCall)                                                          \
     _(PassArg)                                                              \
     _(Call)                                                                 \
     _(BitNot)                                                               \
     _(TypeOf)                                                               \
+    _(ToId)                                                                 \
     _(BitAnd)                                                               \
     _(BitOr)                                                                \
     _(BitXor)                                                               \
     _(Lsh)                                                                  \
     _(Rsh)                                                                  \
     _(Ursh)                                                                 \
     _(Abs)                                                                  \
     _(Add)                                                                  \
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/toid.js
@@ -0,0 +1,10 @@
+function f(arr, index) {
+    for (var i=0; i<100; i++) {
+        arr[index]++;
+        ++arr[index];
+    }
+}
+var arr = [1, 2, 3];
+f(arr, "1");
+f(arr, 1);
+assertEq(arr[1], 402);