Bug 899903 - OdinMonkey: merge AsmJSBoundsCheckVector with HeapAccessVector (r=mjrosenb)
authorLuke Wagner <luke@mozilla.com>
Wed, 31 Jul 2013 03:19:58 -0500
changeset 148311 e8a2344ce2a25929f6155b7c4ee6a64bc1848198
parent 148310 42dffbbe9e577d3ec727cc87d93df3afaee2040e
child 148312 e039d1a5523aa76ecae0c723eb9ba9002c20efa2
push id4085
push userbbajaj@mozilla.com
push dateMon, 05 Aug 2013 20:29:25 +0000
treeherdermozilla-aurora@ede8780a15bc [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmjrosenb
bugs899903
milestone25.0a1
Bug 899903 - OdinMonkey: merge AsmJSBoundsCheckVector with HeapAccessVector (r=mjrosenb)
js/src/ion/AsmJS.cpp
js/src/ion/AsmJSLink.cpp
js/src/ion/AsmJSModule.cpp
js/src/ion/AsmJSModule.h
js/src/ion/MIRGenerator.h
js/src/ion/RegisterSets.h
js/src/ion/arm/CodeGenerator-arm.cpp
js/src/ion/x86/CodeGenerator-x86.cpp
--- a/js/src/ion/AsmJS.cpp
+++ b/js/src/ion/AsmJS.cpp
@@ -1431,23 +1431,18 @@ class MOZ_STACK_CLASS ModuleCompiler
             return false;
         return exits_.add(p, Move(exitDescriptor), *exitIndex);
     }
     bool addGlobalAccess(AsmJSGlobalAccess access) {
         return globalAccesses_.append(access);
     }
 
     bool collectAccesses(MIRGenerator &gen) {
-#ifdef JS_CPU_ARM
-        if (!module_->addBoundsChecks(gen.asmBoundsChecks()))
-            return false;
-#else
         if (!module_->addHeapAccesses(gen.heapAccesses()))
             return false;
-#endif
         if (!globalAccesses_.appendAll(gen.globalAccesses()))
             return false;
         return true;
     }
 
 #ifdef MOZ_VTUNE
     bool trackProfiledFunction(const Func &func, unsigned endCodeOffset) {
         unsigned startCodeOffset = func.code()->offset();
@@ -1584,36 +1579,31 @@ class MOZ_STACK_CLASS ModuleCompiler
         // Function-pointer table entries
         for (unsigned i = 0; i < funcPtrTables_.length(); i++) {
             FuncPtrTable &table = funcPtrTables_[i];
             uint8_t **data = module_->globalDataOffsetToFuncPtrTable(table.globalDataOffset());
             for (unsigned j = 0; j < table.numElems(); j++)
                 data[j] = code + masm_.actualOffset(table.elem(j).code()->offset());
         }
 
-        // Global accesses in function bodies
+        // Fix up heap/global accesses now that compilation has finished
 #ifdef JS_CPU_ARM
-        JS_ASSERT(globalAccesses_.length() == 0);
         // The AsmJSHeapAccess offsets need to be updated to reflect the
         // "actualOffset" (an ARM distinction).
-        module_->convertBoundsChecksToActualOffset(masm_);
-
+        for (unsigned i = 0; i < module_->numHeapAccesses(); i++) {
+            AsmJSHeapAccess &access = module_->heapAccess(i);
+            access.setOffset(masm_.actualOffset(access.offset()));
+        }
+        JS_ASSERT(globalAccesses_.length() == 0);
 #else
-
         for (unsigned i = 0; i < globalAccesses_.length(); i++) {
             AsmJSGlobalAccess access = globalAccesses_[i];
             masm_.patchAsmJSGlobalAccess(access.offset, code, codeBytes, access.globalDataOffset);
         }
 #endif
-        // The AsmJSHeapAccess offsets need to be updated to reflect the
-        // "actualOffset" (an ARM distinction).
-        for (unsigned i = 0; i < module_->numHeapAccesses(); i++) {
-            AsmJSHeapAccess &access = module_->heapAccess(i);
-            access.updateOffset(masm_.actualOffset(access.offset()));
-        }
 
         *module = module_.forget();
 
         buildCompilationTimeReport(report);
         return true;
     }
 };
 
