Oolite 1.91.0.7645-241119-222d325
Loading...
Searching...
No Matches
OOJSFrameCallbacks.m File Reference
+ Include dependency graph for OOJSFrameCallbacks.m:

Go to the source code of this file.

Classes

struct  CallbackEntry
 

Macros

#define DEBUG_FCB_SIMPLE_TRACKING_IDS   0
 
#define DEBUG_FCB_VERBOSE_LOGGING   0
 
#define FCBLog(...)
 
#define FCBLogIndentIf(key)
 
#define FCBLogOutdentIf(key)
 

Enumerations

enum  { kMinCount = 16 , kIDScrambleMask = 0x2315EB16 , kIDIncrement = 992699 }
 

Functions

static JSBool GlobalAddFrameCallback (JSContext *context, uintN argc, jsval *vp)
 
static JSBool GlobalRemoveFrameCallback (JSContext *context, uintN argc, jsval *vp)
 
static JSBool GlobalIsValidFrameCallback (JSContext *context, uintN argc, jsval *vp)
 
static BOOL AddCallback (JSContext *context, jsval callback, uint32 trackingID, NSString **errorString)
 
static BOOL GrowCallbackList (JSContext *context, NSString **errorString)
 
static BOOL GetIndexForTrackingID (uint32 trackingID, NSUInteger *outIndex)
 
static BOOL RemoveCallbackWithTrackingID (JSContext *context, uint32 trackingID)
 
static void RemoveCallbackAtIndex (JSContext *context, NSUInteger index)
 
static void QueueDeferredOperation (NSString *opType, uint32 trackingID, OOJSValue *value)
 
static void RunDeferredOperations (JSContext *context)
 
void InitOOJSFrameCallbacks (JSContext *context, JSObject *global)
 
void OOJSFrameCallbacksInvoke (OOTimeDelta inDeltaT)
 
void OOJSFrameCallbacksRemoveAll (void)
 

Variables

static CallbackEntrysCallbacks
 
static NSUInteger sCount
 
static NSUInteger sSpace
 
static NSUInteger sHighWaterMark
 
static NSMutableArray * sDeferredOps
 
static uint32 sNextID
 
static BOOL sRunning
 

Macro Definition Documentation

◆ DEBUG_FCB_SIMPLE_TRACKING_IDS

#define DEBUG_FCB_SIMPLE_TRACKING_IDS   0

Definition at line 41 of file OOJSFrameCallbacks.m.

◆ DEBUG_FCB_VERBOSE_LOGGING

#define DEBUG_FCB_VERBOSE_LOGGING   0

Definition at line 45 of file OOJSFrameCallbacks.m.

◆ FCBLog

#define FCBLog ( ...)

◆ FCBLogIndentIf

#define FCBLogIndentIf ( key)
Value:
do {} while (0)

Definition at line 60 of file OOJSFrameCallbacks.m.

Referenced by RunDeferredOperations().

◆ FCBLogOutdentIf

#define FCBLogOutdentIf ( key)
Value:
do {} while (0)

Definition at line 61 of file OOJSFrameCallbacks.m.

Referenced by RunDeferredOperations().

Enumeration Type Documentation

◆ anonymous enum

anonymous enum
Enumerator
kMinCount 
kIDScrambleMask 
kIDIncrement 

Definition at line 65 of file OOJSFrameCallbacks.m.

66{
67 kMinCount = 16,
68
69#if DEBUG_FCB_SIMPLE_TRACKING_IDS
71 kIDIncrement = 1
72#else
73 kIDScrambleMask = 0x2315EB16, // Just a random number.
74 kIDIncrement = 992699 // A large prime number, to produce a non-obvious sequence which still uses all 2^32 values.
75#endif
76};
@ kIDIncrement
@ kMinCount
@ kIDScrambleMask

Function Documentation

◆ AddCallback()

static BOOL AddCallback ( JSContext * context,
jsval callback,
uint32 trackingID,
NSString ** errorString )
static

Definition at line 291 of file OOJSFrameCallbacks.m.

