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 +}