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
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.
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
43 #include "jsfriendapi.h"
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)
55 JS_ASSERT(jsdframe->jsdthreadstate);
59 static JSDStackFrameInfo*
60 _addNewFrame(JSDContext* jsdc,
61 JSDThreadState* jsdthreadstate,
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)))
80 if (!JSD_IS_DEBUG_ENABLED(jsdc, jsdscript))
81 jsdthreadstate->flags |= TS_HAS_DISABLED_FRAME;
84 jsdframe = (JSDStackFrameInfo*) calloc(1, sizeof(JSDStackFrameInfo));
88 jsdframe->jsdthreadstate = jsdthreadstate;
89 jsdframe->jsdscript = jsdscript;
93 JS_APPEND_LINK(&jsdframe->links, &jsdthreadstate->stack);
94 jsdthreadstate->stackDepth++;
100 _destroyFrame(JSDStackFrameInfo* jsdframe)
102 /* kill any alloc'd objects in frame here... */
109 jsd_NewThreadState(JSDContext* jsdc, JSContext *cx )
111 JSDThreadState* jsdthreadstate;
112 JSStackFrame * iter = NULL;
115 jsdthreadstate = (JSDThreadState*)calloc(1, sizeof(JSDThreadState));
116 if( ! jsdthreadstate )
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);
132 * don't construct a JSDStackFrame for dummy frames (those without a
133 * |this| object, or native frames, if JSD_INCLUDE_NATIVE_FRAMES
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);
159 JS_EndRequest(jsdthreadstate->context);
161 if (jsdthreadstate->stackDepth == 0)
163 free(jsdthreadstate);
167 JSD_LOCK_THREADSTATES(jsdc);
168 JS_APPEND_LINK(&jsdthreadstate->links, &jsdc->threadsStates);
169 JSD_UNLOCK_THREADSTATES(jsdc);
171 return jsdthreadstate;
175 jsd_DestroyThreadState(JSDContext* jsdc, JSDThreadState* jsdthreadstate)
177 JSDStackFrameInfo* jsdframe;
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);
197 jsd_GetCountOfStackFrames(JSDContext* jsdc, JSDThreadState* jsdthreadstate)
201 JSD_LOCK_THREADSTATES(jsdc);
203 if( jsd_IsValidThreadState(jsdc, jsdthreadstate) )
204 count = jsdthreadstate->stackDepth;
206 JSD_UNLOCK_THREADSTATES(jsdc);
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);
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);
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);
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);
274 jsd_GetPCForStackFrame(JSDContext* jsdc,
275 JSDThreadState* jsdthreadstate,
276 JSDStackFrameInfo* jsdframe)
280 JSD_LOCK_THREADSTATES(jsdc);
282 if( jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe) )
285 JSD_UNLOCK_THREADSTATES(jsdc);
291 jsd_GetCallObjectForStackFrame(JSDContext* jsdc,
292 JSDThreadState* jsdthreadstate,
293 JSDStackFrameInfo* jsdframe)
296 JSDValue* jsdval = NULL;
298 JSD_LOCK_THREADSTATES(jsdc);
300 if( jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe) )
302 obj = JS_GetFrameCallObject(jsdthreadstate->context, jsdframe->fp);
304 jsdval = JSD_NewValue(jsdc, OBJECT_TO_JSVAL(obj));
307 JSD_UNLOCK_THREADSTATES(jsdc);
313 jsd_GetScopeChainForStackFrame(JSDContext* jsdc,
314 JSDThreadState* jsdthreadstate,
315 JSDStackFrameInfo* jsdframe)
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);
328 jsdval = JSD_NewValue(jsdc, OBJECT_TO_JSVAL(obj));
331 JSD_UNLOCK_THREADSTATES(jsdc);
337 jsd_GetThisForStackFrame(JSDContext* jsdc,
338 JSDThreadState* jsdthreadstate,
339 JSDStackFrameInfo* jsdframe)
342 JSDValue* jsdval = NULL;
343 JSD_LOCK_THREADSTATES(jsdc);
345 if( jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe) )
349 JS_BeginRequest(jsdthreadstate->context);
350 ok = JS_GetFrameThis(jsdthreadstate->context, jsdframe->fp, &thisval);
351 JS_EndRequest(jsdthreadstate->context);
353 jsdval = JSD_NewValue(jsdc, thisval);
356 JSD_UNLOCK_THREADSTATES(jsdc);
361 jsd_GetIdForStackFrame(JSDContext* jsdc,
362 JSDThreadState* jsdthreadstate,
363 JSDStackFrameInfo* jsdframe)
367 JSD_LOCK_THREADSTATES(jsdc);
369 if( jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe) )
371 JSFunction *fun = JS_GetFrameFunction (jsdthreadstate->context,
375 rv = JS_GetFunctionId (fun);
378 * For compatibility we return "anonymous", not an empty string
382 rv = JS_GetAnonymousString(jsdc->jsrt);
386 JSD_UNLOCK_THREADSTATES(jsdc);
391 jsd_IsStackFrameDebugger(JSDContext* jsdc,
392 JSDThreadState* jsdthreadstate,
393 JSDStackFrameInfo* jsdframe)
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);
408 jsd_IsStackFrameConstructing(JSDContext* jsdc,
409 JSDThreadState* jsdthreadstate,
410 JSDStackFrameInfo* jsdframe)
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);
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)
434 JSExceptionState* exceptionState = NULL;
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);
446 cx = jsdthreadstate->context;
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);
457 JS_RestoreExceptionState(cx, exceptionState);
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)
472 JSExceptionState* exceptionState = NULL;
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);
484 cx = jsdthreadstate->context;
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);
495 JS_RestoreExceptionState(cx, exceptionState);
501 jsd_ValToStringInStackFrame(JSDContext* jsdc,
502 JSDThreadState* jsdthreadstate,
503 JSDStackFrameInfo* jsdframe,
508 JSExceptionState* exceptionState;
511 JSD_LOCK_THREADSTATES(jsdc);
512 valid = jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe);
513 JSD_UNLOCK_THREADSTATES(jsdc);
518 cx = jsdthreadstate->context;
521 exceptionState = JS_SaveExceptionState(cx);
522 retval = JS_ValueToString(cx, val);
523 JS_RestoreExceptionState(cx, exceptionState);
529 jsd_IsValidThreadState(JSDContext* jsdc,
530 JSDThreadState* jsdthreadstate)
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 )
547 jsd_IsValidFrameInThreadState(JSDContext* jsdc,
548 JSDThreadState* jsdthreadstate,
549 JSDStackFrameInfo* jsdframe)
551 JS_ASSERT(JSD_THREADSTATES_LOCKED(jsdc));
553 if( ! jsd_IsValidThreadState(jsdc, jsdthreadstate) )
555 if( jsdframe->jsdthreadstate != jsdthreadstate )
558 JSD_ASSERT_VALID_THREAD_STATE(jsdthreadstate);
559 JSD_ASSERT_VALID_STACK_FRAME(jsdframe);
565 _getContextForThreadState(JSDContext* jsdc, JSDThreadState* jsdthreadstate)
568 JSD_LOCK_THREADSTATES(jsdc);
569 valid = jsd_IsValidThreadState(jsdc, jsdthreadstate);
570 JSD_UNLOCK_THREADSTATES(jsdc);
572 return jsdthreadstate->context;
577 jsd_GetException(JSDContext* jsdc, JSDThreadState* jsdthreadstate)
582 if(!(cx = _getContextForThreadState(jsdc, jsdthreadstate)))
585 if(JS_GetPendingException(cx, &val))
586 return jsd_NewValue(jsdc, val);
591 jsd_SetException(JSDContext* jsdc, JSDThreadState* jsdthreadstate,
596 if(!(cx = _getContextForThreadState(jsdc, jsdthreadstate)))
600 JS_SetPendingException(cx, JSD_GetValueWrappedJSVal(jsdc, jsdval));
602 JS_ClearPendingException(cx);