37#define __block __glibc_block
47#define OOJS_DEBUG_LIMITER 1
49#define OOJS_DEBUG_LIMITER 0
61#define OOJS_TIME_LIMIT (0.2)
63#define OOJS_TIME_LIMIT (1)
76#if OOJS_PROFILE && defined(MOZ_TRACE_JSCALLS)
77static void FunctionCallback(JSFunction *
function, JSScript *script, JSContext *context,
int entering);
116 OOLog(
@"bug.javaScript.limiterDepth",
@"Attempt to stop JavaScript time limiter while it is already fully stopped. This is an internal bug, please report it. (Last start: %@:%u, last valid stop: %@:%u, this stop attempt: %@:%u.)",
OOLogAbbreviatedFileName(
sLastStartedFile),
sLastStartedLine,
OOLogAbbreviatedFileName(
sLastStoppedFile),
sLastStoppedLine,
OOLogAbbreviatedFileName(file), line);
123#if OOJS_DEBUG_LIMITER
186@implementation OOJavaScriptEngine (WatchdogTimer)
209 JS_TriggerAllOperationCallbacks(_runtime);
219 if (!
sStop)
return YES;
221 JS_ClearPendingException(context);
229 OOLogERR(
@"script.javaScript.timeLimit",
@"Script \"%@\
" ran for %g seconds and has been terminated.", [[
OOJSScript currentlyRunningScript] name], elapsed);
242 if (contextOp == JSCONTEXT_NEW)
246#if OOJS_PROFILE && defined(MOZ_TRACE_JSCALLS)
247 JS_SetFunctionCallback(context, (JSFunctionCallback)FunctionCallback);
256 [NSThread detachNewThreadSelector:@selector(watchdogTimerThread)
266#ifndef MOZ_TRACE_JSCALLS
267#warning Profiling is enabled, but MOZ_TRACE_JSCALLS is disabled, so only native functions will be profiled.
281@interface OOTimeProfile (Private)
283- (void) setTotalTime:(
double)value;
284- (void) setNativeTime:(
double)value;
285#ifdef MOZ_TRACE_JSCALLS
286- (void) setJavaScriptTime:(
double)value;
288- (void) setProfilerOverhead:(
double)value;
289- (void) setExtensionTime:(
double)value;
290- (void) setProfileEntries:(NSArray *)value;
297@interface OOTimeProfileEntry (Private)
299- (id) initWithCName:(const
char *)name;
300#ifdef MOZ_TRACE_JSCALLS
301- (id) initWithJSFunction:(JSFunction *)function context:(JSContext *)context;
316 sProfileInfo = NSCreateMapTable(NSNonOwnedPointerMapKeyCallBacks, NSObjectMapValueCallBacks, 100);
327 OOLog(
@"script.javaScript.trace",
@"%@",
@">>>> Beginning trace.");
346 [result
setTotalTime:OOHighResTimeDeltaInSeconds(sProfilerStartTime, now)];
348#ifdef MOZ_TRACE_JSCALLS
349 [result setJavaScriptTime:sProfilerTotalJavaScriptTime];
356 [result
setProfileEntries:[NSAllMapTableValues(sProfileInfo) sortedArrayUsingSelector:@selector(compareBySelfTimeReverse:)]];
361 OOLog(
@"script.javaScript.trace",
@"%@",
@"<<<< End of trace.");
389#ifdef MOZ_TRACE_JSCALLS
390static void CleanUpJSFrame(OOJSProfileStackFrame *frame)
396static void TraceEnterJSFunction(JSContext *context, JSFunction *
function, OOTimeProfileEntry *profileEntry)
398 NSMutableString *name = [NSMutableString stringWithFormat:@"%@(", [profileEntry
function]];
399 BOOL isNative = JS_GetFunctionNative(context,
function) != NULL;
400 NSString *frameTag =
nil;
401 NSString *logMsgClass =
nil;
406 JSStackFrame *frame = NULL;
410 JSPropertyDescArray properties = { 0 , NULL };
416 if (JS_FrameIterator(context, &frame) != NULL)
418 if (JS_IsConstructorFrame(context, frame))
420 [name insertString:@"new " atIndex:0];
423 if (JS_GetFrameThis(context, frame, &
this))
425 [name appendFormat:@"this: %@", OOJSDescribeValue(context, this, YES)];
429 scope = JS_GetFrameScopeChain(context, frame);
430 if (scope != NULL && JS_GetPropertyDescArray(context, scope, &properties))
432 for (i = 0; i < properties.length; i++)
434 JSPropertyDesc *prop = &properties.array[i];
435 if (prop->flags & JSPD_ARGUMENT)
437 if (!first) [name appendFormat:
@", "];
440 [name appendFormat:
@"%@: %@", OOStringFromJSValueEvenIfNull(context, prop->id), OOJSDescribeValue(context, prop->value, YES)];
449 logMsgClass =
@"script.javaScript.trace.JS";
454 logMsgClass =
@"script.javaScript.trace.NW";
457 [name appendString:@")"];
458 OOLog(logMsgClass,
@">> %@ [%@]", name, frameTag);
463static void FunctionCallback(JSFunction *
function, JSScript *script, JSContext *context,
int entering)
469 if (!
sTracing && JS_GetFunctionNative(context,
function) != NULL)
return;
473 NSAutoreleasePool *pool = [NSAutoreleasePool new];
478 OOTimeProfileEntry *entry = NSMapGet(
sProfileInfo,
function);
489 TraceEnterJSFunction(context,
function, entry);
493 OOJSProfileStackFrame *frame = malloc(
sizeof(OOJSProfileStackFrame));
494 assert(frame != NULL);
496 *frame = (OOJSProfileStackFrame)
503 .cleanup = CleanUpJSFrame
533 OOLog(
@"script.javaScript.trace.ON",
@">> %s [ON]",
function);
537 *frame = (OOJSProfileStackFrame)
541 .function =
function,
554 NSAutoreleasePool *pool = [NSAutoreleasePool new];
599 NSMapInsertKnownAbsent(
sProfileInfo, frame->key, entry);
607 *(frame->total) += selfTime;
610 if (frame->cleanup != NULL) frame->cleanup(frame);
616@implementation OOTimeProfile
631 @"Total time: %g ms\n"
632 "JavaScript: %g ms, native: %g ms\n"
633 "Counted towards limit: %g ms, excluded: %g ms\n"
634 "Profiler overhead: %g ms",
641 NSUInteger i,
count = [profileEntries count];
644 [
result appendString:@"\n NAME T COUNT TOTAL SELF TOTAL% SELF% SELFMAX"];
645 for (i = 0; i <
count; i++)
654 [
result appendFormat:@"\n%60s %c%7lu %8.2f %8.2f %5.1f %5.1f %8.2f",
671- (void) setTotalTime:(
double)value
671- (void) setTotalTime:(
double)value {
…}
679#ifdef MOZ_TRACE_JSCALLS
680 return _javaScriptTime;
687#ifdef MOZ_TRACE_JSCALLS
688- (void) setJavaScriptTime:(
double)value
690 _javaScriptTime = value;
701- (void) setNativeTime:(
double)value
701- (void) setNativeTime:(
double)value {
…}
713- (void) setExtensionTime:(
double)value
715 _extensionTime = value;
713- (void) setExtensionTime:(
double)value {
…}
731- (void) setProfilerOverhead:(
double)value
733 _profilerOverhead = value;
731- (void) setProfilerOverhead:(
double)value {
…}
743- (void) setProfileEntries:(NSArray *)value
745 if (_profileEntries != value)
748 _profileEntries = [
value retain];
743- (void) setProfileEntries:(NSArray *)value {
…}
753- (jsval) oo_jsValueInContext:(JSContext *)context
753- (jsval) oo_jsValueInContext:(JSContext *)context {
…}
763 NSEnumerator *entryEnum =
nil;
765 for (entryEnum = [profileEntries objectEnumerator]; (entry = [
entryEnum nextObject]); )
771 profileEntries, @"profiles",
786- (id) initWithCName:(const
char *)name
788 NSAssert(
sProfiling,
@"Can't create profile entries while not profiling.");
790 if ((
self = [super init]))
794 _function = [[
NSString stringWithUTF8String:name] retain];
786- (id) initWithCName:(const
char *)name {
…}
803- (id) initWithJSFunction:(JSFunction *)function context:(JSContext *)context
805 if ((
self = [
self initWithCName:NULL]))
809 _jsFunction =
function;
811 NSString *funcName =
nil;
812 JSString *jsName = JS_GetFunctionId(_jsFunction);
813 if (jsName != NULL) funcName = [OOStringFromJSString(context, jsName) retain];
814 else funcName =
@"<anonymous>";
817 NSString *location =
nil;
818 if (JS_GetFunctionNative(context,
function) == NULL)
820 JSStackFrame *frame = NULL;
821 if (JS_FrameIterator(context, &frame) != NULL)
829 _function = [[NSString alloc] initWithFormat:@"(%@) %@", location, funcName];
831 else _function = [funcName retain];
852 _totalTimeSum += totalTime;
853 _selfTimeSum += selfTime;
854 _totalTimeMax = fmax(_totalTimeMax, totalTime);
855 _selfTimeMax = fmax(_selfTimeMax, selfTime);
873 return [
NSString stringWithFormat:@"%@: 1 time, %g ms", _function, totalTimeSum];
877 return [
NSString stringWithFormat:@"%@: %lu times, total %g ms, avg %g ms, max %g ms", _function, _hitCount, totalTimeSum, totalTimeSum / _hitCount, totalTimeMax];
884 return [
NSString stringWithFormat:@"%@: 1 time, %g ms (self %g ms)", _function, totalTimeSum, selfTimeSum];
888 return [
NSString stringWithFormat:@"%@: %lu times, total %g ms (self %g ms), avg %g ms (self %g ms), max %g ms, max self %g ms", _function, _hitCount, totalTimeSum, selfTimeSum, totalTimeSum / _hitCount, selfTimeSum / _hitCount, totalTimeMax, selfTimeMax];
945 return _jsFunction != NULL;
963 if (selfTotal < otherTotal)
return NSOrderedDescending;
964 if (selfTotal > otherTotal)
return NSOrderedAscending;
965 return NSOrderedSame;
980 if (selfTotal < otherTotal)
return NSOrderedDescending;
981 if (selfTotal > otherTotal)
return NSOrderedAscending;
982 return NSOrderedSame;
986- (jsval) oo_jsValueInContext:(JSContext *)context
986- (jsval) oo_jsValueInContext:(JSContext *)context {
…}
#define OOJSProfileExit(frame)
#define OOJSProfileEnter(frame, function)
OOTimeProfile * OOJSEndProfiling(void)
#define OOJSStopTimeLimiter()
BOOL OOJSIsProfiling(void)
void OOJSBeginProfiling(BOOL trace)
OOTimeDelta OOJSGetTimeLimiterLimit(void)
void OOJSTimeManagementInit(OOJavaScriptEngine *engine, JSRuntime *runtime)
#define OOJSStartTimeLimiterWithTimeLimit(limit)
void OOJSPauseTimeLimiter(void)
static OOJSProfileStackFrame * sProfileStack
void OOJSBeginTracing(void)
void OOJSResetTimeLimiter(void)
static void UpdateProfileForFrame(OOHighResTimeValue now, OOJSProfileStackFrame *frame)
static double sProfilerTotalNativeTime
static unsigned sLastStoppedLine
static const char * sLastStoppedFile
static OOHighResTimeValue sProfilerStartTime
static double sProfilerOverhead
static JSBool OperationCallback(JSContext *context)
static const char * sLastStartedFile
void OOJSEndTracing(void)
OOHighResTimeValue OOJSCopyTimeLimiterNominalStartTime(void)
static OOHighResTimeValue sLimiterPauseStart
static double sLimiterTimeLimit
OOTimeDelta OOJSGetTimeLimiterLimit(void)
static double sProfilerTotalJavaScriptTime
static int sLimiterPauseDepth
static double sProfilerEntryTimeLimit
void OOJSStartTimeLimiterWithTimeLimit_(OOTimeDelta limit, const char *file, unsigned line)
static unsigned sLimiterStartDepth
void OOJSStopTimeLimiter_(const char *file, unsigned line)
void OOJSResumeTimeLimiter(void)
static OOHighResTimeValue sLimiterStart
static unsigned sLastStartedLine
static JSBool ContextCallback(JSContext *context, uintN contextOp)
static NSMapTable * sProfileInfo
void OOJSSetTimeLimiterLimit(OOTimeDelta limit)
void OOJSPauseTimeLimiter(void)
OOINLINE jsval OOJSValueFromNativeObject(JSContext *context, id object)
void OOJSResumeTimeLimiter(void)
NSString * OOJSDescribeLocation(JSContext *context, JSStackFrame *stackFrame)
void OOJSDumpStack(JSContext *context)
#define OOLogERR(class, format,...)
#define OOLog(class, format,...)
NSString * OOLogAbbreviatedFileName(const char *inName)
OOTimeDelta OOHighResTimeDeltaInSeconds(OOHighResTimeValue startTime, OOHighResTimeValue endTime)
uint64_t OOHighResTimeValue
#define OODisposeHighResTime(time)
void watchdogTimerThread()
NSDictionary * propertyListRepresentation()
NSDictionary * propertyListRepresentation()
double totalTimeAverage()
NSDictionary * propertyListRepresentation()
NSComparisonResult compareBySelfTimeReverse:(OOTimeProfileEntry *other)
NSComparisonResult compareByTotalTimeReverse:(OOTimeProfileEntry *other)
void addSampleWithTotalTime:selfTime:(OOTimeDelta totalTime, [selfTime] OOTimeDelta selfTime)
NSArray * profileEntries()
void setNativeTime:(double value)
void setTotalTime:(double value)
void setProfilerOverhead:(double value)
void setExtensionTime:(double value)
double nonExtensionTime()
NSArray * _profileEntries
NSDictionary * propertyListRepresentation()
double profilerOverhead()
void setProfileEntries:(NSArray *value)