1 : /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is mozilla.org code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 1998
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : *
24 : * Alternatively, the contents of this file may be used under the terms of
25 : * either the GNU General Public License Version 2 or later (the "GPL"), or
26 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 : * in which case the provisions of the GPL or the LGPL are applicable instead
28 : * of those above. If you wish to allow use of your version of this file only
29 : * under the terms of either the GPL or the LGPL, and not to allow others to
30 : * use your version of this file under the terms of the MPL, indicate your
31 : * decision by deleting the provisions above and replace them with the notice
32 : * and other provisions required by the GPL or the LGPL. If you do not delete
33 : * the provisions above, a recipient may use your version of this file under
34 : * the terms of any one of the MPL, the GPL or the LGPL.
35 : *
36 : * ***** END LICENSE BLOCK ***** */
37 :
38 : /*
39 : * JavaScript Debugging support - Stepping support
40 : */
41 :
42 : #include "jsd.h"
43 :
44 : /*
45 : * #define JSD_TRACE 1
46 : */
47 :
48 : #ifdef JSD_TRACE
49 :
50 : static char*
51 : _indentSpaces(int i)
52 : {
53 : #define MAX_INDENT 63
54 : static char* p = NULL;
55 : if(!p)
56 : {
57 : p = calloc(1, MAX_INDENT+1);
58 : if(!p) return "";
59 : memset(p, ' ', MAX_INDENT);
60 : }
61 : if(i > MAX_INDENT) return p;
62 : return p + MAX_INDENT-i;
63 : }
64 :
65 : static void
66 : _interpreterTrace(JSDContext* jsdc, JSContext *cx, JSStackFrame *fp,
67 : JSBool before)
68 : {
69 : JSDScript* jsdscript = NULL;
70 : JSScript * script;
71 : static indent = 0;
72 : JSString* funName = NULL;
73 :
74 : script = JS_GetFrameScript(cx, fp);
75 : if(script)
76 : {
77 : JSD_LOCK_SCRIPTS(jsdc);
78 : jsdscript = jsd_FindOrCreateJSDScript(jsdc, cx, script, fp);
79 : JSD_UNLOCK_SCRIPTS(jsdc);
80 : if(jsdscript)
81 : funName = JSD_GetScriptFunctionId(jsdc, jsdscript);
82 : }
83 :
84 : if(before)
85 : printf("%sentering ", _indentSpaces(indent++));
86 : else
87 : printf("%sleaving ", _indentSpaces(--indent));
88 :
89 : if (!funName)
90 : printf("TOP_LEVEL");
91 : else
92 : JS_FileEscapedString(stdout, funName, 0);
93 :
94 : if(before)
95 : {
96 : jsval thisVal;
97 :
98 : printf("%s this: ", JS_IsConstructorFrame(cx, fp) ? "constructing":"");
99 :
100 : if (JS_GetFrameThis(cx, fp, &thisVal))
101 : printf("0x%0llx", (uintptr_t) thisVal);
102 : else
103 : puts("<unavailable>");
104 : }
105 : printf("\n");
106 : JS_ASSERT(indent >= 0);
107 : }
108 : #endif
109 :
110 : JSBool
111 5801760 : _callHook(JSDContext *jsdc, JSContext *cx, JSStackFrame *fp, JSBool before,
112 : unsigned type, JSD_CallHookProc hook, void *hookData)
113 : {
114 : JSDScript* jsdscript;
115 : JSScript* jsscript;
116 5801760 : JSBool hookresult = JS_TRUE;
117 :
118 5801760 : if (!jsdc || !jsdc->inited)
119 0 : return JS_FALSE;
120 :
121 5801760 : if (!hook && !(jsdc->flags & JSD_COLLECT_PROFILE_DATA))
122 : {
123 : /* no hook to call, no profile data needs to be collected,
124 : * so there is nothing to do here.
125 : */
126 5801760 : return hookresult;
127 : }
128 :
129 0 : if (before && JS_IsConstructorFrame(cx, fp)) {
130 : jsval newObj;
131 0 : if (!JS_GetFrameThis(cx, fp, &newObj))
132 0 : return JS_FALSE;
133 0 : jsd_Constructing(jsdc, cx, JSVAL_TO_OBJECT(newObj), fp);
134 : }
135 :
136 0 : jsscript = JS_GetFrameScript(cx, fp);
137 0 : if (jsscript)
138 : {
139 0 : JSD_LOCK_SCRIPTS(jsdc);
140 0 : jsdscript = jsd_FindOrCreateJSDScript(jsdc, cx, jsscript, fp);
141 0 : JSD_UNLOCK_SCRIPTS(jsdc);
142 :
143 0 : if (jsdscript)
144 : {
145 0 : if (JSD_IS_PROFILE_ENABLED(jsdc, jsdscript))
146 0 : {
147 : JSDProfileData *pdata;
148 0 : pdata = jsd_GetScriptProfileData (jsdc, jsdscript);
149 0 : if (pdata)
150 : {
151 0 : if (before)
152 : {
153 0 : if (!pdata->lastCallStart)
154 : {
155 : int64_t now;
156 : JSDProfileData *callerpdata;
157 :
158 : /* Get the time just the once, for consistency. */
159 0 : now = JS_Now();
160 : /* This contains a pointer to the profile data for
161 : * the caller of this function. */
162 0 : callerpdata = jsdc->callingFunctionPData;
163 0 : if (callerpdata)
164 : {
165 : int64_t ll_delta;
166 0 : pdata->caller = callerpdata;
167 : /* We need to 'stop' the timer for the caller.
168 : * Use time since last return if appropriate. */
169 0 : ll_delta = jsdc->lastReturnTime
170 0 : ? now - jsdc->lastReturnTime
171 0 : : now - callerpdata->lastCallStart;
172 0 : callerpdata->runningTime += ll_delta;
173 : }
174 : /* We're the new current function, and no return
175 : * has happened yet. */
176 0 : jsdc->callingFunctionPData = pdata;
177 0 : jsdc->lastReturnTime = 0;
178 : /* This function has no running time (just been
179 : * called!), and we'll need the call start time. */
180 0 : pdata->runningTime = 0;
181 0 : pdata->lastCallStart = now;
182 : } else {
183 0 : if (++pdata->recurseDepth > pdata->maxRecurseDepth)
184 0 : pdata->maxRecurseDepth = pdata->recurseDepth;
185 : }
186 : /* make sure we're called for the return too. */
187 0 : hookresult = JS_TRUE;
188 0 : } else if (!pdata->recurseDepth && pdata->lastCallStart) {
189 : int64_t now, ll_delta;
190 : double delta;
191 0 : now = JS_Now();
192 0 : ll_delta = now - pdata->lastCallStart;
193 0 : delta = ll_delta;
194 0 : delta /= 1000.0;
195 0 : pdata->totalExecutionTime += delta;
196 : /* minExecutionTime starts as 0, so we need to overwrite
197 : * it on the first call always. */
198 0 : if ((0 == pdata->callCount) ||
199 0 : delta < pdata->minExecutionTime)
200 : {
201 0 : pdata->minExecutionTime = delta;
202 : }
203 0 : if (delta > pdata->maxExecutionTime)
204 0 : pdata->maxExecutionTime = delta;
205 :
206 : /* If we last returned from a function (as opposed to
207 : * having last entered this function), we need to inc.
208 : * the running total by the time delta since the last
209 : * return, and use the running total instead of the
210 : * delta calculated above. */
211 0 : if (jsdc->lastReturnTime)
212 : {
213 : /* Add last chunk to running time, and use total
214 : * running time as 'delta'. */
215 0 : ll_delta = now - jsdc->lastReturnTime;
216 0 : pdata->runningTime += ll_delta;
217 0 : delta = pdata->runningTime;
218 0 : delta /= 1000.0;
219 : }
220 :
221 0 : pdata->totalOwnExecutionTime += delta;
222 : /* See minExecutionTime comment above. */
223 0 : if ((0 == pdata->callCount) ||
224 0 : delta < pdata->minOwnExecutionTime)
225 : {
226 0 : pdata->minOwnExecutionTime = delta;
227 : }
228 0 : if (delta > pdata->maxOwnExecutionTime)
229 0 : pdata->maxOwnExecutionTime = delta;
230 :
231 : /* Current function is now our caller. */
232 0 : jsdc->callingFunctionPData = pdata->caller;
233 : /* No hanging pointers, please. */
234 0 : pdata->caller = NULL;
235 : /* Mark the time we returned, and indicate this
236 : * function is no longer running. */
237 0 : jsdc->lastReturnTime = now;
238 0 : pdata->lastCallStart = 0;
239 0 : ++pdata->callCount;
240 0 : } else if (pdata->recurseDepth) {
241 0 : --pdata->recurseDepth;
242 0 : ++pdata->callCount;
243 : }
244 : }
245 0 : if (hook)
246 0 : jsd_CallCallHook (jsdc, cx, type, hook, hookData);
247 : } else {
248 0 : if (hook)
249 0 : hookresult =
250 : jsd_CallCallHook (jsdc, cx, type, hook, hookData);
251 : else
252 0 : hookresult = JS_TRUE;
253 : }
254 : }
255 : }
256 :
257 : #ifdef JSD_TRACE
258 : _interpreterTrace(jsdc, cx, fp, before);
259 : return JS_TRUE;
260 : #else
261 0 : return hookresult;
262 : #endif
263 :
264 : }
265 :
266 : void *
267 5791558 : jsd_FunctionCallHook(JSContext *cx, JSStackFrame *fp, JSBool before,
268 : JSBool *ok, void *closure)
269 : {
270 : JSDContext* jsdc;
271 : JSD_CallHookProc hook;
272 : void* hookData;
273 :
274 5791558 : jsdc = (JSDContext*) closure;
275 :
276 : /* local in case jsdc->functionHook gets cleared on another thread */
277 5791558 : JSD_LOCK();
278 5791558 : hook = jsdc->functionHook;
279 5791558 : hookData = jsdc->functionHookData;
280 5791558 : JSD_UNLOCK();
281 :
282 5791558 : if (_callHook (jsdc, cx, fp, before,
283 : (before) ? JSD_HOOK_FUNCTION_CALL : JSD_HOOK_FUNCTION_RETURN,
284 : hook, hookData))
285 : {
286 5791558 : return closure;
287 : }
288 :
289 0 : return NULL;
290 : }
291 :
292 : void *
293 10202 : jsd_TopLevelCallHook(JSContext *cx, JSStackFrame *fp, JSBool before,
294 : JSBool *ok, void *closure)
295 : {
296 : JSDContext* jsdc;
297 : JSD_CallHookProc hook;
298 : void* hookData;
299 :
300 10202 : jsdc = (JSDContext*) closure;
301 :
302 : /* local in case jsdc->toplevelHook gets cleared on another thread */
303 10202 : JSD_LOCK();
304 10202 : hook = jsdc->toplevelHook;
305 10202 : hookData = jsdc->toplevelHookData;
306 10202 : JSD_UNLOCK();
307 :
308 10202 : if (_callHook (jsdc, cx, fp, before,
309 : (before) ? JSD_HOOK_TOPLEVEL_START : JSD_HOOK_TOPLEVEL_END,
310 : hook, hookData))
311 : {
312 10202 : return closure;
313 : }
314 :
315 0 : return NULL;
316 :
317 : }
|