--- a/js/src/ion/AsmJSLink.cpp
+++ b/js/src/ion/AsmJSLink.cpp
@@ -215,32 +215,17 @@ DynamicallyLinkModule(JSContext *cx, Cal
         heap = &bufferVal.toObject().as<ArrayBufferObject>();
 
         if (!IsPowerOfTwo(heap->byteLength()) || heap->byteLength() < AsmJSAllocationGranularity)
             return LinkFail(cx, "ArrayBuffer byteLength must be a power of two greater than or equal to 4096");
 
         if (!ArrayBufferObject::prepareForAsmJS(cx, heap))
             return LinkFail(cx, "Unable to prepare ArrayBuffer for asm.js use");
 
-#if defined(JS_CPU_X86)
-        void *heapOffset = (void*)heap->dataPointer();
-        void *heapLength = (void*)heap->byteLength();
-        uint8_t *code = module.functionCode();
-        for (unsigned i = 0; i < module.numHeapAccesses(); i++) {
-            const AsmJSHeapAccess &access = module.heapAccess(i);
-            JSC::X86Assembler::setPointer(access.patchLengthAt(code), heapLength);
-            JSC::X86Assembler::setPointer(access.patchOffsetAt(code), heapOffset);
-        }
-#elif defined(JS_CPU_ARM)
-        // Now the length of the array is know, patch all of the bounds check sites
-        // with the new length.
-        ion::IonContext ic(cx, NULL);
-        module.patchBoundsChecks(heap->byteLength());
-
-#endif
+        module.patchHeapAccesses(heap, cx);
     }
 
     AutoObjectVector ffis(cx);
     if (!ffis.resize(module.numFFIs()))
         return false;
 
     for (unsigned i = 0; i < module.numGlobals(); i++) {
         AsmJSModule::Global &global = module.global(i);
--- a/js/src/ion/AsmJSModule.cpp
+++ b/js/src/ion/AsmJSModule.cpp
@@ -67,16 +67,36 @@ js::NewAsmJSModuleObject(JSContext *cx, 
     JSObject *obj = NewObjectWithGivenProto(cx, &AsmJSModuleClass, NULL, NULL);
     if (!obj)
         return NULL;
 
     obj->setReservedSlot(ASM_CODE_RESERVED_SLOT, PrivateValue(module->forget()));
     return obj;
 }
 
+void
+AsmJSModule::patchHeapAccesses(ArrayBufferObject *heap, JSContext *cx)
+{
+    JS_ASSERT(IsPowerOfTwo(heap->byteLength()));
+#if defined(JS_CPU_X86)
+    void *heapOffset = (void*)heap->dataPointer();
+    void *heapLength = (void*)heap->byteLength();
+    for (unsigned i = 0; i < heapAccesses_.length(); i++) {
+        JSC::X86Assembler::setPointer(heapAccesses_[i].patchLengthAt(code_), heapLength);
+        JSC::X86Assembler::setPointer(heapAccesses_[i].patchOffsetAt(code_), heapOffset);
+    }
+#elif defined(JS_CPU_ARM)
+    ion::IonContext ic(cx, NULL);
+    ion::AutoFlushCache afc("patchBoundsCheck");
+    uint32_t bits = mozilla::CeilingLog2(heap->byteLength());
+    for (unsigned i = 0; i < heapAccesses_.length(); i++)
+        ion::Assembler::updateBoundsCheck(bits, (ion::Instruction*)(heapAccesses_[i].offset() + code_));
+#endif
+}
+
 AsmJSModule::~AsmJSModule()
 {
     if (code_) {
         for (unsigned i = 0; i < numExits(); i++) {
             AsmJSModule::ExitDatum &exitDatum = exitIndexToGlobalDatum(i);
             if (!exitDatum.fun)
                 continue;
 
--- a/js/src/ion/AsmJSModule.h
+++ b/js/src/ion/AsmJSModule.h
@@ -355,31 +355,25 @@ class AsmJSModule
         }
     };
 
   private:
     typedef Vector<ExportedFunction, 0, SystemAllocPolicy> ExportedFunctionVector;
     typedef Vector<Global, 0, SystemAllocPolicy> GlobalVector;
     typedef Vector<Exit, 0, SystemAllocPolicy> ExitVector;
     typedef Vector<ion::AsmJSHeapAccess, 0, SystemAllocPolicy> HeapAccessVector;
-#if defined(JS_CPU_ARM)
-    typedef Vector<ion::AsmJSBoundsCheck, 0, SystemAllocPolicy> BoundsCheckVector;
-#endif
     typedef Vector<ion::IonScriptCounts *, 0, SystemAllocPolicy> FunctionCountsVector;
 #if defined(MOZ_VTUNE) or defined(JS_ION_PERF)
     typedef Vector<ProfiledFunction, 0, SystemAllocPolicy> ProfiledFunctionVector;
 #endif
 
     GlobalVector                          globals_;
     ExitVector                            exits_;
     ExportedFunctionVector                exports_;
     HeapAccessVector                      heapAccesses_;
-#if defined(JS_CPU_ARM)
-    BoundsCheckVector                     boundsChecks_;
-#endif
 #if defined(MOZ_VTUNE)
     ProfiledFunctionVector                profiledFunctions_;
 #endif
 #if defined(JS_ION_PERF)
     ProfiledFunctionVector                perfProfiledFunctions_;
     Vector<ProfiledBlocksFunction, 0, SystemAllocPolicy> perfProfiledBlocksFunctions_;
 #endif
 
@@ -671,43 +665,17 @@ class AsmJSModule
         return heapAccesses_.length();
     }
     ion::AsmJSHeapAccess &heapAccess(unsigned i) {
         return heapAccesses_[i];
     }
     const ion::AsmJSHeapAccess &heapAccess(unsigned i) const {
         return heapAccesses_[i];
     }
-#if defined(JS_CPU_ARM)
-    bool addBoundsChecks(const ion::AsmJSBoundsCheckVector &checks) {
-        return boundsChecks_.appendAll(checks);
-    }
-    void convertBoundsChecksToActualOffset(ion::MacroAssembler &masm) {
-        for (unsigned i = 0; i < boundsChecks_.length(); i++)
-            boundsChecks_[i].setOffset(masm.actualOffset(boundsChecks_[i].offset()));
-    }
-
-    void patchBoundsChecks(unsigned heapSize) {
-        if (heapSize == 0)
-            return;
-
-        ion::AutoFlushCache afc("patchBoundsCheck");
-        uint32_t bits = mozilla::CeilingLog2(heapSize);
-
-        for (unsigned i = 0; i < boundsChecks_.length(); i++)
-            ion::Assembler::updateBoundsCheck(bits, (ion::Instruction*)(boundsChecks_[i].offset() + code_));
-
-    }
-    unsigned numBoundsChecks() const {
-        return boundsChecks_.length();
-    }
-    const ion::AsmJSBoundsCheck &boundsCheck(unsigned i) const {
-        return boundsChecks_[i];
-    }
-#endif
+    void patchHeapAccesses(ArrayBufferObject *heap, JSContext *cx);
 
     void takeOwnership(JSC::ExecutablePool *pool, uint8_t *code, size_t codeBytes, size_t totalBytes) {
         JS_ASSERT(uintptr_t(code) % AsmJSPageSize == 0);
         codePool_ = pool;
         code_ = code;
         codeBytes_ = codeBytes;
         totalBytes_ = totalBytes;
     }
--- a/js/src/ion/MIRGenerator.h
+++ b/js/src/ion/MIRGenerator.h
@@ -110,31 +110,22 @@ class MIRGenerator
     void setPerformsAsmJSCall() {
         JS_ASSERT(compilingAsmJS());
         performsAsmJSCall_ = true;
     }
     bool performsAsmJSCall() const {
         JS_ASSERT(compilingAsmJS());
         return performsAsmJSCall_;
     }
-#ifndef JS_CPU_ARM
     bool noteHeapAccess(AsmJSHeapAccess heapAccess) {
         return asmJSHeapAccesses_.append(heapAccess);
     }
     const Vector<AsmJSHeapAccess, 0, IonAllocPolicy> &heapAccesses() const {
         return asmJSHeapAccesses_;
     }
-#else
-    bool noteBoundsCheck(uint32_t offsetBefore) {
-        return asmJSBoundsChecks_.append(AsmJSBoundsCheck(offsetBefore));
-    }
-    const Vector<AsmJSBoundsCheck, 0, IonAllocPolicy> &asmBoundsChecks() const {
-        return asmJSBoundsChecks_;
-    }
-#endif
     bool noteGlobalAccess(unsigned offset, unsigned globalDataOffset) {
         return asmJSGlobalAccesses_.append(AsmJSGlobalAccess(offset, globalDataOffset));
     }
     const Vector<AsmJSGlobalAccess, 0, IonAllocPolicy> &globalAccesses() const {
         return asmJSGlobalAccesses_;
     }
 
   public:
@@ -146,21 +137,17 @@ class MIRGenerator
     JSFunction *fun_;
     uint32_t nslots_;
     MIRGraph *graph_;
     bool error_;
     size_t cancelBuild_;
 
     uint32_t maxAsmJSStackArgBytes_;
     bool performsAsmJSCall_;
-#ifdef JS_CPU_ARM
-    AsmJSBoundsCheckVector asmJSBoundsChecks_;
-#else
     AsmJSHeapAccessVector asmJSHeapAccesses_;
-#endif
     AsmJSGlobalAccessVector asmJSGlobalAccesses_;
 
 #if defined(JS_ION_PERF)
     AsmJSPerfSpewer asmJSPerfSpewer_;
 
   public:
     AsmJSPerfSpewer &perfSpewer() { return asmJSPerfSpewer_; }
 #endif
--- a/js/src/ion/RegisterSets.h
+++ b/js/src/ion/RegisterSets.h
@@ -780,83 +780,66 @@ class ABIArg
 
     bool argInRegister() const { return kind() != Stack; }
     AnyRegister reg() const { return kind_ == GPR ? AnyRegister(gpr()) : AnyRegister(fpu()); }
 };
 
 class AsmJSHeapAccess
 {
     uint32_t offset_;
-    uint8_t opLength_;
 #if defined(JS_CPU_X86)
-    uint8_t cmpDelta_;
+    uint8_t cmpDelta_;  // the number of bytes from the cmp to the load/store instruction
 #endif
+#if defined(JS_CPU_X86) || defined(JS_CPU_X64)
+    uint8_t opLength_;  // the length of the load/store instruction
     uint8_t isFloat32Load_;
     ion::AnyRegister::Code loadedReg_ : 8;
+#endif
 
     JS_STATIC_ASSERT(ion::AnyRegister::Total < UINT8_MAX);
 
   public:
-#if defined(JS_CPU_X86)
-    AsmJSHeapAccess(uint32_t cmp, uint32_t offset, uint32_t after, ArrayBufferView::ViewType vt,
-                    AnyRegister loadedReg)
+#if defined(JS_CPU_X86) || defined(JS_CPU_X64)
+    AsmJSHeapAccess(uint32_t offset, uint32_t after, ArrayBufferView::ViewType vt,
+                    AnyRegister loadedReg, uint32_t cmp = UINT32_MAX)
       : offset_(offset),
-        opLength_(after - offset),
+# if defined(JS_CPU_X86)
         cmpDelta_(offset - cmp),
-        isFloat32Load_(vt == ArrayBufferView::TYPE_FLOAT32),
-        loadedReg_(loadedReg.code())
-    {}
-    AsmJSHeapAccess(uint32_t cmp, uint32_t offset, uint8_t after)
-      : offset_(offset),
-        opLength_(after - offset),
-        cmpDelta_(offset - cmp),
-        isFloat32Load_(false),
-        loadedReg_(UINT8_MAX)
-    {}
-#else
-    AsmJSHeapAccess(uint32_t offset, uint32_t after, ArrayBufferView::ViewType vt,
-                    AnyRegister loadedReg)
-      : offset_(offset),
+# endif
         opLength_(after - offset),
         isFloat32Load_(vt == ArrayBufferView::TYPE_FLOAT32),
         loadedReg_(loadedReg.code())
     {}
-    AsmJSHeapAccess(uint32_t offset, uint8_t after)
+    AsmJSHeapAccess(uint32_t offset, uint8_t after, uint32_t cmp = UINT32_MAX)
       : offset_(offset),
+# if defined(JS_CPU_X86)
+        cmpDelta_(offset - cmp),
+# endif
         opLength_(after - offset),
         isFloat32Load_(false),
         loadedReg_(UINT8_MAX)
     {}
+#elif defined(JS_CPU_ARM)
+    explicit AsmJSHeapAccess(uint32_t offset)
+      : offset_(offset)
+    {}
 #endif
 
     uint32_t offset() const { return offset_; }
-    unsigned opLength() const { return opLength_; }
-    bool isLoad() const { return loadedReg_ != UINT8_MAX; }
-    bool isFloat32Load() const { return isFloat32Load_; }
-    ion::AnyRegister loadedReg() const { return ion::AnyRegister::FromCode(loadedReg_); }
-
+    void setOffset(uint32_t offset) { offset_ = offset; }
 #if defined(JS_CPU_X86)
     void *patchLengthAt(uint8_t *code) const { return code + (offset_ - cmpDelta_); }
     void *patchOffsetAt(uint8_t *code) const { return code + (offset_ + opLength_); }
 #endif
-    void updateOffset(uint32_t offset) { offset_ = offset; }
+#if defined(JS_CPU_X86) || defined(JS_CPU_X64)
+    unsigned opLength() const { return opLength_; }
+    bool isLoad() const { return loadedReg_ != UINT8_MAX; }
+    bool isFloat32Load() const { return isFloat32Load_; }
+    ion::AnyRegister loadedReg() const { return ion::AnyRegister::FromCode(loadedReg_); }
+#endif
 };
 
 typedef Vector<AsmJSHeapAccess, 0, IonAllocPolicy> AsmJSHeapAccessVector;
 
