1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: set ts=8 sw=4 et tw=99:
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
17 * The Original Code is Mozilla Communicator client code, released
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.
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 ***** */
47 #include "jsutil.h" /* Added by JSIFY */
51 #include "jsversion.h"
63 #include "jsstaticcheck.h"
66 #include "jsatominlines.h"
67 #include "jsobjinlines.h"
68 #include "jsscopeinlines.h"
70 #include "jsautooplen.h"
74 typedef struct JSTrap
{
79 JSTrapHandler handler
;
83 #define DBG_LOCK(rt) JS_ACQUIRE_LOCK((rt)->debuggerLock)
84 #define DBG_UNLOCK(rt) JS_RELEASE_LOCK((rt)->debuggerLock)
85 #define DBG_LOCK_EVAL(rt,expr) (DBG_LOCK(rt), (expr), DBG_UNLOCK(rt))
88 * NB: FindTrap must be called with rt->debuggerLock acquired.
91 FindTrap(JSRuntime
*rt
, JSScript
*script
, jsbytecode
*pc
)
95 for (trap
= (JSTrap
*)rt
->trapList
.next
;
96 &trap
->links
!= &rt
->trapList
;
97 trap
= (JSTrap
*)trap
->links
.next
) {
98 if (trap
->script
== script
&& trap
->pc
== pc
)
105 js_UntrapScriptCode(JSContext
*cx
, JSScript
*script
)
114 for (trap
= (JSTrap
*)rt
->trapList
.next
;
117 trap
= (JSTrap
*)trap
->links
.next
) {
118 if (trap
->script
== script
&&
119 (size_t)(trap
->pc
- script
->code
) < script
->length
) {
120 if (code
== script
->code
) {
121 jssrcnote
*sn
, *notes
;
124 nbytes
= script
->length
* sizeof(jsbytecode
);
125 notes
= script
->notes();
126 for (sn
= notes
; !SN_IS_TERMINATOR(sn
); sn
= SN_NEXT(sn
))
128 nbytes
+= (sn
- notes
+ 1) * sizeof *sn
;
130 code
= (jsbytecode
*) cx
->malloc(nbytes
);
133 memcpy(code
, script
->code
, nbytes
);
134 JS_PURGE_GSN_CACHE(cx
);
136 code
[trap
->pc
- script
->code
] = trap
->op
;
143 JS_PUBLIC_API(JSBool
)
144 JS_SetTrap(JSContext
*cx
, JSScript
*script
, jsbytecode
*pc
,
145 JSTrapHandler handler
, jsval closure
)
147 JSTrap
*junk
, *trap
, *twin
;
151 if (script
== JSScript::emptyScript()) {
152 JS_ReportErrorFlagsAndNumber(cx
, JSREPORT_ERROR
, js_GetErrorMessage
,
153 NULL
, JSMSG_READ_ONLY
, "empty script");
157 JS_ASSERT((JSOp
) *pc
!= JSOP_TRAP
);
161 trap
= FindTrap(rt
, script
, pc
);
163 JS_ASSERT(trap
->script
== script
&& trap
->pc
== pc
);
164 JS_ASSERT(*pc
== JSOP_TRAP
);
166 sample
= rt
->debuggerMutations
;
168 trap
= (JSTrap
*) cx
->malloc(sizeof *trap
);
171 trap
->closure
= JSVAL_NULL
;
173 twin
= (rt
->debuggerMutations
!= sample
)
174 ? FindTrap(rt
, script
, pc
)
180 JS_APPEND_LINK(&trap
->links
, &rt
->trapList
);
181 ++rt
->debuggerMutations
;
182 trap
->script
= script
;
184 trap
->op
= (JSOp
)*pc
;
188 trap
->handler
= handler
;
189 trap
->closure
= closure
;
197 JS_GetTrapOpcode(JSContext
*cx
, JSScript
*script
, jsbytecode
*pc
)
205 trap
= FindTrap(rt
, script
, pc
);
206 op
= trap
? trap
->op
: (JSOp
) *pc
;
212 DestroyTrapAndUnlock(JSContext
*cx
, JSTrap
*trap
)
214 ++cx
->runtime
->debuggerMutations
;
215 JS_REMOVE_LINK(&trap
->links
);
216 *trap
->pc
= (jsbytecode
)trap
->op
;
217 DBG_UNLOCK(cx
->runtime
);
222 JS_ClearTrap(JSContext
*cx
, JSScript
*script
, jsbytecode
*pc
,
223 JSTrapHandler
*handlerp
, jsval
*closurep
)
227 DBG_LOCK(cx
->runtime
);
228 trap
= FindTrap(cx
->runtime
, script
, pc
);
230 *handlerp
= trap
? trap
->handler
: NULL
;
232 *closurep
= trap
? trap
->closure
: JSVAL_NULL
;
234 DestroyTrapAndUnlock(cx
, trap
);
236 DBG_UNLOCK(cx
->runtime
);
240 JS_ClearScriptTraps(JSContext
*cx
, JSScript
*script
)
248 for (trap
= (JSTrap
*)rt
->trapList
.next
;
249 &trap
->links
!= &rt
->trapList
;
251 next
= (JSTrap
*)trap
->links
.next
;
252 if (trap
->script
== script
) {
253 sample
= rt
->debuggerMutations
;
254 DestroyTrapAndUnlock(cx
, trap
);
256 if (rt
->debuggerMutations
!= sample
+ 1)
257 next
= (JSTrap
*)rt
->trapList
.next
;
264 JS_ClearAllTraps(JSContext
*cx
)
272 for (trap
= (JSTrap
*)rt
->trapList
.next
;
273 &trap
->links
!= &rt
->trapList
;
275 next
= (JSTrap
*)trap
->links
.next
;
276 sample
= rt
->debuggerMutations
;
277 DestroyTrapAndUnlock(cx
, trap
);
279 if (rt
->debuggerMutations
!= sample
+ 1)
280 next
= (JSTrap
*)rt
->trapList
.next
;
286 * NB: js_MarkTraps does not acquire cx->runtime->debuggerLock, since the
287 * debugger should never be racing with the GC (i.e., the debugger must
288 * respect the request model).
291 js_MarkTraps(JSTracer
*trc
)
293 JSRuntime
*rt
= trc
->context
->runtime
;
295 for (JSTrap
*trap
= (JSTrap
*) rt
->trapList
.next
;
296 &trap
->links
!= &rt
->trapList
;
297 trap
= (JSTrap
*) trap
->links
.next
) {
298 MarkValue(trc
, Valueify(trap
->closure
), "trap->closure");
302 JS_PUBLIC_API(JSTrapStatus
)
303 JS_HandleTrap(JSContext
*cx
, JSScript
*script
, jsbytecode
*pc
, jsval
*rval
)
309 DBG_LOCK(cx
->runtime
);
310 trap
= FindTrap(cx
->runtime
, script
, pc
);
311 JS_ASSERT(!trap
|| trap
->handler
);
314 DBG_UNLOCK(cx
->runtime
);
316 /* Defend against "pc for wrong script" API usage error. */
317 JS_ASSERT(op
!= JSOP_TRAP
);
320 /* If the API was abused, we must fail for want of the real op. */
324 /* Assume a race with a debugger thread and try to carry on. */
325 *rval
= INT_TO_JSVAL(op
);
326 return JSTRAP_CONTINUE
;
328 /* Always fail if single-threaded (must be an API usage error). */
332 DBG_UNLOCK(cx
->runtime
);
335 * It's important that we not use 'trap->' after calling the callback --
336 * the callback might remove the trap!
338 op
= (jsint
)trap
->op
;
339 status
= trap
->handler(cx
, script
, pc
, rval
, trap
->closure
);
340 if (status
== JSTRAP_CONTINUE
) {
341 /* By convention, return the true op to the interpreter in rval. */
342 *rval
= INT_TO_JSVAL(op
);
349 JITInhibitingHookChange(JSRuntime
*rt
, bool wasInhibited
)
352 if (!rt
->debuggerInhibitsJIT()) {
353 for (JSCList
*cl
= rt
->contextList
.next
; cl
!= &rt
->contextList
; cl
= cl
->next
)
354 js_ContextFromLinkField(cl
)->updateJITEnabled();
356 } else if (rt
->debuggerInhibitsJIT()) {
357 for (JSCList
*cl
= rt
->contextList
.next
; cl
!= &rt
->contextList
; cl
= cl
->next
)
358 js_ContextFromLinkField(cl
)->jitEnabled
= false;
363 LeaveTraceRT(JSRuntime
*rt
)
365 JSThreadData
*data
= js_CurrentThreadData(rt
);
366 JSContext
*cx
= data
? data
->traceMonitor
.tracecx
: NULL
;
374 JS_PUBLIC_API(JSBool
)
375 JS_SetInterrupt(JSRuntime
*rt
, JSInterruptHook hook
, void *closure
)
380 bool wasInhibited
= rt
->debuggerInhibitsJIT();
382 rt
->globalDebugHooks
.interruptHook
= hook
;
383 rt
->globalDebugHooks
.interruptHookData
= closure
;
385 JITInhibitingHookChange(rt
, wasInhibited
);
392 JS_PUBLIC_API(JSBool
)
393 JS_ClearInterrupt(JSRuntime
*rt
, JSInterruptHook
*hoop
, void **closurep
)
397 bool wasInhibited
= rt
->debuggerInhibitsJIT();
400 *hoop
= rt
->globalDebugHooks
.interruptHook
;
402 *closurep
= rt
->globalDebugHooks
.interruptHookData
;
403 rt
->globalDebugHooks
.interruptHook
= 0;
404 rt
->globalDebugHooks
.interruptHookData
= 0;
406 JITInhibitingHookChange(rt
, wasInhibited
);
411 /************************************************************************/
413 typedef struct JSWatchPoint
{
415 JSObject
*object
; /* weak link, see js_FinalizeObject */
416 JSScopeProperty
*sprop
;
418 JSWatchPointHandler handler
;
423 #define JSWP_LIVE 0x1 /* live because set and not cleared */
424 #define JSWP_HELD 0x2 /* held while running handler/setter */
427 IsWatchedProperty(JSContext
*cx
, JSScopeProperty
*sprop
);
430 * NB: DropWatchPointAndUnlock releases cx->runtime->debuggerLock in all cases.
433 DropWatchPointAndUnlock(JSContext
*cx
, JSWatchPoint
*wp
, uintN flag
)
436 JSScopeProperty
*sprop
;
442 if (wp
->flags
!= 0) {
443 DBG_UNLOCK(cx
->runtime
);
448 * Remove wp from the list, then if there are no other watchpoints for
449 * wp->sprop in any scope, restore wp->sprop->setter from wp.
451 ++cx
->runtime
->debuggerMutations
;
452 JS_REMOVE_LINK(&wp
->links
);
456 * Passing null for the scope parameter tells js_GetWatchedSetter to find
457 * any watch point for sprop, and not to lock or unlock rt->debuggerLock.
458 * If js_ChangeNativePropertyAttrs fails, propagate failure after removing
459 * wp->closure's root and freeing wp.
461 setter
= js_GetWatchedSetter(cx
->runtime
, NULL
, sprop
);
462 DBG_UNLOCK(cx
->runtime
);
464 JS_LOCK_OBJ(cx
, wp
->object
);
465 scope
= wp
->object
->scope();
468 * If the property wasn't found on wp->object, or it isn't still being
469 * watched, then someone else must have deleted or unwatched it, and we
470 * don't need to change the property attributes.
472 JSScopeProperty
*wprop
= scope
->lookup(sprop
->id
);
474 wprop
->hasSetterValue() == sprop
->hasSetterValue() &&
475 IsWatchedProperty(cx
, wprop
)) {
476 sprop
= scope
->changeProperty(cx
, wprop
, 0, wprop
->attributes(),
477 wprop
->getter(), wp
->setter
);
481 JS_UNLOCK_SCOPE(cx
, scope
);
489 * NB: js_TraceWatchPoints does not acquire cx->runtime->debuggerLock, since
490 * the debugger should never be racing with the GC (i.e., the debugger must
491 * respect the request model).
494 js_TraceWatchPoints(JSTracer
*trc
, JSObject
*obj
)
499 rt
= trc
->context
->runtime
;
501 for (wp
= (JSWatchPoint
*)rt
->watchPointList
.next
;
502 &wp
->links
!= &rt
->watchPointList
;
503 wp
= (JSWatchPoint
*)wp
->links
.next
) {
504 if (wp
->object
== obj
) {
505 wp
->sprop
->trace(trc
);
506 if (wp
->sprop
->hasSetterValue() && wp
->setter
)
507 JS_CALL_OBJECT_TRACER(trc
, CastAsObject(wp
->setter
), "wp->setter");
508 JS_CALL_OBJECT_TRACER(trc
, wp
->closure
, "wp->closure");
514 js_SweepWatchPoints(JSContext
*cx
)
517 JSWatchPoint
*wp
, *next
;
522 for (wp
= (JSWatchPoint
*)rt
->watchPointList
.next
;
523 &wp
->links
!= &rt
->watchPointList
;
525 next
= (JSWatchPoint
*)wp
->links
.next
;
526 if (js_IsAboutToBeFinalized(wp
->object
)) {
527 sample
= rt
->debuggerMutations
;
529 /* Ignore failures. */
530 DropWatchPointAndUnlock(cx
, wp
, JSWP_LIVE
);
532 if (rt
->debuggerMutations
!= sample
+ 1)
533 next
= (JSWatchPoint
*)rt
->watchPointList
.next
;
542 * NB: FindWatchPoint must be called with rt->debuggerLock acquired.
544 static JSWatchPoint
*
545 FindWatchPoint(JSRuntime
*rt
, JSScope
*scope
, jsid id
)
549 for (wp
= (JSWatchPoint
*)rt
->watchPointList
.next
;
550 &wp
->links
!= &rt
->watchPointList
;
551 wp
= (JSWatchPoint
*)wp
->links
.next
) {
552 if (wp
->object
->scope() == scope
&& wp
->sprop
->id
== id
)
559 js_FindWatchPoint(JSRuntime
*rt
, JSScope
*scope
, jsid id
)
562 JSScopeProperty
*sprop
;
565 wp
= FindWatchPoint(rt
, scope
, id
);
566 sprop
= wp
? wp
->sprop
: NULL
;
572 * Secret handshake with DropWatchPointAndUnlock: if (!scope), we know our
573 * caller has acquired rt->debuggerLock, so we don't have to.
576 js_GetWatchedSetter(JSRuntime
*rt
, JSScope
*scope
,
577 const JSScopeProperty
*sprop
)
585 for (wp
= (JSWatchPoint
*)rt
->watchPointList
.next
;
586 &wp
->links
!= &rt
->watchPointList
;
587 wp
= (JSWatchPoint
*)wp
->links
.next
) {
588 if ((!scope
|| wp
->object
->scope() == scope
) && wp
->sprop
== sprop
) {
599 js_watch_set(JSContext
*cx
, JSObject
*obj
, jsid id
, Value
*vp
)
601 JSRuntime
*rt
= cx
->runtime
;
603 for (JSWatchPoint
*wp
= (JSWatchPoint
*)rt
->watchPointList
.next
;
604 &wp
->links
!= &rt
->watchPointList
;
605 wp
= (JSWatchPoint
*)wp
->links
.next
) {
606 JSScopeProperty
*sprop
= wp
->sprop
;
607 if (wp
->object
== obj
&& SPROP_USERID(sprop
) == id
&&
608 !(wp
->flags
& JSWP_HELD
)) {
609 wp
->flags
|= JSWP_HELD
;
612 JS_LOCK_OBJ(cx
, obj
);
613 jsid propid
= sprop
->id
;
614 jsid userid
= SPROP_USERID(sprop
);
615 JSScope
*scope
= obj
->scope();
616 JS_UNLOCK_OBJ(cx
, obj
);
618 /* NB: wp is held, so we can safely dereference it still. */
619 if (!wp
->handler(cx
, obj
, propid
,
620 SPROP_HAS_VALID_SLOT(sprop
, scope
)
621 ? Jsvalify(obj
->getSlotMT(cx
, sprop
->slot
))
623 Jsvalify(vp
), wp
->closure
)) {
625 DropWatchPointAndUnlock(cx
, wp
, JSWP_HELD
);
630 * Pass the output of the handler to the setter. Security wrappers
631 * prevent any funny business between watchpoints and setters.
633 JSBool ok
= !wp
->setter
||
634 (sprop
->hasSetterValue()
635 ? InternalCall(cx
, obj
,
636 ObjectValue(*CastAsObject(wp
->setter
)),
638 : callJSPropertyOpSetter(cx
, wp
->setter
, obj
, userid
, vp
));
641 return DropWatchPointAndUnlock(cx
, wp
, JSWP_HELD
) && ok
;
649 js_watch_set_wrapper(JSContext
*cx
, JSObject
*obj
, uintN argc
, Value
*argv
,
656 funobj
= &argv
[-2].toObject();
657 wrapper
= GET_FUNCTION_PRIVATE(cx
, funobj
);
658 userid
= ATOM_TO_JSID(wrapper
->atom
);
660 return js_watch_set(cx
, obj
, userid
, rval
);
664 IsWatchedProperty(JSContext
*cx
, JSScopeProperty
*sprop
)
666 if (sprop
->hasSetterValue()) {
667 JSObject
*funobj
= sprop
->setterObject();
668 if (!funobj
|| !funobj
->isFunction())
671 JSFunction
*fun
= GET_FUNCTION_PRIVATE(cx
, funobj
);
672 return FUN_NATIVE(fun
) == js_watch_set_wrapper
;
674 return sprop
->setterOp() == js_watch_set
;
678 js_WrapWatchedSetter(JSContext
*cx
, jsid id
, uintN attrs
, PropertyOp setter
)
683 if (!(attrs
& JSPROP_SETTER
))
684 return &js_watch_set
; /* & to silence schoolmarmish MSVC */
686 if (JSID_IS_ATOM(id
)) {
687 atom
= JSID_TO_ATOM(id
);
688 } else if (JSID_IS_INT(id
)) {
689 if (!js_ValueToStringId(cx
, IdToValue(id
), &id
))
691 atom
= JSID_TO_ATOM(id
);
696 wrapper
= js_NewFunction(cx
, NULL
, js_watch_set_wrapper
, 1, 0,
697 setter
? CastAsObject(setter
)->getParent() : NULL
, atom
);
700 return CastAsPropertyOp(FUN_OBJECT(wrapper
));
703 JS_PUBLIC_API(JSBool
)
704 JS_SetWatchPoint(JSContext
*cx
, JSObject
*obj
, jsid id
,
705 JSWatchPointHandler handler
, JSObject
*closure
)
713 JSScopeProperty
*sprop
;
720 obj
= obj
->wrappedObject(cx
);
721 OBJ_TO_INNER_OBJECT(cx
, obj
);
725 AutoValueRooter
idroot(cx
);
726 if (JSID_IS_INT(id
)) {
729 if (!js_ValueToStringId(cx
, IdToValue(id
), &propid
))
731 propid
= js_CheckForStringIndex(propid
);
732 idroot
.set(IdToValue(propid
));
736 * If, by unwrapping and innerizing, we changed the object, check
737 * again to make sure that we're allowed to set a watch point.
739 if (origobj
!= obj
&& !CheckAccess(cx
, obj
, propid
, JSACC_WATCH
, &v
, &attrs
))
742 if (!obj
->isNative()) {
743 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
, JSMSG_CANT_WATCH
,
744 obj
->getClass()->name
);
748 if (!js_LookupProperty(cx
, obj
, propid
, &pobj
, &prop
))
750 sprop
= (JSScopeProperty
*) prop
;
753 /* Check for a deleted symbol watchpoint, which holds its property. */
754 sprop
= js_FindWatchPoint(rt
, obj
->scope(), propid
);
756 /* Make a new property in obj so we can watch for the first set. */
757 if (!js_DefineNativeProperty(cx
, obj
, propid
, UndefinedValue(), NULL
, NULL
,
758 JSPROP_ENUMERATE
, 0, 0, &prop
)) {
761 sprop
= (JSScopeProperty
*) prop
;
763 } else if (pobj
!= obj
) {
764 /* Clone the prototype property so we can watch the right object. */
765 AutoValueRooter
valroot(cx
);
766 PropertyOp getter
, setter
;
770 if (pobj
->isNative()) {
771 valroot
.set(SPROP_HAS_VALID_SLOT(sprop
, pobj
->scope())
772 ? pobj
->lockedGetSlot(sprop
->slot
)
774 getter
= sprop
->getter();
775 setter
= sprop
->setter();
776 attrs
= sprop
->attributes();
777 flags
= sprop
->getFlags();
778 shortid
= sprop
->shortid
;
779 JS_UNLOCK_OBJ(cx
, pobj
);
781 if (!pobj
->getProperty(cx
, propid
, valroot
.addr()) ||
782 !pobj
->getAttributes(cx
, propid
, &attrs
)) {
785 getter
= setter
= NULL
;
790 /* Recall that obj is native, whether or not pobj is native. */
791 if (!js_DefineNativeProperty(cx
, obj
, propid
, valroot
.value(),
792 getter
, setter
, attrs
, flags
,
796 sprop
= (JSScopeProperty
*) prop
;
800 * At this point, prop/sprop exists in obj, obj is locked, and we must
801 * unlock the object before returning.
805 wp
= FindWatchPoint(rt
, obj
->scope(), propid
);
808 watcher
= js_WrapWatchedSetter(cx
, propid
, sprop
->attributes(), sprop
->setter());
814 wp
= (JSWatchPoint
*) cx
->malloc(sizeof *wp
);
822 wp
->setter
= sprop
->setter();
823 wp
->flags
= JSWP_LIVE
;
825 /* XXXbe nest in obj lock here */
826 sprop
= js_ChangeNativePropertyAttrs(cx
, obj
, sprop
, 0, sprop
->attributes(),
827 sprop
->getter(), watcher
);
829 /* Self-link so DropWatchPointAndUnlock can JS_REMOVE_LINK it. */
830 JS_INIT_CLIST(&wp
->links
);
832 DropWatchPointAndUnlock(cx
, wp
, JSWP_LIVE
);
839 * Now that wp is fully initialized, append it to rt's wp list.
840 * Because obj is locked we know that no other thread could have added
841 * a watchpoint for (obj, propid).
844 JS_ASSERT(!FindWatchPoint(rt
, obj
->scope(), propid
));
845 JS_APPEND_LINK(&wp
->links
, &rt
->watchPointList
);
846 ++rt
->debuggerMutations
;
848 wp
->handler
= handler
;
849 wp
->closure
= reinterpret_cast<JSObject
*>(closure
);
853 JS_UNLOCK_OBJ(cx
, obj
);
857 JS_PUBLIC_API(JSBool
)
858 JS_ClearWatchPoint(JSContext
*cx
, JSObject
*obj
, jsid id
,
859 JSWatchPointHandler
*handlerp
, JSObject
**closurep
)
866 for (wp
= (JSWatchPoint
*)rt
->watchPointList
.next
;
867 &wp
->links
!= &rt
->watchPointList
;
868 wp
= (JSWatchPoint
*)wp
->links
.next
) {
869 if (wp
->object
== obj
&& SPROP_USERID(wp
->sprop
) == id
) {
871 *handlerp
= wp
->handler
;
873 *closurep
= wp
->closure
;
874 return DropWatchPointAndUnlock(cx
, wp
, JSWP_LIVE
);
885 JS_PUBLIC_API(JSBool
)
886 JS_ClearWatchPointsForObject(JSContext
*cx
, JSObject
*obj
)
889 JSWatchPoint
*wp
, *next
;
894 for (wp
= (JSWatchPoint
*)rt
->watchPointList
.next
;
895 &wp
->links
!= &rt
->watchPointList
;
897 next
= (JSWatchPoint
*)wp
->links
.next
;
898 if (wp
->object
== obj
) {
899 sample
= rt
->debuggerMutations
;
900 if (!DropWatchPointAndUnlock(cx
, wp
, JSWP_LIVE
))
903 if (rt
->debuggerMutations
!= sample
+ 1)
904 next
= (JSWatchPoint
*)rt
->watchPointList
.next
;
911 JS_PUBLIC_API(JSBool
)
912 JS_ClearAllWatchPoints(JSContext
*cx
)
915 JSWatchPoint
*wp
, *next
;
920 for (wp
= (JSWatchPoint
*)rt
->watchPointList
.next
;
921 &wp
->links
!= &rt
->watchPointList
;
923 next
= (JSWatchPoint
*)wp
->links
.next
;
924 sample
= rt
->debuggerMutations
;
925 if (!DropWatchPointAndUnlock(cx
, wp
, JSWP_LIVE
))
928 if (rt
->debuggerMutations
!= sample
+ 1)
929 next
= (JSWatchPoint
*)rt
->watchPointList
.next
;
935 /************************************************************************/
938 JS_PCToLineNumber(JSContext
*cx
, JSScript
*script
, jsbytecode
*pc
)
940 return js_PCToLineNumber(cx
, script
, pc
);
943 JS_PUBLIC_API(jsbytecode
*)
944 JS_LineNumberToPC(JSContext
*cx
, JSScript
*script
, uintN lineno
)
946 return js_LineNumberToPC(script
, lineno
);
950 JS_GetFunctionArgumentCount(JSContext
*cx
, JSFunction
*fun
)
955 JS_PUBLIC_API(JSBool
)
956 JS_FunctionHasLocalNames(JSContext
*cx
, JSFunction
*fun
)
958 return fun
->hasLocalNames();
961 extern JS_PUBLIC_API(jsuword
*)
962 JS_GetFunctionLocalNameArray(JSContext
*cx
, JSFunction
*fun
, void **markp
)
964 *markp
= JS_ARENA_MARK(&cx
->tempPool
);
965 return js_GetLocalNameArray(cx
, fun
, &cx
->tempPool
);
968 extern JS_PUBLIC_API(JSAtom
*)
969 JS_LocalNameToAtom(jsuword w
)
971 return JS_LOCAL_NAME_TO_ATOM(w
);
974 extern JS_PUBLIC_API(JSString
*)
975 JS_AtomKey(JSAtom
*atom
)
977 return ATOM_TO_STRING(atom
);
980 extern JS_PUBLIC_API(void)
981 JS_ReleaseFunctionLocalNameArray(JSContext
*cx
, void *mark
)
983 JS_ARENA_RELEASE(&cx
->tempPool
, mark
);
986 JS_PUBLIC_API(JSScript
*)
987 JS_GetFunctionScript(JSContext
*cx
, JSFunction
*fun
)
989 return FUN_SCRIPT(fun
);
992 JS_PUBLIC_API(JSNative
)
993 JS_GetFunctionNative(JSContext
*cx
, JSFunction
*fun
)
995 return Jsvalify(FUN_NATIVE(fun
));
998 JS_PUBLIC_API(JSFastNative
)
999 JS_GetFunctionFastNative(JSContext
*cx
, JSFunction
*fun
)
1001 return Jsvalify(FUN_FAST_NATIVE(fun
));
1004 JS_PUBLIC_API(JSPrincipals
*)
1005 JS_GetScriptPrincipals(JSContext
*cx
, JSScript
*script
)
1007 return script
->principals
;
1010 /************************************************************************/
1013 * Stack Frame Iterator
1015 JS_PUBLIC_API(JSStackFrame
*)
1016 JS_FrameIterator(JSContext
*cx
, JSStackFrame
**iteratorp
)
1018 *iteratorp
= (*iteratorp
== NULL
) ? js_GetTopStackFrame(cx
) : (*iteratorp
)->down
;
1022 JS_PUBLIC_API(JSScript
*)
1023 JS_GetFrameScript(JSContext
*cx
, JSStackFrame
*fp
)
1025 return fp
->maybeScript();
1028 JS_PUBLIC_API(jsbytecode
*)
1029 JS_GetFramePC(JSContext
*cx
, JSStackFrame
*fp
)
1034 JS_PUBLIC_API(JSStackFrame
*)
1035 JS_GetScriptedCaller(JSContext
*cx
, JSStackFrame
*fp
)
1037 return js_GetScriptedCaller(cx
, fp
);
1040 JS_PUBLIC_API(JSPrincipals
*)
1041 JS_StackFramePrincipals(JSContext
*cx
, JSStackFrame
*fp
)
1043 JSSecurityCallbacks
*callbacks
;
1045 if (fp
->hasFunction()) {
1046 callbacks
= JS_GetSecurityCallbacks(cx
);
1047 if (callbacks
&& callbacks
->findObjectPrincipals
) {
1048 if (FUN_OBJECT(fp
->getFunction()) != fp
->callee())
1049 return callbacks
->findObjectPrincipals(cx
, fp
->callee());
1053 if (fp
->hasScript())
1054 return fp
->getScript()->principals
;
1059 js_EvalFramePrincipals(JSContext
*cx
, JSObject
*callee
, JSStackFrame
*caller
)
1061 JSPrincipals
*principals
, *callerPrincipals
;
1062 JSSecurityCallbacks
*callbacks
;
1064 callbacks
= JS_GetSecurityCallbacks(cx
);
1065 if (callbacks
&& callbacks
->findObjectPrincipals
)
1066 principals
= callbacks
->findObjectPrincipals(cx
, callee
);
1071 callerPrincipals
= JS_StackFramePrincipals(cx
, caller
);
1072 return (callerPrincipals
&& principals
&&
1073 callerPrincipals
->subsume(callerPrincipals
, principals
))
1078 JS_PUBLIC_API(JSPrincipals
*)
1079 JS_EvalFramePrincipals(JSContext
*cx
, JSStackFrame
*fp
, JSStackFrame
*caller
)
1081 return js_EvalFramePrincipals(cx
, fp
->callee(), caller
);
1084 JS_PUBLIC_API(void *)
1085 JS_GetFrameAnnotation(JSContext
*cx
, JSStackFrame
*fp
)
1087 if (fp
->hasAnnotation() && fp
->hasScript()) {
1088 JSPrincipals
*principals
= JS_StackFramePrincipals(cx
, fp
);
1090 if (principals
&& principals
->globalPrivilegesEnabled(cx
, principals
)) {
1092 * Give out an annotation only if privileges have not been revoked
1093 * or disabled globally.
1095 return fp
->getAnnotation();
1103 JS_SetFrameAnnotation(JSContext
*cx
, JSStackFrame
*fp
, void *annotation
)
1105 fp
->setAnnotation(annotation
);
1108 JS_PUBLIC_API(void *)
1109 JS_GetFramePrincipalArray(JSContext
*cx
, JSStackFrame
*fp
)
1111 JSPrincipals
*principals
;
1113 principals
= JS_StackFramePrincipals(cx
, fp
);
1116 return principals
->getPrincipalArray(cx
, principals
);
1119 JS_PUBLIC_API(JSBool
)
1120 JS_IsNativeFrame(JSContext
*cx
, JSStackFrame
*fp
)
1122 return !fp
->hasScript();
1125 /* this is deprecated, use JS_GetFrameScopeChain instead */
1126 JS_PUBLIC_API(JSObject
*)
1127 JS_GetFrameObject(JSContext
*cx
, JSStackFrame
*fp
)
1129 return fp
->maybeScopeChain();
1132 JS_PUBLIC_API(JSObject
*)
1133 JS_GetFrameScopeChain(JSContext
*cx
, JSStackFrame
*fp
)
1135 JS_ASSERT(cx
->stack().contains(fp
));
1137 /* Force creation of argument and call objects if not yet created */
1138 (void) JS_GetFrameCallObject(cx
, fp
);
1139 return js_GetScopeChain(cx
, fp
);
1142 JS_PUBLIC_API(JSObject
*)
1143 JS_GetFrameCallObject(JSContext
*cx
, JSStackFrame
*fp
)
1145 JS_ASSERT(cx
->stack().contains(fp
));
1147 if (!fp
->hasFunction())
1150 /* Force creation of argument object if not yet created */
1151 (void) js_GetArgsObject(cx
, fp
);
1154 * XXX ill-defined: null return here means error was reported, unlike a
1155 * null returned above or in the #else
1157 return js_GetCallObject(cx
, fp
);
1160 JS_PUBLIC_API(JSObject
*)
1161 JS_GetFrameThis(JSContext
*cx
, JSStackFrame
*fp
)
1163 if (fp
->isDummyFrame())
1166 return fp
->getThisObject(cx
);
1169 JS_PUBLIC_API(JSFunction
*)
1170 JS_GetFrameFunction(JSContext
*cx
, JSStackFrame
*fp
)
1172 return fp
->maybeFunction();
1175 JS_PUBLIC_API(JSObject
*)
1176 JS_GetFrameFunctionObject(JSContext
*cx
, JSStackFrame
*fp
)
1178 if (!fp
->hasFunction())
1181 JS_ASSERT(fp
->callee()->isFunction());
1182 JS_ASSERT(fp
->callee()->getPrivate() == fp
->getFunction());
1183 return fp
->callee();
1186 JS_PUBLIC_API(JSBool
)
1187 JS_IsConstructorFrame(JSContext
*cx
, JSStackFrame
*fp
)
1189 return (fp
->flags
& JSFRAME_CONSTRUCTING
) != 0;
1192 JS_PUBLIC_API(JSObject
*)
1193 JS_GetFrameCalleeObject(JSContext
*cx
, JSStackFrame
*fp
)
1195 return fp
->callee();
1198 JS_PUBLIC_API(JSBool
)
1199 JS_GetValidFrameCalleeObject(JSContext
*cx
, JSStackFrame
*fp
, jsval
*vp
)
1203 if (!fp
->getValidCalleeObject(cx
, &v
))
1209 JS_PUBLIC_API(JSBool
)
1210 JS_IsDebuggerFrame(JSContext
*cx
, JSStackFrame
*fp
)
1212 return (fp
->flags
& JSFRAME_DEBUGGER
) != 0;
1215 JS_PUBLIC_API(jsval
)
1216 JS_GetFrameReturnValue(JSContext
*cx
, JSStackFrame
*fp
)
1218 return Jsvalify(fp
->getReturnValue());
1222 JS_SetFrameReturnValue(JSContext
*cx
, JSStackFrame
*fp
, jsval rval
)
1224 fp
->setReturnValue(Valueify(rval
));
1227 /************************************************************************/
1229 JS_PUBLIC_API(const char *)
1230 JS_GetScriptFilename(JSContext
*cx
, JSScript
*script
)
1232 return script
->filename
;
1235 JS_PUBLIC_API(uintN
)
1236 JS_GetScriptBaseLineNumber(JSContext
*cx
, JSScript
*script
)
1238 return script
->lineno
;
1241 JS_PUBLIC_API(uintN
)
1242 JS_GetScriptLineExtent(JSContext
*cx
, JSScript
*script
)
1244 return js_GetScriptLineExtent(script
);
1247 JS_PUBLIC_API(JSVersion
)
1248 JS_GetScriptVersion(JSContext
*cx
, JSScript
*script
)
1250 return (JSVersion
) (script
->version
& JSVERSION_MASK
);
1253 /***************************************************************************/
1256 JS_SetNewScriptHook(JSRuntime
*rt
, JSNewScriptHook hook
, void *callerdata
)
1258 rt
->globalDebugHooks
.newScriptHook
= hook
;
1259 rt
->globalDebugHooks
.newScriptHookData
= callerdata
;
1263 JS_SetDestroyScriptHook(JSRuntime
*rt
, JSDestroyScriptHook hook
,
1266 rt
->globalDebugHooks
.destroyScriptHook
= hook
;
1267 rt
->globalDebugHooks
.destroyScriptHookData
= callerdata
;
1270 /***************************************************************************/
1272 JS_PUBLIC_API(JSBool
)
1273 JS_EvaluateUCInStackFrame(JSContext
*cx
, JSStackFrame
*fp
,
1274 const jschar
*chars
, uintN length
,
1275 const char *filename
, uintN lineno
,
1278 JS_ASSERT_NOT_ON_TRACE(cx
);
1280 JSObject
*scobj
= JS_GetFrameScopeChain(cx
, fp
);
1285 * NB: This function breaks the assumption that the compiler can see all
1286 * calls and properly compute a static level. In order to get around this,
1287 * we use a static level that will cause us not to attempt to optimize
1288 * variable references made by this frame.
1290 JSScript
*script
= Compiler::compileScript(cx
, scobj
, fp
, JS_StackFramePrincipals(cx
, fp
),
1291 TCF_COMPILE_N_GO
, chars
, length
, NULL
,
1292 filename
, lineno
, NULL
,
1293 UpvarCookie::UPVAR_LEVEL_LIMIT
);
1298 bool ok
= !!Execute(cx
, scobj
, script
, fp
, JSFRAME_DEBUGGER
| JSFRAME_EVAL
, Valueify(rval
));
1300 js_DestroyScript(cx
, script
);
1304 JS_PUBLIC_API(JSBool
)
1305 JS_EvaluateInStackFrame(JSContext
*cx
, JSStackFrame
*fp
,
1306 const char *bytes
, uintN length
,
1307 const char *filename
, uintN lineno
,
1312 size_t len
= length
;
1314 chars
= js_InflateString(cx
, bytes
, &len
);
1317 length
= (uintN
) len
;
1318 ok
= JS_EvaluateUCInStackFrame(cx
, fp
, chars
, length
, filename
, lineno
,
1325 /************************************************************************/
1327 /* XXXbe this all needs to be reworked to avoid requiring JSScope types. */
1329 JS_PUBLIC_API(JSScopeProperty
*)
1330 JS_PropertyIterator(JSObject
*obj
, JSScopeProperty
**iteratorp
)
1332 JSScopeProperty
*sprop
;
1336 scope
= obj
->scope();
1338 /* XXXbe minor(?) incompatibility: iterate in reverse definition order */
1339 sprop
= sprop
? sprop
->parent
: scope
->lastProperty();
1344 JS_PUBLIC_API(JSBool
)
1345 JS_GetPropertyDesc(JSContext
*cx
, JSObject
*obj
, JSScopeProperty
*sprop
,
1348 pd
->id
= IdToJsval(sprop
->id
);
1350 JSBool wasThrowing
= cx
->throwing
;
1351 AutoValueRooter
lastException(cx
, cx
->exception
);
1352 cx
->throwing
= JS_FALSE
;
1354 if (!js_GetProperty(cx
, obj
, sprop
->id
, Valueify(&pd
->value
))) {
1355 if (!cx
->throwing
) {
1356 pd
->flags
= JSPD_ERROR
;
1357 pd
->value
= JSVAL_VOID
;
1359 pd
->flags
= JSPD_EXCEPTION
;
1360 pd
->value
= Jsvalify(cx
->exception
);
1366 cx
->throwing
= wasThrowing
;
1368 cx
->exception
= lastException
.value();
1370 pd
->flags
|= (sprop
->enumerable() ? JSPD_ENUMERATE
: 0)
1371 | (!sprop
->writable() ? JSPD_READONLY
: 0)
1372 | (!sprop
->configurable() ? JSPD_PERMANENT
: 0);
1374 if (sprop
->getter() == js_GetCallArg
) {
1375 pd
->slot
= sprop
->shortid
;
1376 pd
->flags
|= JSPD_ARGUMENT
;
1377 } else if (sprop
->getter() == js_GetCallVar
) {
1378 pd
->slot
= sprop
->shortid
;
1379 pd
->flags
|= JSPD_VARIABLE
;
1383 pd
->alias
= JSVAL_VOID
;
1385 JSScope
*scope
= obj
->scope();
1386 if (SPROP_HAS_VALID_SLOT(sprop
, scope
)) {
1387 JSScopeProperty
*aprop
;
1388 for (aprop
= scope
->lastProperty(); aprop
; aprop
= aprop
->parent
) {
1389 if (aprop
!= sprop
&& aprop
->slot
== sprop
->slot
) {
1390 pd
->alias
= IdToJsval(aprop
->id
);
1398 JS_PUBLIC_API(JSBool
)
1399 JS_GetPropertyDescArray(JSContext
*cx
, JSObject
*obj
, JSPropertyDescArray
*pda
)
1404 JSScopeProperty
*sprop
;
1406 Class
*clasp
= obj
->getClass();
1407 if (!obj
->isNative() || (clasp
->flags
& JSCLASS_NEW_ENUMERATE
)) {
1408 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
1409 JSMSG_CANT_DESCRIBE_PROPS
, clasp
->name
);
1412 if (!clasp
->enumerate(cx
, obj
))
1415 /* have no props, or object's scope has not mutated from that of proto */
1416 scope
= obj
->scope();
1417 if (scope
->entryCount
== 0) {
1423 n
= scope
->entryCount
;
1424 pd
= (JSPropertyDesc
*) cx
->malloc((size_t)n
* sizeof(JSPropertyDesc
));
1428 for (sprop
= scope
->lastProperty(); sprop
; sprop
= sprop
->parent
) {
1429 if (!js_AddRoot(cx
, Valueify(&pd
[i
].id
), NULL
))
1431 if (!js_AddRoot(cx
, Valueify(&pd
[i
].value
), NULL
))
1433 if (!JS_GetPropertyDesc(cx
, obj
, sprop
, &pd
[i
]))
1435 if ((pd
[i
].flags
& JSPD_ALIAS
) && !js_AddRoot(cx
, Valueify(&pd
[i
].alias
), NULL
))
1445 pda
->length
= i
+ 1;
1447 JS_PutPropertyDescArray(cx
, pda
);
1452 JS_PutPropertyDescArray(JSContext
*cx
, JSPropertyDescArray
*pda
)
1458 for (i
= 0; i
< pda
->length
; i
++) {
1459 js_RemoveRoot(cx
->runtime
, &pd
[i
].id
);
1460 js_RemoveRoot(cx
->runtime
, &pd
[i
].value
);
1461 if (pd
[i
].flags
& JSPD_ALIAS
)
1462 js_RemoveRoot(cx
->runtime
, &pd
[i
].alias
);
1467 /************************************************************************/
1469 JS_FRIEND_API(JSBool
)
1470 js_GetPropertyByIdWithFakeFrame(JSContext
*cx
, JSObject
*obj
, JSObject
*scopeobj
, jsid id
,
1473 JS_ASSERT(scopeobj
->isGlobal());
1477 if (!cx
->stack().pushDummyFrame(cx
, frame
, regs
, scopeobj
))
1480 bool ok
= JS_GetPropertyById(cx
, obj
, id
, vp
);
1481 frame
.getFrame()->putActivationObjects(cx
);
1485 JS_FRIEND_API(JSBool
)
1486 js_SetPropertyByIdWithFakeFrame(JSContext
*cx
, JSObject
*obj
, JSObject
*scopeobj
, jsid id
,
1489 JS_ASSERT(scopeobj
->isGlobal());
1493 if (!cx
->stack().pushDummyFrame(cx
, frame
, regs
, scopeobj
))
1496 bool ok
= JS_SetPropertyById(cx
, obj
, id
, vp
);
1497 frame
.getFrame()->putActivationObjects(cx
);
1501 JS_FRIEND_API(JSBool
)
1502 js_CallFunctionValueWithFakeFrame(JSContext
*cx
, JSObject
*obj
, JSObject
*scopeobj
, jsval funval
,
1503 uintN argc
, jsval
*argv
, jsval
*rval
)
1505 JS_ASSERT(scopeobj
->isGlobal());
1509 if (!cx
->stack().pushDummyFrame(cx
, frame
, regs
, scopeobj
))
1512 bool ok
= JS_CallFunctionValue(cx
, obj
, funval
, argc
, argv
, rval
);
1513 frame
.getFrame()->putActivationObjects(cx
);
1517 /************************************************************************/
1519 JS_PUBLIC_API(JSBool
)
1520 JS_SetDebuggerHandler(JSRuntime
*rt
, JSDebuggerHandler handler
, void *closure
)
1522 rt
->globalDebugHooks
.debuggerHandler
= handler
;
1523 rt
->globalDebugHooks
.debuggerHandlerData
= closure
;
1527 JS_PUBLIC_API(JSBool
)
1528 JS_SetSourceHandler(JSRuntime
*rt
, JSSourceHandler handler
, void *closure
)
1530 rt
->globalDebugHooks
.sourceHandler
= handler
;
1531 rt
->globalDebugHooks
.sourceHandlerData
= closure
;
1535 JS_PUBLIC_API(JSBool
)
1536 JS_SetExecuteHook(JSRuntime
*rt
, JSInterpreterHook hook
, void *closure
)
1538 rt
->globalDebugHooks
.executeHook
= hook
;
1539 rt
->globalDebugHooks
.executeHookData
= closure
;
1543 JS_PUBLIC_API(JSBool
)
1544 JS_SetCallHook(JSRuntime
*rt
, JSInterpreterHook hook
, void *closure
)
1548 AutoLockGC
lock(rt
);
1549 bool wasInhibited
= rt
->debuggerInhibitsJIT();
1551 rt
->globalDebugHooks
.callHook
= hook
;
1552 rt
->globalDebugHooks
.callHookData
= closure
;
1554 JITInhibitingHookChange(rt
, wasInhibited
);
1562 JS_PUBLIC_API(JSBool
)
1563 JS_SetThrowHook(JSRuntime
*rt
, JSThrowHook hook
, void *closure
)
1565 rt
->globalDebugHooks
.throwHook
= hook
;
1566 rt
->globalDebugHooks
.throwHookData
= closure
;
1570 JS_PUBLIC_API(JSBool
)
1571 JS_SetDebugErrorHook(JSRuntime
*rt
, JSDebugErrorHook hook
, void *closure
)
1573 rt
->globalDebugHooks
.debugErrorHook
= hook
;
1574 rt
->globalDebugHooks
.debugErrorHookData
= closure
;
1578 /************************************************************************/
1580 JS_PUBLIC_API(size_t)
1581 JS_GetObjectTotalSize(JSContext
*cx
, JSObject
*obj
)
1586 nbytes
= sizeof *obj
;
1588 nbytes
+= (obj
->dslots
[-1].toPrivateUint32() - JS_INITIAL_NSLOTS
+ 1)
1589 * sizeof obj
->dslots
[0];
1591 if (obj
->isNative()) {
1592 scope
= obj
->scope();
1593 if (!scope
->isSharedEmpty()) {
1594 nbytes
+= sizeof *scope
;
1595 nbytes
+= SCOPE_CAPACITY(scope
) * sizeof(JSScopeProperty
*);
1602 GetAtomTotalSize(JSContext
*cx
, JSAtom
*atom
)
1606 nbytes
= sizeof(JSAtom
*) + sizeof(JSDHashEntryStub
);
1607 nbytes
+= sizeof(JSString
);
1608 nbytes
+= (ATOM_TO_STRING(atom
)->flatLength() + 1) * sizeof(jschar
);
1612 JS_PUBLIC_API(size_t)
1613 JS_GetFunctionTotalSize(JSContext
*cx
, JSFunction
*fun
)
1617 nbytes
= sizeof *fun
;
1618 nbytes
+= JS_GetObjectTotalSize(cx
, FUN_OBJECT(fun
));
1619 if (FUN_INTERPRETED(fun
))
1620 nbytes
+= JS_GetScriptTotalSize(cx
, fun
->u
.i
.script
);
1622 nbytes
+= GetAtomTotalSize(cx
, fun
->atom
);
1628 JS_PUBLIC_API(size_t)
1629 JS_GetScriptTotalSize(JSContext
*cx
, JSScript
*script
)
1631 size_t nbytes
, pbytes
;
1633 jssrcnote
*sn
, *notes
;
1634 JSObjectArray
*objarray
;
1635 JSPrincipals
*principals
;
1637 nbytes
= sizeof *script
;
1638 if (script
->u
.object
)
1639 nbytes
+= JS_GetObjectTotalSize(cx
, script
->u
.object
);
1641 nbytes
+= script
->length
* sizeof script
->code
[0];
1642 nbytes
+= script
->atomMap
.length
* sizeof script
->atomMap
.vector
[0];
1643 for (i
= 0; i
< script
->atomMap
.length
; i
++)
1644 nbytes
+= GetAtomTotalSize(cx
, script
->atomMap
.vector
[i
]);
1646 if (script
->filename
)
1647 nbytes
+= strlen(script
->filename
) + 1;
1649 notes
= script
->notes();
1650 for (sn
= notes
; !SN_IS_TERMINATOR(sn
); sn
= SN_NEXT(sn
))
1652 nbytes
+= (sn
- notes
+ 1) * sizeof *sn
;
1654 if (script
->objectsOffset
!= 0) {
1655 objarray
= script
->objects();
1656 i
= objarray
->length
;
1657 nbytes
+= sizeof *objarray
+ i
* sizeof objarray
->vector
[0];
1659 nbytes
+= JS_GetObjectTotalSize(cx
, objarray
->vector
[--i
]);
1663 if (script
->regexpsOffset
!= 0) {
1664 objarray
= script
->regexps();
1665 i
= objarray
->length
;
1666 nbytes
+= sizeof *objarray
+ i
* sizeof objarray
->vector
[0];
1668 nbytes
+= JS_GetObjectTotalSize(cx
, objarray
->vector
[--i
]);
1672 if (script
->trynotesOffset
!= 0) {
1673 nbytes
+= sizeof(JSTryNoteArray
) +
1674 script
->trynotes()->length
* sizeof(JSTryNote
);
1677 principals
= script
->principals
;
1679 JS_ASSERT(principals
->refcount
);
1680 pbytes
= sizeof *principals
;
1681 if (principals
->refcount
> 1)
1682 pbytes
= JS_HOWMANY(pbytes
, principals
->refcount
);
1689 JS_PUBLIC_API(uint32
)
1690 JS_GetTopScriptFilenameFlags(JSContext
*cx
, JSStackFrame
*fp
)
1693 fp
= js_GetTopStackFrame(cx
);
1695 if (fp
->hasScript())
1696 return JS_GetScriptFilenameFlags(fp
->getScript());
1702 JS_PUBLIC_API(uint32
)
1703 JS_GetScriptFilenameFlags(JSScript
*script
)
1706 if (!script
->filename
)
1707 return JSFILENAME_NULL
;
1708 return js_GetScriptFilenameFlags(script
->filename
);
1711 JS_PUBLIC_API(JSBool
)
1712 JS_FlagScriptFilenamePrefix(JSRuntime
*rt
, const char *prefix
, uint32 flags
)
1714 if (!js_SaveScriptFilenameRT(rt
, prefix
, flags
))
1719 JS_PUBLIC_API(JSBool
)
1720 JS_IsSystemObject(JSContext
*cx
, JSObject
*obj
)
1722 return obj
->isSystem();
1725 JS_PUBLIC_API(JSBool
)
1726 JS_MakeSystemObject(JSContext
*cx
, JSObject
*obj
)
1732 /************************************************************************/
1734 JS_PUBLIC_API(const JSDebugHooks
*)
1735 JS_GetGlobalDebugHooks(JSRuntime
*rt
)
1737 return &rt
->globalDebugHooks
;
1740 const JSDebugHooks js_NullDebugHooks
= {};
1742 JS_PUBLIC_API(JSDebugHooks
*)
1743 JS_SetContextDebugHooks(JSContext
*cx
, const JSDebugHooks
*hooks
)
1746 if (hooks
!= &cx
->runtime
->globalDebugHooks
&& hooks
!= &js_NullDebugHooks
)
1750 AutoLockGC
lock(cx
->runtime
);
1752 JSDebugHooks
*old
= const_cast<JSDebugHooks
*>(cx
->debugHooks
);
1753 cx
->debugHooks
= hooks
;
1755 cx
->updateJITEnabled();
1760 JS_PUBLIC_API(JSDebugHooks
*)
1761 JS_ClearContextDebugHooks(JSContext
*cx
)
1763 return JS_SetContextDebugHooks(cx
, &js_NullDebugHooks
);
1768 #include <CHUD/CHUD.h>
1770 JS_PUBLIC_API(JSBool
)
1771 JS_StartChudRemote()
1773 if (chudIsRemoteAccessAcquired() &&
1774 (chudStartRemotePerfMonitor("Mozilla") == chudSuccess
)) {
1781 JS_PUBLIC_API(JSBool
)
1784 if (chudIsRemoteAccessAcquired() &&
1785 (chudStopRemotePerfMonitor() == chudSuccess
)) {
1792 JS_PUBLIC_API(JSBool
)
1795 if (!chudIsInitialized() && (chudInitialize() != chudSuccess
))
1798 if (chudAcquireRemoteAccess() != chudSuccess
)
1804 JS_PUBLIC_API(JSBool
)
1805 JS_DisconnectShark()
1807 if (chudIsRemoteAccessAcquired() && (chudReleaseRemoteAccess() != chudSuccess
))
1813 JS_FRIEND_API(JSBool
)
1814 js_StartShark(JSContext
*cx
, JSObject
*obj
,
1815 uintN argc
, jsval
*argv
, jsval
*rval
)
1817 if (!JS_StartChudRemote()) {
1818 JS_ReportError(cx
, "Error starting CHUD.");
1825 JS_FRIEND_API(JSBool
)
1826 js_StopShark(JSContext
*cx
, JSObject
*obj
,
1827 uintN argc
, jsval
*argv
, jsval
*rval
)
1829 if (!JS_StopChudRemote()) {
1830 JS_ReportError(cx
, "Error stopping CHUD.");
1837 JS_FRIEND_API(JSBool
)
1838 js_ConnectShark(JSContext
*cx
, JSObject
*obj
,
1839 uintN argc
, jsval
*argv
, jsval
*rval
)
1841 if (!JS_ConnectShark()) {
1842 JS_ReportError(cx
, "Error connecting to Shark.");
1849 JS_FRIEND_API(JSBool
)
1850 js_DisconnectShark(JSContext
*cx
, JSObject
*obj
,
1851 uintN argc
, jsval
*argv
, jsval
*rval
)
1853 if (!JS_DisconnectShark()) {
1854 JS_ReportError(cx
, "Error disconnecting from Shark.");
1861 #endif /* MOZ_SHARK */
1863 #ifdef MOZ_CALLGRIND
1865 #include <valgrind/callgrind.h>
1867 JS_FRIEND_API(JSBool
)
1868 js_StartCallgrind(JSContext
*cx
, JSObject
*obj
,
1869 uintN argc
, jsval
*argv
, jsval
*rval
)
1871 CALLGRIND_START_INSTRUMENTATION
;
1872 CALLGRIND_ZERO_STATS
;
1876 JS_FRIEND_API(JSBool
)
1877 js_StopCallgrind(JSContext
*cx
, JSObject
*obj
,
1878 uintN argc
, jsval
*argv
, jsval
*rval
)
1880 CALLGRIND_STOP_INSTRUMENTATION
;
1884 JS_FRIEND_API(JSBool
)
1885 js_DumpCallgrind(JSContext
*cx
, JSObject
*obj
,
1886 uintN argc
, jsval
*argv
, jsval
*rval
)
1891 if (argc
> 0 && JSVAL_IS_STRING(argv
[0])) {
1892 str
= JSVAL_TO_STRING(argv
[0]);
1893 cstr
= js_DeflateString(cx
, str
->chars(), str
->length());
1895 CALLGRIND_DUMP_STATS_AT(cstr
);
1900 CALLGRIND_DUMP_STATS
;
1905 #endif /* MOZ_CALLGRIND */
1908 #include <VTuneApi.h>
1910 static const char *vtuneErrorMessages
[] = {
1911 "unknown, error #0",
1912 "invalid 'max samples' field",
1913 "invalid 'samples per buffer' field",
1914 "invalid 'sample interval' field",
1916 "sample file in use",
1917 "invalid 'number of events' field",
1918 "unknown, error #7",
1921 "VTStopSampling called without calling VTStartSampling",
1922 "no events selected for event-based sampling",
1923 "events selected cannot be run together",
1924 "no sampling parameters",
1925 "sample database already exists",
1926 "sampling already started",
1927 "time-based sampling not supported",
1928 "invalid 'sampling parameters size' field",
1929 "invalid 'event size' field",
1930 "sampling file already bound",
1931 "invalid event path",
1933 "invalid 'global options' field",
1937 JS_FRIEND_API(JSBool
)
1938 js_StartVtune(JSContext
*cx
, JSObject
*obj
,
1939 uintN argc
, jsval
*argv
, jsval
*rval
)
1941 VTUNE_EVENT events
[] = {
1942 { 1000000, 0, 0, 0, "CPU_CLK_UNHALTED.CORE" },
1943 { 1000000, 0, 0, 0, "INST_RETIRED.ANY" },
1946 U32 n_events
= sizeof(events
) / sizeof(VTUNE_EVENT
);
1947 char *default_filename
= "mozilla-vtune.tb5";
1951 VTUNE_SAMPLING_PARAMS params
=
1952 sizeof(VTUNE_SAMPLING_PARAMS
),
1953 sizeof(VTUNE_EVENT
),
1954 0, 0, /* Reserved fields */
1955 1, /* Initialize in "paused" state */
1956 0, /* Max samples, or 0 for "continuous" */
1957 4096, /* Samples per buffer */
1958 0.1, /* Sampling interval in ms */
1959 1, /* 1 for event-based sampling, 0 for time-based */
1966 if (argc
> 0 && JSVAL_IS_STRING(argv
[0])) {
1967 str
= JSVAL_TO_STRING(argv
[0]);
1968 params
.tb5Filename
= js_DeflateString(cx
, str
->chars(), str
->length());
1971 status
= VTStartSampling(¶ms
);
1973 if (params
.tb5Filename
!= default_filename
)
1974 cx
->free(params
.tb5Filename
);
1977 if (status
== VTAPI_MULTIPLE_RUNS
)
1979 if (status
< sizeof(vtuneErrorMessages
))
1980 JS_ReportError(cx
, "Vtune setup error: %s",
1981 vtuneErrorMessages
[status
]);
1983 JS_ReportError(cx
, "Vtune setup error: %d",
1990 JS_FRIEND_API(JSBool
)
1991 js_StopVtune(JSContext
*cx
, JSObject
*obj
,
1992 uintN argc
, jsval
*argv
, jsval
*rval
)
1994 U32 status
= VTStopSampling(1);
1996 if (status
< sizeof(vtuneErrorMessages
))
1997 JS_ReportError(cx
, "Vtune shutdown error: %s",
1998 vtuneErrorMessages
[status
]);
2000 JS_ReportError(cx
, "Vtune shutdown error: %d",
2007 JS_FRIEND_API(JSBool
)
2008 js_PauseVtune(JSContext
*cx
, JSObject
*obj
,
2009 uintN argc
, jsval
*argv
, jsval
*rval
)
2015 JS_FRIEND_API(JSBool
)
2016 js_ResumeVtune(JSContext
*cx
, JSObject
*obj
,
2017 uintN argc
, jsval
*argv
, jsval
*rval
)
2023 #endif /* MOZ_VTUNE */
2027 * Ethogram - Javascript wrapper for TraceVis state
2029 * ethology: The scientific study of animal behavior,
2030 * especially as it occurs in a natural environment.
2031 * ethogram: A pictorial catalog of the behavioral patterns of
2032 * an organism or a species.
2036 #include <windows.h>
2038 #include <sys/time.h>
2040 #include "jstracer.h"
2042 #define ETHOGRAM_BUF_SIZE 65536
2045 ethogram_construct(JSContext
*cx
, JSObject
*obj
,
2046 uintN argc
, jsval
*argv
, jsval
*rval
);
2048 ethogram_finalize(JSContext
*cx
, JSObject
*obj
);
2050 static JSClass ethogram_class
= {
2052 JSCLASS_HAS_PRIVATE
,
2053 JS_PropertyStub
, JS_PropertyStub
, JS_PropertyStub
, JS_PropertyStub
,
2054 JS_EnumerateStub
, JS_ResolveStub
, JS_ConvertStub
, ethogram_finalize
,
2055 JSCLASS_NO_OPTIONAL_MEMBERS
2058 struct EthogramEvent
{
2060 TraceVisExitReason r
;
2068 compare_strings(const void *k1
, const void *k2
)
2070 return strcmp((const char *) k1
, (const char *) k2
) == 0;
2073 class EthogramEventBuffer
{
2075 EthogramEvent mBuf
[ETHOGRAM_BUF_SIZE
];
2078 JSObject
*mFilenames
;
2081 struct EthogramScriptEntry
{
2083 JSString
*jsfilename
;
2085 EthogramScriptEntry
*next
;
2087 EthogramScriptEntry
*mScripts
;
2091 ethogram_construct(JSContext
*cx
, JSObject
*obj
,
2092 uintN argc
, jsval
*argv
, jsval
*rval
);
2094 inline void push(TraceVisState s
, TraceVisExitReason r
, char *filename
, int lineno
) {
2095 mBuf
[mWritePos
].s
= s
;
2096 mBuf
[mWritePos
].r
= r
;
2099 GetSystemTimeAsFileTime(&now
);
2100 unsigned long long raw_us
= 0.1 *
2101 (((unsigned long long) now
.dwHighDateTime
<< 32ULL) |
2102 (unsigned long long) now
.dwLowDateTime
);
2103 unsigned int sec
= raw_us
/ 1000000L;
2104 unsigned int usec
= raw_us
% 1000000L;
2105 mBuf
[mWritePos
].ts
= sec
- mStartSecond
;
2106 mBuf
[mWritePos
].tus
= usec
;
2109 gettimeofday(&tv
, NULL
);
2110 mBuf
[mWritePos
].ts
= tv
.tv_sec
- mStartSecond
;
2111 mBuf
[mWritePos
].tus
= tv
.tv_usec
;
2114 JSString
*jsfilename
= findScript(filename
);
2115 mBuf
[mWritePos
].filename
= jsfilename
;
2116 mBuf
[mWritePos
].lineno
= lineno
;
2118 mWritePos
= (mWritePos
+ 1) % ETHOGRAM_BUF_SIZE
;
2119 if (mWritePos
== mReadPos
) {
2120 mReadPos
= (mWritePos
+ 1) % ETHOGRAM_BUF_SIZE
;
2124 inline EthogramEvent
*pop() {
2125 EthogramEvent
*e
= &mBuf
[mReadPos
];
2126 mReadPos
= (mReadPos
+ 1) % ETHOGRAM_BUF_SIZE
;
2131 return (mReadPos
== mWritePos
);
2134 EthogramScriptEntry
*addScript(JSContext
*cx
, JSObject
*obj
, char *filename
, JSString
*jsfilename
) {
2135 JSHashNumber hash
= JS_HashString(filename
);
2136 JSHashEntry
**hep
= JS_HashTableRawLookup(traceVisScriptTable
, hash
, filename
);
2140 JS_HashTableRawAdd(traceVisScriptTable
, hep
, hash
, filename
, this);
2142 EthogramScriptEntry
* entry
= (EthogramScriptEntry
*) JS_malloc(cx
, sizeof(EthogramScriptEntry
));
2146 entry
->next
= mScripts
;
2148 entry
->filename
= filename
;
2149 entry
->jsfilename
= jsfilename
;
2154 void removeScripts(JSContext
*cx
) {
2155 EthogramScriptEntry
*se
= mScripts
;
2156 while (se
!= NULL
) {
2157 char *filename
= se
->filename
;
2159 JSHashNumber hash
= JS_HashString(filename
);
2160 JSHashEntry
**hep
= JS_HashTableRawLookup(traceVisScriptTable
, hash
, filename
);
2161 JSHashEntry
*he
= *hep
;
2163 /* we hardly knew he */
2164 JS_HashTableRawRemove(traceVisScriptTable
, hep
, he
);
2167 EthogramScriptEntry
*se_head
= se
;
2169 JS_free(cx
, se_head
);
2173 JSString
*findScript(char *filename
) {
2174 EthogramScriptEntry
*se
= mScripts
;
2175 while (se
!= NULL
) {
2176 if (compare_strings(se
->filename
, filename
))
2177 return (se
->jsfilename
);
2183 JSObject
*filenames() {
2188 if (mWritePos
< mReadPos
)
2189 return (mWritePos
+ ETHOGRAM_BUF_SIZE
) - mReadPos
;
2191 return mWritePos
- mReadPos
;
2195 static char jstv_empty
[] = "<null>";
2198 jstv_Filename(JSStackFrame
*fp
)
2200 while (fp
&& fp
->script
== NULL
)
2202 return (fp
&& fp
->script
&& fp
->script
->filename
)
2203 ? (char *)fp
->script
->filename
2207 jstv_Lineno(JSContext
*cx
, JSStackFrame
*fp
)
2209 while (fp
&& fp
->pc(cx
) == NULL
)
2211 return (fp
&& fp
->pc(cx
)) ? js_FramePCToLineNumber(cx
, fp
) : 0;
2214 /* Collect states here and distribute to a matching buffer, if any */
2216 js::StoreTraceVisState(JSContext
*cx
, TraceVisState s
, TraceVisExitReason r
)
2218 JSStackFrame
*fp
= cx
->fp();
2220 char *script_file
= jstv_Filename(fp
);
2221 JSHashNumber hash
= JS_HashString(script_file
);
2223 JSHashEntry
**hep
= JS_HashTableRawLookup(traceVisScriptTable
, hash
, script_file
);
2224 /* update event buffer, flag if overflowed */
2225 JSHashEntry
*he
= *hep
;
2227 EthogramEventBuffer
*p
;
2228 p
= (EthogramEventBuffer
*) he
->value
;
2230 p
->push(s
, r
, script_file
, jstv_Lineno(cx
, fp
));
2235 ethogram_construct(JSContext
*cx
, JSObject
*obj
,
2236 uintN argc
, jsval
*argv
, jsval
*rval
)
2238 EthogramEventBuffer
*p
;
2240 p
= (EthogramEventBuffer
*) JS_malloc(cx
, sizeof(EthogramEventBuffer
));
2242 p
->mReadPos
= p
->mWritePos
= 0;
2244 p
->mFilenames
= JS_NewArrayObject(cx
, 0, NULL
);
2248 GetSystemTimeAsFileTime(&now
);
2249 unsigned long long raw_us
= 0.1 *
2250 (((unsigned long long) now
.dwHighDateTime
<< 32ULL) |
2251 (unsigned long long) now
.dwLowDateTime
);
2252 unsigned int s
= raw_us
/ 1000000L;
2253 p
->mStartSecond
= s
;
2256 gettimeofday(&tv
, NULL
);
2257 p
->mStartSecond
= tv
.tv_sec
;
2259 jsval filenames
= OBJECT_TO_JSVAL(p
->filenames());
2260 if (!JS_DefineProperty(cx
, obj
, "filenames", filenames
,
2261 NULL
, NULL
, JSPROP_READONLY
|JSPROP_PERMANENT
))
2264 if (!JS_IsConstructing(cx
)) {
2265 obj
= JS_NewObject(cx
, ðogram_class
, NULL
, NULL
);
2268 *rval
= OBJECT_TO_JSVAL(obj
);
2270 JS_SetPrivate(cx
, obj
, p
);
2275 ethogram_finalize(JSContext
*cx
, JSObject
*obj
)
2277 EthogramEventBuffer
*p
;
2278 p
= (EthogramEventBuffer
*) JS_GetInstancePrivate(cx
, obj
, ðogram_class
, NULL
);
2282 p
->removeScripts(cx
);
2288 ethogram_addScript(JSContext
*cx
, JSObject
*obj
,
2289 uintN argc
, jsval
*argv
, jsval
*rval
)
2292 char *filename
= NULL
;
2293 if (argc
> 0 && JSVAL_IS_STRING(argv
[0])) {
2294 str
= JSVAL_TO_STRING(argv
[0]);
2295 filename
= js_DeflateString(cx
,
2300 /* silently ignore no args */
2304 EthogramEventBuffer
*p
= (EthogramEventBuffer
*) JS_GetInstancePrivate(cx
, obj
, ðogram_class
, argv
);
2306 p
->addScript(cx
, obj
, filename
, str
);
2307 JS_CallFunctionName(cx
, p
->filenames(), "push", 1, argv
, rval
);
2312 ethogram_getAllEvents(JSContext
*cx
, JSObject
*obj
,
2313 uintN argc
, jsval
*argv
, jsval
*rval
)
2315 EthogramEventBuffer
*p
;
2317 p
= (EthogramEventBuffer
*) JS_GetInstancePrivate(cx
, obj
, ðogram_class
, argv
);
2326 JSObject
*rarray
= JS_NewArrayObject(cx
, 0, NULL
);
2327 if (rarray
== NULL
) {
2332 *rval
= OBJECT_TO_JSVAL(rarray
);
2334 for (int i
= 0; !p
->isEmpty(); i
++) {
2336 JSObject
*x
= JS_NewObject(cx
, NULL
, NULL
, NULL
);
2340 EthogramEvent
*e
= p
->pop();
2342 jsval state
= INT_TO_JSVAL(e
->s
);
2343 jsval reason
= INT_TO_JSVAL(e
->r
);
2344 jsval ts
= INT_TO_JSVAL(e
->ts
);
2345 jsval tus
= INT_TO_JSVAL(e
->tus
);
2347 jsval filename
= STRING_TO_JSVAL(e
->filename
);
2348 jsval lineno
= INT_TO_JSVAL(e
->lineno
);
2350 if (!JS_SetProperty(cx
, x
, "state", &state
))
2352 if (!JS_SetProperty(cx
, x
, "reason", &reason
))
2354 if (!JS_SetProperty(cx
, x
, "ts", &ts
))
2356 if (!JS_SetProperty(cx
, x
, "tus", &tus
))
2359 if (!JS_SetProperty(cx
, x
, "filename", &filename
))
2361 if (!JS_SetProperty(cx
, x
, "lineno", &lineno
))
2364 jsval element
= OBJECT_TO_JSVAL(x
);
2365 JS_SetElement(cx
, rarray
, i
, &element
);
2372 ethogram_getNextEvent(JSContext
*cx
, JSObject
*obj
,
2373 uintN argc
, jsval
*argv
, jsval
*rval
)
2375 EthogramEventBuffer
*p
;
2377 p
= (EthogramEventBuffer
*) JS_GetInstancePrivate(cx
, obj
, ðogram_class
, argv
);
2381 JSObject
*x
= JS_NewObject(cx
, NULL
, NULL
, NULL
);
2390 EthogramEvent
*e
= p
->pop();
2391 jsval state
= INT_TO_JSVAL(e
->s
);
2392 jsval reason
= INT_TO_JSVAL(e
->r
);
2393 jsval ts
= INT_TO_JSVAL(e
->ts
);
2394 jsval tus
= INT_TO_JSVAL(e
->tus
);
2396 jsval filename
= STRING_TO_JSVAL(e
->filename
);
2397 jsval lineno
= INT_TO_JSVAL(e
->lineno
);
2399 if (!JS_SetProperty(cx
, x
, "state", &state
))
2401 if (!JS_SetProperty(cx
, x
, "reason", &reason
))
2403 if (!JS_SetProperty(cx
, x
, "ts", &ts
))
2405 if (!JS_SetProperty(cx
, x
, "tus", &tus
))
2407 if (!JS_SetProperty(cx
, x
, "filename", &filename
))
2410 if (!JS_SetProperty(cx
, x
, "lineno", &lineno
))
2413 *rval
= OBJECT_TO_JSVAL(x
);
2418 static JSFunctionSpec ethogram_methods
[] = {
2419 {"addScript", ethogram_addScript
, 1},
2420 {"getAllEvents", ethogram_getAllEvents
, 0},
2421 {"getNextEvent", ethogram_getNextEvent
, 0},
2426 * An |Ethogram| organizes the output of a collection of files that should be
2427 * monitored together. A single object gets events for the group.
2429 JS_FRIEND_API(JSBool
)
2430 js_InitEthogram(JSContext
*cx
, JSObject
*obj
,
2431 uintN argc
, jsval
*argv
, jsval
*rval
)
2433 if (!traceVisScriptTable
) {
2434 traceVisScriptTable
= JS_NewHashTable(8, JS_HashString
, compare_strings
,
2438 JS_InitClass(cx
, JS_GetGlobalObject(cx
), NULL
, ðogram_class
,
2439 ethogram_construct
, 0, NULL
, ethogram_methods
,
2445 JS_FRIEND_API(JSBool
)
2446 js_ShutdownEthogram(JSContext
*cx
, JSObject
*obj
,
2447 uintN argc
, jsval
*argv
, jsval
*rval
)
2449 if (traceVisScriptTable
)
2450 JS_HashTableDestroy(traceVisScriptTable
);
2455 #endif /* MOZ_TRACEVIS */