Bug 1057082 - 7/7 - Fix tests. r=jandem
authorKannan Vijayan <kvijayan@mozilla.com>
Thu, 15 Jan 2015 20:11:22 -0500
changeset 251402 809520c9cb0a28f5bd820c25dc531ac6d965dcd4
parent 251401 97c0c777233db3f3eb42b3d5c2bebea9987b3fc3
child 251403 99eff4410e330e99b9d694375f5dae34f5107c6b
push id4610
push userjlund@mozilla.com
push dateMon, 30 Mar 2015 18:32:55 +0000
treeherdermozilla-beta@4df54044d9ef [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjandem
bugs1057082
milestone38.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 1057082 - 7/7 - Fix tests. r=jandem
js/src/jit-test/tests/asm.js/testProfiling.js
js/src/jit/JitcodeMap.cpp
js/src/shell/js.cpp
toolkit/devtools/server/tests/unit/test_profiler_data.js
tools/profiler/tests/test_enterjit_osr.js
--- a/js/src/jit-test/tests/asm.js/testProfiling.js
+++ b/js/src/jit-test/tests/asm.js/testProfiling.js
@@ -1,143 +1,181 @@
 load(libdir + "asm.js");
 load(libdir + "asserts.js");
 
 // Single-step profiling currently only works in the ARM simulator
 if (!getBuildConfiguration()["arm-simulator"])
     quit();
 
-function assertEqualStacks(got, expect)
+function checkSubSequence(got, expect)
 {
-    // Strip off the " (script/library info)"
-    got = String(got).replace(/ \([^\)]*\)/g, "");
+    var got_i = 0;
+    EXP: for (var exp_i = 0; exp_i < expect.length; exp_i++) {
+        var item = expect[exp_i];
+        // Scan for next match in got.
+        while (got_i < got.length) {
+            if (got[got_i++] == expect[exp_i])
+                continue EXP;
+        }
+        print("MISMATCH: " + got.join(",") + "\n" +
+              "    VS    " + expect.join(","));
+        return false;
+    }
+    return true;
+}
+
+function assertStackContainsSeq(got, expect)
+{
+    var normalized = [];
 
-    // Shorten FFI/entry trampolines
-    got = got.replace(/(fast|slow) FFI trampoline/g, "<").replace(/entry trampoline/g, ">");
+    for (var i = 0; i < got.length; i++) {
+        if (got[i].length == 0)
+            continue;
+        var parts = got[i].split(',');
+        for (var j = 0; j < parts.length; j++) {
+            var frame = parts[j];
+            frame = frame.replace(/ \([^\)]*\)/g, "");
+            frame = frame.replace(/(fast|slow) FFI trampoline/g, "<");
+            frame = frame.replace(/entry trampoline/g, ">");
+            frame = frame.replace(/(\/[^\/,<]+)*\/testProfiling.js/g, "");
+            frame = frame.replace(/testBuiltinD2D/g, "");
+            frame = frame.replace(/testBuiltinF2F/g, "");
+            frame = frame.replace(/testBuiltinDD2D/g, "");
+            frame = frame.replace(/assertThrowsInstanceOf/g, "");
+            frame = frame.replace(/^ffi[12]?/g, "");
+            normalized.push(frame);
+        }
+    }
 
-    assertEq(got, expect);
+    var gotNorm = normalized.join(',').replace(/,+/g, ",");
+    gotNorm = gotNorm.replace(/^,/, "").replace(/,$/, "");
+
+    assertEq(checkSubSequence(gotNorm.split(','), expect.split(',')), true);
 }
 
 // Test profiling enablement while asm.js is running.
 var stacks;
 var ffi = function(enable) {
     if (enable == +1)
         enableSPSProfiling();
     if (enable == -1)
         disableSPSProfiling();
     enableSingleStepProfiling();
     stacks = disableSingleStepProfiling();
 }
 var f = asmLink(asmCompile('global','ffis',USE_ASM + "var ffi=ffis.ffi; function g(i) { i=i|0; ffi(i|0) } function f(i) { i=i|0; g(i|0) } return f"), null, {ffi});
 f(0);
-assertEqualStacks(stacks, "");
+assertStackContainsSeq(stacks, "", true);
 f(+1);
-assertEqualStacks(stacks, "");
+assertStackContainsSeq(stacks, "", true);
 f(0);
-assertEqualStacks(stacks, "<gf>");
+assertStackContainsSeq(stacks, "<,g,f,>", true);
 f(-1);
-assertEqualStacks(stacks, "<gf>");
+assertStackContainsSeq(stacks, "<,g,f,>", true);
 f(0);