-#ifdef JS_CPU_ARM
-struct AsmJSBoundsCheck
-{
-    unsigned offset_;
-    AsmJSBoundsCheck(unsigned offset)
-    : offset_(offset)
-    {}
-    void setOffset(uint32_t offset) { offset_ = offset; }
-    unsigned offset() {return offset_;}
-};
-
-typedef Vector<AsmJSBoundsCheck, 0, IonAllocPolicy> AsmJSBoundsCheckVector;
-#endif
-
 } // namespace ion
 } // namespace js
 
 #endif /* ion_RegisterSets_h */
--- a/js/src/ion/arm/CodeGenerator-arm.cpp
+++ b/js/src/ion/arm/CodeGenerator-arm.cpp
@@ -1803,17 +1803,17 @@ CodeGeneratorARM::visitAsmJSLoadHeap(LAs
             masm.ma_vldr(vd, HeapReg, index, 0, Assembler::Zero);
         }
         masm.ma_vmov(NANReg, ToFloatRegister(ins->output()), Assembler::NonZero);
     }  else {
         masm.ma_dataTransferN(IsLoad, size, isSigned, HeapReg, index,
                               ToRegister(ins->output()), Offset, Assembler::Zero);
         masm.ma_mov(Imm32(0), ToRegister(ins->output()), NoSetCond, Assembler::NonZero);
     }
