Back to index

lightning-sunbird  0.9+nobinonly
jsd_scpt.c
Go to the documentation of this file.
00001 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 /*
00039  * JavaScript Debugging support - Script support
00040  */
00041 
00042 #include "jsd.h"
00043 
00044 /* Comment this out to disable (NT specific) dumping as we go */
00045 /*
00046 ** #ifdef DEBUG      
00047 ** #define JSD_DUMP 1
00048 ** #endif            
00049 */
00050 
00051 #define NOT_SET_YET -1
00052 
00053 /***************************************************************************/
00054 
00055 #ifdef DEBUG
00056 void JSD_ASSERT_VALID_SCRIPT(JSDScript* jsdscript)
00057 {
00058     JS_ASSERT(jsdscript);
00059     JS_ASSERT(jsdscript->script);
00060 }
00061 void JSD_ASSERT_VALID_EXEC_HOOK(JSDExecHook* jsdhook)
00062 {
00063     JS_ASSERT(jsdhook);
00064     JS_ASSERT(jsdhook->hook);
00065 }
00066 #endif
00067 
00068 #ifdef LIVEWIRE
00069 static JSBool
00070 HasFileExtention(const char* name, const char* ext)
00071 {
00072     int i;
00073     int len = strlen(ext);
00074     const char* p = strrchr(name,'.');
00075     if( !p )
00076         return JS_FALSE;
00077     p++;
00078     for(i = 0; i < len; i++ )
00079     {
00080         JS_ASSERT(islower(ext[i]));
00081         if( 0 == p[i] || tolower(p[i]) != ext[i] )
00082             return JS_FALSE;
00083     }
00084     if( 0 != p[i] )
00085         return JS_FALSE;
00086     return JS_TRUE;
00087 }    
00088 #endif /* LIVEWIRE */
00089 
00090 static JSDScript*
00091 _newJSDScript(JSDContext*  jsdc,
00092               JSContext    *cx,
00093               JSScript     *script,
00094               JSFunction*  function)
00095 {
00096     JSDScript*  jsdscript;
00097     uintN     lineno;
00098     const char* raw_filename;
00099 
00100     JS_ASSERT(JSD_SCRIPTS_LOCKED(jsdc));
00101 
00102     /* these are inlined javascript: urls and we can't handle them now */
00103     lineno = (uintN) JS_GetScriptBaseLineNumber(cx, script);
00104     if( lineno == 0 )
00105         return NULL;
00106 
00107     jsdscript = (JSDScript*) calloc(1, sizeof(JSDScript));
00108     if( ! jsdscript )
00109         return NULL;
00110 
00111     raw_filename = JS_GetScriptFilename(cx,script);
00112 
00113     JS_HashTableAdd(jsdc->scriptsTable, (void *)script, (void *)jsdscript);
00114     JS_APPEND_LINK(&jsdscript->links, &jsdc->scripts);
00115     jsdscript->jsdc         = jsdc;
00116     jsdscript->script       = script;        
00117     jsdscript->function     = function;
00118     jsdscript->lineBase     = lineno;
00119     jsdscript->lineExtent   = (uintN)NOT_SET_YET;
00120     jsdscript->data         = NULL;
00121 #ifndef LIVEWIRE
00122     jsdscript->url          = (char*) jsd_BuildNormalizedURL(raw_filename);
00123 #else
00124     jsdscript->app = LWDBG_GetCurrentApp();    
00125     if( jsdscript->app && raw_filename )
00126     {
00127         jsdscript->url = jsdlw_BuildAppRelativeFilename(jsdscript->app, raw_filename);
00128         if( function )
00129         {
00130             jsdscript->lwscript = 
00131                 LWDBG_GetScriptOfFunction(jsdscript->app,
00132                                           JS_GetFunctionName(function));
00133     
00134             /* also, make sure this file is added to filelist if is .js file */
00135             if( HasFileExtention(raw_filename,"js") || 
00136                 HasFileExtention(raw_filename,"sjs") )
00137             {
00138                 jsdlw_PreLoadSource(jsdc, jsdscript->app, raw_filename, JS_FALSE);
00139             }
00140         }
00141         else
00142         {
00143             jsdscript->lwscript = LWDBG_GetCurrentTopLevelScript();
00144         }
00145     }
00146 #endif
00147 
00148     JS_INIT_CLIST(&jsdscript->hooks);
00149     
00150     return jsdscript;
00151 }           
00152 
00153 static void 
00154 _destroyJSDScript(JSDContext*  jsdc,
00155                   JSDScript*   jsdscript)
00156 {
00157     JS_ASSERT(JSD_SCRIPTS_LOCKED(jsdc));
00158 
00159     /* destroy all hooks */
00160     jsd_ClearAllExecutionHooksForScript(jsdc, jsdscript);
00161 
00162     JS_REMOVE_LINK(&jsdscript->links);
00163     if(jsdscript->url)
00164         free(jsdscript->url);
00165 
00166     if (jsdscript->profileData)
00167         free(jsdscript->profileData);
00168     
00169     if(jsdscript)
00170         free(jsdscript);
00171 }
00172 
00173 /***************************************************************************/
00174 
00175 #ifdef JSD_DUMP
00176 #ifndef XP_WIN
00177 void
00178 OutputDebugString (char *buf)
00179 {
00180     fprintf (stderr, "%s", buf);
00181 }
00182 #endif
00183 
00184 static void
00185 _dumpJSDScript(JSDContext* jsdc, JSDScript* jsdscript, const char* leadingtext)
00186 {
00187     const char* name;
00188     const char* fun;
00189     uintN base;
00190     uintN extent;
00191     char Buf[256];
00192     
00193     name   = jsd_GetScriptFilename(jsdc, jsdscript);
00194     fun    = jsd_GetScriptFunctionName(jsdc, jsdscript);
00195     base   = jsd_GetScriptBaseLineNumber(jsdc, jsdscript);
00196     extent = jsd_GetScriptLineExtent(jsdc, jsdscript);
00197     
00198     sprintf( Buf, "%sscript=%08X, %s, %s, %d-%d\n", 
00199              leadingtext,
00200              (unsigned) jsdscript->script,
00201              name ? name : "no URL", 
00202              fun  ? fun  : "no fun", 
00203              base, base + extent - 1 );
00204     OutputDebugString( Buf );
00205 }
00206 
00207 static void
00208 _dumpJSDScriptList( JSDContext* jsdc )
00209 {
00210     JSDScript* iterp = NULL;
00211     JSDScript* jsdscript = NULL;
00212     
00213     OutputDebugString( "*** JSDScriptDump\n" );
00214     while( NULL != (jsdscript = jsd_IterateScripts(jsdc, &iterp)) )
00215         _dumpJSDScript( jsdc, jsdscript, "  script: " );
00216 }
00217 #endif /* JSD_DUMP */
00218 
00219 /***************************************************************************/
00220 JS_STATIC_DLL_CALLBACK(JSHashNumber)
00221 jsd_hash_script(const void *key)
00222 {
00223     return ((JSHashNumber) key) >> 2; /* help lame MSVC1.5 on Win16 */
00224 }
00225 
00226 JS_STATIC_DLL_CALLBACK(void *)
00227 jsd_alloc_script_table(void *priv, size_t size)
00228 {
00229     return malloc(size);
00230 }
00231 
00232 JS_STATIC_DLL_CALLBACK(void)
00233 jsd_free_script_table(void *priv, void *item)
00234 {
00235     free(item);
00236 }
00237 
00238 JS_STATIC_DLL_CALLBACK(JSHashEntry *)
00239 jsd_alloc_script_entry(void *priv, const void *item)
00240 {
00241     return (JSHashEntry*) malloc(sizeof(JSHashEntry));
00242 }
00243 
00244 JS_STATIC_DLL_CALLBACK(void)
00245 jsd_free_script_entry(void *priv, JSHashEntry *he, uintN flag)
00246 {
00247     if (flag == HT_FREE_ENTRY)
00248     {
00249         _destroyJSDScript((JSDContext*) priv, (JSDScript*) he->value);
00250         free(he);
00251     }
00252 }
00253 
00254 static JSHashAllocOps script_alloc_ops = {
00255     jsd_alloc_script_table, jsd_free_script_table,
00256     jsd_alloc_script_entry, jsd_free_script_entry
00257 };
00258 
00259 #ifndef JSD_SCRIPT_HASH_SIZE
00260 #define JSD_SCRIPT_HASH_SIZE 1024
00261 #endif
00262 
00263 JSBool
00264 jsd_InitScriptManager(JSDContext* jsdc)
00265 {
00266     JS_INIT_CLIST(&jsdc->scripts);
00267     jsdc->scriptsTable = JS_NewHashTable(JSD_SCRIPT_HASH_SIZE, jsd_hash_script,
00268                                          JS_CompareValues, JS_CompareValues,
00269                                          &script_alloc_ops, (void*) jsdc);
00270     return (JSBool) jsdc->scriptsTable;
00271 }
00272 
00273 void
00274 jsd_DestroyScriptManager(JSDContext* jsdc)
00275 {
00276     JSD_LOCK_SCRIPTS(jsdc);
00277     if (jsdc->scriptsTable)
00278         JS_HashTableDestroy(jsdc->scriptsTable);
00279     JSD_UNLOCK_SCRIPTS(jsdc);
00280 }
00281 
00282 JSDScript*
00283 jsd_FindJSDScript( JSDContext*  jsdc,
00284                    JSScript     *script )
00285 {
00286     JS_ASSERT(JSD_SCRIPTS_LOCKED(jsdc));
00287     return (JSDScript*) JS_HashTableLookup(jsdc->scriptsTable, (void *)script);
00288 }               
00289 
00290 JSDProfileData*
00291 jsd_GetScriptProfileData(JSDContext* jsdc, JSDScript *script)
00292 {
00293     if (!script->profileData)
00294         script->profileData = (JSDProfileData*)calloc(1, sizeof(JSDProfileData));
00295 
00296     return script->profileData;
00297 }
00298 
00299 uint32
00300 jsd_GetScriptFlags(JSDContext *jsdc, JSDScript *script)
00301 {
00302     return script->flags;
00303 }
00304 
00305 void
00306 jsd_SetScriptFlags(JSDContext *jsdc, JSDScript *script, uint32 flags)
00307 {
00308     script->flags = flags;
00309 }
00310 
00311 uintN
00312 jsd_GetScriptCallCount(JSDContext* jsdc, JSDScript *script)
00313 {
00314     if (script->profileData)
00315         return script->profileData->callCount;
00316 
00317     return 0;
00318 }
00319 
00320 uintN
00321 jsd_GetScriptMaxRecurseDepth(JSDContext* jsdc, JSDScript *script)
00322 {
00323     if (script->profileData)
00324         return script->profileData->maxRecurseDepth;
00325 
00326     return 0;
00327 }
00328 
00329 jsdouble
00330 jsd_GetScriptMinExecutionTime(JSDContext* jsdc, JSDScript *script)
00331 {
00332     if (script->profileData)
00333         return script->profileData->minExecutionTime;
00334 
00335     return 0.0;
00336 }
00337 
00338 jsdouble
00339 jsd_GetScriptMaxExecutionTime(JSDContext* jsdc, JSDScript *script)
00340 {
00341     if (script->profileData)
00342         return script->profileData->maxExecutionTime;
00343 
00344     return 0.0;
00345 }
00346 
00347 jsdouble
00348 jsd_GetScriptTotalExecutionTime(JSDContext* jsdc, JSDScript *script)
00349 {
00350     if (script->profileData)
00351         return script->profileData->totalExecutionTime;
00352 
00353     return 0.0;
00354 }
00355 
00356 jsdouble
00357 jsd_GetScriptMinOwnExecutionTime(JSDContext* jsdc, JSDScript *script)
00358 {
00359     if (script->profileData)
00360         return script->profileData->minOwnExecutionTime;
00361 
00362     return 0.0;
00363 }
00364 
00365 jsdouble
00366 jsd_GetScriptMaxOwnExecutionTime(JSDContext* jsdc, JSDScript *script)
00367 {
00368     if (script->profileData)
00369         return script->profileData->maxOwnExecutionTime;
00370 
00371     return 0.0;
00372 }
00373 
00374 jsdouble
00375 jsd_GetScriptTotalOwnExecutionTime(JSDContext* jsdc, JSDScript *script)
00376 {
00377     if (script->profileData)
00378         return script->profileData->totalOwnExecutionTime;
00379 
00380     return 0.0;
00381 }
00382 
00383 void
00384 jsd_ClearScriptProfileData(JSDContext* jsdc, JSDScript *script)
00385 {
00386     if (script->profileData)
00387     {
00388         free(script->profileData);
00389         script->profileData = NULL;
00390     }
00391 }    
00392 
00393 JSScript *
00394 jsd_GetJSScript (JSDContext *jsdc, JSDScript *script)
00395 {
00396     return script->script;
00397 }
00398 
00399 JSFunction *
00400 jsd_GetJSFunction (JSDContext *jsdc, JSDScript *script)
00401 {
00402     return script->function;
00403 }
00404 
00405 JSDScript*
00406 jsd_IterateScripts(JSDContext* jsdc, JSDScript **iterp)
00407 {
00408     JSDScript *jsdscript = *iterp;
00409     
00410     JS_ASSERT(JSD_SCRIPTS_LOCKED(jsdc));
00411 
00412     if( !jsdscript )
00413         jsdscript = (JSDScript *)jsdc->scripts.next;
00414     if( jsdscript == (JSDScript *)&jsdc->scripts )
00415         return NULL;
00416     *iterp = (JSDScript*) jsdscript->links.next;
00417     return jsdscript;
00418 }
00419 
00420 void *
00421 jsd_SetScriptPrivate(JSDScript *jsdscript, void *data)
00422 {
00423     void *rval = jsdscript->data;
00424     jsdscript->data = data;
00425     return rval;
00426 }
00427 
00428 void *
00429 jsd_GetScriptPrivate(JSDScript *jsdscript)
00430 {
00431     return jsdscript->data;
00432 }
00433 
00434 JSBool
00435 jsd_IsActiveScript(JSDContext* jsdc, JSDScript *jsdscript)
00436 {
00437     JSDScript *current;
00438 
00439     JS_ASSERT(JSD_SCRIPTS_LOCKED(jsdc));
00440 
00441     for( current = (JSDScript *)jsdc->scripts.next;
00442          current != (JSDScript *)&jsdc->scripts;
00443          current = (JSDScript *)current->links.next )
00444     {
00445         if(jsdscript == current)
00446             return JS_TRUE;
00447     }
00448     return JS_FALSE;
00449 }        
00450 
00451 const char*
00452 jsd_GetScriptFilename(JSDContext* jsdc, JSDScript *jsdscript)
00453 {
00454     return jsdscript->url;
00455 }
00456 
00457 const char*
00458 jsd_GetScriptFunctionName(JSDContext* jsdc, JSDScript *jsdscript)
00459 {
00460     if( ! jsdscript->function )
00461         return NULL;
00462     return JS_GetFunctionName(jsdscript->function);
00463 }
00464 
00465 uintN
00466 jsd_GetScriptBaseLineNumber(JSDContext* jsdc, JSDScript *jsdscript)
00467 {
00468     return jsdscript->lineBase;
00469 }
00470 
00471 uintN
00472 jsd_GetScriptLineExtent(JSDContext* jsdc, JSDScript *jsdscript)
00473 {
00474     if( NOT_SET_YET == (int)jsdscript->lineExtent )
00475         jsdscript->lineExtent = JS_GetScriptLineExtent(jsdc->dumbContext, jsdscript->script);
00476     return jsdscript->lineExtent;
00477 }
00478 
00479 jsuword
00480 jsd_GetClosestPC(JSDContext* jsdc, JSDScript* jsdscript, uintN line)
00481 {
00482 #ifdef LIVEWIRE
00483     if( jsdscript && jsdscript->lwscript )
00484     {
00485         uintN newline;
00486         jsdlw_RawToProcessedLineNumber(jsdc, jsdscript, line, &newline);
00487         if( line != newline )
00488             line = newline;
00489     }
00490 #endif
00491 
00492     return (jsuword) JS_LineNumberToPC(jsdc->dumbContext, 
00493                                        jsdscript->script, line );
00494 }
00495 
00496 uintN
00497 jsd_GetClosestLine(JSDContext* jsdc, JSDScript* jsdscript, jsuword pc)
00498 {
00499     uintN first = jsdscript->lineBase;
00500     uintN last = first + jsd_GetScriptLineExtent(jsdc, jsdscript) - 1;
00501     uintN line = JS_PCToLineNumber(jsdc->dumbContext, 
00502                                      jsdscript->script, (jsbytecode*)pc);
00503 
00504     if( line < first )
00505         return first;
00506     if( line > last )
00507         return last;
00508 
00509 #ifdef LIVEWIRE
00510     if( jsdscript && jsdscript->lwscript )
00511     {
00512         uintN newline;
00513         jsdlw_ProcessedToRawLineNumber(jsdc, jsdscript, line, &newline);
00514         line = newline;
00515     }
00516 #endif
00517 
00518     return line;    
00519 }
00520 
00521 JSBool
00522 jsd_SetScriptHook(JSDContext* jsdc, JSD_ScriptHookProc hook, void* callerdata)
00523 {
00524     JSD_LOCK();
00525     jsdc->scriptHook = hook;
00526     jsdc->scriptHookData = callerdata;
00527     JSD_UNLOCK();
00528     return JS_TRUE;
00529 }
00530 
00531 JSBool
00532 jsd_GetScriptHook(JSDContext* jsdc, JSD_ScriptHookProc* hook, void** callerdata)
00533 {
00534     JSD_LOCK();
00535     if( hook )
00536         *hook = jsdc->scriptHook;
00537     if( callerdata )
00538         *callerdata = jsdc->scriptHookData;
00539     JSD_UNLOCK();
00540     return JS_TRUE;
00541 }    
00542 
00543 /***************************************************************************/
00544 
00545 void JS_DLL_CALLBACK
00546 jsd_NewScriptHookProc( 
00547                 JSContext   *cx,
00548                 const char  *filename,      /* URL this script loads from */
00549                 uintN       lineno,         /* line where this script starts */
00550                 JSScript    *script,
00551                 JSFunction  *fun,                
00552                 void*       callerdata )
00553 {
00554     JSDScript* jsdscript = NULL;
00555     JSDContext* jsdc = (JSDContext*) callerdata;
00556     JSD_ScriptHookProc      hook;
00557     void*                   hookData;
00558     
00559     JSD_ASSERT_VALID_CONTEXT(jsdc);
00560 
00561     if( JSD_IS_DANGEROUS_THREAD(jsdc) )
00562         return;
00563     
00564 #ifdef LIVEWIRE
00565     if( 1 == lineno )
00566         jsdlw_PreLoadSource(jsdc, LWDBG_GetCurrentApp(), filename, JS_TRUE );
00567 #endif
00568     
00569     JSD_LOCK_SCRIPTS(jsdc);
00570     jsdscript = _newJSDScript(jsdc, cx, script, fun);
00571     JSD_UNLOCK_SCRIPTS(jsdc);
00572     if( ! jsdscript )
00573         return;
00574 
00575 #ifdef JSD_DUMP
00576     JSD_LOCK_SCRIPTS(jsdc);
00577     _dumpJSDScript(jsdc, jsdscript, "***NEW Script: ");
00578     _dumpJSDScriptList( jsdc );
00579     JSD_UNLOCK_SCRIPTS(jsdc);
00580 #endif /* JSD_DUMP */
00581 
00582     /* local in case jsdc->scriptHook gets cleared on another thread */
00583     JSD_LOCK();
00584     hook = jsdc->scriptHook;
00585     hookData = jsdc->scriptHookData;
00586     JSD_UNLOCK();
00587 
00588     if( hook )
00589         hook(jsdc, jsdscript, JS_TRUE, hookData);
00590 }                
00591 
00592 void JS_DLL_CALLBACK
00593 jsd_DestroyScriptHookProc( 
00594                 JSContext   *cx,
00595                 JSScript    *script,
00596                 void*       callerdata )
00597 {
00598     JSDScript* jsdscript = NULL;
00599     JSDContext* jsdc = (JSDContext*) callerdata;
00600     JSD_ScriptHookProc      hook;
00601     void*                   hookData;
00602     
00603     JSD_ASSERT_VALID_CONTEXT(jsdc);
00604 
00605     if( JSD_IS_DANGEROUS_THREAD(jsdc) )
00606         return;
00607     
00608     JSD_LOCK_SCRIPTS(jsdc);
00609     jsdscript = jsd_FindJSDScript(jsdc, script);
00610     JSD_UNLOCK_SCRIPTS(jsdc);
00611 
00612     if( ! jsdscript )
00613         return;
00614 
00615 #ifdef JSD_DUMP
00616     JSD_LOCK_SCRIPTS(jsdc);
00617     _dumpJSDScript(jsdc, jsdscript, "***DESTROY Script: ");
00618     JSD_UNLOCK_SCRIPTS(jsdc);
00619 #endif /* JSD_DUMP */
00620 
00621     /* local in case hook gets cleared on another thread */
00622     JSD_LOCK();
00623     hook = jsdc->scriptHook;
00624     hookData = jsdc->scriptHookData;
00625     JSD_UNLOCK();
00626 
00627     if( hook )
00628         hook(jsdc, jsdscript, JS_FALSE, hookData);
00629 
00630     JSD_LOCK_SCRIPTS(jsdc);
00631     JS_HashTableRemove(jsdc->scriptsTable, (void *)script);
00632     JSD_UNLOCK_SCRIPTS(jsdc);
00633 
00634 #ifdef JSD_DUMP
00635     JSD_LOCK_SCRIPTS(jsdc);
00636     _dumpJSDScriptList(jsdc);
00637     JSD_UNLOCK_SCRIPTS(jsdc);
00638 #endif /* JSD_DUMP */
00639 }                
00640 
00641 
00642 /***************************************************************************/
00643 
00644 static JSDExecHook*
00645 _findHook(JSDContext* jsdc, JSDScript* jsdscript, jsuword pc)
00646 {
00647     JSDExecHook* jsdhook;
00648     JSCList* list = &jsdscript->hooks;
00649 
00650     for( jsdhook = (JSDExecHook*)list->next;
00651          jsdhook != (JSDExecHook*)list;
00652          jsdhook = (JSDExecHook*)jsdhook->links.next )
00653     {
00654         if (jsdhook->pc == pc)
00655             return jsdhook;
00656     }
00657     return NULL;
00658 }
00659 
00660 static JSBool
00661 _isActiveHook(JSDContext* jsdc, JSScript *script, JSDExecHook* jsdhook)
00662 {
00663     JSDExecHook* current;
00664     JSCList* list;
00665     JSDScript* jsdscript;
00666 
00667     JSD_LOCK_SCRIPTS(jsdc);
00668     jsdscript = jsd_FindJSDScript(jsdc, script);
00669     if( ! jsdscript)
00670     {
00671         JSD_UNLOCK_SCRIPTS(jsdc);
00672         return JS_FALSE;
00673     }
00674 
00675     list = &jsdscript->hooks;
00676 
00677     for( current = (JSDExecHook*)list->next;
00678          current != (JSDExecHook*)list;
00679          current = (JSDExecHook*)current->links.next )
00680     {
00681         if(current == jsdhook)
00682         {
00683             JSD_UNLOCK_SCRIPTS(jsdc);
00684             return JS_TRUE;
00685         }
00686     }
00687     JSD_UNLOCK_SCRIPTS(jsdc);
00688     return JS_FALSE;
00689 }
00690 
00691 
00692 JSTrapStatus JS_DLL_CALLBACK
00693 jsd_TrapHandler(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval,
00694                 void *closure)
00695 {
00696     JSDExecHook* jsdhook = (JSDExecHook*) JSVAL_TO_PRIVATE(((jsval)closure));
00697     JSD_ExecutionHookProc hook;
00698     void* hookData;
00699     JSDContext*  jsdc;
00700     JSDScript* jsdscript;
00701 
00702     JSD_LOCK();
00703 
00704     if( NULL == (jsdc = jsd_JSDContextForJSContext(cx)) ||
00705         ! _isActiveHook(jsdc, script, jsdhook) )
00706     {
00707         JSD_UNLOCK();
00708         return JSTRAP_CONTINUE;
00709     }
00710 
00711     JSD_ASSERT_VALID_EXEC_HOOK(jsdhook);
00712     JS_ASSERT(jsdhook->pc == (jsuword)pc);
00713     JS_ASSERT(jsdhook->jsdscript->script == script);
00714     JS_ASSERT(jsdhook->jsdscript->jsdc == jsdc);
00715 
00716     hook = jsdhook->hook;
00717     hookData = jsdhook->callerdata;
00718     jsdscript = jsdhook->jsdscript;
00719 
00720     /* do not use jsdhook-> after this point */
00721     JSD_UNLOCK();
00722 
00723     if( ! jsdc || ! jsdc->inited )
00724         return JSTRAP_CONTINUE;
00725 
00726     if( JSD_IS_DANGEROUS_THREAD(jsdc) )
00727         return JSTRAP_CONTINUE;
00728 
00729 #ifdef LIVEWIRE
00730     if( ! jsdlw_UserCodeAtPC(jsdc, jsdscript, (jsuword)pc) )
00731         return JSTRAP_CONTINUE;
00732 #endif
00733 
00734     return jsd_CallExecutionHook(jsdc, cx, JSD_HOOK_BREAKPOINT,
00735                                  hook, hookData, rval);
00736 }
00737 
00738 
00739 
00740 JSBool
00741 jsd_SetExecutionHook(JSDContext*           jsdc, 
00742                      JSDScript*            jsdscript,
00743                      jsuword               pc,
00744                      JSD_ExecutionHookProc hook,
00745                      void*                 callerdata)
00746 {
00747     JSDExecHook* jsdhook;
00748 
00749     JSD_LOCK();
00750     if( ! hook )
00751     {
00752         jsd_ClearExecutionHook(jsdc, jsdscript, pc);
00753         JSD_UNLOCK();
00754         return JS_TRUE;
00755     }
00756 
00757     jsdhook = _findHook(jsdc, jsdscript, pc);
00758     if( jsdhook )
00759     {
00760         jsdhook->hook       = hook;
00761         jsdhook->callerdata = callerdata;
00762         return JS_TRUE;
00763     }
00764     /* else... */
00765 
00766     jsdhook = (JSDExecHook*)calloc(1, sizeof(JSDExecHook));
00767     if( ! jsdhook )
00768         return JS_FALSE;
00769     jsdhook->jsdscript  = jsdscript;
00770     jsdhook->pc         = pc;
00771     jsdhook->hook       = hook;
00772     jsdhook->callerdata = callerdata;
00773 
00774     if( ! JS_SetTrap(jsdc->dumbContext, jsdscript->script, 
00775                      (jsbytecode*)pc, jsd_TrapHandler, 
00776                      (void*) PRIVATE_TO_JSVAL(jsdhook)) )
00777     {
00778         free(jsdhook);
00779         return JS_FALSE;
00780     }
00781 
00782     JS_APPEND_LINK(&jsdhook->links, &jsdscript->hooks);
00783     JSD_UNLOCK();
00784 
00785     return JS_TRUE;
00786 }
00787 
00788 JSBool
00789 jsd_ClearExecutionHook(JSDContext*           jsdc, 
00790                        JSDScript*            jsdscript,
00791                        jsuword               pc)
00792 {
00793     JSDExecHook* jsdhook;
00794 
00795     JSD_LOCK();
00796 
00797     jsdhook = _findHook(jsdc, jsdscript, pc);
00798     if( ! jsdhook )
00799     {
00800         JS_ASSERT(0);
00801         JSD_UNLOCK();
00802         return JS_FALSE;
00803     }
00804 
00805     JS_ClearTrap(jsdc->dumbContext, jsdscript->script, 
00806                  (jsbytecode*)pc, NULL, NULL );
00807 
00808     JS_REMOVE_LINK(&jsdhook->links);
00809     free(jsdhook);
00810 
00811     JSD_UNLOCK();
00812     return JS_TRUE;
00813 }
00814 
00815 JSBool
00816 jsd_ClearAllExecutionHooksForScript(JSDContext* jsdc, JSDScript* jsdscript)
00817 {
00818     JSDExecHook* jsdhook;
00819     JSCList* list = &jsdscript->hooks;
00820 
00821     JSD_LOCK();
00822 
00823     while( (JSDExecHook*)list != (jsdhook = (JSDExecHook*)list->next) )
00824     {
00825         JS_REMOVE_LINK(&jsdhook->links);
00826         free(jsdhook);
00827     }
00828 
00829     JS_ClearScriptTraps(jsdc->dumbContext, jsdscript->script);
00830     JSD_UNLOCK();
00831 
00832     return JS_TRUE;
00833 }
00834 
00835 JSBool
00836 jsd_ClearAllExecutionHooks(JSDContext* jsdc)
00837 {
00838     JSDScript* jsdscript;
00839     JSDScript* iterp = NULL;
00840 
00841     JSD_LOCK();
00842     while( NULL != (jsdscript = jsd_IterateScripts(jsdc, &iterp)) )
00843         jsd_ClearAllExecutionHooksForScript(jsdc, jsdscript);
00844     JSD_UNLOCK();
00845     return JS_TRUE;
00846 }
00847 
00848 void
00849 jsd_ScriptCreated(JSDContext* jsdc,
00850                   JSContext   *cx,
00851                   const char  *filename,    /* URL this script loads from */
00852                   uintN       lineno,       /* line where this script starts */
00853                   JSScript    *script,
00854                   JSFunction  *fun)
00855 {
00856     jsd_NewScriptHookProc(cx, filename, lineno, script, fun, jsdc);
00857 }
00858 
00859 void
00860 jsd_ScriptDestroyed(JSDContext* jsdc,
00861                     JSContext   *cx,
00862                     JSScript    *script)
00863 {
00864     jsd_DestroyScriptHookProc(cx, script, jsdc);
00865 }