Imported Upstream version 1.0.0
[platform/upstream/js.git] / js / src / jsapi-tests / testFuncCallback.cpp
1 #include "tests.h"
2 #include "jsfun.h"
3 #include "jscntxt.h"
4
5 // For TRACING_ENABLED
6 #include "jstracer.h"
7
8 #ifdef MOZ_TRACE_JSCALLS
9
10 static int depth = 0;
11 static int enters = 0;
12 static int leaves = 0;
13 static int interpreted = 0;
14
15 static void
16 funcTransition(const JSFunction *,
17                const JSScript *,
18                const JSContext *cx,
19                int entering)
20 {
21     if (entering > 0) {
22         ++depth;
23         ++enters;
24         if (! JS_ON_TRACE(cx))
25             ++interpreted;
26     } else {
27         --depth;
28         ++leaves;
29     }
30 }
31
32 static JSBool called2 = false;
33
34 static void
35 funcTransition2(const JSFunction *, const JSScript*, const JSContext*, int)
36 {
37     called2 = true;
38 }
39
40 static int overlays = 0;
41 static JSFunctionCallback innerCallback = NULL;
42 static void
43 funcTransitionOverlay(const JSFunction *fun,
44                       const JSScript *script,
45                       const JSContext *cx,
46                       int entering)
47 {
48     (*innerCallback)(fun, script, cx, entering);
49     overlays++;
50 }
51 #endif
52
53 BEGIN_TEST(testFuncCallback_bug507012)
54 {
55 #ifdef MOZ_TRACE_JSCALLS
56     // Call funcTransition() whenever a Javascript method is invoked
57     JS_SetFunctionCallback(cx, funcTransition);
58
59     EXEC("x = 0; function f (n) { if (n > 1) { f(n - 1); } }");
60     interpreted = enters = leaves = depth = 0;
61
62     // Check whether JS_Execute() tracking works
63     EXEC("42");
64     CHECK(enters == 1 && leaves == 1 && depth == 0);
65     interpreted = enters = leaves = depth = 0;
66
67     // Check whether the basic function tracking works
68     EXEC("f(1)");
69     CHECK(enters == 1+1 && leaves == 1+1 && depth == 0);
70
71     // Can we switch to a different callback?
72     enters = 777;
73     JS_SetFunctionCallback(cx, funcTransition2);
74     EXEC("f(1)");
75     CHECK(called2 && enters == 777);
76
77     // Check whether we can turn off function tracing
78     JS_SetFunctionCallback(cx, NULL);
79     EXEC("f(1)");
80     CHECK(enters == 777);
81     interpreted = enters = leaves = depth = 0;
82
83     // Check nested invocations
84     JS_SetFunctionCallback(cx, funcTransition);
85     enters = leaves = depth = 0;
86     EXEC("f(3)");
87     CHECK(enters == 1+3 && leaves == 1+3 && depth == 0);
88     interpreted = enters = leaves = depth = 0;
89
90     // Check calls invoked while running on trace
91     EXEC("function g () { ++x; }");
92     interpreted = enters = leaves = depth = 0;
93     EXEC("for (i = 0; i < 50; ++i) { g(); }");
94     CHECK(enters == 1+50 && leaves == 1+50 && depth == 0);
95
96     // If this fails, it means that the code was interpreted rather
97     // than trace-JITted, and so is not testing what it's supposed to
98     // be testing. Which doesn't necessarily imply that the
99     // functionality is broken.
100 #ifdef JS_TRACER
101     if (TRACING_ENABLED(cx))
102         CHECK(interpreted < enters);
103 #endif
104
105     // Test nesting callbacks via JS_GetFunctionCallback()
106     JS_SetFunctionCallback(cx, funcTransition);
107     innerCallback = JS_GetFunctionCallback(cx);
108     JS_SetFunctionCallback(cx, funcTransitionOverlay);
109
110     EXEC("x = 0; function f (n) { if (n > 1) { f(n - 1); } }");
111     interpreted = enters = leaves = depth = overlays = 0;
112
113     EXEC("42.5");
114     CHECK(enters == 1);
115     CHECK(leaves == 1);
116     CHECK(depth == 0);
117     CHECK(overlays == enters + leaves);
118     interpreted = enters = leaves = depth = overlays = 0;
119 #endif
120
121     return true;
122 }
123
124 // Not strictly necessary, but part of the test attempts to check
125 // whether these callbacks still trigger when traced, so force
126 // JSOPTION_JIT just to be sure. Once the method jit and tracing jit
127 // are integrated, this'll probably have to change (and we'll probably
128 // want to test in all modes.)
129 virtual
130 JSContext *createContext()
131 {
132     JSContext *cx = JSAPITest::createContext();
133     if (cx)
134         JS_SetOptions(cx, JS_GetOptions(cx) | JSOPTION_JIT);
135     return cx;
136 }
137
138 END_TEST(testFuncCallback_bug507012)