Bug 1166711 part 2.5 - ScalarReplacement: Replace M{Store,Load}UnboxedScalar by an offset on the MObjectState. r=bhackett
authorNicolas B. Pierron <nicolas.b.pierron@mozilla.com>
Thu, 11 Jun 2015 14:30:33 +0200
changeset 248315 46958967c5226d14b405af5e1f12c25414caafee
parent 248314 ace9cd550bf13f9b4ade331380bb1b1a1f2f419f
child 248316 bc6ecd2df3af947cb47026d4cf15ff5f87c69858
push id28893
push userkwierso@gmail.com
push dateFri, 12 Jun 2015 00:02:58 +0000
treeherderautoland@8cf9d3e497f9 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbhackett
bugs1166711
milestone41.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 1166711 part 2.5 - ScalarReplacement: Replace M{Store,Load}UnboxedScalar by an offset on the MObjectState. r=bhackett
js/src/jit/ScalarReplacement.cpp
--- a/js/src/jit/ScalarReplacement.cpp
+++ b/js/src/jit/ScalarReplacement.cpp
@@ -174,16 +174,31 @@ IsObjectEscaped(MInstruction* ins, JSObj
           case MDefinition::Op_LoadFixedSlot:
             // Not escaped if it is the first argument.
             if (def->indexOf(*i) == 0)
                 break;
 
             JitSpewDef(JitSpew_Escape, "is escaped by\n", def);
             return true;
 
+          case MDefinition::Op_LoadUnboxedScalar:
+          case MDefinition::Op_StoreUnboxedScalar:
+            // Not escaped if it is the first argument.
+            if (def->indexOf(*i) != 0) {
+                JitSpewDef(JitSpew_Escape, "is escaped by\n", def);
+                return true;
+            }
+
+            if (!def->getOperand(1)->isConstant()) {
+                JitSpewDef(JitSpew_Escape, "is addressed with unknown index\n", def);
+                return true;
+            }
+
+            break;
+
           case MDefinition::Op_PostWriteBarrier:
             break;
 
           case MDefinition::Op_Slots: {
 #ifdef DEBUG
             // Assert that MSlots are only used by MStoreSlot and MLoadSlot.
             MSlots* ins = def->toSlots();
             MOZ_ASSERT(ins->object() != 0);
@@ -273,16 +288,18 @@ class ObjectMemoryView : public MDefinit
     void visitStoreFixedSlot(MStoreFixedSlot* ins);
     void visitLoadFixedSlot(MLoadFixedSlot* ins);
     void visitPostWriteBarrier(MPostWriteBarrier* ins);
     void visitStoreSlot(MStoreSlot* ins);
     void visitLoadSlot(MLoadSlot* ins);
     void visitGuardShape(MGuardShape* ins);
     void visitFunctionEnvironment(MFunctionEnvironment* ins);
     void visitLambda(MLambda* ins);
+    void visitStoreUnboxedScalar(MStoreUnboxedScalar* ins);
+    void visitLoadUnboxedScalar(MLoadUnboxedScalar* ins);
 };
 
 const char* ObjectMemoryView::phaseName = "Scalar Replacement of Object";
 
 ObjectMemoryView::ObjectMemoryView(TempAllocator& alloc, MInstruction* obj)
   : alloc_(alloc),
     obj_(obj),
     startBlock_(obj->block()),
@@ -585,16 +602,60 @@ ObjectMemoryView::visitLambda(MLambda* i
     if (ins->scopeChain() != obj_)
         return;
 
     // In order to recover the lambda we need to recover the scope chain, as the
     // lambda is holding it.
     ins->setIncompleteObject();
 }
 
+size_t
+GetOffsetOf(MDefinition* index, Scalar::Type type, int32_t baseOffset)
+{
+    int32_t idx = index->toConstant()->value().toInt32();
+    size_t width = Scalar::byteSize(type);
+    MOZ_ASSERT(idx >= 0);
+    MOZ_ASSERT(baseOffset >= 0 && size_t(baseOffset) >= UnboxedPlainObject::offsetOfData());
+    return idx * width + baseOffset - UnboxedPlainObject::offsetOfData();
+}
+
+void
+ObjectMemoryView::visitStoreUnboxedScalar(MStoreUnboxedScalar* ins)
+{
+    // Skip stores made on other objects.
+    if (ins->elements() != obj_)
+        return;
+
+    // Clone the state and update the slot value.
+    size_t offset = GetOffsetOf(ins->index(), ins->storageType(), ins->offsetAdjustment());
+    MOZ_ASSERT(state_->hasOffset(offset));
+    state_ = BlockState::Copy(alloc_, state_);
+    state_->setOffset(offset, ins->value());
+    ins->block()->insertBefore(ins->toInstruction(), state_);
+
+    // Remove original instruction.
+    ins->block()->discard(ins);
+}
+
+void
+ObjectMemoryView::visitLoadUnboxedScalar(MLoadUnboxedScalar* ins)
+{
+    // Skip loads made on other objects.
+    if (ins->elements() != obj_)
+        return;
+
+    // Replace load by the slot value.
+    size_t offset = GetOffsetOf(ins->index(), ins->storageType(), ins->offsetAdjustment());
+    MOZ_ASSERT(state_->hasOffset(offset));
+    ins->replaceAllUsesWith(state_->getOffset(offset));
+
+    // Remove original instruction.
+    ins->block()->discard(ins);
+}
+
 static bool
 IndexOf(MDefinition* ins, int32_t* res)
 {
     MOZ_ASSERT(ins->isLoadElement() || ins->isStoreElement());
     MDefinition* indexDef = ins->getOperand(1); // ins->index();
     if (indexDef->isBoundsCheck())
         indexDef = indexDef->toBoundsCheck()->index();
     if (indexDef->isToInt32())