Trigger another mozilla-central build. a=breakage
[mozilla-central.git] / js / jsd / jsd_stak.c
blob5e1561f043eab804478b9cea15ca48b6c0b5c14a
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
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/
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.
15 * The Original Code is mozilla.org code.
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.
22 * Contributor(s):
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.
36 * ***** END LICENSE BLOCK ***** */
39 * JavaScript Debugging support - Call stack support
42 #include "jsd.h"
43 #include "jsfriendapi.h"
45 #ifdef DEBUG
46 void JSD_ASSERT_VALID_THREAD_STATE(JSDThreadState* jsdthreadstate)
48 JS_ASSERT(jsdthreadstate);
49 JS_ASSERT(jsdthreadstate->stackDepth > 0);
52 void JSD_ASSERT_VALID_STACK_FRAME(JSDStackFrameInfo* jsdframe)
54 JS_ASSERT(jsdframe);
55 JS_ASSERT(jsdframe->jsdthreadstate);
57 #endif
59 static JSDStackFrameInfo*
60 _addNewFrame(JSDContext* jsdc,
61 JSDThreadState* jsdthreadstate,
62 JSScript* script,
63 jsuword pc,
64 JSStackFrame* fp)
66 JSDStackFrameInfo* jsdframe;
67 JSDScript* jsdscript = NULL;
69 if (JS_IsScriptFrame(jsdthreadstate->context, fp))
71 JSD_LOCK_SCRIPTS(jsdc);
72 jsdscript = jsd_FindJSDScript(jsdc, script);
73 JSD_UNLOCK_SCRIPTS(jsdc);
74 if (!jsdscript || (jsdc->flags & JSD_HIDE_DISABLED_FRAMES &&
75 !JSD_IS_DEBUG_ENABLED(jsdc, jsdscript)))
77 return NULL;
80 if (!JSD_IS_DEBUG_ENABLED(jsdc, jsdscript))
81 jsdthreadstate->flags |= TS_HAS_DISABLED_FRAME;
84 jsdframe = (JSDStackFrameInfo*) calloc(1, sizeof(JSDStackFrameInfo));
85 if( ! jsdframe )
86 return NULL;
88 jsdframe->jsdthreadstate = jsdthreadstate;
89 jsdframe->jsdscript = jsdscript;
90 jsdframe->pc = pc;
91 jsdframe->fp = fp;
93 JS_APPEND_LINK(&jsdframe->links, &jsdthreadstate->stack);
94 jsdthreadstate->stackDepth++;
96 return jsdframe;
99 static void
100 _destroyFrame(JSDStackFrameInfo* jsdframe)
102 /* kill any alloc'd objects in frame here... */
104 if( jsdframe )
105 free(jsdframe);
108 JSDThreadState*
109 jsd_NewThreadState(JSDContext* jsdc, JSContext *cx )
111 JSDThreadState* jsdthreadstate;
112 JSStackFrame * iter = NULL;
113 JSStackFrame * fp;
115 jsdthreadstate = (JSDThreadState*)calloc(1, sizeof(JSDThreadState));
116 if( ! jsdthreadstate )
117 return NULL;
119 jsdthreadstate->context = cx;
120 jsdthreadstate->thread = JSD_CURRENT_THREAD();
121 JS_INIT_CLIST(&jsdthreadstate->stack);
122 jsdthreadstate->stackDepth = 0;
124 JS_BeginRequest(jsdthreadstate->context);
125 while( NULL != (fp = JS_FrameIterator(cx, &iter)) )
127 JSScript* script = JS_GetFrameScript(cx, fp);
128 jsuword pc = (jsuword) JS_GetFramePC(cx, fp);
129 jsval dummyThis;
132 * don't construct a JSDStackFrame for dummy frames (those without a
133 * |this| object, or native frames, if JSD_INCLUDE_NATIVE_FRAMES
134 * isn't set.
136 if (JS_GetFrameThis(cx, fp, &dummyThis) &&
137 ((jsdc->flags & JSD_INCLUDE_NATIVE_FRAMES) ||
138 JS_IsScriptFrame(cx, fp)))
140 JSDStackFrameInfo *frame;
142 frame = _addNewFrame( jsdc, jsdthreadstate, script, pc, fp );
144 if ((jsdthreadstate->stackDepth == 0 && !frame) ||
145 (jsdthreadstate->stackDepth == 1 && frame &&
146 frame->jsdscript && !JSD_IS_DEBUG_ENABLED(jsdc, frame->jsdscript)))
149 * if we failed to create the first frame, or the top frame
150 * is not enabled for debugging, fail the entire thread state.
152 JS_INIT_CLIST(&jsdthreadstate->links);
153 JS_EndRequest(jsdthreadstate->context);
154 jsd_DestroyThreadState(jsdc, jsdthreadstate);
155 return NULL;
159 JS_EndRequest(jsdthreadstate->context);
161 if (jsdthreadstate->stackDepth == 0)
163 free(jsdthreadstate);
164 return NULL;
167 JSD_LOCK_THREADSTATES(jsdc);
168 JS_APPEND_LINK(&jsdthreadstate->links, &jsdc->threadsStates);
169 JSD_UNLOCK_THREADSTATES(jsdc);
171 return jsdthreadstate;
174 void
175 jsd_DestroyThreadState(JSDContext* jsdc, JSDThreadState* jsdthreadstate)
177 JSDStackFrameInfo* jsdframe;
178 JSCList* list;
180 JS_ASSERT(jsdthreadstate);
181 JS_ASSERT(JSD_CURRENT_THREAD() == jsdthreadstate->thread);
183 JSD_LOCK_THREADSTATES(jsdc);
184 JS_REMOVE_LINK(&jsdthreadstate->links);
185 JSD_UNLOCK_THREADSTATES(jsdc);
187 list = &jsdthreadstate->stack;
188 while( (JSDStackFrameInfo*)list != (jsdframe = (JSDStackFrameInfo*)list->next) )
190 JS_REMOVE_LINK(&jsdframe->links);
191 _destroyFrame(jsdframe);
193 free(jsdthreadstate);
196 uintN
197 jsd_GetCountOfStackFrames(JSDContext* jsdc, JSDThreadState* jsdthreadstate)
199 uintN count = 0;
201 JSD_LOCK_THREADSTATES(jsdc);
203 if( jsd_IsValidThreadState(jsdc, jsdthreadstate) )
204 count = jsdthreadstate->stackDepth;
206 JSD_UNLOCK_THREADSTATES(jsdc);
208 return count;
211 JSDStackFrameInfo*
212 jsd_GetStackFrame(JSDContext* jsdc, JSDThreadState* jsdthreadstate)
214 JSDStackFrameInfo* jsdframe = NULL;
216 JSD_LOCK_THREADSTATES(jsdc);
218 if( jsd_IsValidThreadState(jsdc, jsdthreadstate) )
219 jsdframe = (JSDStackFrameInfo*) JS_LIST_HEAD(&jsdthreadstate->stack);
220 JSD_UNLOCK_THREADSTATES(jsdc);
222 return jsdframe;
225 JSContext *
226 jsd_GetJSContext (JSDContext* jsdc, JSDThreadState* jsdthreadstate)
228 JSContext* cx = NULL;
230 JSD_LOCK_THREADSTATES(jsdc);
231 if( jsd_IsValidThreadState(jsdc, jsdthreadstate) )
232 cx = jsdthreadstate->context;
233 JSD_UNLOCK_THREADSTATES(jsdc);
235 return cx;
238 JSDStackFrameInfo*
239 jsd_GetCallingStackFrame(JSDContext* jsdc,
240 JSDThreadState* jsdthreadstate,
241 JSDStackFrameInfo* jsdframe)
243 JSDStackFrameInfo* nextjsdframe = NULL;
245 JSD_LOCK_THREADSTATES(jsdc);
247 if( jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe) )
248 if( JS_LIST_HEAD(&jsdframe->links) != &jsdframe->jsdthreadstate->stack )
249 nextjsdframe = (JSDStackFrameInfo*) JS_LIST_HEAD(&jsdframe->links);
251 JSD_UNLOCK_THREADSTATES(jsdc);
253 return nextjsdframe;
256 JSDScript*
257 jsd_GetScriptForStackFrame(JSDContext* jsdc,
258 JSDThreadState* jsdthreadstate,
259 JSDStackFrameInfo* jsdframe)
261 JSDScript* jsdscript = NULL;
263 JSD_LOCK_THREADSTATES(jsdc);
265 if( jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe) )
266 jsdscript = jsdframe->jsdscript;
268 JSD_UNLOCK_THREADSTATES(jsdc);
270 return jsdscript;
273 jsuword
274 jsd_GetPCForStackFrame(JSDContext* jsdc,
275 JSDThreadState* jsdthreadstate,
276 JSDStackFrameInfo* jsdframe)
278 jsuword pc = 0;
280 JSD_LOCK_THREADSTATES(jsdc);
282 if( jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe) )
283 pc = jsdframe->pc;
285 JSD_UNLOCK_THREADSTATES(jsdc);
287 return pc;
290 JSDValue*
291 jsd_GetCallObjectForStackFrame(JSDContext* jsdc,
292 JSDThreadState* jsdthreadstate,
293 JSDStackFrameInfo* jsdframe)
295 JSObject* obj;
296 JSDValue* jsdval = NULL;
298 JSD_LOCK_THREADSTATES(jsdc);
300 if( jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe) )
302 obj = JS_GetFrameCallObject(jsdthreadstate->context, jsdframe->fp);
303 if(obj)
304 jsdval = JSD_NewValue(jsdc, OBJECT_TO_JSVAL(obj));
307 JSD_UNLOCK_THREADSTATES(jsdc);
309 return jsdval;
312 JSDValue*
313 jsd_GetScopeChainForStackFrame(JSDContext* jsdc,
314 JSDThreadState* jsdthreadstate,
315 JSDStackFrameInfo* jsdframe)
317 JSObject* obj;
318 JSDValue* jsdval = NULL;
320 JSD_LOCK_THREADSTATES(jsdc);
322 if( jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe) )
324 JS_BeginRequest(jsdthreadstate->context);
325 obj = JS_GetFrameScopeChain(jsdthreadstate->context, jsdframe->fp);
326 JS_EndRequest(jsdthreadstate->context);
327 if(obj)
328 jsdval = JSD_NewValue(jsdc, OBJECT_TO_JSVAL(obj));
331 JSD_UNLOCK_THREADSTATES(jsdc);
333 return jsdval;
336 JSDValue*
337 jsd_GetThisForStackFrame(JSDContext* jsdc,
338 JSDThreadState* jsdthreadstate,
339 JSDStackFrameInfo* jsdframe)
341 JSObject* obj;
342 JSDValue* jsdval = NULL;
343 JSD_LOCK_THREADSTATES(jsdc);
345 if( jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe) )
347 JSBool ok;
348 jsval thisval;
349 JS_BeginRequest(jsdthreadstate->context);
350 ok = JS_GetFrameThis(jsdthreadstate->context, jsdframe->fp, &thisval);
351 JS_EndRequest(jsdthreadstate->context);
352 if(ok)
353 jsdval = JSD_NewValue(jsdc, thisval);
356 JSD_UNLOCK_THREADSTATES(jsdc);
357 return jsdval;
360 JSString*
361 jsd_GetNameForStackFrame(JSDContext* jsdc,
362 JSDThreadState* jsdthreadstate,
363 JSDStackFrameInfo* jsdframe)
365 JSString *rv = NULL;
367 JSD_LOCK_THREADSTATES(jsdc);
369 if( jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe) )
371 JSFunction *fun = JS_GetFrameFunction (jsdthreadstate->context,
372 jsdframe->fp);
373 if( fun )
375 rv = JS_GetFunctionId (fun);
378 * For compatibility we return "anonymous", not an empty string
379 * here.
381 if( !rv )
382 rv = JS_GetAnonymousString(jsdc->jsrt);
386 JSD_UNLOCK_THREADSTATES(jsdc);
387 return rv;
390 JSBool
391 jsd_IsStackFrameDebugger(JSDContext* jsdc,
392 JSDThreadState* jsdthreadstate,
393 JSDStackFrameInfo* jsdframe)
395 JSBool rv = JS_TRUE;
396 JSD_LOCK_THREADSTATES(jsdc);
398 if( jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe) )
400 rv = JS_IsDebuggerFrame(jsdthreadstate->context, jsdframe->fp);
403 JSD_UNLOCK_THREADSTATES(jsdc);
404 return rv;
407 JSBool
408 jsd_IsStackFrameConstructing(JSDContext* jsdc,
409 JSDThreadState* jsdthreadstate,
410 JSDStackFrameInfo* jsdframe)
412 JSBool rv = JS_TRUE;
413 JSD_LOCK_THREADSTATES(jsdc);
415 if( jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe) )
417 rv = JS_IsConstructorFrame(jsdthreadstate->context, jsdframe->fp);
420 JSD_UNLOCK_THREADSTATES(jsdc);
421 return rv;
424 JSBool
425 jsd_EvaluateUCScriptInStackFrame(JSDContext* jsdc,
426 JSDThreadState* jsdthreadstate,
427 JSDStackFrameInfo* jsdframe,
428 const jschar *bytes, uintN length,
429 const char *filename, uintN lineno,
430 JSBool eatExceptions, jsval *rval)
432 JSBool retval;
433 JSBool valid;
434 JSExceptionState* exceptionState = NULL;
435 JSContext* cx;
437 JS_ASSERT(JSD_CURRENT_THREAD() == jsdthreadstate->thread);
439 JSD_LOCK_THREADSTATES(jsdc);
440 valid = jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe);
441 JSD_UNLOCK_THREADSTATES(jsdc);
443 if( ! valid )
444 return JS_FALSE;
446 cx = jsdthreadstate->context;
447 JS_ASSERT(cx);
449 if (eatExceptions)
450 exceptionState = JS_SaveExceptionState(cx);
451 JS_ClearPendingException(cx);
452 jsd_StartingEvalUsingFilename(jsdc, filename);
453 retval = JS_EvaluateUCInStackFrame(cx, jsdframe->fp, bytes, length,
454 filename, lineno, rval);
455 jsd_FinishedEvalUsingFilename(jsdc, filename);
456 if (eatExceptions)
457 JS_RestoreExceptionState(cx, exceptionState);
459 return retval;
462 JSBool
463 jsd_EvaluateScriptInStackFrame(JSDContext* jsdc,
464 JSDThreadState* jsdthreadstate,
465 JSDStackFrameInfo* jsdframe,
466 const char *bytes, uintN length,
467 const char *filename, uintN lineno,
468 JSBool eatExceptions, jsval *rval)
470 JSBool retval;
471 JSBool valid;
472 JSExceptionState* exceptionState = NULL;
473 JSContext *cx;
475 JS_ASSERT(JSD_CURRENT_THREAD() == jsdthreadstate->thread);
477 JSD_LOCK_THREADSTATES(jsdc);
478 valid = jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe);
479 JSD_UNLOCK_THREADSTATES(jsdc);
481 if (!valid)
482 return JS_FALSE;
484 cx = jsdthreadstate->context;
485 JS_ASSERT(cx);
487 if (eatExceptions)
488 exceptionState = JS_SaveExceptionState(cx);
489 JS_ClearPendingException(cx);
490 jsd_StartingEvalUsingFilename(jsdc, filename);
491 retval = JS_EvaluateInStackFrame(cx, jsdframe->fp, bytes, length,
492 filename, lineno, rval);
493 jsd_FinishedEvalUsingFilename(jsdc, filename);
494 if (eatExceptions)
495 JS_RestoreExceptionState(cx, exceptionState);
497 return retval;
500 JSString*
501 jsd_ValToStringInStackFrame(JSDContext* jsdc,
502 JSDThreadState* jsdthreadstate,
503 JSDStackFrameInfo* jsdframe,
504 jsval val)
506 JSBool valid;
507 JSString* retval;
508 JSExceptionState* exceptionState;
509 JSContext* cx;
511 JSD_LOCK_THREADSTATES(jsdc);
512 valid = jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe);
513 JSD_UNLOCK_THREADSTATES(jsdc);
515 if( ! valid )
516 return NULL;
518 cx = jsdthreadstate->context;
519 JS_ASSERT(cx);
521 exceptionState = JS_SaveExceptionState(cx);
522 retval = JS_ValueToString(cx, val);
523 JS_RestoreExceptionState(cx, exceptionState);
525 return retval;
528 JSBool
529 jsd_IsValidThreadState(JSDContext* jsdc,
530 JSDThreadState* jsdthreadstate)
532 JSDThreadState *cur;
534 JS_ASSERT( JSD_THREADSTATES_LOCKED(jsdc) );
536 for( cur = (JSDThreadState*)jsdc->threadsStates.next;
537 cur != (JSDThreadState*)&jsdc->threadsStates;
538 cur = (JSDThreadState*)cur->links.next )
540 if( cur == jsdthreadstate )
541 return JS_TRUE;
543 return JS_FALSE;
546 JSBool
547 jsd_IsValidFrameInThreadState(JSDContext* jsdc,
548 JSDThreadState* jsdthreadstate,
549 JSDStackFrameInfo* jsdframe)
551 JS_ASSERT(JSD_THREADSTATES_LOCKED(jsdc));
553 if( ! jsd_IsValidThreadState(jsdc, jsdthreadstate) )
554 return JS_FALSE;
555 if( jsdframe->jsdthreadstate != jsdthreadstate )
556 return JS_FALSE;
558 JSD_ASSERT_VALID_THREAD_STATE(jsdthreadstate);
559 JSD_ASSERT_VALID_STACK_FRAME(jsdframe);
561 return JS_TRUE;
564 static JSContext*
565 _getContextForThreadState(JSDContext* jsdc, JSDThreadState* jsdthreadstate)
567 JSBool valid;
568 JSD_LOCK_THREADSTATES(jsdc);
569 valid = jsd_IsValidThreadState(jsdc, jsdthreadstate);
570 JSD_UNLOCK_THREADSTATES(jsdc);
571 if( valid )
572 return jsdthreadstate->context;
573 return NULL;
576 JSDValue*
577 jsd_GetException(JSDContext* jsdc, JSDThreadState* jsdthreadstate)
579 JSContext* cx;
580 jsval val;
582 if(!(cx = _getContextForThreadState(jsdc, jsdthreadstate)))
583 return NULL;
585 if(JS_GetPendingException(cx, &val))
586 return jsd_NewValue(jsdc, val);
587 return NULL;
590 JSBool
591 jsd_SetException(JSDContext* jsdc, JSDThreadState* jsdthreadstate,
592 JSDValue* jsdval)
594 JSContext* cx;
596 if(!(cx = _getContextForThreadState(jsdc, jsdthreadstate)))
597 return JS_FALSE;
599 if(jsdval)
600 JS_SetPendingException(cx, JSD_GetValueWrappedJSVal(jsdc, jsdval));
601 else
602 JS_ClearPendingException(cx);
603 return JS_TRUE;