Bug 1027885 - OdinMonkey: optimize representation of StaticLinkData::absoluteLinks (r=dougc)
authorLuke Wagner <luke@mozilla.com>
Mon, 21 Jul 2014 10:58:33 -0500
changeset 216977 a15e60a850ccbad8e0fe76e7614390a1eb800da6
parent 216976 a90a7709ab2d5508dc1d05c59bc7ab2b4563491e
child 216978 49c063c58f9f40d4232c7c1f5a1d9b27cbe4d3c8
push id3979
push userraliiev@mozilla.com
push dateMon, 13 Oct 2014 16:35:44 +0000
treeherdermozilla-beta@30f2cc610691 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdougc
bugs1027885
milestone33.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 1027885 - OdinMonkey: optimize representation of StaticLinkData::absoluteLinks (r=dougc)
js/src/jit/AsmJS.cpp
js/src/jit/AsmJSModule.cpp
js/src/jit/AsmJSModule.h
js/src/jit/shared/Assembler-shared.h
--- a/js/src/jit/AsmJS.cpp
+++ b/js/src/jit/AsmJS.cpp
@@ -4042,30 +4042,30 @@ CheckMathBuiltinCall(FunctionCompiler &f
       case AsmJSMathBuiltin_imul:   return CheckMathIMul(f, callNode, retType, def, type);
       case AsmJSMathBuiltin_abs:    return CheckMathAbs(f, callNode, retType, def, type);
       case AsmJSMathBuiltin_sqrt:   return CheckMathSqrt(f, callNode, retType, def, type);
       case AsmJSMathBuiltin_fround: return CheckMathFRound(f, callNode, retType, def, type);
       case AsmJSMathBuiltin_min:    return CheckMathMinMax(f, callNode, retType, def, type, /* isMax = */ false);
       case AsmJSMathBuiltin_max:    return CheckMathMinMax(f, callNode, retType, def, type, /* isMax = */ true);
       case AsmJSMathBuiltin_ceil:   arity = 1; doubleCallee = AsmJSImm_CeilD;  floatCallee = AsmJSImm_CeilF;   break;
       case AsmJSMathBuiltin_floor:  arity = 1; doubleCallee = AsmJSImm_FloorD; floatCallee = AsmJSImm_FloorF;  break;
-      case AsmJSMathBuiltin_sin:    arity = 1; doubleCallee = AsmJSImm_SinD;   floatCallee = AsmJSImm_Invalid; break;
-      case AsmJSMathBuiltin_cos:    arity = 1; doubleCallee = AsmJSImm_CosD;   floatCallee = AsmJSImm_Invalid; break;
-      case AsmJSMathBuiltin_tan:    arity = 1; doubleCallee = AsmJSImm_TanD;   floatCallee = AsmJSImm_Invalid; break;
-      case AsmJSMathBuiltin_asin:   arity = 1; doubleCallee = AsmJSImm_ASinD;  floatCallee = AsmJSImm_Invalid; break;
-      case AsmJSMathBuiltin_acos:   arity = 1; doubleCallee = AsmJSImm_ACosD;  floatCallee = AsmJSImm_Invalid; break;
-      case AsmJSMathBuiltin_atan:   arity = 1; doubleCallee = AsmJSImm_ATanD;  floatCallee = AsmJSImm_Invalid; break;
-      case AsmJSMathBuiltin_exp:    arity = 1; doubleCallee = AsmJSImm_ExpD;   floatCallee = AsmJSImm_Invalid; break;
-      case AsmJSMathBuiltin_log:    arity = 1; doubleCallee = AsmJSImm_LogD;   floatCallee = AsmJSImm_Invalid; break;
-      case AsmJSMathBuiltin_pow:    arity = 2; doubleCallee = AsmJSImm_PowD;   floatCallee = AsmJSImm_Invalid; break;
-      case AsmJSMathBuiltin_atan2:  arity = 2; doubleCallee = AsmJSImm_ATan2D; floatCallee = AsmJSImm_Invalid; break;
+      case AsmJSMathBuiltin_sin:    arity = 1; doubleCallee = AsmJSImm_SinD;   floatCallee = AsmJSImm_Limit; break;
+      case AsmJSMathBuiltin_cos:    arity = 1; doubleCallee = AsmJSImm_CosD;   floatCallee = AsmJSImm_Limit; break;
+      case AsmJSMathBuiltin_tan:    arity = 1; doubleCallee = AsmJSImm_TanD;   floatCallee = AsmJSImm_Limit; break;
+      case AsmJSMathBuiltin_asin:   arity = 1; doubleCallee = AsmJSImm_ASinD;  floatCallee = AsmJSImm_Limit; break;
+      case AsmJSMathBuiltin_acos:   arity = 1; doubleCallee = AsmJSImm_ACosD;  floatCallee = AsmJSImm_Limit; break;
+      case AsmJSMathBuiltin_atan:   arity = 1; doubleCallee = AsmJSImm_ATanD;  floatCallee = AsmJSImm_Limit; break;
+      case AsmJSMathBuiltin_exp:    arity = 1; doubleCallee = AsmJSImm_ExpD;   floatCallee = AsmJSImm_Limit; break;
+      case AsmJSMathBuiltin_log:    arity = 1; doubleCallee = AsmJSImm_LogD;   floatCallee = AsmJSImm_Limit; break;
+      case AsmJSMathBuiltin_pow:    arity = 2; doubleCallee = AsmJSImm_PowD;   floatCallee = AsmJSImm_Limit; break;
+      case AsmJSMathBuiltin_atan2:  arity = 2; doubleCallee = AsmJSImm_ATan2D; floatCallee = AsmJSImm_Limit; break;
       default: MOZ_ASSUME_UNREACHABLE("unexpected mathBuiltin function");
     }
 
