Bug 902506 - OdinMonkey: cut all dependency on (Ion|JS)(Compartment|Runtime) via IonContext (r=sstangl)
authorLuke Wagner <luke@mozilla.com>
Thu, 08 Aug 2013 21:38:42 -0500
changeset 155847 dc5ef6e3d1e69f94910c0fc5e9fa549659502a9b
parent 155846 b827d6e2638069a9d92d49ecc0a14de41123839c
child 155848 79edb45669268a4c65044a21e464c586ea0945b4
push id2961
push userlsblakk@mozilla.com
push dateMon, 28 Oct 2013 21:59:28 +0000
treeherdermozilla-beta@73ef4f13486f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssstangl
bugs902506
milestone26.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 902506 - OdinMonkey: cut all dependency on (Ion|JS)(Compartment|Runtime) via IonContext (r=sstangl)
js/src/jit/AsmJS.cpp
js/src/jit/AsmJSModule.cpp
js/src/jit/AsmJSModule.h
js/src/jit/Ion.cpp
js/src/jit/Ion.h
js/src/jit/x64/MacroAssembler-x64.h
js/src/jit/x86/MacroAssembler-x86.h
js/src/jscntxt.h
--- a/js/src/jit/AsmJS.cpp
+++ b/js/src/jit/AsmJS.cpp
@@ -1209,19 +1209,16 @@ class MOZ_STACK_CLASS ModuleCompiler
         // Avoid spurious Label assertions on compilation failure.
         if (!stackOverflowLabel_.bound())
             stackOverflowLabel_.bind(0);
         if (!operationCallbackLabel_.bound())
             operationCallbackLabel_.bind(0);
     }
 
     bool init() {
-        if (!cx_->compartment()->ensureIonCompartmentExists(cx_))
-            return false;
-
         if (!globals_.init() || !exits_.init())
             return false;
 
         if (!standardLibraryMathNames_.init() ||
             !addStandardLibraryMathName("sin", AsmJSMathBuiltin_sin) ||
             !addStandardLibraryMathName("cos", AsmJSMathBuiltin_cos) ||
             !addStandardLibraryMathName("tan", AsmJSMathBuiltin_tan) ||
             !addStandardLibraryMathName("asin", AsmJSMathBuiltin_asin) ||
@@ -1561,36 +1558,20 @@ class MOZ_STACK_CLASS ModuleCompiler
         uint32_t bodyEnd = parser_.tokenStream.currentToken().pos.end;
         module_->initSourceDesc(parser_.ss, bodyStart_, bodyEnd);
 
         // Finish the code section.
         masm_.finish();
         if (masm_.oom())
             return false;
 
-        // The global data section sits immediately after the executable (and
-        // other) data allocated by the MacroAssembler. Round up bytesNeeded so
-        // that doubles/pointers stay aligned.
-        size_t codeBytes = AlignBytes(masm_.bytesNeeded(), sizeof(double));
-        size_t totalBytes = codeBytes + module_->globalDataBytes();
-
-        // The code must be page aligned, so include extra space so that we can
-        // AlignBytes the allocation result below.
-        size_t allocedBytes = totalBytes + AsmJSPageSize;
-
-        // Allocate the slab of memory.
-        JSC::ExecutableAllocator *execAlloc = cx_->compartment()->ionCompartment()->execAlloc();
-        JSC::ExecutablePool *pool;
-        uint8_t *unalignedBytes = (uint8_t*)execAlloc->alloc(allocedBytes, &pool, JSC::ASMJS_CODE);
-        if (!unalignedBytes)
+        // The returned memory is owned by module_.
+        uint8_t *code = module_->allocateCodeAndGlobalSegment(cx_, masm_.bytesNeeded());
+        if (!code)
             return false;
-        uint8_t *code = (uint8_t*)AlignBytes((uintptr_t)unalignedBytes, AsmJSPageSize);
-
-        // The ExecutablePool owns the memory and must be released by the AsmJSModule.
-        module_->takeOwnership(pool, code, codeBytes, totalBytes);
 
         // Copy the buffer into executable memory (c.f. IonCode::copyFrom).
         masm_.executableCopy(code);
         masm_.processCodeLabels(code);
         JS_ASSERT(masm_.jumpRelocationTableBytes() == 0);
         JS_ASSERT(masm_.dataRelocationTableBytes() == 0);
         JS_ASSERT(masm_.preBarrierTableBytes() == 0);
         JS_ASSERT(!masm_.hasEnteredExitFrame());
@@ -1617,24 +1598,24 @@ class MOZ_STACK_CLASS ModuleCompiler
                 data[j] = code + masm_.actualOffset(table.elem(j).code()->offset());
         }
 
         // Fix up heap/global accesses now that compilation has finished
 #ifdef JS_CPU_ARM
         // 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.setOffset(masm_.actualOffset(access.offset()));
+            AsmJSHeapAccess &a = module_->heapAccess(i);
+            a.setOffset(masm_.actualOffset(a.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);
+            AsmJSGlobalAccess a = globalAccesses_[i];
+            masm_.patchAsmJSGlobalAccess(a.offset, code, module_->globalData(), a.globalDataOffset);
         }
 #endif
 
         *module = module_.forget();
 
         buildCompilationTimeReport(report);
         return true;
     }
