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