Implement JSOP_INITELEM. (Bug 691340, r=jandem)
authorNicolas Pierron <nioclas.b.pierron@mozilla.com>
Wed, 08 Feb 2012 08:02:14 -0800
changeset 112664 0eca72ae5ad25ee0dd5012640752b19120f6deb4
parent 112663 e4fb2cc5006a3993277027ff55d9b9708eab6e92
child 112665 c78194c6f53ca7ba2c1d4a3f808adf0adb5a4240
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)
reviewersjandem
bugs691340
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
Implement JSOP_INITELEM. (Bug 691340, r=jandem) Compile JSOP_INITELEM support.
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/ion/arm/MacroAssembler-arm.cpp
js/src/ion/shared/MacroAssembler-x86-shared.h
--- a/js/src/ion/CodeGenerator.cpp
+++ b/js/src/ion/CodeGenerator.cpp
@@ -973,16 +973,29 @@ bool
 CodeGenerator::visitInitializedLength(LInitializedLength *lir)
 {
     Address initLength(ToRegister(lir->elements()), ObjectElements::offsetOfInitializedLength());
     masm.load32(initLength, ToRegister(lir->output()));
     return true;
 }
 
 bool
+CodeGenerator::visitSetInitializedLength(LSetInitializedLength *lir)
+{
+    Address initLength(ToRegister(lir->elements()), ObjectElements::offsetOfInitializedLength());
+    Int32Key index = ToInt32Key(lir->index());
+
+    masm.bumpKey(&index, 1);
+    masm.storeKey(index, initLength);
+    // Restore register value if it is used/captured after.
+    masm.bumpKey(&index, -1);
+    return true;
+}
+
+bool
 CodeGenerator::visitBoundsCheck(LBoundsCheck *lir)
 {
     if (lir->index()->isConstant())
         masm.cmp32(ToRegister(lir->length()), Imm32(ToInt32(lir->index())));
     else
         masm.cmp32(ToRegister(lir->length()), ToRegister(lir->index()));
     return bailoutIf(Assembler::BelowOrEqual, lir->snapshot());
 }
--- a/js/src/ion/CodeGenerator.h
+++ b/js/src/ion/CodeGenerator.h
@@ -98,16 +98,17 @@ class CodeGenerator : public CodeGenerat
     bool visitTypeBarrier(LTypeBarrier *lir);
     bool visitCallNative(LCallNative *lir);
     bool visitCallGeneric(LCallGeneric *lir);
     bool visitDoubleToInt32(LDoubleToInt32 *lir);
     bool visitNewArray(LNewArray *builder);
     bool visitArrayLength(LArrayLength *lir);
     bool visitStringLength(LStringLength *lir);
     bool visitInitializedLength(LInitializedLength *lir);
+    bool visitSetInitializedLength(LSetInitializedLength *lir);
     bool visitBoundsCheck(LBoundsCheck *lir);
     bool visitBoundsCheckRange(LBoundsCheckRange *lir);
     bool visitBoundsCheckLower(LBoundsCheckLower *lir);
     bool visitLoadFixedSlotV(LLoadFixedSlotV *ins);
     bool visitLoadFixedSlotT(LLoadFixedSlotT *ins);
     bool visitStoreFixedSlotV(LStoreFixedSlotV *ins);
     bool visitStoreFixedSlotT(LStoreFixedSlotT *ins);
     bool visitAbsI(LAbsI *lir);
--- a/js/src/ion/IonBuilder.cpp
+++ b/js/src/ion/IonBuilder.cpp
@@ -707,16 +707,19 @@ IonBuilder::inspectOpcode(JSOp op)
 
       case JSOP_POP:
         current->pop();
         return true;
 
       case JSOP_NEWARRAY:
         return jsop_newarray(GET_UINT24(pc));
 
+      case JSOP_INITELEM:
+        return jsop_initelem();
+
       case JSOP_ENDINIT:
         return true;
 
       case JSOP_CALL:
         return jsop_call(GET_ARGC(pc), false);
 
       case JSOP_NEW:
         return jsop_call(GET_ARGC(pc), true);
@@ -2526,16 +2529,52 @@ IonBuilder::jsop_newarray(uint32 count)
     current->add(ins);
     current->push(ins);
 
     if (!resumeAfter(ins))
         return false;
     return true;
 }
 