-    if (retType == RetType::Float && floatCallee == AsmJSImm_Invalid)
+    if (retType == RetType::Float && floatCallee == AsmJSImm_Limit)
         return f.fail(callNode, "math builtin cannot be used as float");
     if (retType != RetType::Double && retType != RetType::Float)
         return f.failf(callNode, "return type of math function is double or float, used as %s", retType.toType().toChars());
 
     FunctionCompiler::Call call(f, callNode, retType);
     if (retType == RetType::Float && !CheckCallArgs(f, callNode, CheckIsMaybeFloat, &call))
         return false;
     if (retType == RetType::Double && !CheckCallArgs(f, callNode, CheckIsMaybeDouble, &call))
--- a/js/src/jit/AsmJSModule.cpp
+++ b/js/src/jit/AsmJSModule.cpp
@@ -341,22 +341,20 @@ AsmJSModule::finish(ExclusiveContext *cx
         codeRanges_[i].updateOffsets(masm);
         JS_ASSERT_IF(i > 0, codeRanges_[i - 1].end() <= codeRanges_[i].begin());
     }
 #endif
     JS_ASSERT(pod.functionBytes_ % AsmJSPageSize == 0);
 
     // Absolute link metadata: absolute addresses that refer to some fixed
     // address in the address space.
+    AbsoluteLinkArray &absoluteLinks = staticLinkData_.absoluteLinks;
     for (size_t i = 0; i < masm.numAsmJSAbsoluteLinks(); i++) {
         AsmJSAbsoluteLink src = masm.asmJSAbsoluteLink(i);
-        AbsoluteLink link;
-        link.patchAt = CodeOffsetLabel(masm.actualOffset(src.patchAt.offset()));
-        link.target = src.target;
-        if (!staticLinkData_.absoluteLinks.append(link))
+        if (!absoluteLinks[src.target].append(masm.actualOffset(src.patchAt.offset())))
             return false;
     }
 
     // Relative link metadata: absolute addresses that refer to another point within
     // the asm.js module.
 
     // CodeLabels are used for switch cases and loads from doubles in the
     // constant pool.
