js/jsd/jsd_step.cpp

branch
TOR_BUG_3246
changeset 7
129ffea94266
equal deleted inserted replaced
-1:000000000000 0:aa56345c50b5
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: set ts=8 sts=4 et sw=4 tw=99:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7 /*
8 * JavaScript Debugging support - Stepping support
9 */
10
11 #include "jsd.h"
12
13 /*
14 * #define JSD_TRACE 1
15 */
16
17 #ifdef JSD_TRACE
18
19 static char*
20 _indentSpaces(int i)
21 {
22 #define MAX_INDENT 63
23 static char* p = nullptr;
24 if(!p)
25 {
26 p = calloc(1, MAX_INDENT+1);
27 if(!p) return "";
28 memset(p, ' ', MAX_INDENT);
29 }
30 if(i > MAX_INDENT) return p;
31 return p + MAX_INDENT-i;
32 }
33
34 static void
35 _interpreterTrace(JSDContext* jsdc, JSContext *cx, JSAbstractFramePtr frame,
36 bool isConstructing, bool before)
37 {
38 JSDScript* jsdscript = nullptr;
39 JSScript * script;
40 static indent = 0;
41 JSString* funName = nullptr;
42
43 script = frame.script();
44 if(script)
45 {
46 JSD_LOCK_SCRIPTS(jsdc);
47 jsdscript = jsd_FindOrCreateJSDScript(jsdc, cx, script, frame);
48 JSD_UNLOCK_SCRIPTS(jsdc);
49 if(jsdscript)
50 funName = JSD_GetScriptFunctionId(jsdc, jsdscript);
51 }
52
53 if(before)
54 printf("%sentering ", _indentSpaces(indent++));
55 else
56 printf("%sleaving ", _indentSpaces(--indent));
57
58 if (!funName)
59 printf("TOP_LEVEL");
60 else
61 JS_FileEscapedString(stdout, funName, 0);
62
63 if(before)
64 {
65 jsval thisVal;
66
67 printf("%s this: ", isConstructing ? "constructing":"");
68
69 if (JS_GetFrameThis(cx, frame, &thisVal))
70 printf("0x%0llx", (uintptr_t) thisVal);
71 else
72 puts("<unavailable>");
73 }
74 printf("\n");
75 MOZ_ASSERT(indent >= 0);
76 }
77 #endif
78
79 bool
80 _callHook(JSDContext *jsdc, JSContext *cx, JSAbstractFramePtr frame, bool isConstructing,
81 bool before, unsigned type, JSD_CallHookProc hook, void *hookData)
82 {
83 JSDScript* jsdscript;
84 JSScript* jsscript;
85 bool hookresult = true;
86
87 if (!jsdc || !jsdc->inited)
88 return false;
89
90 if (!hook && !(jsdc->flags & JSD_COLLECT_PROFILE_DATA))
91 {
92 /* no hook to call, no profile data needs to be collected,
93 * so there is nothing to do here.
94 */
95 return hookresult;
96 }
97
98 if (before && isConstructing) {
99 JS::RootedValue newObj(cx);
100 if (!frame.getThisValue(cx, &newObj))
101 return false;
102 jsd_Constructing(jsdc, cx, JSVAL_TO_OBJECT(newObj), frame);
103 }
104
105 jsscript = frame.script();
106 if (jsscript)
107 {
108 JSD_LOCK_SCRIPTS(jsdc);
109 jsdscript = jsd_FindOrCreateJSDScript(jsdc, cx, jsscript, frame);
110 JSD_UNLOCK_SCRIPTS(jsdc);
111
112 if (jsdscript)
113 {
114 if (JSD_IS_PROFILE_ENABLED(jsdc, jsdscript))
115 {
116 JSDProfileData *pdata;
117 pdata = jsd_GetScriptProfileData (jsdc, jsdscript);
118 if (pdata)
119 {
120 if (before)
121 {
122 if (!pdata->lastCallStart)
123 {
124 int64_t now;
125 JSDProfileData *callerpdata;
126
127 /* Get the time just the once, for consistency. */
128 now = JS_Now();
129 /* This contains a pointer to the profile data for
130 * the caller of this function. */
131 callerpdata = jsdc->callingFunctionPData;
132 if (callerpdata)
133 {
134 int64_t ll_delta;
135 pdata->caller = callerpdata;
136 /* We need to 'stop' the timer for the caller.
137 * Use time since last return if appropriate. */
138 ll_delta = jsdc->lastReturnTime
139 ? now - jsdc->lastReturnTime
140 : now - callerpdata->lastCallStart;
141 callerpdata->runningTime += ll_delta;
142 }
143 /* We're the new current function, and no return
144 * has happened yet. */
145 jsdc->callingFunctionPData = pdata;
146 jsdc->lastReturnTime = 0;
147 /* This function has no running time (just been
148 * called!), and we'll need the call start time. */
149 pdata->runningTime = 0;
150 pdata->lastCallStart = now;
151 } else {
152 if (++pdata->recurseDepth > pdata->maxRecurseDepth)
153 pdata->maxRecurseDepth = pdata->recurseDepth;
154 }
155 /* make sure we're called for the return too. */
156 hookresult = true;
157 } else if (!pdata->recurseDepth && pdata->lastCallStart) {
158 int64_t now, ll_delta;
159 double delta;
160 now = JS_Now();
161 ll_delta = now - pdata->lastCallStart;
162 delta = ll_delta;
163 delta /= 1000.0;
164 pdata->totalExecutionTime += delta;
165 /* minExecutionTime starts as 0, so we need to overwrite
166 * it on the first call always. */
167 if ((0 == pdata->callCount) ||
168 delta < pdata->minExecutionTime)
169 {
170 pdata->minExecutionTime = delta;
171 }
172 if (delta > pdata->maxExecutionTime)
173 pdata->maxExecutionTime = delta;
174
175 /* If we last returned from a function (as opposed to
176 * having last entered this function), we need to inc.
177 * the running total by the time delta since the last
178 * return, and use the running total instead of the
179 * delta calculated above. */
180 if (jsdc->lastReturnTime)
181 {
182 /* Add last chunk to running time, and use total
183 * running time as 'delta'. */
184 ll_delta = now - jsdc->lastReturnTime;
185 pdata->runningTime += ll_delta;
186 delta = pdata->runningTime;
187 delta /= 1000.0;
188 }
189
190 pdata->totalOwnExecutionTime += delta;
191 /* See minExecutionTime comment above. */
192 if ((0 == pdata->callCount) ||
193 delta < pdata->minOwnExecutionTime)
194 {
195 pdata->minOwnExecutionTime = delta;
196 }
197 if (delta > pdata->maxOwnExecutionTime)
198 pdata->maxOwnExecutionTime = delta;
199
200 /* Current function is now our caller. */
201 jsdc->callingFunctionPData = pdata->caller;
202 /* No hanging pointers, please. */
203 pdata->caller = nullptr;
204 /* Mark the time we returned, and indicate this
205 * function is no longer running. */
206 jsdc->lastReturnTime = now;
207 pdata->lastCallStart = 0;
208 ++pdata->callCount;
209 } else if (pdata->recurseDepth) {
210 --pdata->recurseDepth;
211 ++pdata->callCount;
212 }
213 }
214 if (hook)
215 jsd_CallCallHook (jsdc, cx, type, hook, hookData);
216 } else {
217 if (hook)
218 hookresult =
219 jsd_CallCallHook (jsdc, cx, type, hook, hookData);
220 else
221 hookresult = true;
222 }
223 }
224 }
225
226 #ifdef JSD_TRACE
227 _interpreterTrace(jsdc, cx, frame, isConstructing, before);
228 return true;
229 #else
230 return hookresult;
231 #endif
232
233 }
234
235 void *
236 jsd_FunctionCallHook(JSContext *cx, JSAbstractFramePtr frame, bool isConstructing,
237 bool before, bool *ok, void *closure)
238 {
239 JSDContext* jsdc;
240 JSD_CallHookProc hook;
241 void* hookData;
242
243 jsdc = (JSDContext*) closure;
244
245 /* local in case jsdc->functionHook gets cleared on another thread */
246 JSD_LOCK();
247 hook = jsdc->functionHook;
248 hookData = jsdc->functionHookData;
249 JSD_UNLOCK();
250
251 if (_callHook (jsdc, cx, frame, isConstructing, before,
252 (before) ? JSD_HOOK_FUNCTION_CALL : JSD_HOOK_FUNCTION_RETURN,
253 hook, hookData))
254 {
255 return closure;
256 }
257
258 return nullptr;
259 }
260
261 void *
262 jsd_TopLevelCallHook(JSContext *cx, JSAbstractFramePtr frame, bool isConstructing,
263 bool before, bool *ok, void *closure)
264 {
265 JSDContext* jsdc;
266 JSD_CallHookProc hook;
267 void* hookData;
268
269 jsdc = (JSDContext*) closure;
270
271 /* local in case jsdc->toplevelHook gets cleared on another thread */
272 JSD_LOCK();
273 hook = jsdc->toplevelHook;
274 hookData = jsdc->toplevelHookData;
275 JSD_UNLOCK();
276
277 if (_callHook (jsdc, cx, frame, isConstructing, before,
278 (before) ? JSD_HOOK_TOPLEVEL_START : JSD_HOOK_TOPLEVEL_END,
279 hook, hookData))
280 {
281 return closure;
282 }
283
284 return nullptr;
285
286 }

mercurial