292{
293 NSCParameterAssert(context != NULL && JS_IsInRequest(context));
294 NSCParameterAssert(errorString != NULL);
295 NSCAssert1(!sRunning, @"%s cannot be called while frame callbacks are running.", __PRETTY_FUNCTION__);
296
297 if (EXPECT_NOT(sCount == sSpace))
298 {
299 if (!GrowCallbackList(context, errorString)) return NO;
300 }
301
302 FCBLog(@"script.frameCallback.debug.add", @"Adding frame callback with tracking ID %u.", trackingID);
303
304 sCallbacks[sCount].callback = callback;
305 if (sCount >= sHighWaterMark)
306 {
307 // If we haven't used this slot before, root it.
308
309 if (EXPECT_NOT(!OOJSAddGCValueRoot(context, &sCallbacks[sCount].callback, "frame callback")))
310 {
311 *errorString = @"Failed to add GC root for frame callback.";
312 return NO;
313 }
314
316 }
317
318 sCallbacks[sCount].trackingID = trackingID;
319 sCount++;
320
321 return YES;
322}
#define EXPECT_NOT(x)
#define FCBLog(...)
static NSUInteger sCount
static NSUInteger sHighWaterMark
static BOOL sRunning
static CallbackEntry * sCallbacks
static NSUInteger sSpace
static BOOL GrowCallbackList(JSContext *context, NSString **errorString)
#define JS_IsInRequest(context)
#define OOJSAddGCValueRoot(context, root, name)

References CallbackEntry::callback, EXPECT_NOT, FCBLog, GrowCallbackList(), JS_IsInRequest, OOJSAddGCValueRoot, sCallbacks, sCount, sHighWaterMark, sRunning, sSpace, and CallbackEntry::trackingID.

Referenced by GlobalAddFrameCallback(), and RunDeferredOperations().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ GetIndexForTrackingID()

static BOOL GetIndexForTrackingID ( uint32 trackingID,
NSUInteger * outIndex )
static

Definition at line 376 of file OOJSFrameCallbacks.m.

377{
378 NSCParameterAssert(outIndex != NULL);
379
380 /* It is assumed that few frame callbacks will be active at once, so a
381 linear search is reasonable. If they become unexpectedly popular, we
382 can switch to a sorted list or a separate lookup table without changing
383 the API.
384 */
385 NSUInteger i;
386 for (i = 0; i < sCount; i++)
387 {
388 if (sCallbacks[i].trackingID == trackingID)
389 {
390 *outIndex = i;
391 return YES;
392 }
393 }
394
395 return NO;
396}

References sCallbacks, and sCount.

Referenced by GlobalIsValidFrameCallback(), and RemoveCallbackWithTrackingID().

+ Here is the caller graph for this function:

◆ GlobalAddFrameCallback()

static JSBool GlobalAddFrameCallback ( JSContext * context,
uintN argc,
jsval * vp )
static

Definition at line 191 of file OOJSFrameCallbacks.m.

192{
193 OOJS_NATIVE_ENTER(context)
194
195 // Get callback argument and verify that it's a function.
196 jsval callback = OOJS_ARGV[0];
197 if (EXPECT_NOT(argc < 1 || !OOJSValueIsFunction(context, callback)))
198 {
199 OOJSReportBadArguments(context, nil, @"addFrameCallback", MIN(argc, 1U), OOJS_ARGV, nil, @"function");
200 return NO;
201 }
202
203 // Assign a tracking ID.
204 uint32 trackingID = sNextID ^ kIDScrambleMask;
206
207 if (EXPECT(!sRunning))
208 {
209 // Add to list immediately.
210 NSString *errorString = nil;
211 if (EXPECT_NOT(!AddCallback(context, callback, trackingID, &errorString)))
212 {
213 OOJSReportError(context, @"%@", errorString);
214 return NO;
215 }
216 }
217 else
218 {
219 // Defer mutations during callback invocation.
220 FCBLog(@"script.frameCallback.debug.add.deferred", @"Deferring addition of frame callback with tracking ID %u.", trackingID);
221 QueueDeferredOperation(@"add", trackingID, [OOJSValue valueWithJSValue:callback inContext:context]);
222 }
223
224 OOJS_RETURN_INT(trackingID);
225
227}
#define EXPECT(x)
#define OOJS_NATIVE_ENTER(cx)
#define OOJS_NATIVE_EXIT
static uint32 sNextID
static void QueueDeferredOperation(NSString *opType, uint32 trackingID, OOJSValue *value)
static BOOL AddCallback(JSContext *context, jsval callback, uint32 trackingID, NSString **errorString)
OOINLINE BOOL OOJSValueIsFunction(JSContext *context, jsval value)
void OOJSReportError(JSContext *context, NSString *format,...)
#define OOJS_ARGV
void OOJSReportBadArguments(JSContext *context, NSString *scriptClass, NSString *function, uintN argc, jsval *argv, NSString *message, NSString *expectedArgsDescription)
#define OOJS_RETURN_INT(v)
#define MIN(A, B)
Definition OOMaths.h:111
return nil