@@ -678,17 +676,17 @@ AddressOf(AsmJSImmKind kind, ExclusiveCo
       case AsmJSImm_ExpD:
         return RedirectCall(FuncCast<double (double)>(exp), Args_Double_Double);
       case AsmJSImm_LogD:
         return RedirectCall(FuncCast<double (double)>(log), Args_Double_Double);
       case AsmJSImm_PowD:
         return RedirectCall(FuncCast(ecmaPow), Args_Double_DoubleDouble);
       case AsmJSImm_ATan2D:
         return RedirectCall(FuncCast(ecmaAtan2), Args_Double_DoubleDouble);
-      case AsmJSImm_Invalid:
+      case AsmJSImm_Limit:
         break;
     }
 
     MOZ_ASSUME_UNREACHABLE("Bad AsmJSImmKind");
     return nullptr;
 }
 
 void
@@ -706,21 +704,24 @@ AsmJSModule::staticallyLink(ExclusiveCon
         uint8_t *patchAt = code_ + link.patchAtOffset;
         uint8_t *target = code_ + link.targetOffset;
         if (link.isRawPointerPatch())
             *(uint8_t **)(patchAt) = target;
         else
             Assembler::PatchInstructionImmediate(patchAt, PatchedImmPtr(target));
     }
 
-    for (size_t i = 0; i < staticLinkData_.absoluteLinks.length(); i++) {
-        AbsoluteLink link = staticLinkData_.absoluteLinks[i];
-        Assembler::PatchDataWithValueCheck(CodeLocationLabel(code_ + link.patchAt.offset()),
-                                           PatchedImmPtr(AddressOf(link.target, cx)),
-                                           PatchedImmPtr((void*)-1));
+    for (size_t imm = 0; imm < AsmJSImm_Limit; imm++) {
+        const AsmJSModule::OffsetVector &offsets = staticLinkData_.absoluteLinks[imm];
+        void *target = AddressOf(AsmJSImmKind(imm), cx);
+        for (size_t i = 0; i < offsets.length(); i++) {
+            Assembler::PatchDataWithValueCheck(CodeLocationLabel(code_ + offsets[i]),
+                                               PatchedImmPtr(target),
+                                               PatchedImmPtr((void*)-1));
+        }
     }
 
     // Initialize global data segment
 
     for (size_t i = 0; i < exits_.length(); i++) {
         exitIndexToGlobalDatum(i).exit = interpExitTrampoline(exits_[i]);
         exitIndexToGlobalDatum(i).fun = nullptr;
     }
@@ -773,21 +774,24 @@ AsmJSModule::initHeap(Handle<ArrayBuffer
 }
 
 void
 AsmJSModule::restoreToInitialState(ArrayBufferObject *maybePrevBuffer, ExclusiveContext *cx)
 {
 #ifdef DEBUG
     // Put the absolute links back to -1 so PatchDataWithValueCheck assertions
     // in staticallyLink are valid.
-    for (size_t i = 0; i < staticLinkData_.absoluteLinks.length(); i++) {
-        AbsoluteLink link = staticLinkData_.absoluteLinks[i];
-        Assembler::PatchDataWithValueCheck(CodeLocationLabel(code_ + link.patchAt.offset()),
-                                           PatchedImmPtr((void*)-1),
-                                           PatchedImmPtr(AddressOf(link.target, cx)));
+    for (size_t imm = 0; imm < AsmJSImm_Limit; imm++) {
+        const AsmJSModule::OffsetVector &offsets = staticLinkData_.absoluteLinks[imm];
+        void *target = AddressOf(AsmJSImmKind(imm), cx);
+        for (size_t i = 0; i < offsets.length(); i++) {
+            Assembler::PatchDataWithValueCheck(CodeLocationLabel(code_ + offsets[i]),
+                                               PatchedImmPtr((void*)-1),
+                                               PatchedImmPtr(target));
+        }
     }
 #endif
 
     if (maybePrevBuffer) {
 #if defined(JS_CODEGEN_X86)
         // Subtract out the base-pointer added by AsmJSModule::initHeap.
         uint8_t *ptrBase = maybePrevBuffer->dataPointer();
         for (unsigned i = 0; i < heapAccesses_.length(); i++) {
@@ -1229,42 +1233,16 @@ AsmJSModule::CodeRange::updateOffsets(ji
 
     if (isFunction()) {
         setDeltas(masm.actualOffset(entryBefore),
                   masm.actualOffset(profilingJumpBefore),
                   masm.actualOffset(profilingEpilogueBefore));
     }
 }
 
-size_t
-AsmJSModule::StaticLinkData::serializedSize() const
-{
-    return sizeof(uint32_t) +
-           SerializedPodVectorSize(relativeLinks) +
-           SerializedPodVectorSize(absoluteLinks);
-}
-
-uint8_t *
-AsmJSModule::StaticLinkData::serialize(uint8_t *cursor) const
-{
-    cursor = WriteScalar<uint32_t>(cursor, interruptExitOffset);
-    cursor = SerializePodVector(cursor, relativeLinks);
-    cursor = SerializePodVector(cursor, absoluteLinks);
-    return cursor;
-}
-
-const uint8_t *
-AsmJSModule::StaticLinkData::deserialize(ExclusiveContext *cx, const uint8_t *cursor)
-{
-    (cursor = ReadScalar<uint32_t>(cursor, &interruptExitOffset)) &&
-    (cursor = DeserializePodVector(cx, cursor, &relativeLinks)) &&
-    (cursor = DeserializePodVector(cx, cursor, &absoluteLinks));
-    return cursor;
-}
-
 #if defined(MOZ_VTUNE) || defined(JS_ION_PERF)
 size_t
 AsmJSModule::ProfiledFunction::serializedSize() const
 {
     return SerializedNameSize(name) +
            sizeof(pod);
 }
 
@@ -1280,22 +1258,92 @@ const uint8_t *
 AsmJSModule::ProfiledFunction::deserialize(ExclusiveContext *cx, const uint8_t *cursor)
 {
     (cursor = DeserializeName(cx, cursor, &name)) &&
     (cursor = ReadBytes(cursor, &pod, sizeof(pod)));
     return cursor;
 }
 #endif
 
+size_t
+AsmJSModule::AbsoluteLinkArray::serializedSize() const
+{
+    size_t size = 0;
+    for (size_t i = 0; i < AsmJSImm_Limit; i++)
+        size += SerializedPodVectorSize(array_[i]);
+    return size;
+}
+
+uint8_t *
+AsmJSModule::AbsoluteLinkArray::serialize(uint8_t *cursor) const
+{
+    for (size_t i = 0; i < AsmJSImm_Limit; i++)
+        cursor = SerializePodVector(cursor, array_[i]);
+    return cursor;
+}
+
+const uint8_t *
+AsmJSModule::AbsoluteLinkArray::deserialize(ExclusiveContext *cx, const uint8_t *cursor)
+{
+    for (size_t i = 0; i < AsmJSImm_Limit; i++)
+        cursor = DeserializePodVector(cx, cursor, &array_[i]);
+    return cursor;
+}
+
+bool
+AsmJSModule::AbsoluteLinkArray::clone(ExclusiveContext *cx, AbsoluteLinkArray *out) const
+{
+    for (size_t i = 0; i < AsmJSImm_Limit; i++) {
+        if (!ClonePodVector(cx, array_[i], &out->array_[i]))
+            return false;
+    }
+    return true;
+}
+
+size_t
+AsmJSModule::AbsoluteLinkArray::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const
+{
+    size_t size = 0;
+    for (size_t i = 0; i < AsmJSImm_Limit; i++)
+        size += array_[i].sizeOfExcludingThis(mallocSizeOf);
+    return size;
+}
+
+size_t
+AsmJSModule::StaticLinkData::serializedSize() const
+{
+    return sizeof(uint32_t) +
+           SerializedPodVectorSize(relativeLinks) +
+           absoluteLinks.serializedSize();
+}
+
+uint8_t *
+AsmJSModule::StaticLinkData::serialize(uint8_t *cursor) const
+{
+    cursor = WriteScalar<uint32_t>(cursor, interruptExitOffset);
+    cursor = SerializePodVector(cursor, relativeLinks);
+    cursor = absoluteLinks.serialize(cursor);
+    return cursor;
+}
+
+const uint8_t *
+AsmJSModule::StaticLinkData::deserialize(ExclusiveContext *cx, const uint8_t *cursor)
+{
+    (cursor = ReadScalar<uint32_t>(cursor, &interruptExitOffset)) &&
+    (cursor = DeserializePodVector(cx, cursor, &relativeLinks)) &&
+    (cursor = absoluteLinks.deserialize(cx, cursor));
+    return cursor;
+}
+
 bool
 AsmJSModule::StaticLinkData::clone(ExclusiveContext *cx, StaticLinkData *out) const
 {
     out->interruptExitOffset = interruptExitOffset;
     return ClonePodVector(cx, relativeLinks, &out->relativeLinks) &&
-           ClonePodVector(cx, absoluteLinks, &out->absoluteLinks);
+           absoluteLinks.clone(cx, &out->absoluteLinks);
 }
 
 size_t
 AsmJSModule::StaticLinkData::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const
 {
     return relativeLinks.sizeOfExcludingThis(mallocSizeOf) +
            absoluteLinks.sizeOfExcludingThis(mallocSizeOf);
 }
--- a/js/src/jit/AsmJSModule.h
+++ b/js/src/jit/AsmJSModule.h
@@ -511,33 +511,49 @@ class AsmJSModule
         Kind kind_;
 #endif
         uint32_t patchAtOffset;
         uint32_t targetOffset;
     };
 
     typedef Vector<RelativeLink, 0, SystemAllocPolicy> RelativeLinkVector;
 
-    struct AbsoluteLink
+    typedef Vector<uint32_t, 0, SystemAllocPolicy> OffsetVector;
+
+    class AbsoluteLinkArray
     {
-        jit::CodeOffsetLabel patchAt;
-        jit::AsmJSImmKind target;
+        OffsetVector array_[jit::AsmJSImm_Limit];
+
+      public:
+        OffsetVector &operator[](size_t i) {
+            JS_ASSERT(i < jit::AsmJSImm_Limit);
+            return array_[i];
+        }
+        const OffsetVector &operator[](size_t i) const {
+            JS_ASSERT(i < jit::AsmJSImm_Limit);
+            return array_[i];
+        }
+
+        size_t serializedSize() const;
+        uint8_t *serialize(uint8_t *cursor) const;
+        const uint8_t *deserialize(ExclusiveContext *cx, const uint8_t *cursor);
+        bool clone(ExclusiveContext *cx, AbsoluteLinkArray *out) const;
+
+        size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
     };
 
-    typedef Vector<AbsoluteLink, 0, SystemAllocPolicy> AbsoluteLinkVector;
-
     // Static-link data is used to patch a module either after it has been
     // compiled or deserialized with various absolute addresses (of code or
     // data in the process) or relative addresses (of code or data in the same
     // AsmJSModule).
     struct StaticLinkData
     {
         uint32_t interruptExitOffset;
         RelativeLinkVector relativeLinks;
-        AbsoluteLinkVector absoluteLinks;
+        AbsoluteLinkArray absoluteLinks;
 
         size_t serializedSize() const;
         uint8_t *serialize(uint8_t *cursor) const;
         const uint8_t *deserialize(ExclusiveContext *cx, const uint8_t *cursor);
         bool clone(ExclusiveContext *cx, StaticLinkData *out) const;
 
         size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
     };
--- a/js/src/jit/shared/Assembler-shared.h
+++ b/js/src/jit/shared/Assembler-shared.h
@@ -759,17 +759,17 @@ enum AsmJSImmKind
     AsmJSImm_CeilD,
     AsmJSImm_CeilF,
     AsmJSImm_FloorD,
     AsmJSImm_FloorF,
     AsmJSImm_ExpD,
     AsmJSImm_LogD,
     AsmJSImm_PowD,
     AsmJSImm_ATan2D,
-    AsmJSImm_Invalid
+    AsmJSImm_Limit
 };
 
 // Pointer to be embedded as an immediate in asm.js code.
 class AsmJSImmPtr
 {
     AsmJSImmKind kind_;
   public:
     AsmJSImmKind kind() const { return kind_; }