1 |
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- |
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- |
2 |
* vim: set ts=8 sw=4 et tw=78: |
* vim: set ts=8 sw=4 et tw=78: |
3 |
* |
* |
4 |
* ***** BEGIN LICENSE BLOCK ***** |
* ***** BEGIN LICENSE BLOCK ***** |
41 |
/* |
/* |
42 |
* JS debugging API. |
* JS debugging API. |
43 |
*/ |
*/ |
|
#include "jsstddef.h" |
|
44 |
#include <string.h> |
#include <string.h> |
45 |
#include "jstypes.h" |
#include "jstypes.h" |
46 |
|
#include "jsstdint.h" |
47 |
#include "jsutil.h" /* Added by JSIFY */ |
#include "jsutil.h" /* Added by JSIFY */ |
48 |
#include "jsclist.h" |
#include "jsclist.h" |
49 |
#include "jsapi.h" |
#include "jsapi.h" |
63 |
#include "jsstaticcheck.h" |
#include "jsstaticcheck.h" |
64 |
#include "jsstr.h" |
#include "jsstr.h" |
65 |
|
|
66 |
|
#include "jsatominlines.h" |
67 |
|
|
68 |
#include "jsautooplen.h" |
#include "jsautooplen.h" |
69 |
|
|
70 |
typedef struct JSTrap { |
typedef struct JSTrap { |
118 |
size_t nbytes; |
size_t nbytes; |
119 |
|
|
120 |
nbytes = script->length * sizeof(jsbytecode); |
nbytes = script->length * sizeof(jsbytecode); |
121 |
notes = SCRIPT_NOTES(script); |
notes = script->notes(); |
122 |
for (sn = notes; !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) |
for (sn = notes; !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) |
123 |
continue; |
continue; |
124 |
nbytes += (sn - notes + 1) * sizeof *sn; |
nbytes += (sn - notes + 1) * sizeof *sn; |
125 |
|
|
126 |
code = (jsbytecode *) JS_malloc(cx, nbytes); |
code = (jsbytecode *) cx->malloc(nbytes); |
127 |
if (!code) |
if (!code) |
128 |
break; |
break; |
129 |
memcpy(code, script->code, nbytes); |
memcpy(code, script->code, nbytes); |
155 |
} else { |
} else { |
156 |
sample = rt->debuggerMutations; |
sample = rt->debuggerMutations; |
157 |
DBG_UNLOCK(rt); |
DBG_UNLOCK(rt); |
158 |
trap = (JSTrap *) JS_malloc(cx, sizeof *trap); |
trap = (JSTrap *) cx->malloc(sizeof *trap); |
159 |
if (!trap) |
if (!trap) |
160 |
return JS_FALSE; |
return JS_FALSE; |
161 |
trap->closure = NULL; |
trap->closure = NULL; |
162 |
if(!js_AddRoot(cx, &trap->closure, "trap->closure")) { |
if(!js_AddRoot(cx, &trap->closure, "trap->closure")) { |
163 |
JS_free(cx, trap); |
cx->free(trap); |
164 |
return JS_FALSE; |
return JS_FALSE; |
165 |
} |
} |
166 |
DBG_LOCK(rt); |
DBG_LOCK(rt); |
184 |
DBG_UNLOCK(rt); |
DBG_UNLOCK(rt); |
185 |
if (junk) { |
if (junk) { |
186 |
js_RemoveRoot(rt, &junk->closure); |
js_RemoveRoot(rt, &junk->closure); |
187 |
JS_free(cx, junk); |
cx->free(junk); |
188 |
} |
} |
189 |
return JS_TRUE; |
return JS_TRUE; |
190 |
} |
} |
213 |
DBG_UNLOCK(cx->runtime); |
DBG_UNLOCK(cx->runtime); |
214 |
|
|
215 |
js_RemoveRoot(cx->runtime, &trap->closure); |
js_RemoveRoot(cx->runtime, &trap->closure); |
216 |
JS_free(cx, trap); |
cx->free(trap); |
217 |
} |
} |
218 |
|
|
219 |
JS_PUBLIC_API(void) |
JS_PUBLIC_API(void) |
325 |
return status; |
return status; |
326 |
} |
} |
327 |
|
|
328 |
|
#ifdef JS_TRACER |
329 |
|
static void |
330 |
|
JITInhibitingHookChange(JSRuntime *rt, bool wasInhibited) |
331 |
|
{ |
332 |
|
if (wasInhibited) { |
333 |
|
if (!rt->debuggerInhibitsJIT()) { |
334 |
|
for (JSCList *cl = rt->contextList.next; cl != &rt->contextList; cl = cl->next) |
335 |
|
js_ContextFromLinkField(cl)->updateJITEnabled(); |
336 |
|
} |
337 |
|
} else if (rt->debuggerInhibitsJIT()) { |
338 |
|
for (JSCList *cl = rt->contextList.next; cl != &rt->contextList; cl = cl->next) |
339 |
|
js_ContextFromLinkField(cl)->jitEnabled = false; |
340 |
|
} |
341 |
|
} |
342 |
|
|
343 |
|
static void |
344 |
|
LeaveTraceRT(JSRuntime *rt) |
345 |
|
{ |
346 |
|
JSThreadData *data = js_CurrentThreadData(rt); |
347 |
|
JSContext *cx = data ? data->traceMonitor.tracecx : NULL; |
348 |
|
JS_UNLOCK_GC(rt); |
349 |
|
|
350 |
|
if (cx) |
351 |
|
js_LeaveTrace(cx); |
352 |
|
} |
353 |
|
#endif |
354 |
|
|
355 |
JS_PUBLIC_API(JSBool) |
JS_PUBLIC_API(JSBool) |
356 |
JS_SetInterrupt(JSRuntime *rt, JSTrapHandler handler, void *closure) |
JS_SetInterrupt(JSRuntime *rt, JSTrapHandler handler, void *closure) |
357 |
{ |
{ |
358 |
|
#ifdef JS_TRACER |
359 |
|
JS_LOCK_GC(rt); |
360 |
|
bool wasInhibited = rt->debuggerInhibitsJIT(); |
361 |
|
#endif |
362 |
rt->globalDebugHooks.interruptHandler = handler; |
rt->globalDebugHooks.interruptHandler = handler; |
363 |
rt->globalDebugHooks.interruptHandlerData = closure; |
rt->globalDebugHooks.interruptHandlerData = closure; |
364 |
|
#ifdef JS_TRACER |
365 |
|
JITInhibitingHookChange(rt, wasInhibited); |
366 |
|
JS_UNLOCK_GC(rt); |
367 |
|
LeaveTraceRT(rt); |
368 |
|
#endif |
369 |
return JS_TRUE; |
return JS_TRUE; |
370 |
} |
} |
371 |
|
|
372 |
JS_PUBLIC_API(JSBool) |
JS_PUBLIC_API(JSBool) |
373 |
JS_ClearInterrupt(JSRuntime *rt, JSTrapHandler *handlerp, void **closurep) |
JS_ClearInterrupt(JSRuntime *rt, JSTrapHandler *handlerp, void **closurep) |
374 |
{ |
{ |
375 |
|
#ifdef JS_TRACER |
376 |
|
JS_LOCK_GC(rt); |
377 |
|
bool wasInhibited = rt->debuggerInhibitsJIT(); |
378 |
|
#endif |
379 |
if (handlerp) |
if (handlerp) |
380 |
*handlerp = (JSTrapHandler)rt->globalDebugHooks.interruptHandler; |
*handlerp = rt->globalDebugHooks.interruptHandler; |
381 |
if (closurep) |
if (closurep) |
382 |
*closurep = rt->globalDebugHooks.interruptHandlerData; |
*closurep = rt->globalDebugHooks.interruptHandlerData; |
383 |
rt->globalDebugHooks.interruptHandler = 0; |
rt->globalDebugHooks.interruptHandler = 0; |
384 |
rt->globalDebugHooks.interruptHandlerData = 0; |
rt->globalDebugHooks.interruptHandlerData = 0; |
385 |
|
#ifdef JS_TRACER |
386 |
|
JITInhibitingHookChange(rt, wasInhibited); |
387 |
|
JS_UNLOCK_GC(rt); |
388 |
|
#endif |
389 |
return JS_TRUE; |
return JS_TRUE; |
390 |
} |
} |
391 |
|
|
397 |
JSScopeProperty *sprop; |
JSScopeProperty *sprop; |
398 |
JSPropertyOp setter; |
JSPropertyOp setter; |
399 |
JSWatchPointHandler handler; |
JSWatchPointHandler handler; |
400 |
void *closure; |
JSObject *closure; |
401 |
uintN flags; |
uintN flags; |
402 |
} JSWatchPoint; |
} JSWatchPoint; |
403 |
|
|
441 |
if (!setter) { |
if (!setter) { |
442 |
JS_LOCK_OBJ(cx, wp->object); |
JS_LOCK_OBJ(cx, wp->object); |
443 |
scope = OBJ_SCOPE(wp->object); |
scope = OBJ_SCOPE(wp->object); |
444 |
found = (scope->object == wp->object && |
found = (scope->lookup(sprop->id) != NULL); |
|
SCOPE_GET_PROPERTY(scope, sprop->id)); |
|
445 |
JS_UNLOCK_SCOPE(cx, scope); |
JS_UNLOCK_SCOPE(cx, scope); |
446 |
|
|
447 |
/* |
/* |
450 |
* the property attributes. |
* the property attributes. |
451 |
*/ |
*/ |
452 |
if (found) { |
if (found) { |
453 |
sprop = js_ChangeScopePropertyAttrs(cx, scope, sprop, |
sprop = scope->change(cx, sprop, 0, sprop->attrs, |
454 |
0, sprop->attrs, |
sprop->getter, wp->setter); |
|
sprop->getter, |
|
|
wp->setter); |
|
455 |
if (!sprop) |
if (!sprop) |
456 |
ok = JS_FALSE; |
ok = JS_FALSE; |
457 |
} |
} |
458 |
} |
} |
459 |
|
|
460 |
JS_free(cx, wp); |
cx->free(wp); |
461 |
return ok; |
return ok; |
462 |
} |
} |
463 |
|
|
478 |
&wp->links != &rt->watchPointList; |
&wp->links != &rt->watchPointList; |
479 |
wp = (JSWatchPoint *)wp->links.next) { |
wp = (JSWatchPoint *)wp->links.next) { |
480 |
if (wp->object == obj) { |
if (wp->object == obj) { |
481 |
TRACE_SCOPE_PROPERTY(trc, wp->sprop); |
wp->sprop->trace(trc); |
482 |
if ((wp->sprop->attrs & JSPROP_SETTER) && wp->setter) { |
if ((wp->sprop->attrs & JSPROP_SETTER) && wp->setter) { |
483 |
JS_CALL_OBJECT_TRACER(trc, js_CastAsObject(wp->setter), |
JS_CALL_OBJECT_TRACER(trc, js_CastAsObject(wp->setter), |
484 |
"wp->setter"); |
"wp->setter"); |
485 |
} |
} |
486 |
JS_SET_TRACING_NAME(trc, "wp->closure"); |
JS_SET_TRACING_NAME(trc, "wp->closure"); |
487 |
js_CallValueTracerIfGCThing(trc, (jsval) wp->closure); |
js_CallValueTracerIfGCThing(trc, OBJECT_TO_JSVAL(wp->closure)); |
488 |
} |
} |
489 |
} |
} |
490 |
} |
} |
528 |
for (wp = (JSWatchPoint *)rt->watchPointList.next; |
for (wp = (JSWatchPoint *)rt->watchPointList.next; |
529 |
&wp->links != &rt->watchPointList; |
&wp->links != &rt->watchPointList; |
530 |
wp = (JSWatchPoint *)wp->links.next) { |
wp = (JSWatchPoint *)wp->links.next) { |
531 |
if (wp->object == scope->object && wp->sprop->id == id) |
if (OBJ_SCOPE(wp->object) == scope && wp->sprop->id == id) |
532 |
return wp; |
return wp; |
533 |
} |
} |
534 |
return NULL; |
return NULL; |
564 |
for (wp = (JSWatchPoint *)rt->watchPointList.next; |
for (wp = (JSWatchPoint *)rt->watchPointList.next; |
565 |
&wp->links != &rt->watchPointList; |
&wp->links != &rt->watchPointList; |
566 |
wp = (JSWatchPoint *)wp->links.next) { |
wp = (JSWatchPoint *)wp->links.next) { |
567 |
if ((!scope || wp->object == scope->object) && wp->sprop == sprop) { |
if ((!scope || OBJ_SCOPE(wp->object) == scope) && wp->sprop == sprop) { |
568 |
setter = wp->setter; |
setter = wp->setter; |
569 |
break; |
break; |
570 |
} |
} |
632 |
JSStackFrame frame; |
JSStackFrame frame; |
633 |
JSFrameRegs regs; |
JSFrameRegs regs; |
634 |
|
|
635 |
closure = (JSObject *) wp->closure; |
closure = wp->closure; |
636 |
clasp = OBJ_GET_CLASS(cx, closure); |
clasp = OBJ_GET_CLASS(cx, closure); |
637 |
if (clasp == &js_FunctionClass) { |
if (clasp == &js_FunctionClass) { |
638 |
fun = GET_FUNCTION_PRIVATE(cx, closure); |
fun = GET_FUNCTION_PRIVATE(cx, closure); |
639 |
script = FUN_SCRIPT(fun); |
script = FUN_SCRIPT(fun); |
640 |
} else if (clasp == &js_ScriptClass) { |
} else if (clasp == &js_ScriptClass) { |
641 |
fun = NULL; |
fun = NULL; |
642 |
script = (JSScript *) JS_GetPrivate(cx, closure); |
script = (JSScript *) closure->getPrivate(); |
643 |
} else { |
} else { |
644 |
fun = NULL; |
fun = NULL; |
645 |
script = NULL; |
script = NULL; |
663 |
if (nslots <= JS_ARRAY_LENGTH(smallv)) { |
if (nslots <= JS_ARRAY_LENGTH(smallv)) { |
664 |
argv = smallv; |
argv = smallv; |
665 |
} else { |
} else { |
666 |
argv = (jsval *) JS_malloc(cx, nslots * sizeof(jsval)); |
argv = (jsval *) cx->malloc(nslots * sizeof(jsval)); |
667 |
if (!argv) { |
if (!argv) { |
668 |
DBG_LOCK(rt); |
DBG_LOCK(rt); |
669 |
DropWatchPointAndUnlock(cx, wp, JSWP_HELD); |
DropWatchPointAndUnlock(cx, wp, JSWP_HELD); |
678 |
memset(&frame, 0, sizeof(frame)); |
memset(&frame, 0, sizeof(frame)); |
679 |
frame.script = script; |
frame.script = script; |
680 |
frame.regs = NULL; |
frame.regs = NULL; |
|
frame.callee = closure; |
|
681 |
frame.fun = fun; |
frame.fun = fun; |
682 |
frame.argv = argv + 2; |
frame.argv = argv + 2; |
683 |
frame.down = js_GetTopStackFrame(cx); |
frame.down = js_GetTopStackFrame(cx); |
694 |
JSFUN_HEAVYWEIGHT_TEST(fun->flags) && |
JSFUN_HEAVYWEIGHT_TEST(fun->flags) && |
695 |
!js_GetCallObject(cx, &frame)) { |
!js_GetCallObject(cx, &frame)) { |
696 |
if (argv != smallv) |
if (argv != smallv) |
697 |
JS_free(cx, argv); |
cx->free(argv); |
698 |
DBG_LOCK(rt); |
DBG_LOCK(rt); |
699 |
DropWatchPointAndUnlock(cx, wp, JSWP_HELD); |
DropWatchPointAndUnlock(cx, wp, JSWP_HELD); |
700 |
return JS_FALSE; |
return JS_FALSE; |
715 |
: wp->setter(cx, obj, userid, vp)); |
: wp->setter(cx, obj, userid, vp)); |
716 |
if (injectFrame) { |
if (injectFrame) { |
717 |
/* Evil code can cause us to have an arguments object. */ |
/* Evil code can cause us to have an arguments object. */ |
718 |
if (frame.callobj) |
frame.putActivationObjects(cx); |
|
ok &= js_PutCallObject(cx, &frame); |
|
|
if (frame.argsobj) |
|
|
ok &= js_PutArgsObject(cx, &frame); |
|
|
|
|
719 |
cx->fp = frame.down; |
cx->fp = frame.down; |
720 |
if (argv != smallv) |
if (argv != smallv) |
721 |
JS_free(cx, argv); |
cx->free(argv); |
722 |
} |
} |
723 |
} |
} |
724 |
DBG_LOCK(rt); |
DBG_LOCK(rt); |
729 |
return JS_TRUE; |
return JS_TRUE; |
730 |
} |
} |
731 |
|
|
732 |
JS_REQUIRES_STACK JSBool |
JSBool |
733 |
js_watch_set_wrapper(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, |
js_watch_set_wrapper(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, |
734 |
jsval *rval) |
jsval *rval) |
735 |
{ |
{ |
774 |
JS_SetWatchPoint(JSContext *cx, JSObject *obj, jsval idval, |
JS_SetWatchPoint(JSContext *cx, JSObject *obj, jsval idval, |
775 |
JSWatchPointHandler handler, void *closure) |
JSWatchPointHandler handler, void *closure) |
776 |
{ |
{ |
777 |
|
JSObject *origobj; |
778 |
|
jsval v; |
779 |
|
uintN attrs; |
780 |
jsid propid; |
jsid propid; |
781 |
JSObject *pobj; |
JSObject *pobj; |
782 |
JSProperty *prop; |
JSProperty *prop; |
786 |
JSWatchPoint *wp; |
JSWatchPoint *wp; |
787 |
JSPropertyOp watcher; |
JSPropertyOp watcher; |
788 |
|
|
789 |
if (!OBJ_IS_NATIVE(obj)) { |
origobj = obj; |
790 |
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_WATCH, |
obj = js_GetWrappedObject(cx, obj); |
791 |
OBJ_GET_CLASS(cx, obj)->name); |
OBJ_TO_INNER_OBJECT(cx, obj); |
792 |
|
if (!obj) |
793 |
return JS_FALSE; |
return JS_FALSE; |
|
} |
|
794 |
|
|
795 |
if (JSVAL_IS_INT(idval)) { |
if (JSVAL_IS_INT(idval)) { |
796 |
propid = INT_JSVAL_TO_JSID(idval); |
propid = INT_JSVAL_TO_JSID(idval); |
797 |
} else { |
} else { |
798 |
if (!js_ValueToStringId(cx, idval, &propid)) |
if (!js_ValueToStringId(cx, idval, &propid)) |
799 |
return JS_FALSE; |
return JS_FALSE; |
800 |
CHECK_FOR_STRING_INDEX(propid); |
propid = js_CheckForStringIndex(propid); |
801 |
|
} |
802 |
|
|
803 |
|
/* |
804 |
|
* If, by unwrapping and innerizing, we changed the object, check |
805 |
|
* again to make sure that we're allowed to set a watch point. |
806 |
|
*/ |
807 |
|
if (origobj != obj && !obj->checkAccess(cx, propid, JSACC_WATCH, &v, &attrs)) |
808 |
|
return JS_FALSE; |
809 |
|
|
810 |
|
if (!OBJ_IS_NATIVE(obj)) { |
811 |
|
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_WATCH, |
812 |
|
OBJ_GET_CLASS(cx, obj)->name); |
813 |
|
return JS_FALSE; |
814 |
} |
} |
815 |
|
|
816 |
if (!js_LookupProperty(cx, obj, propid, &pobj, &prop)) |
if (!js_LookupProperty(cx, obj, propid, &pobj, &prop)) |
822 |
sprop = js_FindWatchPoint(rt, OBJ_SCOPE(obj), propid); |
sprop = js_FindWatchPoint(rt, OBJ_SCOPE(obj), propid); |
823 |
if (!sprop) { |
if (!sprop) { |
824 |
/* Make a new property in obj so we can watch for the first set. */ |
/* Make a new property in obj so we can watch for the first set. */ |
825 |
if (!js_DefineProperty(cx, obj, propid, JSVAL_VOID, |
if (!js_DefineNativeProperty(cx, obj, propid, JSVAL_VOID, NULL, NULL, |
826 |
NULL, NULL, JSPROP_ENUMERATE, |
JSPROP_ENUMERATE, 0, 0, &prop)) { |
|
&prop)) { |
|
827 |
return JS_FALSE; |
return JS_FALSE; |
828 |
} |
} |
829 |
sprop = (JSScopeProperty *) prop; |
sprop = (JSScopeProperty *) prop; |
845 |
flags = sprop->flags; |
flags = sprop->flags; |
846 |
shortid = sprop->shortid; |
shortid = sprop->shortid; |
847 |
} else { |
} else { |
848 |
if (!OBJ_GET_PROPERTY(cx, pobj, propid, &value) || |
if (!pobj->getProperty(cx, propid, &value) || |
849 |
!OBJ_GET_ATTRIBUTES(cx, pobj, propid, prop, &attrs)) { |
!pobj->getAttributes(cx, propid, prop, &attrs)) { |
850 |
OBJ_DROP_PROPERTY(cx, pobj, prop); |
pobj->dropProperty(cx, prop); |
851 |
return JS_FALSE; |
return JS_FALSE; |
852 |
} |
} |
853 |
getter = setter = NULL; |
getter = setter = NULL; |
854 |
flags = 0; |
flags = 0; |
855 |
shortid = 0; |
shortid = 0; |
856 |
} |
} |
857 |
OBJ_DROP_PROPERTY(cx, pobj, prop); |
pobj->dropProperty(cx, prop); |
858 |
|
|
859 |
/* Recall that obj is native, whether or not pobj is native. */ |
/* Recall that obj is native, whether or not pobj is native. */ |
860 |
if (!js_DefineNativeProperty(cx, obj, propid, value, getter, setter, |
if (!js_DefineNativeProperty(cx, obj, propid, value, getter, setter, |
866 |
|
|
867 |
/* |
/* |
868 |
* At this point, prop/sprop exists in obj, obj is locked, and we must |
* At this point, prop/sprop exists in obj, obj is locked, and we must |
869 |
* OBJ_DROP_PROPERTY(cx, obj, prop) before returning. |
* obj->dropProperty(cx, prop) before returning. |
870 |
*/ |
*/ |
871 |
ok = JS_TRUE; |
ok = JS_TRUE; |
872 |
DBG_LOCK(rt); |
DBG_LOCK(rt); |
879 |
goto out; |
goto out; |
880 |
} |
} |
881 |
|
|
882 |
wp = (JSWatchPoint *) JS_malloc(cx, sizeof *wp); |
wp = (JSWatchPoint *) cx->malloc(sizeof *wp); |
883 |
if (!wp) { |
if (!wp) { |
884 |
ok = JS_FALSE; |
ok = JS_FALSE; |
885 |
goto out; |
goto out; |
915 |
++rt->debuggerMutations; |
++rt->debuggerMutations; |
916 |
} |
} |
917 |
wp->handler = handler; |
wp->handler = handler; |
918 |
wp->closure = closure; |
wp->closure = reinterpret_cast<JSObject*>(closure); |
919 |
DBG_UNLOCK(rt); |
DBG_UNLOCK(rt); |
920 |
|
|
921 |
out: |
out: |
922 |
OBJ_DROP_PROPERTY(cx, obj, prop); |
obj->dropProperty(cx, prop); |
923 |
return ok; |
return ok; |
924 |
} |
} |
925 |
|
|
1077 |
if (fp->fun) { |
if (fp->fun) { |
1078 |
callbacks = JS_GetSecurityCallbacks(cx); |
callbacks = JS_GetSecurityCallbacks(cx); |
1079 |
if (callbacks && callbacks->findObjectPrincipals) { |
if (callbacks && callbacks->findObjectPrincipals) { |
1080 |
if (FUN_OBJECT(fp->fun) != fp->callee) |
if (FUN_OBJECT(fp->fun) != fp->callee()) |
1081 |
return callbacks->findObjectPrincipals(cx, fp->callee); |
return callbacks->findObjectPrincipals(cx, fp->callee()); |
1082 |
/* FALL THROUGH */ |
/* FALL THROUGH */ |
1083 |
} |
} |
1084 |
} |
} |
1095 |
|
|
1096 |
callbacks = JS_GetSecurityCallbacks(cx); |
callbacks = JS_GetSecurityCallbacks(cx); |
1097 |
if (callbacks && callbacks->findObjectPrincipals) { |
if (callbacks && callbacks->findObjectPrincipals) { |
1098 |
principals = callbacks->findObjectPrincipals(cx, fp->callee); |
principals = callbacks->findObjectPrincipals(cx, fp->callee()); |
1099 |
} else { |
} else { |
1100 |
principals = NULL; |
principals = NULL; |
1101 |
} |
} |
1200 |
afp = NULL; |
afp = NULL; |
1201 |
} |
} |
1202 |
|
|
1203 |
if (!fp->thisp && fp->argv) |
if (fp->argv) |
1204 |
fp->thisp = js_ComputeThis(cx, JS_TRUE, fp->argv); |
fp->thisp = js_ComputeThis(cx, JS_TRUE, fp->argv); |
1205 |
|
|
1206 |
if (afp) { |
if (afp) { |
1224 |
if (!fp->fun) |
if (!fp->fun) |
1225 |
return NULL; |
return NULL; |
1226 |
|
|
1227 |
JS_ASSERT(HAS_FUNCTION_CLASS(fp->callee)); |
JS_ASSERT(HAS_FUNCTION_CLASS(fp->callee())); |
1228 |
JS_ASSERT(OBJ_GET_PRIVATE(cx, fp->callee) == fp->fun); |
JS_ASSERT(fp->callee()->getPrivate() == fp->fun); |
1229 |
return fp->callee; |
return fp->callee(); |
1230 |
} |
} |
1231 |
|
|
1232 |
JS_PUBLIC_API(JSBool) |
JS_PUBLIC_API(JSBool) |
1238 |
JS_PUBLIC_API(JSObject *) |
JS_PUBLIC_API(JSObject *) |
1239 |
JS_GetFrameCalleeObject(JSContext *cx, JSStackFrame *fp) |
JS_GetFrameCalleeObject(JSContext *cx, JSStackFrame *fp) |
1240 |
{ |
{ |
1241 |
return fp->callee; |
return fp->callee(); |
1242 |
} |
} |
1243 |
|
|
1244 |
JS_PUBLIC_API(JSBool) |
JS_PUBLIC_API(JSBool) |
1397 |
length = (uintN) len; |
length = (uintN) len; |
1398 |
ok = JS_EvaluateUCInStackFrame(cx, fp, chars, length, filename, lineno, |
ok = JS_EvaluateUCInStackFrame(cx, fp, chars, length, filename, lineno, |
1399 |
rval); |
rval); |
1400 |
JS_free(cx, chars); |
cx->free(chars); |
1401 |
|
|
1402 |
return ok; |
return ok; |
1403 |
} |
} |
1420 |
sprop = SCOPE_LAST_PROP(scope); |
sprop = SCOPE_LAST_PROP(scope); |
1421 |
} else { |
} else { |
1422 |
while ((sprop = sprop->parent) != NULL) { |
while ((sprop = sprop->parent) != NULL) { |
1423 |
if (!SCOPE_HAD_MIDDLE_DELETE(scope)) |
if (!scope->hadMiddleDelete()) |
1424 |
break; |
break; |
1425 |
if (SCOPE_HAS_PROPERTY(scope, sprop)) |
if (scope->has(sprop)) |
1426 |
break; |
break; |
1427 |
} |
} |
1428 |
} |
} |
1516 |
|
|
1517 |
/* have no props, or object's scope has not mutated from that of proto */ |
/* have no props, or object's scope has not mutated from that of proto */ |
1518 |
scope = OBJ_SCOPE(obj); |
scope = OBJ_SCOPE(obj); |
1519 |
if (scope->object != obj || scope->entryCount == 0) { |
if (scope->entryCount == 0) { |
1520 |
pda->length = 0; |
pda->length = 0; |
1521 |
pda->array = NULL; |
pda->array = NULL; |
1522 |
return JS_TRUE; |
return JS_TRUE; |
1523 |
} |
} |
1524 |
|
|
1525 |
n = scope->entryCount; |
n = scope->entryCount; |
1526 |
pd = (JSPropertyDesc *) JS_malloc(cx, (size_t)n * sizeof(JSPropertyDesc)); |
pd = (JSPropertyDesc *) cx->malloc((size_t)n * sizeof(JSPropertyDesc)); |
1527 |
if (!pd) |
if (!pd) |
1528 |
return JS_FALSE; |
return JS_FALSE; |
1529 |
i = 0; |
i = 0; |
1530 |
for (sprop = SCOPE_LAST_PROP(scope); sprop; sprop = sprop->parent) { |
for (sprop = SCOPE_LAST_PROP(scope); sprop; sprop = sprop->parent) { |
1531 |
if (SCOPE_HAD_MIDDLE_DELETE(scope) && !SCOPE_HAS_PROPERTY(scope, sprop)) |
if (scope->hadMiddleDelete() && !scope->has(sprop)) |
1532 |
continue; |
continue; |
1533 |
if (!js_AddRoot(cx, &pd[i].id, NULL)) |
if (!js_AddRoot(cx, &pd[i].id, NULL)) |
1534 |
goto bad; |
goto bad; |
1565 |
if (pd[i].flags & JSPD_ALIAS) |
if (pd[i].flags & JSPD_ALIAS) |
1566 |
js_RemoveRoot(cx->runtime, &pd[i].alias); |
js_RemoveRoot(cx->runtime, &pd[i].alias); |
1567 |
} |
} |
1568 |
JS_free(cx, pd); |
cx->free(pd); |
1569 |
} |
} |
1570 |
|
|
1571 |
/************************************************************************/ |
/************************************************************************/ |
1597 |
JS_PUBLIC_API(JSBool) |
JS_PUBLIC_API(JSBool) |
1598 |
JS_SetCallHook(JSRuntime *rt, JSInterpreterHook hook, void *closure) |
JS_SetCallHook(JSRuntime *rt, JSInterpreterHook hook, void *closure) |
1599 |
{ |
{ |
1600 |
|
#ifdef JS_TRACER |
1601 |
|
JS_LOCK_GC(rt); |
1602 |
|
bool wasInhibited = rt->debuggerInhibitsJIT(); |
1603 |
|
#endif |
1604 |
rt->globalDebugHooks.callHook = hook; |
rt->globalDebugHooks.callHook = hook; |
1605 |
rt->globalDebugHooks.callHookData = closure; |
rt->globalDebugHooks.callHookData = closure; |
1606 |
|
#ifdef JS_TRACER |
1607 |
|
JITInhibitingHookChange(rt, wasInhibited); |
1608 |
|
JS_UNLOCK_GC(rt); |
1609 |
|
if (hook) |
1610 |
|
LeaveTraceRT(rt); |
1611 |
|
#endif |
1612 |
return JS_TRUE; |
return JS_TRUE; |
1613 |
} |
} |
1614 |
|
|
1615 |
JS_PUBLIC_API(JSBool) |
JS_PUBLIC_API(JSBool) |
1616 |
JS_SetObjectHook(JSRuntime *rt, JSObjectHook hook, void *closure) |
JS_SetObjectHook(JSRuntime *rt, JSObjectHook hook, void *closure) |
1617 |
{ |
{ |
1618 |
|
#ifdef JS_TRACER |
1619 |
|
JS_LOCK_GC(rt); |
1620 |
|
bool wasInhibited = rt->debuggerInhibitsJIT(); |
1621 |
|
#endif |
1622 |
rt->globalDebugHooks.objectHook = hook; |
rt->globalDebugHooks.objectHook = hook; |
1623 |
rt->globalDebugHooks.objectHookData = closure; |
rt->globalDebugHooks.objectHookData = closure; |
1624 |
|
#ifdef JS_TRACER |
1625 |
|
JITInhibitingHookChange(rt, wasInhibited); |
1626 |
|
JS_UNLOCK_GC(rt); |
1627 |
|
if (hook) |
1628 |
|
LeaveTraceRT(rt); |
1629 |
|
#endif |
1630 |
return JS_TRUE; |
return JS_TRUE; |
1631 |
} |
} |
1632 |
|
|
1661 |
} |
} |
1662 |
if (OBJ_IS_NATIVE(obj)) { |
if (OBJ_IS_NATIVE(obj)) { |
1663 |
scope = OBJ_SCOPE(obj); |
scope = OBJ_SCOPE(obj); |
1664 |
if (scope->object == obj) { |
if (scope->owned()) { |
1665 |
nbytes += sizeof *scope; |
nbytes += sizeof *scope; |
1666 |
nbytes += SCOPE_CAPACITY(scope) * sizeof(JSScopeProperty *); |
nbytes += SCOPE_CAPACITY(scope) * sizeof(JSScopeProperty *); |
1667 |
} |
} |
1677 |
nbytes = sizeof(JSAtom *) + sizeof(JSDHashEntryStub); |
nbytes = sizeof(JSAtom *) + sizeof(JSDHashEntryStub); |
1678 |
if (ATOM_IS_STRING(atom)) { |
if (ATOM_IS_STRING(atom)) { |
1679 |
nbytes += sizeof(JSString); |
nbytes += sizeof(JSString); |
1680 |
nbytes += (JSFLATSTR_LENGTH(ATOM_TO_STRING(atom)) + 1) * sizeof(jschar); |
nbytes += (ATOM_TO_STRING(atom)->flatLength() + 1) * sizeof(jschar); |
1681 |
} else if (ATOM_IS_DOUBLE(atom)) { |
} else if (ATOM_IS_DOUBLE(atom)) { |
1682 |
nbytes += sizeof(jsdouble); |
nbytes += sizeof(jsdouble); |
1683 |
} |
} |
1721 |
if (script->filename) |
if (script->filename) |
1722 |
nbytes += strlen(script->filename) + 1; |
nbytes += strlen(script->filename) + 1; |
1723 |
|
|
1724 |
notes = SCRIPT_NOTES(script); |
notes = script->notes(); |
1725 |
for (sn = notes; !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) |
for (sn = notes; !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) |
1726 |
continue; |
continue; |
1727 |
nbytes += (sn - notes + 1) * sizeof *sn; |
nbytes += (sn - notes + 1) * sizeof *sn; |
1728 |
|
|
1729 |
if (script->objectsOffset != 0) { |
if (script->objectsOffset != 0) { |
1730 |
objarray = JS_SCRIPT_OBJECTS(script); |
objarray = script->objects(); |
1731 |
i = objarray->length; |
i = objarray->length; |
1732 |
nbytes += sizeof *objarray + i * sizeof objarray->vector[0]; |
nbytes += sizeof *objarray + i * sizeof objarray->vector[0]; |
1733 |
do { |
do { |
1736 |
} |
} |
1737 |
|
|
1738 |
if (script->regexpsOffset != 0) { |
if (script->regexpsOffset != 0) { |
1739 |
objarray = JS_SCRIPT_REGEXPS(script); |
objarray = script->regexps(); |
1740 |
i = objarray->length; |
i = objarray->length; |
1741 |
nbytes += sizeof *objarray + i * sizeof objarray->vector[0]; |
nbytes += sizeof *objarray + i * sizeof objarray->vector[0]; |
1742 |
do { |
do { |
1746 |
|
|
1747 |
if (script->trynotesOffset != 0) { |
if (script->trynotesOffset != 0) { |
1748 |
nbytes += sizeof(JSTryNoteArray) + |
nbytes += sizeof(JSTryNoteArray) + |
1749 |
JS_SCRIPT_TRYNOTES(script)->length * sizeof(JSTryNote); |
script->trynotes()->length * sizeof(JSTryNote); |
1750 |
} |
} |
1751 |
|
|
1752 |
principals = script->principals; |
principals = script->principals; |
1794 |
JS_PUBLIC_API(JSBool) |
JS_PUBLIC_API(JSBool) |
1795 |
JS_IsSystemObject(JSContext *cx, JSObject *obj) |
JS_IsSystemObject(JSContext *cx, JSObject *obj) |
1796 |
{ |
{ |
1797 |
return STOBJ_IS_SYSTEM(obj); |
return obj->isSystem(); |
1798 |
} |
} |
1799 |
|
|
1800 |
JS_PUBLIC_API(JSObject *) |
JS_PUBLIC_API(JSObject *) |
1803 |
{ |
{ |
1804 |
JSObject *obj; |
JSObject *obj; |
1805 |
|
|
1806 |
obj = js_NewObject(cx, clasp, proto, parent, 0); |
obj = js_NewObject(cx, clasp, proto, parent); |
1807 |
if (obj && system) |
if (obj && system) |
1808 |
STOBJ_SET_SYSTEM(obj); |
obj->setSystem(); |
1809 |
return obj; |
return obj; |
1810 |
} |
} |
1811 |
|
|
1812 |
/************************************************************************/ |
/************************************************************************/ |
1813 |
|
|
1814 |
JS_PUBLIC_API(JSDebugHooks *) |
JS_PUBLIC_API(const JSDebugHooks *) |
1815 |
JS_GetGlobalDebugHooks(JSRuntime *rt) |
JS_GetGlobalDebugHooks(JSRuntime *rt) |
1816 |
{ |
{ |
1817 |
return &rt->globalDebugHooks; |
return &rt->globalDebugHooks; |
1818 |
} |
} |
1819 |
|
|
1820 |
JS_PUBLIC_API(JSDebugHooks *) |
JS_PUBLIC_API(JSDebugHooks *) |
1821 |
JS_SetContextDebugHooks(JSContext *cx, JSDebugHooks *hooks) |
JS_SetContextDebugHooks(JSContext *cx, const JSDebugHooks *hooks) |
1822 |
{ |
{ |
|
JSDebugHooks *old; |
|
|
|
|
1823 |
JS_ASSERT(hooks); |
JS_ASSERT(hooks); |
1824 |
old = cx->debugHooks; |
if (hooks != &cx->runtime->globalDebugHooks) |
1825 |
|
js_LeaveTrace(cx); |
1826 |
|
|
1827 |
|
#ifdef JS_TRACER |
1828 |
|
JS_LOCK_GC(cx->runtime); |
1829 |
|
#endif |
1830 |
|
JSDebugHooks *old = const_cast<JSDebugHooks *>(cx->debugHooks); |
1831 |
cx->debugHooks = hooks; |
cx->debugHooks = hooks; |
1832 |
|
#ifdef JS_TRACER |
1833 |
|
cx->updateJITEnabled(); |
1834 |
|
JS_UNLOCK_GC(cx->runtime); |
1835 |
|
#endif |
1836 |
return old; |
return old; |
1837 |
} |
} |
1838 |
|
|
1963 |
|
|
1964 |
if (argc > 0 && JSVAL_IS_STRING(argv[0])) { |
if (argc > 0 && JSVAL_IS_STRING(argv[0])) { |
1965 |
str = JSVAL_TO_STRING(argv[0]); |
str = JSVAL_TO_STRING(argv[0]); |
1966 |
cstr = js_DeflateString(cx, JSSTRING_CHARS(str), JSSTRING_LENGTH(str)); |
cstr = js_DeflateString(cx, str->chars(), str->length()); |
1967 |
if (cstr) { |
if (cstr) { |
1968 |
CALLGRIND_DUMP_STATS_AT(cstr); |
CALLGRIND_DUMP_STATS_AT(cstr); |
1969 |
JS_free(cx, cstr); |
cx->free(cstr); |
1970 |
return JS_TRUE; |
return JS_TRUE; |
1971 |
} |
} |
1972 |
} |
} |
2038 |
|
|
2039 |
if (argc > 0 && JSVAL_IS_STRING(argv[0])) { |
if (argc > 0 && JSVAL_IS_STRING(argv[0])) { |
2040 |
str = JSVAL_TO_STRING(argv[0]); |
str = JSVAL_TO_STRING(argv[0]); |
2041 |
params.tb5Filename = js_DeflateString(cx, |
params.tb5Filename = js_DeflateString(cx, str->chars(), str->length()); |
|
JSSTRING_CHARS(str), |
|
|
JSSTRING_LENGTH(str)); |
|
2042 |
} |
} |
2043 |
|
|
2044 |
status = VTStartSampling(¶ms); |
status = VTStartSampling(¶ms); |
2045 |
|
|
2046 |
if (params.tb5Filename != default_filename) |
if (params.tb5Filename != default_filename) |
2047 |
JS_free(cx, params.tb5Filename); |
cx->free(params.tb5Filename); |
2048 |
|
|
2049 |
if (status != 0) { |
if (status != 0) { |
2050 |
if (status == VTAPI_MULTIPLE_RUNS) |
if (status == VTAPI_MULTIPLE_RUNS) |
2094 |
} |
} |
2095 |
|
|
2096 |
#endif /* MOZ_VTUNE */ |
#endif /* MOZ_VTUNE */ |
2097 |
|
|
2098 |
|
#ifdef MOZ_TRACEVIS |
2099 |
|
/* |
2100 |
|
* Ethogram - Javascript wrapper for TraceVis state |
2101 |
|
* |
2102 |
|
* ethology: The scientific study of animal behavior, |
2103 |
|
* especially as it occurs in a natural environment. |
2104 |
|
* ethogram: A pictorial catalog of the behavioral patterns of |
2105 |
|
* an organism or a species. |
2106 |
|
* |
2107 |
|
*/ |
2108 |
|
#if defined(XP_WIN) |
2109 |
|
#include <windows.h> |
2110 |
|
#else |
2111 |
|
#include <sys/time.h> |
2112 |
|
#endif |
2113 |
|
#include "jstracer.h" |
2114 |
|
|
2115 |
|
#define ETHOGRAM_BUF_SIZE 65536 |
2116 |
|
|
2117 |
|
static JSBool |
2118 |
|
ethogram_construct(JSContext *cx, JSObject *obj, |
2119 |
|
uintN argc, jsval *argv, jsval *rval); |
2120 |
|
static void |
2121 |
|
ethogram_finalize(JSContext *cx, JSObject *obj); |
2122 |
|
|
2123 |
|
static JSClass ethogram_class = { |
2124 |
|
"Ethogram", |
2125 |
|
JSCLASS_HAS_PRIVATE, |
2126 |
|
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, |
2127 |
|
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, ethogram_finalize, |
2128 |
|
JSCLASS_NO_OPTIONAL_MEMBERS |
2129 |
|
}; |
2130 |
|
|
2131 |
|
struct EthogramEvent { |
2132 |
|
TraceVisState s; |
2133 |
|
TraceVisExitReason r; |
2134 |
|
int ts; |
2135 |
|
int tus; |
2136 |
|
JSString *filename; |
2137 |
|
int lineno; |
2138 |
|
}; |
2139 |
|
|
2140 |
|
static int |
2141 |
|
compare_strings(const void *k1, const void *k2) |
2142 |
|
{ |
2143 |
|
return strcmp((const char *) k1, (const char *) k2) == 0; |
2144 |
|
} |
2145 |
|
|
2146 |
|
class EthogramEventBuffer { |
2147 |
|
private: |
2148 |
|
EthogramEvent mBuf[ETHOGRAM_BUF_SIZE]; |
2149 |
|
int mReadPos; |
2150 |
|
int mWritePos; |
2151 |
|
JSObject *mFilenames; |
2152 |
|
int mStartSecond; |
2153 |
|
|
2154 |
|
struct EthogramScriptEntry { |
2155 |
|
char *filename; |
2156 |
|
JSString *jsfilename; |
2157 |
|
|
2158 |
|
EthogramScriptEntry *next; |
2159 |
|
}; |
2160 |
|
EthogramScriptEntry *mScripts; |
2161 |
|
|
2162 |
|
public: |
2163 |
|
friend JSBool |
2164 |
|
ethogram_construct(JSContext *cx, JSObject *obj, |
2165 |
|
uintN argc, jsval *argv, jsval *rval); |
2166 |
|
|
2167 |
|
inline void push(TraceVisState s, TraceVisExitReason r, char *filename, int lineno) { |
2168 |
|
mBuf[mWritePos].s = s; |
2169 |
|
mBuf[mWritePos].r = r; |
2170 |
|
#if defined(XP_WIN) |
2171 |
|
FILETIME now; |
2172 |
|
GetSystemTimeAsFileTime(&now); |
2173 |
|
unsigned long long raw_us = 0.1 * |
2174 |
|
(((unsigned long long) now.dwHighDateTime << 32ULL) | |
2175 |
|
(unsigned long long) now.dwLowDateTime); |
2176 |
|
unsigned int sec = raw_us / 1000000L; |
2177 |
|
unsigned int usec = raw_us % 1000000L; |
2178 |
|
mBuf[mWritePos].ts = sec - mStartSecond; |
2179 |
|
mBuf[mWritePos].tus = usec; |
2180 |
|
#else |
2181 |
|
struct timeval tv; |
2182 |
|
gettimeofday(&tv, NULL); |
2183 |
|
mBuf[mWritePos].ts = tv.tv_sec - mStartSecond; |
2184 |
|
mBuf[mWritePos].tus = tv.tv_usec; |
2185 |
|
#endif |
2186 |
|
|
2187 |
|
JSString *jsfilename = findScript(filename); |
2188 |
|
mBuf[mWritePos].filename = jsfilename; |
2189 |
|
mBuf[mWritePos].lineno = lineno; |
2190 |
|
|
2191 |
|
mWritePos = (mWritePos + 1) % ETHOGRAM_BUF_SIZE; |
2192 |
|
if (mWritePos == mReadPos) { |
2193 |
|
mReadPos = (mWritePos + 1) % ETHOGRAM_BUF_SIZE; |
2194 |
|
} |
2195 |
|
} |
2196 |
|
|
2197 |
|
inline EthogramEvent *pop() { |
2198 |
|
EthogramEvent *e = &mBuf[mReadPos]; |
2199 |
|
mReadPos = (mReadPos + 1) % ETHOGRAM_BUF_SIZE; |
2200 |
|
return e; |
2201 |
|
} |
2202 |
|
|
2203 |
|
bool isEmpty() { |
2204 |
|
return (mReadPos == mWritePos); |
2205 |
|
} |
2206 |
|
|
2207 |
|
EthogramScriptEntry *addScript(JSContext *cx, JSObject *obj, char *filename, JSString *jsfilename) { |
2208 |
|
JSHashNumber hash = JS_HashString(filename); |
2209 |
|
JSHashEntry **hep = JS_HashTableRawLookup(traceVisScriptTable, hash, filename); |
2210 |
|
if (*hep != NULL) |
2211 |
|
return JS_FALSE; |
2212 |
|
|
2213 |
|
JS_HashTableRawAdd(traceVisScriptTable, hep, hash, filename, this); |
2214 |
|
|
2215 |
|
EthogramScriptEntry * entry = (EthogramScriptEntry *) JS_malloc(cx, sizeof(EthogramScriptEntry)); |
2216 |
|
if (entry == NULL) |
2217 |
|
return NULL; |
2218 |
|
|
2219 |
|
entry->next = mScripts; |
2220 |
|
mScripts = entry; |
2221 |
|
entry->filename = filename; |
2222 |
|
entry->jsfilename = jsfilename; |
2223 |
|
|
2224 |
|
return mScripts; |
2225 |
|
} |
2226 |
|
|
2227 |
|
void removeScripts(JSContext *cx) { |
2228 |
|
EthogramScriptEntry *se = mScripts; |
2229 |
|
while (se != NULL) { |
2230 |
|
char *filename = se->filename; |
2231 |
|
|
2232 |
|
JSHashNumber hash = JS_HashString(filename); |
2233 |
|
JSHashEntry **hep = JS_HashTableRawLookup(traceVisScriptTable, hash, filename); |
2234 |
|
JSHashEntry *he = *hep; |
2235 |
|
if (he) { |
2236 |
|
/* we hardly knew he */ |
2237 |
|
JS_HashTableRawRemove(traceVisScriptTable, hep, he); |
2238 |
|
} |
2239 |
|
|
2240 |
|
EthogramScriptEntry *se_head = se; |
2241 |
|
se = se->next; |
2242 |
|
JS_free(cx, se_head); |
2243 |
|
} |
2244 |
|
} |
2245 |
|
|
2246 |
|
JSString *findScript(char *filename) { |
2247 |
|
EthogramScriptEntry *se = mScripts; |
2248 |
|
while (se != NULL) { |
2249 |
|
if (compare_strings(se->filename, filename)) |
2250 |
|
return (se->jsfilename); |
2251 |
|
se = se->next; |
2252 |
|
} |
2253 |
|
return NULL; |
2254 |
|
} |
2255 |
|
|
2256 |
|
JSObject *filenames() { |
2257 |
|
return mFilenames; |
2258 |
|
} |
2259 |
|
|
2260 |
|
int length() { |
2261 |
|
if (mWritePos < mReadPos) |
2262 |
|
return (mWritePos + ETHOGRAM_BUF_SIZE) - mReadPos; |
2263 |
|
else |
2264 |
|
return mWritePos - mReadPos; |
2265 |
|
} |
2266 |
|
}; |
2267 |
|
|
2268 |
|
static char jstv_empty[] = "<null>"; |
2269 |
|
|
2270 |
|
inline char * |
2271 |
|
jstv_Filename(JSStackFrame *fp) |
2272 |
|
{ |
2273 |
|
while (fp && fp->script == NULL) |
2274 |
|
fp = fp->down; |
2275 |
|
return (fp && fp->script && fp->script->filename) |
2276 |
|
? (char *)fp->script->filename |
2277 |
|
: jstv_empty; |
2278 |
|
} |
2279 |
|
inline uintN |
2280 |
|
jstv_Lineno(JSContext *cx, JSStackFrame *fp) |
2281 |
|
{ |
2282 |
|
while (fp && fp->regs == NULL) |
2283 |
|
fp = fp->down; |
2284 |
|
return (fp && fp->regs) ? js_FramePCToLineNumber(cx, fp) : 0; |
2285 |
|
} |
2286 |
|
|
2287 |
|
/* Collect states here and distribute to a matching buffer, if any */ |
2288 |
|
JS_FRIEND_API(void) |
2289 |
|
js_StoreTraceVisState(JSContext *cx, TraceVisState s, TraceVisExitReason r) |
2290 |
|
{ |
2291 |
|
JSStackFrame *fp = cx->fp; |
2292 |
|
|
2293 |
|
char *script_file = jstv_Filename(fp); |
2294 |
|
JSHashNumber hash = JS_HashString(script_file); |
2295 |
|
|
2296 |
|
JSHashEntry **hep = JS_HashTableRawLookup(traceVisScriptTable, hash, script_file); |
2297 |
|
/* update event buffer, flag if overflowed */ |
2298 |
|
JSHashEntry *he = *hep; |
2299 |
|
if (he) { |
2300 |
|
EthogramEventBuffer *p; |
2301 |
|
p = (EthogramEventBuffer *) he->value; |
2302 |
|
|
2303 |
|
p->push(s, r, script_file, jstv_Lineno(cx, fp)); |
2304 |
|
} |
2305 |
|
} |
2306 |
|
|
2307 |
|
static JSBool |
2308 |
|
ethogram_construct(JSContext *cx, JSObject *obj, |
2309 |
|
uintN argc, jsval *argv, jsval *rval) |
2310 |
|
{ |
2311 |
|
EthogramEventBuffer *p; |
2312 |
|
|
2313 |
|
p = (EthogramEventBuffer *) JS_malloc(cx, sizeof(EthogramEventBuffer)); |
2314 |
|
|
2315 |
|
p->mReadPos = p->mWritePos = 0; |
2316 |
|
p->mScripts = NULL; |
2317 |
|
p->mFilenames = JS_NewArrayObject(cx, 0, NULL); |
2318 |
|
|
2319 |
|
#if defined(XP_WIN) |
2320 |
|
FILETIME now; |
2321 |
|
GetSystemTimeAsFileTime(&now); |
2322 |
|
unsigned long long raw_us = 0.1 * |
2323 |
|
(((unsigned long long) now.dwHighDateTime << 32ULL) | |
2324 |
|
(unsigned long long) now.dwLowDateTime); |
2325 |
|
unsigned int s = raw_us / 1000000L; |
2326 |
|
p->mStartSecond = s; |
2327 |
|
#else |
2328 |
|
struct timeval tv; |
2329 |
|
gettimeofday(&tv, NULL); |
2330 |
|
p->mStartSecond = tv.tv_sec; |
2331 |
|
#endif |
2332 |
|
jsval filenames = OBJECT_TO_JSVAL(p->filenames()); |
2333 |
|
if (!JS_DefineProperty(cx, obj, "filenames", filenames, |
2334 |
|
NULL, NULL, JSPROP_READONLY|JSPROP_PERMANENT)) |
2335 |
|
return JS_FALSE; |
2336 |
|
|
2337 |
|
if (!JS_IsConstructing(cx)) { |
2338 |
|
obj = JS_NewObject(cx, ðogram_class, NULL, NULL); |
2339 |
|
if (!obj) |
2340 |
|
return JS_FALSE; |
2341 |
|
*rval = OBJECT_TO_JSVAL(obj); |
2342 |
|
} |
2343 |
|
JS_SetPrivate(cx, obj, p); |
2344 |
|
return JS_TRUE; |
2345 |
|
} |
2346 |
|
|
2347 |
|
static void |
2348 |
|
ethogram_finalize(JSContext *cx, JSObject *obj) |
2349 |
|
{ |
2350 |
|
EthogramEventBuffer *p; |
2351 |
|
p = (EthogramEventBuffer *) JS_GetInstancePrivate(cx, obj, ðogram_class, NULL); |
2352 |
|
if (!p) |
2353 |
|
return; |
2354 |
|
|
2355 |
|
p->removeScripts(cx); |
2356 |
|
|
2357 |
|
JS_free(cx, p); |
2358 |
|
} |
2359 |
|
|
2360 |
|
static JSBool |
2361 |
|
ethogram_addScript(JSContext *cx, JSObject *obj, |
2362 |
|
uintN argc, jsval *argv, jsval *rval) |
2363 |
|
{ |
2364 |
|
JSString *str; |
2365 |
|
char *filename = NULL; |
2366 |
|
if (argc > 0 && JSVAL_IS_STRING(argv[0])) { |
2367 |
|
str = JSVAL_TO_STRING(argv[0]); |
2368 |
|
filename = js_DeflateString(cx, |
2369 |
|
str->chars(), |
2370 |
|
str->length()); |
2371 |
|
} |
2372 |
|
|
2373 |
|
/* silently ignore no args */ |
2374 |
|
if (!filename) |
2375 |
|
return JS_TRUE; |
2376 |
|
|
2377 |
|
EthogramEventBuffer *p = (EthogramEventBuffer *) JS_GetInstancePrivate(cx, obj, ðogram_class, argv); |
2378 |
|
|
2379 |
|
p->addScript(cx, obj, filename, str); |
2380 |
|
JS_CallFunctionName(cx, p->filenames(), "push", 1, argv, rval); |
2381 |
|
return JS_TRUE; |
2382 |
|
} |
2383 |
|
|
2384 |
|
static JSBool |
2385 |
|
ethogram_getAllEvents(JSContext *cx, JSObject *obj, |
2386 |
|
uintN argc, jsval *argv, jsval *rval) |
2387 |
|
{ |
2388 |
|
EthogramEventBuffer *p; |
2389 |
|
|
2390 |
|
p = (EthogramEventBuffer *) JS_GetInstancePrivate(cx, obj, ðogram_class, argv); |
2391 |
|
if (!p) |
2392 |
|
return JS_FALSE; |
2393 |
|
|
2394 |
|
if (p->isEmpty()) { |
2395 |
|
*rval = JSVAL_NULL; |
2396 |
|
return JS_TRUE; |
2397 |
|
} |
2398 |
|
|
2399 |
|
JSObject *rarray = JS_NewArrayObject(cx, 0, NULL); |
2400 |
|
if (rarray == NULL) { |
2401 |
|
*rval = JSVAL_NULL; |
2402 |
|
return JS_TRUE; |
2403 |
|
} |
2404 |
|
|
2405 |
|
*rval = OBJECT_TO_JSVAL(rarray); |
2406 |
|
|
2407 |
|
for (int i = 0; !p->isEmpty(); i++) { |
2408 |
|
|
2409 |
|
JSObject *x = JS_NewObject(cx, NULL, NULL, NULL); |
2410 |
|
if (x == NULL) |
2411 |
|
return JS_FALSE; |
2412 |
|
|
2413 |
|
EthogramEvent *e = p->pop(); |
2414 |
|
|
2415 |
|
jsval state = INT_TO_JSVAL(e->s); |
2416 |
|
jsval reason = INT_TO_JSVAL(e->r); |
2417 |
|
jsval ts = INT_TO_JSVAL(e->ts); |
2418 |
|
jsval tus = INT_TO_JSVAL(e->tus); |
2419 |
|
|
2420 |
|
jsval filename = STRING_TO_JSVAL(e->filename); |
2421 |
|
jsval lineno = INT_TO_JSVAL(e->lineno); |
2422 |
|
|
2423 |
|
if (!JS_SetProperty(cx, x, "state", &state)) |
2424 |
|
return JS_FALSE; |
2425 |
|
if (!JS_SetProperty(cx, x, "reason", &reason)) |
2426 |
|
return JS_FALSE; |
2427 |
|
if (!JS_SetProperty(cx, x, "ts", &ts)) |
2428 |
|
return JS_FALSE; |
2429 |
|
if (!JS_SetProperty(cx, x, "tus", &tus)) |
2430 |
|
return JS_FALSE; |
2431 |
|
|
2432 |
|
if (!JS_SetProperty(cx, x, "filename", &filename)) |
2433 |
|
return JS_FALSE; |
2434 |
|
if (!JS_SetProperty(cx, x, "lineno", &lineno)) |
2435 |
|
return JS_FALSE; |
2436 |
|
|
2437 |
|
jsval element = OBJECT_TO_JSVAL(x); |
2438 |
|
JS_SetElement(cx, rarray, i, &element); |
2439 |
|
} |
2440 |
|
|
2441 |
|
return JS_TRUE; |
2442 |
|
} |
2443 |
|
|
2444 |
|
static JSBool |
2445 |
|
ethogram_getNextEvent(JSContext *cx, JSObject *obj, |
2446 |
|
uintN argc, jsval *argv, jsval *rval) |
2447 |
|
{ |
2448 |
|
EthogramEventBuffer *p; |
2449 |
|
|
2450 |
|
p = (EthogramEventBuffer *) JS_GetInstancePrivate(cx, obj, ðogram_class, argv); |
2451 |
|
if (!p) |
2452 |
|
return JS_FALSE; |
2453 |
|
|
2454 |
|
JSObject *x = JS_NewObject(cx, NULL, NULL, NULL); |
2455 |
|
if (x == NULL) |
2456 |
|
return JS_FALSE; |
2457 |
|
|
2458 |
|
if (p->isEmpty()) { |
2459 |
|
*rval = JSVAL_NULL; |
2460 |
|
return JS_TRUE; |
2461 |
|
} |
2462 |
|
|
2463 |
|
EthogramEvent *e = p->pop(); |
2464 |
|
jsval state = INT_TO_JSVAL(e->s); |
2465 |
|
jsval reason = INT_TO_JSVAL(e->r); |
2466 |
|
jsval ts = INT_TO_JSVAL(e->ts); |
2467 |
|
jsval tus = INT_TO_JSVAL(e->tus); |
2468 |
|
|
2469 |
|
jsval filename = STRING_TO_JSVAL(e->filename); |
2470 |
|
jsval lineno = INT_TO_JSVAL(e->lineno); |
2471 |
|
|
2472 |
|
if (!JS_SetProperty(cx, x, "state", &state)) |
2473 |
|
return JS_FALSE; |
2474 |
|
if (!JS_SetProperty(cx, x, "reason", &reason)) |
2475 |
|
return JS_FALSE; |
2476 |
|
if (!JS_SetProperty(cx, x, "ts", &ts)) |
2477 |
|
return JS_FALSE; |
2478 |
|
if (!JS_SetProperty(cx, x, "tus", &tus)) |
2479 |
|
return JS_FALSE; |
2480 |
|
if (!JS_SetProperty(cx, x, "filename", &filename)) |
2481 |
|
return JS_FALSE; |
2482 |
|
|
2483 |
|
if (!JS_SetProperty(cx, x, "lineno", &lineno)) |
2484 |
|
return JS_FALSE; |
2485 |
|
|
2486 |
|
*rval = OBJECT_TO_JSVAL(x); |
2487 |
|
|
2488 |
|
return JS_TRUE; |
2489 |
|
} |
2490 |
|
|
2491 |
|
static JSFunctionSpec ethogram_methods[] = { |
2492 |
|
{"addScript", ethogram_addScript, 1}, |
2493 |
|
{"getAllEvents", ethogram_getAllEvents, 0}, |
2494 |
|
{"getNextEvent", ethogram_getNextEvent, 0}, |
2495 |
|
{0} |
2496 |
|
}; |
2497 |
|
|
2498 |
|
/* |
2499 |
|
* An |Ethogram| organizes the output of a collection of files that should be |
2500 |
|
* monitored together. A single object gets events for the group. |
2501 |
|
*/ |
2502 |
|
JS_FRIEND_API(JSBool) |
2503 |
|
js_InitEthogram(JSContext *cx, JSObject *obj, |
2504 |
|
uintN argc, jsval *argv, jsval *rval) |
2505 |
|
{ |
2506 |
|
if (!traceVisScriptTable) { |
2507 |
|
traceVisScriptTable = JS_NewHashTable(8, JS_HashString, compare_strings, |
2508 |
|
NULL, NULL, NULL); |
2509 |
|
} |
2510 |
|
|
2511 |
|
JS_InitClass(cx, JS_GetGlobalObject(cx), NULL, ðogram_class, |
2512 |
|
ethogram_construct, 0, NULL, ethogram_methods, |
2513 |
|
NULL, NULL); |
2514 |
|
|
2515 |
|
return JS_TRUE; |
2516 |
|
} |
2517 |
|
|
2518 |
|
JS_FRIEND_API(JSBool) |
2519 |
|
js_ShutdownEthogram(JSContext *cx, JSObject *obj, |
2520 |
|
uintN argc, jsval *argv, jsval *rval) |
2521 |
|
{ |
2522 |
|
if (traceVisScriptTable) |
2523 |
|
JS_HashTableDestroy(traceVisScriptTable); |
2524 |
|
|
2525 |
|
return JS_TRUE; |
2526 |
|
} |
2527 |
|
|
2528 |
|
#endif /* MOZ_TRACEVIS */ |