References AddCallback(), EXPECT, EXPECT_NOT, FCBLog, kIDIncrement, kIDScrambleMask, MIN, nil, OOJS_ARGV, OOJS_NATIVE_ENTER, OOJS_NATIVE_EXIT, OOJS_RETURN_INT, OOJSReportBadArguments(), OOJSReportError(), OOJSValueIsFunction(), QueueDeferredOperation(), sNextID, and sRunning.

Referenced by InitOOJSFrameCallbacks().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ GlobalIsValidFrameCallback()

static JSBool GlobalIsValidFrameCallback ( JSContext * context,
uintN argc,
jsval * vp )
static

Definition at line 265 of file OOJSFrameCallbacks.m.

266{
267 OOJS_NATIVE_ENTER(context)
268
269 if (EXPECT_NOT(argc < 1))
270 {
271 OOJSReportBadArguments(context, nil, @"isValidFrameCallback", 0, OOJS_ARGV, nil, @"frame callback tracking ID");
272 return NO;
273 }
274
275 // Get tracking ID argument.
276 uint32 trackingID;
277 if (EXPECT_NOT(!JS_ValueToECMAUint32(context, OOJS_ARGV[0], &trackingID)))
278 {
280 }
281
282 NSUInteger index;
283 OOJS_RETURN_BOOL(GetIndexForTrackingID(trackingID, &index));
284
286}
static BOOL GetIndexForTrackingID(uint32 trackingID, NSUInteger *outIndex)
#define OOJS_RETURN_BOOL(v)

References EXPECT_NOT, GetIndexForTrackingID(), nil, OOJS_ARGV, OOJS_NATIVE_ENTER, OOJS_NATIVE_EXIT, OOJS_RETURN_BOOL, and OOJSReportBadArguments().

Referenced by InitOOJSFrameCallbacks().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ GlobalRemoveFrameCallback()

static JSBool GlobalRemoveFrameCallback ( JSContext * context,
uintN argc,
jsval * vp )
static

Definition at line 231 of file OOJSFrameCallbacks.m.

232{
233 OOJS_NATIVE_ENTER(context)
234
235 // Get tracking ID argument.
236 uint32 trackingID;
237 if (EXPECT_NOT(argc < 1 || !JS_ValueToECMAUint32(context, OOJS_ARGV[0], &trackingID)))
238 {
239 OOJSReportBadArguments(context, nil, @"removeFrameCallback", MIN(argc, 1U), OOJS_ARGV, nil, @"frame callback tracking ID");
240 return NO;
241 }
242
243 if (EXPECT(!sRunning))
244 {
245 // Remove it.
246 if (EXPECT_NOT(!RemoveCallbackWithTrackingID(context, trackingID)))
247 {
248 OOJSReportWarning(context, @"removeFrameCallback(): invalid tracking ID.");
249 }
250 }
251 else
252 {
253 // Defer mutations during callback invocation.
254 FCBLog(@"script.frameCallback.debug.remove.deferred", @"Deferring removal of frame callback with tracking ID %u.", trackingID);
255 QueueDeferredOperation(@"remove", trackingID, nil);
256 }
257
259
261}
static BOOL RemoveCallbackWithTrackingID(JSContext *context, uint32 trackingID)
void OOJSReportWarning(JSContext *context, NSString *format,...)
#define OOJS_RETURN_VOID

References EXPECT, EXPECT_NOT, FCBLog, MIN, nil, OOJS_ARGV, OOJS_NATIVE_ENTER, OOJS_NATIVE_EXIT, OOJS_RETURN_VOID, OOJSReportBadArguments(), OOJSReportWarning(), QueueDeferredOperation(), RemoveCallbackWithTrackingID(), and sRunning.

