Skip to content

Commit

Permalink
Moved jsCocoaPrivateObjectInContext to instance to always save contex…
Browse files Browse the repository at this point in the history
…t in the box. This allows the finalize callback to remove the box from the boxedObjects hash
  • Loading branch information
parmanoir committed Aug 2, 2011
1 parent 8652196 commit 0a8714e
Show file tree
Hide file tree
Showing 4 changed files with 1,742 additions and 1,601 deletions.
4 changes: 3 additions & 1 deletion JSCocoa/JSCocoaController.h
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,9 @@ typedef struct JSValueRefAndContextRef JSValueRefAndContextRef;
//
// Various internals
//
+ (JSObjectRef)jsCocoaPrivateObjectInContext:(JSContextRef)ctx;
//+ (JSObjectRef)jsCocoaPrivateObjectInContext:(JSContextRef)ctx;
- (JSObjectRef)newPrivateObject;
- (JSObjectRef)newPrivateFunction;
+ (NSMutableArray*)parseObjCMethodEncoding:(const char*)typeEncoding;
+ (NSMutableArray*)parseCFunctionEncoding:(NSString*)xml functionName:(NSString**)functionNamePlaceHolder;

Expand Down
153 changes: 104 additions & 49 deletions JSCocoa/JSCocoaController.m
Original file line number Diff line number Diff line change
Expand Up @@ -1000,8 +1000,34 @@ + (void)logAndSay:(NSString*)string
if (isSpeaking) system([[NSString stringWithFormat:@"say %@ &", string] UTF8String]);
}
*/
- (JSObjectRef)newPrivateObject {
JSCocoaPrivateObject* private = [[JSCocoaPrivateObject alloc] init];
[private setCtx:ctx];
#ifdef __OBJC_GC__
// Mark internal object as non collectable
[[NSGarbageCollector defaultCollector] disableCollectorForPointer:private];
#endif
JSObjectRef o = JSObjectMake(ctx, jsCocoaObjectClass, private);
// Object is retained by jsCocoaObject_initialize, release it to make 'private' sole owner
[private release];
return o;
}
- (JSObjectRef)newPrivateFunction {
JSCocoaPrivateObject* private = [[JSCocoaPrivateObject alloc] init];
[private setCtx:ctx];
#ifdef __OBJC_GC__
// Mark internal object as non collectable
[[NSGarbageCollector defaultCollector] disableCollectorForPointer:private];
#endif
JSObjectRef o = JSObjectMake(ctx, jsCocoaFunctionClass, private);
// Object is retained by jsCocoaObject_initialize, release it to make 'private' sole owner
[private release];
return o;
}
/*
+ (JSObjectRef)jsCocoaPrivateObjectInContext:(JSContextRef)ctx {
JSCocoaPrivateObject* private = [[JSCocoaPrivateObject alloc] init];
[private setCtx:
#ifdef __OBJC_GC__
// Mark internal object as non collectable
[[NSGarbageCollector defaultCollector] disableCollectorForPointer:private];
Expand All @@ -1021,7 +1047,7 @@ + (JSObjectRef)jsCocoaPrivateFunctionInContext:(JSContextRef)ctx {
[private release];
return o;
}

*/
/*
- (BOOL)useAutoCall
{
Expand Down Expand Up @@ -1769,10 +1795,12 @@ - (JSObjectRef)boxObject:(id)o
return [value jsObject];
}

// o --> (JS)JSObjectRef(o) --> (ObjC)BoxedJSObject(JSObjectRef(o)),
// ^stored in the boxedObjects hash to always return the same box for the same object

//
// Create a new ObjC box around the JSValueRef boxing the JSObject
// , so we need to box
// Here's the why of the boxing :
//
// We are returning an ObjC object to Javascript.
// That ObjC object is boxed in a Javascript object.
// For all boxing requests of the same ObjC object, that Javascript object needs to be unique for object comparisons to work :
Expand All @@ -1781,8 +1809,10 @@ - (JSObjectRef)boxObject:(id)o
// To guarantee unicity, we keep a cache of boxed objects.
// As boxed objects are JSObjectRef not derived from NSObject, we box them in an ObjC object.
//

// Box the ObjC object in a JSObjectRef
JSObjectRef jsObject = [JSCocoa jsCocoaPrivateObjectInContext:ctx];
// JSObjectRef jsObject = [JSCocoa jsCocoaPrivateObjectInContext:ctx];
JSObjectRef jsObject = [self newPrivateObject];
JSCocoaPrivateObject* private = JSObjectGetPrivate(jsObject);
private.type = @"@";
[private setObject:o];
Expand Down Expand Up @@ -1930,43 +1960,43 @@ - (void)callDelegateForException:(JSValueRef)exception {
}


//
//
#pragma mark Tests
- (int)runTests:(NSString*)path withSelector:(SEL)sel
{
//
// Tests stay here so that any app might run them, not just TestsRunner
//
- (int)runTests:(NSString*)path withSelector:(SEL)sel {
int count = 0;
#if TARGET_OS_IPHONE
#elif TARGET_IPHONE_SIMULATOR
#else
id files = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:path error:nil];
id predicate = [NSPredicate predicateWithFormat:@"SELF ENDSWITH[c] '.js'"];
files = [files filteredArrayUsingPredicate:predicate];
id files = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:path error:nil];
id predicate= [NSPredicate predicateWithFormat:@"SELF ENDSWITH[c] '.js'"];
files = [files filteredArrayUsingPredicate:predicate];

// Execute in test order, not finder order
files = [files sortedArrayUsingSelector:@selector(localizedStandardCompare:)];
files = [files sortedArrayUsingSelector:@selector(localizedStandardCompare:)];
// NSLog(@"files=%@", files);

if ([files count] == 0) return [JSCocoaController log:@"no test files found"], 0;
if ([files count] == 0)
return [JSCocoaController log:@"no test files found"], 0;

for (id file in files)
{
id filePath = [NSString stringWithFormat:@"%@/%@", path, file];
for (id file in files) {
id filePath = [NSString stringWithFormat:@"%@/%@", path, file];
// NSLog(@">>>evaling %@", filePath);
// BOOL evaled = [self evalJSFile:filePath];

id evaled = nil;
@try
{
evaled = [self performSelector:sel withObject:filePath];
id evaled = nil;
@try {
evaled = [self performSelector:sel withObject:filePath];
// NSLog(@">>>EVALED %d, %@", evaled, filePath);
}
@catch (id e)
{
} @catch (id e) {
NSLog(@"(Test exception from %@) %@", file, e);
evaled = nil;
evaled = nil;
}
if (!evaled)
{
id error = [NSString stringWithFormat:@"test %@ failed (Ran %d out of %d tests)", file, count+1, [files count]];
if (!evaled) {
id error = [NSString stringWithFormat:@"test %@ failed (Ran %d out of %d tests)", file, count+1, [files count]];
[JSCocoaController log:error];
return NO;
}
Expand All @@ -1976,20 +2006,17 @@ - (int)runTests:(NSString*)path withSelector:(SEL)sel
#endif
return count;
}
- (int)runTests:(NSString*)path
{
- (int)runTests:(NSString*)path {
return [self runTests:path withSelector:@selector(evalJSFile:)];
}

#pragma mark Autorelease pool
static id autoreleasePool;
+ (void)allocAutoreleasePool
{
+ (void)allocAutoreleasePool {
autoreleasePool = [[NSAutoreleasePool alloc] init];
}

+ (void)deallocAutoreleasePool
{
+ (void)deallocAutoreleasePool {
[autoreleasePool release];
}

Expand All @@ -1998,8 +2025,12 @@ + (void)deallocAutoreleasePool
//
// Collect on top of the run loop, not in some JS function
//
+ (void)garbageCollect { NSLog(@"*** Deprecated — call garbageCollect on an instance ***"); /*JSGarbageCollect(NULL);*/ }
- (void)garbageCollect { JSGarbageCollect(ctx); }
+ (void)garbageCollect {
NSLog(@"*** Deprecated — call garbageCollect on an instance ***"); /*JSGarbageCollect(NULL);*/
}
- (void)garbageCollect {
JSGarbageCollect(ctx);
}

