Bug 965880 - OdinMonkey: don't forget to AutoUnprotectCode and prepareForAsmJS (r=bbouvier)
authorLuke Wagner <luke@mozilla.com>
Thu, 09 Oct 2014 20:04:41 -0500
changeset 233072 0fbe7cd05a11269bcdd7e43da91ff16994fd97ff
parent 233071 0402daa909e416b596ddac2980e916907ed27205
child 233073 8ac5fed378308a056073c03a4834aabda14860c9
push id1
push usersledru@mozilla.com
push dateThu, 04 Dec 2014 17:57:20 +0000
reviewersbbouvier
bugs965880
milestone35.0a1
Bug 965880 - OdinMonkey: don't forget to AutoUnprotectCode and prepareForAsmJS (r=bbouvier)
js/src/asmjs/AsmJSLink.cpp
js/src/asmjs/AsmJSModule.cpp
js/src/asmjs/AsmJSModule.h
js/src/jit-test/tests/asm.js/testResize.js
--- a/js/src/asmjs/AsmJSLink.cpp
+++ b/js/src/asmjs/AsmJSLink.cpp
@@ -565,19 +565,29 @@ ChangeHeap(JSContext *cx, AsmJSModule &m
 {
     HandleValue bufferArg = args.get(0);
     if (!IsArrayBuffer(bufferArg)) {
         ReportIncompatible(cx, args);
         return false;
     }
 
     Rooted<ArrayBufferObject*> newBuffer(cx, &bufferArg.toObject().as<ArrayBufferObject>());
-    bool rval = module.changeHeap(newBuffer, cx);
+    uint32_t heapLength = newBuffer->byteLength();
+    if (heapLength & module.heapLengthMask() || heapLength < module.minHeapLength()) {
+        args.rval().set(BooleanValue(false));
+        return true;
+    }
 
-    args.rval().set(BooleanValue(rval));
+    MOZ_ASSERT(IsValidAsmJSHeapLength(heapLength));
+    MOZ_ASSERT(!IsDeprecatedAsmJSHeapLength(heapLength));
+
+    if (!ArrayBufferObject::prepareForAsmJS(cx, newBuffer, module.usesSignalHandlersForOOB()))
+        return false;
+
+    args.rval().set(BooleanValue(module.changeHeap(newBuffer, cx)));
     return true;
 }
 
 // An asm.js function stores, in its extended slots:
 //  - a pointer to the module from which it was returned
 //  - its index in the ordered list of exported functions
 static const unsigned ASM_MODULE_SLOT = 0;
 static const unsigned ASM_EXPORT_INDEX_SLOT = 1;
--- a/js/src/asmjs/AsmJSModule.cpp
+++ b/js/src/asmjs/AsmJSModule.cpp
@@ -726,16 +726,18 @@ AsmJSModule::staticallyLink(ExclusiveCon
     }
 
     MOZ_ASSERT(isStaticallyLinked());
 }
 
 void
 AsmJSModule::initHeap(Handle<ArrayBufferObjectMaybeShared *> heap, JSContext *cx)
 {
+    MOZ_ASSERT_IF(heap->is<ArrayBufferObject>(),
+                  heap->as<ArrayBufferObject>().isAsmJSArrayBuffer());
     MOZ_ASSERT(IsValidAsmJSHeapLength(heap->byteLength()));
     MOZ_ASSERT(dynamicallyLinked_);
     MOZ_ASSERT(!maybeHeap_);
 
     maybeHeap_ = heap;
     heapDatum() = heap->dataPointer();
 
 #if defined(JS_CODEGEN_X86)
@@ -767,16 +769,17 @@ AsmJSModule::initHeap(Handle<ArrayBuffer
     uint32_t heapLength = heap->byteLength();
     for (unsigned i = 0; i < heapAccesses_.length(); i++) {
         jit::Assembler::UpdateBoundsCheck(heapLength,
                                           (jit::Instruction*)(heapAccesses_[i].offset() + code_));
     }
 #endif
 }
 
+// This method assumes the caller has a live AutoUnprotectCode.
 void
 AsmJSModule::restoreHeapToInitialState(ArrayBufferObjectMaybeShared *maybePrevBuffer)
 {
 #if defined(JS_CODEGEN_X86)
     if (maybePrevBuffer) {
         // Subtract out the base-pointer added by AsmJSModule::initHeap.
         uint8_t *ptrBase = maybePrevBuffer->dataPointer();
         for (unsigned i = 0; i < heapAccesses_.length(); i++) {
@@ -788,16 +791,17 @@ AsmJSModule::restoreHeapToInitialState(A
         }
     }
 #endif
 
     maybeHeap_ = nullptr;
     heapDatum() = nullptr;
 }
 
+// This method assumes the caller has a live AutoUnprotectCode.
 void
 AsmJSModule::restoreToInitialState(ArrayBufferObjectMaybeShared *maybePrevBuffer,
                                    uint8_t *prevCode,
                                    ExclusiveContext *cx)
 {
 #ifdef DEBUG
     // Put the absolute links back to -1 so PatchDataWithValueCheck assertions
     // in staticallyLink are valid.
@@ -1545,34 +1549,28 @@ AsmJSModule::clone(JSContext *cx, Scoped
     // flush all of them at once.
     out.setAutoFlushICacheRange();
 
     out.restoreToInitialState(maybeHeap_, code_, cx);
     return true;
 }
 
 bool
-AsmJSModule::changeHeap(Handle<ArrayBufferObject*> newBuffer, JSContext *cx)
+AsmJSModule::changeHeap(Handle<ArrayBufferObject*> newHeap, JSContext *cx)
 {
     // Content JS should not be able to run (and change heap) from within an
     // interrupt callback, but in case it does, fail to change heap. Otherwise,
     // the heap can change at every single instruction which would prevent
     // future optimizations like heap-base hoisting.
     if (interrupted_)
         return false;
 
-    uint32_t heapLength = newBuffer->byteLength();
-    if (heapLength & pod.heapLengthMask_ || heapLength < pod.minHeapLength_)
-        return false;
-
-    MOZ_ASSERT(IsValidAsmJSHeapLength(heapLength));
-    MOZ_ASSERT(!IsDeprecatedAsmJSHeapLength(heapLength));
-
+    AutoUnprotectCode auc(cx, *this);
     restoreHeapToInitialState(maybeHeap_);
-    initHeap(newBuffer, cx);
+    initHeap(newHeap, cx);
     return true;
 }
 
 void
 AsmJSModule::setProfilingEnabled(bool enabled, JSContext *cx)
 {
     MOZ_ASSERT(isDynamicallyLinked());
 
--- a/js/src/asmjs/AsmJSModule.h
+++ b/js/src/asmjs/AsmJSModule.h
@@ -879,16 +879,20 @@ class AsmJSModule
         return srcBodyStart_;
     }
 
     // While these functions may be accessed at any time, their values will
     // change as the module is compiled.
     uint32_t minHeapLength() const {
         return pod.minHeapLength_;
     }
+    uint32_t heapLengthMask() const {
+        MOZ_ASSERT(pod.hasFixedMinHeapLength_);
+        return pod.heapLengthMask_;
+    }
     unsigned numFunctionCounts() const {
         return functionCounts_.length();
     }
     jit::IonScriptCounts *functionCounts(unsigned i) {
         return functionCounts_[i];
     }
 
     // about:memory reporting
--- a/js/src/jit-test/tests/asm.js/testResize.js
+++ b/js/src/jit-test/tests/asm.js/testResize.js
@@ -198,26 +198,29 @@ var {get, set, changeHeap} = asmLink(m, 
 
 assertEq(m.toString(), "function anonymous(glob, ffis, b) {\n" + USE_ASM + body + "\n}");
 assertEq(m.toSource(), "(function anonymous(glob, ffis, b) {\n" + USE_ASM + body + "\n})");
 assertEq(changeHeap.toString(), changeHeapSource);
 assertEq(changeHeap.toSource(), changeHeapSource);
 
 set(0, 42);
 set(4, 13);
+set(4, 13);
 assertEq(get(0), 42);
 assertEq(get(4), 13);
 set(BUF_CHANGE_MIN, 262);
 assertEq(get(BUF_CHANGE_MIN), 0);
 var buf2 = new ArrayBuffer(2*BUF_CHANGE_MIN);
 assertEq(changeHeap(buf2), true);
 assertEq(get(0), 0);
 assertEq(get(4), 0);
 set(BUF_CHANGE_MIN, 262);
 assertEq(get(BUF_CHANGE_MIN), 262);
+set(2*BUF_CHANGE_MIN, 262);
+assertEq(get(2*BUF_CHANGE_MIN), 0);
 changeHeap(buf1);
 assertEq(get(0), 42);
 assertEq(get(4), 13);
 set(BUF_CHANGE_MIN, 262);
 assertEq(get(BUF_CHANGE_MIN), 0);
 
 var buf1 = new ArrayBuffer(BUF_CHANGE_MIN);
 new Int32Array(buf1)[0] = 13;