diff --git a/js/src/jit-test/tests/asm.js/testProfiling.js b/js/src/jit-test/tests/asm.js/testProfiling.js index e1e2c1dc0d81..9c280741b395 100644 --- a/js/src/jit-test/tests/asm.js/testProfiling.js +++ b/js/src/jit-test/tests/asm.js/testProfiling.js @@ -5,15 +5,50 @@ load(libdir + "asserts.js"); 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; +} - // Shorten FFI/entry trampolines - got = got.replace(/(fast|slow) FFI trampoline/g, "<").replace(/entry trampoline/g, ">"); +function assertStackContainsSeq(got, expect) +{ + var normalized = []; - assertEq(got, expect); + 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); + } + } + + 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. @@ -28,15 +63,15 @@ var ffi = function(enable) { } 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, ""); +assertStackContainsSeq(stacks, "<,g,f,>", true); f(-1); -assertEqualStacks(stacks, ""); +assertStackContainsSeq(stacks, "<,g,f,>", true); f(0); -assertEqualStacks(stacks, ""); +assertStackContainsSeq(stacks, "", true); // Enable profiling for the rest of the tests. enableSPSProfiling(); @@ -45,27 +80,27 @@ 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); @@ -74,7 +109,7 @@ function testBuiltinF2F(name) { 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); @@ -83,7 +118,7 @@ function testBuiltinDD2D(name) { 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); @@ -100,14 +135,14 @@ var f = asmLink(asmCompile('g','ffis', USE_ASM + "var ffi1=ffis.ffi1, ffi2=ffis. enableSingleStepProfiling(); assertEq(f(), 83); var stacks = disableSingleStepProfiling(); -assertEqualStacks(stacks, ",>,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>,>,"); +assertStackContainsSeq(stacks, ">,f,>,<,f,>,f,>,<,f,>,f,>,>"); var ffi1 = function() { return 15 } var ffi2 = function() { return f2() + 17 } @@ -116,14 +151,17 @@ var {f1,f2} = asmLink(asmCompile('g','ffis', USE_ASM + "var ffi1=ffis.ffi1, ffi2 enableSingleStepProfiling(); assertEq(f1(), 32); var stacks = disableSingleStepProfiling(); -assertEqualStacks(stacks, ",>,f1>,,>,f2>,,f2>,>,,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>,,>,f2>,,f2>,>,,f1>,>,"); +assertStackContainsSeq(stacks, ">,f1,>,<,f1,>,>,<,f1,>,f2,>,<,f1,>,<,f2,>,<,f1,>,f2,>,<,f1,>,>,<,f1,>,<,f1,>,f1,>,>"); + // Detachment exit var buf = new ArrayBuffer(BUF_CHANGE_MIN); @@ -132,7 +170,7 @@ var f = asmLink(asmCompile('g','ffis','buf', USE_ASM + 'var ffi = ffis.ffi; var enableSingleStepProfiling(); assertThrowsInstanceOf(f, InternalError); var stacks = disableSingleStepProfiling(); -assertEqualStacks(stacks, ",>,f>,,inline stubf>,,inline stubf>,"); +assertStackContainsSeq(stacks, ">,f,>,<,f,>,inline stub,f,>,<,f,>,inline stub,f,>"); // This takes forever to run. // Stack-overflow exit test diff --git a/js/src/jit/JitcodeMap.cpp b/js/src/jit/JitcodeMap.cpp index 01655c149c45..8c65861212fa 100644 --- a/js/src/jit/JitcodeMap.cpp +++ b/js/src/jit/JitcodeMap.cpp @@ -147,7 +147,7 @@ JitcodeGlobalEntry::BaselineEntry::destroy() { if (!str_) return; - js_free(str_); + js_free((void*) str_); str_ = nullptr; } diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index 678925d2c40f..cf5803b575b9 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -4160,14 +4160,19 @@ SingleStepCallback(void *arg, jit::Simulator *sim, void *pc) DebugOnly 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. diff --git a/toolkit/devtools/server/tests/unit/test_profiler_data.js b/toolkit/devtools/server/tests/unit/test_profiler_data.js index 6ebb338e7afa..e58a9d33bcf8 100644 --- a/toolkit/devtools/server/tests/unit/test_profiler_data.js +++ b/toolkit/devtools/server/tests/unit/test_profiler_data.js @@ -106,12 +106,11 @@ function test_data(client, actor, callback) // 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(); diff --git a/tools/profiler/tests/test_enterjit_osr.js b/tools/profiler/tests/test_enterjit_osr.js index 2595b28ec8d1..886f66008c74 100644 --- a/tools/profiler/tests/test_enterjit_osr.js +++ b/tools/profiler/tests/test_enterjit_osr.js @@ -5,10 +5,10 @@ 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 @@ -24,12 +24,12 @@ function run_test() { 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; @@ -41,30 +41,18 @@ function run_test() { 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); - // 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(); }