Bug 1046688 - Fix assertion in AsmJSModule::restoreToInitialState (r=dougc)
authorLuke Wagner <luke@mozilla.com>
Mon, 04 Aug 2014 13:02:02 -0500
changeset 219372 34df51f6221eb9a04d899fdc108a56a6e48a0c49
parent 219371 9dc9557dca8ef466ae6e2d82e9c4eeec15c1fe3e
child 219373 f4634a64d20ea34cd46c2ddb00947921cadfba33
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
bugs1046688
milestone34.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 1046688 - Fix assertion in AsmJSModule::restoreToInitialState (r=dougc)
js/src/asmjs/AsmJSModule.cpp
js/src/asmjs/AsmJSModule.h
js/src/jit-test/tests/asm.js/testBug1046688.js
js/src/jit/shared/Assembler-shared.h
--- a/js/src/asmjs/AsmJSModule.cpp
+++ b/js/src/asmjs/AsmJSModule.cpp
@@ -785,28 +785,41 @@ AsmJSModule::initHeap(Handle<ArrayBuffer
     for (unsigned i = 0; i < heapAccesses_.length(); i++) {
         jit::Assembler::UpdateBoundsCheck(heapLength,
                                           (jit::Instruction*)(heapAccesses_[i].offset() + code_));
     }
 #endif
 }
 
 void
-AsmJSModule::restoreToInitialState(ArrayBufferObject *maybePrevBuffer, ExclusiveContext *cx)
+AsmJSModule::restoreToInitialState(uint8_t *prevCode, ArrayBufferObject *maybePrevBuffer,
+                                   ExclusiveContext *cx)
 {
 #ifdef DEBUG
     // Put the absolute links back to -1 so PatchDataWithValueCheck assertions
     // in staticallyLink are valid.
     for (size_t imm = 0; imm < AsmJSImm_Limit; imm++) {
+        void *callee = AddressOf(AsmJSImmKind(imm), cx);
+
+        // If we are in profiling mode, calls to builtins will have been patched
+        // by setProfilingEnabled to be calls to thunks.
+        AsmJSExit::BuiltinKind builtin;
+        void *profilingCallee = profilingEnabled_ && ImmKindIsBuiltin(AsmJSImmKind(imm), &builtin)
+                                ? prevCode + builtinThunkOffsets_[builtin]
+                                : nullptr;
+
         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]),
+            uint8_t *caller = code_ + offsets[i];
+            void *originalValue = profilingCallee && !lookupCodeRange(caller)->isThunk()
+                                  ? profilingCallee
+                                  : callee;
+            Assembler::PatchDataWithValueCheck(CodeLocationLabel(caller),
                                                PatchedImmPtr((void*)-1),
-                                               PatchedImmPtr(target));
+                                               PatchedImmPtr(originalValue));
         }
     }
 #endif
 
     if (maybePrevBuffer) {
 #if defined(JS_CODEGEN_X86)
         // Subtract out the base-pointer added by AsmJSModule::initHeap.
         uint8_t *ptrBase = maybePrevBuffer->dataPointer();
@@ -1533,17 +1546,17 @@ AsmJSModule::clone(JSContext *cx, Scoped
 
     out.loadedFromCache_ = loadedFromCache_;
     out.profilingEnabled_ = profilingEnabled_;
 
     // We already know the exact extent of areas that need to be patched, just make sure we
     // flush all of them at once.
     out.setAutoFlushICacheRange();
 
-    out.restoreToInitialState(maybeHeap_, cx);
+    out.restoreToInitialState(code_, maybeHeap_, cx);
     return true;
 }
 
 void
 AsmJSModule::setProfilingEnabled(bool enabled, JSContext *cx)
 {
     JS_ASSERT(isDynamicallyLinked());
 
--- a/js/src/asmjs/AsmJSModule.h
+++ b/js/src/asmjs/AsmJSModule.h
@@ -1143,17 +1143,18 @@ class AsmJSModule
     // once so, if JS tries, the module is cloned.
     void setIsDynamicallyLinked() {
         JS_ASSERT(!isDynamicallyLinked());
         dynamicallyLinked_ = true;
         JS_ASSERT(isDynamicallyLinked());
     }
     void initHeap(Handle<ArrayBufferObject*> heap, JSContext *cx);
     bool clone(JSContext *cx, ScopedJSDeletePtr<AsmJSModule> *moduleOut) const;
-    void restoreToInitialState(ArrayBufferObject *maybePrevBuffer, ExclusiveContext *cx);
+    void restoreToInitialState(uint8_t *prevCode, ArrayBufferObject *maybePrevBuffer,
+                               ExclusiveContext *cx);
 
     /*************************************************************************/
     // Functions that can be called after dynamic linking succeeds:
 
     CodePtr entryTrampoline(const ExportedFunction &func) const {
         JS_ASSERT(isDynamicallyLinked());
         return JS_DATA_TO_FUNC_PTR(CodePtr, code_ + func.pod.codeOffset_);
     }
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/asm.js/testBug1046688.js
@@ -0,0 +1,11 @@
+enableSPSProfiling();
+for (var j = 0; j < 1000; ++j) {
+  (function(stdlib) {
+    "use asm";
+    var pow = stdlib.Math.pow;
+    function f() {
+        return +pow(.0, .0)
+    }
+    return f;
+})(this)()
+}
--- a/js/src/jit/shared/Assembler-shared.h
+++ b/js/src/jit/shared/Assembler-shared.h
@@ -769,16 +769,25 @@ enum AsmJSImmKind
 };
 
 static inline AsmJSImmKind
 BuiltinToImmKind(AsmJSExit::BuiltinKind builtin)
 {
     return AsmJSImmKind(builtin);
 }
 
+static inline bool
+ImmKindIsBuiltin(AsmJSImmKind imm, AsmJSExit::BuiltinKind *builtin)
+{
+    if (unsigned(imm) >= unsigned(AsmJSExit::Builtin_Limit))
+        return false;
+    *builtin = AsmJSExit::BuiltinKind(imm);
+    return true;
+}
+
 // Pointer to be embedded as an immediate in asm.js code.
 class AsmJSImmPtr
 {
     AsmJSImmKind kind_;
   public:
     AsmJSImmKind kind() const { return kind_; }
     // This needs to be MOZ_IMPLICIT in order to make MacroAssember::CallWithABINoProfiling compile.
     MOZ_IMPLICIT AsmJSImmPtr(AsmJSImmKind kind) : kind_(kind) { JS_ASSERT(IsCompilingAsmJS()); }