Referenced by InitOOJSFrameCallbacks().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ GrowCallbackList()

static BOOL GrowCallbackList ( JSContext * context,
NSString ** errorString )
static

Definition at line 325 of file OOJSFrameCallbacks.m.

326{
327 NSCParameterAssert(context != NULL && JS_IsInRequest(context));
328 NSCParameterAssert(errorString != NULL);
329
330 NSUInteger newSpace = MAX(sSpace * 2, (NSUInteger)kMinCount);
331
332 CallbackEntry *newCallbacks = calloc(sizeof (CallbackEntry), newSpace);
333 if (newCallbacks == NULL) return NO;
334
335 CallbackEntry *oldCallbacks = sCallbacks;
336
337 // Root and copy occupied slots.
338 NSUInteger newHighWaterMark = sCount;
339 NSUInteger i;
340 for (i = 0; i < newHighWaterMark; i++)
341 {
342 if (EXPECT_NOT(!OOJSAddGCValueRoot(context, &newCallbacks[i].callback, "frame callback")))
343 {
344 // If we can't root them all, we fail; unroot all entries to date, free the buffer and return NO.
345 NSUInteger j;
346 for (j = 0; j < i; j++)
347 {
348 JS_RemoveValueRoot(context, &newCallbacks[j].callback);
349 }
350 free(newCallbacks);
351
352 *errorString = @"Failed to add GC root for frame callback.";
353 return NO;
354 }
355 newCallbacks[i] = oldCallbacks[i];
356 }
357
358 // Unroot old array's slots.
359 for (i = 0; i < sHighWaterMark; i++)
360 {
361 JS_RemoveValueRoot(context, &oldCallbacks[i].callback);
362 }
363
364 // We only rooted the occupied slots, so reset high water mark.
365 sHighWaterMark = newHighWaterMark;
366
367 // Replace array.
368 sCallbacks = newCallbacks;
369 free(oldCallbacks);
370 sSpace = newSpace;
371
372 return YES;
373}
#define MAX(A, B)
Definition OOMaths.h:114

References EXPECT_NOT, JS_IsInRequest, kMinCount, MAX, OOJSAddGCValueRoot, sCallbacks, sCount, sHighWaterMark, and sSpace.

Referenced by AddCallback().

+ Here is the caller graph for this function:

◆ InitOOJSFrameCallbacks()

void InitOOJSFrameCallbacks ( JSContext * context,
JSObject * global )

Definition at line 117 of file OOJSFrameCallbacks.m.

118{
119 JS_DefineFunction(context, global, "addFrameCallback", GlobalAddFrameCallback, 1, OOJS_METHOD_READONLY);
120 JS_DefineFunction(context, global, "removeFrameCallback", GlobalRemoveFrameCallback, 1, OOJS_METHOD_READONLY);
121 JS_DefineFunction(context, global, "isValidFrameCallback", GlobalIsValidFrameCallback, 1, OOJS_METHOD_READONLY);
122
123#if DEBUG_FCB_SIMPLE_TRACKING_IDS
124 sNextID = 1;
125#else
126 // Set randomish initial ID to catch bad habits.
127 sNextID = [[NSDate date] timeIntervalSinceReferenceDate];
128#endif
129}
static JSBool GlobalAddFrameCallback(JSContext *context, uintN argc, jsval *vp)
static JSBool GlobalRemoveFrameCallback(JSContext *context, uintN argc, jsval *vp)
static JSBool GlobalIsValidFrameCallback(JSContext *context, uintN argc, jsval *vp)
#define OOJS_METHOD_READONLY

References GlobalAddFrameCallback(), GlobalIsValidFrameCallback(), GlobalRemoveFrameCallback(), OOJS_METHOD_READONLY, and sNextID.

+ Here is the call graph for this function:

◆ OOJSFrameCallbacksInvoke()

void OOJSFrameCallbacksInvoke ( OOTimeDelta inDeltaT)

Definition at line 132 of file OOJSFrameCallbacks.m.

