js/jsd/jsd_scpt.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/js/jsd/jsd_scpt.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,883 @@
     1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     1.5 + * vim: set ts=8 sts=4 et sw=4 tw=99:
     1.6 + * This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +/*
    1.11 + * JavaScript Debugging support - Script support
    1.12 + */
    1.13 +
    1.14 +#include "jsd.h"
    1.15 +#include "jsfriendapi.h"
    1.16 +#include "nsCxPusher.h"
    1.17 +
    1.18 +using mozilla::AutoSafeJSContext;
    1.19 +
    1.20 +/* Comment this out to disable (NT specific) dumping as we go */
    1.21 +/*
    1.22 +** #ifdef DEBUG      
    1.23 +** #define JSD_DUMP 1
    1.24 +** #endif            
    1.25 +*/
    1.26 +
    1.27 +#define NOT_SET_YET -1
    1.28 +
    1.29 +/***************************************************************************/
    1.30 +
    1.31 +#ifdef DEBUG
    1.32 +void JSD_ASSERT_VALID_SCRIPT(JSDScript* jsdscript)
    1.33 +{
    1.34 +    MOZ_ASSERT(jsdscript);
    1.35 +    MOZ_ASSERT(jsdscript->script);
    1.36 +}
    1.37 +void JSD_ASSERT_VALID_EXEC_HOOK(JSDExecHook* jsdhook)
    1.38 +{
    1.39 +    MOZ_ASSERT(jsdhook);
    1.40 +    MOZ_ASSERT(jsdhook->hook);
    1.41 +}
    1.42 +#endif
    1.43 +
    1.44 +static JSDScript*
    1.45 +_newJSDScript(JSDContext*  jsdc,
    1.46 +              JSContext    *cx,
    1.47 +              JSScript     *script_)
    1.48 +{
    1.49 +    JS::RootedScript script(cx, script_);
    1.50 +    if ( JS_GetScriptIsSelfHosted(script) )
    1.51 +        return nullptr;
    1.52 +
    1.53 +    JSDScript*  jsdscript;
    1.54 +    unsigned     lineno;
    1.55 +    const char* raw_filename;
    1.56 +
    1.57 +    MOZ_ASSERT(JSD_SCRIPTS_LOCKED(jsdc));
    1.58 +
    1.59 +    /* these are inlined javascript: urls and we can't handle them now */
    1.60 +    lineno = (unsigned) JS_GetScriptBaseLineNumber(cx, script);
    1.61 +    if( lineno == 0 )
    1.62 +        return nullptr;
    1.63 +
    1.64 +    jsdscript = (JSDScript*) calloc(1, sizeof(JSDScript));
    1.65 +    if( ! jsdscript )
    1.66 +        return nullptr;
    1.67 +
    1.68 +    raw_filename = JS_GetScriptFilename(script);
    1.69 +
    1.70 +    JS_HashTableAdd(jsdc->scriptsTable, (void *)script, (void *)jsdscript);
    1.71 +    JS_APPEND_LINK(&jsdscript->links, &jsdc->scripts);
    1.72 +    jsdscript->jsdc         = jsdc;
    1.73 +    jsdscript->script       = script;  
    1.74 +    jsdscript->lineBase     = lineno;
    1.75 +    jsdscript->lineExtent   = (unsigned)NOT_SET_YET;
    1.76 +    jsdscript->data         = nullptr;
    1.77 +    jsdscript->url          = (char*) jsd_BuildNormalizedURL(raw_filename);
    1.78 +
    1.79 +    JS_INIT_CLIST(&jsdscript->hooks);
    1.80 +    
    1.81 +    return jsdscript;
    1.82 +}           
    1.83 +
    1.84 +static void 
    1.85 +_destroyJSDScript(JSDContext*  jsdc,
    1.86 +                  JSDScript*   jsdscript)
    1.87 +{
    1.88 +    MOZ_ASSERT(JSD_SCRIPTS_LOCKED(jsdc));
    1.89 +
    1.90 +    /* destroy all hooks */
    1.91 +    jsd_ClearAllExecutionHooksForScript(jsdc, jsdscript);
    1.92 +
    1.93 +    JS_REMOVE_LINK(&jsdscript->links);
    1.94 +    if(jsdscript->url)
    1.95 +        free(jsdscript->url);
    1.96 +
    1.97 +    if (jsdscript->profileData)
    1.98 +        free(jsdscript->profileData);
    1.99 +    
   1.100 +    free(jsdscript);
   1.101 +}
   1.102 +
   1.103 +/***************************************************************************/
   1.104 +
   1.105 +#ifdef JSD_DUMP
   1.106 +#ifndef XP_WIN
   1.107 +void
   1.108 +OutputDebugString (char *buf)
   1.109 +{
   1.110 +    fprintf (stderr, "%s", buf);
   1.111 +}
   1.112 +#endif
   1.113 +
   1.114 +static void
   1.115 +_dumpJSDScript(JSDContext* jsdc, JSDScript* jsdscript, const char* leadingtext)
   1.116 +{
   1.117 +    const char* name;
   1.118 +    JSString* fun;
   1.119 +    unsigned base;
   1.120 +    unsigned extent;
   1.121 +    char Buf[256];
   1.122 +    size_t n;
   1.123 +
   1.124 +    name   = jsd_GetScriptFilename(jsdc, jsdscript);
   1.125 +    fun    = jsd_GetScriptFunctionId(jsdc, jsdscript);
   1.126 +    base   = jsd_GetScriptBaseLineNumber(jsdc, jsdscript);
   1.127 +    extent = jsd_GetScriptLineExtent(jsdc, jsdscript);
   1.128 +    n = size_t(snprintf(Buf, sizeof(Buf), "%sscript=%08X, %s, ",
   1.129 +                        leadingtext, (unsigned) jsdscript->script,
   1.130 +                        name ? name : "no URL"));
   1.131 +    if (n + 1 < sizeof(Buf)) {
   1.132 +        if (fun) {
   1.133 +            n += size_t(snprintf(Buf + n, sizeof(Buf) - n, "%s", "no fun"));
   1.134 +        } else {
   1.135 +            n += JS_PutEscapedFlatString(Buf + n, sizeof(Buf) - n,
   1.136 +                                         MOZ_ASSERT_STRING_IS_FLAT(fun), 0);
   1.137 +            Buf[sizeof(Buf) - 1] = '\0';
   1.138 +        }
   1.139 +        if (n + 1 < sizeof(Buf))
   1.140 +            snprintf(Buf + n, sizeof(Buf) - n, ", %d-%d\n", base, base + extent - 1);
   1.141 +    }
   1.142 +    OutputDebugString( Buf );
   1.143 +}
   1.144 +
   1.145 +static void
   1.146 +_dumpJSDScriptList( JSDContext* jsdc )
   1.147 +{
   1.148 +    JSDScript* iterp = nullptr;
   1.149 +    JSDScript* jsdscript = nullptr;
   1.150 +    
   1.151 +    OutputDebugString( "*** JSDScriptDump\n" );
   1.152 +    while( nullptr != (jsdscript = jsd_IterateScripts(jsdc, &iterp)) )
   1.153 +        _dumpJSDScript( jsdc, jsdscript, "  script: " );
   1.154 +}
   1.155 +#endif /* JSD_DUMP */
   1.156 +
   1.157 +/***************************************************************************/
   1.158 +static JSHashNumber
   1.159 +jsd_hash_script(const void *key)
   1.160 +{
   1.161 +    return ((JSHashNumber)(ptrdiff_t) key) >> 2; /* help lame MSVC1.5 on Win16 */
   1.162 +}
   1.163 +
   1.164 +static void *
   1.165 +jsd_alloc_script_table(void *priv, size_t size)
   1.166 +{
   1.167 +    return malloc(size);
   1.168 +}
   1.169 +
   1.170 +static void
   1.171 +jsd_free_script_table(void *priv, void *item, size_t size)
   1.172 +{
   1.173 +    free(item);
   1.174 +}
   1.175 +
   1.176 +static JSHashEntry *
   1.177 +jsd_alloc_script_entry(void *priv, const void *item)
   1.178 +{
   1.179 +    return (JSHashEntry*) malloc(sizeof(JSHashEntry));
   1.180 +}
   1.181 +
   1.182 +static void
   1.183 +jsd_free_script_entry(void *priv, JSHashEntry *he, unsigned flag)
   1.184 +{
   1.185 +    if (flag == HT_FREE_ENTRY)
   1.186 +    {
   1.187 +        _destroyJSDScript((JSDContext*) priv, (JSDScript*) he->value);
   1.188 +        free(he);
   1.189 +    }
   1.190 +}
   1.191 +
   1.192 +static const JSHashAllocOps script_alloc_ops = {
   1.193 +    jsd_alloc_script_table, jsd_free_script_table,
   1.194 +    jsd_alloc_script_entry, jsd_free_script_entry
   1.195 +};
   1.196 +
   1.197 +#ifndef JSD_SCRIPT_HASH_SIZE
   1.198 +#define JSD_SCRIPT_HASH_SIZE 1024
   1.199 +#endif
   1.200 +
   1.201 +bool
   1.202 +jsd_InitScriptManager(JSDContext* jsdc)
   1.203 +{
   1.204 +    JS_INIT_CLIST(&jsdc->scripts);
   1.205 +    jsdc->scriptsTable = JS_NewHashTable(JSD_SCRIPT_HASH_SIZE, jsd_hash_script,
   1.206 +                                         JS_CompareValues, JS_CompareValues,
   1.207 +                                         &script_alloc_ops, (void*) jsdc);
   1.208 +    return !!jsdc->scriptsTable;
   1.209 +}
   1.210 +
   1.211 +void
   1.212 +jsd_DestroyScriptManager(JSDContext* jsdc)
   1.213 +{
   1.214 +    JSD_LOCK_SCRIPTS(jsdc);
   1.215 +    if (jsdc->scriptsTable)
   1.216 +        JS_HashTableDestroy(jsdc->scriptsTable);
   1.217 +    JSD_UNLOCK_SCRIPTS(jsdc);
   1.218 +}
   1.219 +
   1.220 +JSDScript*
   1.221 +jsd_FindJSDScript( JSDContext*  jsdc,
   1.222 +                   JSScript     *script )
   1.223 +{
   1.224 +    MOZ_ASSERT(JSD_SCRIPTS_LOCKED(jsdc));
   1.225 +    return (JSDScript*) JS_HashTableLookup(jsdc->scriptsTable, (void *)script);
   1.226 +}
   1.227 +
   1.228 +JSDScript *
   1.229 +jsd_FindOrCreateJSDScript(JSDContext    *jsdc,
   1.230 +                          JSContext     *cx,
   1.231 +                          JSScript      *script_,
   1.232 +                          JSAbstractFramePtr frame)
   1.233 +{
   1.234 +    JS::RootedScript script(cx, script_);
   1.235 +    JSDScript *jsdscript;
   1.236 +    MOZ_ASSERT(JSD_SCRIPTS_LOCKED(jsdc));
   1.237 +
   1.238 +    jsdscript = jsd_FindJSDScript(jsdc, script);
   1.239 +    if (jsdscript)
   1.240 +        return jsdscript;
   1.241 +
   1.242 +    /* Fallback for unknown scripts: create a new script. */
   1.243 +    if (!frame) {
   1.244 +        JSBrokenFrameIterator iter(cx);
   1.245 +        if (!iter.done())
   1.246 +            frame = iter.abstractFramePtr();
   1.247 +    }
   1.248 +    if (frame)
   1.249 +        jsdscript = _newJSDScript(jsdc, cx, script);
   1.250 +
   1.251 +    return jsdscript;
   1.252 +}
   1.253 +
   1.254 +JSDProfileData*
   1.255 +jsd_GetScriptProfileData(JSDContext* jsdc, JSDScript *script)
   1.256 +{
   1.257 +    if (!script->profileData)
   1.258 +        script->profileData = (JSDProfileData*)calloc(1, sizeof(JSDProfileData));
   1.259 +
   1.260 +    return script->profileData;
   1.261 +}
   1.262 +
   1.263 +uint32_t
   1.264 +jsd_GetScriptFlags(JSDContext *jsdc, JSDScript *script)
   1.265 +{
   1.266 +    return script->flags;
   1.267 +}
   1.268 +
   1.269 +void
   1.270 +jsd_SetScriptFlags(JSDContext *jsdc, JSDScript *script, uint32_t flags)
   1.271 +{
   1.272 +    script->flags = flags;
   1.273 +}
   1.274 +
   1.275 +unsigned
   1.276 +jsd_GetScriptCallCount(JSDContext* jsdc, JSDScript *script)
   1.277 +{
   1.278 +    if (script->profileData)
   1.279 +        return script->profileData->callCount;
   1.280 +
   1.281 +    return 0;
   1.282 +}
   1.283 +
   1.284 +unsigned
   1.285 +jsd_GetScriptMaxRecurseDepth(JSDContext* jsdc, JSDScript *script)
   1.286 +{
   1.287 +    if (script->profileData)
   1.288 +        return script->profileData->maxRecurseDepth;
   1.289 +
   1.290 +    return 0;
   1.291 +}
   1.292 +
   1.293 +double
   1.294 +jsd_GetScriptMinExecutionTime(JSDContext* jsdc, JSDScript *script)
   1.295 +{
   1.296 +    if (script->profileData)
   1.297 +        return script->profileData->minExecutionTime;
   1.298 +
   1.299 +    return 0.0;
   1.300 +}
   1.301 +
   1.302 +double
   1.303 +jsd_GetScriptMaxExecutionTime(JSDContext* jsdc, JSDScript *script)
   1.304 +{
   1.305 +    if (script->profileData)
   1.306 +        return script->profileData->maxExecutionTime;
   1.307 +
   1.308 +    return 0.0;
   1.309 +}
   1.310 +
   1.311 +double
   1.312 +jsd_GetScriptTotalExecutionTime(JSDContext* jsdc, JSDScript *script)
   1.313 +{
   1.314 +    if (script->profileData)
   1.315 +        return script->profileData->totalExecutionTime;
   1.316 +
   1.317 +    return 0.0;
   1.318 +}
   1.319 +
   1.320 +double
   1.321 +jsd_GetScriptMinOwnExecutionTime(JSDContext* jsdc, JSDScript *script)
   1.322 +{
   1.323 +    if (script->profileData)
   1.324 +        return script->profileData->minOwnExecutionTime;
   1.325 +
   1.326 +    return 0.0;
   1.327 +}
   1.328 +
   1.329 +double
   1.330 +jsd_GetScriptMaxOwnExecutionTime(JSDContext* jsdc, JSDScript *script)
   1.331 +{
   1.332 +    if (script->profileData)
   1.333 +        return script->profileData->maxOwnExecutionTime;
   1.334 +
   1.335 +    return 0.0;
   1.336 +}
   1.337 +
   1.338 +double
   1.339 +jsd_GetScriptTotalOwnExecutionTime(JSDContext* jsdc, JSDScript *script)
   1.340 +{
   1.341 +    if (script->profileData)
   1.342 +        return script->profileData->totalOwnExecutionTime;
   1.343 +
   1.344 +    return 0.0;
   1.345 +}
   1.346 +
   1.347 +void
   1.348 +jsd_ClearScriptProfileData(JSDContext* jsdc, JSDScript *script)
   1.349 +{
   1.350 +    if (script->profileData)
   1.351 +    {
   1.352 +        free(script->profileData);
   1.353 +        script->profileData = nullptr;
   1.354 +    }
   1.355 +}    
   1.356 +
   1.357 +JSScript *
   1.358 +jsd_GetJSScript (JSDContext *jsdc, JSDScript *script)
   1.359 +{
   1.360 +    return script->script;
   1.361 +}
   1.362 +
   1.363 +JSFunction *
   1.364 +jsd_GetJSFunction (JSDContext *jsdc, JSDScript *script)
   1.365 +{
   1.366 +    AutoSafeJSContext cx;
   1.367 +    return JS_GetScriptFunction(cx, script->script);
   1.368 +}
   1.369 +
   1.370 +JSDScript*
   1.371 +jsd_IterateScripts(JSDContext* jsdc, JSDScript **iterp)
   1.372 +{
   1.373 +    JSDScript *jsdscript = *iterp;
   1.374 +    
   1.375 +    MOZ_ASSERT(JSD_SCRIPTS_LOCKED(jsdc));
   1.376 +
   1.377 +    if( !jsdscript )
   1.378 +        jsdscript = (JSDScript *)jsdc->scripts.next;
   1.379 +    if( jsdscript == (JSDScript *)&jsdc->scripts )
   1.380 +        return nullptr;
   1.381 +    *iterp = (JSDScript*) jsdscript->links.next;
   1.382 +    return jsdscript;
   1.383 +}
   1.384 +
   1.385 +void *
   1.386 +jsd_SetScriptPrivate(JSDScript *jsdscript, void *data)
   1.387 +{
   1.388 +    void *rval = jsdscript->data;
   1.389 +    jsdscript->data = data;
   1.390 +    return rval;
   1.391 +}
   1.392 +
   1.393 +void *
   1.394 +jsd_GetScriptPrivate(JSDScript *jsdscript)
   1.395 +{
   1.396 +    return jsdscript->data;
   1.397 +}
   1.398 +
   1.399 +bool
   1.400 +jsd_IsActiveScript(JSDContext* jsdc, JSDScript *jsdscript)
   1.401 +{
   1.402 +    JSDScript *current;
   1.403 +
   1.404 +    MOZ_ASSERT(JSD_SCRIPTS_LOCKED(jsdc));
   1.405 +
   1.406 +    for( current = (JSDScript *)jsdc->scripts.next;
   1.407 +         current != (JSDScript *)&jsdc->scripts;
   1.408 +         current = (JSDScript *)current->links.next )
   1.409 +    {
   1.410 +        if(jsdscript == current)
   1.411 +            return true;
   1.412 +    }
   1.413 +    return false;
   1.414 +}        
   1.415 +
   1.416 +const char*
   1.417 +jsd_GetScriptFilename(JSDContext* jsdc, JSDScript *jsdscript)
   1.418 +{
   1.419 +    return jsdscript->url;
   1.420 +}
   1.421 +
   1.422 +JSString*
   1.423 +jsd_GetScriptFunctionId(JSDContext* jsdc, JSDScript *jsdscript)
   1.424 +{
   1.425 +    JSString* str;
   1.426 +    JSFunction *fun = jsd_GetJSFunction(jsdc, jsdscript);
   1.427 +
   1.428 +    if( ! fun )
   1.429 +        return nullptr;
   1.430 +    str = JS_GetFunctionId(fun);
   1.431 +
   1.432 +    /* For compatibility we return "anonymous", not an empty string here. */
   1.433 +    return str ? str : JS_GetAnonymousString(jsdc->jsrt);
   1.434 +}
   1.435 +
   1.436 +unsigned
   1.437 +jsd_GetScriptBaseLineNumber(JSDContext* jsdc, JSDScript *jsdscript)
   1.438 +{
   1.439 +    return jsdscript->lineBase;
   1.440 +}
   1.441 +
   1.442 +unsigned
   1.443 +jsd_GetScriptLineExtent(JSDContext* jsdc, JSDScript *jsdscript)
   1.444 +{
   1.445 +    AutoSafeJSContext cx;
   1.446 +    JSAutoCompartment ac(cx, jsdc->glob); // Just in case.
   1.447 +    if( NOT_SET_YET == (int)jsdscript->lineExtent )
   1.448 +        jsdscript->lineExtent = JS_GetScriptLineExtent(cx, jsdscript->script);
   1.449 +    return jsdscript->lineExtent;
   1.450 +}
   1.451 +
   1.452 +uintptr_t
   1.453 +jsd_GetClosestPC(JSDContext* jsdc, JSDScript* jsdscript, unsigned line)
   1.454 +{
   1.455 +    uintptr_t pc;
   1.456 +
   1.457 +    if( !jsdscript )
   1.458 +        return 0;
   1.459 +
   1.460 +    AutoSafeJSContext cx;
   1.461 +    JSAutoCompartment ac(cx, jsdscript->script);
   1.462 +    pc = (uintptr_t) JS_LineNumberToPC(cx, jsdscript->script, line );
   1.463 +    return pc;
   1.464 +}
   1.465 +
   1.466 +unsigned
   1.467 +jsd_GetClosestLine(JSDContext* jsdc, JSDScript* jsdscript, uintptr_t pc)
   1.468 +{
   1.469 +    unsigned first = jsdscript->lineBase;
   1.470 +    unsigned last = first + jsd_GetScriptLineExtent(jsdc, jsdscript) - 1;
   1.471 +    unsigned line = 0;
   1.472 +
   1.473 +    if (pc) {
   1.474 +        AutoSafeJSContext cx;
   1.475 +        JSAutoCompartment ac(cx, jsdscript->script);
   1.476 +        line = JS_PCToLineNumber(cx, jsdscript->script, (jsbytecode*)pc);
   1.477 +    }
   1.478 +
   1.479 +    if( line < first )
   1.480 +        return first;
   1.481 +    if( line > last )
   1.482 +        return last;
   1.483 +
   1.484 +    return line;    
   1.485 +}
   1.486 +
   1.487 +bool
   1.488 +jsd_GetLinePCs(JSDContext* jsdc, JSDScript* jsdscript,
   1.489 +               unsigned startLine, unsigned maxLines,
   1.490 +               unsigned* count, unsigned** retLines, uintptr_t** retPCs)
   1.491 +{
   1.492 +    unsigned first = jsdscript->lineBase;
   1.493 +    unsigned last = first + jsd_GetScriptLineExtent(jsdc, jsdscript) - 1;
   1.494 +    bool ok;
   1.495 +    jsbytecode **pcs;
   1.496 +    unsigned i;
   1.497 +
   1.498 +    if (last < startLine)
   1.499 +        return true;
   1.500 +
   1.501 +    AutoSafeJSContext cx;
   1.502 +    JSAutoCompartment ac(cx, jsdscript->script);
   1.503 +
   1.504 +    ok = JS_GetLinePCs(cx, jsdscript->script,
   1.505 +                       startLine, maxLines,
   1.506 +                       count, retLines, &pcs);
   1.507 +
   1.508 +    if (ok) {
   1.509 +        if (retPCs) {
   1.510 +            for (i = 0; i < *count; ++i) {
   1.511 +                (*retPCs)[i] = (*pcs)[i];
   1.512 +            }
   1.513 +        }
   1.514 +
   1.515 +        JS_free(cx, pcs);
   1.516 +    }
   1.517 +
   1.518 +    return ok;
   1.519 +}
   1.520 +
   1.521 +bool
   1.522 +jsd_SetScriptHook(JSDContext* jsdc, JSD_ScriptHookProc hook, void* callerdata)
   1.523 +{
   1.524 +    JSD_LOCK();
   1.525 +    jsdc->scriptHook = hook;
   1.526 +    jsdc->scriptHookData = callerdata;
   1.527 +    JSD_UNLOCK();
   1.528 +    return true;
   1.529 +}
   1.530 +
   1.531 +bool
   1.532 +jsd_GetScriptHook(JSDContext* jsdc, JSD_ScriptHookProc* hook, void** callerdata)
   1.533 +{
   1.534 +    JSD_LOCK();
   1.535 +    if( hook )
   1.536 +        *hook = jsdc->scriptHook;
   1.537 +    if( callerdata )
   1.538 +        *callerdata = jsdc->scriptHookData;
   1.539 +    JSD_UNLOCK();
   1.540 +    return true;
   1.541 +}    
   1.542 +
   1.543 +bool
   1.544 +jsd_EnableSingleStepInterrupts(JSDContext* jsdc, JSDScript* jsdscript, bool enable)
   1.545 +{
   1.546 +    bool rv;
   1.547 +    AutoSafeJSContext cx;
   1.548 +    JS::RootedScript script(cx, jsdscript->script);
   1.549 +    JSAutoCompartment ac(cx, script);
   1.550 +    JSD_LOCK();
   1.551 +    rv = JS_SetSingleStepMode(cx, script, enable);
   1.552 +    JSD_UNLOCK();
   1.553 +    return rv;
   1.554 +}
   1.555 +
   1.556 +
   1.557 +/***************************************************************************/
   1.558 +
   1.559 +void
   1.560 +jsd_NewScriptHookProc( 
   1.561 +                JSContext   *cx,
   1.562 +                const char  *filename,      /* URL this script loads from */
   1.563 +                unsigned       lineno,         /* line where this script starts */
   1.564 +                JSScript    *script,
   1.565 +                JSFunction  *fun,                
   1.566 +                void*       callerdata )
   1.567 +{
   1.568 +    JSDScript* jsdscript = nullptr;
   1.569 +    JSDContext* jsdc = (JSDContext*) callerdata;
   1.570 +    JSD_ScriptHookProc      hook;
   1.571 +    void*                   hookData;
   1.572 +    
   1.573 +    JSD_ASSERT_VALID_CONTEXT(jsdc);
   1.574 +
   1.575 +    if( JSD_IS_DANGEROUS_THREAD(jsdc) )
   1.576 +        return;
   1.577 +    
   1.578 +    JSD_LOCK_SCRIPTS(jsdc);
   1.579 +    jsdscript = _newJSDScript(jsdc, cx, script);
   1.580 +    JSD_UNLOCK_SCRIPTS(jsdc);
   1.581 +    if( ! jsdscript )
   1.582 +        return;
   1.583 +
   1.584 +#ifdef JSD_DUMP
   1.585 +    JSD_LOCK_SCRIPTS(jsdc);
   1.586 +    _dumpJSDScript(jsdc, jsdscript, "***NEW Script: ");
   1.587 +    _dumpJSDScriptList( jsdc );
   1.588 +    JSD_UNLOCK_SCRIPTS(jsdc);
   1.589 +#endif /* JSD_DUMP */
   1.590 +
   1.591 +    /* local in case jsdc->scriptHook gets cleared on another thread */
   1.592 +    JSD_LOCK();
   1.593 +    hook = jsdc->scriptHook;
   1.594 +    if( hook )
   1.595 +        jsdscript->flags = jsdscript->flags | JSD_SCRIPT_CALL_DESTROY_HOOK_BIT;
   1.596 +    hookData = jsdc->scriptHookData;
   1.597 +    JSD_UNLOCK();
   1.598 +
   1.599 +    if( hook )
   1.600 +        hook(jsdc, jsdscript, true, hookData);
   1.601 +}
   1.602 +
   1.603 +void
   1.604 +jsd_DestroyScriptHookProc( 
   1.605 +                JSFreeOp    *fop,
   1.606 +                JSScript    *script_,
   1.607 +                void*       callerdata )
   1.608 +{
   1.609 +    JSDScript* jsdscript = nullptr;
   1.610 +    JSDContext* jsdc = (JSDContext*) callerdata;
   1.611 +    // NB: We're called during GC, so we can't push a cx. Root directly with
   1.612 +    // the runtime.
   1.613 +    JS::RootedScript script(jsdc->jsrt, script_);
   1.614 +    JSD_ScriptHookProc      hook;
   1.615 +    void*                   hookData;
   1.616 +
   1.617 +    JSD_ASSERT_VALID_CONTEXT(jsdc);
   1.618 +
   1.619 +    if( JSD_IS_DANGEROUS_THREAD(jsdc) )
   1.620 +        return;
   1.621 +
   1.622 +    JSD_LOCK_SCRIPTS(jsdc);
   1.623 +    jsdscript = jsd_FindJSDScript(jsdc, script);
   1.624 +    JSD_UNLOCK_SCRIPTS(jsdc);
   1.625 +
   1.626 +    if( ! jsdscript )
   1.627 +        return;
   1.628 +
   1.629 +#ifdef JSD_DUMP
   1.630 +    JSD_LOCK_SCRIPTS(jsdc);
   1.631 +    _dumpJSDScript(jsdc, jsdscript, "***DESTROY Script: ");
   1.632 +    JSD_UNLOCK_SCRIPTS(jsdc);
   1.633 +#endif /* JSD_DUMP */
   1.634 +
   1.635 +    /* local in case hook gets cleared on another thread */
   1.636 +    JSD_LOCK();
   1.637 +    hook = (jsdscript->flags & JSD_SCRIPT_CALL_DESTROY_HOOK_BIT) ? jsdc->scriptHook
   1.638 +                                                                 : nullptr;
   1.639 +    hookData = jsdc->scriptHookData;
   1.640 +    JSD_UNLOCK();
   1.641 +
   1.642 +    if( hook )
   1.643 +        hook(jsdc, jsdscript, false, hookData);
   1.644 +
   1.645 +    JSD_LOCK_SCRIPTS(jsdc);
   1.646 +    JS_HashTableRemove(jsdc->scriptsTable, (void *)script);
   1.647 +    JSD_UNLOCK_SCRIPTS(jsdc);
   1.648 +
   1.649 +#ifdef JSD_DUMP
   1.650 +    JSD_LOCK_SCRIPTS(jsdc);
   1.651 +    _dumpJSDScriptList(jsdc);
   1.652 +    JSD_UNLOCK_SCRIPTS(jsdc);
   1.653 +#endif /* JSD_DUMP */
   1.654 +}                
   1.655 +
   1.656 +
   1.657 +/***************************************************************************/
   1.658 +
   1.659 +static JSDExecHook*
   1.660 +_findHook(JSDContext* jsdc, JSDScript* jsdscript, uintptr_t pc)
   1.661 +{
   1.662 +    JSDExecHook* jsdhook;
   1.663 +    JSCList* list = &jsdscript->hooks;
   1.664 +
   1.665 +    for( jsdhook = (JSDExecHook*)list->next;
   1.666 +         jsdhook != (JSDExecHook*)list;
   1.667 +         jsdhook = (JSDExecHook*)jsdhook->links.next )
   1.668 +    {
   1.669 +        if (jsdhook->pc == pc)
   1.670 +            return jsdhook;
   1.671 +    }
   1.672 +    return nullptr;
   1.673 +}
   1.674 +
   1.675 +static bool
   1.676 +_isActiveHook(JSDContext* jsdc, JSScript *script, JSDExecHook* jsdhook)
   1.677 +{
   1.678 +    JSDExecHook* current;
   1.679 +    JSCList* list;
   1.680 +    JSDScript* jsdscript;
   1.681 +
   1.682 +    JSD_LOCK_SCRIPTS(jsdc);
   1.683 +    jsdscript = jsd_FindJSDScript(jsdc, script);
   1.684 +    if( ! jsdscript)
   1.685 +    {
   1.686 +        JSD_UNLOCK_SCRIPTS(jsdc);
   1.687 +        return false;
   1.688 +    }
   1.689 +
   1.690 +    list = &jsdscript->hooks;
   1.691 +
   1.692 +    for( current = (JSDExecHook*)list->next;
   1.693 +         current != (JSDExecHook*)list;
   1.694 +         current = (JSDExecHook*)current->links.next )
   1.695 +    {
   1.696 +        if(current == jsdhook)
   1.697 +        {
   1.698 +            JSD_UNLOCK_SCRIPTS(jsdc);
   1.699 +            return true;
   1.700 +        }
   1.701 +    }
   1.702 +    JSD_UNLOCK_SCRIPTS(jsdc);
   1.703 +    return false;
   1.704 +}
   1.705 +
   1.706 +
   1.707 +JSTrapStatus
   1.708 +jsd_TrapHandler(JSContext *cx, JSScript *script_, jsbytecode *pc, jsval *rval,
   1.709 +                jsval closure)
   1.710 +{
   1.711 +    JS::RootedScript script(cx, script_);
   1.712 +    JSDExecHook* jsdhook = (JSDExecHook*) JSVAL_TO_PRIVATE(closure);
   1.713 +    JSD_ExecutionHookProc hook;
   1.714 +    void* hookData;
   1.715 +    JSDContext*  jsdc;
   1.716 +
   1.717 +    JSD_LOCK();
   1.718 +
   1.719 +    if( nullptr == (jsdc = jsd_JSDContextForJSContext(cx)) ||
   1.720 +        ! _isActiveHook(jsdc, script, jsdhook) )
   1.721 +    {
   1.722 +        JSD_UNLOCK();
   1.723 +        return JSTRAP_CONTINUE;
   1.724 +    }
   1.725 +
   1.726 +    JSD_ASSERT_VALID_EXEC_HOOK(jsdhook);
   1.727 +    MOZ_ASSERT(!jsdhook->pc || jsdhook->pc == (uintptr_t)pc);
   1.728 +    MOZ_ASSERT(jsdhook->jsdscript->script == script);
   1.729 +    MOZ_ASSERT(jsdhook->jsdscript->jsdc == jsdc);
   1.730 +
   1.731 +    hook = jsdhook->hook;
   1.732 +    hookData = jsdhook->callerdata;
   1.733 +
   1.734 +    /* do not use jsdhook-> after this point */
   1.735 +    JSD_UNLOCK();
   1.736 +
   1.737 +    if( ! jsdc || ! jsdc->inited )
   1.738 +        return JSTRAP_CONTINUE;
   1.739 +
   1.740 +    if( JSD_IS_DANGEROUS_THREAD(jsdc) )
   1.741 +        return JSTRAP_CONTINUE;
   1.742 +
   1.743 +    return jsd_CallExecutionHook(jsdc, cx, JSD_HOOK_BREAKPOINT,
   1.744 +                                 hook, hookData, rval);
   1.745 +}
   1.746 +
   1.747 +
   1.748 +
   1.749 +bool
   1.750 +jsd_SetExecutionHook(JSDContext*           jsdc, 
   1.751 +                     JSDScript*            jsdscript,
   1.752 +                     uintptr_t             pc,
   1.753 +                     JSD_ExecutionHookProc hook,
   1.754 +                     void*                 callerdata)
   1.755 +{
   1.756 +    JSDExecHook* jsdhook;
   1.757 +    bool rv;
   1.758 +
   1.759 +    JSD_LOCK();
   1.760 +    if( ! hook )
   1.761 +    {
   1.762 +        jsd_ClearExecutionHook(jsdc, jsdscript, pc);
   1.763 +        JSD_UNLOCK();
   1.764 +        return true;
   1.765 +    }
   1.766 +
   1.767 +    jsdhook = _findHook(jsdc, jsdscript, pc);
   1.768 +    if( jsdhook )
   1.769 +    {
   1.770 +        jsdhook->hook       = hook;
   1.771 +        jsdhook->callerdata = callerdata;
   1.772 +        JSD_UNLOCK();
   1.773 +        return true;
   1.774 +    }
   1.775 +    /* else... */
   1.776 +
   1.777 +    jsdhook = (JSDExecHook*)calloc(1, sizeof(JSDExecHook));
   1.778 +    if( ! jsdhook ) {
   1.779 +        JSD_UNLOCK();
   1.780 +        return false;
   1.781 +    }
   1.782 +    jsdhook->jsdscript  = jsdscript;
   1.783 +    jsdhook->pc         = pc;
   1.784 +    jsdhook->hook       = hook;
   1.785 +    jsdhook->callerdata = callerdata;
   1.786 +
   1.787 +    {
   1.788 +        AutoSafeJSContext cx;
   1.789 +        JSAutoCompartment ac(cx, jsdscript->script);
   1.790 +        JS::RootedScript script(cx, jsdscript->script);
   1.791 +        JS::RootedValue hookValue(cx, PRIVATE_TO_JSVAL(jsdhook));
   1.792 +        rv = JS_SetTrap(cx, script, (jsbytecode*)pc, jsd_TrapHandler, hookValue);
   1.793 +    }
   1.794 +
   1.795 +    if ( ! rv ) {
   1.796 +        free(jsdhook);
   1.797 +        JSD_UNLOCK();
   1.798 +        return false;
   1.799 +    }
   1.800 +
   1.801 +    JS_APPEND_LINK(&jsdhook->links, &jsdscript->hooks);
   1.802 +    JSD_UNLOCK();
   1.803 +
   1.804 +    return true;
   1.805 +}
   1.806 +
   1.807 +bool
   1.808 +jsd_ClearExecutionHook(JSDContext*           jsdc, 
   1.809 +                       JSDScript*            jsdscript,
   1.810 +                       uintptr_t             pc)
   1.811 +{
   1.812 +    JSDExecHook* jsdhook;
   1.813 +
   1.814 +    JSD_LOCK();
   1.815 +
   1.816 +    jsdhook = _findHook(jsdc, jsdscript, pc);
   1.817 +    if( ! jsdhook )
   1.818 +    {
   1.819 +        JSD_UNLOCK();
   1.820 +        return false;
   1.821 +    }
   1.822 +
   1.823 +    {
   1.824 +        AutoSafeJSContext cx;
   1.825 +        JSAutoCompartment ac(cx, jsdscript->script);
   1.826 +        JS_ClearTrap(cx, jsdscript->script, 
   1.827 +                     (jsbytecode*)pc, nullptr, nullptr);
   1.828 +    }
   1.829 +
   1.830 +    JS_REMOVE_LINK(&jsdhook->links);
   1.831 +    free(jsdhook);
   1.832 +
   1.833 +    JSD_UNLOCK();
   1.834 +    return true;
   1.835 +}
   1.836 +
   1.837 +bool
   1.838 +jsd_ClearAllExecutionHooksForScript(JSDContext* jsdc, JSDScript* jsdscript)
   1.839 +{
   1.840 +    JSDExecHook* jsdhook;
   1.841 +    JSCList* list = &jsdscript->hooks;
   1.842 +    JSD_LOCK();
   1.843 +
   1.844 +    while( (JSDExecHook*)list != (jsdhook = (JSDExecHook*)list->next) )
   1.845 +    {
   1.846 +        JS_REMOVE_LINK(&jsdhook->links);
   1.847 +        free(jsdhook);
   1.848 +    }
   1.849 +
   1.850 +    JS_ClearScriptTraps(jsdc->jsrt, jsdscript->script);
   1.851 +    JSD_UNLOCK();
   1.852 +
   1.853 +    return true;
   1.854 +}
   1.855 +
   1.856 +bool
   1.857 +jsd_ClearAllExecutionHooks(JSDContext* jsdc)
   1.858 +{
   1.859 +    JSDScript* jsdscript;
   1.860 +    JSDScript* iterp = nullptr;
   1.861 +
   1.862 +    JSD_LOCK();
   1.863 +    while( nullptr != (jsdscript = jsd_IterateScripts(jsdc, &iterp)) )
   1.864 +        jsd_ClearAllExecutionHooksForScript(jsdc, jsdscript);
   1.865 +    JSD_UNLOCK();
   1.866 +    return true;
   1.867 +}
   1.868 +
   1.869 +void
   1.870 +jsd_ScriptCreated(JSDContext* jsdc,
   1.871 +                  JSContext   *cx,
   1.872 +                  const char  *filename,    /* URL this script loads from */
   1.873 +                  unsigned       lineno,       /* line where this script starts */
   1.874 +                  JSScript    *script,
   1.875 +                  JSFunction  *fun)
   1.876 +{
   1.877 +    jsd_NewScriptHookProc(cx, filename, lineno, script, fun, jsdc);
   1.878 +}
   1.879 +
   1.880 +void
   1.881 +jsd_ScriptDestroyed(JSDContext* jsdc,
   1.882 +                    JSFreeOp    *fop,
   1.883 +                    JSScript    *script)
   1.884 +{
   1.885 +    jsd_DestroyScriptHookProc(fop, script, jsdc);
   1.886 +}

mercurial