+bool
+IonBuilder::jsop_initelem()
+{
+    if (oracle->propertyWriteCanSpecialize(script, pc)) {
+        if (oracle->elementWriteIsDense(script, pc))
+            return jsop_setelem_dense();
+    }
+
+    return abort("NYI: JSOP_INITELEM supports for non dense objects/arrays.");
+}
+
+bool
+IonBuilder::jsop_initelem_dense()
+{
+    MDefinition *value = current->pop();
+    MDefinition *id = current->pop();
+    MDefinition *obj = current->peek(-1);
+
+    // Get the elements vector.
+    MElements *elements = MElements::New(obj);
+    current->add(elements);
+
+    // Store the value.
+    MStoreElement *store = MStoreElement::New(elements, id, value);
+    current->add(store);
+
+    // Update the length.
+    MSetInitializedLength *initLength = MSetInitializedLength::New(elements, id);
+    current->add(initLength);
+
+    if (!resumeAfter(initLength))
+        return false;
+
+   return true;
+}
+
 MBasicBlock *
 IonBuilder::addBlock(MBasicBlock *block)
 {
     if (!block)
         return NULL;
     graph().addBlock(block);
     block->setLoopDepth(loops_.length());
     return block;
--- a/js/src/ion/IonBuilder.h
+++ b/js/src/ion/IonBuilder.h
@@ -300,16 +300,18 @@ class IonBuilder : public MIRGenerator
     bool jsop_getelem_dense();
     bool jsop_setelem();
     bool jsop_setelem_dense();
     bool jsop_length();
     bool jsop_length_fastPath();
     bool jsop_getprop(JSAtom *atom);
     bool jsop_setprop(JSAtom *atom);
     bool jsop_newarray(uint32 count);
+    bool jsop_initelem();
+    bool jsop_initelem_dense();
     bool jsop_regexp(RegExpObject *reobj);
     bool jsop_object(JSObject *obj);
     bool jsop_this();
     bool jsop_iter(uint8 flags);
     bool jsop_iternext(uint8 depth);
     bool jsop_itermore();
     bool jsop_iterend();
 
--- a/js/src/ion/LIR-Common.h
+++ b/js/src/ion/LIR-Common.h
@@ -1070,16 +1070,35 @@ class LInitializedLength : public LInstr
     const LAllocation *elements() {
         return getOperand(0);
     }
     const LDefinition *output() {
         return getDef(0);
     }
 };
 
