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 ***** */
51 #include "jsversion.h"
63 #include "jsstaticcheck.h"
65 #include "jswrapper.h"
67 #include "jsatominlines.h"
68 #include "jsdbgapiinlines.h"
69 #include "jsinterpinlines.h"
70 #include "jsobjinlines.h"
71 #include "jsscopeinlines.h"
72 #include "jsscriptinlines.h"
74 #include "jsautooplen.h"
76 #include "methodjit/MethodJIT.h"
77 #include "methodjit/Retcon.h"
80 using namespace js::gc
;
82 typedef struct JSTrap
{
87 JSTrapHandler handler
;
91 #define DBG_LOCK(rt) JS_ACQUIRE_LOCK((rt)->debuggerLock)
92 #define DBG_UNLOCK(rt) JS_RELEASE_LOCK((rt)->debuggerLock)
93 #define DBG_LOCK_EVAL(rt,expr) (DBG_LOCK(rt), (expr), DBG_UNLOCK(rt))
96 JS_GetDebugMode(JSContext
*cx
)
98 return cx
->compartment
->debugMode
;
103 IsScriptLive(JSContext
*cx
, JSScript
*script
)
105 for (AllFramesIter
i(cx
); !i
.done(); ++i
) {
106 if (i
.fp()->maybeScript() == script
)
114 JS_SetRuntimeDebugMode(JSRuntime
*rt
, JSBool debug
)
116 rt
->debugMode
= debug
;
121 PurgeCallICs(JSContext
*cx
, JSScript
*start
)
123 for (JSScript
*script
= start
;
124 &script
->links
!= &cx
->compartment
->scripts
;
125 script
= (JSScript
*)script
->links
.next
)
127 // Debug mode does not use call ICs.
128 if (script
->debugMode
)
131 JS_ASSERT(!IsScriptLive(cx
, script
));
133 if (script
->jitNormal
)
134 script
->jitNormal
->nukeScriptDependentICs();
136 script
->jitCtor
->nukeScriptDependentICs();
141 JS_FRIEND_API(JSBool
)
142 js_SetDebugMode(JSContext
*cx
, JSBool debug
)
144 if (!cx
->compartment
)
147 cx
->compartment
->debugMode
= debug
;
149 for (JSScript
*script
= (JSScript
*)cx
->compartment
->scripts
.next
;
150 &script
->links
!= &cx
->compartment
->scripts
;
151 script
= (JSScript
*)script
->links
.next
) {
152 if (script
->debugMode
!= !!debug
&&
153 script
->hasJITCode() &&
154 !IsScriptLive(cx
, script
)) {
156 * In the event that this fails, debug mode is left partially on,
157 * leading to a small performance overhead but no loss of
158 * correctness. We set the debug flag to false so that the caller
159 * will not later attempt to use debugging features.
161 js::mjit::Recompiler
recompiler(cx
, script
);
162 if (!recompiler
.recompile()) {
164 * If recompilation failed, we could be in a state where
165 * remaining compiled scripts hold call IC references that
166 * have been destroyed by recompilation. Clear those ICs now.
168 PurgeCallICs(cx
, script
);
169 cx
->compartment
->debugMode
= JS_FALSE
;
178 JS_PUBLIC_API(JSBool
)
179 JS_SetDebugMode(JSContext
*cx
, JSBool debug
)
182 for (AllFramesIter
i(cx
); !i
.done(); ++i
)
183 JS_ASSERT(!JS_IsScriptFrame(cx
, i
.fp()));
186 return js_SetDebugMode(cx
, debug
);
189 JS_FRIEND_API(JSBool
)
190 js_SetSingleStepMode(JSContext
*cx
, JSScript
*script
, JSBool singleStep
)
193 if (!script
->singleStepMode
== !singleStep
)
197 JS_ASSERT_IF(singleStep
, cx
->compartment
->debugMode
);
200 /* request the next recompile to inject single step interrupts */
201 script
->singleStepMode
= !!singleStep
;
203 js::mjit::JITScript
*jit
= script
->jitNormal
? script
->jitNormal
: script
->jitCtor
;
204 if (jit
&& script
->singleStepMode
!= jit
->singleStepMode
) {
205 js::mjit::Recompiler
recompiler(cx
, script
);
206 if (!recompiler
.recompile()) {
207 script
->singleStepMode
= !singleStep
;
216 CheckDebugMode(JSContext
*cx
)
218 JSBool debugMode
= JS_GetDebugMode(cx
);
221 * This probably should be an assertion, since it's indicative of a severe
225 JS_ReportErrorFlagsAndNumber(cx
, JSREPORT_ERROR
, js_GetErrorMessage
,
226 NULL
, JSMSG_NEED_DEBUG_MODE
);
231 JS_PUBLIC_API(JSBool
)
232 JS_SetSingleStepMode(JSContext
*cx
, JSScript
*script
, JSBool singleStep
)
234 if (!CheckDebugMode(cx
))
237 return js_SetSingleStepMode(cx
, script
, singleStep
);
241 * NB: FindTrap must be called with rt->debuggerLock acquired.
244 FindTrap(JSRuntime
*rt
, JSScript
*script
, jsbytecode
*pc
)
248 for (trap
= (JSTrap
*)rt
->trapList
.next
;
249 &trap
->links
!= &rt
->trapList
;
250 trap
= (JSTrap
*)trap
->links
.next
) {
251 if (trap
->script
== script
&& trap
->pc
== pc
)
258 js_UntrapScriptCode(JSContext
*cx
, JSScript
*script
)
267 for (trap
= (JSTrap
*)rt
->trapList
.next
;
270 trap
= (JSTrap
*)trap
->links
.next
) {
271 if (trap
->script
== script
&&
272 (size_t)(trap
->pc
- script
->code
) < script
->length
) {
273 if (code
== script
->code
) {
274 jssrcnote
*sn
, *notes
;
277 nbytes
= script
->length
* sizeof(jsbytecode
);
278 notes
= script
->notes();
279 for (sn
= notes
; !SN_IS_TERMINATOR(sn
); sn
= SN_NEXT(sn
))
281 nbytes
+= (sn
- notes
+ 1) * sizeof *sn
;
283 code
= (jsbytecode
*) cx
->malloc(nbytes
);
286 memcpy(code
, script
->code
, nbytes
);
287 JS_PURGE_GSN_CACHE(cx
);
289 code
[trap
->pc
- script
->code
] = trap
->op
;
296 JS_PUBLIC_API(JSBool
)
297 JS_SetTrap(JSContext
*cx
, JSScript
*script
, jsbytecode
*pc
,
298 JSTrapHandler handler
, jsval closure
)
300 JSTrap
*junk
, *trap
, *twin
;
304 if (!CheckDebugMode(cx
))
307 JS_ASSERT((JSOp
) *pc
!= JSOP_TRAP
);
311 trap
= FindTrap(rt
, script
, pc
);
313 JS_ASSERT(trap
->script
== script
&& trap
->pc
== pc
);
314 JS_ASSERT(*pc
== JSOP_TRAP
);
316 sample
= rt
->debuggerMutations
;
318 trap
= (JSTrap
*) cx
->malloc(sizeof *trap
);
321 trap
->closure
= JSVAL_NULL
;
323 twin
= (rt
->debuggerMutations
!= sample
)
324 ? FindTrap(rt
, script
, pc
)
330 JS_APPEND_LINK(&trap
->links
, &rt
->trapList
);
331 ++rt
->debuggerMutations
;
332 trap
->script
= script
;
334 trap
->op
= (JSOp
)*pc
;
338 trap
->handler
= handler
;
339 trap
->closure
= closure
;
345 if (script
->hasJITCode()) {
346 js::mjit::Recompiler
recompiler(cx
, script
);
347 if (!recompiler
.recompile())
356 JS_GetTrapOpcode(JSContext
*cx
, JSScript
*script
, jsbytecode
*pc
)
364 trap
= FindTrap(rt
, script
, pc
);
365 op
= trap
? trap
->op
: (JSOp
) *pc
;
371 DestroyTrapAndUnlock(JSContext
*cx
, JSTrap
*trap
)
373 ++cx
->runtime
->debuggerMutations
;
374 JS_REMOVE_LINK(&trap
->links
);
375 *trap
->pc
= (jsbytecode
)trap
->op
;
376 DBG_UNLOCK(cx
->runtime
);
381 JS_ClearTrap(JSContext
*cx
, JSScript
*script
, jsbytecode
*pc
,
382 JSTrapHandler
*handlerp
, jsval
*closurep
)
386 DBG_LOCK(cx
->runtime
);
387 trap
= FindTrap(cx
->runtime
, script
, pc
);
389 *handlerp
= trap
? trap
->handler
: NULL
;
391 *closurep
= trap
? trap
->closure
: JSVAL_NULL
;
393 DestroyTrapAndUnlock(cx
, trap
);
395 DBG_UNLOCK(cx
->runtime
);
398 if (script
->hasJITCode()) {
399 mjit::Recompiler
recompiler(cx
, script
);
400 recompiler
.recompile();
406 JS_ClearScriptTraps(JSContext
*cx
, JSScript
*script
)
414 for (trap
= (JSTrap
*)rt
->trapList
.next
;
415 &trap
->links
!= &rt
->trapList
;
417 next
= (JSTrap
*)trap
->links
.next
;
418 if (trap
->script
== script
) {
419 sample
= rt
->debuggerMutations
;
420 DestroyTrapAndUnlock(cx
, trap
);
422 if (rt
->debuggerMutations
!= sample
+ 1)
423 next
= (JSTrap
*)rt
->trapList
.next
;
430 JS_ClearAllTraps(JSContext
*cx
)
438 for (trap
= (JSTrap
*)rt
->trapList
.next
;
439 &trap
->links
!= &rt
->trapList
;
441 next
= (JSTrap
*)trap
->links
.next
;
442 sample
= rt
->debuggerMutations
;
443 DestroyTrapAndUnlock(cx
, trap
);
445 if (rt
->debuggerMutations
!= sample
+ 1)
446 next
= (JSTrap
*)rt
->trapList
.next
;
452 * NB: js_MarkTraps does not acquire cx->runtime->debuggerLock, since the
453 * debugger should never be racing with the GC (i.e., the debugger must
454 * respect the request model).
457 js_MarkTraps(JSTracer
*trc
)
459 JSRuntime
*rt
= trc
->context
->runtime
;
461 for (JSTrap
*trap
= (JSTrap
*) rt
->trapList
.next
;
462 &trap
->links
!= &rt
->trapList
;
463 trap
= (JSTrap
*) trap
->links
.next
) {
464 MarkValue(trc
, Valueify(trap
->closure
), "trap->closure");
468 JS_PUBLIC_API(JSTrapStatus
)
469 JS_HandleTrap(JSContext
*cx
, JSScript
*script
, jsbytecode
*pc
, jsval
*rval
)
475 DBG_LOCK(cx
->runtime
);
476 trap
= FindTrap(cx
->runtime
, script
, pc
);
477 JS_ASSERT(!trap
|| trap
->handler
);
480 DBG_UNLOCK(cx
->runtime
);
482 /* Defend against "pc for wrong script" API usage error. */
483 JS_ASSERT(op
!= JSOP_TRAP
);
486 /* If the API was abused, we must fail for want of the real op. */
490 /* Assume a race with a debugger thread and try to carry on. */
491 *rval
= INT_TO_JSVAL(op
);
492 return JSTRAP_CONTINUE
;
494 /* Always fail if single-threaded (must be an API usage error). */
498 DBG_UNLOCK(cx
->runtime
);
501 * It's important that we not use 'trap->' after calling the callback --
502 * the callback might remove the trap!
504 op
= (jsint
)trap
->op
;
505 status
= trap
->handler(cx
, script
, pc
, rval
, trap
->closure
);
506 if (status
== JSTRAP_CONTINUE
) {
507 /* By convention, return the true op to the interpreter in rval. */
508 *rval
= INT_TO_JSVAL(op
);
515 JITInhibitingHookChange(JSRuntime
*rt
, bool wasInhibited
)
518 if (!rt
->debuggerInhibitsJIT()) {
519 for (JSCList
*cl
= rt
->contextList
.next
; cl
!= &rt
->contextList
; cl
= cl
->next
)
520 js_ContextFromLinkField(cl
)->updateJITEnabled();
522 } else if (rt
->debuggerInhibitsJIT()) {
523 for (JSCList
*cl
= rt
->contextList
.next
; cl
!= &rt
->contextList
; cl
= cl
->next
)
524 js_ContextFromLinkField(cl
)->traceJitEnabled
= false;
529 JS_PUBLIC_API(JSBool
)
530 JS_SetInterrupt(JSRuntime
*rt
, JSInterruptHook hook
, void *closure
)
535 bool wasInhibited
= rt
->debuggerInhibitsJIT();
537 rt
->globalDebugHooks
.interruptHook
= hook
;
538 rt
->globalDebugHooks
.interruptHookData
= closure
;
540 JITInhibitingHookChange(rt
, wasInhibited
);
546 JS_PUBLIC_API(JSBool
)
547 JS_ClearInterrupt(JSRuntime
*rt
, JSInterruptHook
*hoop
, void **closurep
)
551 bool wasInhibited
= rt
->debuggerInhibitsJIT();
554 *hoop
= rt
->globalDebugHooks
.interruptHook
;
556 *closurep
= rt
->globalDebugHooks
.interruptHookData
;
557 rt
->globalDebugHooks
.interruptHook
= 0;
558 rt
->globalDebugHooks
.interruptHookData
= 0;
560 JITInhibitingHookChange(rt
, wasInhibited
);
565 /************************************************************************/
567 struct JSWatchPoint
{
569 JSObject
*object
; /* weak link, see js_FinalizeObject */
572 JSWatchPointHandler handler
;
577 #define JSWP_LIVE 0x1 /* live because set and not cleared */
578 #define JSWP_HELD 0x2 /* held while running handler/setter */
581 IsWatchedProperty(JSContext
*cx
, const Shape
*shape
);
584 * NB: DropWatchPointAndUnlock releases cx->runtime->debuggerLock in all cases.
587 DropWatchPointAndUnlock(JSContext
*cx
, JSWatchPoint
*wp
, uintN flag
)
590 JSRuntime
*rt
= cx
->runtime
;
593 if (wp
->flags
!= 0) {
598 /* Remove wp from the list, then restore wp->shape->setter from wp. */
599 ++rt
->debuggerMutations
;
600 JS_REMOVE_LINK(&wp
->links
);
604 * If the property isn't found on wp->object, then someone else must have deleted it,
605 * and we don't need to change the property attributes.
607 const Shape
*shape
= wp
->shape
;
608 const Shape
*wprop
= wp
->object
->nativeLookup(shape
->id
);
610 wprop
->hasSetterValue() == shape
->hasSetterValue() &&
611 IsWatchedProperty(cx
, wprop
)) {
612 shape
= wp
->object
->changeProperty(cx
, wprop
, 0, wprop
->attributes(),
613 wprop
->getter(), wp
->setter
);
623 * NB: js_TraceWatchPoints does not acquire cx->runtime->debuggerLock, since
624 * the debugger should never be racing with the GC (i.e., the debugger must
625 * respect the request model).
628 js_TraceWatchPoints(JSTracer
*trc
, JSObject
*obj
)
633 rt
= trc
->context
->runtime
;
635 for (wp
= (JSWatchPoint
*)rt
->watchPointList
.next
;
636 &wp
->links
!= &rt
->watchPointList
;
637 wp
= (JSWatchPoint
*)wp
->links
.next
) {
638 if (wp
->object
== obj
) {
639 wp
->shape
->trace(trc
);
640 if (wp
->shape
->hasSetterValue() && wp
->setter
)
641 MarkObject(trc
, *CastAsObject(wp
->setter
), "wp->setter");
642 MarkObject(trc
, *wp
->closure
, "wp->closure");
648 js_SweepWatchPoints(JSContext
*cx
)
651 JSWatchPoint
*wp
, *next
;
656 for (wp
= (JSWatchPoint
*)rt
->watchPointList
.next
;
657 &wp
->links
!= &rt
->watchPointList
;
659 next
= (JSWatchPoint
*)wp
->links
.next
;
660 if (IsAboutToBeFinalized(cx
, wp
->object
)) {
661 sample
= rt
->debuggerMutations
;
663 /* Ignore failures. */
664 DropWatchPointAndUnlock(cx
, wp
, JSWP_LIVE
);
666 if (rt
->debuggerMutations
!= sample
+ 1)
667 next
= (JSWatchPoint
*)rt
->watchPointList
.next
;
676 * NB: LockedFindWatchPoint must be called with rt->debuggerLock acquired.
678 static JSWatchPoint
*
679 LockedFindWatchPoint(JSRuntime
*rt
, JSObject
*obj
, jsid id
)
683 for (wp
= (JSWatchPoint
*)rt
->watchPointList
.next
;
684 &wp
->links
!= &rt
->watchPointList
;
685 wp
= (JSWatchPoint
*)wp
->links
.next
) {
686 if (wp
->object
== obj
&& wp
->shape
->id
== id
)
692 static JSWatchPoint
*
693 FindWatchPoint(JSRuntime
*rt
, JSObject
*obj
, jsid id
)
698 wp
= LockedFindWatchPoint(rt
, obj
, id
);
704 js_watch_set(JSContext
*cx
, JSObject
*obj
, jsid id
, Value
*vp
)
706 JSRuntime
*rt
= cx
->runtime
;
708 for (JSWatchPoint
*wp
= (JSWatchPoint
*)rt
->watchPointList
.next
;
709 &wp
->links
!= &rt
->watchPointList
;
710 wp
= (JSWatchPoint
*)wp
->links
.next
) {
711 const Shape
*shape
= wp
->shape
;
712 if (wp
->object
== obj
&& SHAPE_USERID(shape
) == id
&&
713 !(wp
->flags
& JSWP_HELD
)) {
714 wp
->flags
|= JSWP_HELD
;
717 jsid propid
= shape
->id
;
718 jsid userid
= SHAPE_USERID(shape
);
720 /* NB: wp is held, so we can safely dereference it still. */
721 if (!wp
->handler(cx
, obj
, propid
,
722 obj
->containsSlot(shape
->slot
)
723 ? Jsvalify(obj
->nativeGetSlot(shape
->slot
))
725 Jsvalify(vp
), wp
->closure
)) {
727 DropWatchPointAndUnlock(cx
, wp
, JSWP_HELD
);
731 /* Handler could have redefined the shape; see bug 624050. */
735 * Pass the output of the handler to the setter. Security wrappers
736 * prevent any funny business between watchpoints and setters.
738 JSBool ok
= !wp
->setter
||
739 (shape
->hasSetterValue()
740 ? ExternalInvoke(cx
, obj
,
741 ObjectValue(*CastAsObject(wp
->setter
)),
743 : CallJSPropertyOpSetter(cx
, wp
->setter
, obj
, userid
, vp
));
746 return DropWatchPointAndUnlock(cx
, wp
, JSWP_HELD
) && ok
;
754 js_watch_set_wrapper(JSContext
*cx
, uintN argc
, Value
*vp
)
756 JSObject
*obj
= ComputeThisFromVp(cx
, vp
);
760 JSObject
&funobj
= JS_CALLEE(cx
, vp
).toObject();
761 JSFunction
*wrapper
= funobj
.getFunctionPrivate();
762 jsid userid
= ATOM_TO_JSID(wrapper
->atom
);
764 JS_SET_RVAL(cx
, vp
, argc
? JS_ARGV(cx
, vp
)[0] : UndefinedValue());
765 return js_watch_set(cx
, obj
, userid
, vp
);
769 IsWatchedProperty(JSContext
*cx
, const Shape
*shape
)
771 if (shape
->hasSetterValue()) {
772 JSObject
*funobj
= shape
->setterObject();
773 if (!funobj
|| !funobj
->isFunction())
776 JSFunction
*fun
= GET_FUNCTION_PRIVATE(cx
, funobj
);
777 return fun
->maybeNative() == js_watch_set_wrapper
;
779 return shape
->setterOp() == js_watch_set
;
783 * Return an appropriate setter to substitute for |setter| on a property
784 * with attributes |attrs|, to implement a watchpoint on the property named
788 WrapWatchedSetter(JSContext
*cx
, jsid id
, uintN attrs
, PropertyOp setter
)
793 /* Wrap a JSPropertyOp setter simply by returning our own JSPropertyOp. */
794 if (!(attrs
& JSPROP_SETTER
))
795 return &js_watch_set
; /* & to silence schoolmarmish MSVC */
798 * Wrap a JSObject * setter by constructing our own JSFunction * that saves the
799 * property id as the function name, and calls js_watch_set.
801 if (JSID_IS_ATOM(id
)) {
802 atom
= JSID_TO_ATOM(id
);
803 } else if (JSID_IS_INT(id
)) {
804 if (!js_ValueToStringId(cx
, IdToValue(id
), &id
))
806 atom
= JSID_TO_ATOM(id
);
811 wrapper
= js_NewFunction(cx
, NULL
, js_watch_set_wrapper
, 1, 0,
812 setter
? CastAsObject(setter
)->getParent() : NULL
, atom
);
815 return CastAsPropertyOp(FUN_OBJECT(wrapper
));
819 UpdateWatchpointShape(JSContext
*cx
, JSWatchPoint
*wp
, const js::Shape
*newShape
)
821 JS_ASSERT_IF(wp
->shape
, wp
->shape
->id
== newShape
->id
);
822 JS_ASSERT(!IsWatchedProperty(cx
, newShape
));
824 /* Create a watching setter we can substitute for the new shape's setter. */
825 js::PropertyOp watchingSetter
= WrapWatchedSetter(cx
, newShape
->id
, newShape
->attributes(),
831 * Save the shape's setter; we don't know whether js_ChangeNativePropertyAttrs will
832 * return a new shape, or mutate this one.
834 js::PropertyOp originalSetter
= newShape
->setter();
837 * Drop the watching setter into the object, in place of newShape. Note that a single
838 * watchpoint-wrapped shape may correspond to more than one non-watchpoint shape: we
839 * wrap all (JSPropertyOp, not JSObject *) setters with js_watch_set, so shapes that
840 * differ only in their setter may all get wrapped to the same shape.
842 const js::Shape
*watchingShape
=
843 js_ChangeNativePropertyAttrs(cx
, wp
->object
, newShape
, 0, newShape
->attributes(),
844 newShape
->getter(), watchingSetter
);
848 /* Update the watchpoint with the new shape and its original setter. */
849 wp
->setter
= originalSetter
;
850 wp
->shape
= watchingShape
;
856 js_SlowPathUpdateWatchpointsForShape(JSContext
*cx
, JSObject
*obj
, const js::Shape
*newShape
)
859 * The watchpoint code uses the normal property-modification functions to install its
860 * own watchpoint-aware shapes. Those functions report those changes back to the
861 * watchpoint code, just as they do user-level changes. So if this change is
862 * installing a watchpoint-aware shape, it's something we asked for ourselves, and can
863 * proceed without interference.
865 if (IsWatchedProperty(cx
, newShape
))
868 JSWatchPoint
*wp
= FindWatchPoint(cx
->runtime
, obj
, newShape
->id
);
872 return UpdateWatchpointShape(cx
, wp
, newShape
);
876 * Return the underlying setter for |shape| on |obj|, seeing through any
877 * watchpoint-wrapping. Note that we need |obj| to disambiguate, since a single
878 * watchpoint-wrapped shape may correspond to more than one non-watchpoint shape; see the
879 * comments in UpdateWatchpointShape.
882 UnwrapSetter(JSContext
*cx
, JSObject
*obj
, const Shape
*shape
)
884 /* If it's not a watched property, its setter is not wrapped. */
885 if (!IsWatchedProperty(cx
, shape
))
886 return shape
->setter();
888 /* Look up the watchpoint, from which we can retrieve the underlying setter. */
889 JSWatchPoint
*wp
= FindWatchPoint(cx
->runtime
, obj
, shape
->id
);
892 * Since we know |shape| is watched, we *must* find a watchpoint: we should never
893 * leave wrapped setters lying around in shapes after removing a watchpoint.
900 JS_PUBLIC_API(JSBool
)
901 JS_SetWatchPoint(JSContext
*cx
, JSObject
*obj
, jsid id
,
902 JSWatchPointHandler handler
, JSObject
*closure
)
910 OBJ_TO_INNER_OBJECT(cx
, obj
);
914 AutoValueRooter
idroot(cx
);
915 if (JSID_IS_INT(id
)) {
918 if (!js_ValueToStringId(cx
, IdToValue(id
), &propid
))
920 propid
= js_CheckForStringIndex(propid
);
921 idroot
.set(IdToValue(propid
));
925 * If, by unwrapping and innerizing, we changed the object, check
926 * again to make sure that we're allowed to set a watch point.
928 if (origobj
!= obj
&& !CheckAccess(cx
, obj
, propid
, JSACC_WATCH
, &v
, &attrs
))
931 if (!obj
->isNative()) {
932 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
, JSMSG_CANT_WATCH
,
933 obj
->getClass()->name
);
939 if (!js_LookupProperty(cx
, obj
, propid
, &pobj
, &prop
))
941 const Shape
*shape
= (Shape
*) prop
;
942 JSRuntime
*rt
= cx
->runtime
;
944 /* Check for a deleted symbol watchpoint, which holds its property. */
945 JSWatchPoint
*wp
= FindWatchPoint(rt
, obj
, propid
);
947 /* Make a new property in obj so we can watch for the first set. */
948 if (!js_DefineNativeProperty(cx
, obj
, propid
, UndefinedValue(), NULL
, NULL
,
949 JSPROP_ENUMERATE
, 0, 0, &prop
)) {
952 shape
= (Shape
*) prop
;
954 } else if (pobj
!= obj
) {
955 /* Clone the prototype property so we can watch the right object. */
956 AutoValueRooter
valroot(cx
);
957 PropertyOp getter
, setter
;
961 if (pobj
->isNative()) {
962 valroot
.set(pobj
->containsSlot(shape
->slot
)
963 ? pobj
->nativeGetSlot(shape
->slot
)
965 getter
= shape
->getter();
966 setter
= UnwrapSetter(cx
, pobj
, shape
);
967 attrs
= shape
->attributes();
968 flags
= shape
->getFlags();
969 shortid
= shape
->shortid
;
971 if (!pobj
->getProperty(cx
, propid
, valroot
.addr()) ||
972 !pobj
->getAttributes(cx
, propid
, &attrs
)) {
975 getter
= setter
= NULL
;
980 /* Recall that obj is native, whether or not pobj is native. */
981 if (!js_DefineNativeProperty(cx
, obj
, propid
, valroot
.value(),
982 getter
, setter
, attrs
, flags
,
986 shape
= (Shape
*) prop
;
990 * At this point, prop/shape exists in obj, obj is locked, and we must
991 * unlock the object before returning.
994 JSWatchPoint
*wp
= LockedFindWatchPoint(rt
, obj
, propid
);
997 wp
= (JSWatchPoint
*) cx
->malloc(sizeof *wp
);
1004 wp
->flags
= JSWP_LIVE
;
1006 /* XXXbe nest in obj lock here */
1007 if (!UpdateWatchpointShape(cx
, wp
, shape
)) {
1008 /* Self-link so DropWatchPointAndUnlock can JS_REMOVE_LINK it. */
1009 JS_INIT_CLIST(&wp
->links
);
1011 DropWatchPointAndUnlock(cx
, wp
, JSWP_LIVE
);
1016 * Now that wp is fully initialized, append it to rt's wp list.
1017 * Because obj is locked we know that no other thread could have added
1018 * a watchpoint for (obj, propid).
1021 JS_ASSERT(!LockedFindWatchPoint(rt
, obj
, propid
));
1022 JS_APPEND_LINK(&wp
->links
, &rt
->watchPointList
);
1023 ++rt
->debuggerMutations
;
1025 wp
->handler
= handler
;
1026 wp
->closure
= reinterpret_cast<JSObject
*>(closure
);
1031 JS_PUBLIC_API(JSBool
)
1032 JS_ClearWatchPoint(JSContext
*cx
, JSObject
*obj
, jsid id
,
1033 JSWatchPointHandler
*handlerp
, JSObject
**closurep
)
1040 for (wp
= (JSWatchPoint
*)rt
->watchPointList
.next
;
1041 &wp
->links
!= &rt
->watchPointList
;
1042 wp
= (JSWatchPoint
*)wp
->links
.next
) {
1043 if (wp
->object
== obj
&& SHAPE_USERID(wp
->shape
) == id
) {
1045 *handlerp
= wp
->handler
;
1047 *closurep
= wp
->closure
;
1048 return DropWatchPointAndUnlock(cx
, wp
, JSWP_LIVE
);
1059 JS_PUBLIC_API(JSBool
)
1060 JS_ClearWatchPointsForObject(JSContext
*cx
, JSObject
*obj
)
1063 JSWatchPoint
*wp
, *next
;
1068 for (wp
= (JSWatchPoint
*)rt
->watchPointList
.next
;
1069 &wp
->links
!= &rt
->watchPointList
;
1071 next
= (JSWatchPoint
*)wp
->links
.next
;
1072 if (wp
->object
== obj
) {
1073 sample
= rt
->debuggerMutations
;
1074 if (!DropWatchPointAndUnlock(cx
, wp
, JSWP_LIVE
))
1077 if (rt
->debuggerMutations
!= sample
+ 1)
1078 next
= (JSWatchPoint
*)rt
->watchPointList
.next
;
1085 JS_PUBLIC_API(JSBool
)
1086 JS_ClearAllWatchPoints(JSContext
*cx
)
1089 JSWatchPoint
*wp
, *next
;
1094 for (wp
= (JSWatchPoint
*)rt
->watchPointList
.next
;
1095 &wp
->links
!= &rt
->watchPointList
;
1097 next
= (JSWatchPoint
*)wp
->links
.next
;
1098 sample
= rt
->debuggerMutations
;
1099 if (!DropWatchPointAndUnlock(cx
, wp
, JSWP_LIVE
))
1102 if (rt
->debuggerMutations
!= sample
+ 1)
1103 next
= (JSWatchPoint
*)rt
->watchPointList
.next
;
1109 /************************************************************************/
1111 JS_PUBLIC_API(uintN
)
1112 JS_PCToLineNumber(JSContext
*cx
, JSScript
*script
, jsbytecode
*pc
)
1114 return js_PCToLineNumber(cx
, script
, pc
);
1117 JS_PUBLIC_API(jsbytecode
*)
1118 JS_LineNumberToPC(JSContext
*cx
, JSScript
*script
, uintN lineno
)
1120 return js_LineNumberToPC(script
, lineno
);
1123 JS_PUBLIC_API(jsbytecode
*)
1124 JS_EndPC(JSContext
*cx
, JSScript
*script
)
1126 return script
->code
+ script
->length
;
1129 JS_PUBLIC_API(uintN
)
1130 JS_GetFunctionArgumentCount(JSContext
*cx
, JSFunction
*fun
)
1135 JS_PUBLIC_API(JSBool
)
1136 JS_FunctionHasLocalNames(JSContext
*cx
, JSFunction
*fun
)
1138 return fun
->script()->bindings
.hasLocalNames();
1141 extern JS_PUBLIC_API(jsuword
*)
1142 JS_GetFunctionLocalNameArray(JSContext
*cx
, JSFunction
*fun
, void **markp
)
1144 *markp
= JS_ARENA_MARK(&cx
->tempPool
);
1145 return fun
->script()->bindings
.getLocalNameArray(cx
, &cx
->tempPool
);
1148 extern JS_PUBLIC_API(JSAtom
*)
1149 JS_LocalNameToAtom(jsuword w
)
1151 return JS_LOCAL_NAME_TO_ATOM(w
);
1154 extern JS_PUBLIC_API(JSString
*)
1155 JS_AtomKey(JSAtom
*atom
)
1157 return ATOM_TO_STRING(atom
);
1160 extern JS_PUBLIC_API(void)
1161 JS_ReleaseFunctionLocalNameArray(JSContext
*cx
, void *mark
)
1163 JS_ARENA_RELEASE(&cx
->tempPool
, mark
);
1166 JS_PUBLIC_API(JSScript
*)
1167 JS_GetFunctionScript(JSContext
*cx
, JSFunction
*fun
)
1169 return FUN_SCRIPT(fun
);
1172 JS_PUBLIC_API(JSNative
)
1173 JS_GetFunctionNative(JSContext
*cx
, JSFunction
*fun
)
1175 return Jsvalify(fun
->maybeNative());
1178 JS_PUBLIC_API(JSPrincipals
*)
1179 JS_GetScriptPrincipals(JSContext
*cx
, JSScript
*script
)
1181 return script
->principals
;
1184 /************************************************************************/
1187 * Stack Frame Iterator
1189 JS_PUBLIC_API(JSStackFrame
*)
1190 JS_FrameIterator(JSContext
*cx
, JSStackFrame
**iteratorp
)
1192 *iteratorp
= (*iteratorp
== NULL
) ? js_GetTopStackFrame(cx
) : (*iteratorp
)->prev();
1196 JS_PUBLIC_API(JSScript
*)
1197 JS_GetFrameScript(JSContext
*cx
, JSStackFrame
*fp
)
1199 return fp
->maybeScript();
1202 JS_PUBLIC_API(jsbytecode
*)
1203 JS_GetFramePC(JSContext
*cx
, JSStackFrame
*fp
)
1208 JS_PUBLIC_API(JSStackFrame
*)
1209 JS_GetScriptedCaller(JSContext
*cx
, JSStackFrame
*fp
)
1211 return js_GetScriptedCaller(cx
, fp
);
1215 js_StackFramePrincipals(JSContext
*cx
, JSStackFrame
*fp
)
1217 JSSecurityCallbacks
*callbacks
;
1219 if (fp
->isFunctionFrame()) {
1220 callbacks
= JS_GetSecurityCallbacks(cx
);
1221 if (callbacks
&& callbacks
->findObjectPrincipals
) {
1222 if (&fp
->fun()->compiledFunObj() != &fp
->callee())
1223 return callbacks
->findObjectPrincipals(cx
, &fp
->callee());
1227 if (fp
->isScriptFrame())
1228 return fp
->script()->principals
;
1233 js_EvalFramePrincipals(JSContext
*cx
, JSObject
*callee
, JSStackFrame
*caller
)
1235 JSPrincipals
*principals
, *callerPrincipals
;
1236 JSSecurityCallbacks
*callbacks
;
1238 callbacks
= JS_GetSecurityCallbacks(cx
);
1239 if (callbacks
&& callbacks
->findObjectPrincipals
)
1240 principals
= callbacks
->findObjectPrincipals(cx
, callee
);
1245 callerPrincipals
= js_StackFramePrincipals(cx
, caller
);
1246 return (callerPrincipals
&& principals
&&
1247 callerPrincipals
->subsume(callerPrincipals
, principals
))
1252 JS_PUBLIC_API(void *)
1253 JS_GetFrameAnnotation(JSContext
*cx
, JSStackFrame
*fp
)
1255 if (fp
->annotation() && fp
->isScriptFrame()) {
1256 JSPrincipals
*principals
= js_StackFramePrincipals(cx
, fp
);
1258 if (principals
&& principals
->globalPrivilegesEnabled(cx
, principals
)) {
1260 * Give out an annotation only if privileges have not been revoked
1261 * or disabled globally.
1263 return fp
->annotation();
1271 JS_SetFrameAnnotation(JSContext
*cx
, JSStackFrame
*fp
, void *annotation
)
1273 fp
->setAnnotation(annotation
);
1276 JS_PUBLIC_API(void *)
1277 JS_GetFramePrincipalArray(JSContext
*cx
, JSStackFrame
*fp
)
1279 JSPrincipals
*principals
;
1281 principals
= js_StackFramePrincipals(cx
, fp
);
1284 return principals
->getPrincipalArray(cx
, principals
);
1287 JS_PUBLIC_API(JSBool
)
1288 JS_IsScriptFrame(JSContext
*cx
, JSStackFrame
*fp
)
1290 return !fp
->isDummyFrame();
1293 /* this is deprecated, use JS_GetFrameScopeChain instead */
1294 JS_PUBLIC_API(JSObject
*)
1295 JS_GetFrameObject(JSContext
*cx
, JSStackFrame
*fp
)
1297 return &fp
->scopeChain();
1300 JS_PUBLIC_API(JSObject
*)
1301 JS_GetFrameScopeChain(JSContext
*cx
, JSStackFrame
*fp
)
1303 JS_ASSERT(cx
->stack().contains(fp
));
1305 js::AutoCompartment
ac(cx
, &fp
->scopeChain());
1309 /* Force creation of argument and call objects if not yet created */
1310 (void) JS_GetFrameCallObject(cx
, fp
);
1311 return GetScopeChain(cx
, fp
);
1314 JS_PUBLIC_API(JSObject
*)
1315 JS_GetFrameCallObject(JSContext
*cx
, JSStackFrame
*fp
)
1317 JS_ASSERT(cx
->stack().contains(fp
));
1319 if (!fp
->isFunctionFrame())
1322 js::AutoCompartment
ac(cx
, &fp
->scopeChain());
1326 /* Force creation of argument object if not yet created */
1327 (void) js_GetArgsObject(cx
, fp
);
1330 * XXX ill-defined: null return here means error was reported, unlike a
1331 * null returned above or in the #else
1333 return js_GetCallObject(cx
, fp
);
1336 JS_PUBLIC_API(JSBool
)
1337 JS_GetFrameThis(JSContext
*cx
, JSStackFrame
*fp
, jsval
*thisv
)
1339 if (fp
->isDummyFrame())
1342 js::AutoCompartment
ac(cx
, &fp
->scopeChain());
1346 if (!fp
->computeThis(cx
))
1348 *thisv
= Jsvalify(fp
->thisValue());
1352 JS_PUBLIC_API(JSFunction
*)
1353 JS_GetFrameFunction(JSContext
*cx
, JSStackFrame
*fp
)
1355 return fp
->maybeFun();
1358 JS_PUBLIC_API(JSObject
*)
1359 JS_GetFrameFunctionObject(JSContext
*cx
, JSStackFrame
*fp
)
1361 if (!fp
->isFunctionFrame())
1364 JS_ASSERT(fp
->callee().isFunction());
1365 JS_ASSERT(fp
->callee().getPrivate() == fp
->fun());
1366 return &fp
->callee();
1369 JS_PUBLIC_API(JSBool
)
1370 JS_IsConstructorFrame(JSContext
*cx
, JSStackFrame
*fp
)
1372 return fp
->isConstructing();
1375 JS_PUBLIC_API(JSObject
*)
1376 JS_GetFrameCalleeObject(JSContext
*cx
, JSStackFrame
*fp
)
1378 return fp
->maybeCallee();
1381 JS_PUBLIC_API(JSBool
)
1382 JS_GetValidFrameCalleeObject(JSContext
*cx
, JSStackFrame
*fp
, jsval
*vp
)
1386 if (!fp
->getValidCalleeObject(cx
, &v
))
1392 JS_PUBLIC_API(JSBool
)
1393 JS_IsDebuggerFrame(JSContext
*cx
, JSStackFrame
*fp
)
1395 return fp
->isDebuggerFrame();
1398 JS_PUBLIC_API(jsval
)
1399 JS_GetFrameReturnValue(JSContext
*cx
, JSStackFrame
*fp
)
1401 return Jsvalify(fp
->returnValue());
1405 JS_SetFrameReturnValue(JSContext
*cx
, JSStackFrame
*fp
, jsval rval
)
1408 JS_ASSERT_IF(fp
->isScriptFrame(), fp
->script()->debugMode
);
1410 assertSameCompartment(cx
, fp
, rval
);
1411 fp
->setReturnValue(Valueify(rval
));
1414 /************************************************************************/
1416 JS_PUBLIC_API(const char *)
1417 JS_GetScriptFilename(JSContext
*cx
, JSScript
*script
)
1419 return script
->filename
;
1422 JS_PUBLIC_API(uintN
)
1423 JS_GetScriptBaseLineNumber(JSContext
*cx
, JSScript
*script
)
1425 return script
->lineno
;
1428 JS_PUBLIC_API(uintN
)
1429 JS_GetScriptLineExtent(JSContext
*cx
, JSScript
*script
)
1431 return js_GetScriptLineExtent(script
);
1434 JS_PUBLIC_API(JSVersion
)
1435 JS_GetScriptVersion(JSContext
*cx
, JSScript
*script
)
1437 return VersionNumber(script
->getVersion());
1440 /***************************************************************************/
1443 JS_SetNewScriptHook(JSRuntime
*rt
, JSNewScriptHook hook
, void *callerdata
)
1445 rt
->globalDebugHooks
.newScriptHook
= hook
;
1446 rt
->globalDebugHooks
.newScriptHookData
= callerdata
;
1450 JS_SetDestroyScriptHook(JSRuntime
*rt
, JSDestroyScriptHook hook
,
1453 rt
->globalDebugHooks
.destroyScriptHook
= hook
;
1454 rt
->globalDebugHooks
.destroyScriptHookData
= callerdata
;
1457 /***************************************************************************/
1459 JS_PUBLIC_API(JSBool
)
1460 JS_EvaluateUCInStackFrame(JSContext
*cx
, JSStackFrame
*fp
,
1461 const jschar
*chars
, uintN length
,
1462 const char *filename
, uintN lineno
,
1465 JS_ASSERT_NOT_ON_TRACE(cx
);
1467 if (!CheckDebugMode(cx
))
1470 JSObject
*scobj
= JS_GetFrameScopeChain(cx
, fp
);
1474 js::AutoCompartment
ac(cx
, scobj
);
1479 * NB: This function breaks the assumption that the compiler can see all
1480 * calls and properly compute a static level. In order to get around this,
1481 * we use a static level that will cause us not to attempt to optimize
1482 * variable references made by this frame.
1484 JSScript
*script
= Compiler::compileScript(cx
, scobj
, fp
, js_StackFramePrincipals(cx
, fp
),
1485 TCF_COMPILE_N_GO
, chars
, length
,
1486 filename
, lineno
, NULL
,
1487 UpvarCookie::UPVAR_LEVEL_LIMIT
);
1492 bool ok
= Execute(cx
, scobj
, script
, fp
, JSFRAME_DEBUGGER
| JSFRAME_EVAL
, Valueify(rval
));
1494 js_DestroyScript(cx
, script
);
1498 JS_PUBLIC_API(JSBool
)
1499 JS_EvaluateInStackFrame(JSContext
*cx
, JSStackFrame
*fp
,
1500 const char *bytes
, uintN length
,
1501 const char *filename
, uintN lineno
,
1506 size_t len
= length
;
1508 if (!CheckDebugMode(cx
))
1511 chars
= js_InflateString(cx
, bytes
, &len
);
1514 length
= (uintN
) len
;
1515 ok
= JS_EvaluateUCInStackFrame(cx
, fp
, chars
, length
, filename
, lineno
,
1522 /************************************************************************/
1524 /* This all should be reworked to avoid requiring JSScopeProperty types. */
1526 JS_PUBLIC_API(JSScopeProperty
*)
1527 JS_PropertyIterator(JSObject
*obj
, JSScopeProperty
**iteratorp
)
1531 /* The caller passes null in *iteratorp to get things started. */
1532 shape
= (Shape
*) *iteratorp
;
1534 shape
= obj
->lastProperty();
1536 shape
= shape
->previous();
1537 if (!shape
->previous()) {
1538 JS_ASSERT(JSID_IS_EMPTY(shape
->id
));
1543 return *iteratorp
= reinterpret_cast<JSScopeProperty
*>(const_cast<Shape
*>(shape
));
1546 JS_PUBLIC_API(JSBool
)
1547 JS_GetPropertyDesc(JSContext
*cx
, JSObject
*obj
, JSScopeProperty
*sprop
,
1550 assertSameCompartment(cx
, obj
);
1551 Shape
*shape
= (Shape
*) sprop
;
1552 pd
->id
= IdToJsval(shape
->id
);
1554 JSBool wasThrowing
= cx
->isExceptionPending();
1555 Value lastException
= UndefinedValue();
1557 lastException
= cx
->getPendingException();
1558 cx
->clearPendingException();
1560 if (!js_GetProperty(cx
, obj
, shape
->id
, Valueify(&pd
->value
))) {
1561 if (!cx
->isExceptionPending()) {
1562 pd
->flags
= JSPD_ERROR
;
1563 pd
->value
= JSVAL_VOID
;
1565 pd
->flags
= JSPD_EXCEPTION
;
1566 pd
->value
= Jsvalify(cx
->getPendingException());
1573 cx
->setPendingException(lastException
);
1575 pd
->flags
|= (shape
->enumerable() ? JSPD_ENUMERATE
: 0)
1576 | (!shape
->writable() ? JSPD_READONLY
: 0)
1577 | (!shape
->configurable() ? JSPD_PERMANENT
: 0);
1579 if (shape
->getter() == GetCallArg
) {
1580 pd
->slot
= shape
->shortid
;
1581 pd
->flags
|= JSPD_ARGUMENT
;
1582 } else if (shape
->getter() == GetCallVar
) {
1583 pd
->slot
= shape
->shortid
;
1584 pd
->flags
|= JSPD_VARIABLE
;
1588 pd
->alias
= JSVAL_VOID
;
1590 if (obj
->containsSlot(shape
->slot
)) {
1591 for (Shape::Range r
= obj
->lastProperty()->all(); !r
.empty(); r
.popFront()) {
1592 const Shape
&aprop
= r
.front();
1593 if (&aprop
!= shape
&& aprop
.slot
== shape
->slot
) {
1594 pd
->alias
= IdToJsval(aprop
.id
);
1602 JS_PUBLIC_API(JSBool
)
1603 JS_GetPropertyDescArray(JSContext
*cx
, JSObject
*obj
, JSPropertyDescArray
*pda
)
1605 assertSameCompartment(cx
, obj
);
1606 Class
*clasp
= obj
->getClass();
1607 if (!obj
->isNative() || (clasp
->flags
& JSCLASS_NEW_ENUMERATE
)) {
1608 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
1609 JSMSG_CANT_DESCRIBE_PROPS
, clasp
->name
);
1612 if (!clasp
->enumerate(cx
, obj
))
1615 /* Return an empty pda early if obj has no own properties. */
1616 if (obj
->nativeEmpty()) {
1622 uint32 n
= obj
->propertyCount();
1623 JSPropertyDesc
*pd
= (JSPropertyDesc
*) cx
->malloc(size_t(n
) * sizeof(JSPropertyDesc
));
1627 for (Shape::Range r
= obj
->lastProperty()->all(); !r
.empty(); r
.popFront()) {
1628 if (!js_AddRoot(cx
, Valueify(&pd
[i
].id
), NULL
))
1630 if (!js_AddRoot(cx
, Valueify(&pd
[i
].value
), NULL
))
1632 Shape
*shape
= const_cast<Shape
*>(&r
.front());
1633 if (!JS_GetPropertyDesc(cx
, obj
, reinterpret_cast<JSScopeProperty
*>(shape
), &pd
[i
]))
1635 if ((pd
[i
].flags
& JSPD_ALIAS
) && !js_AddRoot(cx
, Valueify(&pd
[i
].alias
), NULL
))
1645 pda
->length
= i
+ 1;
1647 JS_PutPropertyDescArray(cx
, pda
);
1652 JS_PutPropertyDescArray(JSContext
*cx
, JSPropertyDescArray
*pda
)
1658 for (i
= 0; i
< pda
->length
; i
++) {
1659 js_RemoveRoot(cx
->runtime
, &pd
[i
].id
);
1660 js_RemoveRoot(cx
->runtime
, &pd
[i
].value
);
1661 if (pd
[i
].flags
& JSPD_ALIAS
)
1662 js_RemoveRoot(cx
->runtime
, &pd
[i
].alias
);
1667 /************************************************************************/
1669 JS_PUBLIC_API(JSBool
)
1670 JS_SetDebuggerHandler(JSRuntime
*rt
, JSDebuggerHandler handler
, void *closure
)
1672 rt
->globalDebugHooks
.debuggerHandler
= handler
;
1673 rt
->globalDebugHooks
.debuggerHandlerData
= closure
;
1677 JS_PUBLIC_API(JSBool
)
1678 JS_SetSourceHandler(JSRuntime
*rt
, JSSourceHandler handler
, void *closure
)
1680 rt
->globalDebugHooks
.sourceHandler
= handler
;
1681 rt
->globalDebugHooks
.sourceHandlerData
= closure
;
1685 JS_PUBLIC_API(JSBool
)
1686 JS_SetExecuteHook(JSRuntime
*rt
, JSInterpreterHook hook
, void *closure
)
1688 rt
->globalDebugHooks
.executeHook
= hook
;
1689 rt
->globalDebugHooks
.executeHookData
= closure
;
1693 JS_PUBLIC_API(JSBool
)
1694 JS_SetCallHook(JSRuntime
*rt
, JSInterpreterHook hook
, void *closure
)
1698 AutoLockGC
lock(rt
);
1699 bool wasInhibited
= rt
->debuggerInhibitsJIT();
1701 rt
->globalDebugHooks
.callHook
= hook
;
1702 rt
->globalDebugHooks
.callHookData
= closure
;
1704 JITInhibitingHookChange(rt
, wasInhibited
);
1710 JS_PUBLIC_API(JSBool
)
1711 JS_SetThrowHook(JSRuntime
*rt
, JSThrowHook hook
, void *closure
)
1713 rt
->globalDebugHooks
.throwHook
= hook
;
1714 rt
->globalDebugHooks
.throwHookData
= closure
;
1718 JS_PUBLIC_API(JSBool
)
1719 JS_SetDebugErrorHook(JSRuntime
*rt
, JSDebugErrorHook hook
, void *closure
)
1721 rt
->globalDebugHooks
.debugErrorHook
= hook
;
1722 rt
->globalDebugHooks
.debugErrorHookData
= closure
;
1726 /************************************************************************/
1728 JS_PUBLIC_API(size_t)
1729 JS_GetObjectTotalSize(JSContext
*cx
, JSObject
*obj
)
1731 return obj
->slotsAndStructSize();
1735 GetAtomTotalSize(JSContext
*cx
, JSAtom
*atom
)
1739 nbytes
= sizeof(JSAtom
*) + sizeof(JSDHashEntryStub
);
1740 nbytes
+= sizeof(JSString
);
1741 nbytes
+= (ATOM_TO_STRING(atom
)->flatLength() + 1) * sizeof(jschar
);
1745 JS_PUBLIC_API(size_t)
1746 JS_GetFunctionTotalSize(JSContext
*cx
, JSFunction
*fun
)
1750 nbytes
= sizeof *fun
;
1751 nbytes
+= JS_GetObjectTotalSize(cx
, FUN_OBJECT(fun
));
1752 if (FUN_INTERPRETED(fun
))
1753 nbytes
+= JS_GetScriptTotalSize(cx
, fun
->u
.i
.script
);
1755 nbytes
+= GetAtomTotalSize(cx
, fun
->atom
);
1761 JS_PUBLIC_API(size_t)
1762 JS_GetScriptTotalSize(JSContext
*cx
, JSScript
*script
)
1764 size_t nbytes
, pbytes
;
1766 jssrcnote
*sn
, *notes
;
1767 JSObjectArray
*objarray
;
1768 JSPrincipals
*principals
;
1770 nbytes
= sizeof *script
;
1771 if (script
->u
.object
)
1772 nbytes
+= JS_GetObjectTotalSize(cx
, script
->u
.object
);
1774 nbytes
+= script
->length
* sizeof script
->code
[0];
1775 nbytes
+= script
->atomMap
.length
* sizeof script
->atomMap
.vector
[0];
1776 for (i
= 0; i
< script
->atomMap
.length
; i
++)
1777 nbytes
+= GetAtomTotalSize(cx
, script
->atomMap
.vector
[i
]);
1779 if (script
->filename
)
1780 nbytes
+= strlen(script
->filename
) + 1;
1782 notes
= script
->notes();
1783 for (sn
= notes
; !SN_IS_TERMINATOR(sn
); sn
= SN_NEXT(sn
))
1785 nbytes
+= (sn
- notes
+ 1) * sizeof *sn
;
1787 if (JSScript::isValidOffset(script
->objectsOffset
)) {
1788 objarray
= script
->objects();
1789 i
= objarray
->length
;
1790 nbytes
+= sizeof *objarray
+ i
* sizeof objarray
->vector
[0];
1792 nbytes
+= JS_GetObjectTotalSize(cx
, objarray
->vector
[--i
]);
1796 if (JSScript::isValidOffset(script
->regexpsOffset
)) {
1797 objarray
= script
->regexps();
1798 i
= objarray
->length
;
1799 nbytes
+= sizeof *objarray
+ i
* sizeof objarray
->vector
[0];
1801 nbytes
+= JS_GetObjectTotalSize(cx
, objarray
->vector
[--i
]);
1805 if (JSScript::isValidOffset(script
->trynotesOffset
)) {
1806 nbytes
+= sizeof(JSTryNoteArray
) +
1807 script
->trynotes()->length
* sizeof(JSTryNote
);
1810 principals
= script
->principals
;
1812 JS_ASSERT(principals
->refcount
);
1813 pbytes
= sizeof *principals
;
1814 if (principals
->refcount
> 1)
1815 pbytes
= JS_HOWMANY(pbytes
, principals
->refcount
);
1822 JS_PUBLIC_API(uint32
)
1823 JS_GetTopScriptFilenameFlags(JSContext
*cx
, JSStackFrame
*fp
)
1826 fp
= js_GetTopStackFrame(cx
);
1828 if (fp
->isScriptFrame())
1829 return JS_GetScriptFilenameFlags(fp
->script());
1835 JS_PUBLIC_API(uint32
)
1836 JS_GetScriptFilenameFlags(JSScript
*script
)
1839 if (!script
->filename
)
1840 return JSFILENAME_NULL
;
1841 return js_GetScriptFilenameFlags(script
->filename
);
1844 JS_PUBLIC_API(JSBool
)
1845 JS_FlagScriptFilenamePrefix(JSRuntime
*rt
, const char *prefix
, uint32 flags
)
1847 if (!js_SaveScriptFilenameRT(rt
, prefix
, flags
))
1852 JS_PUBLIC_API(JSBool
)
1853 JS_IsSystemObject(JSContext
*cx
, JSObject
*obj
)
1855 return obj
->isSystem();
1858 JS_PUBLIC_API(JSBool
)
1859 JS_MakeSystemObject(JSContext
*cx
, JSObject
*obj
)
1865 /************************************************************************/
1867 JS_PUBLIC_API(JSObject
*)
1868 JS_UnwrapObject(JSContext
*cx
, JSObject
*obj
)
1870 return obj
->unwrap();
1873 /************************************************************************/
1876 js_RevertVersion(JSContext
*cx
)
1878 cx
->clearVersionOverride();
1881 JS_PUBLIC_API(const JSDebugHooks
*)
1882 JS_GetGlobalDebugHooks(JSRuntime
*rt
)
1884 return &rt
->globalDebugHooks
;
1887 const JSDebugHooks js_NullDebugHooks
= {};
1889 JS_PUBLIC_API(JSDebugHooks
*)
1890 JS_SetContextDebugHooks(JSContext
*cx
, const JSDebugHooks
*hooks
)
1893 if (hooks
!= &cx
->runtime
->globalDebugHooks
&& hooks
!= &js_NullDebugHooks
)
1897 AutoLockGC
lock(cx
->runtime
);
1899 JSDebugHooks
*old
= const_cast<JSDebugHooks
*>(cx
->debugHooks
);
1900 cx
->debugHooks
= hooks
;
1902 cx
->updateJITEnabled();
1907 JS_PUBLIC_API(JSDebugHooks
*)
1908 JS_ClearContextDebugHooks(JSContext
*cx
)
1910 return JS_SetContextDebugHooks(cx
, &js_NullDebugHooks
);
1913 JS_PUBLIC_API(JSBool
)
1916 return Probes::startProfiling();
1922 Probes::stopProfiling();
1925 #ifdef MOZ_PROFILING
1928 StartProfiling(JSContext
*cx
, uintN argc
, jsval
*vp
)
1930 JS_SET_RVAL(cx
, vp
, BOOLEAN_TO_JSVAL(JS_StartProfiling()));
1935 StopProfiling(JSContext
*cx
, uintN argc
, jsval
*vp
)
1938 JS_SET_RVAL(cx
, vp
, JSVAL_VOID
);
1945 IgnoreAndReturnTrue(JSContext
*cx
, uintN argc
, jsval
*vp
)
1947 JS_SET_RVAL(cx
, vp
, JSVAL_TRUE
);
1953 static JSFunctionSpec profiling_functions
[] = {
1954 JS_FN("startProfiling", StartProfiling
, 0,0),
1955 JS_FN("stopProfiling", StopProfiling
, 0,0),
1957 /* Keep users of the old shark API happy. */
1958 JS_FN("connectShark", IgnoreAndReturnTrue
, 0,0),
1959 JS_FN("disconnectShark", IgnoreAndReturnTrue
, 0,0),
1960 JS_FN("startShark", StartProfiling
, 0,0),
1961 JS_FN("stopShark", StopProfiling
, 0,0),
1968 JS_PUBLIC_API(JSBool
)
1969 JS_DefineProfilingFunctions(JSContext
*cx
, JSObject
*obj
)
1971 #ifdef MOZ_PROFILING
1972 return JS_DefineFunctions(cx
, obj
, profiling_functions
);
1978 #ifdef MOZ_CALLGRIND
1980 #include <valgrind/callgrind.h>
1982 JS_FRIEND_API(JSBool
)
1983 js_StartCallgrind(JSContext
*cx
, uintN argc
, jsval
*vp
)
1985 CALLGRIND_START_INSTRUMENTATION
;
1986 CALLGRIND_ZERO_STATS
;
1987 JS_SET_RVAL(cx
, vp
, JSVAL_VOID
);
1991 JS_FRIEND_API(JSBool
)
1992 js_StopCallgrind(JSContext
*cx
, uintN argc
, jsval
*vp
)
1994 CALLGRIND_STOP_INSTRUMENTATION
;
1995 JS_SET_RVAL(cx
, vp
, JSVAL_VOID
);
1999 JS_FRIEND_API(JSBool
)
2000 js_DumpCallgrind(JSContext
*cx
, uintN argc
, jsval
*vp
)
2004 jsval
*argv
= JS_ARGV(cx
, vp
);
2005 if (argc
> 0 && JSVAL_IS_STRING(argv
[0])) {
2006 str
= JSVAL_TO_STRING(argv
[0]);
2007 JSAutoByteString
bytes(cx
, str
);
2009 CALLGRIND_DUMP_STATS_AT(bytes
.ptr());
2013 CALLGRIND_DUMP_STATS
;
2015 JS_SET_RVAL(cx
, vp
, JSVAL_VOID
);
2019 #endif /* MOZ_CALLGRIND */
2022 #include <VTuneApi.h>
2024 static const char *vtuneErrorMessages
[] = {
2025 "unknown, error #0",
2026 "invalid 'max samples' field",
2027 "invalid 'samples per buffer' field",
2028 "invalid 'sample interval' field",
2030 "sample file in use",
2031 "invalid 'number of events' field",
2032 "unknown, error #7",
2035 "VTStopSampling called without calling VTStartSampling",
2036 "no events selected for event-based sampling",
2037 "events selected cannot be run together",
2038 "no sampling parameters",
2039 "sample database already exists",
2040 "sampling already started",
2041 "time-based sampling not supported",
2042 "invalid 'sampling parameters size' field",
2043 "invalid 'event size' field",
2044 "sampling file already bound",
2045 "invalid event path",
2047 "invalid 'global options' field",
2051 JS_FRIEND_API(JSBool
)
2052 js_StartVtune(JSContext
*cx
, uintN argc
, jsval
*vp
)
2054 VTUNE_EVENT events
[] = {
2055 { 1000000, 0, 0, 0, "CPU_CLK_UNHALTED.CORE" },
2056 { 1000000, 0, 0, 0, "INST_RETIRED.ANY" },
2059 U32 n_events
= sizeof(events
) / sizeof(VTUNE_EVENT
);
2060 char *default_filename
= "mozilla-vtune.tb5";
2064 VTUNE_SAMPLING_PARAMS params
= {
2065 sizeof(VTUNE_SAMPLING_PARAMS
),
2066 sizeof(VTUNE_EVENT
),
2067 0, 0, /* Reserved fields */
2068 1, /* Initialize in "paused" state */
2069 0, /* Max samples, or 0 for "continuous" */
2070 4096, /* Samples per buffer */
2071 0.1, /* Sampling interval in ms */
2072 1, /* 1 for event-based sampling, 0 for time-based */
2079 jsval
*argv
= JS_ARGV(cx
, vp
);
2080 if (argc
> 0 && JSVAL_IS_STRING(argv
[0])) {
2081 str
= JSVAL_TO_STRING(argv
[0]);
2082 params
.tb5Filename
= js_DeflateString(cx
, str
->chars(), str
->length());
2085 status
= VTStartSampling(¶ms
);
2087 if (params
.tb5Filename
!= default_filename
)
2088 cx
->free(params
.tb5Filename
);
2091 if (status
== VTAPI_MULTIPLE_RUNS
)
2093 if (status
< sizeof(vtuneErrorMessages
))
2094 JS_ReportError(cx
, "Vtune setup error: %s",
2095 vtuneErrorMessages
[status
]);
2097 JS_ReportError(cx
, "Vtune setup error: %d",
2101 JS_SET_RVAL(cx
, vp
, JSVAL_VOID
);
2105 JS_FRIEND_API(JSBool
)
2106 js_StopVtune(JSContext
*cx
, uintN argc
, jsval
*vp
)
2108 U32 status
= VTStopSampling(1);
2110 if (status
< sizeof(vtuneErrorMessages
))
2111 JS_ReportError(cx
, "Vtune shutdown error: %s",
2112 vtuneErrorMessages
[status
]);
2114 JS_ReportError(cx
, "Vtune shutdown error: %d",
2118 JS_SET_RVAL(cx
, vp
, JSVAL_VOID
);
2122 JS_FRIEND_API(JSBool
)
2123 js_PauseVtune(JSContext
*cx
, uintN argc
, jsval
*vp
)
2126 JS_SET_RVAL(cx
, vp
, JSVAL_VOID
);
2130 JS_FRIEND_API(JSBool
)
2131 js_ResumeVtune(JSContext
*cx
, uintN argc
, jsval
*vp
)
2134 JS_SET_RVAL(cx
, vp
, JSVAL_VOID
);
2138 #endif /* MOZ_VTUNE */
2142 * Ethogram - Javascript wrapper for TraceVis state
2144 * ethology: The scientific study of animal behavior,
2145 * especially as it occurs in a natural environment.
2146 * ethogram: A pictorial catalog of the behavioral patterns of
2147 * an organism or a species.
2153 #include <sys/time.h>
2155 #include "jstracer.h"
2157 #define ETHOGRAM_BUF_SIZE 65536
2160 ethogram_construct(JSContext
*cx
, uintN argc
, jsval
*vp
);
2162 ethogram_finalize(JSContext
*cx
, JSObject
*obj
);
2164 static JSClass ethogram_class
= {
2166 JSCLASS_HAS_PRIVATE
,
2167 JS_PropertyStub
, JS_PropertyStub
, JS_PropertyStub
, JS_PropertyStub
,
2168 JS_EnumerateStub
, JS_ResolveStub
, JS_ConvertStub
, ethogram_finalize
,
2169 JSCLASS_NO_OPTIONAL_MEMBERS
2172 struct EthogramEvent
{
2174 TraceVisExitReason r
;
2182 compare_strings(const void *k1
, const void *k2
)
2184 return strcmp((const char *) k1
, (const char *) k2
) == 0;
2187 class EthogramEventBuffer
{
2189 EthogramEvent mBuf
[ETHOGRAM_BUF_SIZE
];
2192 JSObject
*mFilenames
;
2195 struct EthogramScriptEntry
{
2197 JSString
*jsfilename
;
2199 EthogramScriptEntry
*next
;
2201 EthogramScriptEntry
*mScripts
;
2205 ethogram_construct(JSContext
*cx
, uintN argc
, jsval
*vp
);
2207 inline void push(TraceVisState s
, TraceVisExitReason r
, char *filename
, int lineno
) {
2208 mBuf
[mWritePos
].s
= s
;
2209 mBuf
[mWritePos
].r
= r
;
2212 GetSystemTimeAsFileTime(&now
);
2213 unsigned long long raw_us
= 0.1 *
2214 (((unsigned long long) now
.dwHighDateTime
<< 32ULL) |
2215 (unsigned long long) now
.dwLowDateTime
);
2216 unsigned int sec
= raw_us
/ 1000000L;
2217 unsigned int usec
= raw_us
% 1000000L;
2218 mBuf
[mWritePos
].ts
= sec
- mStartSecond
;
2219 mBuf
[mWritePos
].tus
= usec
;
2222 gettimeofday(&tv
, NULL
);
2223 mBuf
[mWritePos
].ts
= tv
.tv_sec
- mStartSecond
;
2224 mBuf
[mWritePos
].tus
= tv
.tv_usec
;
2227 JSString
*jsfilename
= findScript(filename
);
2228 mBuf
[mWritePos
].filename
= jsfilename
;
2229 mBuf
[mWritePos
].lineno
= lineno
;
2231 mWritePos
= (mWritePos
+ 1) % ETHOGRAM_BUF_SIZE
;
2232 if (mWritePos
== mReadPos
) {
2233 mReadPos
= (mWritePos
+ 1) % ETHOGRAM_BUF_SIZE
;
2237 inline EthogramEvent
*pop() {
2238 EthogramEvent
*e
= &mBuf
[mReadPos
];
2239 mReadPos
= (mReadPos
+ 1) % ETHOGRAM_BUF_SIZE
;
2244 return (mReadPos
== mWritePos
);
2247 EthogramScriptEntry
*addScript(JSContext
*cx
, JSObject
*obj
, char *filename
, JSString
*jsfilename
) {
2248 JSHashNumber hash
= JS_HashString(filename
);
2249 JSHashEntry
**hep
= JS_HashTableRawLookup(traceVisScriptTable
, hash
, filename
);
2253 JS_HashTableRawAdd(traceVisScriptTable
, hep
, hash
, filename
, this);
2255 EthogramScriptEntry
* entry
= (EthogramScriptEntry
*) JS_malloc(cx
, sizeof(EthogramScriptEntry
));
2259 entry
->next
= mScripts
;
2261 entry
->filename
= filename
;
2262 entry
->jsfilename
= jsfilename
;
2267 void removeScripts(JSContext
*cx
) {
2268 EthogramScriptEntry
*se
= mScripts
;
2269 while (se
!= NULL
) {
2270 char *filename
= se
->filename
;
2272 JSHashNumber hash
= JS_HashString(filename
);
2273 JSHashEntry
**hep
= JS_HashTableRawLookup(traceVisScriptTable
, hash
, filename
);
2274 JSHashEntry
*he
= *hep
;
2276 /* we hardly knew he */
2277 JS_HashTableRawRemove(traceVisScriptTable
, hep
, he
);
2280 EthogramScriptEntry
*se_head
= se
;
2282 JS_free(cx
, se_head
);
2286 JSString
*findScript(char *filename
) {
2287 EthogramScriptEntry
*se
= mScripts
;
2288 while (se
!= NULL
) {
2289 if (compare_strings(se
->filename
, filename
))
2290 return (se
->jsfilename
);
2296 JSObject
*filenames() {
2301 if (mWritePos
< mReadPos
)
2302 return (mWritePos
+ ETHOGRAM_BUF_SIZE
) - mReadPos
;
2304 return mWritePos
- mReadPos
;
2308 static char jstv_empty
[] = "<null>";
2311 jstv_Filename(JSStackFrame
*fp
)
2313 while (fp
&& !fp
->isScriptFrame())
2315 return (fp
&& fp
->maybeScript() && fp
->script()->filename
)
2316 ? (char *)fp
->script()->filename
2320 jstv_Lineno(JSContext
*cx
, JSStackFrame
*fp
)
2322 while (fp
&& fp
->pc(cx
) == NULL
)
2324 return (fp
&& fp
->pc(cx
)) ? js_FramePCToLineNumber(cx
, fp
) : 0;
2327 /* Collect states here and distribute to a matching buffer, if any */
2329 js::StoreTraceVisState(JSContext
*cx
, TraceVisState s
, TraceVisExitReason r
)
2331 JSStackFrame
*fp
= cx
->fp();
2333 char *script_file
= jstv_Filename(fp
);
2334 JSHashNumber hash
= JS_HashString(script_file
);
2336 JSHashEntry
**hep
= JS_HashTableRawLookup(traceVisScriptTable
, hash
, script_file
);
2337 /* update event buffer, flag if overflowed */
2338 JSHashEntry
*he
= *hep
;
2340 EthogramEventBuffer
*p
;
2341 p
= (EthogramEventBuffer
*) he
->value
;
2343 p
->push(s
, r
, script_file
, jstv_Lineno(cx
, fp
));
2348 ethogram_construct(JSContext
*cx
, uintN argc
, jsval
*vp
)
2350 EthogramEventBuffer
*p
;
2352 p
= (EthogramEventBuffer
*) JS_malloc(cx
, sizeof(EthogramEventBuffer
));
2356 p
->mReadPos
= p
->mWritePos
= 0;
2358 p
->mFilenames
= JS_NewArrayObject(cx
, 0, NULL
);
2362 GetSystemTimeAsFileTime(&now
);
2363 unsigned long long raw_us
= 0.1 *
2364 (((unsigned long long) now
.dwHighDateTime
<< 32ULL) |
2365 (unsigned long long) now
.dwLowDateTime
);
2366 unsigned int s
= raw_us
/ 1000000L;
2367 p
->mStartSecond
= s
;
2370 gettimeofday(&tv
, NULL
);
2371 p
->mStartSecond
= tv
.tv_sec
;
2374 if (JS_IsConstructing(cx
, vp
)) {
2375 obj
= JS_NewObject(cx
, ðogram_class
, NULL
, NULL
);
2379 obj
= JS_THIS_OBJECT(cx
, vp
);
2382 jsval filenames
= OBJECT_TO_JSVAL(p
->filenames());
2383 if (!JS_DefineProperty(cx
, obj
, "filenames", filenames
,
2384 NULL
, NULL
, JSPROP_READONLY
|JSPROP_PERMANENT
))
2387 JS_SET_RVAL(cx
, vp
, OBJECT_TO_JSVAL(obj
));
2388 JS_SetPrivate(cx
, obj
, p
);
2393 ethogram_finalize(JSContext
*cx
, JSObject
*obj
)
2395 EthogramEventBuffer
*p
;
2396 p
= (EthogramEventBuffer
*) JS_GetInstancePrivate(cx
, obj
, ðogram_class
, NULL
);
2400 p
->removeScripts(cx
);
2406 ethogram_addScript(JSContext
*cx
, uintN argc
, jsval
*vp
)
2409 char *filename
= NULL
;
2410 jsval
*argv
= JS_ARGV(cx
, vp
);
2411 JSObject
*obj
= JS_THIS_OBJECT(cx
, vp
);
2415 /* silently ignore no args */
2416 JS_SET_RVAL(cx
, vp
, JSVAL_VOID
);
2419 if (JSVAL_IS_STRING(argv
[0])) {
2420 str
= JSVAL_TO_STRING(argv
[0]);
2421 filename
= js_DeflateString(cx
, str
->chars(), str
->length());
2426 EthogramEventBuffer
*p
= (EthogramEventBuffer
*) JS_GetInstancePrivate(cx
, obj
, ðogram_class
, argv
);
2428 p
->addScript(cx
, obj
, filename
, str
);
2429 JS_SET_RVAL(cx
, vp
, JSVAL_VOID
);
2431 JS_CallFunctionName(cx
, p
->filenames(), "push", 1, argv
, &dummy
);
2436 ethogram_getAllEvents(JSContext
*cx
, uintN argc
, jsval
*vp
)
2438 EthogramEventBuffer
*p
;
2439 jsval
*argv
= JS_ARGV(cx
, vp
);
2441 JSObject
*obj
= JS_THIS_OBJECT(cx
, vp
);
2445 p
= (EthogramEventBuffer
*) JS_GetInstancePrivate(cx
, obj
, ðogram_class
, argv
);
2450 JS_SET_RVAL(cx
, vp
, JSVAL_NULL
);
2454 JSObject
*rarray
= JS_NewArrayObject(cx
, 0, NULL
);
2455 if (rarray
== NULL
) {
2456 JS_SET_RVAL(cx
, vp
, JSVAL_NULL
);
2460 JS_SET_RVAL(cx
, vp
, OBJECT_TO_JSVAL(rarray
));
2462 for (int i
= 0; !p
->isEmpty(); i
++) {
2464 JSObject
*x
= JS_NewObject(cx
, NULL
, NULL
, NULL
);
2468 EthogramEvent
*e
= p
->pop();
2470 jsval state
= INT_TO_JSVAL(e
->s
);
2471 jsval reason
= INT_TO_JSVAL(e
->r
);
2472 jsval ts
= INT_TO_JSVAL(e
->ts
);
2473 jsval tus
= INT_TO_JSVAL(e
->tus
);
2475 jsval filename
= STRING_TO_JSVAL(e
->filename
);
2476 jsval lineno
= INT_TO_JSVAL(e
->lineno
);
2478 if (!JS_SetProperty(cx
, x
, "state", &state
))
2480 if (!JS_SetProperty(cx
, x
, "reason", &reason
))
2482 if (!JS_SetProperty(cx
, x
, "ts", &ts
))
2484 if (!JS_SetProperty(cx
, x
, "tus", &tus
))
2487 if (!JS_SetProperty(cx
, x
, "filename", &filename
))
2489 if (!JS_SetProperty(cx
, x
, "lineno", &lineno
))
2492 jsval element
= OBJECT_TO_JSVAL(x
);
2493 JS_SetElement(cx
, rarray
, i
, &element
);
2500 ethogram_getNextEvent(JSContext
*cx
, uintN argc
, jsval
*vp
)
2502 EthogramEventBuffer
*p
;
2503 jsval
*argv
= JS_ARGV(cx
, vp
);
2505 JSObject
*obj
= JS_THIS_OBJECT(cx
, vp
);
2509 p
= (EthogramEventBuffer
*) JS_GetInstancePrivate(cx
, obj
, ðogram_class
, argv
);
2513 JSObject
*x
= JS_NewObject(cx
, NULL
, NULL
, NULL
);
2518 JS_SET_RVAL(cx
, vp
, JSVAL_NULL
);
2522 EthogramEvent
*e
= p
->pop();
2523 jsval state
= INT_TO_JSVAL(e
->s
);
2524 jsval reason
= INT_TO_JSVAL(e
->r
);
2525 jsval ts
= INT_TO_JSVAL(e
->ts
);
2526 jsval tus
= INT_TO_JSVAL(e
->tus
);
2528 jsval filename
= STRING_TO_JSVAL(e
->filename
);
2529 jsval lineno
= INT_TO_JSVAL(e
->lineno
);
2531 if (!JS_SetProperty(cx
, x
, "state", &state
))
2533 if (!JS_SetProperty(cx
, x
, "reason", &reason
))
2535 if (!JS_SetProperty(cx
, x
, "ts", &ts
))
2537 if (!JS_SetProperty(cx
, x
, "tus", &tus
))
2539 if (!JS_SetProperty(cx
, x
, "filename", &filename
))
2542 if (!JS_SetProperty(cx
, x
, "lineno", &lineno
))
2545 JS_SET_RVAL(cx
, vp
, OBJECT_TO_JSVAL(x
));
2550 static JSFunctionSpec ethogram_methods
[] = {
2551 JS_FN("addScript", ethogram_addScript
, 1,0),
2552 JS_FN("getAllEvents", ethogram_getAllEvents
, 0,0),
2553 JS_FN("getNextEvent", ethogram_getNextEvent
, 0,0),
2558 * An |Ethogram| organizes the output of a collection of files that should be
2559 * monitored together. A single object gets events for the group.
2561 JS_FRIEND_API(JSBool
)
2562 js_InitEthogram(JSContext
*cx
, uintN argc
, jsval
*vp
)
2564 if (!traceVisScriptTable
) {
2565 traceVisScriptTable
= JS_NewHashTable(8, JS_HashString
, compare_strings
,
2569 JS_InitClass(cx
, JS_GetGlobalObject(cx
), NULL
, ðogram_class
,
2570 ethogram_construct
, 0, NULL
, ethogram_methods
,
2573 JS_SET_RVAL(cx
, vp
, JSVAL_VOID
);
2577 JS_FRIEND_API(JSBool
)
2578 js_ShutdownEthogram(JSContext
*cx
, uintN argc
, jsval
*vp
)
2580 if (traceVisScriptTable
)
2581 JS_HashTableDestroy(traceVisScriptTable
);
2583 JS_SET_RVAL(cx
, vp
, JSVAL_VOID
);
2587 #endif /* MOZ_TRACEVIS */