diff -r 000000000000 -r 6474c204b198 js/src/jsapi-tests/testFuncCallback.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/js/src/jsapi-tests/testFuncCallback.cpp Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,141 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "jsapi-tests/tests.h" + +#ifdef MOZ_TRACE_JSCALLS + +static int depth = 0; +static int enters = 0; +static int leaves = 0; +static int interpreted = 0; + +static void +funcTransition(const JSFunction *, + const JSScript *, + const JSContext *cx, + int entering) +{ + if (entering > 0) { + ++depth; + ++enters; + ++interpreted; + } else { + --depth; + ++leaves; + } +} + +static bool called2 = false; + +static void +funcTransition2(const JSFunction *, const JSScript*, const JSContext*, int) +{ + called2 = true; +} + +static int overlays = 0; +static JSFunctionCallback innerCallback = nullptr; +static void +funcTransitionOverlay(const JSFunction *fun, + const JSScript *script, + const JSContext *cx, + int entering) +{ + (*innerCallback)(fun, script, cx, entering); + overlays++; +} +#endif + +BEGIN_TEST(testFuncCallback_bug507012) +{ +#ifdef MOZ_TRACE_JSCALLS + // Call funcTransition() whenever a Javascript method is invoked + JS_SetFunctionCallback(cx, funcTransition); + + EXEC("x = 0; function f (n) { if (n > 1) { f(n - 1); } }"); + interpreted = enters = leaves = depth = 0; + + // Check whether JS_Execute() tracking works + EXEC("42"); + CHECK_EQUAL(enters, 1); + CHECK_EQUAL(leaves, 1); + CHECK_EQUAL(depth, 0); + interpreted = enters = leaves = depth = 0; + + // Check whether the basic function tracking works + EXEC("f(1)"); + CHECK_EQUAL(enters, 1+1); + CHECK_EQUAL(leaves, 1+1); + CHECK_EQUAL(depth, 0); + + // Can we switch to a different callback? + enters = 777; + JS_SetFunctionCallback(cx, funcTransition2); + EXEC("f(1)"); + CHECK(called2); + CHECK_EQUAL(enters, 777); + + // Check whether we can turn off function tracing + JS_SetFunctionCallback(cx, nullptr); + EXEC("f(1)"); + CHECK_EQUAL(enters, 777); + interpreted = enters = leaves = depth = 0; + + // Check nested invocations + JS_SetFunctionCallback(cx, funcTransition); + enters = leaves = depth = 0; + EXEC("f(3)"); + CHECK_EQUAL(enters, 1+3); + CHECK_EQUAL(leaves, 1+3); + CHECK_EQUAL(depth, 0); + interpreted = enters = leaves = depth = 0; + + // Check calls invoked while running on trace -- or now, perhaps on + // IonMonkey's equivalent, if it ever starts to exist? + EXEC("function g () { ++x; }"); + interpreted = enters = leaves = depth = 0; + EXEC("for (i = 0; i < 5000; ++i) { g(); }"); + CHECK_EQUAL(enters, 1+5000); + CHECK_EQUAL(leaves, 1+5000); + CHECK_EQUAL(depth, 0); + + // Test nesting callbacks via JS_GetFunctionCallback() + JS_SetFunctionCallback(cx, funcTransition); + innerCallback = JS_GetFunctionCallback(cx); + JS_SetFunctionCallback(cx, funcTransitionOverlay); + + EXEC("x = 0; function f (n) { if (n > 1) { f(n - 1); } }"); + interpreted = enters = leaves = depth = overlays = 0; + + EXEC("42.5"); + CHECK_EQUAL(enters, 1); + CHECK_EQUAL(leaves, 1); + CHECK_EQUAL(depth, 0); + CHECK_EQUAL(overlays, enters + leaves); + interpreted = enters = leaves = depth = overlays = 0; +#endif + + // Uncomment this to validate whether you're hitting all runmodes (interp, + // mjit, ...?) Unfortunately, that still doesn't cover all + // transitions between the various runmodes, but it's a start. + //JS_DumpAllProfiles(cx); + + return true; +} + +// Make sure that the method jit is enabled. +// We'll probably want to test in all modes. +virtual +JSContext *createContext() +{ + JSContext *cx = JSAPITest::createContext(); + if (!cx) + return nullptr; + JS::RuntimeOptionsRef(cx).setBaseline(true) + .setIon(true); + return cx; +} + +END_TEST(testFuncCallback_bug507012)