-assertEqualStacks(stacks, "");
+assertStackContainsSeq(stacks, "", true);
 
 // Enable profiling for the rest of the tests.
 enableSPSProfiling();
 
 var f = asmLink(asmCompile(USE_ASM + "function f() { return 42 } return f"));
 enableSingleStepProfiling();
 assertEq(f(), 42);
 var stacks = disableSingleStepProfiling();
-assertEqualStacks(stacks, ",>,f>,>,");
+assertStackContainsSeq(stacks, ">,f,>,>");
 
 var f = asmLink(asmCompile(USE_ASM + "function g(i) { i=i|0; return (i+1)|0 } function f() { return g(42)|0 } return f"));
 enableSingleStepProfiling();
 assertEq(f(), 43);
 var stacks = disableSingleStepProfiling();
-assertEqualStacks(stacks, ",>,f>,gf>,f>,>,");
+assertStackContainsSeq(stacks, ">,f,>,g,f,>,f,>,>");
 
 var f = asmLink(asmCompile(USE_ASM + "function g1() { return 1 } function g2() { return 2 } function f(i) { i=i|0; return TBL[i&1]()|0 } var TBL=[g1,g2]; return f"));
 enableSingleStepProfiling();
 assertEq(f(0), 1);
 assertEq(f(1), 2);
 var stacks = disableSingleStepProfiling();
-assertEqualStacks(stacks, ",>,f>,g1f>,f>,>,,>,f>,g2f>,f>,>,");
+assertStackContainsSeq(stacks, ">,f,>,g1,f,>,f,>,>,>,f,>,g2,f,>,f,>,>");
 
 function testBuiltinD2D(name) {
     var f = asmLink(asmCompile('g', USE_ASM + "var fun=g.Math." + name + "; function f(d) { d=+d; return +fun(d) } return f"), this);
     enableSingleStepProfiling();
     assertEq(f(.1), eval("Math." + name + "(.1)"));
     var stacks = disableSingleStepProfiling();
-    assertEqualStacks(stacks, ",>,f>,Math." + name + "f>,f>,>,");
+    assertStackContainsSeq(stacks, ">,f,>,Math." + name + ",f,>,f,>,>");
 }
 for (name of ['sin', 'cos', 'tan', 'asin', 'acos', 'atan', 'ceil', 'floor', 'exp', 'log'])
     testBuiltinD2D(name);
 function testBuiltinF2F(name) {
     var f = asmLink(asmCompile('g', USE_ASM + "var tof=g.Math.fround; var fun=g.Math." + name + "; function f(d) { d=tof(d); return tof(fun(d)) } return f"), this);
     enableSingleStepProfiling();
     assertEq(f(.1), eval("Math.fround(Math." + name + "(Math.fround(.1)))"));
     var stacks = disableSingleStepProfiling();
-    assertEqualStacks(stacks, ",>,f>,Math." + name + "f>,f>,>,");
+    assertStackContainsSeq(stacks, ">,f,>,Math." + name + ",f,>,f,>,>");
 }
 for (name of ['ceil', 'floor'])
     testBuiltinF2F(name);
 function testBuiltinDD2D(name) {
     var f = asmLink(asmCompile('g', USE_ASM + "var fun=g.Math." + name + "; function f(d, e) { d=+d; e=+e; return +fun(d,e) } return f"), this);
     enableSingleStepProfiling();
     assertEq(f(.1, .2), eval("Math." + name + "(.1, .2)"));
     var stacks = disableSingleStepProfiling();
-    assertEqualStacks(stacks, ",>,f>,Math." + name + "f>,f>,>,");
+    assertStackContainsSeq(stacks, ">,f,>,Math." + name + ",f,>,f,>,>");
 }
 for (name of ['atan2', 'pow'])
     testBuiltinDD2D(name);
 
 // FFI tests:
 setJitCompilerOption("ion.warmup.trigger", 10);
 setJitCompilerOption("baseline.warmup.trigger", 0);
 setJitCompilerOption("offthread-compilation.enable", 0);
 
 var ffi1 = function() { return 10 }
 var ffi2 = function() { return 73 }
 var f = asmLink(asmCompile('g','ffis', USE_ASM + "var ffi1=ffis.ffi1, ffi2=ffis.ffi2; function f() { return ((ffi1()|0) + (ffi2()|0))|0 } return f"), null, {ffi1,ffi2});
 // Interpreter FFI exit
 enableSingleStepProfiling();
 assertEq(f(), 83);
 var stacks = disableSingleStepProfiling();
-assertEqualStacks(stacks, ",>,f>,<f>,f>,<f>,f>,>,");
-// Ion FFI exit
+assertStackContainsSeq(stacks, ">,f,>,<,f,>,f,>,<,f,>,f,>,>");
+
 for (var i = 0; i < 20; i++)
     assertEq(f(), 83);
 enableSingleStepProfiling();
 assertEq(f(), 83);
 var stacks = disableSingleStepProfiling();
