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
, size_t size
)
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_FindOrCreateJSDScript(JSDContext
*jsdc
,
295 JSDScript
*jsdscript
;
296 JS_ASSERT(JSD_SCRIPTS_LOCKED(jsdc
));
298 jsdscript
= jsd_FindJSDScript(jsdc
, script
);
302 /* Fallback for unknown scripts: create a new script. */
304 JS_FrameIterator(cx
, &fp
);
306 jsdscript
= _newJSDScript(jsdc
, cx
, script
, JS_GetFrameFunction(cx
, fp
));
312 jsd_GetScriptProfileData(JSDContext
* jsdc
, JSDScript
*script
)
314 if (!script
->profileData
)
315 script
->profileData
= (JSDProfileData
*)calloc(1, sizeof(JSDProfileData
));
317 return script
->profileData
;
321 jsd_GetScriptFlags(JSDContext
*jsdc
, JSDScript
*script
)
323 return script
->flags
;
327 jsd_SetScriptFlags(JSDContext
*jsdc
, JSDScript
*script
, uint32 flags
)
329 script
->flags
= flags
;
333 jsd_GetScriptCallCount(JSDContext
* jsdc
, JSDScript
*script
)
335 if (script
->profileData
)
336 return script
->profileData
->callCount
;
342 jsd_GetScriptMaxRecurseDepth(JSDContext
* jsdc
, JSDScript
*script
)
344 if (script
->profileData
)
345 return script
->profileData
->maxRecurseDepth
;
351 jsd_GetScriptMinExecutionTime(JSDContext
* jsdc
, JSDScript
*script
)
353 if (script
->profileData
)
354 return script
->profileData
->minExecutionTime
;
360 jsd_GetScriptMaxExecutionTime(JSDContext
* jsdc
, JSDScript
*script
)
362 if (script
->profileData
)
363 return script
->profileData
->maxExecutionTime
;
369 jsd_GetScriptTotalExecutionTime(JSDContext
* jsdc
, JSDScript
*script
)
371 if (script
->profileData
)
372 return script
->profileData
->totalExecutionTime
;
378 jsd_GetScriptMinOwnExecutionTime(JSDContext
* jsdc
, JSDScript
*script
)
380 if (script
->profileData
)
381 return script
->profileData
->minOwnExecutionTime
;
387 jsd_GetScriptMaxOwnExecutionTime(JSDContext
* jsdc
, JSDScript
*script
)
389 if (script
->profileData
)
390 return script
->profileData
->maxOwnExecutionTime
;
396 jsd_GetScriptTotalOwnExecutionTime(JSDContext
* jsdc
, JSDScript
*script
)
398 if (script
->profileData
)
399 return script
->profileData
->totalOwnExecutionTime
;
405 jsd_ClearScriptProfileData(JSDContext
* jsdc
, JSDScript
*script
)
407 if (script
->profileData
)
409 free(script
->profileData
);
410 script
->profileData
= NULL
;
415 jsd_GetJSScript (JSDContext
*jsdc
, JSDScript
*script
)
417 return script
->script
;
421 jsd_GetJSFunction (JSDContext
*jsdc
, JSDScript
*script
)
423 return script
->function
;
427 jsd_IterateScripts(JSDContext
* jsdc
, JSDScript
**iterp
)
429 JSDScript
*jsdscript
= *iterp
;
431 JS_ASSERT(JSD_SCRIPTS_LOCKED(jsdc
));
434 jsdscript
= (JSDScript
*)jsdc
->scripts
.next
;
435 if( jsdscript
== (JSDScript
*)&jsdc
->scripts
)
437 *iterp
= (JSDScript
*) jsdscript
->links
.next
;
442 jsd_SetScriptPrivate(JSDScript
*jsdscript
, void *data
)
444 void *rval
= jsdscript
->data
;
445 jsdscript
->data
= data
;
450 jsd_GetScriptPrivate(JSDScript
*jsdscript
)
452 return jsdscript
->data
;
456 jsd_IsActiveScript(JSDContext
* jsdc
, JSDScript
*jsdscript
)
460 JS_ASSERT(JSD_SCRIPTS_LOCKED(jsdc
));
462 for( current
= (JSDScript
*)jsdc
->scripts
.next
;
463 current
!= (JSDScript
*)&jsdc
->scripts
;
464 current
= (JSDScript
*)current
->links
.next
)
466 if(jsdscript
== current
)
473 jsd_GetScriptFilename(JSDContext
* jsdc
, JSDScript
*jsdscript
)
475 return jsdscript
->url
;
479 jsd_GetScriptFunctionName(JSDContext
* jsdc
, JSDScript
*jsdscript
)
481 if( ! jsdscript
->function
)
483 return JS_GetFunctionName(jsdscript
->function
);
487 jsd_GetScriptBaseLineNumber(JSDContext
* jsdc
, JSDScript
*jsdscript
)
489 return jsdscript
->lineBase
;
493 jsd_GetScriptLineExtent(JSDContext
* jsdc
, JSDScript
*jsdscript
)
495 if( NOT_SET_YET
== (int)jsdscript
->lineExtent
)
496 jsdscript
->lineExtent
= JS_GetScriptLineExtent(jsdc
->dumbContext
, jsdscript
->script
);
497 return jsdscript
->lineExtent
;
501 jsd_GetClosestPC(JSDContext
* jsdc
, JSDScript
* jsdscript
, uintN line
)
504 if( jsdscript
&& jsdscript
->lwscript
)
507 jsdlw_RawToProcessedLineNumber(jsdc
, jsdscript
, line
, &newline
);
508 if( line
!= newline
)
513 return (jsuword
) JS_LineNumberToPC(jsdc
->dumbContext
,
514 jsdscript
->script
, line
);
518 jsd_GetClosestLine(JSDContext
* jsdc
, JSDScript
* jsdscript
, jsuword pc
)
520 uintN first
= jsdscript
->lineBase
;
521 uintN last
= first
+ jsd_GetScriptLineExtent(jsdc
, jsdscript
) - 1;
523 ? JS_PCToLineNumber(jsdc
->dumbContext
,
534 if( jsdscript
&& jsdscript
->lwscript
)
537 jsdlw_ProcessedToRawLineNumber(jsdc
, jsdscript
, line
, &newline
);
546 jsd_SetScriptHook(JSDContext
* jsdc
, JSD_ScriptHookProc hook
, void* callerdata
)
549 jsdc
->scriptHook
= hook
;
550 jsdc
->scriptHookData
= callerdata
;
556 jsd_GetScriptHook(JSDContext
* jsdc
, JSD_ScriptHookProc
* hook
, void** callerdata
)
560 *hook
= jsdc
->scriptHook
;
562 *callerdata
= jsdc
->scriptHookData
;
567 /***************************************************************************/
570 jsd_NewScriptHookProc(
572 const char *filename
, /* URL this script loads from */
573 uintN lineno
, /* line where this script starts */
578 JSDScript
* jsdscript
= NULL
;
579 JSDContext
* jsdc
= (JSDContext
*) callerdata
;
580 JSD_ScriptHookProc hook
;
583 JSD_ASSERT_VALID_CONTEXT(jsdc
);
585 if( JSD_IS_DANGEROUS_THREAD(jsdc
) )
590 jsdlw_PreLoadSource(jsdc
, LWDBG_GetCurrentApp(), filename
, JS_TRUE
);
593 JSD_LOCK_SCRIPTS(jsdc
);
594 jsdscript
= _newJSDScript(jsdc
, cx
, script
, fun
);
595 JSD_UNLOCK_SCRIPTS(jsdc
);
600 JSD_LOCK_SCRIPTS(jsdc
);
601 _dumpJSDScript(jsdc
, jsdscript
, "***NEW Script: ");
602 _dumpJSDScriptList( jsdc
);
603 JSD_UNLOCK_SCRIPTS(jsdc
);
604 #endif /* JSD_DUMP */
606 /* local in case jsdc->scriptHook gets cleared on another thread */
608 hook
= jsdc
->scriptHook
;
609 hookData
= jsdc
->scriptHookData
;
613 hook(jsdc
, jsdscript
, JS_TRUE
, hookData
);
617 jsd_DestroyScriptHookProc(
622 JSDScript
* jsdscript
= NULL
;
623 JSDContext
* jsdc
= (JSDContext
*) callerdata
;
624 JSD_ScriptHookProc hook
;
627 JSD_ASSERT_VALID_CONTEXT(jsdc
);
629 if( JSD_IS_DANGEROUS_THREAD(jsdc
) )
632 JSD_LOCK_SCRIPTS(jsdc
);
633 jsdscript
= jsd_FindJSDScript(jsdc
, script
);
634 JSD_UNLOCK_SCRIPTS(jsdc
);
640 JSD_LOCK_SCRIPTS(jsdc
);
641 _dumpJSDScript(jsdc
, jsdscript
, "***DESTROY Script: ");
642 JSD_UNLOCK_SCRIPTS(jsdc
);
643 #endif /* JSD_DUMP */
645 /* local in case hook gets cleared on another thread */
647 hook
= jsdc
->scriptHook
;
648 hookData
= jsdc
->scriptHookData
;
652 hook(jsdc
, jsdscript
, JS_FALSE
, hookData
);
654 JSD_LOCK_SCRIPTS(jsdc
);
655 JS_HashTableRemove(jsdc
->scriptsTable
, (void *)script
);
656 JSD_UNLOCK_SCRIPTS(jsdc
);
659 JSD_LOCK_SCRIPTS(jsdc
);
660 _dumpJSDScriptList(jsdc
);
661 JSD_UNLOCK_SCRIPTS(jsdc
);
662 #endif /* JSD_DUMP */
666 /***************************************************************************/
669 _findHook(JSDContext
* jsdc
, JSDScript
* jsdscript
, jsuword pc
)
671 JSDExecHook
* jsdhook
;
672 JSCList
* list
= &jsdscript
->hooks
;
674 for( jsdhook
= (JSDExecHook
*)list
->next
;
675 jsdhook
!= (JSDExecHook
*)list
;
676 jsdhook
= (JSDExecHook
*)jsdhook
->links
.next
)
678 if (jsdhook
->pc
== pc
)
685 _isActiveHook(JSDContext
* jsdc
, JSScript
*script
, JSDExecHook
* jsdhook
)
687 JSDExecHook
* current
;
689 JSDScript
* jsdscript
;
691 JSD_LOCK_SCRIPTS(jsdc
);
692 jsdscript
= jsd_FindJSDScript(jsdc
, script
);
695 JSD_UNLOCK_SCRIPTS(jsdc
);
699 list
= &jsdscript
->hooks
;
701 for( current
= (JSDExecHook
*)list
->next
;
702 current
!= (JSDExecHook
*)list
;
703 current
= (JSDExecHook
*)current
->links
.next
)
705 if(current
== jsdhook
)
707 JSD_UNLOCK_SCRIPTS(jsdc
);
711 JSD_UNLOCK_SCRIPTS(jsdc
);
717 jsd_TrapHandler(JSContext
*cx
, JSScript
*script
, jsbytecode
*pc
, jsval
*rval
,
720 JSDExecHook
* jsdhook
= (JSDExecHook
*) JSVAL_TO_PRIVATE(closure
);
721 JSD_ExecutionHookProc hook
;
724 JSDScript
* jsdscript
;
728 if( NULL
== (jsdc
= jsd_JSDContextForJSContext(cx
)) ||
729 ! _isActiveHook(jsdc
, script
, jsdhook
) )
732 return JSTRAP_CONTINUE
;
735 JSD_ASSERT_VALID_EXEC_HOOK(jsdhook
);
736 JS_ASSERT(jsdhook
->pc
== (jsuword
)pc
);
737 JS_ASSERT(jsdhook
->jsdscript
->script
== script
);
738 JS_ASSERT(jsdhook
->jsdscript
->jsdc
== jsdc
);
740 hook
= jsdhook
->hook
;
741 hookData
= jsdhook
->callerdata
;
742 jsdscript
= jsdhook
->jsdscript
;
744 /* do not use jsdhook-> after this point */
747 if( ! jsdc
|| ! jsdc
->inited
)
748 return JSTRAP_CONTINUE
;
750 if( JSD_IS_DANGEROUS_THREAD(jsdc
) )
751 return JSTRAP_CONTINUE
;
754 if( ! jsdlw_UserCodeAtPC(jsdc
, jsdscript
, (jsuword
)pc
) )
755 return JSTRAP_CONTINUE
;
758 return jsd_CallExecutionHook(jsdc
, cx
, JSD_HOOK_BREAKPOINT
,
759 hook
, hookData
, rval
);
765 jsd_SetExecutionHook(JSDContext
* jsdc
,
766 JSDScript
* jsdscript
,
768 JSD_ExecutionHookProc hook
,
771 JSDExecHook
* jsdhook
;
776 jsd_ClearExecutionHook(jsdc
, jsdscript
, pc
);
781 jsdhook
= _findHook(jsdc
, jsdscript
, pc
);
784 jsdhook
->hook
= hook
;
785 jsdhook
->callerdata
= callerdata
;
791 jsdhook
= (JSDExecHook
*)calloc(1, sizeof(JSDExecHook
));
796 jsdhook
->jsdscript
= jsdscript
;
798 jsdhook
->hook
= hook
;
799 jsdhook
->callerdata
= callerdata
;
801 if( ! JS_SetTrap(jsdc
->dumbContext
, jsdscript
->script
,
802 (jsbytecode
*)pc
, jsd_TrapHandler
,
803 PRIVATE_TO_JSVAL(jsdhook
)) )
810 JS_APPEND_LINK(&jsdhook
->links
, &jsdscript
->hooks
);
817 jsd_ClearExecutionHook(JSDContext
* jsdc
,
818 JSDScript
* jsdscript
,
821 JSDExecHook
* jsdhook
;
825 jsdhook
= _findHook(jsdc
, jsdscript
, pc
);
832 JS_ClearTrap(jsdc
->dumbContext
, jsdscript
->script
,
833 (jsbytecode
*)pc
, NULL
, NULL
);
835 JS_REMOVE_LINK(&jsdhook
->links
);
843 jsd_ClearAllExecutionHooksForScript(JSDContext
* jsdc
, JSDScript
* jsdscript
)
845 JSDExecHook
* jsdhook
;
846 JSCList
* list
= &jsdscript
->hooks
;
850 while( (JSDExecHook
*)list
!= (jsdhook
= (JSDExecHook
*)list
->next
) )
852 JS_REMOVE_LINK(&jsdhook
->links
);
856 JS_ClearScriptTraps(jsdc
->dumbContext
, jsdscript
->script
);
863 jsd_ClearAllExecutionHooks(JSDContext
* jsdc
)
865 JSDScript
* jsdscript
;
866 JSDScript
* iterp
= NULL
;
869 while( NULL
!= (jsdscript
= jsd_IterateScripts(jsdc
, &iterp
)) )
870 jsd_ClearAllExecutionHooksForScript(jsdc
, jsdscript
);
876 jsd_ScriptCreated(JSDContext
* jsdc
,
878 const char *filename
, /* URL this script loads from */
879 uintN lineno
, /* line where this script starts */
883 jsd_NewScriptHookProc(cx
, filename
, lineno
, script
, fun
, jsdc
);
887 jsd_ScriptDestroyed(JSDContext
* jsdc
,
891 jsd_DestroyScriptHookProc(cx
, script
, jsdc
);