Bug 470165 - Cleanup the GTK nsFilePicker code; r+sr=roc
[wine-gecko.git] / js / src / jsdbgapi.cpp
blobd7ce50bccc5cb81122feed9eb0b35cba2440b47b
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: set ts=8 sw=4 et tw=78:
4 * ***** BEGIN LICENSE BLOCK *****
5 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
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/
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.
17 * The Original Code is Mozilla Communicator client code, released
18 * March 31, 1998.
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.
25 * Contributor(s):
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.
39 * ***** END LICENSE BLOCK ***** */
42 * JS debugging API.
44 #include "jsstddef.h"
45 #include <string.h>
46 #include "jstypes.h"
47 #include "jsutil.h" /* Added by JSIFY */
48 #include "jsclist.h"
49 #include "jsapi.h"
50 #include "jscntxt.h"
51 #include "jsversion.h"
52 #include "jsdbgapi.h"
53 #include "jsemit.h"
54 #include "jsfun.h"
55 #include "jsgc.h"
56 #include "jsinterp.h"
57 #include "jslock.h"
58 #include "jsobj.h"
59 #include "jsopcode.h"
60 #include "jsparse.h"
61 #include "jsscope.h"
62 #include "jsscript.h"
63 #include "jsstr.h"
65 #include "jsautooplen.h"
67 typedef struct JSTrap {
68 JSCList links;
69 JSScript *script;
70 jsbytecode *pc;
71 JSOp op;
72 JSTrapHandler handler;
73 void *closure;
74 } JSTrap;
76 #define DBG_LOCK(rt) JS_ACQUIRE_LOCK((rt)->debuggerLock)
77 #define DBG_UNLOCK(rt) JS_RELEASE_LOCK((rt)->debuggerLock)
78 #define DBG_LOCK_EVAL(rt,expr) (DBG_LOCK(rt), (expr), DBG_UNLOCK(rt))
81 * NB: FindTrap must be called with rt->debuggerLock acquired.
83 static JSTrap *
84 FindTrap(JSRuntime *rt, JSScript *script, jsbytecode *pc)
86 JSTrap *trap;
88 for (trap = (JSTrap *)rt->trapList.next;
89 &trap->links != &rt->trapList;
90 trap = (JSTrap *)trap->links.next) {
91 if (trap->script == script && trap->pc == pc)
92 return trap;
94 return NULL;
97 jsbytecode *
98 js_UntrapScriptCode(JSContext *cx, JSScript *script)
100 jsbytecode *code;
101 JSRuntime *rt;
102 JSTrap *trap;
104 code = script->code;
105 rt = cx->runtime;
106 DBG_LOCK(rt);
107 for (trap = (JSTrap *)rt->trapList.next;
108 &trap->links !=
109 &rt->trapList;
110 trap = (JSTrap *)trap->links.next) {
111 if (trap->script == script &&
112 (size_t)(trap->pc - script->code) < script->length) {
113 if (code == script->code) {
114 jssrcnote *sn, *notes;
115 size_t nbytes;
117 nbytes = script->length * sizeof(jsbytecode);
118 notes = SCRIPT_NOTES(script);
119 for (sn = notes; !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn))
120 continue;
121 nbytes += (sn - notes + 1) * sizeof *sn;
123 code = (jsbytecode *) JS_malloc(cx, nbytes);
124 if (!code)
125 break;
126 memcpy(code, script->code, nbytes);
127 JS_CLEAR_GSN_CACHE(cx);
129 code[trap->pc - script->code] = trap->op;
132 DBG_UNLOCK(rt);
133 return code;
136 JS_PUBLIC_API(JSBool)
137 JS_SetTrap(JSContext *cx, JSScript *script, jsbytecode *pc,
138 JSTrapHandler handler, void *closure)
140 JSTrap *junk, *trap, *twin;
141 JSRuntime *rt;
142 uint32 sample;
144 JS_ASSERT((JSOp) *pc != JSOP_TRAP);
145 junk = NULL;
146 rt = cx->runtime;
147 DBG_LOCK(rt);
148 trap = FindTrap(rt, script, pc);
149 if (trap) {
150 JS_ASSERT(trap->script == script && trap->pc == pc);
151 JS_ASSERT(*pc == JSOP_TRAP);
152 } else {
153 sample = rt->debuggerMutations;
154 DBG_UNLOCK(rt);
155 trap = (JSTrap *) JS_malloc(cx, sizeof *trap);
156 if (!trap)
157 return JS_FALSE;
158 trap->closure = NULL;
159 if(!js_AddRoot(cx, &trap->closure, "trap->closure")) {
160 JS_free(cx, trap);
161 return JS_FALSE;
163 DBG_LOCK(rt);
164 twin = (rt->debuggerMutations != sample)
165 ? FindTrap(rt, script, pc)
166 : NULL;
167 if (twin) {
168 junk = trap;
169 trap = twin;
170 } else {
171 JS_APPEND_LINK(&trap->links, &rt->trapList);
172 ++rt->debuggerMutations;
173 trap->script = script;
174 trap->pc = pc;
175 trap->op = (JSOp)*pc;
176 *pc = JSOP_TRAP;
179 trap->handler = handler;
180 trap->closure = closure;
181 DBG_UNLOCK(rt);
182 if (junk) {
183 js_RemoveRoot(rt, &junk->closure);
184 JS_free(cx, junk);
186 return JS_TRUE;
189 JS_PUBLIC_API(JSOp)
190 JS_GetTrapOpcode(JSContext *cx, JSScript *script, jsbytecode *pc)
192 JSRuntime *rt;
193 JSTrap *trap;
194 JSOp op;
196 rt = cx->runtime;
197 DBG_LOCK(rt);
198 trap = FindTrap(rt, script, pc);
199 op = trap ? trap->op : (JSOp) *pc;
200 DBG_UNLOCK(rt);
201 return op;
204 static void
205 DestroyTrapAndUnlock(JSContext *cx, JSTrap *trap)
207 ++cx->runtime->debuggerMutations;
208 JS_REMOVE_LINK(&trap->links);
209 *trap->pc = (jsbytecode)trap->op;
210 DBG_UNLOCK(cx->runtime);
212 js_RemoveRoot(cx->runtime, &trap->closure);
213 JS_free(cx, trap);
216 JS_PUBLIC_API(void)
217 JS_ClearTrap(JSContext *cx, JSScript *script, jsbytecode *pc,
218 JSTrapHandler *handlerp, void **closurep)
220 JSTrap *trap;
222 DBG_LOCK(cx->runtime);
223 trap = FindTrap(cx->runtime, script, pc);
224 if (handlerp)
225 *handlerp = trap ? trap->handler : NULL;
226 if (closurep)
227 *closurep = trap ? trap->closure : NULL;
228 if (trap)
229 DestroyTrapAndUnlock(cx, trap);
230 else
231 DBG_UNLOCK(cx->runtime);
234 JS_PUBLIC_API(void)
235 JS_ClearScriptTraps(JSContext *cx, JSScript *script)
237 JSRuntime *rt;
238 JSTrap *trap, *next;
239 uint32 sample;
241 rt = cx->runtime;
242 DBG_LOCK(rt);
243 for (trap = (JSTrap *)rt->trapList.next;
244 &trap->links != &rt->trapList;
245 trap = next) {
246 next = (JSTrap *)trap->links.next;
247 if (trap->script == script) {
248 sample = rt->debuggerMutations;
249 DestroyTrapAndUnlock(cx, trap);
250 DBG_LOCK(rt);
251 if (rt->debuggerMutations != sample + 1)
252 next = (JSTrap *)rt->trapList.next;
255 DBG_UNLOCK(rt);
258 JS_PUBLIC_API(void)
259 JS_ClearAllTraps(JSContext *cx)
261 JSRuntime *rt;
262 JSTrap *trap, *next;
263 uint32 sample;
265 rt = cx->runtime;
266 DBG_LOCK(rt);
267 for (trap = (JSTrap *)rt->trapList.next;
268 &trap->links != &rt->trapList;
269 trap = next) {
270 next = (JSTrap *)trap->links.next;
271 sample = rt->debuggerMutations;
272 DestroyTrapAndUnlock(cx, trap);
273 DBG_LOCK(rt);
274 if (rt->debuggerMutations != sample + 1)
275 next = (JSTrap *)rt->trapList.next;
277 DBG_UNLOCK(rt);
280 JS_PUBLIC_API(JSTrapStatus)
281 JS_HandleTrap(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval)
283 JSTrap *trap;
284 jsint op;
285 JSTrapStatus status;
287 DBG_LOCK(cx->runtime);
288 trap = FindTrap(cx->runtime, script, pc);
289 JS_ASSERT(!trap || trap->handler);
290 if (!trap) {
291 op = (JSOp) *pc;
292 DBG_UNLOCK(cx->runtime);
294 /* Defend against "pc for wrong script" API usage error. */
295 JS_ASSERT(op != JSOP_TRAP);
297 #ifdef JS_THREADSAFE
298 /* If the API was abused, we must fail for want of the real op. */
299 if (op == JSOP_TRAP)
300 return JSTRAP_ERROR;
302 /* Assume a race with a debugger thread and try to carry on. */
303 *rval = INT_TO_JSVAL(op);
304 return JSTRAP_CONTINUE;
305 #else
306 /* Always fail if single-threaded (must be an API usage error). */
307 return JSTRAP_ERROR;
308 #endif
310 DBG_UNLOCK(cx->runtime);
313 * It's important that we not use 'trap->' after calling the callback --
314 * the callback might remove the trap!
316 op = (jsint)trap->op;
317 status = trap->handler(cx, script, pc, rval, trap->closure);
318 if (status == JSTRAP_CONTINUE) {
319 /* By convention, return the true op to the interpreter in rval. */
320 *rval = INT_TO_JSVAL(op);
322 return status;
325 JS_PUBLIC_API(JSBool)
326 JS_SetInterrupt(JSRuntime *rt, JSTrapHandler handler, void *closure)
328 rt->globalDebugHooks.interruptHandler = handler;
329 rt->globalDebugHooks.interruptHandlerData = closure;
330 return JS_TRUE;
333 JS_PUBLIC_API(JSBool)
334 JS_ClearInterrupt(JSRuntime *rt, JSTrapHandler *handlerp, void **closurep)
336 if (handlerp)
337 *handlerp = (JSTrapHandler)rt->globalDebugHooks.interruptHandler;
338 if (closurep)
339 *closurep = rt->globalDebugHooks.interruptHandlerData;
340 rt->globalDebugHooks.interruptHandler = 0;
341 rt->globalDebugHooks.interruptHandlerData = 0;
342 return JS_TRUE;
345 /************************************************************************/
347 typedef struct JSWatchPoint {
348 JSCList links;
349 JSObject *object; /* weak link, see js_FinalizeObject */
350 JSScopeProperty *sprop;
351 JSPropertyOp setter;
352 JSWatchPointHandler handler;
353 void *closure;
354 uintN flags;
355 } JSWatchPoint;
357 #define JSWP_LIVE 0x1 /* live because set and not cleared */
358 #define JSWP_HELD 0x2 /* held while running handler/setter */
361 * NB: DropWatchPointAndUnlock releases cx->runtime->debuggerLock in all cases.
363 static JSBool
364 DropWatchPointAndUnlock(JSContext *cx, JSWatchPoint *wp, uintN flag)
366 JSBool ok, found;
367 JSScopeProperty *sprop;
368 JSScope *scope;
369 JSPropertyOp setter;
371 ok = JS_TRUE;
372 wp->flags &= ~flag;
373 if (wp->flags != 0) {
374 DBG_UNLOCK(cx->runtime);
375 return ok;
379 * Remove wp from the list, then if there are no other watchpoints for
380 * wp->sprop in any scope, restore wp->sprop->setter from wp.
382 ++cx->runtime->debuggerMutations;
383 JS_REMOVE_LINK(&wp->links);
384 sprop = wp->sprop;
387 * Passing null for the scope parameter tells js_GetWatchedSetter to find
388 * any watch point for sprop, and not to lock or unlock rt->debuggerLock.
389 * If js_ChangeNativePropertyAttrs fails, propagate failure after removing
390 * wp->closure's root and freeing wp.
392 setter = js_GetWatchedSetter(cx->runtime, NULL, sprop);
393 DBG_UNLOCK(cx->runtime);
394 if (!setter) {
395 JS_LOCK_OBJ(cx, wp->object);
396 scope = OBJ_SCOPE(wp->object);
397 found = (scope->object == wp->object &&
398 SCOPE_GET_PROPERTY(scope, sprop->id));
399 JS_UNLOCK_SCOPE(cx, scope);
402 * If the property wasn't found on wp->object or didn't exist, then
403 * someone else has dealt with this sprop, and we don't need to change
404 * the property attributes.
406 if (found) {
407 sprop = js_ChangeScopePropertyAttrs(cx, scope, sprop,
408 0, sprop->attrs,
409 sprop->getter,
410 wp->setter);
411 if (!sprop)
412 ok = JS_FALSE;
416 JS_free(cx, wp);
417 return ok;
421 * NB: js_TraceWatchPoints does not acquire cx->runtime->debuggerLock, since
422 * the debugger should never be racing with the GC (i.e., the debugger must
423 * respect the request model).
425 void
426 js_TraceWatchPoints(JSTracer *trc, JSObject *obj)
428 JSRuntime *rt;
429 JSWatchPoint *wp;
431 rt = trc->context->runtime;
433 for (wp = (JSWatchPoint *)rt->watchPointList.next;
434 &wp->links != &rt->watchPointList;
435 wp = (JSWatchPoint *)wp->links.next) {
436 if (wp->object == obj) {
437 TRACE_SCOPE_PROPERTY(trc, wp->sprop);
438 if ((wp->sprop->attrs & JSPROP_SETTER) && wp->setter) {
439 JS_CALL_OBJECT_TRACER(trc, (JSObject *)wp->setter,
440 "wp->setter");
442 JS_SET_TRACING_NAME(trc, "wp->closure");
443 js_CallValueTracerIfGCThing(trc, (jsval) wp->closure);
448 void
449 js_SweepWatchPoints(JSContext *cx)
451 JSRuntime *rt;
452 JSWatchPoint *wp, *next;
453 uint32 sample;
455 rt = cx->runtime;
456 DBG_LOCK(rt);
457 for (wp = (JSWatchPoint *)rt->watchPointList.next;
458 &wp->links != &rt->watchPointList;
459 wp = next) {
460 next = (JSWatchPoint *)wp->links.next;
461 if (js_IsAboutToBeFinalized(cx, wp->object)) {
462 sample = rt->debuggerMutations;
464 /* Ignore failures. */
465 DropWatchPointAndUnlock(cx, wp, JSWP_LIVE);
466 DBG_LOCK(rt);
467 if (rt->debuggerMutations != sample + 1)
468 next = (JSWatchPoint *)rt->watchPointList.next;
471 DBG_UNLOCK(rt);
477 * NB: FindWatchPoint must be called with rt->debuggerLock acquired.
479 static JSWatchPoint *
480 FindWatchPoint(JSRuntime *rt, JSScope *scope, jsid id)
482 JSWatchPoint *wp;
484 for (wp = (JSWatchPoint *)rt->watchPointList.next;
485 &wp->links != &rt->watchPointList;
486 wp = (JSWatchPoint *)wp->links.next) {
487 if (wp->object == scope->object && wp->sprop->id == id)
488 return wp;
490 return NULL;
493 JSScopeProperty *
494 js_FindWatchPoint(JSRuntime *rt, JSScope *scope, jsid id)
496 JSWatchPoint *wp;
497 JSScopeProperty *sprop;
499 DBG_LOCK(rt);
500 wp = FindWatchPoint(rt, scope, id);
501 sprop = wp ? wp->sprop : NULL;
502 DBG_UNLOCK(rt);
503 return sprop;
507 * Secret handshake with DropWatchPointAndUnlock: if (!scope), we know our
508 * caller has acquired rt->debuggerLock, so we don't have to.
510 JSPropertyOp
511 js_GetWatchedSetter(JSRuntime *rt, JSScope *scope,
512 const JSScopeProperty *sprop)
514 JSPropertyOp setter;
515 JSWatchPoint *wp;
517 setter = NULL;
518 if (scope)
519 DBG_LOCK(rt);
520 for (wp = (JSWatchPoint *)rt->watchPointList.next;
521 &wp->links != &rt->watchPointList;
522 wp = (JSWatchPoint *)wp->links.next) {
523 if ((!scope || wp->object == scope->object) && wp->sprop == sprop) {
524 setter = wp->setter;
525 break;
528 if (scope)
529 DBG_UNLOCK(rt);
530 return setter;
533 JSBool
534 js_watch_set(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
536 JSRuntime *rt;
537 JSWatchPoint *wp;
538 JSScopeProperty *sprop;
539 jsval propid, userid;
540 JSScope *scope;
541 JSBool ok;
543 rt = cx->runtime;
544 DBG_LOCK(rt);
545 for (wp = (JSWatchPoint *)rt->watchPointList.next;
546 &wp->links != &rt->watchPointList;
547 wp = (JSWatchPoint *)wp->links.next) {
548 sprop = wp->sprop;
549 if (wp->object == obj && SPROP_USERID(sprop) == id &&
550 !(wp->flags & JSWP_HELD)) {
551 wp->flags |= JSWP_HELD;
552 DBG_UNLOCK(rt);
554 JS_LOCK_OBJ(cx, obj);
555 propid = ID_TO_VALUE(sprop->id);
556 userid = (sprop->flags & SPROP_HAS_SHORTID)
557 ? INT_TO_JSVAL(sprop->shortid)
558 : propid;
559 scope = OBJ_SCOPE(obj);
560 JS_UNLOCK_OBJ(cx, obj);
562 /* NB: wp is held, so we can safely dereference it still. */
563 ok = wp->handler(cx, obj, propid,
564 SPROP_HAS_VALID_SLOT(sprop, scope)
565 ? OBJ_GET_SLOT(cx, obj, sprop->slot)
566 : JSVAL_VOID,
567 vp, wp->closure);
568 if (ok) {
570 * Create a pseudo-frame for the setter invocation so that any
571 * stack-walking security code under the setter will correctly
572 * identify the guilty party. So that the watcher appears to
573 * be active to obj_eval and other such code, point frame.pc
574 * at the JSOP_STOP at the end of the script.
576 * The pseudo-frame is not created for fast natives as they
577 * are treated as interpreter frame extensions and always
578 * trusted.
580 JSObject *closure;
581 JSClass *clasp;
582 JSFunction *fun;
583 JSScript *script;
584 JSBool injectFrame;
585 uintN nslots;
586 jsval smallv[5];
587 jsval *argv;
588 JSStackFrame frame;
589 JSFrameRegs regs;
591 closure = (JSObject *) wp->closure;
592 clasp = OBJ_GET_CLASS(cx, closure);
593 if (clasp == &js_FunctionClass) {
594 fun = GET_FUNCTION_PRIVATE(cx, closure);
595 script = FUN_SCRIPT(fun);
596 } else if (clasp == &js_ScriptClass) {
597 fun = NULL;
598 script = (JSScript *) JS_GetPrivate(cx, closure);
599 } else {
600 fun = NULL;
601 script = NULL;
604 nslots = 2;
605 injectFrame = JS_TRUE;
606 if (fun) {
607 nslots += FUN_MINARGS(fun);
608 if (!FUN_INTERPRETED(fun)) {
609 nslots += fun->u.n.extra;
610 injectFrame = !(fun->flags & JSFUN_FAST_NATIVE);
614 if (injectFrame) {
615 if (nslots <= JS_ARRAY_LENGTH(smallv)) {
616 argv = smallv;
617 } else {
618 argv = (jsval *) JS_malloc(cx, nslots * sizeof(jsval));
619 if (!argv) {
620 DBG_LOCK(rt);
621 DropWatchPointAndUnlock(cx, wp, JSWP_HELD);
622 return JS_FALSE;
626 argv[0] = OBJECT_TO_JSVAL(closure);
627 argv[1] = JSVAL_NULL;
628 memset(argv + 2, 0, (nslots - 2) * sizeof(jsval));
630 memset(&frame, 0, sizeof(frame));
631 frame.script = script;
632 frame.regs = NULL;
633 if (script) {
634 JS_ASSERT(script->length >= JSOP_STOP_LENGTH);
635 regs.pc = script->code + script->length
636 - JSOP_STOP_LENGTH;
637 regs.sp = NULL;
638 frame.regs = &regs;
640 frame.callee = closure;
641 frame.fun = fun;
642 frame.argv = argv + 2;
643 frame.down = js_GetTopStackFrame(cx);
644 frame.scopeChain = OBJ_GET_PARENT(cx, closure);
646 cx->fp = &frame;
648 #ifdef __GNUC__
649 else
650 argv = NULL; /* suppress bogus gcc warnings */
651 #endif
652 ok = !wp->setter ||
653 ((sprop->attrs & JSPROP_SETTER)
654 ? js_InternalCall(cx, obj, OBJECT_TO_JSVAL(wp->setter),
655 1, vp, vp)
656 : wp->setter(cx, OBJ_THIS_OBJECT(cx, obj), userid, vp));
657 if (injectFrame) {
658 /* Evil code can cause us to have an arguments object. */
659 if (frame.callobj)
660 ok &= js_PutCallObject(cx, &frame);
661 if (frame.argsobj)
662 ok &= js_PutArgsObject(cx, &frame);
664 cx->fp = frame.down;
665 if (argv != smallv)
666 JS_free(cx, argv);
669 DBG_LOCK(rt);
670 return DropWatchPointAndUnlock(cx, wp, JSWP_HELD) && ok;
673 DBG_UNLOCK(rt);
674 return JS_TRUE;
677 JSBool
678 js_watch_set_wrapper(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
679 jsval *rval)
681 JSObject *funobj;
682 JSFunction *wrapper;
683 jsval userid;
685 funobj = JSVAL_TO_OBJECT(argv[-2]);
686 JS_ASSERT(OBJ_GET_CLASS(cx, funobj) == &js_FunctionClass);
687 wrapper = GET_FUNCTION_PRIVATE(cx, funobj);
688 userid = ATOM_KEY(wrapper->atom);
689 *rval = argv[0];
690 return js_watch_set(cx, obj, userid, rval);
693 JSPropertyOp
694 js_WrapWatchedSetter(JSContext *cx, jsid id, uintN attrs, JSPropertyOp setter)
696 JSAtom *atom;
697 JSFunction *wrapper;
699 if (!(attrs & JSPROP_SETTER))
700 return &js_watch_set; /* & to silence schoolmarmish MSVC */
702 if (JSID_IS_ATOM(id)) {
703 atom = JSID_TO_ATOM(id);
704 } else if (JSID_IS_INT(id)) {
705 if (!js_ValueToStringId(cx, INT_JSID_TO_JSVAL(id), &id))
706 return NULL;
707 atom = JSID_TO_ATOM(id);
708 } else {
709 atom = NULL;
711 wrapper = js_NewFunction(cx, NULL, js_watch_set_wrapper, 1, 0,
712 OBJ_GET_PARENT(cx, (JSObject *)setter),
713 atom);
714 if (!wrapper)
715 return NULL;
716 return (JSPropertyOp) FUN_OBJECT(wrapper);
719 JS_PUBLIC_API(JSBool)
720 JS_SetWatchPoint(JSContext *cx, JSObject *obj, jsval idval,
721 JSWatchPointHandler handler, void *closure)
723 jsid propid;
724 JSObject *pobj;
725 JSProperty *prop;
726 JSScopeProperty *sprop;
727 JSRuntime *rt;
728 JSBool ok;
729 JSWatchPoint *wp;
730 JSPropertyOp watcher;
732 if (!OBJ_IS_NATIVE(obj)) {
733 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_WATCH,
734 OBJ_GET_CLASS(cx, obj)->name);
735 return JS_FALSE;
738 if (JSVAL_IS_INT(idval))
739 propid = INT_JSVAL_TO_JSID(idval);
740 else if (!js_ValueToStringId(cx, idval, &propid))
741 return JS_FALSE;
743 if (!js_LookupProperty(cx, obj, propid, &pobj, &prop))
744 return JS_FALSE;
745 sprop = (JSScopeProperty *) prop;
746 rt = cx->runtime;
747 if (!sprop) {
748 /* Check for a deleted symbol watchpoint, which holds its property. */
749 sprop = js_FindWatchPoint(rt, OBJ_SCOPE(obj), propid);
750 if (!sprop) {
751 /* Make a new property in obj so we can watch for the first set. */
752 if (!js_DefineProperty(cx, obj, propid, JSVAL_VOID,
753 NULL, NULL, JSPROP_ENUMERATE,
754 &prop)) {
755 return JS_FALSE;
757 sprop = (JSScopeProperty *) prop;
759 } else if (pobj != obj) {
760 /* Clone the prototype property so we can watch the right object. */
761 jsval value;
762 JSPropertyOp getter, setter;
763 uintN attrs, flags;
764 intN shortid;
766 if (OBJ_IS_NATIVE(pobj)) {
767 value = SPROP_HAS_VALID_SLOT(sprop, OBJ_SCOPE(pobj))
768 ? LOCKED_OBJ_GET_SLOT(pobj, sprop->slot)
769 : JSVAL_VOID;
770 getter = sprop->getter;
771 setter = sprop->setter;
772 attrs = sprop->attrs;
773 flags = sprop->flags;
774 shortid = sprop->shortid;
775 } else {
776 if (!OBJ_GET_PROPERTY(cx, pobj, propid, &value) ||
777 !OBJ_GET_ATTRIBUTES(cx, pobj, propid, prop, &attrs)) {
778 OBJ_DROP_PROPERTY(cx, pobj, prop);
779 return JS_FALSE;
781 getter = setter = NULL;
782 flags = 0;
783 shortid = 0;
785 OBJ_DROP_PROPERTY(cx, pobj, prop);
787 /* Recall that obj is native, whether or not pobj is native. */
788 if (!js_DefineNativeProperty(cx, obj, propid, value, getter, setter,
789 attrs, flags, shortid, &prop)) {
790 return JS_FALSE;
792 sprop = (JSScopeProperty *) prop;
796 * At this point, prop/sprop exists in obj, obj is locked, and we must
797 * OBJ_DROP_PROPERTY(cx, obj, prop) before returning.
799 ok = JS_TRUE;
800 DBG_LOCK(rt);
801 wp = FindWatchPoint(rt, OBJ_SCOPE(obj), propid);
802 if (!wp) {
803 DBG_UNLOCK(rt);
804 watcher = js_WrapWatchedSetter(cx, propid, sprop->attrs, sprop->setter);
805 if (!watcher) {
806 ok = JS_FALSE;
807 goto out;
810 wp = (JSWatchPoint *) JS_malloc(cx, sizeof *wp);
811 if (!wp) {
812 ok = JS_FALSE;
813 goto out;
815 wp->handler = NULL;
816 wp->closure = NULL;
817 wp->object = obj;
818 JS_ASSERT(sprop->setter != js_watch_set || pobj != obj);
819 wp->setter = sprop->setter;
820 wp->flags = JSWP_LIVE;
822 /* XXXbe nest in obj lock here */
823 sprop = js_ChangeNativePropertyAttrs(cx, obj, sprop, 0, sprop->attrs,
824 sprop->getter, watcher);
825 if (!sprop) {
826 /* Self-link so DropWatchPointAndUnlock can JS_REMOVE_LINK it. */
827 JS_INIT_CLIST(&wp->links);
828 DBG_LOCK(rt);
829 DropWatchPointAndUnlock(cx, wp, JSWP_LIVE);
830 ok = JS_FALSE;
831 goto out;
833 wp->sprop = sprop;
836 * Now that wp is fully initialized, append it to rt's wp list.
837 * Because obj is locked we know that no other thread could have added
838 * a watchpoint for (obj, propid).
840 DBG_LOCK(rt);
841 JS_ASSERT(!FindWatchPoint(rt, OBJ_SCOPE(obj), propid));
842 JS_APPEND_LINK(&wp->links, &rt->watchPointList);
843 ++rt->debuggerMutations;
845 wp->handler = handler;
846 wp->closure = closure;
847 DBG_UNLOCK(rt);
849 out:
850 OBJ_DROP_PROPERTY(cx, obj, prop);
851 return ok;
854 JS_PUBLIC_API(JSBool)
855 JS_ClearWatchPoint(JSContext *cx, JSObject *obj, jsval id,
856 JSWatchPointHandler *handlerp, void **closurep)
858 JSRuntime *rt;
859 JSWatchPoint *wp;
861 rt = cx->runtime;
862 DBG_LOCK(rt);
863 for (wp = (JSWatchPoint *)rt->watchPointList.next;
864 &wp->links != &rt->watchPointList;
865 wp = (JSWatchPoint *)wp->links.next) {
866 if (wp->object == obj && SPROP_USERID(wp->sprop) == id) {
867 if (handlerp)
868 *handlerp = wp->handler;
869 if (closurep)
870 *closurep = wp->closure;
871 return DropWatchPointAndUnlock(cx, wp, JSWP_LIVE);
874 DBG_UNLOCK(rt);
875 if (handlerp)
876 *handlerp = NULL;
877 if (closurep)
878 *closurep = NULL;
879 return JS_TRUE;
882 JS_PUBLIC_API(JSBool)
883 JS_ClearWatchPointsForObject(JSContext *cx, JSObject *obj)
885 JSRuntime *rt;
886 JSWatchPoint *wp, *next;
887 uint32 sample;
889 rt = cx->runtime;
890 DBG_LOCK(rt);
891 for (wp = (JSWatchPoint *)rt->watchPointList.next;
892 &wp->links != &rt->watchPointList;
893 wp = next) {
894 next = (JSWatchPoint *)wp->links.next;
895 if (wp->object == obj) {
896 sample = rt->debuggerMutations;
897 if (!DropWatchPointAndUnlock(cx, wp, JSWP_LIVE))
898 return JS_FALSE;
899 DBG_LOCK(rt);
900 if (rt->debuggerMutations != sample + 1)
901 next = (JSWatchPoint *)rt->watchPointList.next;
904 DBG_UNLOCK(rt);
905 return JS_TRUE;
908 JS_PUBLIC_API(JSBool)
909 JS_ClearAllWatchPoints(JSContext *cx)
911 JSRuntime *rt;
912 JSWatchPoint *wp, *next;
913 uint32 sample;
915 rt = cx->runtime;
916 DBG_LOCK(rt);
917 for (wp = (JSWatchPoint *)rt->watchPointList.next;
918 &wp->links != &rt->watchPointList;
919 wp = next) {
920 next = (JSWatchPoint *)wp->links.next;
921 sample = rt->debuggerMutations;
922 if (!DropWatchPointAndUnlock(cx, wp, JSWP_LIVE))
923 return JS_FALSE;
924 DBG_LOCK(rt);
925 if (rt->debuggerMutations != sample + 1)
926 next = (JSWatchPoint *)rt->watchPointList.next;
928 DBG_UNLOCK(rt);
929 return JS_TRUE;
932 /************************************************************************/
934 JS_PUBLIC_API(uintN)
935 JS_PCToLineNumber(JSContext *cx, JSScript *script, jsbytecode *pc)
937 return js_PCToLineNumber(cx, script, pc);
940 JS_PUBLIC_API(jsbytecode *)
941 JS_LineNumberToPC(JSContext *cx, JSScript *script, uintN lineno)
943 return js_LineNumberToPC(script, lineno);
946 JS_PUBLIC_API(JSScript *)
947 JS_GetFunctionScript(JSContext *cx, JSFunction *fun)
949 return FUN_SCRIPT(fun);
952 JS_PUBLIC_API(JSNative)
953 JS_GetFunctionNative(JSContext *cx, JSFunction *fun)
955 return FUN_NATIVE(fun);
958 JS_PUBLIC_API(JSFastNative)
959 JS_GetFunctionFastNative(JSContext *cx, JSFunction *fun)
961 return FUN_FAST_NATIVE(fun);
964 JS_PUBLIC_API(JSPrincipals *)
965 JS_GetScriptPrincipals(JSContext *cx, JSScript *script)
967 return script->principals;
970 /************************************************************************/
973 * Stack Frame Iterator
975 JS_PUBLIC_API(JSStackFrame *)
976 JS_FrameIterator(JSContext *cx, JSStackFrame **iteratorp)
978 *iteratorp = (*iteratorp == NULL) ? js_GetTopStackFrame(cx) : (*iteratorp)->down;
979 return *iteratorp;
982 JS_PUBLIC_API(JSScript *)
983 JS_GetFrameScript(JSContext *cx, JSStackFrame *fp)
985 return fp->script;
988 JS_PUBLIC_API(jsbytecode *)
989 JS_GetFramePC(JSContext *cx, JSStackFrame *fp)
991 return fp->regs ? fp->regs->pc : NULL;
994 JS_PUBLIC_API(JSStackFrame *)
995 JS_GetScriptedCaller(JSContext *cx, JSStackFrame *fp)
997 return js_GetScriptedCaller(cx, fp);
1000 JS_PUBLIC_API(JSPrincipals *)
1001 JS_StackFramePrincipals(JSContext *cx, JSStackFrame *fp)
1003 JSSecurityCallbacks *callbacks;
1005 if (fp->fun) {
1006 callbacks = JS_GetSecurityCallbacks(cx);
1007 if (callbacks && callbacks->findObjectPrincipals) {
1008 if (FUN_OBJECT(fp->fun) != fp->callee)
1009 return callbacks->findObjectPrincipals(cx, fp->callee);
1010 /* FALL THROUGH */
1013 if (fp->script)
1014 return fp->script->principals;
1015 return NULL;
1018 JS_PUBLIC_API(JSPrincipals *)
1019 JS_EvalFramePrincipals(JSContext *cx, JSStackFrame *fp, JSStackFrame *caller)
1021 JSPrincipals *principals, *callerPrincipals;
1022 JSSecurityCallbacks *callbacks;
1024 callbacks = JS_GetSecurityCallbacks(cx);
1025 if (callbacks && callbacks->findObjectPrincipals) {
1026 principals = callbacks->findObjectPrincipals(cx, fp->callee);
1027 } else {
1028 principals = NULL;
1030 if (!caller)
1031 return principals;
1032 callerPrincipals = JS_StackFramePrincipals(cx, caller);
1033 return (callerPrincipals && principals &&
1034 callerPrincipals->subsume(callerPrincipals, principals))
1035 ? principals
1036 : callerPrincipals;
1039 JS_PUBLIC_API(void *)
1040 JS_GetFrameAnnotation(JSContext *cx, JSStackFrame *fp)
1042 if (fp->annotation && fp->script) {
1043 JSPrincipals *principals = JS_StackFramePrincipals(cx, fp);
1045 if (principals && principals->globalPrivilegesEnabled(cx, principals)) {
1047 * Give out an annotation only if privileges have not been revoked
1048 * or disabled globally.
1050 return fp->annotation;
1054 return NULL;
1057 JS_PUBLIC_API(void)
1058 JS_SetFrameAnnotation(JSContext *cx, JSStackFrame *fp, void *annotation)
1060 fp->annotation = annotation;
1063 JS_PUBLIC_API(void *)
1064 JS_GetFramePrincipalArray(JSContext *cx, JSStackFrame *fp)
1066 JSPrincipals *principals;
1068 principals = JS_StackFramePrincipals(cx, fp);
1069 if (!principals)
1070 return NULL;
1071 return principals->getPrincipalArray(cx, principals);
1074 JS_PUBLIC_API(JSBool)
1075 JS_IsNativeFrame(JSContext *cx, JSStackFrame *fp)
1077 return !fp->script;
1080 /* this is deprecated, use JS_GetFrameScopeChain instead */
1081 JS_PUBLIC_API(JSObject *)
1082 JS_GetFrameObject(JSContext *cx, JSStackFrame *fp)
1084 return fp->scopeChain;
1087 JS_PUBLIC_API(JSObject *)
1088 JS_GetFrameScopeChain(JSContext *cx, JSStackFrame *fp)
1090 /* Force creation of argument and call objects if not yet created */
1091 (void) JS_GetFrameCallObject(cx, fp);
1092 return js_GetScopeChain(cx, fp);
1095 JS_PUBLIC_API(JSObject *)
1096 JS_GetFrameCallObject(JSContext *cx, JSStackFrame *fp)
1098 if (! fp->fun)
1099 return NULL;
1101 /* Force creation of argument object if not yet created */
1102 (void) js_GetArgsObject(cx, fp);
1105 * XXX ill-defined: null return here means error was reported, unlike a
1106 * null returned above or in the #else
1108 return js_GetCallObject(cx, fp, NULL);
1111 JS_PUBLIC_API(JSObject *)
1112 JS_GetFrameThis(JSContext *cx, JSStackFrame *fp)
1114 JSStackFrame *afp;
1116 if (fp->flags & JSFRAME_COMPUTED_THIS)
1117 return fp->thisp;
1119 /* js_ComputeThis gets confused if fp != cx->fp, so set it aside. */
1120 if (js_GetTopStackFrame(cx) != fp) {
1121 afp = cx->fp;
1122 if (afp) {
1123 afp->dormantNext = cx->dormantFrameChain;
1124 cx->dormantFrameChain = afp;
1125 cx->fp = fp;
1127 } else {
1128 afp = NULL;
1131 if (!fp->thisp && fp->argv)
1132 fp->thisp = js_ComputeThis(cx, JS_TRUE, fp->argv);
1134 if (afp) {
1135 cx->fp = afp;
1136 cx->dormantFrameChain = afp->dormantNext;
1137 afp->dormantNext = NULL;
1140 return fp->thisp;
1143 JS_PUBLIC_API(JSFunction *)
1144 JS_GetFrameFunction(JSContext *cx, JSStackFrame *fp)
1146 return fp->fun;
1149 JS_PUBLIC_API(JSObject *)
1150 JS_GetFrameFunctionObject(JSContext *cx, JSStackFrame *fp)
1152 if (!fp->fun)
1153 return NULL;
1155 JS_ASSERT(OBJ_GET_CLASS(cx, fp->callee) == &js_FunctionClass);
1156 JS_ASSERT(OBJ_GET_PRIVATE(cx, fp->callee) == fp->fun);
1157 return fp->callee;
1160 JS_PUBLIC_API(JSBool)
1161 JS_IsConstructorFrame(JSContext *cx, JSStackFrame *fp)
1163 return (fp->flags & JSFRAME_CONSTRUCTING) != 0;
1166 JS_PUBLIC_API(JSObject *)
1167 JS_GetFrameCalleeObject(JSContext *cx, JSStackFrame *fp)
1169 return fp->callee;
1172 JS_PUBLIC_API(JSBool)
1173 JS_IsDebuggerFrame(JSContext *cx, JSStackFrame *fp)
1175 return (fp->flags & JSFRAME_DEBUGGER) != 0;
1178 JS_PUBLIC_API(jsval)
1179 JS_GetFrameReturnValue(JSContext *cx, JSStackFrame *fp)
1181 return fp->rval;
1184 JS_PUBLIC_API(void)
1185 JS_SetFrameReturnValue(JSContext *cx, JSStackFrame *fp, jsval rval)
1187 fp->rval = rval;
1190 /************************************************************************/
1192 JS_PUBLIC_API(const char *)
1193 JS_GetScriptFilename(JSContext *cx, JSScript *script)
1195 return script->filename;
1198 JS_PUBLIC_API(uintN)
1199 JS_GetScriptBaseLineNumber(JSContext *cx, JSScript *script)
1201 return script->lineno;
1204 JS_PUBLIC_API(uintN)
1205 JS_GetScriptLineExtent(JSContext *cx, JSScript *script)
1207 return js_GetScriptLineExtent(script);
1210 JS_PUBLIC_API(JSVersion)
1211 JS_GetScriptVersion(JSContext *cx, JSScript *script)
1213 return (JSVersion) (script->version & JSVERSION_MASK);
1216 /***************************************************************************/
1218 JS_PUBLIC_API(void)
1219 JS_SetNewScriptHook(JSRuntime *rt, JSNewScriptHook hook, void *callerdata)
1221 rt->globalDebugHooks.newScriptHook = hook;
1222 rt->globalDebugHooks.newScriptHookData = callerdata;
1225 JS_PUBLIC_API(void)
1226 JS_SetDestroyScriptHook(JSRuntime *rt, JSDestroyScriptHook hook,
1227 void *callerdata)
1229 rt->globalDebugHooks.destroyScriptHook = hook;
1230 rt->globalDebugHooks.destroyScriptHookData = callerdata;
1233 /***************************************************************************/
1235 JS_PUBLIC_API(JSBool)
1236 JS_EvaluateUCInStackFrame(JSContext *cx, JSStackFrame *fp,
1237 const jschar *chars, uintN length,
1238 const char *filename, uintN lineno,
1239 jsval *rval)
1241 JSObject *scobj;
1242 JSScript *script;
1243 JSBool ok;
1245 scobj = JS_GetFrameScopeChain(cx, fp);
1246 if (!scobj)
1247 return JS_FALSE;
1249 script = js_CompileScript(cx, scobj, fp, JS_StackFramePrincipals(cx, fp),
1250 TCF_COMPILE_N_GO |
1251 TCF_PUT_STATIC_DEPTH(fp->script->staticDepth + 1),
1252 chars, length, NULL,
1253 filename, lineno);
1254 if (!script)
1255 return JS_FALSE;
1257 ok = js_Execute(cx, scobj, script, fp, JSFRAME_DEBUGGER | JSFRAME_EVAL,
1258 rval);
1259 js_DestroyScript(cx, script);
1260 return ok;
1263 JS_PUBLIC_API(JSBool)
1264 JS_EvaluateInStackFrame(JSContext *cx, JSStackFrame *fp,
1265 const char *bytes, uintN length,
1266 const char *filename, uintN lineno,
1267 jsval *rval)
1269 jschar *chars;
1270 JSBool ok;
1271 size_t len = length;
1273 chars = js_InflateString(cx, bytes, &len);
1274 if (!chars)
1275 return JS_FALSE;
1276 length = (uintN) len;
1277 ok = JS_EvaluateUCInStackFrame(cx, fp, chars, length, filename, lineno,
1278 rval);
1279 JS_free(cx, chars);
1281 return ok;
1284 /************************************************************************/
1286 /* XXXbe this all needs to be reworked to avoid requiring JSScope types. */
1288 JS_PUBLIC_API(JSScopeProperty *)
1289 JS_PropertyIterator(JSObject *obj, JSScopeProperty **iteratorp)
1291 JSScopeProperty *sprop;
1292 JSScope *scope;
1294 sprop = *iteratorp;
1295 scope = OBJ_SCOPE(obj);
1297 /* XXXbe minor(?) incompatibility: iterate in reverse definition order */
1298 if (!sprop) {
1299 sprop = SCOPE_LAST_PROP(scope);
1300 } else {
1301 while ((sprop = sprop->parent) != NULL) {
1302 if (!SCOPE_HAD_MIDDLE_DELETE(scope))
1303 break;
1304 if (SCOPE_HAS_PROPERTY(scope, sprop))
1305 break;
1308 *iteratorp = sprop;
1309 return sprop;
1312 JS_PUBLIC_API(JSBool)
1313 JS_GetPropertyDesc(JSContext *cx, JSObject *obj, JSScopeProperty *sprop,
1314 JSPropertyDesc *pd)
1316 JSScope *scope;
1317 JSScopeProperty *aprop;
1318 jsval lastException;
1319 JSBool wasThrowing;
1321 pd->id = ID_TO_VALUE(sprop->id);
1323 wasThrowing = cx->throwing;
1324 if (wasThrowing) {
1325 lastException = cx->exception;
1326 if (JSVAL_IS_GCTHING(lastException) &&
1327 !js_AddRoot(cx, &lastException, "lastException")) {
1328 return JS_FALSE;
1330 cx->throwing = JS_FALSE;
1333 if (!js_GetProperty(cx, obj, sprop->id, &pd->value)) {
1334 if (!cx->throwing) {
1335 pd->flags = JSPD_ERROR;
1336 pd->value = JSVAL_VOID;
1337 } else {
1338 pd->flags = JSPD_EXCEPTION;
1339 pd->value = cx->exception;
1341 } else {
1342 pd->flags = 0;
1345 cx->throwing = wasThrowing;
1346 if (wasThrowing) {
1347 cx->exception = lastException;
1348 if (JSVAL_IS_GCTHING(lastException))
1349 js_RemoveRoot(cx->runtime, &lastException);
1352 pd->flags |= ((sprop->attrs & JSPROP_ENUMERATE) ? JSPD_ENUMERATE : 0)
1353 | ((sprop->attrs & JSPROP_READONLY) ? JSPD_READONLY : 0)
1354 | ((sprop->attrs & JSPROP_PERMANENT) ? JSPD_PERMANENT : 0);
1355 pd->spare = 0;
1356 if (sprop->getter == js_GetCallArg) {
1357 pd->slot = sprop->shortid;
1358 pd->flags |= JSPD_ARGUMENT;
1359 } else if (sprop->getter == js_GetCallVar) {
1360 pd->slot = sprop->shortid;
1361 pd->flags |= JSPD_VARIABLE;
1362 } else {
1363 pd->slot = 0;
1365 pd->alias = JSVAL_VOID;
1366 scope = OBJ_SCOPE(obj);
1367 if (SPROP_HAS_VALID_SLOT(sprop, scope)) {
1368 for (aprop = SCOPE_LAST_PROP(scope); aprop; aprop = aprop->parent) {
1369 if (aprop != sprop && aprop->slot == sprop->slot) {
1370 pd->alias = ID_TO_VALUE(aprop->id);
1371 break;
1375 return JS_TRUE;
1378 JS_PUBLIC_API(JSBool)
1379 JS_GetPropertyDescArray(JSContext *cx, JSObject *obj, JSPropertyDescArray *pda)
1381 JSClass *clasp;
1382 JSScope *scope;
1383 uint32 i, n;
1384 JSPropertyDesc *pd;
1385 JSScopeProperty *sprop;
1387 clasp = OBJ_GET_CLASS(cx, obj);
1388 if (!OBJ_IS_NATIVE(obj) || (clasp->flags & JSCLASS_NEW_ENUMERATE)) {
1389 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
1390 JSMSG_CANT_DESCRIBE_PROPS, clasp->name);
1391 return JS_FALSE;
1393 if (!clasp->enumerate(cx, obj))
1394 return JS_FALSE;
1396 /* have no props, or object's scope has not mutated from that of proto */
1397 scope = OBJ_SCOPE(obj);
1398 if (scope->object != obj || scope->entryCount == 0) {
1399 pda->length = 0;
1400 pda->array = NULL;
1401 return JS_TRUE;
1404 n = STOBJ_NSLOTS(obj);
1405 if (n > scope->entryCount)
1406 n = scope->entryCount;
1407 pd = (JSPropertyDesc *) JS_malloc(cx, (size_t)n * sizeof(JSPropertyDesc));
1408 if (!pd)
1409 return JS_FALSE;
1410 i = 0;
1411 for (sprop = SCOPE_LAST_PROP(scope); sprop; sprop = sprop->parent) {
1412 if (SCOPE_HAD_MIDDLE_DELETE(scope) && !SCOPE_HAS_PROPERTY(scope, sprop))
1413 continue;
1414 if (!js_AddRoot(cx, &pd[i].id, NULL))
1415 goto bad;
1416 if (!js_AddRoot(cx, &pd[i].value, NULL))
1417 goto bad;
1418 if (!JS_GetPropertyDesc(cx, obj, sprop, &pd[i]))
1419 goto bad;
1420 if ((pd[i].flags & JSPD_ALIAS) && !js_AddRoot(cx, &pd[i].alias, NULL))
1421 goto bad;
1422 if (++i == n)
1423 break;
1425 pda->length = i;
1426 pda->array = pd;
1427 return JS_TRUE;
1429 bad:
1430 pda->length = i + 1;
1431 pda->array = pd;
1432 JS_PutPropertyDescArray(cx, pda);
1433 return JS_FALSE;
1436 JS_PUBLIC_API(void)
1437 JS_PutPropertyDescArray(JSContext *cx, JSPropertyDescArray *pda)
1439 JSPropertyDesc *pd;
1440 uint32 i;
1442 pd = pda->array;
1443 for (i = 0; i < pda->length; i++) {
1444 js_RemoveRoot(cx->runtime, &pd[i].id);
1445 js_RemoveRoot(cx->runtime, &pd[i].value);
1446 if (pd[i].flags & JSPD_ALIAS)
1447 js_RemoveRoot(cx->runtime, &pd[i].alias);
1449 JS_free(cx, pd);
1452 /************************************************************************/
1454 JS_PUBLIC_API(JSBool)
1455 JS_SetDebuggerHandler(JSRuntime *rt, JSTrapHandler handler, void *closure)
1457 rt->globalDebugHooks.debuggerHandler = handler;
1458 rt->globalDebugHooks.debuggerHandlerData = closure;
1459 return JS_TRUE;
1462 JS_PUBLIC_API(JSBool)
1463 JS_SetSourceHandler(JSRuntime *rt, JSSourceHandler handler, void *closure)
1465 rt->globalDebugHooks.sourceHandler = handler;
1466 rt->globalDebugHooks.sourceHandlerData = closure;
1467 return JS_TRUE;
1470 JS_PUBLIC_API(JSBool)
1471 JS_SetExecuteHook(JSRuntime *rt, JSInterpreterHook hook, void *closure)
1473 rt->globalDebugHooks.executeHook = hook;
1474 rt->globalDebugHooks.executeHookData = closure;
1475 return JS_TRUE;
1478 JS_PUBLIC_API(JSBool)
1479 JS_SetCallHook(JSRuntime *rt, JSInterpreterHook hook, void *closure)
1481 rt->globalDebugHooks.callHook = hook;
1482 rt->globalDebugHooks.callHookData = closure;
1483 return JS_TRUE;
1486 JS_PUBLIC_API(JSBool)
1487 JS_SetObjectHook(JSRuntime *rt, JSObjectHook hook, void *closure)
1489 rt->globalDebugHooks.objectHook = hook;
1490 rt->globalDebugHooks.objectHookData = closure;
1491 return JS_TRUE;
1494 JS_PUBLIC_API(JSBool)
1495 JS_SetThrowHook(JSRuntime *rt, JSTrapHandler hook, void *closure)
1497 rt->globalDebugHooks.throwHook = hook;
1498 rt->globalDebugHooks.throwHookData = closure;
1499 return JS_TRUE;
1502 JS_PUBLIC_API(JSBool)
1503 JS_SetDebugErrorHook(JSRuntime *rt, JSDebugErrorHook hook, void *closure)
1505 rt->globalDebugHooks.debugErrorHook = hook;
1506 rt->globalDebugHooks.debugErrorHookData = closure;
1507 return JS_TRUE;
1510 /************************************************************************/
1512 JS_PUBLIC_API(size_t)
1513 JS_GetObjectTotalSize(JSContext *cx, JSObject *obj)
1515 size_t nbytes;
1516 JSScope *scope;
1518 nbytes = sizeof *obj;
1519 if (obj->dslots) {
1520 nbytes += ((uint32)obj->dslots[-1] - JS_INITIAL_NSLOTS + 1)
1521 * sizeof obj->dslots[0];
1523 if (OBJ_IS_NATIVE(obj)) {
1524 scope = OBJ_SCOPE(obj);
1525 if (scope->object == obj) {
1526 nbytes += sizeof *scope;
1527 nbytes += SCOPE_CAPACITY(scope) * sizeof(JSScopeProperty *);
1530 return nbytes;
1533 static size_t
1534 GetAtomTotalSize(JSContext *cx, JSAtom *atom)
1536 size_t nbytes;
1538 nbytes = sizeof(JSAtom *) + sizeof(JSDHashEntryStub);
1539 if (ATOM_IS_STRING(atom)) {
1540 nbytes += sizeof(JSString);
1541 nbytes += (JSFLATSTR_LENGTH(ATOM_TO_STRING(atom)) + 1) * sizeof(jschar);
1542 } else if (ATOM_IS_DOUBLE(atom)) {
1543 nbytes += sizeof(jsdouble);
1545 return nbytes;
1548 JS_PUBLIC_API(size_t)
1549 JS_GetFunctionTotalSize(JSContext *cx, JSFunction *fun)
1551 size_t nbytes;
1553 nbytes = sizeof *fun;
1554 nbytes += JS_GetObjectTotalSize(cx, FUN_OBJECT(fun));
1555 if (FUN_INTERPRETED(fun))
1556 nbytes += JS_GetScriptTotalSize(cx, fun->u.i.script);
1557 if (fun->atom)
1558 nbytes += GetAtomTotalSize(cx, fun->atom);
1559 return nbytes;
1562 #include "jsemit.h"
1564 JS_PUBLIC_API(size_t)
1565 JS_GetScriptTotalSize(JSContext *cx, JSScript *script)
1567 size_t nbytes, pbytes;
1568 jsatomid i;
1569 jssrcnote *sn, *notes;
1570 JSObjectArray *objarray;
1571 JSPrincipals *principals;
1573 nbytes = sizeof *script;
1574 if (script->u.object)
1575 nbytes += JS_GetObjectTotalSize(cx, script->u.object);
1577 nbytes += script->length * sizeof script->code[0];
1578 nbytes += script->atomMap.length * sizeof script->atomMap.vector[0];
1579 for (i = 0; i < script->atomMap.length; i++)
1580 nbytes += GetAtomTotalSize(cx, script->atomMap.vector[i]);
1582 if (script->filename)
1583 nbytes += strlen(script->filename) + 1;
1585 notes = SCRIPT_NOTES(script);
1586 for (sn = notes; !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn))
1587 continue;
1588 nbytes += (sn - notes + 1) * sizeof *sn;
1590 if (script->objectsOffset != 0) {
1591 objarray = JS_SCRIPT_OBJECTS(script);
1592 i = objarray->length;
1593 nbytes += sizeof *objarray + i * sizeof objarray->vector[0];
1594 do {
1595 nbytes += JS_GetObjectTotalSize(cx, objarray->vector[--i]);
1596 } while (i != 0);
1599 if (script->regexpsOffset != 0) {
1600 objarray = JS_SCRIPT_REGEXPS(script);
1601 i = objarray->length;
1602 nbytes += sizeof *objarray + i * sizeof objarray->vector[0];
1603 do {
1604 nbytes += JS_GetObjectTotalSize(cx, objarray->vector[--i]);
1605 } while (i != 0);
1608 if (script->trynotesOffset != 0) {
1609 nbytes += sizeof(JSTryNoteArray) +
1610 JS_SCRIPT_TRYNOTES(script)->length * sizeof(JSTryNote);
1613 principals = script->principals;
1614 if (principals) {
1615 JS_ASSERT(principals->refcount);
1616 pbytes = sizeof *principals;
1617 if (principals->refcount > 1)
1618 pbytes = JS_HOWMANY(pbytes, principals->refcount);
1619 nbytes += pbytes;
1622 return nbytes;
1625 JS_PUBLIC_API(uint32)
1626 JS_GetTopScriptFilenameFlags(JSContext *cx, JSStackFrame *fp)
1628 if (!fp)
1629 fp = js_GetTopStackFrame(cx);
1630 while (fp) {
1631 if (fp->script)
1632 return JS_GetScriptFilenameFlags(fp->script);
1633 fp = fp->down;
1635 return 0;
1638 JS_PUBLIC_API(uint32)
1639 JS_GetScriptFilenameFlags(JSScript *script)
1641 JS_ASSERT(script);
1642 if (!script->filename)
1643 return JSFILENAME_NULL;
1644 return js_GetScriptFilenameFlags(script->filename);
1647 JS_PUBLIC_API(JSBool)
1648 JS_FlagScriptFilenamePrefix(JSRuntime *rt, const char *prefix, uint32 flags)
1650 if (!js_SaveScriptFilenameRT(rt, prefix, flags))
1651 return JS_FALSE;
1652 return JS_TRUE;
1655 JS_PUBLIC_API(JSBool)
1656 JS_IsSystemObject(JSContext *cx, JSObject *obj)
1658 return STOBJ_IS_SYSTEM(obj);
1661 JS_PUBLIC_API(JSObject *)
1662 JS_NewSystemObject(JSContext *cx, JSClass *clasp, JSObject *proto,
1663 JSObject *parent, JSBool system)
1665 JSObject *obj;
1667 obj = js_NewObject(cx, clasp, proto, parent, 0);
1668 if (obj && system)
1669 STOBJ_SET_SYSTEM(obj);
1670 return obj;
1673 /************************************************************************/
1675 JS_PUBLIC_API(JSDebugHooks *)
1676 JS_GetGlobalDebugHooks(JSRuntime *rt)
1678 return &rt->globalDebugHooks;
1681 JS_PUBLIC_API(JSDebugHooks *)
1682 JS_SetContextDebugHooks(JSContext *cx, JSDebugHooks *hooks)
1684 JSDebugHooks *old;
1686 JS_ASSERT(hooks);
1687 old = cx->debugHooks;
1688 cx->debugHooks = hooks;
1689 return old;
1692 #ifdef MOZ_SHARK
1694 #include <CHUD/CHUD.h>
1696 JS_PUBLIC_API(JSBool)
1697 JS_StartChudRemote()
1699 if (chudIsRemoteAccessAcquired() &&
1700 (chudStartRemotePerfMonitor("Mozilla") == chudSuccess)) {
1701 return JS_TRUE;
1704 return JS_FALSE;
1707 JS_PUBLIC_API(JSBool)
1708 JS_StopChudRemote()
1710 if (chudIsRemoteAccessAcquired() &&
1711 (chudStopRemotePerfMonitor() == chudSuccess)) {
1712 return JS_TRUE;
1715 return JS_FALSE;
1718 JS_PUBLIC_API(JSBool)
1719 JS_ConnectShark()
1721 if (!chudIsInitialized() && (chudInitialize() != chudSuccess))
1722 return JS_FALSE;
1724 if (chudAcquireRemoteAccess() != chudSuccess)
1725 return JS_FALSE;
1727 return JS_TRUE;
1730 JS_PUBLIC_API(JSBool)
1731 JS_DisconnectShark()
1733 if (chudIsRemoteAccessAcquired() && (chudReleaseRemoteAccess() != chudSuccess))
1734 return JS_FALSE;
1736 return JS_TRUE;
1739 JS_FRIEND_API(JSBool)
1740 js_StartShark(JSContext *cx, JSObject *obj,
1741 uintN argc, jsval *argv, jsval *rval)
1743 if (!JS_StartChudRemote()) {
1744 JS_ReportError(cx, "Error starting CHUD.");
1747 return JS_TRUE;
1750 JS_FRIEND_API(JSBool)
1751 js_StopShark(JSContext *cx, JSObject *obj,
1752 uintN argc, jsval *argv, jsval *rval)
1754 if (!JS_StopChudRemote()) {
1755 JS_ReportError(cx, "Error stopping CHUD.");
1758 return JS_TRUE;
1761 JS_FRIEND_API(JSBool)
1762 js_ConnectShark(JSContext *cx, JSObject *obj,
1763 uintN argc, jsval *argv, jsval *rval)
1765 if (!JS_ConnectShark()) {
1766 JS_ReportError(cx, "Error connecting to Shark.");
1769 return JS_TRUE;
1772 JS_FRIEND_API(JSBool)
1773 js_DisconnectShark(JSContext *cx, JSObject *obj,
1774 uintN argc, jsval *argv, jsval *rval)
1776 if (!JS_DisconnectShark()) {
1777 JS_ReportError(cx, "Error disconnecting from Shark.");
1780 return JS_TRUE;
1783 #endif /* MOZ_SHARK */
1785 #ifdef MOZ_CALLGRIND
1787 #include <valgrind/callgrind.h>
1789 JS_FRIEND_API(JSBool)
1790 js_StartCallgrind(JSContext *cx, JSObject *obj,
1791 uintN argc, jsval *argv, jsval *rval)
1793 CALLGRIND_START_INSTRUMENTATION;
1794 CALLGRIND_ZERO_STATS;
1795 return JS_TRUE;
1798 JS_FRIEND_API(JSBool)
1799 js_StopCallgrind(JSContext *cx, JSObject *obj,
1800 uintN argc, jsval *argv, jsval *rval)
1802 CALLGRIND_STOP_INSTRUMENTATION;
1803 return JS_TRUE;
1806 JS_FRIEND_API(JSBool)
1807 js_DumpCallgrind(JSContext *cx, JSObject *obj,
1808 uintN argc, jsval *argv, jsval *rval)
1810 JSString *str;
1811 char *cstr;
1813 if (argc > 0 && JSVAL_IS_STRING(argv[0])) {
1814 str = JSVAL_TO_STRING(argv[0]);
1815 cstr = js_DeflateString(cx, JSSTRING_CHARS(str), JSSTRING_LENGTH(str));
1816 if (cstr) {
1817 CALLGRIND_DUMP_STATS_AT(cstr);
1818 JS_free(cx, cstr);
1819 return JS_TRUE;
1822 CALLGRIND_DUMP_STATS;
1824 return JS_TRUE;
1827 #endif /* MOZ_CALLGRIND */
1829 #ifdef MOZ_VTUNE
1830 #include <VTuneApi.h>
1832 static const char *vtuneErrorMessages[] = {
1833 "unknown, error #0",
1834 "invalid 'max samples' field",
1835 "invalid 'samples per buffer' field",
1836 "invalid 'sample interval' field",
1837 "invalid path",
1838 "sample file in use",
1839 "invalid 'number of events' field",
1840 "unknown, error #7",
1841 "internal error",
1842 "bad event name",
1843 "VTStopSampling called without calling VTStartSampling",
1844 "no events selected for event-based sampling",
1845 "events selected cannot be run together",
1846 "no sampling parameters",
1847 "sample database already exists",
1848 "sampling already started",
1849 "time-based sampling not supported",
1850 "invalid 'sampling parameters size' field",
1851 "invalid 'event size' field",
1852 "sampling file already bound",
1853 "invalid event path",
1854 "invalid license",
1855 "invalid 'global options' field",
1859 JS_FRIEND_API(JSBool)
1860 js_StartVtune(JSContext *cx, JSObject *obj,
1861 uintN argc, jsval *argv, jsval *rval)
1863 VTUNE_EVENT events[] = {
1864 { 1000000, 0, 0, 0, "CPU_CLK_UNHALTED.CORE" },
1865 { 1000000, 0, 0, 0, "INST_RETIRED.ANY" },
1868 U32 n_events = sizeof(events) / sizeof(VTUNE_EVENT);
1869 char *default_filename = "mozilla-vtune.tb5";
1870 JSString *str;
1871 U32 status;
1873 VTUNE_SAMPLING_PARAMS params = {
1874 sizeof(VTUNE_SAMPLING_PARAMS),
1875 sizeof(VTUNE_EVENT),
1876 0, 0, /* Reserved fields */
1877 1, /* Initialize in "paused" state */
1878 0, /* Max samples, or 0 for "continuous" */
1879 4096, /* Samples per buffer */
1880 0.1, /* Sampling interval in ms */
1881 1, /* 1 for event-based sampling, 0 for time-based */
1883 n_events,
1884 events,
1885 default_filename,
1888 if (argc > 0 && JSVAL_IS_STRING(argv[0])) {
1889 str = JSVAL_TO_STRING(argv[0]);
1890 params.tb5Filename = js_DeflateString(cx,
1891 JSSTRING_CHARS(str),
1892 JSSTRING_LENGTH(str));
1895 status = VTStartSampling(&params);
1897 if (params.tb5Filename != default_filename)
1898 JS_free(cx, params.tb5Filename);
1900 if (status != 0) {
1901 if (status == VTAPI_MULTIPLE_RUNS)
1902 VTStopSampling(0);
1903 if (status < sizeof(vtuneErrorMessages))
1904 JS_ReportError(cx, "Vtune setup error: %s",
1905 vtuneErrorMessages[status]);
1906 else
1907 JS_ReportError(cx, "Vtune setup error: %d",
1908 status);
1909 return JS_FALSE;
1911 return JS_TRUE;
1914 JS_FRIEND_API(JSBool)
1915 js_StopVtune(JSContext *cx, JSObject *obj,
1916 uintN argc, jsval *argv, jsval *rval)
1918 U32 status = VTStopSampling(1);
1919 if (status) {
1920 if (status < sizeof(vtuneErrorMessages))
1921 JS_ReportError(cx, "Vtune shutdown error: %s",
1922 vtuneErrorMessages[status]);
1923 else
1924 JS_ReportError(cx, "Vtune shutdown error: %d",
1925 status);
1926 return JS_FALSE;
1928 return JS_TRUE;
1931 JS_FRIEND_API(JSBool)
1932 js_PauseVtune(JSContext *cx, JSObject *obj,
1933 uintN argc, jsval *argv, jsval *rval)
1935 VTPause();
1936 return JS_TRUE;
1939 JS_FRIEND_API(JSBool)
1940 js_ResumeVtune(JSContext *cx, JSObject *obj,
1941 uintN argc, jsval *argv, jsval *rval)
1943 VTResume();
1944 return JS_TRUE;
1947 #endif /* MOZ_VTUNE */