-assertEqualStacks(stacks, ",>,f>,<f>,f>,<f>,f>,>,");
+assertStackContainsSeq(stacks, ">,f,>,<,f,>,f,>,<,f,>,f,>,>");
 
 var ffi1 = function() { return 15 }
 var ffi2 = function() { return f2() + 17 }
 var {f1,f2} = asmLink(asmCompile('g','ffis', USE_ASM + "var ffi1=ffis.ffi1, ffi2=ffis.ffi2; function f2() { return ffi1()|0 } function f1() { return ffi2()|0 } return {f1:f1, f2:f2}"), null, {ffi1, ffi2});
 // Interpreter FFI exit
 enableSingleStepProfiling();
 assertEq(f1(), 32);
 var stacks = disableSingleStepProfiling();
-assertEqualStacks(stacks, ",>,f1>,<f1>,><f1>,f2><f1>,<f2><f1>,f2><f1>,><f1>,<f1>,f1>,>,");
+assertStackContainsSeq(stacks, ">,f1,>,<,f1,>,>,<,f1,>,f2,>,<,f1,>,<,f2,>,<,f1,>,f2,>,<,f1,>,>,<,f1,>,<,f1,>,f1,>,>");
+
+
 // Ion FFI exit
 for (var i = 0; i < 20; i++)
     assertEq(f1(), 32);
 enableSingleStepProfiling();
 assertEq(f1(), 32);
 var stacks = disableSingleStepProfiling();
-assertEqualStacks(stacks, ",>,f1>,<f1>,><f1>,f2><f1>,<f2><f1>,f2><f1>,><f1>,<f1>,f1>,>,");
+assertStackContainsSeq(stacks, ">,f1,>,<,f1,>,>,<,f1,>,f2,>,<,f1,>,<,f2,>,<,f1,>,f2,>,<,f1,>,>,<,f1,>,<,f1,>,f1,>,>");
+
 
 // Detachment exit
 var buf = new ArrayBuffer(BUF_CHANGE_MIN);
 var ffi = function() { neuter(buf, 'change-data') }
 var f = asmLink(asmCompile('g','ffis','buf', USE_ASM + 'var ffi = ffis.ffi; var i32 = new g.Int32Array(buf); function f() { ffi() } return f'), this, {ffi:ffi}, buf);
 enableSingleStepProfiling();
 assertThrowsInstanceOf(f, InternalError);
 var stacks = disableSingleStepProfiling();
-assertEqualStacks(stacks, ",>,f>,<f>,inline stubf>,<f>,inline stubf>,");
+assertStackContainsSeq(stacks, ">,f,>,<,f,>,inline stub,f,>,<,f,>,inline stub,f,>");
 
 // This takes forever to run.
 // Stack-overflow exit test
 //var limit = -1;
 //var maxct = 0;
 //function ffi(ct) { if (ct == limit) { enableSingleStepProfiling(); print("enabled"); } maxct = ct; }
 //var f = asmLink(asmCompile('g', 'ffis',USE_ASM + "var ffi=ffis.ffi; var ct=0; function rec(){ ct=(ct+1)|0; ffi(ct|0); rec() } function f() { ct=0; rec() } return f"), null, {ffi});
 //// First find the stack limit:
--- a/js/src/jit/JitcodeMap.cpp
+++ b/js/src/jit/JitcodeMap.cpp
@@ -142,17 +142,17 @@ JitcodeGlobalEntry::BaselineEntry::callS
     return 1;
 }
 
 void
 JitcodeGlobalEntry::BaselineEntry::destroy()
 {
     if (!str_)
         return;
-    js_free(str_);
+    js_free((void*) str_);
     str_ = nullptr;
 }
 
 bool
 JitcodeGlobalEntry::IonCacheEntry::callStackAtAddr(JSRuntime *rt, void *ptr,
                                                    BytecodeLocationVector &results,
                                                    uint32_t *depth) const
 {
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -4155,24 +4155,29 @@ SingleStepCallback(void *arg, jit::Simul
 
     JS::ProfilingFrameIterator::RegisterState state;
     state.pc = pc;
     state.sp = (void*)sim->get_register(jit::Simulator::sp);
     state.lr = (void*)sim->get_register(jit::Simulator::lr);
 
     DebugOnly<void*> lastStackAddress = nullptr;
     StackChars stack;
+    uint32_t frameNo = 0;
     for (JS::ProfilingFrameIterator i(rt, state); !i.done(); ++i) {
         MOZ_ASSERT(i.stackAddress() != nullptr);
         MOZ_ASSERT(lastStackAddress <= i.stackAddress());
         lastStackAddress = i.stackAddress();
         JS::ProfilingFrameIterator::Frame frames[16];
         uint32_t nframes = i.extractStack(frames, 0, 16);
-        for (uint32_t i = 0; i < nframes; i++)
+        for (uint32_t i = 0; i < nframes; i++) {
+            if (frameNo > 0)
+                stack.append(",", 1);
             stack.append(frames[i].label, strlen(frames[i].label));
+            frameNo++;
+        }
     }
 
     // Only append the stack if it differs from the last stack.
     if (stacks.empty() ||
         stacks.back().length() != stack.length() ||
         !PodEqual(stacks.back().begin(), stack.begin(), stack.length()))
     {
         stacks.append(Move(stack));
--- a/toolkit/devtools/server/tests/unit/test_profiler_data.js
+++ b/toolkit/devtools/server/tests/unit/test_profiler_data.js
@@ -101,22 +101,21 @@ function test_data(client, actor, callba
           do_check_true(false);
           return;
         }
       }
 
       // Now check the samples. At least one sample is expected to
       // have been in the busy wait above.
       let loc = stack.name + " (" + stack.filename + ":" + funcLine + ")";
-      let line = stack.lineNumber;
 
       do_check_true(response.profile.threads[0].samples.some(sample => {
         return typeof sample.frames == "object" &&
                sample.frames.length != 0 &&
-               sample.frames.some(f => (f.line == line) && (f.location == loc));
+               sample.frames.some(f => (f.location == loc));
       }));
 
       callback();
     });
   }
 
   // Start off with a 100 millisecond delay.
   attempt(INITIAL_WAIT_TIME);
