Bug 435739 Poor performance of Firefox 3 with no X RENDER extension
[wine-gecko.git] / js / jsd / jsd_stak.c
blobbb4845826d6edf0b2cf2f875eaba44280c892dde
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_IsNativeFrame(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 while( NULL != (fp = JS_FrameIterator(cx, &iter)) )
125 JSScript* script = JS_GetFrameScript(cx, fp);
126 jsuword pc = (jsuword) JS_GetFramePC(cx, fp);
129 * don't construct a JSDStackFrame for dummy frames (those without a
130 * |this| object, or native frames, if JSD_INCLUDE_NATIVE_FRAMES
131 * isn't set.
133 if (JS_GetFrameThis(cx, fp) &&
134 ((jsdc->flags & JSD_INCLUDE_NATIVE_FRAMES) ||
135 !JS_IsNativeFrame(cx, fp)))
137 JSDStackFrameInfo *frame;
139 frame = _addNewFrame( jsdc, jsdthreadstate, script, pc, fp );
141 if ((jsdthreadstate->stackDepth == 0 && !frame) ||
142 (jsdthreadstate->stackDepth == 1 && frame &&
143 frame->jsdscript && !JSD_IS_DEBUG_ENABLED(jsdc, frame->jsdscript)))
146 * if we failed to create the first frame, or the top frame
147 * is not enabled for debugging, fail the entire thread state.
149 JS_INIT_CLIST(&jsdthreadstate->links);
150 jsd_DestroyThreadState(jsdc, jsdthreadstate);
151 return NULL;
156 if (jsdthreadstate->stackDepth == 0)
158 free(jsdthreadstate);
159 return NULL;
162 JSD_LOCK_THREADSTATES(jsdc);
163 JS_APPEND_LINK(&jsdthreadstate->links, &jsdc->threadsStates);
164 JSD_UNLOCK_THREADSTATES(jsdc);
166 return jsdthreadstate;
169 void
170 jsd_DestroyThreadState(JSDContext* jsdc, JSDThreadState* jsdthreadstate)
172 JSDStackFrameInfo* jsdframe;
173 JSCList* list;
175 JS_ASSERT(jsdthreadstate);
176 JS_ASSERT(JSD_CURRENT_THREAD() == jsdthreadstate->thread);
178 JSD_LOCK_THREADSTATES(jsdc);
179 JS_REMOVE_LINK(&jsdthreadstate->links);
180 JSD_UNLOCK_THREADSTATES(jsdc);
182 list = &jsdthreadstate->stack;
183 while( (JSDStackFrameInfo*)list != (jsdframe = (JSDStackFrameInfo*)list->next) )
185 JS_REMOVE_LINK(&jsdframe->links);
186 _destroyFrame(jsdframe);
188 free(jsdthreadstate);
191 uintN
192 jsd_GetCountOfStackFrames(JSDContext* jsdc, JSDThreadState* jsdthreadstate)
194 uintN count = 0;
196 JSD_LOCK_THREADSTATES(jsdc);
198 if( jsd_IsValidThreadState(jsdc, jsdthreadstate) )
199 count = jsdthreadstate->stackDepth;
201 JSD_UNLOCK_THREADSTATES(jsdc);
203 return count;
206 JSDStackFrameInfo*
207 jsd_GetStackFrame(JSDContext* jsdc, JSDThreadState* jsdthreadstate)
209 JSDStackFrameInfo* jsdframe = NULL;
211 JSD_LOCK_THREADSTATES(jsdc);
213 if( jsd_IsValidThreadState(jsdc, jsdthreadstate) )
214 jsdframe = (JSDStackFrameInfo*) JS_LIST_HEAD(&jsdthreadstate->stack);
215 JSD_UNLOCK_THREADSTATES(jsdc);
217 return jsdframe;
220 JSContext *
221 jsd_GetJSContext (JSDContext* jsdc, JSDThreadState* jsdthreadstate)
223 JSContext* cx = NULL;
225 JSD_LOCK_THREADSTATES(jsdc);
226 if( jsd_IsValidThreadState(jsdc, jsdthreadstate) )
227 cx = jsdthreadstate->context;
228 JSD_UNLOCK_THREADSTATES(jsdc);
230 return cx;
233 JSDStackFrameInfo*
234 jsd_GetCallingStackFrame(JSDContext* jsdc,
235 JSDThreadState* jsdthreadstate,
236 JSDStackFrameInfo* jsdframe)
238 JSDStackFrameInfo* nextjsdframe = NULL;
240 JSD_LOCK_THREADSTATES(jsdc);
242 if( jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe) )
243 if( JS_LIST_HEAD(&jsdframe->links) != &jsdframe->jsdthreadstate->stack )
244 nextjsdframe = (JSDStackFrameInfo*) JS_LIST_HEAD(&jsdframe->links);
246 JSD_UNLOCK_THREADSTATES(jsdc);
248 return nextjsdframe;
251 JSDScript*
252 jsd_GetScriptForStackFrame(JSDContext* jsdc,
253 JSDThreadState* jsdthreadstate,
254 JSDStackFrameInfo* jsdframe)
256 JSDScript* jsdscript = NULL;
258 JSD_LOCK_THREADSTATES(jsdc);
260 if( jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe) )
261 jsdscript = jsdframe->jsdscript;
263 JSD_UNLOCK_THREADSTATES(jsdc);
265 return jsdscript;
268 jsuword
269 jsd_GetPCForStackFrame(JSDContext* jsdc,
270 JSDThreadState* jsdthreadstate,
271 JSDStackFrameInfo* jsdframe)
273 jsuword pc = 0;
275 JSD_LOCK_THREADSTATES(jsdc);
277 if( jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe) )
278 pc = jsdframe->pc;
280 JSD_UNLOCK_THREADSTATES(jsdc);
282 return pc;
285 JSDValue*
286 jsd_GetCallObjectForStackFrame(JSDContext* jsdc,
287 JSDThreadState* jsdthreadstate,
288 JSDStackFrameInfo* jsdframe)
290 JSObject* obj;
291 JSDValue* jsdval = NULL;
293 JSD_LOCK_THREADSTATES(jsdc);
295 if( jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe) )
297 obj = JS_GetFrameCallObject(jsdthreadstate->context, jsdframe->fp);
298 if(obj)
299 jsdval = JSD_NewValue(jsdc, OBJECT_TO_JSVAL(obj));
302 JSD_UNLOCK_THREADSTATES(jsdc);
304 return jsdval;
307 JSDValue*
308 jsd_GetScopeChainForStackFrame(JSDContext* jsdc,
309 JSDThreadState* jsdthreadstate,
310 JSDStackFrameInfo* jsdframe)
312 JSObject* obj;
313 JSDValue* jsdval = NULL;
315 JSD_LOCK_THREADSTATES(jsdc);
317 if( jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe) )
319 JS_BeginRequest(jsdthreadstate->context);
320 obj = JS_GetFrameScopeChain(jsdthreadstate->context, jsdframe->fp);
321 JS_EndRequest(jsdthreadstate->context);
322 if(obj)
323 jsdval = JSD_NewValue(jsdc, OBJECT_TO_JSVAL(obj));
326 JSD_UNLOCK_THREADSTATES(jsdc);
328 return jsdval;
331 JSDValue*
332 jsd_GetThisForStackFrame(JSDContext* jsdc,
333 JSDThreadState* jsdthreadstate,
334 JSDStackFrameInfo* jsdframe)
336 JSObject* obj;
337 JSDValue* jsdval = NULL;
338 JSD_LOCK_THREADSTATES(jsdc);
340 if( jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe) )
342 obj = JS_GetFrameThis(jsdthreadstate->context, jsdframe->fp);
343 if(obj)
344 jsdval = JSD_NewValue(jsdc, OBJECT_TO_JSVAL(obj));
347 JSD_UNLOCK_THREADSTATES(jsdc);
348 return jsdval;
351 const char*
352 jsd_GetNameForStackFrame(JSDContext* jsdc,
353 JSDThreadState* jsdthreadstate,
354 JSDStackFrameInfo* jsdframe)
356 const char *rv = NULL;
358 JSD_LOCK_THREADSTATES(jsdc);
360 if( jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe) )
362 JSFunction *fun = JS_GetFrameFunction (jsdthreadstate->context,
363 jsdframe->fp);
364 if (fun)
365 rv = JS_GetFunctionName (fun);
368 JSD_UNLOCK_THREADSTATES(jsdc);
369 return rv;
372 JSBool
373 jsd_IsStackFrameNative(JSDContext* jsdc,
374 JSDThreadState* jsdthreadstate,
375 JSDStackFrameInfo* jsdframe)
377 JSBool rv;
379 JSD_LOCK_THREADSTATES(jsdc);
381 if( jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe) )
383 rv = JS_IsNativeFrame(jsdthreadstate->context, jsdframe->fp);
385 else
387 rv = JS_FALSE;
390 JSD_UNLOCK_THREADSTATES(jsdc);
391 return rv;
394 JSBool
395 jsd_IsStackFrameDebugger(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_IsDebuggerFrame(jsdthreadstate->context, jsdframe->fp);
407 JSD_UNLOCK_THREADSTATES(jsdc);
408 return rv;
411 JSBool
412 jsd_IsStackFrameConstructing(JSDContext* jsdc,
413 JSDThreadState* jsdthreadstate,
414 JSDStackFrameInfo* jsdframe)
416 JSBool rv = JS_TRUE;
417 JSD_LOCK_THREADSTATES(jsdc);
419 if( jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe) )
421 rv = JS_IsConstructorFrame(jsdthreadstate->context, jsdframe->fp);
424 JSD_UNLOCK_THREADSTATES(jsdc);
425 return rv;
428 JSBool
429 jsd_EvaluateUCScriptInStackFrame(JSDContext* jsdc,
430 JSDThreadState* jsdthreadstate,
431 JSDStackFrameInfo* jsdframe,
432 const jschar *bytes, uintN length,
433 const char *filename, uintN lineno,
434 JSBool eatExceptions, jsval *rval)
436 JSBool retval;
437 JSBool valid;
438 JSExceptionState* exceptionState = NULL;
439 JSContext* cx;
441 JS_ASSERT(JSD_CURRENT_THREAD() == jsdthreadstate->thread);
443 JSD_LOCK_THREADSTATES(jsdc);
444 valid = jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe);
445 JSD_UNLOCK_THREADSTATES(jsdc);
447 if( ! valid )
448 return JS_FALSE;
450 cx = jsdthreadstate->context;
451 JS_ASSERT(cx);
453 if (eatExceptions)
454 exceptionState = JS_SaveExceptionState(cx);
455 JS_ClearPendingException(cx);
456 jsd_StartingEvalUsingFilename(jsdc, filename);
457 retval = JS_EvaluateUCInStackFrame(cx, jsdframe->fp, bytes, length,
458 filename, lineno, rval);
459 jsd_FinishedEvalUsingFilename(jsdc, filename);
460 if (eatExceptions)
461 JS_RestoreExceptionState(cx, exceptionState);
463 return retval;
466 JSBool
467 jsd_EvaluateScriptInStackFrame(JSDContext* jsdc,
468 JSDThreadState* jsdthreadstate,
469 JSDStackFrameInfo* jsdframe,
470 const char *bytes, uintN length,
471 const char *filename, uintN lineno,
472 JSBool eatExceptions, jsval *rval)
474 JSBool retval;
475 JSBool valid;
476 JSExceptionState* exceptionState = NULL;
477 JSContext *cx;
479 JS_ASSERT(JSD_CURRENT_THREAD() == jsdthreadstate->thread);
481 JSD_LOCK_THREADSTATES(jsdc);
482 valid = jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe);
483 JSD_UNLOCK_THREADSTATES(jsdc);
485 if (!valid)
486 return JS_FALSE;
488 cx = jsdthreadstate->context;
489 JS_ASSERT(cx);
491 if (eatExceptions)
492 exceptionState = JS_SaveExceptionState(cx);
493 JS_ClearPendingException(cx);
494 jsd_StartingEvalUsingFilename(jsdc, filename);
495 retval = JS_EvaluateInStackFrame(cx, jsdframe->fp, bytes, length,
496 filename, lineno, rval);
497 jsd_FinishedEvalUsingFilename(jsdc, filename);
498 if (eatExceptions)
499 JS_RestoreExceptionState(cx, exceptionState);
501 return retval;
504 JSString*
505 jsd_ValToStringInStackFrame(JSDContext* jsdc,
506 JSDThreadState* jsdthreadstate,
507 JSDStackFrameInfo* jsdframe,
508 jsval val)
510 JSBool valid;
511 JSString* retval;
512 JSExceptionState* exceptionState;
513 JSContext* cx;
515 JSD_LOCK_THREADSTATES(jsdc);
516 valid = jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe);
517 JSD_UNLOCK_THREADSTATES(jsdc);
519 if( ! valid )
520 return NULL;
522 cx = jsdthreadstate->context;
523 JS_ASSERT(cx);
525 exceptionState = JS_SaveExceptionState(cx);
526 retval = JS_ValueToString(cx, val);
527 JS_RestoreExceptionState(cx, exceptionState);
529 return retval;
532 JSBool
533 jsd_IsValidThreadState(JSDContext* jsdc,
534 JSDThreadState* jsdthreadstate)
536 JSDThreadState *cur;
538 JS_ASSERT( JSD_THREADSTATES_LOCKED(jsdc) );
540 for( cur = (JSDThreadState*)jsdc->threadsStates.next;
541 cur != (JSDThreadState*)&jsdc->threadsStates;
542 cur = (JSDThreadState*)cur->links.next )
544 if( cur == jsdthreadstate )
545 return JS_TRUE;
547 return JS_FALSE;
550 JSBool
551 jsd_IsValidFrameInThreadState(JSDContext* jsdc,
552 JSDThreadState* jsdthreadstate,
553 JSDStackFrameInfo* jsdframe)
555 JS_ASSERT(JSD_THREADSTATES_LOCKED(jsdc));
557 if( ! jsd_IsValidThreadState(jsdc, jsdthreadstate) )
558 return JS_FALSE;
559 if( jsdframe->jsdthreadstate != jsdthreadstate )
560 return JS_FALSE;
562 JSD_ASSERT_VALID_THREAD_STATE(jsdthreadstate);
563 JSD_ASSERT_VALID_STACK_FRAME(jsdframe);
565 return JS_TRUE;
568 static JSContext*
569 _getContextForThreadState(JSDContext* jsdc, JSDThreadState* jsdthreadstate)
571 JSBool valid;
572 JSD_LOCK_THREADSTATES(jsdc);
573 valid = jsd_IsValidThreadState(jsdc, jsdthreadstate);
574 JSD_UNLOCK_THREADSTATES(jsdc);
575 if( valid )
576 return jsdthreadstate->context;
577 return NULL;
580 JSDValue*
581 jsd_GetException(JSDContext* jsdc, JSDThreadState* jsdthreadstate)
583 JSContext* cx;
584 jsval val;
586 if(!(cx = _getContextForThreadState(jsdc, jsdthreadstate)))
587 return NULL;
589 if(JS_GetPendingException(cx, &val))
590 return jsd_NewValue(jsdc, val);
591 return NULL;
594 JSBool
595 jsd_SetException(JSDContext* jsdc, JSDThreadState* jsdthreadstate,
596 JSDValue* jsdval)
598 JSContext* cx;
600 if(!(cx = _getContextForThreadState(jsdc, jsdthreadstate)))
601 return JS_FALSE;
603 if(jsdval)
604 JS_SetPendingException(cx, JSD_GetValueWrappedJSVal(jsdc, jsdval));
605 else
606 JS_ClearPendingException(cx);
607 return JS_TRUE;