Fix crash in AtSafePoint (bug 589398, r=dmandelin).
[mozilla-central.git] / js / jsd / jsd_stak.c
blob9b1ba2c12434193567d14d51f124b7aac491b276
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"
44 #ifdef DEBUG
45 void JSD_ASSERT_VALID_THREAD_STATE(JSDThreadState* jsdthreadstate)
47 JS_ASSERT(jsdthreadstate);
48 JS_ASSERT(jsdthreadstate->stackDepth > 0);
51 void JSD_ASSERT_VALID_STACK_FRAME(JSDStackFrameInfo* jsdframe)
53 JS_ASSERT(jsdframe);
54 JS_ASSERT(jsdframe->jsdthreadstate);
56 #endif
58 static JSDStackFrameInfo*
59 _addNewFrame(JSDContext* jsdc,
60 JSDThreadState* jsdthreadstate,
61 JSScript* script,
62 jsuword pc,
63 JSStackFrame* fp)
65 JSDStackFrameInfo* jsdframe;
66 JSDScript* jsdscript = NULL;
68 if (JS_IsScriptFrame(jsdthreadstate->context, fp))
70 JSD_LOCK_SCRIPTS(jsdc);
71 jsdscript = jsd_FindJSDScript(jsdc, script);
72 JSD_UNLOCK_SCRIPTS(jsdc);
73 if (!jsdscript || (jsdc->flags & JSD_HIDE_DISABLED_FRAMES &&
74 !JSD_IS_DEBUG_ENABLED(jsdc, jsdscript)))
76 return NULL;
79 if (!JSD_IS_DEBUG_ENABLED(jsdc, jsdscript))
80 jsdthreadstate->flags |= TS_HAS_DISABLED_FRAME;
83 jsdframe = (JSDStackFrameInfo*) calloc(1, sizeof(JSDStackFrameInfo));
84 if( ! jsdframe )
85 return NULL;
87 jsdframe->jsdthreadstate = jsdthreadstate;
88 jsdframe->jsdscript = jsdscript;
89 jsdframe->pc = pc;
90 jsdframe->fp = fp;
92 JS_APPEND_LINK(&jsdframe->links, &jsdthreadstate->stack);
93 jsdthreadstate->stackDepth++;
95 return jsdframe;
98 static void
99 _destroyFrame(JSDStackFrameInfo* jsdframe)
101 /* kill any alloc'd objects in frame here... */
103 if( jsdframe )
104 free(jsdframe);
107 JSDThreadState*
108 jsd_NewThreadState(JSDContext* jsdc, JSContext *cx )
110 JSDThreadState* jsdthreadstate;
111 JSStackFrame * iter = NULL;
112 JSStackFrame * fp;
114 jsdthreadstate = (JSDThreadState*)calloc(1, sizeof(JSDThreadState));
115 if( ! jsdthreadstate )
116 return NULL;
118 jsdthreadstate->context = cx;
119 jsdthreadstate->thread = JSD_CURRENT_THREAD();
120 JS_INIT_CLIST(&jsdthreadstate->stack);
121 jsdthreadstate->stackDepth = 0;
123 JS_BeginRequest(jsdthreadstate->context);
124 while( NULL != (fp = JS_FrameIterator(cx, &iter)) )
126 JSScript* script = JS_GetFrameScript(cx, fp);
127 jsuword pc = (jsuword) JS_GetFramePC(cx, fp);
130 * don't construct a JSDStackFrame for dummy frames (those without a
131 * |this| object, or native frames, if JSD_INCLUDE_NATIVE_FRAMES
132 * isn't set.
134 if (JS_GetFrameThis(cx, fp) &&
135 ((jsdc->flags & JSD_INCLUDE_NATIVE_FRAMES) ||
136 JS_IsScriptFrame(cx, fp)))
138 JSDStackFrameInfo *frame;
140 frame = _addNewFrame( jsdc, jsdthreadstate, script, pc, fp );
142 if ((jsdthreadstate->stackDepth == 0 && !frame) ||
143 (jsdthreadstate->stackDepth == 1 && frame &&
144 frame->jsdscript && !JSD_IS_DEBUG_ENABLED(jsdc, frame->jsdscript)))
147 * if we failed to create the first frame, or the top frame
148 * is not enabled for debugging, fail the entire thread state.
150 JS_INIT_CLIST(&jsdthreadstate->links);
151 JS_EndRequest(jsdthreadstate->context);
152 jsd_DestroyThreadState(jsdc, jsdthreadstate);
153 return NULL;
157 JS_EndRequest(jsdthreadstate->context);
159 if (jsdthreadstate->stackDepth == 0)
161 free(jsdthreadstate);
162 return NULL;
165 JSD_LOCK_THREADSTATES(jsdc);
166 JS_APPEND_LINK(&jsdthreadstate->links, &jsdc->threadsStates);
167 JSD_UNLOCK_THREADSTATES(jsdc);
169 return jsdthreadstate;
172 void
173 jsd_DestroyThreadState(JSDContext* jsdc, JSDThreadState* jsdthreadstate)
175 JSDStackFrameInfo* jsdframe;
176 JSCList* list;
178 JS_ASSERT(jsdthreadstate);
179 JS_ASSERT(JSD_CURRENT_THREAD() == jsdthreadstate->thread);
181 JSD_LOCK_THREADSTATES(jsdc);
182 JS_REMOVE_LINK(&jsdthreadstate->links);
183 JSD_UNLOCK_THREADSTATES(jsdc);
185 list = &jsdthreadstate->stack;
186 while( (JSDStackFrameInfo*)list != (jsdframe = (JSDStackFrameInfo*)list->next) )
188 JS_REMOVE_LINK(&jsdframe->links);
189 _destroyFrame(jsdframe);
191 free(jsdthreadstate);
194 uintN
195 jsd_GetCountOfStackFrames(JSDContext* jsdc, JSDThreadState* jsdthreadstate)
197 uintN count = 0;
199 JSD_LOCK_THREADSTATES(jsdc);
201 if( jsd_IsValidThreadState(jsdc, jsdthreadstate) )
202 count = jsdthreadstate->stackDepth;
204 JSD_UNLOCK_THREADSTATES(jsdc);
206 return count;
209 JSDStackFrameInfo*
210 jsd_GetStackFrame(JSDContext* jsdc, JSDThreadState* jsdthreadstate)
212 JSDStackFrameInfo* jsdframe = NULL;
214 JSD_LOCK_THREADSTATES(jsdc);
216 if( jsd_IsValidThreadState(jsdc, jsdthreadstate) )
217 jsdframe = (JSDStackFrameInfo*) JS_LIST_HEAD(&jsdthreadstate->stack);
218 JSD_UNLOCK_THREADSTATES(jsdc);
220 return jsdframe;
223 JSContext *
224 jsd_GetJSContext (JSDContext* jsdc, JSDThreadState* jsdthreadstate)
226 JSContext* cx = NULL;
228 JSD_LOCK_THREADSTATES(jsdc);
229 if( jsd_IsValidThreadState(jsdc, jsdthreadstate) )
230 cx = jsdthreadstate->context;
231 JSD_UNLOCK_THREADSTATES(jsdc);
233 return cx;
236 JSDStackFrameInfo*
237 jsd_GetCallingStackFrame(JSDContext* jsdc,
238 JSDThreadState* jsdthreadstate,
239 JSDStackFrameInfo* jsdframe)
241 JSDStackFrameInfo* nextjsdframe = NULL;
243 JSD_LOCK_THREADSTATES(jsdc);
245 if( jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe) )
246 if( JS_LIST_HEAD(&jsdframe->links) != &jsdframe->jsdthreadstate->stack )
247 nextjsdframe = (JSDStackFrameInfo*) JS_LIST_HEAD(&jsdframe->links);
249 JSD_UNLOCK_THREADSTATES(jsdc);
251 return nextjsdframe;
254 JSDScript*
255 jsd_GetScriptForStackFrame(JSDContext* jsdc,
256 JSDThreadState* jsdthreadstate,
257 JSDStackFrameInfo* jsdframe)
259 JSDScript* jsdscript = NULL;
261 JSD_LOCK_THREADSTATES(jsdc);
263 if( jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe) )
264 jsdscript = jsdframe->jsdscript;
266 JSD_UNLOCK_THREADSTATES(jsdc);
268 return jsdscript;
271 jsuword
272 jsd_GetPCForStackFrame(JSDContext* jsdc,
273 JSDThreadState* jsdthreadstate,
274 JSDStackFrameInfo* jsdframe)
276 jsuword pc = 0;
278 JSD_LOCK_THREADSTATES(jsdc);
280 if( jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe) )
281 pc = jsdframe->pc;
283 JSD_UNLOCK_THREADSTATES(jsdc);
285 return pc;
288 JSDValue*
289 jsd_GetCallObjectForStackFrame(JSDContext* jsdc,
290 JSDThreadState* jsdthreadstate,
291 JSDStackFrameInfo* jsdframe)
293 JSObject* obj;
294 JSDValue* jsdval = NULL;
296 JSD_LOCK_THREADSTATES(jsdc);
298 if( jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe) )
300 obj = JS_GetFrameCallObject(jsdthreadstate->context, jsdframe->fp);
301 if(obj)
302 jsdval = JSD_NewValue(jsdc, OBJECT_TO_JSVAL(obj));
305 JSD_UNLOCK_THREADSTATES(jsdc);
307 return jsdval;
310 JSDValue*
311 jsd_GetScopeChainForStackFrame(JSDContext* jsdc,
312 JSDThreadState* jsdthreadstate,
313 JSDStackFrameInfo* jsdframe)
315 JSObject* obj;
316 JSDValue* jsdval = NULL;
318 JSD_LOCK_THREADSTATES(jsdc);
320 if( jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe) )
322 JS_BeginRequest(jsdthreadstate->context);
323 obj = JS_GetFrameScopeChain(jsdthreadstate->context, jsdframe->fp);
324 JS_EndRequest(jsdthreadstate->context);
325 if(obj)
326 jsdval = JSD_NewValue(jsdc, OBJECT_TO_JSVAL(obj));
329 JSD_UNLOCK_THREADSTATES(jsdc);
331 return jsdval;
334 JSDValue*
335 jsd_GetThisForStackFrame(JSDContext* jsdc,
336 JSDThreadState* jsdthreadstate,
337 JSDStackFrameInfo* jsdframe)
339 JSObject* obj;
340 JSDValue* jsdval = NULL;
341 JSD_LOCK_THREADSTATES(jsdc);
343 if( jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe) )
345 JS_BeginRequest(jsdthreadstate->context);
346 obj = JS_GetFrameThis(jsdthreadstate->context, jsdframe->fp);
347 JS_EndRequest(jsdthreadstate->context);
348 if(obj)
349 jsdval = JSD_NewValue(jsdc, OBJECT_TO_JSVAL(obj));
352 JSD_UNLOCK_THREADSTATES(jsdc);
353 return jsdval;
356 const char*
357 jsd_GetNameForStackFrame(JSDContext* jsdc,
358 JSDThreadState* jsdthreadstate,
359 JSDStackFrameInfo* jsdframe)
361 const char *rv = NULL;
363 JSD_LOCK_THREADSTATES(jsdc);
365 if( jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe) )
367 JSFunction *fun = JS_GetFrameFunction (jsdthreadstate->context,
368 jsdframe->fp);
369 if (fun)
370 rv = JS_GetFunctionName (fun);
373 JSD_UNLOCK_THREADSTATES(jsdc);
374 return rv;
377 JSBool
378 jsd_IsStackFrameDebugger(JSDContext* jsdc,
379 JSDThreadState* jsdthreadstate,
380 JSDStackFrameInfo* jsdframe)
382 JSBool rv = JS_TRUE;
383 JSD_LOCK_THREADSTATES(jsdc);
385 if( jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe) )
387 rv = JS_IsDebuggerFrame(jsdthreadstate->context, jsdframe->fp);
390 JSD_UNLOCK_THREADSTATES(jsdc);
391 return rv;
394 JSBool
395 jsd_IsStackFrameConstructing(JSDContext* jsdc,
396 JSDThreadState* jsdthreadstate,
397 JSDStackFrameInfo* jsdframe)
399 JSBool rv = JS_TRUE;
400 JSD_LOCK_THREADSTATES(jsdc);
402 if( jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe) )
404 rv = JS_IsConstructorFrame(jsdthreadstate->context, jsdframe->fp);
407 JSD_UNLOCK_THREADSTATES(jsdc);
408 return rv;
411 JSBool
412 jsd_EvaluateUCScriptInStackFrame(JSDContext* jsdc,
413 JSDThreadState* jsdthreadstate,
414 JSDStackFrameInfo* jsdframe,
415 const jschar *bytes, uintN length,
416 const char *filename, uintN lineno,
417 JSBool eatExceptions, jsval *rval)
419 JSBool retval;
420 JSBool valid;
421 JSExceptionState* exceptionState = NULL;
422 JSContext* cx;
424 JS_ASSERT(JSD_CURRENT_THREAD() == jsdthreadstate->thread);
426 JSD_LOCK_THREADSTATES(jsdc);
427 valid = jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe);
428 JSD_UNLOCK_THREADSTATES(jsdc);
430 if( ! valid )
431 return JS_FALSE;
433 cx = jsdthreadstate->context;
434 JS_ASSERT(cx);
436 if (eatExceptions)
437 exceptionState = JS_SaveExceptionState(cx);
438 JS_ClearPendingException(cx);
439 jsd_StartingEvalUsingFilename(jsdc, filename);
440 retval = JS_EvaluateUCInStackFrame(cx, jsdframe->fp, bytes, length,
441 filename, lineno, rval);
442 jsd_FinishedEvalUsingFilename(jsdc, filename);
443 if (eatExceptions)
444 JS_RestoreExceptionState(cx, exceptionState);
446 return retval;
449 JSBool
450 jsd_EvaluateScriptInStackFrame(JSDContext* jsdc,
451 JSDThreadState* jsdthreadstate,
452 JSDStackFrameInfo* jsdframe,
453 const char *bytes, uintN length,
454 const char *filename, uintN lineno,
455 JSBool eatExceptions, jsval *rval)
457 JSBool retval;
458 JSBool valid;
459 JSExceptionState* exceptionState = NULL;
460 JSContext *cx;
462 JS_ASSERT(JSD_CURRENT_THREAD() == jsdthreadstate->thread);
464 JSD_LOCK_THREADSTATES(jsdc);
465 valid = jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe);
466 JSD_UNLOCK_THREADSTATES(jsdc);
468 if (!valid)
469 return JS_FALSE;
471 cx = jsdthreadstate->context;
472 JS_ASSERT(cx);
474 if (eatExceptions)
475 exceptionState = JS_SaveExceptionState(cx);
476 JS_ClearPendingException(cx);
477 jsd_StartingEvalUsingFilename(jsdc, filename);
478 retval = JS_EvaluateInStackFrame(cx, jsdframe->fp, bytes, length,
479 filename, lineno, rval);
480 jsd_FinishedEvalUsingFilename(jsdc, filename);
481 if (eatExceptions)
482 JS_RestoreExceptionState(cx, exceptionState);
484 return retval;
487 JSString*
488 jsd_ValToStringInStackFrame(JSDContext* jsdc,
489 JSDThreadState* jsdthreadstate,
490 JSDStackFrameInfo* jsdframe,
491 jsval val)
493 JSBool valid;
494 JSString* retval;
495 JSExceptionState* exceptionState;
496 JSContext* cx;
498 JSD_LOCK_THREADSTATES(jsdc);
499 valid = jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe);
500 JSD_UNLOCK_THREADSTATES(jsdc);
502 if( ! valid )
503 return NULL;
505 cx = jsdthreadstate->context;
506 JS_ASSERT(cx);
508 exceptionState = JS_SaveExceptionState(cx);
509 retval = JS_ValueToString(cx, val);
510 JS_RestoreExceptionState(cx, exceptionState);
512 return retval;
515 JSBool
516 jsd_IsValidThreadState(JSDContext* jsdc,
517 JSDThreadState* jsdthreadstate)
519 JSDThreadState *cur;
521 JS_ASSERT( JSD_THREADSTATES_LOCKED(jsdc) );
523 for( cur = (JSDThreadState*)jsdc->threadsStates.next;
524 cur != (JSDThreadState*)&jsdc->threadsStates;
525 cur = (JSDThreadState*)cur->links.next )
527 if( cur == jsdthreadstate )
528 return JS_TRUE;
530 return JS_FALSE;
533 JSBool
534 jsd_IsValidFrameInThreadState(JSDContext* jsdc,
535 JSDThreadState* jsdthreadstate,
536 JSDStackFrameInfo* jsdframe)
538 JS_ASSERT(JSD_THREADSTATES_LOCKED(jsdc));
540 if( ! jsd_IsValidThreadState(jsdc, jsdthreadstate) )
541 return JS_FALSE;
542 if( jsdframe->jsdthreadstate != jsdthreadstate )
543 return JS_FALSE;
545 JSD_ASSERT_VALID_THREAD_STATE(jsdthreadstate);
546 JSD_ASSERT_VALID_STACK_FRAME(jsdframe);
548 return JS_TRUE;
551 static JSContext*
552 _getContextForThreadState(JSDContext* jsdc, JSDThreadState* jsdthreadstate)
554 JSBool valid;
555 JSD_LOCK_THREADSTATES(jsdc);
556 valid = jsd_IsValidThreadState(jsdc, jsdthreadstate);
557 JSD_UNLOCK_THREADSTATES(jsdc);
558 if( valid )
559 return jsdthreadstate->context;
560 return NULL;
563 JSDValue*
564 jsd_GetException(JSDContext* jsdc, JSDThreadState* jsdthreadstate)
566 JSContext* cx;
567 jsval val;
569 if(!(cx = _getContextForThreadState(jsdc, jsdthreadstate)))
570 return NULL;
572 if(JS_GetPendingException(cx, &val))
573 return jsd_NewValue(jsdc, val);
574 return NULL;
577 JSBool
578 jsd_SetException(JSDContext* jsdc, JSDThreadState* jsdthreadstate,
579 JSDValue* jsdval)
581 JSContext* cx;
583 if(!(cx = _getContextForThreadState(jsdc, jsdthreadstate)))
584 return JS_FALSE;
586 if(jsdval)
587 JS_SetPendingException(cx, JSD_GetValueWrappedJSVal(jsdc, jsdval));
588 else
589 JS_ClearPendingException(cx);
590 return JS_TRUE;