/js/jsd/jsd_scpt.c

http://github.com/zpao/v8monkey · C · 1002 lines · 779 code · 163 blank · 60 comment · 106 complexity · 83f14ea7f9ef847a101ad703cc421983 MD5 · raw file

  1. /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
  2. /* ***** BEGIN LICENSE BLOCK *****
  3. * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  4. *
  5. * The contents of this file are subject to the Mozilla Public License Version
  6. * 1.1 (the "License"); you may not use this file except in compliance with
  7. * the License. You may obtain a copy of the License at
  8. * http://www.mozilla.org/MPL/
  9. *
  10. * Software distributed under the License is distributed on an "AS IS" basis,
  11. * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  12. * for the specific language governing rights and limitations under the
  13. * License.
  14. *
  15. * The Original Code is mozilla.org code.
  16. *
  17. * The Initial Developer of the Original Code is
  18. * Netscape Communications Corporation.
  19. * Portions created by the Initial Developer are Copyright (C) 1998
  20. * the Initial Developer. All Rights Reserved.
  21. *
  22. * Contributor(s):
  23. *
  24. * Alternatively, the contents of this file may be used under the terms of
  25. * either the GNU General Public License Version 2 or later (the "GPL"), or
  26. * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  27. * in which case the provisions of the GPL or the LGPL are applicable instead
  28. * of those above. If you wish to allow use of your version of this file only
  29. * under the terms of either the GPL or the LGPL, and not to allow others to
  30. * use your version of this file under the terms of the MPL, indicate your
  31. * decision by deleting the provisions above and replace them with the notice
  32. * and other provisions required by the GPL or the LGPL. If you do not delete
  33. * the provisions above, a recipient may use your version of this file under
  34. * the terms of any one of the MPL, the GPL or the LGPL.
  35. *
  36. * ***** END LICENSE BLOCK ***** */
  37. /*
  38. * JavaScript Debugging support - Script support
  39. */
  40. #include "jsd.h"
  41. #include "jsfriendapi.h"
  42. /* Comment this out to disable (NT specific) dumping as we go */
  43. /*
  44. ** #ifdef DEBUG
  45. ** #define JSD_DUMP 1
  46. ** #endif
  47. */
  48. #define NOT_SET_YET -1
  49. /***************************************************************************/
  50. #ifdef DEBUG
  51. void JSD_ASSERT_VALID_SCRIPT(JSDScript* jsdscript)
  52. {
  53. JS_ASSERT(jsdscript);
  54. JS_ASSERT(jsdscript->script);
  55. }
  56. void JSD_ASSERT_VALID_EXEC_HOOK(JSDExecHook* jsdhook)
  57. {
  58. JS_ASSERT(jsdhook);
  59. JS_ASSERT(jsdhook->hook);
  60. }
  61. #endif
  62. #ifdef LIVEWIRE
  63. static JSBool
  64. HasFileExtention(const char* name, const char* ext)
  65. {
  66. int i;
  67. int len = strlen(ext);
  68. const char* p = strrchr(name,'.');
  69. if( !p )
  70. return JS_FALSE;
  71. p++;
  72. for(i = 0; i < len; i++ )
  73. {
  74. JS_ASSERT(islower(ext[i]));
  75. if( 0 == p[i] || tolower(p[i]) != ext[i] )
  76. return JS_FALSE;
  77. }
  78. if( 0 != p[i] )
  79. return JS_FALSE;
  80. return JS_TRUE;
  81. }
  82. #endif /* LIVEWIRE */
  83. static JSDScript*
  84. _newJSDScript(JSDContext* jsdc,
  85. JSContext *cx,
  86. JSScript *script)
  87. {
  88. JSDScript* jsdscript;
  89. uintN lineno;
  90. const char* raw_filename;
  91. JS_ASSERT(JSD_SCRIPTS_LOCKED(jsdc));
  92. /* these are inlined javascript: urls and we can't handle them now */
  93. lineno = (uintN) JS_GetScriptBaseLineNumber(cx, script);
  94. if( lineno == 0 )
  95. return NULL;
  96. jsdscript = (JSDScript*) calloc(1, sizeof(JSDScript));
  97. if( ! jsdscript )
  98. return NULL;
  99. raw_filename = JS_GetScriptFilename(cx,script);
  100. JS_HashTableAdd(jsdc->scriptsTable, (void *)script, (void *)jsdscript);
  101. JS_APPEND_LINK(&jsdscript->links, &jsdc->scripts);
  102. jsdscript->jsdc = jsdc;
  103. jsdscript->script = script;
  104. jsdscript->lineBase = lineno;
  105. jsdscript->lineExtent = (uintN)NOT_SET_YET;
  106. jsdscript->data = NULL;
  107. #ifndef LIVEWIRE
  108. jsdscript->url = (char*) jsd_BuildNormalizedURL(raw_filename);
  109. #else
  110. jsdscript->app = LWDBG_GetCurrentApp();
  111. if( jsdscript->app && raw_filename )
  112. {
  113. jsdscript->url = jsdlw_BuildAppRelativeFilename(jsdscript->app, raw_filename);
  114. if( function )
  115. {
  116. JSString* funid = JS_GetFunctionId(function);
  117. char* funbytes;
  118. const char* funnanme;
  119. if( fuinid )
  120. {
  121. funbytes = JS_EncodeString(cx, funid);
  122. funname = funbytes ? funbytes : "";
  123. }
  124. else
  125. {
  126. funbytes = NULL;
  127. funname = "anonymous";
  128. }
  129. jsdscript->lwscript =
  130. LWDBG_GetScriptOfFunction(jsdscript->app,funname);
  131. JS_Free(cx, funbytes);
  132. /* also, make sure this file is added to filelist if is .js file */
  133. if( HasFileExtention(raw_filename,"js") ||
  134. HasFileExtention(raw_filename,"sjs") )
  135. {
  136. jsdlw_PreLoadSource(jsdc, jsdscript->app, raw_filename, JS_FALSE);
  137. }
  138. }
  139. else
  140. {
  141. jsdscript->lwscript = LWDBG_GetCurrentTopLevelScript();
  142. }
  143. }
  144. #endif
  145. JS_INIT_CLIST(&jsdscript->hooks);
  146. return jsdscript;
  147. }
  148. static void
  149. _destroyJSDScript(JSDContext* jsdc,
  150. JSDScript* jsdscript)
  151. {
  152. JS_ASSERT(JSD_SCRIPTS_LOCKED(jsdc));
  153. /* destroy all hooks */
  154. jsd_ClearAllExecutionHooksForScript(jsdc, jsdscript);
  155. JS_REMOVE_LINK(&jsdscript->links);
  156. if(jsdscript->url)
  157. free(jsdscript->url);
  158. if (jsdscript->profileData)
  159. free(jsdscript->profileData);
  160. free(jsdscript);
  161. }
  162. /***************************************************************************/
  163. #ifdef JSD_DUMP
  164. #ifndef XP_WIN
  165. void
  166. OutputDebugString (char *buf)
  167. {
  168. fprintf (stderr, "%s", buf);
  169. }
  170. #endif
  171. static void
  172. _dumpJSDScript(JSDContext* jsdc, JSDScript* jsdscript, const char* leadingtext)
  173. {
  174. const char* name;
  175. JSString* fun;
  176. uintN base;
  177. uintN extent;
  178. char Buf[256];
  179. size_t n;
  180. name = jsd_GetScriptFilename(jsdc, jsdscript);
  181. fun = jsd_GetScriptFunctionId(jsdc, jsdscript);
  182. base = jsd_GetScriptBaseLineNumber(jsdc, jsdscript);
  183. extent = jsd_GetScriptLineExtent(jsdc, jsdscript);
  184. n = size_t(snprintf(Buf, sizeof(Buf), "%sscript=%08X, %s, ",
  185. leadingtext, (unsigned) jsdscript->script,
  186. name ? name : "no URL"));
  187. if (n + 1 < sizeof(Buf)) {
  188. if (fun) {
  189. n += size_t(snprintf(Buf + n, sizeof(Buf) - n, "%s", "no fun"));
  190. } else {
  191. n += JS_PutEscapedFlatString(Buf + n, sizeof(Buf) - n,
  192. JS_ASSERT_STRING_IS_FLAT(fun), 0);
  193. Buf[sizeof(Buf) - 1] = '\0';
  194. }
  195. if (n + 1 < sizeof(Buf))
  196. snprintf(Buf + n, sizeof(Buf) - n, ", %d-%d\n", base, base + extent - 1);
  197. }
  198. OutputDebugString( Buf );
  199. }
  200. static void
  201. _dumpJSDScriptList( JSDContext* jsdc )
  202. {
  203. JSDScript* iterp = NULL;
  204. JSDScript* jsdscript = NULL;
  205. OutputDebugString( "*** JSDScriptDump\n" );
  206. while( NULL != (jsdscript = jsd_IterateScripts(jsdc, &iterp)) )
  207. _dumpJSDScript( jsdc, jsdscript, " script: " );
  208. }
  209. #endif /* JSD_DUMP */
  210. /***************************************************************************/
  211. static JSHashNumber
  212. jsd_hash_script(const void *key)
  213. {
  214. return ((JSHashNumber)(ptrdiff_t) key) >> 2; /* help lame MSVC1.5 on Win16 */
  215. }
  216. static void *
  217. jsd_alloc_script_table(void *priv, size_t size)
  218. {
  219. return malloc(size);
  220. }
  221. static void
  222. jsd_free_script_table(void *priv, void *item, size_t size)
  223. {
  224. free(item);
  225. }
  226. static JSHashEntry *
  227. jsd_alloc_script_entry(void *priv, const void *item)
  228. {
  229. return (JSHashEntry*) malloc(sizeof(JSHashEntry));
  230. }
  231. static void
  232. jsd_free_script_entry(void *priv, JSHashEntry *he, uintN flag)
  233. {
  234. if (flag == HT_FREE_ENTRY)
  235. {
  236. _destroyJSDScript((JSDContext*) priv, (JSDScript*) he->value);
  237. free(he);
  238. }
  239. }
  240. static JSHashAllocOps script_alloc_ops = {
  241. jsd_alloc_script_table, jsd_free_script_table,
  242. jsd_alloc_script_entry, jsd_free_script_entry
  243. };
  244. #ifndef JSD_SCRIPT_HASH_SIZE
  245. #define JSD_SCRIPT_HASH_SIZE 1024
  246. #endif
  247. JSBool
  248. jsd_InitScriptManager(JSDContext* jsdc)
  249. {
  250. JS_INIT_CLIST(&jsdc->scripts);
  251. jsdc->scriptsTable = JS_NewHashTable(JSD_SCRIPT_HASH_SIZE, jsd_hash_script,
  252. JS_CompareValues, JS_CompareValues,
  253. &script_alloc_ops, (void*) jsdc);
  254. return !!jsdc->scriptsTable;
  255. }
  256. void
  257. jsd_DestroyScriptManager(JSDContext* jsdc)
  258. {
  259. JSD_LOCK_SCRIPTS(jsdc);
  260. if (jsdc->scriptsTable)
  261. JS_HashTableDestroy(jsdc->scriptsTable);
  262. JSD_UNLOCK_SCRIPTS(jsdc);
  263. }
  264. JSDScript*
  265. jsd_FindJSDScript( JSDContext* jsdc,
  266. JSScript *script )
  267. {
  268. JS_ASSERT(JSD_SCRIPTS_LOCKED(jsdc));
  269. return (JSDScript*) JS_HashTableLookup(jsdc->scriptsTable, (void *)script);
  270. }
  271. JSDScript *
  272. jsd_FindOrCreateJSDScript(JSDContext *jsdc,
  273. JSContext *cx,
  274. JSScript *script,
  275. JSStackFrame *fp)
  276. {
  277. JSDScript *jsdscript;
  278. JS_ASSERT(JSD_SCRIPTS_LOCKED(jsdc));
  279. jsdscript = jsd_FindJSDScript(jsdc, script);
  280. if (jsdscript)
  281. return jsdscript;
  282. /* Fallback for unknown scripts: create a new script. */
  283. if (!fp)
  284. JS_FrameIterator(cx, &fp);
  285. if (fp)
  286. jsdscript = _newJSDScript(jsdc, cx, script);
  287. return jsdscript;
  288. }
  289. JSDProfileData*
  290. jsd_GetScriptProfileData(JSDContext* jsdc, JSDScript *script)
  291. {
  292. if (!script->profileData)
  293. script->profileData = (JSDProfileData*)calloc(1, sizeof(JSDProfileData));
  294. return script->profileData;
  295. }
  296. uint32_t
  297. jsd_GetScriptFlags(JSDContext *jsdc, JSDScript *script)
  298. {
  299. return script->flags;
  300. }
  301. void
  302. jsd_SetScriptFlags(JSDContext *jsdc, JSDScript *script, uint32_t flags)
  303. {
  304. script->flags = flags;
  305. }
  306. uintN
  307. jsd_GetScriptCallCount(JSDContext* jsdc, JSDScript *script)
  308. {
  309. if (script->profileData)
  310. return script->profileData->callCount;
  311. return 0;
  312. }
  313. uintN
  314. jsd_GetScriptMaxRecurseDepth(JSDContext* jsdc, JSDScript *script)
  315. {
  316. if (script->profileData)
  317. return script->profileData->maxRecurseDepth;
  318. return 0;
  319. }
  320. jsdouble
  321. jsd_GetScriptMinExecutionTime(JSDContext* jsdc, JSDScript *script)
  322. {
  323. if (script->profileData)
  324. return script->profileData->minExecutionTime;
  325. return 0.0;
  326. }
  327. jsdouble
  328. jsd_GetScriptMaxExecutionTime(JSDContext* jsdc, JSDScript *script)
  329. {
  330. if (script->profileData)
  331. return script->profileData->maxExecutionTime;
  332. return 0.0;
  333. }
  334. jsdouble
  335. jsd_GetScriptTotalExecutionTime(JSDContext* jsdc, JSDScript *script)
  336. {
  337. if (script->profileData)
  338. return script->profileData->totalExecutionTime;
  339. return 0.0;
  340. }
  341. jsdouble
  342. jsd_GetScriptMinOwnExecutionTime(JSDContext* jsdc, JSDScript *script)
  343. {
  344. if (script->profileData)
  345. return script->profileData->minOwnExecutionTime;
  346. return 0.0;
  347. }
  348. jsdouble
  349. jsd_GetScriptMaxOwnExecutionTime(JSDContext* jsdc, JSDScript *script)
  350. {
  351. if (script->profileData)
  352. return script->profileData->maxOwnExecutionTime;
  353. return 0.0;
  354. }
  355. jsdouble
  356. jsd_GetScriptTotalOwnExecutionTime(JSDContext* jsdc, JSDScript *script)
  357. {
  358. if (script->profileData)
  359. return script->profileData->totalOwnExecutionTime;
  360. return 0.0;
  361. }
  362. void
  363. jsd_ClearScriptProfileData(JSDContext* jsdc, JSDScript *script)
  364. {
  365. if (script->profileData)
  366. {
  367. free(script->profileData);
  368. script->profileData = NULL;
  369. }
  370. }
  371. JSScript *
  372. jsd_GetJSScript (JSDContext *jsdc, JSDScript *script)
  373. {
  374. return script->script;
  375. }
  376. JSFunction *
  377. jsd_GetJSFunction (JSDContext *jsdc, JSDScript *script)
  378. {
  379. return JS_GetScriptFunction(jsdc->dumbContext, script->script);
  380. }
  381. JSDScript*
  382. jsd_IterateScripts(JSDContext* jsdc, JSDScript **iterp)
  383. {
  384. JSDScript *jsdscript = *iterp;
  385. JS_ASSERT(JSD_SCRIPTS_LOCKED(jsdc));
  386. if( !jsdscript )
  387. jsdscript = (JSDScript *)jsdc->scripts.next;
  388. if( jsdscript == (JSDScript *)&jsdc->scripts )
  389. return NULL;
  390. *iterp = (JSDScript*) jsdscript->links.next;
  391. return jsdscript;
  392. }
  393. void *
  394. jsd_SetScriptPrivate(JSDScript *jsdscript, void *data)
  395. {
  396. void *rval = jsdscript->data;
  397. jsdscript->data = data;
  398. return rval;
  399. }
  400. void *
  401. jsd_GetScriptPrivate(JSDScript *jsdscript)
  402. {
  403. return jsdscript->data;
  404. }
  405. JSBool
  406. jsd_IsActiveScript(JSDContext* jsdc, JSDScript *jsdscript)
  407. {
  408. JSDScript *current;
  409. JS_ASSERT(JSD_SCRIPTS_LOCKED(jsdc));
  410. for( current = (JSDScript *)jsdc->scripts.next;
  411. current != (JSDScript *)&jsdc->scripts;
  412. current = (JSDScript *)current->links.next )
  413. {
  414. if(jsdscript == current)
  415. return JS_TRUE;
  416. }
  417. return JS_FALSE;
  418. }
  419. const char*
  420. jsd_GetScriptFilename(JSDContext* jsdc, JSDScript *jsdscript)
  421. {
  422. return jsdscript->url;
  423. }
  424. JSString*
  425. jsd_GetScriptFunctionId(JSDContext* jsdc, JSDScript *jsdscript)
  426. {
  427. JSString* str;
  428. JSFunction *fun = jsd_GetJSFunction(jsdc, jsdscript);
  429. if( ! fun )
  430. return NULL;
  431. str = JS_GetFunctionId(fun);
  432. /* For compatibility we return "anonymous", not an empty string here. */
  433. return str ? str : JS_GetAnonymousString(jsdc->jsrt);
  434. }
  435. uintN
  436. jsd_GetScriptBaseLineNumber(JSDContext* jsdc, JSDScript *jsdscript)
  437. {
  438. return jsdscript->lineBase;
  439. }
  440. uintN
  441. jsd_GetScriptLineExtent(JSDContext* jsdc, JSDScript *jsdscript)
  442. {
  443. if( NOT_SET_YET == (int)jsdscript->lineExtent )
  444. jsdscript->lineExtent = JS_GetScriptLineExtent(jsdc->dumbContext, jsdscript->script);
  445. return jsdscript->lineExtent;
  446. }
  447. uintptr_t
  448. jsd_GetClosestPC(JSDContext* jsdc, JSDScript* jsdscript, uintN line)
  449. {
  450. uintptr_t pc;
  451. JSCrossCompartmentCall *call;
  452. if( !jsdscript )
  453. return 0;
  454. #ifdef LIVEWIRE
  455. if( jsdscript->lwscript )
  456. {
  457. uintN newline;
  458. jsdlw_RawToProcessedLineNumber(jsdc, jsdscript, line, &newline);
  459. if( line != newline )
  460. line = newline;
  461. }
  462. #endif
  463. call = JS_EnterCrossCompartmentCallScript(jsdc->dumbContext, jsdscript->script);
  464. if(!call)
  465. return 0;
  466. pc = (uintptr_t) JS_LineNumberToPC(jsdc->dumbContext, jsdscript->script, line );
  467. JS_LeaveCrossCompartmentCall(call);
  468. return pc;
  469. }
  470. uintN
  471. jsd_GetClosestLine(JSDContext* jsdc, JSDScript* jsdscript, uintptr_t pc)
  472. {
  473. JSCrossCompartmentCall *call;
  474. uintN first = jsdscript->lineBase;
  475. uintN last = first + jsd_GetScriptLineExtent(jsdc, jsdscript) - 1;
  476. uintN line = 0;
  477. call = JS_EnterCrossCompartmentCallScript(jsdc->dumbContext, jsdscript->script);
  478. if(!call)
  479. return 0;
  480. if (pc)
  481. line = JS_PCToLineNumber(jsdc->dumbContext, jsdscript->script, (jsbytecode*)pc);
  482. JS_LeaveCrossCompartmentCall(call);
  483. if( line < first )
  484. return first;
  485. if( line > last )
  486. return last;
  487. #ifdef LIVEWIRE
  488. if( jsdscript && jsdscript->lwscript )
  489. {
  490. uintN newline;
  491. jsdlw_ProcessedToRawLineNumber(jsdc, jsdscript, line, &newline);
  492. line = newline;
  493. }
  494. #endif
  495. return line;
  496. }
  497. JSBool
  498. jsd_GetLinePCs(JSDContext* jsdc, JSDScript* jsdscript,
  499. uintN startLine, uintN maxLines,
  500. uintN* count, uintN** retLines, uintptr_t** retPCs)
  501. {
  502. JSCrossCompartmentCall *call;
  503. uintN first = jsdscript->lineBase;
  504. uintN last = first + jsd_GetScriptLineExtent(jsdc, jsdscript) - 1;
  505. JSBool ok;
  506. uintN *lines;
  507. jsbytecode **pcs;
  508. uintN i;
  509. if (last < startLine)
  510. return JS_TRUE;
  511. call = JS_EnterCrossCompartmentCallScript(jsdc->dumbContext, jsdscript->script);
  512. if (!call)
  513. return JS_FALSE;
  514. ok = JS_GetLinePCs(jsdc->dumbContext, jsdscript->script,
  515. startLine, maxLines,
  516. count, retLines, &pcs);
  517. if (ok) {
  518. if (retPCs) {
  519. for (i = 0; i < *count; ++i) {
  520. (*retPCs)[i] = (*pcs)[i];
  521. }
  522. }
  523. JS_free(jsdc->dumbContext, pcs);
  524. }
  525. JS_LeaveCrossCompartmentCall(call);
  526. return ok;
  527. }
  528. JSBool
  529. jsd_SetScriptHook(JSDContext* jsdc, JSD_ScriptHookProc hook, void* callerdata)
  530. {
  531. JSD_LOCK();
  532. jsdc->scriptHook = hook;
  533. jsdc->scriptHookData = callerdata;
  534. JSD_UNLOCK();
  535. return JS_TRUE;
  536. }
  537. JSBool
  538. jsd_GetScriptHook(JSDContext* jsdc, JSD_ScriptHookProc* hook, void** callerdata)
  539. {
  540. JSD_LOCK();
  541. if( hook )
  542. *hook = jsdc->scriptHook;
  543. if( callerdata )
  544. *callerdata = jsdc->scriptHookData;
  545. JSD_UNLOCK();
  546. return JS_TRUE;
  547. }
  548. JSBool
  549. jsd_EnableSingleStepInterrupts(JSDContext* jsdc, JSDScript* jsdscript, JSBool enable)
  550. {
  551. JSCrossCompartmentCall *call;
  552. JSBool rv;
  553. call = JS_EnterCrossCompartmentCallScript(jsdc->dumbContext, jsdscript->script);
  554. if(!call)
  555. return JS_FALSE;
  556. JSD_LOCK();
  557. rv = JS_SetSingleStepMode(jsdc->dumbContext, jsdscript->script, enable);
  558. JSD_UNLOCK();
  559. JS_LeaveCrossCompartmentCall(call);
  560. return rv;
  561. }
  562. /***************************************************************************/
  563. void
  564. jsd_NewScriptHookProc(
  565. JSContext *cx,
  566. const char *filename, /* URL this script loads from */
  567. uintN lineno, /* line where this script starts */
  568. JSScript *script,
  569. JSFunction *fun,
  570. void* callerdata )
  571. {
  572. JSDScript* jsdscript = NULL;
  573. JSDContext* jsdc = (JSDContext*) callerdata;
  574. JSD_ScriptHookProc hook;
  575. void* hookData;
  576. JSD_ASSERT_VALID_CONTEXT(jsdc);
  577. if( JSD_IS_DANGEROUS_THREAD(jsdc) )
  578. return;
  579. JSD_LOCK_SCRIPTS(jsdc);
  580. jsdscript = _newJSDScript(jsdc, cx, script);
  581. JSD_UNLOCK_SCRIPTS(jsdc);
  582. if( ! jsdscript )
  583. return;
  584. #ifdef JSD_DUMP
  585. JSD_LOCK_SCRIPTS(jsdc);
  586. _dumpJSDScript(jsdc, jsdscript, "***NEW Script: ");
  587. _dumpJSDScriptList( jsdc );
  588. JSD_UNLOCK_SCRIPTS(jsdc);
  589. #endif /* JSD_DUMP */
  590. /* local in case jsdc->scriptHook gets cleared on another thread */
  591. JSD_LOCK();
  592. hook = jsdc->scriptHook;
  593. hookData = jsdc->scriptHookData;
  594. JSD_UNLOCK();
  595. if( hook )
  596. hook(jsdc, jsdscript, JS_TRUE, hookData);
  597. }
  598. void
  599. jsd_DestroyScriptHookProc(
  600. JSContext *cx,
  601. JSScript *script,
  602. void* callerdata )
  603. {
  604. JSDScript* jsdscript = NULL;
  605. JSDContext* jsdc = (JSDContext*) callerdata;
  606. JSD_ScriptHookProc hook;
  607. void* hookData;
  608. JSD_ASSERT_VALID_CONTEXT(jsdc);
  609. if( JSD_IS_DANGEROUS_THREAD(jsdc) )
  610. return;
  611. JSD_LOCK_SCRIPTS(jsdc);
  612. jsdscript = jsd_FindJSDScript(jsdc, script);
  613. JSD_UNLOCK_SCRIPTS(jsdc);
  614. if( ! jsdscript )
  615. return;
  616. #ifdef JSD_DUMP
  617. JSD_LOCK_SCRIPTS(jsdc);
  618. _dumpJSDScript(jsdc, jsdscript, "***DESTROY Script: ");
  619. JSD_UNLOCK_SCRIPTS(jsdc);
  620. #endif /* JSD_DUMP */
  621. /* local in case hook gets cleared on another thread */
  622. JSD_LOCK();
  623. hook = jsdc->scriptHook;
  624. hookData = jsdc->scriptHookData;
  625. JSD_UNLOCK();
  626. if( hook )
  627. hook(jsdc, jsdscript, JS_FALSE, hookData);
  628. JSD_LOCK_SCRIPTS(jsdc);
  629. JS_HashTableRemove(jsdc->scriptsTable, (void *)script);
  630. JSD_UNLOCK_SCRIPTS(jsdc);
  631. #ifdef JSD_DUMP
  632. JSD_LOCK_SCRIPTS(jsdc);
  633. _dumpJSDScriptList(jsdc);
  634. JSD_UNLOCK_SCRIPTS(jsdc);
  635. #endif /* JSD_DUMP */
  636. }
  637. /***************************************************************************/
  638. static JSDExecHook*
  639. _findHook(JSDContext* jsdc, JSDScript* jsdscript, uintptr_t pc)
  640. {
  641. JSDExecHook* jsdhook;
  642. JSCList* list = &jsdscript->hooks;
  643. for( jsdhook = (JSDExecHook*)list->next;
  644. jsdhook != (JSDExecHook*)list;
  645. jsdhook = (JSDExecHook*)jsdhook->links.next )
  646. {
  647. if (jsdhook->pc == pc)
  648. return jsdhook;
  649. }
  650. return NULL;
  651. }
  652. static JSBool
  653. _isActiveHook(JSDContext* jsdc, JSScript *script, JSDExecHook* jsdhook)
  654. {
  655. JSDExecHook* current;
  656. JSCList* list;
  657. JSDScript* jsdscript;
  658. JSD_LOCK_SCRIPTS(jsdc);
  659. jsdscript = jsd_FindJSDScript(jsdc, script);
  660. if( ! jsdscript)
  661. {
  662. JSD_UNLOCK_SCRIPTS(jsdc);
  663. return JS_FALSE;
  664. }
  665. list = &jsdscript->hooks;
  666. for( current = (JSDExecHook*)list->next;
  667. current != (JSDExecHook*)list;
  668. current = (JSDExecHook*)current->links.next )
  669. {
  670. if(current == jsdhook)
  671. {
  672. JSD_UNLOCK_SCRIPTS(jsdc);
  673. return JS_TRUE;
  674. }
  675. }
  676. JSD_UNLOCK_SCRIPTS(jsdc);
  677. return JS_FALSE;
  678. }
  679. JSTrapStatus
  680. jsd_TrapHandler(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval,
  681. jsval closure)
  682. {
  683. JSDExecHook* jsdhook = (JSDExecHook*) JSVAL_TO_PRIVATE(closure);
  684. JSD_ExecutionHookProc hook;
  685. void* hookData;
  686. JSDContext* jsdc;
  687. JSDScript* jsdscript;
  688. JSD_LOCK();
  689. if( NULL == (jsdc = jsd_JSDContextForJSContext(cx)) ||
  690. ! _isActiveHook(jsdc, script, jsdhook) )
  691. {
  692. JSD_UNLOCK();
  693. return JSTRAP_CONTINUE;
  694. }
  695. JSD_ASSERT_VALID_EXEC_HOOK(jsdhook);
  696. JS_ASSERT(!jsdhook->pc || jsdhook->pc == (uintptr_t)pc);
  697. JS_ASSERT(jsdhook->jsdscript->script == script);
  698. JS_ASSERT(jsdhook->jsdscript->jsdc == jsdc);
  699. hook = jsdhook->hook;
  700. hookData = jsdhook->callerdata;
  701. jsdscript = jsdhook->jsdscript;
  702. /* do not use jsdhook-> after this point */
  703. JSD_UNLOCK();
  704. if( ! jsdc || ! jsdc->inited )
  705. return JSTRAP_CONTINUE;
  706. if( JSD_IS_DANGEROUS_THREAD(jsdc) )
  707. return JSTRAP_CONTINUE;
  708. #ifdef LIVEWIRE
  709. if( ! jsdlw_UserCodeAtPC(jsdc, jsdscript, (uintptr_t)pc) )
  710. return JSTRAP_CONTINUE;
  711. #endif
  712. return jsd_CallExecutionHook(jsdc, cx, JSD_HOOK_BREAKPOINT,
  713. hook, hookData, rval);
  714. }
  715. JSBool
  716. jsd_SetExecutionHook(JSDContext* jsdc,
  717. JSDScript* jsdscript,
  718. uintptr_t pc,
  719. JSD_ExecutionHookProc hook,
  720. void* callerdata)
  721. {
  722. JSDExecHook* jsdhook;
  723. JSBool rv;
  724. JSCrossCompartmentCall *call;
  725. JSD_LOCK();
  726. if( ! hook )
  727. {
  728. jsd_ClearExecutionHook(jsdc, jsdscript, pc);
  729. JSD_UNLOCK();
  730. return JS_TRUE;
  731. }
  732. jsdhook = _findHook(jsdc, jsdscript, pc);
  733. if( jsdhook )
  734. {
  735. jsdhook->hook = hook;
  736. jsdhook->callerdata = callerdata;
  737. JSD_UNLOCK();
  738. return JS_TRUE;
  739. }
  740. /* else... */
  741. jsdhook = (JSDExecHook*)calloc(1, sizeof(JSDExecHook));
  742. if( ! jsdhook ) {
  743. JSD_UNLOCK();
  744. return JS_FALSE;
  745. }
  746. jsdhook->jsdscript = jsdscript;
  747. jsdhook->pc = pc;
  748. jsdhook->hook = hook;
  749. jsdhook->callerdata = callerdata;
  750. call = JS_EnterCrossCompartmentCallScript(jsdc->dumbContext, jsdscript->script);
  751. if(!call) {
  752. free(jsdhook);
  753. JSD_UNLOCK();
  754. return JS_FALSE;
  755. }
  756. rv = JS_SetTrap(jsdc->dumbContext, jsdscript->script,
  757. (jsbytecode*)pc, jsd_TrapHandler,
  758. PRIVATE_TO_JSVAL(jsdhook));
  759. JS_LeaveCrossCompartmentCall(call);
  760. if ( ! rv ) {
  761. free(jsdhook);
  762. JSD_UNLOCK();
  763. return JS_FALSE;
  764. }
  765. JS_APPEND_LINK(&jsdhook->links, &jsdscript->hooks);
  766. JSD_UNLOCK();
  767. return JS_TRUE;
  768. }
  769. JSBool
  770. jsd_ClearExecutionHook(JSDContext* jsdc,
  771. JSDScript* jsdscript,
  772. uintptr_t pc)
  773. {
  774. JSCrossCompartmentCall *call;
  775. JSDExecHook* jsdhook;
  776. JSD_LOCK();
  777. jsdhook = _findHook(jsdc, jsdscript, pc);
  778. if( ! jsdhook )
  779. {
  780. JSD_UNLOCK();
  781. return JS_FALSE;
  782. }
  783. call = JS_EnterCrossCompartmentCallScript(jsdc->dumbContext, jsdscript->script);
  784. if(!call) {
  785. JSD_UNLOCK();
  786. return JS_FALSE;
  787. }
  788. JS_ClearTrap(jsdc->dumbContext, jsdscript->script,
  789. (jsbytecode*)pc, NULL, NULL );
  790. JS_LeaveCrossCompartmentCall(call);
  791. JS_REMOVE_LINK(&jsdhook->links);
  792. free(jsdhook);
  793. JSD_UNLOCK();
  794. return JS_TRUE;
  795. }
  796. JSBool
  797. jsd_ClearAllExecutionHooksForScript(JSDContext* jsdc, JSDScript* jsdscript)
  798. {
  799. JSDExecHook* jsdhook;
  800. JSCList* list = &jsdscript->hooks;
  801. JSD_LOCK();
  802. while( (JSDExecHook*)list != (jsdhook = (JSDExecHook*)list->next) )
  803. {
  804. JS_REMOVE_LINK(&jsdhook->links);
  805. free(jsdhook);
  806. }
  807. /* No cross-compartment call here because we may be in the middle of GC */
  808. JS_ClearScriptTraps(jsdc->dumbContext, jsdscript->script);
  809. JSD_UNLOCK();
  810. return JS_TRUE;
  811. }
  812. JSBool
  813. jsd_ClearAllExecutionHooks(JSDContext* jsdc)
  814. {
  815. JSDScript* jsdscript;
  816. JSDScript* iterp = NULL;
  817. JSD_LOCK();
  818. while( NULL != (jsdscript = jsd_IterateScripts(jsdc, &iterp)) )
  819. jsd_ClearAllExecutionHooksForScript(jsdc, jsdscript);
  820. JSD_UNLOCK();
  821. return JS_TRUE;
  822. }
  823. void
  824. jsd_ScriptCreated(JSDContext* jsdc,
  825. JSContext *cx,
  826. const char *filename, /* URL this script loads from */
  827. uintN lineno, /* line where this script starts */
  828. JSScript *script,
  829. JSFunction *fun)
  830. {
  831. jsd_NewScriptHookProc(cx, filename, lineno, script, fun, jsdc);
  832. }
  833. void
  834. jsd_ScriptDestroyed(JSDContext* jsdc,
  835. JSContext *cx,
  836. JSScript *script)
  837. {
  838. jsd_DestroyScriptHookProc(cx, script, jsdc);
  839. }