js/jsd/jsd_scpt.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     2  * vim: set ts=8 sts=4 et sw=4 tw=99:
     3  * This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 /*
     8  * JavaScript Debugging support - Script support
     9  */
    11 #include "jsd.h"
    12 #include "jsfriendapi.h"
    13 #include "nsCxPusher.h"
    15 using mozilla::AutoSafeJSContext;
    17 /* Comment this out to disable (NT specific) dumping as we go */
    18 /*
    19 ** #ifdef DEBUG      
    20 ** #define JSD_DUMP 1
    21 ** #endif            
    22 */
    24 #define NOT_SET_YET -1
    26 /***************************************************************************/
    28 #ifdef DEBUG
    29 void JSD_ASSERT_VALID_SCRIPT(JSDScript* jsdscript)
    30 {
    31     MOZ_ASSERT(jsdscript);
    32     MOZ_ASSERT(jsdscript->script);
    33 }
    34 void JSD_ASSERT_VALID_EXEC_HOOK(JSDExecHook* jsdhook)
    35 {
    36     MOZ_ASSERT(jsdhook);
    37     MOZ_ASSERT(jsdhook->hook);
    38 }
    39 #endif
    41 static JSDScript*
    42 _newJSDScript(JSDContext*  jsdc,
    43               JSContext    *cx,
    44               JSScript     *script_)
    45 {
    46     JS::RootedScript script(cx, script_);
    47     if ( JS_GetScriptIsSelfHosted(script) )
    48         return nullptr;
    50     JSDScript*  jsdscript;
    51     unsigned     lineno;
    52     const char* raw_filename;
    54     MOZ_ASSERT(JSD_SCRIPTS_LOCKED(jsdc));
    56     /* these are inlined javascript: urls and we can't handle them now */
    57     lineno = (unsigned) JS_GetScriptBaseLineNumber(cx, script);
    58     if( lineno == 0 )
    59         return nullptr;
    61     jsdscript = (JSDScript*) calloc(1, sizeof(JSDScript));
    62     if( ! jsdscript )
    63         return nullptr;
    65     raw_filename = JS_GetScriptFilename(script);
    67     JS_HashTableAdd(jsdc->scriptsTable, (void *)script, (void *)jsdscript);
    68     JS_APPEND_LINK(&jsdscript->links, &jsdc->scripts);
    69     jsdscript->jsdc         = jsdc;
    70     jsdscript->script       = script;  
    71     jsdscript->lineBase     = lineno;
    72     jsdscript->lineExtent   = (unsigned)NOT_SET_YET;
    73     jsdscript->data         = nullptr;
    74     jsdscript->url          = (char*) jsd_BuildNormalizedURL(raw_filename);
    76     JS_INIT_CLIST(&jsdscript->hooks);
    78     return jsdscript;
    79 }           
    81 static void 
    82 _destroyJSDScript(JSDContext*  jsdc,
    83                   JSDScript*   jsdscript)
    84 {
    85     MOZ_ASSERT(JSD_SCRIPTS_LOCKED(jsdc));
    87     /* destroy all hooks */
    88     jsd_ClearAllExecutionHooksForScript(jsdc, jsdscript);
    90     JS_REMOVE_LINK(&jsdscript->links);
    91     if(jsdscript->url)
    92         free(jsdscript->url);
    94     if (jsdscript->profileData)
    95         free(jsdscript->profileData);
    97     free(jsdscript);
    98 }
   100 /***************************************************************************/
   102 #ifdef JSD_DUMP
   103 #ifndef XP_WIN
   104 void
   105 OutputDebugString (char *buf)
   106 {
   107     fprintf (stderr, "%s", buf);
   108 }
   109 #endif
   111 static void
   112 _dumpJSDScript(JSDContext* jsdc, JSDScript* jsdscript, const char* leadingtext)
   113 {
   114     const char* name;
   115     JSString* fun;
   116     unsigned base;
   117     unsigned extent;
   118     char Buf[256];
   119     size_t n;
   121     name   = jsd_GetScriptFilename(jsdc, jsdscript);
   122     fun    = jsd_GetScriptFunctionId(jsdc, jsdscript);
   123     base   = jsd_GetScriptBaseLineNumber(jsdc, jsdscript);
   124     extent = jsd_GetScriptLineExtent(jsdc, jsdscript);
   125     n = size_t(snprintf(Buf, sizeof(Buf), "%sscript=%08X, %s, ",
   126                         leadingtext, (unsigned) jsdscript->script,
   127                         name ? name : "no URL"));
   128     if (n + 1 < sizeof(Buf)) {
   129         if (fun) {
   130             n += size_t(snprintf(Buf + n, sizeof(Buf) - n, "%s", "no fun"));
   131         } else {
   132             n += JS_PutEscapedFlatString(Buf + n, sizeof(Buf) - n,
   133                                          MOZ_ASSERT_STRING_IS_FLAT(fun), 0);
   134             Buf[sizeof(Buf) - 1] = '\0';
   135         }
   136         if (n + 1 < sizeof(Buf))
   137             snprintf(Buf + n, sizeof(Buf) - n, ", %d-%d\n", base, base + extent - 1);
   138     }
   139     OutputDebugString( Buf );
   140 }
   142 static void
   143 _dumpJSDScriptList( JSDContext* jsdc )
   144 {
   145     JSDScript* iterp = nullptr;
   146     JSDScript* jsdscript = nullptr;
   148     OutputDebugString( "*** JSDScriptDump\n" );
   149     while( nullptr != (jsdscript = jsd_IterateScripts(jsdc, &iterp)) )
   150         _dumpJSDScript( jsdc, jsdscript, "  script: " );
   151 }
   152 #endif /* JSD_DUMP */
   154 /***************************************************************************/
   155 static JSHashNumber
   156 jsd_hash_script(const void *key)
   157 {
   158     return ((JSHashNumber)(ptrdiff_t) key) >> 2; /* help lame MSVC1.5 on Win16 */
   159 }
   161 static void *
   162 jsd_alloc_script_table(void *priv, size_t size)
   163 {
   164     return malloc(size);
   165 }
   167 static void
   168 jsd_free_script_table(void *priv, void *item, size_t size)
   169 {
   170     free(item);
   171 }
   173 static JSHashEntry *
   174 jsd_alloc_script_entry(void *priv, const void *item)
   175 {
   176     return (JSHashEntry*) malloc(sizeof(JSHashEntry));
   177 }
   179 static void
   180 jsd_free_script_entry(void *priv, JSHashEntry *he, unsigned flag)
   181 {
   182     if (flag == HT_FREE_ENTRY)
   183     {
   184         _destroyJSDScript((JSDContext*) priv, (JSDScript*) he->value);
   185         free(he);
   186     }
   187 }
   189 static const JSHashAllocOps script_alloc_ops = {
   190     jsd_alloc_script_table, jsd_free_script_table,
   191     jsd_alloc_script_entry, jsd_free_script_entry
   192 };
   194 #ifndef JSD_SCRIPT_HASH_SIZE
   195 #define JSD_SCRIPT_HASH_SIZE 1024
   196 #endif
   198 bool
   199 jsd_InitScriptManager(JSDContext* jsdc)
   200 {
   201     JS_INIT_CLIST(&jsdc->scripts);
   202     jsdc->scriptsTable = JS_NewHashTable(JSD_SCRIPT_HASH_SIZE, jsd_hash_script,
   203                                          JS_CompareValues, JS_CompareValues,
   204                                          &script_alloc_ops, (void*) jsdc);
   205     return !!jsdc->scriptsTable;
   206 }
   208 void
   209 jsd_DestroyScriptManager(JSDContext* jsdc)
   210 {
   211     JSD_LOCK_SCRIPTS(jsdc);
   212     if (jsdc->scriptsTable)
   213         JS_HashTableDestroy(jsdc->scriptsTable);
   214     JSD_UNLOCK_SCRIPTS(jsdc);
   215 }
   217 JSDScript*
   218 jsd_FindJSDScript( JSDContext*  jsdc,
   219                    JSScript     *script )
   220 {
   221     MOZ_ASSERT(JSD_SCRIPTS_LOCKED(jsdc));
   222     return (JSDScript*) JS_HashTableLookup(jsdc->scriptsTable, (void *)script);
   223 }
   225 JSDScript *
   226 jsd_FindOrCreateJSDScript(JSDContext    *jsdc,
   227                           JSContext     *cx,
   228                           JSScript      *script_,
   229                           JSAbstractFramePtr frame)
   230 {
   231     JS::RootedScript script(cx, script_);
   232     JSDScript *jsdscript;
   233     MOZ_ASSERT(JSD_SCRIPTS_LOCKED(jsdc));
   235     jsdscript = jsd_FindJSDScript(jsdc, script);
   236     if (jsdscript)
   237         return jsdscript;
   239     /* Fallback for unknown scripts: create a new script. */
   240     if (!frame) {
   241         JSBrokenFrameIterator iter(cx);
   242         if (!iter.done())
   243             frame = iter.abstractFramePtr();
   244     }
   245     if (frame)
   246         jsdscript = _newJSDScript(jsdc, cx, script);
   248     return jsdscript;
   249 }
   251 JSDProfileData*
   252 jsd_GetScriptProfileData(JSDContext* jsdc, JSDScript *script)
   253 {
   254     if (!script->profileData)
   255         script->profileData = (JSDProfileData*)calloc(1, sizeof(JSDProfileData));
   257     return script->profileData;
   258 }
   260 uint32_t
   261 jsd_GetScriptFlags(JSDContext *jsdc, JSDScript *script)
   262 {
   263     return script->flags;
   264 }
   266 void
   267 jsd_SetScriptFlags(JSDContext *jsdc, JSDScript *script, uint32_t flags)
   268 {
   269     script->flags = flags;
   270 }
   272 unsigned
   273 jsd_GetScriptCallCount(JSDContext* jsdc, JSDScript *script)
   274 {
   275     if (script->profileData)
   276         return script->profileData->callCount;
   278     return 0;
   279 }
   281 unsigned
   282 jsd_GetScriptMaxRecurseDepth(JSDContext* jsdc, JSDScript *script)
   283 {
   284     if (script->profileData)
   285         return script->profileData->maxRecurseDepth;
   287     return 0;
   288 }
   290 double
   291 jsd_GetScriptMinExecutionTime(JSDContext* jsdc, JSDScript *script)
   292 {
   293     if (script->profileData)
   294         return script->profileData->minExecutionTime;
   296     return 0.0;
   297 }
   299 double
   300 jsd_GetScriptMaxExecutionTime(JSDContext* jsdc, JSDScript *script)
   301 {
   302     if (script->profileData)
   303         return script->profileData->maxExecutionTime;
   305     return 0.0;
   306 }
   308 double
   309 jsd_GetScriptTotalExecutionTime(JSDContext* jsdc, JSDScript *script)
   310 {
   311     if (script->profileData)
   312         return script->profileData->totalExecutionTime;
   314     return 0.0;
   315 }
   317 double
   318 jsd_GetScriptMinOwnExecutionTime(JSDContext* jsdc, JSDScript *script)
   319 {
   320     if (script->profileData)
   321         return script->profileData->minOwnExecutionTime;
   323     return 0.0;
   324 }
   326 double
   327 jsd_GetScriptMaxOwnExecutionTime(JSDContext* jsdc, JSDScript *script)
   328 {
   329     if (script->profileData)
   330         return script->profileData->maxOwnExecutionTime;
   332     return 0.0;
   333 }
   335 double
   336 jsd_GetScriptTotalOwnExecutionTime(JSDContext* jsdc, JSDScript *script)
   337 {
   338     if (script->profileData)
   339         return script->profileData->totalOwnExecutionTime;
   341     return 0.0;
   342 }
   344 void
   345 jsd_ClearScriptProfileData(JSDContext* jsdc, JSDScript *script)
   346 {
   347     if (script->profileData)
   348     {
   349         free(script->profileData);
   350         script->profileData = nullptr;
   351     }
   352 }    
   354 JSScript *
   355 jsd_GetJSScript (JSDContext *jsdc, JSDScript *script)
   356 {
   357     return script->script;
   358 }
   360 JSFunction *
   361 jsd_GetJSFunction (JSDContext *jsdc, JSDScript *script)
   362 {
   363     AutoSafeJSContext cx;
   364     return JS_GetScriptFunction(cx, script->script);
   365 }
   367 JSDScript*
   368 jsd_IterateScripts(JSDContext* jsdc, JSDScript **iterp)
   369 {
   370     JSDScript *jsdscript = *iterp;
   372     MOZ_ASSERT(JSD_SCRIPTS_LOCKED(jsdc));
   374     if( !jsdscript )
   375         jsdscript = (JSDScript *)jsdc->scripts.next;
   376     if( jsdscript == (JSDScript *)&jsdc->scripts )
   377         return nullptr;
   378     *iterp = (JSDScript*) jsdscript->links.next;
   379     return jsdscript;
   380 }
   382 void *
   383 jsd_SetScriptPrivate(JSDScript *jsdscript, void *data)
   384 {
   385     void *rval = jsdscript->data;
   386     jsdscript->data = data;
   387     return rval;
   388 }
   390 void *
   391 jsd_GetScriptPrivate(JSDScript *jsdscript)
   392 {
   393     return jsdscript->data;
   394 }
   396 bool
   397 jsd_IsActiveScript(JSDContext* jsdc, JSDScript *jsdscript)
   398 {
   399     JSDScript *current;
   401     MOZ_ASSERT(JSD_SCRIPTS_LOCKED(jsdc));
   403     for( current = (JSDScript *)jsdc->scripts.next;
   404          current != (JSDScript *)&jsdc->scripts;
   405          current = (JSDScript *)current->links.next )
   406     {
   407         if(jsdscript == current)
   408             return true;
   409     }
   410     return false;
   411 }        
   413 const char*
   414 jsd_GetScriptFilename(JSDContext* jsdc, JSDScript *jsdscript)
   415 {
   416     return jsdscript->url;
   417 }
   419 JSString*
   420 jsd_GetScriptFunctionId(JSDContext* jsdc, JSDScript *jsdscript)
   421 {
   422     JSString* str;
   423     JSFunction *fun = jsd_GetJSFunction(jsdc, jsdscript);
   425     if( ! fun )
   426         return nullptr;
   427     str = JS_GetFunctionId(fun);
   429     /* For compatibility we return "anonymous", not an empty string here. */
   430     return str ? str : JS_GetAnonymousString(jsdc->jsrt);
   431 }
   433 unsigned
   434 jsd_GetScriptBaseLineNumber(JSDContext* jsdc, JSDScript *jsdscript)
   435 {
   436     return jsdscript->lineBase;
   437 }
   439 unsigned
   440 jsd_GetScriptLineExtent(JSDContext* jsdc, JSDScript *jsdscript)
   441 {
   442     AutoSafeJSContext cx;
   443     JSAutoCompartment ac(cx, jsdc->glob); // Just in case.
   444     if( NOT_SET_YET == (int)jsdscript->lineExtent )
   445         jsdscript->lineExtent = JS_GetScriptLineExtent(cx, jsdscript->script);
   446     return jsdscript->lineExtent;
   447 }
   449 uintptr_t
   450 jsd_GetClosestPC(JSDContext* jsdc, JSDScript* jsdscript, unsigned line)
   451 {
   452     uintptr_t pc;
   454     if( !jsdscript )
   455         return 0;
   457     AutoSafeJSContext cx;
   458     JSAutoCompartment ac(cx, jsdscript->script);
   459     pc = (uintptr_t) JS_LineNumberToPC(cx, jsdscript->script, line );
   460     return pc;
   461 }
   463 unsigned
   464 jsd_GetClosestLine(JSDContext* jsdc, JSDScript* jsdscript, uintptr_t pc)
   465 {
   466     unsigned first = jsdscript->lineBase;
   467     unsigned last = first + jsd_GetScriptLineExtent(jsdc, jsdscript) - 1;
   468     unsigned line = 0;
   470     if (pc) {
   471         AutoSafeJSContext cx;
   472         JSAutoCompartment ac(cx, jsdscript->script);
   473         line = JS_PCToLineNumber(cx, jsdscript->script, (jsbytecode*)pc);
   474     }
   476     if( line < first )
   477         return first;
   478     if( line > last )
   479         return last;
   481     return line;    
   482 }
   484 bool
   485 jsd_GetLinePCs(JSDContext* jsdc, JSDScript* jsdscript,
   486                unsigned startLine, unsigned maxLines,
   487                unsigned* count, unsigned** retLines, uintptr_t** retPCs)
   488 {
   489     unsigned first = jsdscript->lineBase;
   490     unsigned last = first + jsd_GetScriptLineExtent(jsdc, jsdscript) - 1;
   491     bool ok;
   492     jsbytecode **pcs;
   493     unsigned i;
   495     if (last < startLine)
   496         return true;
   498     AutoSafeJSContext cx;
   499     JSAutoCompartment ac(cx, jsdscript->script);
   501     ok = JS_GetLinePCs(cx, jsdscript->script,
   502                        startLine, maxLines,
   503                        count, retLines, &pcs);
   505     if (ok) {
   506         if (retPCs) {
   507             for (i = 0; i < *count; ++i) {
   508                 (*retPCs)[i] = (*pcs)[i];
   509             }
   510         }
   512         JS_free(cx, pcs);
   513     }
   515     return ok;
   516 }
   518 bool
   519 jsd_SetScriptHook(JSDContext* jsdc, JSD_ScriptHookProc hook, void* callerdata)
   520 {
   521     JSD_LOCK();
   522     jsdc->scriptHook = hook;
   523     jsdc->scriptHookData = callerdata;
   524     JSD_UNLOCK();
   525     return true;
   526 }
   528 bool
   529 jsd_GetScriptHook(JSDContext* jsdc, JSD_ScriptHookProc* hook, void** callerdata)
   530 {
   531     JSD_LOCK();
   532     if( hook )
   533         *hook = jsdc->scriptHook;
   534     if( callerdata )
   535         *callerdata = jsdc->scriptHookData;
   536     JSD_UNLOCK();
   537     return true;
   538 }    
   540 bool
   541 jsd_EnableSingleStepInterrupts(JSDContext* jsdc, JSDScript* jsdscript, bool enable)
   542 {
   543     bool rv;
   544     AutoSafeJSContext cx;
   545     JS::RootedScript script(cx, jsdscript->script);
   546     JSAutoCompartment ac(cx, script);
   547     JSD_LOCK();
   548     rv = JS_SetSingleStepMode(cx, script, enable);
   549     JSD_UNLOCK();
   550     return rv;
   551 }
   554 /***************************************************************************/
   556 void
   557 jsd_NewScriptHookProc( 
   558                 JSContext   *cx,
   559                 const char  *filename,      /* URL this script loads from */
   560                 unsigned       lineno,         /* line where this script starts */
   561                 JSScript    *script,
   562                 JSFunction  *fun,                
   563                 void*       callerdata )
   564 {
   565     JSDScript* jsdscript = nullptr;
   566     JSDContext* jsdc = (JSDContext*) callerdata;
   567     JSD_ScriptHookProc      hook;
   568     void*                   hookData;
   570     JSD_ASSERT_VALID_CONTEXT(jsdc);
   572     if( JSD_IS_DANGEROUS_THREAD(jsdc) )
   573         return;
   575     JSD_LOCK_SCRIPTS(jsdc);
   576     jsdscript = _newJSDScript(jsdc, cx, script);
   577     JSD_UNLOCK_SCRIPTS(jsdc);
   578     if( ! jsdscript )
   579         return;
   581 #ifdef JSD_DUMP
   582     JSD_LOCK_SCRIPTS(jsdc);
   583     _dumpJSDScript(jsdc, jsdscript, "***NEW Script: ");
   584     _dumpJSDScriptList( jsdc );
   585     JSD_UNLOCK_SCRIPTS(jsdc);
   586 #endif /* JSD_DUMP */
   588     /* local in case jsdc->scriptHook gets cleared on another thread */
   589     JSD_LOCK();
   590     hook = jsdc->scriptHook;
   591     if( hook )
   592         jsdscript->flags = jsdscript->flags | JSD_SCRIPT_CALL_DESTROY_HOOK_BIT;
   593     hookData = jsdc->scriptHookData;
   594     JSD_UNLOCK();
   596     if( hook )
   597         hook(jsdc, jsdscript, true, hookData);
   598 }
   600 void
   601 jsd_DestroyScriptHookProc( 
   602                 JSFreeOp    *fop,
   603                 JSScript    *script_,
   604                 void*       callerdata )
   605 {
   606     JSDScript* jsdscript = nullptr;
   607     JSDContext* jsdc = (JSDContext*) callerdata;
   608     // NB: We're called during GC, so we can't push a cx. Root directly with
   609     // the runtime.
   610     JS::RootedScript script(jsdc->jsrt, script_);
   611     JSD_ScriptHookProc      hook;
   612     void*                   hookData;
   614     JSD_ASSERT_VALID_CONTEXT(jsdc);
   616     if( JSD_IS_DANGEROUS_THREAD(jsdc) )
   617         return;
   619     JSD_LOCK_SCRIPTS(jsdc);
   620     jsdscript = jsd_FindJSDScript(jsdc, script);
   621     JSD_UNLOCK_SCRIPTS(jsdc);
   623     if( ! jsdscript )
   624         return;
   626 #ifdef JSD_DUMP
   627     JSD_LOCK_SCRIPTS(jsdc);
   628     _dumpJSDScript(jsdc, jsdscript, "***DESTROY Script: ");
   629     JSD_UNLOCK_SCRIPTS(jsdc);
   630 #endif /* JSD_DUMP */
   632     /* local in case hook gets cleared on another thread */
   633     JSD_LOCK();
   634     hook = (jsdscript->flags & JSD_SCRIPT_CALL_DESTROY_HOOK_BIT) ? jsdc->scriptHook
   635                                                                  : nullptr;
   636     hookData = jsdc->scriptHookData;
   637     JSD_UNLOCK();
   639     if( hook )
   640         hook(jsdc, jsdscript, false, hookData);
   642     JSD_LOCK_SCRIPTS(jsdc);
   643     JS_HashTableRemove(jsdc->scriptsTable, (void *)script);
   644     JSD_UNLOCK_SCRIPTS(jsdc);
   646 #ifdef JSD_DUMP
   647     JSD_LOCK_SCRIPTS(jsdc);
   648     _dumpJSDScriptList(jsdc);
   649     JSD_UNLOCK_SCRIPTS(jsdc);
   650 #endif /* JSD_DUMP */
   651 }                
   654 /***************************************************************************/
   656 static JSDExecHook*
   657 _findHook(JSDContext* jsdc, JSDScript* jsdscript, uintptr_t pc)
   658 {
   659     JSDExecHook* jsdhook;
   660     JSCList* list = &jsdscript->hooks;
   662     for( jsdhook = (JSDExecHook*)list->next;
   663          jsdhook != (JSDExecHook*)list;
   664          jsdhook = (JSDExecHook*)jsdhook->links.next )
   665     {
   666         if (jsdhook->pc == pc)
   667             return jsdhook;
   668     }
   669     return nullptr;
   670 }
   672 static bool
   673 _isActiveHook(JSDContext* jsdc, JSScript *script, JSDExecHook* jsdhook)
   674 {
   675     JSDExecHook* current;
   676     JSCList* list;
   677     JSDScript* jsdscript;
   679     JSD_LOCK_SCRIPTS(jsdc);
   680     jsdscript = jsd_FindJSDScript(jsdc, script);
   681     if( ! jsdscript)
   682     {
   683         JSD_UNLOCK_SCRIPTS(jsdc);
   684         return false;
   685     }
   687     list = &jsdscript->hooks;
   689     for( current = (JSDExecHook*)list->next;
   690          current != (JSDExecHook*)list;
   691          current = (JSDExecHook*)current->links.next )
   692     {
   693         if(current == jsdhook)
   694         {
   695             JSD_UNLOCK_SCRIPTS(jsdc);
   696             return true;
   697         }
   698     }
   699     JSD_UNLOCK_SCRIPTS(jsdc);
   700     return false;
   701 }
   704 JSTrapStatus
   705 jsd_TrapHandler(JSContext *cx, JSScript *script_, jsbytecode *pc, jsval *rval,
   706                 jsval closure)
   707 {
   708     JS::RootedScript script(cx, script_);
   709     JSDExecHook* jsdhook = (JSDExecHook*) JSVAL_TO_PRIVATE(closure);
   710     JSD_ExecutionHookProc hook;
   711     void* hookData;
   712     JSDContext*  jsdc;
   714     JSD_LOCK();
   716     if( nullptr == (jsdc = jsd_JSDContextForJSContext(cx)) ||
   717         ! _isActiveHook(jsdc, script, jsdhook) )
   718     {
   719         JSD_UNLOCK();
   720         return JSTRAP_CONTINUE;
   721     }
   723     JSD_ASSERT_VALID_EXEC_HOOK(jsdhook);
   724     MOZ_ASSERT(!jsdhook->pc || jsdhook->pc == (uintptr_t)pc);
   725     MOZ_ASSERT(jsdhook->jsdscript->script == script);
   726     MOZ_ASSERT(jsdhook->jsdscript->jsdc == jsdc);
   728     hook = jsdhook->hook;
   729     hookData = jsdhook->callerdata;
   731     /* do not use jsdhook-> after this point */
   732     JSD_UNLOCK();
   734     if( ! jsdc || ! jsdc->inited )
   735         return JSTRAP_CONTINUE;
   737     if( JSD_IS_DANGEROUS_THREAD(jsdc) )
   738         return JSTRAP_CONTINUE;
   740     return jsd_CallExecutionHook(jsdc, cx, JSD_HOOK_BREAKPOINT,
   741                                  hook, hookData, rval);
   742 }
   746 bool
   747 jsd_SetExecutionHook(JSDContext*           jsdc, 
   748                      JSDScript*            jsdscript,
   749                      uintptr_t             pc,
   750                      JSD_ExecutionHookProc hook,
   751                      void*                 callerdata)
   752 {
   753     JSDExecHook* jsdhook;
   754     bool rv;
   756     JSD_LOCK();
   757     if( ! hook )
   758     {
   759         jsd_ClearExecutionHook(jsdc, jsdscript, pc);
   760         JSD_UNLOCK();
   761         return true;
   762     }
   764     jsdhook = _findHook(jsdc, jsdscript, pc);
   765     if( jsdhook )
   766     {
   767         jsdhook->hook       = hook;
   768         jsdhook->callerdata = callerdata;
   769         JSD_UNLOCK();
   770         return true;
   771     }
   772     /* else... */
   774     jsdhook = (JSDExecHook*)calloc(1, sizeof(JSDExecHook));
   775     if( ! jsdhook ) {
   776         JSD_UNLOCK();
   777         return false;
   778     }
   779     jsdhook->jsdscript  = jsdscript;
   780     jsdhook->pc         = pc;
   781     jsdhook->hook       = hook;
   782     jsdhook->callerdata = callerdata;
   784     {
   785         AutoSafeJSContext cx;
   786         JSAutoCompartment ac(cx, jsdscript->script);
   787         JS::RootedScript script(cx, jsdscript->script);
   788         JS::RootedValue hookValue(cx, PRIVATE_TO_JSVAL(jsdhook));
   789         rv = JS_SetTrap(cx, script, (jsbytecode*)pc, jsd_TrapHandler, hookValue);
   790     }
   792     if ( ! rv ) {
   793         free(jsdhook);
   794         JSD_UNLOCK();
   795         return false;
   796     }
   798     JS_APPEND_LINK(&jsdhook->links, &jsdscript->hooks);
   799     JSD_UNLOCK();
   801     return true;
   802 }
   804 bool
   805 jsd_ClearExecutionHook(JSDContext*           jsdc, 
   806                        JSDScript*            jsdscript,
   807                        uintptr_t             pc)
   808 {
   809     JSDExecHook* jsdhook;
   811     JSD_LOCK();
   813     jsdhook = _findHook(jsdc, jsdscript, pc);
   814     if( ! jsdhook )
   815     {
   816         JSD_UNLOCK();
   817         return false;
   818     }
   820     {
   821         AutoSafeJSContext cx;
   822         JSAutoCompartment ac(cx, jsdscript->script);
   823         JS_ClearTrap(cx, jsdscript->script, 
   824                      (jsbytecode*)pc, nullptr, nullptr);
   825     }
   827     JS_REMOVE_LINK(&jsdhook->links);
   828     free(jsdhook);
   830     JSD_UNLOCK();
   831     return true;
   832 }
   834 bool
   835 jsd_ClearAllExecutionHooksForScript(JSDContext* jsdc, JSDScript* jsdscript)
   836 {
   837     JSDExecHook* jsdhook;
   838     JSCList* list = &jsdscript->hooks;
   839     JSD_LOCK();
   841     while( (JSDExecHook*)list != (jsdhook = (JSDExecHook*)list->next) )
   842     {
   843         JS_REMOVE_LINK(&jsdhook->links);
   844         free(jsdhook);
   845     }
   847     JS_ClearScriptTraps(jsdc->jsrt, jsdscript->script);
   848     JSD_UNLOCK();
   850     return true;
   851 }
   853 bool
   854 jsd_ClearAllExecutionHooks(JSDContext* jsdc)
   855 {
   856     JSDScript* jsdscript;
   857     JSDScript* iterp = nullptr;
   859     JSD_LOCK();
   860     while( nullptr != (jsdscript = jsd_IterateScripts(jsdc, &iterp)) )
   861         jsd_ClearAllExecutionHooksForScript(jsdc, jsdscript);
   862     JSD_UNLOCK();
   863     return true;
   864 }
   866 void
   867 jsd_ScriptCreated(JSDContext* jsdc,
   868                   JSContext   *cx,
   869                   const char  *filename,    /* URL this script loads from */
   870                   unsigned       lineno,       /* line where this script starts */
   871                   JSScript    *script,
   872                   JSFunction  *fun)
   873 {
   874     jsd_NewScriptHookProc(cx, filename, lineno, script, fun, jsdc);
   875 }
   877 void
   878 jsd_ScriptDestroyed(JSDContext* jsdc,
   879                     JSFreeOp    *fop,
   880                     JSScript    *script)
   881 {
   882     jsd_DestroyScriptHookProc(fop, script, jsdc);
   883 }

mercurial