Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Made boxedObjects local, fixing the WebView test (Two contexts, our o…

…wn and WebView's, shared the same box, but an object boxed in one context didn't work in the other
  • Loading branch information...
commit 86521965d7c79a9bf3513f5e2d0d60d0fe20f236 1 parent 3117230
@parmanoir authored
View
44 JSCocoa/JSCocoaController.h
@@ -41,14 +41,6 @@ typedef struct JSValueRefAndContextRef JSValueRefAndContextRef;
id _delegate;
//
- // Safe dealloc
- // - (void)dealloc cannot be overloaded as it is called during JS GC, which forbids new JS code execution.
- // As the js dealloc method cannot be called, safe dealloc allows it to be executed during the next run loop cycle
- // NOTE : upon destroying a JSCocoaController, safe dealloc is disabled
- //
- BOOL useSafeDealloc;
-
- //
// Split call
// Allows calling multi param ObjC messages with a jQuery-like syntax.
//
@@ -63,13 +55,26 @@ typedef struct JSValueRefAndContextRef JSValueRefAndContextRef;
// Auto call zero arg methods : allow NSWorkspace.sharedWorkspace instead of NSWorkspace.sharedWorkspace()
BOOL useAutoCall;
- // Allows setting javascript values on boxed objects (which are collected after nulling all references to them)
+ // Allow setting javascript values on boxed objects (which are collected after nulling all references to them)
BOOL canSetOnBoxedObjects;
// Allow calling obj.method(...) instead of obj.method_(...)
BOOL callSelectorsMissingTrailingSemicolon;
-
+
+ // Log all exceptions to NSLog, even if they're caught later by downstream Javascript (in f(g()), log even if f catches after g threw)
BOOL logAllExceptions;
+ //
+ // Safe dealloc (For ObjC classes written in Javascript)
+ // - (void)dealloc cannot be overloaded as it is called during JS GC, which forbids new JS code execution.
+ // As the js dealloc method cannot be called, safe dealloc allows it to be executed during the next run loop cycle
+ // NOTE : upon destroying a JSCocoaController, safe dealloc is disabled
+ //
+ BOOL useSafeDealloc;
+
+
+ NSMutableDictionary* boxedObjects;
+
+
}
@property (assign) id delegate;
@@ -144,7 +149,7 @@ typedef struct JSValueRefAndContextRef JSValueRefAndContextRef;
+ (void)logInstanceStats;
- (id)instanceStats;
-+ (void)logBoxedObjects;
+- (void)logBoxedObjects;
//
// Class inspection (shortcuts to JSCocoaLib)
@@ -177,9 +182,12 @@ typedef struct JSValueRefAndContextRef JSValueRefAndContextRef;
+ (void)deallocAutoreleasePool;
//
-// Global boxer : only one JSValueRef for multiple box requests of one pointer
+// Boxing : each object gets only one box, stored in boxedObjects
//
//+ (JSObjectRef)boxedJSObject:(id)o inContext:(JSContextRef)ctx;
+- (JSObjectRef)boxObject:(id)o;
+- (BOOL)isObjectBoxed:(id)o;
+- (void)deleteBoxOfObject:(id)o;
//+ (void)downBoxedJSObjectCount:(id)o;
@@ -333,3 +341,15 @@ JSValueRef valueOfCallback(JSContextRef ctx, JSObjectRef function, JSObjectRef t
#define RuntimeInformationPropertyName "info"
+
+/*
+Some more doc
+
+ __jsHash
+ __jsCocoaController
+ Instance variables set on ObjC classes written in Javascript.
+ These variables enable classes to store Javascript values in them.
+
+*/
+
+
View
113 JSCocoa/JSCocoaController.m
@@ -143,6 +143,7 @@ - (id)initWithGlobalContext:(JSGlobalContextRef)_ctx
callSelectorsMissingTrailingSemicolon = YES;
canSetOnBoxedObjects= NO;
logAllExceptions = NO;
+ boxedObjects = [NSMutableDictionary new];
@synchronized(self)
{
@@ -155,7 +156,7 @@ - (id)initWithGlobalContext:(JSGlobalContextRef)_ctx
jsFunctionHash = [NSMutableDictionary new];
splitCallCache = [NSMutableDictionary new];
jsClassParents = [NSMutableDictionary new];
- boxedObjects = [NSMutableDictionary new];
+// boxedObjects = [NSMutableDictionary new];
jsClasses = [NSMutableArray new];
customCallPathsCacheIsClean = NO;
customCallPaths = nil;
@@ -325,6 +326,7 @@ - (id)init
- (void)cleanUp
{
NSLog(@"JSCocoa : %llx dying", self);
+ [boxedObjects release];
[self setUseSafeDealloc:NO];
[self unlinkAllReferences];
JSGarbageCollect(ctx);
@@ -333,28 +335,18 @@ - (void)cleanUp
if (controllerCount == 0)
{
if (OSXObjectClass) {
- JSClassRelease(OSXObjectClass);
- OSXObjectClass = nil;
- }
-
- if (jsCocoaObjectClass) {
- JSClassRelease(jsCocoaObjectClass);
- jsCocoaObjectClass = nil;
- }
- if (jsCocoaFunctionClass) {
- JSClassRelease(jsCocoaFunctionClass);
- jsCocoaFunctionClass = nil;
- }
- if (jsCocoaInfoClass) {
- JSClassRelease(jsCocoaInfoClass);
- jsCocoaInfoClass = nil;
+ JSClassRelease(OSXObjectClass);
+ JSClassRelease(jsCocoaObjectClass);
+ JSClassRelease(jsCocoaFunctionClass);
+ JSClassRelease(jsCocoaInfoClass);
+ JSClassRelease(hashObjectClass);
+ OSXObjectClass = nil;
+ jsCocoaObjectClass = nil;
+ jsCocoaFunctionClass = nil;
+ jsCocoaInfoClass = nil;
+ hashObjectClass = nil;
}
- if (hashObjectClass) {
- JSClassRelease(hashObjectClass);
- hashObjectClass = nil;
- }
-
// We need to nil these all out, since they are static
// and if we make another JSCocoaController after this- they will
// still be around and that's kinda bad (like crashing bad).
@@ -372,8 +364,8 @@ - (void)cleanUp
splitCallCache = nil;
[jsClassParents release];
jsClassParents = nil;
- [boxedObjects release];
- boxedObjects = nil;
+// [boxedObjects release];
+// boxedObjects = nil;
[customCallPaths release];
customCallPaths = nil;
@@ -392,7 +384,8 @@ - (void)cleanUp
}
- if (ownsContext) JSGlobalContextRelease(ctx);
+ if (ownsContext)
+ JSGlobalContextRelease(ctx);
}
- (oneway void)release
@@ -891,7 +884,7 @@ - (id)toObject:(JSValueRef)value
//
- (BOOL)setObject:(id)object withName:(id)name attributes:(JSPropertyAttributes)attributes
{
- JSObjectRef o = [JSCocoaController boxedJSObject:object inContext:ctx];
+ JSObjectRef o = [self boxObject:object];
// Set
JSValueRef exception = NULL;
@@ -1007,25 +1000,24 @@ + (void)logAndSay:(NSString*)string
if (isSpeaking) system([[NSString stringWithFormat:@"say %@ &", string] UTF8String]);
}
*/
-+ (JSObjectRef)jsCocoaPrivateObjectInContext:(JSContextRef)ctx
-{
++ (JSObjectRef)jsCocoaPrivateObjectInContext:(JSContextRef)ctx {
JSCocoaPrivateObject* private = [[JSCocoaPrivateObject alloc] init];
#ifdef __OBJC_GC__
-// Mark internal object as non collectable
-[[NSGarbageCollector defaultCollector] disableCollectorForPointer:private];
+ // Mark internal object as non collectable
+ [[NSGarbageCollector defaultCollector] disableCollectorForPointer:private];
#endif
JSObjectRef o = JSObjectMake(ctx, jsCocoaObjectClass, private);
[private release];
return o;
}
-+ (JSObjectRef)jsCocoaPrivateFunctionInContext:(JSContextRef)ctx
-{
++ (JSObjectRef)jsCocoaPrivateFunctionInContext:(JSContextRef)ctx {
JSCocoaPrivateObject* private = [[JSCocoaPrivateObject alloc] init];
#ifdef __OBJC_GC__
-// Mark internal object as non collectable
-[[NSGarbageCollector defaultCollector] disableCollectorForPointer:private];
+ // 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;
}
@@ -1760,12 +1752,13 @@ - (BOOL)isFunctionVariadic:(id)functionName
#pragma mark Boxed object hash
-+ (JSObjectRef)boxedJSObject:(id)o inContext:(JSContextRef)ctx
+//+ (JSObjectRef)boxedJSObject:(id)o inContext:(JSContextRef)ctx
+- (JSObjectRef)boxObject:(id)o
{
NSLog(@"QUICK FIX : key is ctx+llx, AND ctx is always the global context");
- id key = [NSString stringWithFormat:@"%llx", o];
- id value = [boxedObjects valueForKey:key];
+ id key = [NSString stringWithFormat:@"%llx", o];
+ id value= [boxedObjects valueForKey:key];
NSLog(@"boxing (in ctx %llx) %@ (key %@)", ctx, o, key);
// If object is boxed, up its usage count and return it
@@ -1789,7 +1782,7 @@ + (JSObjectRef)boxedJSObject:(id)o inContext:(JSContextRef)ctx
// 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 = [self jsCocoaPrivateObjectInContext:ctx];
+ JSObjectRef jsObject = [JSCocoa jsCocoaPrivateObjectInContext:ctx];
JSCocoaPrivateObject* private = JSObjectGetPrivate(jsObject);
private.type = @"@";
[private setObject:o];
@@ -1802,10 +1795,22 @@ + (JSObjectRef)boxedJSObject:(id)o inContext:(JSContextRef)ctx
[boxedObjects setValue:value forKey:key];
[value release];
return jsObject;
+}
+- (BOOL)isObjectBoxed:(id)o {
+ id key = [NSString stringWithFormat:@"%llx", o];
+ return !![boxedObjects valueForKey:key];
}
+- (void)deleteBoxOfObject:(id)o {
+ id key = [NSString stringWithFormat:@"%llx", o];
+ id value= [boxedObjects valueForKey:key];
+ if (!value)
+ return;
+ [boxedObjects removeObjectForKey:key];
+}
+/*
+ (void)downBoxedJSObjectCount:(id)o
{
id key = [NSString stringWithFormat:@"%llx", o];
@@ -1820,7 +1825,7 @@ + (id)boxedObjects
{
return boxedObjects;
}
-
+*/
#pragma mark Helpers
- (id)selectorForJSFunction:(JSObjectRef)function
{
@@ -1940,7 +1945,7 @@ - (int)runTests:(NSString*)path withSelector:(SEL)sel
files = [files sortedArrayUsingSelector:@selector(localizedStandardCompare:)];
// NSLog(@"files=%@", files);
- if ([files count] == 0) return [JSCocoaController logAndSay:@"no test files found"], 0;
+ if ([files count] == 0) return [JSCocoaController log:@"no test files found"], 0;
for (id file in files)
{
@@ -1962,7 +1967,7 @@ - (int)runTests:(NSString*)path withSelector:(SEL)sel
if (!evaled)
{
id error = [NSString stringWithFormat:@"test %@ failed (Ran %d out of %d tests)", file, count+1, [files count]];
- [JSCocoaController logAndSay:error];
+ [JSCocoaController log:error];
return NO;
}
count ++;
@@ -2100,7 +2105,7 @@ + (void)logInstanceStats
if ([allKeys count]) NSLog(@"====");
}
-+ (void)logBoxedObjects
+- (void)logBoxedObjects
{
NSLog(@"====%ld boxedObjects====", (long)[[boxedObjects allKeys] count]);
NSLog(@"%@", boxedObjects);
@@ -2392,10 +2397,10 @@ - (JSValueRef)JSCocoa:(JSCocoaController*)controller callMethod:(NSString*)metho
#pragma mark Javascript setter functions
-// Hold these methods in a derived NSObject class : only derived classes created with a __jsHash (capable of hosting js objects) will get them
+// Give ObjC classes written in Javascript extra abilities like storing extra javascript variables in an internal __jsHash.
+// The following methods handle that. JSCocoaMethodHolder is a dummy class to hold them.
@interface JSCocoaMethodHolder : NSObject
@end
-// Stored there for convenience. They won't be used by JSCocoaPrivateObject but will be patched in for any derived class
@implementation JSCocoaMethodHolder
- (BOOL)setJSValue:(JSValueRefAndContextRef)valueAndContext forJSName:(JSValueRefAndContextRef)nameAndContext
{
@@ -2713,7 +2718,7 @@ JSValueRef OSXObject_getProperty(JSContextRef ctx, JSObjectRef object, JSStringR
Class objCClass = NSClassFromString(propertyName);
if (objCClass && ![propertyName isEqualToString:@"Object"])
{
- JSValueRef ret = [JSCocoaController boxedJSObject:objCClass inContext:ctx];
+ JSValueRef ret = [jsc boxObject:objCClass];
return ret;
}
@@ -2781,7 +2786,7 @@ JSValueRef OSXObject_getProperty(JSContextRef ctx, JSObjectRef object, JSStringR
if ([[declared_type stringValue] isEqualToString:@"@"])
{
id o = *(id*)symbol;
- return [JSCocoaController boxedJSObject:o inContext:ctx];
+ return [jsc boxObject:o];
}
// Return symbol as a Javascript string
@@ -3172,28 +3177,31 @@ static void jsCocoaObject_finalize(JSObjectRef object)
{
// if dealloc is overloaded, releasing now will trigger JS code and fail
// As we're being called by GC, KJS might assert() in operationInProgress == NoOperation
- id private = JSObjectGetPrivate(object);
+ JSCocoaPrivateObject* private = JSObjectGetPrivate(object);
// Clean up the object now as WebKit calls us twice while cleaning __jsc__ (20110730)
JSObjectSetPrivate(object, NULL);
+ id jsc = [private ctx];
//
// If a boxed object is being destroyed, remove it from the cache
//
id boxedObject = [private object];
if (boxedObject)
{
- id key = [NSString stringWithFormat:@"%llx", boxedObject];
+// id key = [NSString stringWithFormat:@"%llx", boxedObject];
// Object may have been already deallocated
- id existingBoxedObject = [boxedObjects objectForKey:key];
- if (existingBoxedObject)
+// id existingBoxedObject = [boxedObjects objectForKey:key];
+// id existingBoxedObject = [jsc boxedObject];
+// if (existingBoxedObject)
+ if ([jsc isObjectBoxed:boxedObject])
{
// Safe dealloc ?
if ([boxedObject retainCount] == 1)
{
if ([boxedObject respondsToSelector:@selector(safeDealloc)])
{
- id jsc = NULL;
+ jsc = NULL;
object_getInstanceVariable(boxedObject, "__jsCocoaController", (void**)&jsc);
// Call safeDealloc if enabled (will be disabled upon last JSCocoaController release, to make sure the )
if (jsc)
@@ -3205,7 +3213,8 @@ static void jsCocoaObject_finalize(JSObjectRef object)
}
}
- [boxedObjects removeObjectForKey:key];
+// [boxedObjects removeObjectForKey:key];
+ [jsc deleteBoxOfObject:boxedObject];
}
else
{
@@ -4842,7 +4851,7 @@ static JSValueRef jsCocoaInfo_getProperty(JSContextRef ctx, JSObjectRef object,
if ([propertyName isEqualToString:@"protocols"]) r = [class __protocols];
if (r)
- return [JSCocoa boxedJSObject:r inContext:ctx];
+ return [[JSCocoa controllerFromContext:ctx] boxObject:r];
return JSValueMakeUndefined(ctx);
}
View
8 JSCocoa/JSCocoaFFIArgument.m
@@ -1153,17 +1153,15 @@ + (int)sizeOfStructure:(NSString*)encoding
//
// Box
//
-+ (BOOL)boxObject:(id)objcObject toJSValueRef:(JSValueRef*)value inContext:(JSContextRef)ctx
-{
++ (BOOL)boxObject:(id)objcObject toJSValueRef:(JSValueRef*)value inContext:(JSContextRef)ctx {
// Return null if our pointer is null
- if (!objcObject)
- {
+ if (!objcObject) {
*value = JSValueMakeNull(ctx);
return YES;
}
// Use a global boxing function to always return the same Javascript object
// when requesting multiple boxings of the same ObjC object
- *value = [JSCocoaController boxedJSObject:objcObject inContext:ctx];
+ *value = [[JSCocoa controllerFromContext:ctx] boxObject:objcObject];
return YES;
}
View
2  JSCocoa/JSCocoaFFIClosure.m
@@ -179,7 +179,7 @@ - (void)calledByClosureWithArgs:(void**)closureArgs returnValue:(void*)returnVal
// Create 'this'
if (isObjC)
- jsThis = [JSCocoaController boxedJSObject:*(void**)closureArgs[0] inContext:ctx];
+ jsThis = [[JSCocoa controllerFromContext:ctx] boxObject:*(void**)closureArgs[0]];
// Call !
JSValueRef jsReturnValue = JSObjectCallAsFunction(ctx, jsFunctionObject, jsThis, effectiveArgumentCount, args, &exception);
View
4 JSCocoa/JSCocoaPrivateObject.h
@@ -49,8 +49,7 @@
JSContextRef ctx;
unsigned int externalJSValueIndex;
// (test) when storing JSValues from a WebView, used to retain the WebView's context.
- // Disabled for now. Just make sure the WebView has a longer life than the vars
- // it's using.
+ // Disabled for now. Just make sure the WebView has a longer life than the vars it uses.
//
// Disabled because retaining the context crashes in 32 bits, but works in 64 bit.
// May be reenabled someday.
@@ -82,6 +81,7 @@
- (void)setJSValueRef:(JSValueRef)v ctx:(JSContextRef)ctx;
- (JSValueRef)jsValueRef;
+- (void)setCtx:(JSContextRef)ctx;
- (JSContextRef)ctx;
- (void)setExternalJSValueRef:(JSValueRef)v ctx:(JSContextRef)ctx;
View
8 JSCocoa/JSCocoaPrivateObject.m
@@ -21,7 +21,7 @@ - (id)init
object = nil;
isAutoCall = NO;
jsValue = NULL;
- retainObject = YES;
+ retainObject= YES;
rawPointer = NULL;
ctx = NULL;
// retainContext = NO;
@@ -37,7 +37,8 @@ - (void)cleanUp
[JSCocoaController downJSCocoaPrivateObjectCount];
if (object && retainObject)
{
- [JSCocoaController downBoxedJSObjectCount:object];
+ NSLog(@"commented downBoxedJSObjectCount");
+// [JSCocoaController downBoxedJSObjectCount:object];
// NSLog(@"releasing %@(%d)", [object class], [object retainCount]);
// if ([object isKindOfClass:[JSCocoaController class]])
// [object autorelease];
@@ -145,6 +146,9 @@ - (JSValueRef)jsValueRef
return jsValue;
}
+- (void)setCtx:(JSContextRef)_ctx {
+ ctx = _ctx;
+}
- (JSContextRef)ctx
{
return ctx;
View
7 Tests/Resources/37 inited from webview.html
@@ -40,8 +40,8 @@
objCDate.release
objCDate = null
-// var delegate = OSX.NSApplication.sharedApplication.delegate
-//log('delegate=' + delegate)
+ var delegate = OSX.NSApplication.sharedApplication.delegate
+log('delegate=' + delegate)
log('NSDate.date=' + OSX.NSDate)
log('NSDate.date=' + OSX.NSDate.date)
log('NSDate.date=' + OSX.NSDate.date.timeIntervalSinceNow)
@@ -61,7 +61,6 @@
// if (delegate.add1(5) !=6) throw 'add1 failed'
// delegate.dummyValue = 13
// if (delegate.dummyValue != 13) throw 'dummyValue failed'
-/*
var point = new OSX.NSPoint(123, 456)
if (point.x != 123 || point.y != 456) throw 'new NSPoint failed'
@@ -89,7 +88,7 @@
log('NSDate=' + OSX.NSDate.valueOf())
log('OSX=' + OSX)
delegate.finishTest37(true)
-*/
+
document.getElementById('dump').innerHTML += '<br><h2 style="color: lime">OK</h2>'
}
catch(e)
View
3  TestsRunner/ApplicationController.m
@@ -290,7 +290,7 @@ - (IBAction)logInstanceStats:(id)sender
- (IBAction)logBoxedObjects:(id)sender
{
- [JSCocoa logBoxedObjects];
+ [jsc logBoxedObjects];
}
- (void)log:(NSString*)message
@@ -948,6 +948,7 @@ - (void)finishTest37:(BOOL)b
[jsc callJSFunctionNamed:@"completeDelayedTest" withArguments:@"37 init from webview", [NSNumber numberWithInt:1], nil];
NSLog(@"COMMENTED test 37 !");
+ return;
NSLog(@"jsc2 rc=%lu (%llx)", [jsc2 retainCount], self);
NSLog(@"get1 %@", [jsc2 eval:@"__jsc__"]);
// b = [jsc2 removeObjectWithName:@"__jsc__"];
View
36,464 ....xcodeproj/project.xcworkspace/xcuserdata/mini.xcuserdatad/UserInterfaceState.xcuserstate
13,333 additions, 23,131 deletions not shown
Please sign in to comment.
Something went wrong with that request. Please try again.