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 - Script support
44 /* Comment this out to disable (NT specific) dumping as we go */
51 #define NOT_SET_YET -1
53 /***************************************************************************/
56 void JSD_ASSERT_VALID_SCRIPT(JSDScript
* jsdscript
)
59 JS_ASSERT(jsdscript
->script
);
61 void JSD_ASSERT_VALID_EXEC_HOOK(JSDExecHook
* jsdhook
)
64 JS_ASSERT(jsdhook
->hook
);
70 HasFileExtention(const char* name
, const char* ext
)
73 int len
= strlen(ext
);
74 const char* p
= strrchr(name
,'.');
78 for(i
= 0; i
< len
; i
++ )
80 JS_ASSERT(islower(ext
[i
]));
81 if( 0 == p
[i
] || tolower(p
[i
]) != ext
[i
] )
91 _newJSDScript(JSDContext
* jsdc
,
98 const char* raw_filename
;
100 JS_ASSERT(JSD_SCRIPTS_LOCKED(jsdc
));
102 /* these are inlined javascript: urls and we can't handle them now */
103 lineno
= (uintN
) JS_GetScriptBaseLineNumber(cx
, script
);
107 jsdscript
= (JSDScript
*) calloc(1, sizeof(JSDScript
));
111 raw_filename
= JS_GetScriptFilename(cx
,script
);
113 JS_HashTableAdd(jsdc
->scriptsTable
, (void *)script
, (void *)jsdscript
);
114 JS_APPEND_LINK(&jsdscript
->links
, &jsdc
->scripts
);
115 jsdscript
->jsdc
= jsdc
;
116 jsdscript
->script
= script
;
117 jsdscript
->function
= function
;
118 jsdscript
->lineBase
= lineno
;
119 jsdscript
->lineExtent
= (uintN
)NOT_SET_YET
;
120 jsdscript
->data
= NULL
;
122 jsdscript
->url
= (char*) jsd_BuildNormalizedURL(raw_filename
);
124 jsdscript
->app
= LWDBG_GetCurrentApp();
125 if( jsdscript
->app
&& raw_filename
)
127 jsdscript
->url
= jsdlw_BuildAppRelativeFilename(jsdscript
->app
, raw_filename
);
130 jsdscript
->lwscript
=
131 LWDBG_GetScriptOfFunction(jsdscript
->app
,
132 JS_GetFunctionName(function
));
134 /* also, make sure this file is added to filelist if is .js file */
135 if( HasFileExtention(raw_filename
,"js") ||
136 HasFileExtention(raw_filename
,"sjs") )
138 jsdlw_PreLoadSource(jsdc
, jsdscript
->app
, raw_filename
, JS_FALSE
);
143 jsdscript
->lwscript
= LWDBG_GetCurrentTopLevelScript();
148 JS_INIT_CLIST(&jsdscript
->hooks
);
154 _destroyJSDScript(JSDContext
* jsdc
,
155 JSDScript
* jsdscript
)
157 JS_ASSERT(JSD_SCRIPTS_LOCKED(jsdc
));
159 /* destroy all hooks */
160 jsd_ClearAllExecutionHooksForScript(jsdc
, jsdscript
);
162 JS_REMOVE_LINK(&jsdscript
->links
);
164 free(jsdscript
->url
);
166 if (jsdscript
->profileData
)
167 free(jsdscript
->profileData
);
172 /***************************************************************************/
177 OutputDebugString (char *buf
)
179 fprintf (stderr
, "%s", buf
);
184 _dumpJSDScript(JSDContext
* jsdc
, JSDScript
* jsdscript
, const char* leadingtext
)
192 name
= jsd_GetScriptFilename(jsdc
, jsdscript
);
193 fun
= jsd_GetScriptFunctionName(jsdc
, jsdscript
);
194 base
= jsd_GetScriptBaseLineNumber(jsdc
, jsdscript
);
195 extent
= jsd_GetScriptLineExtent(jsdc
, jsdscript
);
197 sprintf( Buf
, "%sscript=%08X, %s, %s, %d-%d\n",
199 (unsigned) jsdscript
->script
,
200 name
? name
: "no URL",
201 fun
? fun
: "no fun",
202 base
, base
+ extent
- 1 );
203 OutputDebugString( Buf
);
207 _dumpJSDScriptList( JSDContext
* jsdc
)
209 JSDScript
* iterp
= NULL
;
210 JSDScript
* jsdscript
= NULL
;
212 OutputDebugString( "*** JSDScriptDump\n" );
213 while( NULL
!= (jsdscript
= jsd_IterateScripts(jsdc
, &iterp
)) )
214 _dumpJSDScript( jsdc
, jsdscript
, " script: " );
216 #endif /* JSD_DUMP */
218 /***************************************************************************/
220 jsd_hash_script(const void *key
)
222 return ((JSHashNumber
) key
) >> 2; /* help lame MSVC1.5 on Win16 */
226 jsd_alloc_script_table(void *priv
, size_t size
)
232 jsd_free_script_table(void *priv
, void *item
)
238 jsd_alloc_script_entry(void *priv
, const void *item
)
240 return (JSHashEntry
*) malloc(sizeof(JSHashEntry
));
244 jsd_free_script_entry(void *priv
, JSHashEntry
*he
, uintN flag
)
246 if (flag
== HT_FREE_ENTRY
)
248 _destroyJSDScript((JSDContext
*) priv
, (JSDScript
*) he
->value
);
253 static JSHashAllocOps script_alloc_ops
= {
254 jsd_alloc_script_table
, jsd_free_script_table
,
255 jsd_alloc_script_entry
, jsd_free_script_entry
258 #ifndef JSD_SCRIPT_HASH_SIZE
259 #define JSD_SCRIPT_HASH_SIZE 1024
263 jsd_InitScriptManager(JSDContext
* jsdc
)
265 JS_INIT_CLIST(&jsdc
->scripts
);
266 jsdc
->scriptsTable
= JS_NewHashTable(JSD_SCRIPT_HASH_SIZE
, jsd_hash_script
,
267 JS_CompareValues
, JS_CompareValues
,
268 &script_alloc_ops
, (void*) jsdc
);
269 return (JSBool
) jsdc
->scriptsTable
;
273 jsd_DestroyScriptManager(JSDContext
* jsdc
)
275 JSD_LOCK_SCRIPTS(jsdc
);
276 if (jsdc
->scriptsTable
)
277 JS_HashTableDestroy(jsdc
->scriptsTable
);
278 JSD_UNLOCK_SCRIPTS(jsdc
);
282 jsd_FindJSDScript( JSDContext
* jsdc
,
285 JS_ASSERT(JSD_SCRIPTS_LOCKED(jsdc
));
286 return (JSDScript
*) JS_HashTableLookup(jsdc
->scriptsTable
, (void *)script
);
290 jsd_GetScriptProfileData(JSDContext
* jsdc
, JSDScript
*script
)
292 if (!script
->profileData
)
293 script
->profileData
= (JSDProfileData
*)calloc(1, sizeof(JSDProfileData
));
295 return script
->profileData
;
299 jsd_GetScriptFlags(JSDContext
*jsdc
, JSDScript
*script
)
301 return script
->flags
;
305 jsd_SetScriptFlags(JSDContext
*jsdc
, JSDScript
*script
, uint32 flags
)
307 script
->flags
= flags
;
311 jsd_GetScriptCallCount(JSDContext
* jsdc
, JSDScript
*script
)
313 if (script
->profileData
)
314 return script
->profileData
->callCount
;
320 jsd_GetScriptMaxRecurseDepth(JSDContext
* jsdc
, JSDScript
*script
)
322 if (script
->profileData
)
323 return script
->profileData
->maxRecurseDepth
;
329 jsd_GetScriptMinExecutionTime(JSDContext
* jsdc
, JSDScript
*script
)
331 if (script
->profileData
)
332 return script
->profileData
->minExecutionTime
;
338 jsd_GetScriptMaxExecutionTime(JSDContext
* jsdc
, JSDScript
*script
)
340 if (script
->profileData
)
341 return script
->profileData
->maxExecutionTime
;
347 jsd_GetScriptTotalExecutionTime(JSDContext
* jsdc
, JSDScript
*script
)
349 if (script
->profileData
)
350 return script
->profileData
->totalExecutionTime
;
356 jsd_GetScriptMinOwnExecutionTime(JSDContext
* jsdc
, JSDScript
*script
)
358 if (script
->profileData
)
359 return script
->profileData
->minOwnExecutionTime
;
365 jsd_GetScriptMaxOwnExecutionTime(JSDContext
* jsdc
, JSDScript
*script
)
367 if (script
->profileData
)
368 return script
->profileData
->maxOwnExecutionTime
;
374 jsd_GetScriptTotalOwnExecutionTime(JSDContext
* jsdc
, JSDScript
*script
)
376 if (script
->profileData
)
377 return script
->profileData
->totalOwnExecutionTime
;
383 jsd_ClearScriptProfileData(JSDContext
* jsdc
, JSDScript
*script
)
385 if (script
->profileData
)
387 free(script
->profileData
);
388 script
->profileData
= NULL
;
393 jsd_GetJSScript (JSDContext
*jsdc
, JSDScript
*script
)
395 return script
->script
;
399 jsd_GetJSFunction (JSDContext
*jsdc
, JSDScript
*script
)
401 return script
->function
;
405 jsd_IterateScripts(JSDContext
* jsdc
, JSDScript
**iterp
)
407 JSDScript
*jsdscript
= *iterp
;
409 JS_ASSERT(JSD_SCRIPTS_LOCKED(jsdc
));
412 jsdscript
= (JSDScript
*)jsdc
->scripts
.next
;
413 if( jsdscript
== (JSDScript
*)&jsdc
->scripts
)
415 *iterp
= (JSDScript
*) jsdscript
->links
.next
;
420 jsd_SetScriptPrivate(JSDScript
*jsdscript
, void *data
)
422 void *rval
= jsdscript
->data
;
423 jsdscript
->data
= data
;
428 jsd_GetScriptPrivate(JSDScript
*jsdscript
)
430 return jsdscript
->data
;
434 jsd_IsActiveScript(JSDContext
* jsdc
, JSDScript
*jsdscript
)
438 JS_ASSERT(JSD_SCRIPTS_LOCKED(jsdc
));
440 for( current
= (JSDScript
*)jsdc
->scripts
.next
;
441 current
!= (JSDScript
*)&jsdc
->scripts
;
442 current
= (JSDScript
*)current
->links
.next
)
444 if(jsdscript
== current
)
451 jsd_GetScriptFilename(JSDContext
* jsdc
, JSDScript
*jsdscript
)
453 return jsdscript
->url
;
457 jsd_GetScriptFunctionName(JSDContext
* jsdc
, JSDScript
*jsdscript
)
459 if( ! jsdscript
->function
)
461 return JS_GetFunctionName(jsdscript
->function
);
465 jsd_GetScriptBaseLineNumber(JSDContext
* jsdc
, JSDScript
*jsdscript
)
467 return jsdscript
->lineBase
;
471 jsd_GetScriptLineExtent(JSDContext
* jsdc
, JSDScript
*jsdscript
)
473 if( NOT_SET_YET
== (int)jsdscript
->lineExtent
)
474 jsdscript
->lineExtent
= JS_GetScriptLineExtent(jsdc
->dumbContext
, jsdscript
->script
);
475 return jsdscript
->lineExtent
;
479 jsd_GetClosestPC(JSDContext
* jsdc
, JSDScript
* jsdscript
, uintN line
)
482 if( jsdscript
&& jsdscript
->lwscript
)
485 jsdlw_RawToProcessedLineNumber(jsdc
, jsdscript
, line
, &newline
);
486 if( line
!= newline
)
491 return (jsuword
) JS_LineNumberToPC(jsdc
->dumbContext
,
492 jsdscript
->script
, line
);
496 jsd_GetClosestLine(JSDContext
* jsdc
, JSDScript
* jsdscript
, jsuword pc
)
498 uintN first
= jsdscript
->lineBase
;
499 uintN last
= first
+ jsd_GetScriptLineExtent(jsdc
, jsdscript
) - 1;
501 ? JS_PCToLineNumber(jsdc
->dumbContext
,
512 if( jsdscript
&& jsdscript
->lwscript
)
515 jsdlw_ProcessedToRawLineNumber(jsdc
, jsdscript
, line
, &newline
);
524 jsd_SetScriptHook(JSDContext
* jsdc
, JSD_ScriptHookProc hook
, void* callerdata
)
527 jsdc
->scriptHook
= hook
;
528 jsdc
->scriptHookData
= callerdata
;
534 jsd_GetScriptHook(JSDContext
* jsdc
, JSD_ScriptHookProc
* hook
, void** callerdata
)
538 *hook
= jsdc
->scriptHook
;
540 *callerdata
= jsdc
->scriptHookData
;
545 /***************************************************************************/
548 jsd_NewScriptHookProc(
550 const char *filename
, /* URL this script loads from */
551 uintN lineno
, /* line where this script starts */
556 JSDScript
* jsdscript
= NULL
;
557 JSDContext
* jsdc
= (JSDContext
*) callerdata
;
558 JSD_ScriptHookProc hook
;
561 JSD_ASSERT_VALID_CONTEXT(jsdc
);
563 if( JSD_IS_DANGEROUS_THREAD(jsdc
) )
568 jsdlw_PreLoadSource(jsdc
, LWDBG_GetCurrentApp(), filename
, JS_TRUE
);
571 JSD_LOCK_SCRIPTS(jsdc
);
572 jsdscript
= _newJSDScript(jsdc
, cx
, script
, fun
);
573 JSD_UNLOCK_SCRIPTS(jsdc
);
578 JSD_LOCK_SCRIPTS(jsdc
);
579 _dumpJSDScript(jsdc
, jsdscript
, "***NEW Script: ");
580 _dumpJSDScriptList( jsdc
);
581 JSD_UNLOCK_SCRIPTS(jsdc
);
582 #endif /* JSD_DUMP */
584 /* local in case jsdc->scriptHook gets cleared on another thread */
586 hook
= jsdc
->scriptHook
;
587 hookData
= jsdc
->scriptHookData
;
591 hook(jsdc
, jsdscript
, JS_TRUE
, hookData
);
595 jsd_DestroyScriptHookProc(
600 JSDScript
* jsdscript
= NULL
;
601 JSDContext
* jsdc
= (JSDContext
*) callerdata
;
602 JSD_ScriptHookProc hook
;
605 JSD_ASSERT_VALID_CONTEXT(jsdc
);
607 if( JSD_IS_DANGEROUS_THREAD(jsdc
) )
610 JSD_LOCK_SCRIPTS(jsdc
);
611 jsdscript
= jsd_FindJSDScript(jsdc
, script
);
612 JSD_UNLOCK_SCRIPTS(jsdc
);
618 JSD_LOCK_SCRIPTS(jsdc
);
619 _dumpJSDScript(jsdc
, jsdscript
, "***DESTROY Script: ");
620 JSD_UNLOCK_SCRIPTS(jsdc
);
621 #endif /* JSD_DUMP */
623 /* local in case hook gets cleared on another thread */
625 hook
= jsdc
->scriptHook
;
626 hookData
= jsdc
->scriptHookData
;
630 hook(jsdc
, jsdscript
, JS_FALSE
, hookData
);
632 JSD_LOCK_SCRIPTS(jsdc
);
633 JS_HashTableRemove(jsdc
->scriptsTable
, (void *)script
);
634 JSD_UNLOCK_SCRIPTS(jsdc
);
637 JSD_LOCK_SCRIPTS(jsdc
);
638 _dumpJSDScriptList(jsdc
);
639 JSD_UNLOCK_SCRIPTS(jsdc
);
640 #endif /* JSD_DUMP */
644 /***************************************************************************/
647 _findHook(JSDContext
* jsdc
, JSDScript
* jsdscript
, jsuword pc
)
649 JSDExecHook
* jsdhook
;
650 JSCList
* list
= &jsdscript
->hooks
;
652 for( jsdhook
= (JSDExecHook
*)list
->next
;
653 jsdhook
!= (JSDExecHook
*)list
;
654 jsdhook
= (JSDExecHook
*)jsdhook
->links
.next
)
656 if (jsdhook
->pc
== pc
)
663 _isActiveHook(JSDContext
* jsdc
, JSScript
*script
, JSDExecHook
* jsdhook
)
665 JSDExecHook
* current
;
667 JSDScript
* jsdscript
;
669 JSD_LOCK_SCRIPTS(jsdc
);
670 jsdscript
= jsd_FindJSDScript(jsdc
, script
);
673 JSD_UNLOCK_SCRIPTS(jsdc
);
677 list
= &jsdscript
->hooks
;
679 for( current
= (JSDExecHook
*)list
->next
;
680 current
!= (JSDExecHook
*)list
;
681 current
= (JSDExecHook
*)current
->links
.next
)
683 if(current
== jsdhook
)
685 JSD_UNLOCK_SCRIPTS(jsdc
);
689 JSD_UNLOCK_SCRIPTS(jsdc
);
695 jsd_TrapHandler(JSContext
*cx
, JSScript
*script
, jsbytecode
*pc
, jsval
*rval
,
698 JSDExecHook
* jsdhook
= (JSDExecHook
*) JSVAL_TO_PRIVATE(((jsval
)closure
));
699 JSD_ExecutionHookProc hook
;
702 JSDScript
* jsdscript
;
706 if( NULL
== (jsdc
= jsd_JSDContextForJSContext(cx
)) ||
707 ! _isActiveHook(jsdc
, script
, jsdhook
) )
710 return JSTRAP_CONTINUE
;
713 JSD_ASSERT_VALID_EXEC_HOOK(jsdhook
);
714 JS_ASSERT(jsdhook
->pc
== (jsuword
)pc
);
715 JS_ASSERT(jsdhook
->jsdscript
->script
== script
);
716 JS_ASSERT(jsdhook
->jsdscript
->jsdc
== jsdc
);
718 hook
= jsdhook
->hook
;
719 hookData
= jsdhook
->callerdata
;
720 jsdscript
= jsdhook
->jsdscript
;
722 /* do not use jsdhook-> after this point */
725 if( ! jsdc
|| ! jsdc
->inited
)
726 return JSTRAP_CONTINUE
;
728 if( JSD_IS_DANGEROUS_THREAD(jsdc
) )
729 return JSTRAP_CONTINUE
;
732 if( ! jsdlw_UserCodeAtPC(jsdc
, jsdscript
, (jsuword
)pc
) )
733 return JSTRAP_CONTINUE
;
736 return jsd_CallExecutionHook(jsdc
, cx
, JSD_HOOK_BREAKPOINT
,
737 hook
, hookData
, rval
);
743 jsd_SetExecutionHook(JSDContext
* jsdc
,
744 JSDScript
* jsdscript
,
746 JSD_ExecutionHookProc hook
,
749 JSDExecHook
* jsdhook
;
754 jsd_ClearExecutionHook(jsdc
, jsdscript
, pc
);
759 jsdhook
= _findHook(jsdc
, jsdscript
, pc
);
762 jsdhook
->hook
= hook
;
763 jsdhook
->callerdata
= callerdata
;
769 jsdhook
= (JSDExecHook
*)calloc(1, sizeof(JSDExecHook
));
774 jsdhook
->jsdscript
= jsdscript
;
776 jsdhook
->hook
= hook
;
777 jsdhook
->callerdata
= callerdata
;
779 if( ! JS_SetTrap(jsdc
->dumbContext
, jsdscript
->script
,
780 (jsbytecode
*)pc
, jsd_TrapHandler
,
781 (void*) PRIVATE_TO_JSVAL(jsdhook
)) )
788 JS_APPEND_LINK(&jsdhook
->links
, &jsdscript
->hooks
);
795 jsd_ClearExecutionHook(JSDContext
* jsdc
,
796 JSDScript
* jsdscript
,
799 JSDExecHook
* jsdhook
;
803 jsdhook
= _findHook(jsdc
, jsdscript
, pc
);
811 JS_ClearTrap(jsdc
->dumbContext
, jsdscript
->script
,
812 (jsbytecode
*)pc
, NULL
, NULL
);
814 JS_REMOVE_LINK(&jsdhook
->links
);
822 jsd_ClearAllExecutionHooksForScript(JSDContext
* jsdc
, JSDScript
* jsdscript
)
824 JSDExecHook
* jsdhook
;
825 JSCList
* list
= &jsdscript
->hooks
;
829 while( (JSDExecHook
*)list
!= (jsdhook
= (JSDExecHook
*)list
->next
) )
831 JS_REMOVE_LINK(&jsdhook
->links
);
835 JS_ClearScriptTraps(jsdc
->dumbContext
, jsdscript
->script
);
842 jsd_ClearAllExecutionHooks(JSDContext
* jsdc
)
844 JSDScript
* jsdscript
;
845 JSDScript
* iterp
= NULL
;
848 while( NULL
!= (jsdscript
= jsd_IterateScripts(jsdc
, &iterp
)) )
849 jsd_ClearAllExecutionHooksForScript(jsdc
, jsdscript
);
855 jsd_ScriptCreated(JSDContext
* jsdc
,
857 const char *filename
, /* URL this script loads from */
858 uintN lineno
, /* line where this script starts */
862 jsd_NewScriptHookProc(cx
, filename
, lineno
, script
, fun
, jsdc
);
866 jsd_ScriptDestroyed(JSDContext
* jsdc
,
870 jsd_DestroyScriptHookProc(cx
, script
, jsdc
);