-    return gen->noteBoundsCheck(bo.getOffset());
+    return gen->noteHeapAccess(AsmJSHeapAccess(bo.getOffset()));
 }
 
 bool
 CodeGeneratorARM::visitAsmJSStoreHeap(LAsmJSStoreHeap *ins)
 {
     const MAsmJSStoreHeap *mir = ins->mir();
     bool isSigned;
     int size;
@@ -1841,17 +1841,17 @@ CodeGeneratorARM::visitAsmJSStoreHeap(LA
             masm.storeFloat(vd, HeapReg, index, Assembler::Zero);
         } else {
             masm.ma_vstr(vd, HeapReg, index, 0, Assembler::Zero);
         }
     }  else {
         masm.ma_dataTransferN(IsStore, size, isSigned, HeapReg, index,
                               ToRegister(ins->value()), Offset, Assembler::Zero);
     }
-    return gen->noteBoundsCheck(bo.getOffset());
+    return gen->noteHeapAccess(AsmJSHeapAccess(bo.getOffset()));
 }
 
 bool
 CodeGeneratorARM::visitAsmJSPassStackArg(LAsmJSPassStackArg *ins)
 {
     const MAsmJSPassStackArg *mir = ins->mir();
     Operand dst(StackPointer, mir->spOffset());
     if (ins->arg()->isConstant()) {
--- a/js/src/ion/x86/CodeGenerator-x86.cpp
+++ b/js/src/ion/x86/CodeGenerator-x86.cpp
@@ -491,23 +491,23 @@ CodeGeneratorX86::visitAsmJSLoadHeap(LAs
     Address srcAddr(ptr, 0);
     if (vt == ArrayBufferView::TYPE_FLOAT32) {
         FloatRegister dest = ToFloatRegister(out);
         uint32_t before = masm.size();
         masm.movssWithPatch(srcAddr, dest);
         uint32_t after = masm.size();
         masm.cvtss2sd(dest, dest);
         masm.bind(ool->rejoin());
-        return gen->noteHeapAccess(AsmJSHeapAccess(cmp.offset(), before, after, vt, AnyRegister(dest)));
+        return gen->noteHeapAccess(AsmJSHeapAccess(before, after, vt, AnyRegister(dest), cmp.offset()));
     }
     uint32_t before = masm.size();
     loadViewTypeElement(vt, srcAddr, out);
     uint32_t after = masm.size();
     masm.bind(ool->rejoin());
-    return gen->noteHeapAccess(AsmJSHeapAccess(cmp.offset(), before, after, vt, ToAnyRegister(out)));
+    return gen->noteHeapAccess(AsmJSHeapAccess(before, after, vt, ToAnyRegister(out), cmp.offset()));
 }
 
 bool
 CodeGeneratorX86::visitOutOfLineLoadTypedArrayOutOfBounds(OutOfLineLoadTypedArrayOutOfBounds *ool)
 {
     if (ool->dest().isFloat()) {
         masm.movsd(&js_NaN, ool->dest().fpu());
     } else {
@@ -578,23 +578,23 @@ CodeGeneratorX86::visitAsmJSStoreHeap(LA
 
     Address dstAddr(ptr, 0);
     if (vt == ArrayBufferView::TYPE_FLOAT32) {
         masm.convertDoubleToFloat(ToFloatRegister(value), ScratchFloatReg);
         uint32_t before = masm.size();
         masm.movssWithPatch(ScratchFloatReg, dstAddr);
         uint32_t after = masm.size();
         masm.bind(&rejoin);
-        return gen->noteHeapAccess(AsmJSHeapAccess(cmp.offset(), before, after));
+        return gen->noteHeapAccess(AsmJSHeapAccess(before, after, cmp.offset()));
     }
     uint32_t before = masm.size();
     storeViewTypeElement(vt, value, dstAddr);
     uint32_t after = masm.size();
     masm.bind(&rejoin);
-    return gen->noteHeapAccess(AsmJSHeapAccess(cmp.offset(), before, after));
+    return gen->noteHeapAccess(AsmJSHeapAccess(before, after, cmp.offset()));
 }
 
 bool
 CodeGeneratorX86::visitAsmJSLoadGlobalVar(LAsmJSLoadGlobalVar *ins)
 {
     MAsmJSLoadGlobalVar *mir = ins->mir();
 
     CodeOffsetLabel label;