+// Set a dense array's initialized length to an elements vector.
+class LSetInitializedLength : public LInstructionHelper<0, 2, 0>
+{
+  public:
+    LIR_HEADER(SetInitializedLength);
+
+    LSetInitializedLength(const LAllocation &elements, const LAllocation &index) {
+        setOperand(0, elements);
+        setOperand(1, index);
+    }
+
+    const LAllocation *elements() {
+        return getOperand(0);
+    }
+    const LAllocation *index() {
+        return getOperand(1);
+    }
+};
+
 // Read length field of an object element.
 class LArrayLength : public LInstructionHelper<1, 1, 0>
 {
   public:
     LIR_HEADER(ArrayLength);
 
     LArrayLength(const LAllocation &elements) {
         setOperand(0, elements);
--- a/js/src/ion/LOpcodes.h
+++ b/js/src/ion/LOpcodes.h
@@ -102,16 +102,17 @@
     _(StoreSlotV)                   \
     _(StoreSlotT)                   \
     _(GuardShape)                   \
     _(GuardClass)                   \
     _(WriteBarrierV)                \
     _(WriteBarrierT)                \
     _(TypeBarrier)                  \
     _(InitializedLength)            \
+    _(SetInitializedLength)         \
     _(BoundsCheck)                  \
     _(BoundsCheckRange)             \
     _(BoundsCheckLower)             \
     _(LoadElementV)                 \
     _(LoadElementT)                 \
     _(LoadElementHole)              \
     _(StoreElementV)                \
     _(StoreElementT)                \
--- a/js/src/ion/Lowering.cpp
+++ b/js/src/ion/Lowering.cpp
@@ -899,16 +899,27 @@ LIRGenerator::visitArrayLength(MArrayLen
 bool
 LIRGenerator::visitInitializedLength(MInitializedLength *ins)
 {
     JS_ASSERT(ins->elements()->type() == MIRType_Elements);
     return define(new LInitializedLength(useRegister(ins->elements())), ins);
 }
 
 bool
+LIRGenerator::visitSetInitializedLength(MSetInitializedLength *ins)
+{
+    JS_ASSERT(ins->elements()->type() == MIRType_Elements);
+    JS_ASSERT(ins->index()->type() == MIRType_Int32);
+
+    JS_ASSERT(ins->index()->isConstant());
+    return add(new LSetInitializedLength(useRegister(ins->elements()),
+                                         useRegisterOrConstant(ins->index())), ins);
+}
+
+bool
 LIRGenerator::visitBoundsCheck(MBoundsCheck *ins)
 {
     LInstruction *check;
     if (ins->minimum() || ins->maximum()) {
         check = new LBoundsCheckRange(useRegisterOrConstant(ins->index()),
                                       useRegister(ins->length()),
                                       temp(LDefinition::GENERAL));
     } else {
--- a/js/src/ion/Lowering.h
+++ b/js/src/ion/Lowering.h
@@ -150,16 +150,17 @@ class LIRGenerator : public LIRGenerator
     bool visitSlots(MSlots *ins);
     bool visitElements(MElements *ins);
     bool visitLoadSlot(MLoadSlot *ins);
     bool visitFunctionEnvironment(MFunctionEnvironment *ins);
     bool visitStoreSlot(MStoreSlot *ins);
     bool visitTypeBarrier(MTypeBarrier *ins);
     bool visitArrayLength(MArrayLength *ins);
     bool visitInitializedLength(MInitializedLength *ins);
+    bool visitSetInitializedLength(MSetInitializedLength *ins);
     bool visitBoundsCheck(MBoundsCheck *ins);
     bool visitBoundsCheckLower(MBoundsCheckLower *ins);
     bool visitLoadElement(MLoadElement *ins);
     bool visitLoadElementHole(MLoadElementHole *ins);
     bool visitStoreElement(MStoreElement *ins);
     bool visitStoreElementHole(MStoreElementHole *ins);
     bool visitLoadFixedSlot(MLoadFixedSlot *ins);
     bool visitStoreFixedSlot(MStoreFixedSlot *ins);
--- a/js/src/ion/MIR.h
+++ b/js/src/ion/MIR.h
@@ -2223,16 +2223,44 @@ class MInitializedLength
     bool congruentTo(MDefinition *const &ins) const {
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const {
         return AliasSet::Load(AliasSet::ObjectFields);
     }
 };
 
+// Set a dense array's initialized length to an elements vector.
+class MSetInitializedLength
+  : public MAryInstruction<2>
+{
+    MSetInitializedLength(MDefinition *elements, MDefinition *index)
+    {
+        setOperand(0, elements);
+        setOperand(1, index);
+    }
+
+  public:
+    INSTRUCTION_HEADER(SetInitializedLength);
+
+    static MSetInitializedLength *New(MDefinition *elements, MDefinition *index) {
+        return new MSetInitializedLength(elements, index);
+    }
+
+    MDefinition *elements() const {
+        return getOperand(0);
+    }
+    MDefinition *index() const {
+        return getOperand(1);
+    }
+    AliasSet getAliasSet() const {
+        return AliasSet::Store(AliasSet::ObjectFields);
+    }
+};
+
 // Load a dense array's initialized length from an elements vector.
 class MArrayLength
   : public MUnaryInstruction
 {
   public:
     MArrayLength(MDefinition *elements)
       : MUnaryInstruction(elements)
     {
--- a/js/src/ion/MOpcodes.h
+++ b/js/src/ion/MOpcodes.h
@@ -97,16 +97,17 @@ namespace ion {
     _(StoreSlot)                                                            \
     _(FunctionEnvironment)                                                  \
     _(TypeBarrier)                                                          \
     _(GetPropertyCache)                                                     \
     _(GuardShape)                                                           \
     _(GuardClass)                                                           \
     _(ArrayLength)                                                          \
     _(InitializedLength)                                                    \
+    _(SetInitializedLength)                                                 \
     _(BoundsCheck)                                                          \
     _(BoundsCheckLower)                                                     \
     _(LoadElement)                                                          \
     _(LoadElementHole)                                                      \
     _(StoreElement)                                                         \
     _(StoreElementHole)                                                     \
     _(LoadFixedSlot)                                                        \
     _(StoreFixedSlot)                                                       \
--- a/js/src/ion/arm/MacroAssembler-arm.cpp
+++ b/js/src/ion/arm/MacroAssembler-arm.cpp
@@ -1233,17 +1233,16 @@ MacroAssemblerARMCompat::setStackArg(con
 
 }
 
 void
 MacroAssemblerARMCompat::subPtr(Imm32 imm, const Register dest)
 {
     ma_sub(imm, dest);
 }
-
 void
 MacroAssemblerARMCompat::addPtr(Imm32 imm, const Register dest)
 {
     ma_add(imm, dest);
 }
 
 // higher level tag testing code
 Assembler::Condition
--- a/js/src/ion/shared/MacroAssembler-x86-shared.h
+++ b/js/src/ion/shared/MacroAssembler-x86-shared.h
@@ -230,17 +230,16 @@ class MacroAssemblerX86Shared : public A
 
         uint32 descriptor = MakeFrameDescriptor(framePushed(), IonFrame_JS);
         Push(Imm32(descriptor));
         Push(scratch);
 
         JS_ASSERT(framePushed() == initialDepth + IonExitFrameLayout::Size());
         return callOffset;
     }
-
     void callWithExitFrame(IonCode *target) {
         uint32 descriptor = MakeFrameDescriptor(framePushed(), IonFrame_JS);
         Push(Imm32(descriptor));
         call(target);
     }
     void callIon(const Register &callee) {
         call(callee);
     }