133{
134 NSCAssert1(!sRunning, @"%s cannot be called while frame callbacks are running.", __PRETTY_FUNCTION__);
135
136 if (sCount != 0)
137 {
138 const OOTimeDelta delta = inDeltaT * [UNIVERSE timeAccelerationFactor];
139 JSContext *context = OOJSAcquireContext();
140 jsval deltaVal, result;
141 NSUInteger i;
142
143 if (EXPECT(JS_NewNumberValue(context, delta, &deltaVal)))
144 {
145 // Block mutations.
146 sRunning = YES;
147
148 /*
149 The watchdog timer only fires once per second in deployment builds,
150 but in testrelease builds at least we can keep them on a short leash.
151 */
153
154 for (i = 0; i < sCount; i++)
155 {
156 // TODO: remove out of scope callbacks - post MNSR!
157 JS_CallFunctionValue(context, NULL, sCallbacks[i].callback, 1, &deltaVal, &result);
158 JS_ReportPendingException(context);
159 }
160
162 sRunning = NO;
163
164 if (EXPECT_NOT(sDeferredOps != NULL))
165 {
166 RunDeferredOperations(context);
168 }
169 }
170 OOJSRelinquishContext(context);
171 }
172}
#define DESTROY(x)
Definition OOCocoa.h:77
#define OOJSStopTimeLimiter()
#define OOJSStartTimeLimiterWithTimeLimit(limit)
static void RunDeferredOperations(JSContext *context)
static NSMutableArray * sDeferredOps
OOINLINE JSContext * OOJSAcquireContext(void)
OOINLINE void OOJSRelinquishContext(JSContext *context)
double OOTimeDelta
Definition OOTypes.h:224

References DESTROY, EXPECT, EXPECT_NOT, OOJSAcquireContext(), OOJSRelinquishContext(), OOJSStartTimeLimiterWithTimeLimit, OOJSStopTimeLimiter, RunDeferredOperations(), sCallbacks, sCount, sDeferredOps, and sRunning.

+ Here is the call graph for this function:

◆ OOJSFrameCallbacksRemoveAll()

void OOJSFrameCallbacksRemoveAll ( void )

Definition at line 175 of file OOJSFrameCallbacks.m.

176{
177 NSCAssert1(!sRunning, @"%s cannot be called while frame callbacks are running.", __PRETTY_FUNCTION__);
178
179 if (sCount != 0)
180 {
181 JSContext *context = OOJSAcquireContext();
182 while (sCount != 0) RemoveCallbackAtIndex(context, sCount - 1);
183 OOJSRelinquishContext(context);
184 }
185}
static void RemoveCallbackAtIndex(JSContext *context, NSUInteger index)

References OOJSAcquireContext(), OOJSRelinquishContext(), RemoveCallbackAtIndex(), sCount, and sRunning.

+ Here is the call graph for this function:

◆ QueueDeferredOperation()

static void QueueDeferredOperation ( NSString * opType,
uint32 trackingID,
OOJSValue * value )
static

Definition at line 438 of file OOJSFrameCallbacks.m.

439{
440 NSCAssert1(sRunning, @"%s can only be called while frame callbacks are running.", __PRETTY_FUNCTION__);
441
442 if (sDeferredOps == nil) sDeferredOps = [[NSMutableArray alloc] init];
443 [sDeferredOps addObject:[NSDictionary dictionaryWithObjectsAndKeys:
444 opType, @"operation",
445 [NSNumber numberWithInt:trackingID], @"trackingID",
446 value, @"value",
447 nil]];
448}

References nil, sDeferredOps, and sRunning.

Referenced by GlobalAddFrameCallback(), and GlobalRemoveFrameCallback().

+ Here is the caller graph for this function:

◆ RemoveCallbackAtIndex()

static void RemoveCallbackAtIndex ( JSContext * context,
NSUInteger index )
static

Definition at line 415 of file OOJSFrameCallbacks.m.

416{
417 NSCParameterAssert(context != NULL && JS_IsInRequest(context));
418 NSCParameterAssert(index < sCount && sCallbacks != NULL);
419 NSCAssert1(!sRunning, @"%s cannot be called while frame callbacks are running.", __PRETTY_FUNCTION__);
420
421 FCBLog(@"script.frameCallback.debug.remove", @"Removing frame callback with tracking ID %u.", sCallbacks[index].trackingID);
422
423 // Overwrite entry to be removed with last entry, and decrement count.
424 sCount--;
425 sCallbacks[index] = sCallbacks[sCount];
426 sCallbacks[sCount].callback = JSVAL_NULL;
427
428#if DEBUG_FCB_SIMPLE_TRACKING_IDS
429 if (sCount == 0)
430 {
431 OOLog(@"script.frameCallback.debug.reset", @"All frame callbacks removed, resetting next ID to 1.");
432 sNextID = 1;
433 }
434#endif
435}
#define OOLog(class, format,...)
Definition OOLogging.h:88

