Bug 965880 - OdinMonkey: don't forget to AutoUnprotectCode and prepareForAsmJS (r=bbouvier)
--- 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;