PageRenderTime 48ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 1ms

/js/lib/Socket.IO-node/support/expresso/deps/jscoverage/js/jsdbgapi.cpp

http://github.com/onedayitwillmake/RealtimeMultiplayerNodeJs
C++ | 1954 lines | 1571 code | 241 blank | 142 comment | 304 complexity | 9da1bf018cd02a156e9fd449d3e17c9d MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1, MPL-2.0-no-copyleft-exception, BSD-3-Clause
  1. /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  2. * vim: set ts=8 sw=4 et tw=78:
  3. *
  4. * ***** BEGIN LICENSE BLOCK *****
  5. * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  6. *
  7. * The contents of this file are subject to the Mozilla Public License Version
  8. * 1.1 (the "License"); you may not use this file except in compliance with
  9. * the License. You may obtain a copy of the License at
  10. * http://www.mozilla.org/MPL/
  11. *
  12. * Software distributed under the License is distributed on an "AS IS" basis,
  13. * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  14. * for the specific language governing rights and limitations under the
  15. * License.
  16. *
  17. * The Original Code is Mozilla Communicator client code, released
  18. * March 31, 1998.
  19. *
  20. * The Initial Developer of the Original Code is
  21. * Netscape Communications Corporation.
  22. * Portions created by the Initial Developer are Copyright (C) 1998
  23. * the Initial Developer. All Rights Reserved.
  24. *
  25. * Contributor(s):
  26. *
  27. * Alternatively, the contents of this file may be used under the terms of
  28. * either of the GNU General Public License Version 2 or later (the "GPL"),
  29. * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  30. * in which case the provisions of the GPL or the LGPL are applicable instead
  31. * of those above. If you wish to allow use of your version of this file only
  32. * under the terms of either the GPL or the LGPL, and not to allow others to
  33. * use your version of this file under the terms of the MPL, indicate your
  34. * decision by deleting the provisions above and replace them with the notice
  35. * and other provisions required by the GPL or the LGPL. If you do not delete
  36. * the provisions above, a recipient may use your version of this file under
  37. * the terms of any one of the MPL, the GPL or the LGPL.
  38. *
  39. * ***** END LICENSE BLOCK ***** */
  40. /*
  41. * JS debugging API.
  42. */
  43. #include "jsstddef.h"
  44. #include <string.h>
  45. #include "jstypes.h"
  46. #include "jsutil.h" /* Added by JSIFY */
  47. #include "jsclist.h"
  48. #include "jsapi.h"
  49. #include "jscntxt.h"
  50. #include "jsversion.h"
  51. #include "jsdbgapi.h"
  52. #include "jsemit.h"
  53. #include "jsfun.h"
  54. #include "jsgc.h"
  55. #include "jsinterp.h"
  56. #include "jslock.h"
  57. #include "jsobj.h"
  58. #include "jsopcode.h"
  59. #include "jsparse.h"
  60. #include "jsscope.h"
  61. #include "jsscript.h"
  62. #include "jsstr.h"
  63. #include "jsautooplen.h"
  64. typedef struct JSTrap {
  65. JSCList links;
  66. JSScript *script;
  67. jsbytecode *pc;
  68. JSOp op;
  69. JSTrapHandler handler;
  70. void *closure;
  71. } JSTrap;
  72. #define DBG_LOCK(rt) JS_ACQUIRE_LOCK((rt)->debuggerLock)
  73. #define DBG_UNLOCK(rt) JS_RELEASE_LOCK((rt)->debuggerLock)
  74. #define DBG_LOCK_EVAL(rt,expr) (DBG_LOCK(rt), (expr), DBG_UNLOCK(rt))
  75. /*
  76. * NB: FindTrap must be called with rt->debuggerLock acquired.
  77. */
  78. static JSTrap *
  79. FindTrap(JSRuntime *rt, JSScript *script, jsbytecode *pc)
  80. {
  81. JSTrap *trap;
  82. for (trap = (JSTrap *)rt->trapList.next;
  83. &trap->links != &rt->trapList;
  84. trap = (JSTrap *)trap->links.next) {
  85. if (trap->script == script && trap->pc == pc)
  86. return trap;
  87. }
  88. return NULL;
  89. }
  90. jsbytecode *
  91. js_UntrapScriptCode(JSContext *cx, JSScript *script)
  92. {
  93. jsbytecode *code;
  94. JSRuntime *rt;
  95. JSTrap *trap;
  96. code = script->code;
  97. rt = cx->runtime;
  98. DBG_LOCK(rt);
  99. for (trap = (JSTrap *)rt->trapList.next;
  100. &trap->links !=
  101. &rt->trapList;
  102. trap = (JSTrap *)trap->links.next) {
  103. if (trap->script == script &&
  104. (size_t)(trap->pc - script->code) < script->length) {
  105. if (code == script->code) {
  106. jssrcnote *sn, *notes;
  107. size_t nbytes;
  108. nbytes = script->length * sizeof(jsbytecode);
  109. notes = SCRIPT_NOTES(script);
  110. for (sn = notes; !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn))
  111. continue;
  112. nbytes += (sn - notes + 1) * sizeof *sn;
  113. code = (jsbytecode *) JS_malloc(cx, nbytes);
  114. if (!code)
  115. break;
  116. memcpy(code, script->code, nbytes);
  117. JS_CLEAR_GSN_CACHE(cx);
  118. }
  119. code[trap->pc - script->code] = trap->op;
  120. }
  121. }
  122. DBG_UNLOCK(rt);
  123. return code;
  124. }
  125. JS_PUBLIC_API(JSBool)
  126. JS_SetTrap(JSContext *cx, JSScript *script, jsbytecode *pc,
  127. JSTrapHandler handler, void *closure)
  128. {
  129. JSTrap *junk, *trap, *twin;
  130. JSRuntime *rt;
  131. uint32 sample;
  132. JS_ASSERT((JSOp) *pc != JSOP_TRAP);
  133. junk = NULL;
  134. rt = cx->runtime;
  135. DBG_LOCK(rt);
  136. trap = FindTrap(rt, script, pc);
  137. if (trap) {
  138. JS_ASSERT(trap->script == script && trap->pc == pc);
  139. JS_ASSERT(*pc == JSOP_TRAP);
  140. } else {
  141. sample = rt->debuggerMutations;
  142. DBG_UNLOCK(rt);
  143. trap = (JSTrap *) JS_malloc(cx, sizeof *trap);
  144. if (!trap)
  145. return JS_FALSE;
  146. trap->closure = NULL;
  147. if(!js_AddRoot(cx, &trap->closure, "trap->closure")) {
  148. JS_free(cx, trap);
  149. return JS_FALSE;
  150. }
  151. DBG_LOCK(rt);
  152. twin = (rt->debuggerMutations != sample)
  153. ? FindTrap(rt, script, pc)
  154. : NULL;
  155. if (twin) {
  156. junk = trap;
  157. trap = twin;
  158. } else {
  159. JS_APPEND_LINK(&trap->links, &rt->trapList);
  160. ++rt->debuggerMutations;
  161. trap->script = script;
  162. trap->pc = pc;
  163. trap->op = (JSOp)*pc;
  164. *pc = JSOP_TRAP;
  165. }
  166. }
  167. trap->handler = handler;
  168. trap->closure = closure;
  169. DBG_UNLOCK(rt);
  170. if (junk) {
  171. js_RemoveRoot(rt, &junk->closure);
  172. JS_free(cx, junk);
  173. }
  174. return JS_TRUE;
  175. }
  176. JS_PUBLIC_API(JSOp)
  177. JS_GetTrapOpcode(JSContext *cx, JSScript *script, jsbytecode *pc)
  178. {
  179. JSRuntime *rt;
  180. JSTrap *trap;
  181. JSOp op;
  182. rt = cx->runtime;
  183. DBG_LOCK(rt);
  184. trap = FindTrap(rt, script, pc);
  185. op = trap ? trap->op : (JSOp) *pc;
  186. DBG_UNLOCK(rt);
  187. return op;
  188. }
  189. static void
  190. DestroyTrapAndUnlock(JSContext *cx, JSTrap *trap)
  191. {
  192. ++cx->runtime->debuggerMutations;
  193. JS_REMOVE_LINK(&trap->links);
  194. *trap->pc = (jsbytecode)trap->op;
  195. DBG_UNLOCK(cx->runtime);
  196. js_RemoveRoot(cx->runtime, &trap->closure);
  197. JS_free(cx, trap);
  198. }
  199. JS_PUBLIC_API(void)
  200. JS_ClearTrap(JSContext *cx, JSScript *script, jsbytecode *pc,
  201. JSTrapHandler *handlerp, void **closurep)
  202. {
  203. JSTrap *trap;
  204. DBG_LOCK(cx->runtime);
  205. trap = FindTrap(cx->runtime, script, pc);
  206. if (handlerp)
  207. *handlerp = trap ? trap->handler : NULL;
  208. if (closurep)
  209. *closurep = trap ? trap->closure : NULL;
  210. if (trap)
  211. DestroyTrapAndUnlock(cx, trap);
  212. else
  213. DBG_UNLOCK(cx->runtime);
  214. }
  215. JS_PUBLIC_API(void)
  216. JS_ClearScriptTraps(JSContext *cx, JSScript *script)
  217. {
  218. JSRuntime *rt;
  219. JSTrap *trap, *next;
  220. uint32 sample;
  221. rt = cx->runtime;
  222. DBG_LOCK(rt);
  223. for (trap = (JSTrap *)rt->trapList.next;
  224. &trap->links != &rt->trapList;
  225. trap = next) {
  226. next = (JSTrap *)trap->links.next;
  227. if (trap->script == script) {
  228. sample = rt->debuggerMutations;
  229. DestroyTrapAndUnlock(cx, trap);
  230. DBG_LOCK(rt);
  231. if (rt->debuggerMutations != sample + 1)
  232. next = (JSTrap *)rt->trapList.next;
  233. }
  234. }
  235. DBG_UNLOCK(rt);
  236. }
  237. JS_PUBLIC_API(void)
  238. JS_ClearAllTraps(JSContext *cx)
  239. {
  240. JSRuntime *rt;
  241. JSTrap *trap, *next;
  242. uint32 sample;
  243. rt = cx->runtime;
  244. DBG_LOCK(rt);
  245. for (trap = (JSTrap *)rt->trapList.next;
  246. &trap->links != &rt->trapList;
  247. trap = next) {
  248. next = (JSTrap *)trap->links.next;
  249. sample = rt->debuggerMutations;
  250. DestroyTrapAndUnlock(cx, trap);
  251. DBG_LOCK(rt);
  252. if (rt->debuggerMutations != sample + 1)
  253. next = (JSTrap *)rt->trapList.next;
  254. }
  255. DBG_UNLOCK(rt);
  256. }
  257. JS_PUBLIC_API(JSTrapStatus)
  258. JS_HandleTrap(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval)
  259. {
  260. JSTrap *trap;
  261. jsint op;
  262. JSTrapStatus status;
  263. DBG_LOCK(cx->runtime);
  264. trap = FindTrap(cx->runtime, script, pc);
  265. JS_ASSERT(!trap || trap->handler);
  266. if (!trap) {
  267. op = (JSOp) *pc;
  268. DBG_UNLOCK(cx->runtime);
  269. /* Defend against "pc for wrong script" API usage error. */
  270. JS_ASSERT(op != JSOP_TRAP);
  271. #ifdef JS_THREADSAFE
  272. /* If the API was abused, we must fail for want of the real op. */
  273. if (op == JSOP_TRAP)
  274. return JSTRAP_ERROR;
  275. /* Assume a race with a debugger thread and try to carry on. */
  276. *rval = INT_TO_JSVAL(op);
  277. return JSTRAP_CONTINUE;
  278. #else
  279. /* Always fail if single-threaded (must be an API usage error). */
  280. return JSTRAP_ERROR;
  281. #endif
  282. }
  283. DBG_UNLOCK(cx->runtime);
  284. /*
  285. * It's important that we not use 'trap->' after calling the callback --
  286. * the callback might remove the trap!
  287. */
  288. op = (jsint)trap->op;
  289. status = trap->handler(cx, script, pc, rval, trap->closure);
  290. if (status == JSTRAP_CONTINUE) {
  291. /* By convention, return the true op to the interpreter in rval. */
  292. *rval = INT_TO_JSVAL(op);
  293. }
  294. return status;
  295. }
  296. JS_PUBLIC_API(JSBool)
  297. JS_SetInterrupt(JSRuntime *rt, JSTrapHandler handler, void *closure)
  298. {
  299. rt->globalDebugHooks.interruptHandler = handler;
  300. rt->globalDebugHooks.interruptHandlerData = closure;
  301. return JS_TRUE;
  302. }
  303. JS_PUBLIC_API(JSBool)
  304. JS_ClearInterrupt(JSRuntime *rt, JSTrapHandler *handlerp, void **closurep)
  305. {
  306. if (handlerp)
  307. *handlerp = (JSTrapHandler)rt->globalDebugHooks.interruptHandler;
  308. if (closurep)
  309. *closurep = rt->globalDebugHooks.interruptHandlerData;
  310. rt->globalDebugHooks.interruptHandler = 0;
  311. rt->globalDebugHooks.interruptHandlerData = 0;
  312. return JS_TRUE;
  313. }
  314. /************************************************************************/
  315. typedef struct JSWatchPoint {
  316. JSCList links;
  317. JSObject *object; /* weak link, see js_FinalizeObject */
  318. JSScopeProperty *sprop;
  319. JSPropertyOp setter;
  320. JSWatchPointHandler handler;
  321. void *closure;
  322. uintN flags;
  323. } JSWatchPoint;
  324. #define JSWP_LIVE 0x1 /* live because set and not cleared */
  325. #define JSWP_HELD 0x2 /* held while running handler/setter */
  326. /*
  327. * NB: DropWatchPointAndUnlock releases cx->runtime->debuggerLock in all cases.
  328. */
  329. static JSBool
  330. DropWatchPointAndUnlock(JSContext *cx, JSWatchPoint *wp, uintN flag)
  331. {
  332. JSBool ok, found;
  333. JSScopeProperty *sprop;
  334. JSScope *scope;
  335. JSPropertyOp setter;
  336. ok = JS_TRUE;
  337. wp->flags &= ~flag;
  338. if (wp->flags != 0) {
  339. DBG_UNLOCK(cx->runtime);
  340. return ok;
  341. }
  342. /*
  343. * Remove wp from the list, then if there are no other watchpoints for
  344. * wp->sprop in any scope, restore wp->sprop->setter from wp.
  345. */
  346. ++cx->runtime->debuggerMutations;
  347. JS_REMOVE_LINK(&wp->links);
  348. sprop = wp->sprop;
  349. /*
  350. * Passing null for the scope parameter tells js_GetWatchedSetter to find
  351. * any watch point for sprop, and not to lock or unlock rt->debuggerLock.
  352. * If js_ChangeNativePropertyAttrs fails, propagate failure after removing
  353. * wp->closure's root and freeing wp.
  354. */
  355. setter = js_GetWatchedSetter(cx->runtime, NULL, sprop);
  356. DBG_UNLOCK(cx->runtime);
  357. if (!setter) {
  358. JS_LOCK_OBJ(cx, wp->object);
  359. scope = OBJ_SCOPE(wp->object);
  360. found = (scope->object == wp->object &&
  361. SCOPE_GET_PROPERTY(scope, sprop->id));
  362. JS_UNLOCK_SCOPE(cx, scope);
  363. /*
  364. * If the property wasn't found on wp->object or didn't exist, then
  365. * someone else has dealt with this sprop, and we don't need to change
  366. * the property attributes.
  367. */
  368. if (found) {
  369. sprop = js_ChangeScopePropertyAttrs(cx, scope, sprop,
  370. 0, sprop->attrs,
  371. sprop->getter,
  372. wp->setter);
  373. if (!sprop)
  374. ok = JS_FALSE;
  375. }
  376. }
  377. JS_free(cx, wp);
  378. return ok;
  379. }
  380. /*
  381. * NB: js_TraceWatchPoints does not acquire cx->runtime->debuggerLock, since
  382. * the debugger should never be racing with the GC (i.e., the debugger must
  383. * respect the request model).
  384. */
  385. void
  386. js_TraceWatchPoints(JSTracer *trc, JSObject *obj)
  387. {
  388. JSRuntime *rt;
  389. JSWatchPoint *wp;
  390. rt = trc->context->runtime;
  391. for (wp = (JSWatchPoint *)rt->watchPointList.next;
  392. &wp->links != &rt->watchPointList;
  393. wp = (JSWatchPoint *)wp->links.next) {
  394. if (wp->object == obj) {
  395. TRACE_SCOPE_PROPERTY(trc, wp->sprop);
  396. if ((wp->sprop->attrs & JSPROP_SETTER) && wp->setter) {
  397. JS_CALL_OBJECT_TRACER(trc, (JSObject *)wp->setter,
  398. "wp->setter");
  399. }
  400. JS_SET_TRACING_NAME(trc, "wp->closure");
  401. js_CallValueTracerIfGCThing(trc, (jsval) wp->closure);
  402. }
  403. }
  404. }
  405. void
  406. js_SweepWatchPoints(JSContext *cx)
  407. {
  408. JSRuntime *rt;
  409. JSWatchPoint *wp, *next;
  410. uint32 sample;
  411. rt = cx->runtime;
  412. DBG_LOCK(rt);
  413. for (wp = (JSWatchPoint *)rt->watchPointList.next;
  414. &wp->links != &rt->watchPointList;
  415. wp = next) {
  416. next = (JSWatchPoint *)wp->links.next;
  417. if (js_IsAboutToBeFinalized(cx, wp->object)) {
  418. sample = rt->debuggerMutations;
  419. /* Ignore failures. */
  420. DropWatchPointAndUnlock(cx, wp, JSWP_LIVE);
  421. DBG_LOCK(rt);
  422. if (rt->debuggerMutations != sample + 1)
  423. next = (JSWatchPoint *)rt->watchPointList.next;
  424. }
  425. }
  426. DBG_UNLOCK(rt);
  427. }
  428. /*
  429. * NB: FindWatchPoint must be called with rt->debuggerLock acquired.
  430. */
  431. static JSWatchPoint *
  432. FindWatchPoint(JSRuntime *rt, JSScope *scope, jsid id)
  433. {
  434. JSWatchPoint *wp;
  435. for (wp = (JSWatchPoint *)rt->watchPointList.next;
  436. &wp->links != &rt->watchPointList;
  437. wp = (JSWatchPoint *)wp->links.next) {
  438. if (wp->object == scope->object && wp->sprop->id == id)
  439. return wp;
  440. }
  441. return NULL;
  442. }
  443. JSScopeProperty *
  444. js_FindWatchPoint(JSRuntime *rt, JSScope *scope, jsid id)
  445. {
  446. JSWatchPoint *wp;
  447. JSScopeProperty *sprop;
  448. DBG_LOCK(rt);
  449. wp = FindWatchPoint(rt, scope, id);
  450. sprop = wp ? wp->sprop : NULL;
  451. DBG_UNLOCK(rt);
  452. return sprop;
  453. }
  454. /*
  455. * Secret handshake with DropWatchPointAndUnlock: if (!scope), we know our
  456. * caller has acquired rt->debuggerLock, so we don't have to.
  457. */
  458. JSPropertyOp
  459. js_GetWatchedSetter(JSRuntime *rt, JSScope *scope,
  460. const JSScopeProperty *sprop)
  461. {
  462. JSPropertyOp setter;
  463. JSWatchPoint *wp;
  464. setter = NULL;
  465. if (scope)
  466. DBG_LOCK(rt);
  467. for (wp = (JSWatchPoint *)rt->watchPointList.next;
  468. &wp->links != &rt->watchPointList;
  469. wp = (JSWatchPoint *)wp->links.next) {
  470. if ((!scope || wp->object == scope->object) && wp->sprop == sprop) {
  471. setter = wp->setter;
  472. break;
  473. }
  474. }
  475. if (scope)
  476. DBG_UNLOCK(rt);
  477. return setter;
  478. }
  479. JSBool
  480. js_watch_set(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
  481. {
  482. JSRuntime *rt;
  483. JSWatchPoint *wp;
  484. JSScopeProperty *sprop;
  485. jsval propid, userid;
  486. JSScope *scope;
  487. JSBool ok;
  488. rt = cx->runtime;
  489. DBG_LOCK(rt);
  490. for (wp = (JSWatchPoint *)rt->watchPointList.next;
  491. &wp->links != &rt->watchPointList;
  492. wp = (JSWatchPoint *)wp->links.next) {
  493. sprop = wp->sprop;
  494. if (wp->object == obj && SPROP_USERID(sprop) == id &&
  495. !(wp->flags & JSWP_HELD)) {
  496. wp->flags |= JSWP_HELD;
  497. DBG_UNLOCK(rt);
  498. JS_LOCK_OBJ(cx, obj);
  499. propid = ID_TO_VALUE(sprop->id);
  500. userid = (sprop->flags & SPROP_HAS_SHORTID)
  501. ? INT_TO_JSVAL(sprop->shortid)
  502. : propid;
  503. scope = OBJ_SCOPE(obj);
  504. JS_UNLOCK_OBJ(cx, obj);
  505. /* NB: wp is held, so we can safely dereference it still. */
  506. ok = wp->handler(cx, obj, propid,
  507. SPROP_HAS_VALID_SLOT(sprop, scope)
  508. ? OBJ_GET_SLOT(cx, obj, sprop->slot)
  509. : JSVAL_VOID,
  510. vp, wp->closure);
  511. if (ok) {
  512. /*
  513. * Create a pseudo-frame for the setter invocation so that any
  514. * stack-walking security code under the setter will correctly
  515. * identify the guilty party. So that the watcher appears to
  516. * be active to obj_eval and other such code, point frame.pc
  517. * at the JSOP_STOP at the end of the script.
  518. *
  519. * The pseudo-frame is not created for fast natives as they
  520. * are treated as interpreter frame extensions and always
  521. * trusted.
  522. */
  523. JSObject *closure;
  524. JSClass *clasp;
  525. JSFunction *fun;
  526. JSScript *script;
  527. JSBool injectFrame;
  528. uintN nslots;
  529. jsval smallv[5];
  530. jsval *argv;
  531. JSStackFrame frame;
  532. JSFrameRegs regs;
  533. closure = (JSObject *) wp->closure;
  534. clasp = OBJ_GET_CLASS(cx, closure);
  535. if (clasp == &js_FunctionClass) {
  536. fun = GET_FUNCTION_PRIVATE(cx, closure);
  537. script = FUN_SCRIPT(fun);
  538. } else if (clasp == &js_ScriptClass) {
  539. fun = NULL;
  540. script = (JSScript *) JS_GetPrivate(cx, closure);
  541. } else {
  542. fun = NULL;
  543. script = NULL;
  544. }
  545. nslots = 2;
  546. injectFrame = JS_TRUE;
  547. if (fun) {
  548. nslots += FUN_MINARGS(fun);
  549. if (!FUN_INTERPRETED(fun)) {
  550. nslots += fun->u.n.extra;
  551. injectFrame = !(fun->flags & JSFUN_FAST_NATIVE);
  552. }
  553. }
  554. if (injectFrame) {
  555. if (nslots <= JS_ARRAY_LENGTH(smallv)) {
  556. argv = smallv;
  557. } else {
  558. argv = (jsval *) JS_malloc(cx, nslots * sizeof(jsval));
  559. if (!argv) {
  560. DBG_LOCK(rt);
  561. DropWatchPointAndUnlock(cx, wp, JSWP_HELD);
  562. return JS_FALSE;
  563. }
  564. }
  565. argv[0] = OBJECT_TO_JSVAL(closure);
  566. argv[1] = JSVAL_NULL;
  567. memset(argv + 2, 0, (nslots - 2) * sizeof(jsval));
  568. memset(&frame, 0, sizeof(frame));
  569. frame.script = script;
  570. frame.regs = NULL;
  571. if (script) {
  572. JS_ASSERT(script->length >= JSOP_STOP_LENGTH);
  573. regs.pc = script->code + script->length
  574. - JSOP_STOP_LENGTH;
  575. regs.sp = NULL;
  576. frame.regs = &regs;
  577. }
  578. frame.callee = closure;
  579. frame.fun = fun;
  580. frame.argv = argv + 2;
  581. frame.down = cx->fp;
  582. frame.scopeChain = OBJ_GET_PARENT(cx, closure);
  583. cx->fp = &frame;
  584. }
  585. #ifdef __GNUC__
  586. else
  587. argv = NULL; /* suppress bogus gcc warnings */
  588. #endif
  589. ok = !wp->setter ||
  590. ((sprop->attrs & JSPROP_SETTER)
  591. ? js_InternalCall(cx, obj, OBJECT_TO_JSVAL(wp->setter),
  592. 1, vp, vp)
  593. : wp->setter(cx, OBJ_THIS_OBJECT(cx, obj), userid, vp));
  594. if (injectFrame) {
  595. /* Evil code can cause us to have an arguments object. */
  596. if (frame.callobj)
  597. ok &= js_PutCallObject(cx, &frame);
  598. if (frame.argsobj)
  599. ok &= js_PutArgsObject(cx, &frame);
  600. cx->fp = frame.down;
  601. if (argv != smallv)
  602. JS_free(cx, argv);
  603. }
  604. }
  605. DBG_LOCK(rt);
  606. return DropWatchPointAndUnlock(cx, wp, JSWP_HELD) && ok;
  607. }
  608. }
  609. DBG_UNLOCK(rt);
  610. return JS_TRUE;
  611. }
  612. JSBool
  613. js_watch_set_wrapper(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
  614. jsval *rval)
  615. {
  616. JSObject *funobj;
  617. JSFunction *wrapper;
  618. jsval userid;
  619. funobj = JSVAL_TO_OBJECT(argv[-2]);
  620. JS_ASSERT(OBJ_GET_CLASS(cx, funobj) == &js_FunctionClass);
  621. wrapper = GET_FUNCTION_PRIVATE(cx, funobj);
  622. userid = ATOM_KEY(wrapper->atom);
  623. *rval = argv[0];
  624. return js_watch_set(cx, obj, userid, rval);
  625. }
  626. JSPropertyOp
  627. js_WrapWatchedSetter(JSContext *cx, jsid id, uintN attrs, JSPropertyOp setter)
  628. {
  629. JSAtom *atom;
  630. JSFunction *wrapper;
  631. if (!(attrs & JSPROP_SETTER))
  632. return &js_watch_set; /* & to silence schoolmarmish MSVC */
  633. if (JSID_IS_ATOM(id)) {
  634. atom = JSID_TO_ATOM(id);
  635. } else if (JSID_IS_INT(id)) {
  636. if (!js_ValueToStringId(cx, INT_JSID_TO_JSVAL(id), &id))
  637. return NULL;
  638. atom = JSID_TO_ATOM(id);
  639. } else {
  640. atom = NULL;
  641. }
  642. wrapper = js_NewFunction(cx, NULL, js_watch_set_wrapper, 1, 0,
  643. OBJ_GET_PARENT(cx, (JSObject *)setter),
  644. atom);
  645. if (!wrapper)
  646. return NULL;
  647. return (JSPropertyOp) FUN_OBJECT(wrapper);
  648. }
  649. JS_PUBLIC_API(JSBool)
  650. JS_SetWatchPoint(JSContext *cx, JSObject *obj, jsval idval,
  651. JSWatchPointHandler handler, void *closure)
  652. {
  653. jsid propid;
  654. JSObject *pobj;
  655. JSProperty *prop;
  656. JSScopeProperty *sprop;
  657. JSRuntime *rt;
  658. JSBool ok;
  659. JSWatchPoint *wp;
  660. JSPropertyOp watcher;
  661. if (!OBJ_IS_NATIVE(obj)) {
  662. JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_WATCH,
  663. OBJ_GET_CLASS(cx, obj)->name);
  664. return JS_FALSE;
  665. }
  666. if (JSVAL_IS_INT(idval))
  667. propid = INT_JSVAL_TO_JSID(idval);
  668. else if (!js_ValueToStringId(cx, idval, &propid))
  669. return JS_FALSE;
  670. if (!js_LookupProperty(cx, obj, propid, &pobj, &prop))
  671. return JS_FALSE;
  672. sprop = (JSScopeProperty *) prop;
  673. rt = cx->runtime;
  674. if (!sprop) {
  675. /* Check for a deleted symbol watchpoint, which holds its property. */
  676. sprop = js_FindWatchPoint(rt, OBJ_SCOPE(obj), propid);
  677. if (!sprop) {
  678. /* Make a new property in obj so we can watch for the first set. */
  679. if (!js_DefineProperty(cx, obj, propid, JSVAL_VOID,
  680. NULL, NULL, JSPROP_ENUMERATE,
  681. &prop)) {
  682. return JS_FALSE;
  683. }
  684. sprop = (JSScopeProperty *) prop;
  685. }
  686. } else if (pobj != obj) {
  687. /* Clone the prototype property so we can watch the right object. */
  688. jsval value;
  689. JSPropertyOp getter, setter;
  690. uintN attrs, flags;
  691. intN shortid;
  692. if (OBJ_IS_NATIVE(pobj)) {
  693. value = SPROP_HAS_VALID_SLOT(sprop, OBJ_SCOPE(pobj))
  694. ? LOCKED_OBJ_GET_SLOT(pobj, sprop->slot)
  695. : JSVAL_VOID;
  696. getter = sprop->getter;
  697. setter = sprop->setter;
  698. attrs = sprop->attrs;
  699. flags = sprop->flags;
  700. shortid = sprop->shortid;
  701. } else {
  702. if (!OBJ_GET_PROPERTY(cx, pobj, propid, &value) ||
  703. !OBJ_GET_ATTRIBUTES(cx, pobj, propid, prop, &attrs)) {
  704. OBJ_DROP_PROPERTY(cx, pobj, prop);
  705. return JS_FALSE;
  706. }
  707. getter = setter = NULL;
  708. flags = 0;
  709. shortid = 0;
  710. }
  711. OBJ_DROP_PROPERTY(cx, pobj, prop);
  712. /* Recall that obj is native, whether or not pobj is native. */
  713. if (!js_DefineNativeProperty(cx, obj, propid, value, getter, setter,
  714. attrs, flags, shortid, &prop)) {
  715. return JS_FALSE;
  716. }
  717. sprop = (JSScopeProperty *) prop;
  718. }
  719. /*
  720. * At this point, prop/sprop exists in obj, obj is locked, and we must
  721. * OBJ_DROP_PROPERTY(cx, obj, prop) before returning.
  722. */
  723. ok = JS_TRUE;
  724. DBG_LOCK(rt);
  725. wp = FindWatchPoint(rt, OBJ_SCOPE(obj), propid);
  726. if (!wp) {
  727. DBG_UNLOCK(rt);
  728. watcher = js_WrapWatchedSetter(cx, propid, sprop->attrs, sprop->setter);
  729. if (!watcher) {
  730. ok = JS_FALSE;
  731. goto out;
  732. }
  733. wp = (JSWatchPoint *) JS_malloc(cx, sizeof *wp);
  734. if (!wp) {
  735. ok = JS_FALSE;
  736. goto out;
  737. }
  738. wp->handler = NULL;
  739. wp->closure = NULL;
  740. wp->object = obj;
  741. JS_ASSERT(sprop->setter != js_watch_set || pobj != obj);
  742. wp->setter = sprop->setter;
  743. wp->flags = JSWP_LIVE;
  744. /* XXXbe nest in obj lock here */
  745. sprop = js_ChangeNativePropertyAttrs(cx, obj, sprop, 0, sprop->attrs,
  746. sprop->getter, watcher);
  747. if (!sprop) {
  748. /* Self-link so DropWatchPointAndUnlock can JS_REMOVE_LINK it. */
  749. JS_INIT_CLIST(&wp->links);
  750. DBG_LOCK(rt);
  751. DropWatchPointAndUnlock(cx, wp, JSWP_LIVE);
  752. ok = JS_FALSE;
  753. goto out;
  754. }
  755. wp->sprop = sprop;
  756. /*
  757. * Now that wp is fully initialized, append it to rt's wp list.
  758. * Because obj is locked we know that no other thread could have added
  759. * a watchpoint for (obj, propid).
  760. */
  761. DBG_LOCK(rt);
  762. JS_ASSERT(!FindWatchPoint(rt, OBJ_SCOPE(obj), propid));
  763. JS_APPEND_LINK(&wp->links, &rt->watchPointList);
  764. ++rt->debuggerMutations;
  765. }
  766. wp->handler = handler;
  767. wp->closure = closure;
  768. DBG_UNLOCK(rt);
  769. out:
  770. OBJ_DROP_PROPERTY(cx, obj, prop);
  771. return ok;
  772. }
  773. JS_PUBLIC_API(JSBool)
  774. JS_ClearWatchPoint(JSContext *cx, JSObject *obj, jsval id,
  775. JSWatchPointHandler *handlerp, void **closurep)
  776. {
  777. JSRuntime *rt;
  778. JSWatchPoint *wp;
  779. rt = cx->runtime;
  780. DBG_LOCK(rt);
  781. for (wp = (JSWatchPoint *)rt->watchPointList.next;
  782. &wp->links != &rt->watchPointList;
  783. wp = (JSWatchPoint *)wp->links.next) {
  784. if (wp->object == obj && SPROP_USERID(wp->sprop) == id) {
  785. if (handlerp)
  786. *handlerp = wp->handler;
  787. if (closurep)
  788. *closurep = wp->closure;
  789. return DropWatchPointAndUnlock(cx, wp, JSWP_LIVE);
  790. }
  791. }
  792. DBG_UNLOCK(rt);
  793. if (handlerp)
  794. *handlerp = NULL;
  795. if (closurep)
  796. *closurep = NULL;
  797. return JS_TRUE;
  798. }
  799. JS_PUBLIC_API(JSBool)
  800. JS_ClearWatchPointsForObject(JSContext *cx, JSObject *obj)
  801. {
  802. JSRuntime *rt;
  803. JSWatchPoint *wp, *next;
  804. uint32 sample;
  805. rt = cx->runtime;
  806. DBG_LOCK(rt);
  807. for (wp = (JSWatchPoint *)rt->watchPointList.next;
  808. &wp->links != &rt->watchPointList;
  809. wp = next) {
  810. next = (JSWatchPoint *)wp->links.next;
  811. if (wp->object == obj) {
  812. sample = rt->debuggerMutations;
  813. if (!DropWatchPointAndUnlock(cx, wp, JSWP_LIVE))
  814. return JS_FALSE;
  815. DBG_LOCK(rt);
  816. if (rt->debuggerMutations != sample + 1)
  817. next = (JSWatchPoint *)rt->watchPointList.next;
  818. }
  819. }
  820. DBG_UNLOCK(rt);
  821. return JS_TRUE;
  822. }
  823. JS_PUBLIC_API(JSBool)
  824. JS_ClearAllWatchPoints(JSContext *cx)
  825. {
  826. JSRuntime *rt;
  827. JSWatchPoint *wp, *next;
  828. uint32 sample;
  829. rt = cx->runtime;
  830. DBG_LOCK(rt);
  831. for (wp = (JSWatchPoint *)rt->watchPointList.next;
  832. &wp->links != &rt->watchPointList;
  833. wp = next) {
  834. next = (JSWatchPoint *)wp->links.next;
  835. sample = rt->debuggerMutations;
  836. if (!DropWatchPointAndUnlock(cx, wp, JSWP_LIVE))
  837. return JS_FALSE;
  838. DBG_LOCK(rt);
  839. if (rt->debuggerMutations != sample + 1)
  840. next = (JSWatchPoint *)rt->watchPointList.next;
  841. }
  842. DBG_UNLOCK(rt);
  843. return JS_TRUE;
  844. }
  845. /************************************************************************/
  846. JS_PUBLIC_API(uintN)
  847. JS_PCToLineNumber(JSContext *cx, JSScript *script, jsbytecode *pc)
  848. {
  849. return js_PCToLineNumber(cx, script, pc);
  850. }
  851. JS_PUBLIC_API(jsbytecode *)
  852. JS_LineNumberToPC(JSContext *cx, JSScript *script, uintN lineno)
  853. {
  854. return js_LineNumberToPC(script, lineno);
  855. }
  856. JS_PUBLIC_API(JSScript *)
  857. JS_GetFunctionScript(JSContext *cx, JSFunction *fun)
  858. {
  859. return FUN_SCRIPT(fun);
  860. }
  861. JS_PUBLIC_API(JSNative)
  862. JS_GetFunctionNative(JSContext *cx, JSFunction *fun)
  863. {
  864. return FUN_NATIVE(fun);
  865. }
  866. JS_PUBLIC_API(JSFastNative)
  867. JS_GetFunctionFastNative(JSContext *cx, JSFunction *fun)
  868. {
  869. return FUN_FAST_NATIVE(fun);
  870. }
  871. JS_PUBLIC_API(JSPrincipals *)
  872. JS_GetScriptPrincipals(JSContext *cx, JSScript *script)
  873. {
  874. return script->principals;
  875. }
  876. /************************************************************************/
  877. /*
  878. * Stack Frame Iterator
  879. */
  880. JS_PUBLIC_API(JSStackFrame *)
  881. JS_FrameIterator(JSContext *cx, JSStackFrame **iteratorp)
  882. {
  883. *iteratorp = (*iteratorp == NULL) ? cx->fp : (*iteratorp)->down;
  884. return *iteratorp;
  885. }
  886. JS_PUBLIC_API(JSScript *)
  887. JS_GetFrameScript(JSContext *cx, JSStackFrame *fp)
  888. {
  889. return fp->script;
  890. }
  891. JS_PUBLIC_API(jsbytecode *)
  892. JS_GetFramePC(JSContext *cx, JSStackFrame *fp)
  893. {
  894. return fp->regs ? fp->regs->pc : NULL;
  895. }
  896. JS_PUBLIC_API(JSStackFrame *)
  897. JS_GetScriptedCaller(JSContext *cx, JSStackFrame *fp)
  898. {
  899. if (!fp)
  900. fp = cx->fp;
  901. while (fp) {
  902. if (fp->script)
  903. return fp;
  904. fp = fp->down;
  905. }
  906. return NULL;
  907. }
  908. JS_PUBLIC_API(JSPrincipals *)
  909. JS_StackFramePrincipals(JSContext *cx, JSStackFrame *fp)
  910. {
  911. JSSecurityCallbacks *callbacks;
  912. if (fp->fun) {
  913. callbacks = JS_GetSecurityCallbacks(cx);
  914. if (callbacks && callbacks->findObjectPrincipals) {
  915. if (FUN_OBJECT(fp->fun) != fp->callee)
  916. return callbacks->findObjectPrincipals(cx, fp->callee);
  917. /* FALL THROUGH */
  918. }
  919. }
  920. if (fp->script)
  921. return fp->script->principals;
  922. return NULL;
  923. }
  924. JS_PUBLIC_API(JSPrincipals *)
  925. JS_EvalFramePrincipals(JSContext *cx, JSStackFrame *fp, JSStackFrame *caller)
  926. {
  927. JSPrincipals *principals, *callerPrincipals;
  928. JSSecurityCallbacks *callbacks;
  929. callbacks = JS_GetSecurityCallbacks(cx);
  930. if (callbacks && callbacks->findObjectPrincipals) {
  931. principals = callbacks->findObjectPrincipals(cx, fp->callee);
  932. } else {
  933. principals = NULL;
  934. }
  935. if (!caller)
  936. return principals;
  937. callerPrincipals = JS_StackFramePrincipals(cx, caller);
  938. return (callerPrincipals && principals &&
  939. callerPrincipals->subsume(callerPrincipals, principals))
  940. ? principals
  941. : callerPrincipals;
  942. }
  943. JS_PUBLIC_API(void *)
  944. JS_GetFrameAnnotation(JSContext *cx, JSStackFrame *fp)
  945. {
  946. if (fp->annotation && fp->script) {
  947. JSPrincipals *principals = JS_StackFramePrincipals(cx, fp);
  948. if (principals && principals->globalPrivilegesEnabled(cx, principals)) {
  949. /*
  950. * Give out an annotation only if privileges have not been revoked
  951. * or disabled globally.
  952. */
  953. return fp->annotation;
  954. }
  955. }
  956. return NULL;
  957. }
  958. JS_PUBLIC_API(void)
  959. JS_SetFrameAnnotation(JSContext *cx, JSStackFrame *fp, void *annotation)
  960. {
  961. fp->annotation = annotation;
  962. }
  963. JS_PUBLIC_API(void *)
  964. JS_GetFramePrincipalArray(JSContext *cx, JSStackFrame *fp)
  965. {
  966. JSPrincipals *principals;
  967. principals = JS_StackFramePrincipals(cx, fp);
  968. if (!principals)
  969. return NULL;
  970. return principals->getPrincipalArray(cx, principals);
  971. }
  972. JS_PUBLIC_API(JSBool)
  973. JS_IsNativeFrame(JSContext *cx, JSStackFrame *fp)
  974. {
  975. return !fp->script;
  976. }
  977. /* this is deprecated, use JS_GetFrameScopeChain instead */
  978. JS_PUBLIC_API(JSObject *)
  979. JS_GetFrameObject(JSContext *cx, JSStackFrame *fp)
  980. {
  981. return fp->scopeChain;
  982. }
  983. JS_PUBLIC_API(JSObject *)
  984. JS_GetFrameScopeChain(JSContext *cx, JSStackFrame *fp)
  985. {
  986. /* Force creation of argument and call objects if not yet created */
  987. (void) JS_GetFrameCallObject(cx, fp);
  988. return js_GetScopeChain(cx, fp);
  989. }
  990. JS_PUBLIC_API(JSObject *)
  991. JS_GetFrameCallObject(JSContext *cx, JSStackFrame *fp)
  992. {
  993. if (! fp->fun)
  994. return NULL;
  995. /* Force creation of argument object if not yet created */
  996. (void) js_GetArgsObject(cx, fp);
  997. /*
  998. * XXX ill-defined: null return here means error was reported, unlike a
  999. * null returned above or in the #else
  1000. */
  1001. return js_GetCallObject(cx, fp, NULL);
  1002. }
  1003. JS_PUBLIC_API(JSObject *)
  1004. JS_GetFrameThis(JSContext *cx, JSStackFrame *fp)
  1005. {
  1006. JSStackFrame *afp;
  1007. if (fp->flags & JSFRAME_COMPUTED_THIS)
  1008. return fp->thisp;
  1009. /* js_ComputeThis gets confused if fp != cx->fp, so set it aside. */
  1010. if (cx->fp != fp) {
  1011. afp = cx->fp;
  1012. if (afp) {
  1013. afp->dormantNext = cx->dormantFrameChain;
  1014. cx->dormantFrameChain = afp;
  1015. cx->fp = fp;
  1016. }
  1017. } else {
  1018. afp = NULL;
  1019. }
  1020. if (!fp->thisp && fp->argv)
  1021. fp->thisp = js_ComputeThis(cx, JS_TRUE, fp->argv);
  1022. if (afp) {
  1023. cx->fp = afp;
  1024. cx->dormantFrameChain = afp->dormantNext;
  1025. afp->dormantNext = NULL;
  1026. }
  1027. return fp->thisp;
  1028. }
  1029. JS_PUBLIC_API(JSFunction *)
  1030. JS_GetFrameFunction(JSContext *cx, JSStackFrame *fp)
  1031. {
  1032. return fp->fun;
  1033. }
  1034. JS_PUBLIC_API(JSObject *)
  1035. JS_GetFrameFunctionObject(JSContext *cx, JSStackFrame *fp)
  1036. {
  1037. if (!fp->fun)
  1038. return NULL;
  1039. JS_ASSERT(OBJ_GET_CLASS(cx, fp->callee) == &js_FunctionClass);
  1040. JS_ASSERT(OBJ_GET_PRIVATE(cx, fp->callee) == fp->fun);
  1041. return fp->callee;
  1042. }
  1043. JS_PUBLIC_API(JSBool)
  1044. JS_IsConstructorFrame(JSContext *cx, JSStackFrame *fp)
  1045. {
  1046. return (fp->flags & JSFRAME_CONSTRUCTING) != 0;
  1047. }
  1048. JS_PUBLIC_API(JSObject *)
  1049. JS_GetFrameCalleeObject(JSContext *cx, JSStackFrame *fp)
  1050. {
  1051. return fp->callee;
  1052. }
  1053. JS_PUBLIC_API(JSBool)
  1054. JS_IsDebuggerFrame(JSContext *cx, JSStackFrame *fp)
  1055. {
  1056. return (fp->flags & JSFRAME_DEBUGGER) != 0;
  1057. }
  1058. JS_PUBLIC_API(jsval)
  1059. JS_GetFrameReturnValue(JSContext *cx, JSStackFrame *fp)
  1060. {
  1061. return fp->rval;
  1062. }
  1063. JS_PUBLIC_API(void)
  1064. JS_SetFrameReturnValue(JSContext *cx, JSStackFrame *fp, jsval rval)
  1065. {
  1066. fp->rval = rval;
  1067. }
  1068. /************************************************************************/
  1069. JS_PUBLIC_API(const char *)
  1070. JS_GetScriptFilename(JSContext *cx, JSScript *script)
  1071. {
  1072. return script->filename;
  1073. }
  1074. JS_PUBLIC_API(uintN)
  1075. JS_GetScriptBaseLineNumber(JSContext *cx, JSScript *script)
  1076. {
  1077. return script->lineno;
  1078. }
  1079. JS_PUBLIC_API(uintN)
  1080. JS_GetScriptLineExtent(JSContext *cx, JSScript *script)
  1081. {
  1082. return js_GetScriptLineExtent(script);
  1083. }
  1084. JS_PUBLIC_API(JSVersion)
  1085. JS_GetScriptVersion(JSContext *cx, JSScript *script)
  1086. {
  1087. return (JSVersion) (script->version & JSVERSION_MASK);
  1088. }
  1089. /***************************************************************************/
  1090. JS_PUBLIC_API(void)
  1091. JS_SetNewScriptHook(JSRuntime *rt, JSNewScriptHook hook, void *callerdata)
  1092. {
  1093. rt->globalDebugHooks.newScriptHook = hook;
  1094. rt->globalDebugHooks.newScriptHookData = callerdata;
  1095. }
  1096. JS_PUBLIC_API(void)
  1097. JS_SetDestroyScriptHook(JSRuntime *rt, JSDestroyScriptHook hook,
  1098. void *callerdata)
  1099. {
  1100. rt->globalDebugHooks.destroyScriptHook = hook;
  1101. rt->globalDebugHooks.destroyScriptHookData = callerdata;
  1102. }
  1103. /***************************************************************************/
  1104. JS_PUBLIC_API(JSBool)
  1105. JS_EvaluateUCInStackFrame(JSContext *cx, JSStackFrame *fp,
  1106. const jschar *chars, uintN length,
  1107. const char *filename, uintN lineno,
  1108. jsval *rval)
  1109. {
  1110. JSObject *scobj;
  1111. JSScript *script;
  1112. JSBool ok;
  1113. scobj = JS_GetFrameScopeChain(cx, fp);
  1114. if (!scobj)
  1115. return JS_FALSE;
  1116. script = js_CompileScript(cx, scobj, fp, JS_StackFramePrincipals(cx, fp),
  1117. TCF_COMPILE_N_GO |
  1118. TCF_PUT_STATIC_DEPTH(fp->script->staticDepth + 1),
  1119. chars, length, NULL,
  1120. filename, lineno);
  1121. if (!script)
  1122. return JS_FALSE;
  1123. ok = js_Execute(cx, scobj, script, fp, JSFRAME_DEBUGGER | JSFRAME_EVAL,
  1124. rval);
  1125. js_DestroyScript(cx, script);
  1126. return ok;
  1127. }
  1128. JS_PUBLIC_API(JSBool)
  1129. JS_EvaluateInStackFrame(JSContext *cx, JSStackFrame *fp,
  1130. const char *bytes, uintN length,
  1131. const char *filename, uintN lineno,
  1132. jsval *rval)
  1133. {
  1134. jschar *chars;
  1135. JSBool ok;
  1136. size_t len = length;
  1137. chars = js_InflateString(cx, bytes, &len);
  1138. if (!chars)
  1139. return JS_FALSE;
  1140. length = (uintN) len;
  1141. ok = JS_EvaluateUCInStackFrame(cx, fp, chars, length, filename, lineno,
  1142. rval);
  1143. JS_free(cx, chars);
  1144. return ok;
  1145. }
  1146. /************************************************************************/
  1147. /* XXXbe this all needs to be reworked to avoid requiring JSScope types. */
  1148. JS_PUBLIC_API(JSScopeProperty *)
  1149. JS_PropertyIterator(JSObject *obj, JSScopeProperty **iteratorp)
  1150. {
  1151. JSScopeProperty *sprop;
  1152. JSScope *scope;
  1153. sprop = *iteratorp;
  1154. scope = OBJ_SCOPE(obj);
  1155. /* XXXbe minor(?) incompatibility: iterate in reverse definition order */
  1156. if (!sprop) {
  1157. sprop = SCOPE_LAST_PROP(scope);
  1158. } else {
  1159. while ((sprop = sprop->parent) != NULL) {
  1160. if (!SCOPE_HAD_MIDDLE_DELETE(scope))
  1161. break;
  1162. if (SCOPE_HAS_PROPERTY(scope, sprop))
  1163. break;
  1164. }
  1165. }
  1166. *iteratorp = sprop;
  1167. return sprop;
  1168. }
  1169. JS_PUBLIC_API(JSBool)
  1170. JS_GetPropertyDesc(JSContext *cx, JSObject *obj, JSScopeProperty *sprop,
  1171. JSPropertyDesc *pd)
  1172. {
  1173. JSScope *scope;
  1174. JSScopeProperty *aprop;
  1175. jsval lastException;
  1176. JSBool wasThrowing;
  1177. pd->id = ID_TO_VALUE(sprop->id);
  1178. wasThrowing = cx->throwing;
  1179. if (wasThrowing) {
  1180. lastException = cx->exception;
  1181. if (JSVAL_IS_GCTHING(lastException) &&
  1182. !js_AddRoot(cx, &lastException, "lastException")) {
  1183. return JS_FALSE;
  1184. }
  1185. cx->throwing = JS_FALSE;
  1186. }
  1187. if (!js_GetProperty(cx, obj, sprop->id, &pd->value)) {
  1188. if (!cx->throwing) {
  1189. pd->flags = JSPD_ERROR;
  1190. pd->value = JSVAL_VOID;
  1191. } else {
  1192. pd->flags = JSPD_EXCEPTION;
  1193. pd->value = cx->exception;
  1194. }
  1195. } else {
  1196. pd->flags = 0;
  1197. }
  1198. cx->throwing = wasThrowing;
  1199. if (wasThrowing) {
  1200. cx->exception = lastException;
  1201. if (JSVAL_IS_GCTHING(lastException))
  1202. js_RemoveRoot(cx->runtime, &lastException);
  1203. }
  1204. pd->flags |= ((sprop->attrs & JSPROP_ENUMERATE) ? JSPD_ENUMERATE : 0)
  1205. | ((sprop->attrs & JSPROP_READONLY) ? JSPD_READONLY : 0)
  1206. | ((sprop->attrs & JSPROP_PERMANENT) ? JSPD_PERMANENT : 0);
  1207. pd->spare = 0;
  1208. if (sprop->getter == js_GetCallArg) {
  1209. pd->slot = sprop->shortid;
  1210. pd->flags |= JSPD_ARGUMENT;
  1211. } else if (sprop->getter == js_GetCallVar) {
  1212. pd->slot = sprop->shortid;
  1213. pd->flags |= JSPD_VARIABLE;
  1214. } else {
  1215. pd->slot = 0;
  1216. }
  1217. pd->alias = JSVAL_VOID;
  1218. scope = OBJ_SCOPE(obj);
  1219. if (SPROP_HAS_VALID_SLOT(sprop, scope)) {
  1220. for (aprop = SCOPE_LAST_PROP(scope); aprop; aprop = aprop->parent) {
  1221. if (aprop != sprop && aprop->slot == sprop->slot) {
  1222. pd->alias = ID_TO_VALUE(aprop->id);
  1223. break;
  1224. }
  1225. }
  1226. }
  1227. return JS_TRUE;
  1228. }
  1229. JS_PUBLIC_API(JSBool)
  1230. JS_GetPropertyDescArray(JSContext *cx, JSObject *obj, JSPropertyDescArray *pda)
  1231. {
  1232. JSClass *clasp;
  1233. JSScope *scope;
  1234. uint32 i, n;
  1235. JSPropertyDesc *pd;
  1236. JSScopeProperty *sprop;
  1237. clasp = OBJ_GET_CLASS(cx, obj);
  1238. if (!OBJ_IS_NATIVE(obj) || (clasp->flags & JSCLASS_NEW_ENUMERATE)) {
  1239. JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
  1240. JSMSG_CANT_DESCRIBE_PROPS, clasp->name);
  1241. return JS_FALSE;
  1242. }
  1243. if (!clasp->enumerate(cx, obj))
  1244. return JS_FALSE;
  1245. /* have no props, or object's scope has not mutated from that of proto */
  1246. scope = OBJ_SCOPE(obj);
  1247. if (scope->object != obj || scope->entryCount == 0) {
  1248. pda->length = 0;
  1249. pda->array = NULL;
  1250. return JS_TRUE;
  1251. }
  1252. n = STOBJ_NSLOTS(obj);
  1253. if (n > scope->entryCount)
  1254. n = scope->entryCount;
  1255. pd = (JSPropertyDesc *) JS_malloc(cx, (size_t)n * sizeof(JSPropertyDesc));
  1256. if (!pd)
  1257. return JS_FALSE;
  1258. i = 0;
  1259. for (sprop = SCOPE_LAST_PROP(scope); sprop; sprop = sprop->parent) {
  1260. if (SCOPE_HAD_MIDDLE_DELETE(scope) && !SCOPE_HAS_PROPERTY(scope, sprop))
  1261. continue;
  1262. if (!js_AddRoot(cx, &pd[i].id, NULL))
  1263. goto bad;
  1264. if (!js_AddRoot(cx, &pd[i].value, NULL))
  1265. goto bad;
  1266. if (!JS_GetPropertyDesc(cx, obj, sprop, &pd[i]))
  1267. goto bad;
  1268. if ((pd[i].flags & JSPD_ALIAS) && !js_AddRoot(cx, &pd[i].alias, NULL))
  1269. goto bad;
  1270. if (++i == n)
  1271. break;
  1272. }
  1273. pda->length = i;
  1274. pda->array = pd;
  1275. return JS_TRUE;
  1276. bad:
  1277. pda->length = i + 1;
  1278. pda->array = pd;
  1279. JS_PutPropertyDescArray(cx, pda);
  1280. return JS_FALSE;
  1281. }
  1282. JS_PUBLIC_API(void)
  1283. JS_PutPropertyDescArray(JSContext *cx, JSPropertyDescArray *pda)
  1284. {
  1285. JSPropertyDesc *pd;
  1286. uint32 i;
  1287. pd = pda->array;
  1288. for (i = 0; i < pda->length; i++) {
  1289. js_RemoveRoot(cx->runtime, &pd[i].id);
  1290. js_RemoveRoot(cx->runtime, &pd[i].value);
  1291. if (pd[i].flags & JSPD_ALIAS)
  1292. js_RemoveRoot(cx->runtime, &pd[i].alias);
  1293. }
  1294. JS_free(cx, pd);
  1295. }
  1296. /************************************************************************/
  1297. JS_PUBLIC_API(JSBool)
  1298. JS_SetDebuggerHandler(JSRuntime *rt, JSTrapHandler handler, void *closure)
  1299. {
  1300. rt->globalDebugHooks.debuggerHandler = handler;
  1301. rt->globalDebugHooks.debuggerHandlerData = closure;
  1302. return JS_TRUE;
  1303. }
  1304. JS_PUBLIC_API(JSBool)
  1305. JS_SetSourceHandler(JSRuntime *rt, JSSourceHandler handler, void *closure)
  1306. {
  1307. rt->globalDebugHooks.sourceHandler = handler;
  1308. rt->globalDebugHooks.sourceHandlerData = closure;
  1309. return JS_TRUE;
  1310. }
  1311. JS_PUBLIC_API(JSBool)
  1312. JS_SetExecuteHook(JSRuntime *rt, JSInterpreterHook hook, void *closure)
  1313. {
  1314. rt->globalDebugHooks.executeHook = hook;
  1315. rt->globalDebugHooks.executeHookData = closure;
  1316. return JS_TRUE;
  1317. }
  1318. JS_PUBLIC_API(JSBool)
  1319. JS_SetCallHook(JSRuntime *rt, JSInterpreterHook hook, void *closure)
  1320. {
  1321. rt->globalDebugHooks.callHook = hook;
  1322. rt->globalDebugHooks.callHookData = closure;
  1323. return JS_TRUE;
  1324. }
  1325. JS_PUBLIC_API(JSBool)
  1326. JS_SetObjectHook(JSRuntime *rt, JSObjectHook hook, void *closure)
  1327. {
  1328. rt->globalDebugHooks.objectHook = hook;
  1329. rt->globalDebugHooks.objectHookData = closure;
  1330. return JS_TRUE;
  1331. }
  1332. JS_PUBLIC_API(JSBool)
  1333. JS_SetThrowHook(JSRuntime *rt, JSTrapHandler hook, void *closure)
  1334. {
  1335. rt->globalDebugHooks.throwHook = hook;
  1336. rt->globalDebugHooks.throwHookData = closure;
  1337. return JS_TRUE;
  1338. }
  1339. JS_PUBLIC_API(JSBool)
  1340. JS_SetDebugErrorHook(JSRuntime *rt, JSDebugErrorHook hook, void *closure)
  1341. {
  1342. rt->globalDebugHooks.debugErrorHook = hook;
  1343. rt->globalDebugHooks.debugErrorHookData = closure;
  1344. return JS_TRUE;
  1345. }
  1346. /************************************************************************/
  1347. JS_PUBLIC_API(size_t)
  1348. JS_GetObjectTotalSize(JSContext *cx, JSObject *obj)
  1349. {
  1350. size_t nbytes;
  1351. JSScope *scope;
  1352. nbytes = sizeof *obj;
  1353. if (obj->dslots) {
  1354. nbytes += ((uint32)obj->dslots[-1] - JS_INITIAL_NSLOTS + 1)
  1355. * sizeof obj->dslots[0];
  1356. }
  1357. if (OBJ_IS_NATIVE(obj)) {
  1358. scope = OBJ_SCOPE(obj);
  1359. if (scope->object == obj) {
  1360. nbytes += sizeof *scope;
  1361. nbytes += SCOPE_CAPACITY(scope) * sizeof(JSScopeProperty *);
  1362. }
  1363. }
  1364. return nbytes;
  1365. }
  1366. static size_t
  1367. GetAtomTotalSize(JSContext *cx, JSAtom *atom)
  1368. {
  1369. size_t nbytes;
  1370. nbytes = sizeof(JSAtom *) + sizeof(JSDHashEntryStub);
  1371. if (ATOM_IS_STRING(atom)) {
  1372. nbytes += sizeof(JSString);
  1373. nbytes += (JSFLATSTR_LENGTH(ATOM_TO_STRING(atom)) + 1) * sizeof(jschar);
  1374. } else if (ATOM_IS_DOUBLE(atom)) {
  1375. nbytes += sizeof(jsdouble);
  1376. }
  1377. return nbytes;
  1378. }
  1379. JS_PUBLIC_API(size_t)
  1380. JS_GetFunctionTotalSize(JSContext *cx, JSFunction *fun)
  1381. {
  1382. size_t nbytes;
  1383. nbytes = sizeof *fun;
  1384. nbytes += JS_GetObjectTotalSize(cx, FUN_OBJECT(fun));
  1385. if (FUN_INTERPRETED(fun))
  1386. nbytes += JS_GetScriptTotalSize(cx, fun->u.i.script);
  1387. if (fun->atom)
  1388. nbytes += GetAtomTotalSize(cx, fun->atom);
  1389. return nbytes;
  1390. }
  1391. #include "jsemit.h"
  1392. JS_PUBLIC_API(size_t)
  1393. JS_GetScriptTotalSize(JSContext *cx, JSScript *script)
  1394. {
  1395. size_t nbytes, pbytes;
  1396. jsatomid i;
  1397. jssrcnote *sn, *notes;
  1398. JSObjectArray *objarray;
  1399. JSPrincipals *principals;
  1400. nbytes = sizeof *script;
  1401. if (script->u.object)
  1402. nbytes += JS_GetObjectTotalSize(cx, script->u.object);
  1403. nbytes += script->length * sizeof script->code[0];
  1404. nbytes += script->atomMap.length * sizeof script->atomMap.vector[0];
  1405. for (i = 0; i < script->atomMap.length; i++)
  1406. nbytes += GetAtomTotalSize(cx, script->atomMap.vector[i]);
  1407. if (script->filename)
  1408. nbytes += strlen(script->filename) + 1;
  1409. notes = SCRIPT_NOTES(script);
  1410. for (sn = notes; !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn))
  1411. continue;
  1412. nbytes += (sn - notes + 1) * sizeof *sn;
  1413. if (script->objectsOffset != 0) {
  1414. objarray = JS_SCRIPT_OBJECTS(script);
  1415. i = objarray->length;
  1416. nbytes += sizeof *objarray + i * sizeof objarray->vector[0];
  1417. do {
  1418. nbytes += JS_GetObjectTotalSize(cx, objarray->vector[--i]);
  1419. } while (i != 0);
  1420. }
  1421. if (script->regexpsOffset != 0) {
  1422. objarray = JS_SCRIPT_REGEXPS(script);
  1423. i = objarray->length;
  1424. nbytes += sizeof *objarray + i * sizeof objarray->vector[0];
  1425. do {
  1426. nbytes += JS_GetObjectTotalSize(cx, objarray->vector[--i]);
  1427. } while (i != 0);
  1428. }
  1429. if (script->trynotesOffset != 0) {
  1430. nbytes += sizeof(JSTryNoteArray) +
  1431. JS_SCRIPT_TRYNOTES(script)->length * sizeof(JSTryNote);
  1432. }
  1433. principals = script->principals;
  1434. if (principals) {
  1435. JS_ASSERT(principals->refcount);
  1436. pbytes = sizeof *principals;
  1437. if (principals->refcount > 1)
  1438. pbytes = JS_HOWMANY(pbytes, principals->refcount);
  1439. nbytes += pbytes;
  1440. }
  1441. return nbytes;
  1442. }
  1443. JS_PUBLIC_API(uint32)
  1444. JS_GetTopScriptFilenameFlags(JSContext *cx, JSStackFrame *fp)
  1445. {
  1446. if (!fp)
  1447. fp = cx->fp;
  1448. while (fp) {
  1449. if (fp->script)
  1450. return JS_GetScriptFilenameFlags(fp->script);
  1451. fp = fp->down;
  1452. }
  1453. return 0;
  1454. }
  1455. JS_PUBLIC_API(uint32)
  1456. JS_GetScriptFilenameFlags(JSScript *script)
  1457. {
  1458. JS_ASSERT(script);
  1459. if (!script->filename)
  1460. return JSFILENAME_NULL;
  1461. return js_GetScriptFilenameFlags(script->filename);
  1462. }
  1463. JS_PUBLIC_API(JSBool)
  1464. JS_FlagScriptFilenamePrefix(JSRuntime *rt, const char *prefix, uint32 flags)
  1465. {
  1466. if (!js_SaveScriptFilenameRT(rt, prefix, flags))
  1467. return JS_FALSE;
  1468. return JS_TRUE;
  1469. }
  1470. JS_PUBLIC_API(JSBool)
  1471. JS_IsSystemObject(JSContext *cx, JSObject *obj)
  1472. {
  1473. return STOBJ_IS_SYSTEM(obj);
  1474. }
  1475. JS_PUBLIC_API(JSObject *)
  1476. JS_NewSystemObject(JSContext *cx, JSClass *clasp, JSObject *proto,
  1477. JSObject *parent, JSBool system)
  1478. {
  1479. JSObject *obj;
  1480. obj = js_NewObject(cx, clasp, proto, parent, 0);
  1481. if (obj && system)
  1482. STOBJ_SET_SYSTEM(obj);
  1483. return obj;
  1484. }
  1485. /************************************************************************/
  1486. JS_PUBLIC_API(JSDebugHooks *)
  1487. JS_GetGlobalDebugHooks(JSRuntime *rt)
  1488. {
  1489. return &rt->globalDebugHooks;
  1490. }
  1491. JS_PUBLIC_API(JSDebugHooks *)
  1492. JS_SetContextDebugHooks(JSContext *cx, JSDebugHooks *hooks)
  1493. {
  1494. JSDebugHooks *old;
  1495. JS_ASSERT(hooks);
  1496. old = cx->debugHooks;
  1497. cx->debugHooks = hooks;
  1498. return old;
  1499. }
  1500. #ifdef MOZ_SHARK
  1501. #include <CHUD/CHUD.h>
  1502. JS_PUBLIC_API(JSBool)
  1503. JS_StartChudRemote()
  1504. {
  1505. if (chudIsRemoteAccessAcquired() &&
  1506. (chudStartRemotePerfMonitor("Mozilla") == chudSuccess)) {
  1507. return JS_TRUE;
  1508. }
  1509. return JS_FALSE;
  1510. }
  1511. JS_PUBLIC_API(JSBool)
  1512. JS_StopChudRemote()
  1513. {
  1514. if (chudIsRemoteAccessAcquired() &&
  1515. (chudStopRemotePerfMonitor() == chudSuccess)) {
  1516. return JS_TRUE;
  1517. }
  1518. return JS_FALSE;
  1519. }
  1520. JS_PUBLIC_API(JSBool)
  1521. JS_ConnectShark()
  1522. {
  1523. if (!chudIsInitialized() && (chudInitialize() != chudSuccess))
  1524. return JS_FALSE;
  1525. if (chudAcquireRemoteAccess() != chudSuccess)
  1526. return JS_FALSE;
  1527. return JS_TRUE;
  1528. }
  1529. JS_PUBLIC_API(JSBool)
  1530. JS_DisconnectShark()
  1531. {
  1532. if (chudIsRemoteAccessAcquired() && (chudReleaseRemoteAccess() != chudSuccess))
  1533. return JS_FALSE;
  1534. return JS_TRUE;
  1535. }
  1536. JS_FRIEND_API(JSBool)
  1537. js_StartShark(JSContext *cx, JSObject *obj,
  1538. uintN argc, jsval *argv, jsval *rval)
  1539. {
  1540. if (!JS_StartChudRemote()) {
  1541. JS_ReportError(cx, "Error starting CHUD.");
  1542. }
  1543. return JS_TRUE;
  1544. }
  1545. JS_FRIEND_API(JSBool)
  1546. js_StopShark(JSContext *cx, JSObject *obj,
  1547. uintN argc, jsval *argv, jsval *rval)
  1548. {
  1549. if (!JS_StopChudRemote()) {
  1550. JS_ReportError(cx, "Error stopping CHUD.");
  1551. }
  1552. return JS_TRUE;
  1553. }
  1554. JS_FRIEND_API(JSBool)
  1555. js_ConnectShark(JSContext *cx, JSObject *obj,
  1556. uintN argc, jsval *argv, jsval *rval)
  1557. {
  1558. if (!JS_ConnectShark()) {
  1559. JS_ReportError(cx, "Error connecting to Shark.");
  1560. }
  1561. return JS_TRUE;
  1562. }
  1563. JS_FRIEND_API(JSBool)
  1564. js_DisconnectShark(JSContext *cx, JSObject *obj,
  1565. uintN argc, jsval *argv, jsval *rval)
  1566. {
  1567. if (!JS_DisconnectShark()) {
  1568. JS_ReportError(cx, "Error disconnecting from Shark.");
  1569. }
  1570. return JS_TRUE;
  1571. }
  1572. #endif /* MOZ_SHARK */
  1573. #ifdef MOZ_CALLGRIND
  1574. #include <valgrind/callgrind.h>
  1575. JS_FRIEND_API(JSBool)
  1576. js_StartCallgrind(JSContext *cx, JSObject *obj,
  1577. uintN argc, jsval *argv, jsval *rval)
  1578. {
  1579. CALLGRIND_START_INSTRUMENTATION;
  1580. CALLGRIND_ZERO_STATS;
  1581. return JS_TRUE;
  1582. }
  1583. JS_FRIEND_API(JSBool)
  1584. js_StopCallgrind(JSContext *cx, JSObject *obj,
  1585. uintN argc, jsval *argv, jsval *rval)
  1586. {
  1587. CALLGRIND_STOP_INSTRUMENTATION;
  1588. return JS_TRUE;
  1589. }
  1590. JS_FRIEND_API(JSBool)
  1591. js_DumpCallgrind(JSContext *cx, JSObject *obj,
  1592. uintN argc, jsval *argv, jsval *rval)
  1593. {
  1594. JSString *str;
  1595. char *cstr;
  1596. if (argc > 0 && JSVAL_IS_STRING(argv[0])) {
  1597. str = JSVAL_TO_STRING(argv[0]);
  1598. cstr = js_DeflateString(cx, JSSTRING_CHARS(str), JSSTRING_LENGTH(str));
  1599. if (cstr) {
  1600. CALLGRIND_DUMP_STATS_AT(cstr);
  1601. JS_free(cx, cstr);
  1602. return JS_TRUE;
  1603. }
  1604. }
  1605. CALLGRIND_DUMP_STATS;
  1606. return JS_TRUE;
  1607. }
  1608. #endif /* MOZ_CALLGRIND */
  1609. #ifdef MOZ_VTUNE
  1610. #include <VTuneApi.h>
  1611. static const char *vtuneErrorMessages[] = {
  1612. "unknown, error #0",
  1613. "invalid 'max samples' field",
  1614. "invalid 'samples per buffer' field",
  1615. "invalid 'sample interval' field",
  1616. "invalid path",
  1617. "sample file in use",
  1618. "invalid 'number of events' field",
  1619. "unknown, error #7",
  1620. "internal error",
  1621. "bad event name",
  1622. "VTStopSampling called without calling VTStartSampling",
  1623. "no events selected for event-based sampling",
  1624. "events selected cannot be run together",
  1625. "no sampling parameters",
  1626. "sample database already exists",
  1627. "sampling already started",
  1628. "time-based sampling not supported",
  1629. "invalid 'sampling parameters size' field",
  1630. "invalid 'event size' field",
  1631. "sampling file already bound",
  1632. "invalid event path",
  1633. "invalid license",
  1634. "invalid 'global options' field",
  1635. };
  1636. JS_FRIEND_API(JSBool)
  1637. js_StartVtune(JSContext *cx, JSObject *obj,
  1638. uintN argc, jsval *argv, jsval *rval)
  1639. {
  1640. VTUNE_EVENT events[] = {
  1641. { 1000000, 0, 0, 0, "CPU_CLK_UNHALTED.CORE" },
  1642. { 1000000, 0, 0, 0, "INST_RETIRED.ANY" },
  1643. };
  1644. U32 n_events = sizeof(events) / sizeof(VTUNE_EVENT);
  1645. char *default_filename = "mozilla-vtune.tb5";
  1646. JSString *str;
  1647. U32 status;
  1648. VTUNE_SAMPLING_PARAMS params = {
  1649. sizeof(VTUNE_SAMPLING_PARAMS),
  1650. sizeof(VTUNE_EVENT),
  1651. 0, 0, /* Reserved fields */
  1652. 1, /* Initialize in "paused" state */
  1653. 0, /* Max samples, or 0 for "continuous" */
  1654. 4096, /* Samples per buffer */
  1655. 0.1, /* Sampling interval in ms */
  1656. 1, /* 1 for event-based sampling, 0 for time-based */
  1657. n_events,
  1658. events,
  1659. default_filename,
  1660. };
  1661. if (argc > 0 && JSVAL_IS_STRING(argv[0])) {
  1662. str = JSVAL_TO_STRING(argv[0]);
  1663. params.tb5Filename = js_DeflateString(cx,
  1664. JSSTRING_CHARS(str),
  1665. JSSTRING_LENGTH(str));
  1666. }
  1667. status = VTStartSampling(&params);
  1668. if (params.tb5Filename != default_filename)
  1669. JS_free(cx, params.tb5Filename);
  1670. if (status != 0) {
  1671. if (status == VTAPI_MULTIPLE_RUNS)
  1672. VTStopSampling(0);
  1673. if (status < sizeof(vtuneErrorMessages))
  1674. JS_ReportError(cx, "Vtune setup error: %s",
  1675. vtuneErrorMessages[status]);
  1676. else
  1677. JS_ReportError(cx, "Vtune setup error: %d",
  1678. status);
  1679. return JS_FALSE;
  1680. }
  1681. return JS_TRUE;
  1682. }
  1683. JS_FRIEND_API(JSBool)
  1684. js_StopVtune(JSContext *cx, JSObject *obj,
  1685. uintN argc, jsval *argv, jsval *rval)
  1686. {
  1687. U32 status = VTStopSampling(1);
  1688. if (status) {
  1689. if (status < sizeof(vtuneErrorMessages))
  1690. JS_ReportError(cx, "Vtune shutdown error: %s",
  1691. vtuneErrorMessages[status]);
  1692. else
  1693. JS_ReportError(cx, "Vtune shutdown error: %d",
  1694. status);
  1695. return JS_FALSE;
  1696. }
  1697. return JS_TRUE;
  1698. }
  1699. JS_FRIEND_API(JSBool)
  1700. js_PauseVtune(JSContext *cx, JSObject *obj,
  1701. uintN argc, jsval *argv, jsval *rval)
  1702. {
  1703. VTPause();
  1704. return JS_TRUE;
  1705. }
  1706. JS_FRIEND_API(JSBool)
  1707. js_ResumeVtune(JSContext *cx, JSObject *obj,
  1708. uintN argc, jsval *argv, jsval *rval)
  1709. {
  1710. VTResume();
  1711. return JS_TRUE;
  1712. }
  1713. #endif /* MOZ_VTUNE */