References CallbackEntry::callback, FCBLog, JS_IsInRequest, OOLog, sCallbacks, sCount, sNextID, and sRunning.

Referenced by OOJSFrameCallbacksRemoveAll(), and RemoveCallbackWithTrackingID().

+ Here is the caller graph for this function:

◆ RemoveCallbackWithTrackingID()

static BOOL RemoveCallbackWithTrackingID ( JSContext * context,
uint32 trackingID )
static

Definition at line 399 of file OOJSFrameCallbacks.m.

400{
401 NSCParameterAssert(context != NULL && JS_IsInRequest(context));
402 NSCAssert1(!sRunning, @"%s cannot be called while frame callbacks are running.", __PRETTY_FUNCTION__);
403
404 NSUInteger index = 0;
405 if (GetIndexForTrackingID(trackingID, &index))
406 {
407 RemoveCallbackAtIndex(context, index);
408 return YES;
409 }
410
411 return NO;
412}

References GetIndexForTrackingID(), JS_IsInRequest, RemoveCallbackAtIndex(), and sRunning.

Referenced by GlobalRemoveFrameCallback(), and RunDeferredOperations().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ RunDeferredOperations()

static void RunDeferredOperations ( JSContext * context)
static

Definition at line 451 of file OOJSFrameCallbacks.m.

452{
453 NSDictionary *operation = nil;
454 NSEnumerator *operationEnum = nil;
455
456 FCBLog(@"script.frameCallback.debug.run-deferred", @"Running %lu deferred frame callback operations.", (long)[sDeferredOps count]);
457 FCBLogIndentIf(@"script.frameCallback.debug.run-deferred");
458
459 for (operationEnum = [sDeferredOps objectEnumerator]; (operation = [operationEnum nextObject]); )
460 {
461 NSString *opType = [operation objectForKey:@"operation"];
462 uint32 trackingID = [operation oo_intForKey:@"trackingID"];
463
464 if ([opType isEqualToString:@"add"])
465 {
466 OOJSValue *callbackObj = [operation objectForKey:@"value"];
467 NSString *errorString = nil;
468
469 if (!AddCallback(context, OOJSValueFromNativeObject(context, callbackObj), trackingID, &errorString))
470 {
471 OOLogWARN(@"script.frameCallback.deferredAdd.failed", @"Deferred frame callback insertion failed: %@", errorString);
472 }
473 }
474 else if ([opType isEqualToString:@"remove"])
475 {
476 RemoveCallbackWithTrackingID(context, trackingID);
477 }
478 }
479
480 FCBLogOutdentIf(@"script.frameCallback.debug.run-deferred");
481}
#define FCBLogOutdentIf(key)
#define FCBLogIndentIf(key)
OOINLINE jsval OOJSValueFromNativeObject(JSContext *context, id object)
#define OOLogWARN(class, format,...)
Definition OOLogging.h:113
unsigned count

References AddCallback(), count, FCBLog, FCBLogIndentIf, FCBLogOutdentIf, nil, OOJSValueFromNativeObject(), OOLogWARN, RemoveCallbackWithTrackingID(), and sDeferredOps.

Referenced by OOJSFrameCallbacksInvoke().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

Variable Documentation

◆ sCallbacks

◆ sCount

◆ sDeferredOps

NSMutableArray* sDeferredOps
static

◆ sHighWaterMark

NSUInteger sHighWaterMark
static

Definition at line 90 of file OOJSFrameCallbacks.m.

Referenced by AddCallback(), and GrowCallbackList().

◆ sNextID

uint32 sNextID
static

◆ sRunning

◆ sSpace

NSUInteger sSpace
static

Definition at line 89 of file OOJSFrameCallbacks.m.

Referenced by AddCallback(), and GrowCallbackList().