@@ -1775,17 +1756,17 @@ class FunctionCompiler
         return varInitializers_.append(init);
     }
 
     bool prepareToEmitMIR(const VarTypeVector &argTypes)
     {
         JS_ASSERT(locals_.count() == argTypes.length() + varInitializers_.length());
 
         alloc_  = lifo_.new_<TempAllocator>(&lifo_);
-        ionContext_.construct(m_.cx()->runtime(), m_.cx()->compartment(), alloc_);
+        ionContext_.construct(m_.cx(), alloc_);
 
         graph_  = lifo_.new_<MIRGraph>(alloc_);
         info_   = lifo_.new_<CompileInfo>(locals_.count(), SequentialExecution);
         mirGen_ = lifo_.new_<MIRGenerator>(cx()->compartment(), alloc_, graph_, info_);
 
         if (!newBlock(/* pred = */ NULL, &curBlock_, fn_))
             return false;
 
@@ -4857,17 +4838,17 @@ GenerateCodeForFinishedJob(ModuleCompile
     if (!task)
         return false;
 
     ModuleCompiler::Func &func = *reinterpret_cast<ModuleCompiler::Func *>(task->func);
     func.accumulateCompileTime(task->compileTime);
 
     {
         // Perform code generation on the main thread.
-        IonContext ionContext(m.cx()->runtime(), m.cx()->compartment(), &task->mir->temp());
+        IonContext ionContext(m.cx(), &task->mir->temp());
         if (!GenerateCode(m, func, *task->mir, *task->lir))
             return false;
     }
 
     group.compiledJobs++;
 
     // Clear the LifoAlloc for use by another worker.
     TempAllocator &tempAlloc = task->mir->temp();
@@ -6218,17 +6199,17 @@ GenerateStubs(ModuleCompiler &m)
 }
 
 static bool
 FinishModule(ModuleCompiler &m,
              ScopedJSDeletePtr<AsmJSModule> *module,
              ScopedJSFreePtr<char> *compilationTimeReport)
 {
     TempAllocator alloc(&m.cx()->tempLifoAlloc());
-    IonContext ionContext(m.cx()->runtime(), m.cx()->compartment(), &alloc);
+    IonContext ionContext(m.cx(), &alloc);
 
     if (!GenerateStubs(m))
         return false;
 
     return m.staticallyLink(module, compilationTimeReport);
 }
 
 static bool
--- a/js/src/jit/AsmJSModule.cpp
+++ b/js/src/jit/AsmJSModule.cpp
@@ -2,16 +2,24 @@
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "jit/AsmJSModule.h"
 #include "jit/IonCode.h"
 
+#ifndef XP_WIN
+# include <sys/mman.h>
+#endif
+
+#ifdef XP_WIN
+# include "jswin.h"
+#endif
+
 #include "jsobjinlines.h"
 
 using namespace js;
 
 static void AsmJSModuleObject_finalize(FreeOp *fop, JSObject *obj);
 static void AsmJSModuleObject_trace(JSTracer *trc, JSObject *obj);
 
 static const unsigned ASM_CODE_RESERVED_SLOT = 0;
@@ -87,16 +95,70 @@ AsmJSModule::patchHeapAccesses(ArrayBuff
     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
 }
 
+static uint8_t *
+AllocateExecutableMemory(ExclusiveContext *cx, size_t totalBytes)
+{
+    JS_ASSERT(totalBytes % AsmJSPageSize == 0);
+
+#ifdef XP_WIN
+    void *p = VirtualAlloc(NULL, totalBytes, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
+    if (!p) {
+        js_ReportOutOfMemory(cx);
+        return NULL;
+    }
+#else  // assume Unix
+    void *p = mmap(NULL, totalBytes, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANON, -1, 0);
+    if (p == MAP_FAILED) {
+        js_ReportOutOfMemory(cx);
+        return NULL;
+    }
+#endif
+
+    return (uint8_t *)p;
+}
+
+static void
+DeallocateExecutableMemory(uint8_t *code, size_t totalBytes)
+{
+#ifdef XP_WIN
+        JS_ALWAYS_TRUE(VirtualFree(code, 0, MEM_RELEASE));
+#else
+        JS_ALWAYS_TRUE(munmap(code, totalBytes) == 0);
+#endif
+}
+
+uint8_t *
+AsmJSModule::allocateCodeAndGlobalSegment(ExclusiveContext *cx, size_t bytesNeeded)
+{
+    JS_ASSERT(!code_);
+
+    // The global data section sits immediately after the executable (and
+    // other) data allocated by the MacroAssembler, so ensure it is
+    // double-aligned.
+    codeBytes_ = AlignBytes(bytesNeeded, sizeof(double));
+
+    // The entire region is allocated via mmap/VirtualAlloc which requires
+    // units of pages.
+    totalBytes_ = AlignBytes(codeBytes_ + globalDataBytes(), AsmJSPageSize);
+
+    code_ = AllocateExecutableMemory(cx, totalBytes_);
+    if (!code_)
+        return NULL;
+
+    JS_ASSERT(uintptr_t(code_) % AsmJSPageSize == 0);
+    return code_;
+}
+
 AsmJSModule::~AsmJSModule()
 {
     if (code_) {
         for (unsigned i = 0; i < numExits(); i++) {
             AsmJSModule::ExitDatum &exitDatum = exitIndexToGlobalDatum(i);
             if (!exitDatum.fun)
                 continue;
 
@@ -105,13 +167,15 @@ AsmJSModule::~AsmJSModule()
 
             JSScript *script = exitDatum.fun->nonLazyScript();
             if (!script->hasIonScript())
                 continue;
 
             ion::DependentAsmJSModuleExit exit(this, i);
             script->ionScript()->removeDependentAsmJSModule(exit);
         }
+
+        DeallocateExecutableMemory(code_, totalBytes_);
     }
 
     for (size_t i = 0; i < numFunctionCounts(); i++)
         js_delete(functionCounts(i));
 }
--- a/js/src/jit/AsmJSModule.h
+++ b/js/src/jit/AsmJSModule.h
@@ -348,17 +348,16 @@ class AsmJSModule
     Vector<ProfiledBlocksFunction, 0, SystemAllocPolicy> perfProfiledBlocksFunctions_;
 #endif
 
     uint32_t                              numGlobalVars_;
     uint32_t                              numFFIs_;
     size_t                                funcPtrTableAndExitBytes_;
     bool                                  hasArrayView_;
 
-    ScopedReleasePtr<JSC::ExecutablePool> codePool_;
     uint8_t *                             code_;
     uint8_t *                             operationCallbackExit_;
     size_t                                functionBytes_;
     size_t                                codeBytes_;
     size_t                                totalBytes_;
 
     bool                                  linked_;
     HeapPtr<ArrayBufferObject>            maybeHeap_;
@@ -643,23 +642,18 @@ class AsmJSModule
     ion::AsmJSHeapAccess &heapAccess(unsigned i) {
         return heapAccesses_[i];
     }
     const ion::AsmJSHeapAccess &heapAccess(unsigned i) const {
         return heapAccesses_[i];
     }
     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;
-    }
+    uint8_t *allocateCodeAndGlobalSegment(ExclusiveContext *cx, size_t bytesNeeded);
+
     uint8_t *functionCode() const {
         JS_ASSERT(code_);
         JS_ASSERT(uintptr_t(code_) % AsmJSPageSize == 0);
         return code_;
     }
 
     void setOperationCallbackExit(uint8_t *ptr) {
         operationCallbackExit_ = ptr;
--- a/js/src/jit/Ion.cpp
+++ b/js/src/jit/Ion.cpp
@@ -119,16 +119,27 @@ IonContext::IonContext(JSContext *cx, Te
     compartment(cx->compartment()),
     temp(temp),
     prev_(CurrentIonContext()),
     assemblerCount_(0)
 {
     SetIonContext(this);
 }
 
+IonContext::IonContext(ExclusiveContext *cx, TempAllocator *temp)
+  : runtime(cx->runtime_),
+    cx(NULL),
+    compartment(NULL),
+    temp(temp),
+    prev_(CurrentIonContext()),
+    assemblerCount_(0)
+{
+    SetIonContext(this);
+}
+
 IonContext::IonContext(JSRuntime *rt, JSCompartment *comp, TempAllocator *temp)
   : runtime(rt),
     cx(NULL),
     compartment(comp),
     temp(temp),
     prev_(CurrentIonContext()),
     assemblerCount_(0)
 {
--- a/js/src/jit/Ion.h
+++ b/js/src/jit/Ion.h
@@ -268,16 +268,17 @@ enum AbortReason {
 // of the Ion compiler. It points to a temporary allocator and the active
 // JSContext, either of which may be NULL, and the active compartment, which
 // will not be NULL.
 
 class IonContext
 {
   public:
     IonContext(JSContext *cx, TempAllocator *temp);
+    IonContext(ExclusiveContext *cx, TempAllocator *temp);
     IonContext(JSRuntime *rt, JSCompartment *comp, TempAllocator *temp);
     IonContext(JSRuntime *rt);
     ~IonContext();
 
     JSRuntime *runtime;
     JSContext *cx;
     JSCompartment *compartment;
     TempAllocator *temp;
--- a/js/src/jit/x64/MacroAssembler-x64.h
+++ b/js/src/jit/x64/MacroAssembler-x64.h
@@ -1112,22 +1112,22 @@ class MacroAssemblerX64 : public MacroAs
         push(Imm32(0)); // num actual args.
         push(calleeToken);
         push(Imm32(MakeFrameDescriptor(0, IonFrame_Osr)));
         call(code);
         addq(Imm32(sizeof(uintptr_t) * 2), rsp);
     }
 
     // See CodeGeneratorX64 calls to noteAsmJSGlobalAccess.
-    void patchAsmJSGlobalAccess(unsigned offset, uint8_t *code, unsigned codeBytes,
+    void patchAsmJSGlobalAccess(unsigned offset, uint8_t *code, uint8_t *globalData,
                                 unsigned globalDataOffset)
     {
         uint8_t *nextInsn = code + offset;
-        JS_ASSERT(nextInsn <= code + codeBytes);
-        uint8_t *target = code + codeBytes + globalDataOffset;
+        JS_ASSERT(nextInsn <= globalData);
+        uint8_t *target = globalData + globalDataOffset;
         ((int32_t *)nextInsn)[-1] = target - nextInsn;
     }
     void memIntToValue(Address Source, Address Dest) {
         load32(Source, ScratchReg);
         storeValue(JSVAL_TYPE_INT32, ScratchReg, Dest);
     }
 
 };
--- a/js/src/jit/x86/MacroAssembler-x86.h
+++ b/js/src/jit/x86/MacroAssembler-x86.h
@@ -976,22 +976,22 @@ class MacroAssemblerX86 : public MacroAs
         push(Imm32(0)); // num actual args.
         push(calleeToken);
         push(Imm32(MakeFrameDescriptor(0, IonFrame_Osr)));
         call(code);
         addl(Imm32(sizeof(uintptr_t) * 2), esp);
     }
 
     // See CodeGeneratorX86 calls to noteAsmJSGlobalAccess.
-    void patchAsmJSGlobalAccess(unsigned offset, uint8_t *code, unsigned codeBytes,
+    void patchAsmJSGlobalAccess(unsigned offset, uint8_t *code, uint8_t *globalData,
                                 unsigned globalDataOffset)
     {
         uint8_t *nextInsn = code + offset;
-        JS_ASSERT(nextInsn <= code + codeBytes);
-        uint8_t *target = code + codeBytes + globalDataOffset;
+        JS_ASSERT(nextInsn <= globalData);
+        uint8_t *target = globalData + globalDataOffset;
         ((int32_t *)nextInsn)[-1] = uintptr_t(target);
     }
 };
 
 typedef MacroAssemblerX86 MacroAssemblerSpecific;
 
 } // namespace ion
 } // namespace js
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -29,16 +29,18 @@ js_ReportOutOfMemory(js::ThreadSafeConte
 extern void
 js_ReportAllocationOverflow(js::ThreadSafeContext *cx);
 
 extern void
 js_ReportOverRecursed(js::ThreadSafeContext *cx);
 
 namespace js {
 
+namespace ion { class IonContext; }
+
 struct CallsiteCloneKey {
     /* The original function that we are cloning. */
     JSFunction *original;
 
     /* The script of the call. */
     JSScript *script;
 
     /* The offset of the call. */
@@ -276,16 +278,17 @@ struct WorkerThread;
 
 class ExclusiveContext : public ThreadSafeContext
 {
     friend class gc::ArenaLists;
     friend class AutoCompartment;
     friend class AutoLockForExclusiveAccess;
     friend struct StackBaseShape;
     friend void JSScript::initCompartment(ExclusiveContext *cx);
+    friend class ion::IonContext;
 
     // The worker on which this context is running, if this is not a JSContext.
     WorkerThread *workerThread;
 
   public:
 
     ExclusiveContext(JSRuntime *rt, PerThreadData *pt, ContextKind kind)
       : ThreadSafeContext(rt, pt, kind),