//
// Make all root Javascript variables point to null
Expand Down Expand Up @@ -2623,7 +2654,9 @@ + (JSValueRef)instanceWithContext:(JSContextRef)ctx argumentCount:(size_t)argume
id newInstance = [self alloc];

// Set it as new object
JSObjectRef thisObject = [JSCocoaController jsCocoaPrivateObjectInContext:ctx];
// JSObjectRef thisObject = [JSCocoaController jsCocoaPrivateObjectInContext:ctx];
id jsc = [JSCocoa controllerFromContext:ctx];
JSObjectRef thisObject = [jsc newPrivateObject];
JSCocoaPrivateObject* private = JSObjectGetPrivate(thisObject);
private.type = @"@";
[private setObjectNoRetain:newInstance];
Expand All @@ -2632,7 +2665,8 @@ + (JSValueRef)instanceWithContext:(JSContextRef)ctx argumentCount:(size_t)argume
// JSObjectRef thisObject = [JSCocoaController boxedJSObject:newInstance inContext:ctx];

// Create function object boxing our init method
JSObjectRef function = [JSCocoaController jsCocoaPrivateFunctionInContext:ctx];
// JSObjectRef function = [JSCocoaController jsCocoaPrivateFunctionInContext:ctx];
JSObjectRef function = [jsc newPrivateFunction];
private = JSObjectGetPrivate(function);
private.type = @"method";
private.methodName = methodName;
Expand All @@ -2655,7 +2689,7 @@ + (JSValueRef)instanceWithContext:(JSContextRef)ctx argumentCount:(size_t)argume
// Register our context in there so that safeDealloc finds it.
if ([boxedObject respondsToSelector:@selector(safeDealloc)])
{
id jsc = [JSCocoaController controllerFromContext:ctx];
// id jsc = [JSCocoaController controllerFromContext:ctx];
object_setInstanceVariable(boxedObject, "__jsCocoaController", (void*)jsc);
}
return returnValue;
Expand Down Expand Up @@ -2742,7 +2776,8 @@ JSValueRef OSXObject_getProperty(JSContextRef ctx, JSObjectRef object, JSStringR
//
if ([type isEqualToString:@"function"])
{
JSObjectRef o = [JSCocoaController jsCocoaPrivateFunctionInContext:ctx];
// JSObjectRef o = [JSCocoaController jsCocoaPrivateFunctionInContext:ctx];
JSObjectRef o = [jsc newPrivateFunction];
JSCocoaPrivateObject* private = JSObjectGetPrivate(o);
private.type = @"function";
private.xml = xml;
Expand All @@ -2755,7 +2790,8 @@ JSValueRef OSXObject_getProperty(JSContextRef ctx, JSObjectRef object, JSStringR
else
if ([type isEqualToString:@"struct"])
{
JSObjectRef o = [JSCocoaController jsCocoaPrivateObjectInContext:ctx];
// JSObjectRef o = [JSCocoaController jsCocoaPrivateObjectInContext:ctx];
JSObjectRef o = [jsc newPrivateObject];
JSCocoaPrivateObject* private = JSObjectGetPrivate(o);
private.type = @"struct";
private.xml = xml;
Expand Down Expand Up @@ -3055,9 +3091,11 @@ JSValueRef boxedValueFromExternalContext(JSContextRef externalCtx, JSValueRef va
// ... use the function boxer
JSObjectRef o;
if (JSValueIsBoolean(externalCtx, result))
o = [JSCocoaController jsCocoaPrivateFunctionInContext:ctx];
// o = [JSCocoaController jsCocoaPrivateFunctionInContext:ctx];
o = [[JSCocoa controllerFromContext:ctx] newPrivateObject];
else
o = [JSCocoaController jsCocoaPrivateObjectInContext:ctx];
// o = [JSCocoaController jsCocoaPrivateObjectInContext:ctx];
o = [[JSCocoa controllerFromContext:ctx] newPrivateFunction];

JSCocoaPrivateObject* private = JSObjectGetPrivate(o);
private.type = @"externalJSValueRef";
Expand Down Expand Up @@ -3182,7 +3220,16 @@ static void jsCocoaObject_finalize(JSObjectRef object)
// Clean up the object now as WebKit calls us twice while cleaning __jsc__ (20110730)
JSObjectSetPrivate(object, NULL);

id jsc = [private ctx];
id jsc = nil;
JSContextRef ctx = [private ctx];
if (!ctx) {
NSLog(@"+++++++NO CONTEXT, NO DELETE");
} else {
jsc = [JSCocoa controllerFromContext:ctx];
}
if (!jsc) {
NSLog(@"*******NO CONTEXT+++++++++++");
}
//
// If a boxed object is being destroyed, remove it from the cache
//
Expand Down Expand Up @@ -3346,7 +3393,8 @@ static JSValueRef jsCocoaObject_getProperty(JSContextRef ctx, JSObjectRef object
if (isJavascriptArrayMethod)
{
// NSLog(@"*** array method : %@", propertyName);
JSObjectRef o = [JSCocoaController jsCocoaPrivateFunctionInContext:ctx];
// JSObjectRef o = [JSCocoaController jsCocoaPrivateFunctionInContext:ctx];
JSObjectRef o = [jsc newPrivateObject];
JSCocoaPrivateObject* private = JSObjectGetPrivate(o);
private.type = @"jsFunction";
[private setJSValueRef:result ctx:ctx];
Expand Down Expand Up @@ -3487,7 +3535,8 @@ static JSValueRef jsCocoaObject_getProperty(JSContextRef ctx, JSObjectRef object
if ([propertyName isEqualToString:@"alloc"])
{
id allocatedObject = [callee alloc];
JSObjectRef jsObject = [JSCocoaController jsCocoaPrivateObjectInContext:ctx];
// JSObjectRef jsObject = [JSCocoaController jsCocoaPrivateObjectInContext:ctx];
JSObjectRef jsObject = [jsc newPrivateObject];
JSCocoaPrivateObject* private = JSObjectGetPrivate(jsObject);
private.type = @"@";
[private setObjectNoRetain:allocatedObject];
Expand Down Expand Up @@ -3638,7 +3687,8 @@ static JSValueRef jsCocoaObject_getProperty(JSContextRef ctx, JSObjectRef object
id initMethodName = [NSString stringWithFormat:@"init%@", [methodName substringFromIndex:8]];
if ([callee instancesRespondToSelector:NSSelectorFromString(initMethodName)])
{
JSObjectRef o = [JSCocoaController jsCocoaPrivateFunctionInContext:ctx];
// JSObjectRef o = [JSCocoaController jsCocoaPrivateFunctionInContext:ctx];
JSObjectRef o = [jsc newPrivateFunction];
JSCocoaPrivateObject* private = JSObjectGetPrivate(o);
private.type = @"method";
private.methodName = methodName;
Expand Down Expand Up @@ -3666,7 +3716,8 @@ static JSValueRef jsCocoaObject_getProperty(JSContextRef ctx, JSObjectRef object
// This is a pure JS function call — box it
if (result && JSValueGetType(ctx, result) == kJSTypeObject)
{
JSObjectRef o = [JSCocoaController jsCocoaPrivateFunctionInContext:ctx];
// JSObjectRef o = [JSCocoaController jsCocoaPrivateFunctionInContext:ctx];
JSObjectRef o = [jsc newPrivateFunction];
JSCocoaPrivateObject* private = JSObjectGetPrivate(o);
private.type = @"jsFunction";
[private setJSValueRef:result ctx:ctx];
Expand All @@ -3692,7 +3743,8 @@ static JSValueRef jsCocoaObject_getProperty(JSContextRef ctx, JSObjectRef object
}

// Get ready for method call
JSObjectRef o = [JSCocoaController jsCocoaPrivateFunctionInContext:ctx];
// JSObjectRef o = [JSCocoaController jsCocoaPrivateFunctionInContext:ctx];
JSObjectRef o = [jsc newPrivateFunction];
JSCocoaPrivateObject* private = JSObjectGetPrivate(o);
private.type = @"method";
private.methodName = methodName;
Expand All @@ -3703,7 +3755,8 @@ static JSValueRef jsCocoaObject_getProperty(JSContextRef ctx, JSObjectRef object
// Struct + rawPointer valueOf
if (/*[privateObject.type isEqualToString:@"struct"] &&*/ ([propertyName isEqualToString:@"valueOf"] || [propertyName isEqualToString:@"toString"]))
{
JSObjectRef o = [JSCocoaController jsCocoaPrivateFunctionInContext:ctx];
// JSObjectRef o = [JSCocoaController jsCocoaPrivateFunctionInContext:ctx];
JSObjectRef o = [jsc newPrivateFunction];
JSCocoaPrivateObject* private = JSObjectGetPrivate(o);
private.type = @"method";
private.methodName = propertyName;
Expand Down Expand Up @@ -4171,7 +4224,8 @@ static JSValueRef jsCocoaObject_callAsFunction_ffi(JSContextRef ctx, JSObjectRef
if (![jsc useAutoCall] && argumentCount == 0 && [methodName isEqualToString:@"alloc"])
{
id allocatedObject = [callee alloc];
JSObjectRef jsObject = [JSCocoaController jsCocoaPrivateObjectInContext:ctx];
// JSObjectRef jsObject = [JSCocoaController jsCocoaPrivateObjectInContext:ctx];
JSObjectRef jsObject = [jsc newPrivateObject];
JSCocoaPrivateObject* private = JSObjectGetPrivate(jsObject);
private.type = @"@";
[private setObjectNoRetain:allocatedObject];
Expand Down Expand Up @@ -4680,7 +4734,8 @@ static JSValueRef jsCocoaObject_callAsFunction(JSContextRef ctx, JSObjectRef fun
if (superArguments) free(superArguments);
return throwException(ctx, exception, [NSString stringWithFormat:@"Original called on a non swizzled method (%@)", superSelector]), NULL;
}
function = [JSCocoaController jsCocoaPrivateFunctionInContext:ctx];
// function = [JSCocoaController jsCocoaPrivateFunctionInContext:ctx];
function = [[JSCocoa controllerFromContext:ctx] newPrivateFunction];
JSCocoaPrivateObject* private = JSObjectGetPrivate(function);
private.type = @"method";
private.methodName = superSelector;
Expand Down
9 changes: 6 additions & 3 deletions JSCocoa/JSCocoaFFIArgument.m
Original file line number Diff line number Diff line change
Expand Up @@ -590,7 +590,8 @@ + (BOOL)toJSValueRef:(JSValueRef*)value inContext:(JSContextRef)ctx typeEncoding
// Bail if structure not found
if (!type) return 0;

JSObjectRef jsObject = [JSCocoaController jsCocoaPrivateObjectInContext:ctx];
// JSObjectRef jsObject = [JSCocoaController jsCocoaPrivateObjectInContext:ctx];
JSObjectRef jsObject = [[JSCocoa controllerFromContext:ctx] newPrivateObject];
JSCocoaPrivateObject* private = JSObjectGetPrivate(jsObject);
private.type = @"struct";
NSInteger numParsed = [JSCocoaFFIArgument structureToJSValueRef:value inContext:ctx fromCString:(char*)[type UTF8String] fromStorage:&p];
Expand Down Expand Up @@ -632,7 +633,8 @@ + (BOOL)toJSValueRef:(JSValueRef*)value inContext:(JSContextRef)ctx typeEncoding

case _C_PTR:
{
JSObjectRef o = [JSCocoaController jsCocoaPrivateObjectInContext:ctx];
// JSObjectRef o = [JSCocoaController jsCocoaPrivateObjectInContext:ctx];
JSObjectRef o = [[JSCocoa controllerFromContext:ctx] newPrivateObject];
JSCocoaPrivateObject* private = JSObjectGetPrivate(o);
private.type = @"rawPointer";
[private setRawPointer:*(void**)ptr encoding:fullTypeEncoding];
Expand Down Expand Up @@ -660,7 +662,8 @@ + (NSInteger)structureToJSValueRef:(JSValueRef*)value inContext:(JSContextRef)ct
+ (NSInteger)structureToJSValueRef:(JSValueRef*)value inContext:(JSContextRef)ctx fromCString:(char*)c fromStorage:(void**)ptr initialValues:(JSValueRef*)initialValues initialValueCount:(NSInteger)initialValueCount convertedValueCount:(NSInteger*)convertedValueCount
{
// Build new structure object
JSObjectRef jsObject = [JSCocoaController jsCocoaPrivateObjectInContext:ctx];
// JSObjectRef jsObject = [JSCocoaController jsCocoaPrivateObjectInContext:ctx];
JSObjectRef jsObject = [[JSCocoa controllerFromContext:ctx] newPrivateObject];
JSCocoaPrivateObject* private = JSObjectGetPrivate(jsObject);
private.type = @"struct";
private.structureName = [JSCocoaFFIArgument structureNameFromStructureTypeEncoding:[NSString stringWithUTF8String:c]];
Expand Down
Loading

0 comments on commit 0a8714e

Please sign in to comment.