--- a/tools/profiler/tests/test_enterjit_osr.js
+++ b/tools/profiler/tests/test_enterjit_osr.js
@@ -1,70 +1,58 @@
 // Check that the EnterJIT frame, added by the JIT trampoline and
 // usable by a native unwinder to resume unwinding after encountering
 // JIT code, is pushed as expected.
 function run_test() {
     let p = Cc["@mozilla.org/tools/profiler;1"];
     // Just skip the test if the profiler component isn't present.
     if (!p)
-	return;
+        return;
     p = p.getService(Ci.nsIProfiler);
     if (!p)
-	return;
+        return;
 
     // This test assumes that it's starting on an empty SPS stack.
     // (Note that the other profiler tests also assume the profiler
     // isn't already started.)
     do_check_true(!p.IsActive());
 
     const ms = 5;
     p.StartProfiler(100, ms, ["js"], 1);
 
     function arbitrary_name(){
         // A frame for |arbitrary_name| has been pushed.  Do a sequence of
         // increasingly long spins until we get a sample.
         var delayMS = 5;
         while (1) {
             do_print("loop: ms = " + delayMS);
-	    let then = Date.now();
-	    do {
-	        let n = 10000;
-	        while (--n); // OSR happens here
-	        // Spin in the hope of getting a sample.
-	    } while (Date.now() - then < delayMS);
+            let then = Date.now();
+            do {
+                let n = 10000;
+                while (--n); // OSR happens here
+                // Spin in the hope of getting a sample.
+            } while (Date.now() - then < delayMS);
             let pr = p.getProfileData().threads[0].samples;
             if (pr.length > 0 || delayMS > 30000)
                 return pr;
             delayMS *= 2;
         }
     };
 
     var profile = arbitrary_name();
 
     do_check_neq(profile.length, 0);
     let stack = profile[profile.length - 1].frames.map(f => f.location);
-    stack = stack.slice(stack.lastIndexOf("js::RunScript") + 1);
+    do_print(stack);
 
-    do_print(stack);
-    // This test needs to not break on platforms and configurations
-    // where IonMonkey isn't available / enabled.
-    if (stack.length < 2 || stack[1] != "EnterJIT") {
-	do_print("No JIT?");
-	// Try to check what we can....
-	do_check_eq(Math.min(stack.length, 1), 1);
-	let thisInterp = stack[0];
-	do_check_eq(thisInterp.split(" ")[0], "arbitrary_name");
-	if (stack.length >= 2) {
-	    let nextFrame = stack[1];
-	    do_check_neq(nextFrame.split(" ")[0], "arbitrary_name");
-	}
-    } else {
-	do_check_eq(Math.min(stack.length, 3), 3);
-	let thisInterp = stack[0];
-	let enterJit = stack[1];
-	let thisBC = stack[2];
-	do_check_eq(thisInterp.split(" ")[0], "arbitrary_name");
-	do_check_eq(enterJit, "EnterJIT");
-	do_check_eq(thisBC.split(" ")[0], "arbitrary_name");
+    // All we can really check here is ensure that there is exactly
+    // one arbitrary_name frame in the list.
+    var gotName = false;
+    for (var i = 0; i < stack.length; i++) {
+        if (stack[i].match(/arbitrary_name/)) {
+            do_check_eq(gotName, false);
+            gotName = true;
+        }
     }
+    do_check_eq(gotName, true);
 
     p.StopProfiler();
 }