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 ***** */
50 #include "jshashtable.h"
53 #include "jsversion.h"
65 #include "jsstaticcheck.h"
67 #include "jswrapper.h"
69 #include "jsatominlines.h"
70 #include "jsdbgapiinlines.h"
71 #include "jsinterpinlines.h"
72 #include "jsobjinlines.h"
73 #include "jsscopeinlines.h"
74 #include "jsscriptinlines.h"
76 #include "jsautooplen.h"
78 #include "methodjit/MethodJIT.h"
79 #include "methodjit/Retcon.h"
82 using namespace js::gc
;
84 typedef struct JSTrap
{
89 JSTrapHandler handler
;
93 #define DBG_LOCK(rt) JS_ACQUIRE_LOCK((rt)->debuggerLock)
94 #define DBG_UNLOCK(rt) JS_RELEASE_LOCK((rt)->debuggerLock)
95 #define DBG_LOCK_EVAL(rt,expr) (DBG_LOCK(rt), (expr), DBG_UNLOCK(rt))
98 JS_GetDebugMode(JSContext
*cx
)
100 return cx
->compartment
->debugMode
;
103 JS_PUBLIC_API(JSBool
)
104 JS_SetDebugMode(JSContext
*cx
, JSBool debug
)
106 return JS_SetDebugModeForCompartment(cx
, cx
->compartment
, debug
);
110 JS_SetRuntimeDebugMode(JSRuntime
*rt
, JSBool debug
)
112 rt
->debugMode
= debug
;
117 CompartmentHasLiveScripts(JSCompartment
*comp
)
120 # ifdef JS_THREADSAFE
121 jsword currentThreadId
= reinterpret_cast<jsword
>(js_CurrentThreadId());
125 // Unsynchronized context iteration is technically a race; but this is only
126 // for debug asserts where such a race would be rare
127 JSContext
*iter
= NULL
;
129 while ((icx
= JS_ContextIterator(comp
->rt
, &iter
))) {
131 if (JS_GetContextThread(icx
) != currentThreadId
)
134 for (AllFramesIter
i(icx
); !i
.done(); ++i
) {
135 JSScript
*script
= i
.fp()->maybeScript();
136 if (script
&& script
->compartment
== comp
)
145 JS_FRIEND_API(JSBool
)
146 JS_SetDebugModeForCompartment(JSContext
*cx
, JSCompartment
*comp
, JSBool debug
)
148 if (comp
->debugMode
== debug
)
151 // This should only be called when no scripts are live. It would even be
152 // incorrect to discard just the non-live scripts' JITScripts because they
153 // might share ICs with live scripts (bug 632343).
154 JS_ASSERT(!CompartmentHasLiveScripts(comp
));
156 // All scripts compiled from this point on should be in the requested debugMode.
157 comp
->debugMode
= debug
;
159 // Discard JIT code for any scripts that change debugMode. This function
160 // assumes that 'comp' is in the same thread as 'cx'.
163 JSAutoEnterCompartment ac
;
165 for (JSScript
*script
= (JSScript
*)comp
->scripts
.next
;
166 &script
->links
!= &comp
->scripts
;
167 script
= (JSScript
*)script
->links
.next
)
169 if (!script
->debugMode
== !debug
)
173 * If compartment entry fails, debug mode is left partially on, leading
174 * to a small performance overhead but no loss of correctness. We set
175 * the debug flags to false so that the caller will not later attempt
176 * to use debugging features.
178 if (!ac
.entered() && !ac
.enter(cx
, script
)) {
179 comp
->debugMode
= JS_FALSE
;
183 mjit::ReleaseScriptCode(cx
, script
);
184 script
->debugMode
= !!debug
;
191 JS_FRIEND_API(JSBool
)
192 js_SetSingleStepMode(JSContext
*cx
, JSScript
*script
, JSBool singleStep
)
195 if (!script
->singleStepMode
== !singleStep
)
199 JS_ASSERT_IF(singleStep
, cx
->compartment
->debugMode
);
202 /* request the next recompile to inject single step interrupts */
203 script
->singleStepMode
= !!singleStep
;
205 js::mjit::JITScript
*jit
= script
->jitNormal
? script
->jitNormal
: script
->jitCtor
;
206 if (jit
&& script
->singleStepMode
!= jit
->singleStepMode
) {
207 js::mjit::Recompiler
recompiler(cx
, script
);
208 if (!recompiler
.recompile()) {
209 script
->singleStepMode
= !singleStep
;
218 CheckDebugMode(JSContext
*cx
)
220 JSBool debugMode
= JS_GetDebugMode(cx
);
223 * This probably should be an assertion, since it's indicative of a severe
227 JS_ReportErrorFlagsAndNumber(cx
, JSREPORT_ERROR
, js_GetErrorMessage
,
228 NULL
, JSMSG_NEED_DEBUG_MODE
);
233 JS_PUBLIC_API(JSBool
)
234 JS_SetSingleStepMode(JSContext
*cx
, JSScript
*script
, JSBool singleStep
)
236 if (!CheckDebugMode(cx
))
239 return js_SetSingleStepMode(cx
, script
, singleStep
);
243 * NB: FindTrap must be called with rt->debuggerLock acquired.
246 FindTrap(JSRuntime
*rt
, JSScript
*script
, jsbytecode
*pc
)
250 for (trap
= (JSTrap
*)rt
->trapList
.next
;
251 &trap
->links
!= &rt
->trapList
;
252 trap
= (JSTrap
*)trap
->links
.next
) {
253 if (trap
->script
== script
&& trap
->pc
== pc
)
260 js_UntrapScriptCode(JSContext
*cx
, JSScript
*script
)
269 for (trap
= (JSTrap
*)rt
->trapList
.next
;
272 trap
= (JSTrap
*)trap
->links
.next
) {
273 if (trap
->script
== script
&&
274 (size_t)(trap
->pc
- script
->code
) < script
->length
) {
275 if (code
== script
->code
) {
276 jssrcnote
*sn
, *notes
;
279 nbytes
= script
->length
* sizeof(jsbytecode
);
280 notes
= script
->notes();
281 for (sn
= notes
; !SN_IS_TERMINATOR(sn
); sn
= SN_NEXT(sn
))
283 nbytes
+= (sn
- notes
+ 1) * sizeof *sn
;
285 code
= (jsbytecode
*) cx
->malloc(nbytes
);
288 memcpy(code
, script
->code
, nbytes
);
289 JS_PURGE_GSN_CACHE(cx
);
291 code
[trap
->pc
- script
->code
] = trap
->op
;
298 JS_PUBLIC_API(JSBool
)
299 JS_SetTrap(JSContext
*cx
, JSScript
*script
, jsbytecode
*pc
,
300 JSTrapHandler handler
, jsval closure
)
302 JSTrap
*junk
, *trap
, *twin
;
306 if (!CheckDebugMode(cx
))
309 JS_ASSERT((JSOp
) *pc
!= JSOP_TRAP
);
313 trap
= FindTrap(rt
, script
, pc
);
315 JS_ASSERT(trap
->script
== script
&& trap
->pc
== pc
);
316 JS_ASSERT(*pc
== JSOP_TRAP
);
318 sample
= rt
->debuggerMutations
;
320 trap
= (JSTrap
*) cx
->malloc(sizeof *trap
);
323 trap
->closure
= JSVAL_NULL
;
325 twin
= (rt
->debuggerMutations
!= sample
)
326 ? FindTrap(rt
, script
, pc
)
332 JS_APPEND_LINK(&trap
->links
, &rt
->trapList
);
333 ++rt
->debuggerMutations
;
334 trap
->script
= script
;
336 trap
->op
= (JSOp
)*pc
;
340 trap
->handler
= handler
;
341 trap
->closure
= closure
;
347 if (script
->hasJITCode()) {
348 js::mjit::Recompiler
recompiler(cx
, script
);
349 if (!recompiler
.recompile())
358 JS_GetTrapOpcode(JSContext
*cx
, JSScript
*script
, jsbytecode
*pc
)
366 trap
= FindTrap(rt
, script
, pc
);
367 op
= trap
? trap
->op
: (JSOp
) *pc
;
373 DestroyTrapAndUnlock(JSContext
*cx
, JSTrap
*trap
)
375 ++cx
->runtime
->debuggerMutations
;
376 JS_REMOVE_LINK(&trap
->links
);
377 *trap
->pc
= (jsbytecode
)trap
->op
;
378 DBG_UNLOCK(cx
->runtime
);
383 JS_ClearTrap(JSContext
*cx
, JSScript
*script
, jsbytecode
*pc
,
384 JSTrapHandler
*handlerp
, jsval
*closurep
)
388 DBG_LOCK(cx
->runtime
);
389 trap
= FindTrap(cx
->runtime
, script
, pc
);
391 *handlerp
= trap
? trap
->handler
: NULL
;
393 *closurep
= trap
? trap
->closure
: JSVAL_NULL
;
395 DestroyTrapAndUnlock(cx
, trap
);
397 DBG_UNLOCK(cx
->runtime
);
400 if (script
->hasJITCode()) {
401 mjit::Recompiler
recompiler(cx
, script
);
402 recompiler
.recompile();
408 JS_ClearScriptTraps(JSContext
*cx
, JSScript
*script
)
416 for (trap
= (JSTrap
*)rt
->trapList
.next
;
417 &trap
->links
!= &rt
->trapList
;
419 next
= (JSTrap
*)trap
->links
.next
;
420 if (trap
->script
== script
) {
421 sample
= rt
->debuggerMutations
;
422 DestroyTrapAndUnlock(cx
, trap
);
424 if (rt
->debuggerMutations
!= sample
+ 1)
425 next
= (JSTrap
*)rt
->trapList
.next
;
432 JS_ClearAllTraps(JSContext
*cx
)
440 for (trap
= (JSTrap
*)rt
->trapList
.next
;
441 &trap
->links
!= &rt
->trapList
;
443 next
= (JSTrap
*)trap
->links
.next
;
444 sample
= rt
->debuggerMutations
;
445 DestroyTrapAndUnlock(cx
, trap
);
447 if (rt
->debuggerMutations
!= sample
+ 1)
448 next
= (JSTrap
*)rt
->trapList
.next
;
454 * NB: js_MarkTraps does not acquire cx->runtime->debuggerLock, since the
455 * debugger should never be racing with the GC (i.e., the debugger must
456 * respect the request model).
459 js_MarkTraps(JSTracer
*trc
)
461 JSRuntime
*rt
= trc
->context
->runtime
;
463 for (JSTrap
*trap
= (JSTrap
*) rt
->trapList
.next
;
464 &trap
->links
!= &rt
->trapList
;
465 trap
= (JSTrap
*) trap
->links
.next
) {
466 MarkValue(trc
, Valueify(trap
->closure
), "trap->closure");
470 JS_PUBLIC_API(JSTrapStatus
)
471 JS_HandleTrap(JSContext
*cx
, JSScript
*script
, jsbytecode
*pc
, jsval
*rval
)
477 DBG_LOCK(cx
->runtime
);
478 trap
= FindTrap(cx
->runtime
, script
, pc
);
479 JS_ASSERT(!trap
|| trap
->handler
);
482 DBG_UNLOCK(cx
->runtime
);
484 /* Defend against "pc for wrong script" API usage error. */
485 JS_ASSERT(op
!= JSOP_TRAP
);
488 /* If the API was abused, we must fail for want of the real op. */
492 /* Assume a race with a debugger thread and try to carry on. */
493 *rval
= INT_TO_JSVAL(op
);
494 return JSTRAP_CONTINUE
;
496 /* Always fail if single-threaded (must be an API usage error). */
500 DBG_UNLOCK(cx
->runtime
);
503 * It's important that we not use 'trap->' after calling the callback --
504 * the callback might remove the trap!
506 op
= (jsint
)trap
->op
;
507 status
= trap
->handler(cx
, script
, pc
, rval
, trap
->closure
);
508 if (status
== JSTRAP_CONTINUE
) {
509 /* By convention, return the true op to the interpreter in rval. */
510 *rval
= INT_TO_JSVAL(op
);
517 JITInhibitingHookChange(JSRuntime
*rt
, bool wasInhibited
)
520 if (!rt
->debuggerInhibitsJIT()) {
521 for (JSCList
*cl
= rt
->contextList
.next
; cl
!= &rt
->contextList
; cl
= cl
->next
)
522 js_ContextFromLinkField(cl
)->updateJITEnabled();
524 } else if (rt
->debuggerInhibitsJIT()) {
525 for (JSCList
*cl
= rt
->contextList
.next
; cl
!= &rt
->contextList
; cl
= cl
->next
)
526 js_ContextFromLinkField(cl
)->traceJitEnabled
= false;
531 JS_PUBLIC_API(JSBool
)
532 JS_SetInterrupt(JSRuntime
*rt
, JSInterruptHook hook
, void *closure
)
537 bool wasInhibited
= rt
->debuggerInhibitsJIT();
539 rt
->globalDebugHooks
.interruptHook
= hook
;
540 rt
->globalDebugHooks
.interruptHookData
= closure
;
542 JITInhibitingHookChange(rt
, wasInhibited
);
548 JS_PUBLIC_API(JSBool
)
549 JS_ClearInterrupt(JSRuntime
*rt
, JSInterruptHook
*hoop
, void **closurep
)
553 bool wasInhibited
= rt
->debuggerInhibitsJIT();
556 *hoop
= rt
->globalDebugHooks
.interruptHook
;
558 *closurep
= rt
->globalDebugHooks
.interruptHookData
;
559 rt
->globalDebugHooks
.interruptHook
= 0;
560 rt
->globalDebugHooks
.interruptHookData
= 0;
562 JITInhibitingHookChange(rt
, wasInhibited
);
567 /************************************************************************/
569 struct JSWatchPoint
{
571 JSObject
*object
; /* weak link, see js_SweepWatchPoints */
573 StrictPropertyOp setter
;
574 JSWatchPointHandler handler
;
579 #define JSWP_LIVE 0x1 /* live because set and not cleared */
580 #define JSWP_HELD 0x2 /* held while running handler/setter */
583 * NB: DropWatchPointAndUnlock releases cx->runtime->debuggerLock in all cases.
586 DropWatchPointAndUnlock(JSContext
*cx
, JSWatchPoint
*wp
, uintN flag
)
589 JSRuntime
*rt
= cx
->runtime
;
592 if (wp
->flags
!= 0) {
598 * Switch to the same compartment as the watch point, since changeProperty, below,
599 * needs to have a compartment.
601 SwitchToCompartment
sc(cx
, wp
->object
);
603 /* Remove wp from the list, then restore wp->shape->setter from wp. */
604 ++rt
->debuggerMutations
;
605 JS_REMOVE_LINK(&wp
->links
);
609 * If the property isn't found on wp->object, then someone else must have deleted it,
610 * and we don't need to change the property attributes.
612 const Shape
*shape
= wp
->shape
;
613 const Shape
*wprop
= wp
->object
->nativeLookup(shape
->id
);
615 wprop
->hasSetterValue() == shape
->hasSetterValue() &&
616 IsWatchedProperty(cx
, wprop
)) {
617 shape
= wp
->object
->changeProperty(cx
, wprop
, 0, wprop
->attributes(),
618 wprop
->getter(), wp
->setter
);
628 * NB: js_TraceWatchPoints does not acquire cx->runtime->debuggerLock, since
629 * the debugger should never be racing with the GC (i.e., the debugger must
630 * respect the request model).
633 js_TraceWatchPoints(JSTracer
*trc
, JSObject
*obj
)
638 rt
= trc
->context
->runtime
;
640 for (wp
= (JSWatchPoint
*)rt
->watchPointList
.next
;
641 &wp
->links
!= &rt
->watchPointList
;
642 wp
= (JSWatchPoint
*)wp
->links
.next
) {
643 if (wp
->object
== obj
) {
644 wp
->shape
->trace(trc
);
645 if (wp
->shape
->hasSetterValue() && wp
->setter
)
646 MarkObject(trc
, *CastAsObject(wp
->setter
), "wp->setter");
647 MarkObject(trc
, *wp
->closure
, "wp->closure");
653 js_SweepWatchPoints(JSContext
*cx
)
656 JSWatchPoint
*wp
, *next
;
661 for (wp
= (JSWatchPoint
*)rt
->watchPointList
.next
;
662 &wp
->links
!= &rt
->watchPointList
;
664 next
= (JSWatchPoint
*)wp
->links
.next
;
665 if (IsAboutToBeFinalized(cx
, wp
->object
)) {
666 sample
= rt
->debuggerMutations
;
668 /* Ignore failures. */
669 DropWatchPointAndUnlock(cx
, wp
, JSWP_LIVE
);
671 if (rt
->debuggerMutations
!= sample
+ 1)
672 next
= (JSWatchPoint
*)rt
->watchPointList
.next
;
681 * NB: LockedFindWatchPoint must be called with rt->debuggerLock acquired.
683 static JSWatchPoint
*
684 LockedFindWatchPoint(JSRuntime
*rt
, JSObject
*obj
, jsid id
)
688 for (wp
= (JSWatchPoint
*)rt
->watchPointList
.next
;
689 &wp
->links
!= &rt
->watchPointList
;
690 wp
= (JSWatchPoint
*)wp
->links
.next
) {
691 if (wp
->object
== obj
&& wp
->shape
->id
== id
)
697 static JSWatchPoint
*
698 FindWatchPoint(JSRuntime
*rt
, JSObject
*obj
, jsid id
)
703 wp
= LockedFindWatchPoint(rt
, obj
, id
);
709 js_watch_set(JSContext
*cx
, JSObject
*obj
, jsid id
, JSBool strict
, Value
*vp
)
711 JSRuntime
*rt
= cx
->runtime
;
713 for (JSWatchPoint
*wp
= (JSWatchPoint
*)rt
->watchPointList
.next
;
714 &wp
->links
!= &rt
->watchPointList
;
715 wp
= (JSWatchPoint
*)wp
->links
.next
) {
716 const Shape
*shape
= wp
->shape
;
717 if (wp
->object
== obj
&& SHAPE_USERID(shape
) == id
&& !(wp
->flags
& JSWP_HELD
)) {
718 wp
->flags
|= JSWP_HELD
;
721 jsid propid
= shape
->id
;
722 shape
= obj
->nativeLookup(propid
);
723 JS_ASSERT(IsWatchedProperty(cx
, shape
));
724 jsid userid
= SHAPE_USERID(shape
);
726 /* Determine the property's old value. */
728 uint32 slot
= shape
->slot
;
729 Value old
= obj
->containsSlot(slot
) ? obj
->nativeGetSlot(slot
) : UndefinedValue();
730 const Shape
*needMethodSlotWrite
= NULL
;
731 if (shape
->isMethod()) {
733 * We get here in two cases: (1) the existing watched property
734 * is a method; or (2) the watched property was deleted and is
735 * now in the middle of being re-added via JSOP_SETMETHOD. In
736 * both cases we must trip the method read barrier in order to
737 * avoid passing an uncloned function object to the handler.
739 * Case 2 is especially hairy. js_watch_set, uniquely, gets
740 * called in the middle of creating a method property, after
741 * shape is in obj but before the slot has been set. So in this
742 * case we must finish initializing the half-finished method
743 * property before triggering the method read barrier.
745 * Bonus weirdness: because this changes obj's shape,
746 * js_NativeSet (which is our caller) will not write to the
747 * slot, as it will appear the property was deleted and a new
748 * property added. We must write the slot ourselves -- however
749 * we must do it after calling the watchpoint handler. So set
750 * needMethodSlotWrite here and use it to write to the slot
751 * below, if the handler does not tinker with the property
754 JS_ASSERT(!wp
->setter
);
755 Value method
= ObjectValue(shape
->methodObject());
756 if (old
.isUndefined())
757 obj
->nativeSetSlot(slot
, method
);
758 ok
= obj
->methodReadBarrier(cx
, *shape
, &method
);
761 wp
->shape
= shape
= needMethodSlotWrite
= obj
->nativeLookup(propid
);
762 JS_ASSERT(shape
->isDataDescriptor());
763 JS_ASSERT(!shape
->isMethod());
764 if (old
.isUndefined())
765 obj
->nativeSetSlot(shape
->slot
, old
);
771 Conditionally
<AutoShapeRooter
> tvr(needMethodSlotWrite
, cx
, needMethodSlotWrite
);
774 * Call the handler. This invalidates shape, so re-lookup the shape.
775 * NB: wp is held, so we can safely dereference it still.
777 ok
= wp
->handler(cx
, obj
, propid
, Jsvalify(old
), Jsvalify(vp
), wp
->closure
);
780 shape
= obj
->nativeLookup(propid
);
781 JS_ASSERT_IF(!shape
, !wp
->setter
);
785 } else if (wp
->setter
) {
787 * Pass the output of the handler to the setter. Security wrappers
788 * prevent any funny business between watchpoints and setters.
790 ok
= shape
->hasSetterValue()
791 ? ExternalInvoke(cx
, ObjectValue(*obj
),
792 ObjectValue(*CastAsObject(wp
->setter
)),
794 : CallJSPropertyOpSetter(cx
, wp
->setter
, obj
, userid
, strict
, vp
);
795 } else if (shape
== needMethodSlotWrite
) {
796 /* See comment above about needMethodSlotWrite. */
797 obj
->nativeSetSlot(shape
->slot
, *vp
);
801 * A property with the default setter might be either a method
802 * or an ordinary function-valued data property subject to the
803 * method write barrier.
805 * It is not the setter's job to call methodWriteBarrier,
806 * but js_watch_set must do so, because the caller will be
807 * fooled into not doing it: shape does *not* have the
808 * default setter and therefore seems not to be a method.
810 ok
= obj
->methodWriteBarrier(cx
, *shape
, *vp
) != NULL
;
816 return DropWatchPointAndUnlock(cx
, wp
, JSWP_HELD
) && ok
;
824 js_watch_set_wrapper(JSContext
*cx
, uintN argc
, Value
*vp
)
826 JSObject
*obj
= ToObject(cx
, &vp
[1]);
830 JSObject
&funobj
= JS_CALLEE(cx
, vp
).toObject();
831 JSFunction
*wrapper
= funobj
.getFunctionPrivate();
832 jsid userid
= ATOM_TO_JSID(wrapper
->atom
);
834 JS_SET_RVAL(cx
, vp
, argc
? JS_ARGV(cx
, vp
)[0] : UndefinedValue());
836 * The strictness we pass here doesn't matter, since we know that it's
837 * a JS setter, which can't depend on the assigning code's strictness.
839 return js_watch_set(cx
, obj
, userid
, false, vp
);
845 IsWatchedProperty(JSContext
*cx
, const Shape
*shape
)
847 if (shape
->hasSetterValue()) {
848 JSObject
*funobj
= shape
->setterObject();
849 if (!funobj
|| !funobj
->isFunction())
852 JSFunction
*fun
= funobj
->getFunctionPrivate();
853 return fun
->maybeNative() == js_watch_set_wrapper
;
855 return shape
->setterOp() == js_watch_set
;
861 * Return an appropriate setter to substitute for |setter| on a property
862 * with attributes |attrs|, to implement a watchpoint on the property named
865 static StrictPropertyOp
866 WrapWatchedSetter(JSContext
*cx
, jsid id
, uintN attrs
, StrictPropertyOp setter
)
871 /* Wrap a C++ setter simply by returning our own C++ setter. */
872 if (!(attrs
& JSPROP_SETTER
))
873 return &js_watch_set
; /* & to silence schoolmarmish MSVC */
876 * Wrap a JSObject * setter by constructing our own JSFunction * that saves the
877 * property id as the function name, and calls js_watch_set.
879 if (JSID_IS_ATOM(id
)) {
880 atom
= JSID_TO_ATOM(id
);
881 } else if (JSID_IS_INT(id
)) {
882 if (!js_ValueToStringId(cx
, IdToValue(id
), &id
))
884 atom
= JSID_TO_ATOM(id
);
889 wrapper
= js_NewFunction(cx
, NULL
, js_watch_set_wrapper
, 1, 0,
890 setter
? CastAsObject(setter
)->getParent() : NULL
, atom
);
893 return CastAsStrictPropertyOp(FUN_OBJECT(wrapper
));
897 UpdateWatchpointShape(JSContext
*cx
, JSWatchPoint
*wp
, const Shape
*newShape
)
899 JS_ASSERT_IF(wp
->shape
, wp
->shape
->id
== newShape
->id
);
900 JS_ASSERT(!IsWatchedProperty(cx
, newShape
));
902 /* Create a watching setter we can substitute for the new shape's setter. */
903 StrictPropertyOp watchingSetter
=
904 WrapWatchedSetter(cx
, newShape
->id
, newShape
->attributes(), newShape
->setter());
909 * Save the shape's setter; we don't know whether js_ChangeNativePropertyAttrs will
910 * return a new shape, or mutate this one.
912 StrictPropertyOp originalSetter
= newShape
->setter();
915 * Drop the watching setter into the object, in place of newShape. Note that a single
916 * watchpoint-wrapped shape may correspond to more than one non-watchpoint shape: we
917 * wrap all (JSPropertyOp, not JSObject *) setters with js_watch_set, so shapes that
918 * differ only in their setter may all get wrapped to the same shape.
920 const Shape
*watchingShape
=
921 js_ChangeNativePropertyAttrs(cx
, wp
->object
, newShape
, 0, newShape
->attributes(),
922 newShape
->getter(), watchingSetter
);
926 /* Update the watchpoint with the new shape and its original setter. */
927 wp
->setter
= originalSetter
;
928 wp
->shape
= watchingShape
;
930 return watchingShape
;
934 js_SlowPathUpdateWatchpointsForShape(JSContext
*cx
, JSObject
*obj
, const Shape
*newShape
)
937 * The watchpoint code uses the normal property-modification functions to install its
938 * own watchpoint-aware shapes. Those functions report those changes back to the
939 * watchpoint code, just as they do user-level changes. So if this change is
940 * installing a watchpoint-aware shape, it's something we asked for ourselves, and can
941 * proceed without interference.
943 if (IsWatchedProperty(cx
, newShape
))
946 JSWatchPoint
*wp
= FindWatchPoint(cx
->runtime
, obj
, newShape
->id
);
950 return UpdateWatchpointShape(cx
, wp
, newShape
);
954 * Return the underlying setter for |shape| on |obj|, seeing through any
955 * watchpoint-wrapping. Note that we need |obj| to disambiguate, since a single
956 * watchpoint-wrapped shape may correspond to more than one non-watchpoint shape; see the
957 * comments in UpdateWatchpointShape.
959 static StrictPropertyOp
960 UnwrapSetter(JSContext
*cx
, JSObject
*obj
, const Shape
*shape
)
962 /* If it's not a watched property, its setter is not wrapped. */
963 if (!IsWatchedProperty(cx
, shape
))
964 return shape
->setter();
966 /* Look up the watchpoint, from which we can retrieve the underlying setter. */
967 JSWatchPoint
*wp
= FindWatchPoint(cx
->runtime
, obj
, shape
->id
);
970 * Since we know |shape| is watched, we *must* find a watchpoint: we should never
971 * leave wrapped setters lying around in shapes after removing a watchpoint.
978 JS_PUBLIC_API(JSBool
)
979 JS_SetWatchPoint(JSContext
*cx
, JSObject
*obj
, jsid id
,
980 JSWatchPointHandler handler
, JSObject
*closure
)
988 OBJ_TO_INNER_OBJECT(cx
, obj
);
992 AutoValueRooter
idroot(cx
);
993 if (JSID_IS_INT(id
)) {
996 if (!js_ValueToStringId(cx
, IdToValue(id
), &propid
))
998 propid
= js_CheckForStringIndex(propid
);
999 idroot
.set(IdToValue(propid
));
1003 * If, by unwrapping and innerizing, we changed the object, check
1004 * again to make sure that we're allowed to set a watch point.
1006 if (origobj
!= obj
&& !CheckAccess(cx
, obj
, propid
, JSACC_WATCH
, &v
, &attrs
))
1009 if (!obj
->isNative()) {
1010 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
, JSMSG_CANT_WATCH
,
1011 obj
->getClass()->name
);
1017 if (!js_LookupProperty(cx
, obj
, propid
, &pobj
, &prop
))
1019 const Shape
*shape
= (Shape
*) prop
;
1020 JSRuntime
*rt
= cx
->runtime
;
1022 /* Check for a deleted symbol watchpoint, which holds its property. */
1023 JSWatchPoint
*wp
= FindWatchPoint(rt
, obj
, propid
);
1025 /* Make a new property in obj so we can watch for the first set. */
1026 if (!js_DefineNativeProperty(cx
, obj
, propid
, UndefinedValue(), NULL
, NULL
,
1027 JSPROP_ENUMERATE
, 0, 0, &prop
)) {
1030 shape
= (Shape
*) prop
;
1032 } else if (pobj
!= obj
) {
1033 /* Clone the prototype property so we can watch the right object. */
1034 AutoValueRooter
valroot(cx
);
1036 StrictPropertyOp setter
;
1040 if (pobj
->isNative()) {
1041 valroot
.set(pobj
->containsSlot(shape
->slot
)
1042 ? pobj
->nativeGetSlot(shape
->slot
)
1043 : UndefinedValue());
1044 getter
= shape
->getter();
1045 setter
= UnwrapSetter(cx
, pobj
, shape
);
1046 attrs
= shape
->attributes();
1047 flags
= shape
->getFlags();
1048 shortid
= shape
->shortid
;
1050 if (!pobj
->getProperty(cx
, propid
, valroot
.addr()) ||
1051 !pobj
->getAttributes(cx
, propid
, &attrs
)) {
1060 /* Recall that obj is native, whether or not pobj is native. */
1061 if (!js_DefineNativeProperty(cx
, obj
, propid
, valroot
.value(),
1062 getter
, setter
, attrs
, flags
,
1066 shape
= (Shape
*) prop
;
1070 * At this point, prop/shape exists in obj, obj is locked, and we must
1071 * unlock the object before returning.
1074 JSWatchPoint
*wp
= LockedFindWatchPoint(rt
, obj
, propid
);
1077 wp
= (JSWatchPoint
*) cx
->malloc(sizeof *wp
);
1084 wp
->flags
= JSWP_LIVE
;
1086 /* XXXbe nest in obj lock here */
1087 if (!UpdateWatchpointShape(cx
, wp
, shape
)) {
1088 /* Self-link so DropWatchPointAndUnlock can JS_REMOVE_LINK it. */
1089 JS_INIT_CLIST(&wp
->links
);
1091 DropWatchPointAndUnlock(cx
, wp
, JSWP_LIVE
);
1096 * Now that wp is fully initialized, append it to rt's wp list.
1097 * Because obj is locked we know that no other thread could have added
1098 * a watchpoint for (obj, propid).
1101 JS_ASSERT(!LockedFindWatchPoint(rt
, obj
, propid
));
1102 JS_APPEND_LINK(&wp
->links
, &rt
->watchPointList
);
1103 ++rt
->debuggerMutations
;
1107 * Ensure that an object with watchpoints never has the same shape as an
1108 * object without them, even if the watched properties are deleted.
1110 obj
->watchpointOwnShapeChange(cx
);
1112 wp
->handler
= handler
;
1113 wp
->closure
= reinterpret_cast<JSObject
*>(closure
);
1118 JS_PUBLIC_API(JSBool
)
1119 JS_ClearWatchPoint(JSContext
*cx
, JSObject
*obj
, jsid id
,
1120 JSWatchPointHandler
*handlerp
, JSObject
**closurep
)
1127 for (wp
= (JSWatchPoint
*)rt
->watchPointList
.next
;
1128 &wp
->links
!= &rt
->watchPointList
;
1129 wp
= (JSWatchPoint
*)wp
->links
.next
) {
1130 if (wp
->object
== obj
&& SHAPE_USERID(wp
->shape
) == id
) {
1132 *handlerp
= wp
->handler
;
1134 *closurep
= wp
->closure
;
1135 return DropWatchPointAndUnlock(cx
, wp
, JSWP_LIVE
);
1146 JS_PUBLIC_API(JSBool
)
1147 JS_ClearWatchPointsForObject(JSContext
*cx
, JSObject
*obj
)
1150 JSWatchPoint
*wp
, *next
;
1155 for (wp
= (JSWatchPoint
*)rt
->watchPointList
.next
;
1156 &wp
->links
!= &rt
->watchPointList
;
1158 next
= (JSWatchPoint
*)wp
->links
.next
;
1159 if (wp
->object
== obj
) {
1160 sample
= rt
->debuggerMutations
;
1161 if (!DropWatchPointAndUnlock(cx
, wp
, JSWP_LIVE
))
1164 if (rt
->debuggerMutations
!= sample
+ 1)
1165 next
= (JSWatchPoint
*)rt
->watchPointList
.next
;
1172 JS_PUBLIC_API(JSBool
)
1173 JS_ClearAllWatchPoints(JSContext
*cx
)
1176 JSWatchPoint
*wp
, *next
;
1181 for (wp
= (JSWatchPoint
*)rt
->watchPointList
.next
;
1182 &wp
->links
!= &rt
->watchPointList
;
1184 next
= (JSWatchPoint
*)wp
->links
.next
;
1185 sample
= rt
->debuggerMutations
;
1186 if (!DropWatchPointAndUnlock(cx
, wp
, JSWP_LIVE
))
1189 if (rt
->debuggerMutations
!= sample
+ 1)
1190 next
= (JSWatchPoint
*)rt
->watchPointList
.next
;
1196 /************************************************************************/
1198 JS_PUBLIC_API(uintN
)
1199 JS_PCToLineNumber(JSContext
*cx
, JSScript
*script
, jsbytecode
*pc
)
1201 return js_PCToLineNumber(cx
, script
, pc
);
1204 JS_PUBLIC_API(jsbytecode
*)
1205 JS_LineNumberToPC(JSContext
*cx
, JSScript
*script
, uintN lineno
)
1207 return js_LineNumberToPC(script
, lineno
);
1210 JS_PUBLIC_API(jsbytecode
*)
1211 JS_EndPC(JSContext
*cx
, JSScript
*script
)
1213 return script
->code
+ script
->length
;
1216 JS_PUBLIC_API(uintN
)
1217 JS_GetFunctionArgumentCount(JSContext
*cx
, JSFunction
*fun
)
1222 JS_PUBLIC_API(JSBool
)
1223 JS_FunctionHasLocalNames(JSContext
*cx
, JSFunction
*fun
)
1225 return fun
->script()->bindings
.hasLocalNames();
1228 extern JS_PUBLIC_API(jsuword
*)
1229 JS_GetFunctionLocalNameArray(JSContext
*cx
, JSFunction
*fun
, void **markp
)
1231 *markp
= JS_ARENA_MARK(&cx
->tempPool
);
1232 return fun
->script()->bindings
.getLocalNameArray(cx
, &cx
->tempPool
);
1235 extern JS_PUBLIC_API(JSAtom
*)
1236 JS_LocalNameToAtom(jsuword w
)
1238 return JS_LOCAL_NAME_TO_ATOM(w
);
1241 extern JS_PUBLIC_API(JSString
*)
1242 JS_AtomKey(JSAtom
*atom
)
1244 return ATOM_TO_STRING(atom
);
1247 extern JS_PUBLIC_API(void)
1248 JS_ReleaseFunctionLocalNameArray(JSContext
*cx
, void *mark
)
1250 JS_ARENA_RELEASE(&cx
->tempPool
, mark
);
1253 JS_PUBLIC_API(JSScript
*)
1254 JS_GetFunctionScript(JSContext
*cx
, JSFunction
*fun
)
1256 return FUN_SCRIPT(fun
);
1259 JS_PUBLIC_API(JSNative
)
1260 JS_GetFunctionNative(JSContext
*cx
, JSFunction
*fun
)
1262 return Jsvalify(fun
->maybeNative());
1265 JS_PUBLIC_API(JSPrincipals
*)
1266 JS_GetScriptPrincipals(JSContext
*cx
, JSScript
*script
)
1268 return script
->principals
;
1271 /************************************************************************/
1274 * Stack Frame Iterator
1276 JS_PUBLIC_API(JSStackFrame
*)
1277 JS_FrameIterator(JSContext
*cx
, JSStackFrame
**iteratorp
)
1279 *iteratorp
= (*iteratorp
== NULL
) ? js_GetTopStackFrame(cx
) : (*iteratorp
)->prev();
1283 JS_PUBLIC_API(JSScript
*)
1284 JS_GetFrameScript(JSContext
*cx
, JSStackFrame
*fp
)
1286 return fp
->maybeScript();
1289 JS_PUBLIC_API(jsbytecode
*)
1290 JS_GetFramePC(JSContext
*cx
, JSStackFrame
*fp
)
1295 JS_PUBLIC_API(JSStackFrame
*)
1296 JS_GetScriptedCaller(JSContext
*cx
, JSStackFrame
*fp
)
1298 return js_GetScriptedCaller(cx
, fp
);
1302 js_StackFramePrincipals(JSContext
*cx
, JSStackFrame
*fp
)
1304 JSSecurityCallbacks
*callbacks
;
1306 if (fp
->isFunctionFrame()) {
1307 callbacks
= JS_GetSecurityCallbacks(cx
);
1308 if (callbacks
&& callbacks
->findObjectPrincipals
) {
1309 if (&fp
->fun()->compiledFunObj() != &fp
->callee())
1310 return callbacks
->findObjectPrincipals(cx
, &fp
->callee());
1314 if (fp
->isScriptFrame())
1315 return fp
->script()->principals
;
1320 js_EvalFramePrincipals(JSContext
*cx
, JSObject
*callee
, JSStackFrame
*caller
)
1322 JSPrincipals
*principals
, *callerPrincipals
;
1323 JSSecurityCallbacks
*callbacks
;
1325 callbacks
= JS_GetSecurityCallbacks(cx
);
1326 if (callbacks
&& callbacks
->findObjectPrincipals
)
1327 principals
= callbacks
->findObjectPrincipals(cx
, callee
);
1332 callerPrincipals
= js_StackFramePrincipals(cx
, caller
);
1333 return (callerPrincipals
&& principals
&&
1334 callerPrincipals
->subsume(callerPrincipals
, principals
))
1339 JS_PUBLIC_API(void *)
1340 JS_GetFrameAnnotation(JSContext
*cx
, JSStackFrame
*fp
)
1342 if (fp
->annotation() && fp
->isScriptFrame()) {
1343 JSPrincipals
*principals
= js_StackFramePrincipals(cx
, fp
);
1345 if (principals
&& principals
->globalPrivilegesEnabled(cx
, principals
)) {
1347 * Give out an annotation only if privileges have not been revoked
1348 * or disabled globally.
1350 return fp
->annotation();
1358 JS_SetFrameAnnotation(JSContext
*cx
, JSStackFrame
*fp
, void *annotation
)
1360 fp
->setAnnotation(annotation
);
1363 JS_PUBLIC_API(void *)
1364 JS_GetFramePrincipalArray(JSContext
*cx
, JSStackFrame
*fp
)
1366 JSPrincipals
*principals
;
1368 principals
= js_StackFramePrincipals(cx
, fp
);
1371 return principals
->getPrincipalArray(cx
, principals
);
1374 JS_PUBLIC_API(JSBool
)
1375 JS_IsScriptFrame(JSContext
*cx
, JSStackFrame
*fp
)
1377 return !fp
->isDummyFrame();
1380 /* this is deprecated, use JS_GetFrameScopeChain instead */
1381 JS_PUBLIC_API(JSObject
*)
1382 JS_GetFrameObject(JSContext
*cx
, JSStackFrame
*fp
)
1384 return &fp
->scopeChain();
1387 JS_PUBLIC_API(JSObject
*)
1388 JS_GetFrameScopeChain(JSContext
*cx
, JSStackFrame
*fp
)
1390 JS_ASSERT(cx
->stack().contains(fp
));
1392 js::AutoCompartment
ac(cx
, &fp
->scopeChain());
1396 /* Force creation of argument and call objects if not yet created */
1397 (void) JS_GetFrameCallObject(cx
, fp
);
1398 return GetScopeChain(cx
, fp
);
1401 JS_PUBLIC_API(JSObject
*)
1402 JS_GetFrameCallObject(JSContext
*cx
, JSStackFrame
*fp
)
1404 JS_ASSERT(cx
->stack().contains(fp
));
1406 if (!fp
->isFunctionFrame())
1409 js::AutoCompartment
ac(cx
, &fp
->scopeChain());
1413 /* Force creation of argument object if not yet created */
1414 (void) js_GetArgsObject(cx
, fp
);
1417 * XXX ill-defined: null return here means error was reported, unlike a
1418 * null returned above or in the #else
1420 return js_GetCallObject(cx
, fp
);
1423 JS_PUBLIC_API(JSBool
)
1424 JS_GetFrameThis(JSContext
*cx
, JSStackFrame
*fp
, jsval
*thisv
)
1426 if (fp
->isDummyFrame())
1429 js::AutoCompartment
ac(cx
, &fp
->scopeChain());
1433 if (!fp
->computeThis(cx
))
1435 *thisv
= Jsvalify(fp
->thisValue());
1439 JS_PUBLIC_API(JSFunction
*)
1440 JS_GetFrameFunction(JSContext
*cx
, JSStackFrame
*fp
)
1442 return fp
->maybeFun();
1445 JS_PUBLIC_API(JSObject
*)
1446 JS_GetFrameFunctionObject(JSContext
*cx
, JSStackFrame
*fp
)
1448 if (!fp
->isFunctionFrame())
1451 JS_ASSERT(fp
->callee().isFunction());
1452 JS_ASSERT(fp
->callee().getPrivate() == fp
->fun());
1453 return &fp
->callee();
1456 JS_PUBLIC_API(JSBool
)
1457 JS_IsConstructorFrame(JSContext
*cx
, JSStackFrame
*fp
)
1459 return fp
->isConstructing();
1462 JS_PUBLIC_API(JSObject
*)
1463 JS_GetFrameCalleeObject(JSContext
*cx
, JSStackFrame
*fp
)
1465 return fp
->maybeCallee();
1468 JS_PUBLIC_API(JSBool
)
1469 JS_GetValidFrameCalleeObject(JSContext
*cx
, JSStackFrame
*fp
, jsval
*vp
)
1473 if (!fp
->getValidCalleeObject(cx
, &v
))
1479 JS_PUBLIC_API(JSBool
)
1480 JS_IsDebuggerFrame(JSContext
*cx
, JSStackFrame
*fp
)
1482 return fp
->isDebuggerFrame();
1485 JS_PUBLIC_API(jsval
)
1486 JS_GetFrameReturnValue(JSContext
*cx
, JSStackFrame
*fp
)
1488 return Jsvalify(fp
->returnValue());
1492 JS_SetFrameReturnValue(JSContext
*cx
, JSStackFrame
*fp
, jsval rval
)
1495 JS_ASSERT_IF(fp
->isScriptFrame(), fp
->script()->debugMode
);
1497 assertSameCompartment(cx
, fp
, rval
);
1498 fp
->setReturnValue(Valueify(rval
));
1501 /************************************************************************/
1503 JS_PUBLIC_API(const char *)
1504 JS_GetScriptFilename(JSContext
*cx
, JSScript
*script
)
1506 return script
->filename
;
1509 JS_PUBLIC_API(uintN
)
1510 JS_GetScriptBaseLineNumber(JSContext
*cx
, JSScript
*script
)
1512 return script
->lineno
;
1515 JS_PUBLIC_API(uintN
)
1516 JS_GetScriptLineExtent(JSContext
*cx
, JSScript
*script
)
1518 return js_GetScriptLineExtent(script
);
1521 JS_PUBLIC_API(JSVersion
)
1522 JS_GetScriptVersion(JSContext
*cx
, JSScript
*script
)
1524 return VersionNumber(script
->getVersion());
1527 /***************************************************************************/
1530 JS_SetNewScriptHook(JSRuntime
*rt
, JSNewScriptHook hook
, void *callerdata
)
1532 rt
->globalDebugHooks
.newScriptHook
= hook
;
1533 rt
->globalDebugHooks
.newScriptHookData
= callerdata
;
1537 JS_SetDestroyScriptHook(JSRuntime
*rt
, JSDestroyScriptHook hook
,
1540 rt
->globalDebugHooks
.destroyScriptHook
= hook
;
1541 rt
->globalDebugHooks
.destroyScriptHookData
= callerdata
;
1544 /***************************************************************************/
1546 JS_PUBLIC_API(JSBool
)
1547 JS_EvaluateUCInStackFrame(JSContext
*cx
, JSStackFrame
*fp
,
1548 const jschar
*chars
, uintN length
,
1549 const char *filename
, uintN lineno
,
1552 JS_ASSERT_NOT_ON_TRACE(cx
);
1554 if (!CheckDebugMode(cx
))
1557 JSObject
*scobj
= JS_GetFrameScopeChain(cx
, fp
);
1561 js::AutoCompartment
ac(cx
, scobj
);
1566 * NB: This function breaks the assumption that the compiler can see all
1567 * calls and properly compute a static level. In order to get around this,
1568 * we use a static level that will cause us not to attempt to optimize
1569 * variable references made by this frame.
1571 JSScript
*script
= Compiler::compileScript(cx
, scobj
, fp
, js_StackFramePrincipals(cx
, fp
),
1572 TCF_COMPILE_N_GO
, chars
, length
,
1573 filename
, lineno
, cx
->findVersion(),
1574 NULL
, UpvarCookie::UPVAR_LEVEL_LIMIT
);
1579 bool ok
= Execute(cx
, scobj
, script
, fp
, JSFRAME_DEBUGGER
| JSFRAME_EVAL
, Valueify(rval
));
1581 js_DestroyScript(cx
, script
);
1585 JS_PUBLIC_API(JSBool
)
1586 JS_EvaluateInStackFrame(JSContext
*cx
, JSStackFrame
*fp
,
1587 const char *bytes
, uintN length
,
1588 const char *filename
, uintN lineno
,
1593 size_t len
= length
;
1595 if (!CheckDebugMode(cx
))
1598 chars
= js_InflateString(cx
, bytes
, &len
);
1601 length
= (uintN
) len
;
1602 ok
= JS_EvaluateUCInStackFrame(cx
, fp
, chars
, length
, filename
, lineno
,
1609 /************************************************************************/
1611 /* This all should be reworked to avoid requiring JSScopeProperty types. */
1613 JS_PUBLIC_API(JSScopeProperty
*)
1614 JS_PropertyIterator(JSObject
*obj
, JSScopeProperty
**iteratorp
)
1618 /* The caller passes null in *iteratorp to get things started. */
1619 shape
= (Shape
*) *iteratorp
;
1621 shape
= obj
->lastProperty();
1623 shape
= shape
->previous();
1624 if (!shape
->previous()) {
1625 JS_ASSERT(JSID_IS_EMPTY(shape
->id
));
1630 return *iteratorp
= reinterpret_cast<JSScopeProperty
*>(const_cast<Shape
*>(shape
));
1633 JS_PUBLIC_API(JSBool
)
1634 JS_GetPropertyDesc(JSContext
*cx
, JSObject
*obj
, JSScopeProperty
*sprop
,
1637 assertSameCompartment(cx
, obj
);
1638 Shape
*shape
= (Shape
*) sprop
;
1639 pd
->id
= IdToJsval(shape
->id
);
1641 JSBool wasThrowing
= cx
->isExceptionPending();
1642 Value lastException
= UndefinedValue();
1644 lastException
= cx
->getPendingException();
1645 cx
->clearPendingException();
1647 if (!js_GetProperty(cx
, obj
, shape
->id
, Valueify(&pd
->value
))) {
1648 if (!cx
->isExceptionPending()) {
1649 pd
->flags
= JSPD_ERROR
;
1650 pd
->value
= JSVAL_VOID
;
1652 pd
->flags
= JSPD_EXCEPTION
;
1653 pd
->value
= Jsvalify(cx
->getPendingException());
1660 cx
->setPendingException(lastException
);
1662 pd
->flags
|= (shape
->enumerable() ? JSPD_ENUMERATE
: 0)
1663 | (!shape
->writable() ? JSPD_READONLY
: 0)
1664 | (!shape
->configurable() ? JSPD_PERMANENT
: 0);
1666 if (shape
->getter() == GetCallArg
) {
1667 pd
->slot
= shape
->shortid
;
1668 pd
->flags
|= JSPD_ARGUMENT
;
1669 } else if (shape
->getter() == GetCallVar
) {
1670 pd
->slot
= shape
->shortid
;
1671 pd
->flags
|= JSPD_VARIABLE
;
1675 pd
->alias
= JSVAL_VOID
;
1677 if (obj
->containsSlot(shape
->slot
)) {
1678 for (Shape::Range r
= obj
->lastProperty()->all(); !r
.empty(); r
.popFront()) {
1679 const Shape
&aprop
= r
.front();
1680 if (&aprop
!= shape
&& aprop
.slot
== shape
->slot
) {
1681 pd
->alias
= IdToJsval(aprop
.id
);
1689 JS_PUBLIC_API(JSBool
)
1690 JS_GetPropertyDescArray(JSContext
*cx
, JSObject
*obj
, JSPropertyDescArray
*pda
)
1692 assertSameCompartment(cx
, obj
);
1693 Class
*clasp
= obj
->getClass();
1694 if (!obj
->isNative() || (clasp
->flags
& JSCLASS_NEW_ENUMERATE
)) {
1695 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
1696 JSMSG_CANT_DESCRIBE_PROPS
, clasp
->name
);
1699 if (!clasp
->enumerate(cx
, obj
))
1702 /* Return an empty pda early if obj has no own properties. */
1703 if (obj
->nativeEmpty()) {
1709 uint32 n
= obj
->propertyCount();
1710 JSPropertyDesc
*pd
= (JSPropertyDesc
*) cx
->malloc(size_t(n
) * sizeof(JSPropertyDesc
));
1714 for (Shape::Range r
= obj
->lastProperty()->all(); !r
.empty(); r
.popFront()) {
1715 if (!js_AddRoot(cx
, Valueify(&pd
[i
].id
), NULL
))
1717 if (!js_AddRoot(cx
, Valueify(&pd
[i
].value
), NULL
))
1719 Shape
*shape
= const_cast<Shape
*>(&r
.front());
1720 if (!JS_GetPropertyDesc(cx
, obj
, reinterpret_cast<JSScopeProperty
*>(shape
), &pd
[i
]))
1722 if ((pd
[i
].flags
& JSPD_ALIAS
) && !js_AddRoot(cx
, Valueify(&pd
[i
].alias
), NULL
))
1732 pda
->length
= i
+ 1;
1734 JS_PutPropertyDescArray(cx
, pda
);
1739 JS_PutPropertyDescArray(JSContext
*cx
, JSPropertyDescArray
*pda
)
1745 for (i
= 0; i
< pda
->length
; i
++) {
1746 js_RemoveRoot(cx
->runtime
, &pd
[i
].id
);
1747 js_RemoveRoot(cx
->runtime
, &pd
[i
].value
);
1748 if (pd
[i
].flags
& JSPD_ALIAS
)
1749 js_RemoveRoot(cx
->runtime
, &pd
[i
].alias
);
1754 /************************************************************************/
1756 JS_PUBLIC_API(JSBool
)
1757 JS_SetDebuggerHandler(JSRuntime
*rt
, JSDebuggerHandler handler
, void *closure
)
1759 rt
->globalDebugHooks
.debuggerHandler
= handler
;
1760 rt
->globalDebugHooks
.debuggerHandlerData
= closure
;
1764 JS_PUBLIC_API(JSBool
)
1765 JS_SetSourceHandler(JSRuntime
*rt
, JSSourceHandler handler
, void *closure
)
1767 rt
->globalDebugHooks
.sourceHandler
= handler
;
1768 rt
->globalDebugHooks
.sourceHandlerData
= closure
;
1772 JS_PUBLIC_API(JSBool
)
1773 JS_SetExecuteHook(JSRuntime
*rt
, JSInterpreterHook hook
, void *closure
)
1775 rt
->globalDebugHooks
.executeHook
= hook
;
1776 rt
->globalDebugHooks
.executeHookData
= closure
;
1780 JS_PUBLIC_API(JSBool
)
1781 JS_SetCallHook(JSRuntime
*rt
, JSInterpreterHook hook
, void *closure
)
1785 AutoLockGC
lock(rt
);
1786 bool wasInhibited
= rt
->debuggerInhibitsJIT();
1788 rt
->globalDebugHooks
.callHook
= hook
;
1789 rt
->globalDebugHooks
.callHookData
= closure
;
1791 JITInhibitingHookChange(rt
, wasInhibited
);
1797 JS_PUBLIC_API(JSBool
)
1798 JS_SetThrowHook(JSRuntime
*rt
, JSThrowHook hook
, void *closure
)
1800 rt
->globalDebugHooks
.throwHook
= hook
;
1801 rt
->globalDebugHooks
.throwHookData
= closure
;
1805 JS_PUBLIC_API(JSBool
)
1806 JS_SetDebugErrorHook(JSRuntime
*rt
, JSDebugErrorHook hook
, void *closure
)
1808 rt
->globalDebugHooks
.debugErrorHook
= hook
;
1809 rt
->globalDebugHooks
.debugErrorHookData
= closure
;
1813 /************************************************************************/
1815 JS_PUBLIC_API(size_t)
1816 JS_GetObjectTotalSize(JSContext
*cx
, JSObject
*obj
)
1818 return obj
->slotsAndStructSize();
1822 GetAtomTotalSize(JSContext
*cx
, JSAtom
*atom
)
1826 nbytes
= sizeof(JSAtom
*) + sizeof(JSDHashEntryStub
);
1827 nbytes
+= sizeof(JSString
);
1828 nbytes
+= (ATOM_TO_STRING(atom
)->flatLength() + 1) * sizeof(jschar
);
1832 JS_PUBLIC_API(size_t)
1833 JS_GetFunctionTotalSize(JSContext
*cx
, JSFunction
*fun
)
1837 nbytes
= sizeof *fun
;
1838 nbytes
+= JS_GetObjectTotalSize(cx
, FUN_OBJECT(fun
));
1839 if (FUN_INTERPRETED(fun
))
1840 nbytes
+= JS_GetScriptTotalSize(cx
, fun
->u
.i
.script
);
1842 nbytes
+= GetAtomTotalSize(cx
, fun
->atom
);
1848 JS_PUBLIC_API(size_t)
1849 JS_GetScriptTotalSize(JSContext
*cx
, JSScript
*script
)
1851 size_t nbytes
, pbytes
;
1853 jssrcnote
*sn
, *notes
;
1854 JSObjectArray
*objarray
;
1855 JSPrincipals
*principals
;
1857 nbytes
= sizeof *script
;
1858 if (script
->u
.object
)
1859 nbytes
+= JS_GetObjectTotalSize(cx
, script
->u
.object
);
1861 nbytes
+= script
->length
* sizeof script
->code
[0];
1862 nbytes
+= script
->atomMap
.length
* sizeof script
->atomMap
.vector
[0];
1863 for (i
= 0; i
< script
->atomMap
.length
; i
++)
1864 nbytes
+= GetAtomTotalSize(cx
, script
->atomMap
.vector
[i
]);
1866 if (script
->filename
)
1867 nbytes
+= strlen(script
->filename
) + 1;
1869 notes
= script
->notes();
1870 for (sn
= notes
; !SN_IS_TERMINATOR(sn
); sn
= SN_NEXT(sn
))
1872 nbytes
+= (sn
- notes
+ 1) * sizeof *sn
;
1874 if (JSScript::isValidOffset(script
->objectsOffset
)) {
1875 objarray
= script
->objects();
1876 i
= objarray
->length
;
1877 nbytes
+= sizeof *objarray
+ i
* sizeof objarray
->vector
[0];
1879 nbytes
+= JS_GetObjectTotalSize(cx
, objarray
->vector
[--i
]);
1883 if (JSScript::isValidOffset(script
->regexpsOffset
)) {
1884 objarray
= script
->regexps();
1885 i
= objarray
->length
;
1886 nbytes
+= sizeof *objarray
+ i
* sizeof objarray
->vector
[0];
1888 nbytes
+= JS_GetObjectTotalSize(cx
, objarray
->vector
[--i
]);
1892 if (JSScript::isValidOffset(script
->trynotesOffset
)) {
1893 nbytes
+= sizeof(JSTryNoteArray
) +
1894 script
->trynotes()->length
* sizeof(JSTryNote
);
1897 principals
= script
->principals
;
1899 JS_ASSERT(principals
->refcount
);
1900 pbytes
= sizeof *principals
;
1901 if (principals
->refcount
> 1)
1902 pbytes
= JS_HOWMANY(pbytes
, principals
->refcount
);
1909 JS_PUBLIC_API(uint32
)
1910 JS_GetTopScriptFilenameFlags(JSContext
*cx
, JSStackFrame
*fp
)
1913 fp
= js_GetTopStackFrame(cx
);
1915 if (fp
->isScriptFrame())
1916 return JS_GetScriptFilenameFlags(fp
->script());
1922 JS_PUBLIC_API(uint32
)
1923 JS_GetScriptFilenameFlags(JSScript
*script
)
1926 if (!script
->filename
)
1927 return JSFILENAME_NULL
;
1928 return js_GetScriptFilenameFlags(script
->filename
);
1931 JS_PUBLIC_API(JSBool
)
1932 JS_FlagScriptFilenamePrefix(JSRuntime
*rt
, const char *prefix
, uint32 flags
)
1934 if (!js_SaveScriptFilenameRT(rt
, prefix
, flags
))
1939 JS_PUBLIC_API(JSBool
)
1940 JS_IsSystemObject(JSContext
*cx
, JSObject
*obj
)
1942 return obj
->isSystem();
1945 JS_PUBLIC_API(JSBool
)
1946 JS_MakeSystemObject(JSContext
*cx
, JSObject
*obj
)
1952 /************************************************************************/
1954 JS_PUBLIC_API(JSObject
*)
1955 JS_UnwrapObject(JSContext
*cx
, JSObject
*obj
)
1957 return obj
->unwrap();
1960 /************************************************************************/
1963 js_RevertVersion(JSContext
*cx
)
1965 cx
->clearVersionOverride();
1968 JS_PUBLIC_API(const JSDebugHooks
*)
1969 JS_GetGlobalDebugHooks(JSRuntime
*rt
)
1971 return &rt
->globalDebugHooks
;
1974 const JSDebugHooks js_NullDebugHooks
= {};
1976 JS_PUBLIC_API(JSDebugHooks
*)
1977 JS_SetContextDebugHooks(JSContext
*cx
, const JSDebugHooks
*hooks
)
1980 if (hooks
!= &cx
->runtime
->globalDebugHooks
&& hooks
!= &js_NullDebugHooks
)
1984 AutoLockGC
lock(cx
->runtime
);
1986 JSDebugHooks
*old
= const_cast<JSDebugHooks
*>(cx
->debugHooks
);
1987 cx
->debugHooks
= hooks
;
1989 cx
->updateJITEnabled();
1994 JS_PUBLIC_API(JSDebugHooks
*)
1995 JS_ClearContextDebugHooks(JSContext
*cx
)
1997 return JS_SetContextDebugHooks(cx
, &js_NullDebugHooks
);
2000 JS_PUBLIC_API(JSBool
)
2003 return Probes::startProfiling();
2009 Probes::stopProfiling();
2012 #ifdef MOZ_PROFILING
2015 StartProfiling(JSContext
*cx
, uintN argc
, jsval
*vp
)
2017 JS_SET_RVAL(cx
, vp
, BOOLEAN_TO_JSVAL(JS_StartProfiling()));
2022 StopProfiling(JSContext
*cx
, uintN argc
, jsval
*vp
)
2025 JS_SET_RVAL(cx
, vp
, JSVAL_VOID
);
2032 IgnoreAndReturnTrue(JSContext
*cx
, uintN argc
, jsval
*vp
)
2034 JS_SET_RVAL(cx
, vp
, JSVAL_TRUE
);
2040 static JSFunctionSpec profiling_functions
[] = {
2041 JS_FN("startProfiling", StartProfiling
, 0,0),
2042 JS_FN("stopProfiling", StopProfiling
, 0,0),
2044 /* Keep users of the old shark API happy. */
2045 JS_FN("connectShark", IgnoreAndReturnTrue
, 0,0),
2046 JS_FN("disconnectShark", IgnoreAndReturnTrue
, 0,0),
2047 JS_FN("startShark", StartProfiling
, 0,0),
2048 JS_FN("stopShark", StopProfiling
, 0,0),
2055 JS_PUBLIC_API(JSBool
)
2056 JS_DefineProfilingFunctions(JSContext
*cx
, JSObject
*obj
)
2058 #ifdef MOZ_PROFILING
2059 return JS_DefineFunctions(cx
, obj
, profiling_functions
);
2065 #ifdef MOZ_CALLGRIND
2067 #include <valgrind/callgrind.h>
2069 JS_FRIEND_API(JSBool
)
2070 js_StartCallgrind(JSContext
*cx
, uintN argc
, jsval
*vp
)
2072 CALLGRIND_START_INSTRUMENTATION
;
2073 CALLGRIND_ZERO_STATS
;
2074 JS_SET_RVAL(cx
, vp
, JSVAL_VOID
);
2078 JS_FRIEND_API(JSBool
)
2079 js_StopCallgrind(JSContext
*cx
, uintN argc
, jsval
*vp
)
2081 CALLGRIND_STOP_INSTRUMENTATION
;
2082 JS_SET_RVAL(cx
, vp
, JSVAL_VOID
);
2086 JS_FRIEND_API(JSBool
)
2087 js_DumpCallgrind(JSContext
*cx
, uintN argc
, jsval
*vp
)
2091 jsval
*argv
= JS_ARGV(cx
, vp
);
2092 if (argc
> 0 && JSVAL_IS_STRING(argv
[0])) {
2093 str
= JSVAL_TO_STRING(argv
[0]);
2094 JSAutoByteString
bytes(cx
, str
);
2096 CALLGRIND_DUMP_STATS_AT(bytes
.ptr());
2100 CALLGRIND_DUMP_STATS
;
2102 JS_SET_RVAL(cx
, vp
, JSVAL_VOID
);
2106 #endif /* MOZ_CALLGRIND */
2109 #include <VTuneApi.h>
2111 static const char *vtuneErrorMessages
[] = {
2112 "unknown, error #0",
2113 "invalid 'max samples' field",
2114 "invalid 'samples per buffer' field",
2115 "invalid 'sample interval' field",
2117 "sample file in use",
2118 "invalid 'number of events' field",
2119 "unknown, error #7",
2122 "VTStopSampling called without calling VTStartSampling",
2123 "no events selected for event-based sampling",
2124 "events selected cannot be run together",
2125 "no sampling parameters",
2126 "sample database already exists",
2127 "sampling already started",
2128 "time-based sampling not supported",
2129 "invalid 'sampling parameters size' field",
2130 "invalid 'event size' field",
2131 "sampling file already bound",
2132 "invalid event path",
2134 "invalid 'global options' field",
2138 JS_FRIEND_API(JSBool
)
2139 js_StartVtune(JSContext
*cx
, uintN argc
, jsval
*vp
)
2141 VTUNE_EVENT events
[] = {
2142 { 1000000, 0, 0, 0, "CPU_CLK_UNHALTED.CORE" },
2143 { 1000000, 0, 0, 0, "INST_RETIRED.ANY" },
2146 U32 n_events
= sizeof(events
) / sizeof(VTUNE_EVENT
);
2147 char *default_filename
= "mozilla-vtune.tb5";
2151 VTUNE_SAMPLING_PARAMS params
= {
2152 sizeof(VTUNE_SAMPLING_PARAMS
),
2153 sizeof(VTUNE_EVENT
),
2154 0, 0, /* Reserved fields */
2155 1, /* Initialize in "paused" state */
2156 0, /* Max samples, or 0 for "continuous" */
2157 4096, /* Samples per buffer */
2158 0.1, /* Sampling interval in ms */
2159 1, /* 1 for event-based sampling, 0 for time-based */
2166 jsval
*argv
= JS_ARGV(cx
, vp
);
2167 if (argc
> 0 && JSVAL_IS_STRING(argv
[0])) {
2168 str
= JSVAL_TO_STRING(argv
[0]);
2169 params
.tb5Filename
= js_DeflateString(cx
, str
->chars(), str
->length());
2172 status
= VTStartSampling(¶ms
);
2174 if (params
.tb5Filename
!= default_filename
)
2175 cx
->free(params
.tb5Filename
);
2178 if (status
== VTAPI_MULTIPLE_RUNS
)
2180 if (status
< sizeof(vtuneErrorMessages
))
2181 JS_ReportError(cx
, "Vtune setup error: %s",
2182 vtuneErrorMessages
[status
]);
2184 JS_ReportError(cx
, "Vtune setup error: %d",
2188 JS_SET_RVAL(cx
, vp
, JSVAL_VOID
);
2192 JS_FRIEND_API(JSBool
)
2193 js_StopVtune(JSContext
*cx
, uintN argc
, jsval
*vp
)
2195 U32 status
= VTStopSampling(1);
2197 if (status
< sizeof(vtuneErrorMessages
))
2198 JS_ReportError(cx
, "Vtune shutdown error: %s",
2199 vtuneErrorMessages
[status
]);
2201 JS_ReportError(cx
, "Vtune shutdown error: %d",
2205 JS_SET_RVAL(cx
, vp
, JSVAL_VOID
);
2209 JS_FRIEND_API(JSBool
)
2210 js_PauseVtune(JSContext
*cx
, uintN argc
, jsval
*vp
)
2213 JS_SET_RVAL(cx
, vp
, JSVAL_VOID
);
2217 JS_FRIEND_API(JSBool
)
2218 js_ResumeVtune(JSContext
*cx
, uintN argc
, jsval
*vp
)
2221 JS_SET_RVAL(cx
, vp
, JSVAL_VOID
);
2225 #endif /* MOZ_VTUNE */
2229 * Ethogram - Javascript wrapper for TraceVis state
2231 * ethology: The scientific study of animal behavior,
2232 * especially as it occurs in a natural environment.
2233 * ethogram: A pictorial catalog of the behavioral patterns of
2234 * an organism or a species.
2240 #include <sys/time.h>
2242 #include "jstracer.h"
2244 #define ETHOGRAM_BUF_SIZE 65536
2247 ethogram_construct(JSContext
*cx
, uintN argc
, jsval
*vp
);
2249 ethogram_finalize(JSContext
*cx
, JSObject
*obj
);
2251 static JSClass ethogram_class
= {
2253 JSCLASS_HAS_PRIVATE
,
2254 JS_PropertyStub
, JS_PropertyStub
, JS_PropertyStub
, JS_StrictPropertyStub
,
2255 JS_EnumerateStub
, JS_ResolveStub
, JS_ConvertStub
, ethogram_finalize
,
2256 JSCLASS_NO_OPTIONAL_MEMBERS
2259 struct EthogramEvent
{
2261 TraceVisExitReason r
;
2269 compare_strings(const void *k1
, const void *k2
)
2271 return strcmp((const char *) k1
, (const char *) k2
) == 0;
2274 class EthogramEventBuffer
{
2276 EthogramEvent mBuf
[ETHOGRAM_BUF_SIZE
];
2279 JSObject
*mFilenames
;
2282 struct EthogramScriptEntry
{
2284 JSString
*jsfilename
;
2286 EthogramScriptEntry
*next
;
2288 EthogramScriptEntry
*mScripts
;
2292 ethogram_construct(JSContext
*cx
, uintN argc
, jsval
*vp
);
2294 inline void push(TraceVisState s
, TraceVisExitReason r
, char *filename
, int lineno
) {
2295 mBuf
[mWritePos
].s
= s
;
2296 mBuf
[mWritePos
].r
= r
;
2299 GetSystemTimeAsFileTime(&now
);
2300 unsigned long long raw_us
= 0.1 *
2301 (((unsigned long long) now
.dwHighDateTime
<< 32ULL) |
2302 (unsigned long long) now
.dwLowDateTime
);
2303 unsigned int sec
= raw_us
/ 1000000L;
2304 unsigned int usec
= raw_us
% 1000000L;
2305 mBuf
[mWritePos
].ts
= sec
- mStartSecond
;
2306 mBuf
[mWritePos
].tus
= usec
;
2309 gettimeofday(&tv
, NULL
);
2310 mBuf
[mWritePos
].ts
= tv
.tv_sec
- mStartSecond
;
2311 mBuf
[mWritePos
].tus
= tv
.tv_usec
;
2314 JSString
*jsfilename
= findScript(filename
);
2315 mBuf
[mWritePos
].filename
= jsfilename
;
2316 mBuf
[mWritePos
].lineno
= lineno
;
2318 mWritePos
= (mWritePos
+ 1) % ETHOGRAM_BUF_SIZE
;
2319 if (mWritePos
== mReadPos
) {
2320 mReadPos
= (mWritePos
+ 1) % ETHOGRAM_BUF_SIZE
;
2324 inline EthogramEvent
*pop() {
2325 EthogramEvent
*e
= &mBuf
[mReadPos
];
2326 mReadPos
= (mReadPos
+ 1) % ETHOGRAM_BUF_SIZE
;
2331 return (mReadPos
== mWritePos
);
2334 EthogramScriptEntry
*addScript(JSContext
*cx
, JSObject
*obj
, char *filename
, JSString
*jsfilename
) {
2335 JSHashNumber hash
= JS_HashString(filename
);
2336 JSHashEntry
**hep
= JS_HashTableRawLookup(traceVisScriptTable
, hash
, filename
);
2340 JS_HashTableRawAdd(traceVisScriptTable
, hep
, hash
, filename
, this);
2342 EthogramScriptEntry
* entry
= (EthogramScriptEntry
*) JS_malloc(cx
, sizeof(EthogramScriptEntry
));
2346 entry
->next
= mScripts
;
2348 entry
->filename
= filename
;
2349 entry
->jsfilename
= jsfilename
;
2354 void removeScripts(JSContext
*cx
) {
2355 EthogramScriptEntry
*se
= mScripts
;
2356 while (se
!= NULL
) {
2357 char *filename
= se
->filename
;
2359 JSHashNumber hash
= JS_HashString(filename
);
2360 JSHashEntry
**hep
= JS_HashTableRawLookup(traceVisScriptTable
, hash
, filename
);
2361 JSHashEntry
*he
= *hep
;
2363 /* we hardly knew he */
2364 JS_HashTableRawRemove(traceVisScriptTable
, hep
, he
);
2367 EthogramScriptEntry
*se_head
= se
;
2369 JS_free(cx
, se_head
);
2373 JSString
*findScript(char *filename
) {
2374 EthogramScriptEntry
*se
= mScripts
;
2375 while (se
!= NULL
) {
2376 if (compare_strings(se
->filename
, filename
))
2377 return (se
->jsfilename
);
2383 JSObject
*filenames() {
2388 if (mWritePos
< mReadPos
)
2389 return (mWritePos
+ ETHOGRAM_BUF_SIZE
) - mReadPos
;
2391 return mWritePos
- mReadPos
;
2395 static char jstv_empty
[] = "<null>";
2398 jstv_Filename(JSStackFrame
*fp
)
2400 while (fp
&& !fp
->isScriptFrame())
2402 return (fp
&& fp
->maybeScript() && fp
->script()->filename
)
2403 ? (char *)fp
->script()->filename
2407 jstv_Lineno(JSContext
*cx
, JSStackFrame
*fp
)
2409 while (fp
&& fp
->pc(cx
) == NULL
)
2411 return (fp
&& fp
->pc(cx
)) ? js_FramePCToLineNumber(cx
, fp
) : 0;
2414 /* Collect states here and distribute to a matching buffer, if any */
2416 js::StoreTraceVisState(JSContext
*cx
, TraceVisState s
, TraceVisExitReason r
)
2418 JSStackFrame
*fp
= cx
->fp();
2420 char *script_file
= jstv_Filename(fp
);
2421 JSHashNumber hash
= JS_HashString(script_file
);
2423 JSHashEntry
**hep
= JS_HashTableRawLookup(traceVisScriptTable
, hash
, script_file
);
2424 /* update event buffer, flag if overflowed */
2425 JSHashEntry
*he
= *hep
;
2427 EthogramEventBuffer
*p
;
2428 p
= (EthogramEventBuffer
*) he
->value
;
2430 p
->push(s
, r
, script_file
, jstv_Lineno(cx
, fp
));
2435 ethogram_construct(JSContext
*cx
, uintN argc
, jsval
*vp
)
2437 EthogramEventBuffer
*p
;
2439 p
= (EthogramEventBuffer
*) JS_malloc(cx
, sizeof(EthogramEventBuffer
));
2443 p
->mReadPos
= p
->mWritePos
= 0;
2445 p
->mFilenames
= JS_NewArrayObject(cx
, 0, NULL
);
2449 GetSystemTimeAsFileTime(&now
);
2450 unsigned long long raw_us
= 0.1 *
2451 (((unsigned long long) now
.dwHighDateTime
<< 32ULL) |
2452 (unsigned long long) now
.dwLowDateTime
);
2453 unsigned int s
= raw_us
/ 1000000L;
2454 p
->mStartSecond
= s
;
2457 gettimeofday(&tv
, NULL
);
2458 p
->mStartSecond
= tv
.tv_sec
;
2461 if (JS_IsConstructing(cx
, vp
)) {
2462 obj
= JS_NewObject(cx
, ðogram_class
, NULL
, NULL
);
2466 obj
= JS_THIS_OBJECT(cx
, vp
);
2469 jsval filenames
= OBJECT_TO_JSVAL(p
->filenames());
2470 if (!JS_DefineProperty(cx
, obj
, "filenames", filenames
,
2471 NULL
, NULL
, JSPROP_READONLY
|JSPROP_PERMANENT
))
2474 JS_SET_RVAL(cx
, vp
, OBJECT_TO_JSVAL(obj
));
2475 JS_SetPrivate(cx
, obj
, p
);
2480 ethogram_finalize(JSContext
*cx
, JSObject
*obj
)
2482 EthogramEventBuffer
*p
;
2483 p
= (EthogramEventBuffer
*) JS_GetInstancePrivate(cx
, obj
, ðogram_class
, NULL
);
2487 p
->removeScripts(cx
);
2493 ethogram_addScript(JSContext
*cx
, uintN argc
, jsval
*vp
)
2496 char *filename
= NULL
;
2497 jsval
*argv
= JS_ARGV(cx
, vp
);
2498 JSObject
*obj
= JS_THIS_OBJECT(cx
, vp
);
2502 /* silently ignore no args */
2503 JS_SET_RVAL(cx
, vp
, JSVAL_VOID
);
2506 if (JSVAL_IS_STRING(argv
[0])) {
2507 str
= JSVAL_TO_STRING(argv
[0]);
2508 filename
= js_DeflateString(cx
, str
->chars(), str
->length());
2513 EthogramEventBuffer
*p
= (EthogramEventBuffer
*) JS_GetInstancePrivate(cx
, obj
, ðogram_class
, argv
);
2515 p
->addScript(cx
, obj
, filename
, str
);
2516 JS_SET_RVAL(cx
, vp
, JSVAL_VOID
);
2518 JS_CallFunctionName(cx
, p
->filenames(), "push", 1, argv
, &dummy
);
2523 ethogram_getAllEvents(JSContext
*cx
, uintN argc
, jsval
*vp
)
2525 EthogramEventBuffer
*p
;
2526 jsval
*argv
= JS_ARGV(cx
, vp
);
2528 JSObject
*obj
= JS_THIS_OBJECT(cx
, vp
);
2532 p
= (EthogramEventBuffer
*) JS_GetInstancePrivate(cx
, obj
, ðogram_class
, argv
);
2537 JS_SET_RVAL(cx
, vp
, JSVAL_NULL
);
2541 JSObject
*rarray
= JS_NewArrayObject(cx
, 0, NULL
);
2542 if (rarray
== NULL
) {
2543 JS_SET_RVAL(cx
, vp
, JSVAL_NULL
);
2547 JS_SET_RVAL(cx
, vp
, OBJECT_TO_JSVAL(rarray
));
2549 for (int i
= 0; !p
->isEmpty(); i
++) {
2551 JSObject
*x
= JS_NewObject(cx
, NULL
, NULL
, NULL
);
2555 EthogramEvent
*e
= p
->pop();
2557 jsval state
= INT_TO_JSVAL(e
->s
);
2558 jsval reason
= INT_TO_JSVAL(e
->r
);
2559 jsval ts
= INT_TO_JSVAL(e
->ts
);
2560 jsval tus
= INT_TO_JSVAL(e
->tus
);
2562 jsval filename
= STRING_TO_JSVAL(e
->filename
);
2563 jsval lineno
= INT_TO_JSVAL(e
->lineno
);
2565 if (!JS_SetProperty(cx
, x
, "state", &state
))
2567 if (!JS_SetProperty(cx
, x
, "reason", &reason
))
2569 if (!JS_SetProperty(cx
, x
, "ts", &ts
))
2571 if (!JS_SetProperty(cx
, x
, "tus", &tus
))
2574 if (!JS_SetProperty(cx
, x
, "filename", &filename
))
2576 if (!JS_SetProperty(cx
, x
, "lineno", &lineno
))
2579 jsval element
= OBJECT_TO_JSVAL(x
);
2580 JS_SetElement(cx
, rarray
, i
, &element
);
2587 ethogram_getNextEvent(JSContext
*cx
, uintN argc
, jsval
*vp
)
2589 EthogramEventBuffer
*p
;
2590 jsval
*argv
= JS_ARGV(cx
, vp
);
2592 JSObject
*obj
= JS_THIS_OBJECT(cx
, vp
);
2596 p
= (EthogramEventBuffer
*) JS_GetInstancePrivate(cx
, obj
, ðogram_class
, argv
);
2600 JSObject
*x
= JS_NewObject(cx
, NULL
, NULL
, NULL
);
2605 JS_SET_RVAL(cx
, vp
, JSVAL_NULL
);
2609 EthogramEvent
*e
= p
->pop();
2610 jsval state
= INT_TO_JSVAL(e
->s
);
2611 jsval reason
= INT_TO_JSVAL(e
->r
);
2612 jsval ts
= INT_TO_JSVAL(e
->ts
);
2613 jsval tus
= INT_TO_JSVAL(e
->tus
);
2615 jsval filename
= STRING_TO_JSVAL(e
->filename
);
2616 jsval lineno
= INT_TO_JSVAL(e
->lineno
);
2618 if (!JS_SetProperty(cx
, x
, "state", &state
))
2620 if (!JS_SetProperty(cx
, x
, "reason", &reason
))
2622 if (!JS_SetProperty(cx
, x
, "ts", &ts
))
2624 if (!JS_SetProperty(cx
, x
, "tus", &tus
))
2626 if (!JS_SetProperty(cx
, x
, "filename", &filename
))
2629 if (!JS_SetProperty(cx
, x
, "lineno", &lineno
))
2632 JS_SET_RVAL(cx
, vp
, OBJECT_TO_JSVAL(x
));
2637 static JSFunctionSpec ethogram_methods
[] = {
2638 JS_FN("addScript", ethogram_addScript
, 1,0),
2639 JS_FN("getAllEvents", ethogram_getAllEvents
, 0,0),
2640 JS_FN("getNextEvent", ethogram_getNextEvent
, 0,0),
2645 * An |Ethogram| organizes the output of a collection of files that should be
2646 * monitored together. A single object gets events for the group.
2648 JS_FRIEND_API(JSBool
)
2649 js_InitEthogram(JSContext
*cx
, uintN argc
, jsval
*vp
)
2651 if (!traceVisScriptTable
) {
2652 traceVisScriptTable
= JS_NewHashTable(8, JS_HashString
, compare_strings
,
2656 JS_InitClass(cx
, JS_GetGlobalObject(cx
), NULL
, ðogram_class
,
2657 ethogram_construct
, 0, NULL
, ethogram_methods
,
2660 JS_SET_RVAL(cx
, vp
, JSVAL_VOID
);
2664 JS_FRIEND_API(JSBool
)
2665 js_ShutdownEthogram(JSContext
*cx
, uintN argc
, jsval
*vp
)
2667 if (traceVisScriptTable
)
2668 JS_HashTableDestroy(traceVisScriptTable
);
2670 JS_SET_RVAL(cx
, vp
, JSVAL_VOID
);
2674 #endif /* MOZ_TRACEVIS */