This commit is contained in:
Chris Wanstrath 2011-08-18 22:10:11 -07:00
parent bb51f70c5b
commit 7a773615f2
17 changed files with 15486 additions and 0 deletions

View File

@ -61,6 +61,15 @@
8359A69213FE1FE900AC37E3 /* worker-javascript.js in Resources */ = {isa = PBXBuildFile; fileRef = 8359A63413FE1FCA00AC37E3 /* worker-javascript.js */; };
8359A6B413FE24B300AC37E3 /* atomicity.js in Sources */ = {isa = PBXBuildFile; fileRef = 8359A6B313FE24B300AC37E3 /* atomicity.js */; };
8359A6B713FE24BC00AC37E3 /* atomicity.js in Resources */ = {isa = PBXBuildFile; fileRef = 8359A6B313FE24B300AC37E3 /* atomicity.js */; };
8359A6EE13FE26DA00AC37E3 /* JavaScriptCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8359A6ED13FE26DA00AC37E3 /* JavaScriptCore.framework */; };
8359A72213FE270F00AC37E3 /* BridgeSupportController.m in Sources */ = {isa = PBXBuildFile; fileRef = 8359A6F913FE270F00AC37E3 /* BridgeSupportController.m */; };
8359A72313FE270F00AC37E3 /* class.js in Sources */ = {isa = PBXBuildFile; fileRef = 8359A6FA13FE270F00AC37E3 /* class.js */; };
8359A72F13FE270F00AC37E3 /* JSCocoaController.m in Sources */ = {isa = PBXBuildFile; fileRef = 8359A71813FE270F00AC37E3 /* JSCocoaController.m */; };
8359A73013FE270F00AC37E3 /* JSCocoaFFIArgument.m in Sources */ = {isa = PBXBuildFile; fileRef = 8359A71A13FE270F00AC37E3 /* JSCocoaFFIArgument.m */; };
8359A73113FE270F00AC37E3 /* JSCocoaFFIClosure.m in Sources */ = {isa = PBXBuildFile; fileRef = 8359A71C13FE270F00AC37E3 /* JSCocoaFFIClosure.m */; };
8359A73213FE270F00AC37E3 /* JSCocoaLib.m in Sources */ = {isa = PBXBuildFile; fileRef = 8359A71E13FE270F00AC37E3 /* JSCocoaLib.m */; };
8359A73313FE270F00AC37E3 /* JSCocoaPrivateObject.m in Sources */ = {isa = PBXBuildFile; fileRef = 8359A72013FE270F00AC37E3 /* JSCocoaPrivateObject.m */; };
8359A73413FE270F00AC37E3 /* jslint-jscocoa.js in Sources */ = {isa = PBXBuildFile; fileRef = 8359A72113FE270F00AC37E3 /* jslint-jscocoa.js */; };
8D11072B0486CEB800E47090 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */; };
8D11072D0486CEB800E47090 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* main.m */; settings = {ATTRIBUTES = (); }; };
8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */; };
@ -128,6 +137,22 @@
8359A63313FE1FCA00AC37E3 /* worker-css.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = "worker-css.js"; path = "HTML/ace/worker-css.js"; sourceTree = "<group>"; };
8359A63413FE1FCA00AC37E3 /* worker-javascript.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = "worker-javascript.js"; path = "HTML/ace/worker-javascript.js"; sourceTree = "<group>"; };
8359A6B313FE24B300AC37E3 /* atomicity.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = atomicity.js; path = HTML/atomicity.js; sourceTree = "<group>"; };
8359A6ED13FE26DA00AC37E3 /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; };
8359A6F813FE270F00AC37E3 /* BridgeSupportController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BridgeSupportController.h; sourceTree = "<group>"; };
8359A6F913FE270F00AC37E3 /* BridgeSupportController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BridgeSupportController.m; sourceTree = "<group>"; };
8359A6FA13FE270F00AC37E3 /* class.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = class.js; sourceTree = "<group>"; };
8359A71313FE270F00AC37E3 /* JSCocoa.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSCocoa.h; sourceTree = "<group>"; };
8359A71713FE270F00AC37E3 /* JSCocoaController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSCocoaController.h; sourceTree = "<group>"; };
8359A71813FE270F00AC37E3 /* JSCocoaController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSCocoaController.m; sourceTree = "<group>"; };
8359A71913FE270F00AC37E3 /* JSCocoaFFIArgument.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSCocoaFFIArgument.h; sourceTree = "<group>"; };
8359A71A13FE270F00AC37E3 /* JSCocoaFFIArgument.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSCocoaFFIArgument.m; sourceTree = "<group>"; };
8359A71B13FE270F00AC37E3 /* JSCocoaFFIClosure.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSCocoaFFIClosure.h; sourceTree = "<group>"; };
8359A71C13FE270F00AC37E3 /* JSCocoaFFIClosure.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSCocoaFFIClosure.m; sourceTree = "<group>"; };
8359A71D13FE270F00AC37E3 /* JSCocoaLib.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSCocoaLib.h; sourceTree = "<group>"; };
8359A71E13FE270F00AC37E3 /* JSCocoaLib.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSCocoaLib.m; sourceTree = "<group>"; };
8359A71F13FE270F00AC37E3 /* JSCocoaPrivateObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSCocoaPrivateObject.h; sourceTree = "<group>"; };
8359A72013FE270F00AC37E3 /* JSCocoaPrivateObject.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSCocoaPrivateObject.m; sourceTree = "<group>"; };
8359A72113FE270F00AC37E3 /* jslint-jscocoa.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = "jslint-jscocoa.js"; sourceTree = "<group>"; };
8D1107310486CEB800E47090 /* Atomicity-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "Atomicity-Info.plist"; sourceTree = "<group>"; };
8D1107320486CEB800E47090 /* Atomicity.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Atomicity.app; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */
@ -139,6 +164,7 @@
files = (
8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */,
83599F9B13FE0F8400AC37E3 /* WebKit.framework in Frameworks */,
8359A6EE13FE26DA00AC37E3 /* JavaScriptCore.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -159,6 +185,7 @@
children = (
1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */,
83599F9A13FE0F8400AC37E3 /* WebKit.framework */,
8359A6ED13FE26DA00AC37E3 /* JavaScriptCore.framework */,
);
name = "Linked Frameworks";
sourceTree = "<group>";
@ -188,6 +215,7 @@
080E96DDFE201D6D7F000001 /* Classes */,
29B97315FDCFA39411CA2CEA /* Other Sources */,
29B97317FDCFA39411CA2CEA /* Resources */,
8359A6F713FE270F00AC37E3 /* JSCocoa */,
29B97323FDCFA39411CA2CEA /* Frameworks */,
19C28FACFE9D520D11CA2CBB /* Products */,
);
@ -287,6 +315,28 @@
name = ace;
sourceTree = "<group>";
};
8359A6F713FE270F00AC37E3 /* JSCocoa */ = {
isa = PBXGroup;
children = (
8359A6F813FE270F00AC37E3 /* BridgeSupportController.h */,
8359A6F913FE270F00AC37E3 /* BridgeSupportController.m */,
8359A6FA13FE270F00AC37E3 /* class.js */,
8359A71313FE270F00AC37E3 /* JSCocoa.h */,
8359A71713FE270F00AC37E3 /* JSCocoaController.h */,
8359A71813FE270F00AC37E3 /* JSCocoaController.m */,
8359A71913FE270F00AC37E3 /* JSCocoaFFIArgument.h */,
8359A71A13FE270F00AC37E3 /* JSCocoaFFIArgument.m */,
8359A71B13FE270F00AC37E3 /* JSCocoaFFIClosure.h */,
8359A71C13FE270F00AC37E3 /* JSCocoaFFIClosure.m */,
8359A71D13FE270F00AC37E3 /* JSCocoaLib.h */,
8359A71E13FE270F00AC37E3 /* JSCocoaLib.m */,
8359A71F13FE270F00AC37E3 /* JSCocoaPrivateObject.h */,
8359A72013FE270F00AC37E3 /* JSCocoaPrivateObject.m */,
8359A72113FE270F00AC37E3 /* jslint-jscocoa.js */,
);
path = JSCocoa;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
@ -402,6 +452,14 @@
8D11072D0486CEB800E47090 /* main.m in Sources */,
256AC3DA0F4B6AC300CF3369 /* AtomicityAppDelegate.m in Sources */,
8359A6B413FE24B300AC37E3 /* atomicity.js in Sources */,
8359A72213FE270F00AC37E3 /* BridgeSupportController.m in Sources */,
8359A72313FE270F00AC37E3 /* class.js in Sources */,
8359A72F13FE270F00AC37E3 /* JSCocoaController.m in Sources */,
8359A73013FE270F00AC37E3 /* JSCocoaFFIArgument.m in Sources */,
8359A73113FE270F00AC37E3 /* JSCocoaFFIClosure.m in Sources */,
8359A73213FE270F00AC37E3 /* JSCocoaLib.m in Sources */,
8359A73313FE270F00AC37E3 /* JSCocoaPrivateObject.m in Sources */,
8359A73413FE270F00AC37E3 /* jslint-jscocoa.js in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -432,6 +490,10 @@
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
COPY_PHASE_STRIP = NO;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"\"$(SRCROOT)\"",
);
GCC_DYNAMIC_NO_PIC = NO;
GCC_ENABLE_FIX_AND_CONTINUE = YES;
GCC_MODEL_TUNING = G5;
@ -449,6 +511,10 @@
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"\"$(SRCROOT)\"",
);
GCC_MODEL_TUNING = G5;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = Atomicity_Prefix.pch;
@ -467,6 +533,10 @@
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
ONLY_ACTIVE_ARCH = YES;
OTHER_LDFLAGS = (
"-lxml2",
"-lffi",
);
PREBINDING = NO;
SDKROOT = macosx10.6;
};
@ -479,6 +549,10 @@
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
OTHER_LDFLAGS = (
"-lxml2",
"-lffi",
);
PREBINDING = NO;
SDKROOT = macosx10.6;
};

View File

@ -0,0 +1,43 @@
//
// BridgeSupportController.h
// JSCocoa
//
// Created by Patrick Geiller on 08/07/08.
// Copyright 2008 __MyCompanyName__. All rights reserved.
//
#if !TARGET_IPHONE_SIMULATOR && !TARGET_OS_IPHONE
#import <Cocoa/Cocoa.h>
#endif
@interface BridgeSupportController : NSObject {
NSMutableArray* paths;
NSMutableArray* xmlDocuments;
NSMutableDictionary* hash;
NSMutableDictionary* variadicSelectors;
NSMutableDictionary* variadicFunctions;
}
+ (id)sharedController;
- (BOOL)loadBridgeSupport:(NSString*)path;
- (BOOL)isBridgeSupportLoaded:(NSString*)path;
- (NSUInteger)bridgeSupportIndexForString:(NSString*)string;
- (NSMutableDictionary*)variadicSelectors;
- (NSMutableDictionary*)variadicFunctions;
/*
- (NSString*)query:(NSString*)name withType:(NSString*)type;
- (NSString*)query:(NSString*)name withType:(NSString*)type inBridgeSupportFile:(NSString*)file;
*/
- (NSString*)queryName:(NSString*)name;
- (NSString*)queryName:(NSString*)name type:(NSString*)type;
- (NSArray*)keys;
@end

View File

@ -0,0 +1,254 @@
//
// BridgeSupportController.m
// JSCocoa
//
// Created by Patrick Geiller on 08/07/08.
// Copyright 2008 __MyCompanyName__. All rights reserved.
//
#import "BridgeSupportController.h"
@implementation BridgeSupportController
+ (id)sharedController
{
static id singleton;
@synchronized(self)
{
if (!singleton)
singleton = [[BridgeSupportController alloc] init];
return singleton;
}
return singleton;
}
- (id)init
{
self = [super init];
paths = [[NSMutableArray alloc] init];
xmlDocuments = [[NSMutableArray alloc] init];
hash = [[NSMutableDictionary alloc] init];
variadicSelectors = [[NSMutableDictionary alloc] init];
variadicFunctions = [[NSMutableDictionary alloc] init];
return self;
}
- (void)dealloc
{
[variadicFunctions release];
[variadicSelectors release];
[hash release];
[paths release];
[xmlDocuments release];
[super dealloc];
}
//
// Load a bridgeSupport file into a hash as { name : xmlTagString }
//
- (BOOL)loadBridgeSupport:(NSString*)path
{
NSError* error = nil;
/*
Adhoc parser
NSXMLDocument is too slow
loading xml document as string then querying on-demand is too slow
can't get CFXMLParserRef to work
don't wan't to delve into expat
-> ad hoc : load file, build a hash of { name : xmlTagString }
*/
NSString* xmlDocument = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:&error];
if (error) return NSLog(@"loadBridgeSupport : %@", error), NO;
char* c = (char*)[xmlDocument UTF8String];
#ifdef __OBJC_GC__
char* originalC = c;
[[NSGarbageCollector defaultCollector] disableCollectorForPointer:originalC];
#endif
// double t0 = CFAbsoluteTimeGetCurrent();
// Start parsing
for (; *c; c++)
{
if (*c == '<')
{
char startTagChar = c[1];
if (startTagChar == 0) return NO;
// 'co' constant
// 'cl' class
// 'e' enum
// 'fu' function
// 'st' struct
if ((c[1] == 'c' && (c[2] == 'o' || c[2] == 'l')) || c[1] == 'e' || (c[1] == 'f' && c[2] == 'u') || (c[1] == 's' && c[2] == 't'))
{
// Extract name
char* tagStart = c;
for (; *c && *c != '\''; c++);
c++;
char* c0 = c;
for (; *c && *c != '\''; c++);
id name = [[NSString alloc] initWithBytes:c0 length:c-c0 encoding:NSUTF8StringEncoding];
// Move to tag end
BOOL foundEndTag = NO;
BOOL foundOpenTag = NO;
c++;
for (; *c && !foundEndTag; c++)
{
if (*c == '<') foundOpenTag = YES;
else
if (*c == '/')
{
if (!foundOpenTag)
{
if(c[1] == '>') foundEndTag = YES, c++;
}
else
{
if (startTagChar == c[1])
{
foundEndTag = YES;
// Skip to end of tag
for (; *c && *c != '>'; c++);
}
}
}
else
// Variadic parsing
if (c[0] == 'v' && c[1] == 'a' && c[2] == 'r')
{
if (strncmp(c, "variadic", 8) == 0)
{
// Skip back to tag start
c0 = c;
for (; *c0 != '<'; c0--);
// Tag name starts with 'm' : variadic method
// <method variadic='true' selector='alertWithMessageText:defaultButton:alternateButton:otherButton:informativeTextWithFormat:' class_method='true'>
if (c0[1] == 'm')
{
c = c0;
id variadicMethodName = nil;
// Extract selector name
for (; *c != '>'; c++)
{
if (c[0] == ' ' && c[1] == 's' && c[2] == 'e' && c[3] == 'l')
{
for (; *c && *c != '\''; c++);
c++;
c0 = c;
for (; *c && *c != '\''; c++);
variadicMethodName = [[[NSString alloc] initWithBytes:c0 length:c-c0 encoding:NSUTF8StringEncoding] autorelease];
}
}
[variadicSelectors setValue:@"true" forKey:variadicMethodName];
// NSLog(@"SELECTOR %@", name);
}
else
// Variadic function
// <function name='NSBeginAlertSheet' variadic='true'>
{
[variadicFunctions setValue:@"true" forKey:name];
// NSLog(@"function %@", name);
}
}
}
}
c0 = tagStart;
id value = [[NSString alloc] initWithBytes:c0 length:c-c0 encoding:NSUTF8StringEncoding];
[hash setValue:value forKey:name];
[value release];
[name release];
}
}
}
// double t1 = CFAbsoluteTimeGetCurrent();
// NSLog(@"BridgeSupport %@ parsed in %f", [[path lastPathComponent] stringByDeletingPathExtension], t1-t0);
#ifdef __OBJC_GC__
[[NSGarbageCollector defaultCollector] enableCollectorForPointer:originalC];
#endif
[paths addObject:path];
[xmlDocuments addObject:xmlDocument];
return YES;
}
- (BOOL)isBridgeSupportLoaded:(NSString*)path
{
NSUInteger idx = [self bridgeSupportIndexForString:path];
return idx == NSNotFound ? NO : YES;
}
//
// bridgeSupportIndexForString
// given 'AppKit', return index of '/System/Library/Frameworks/AppKit.framework/Versions/C/Resources/BridgeSupport/AppKitFull.bridgesupport'
//
- (NSUInteger)bridgeSupportIndexForString:(NSString*)string
{
NSUInteger i, l = [paths count];
for (i=0; i<l; i++)
{
NSString* path = [paths objectAtIndex:i];
NSRange range = [path rangeOfString:string];
if (range.location != NSNotFound) return range.location;
}
return NSNotFound;
}
- (NSMutableDictionary*)variadicSelectors
{
return variadicSelectors;
}
- (NSMutableDictionary*)variadicFunctions
{
return variadicFunctions;
}
- (NSArray*)keys
{
[hash removeObjectForKey:@"NSProxy"];
[hash removeObjectForKey:@"NSProtocolChecker"];
[hash removeObjectForKey:@"NSDistantObject"];
return [hash allKeys];
}
- (NSString*)queryName:(NSString*)name
{
return [hash valueForKey:name];
}
- (NSString*)queryName:(NSString*)name type:(NSString*)type
{
id v = [self queryName:name];
if (!v) return nil;
char* c = (char*)[v UTF8String];
// Skip tag start
c++;
char* c0 = c;
for (; *c && *c != ' '; c++);
id extractedType = [[NSString alloc] initWithBytes:c0 length:c-c0 encoding:NSUTF8StringEncoding];
[extractedType autorelease];
// NSLog(@"extractedType=%@", extractedType);
if (![extractedType isEqualToString:type]) return nil;
return v;
}
@end

11
JSCocoa/JSCocoa.h Normal file
View File

@ -0,0 +1,11 @@
//
// JSCocoa.h
// JSCocoa
//
// Created by Patrick Geiller on 16/12/08.
// Copyright 2008 __MyCompanyName__. All rights reserved.
//
#define JSCOCOA
#import "JSCocoaController.h"

359
JSCocoa/JSCocoaController.h Normal file
View File

@ -0,0 +1,359 @@
//
// JSCocoa.h
// JSCocoa
//
// Created by Patrick Geiller on 09/07/08.
// Copyright 2008 __MyCompanyName__. All rights reserved.
//
#if !TARGET_IPHONE_SIMULATOR && !TARGET_OS_IPHONE
#import <Cocoa/Cocoa.h>
#import <JavaScriptCore/JavaScriptCore.h>
#define MACOSX
#import <ffi/ffi.h>
#endif
#import "BridgeSupportController.h"
#import "JSCocoaPrivateObject.h"
#import "JSCocoaFFIArgument.h"
#import "JSCocoaFFIClosure.h"
// JS value container, used by methods wanting a straight JSValue and not a converted JS->ObjC value.
struct JSValueRefAndContextRef
{
JSValueRef value;
JSContextRef ctx;
};
typedef struct JSValueRefAndContextRef JSValueRefAndContextRef;
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
#import "iPhone/libffi/ffi.h"
#import "iPhone/BurksPool.h"
#endif
//
// JSCocoaController
//
@interface JSCocoaController : NSObject {
JSGlobalContextRef ctx;
BOOL ownsContext;
id _delegate;
//
// Split call
// Allows calling multi param ObjC messages with a jQuery-like syntax.
//
// obj.do({ this : 'hello', andThat : 'world' })
// instead of
// obj.dothis_andThat_('hello', 'world')
//
BOOL useSplitCall;
// JSLint : used for ObjJ syntax, class syntax, return if
BOOL useJSLint;
// Auto call zero arg methods : allow NSWorkspace.sharedWorkspace instead of NSWorkspace.sharedWorkspace()
BOOL useAutoCall;
// 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;
@property BOOL useSafeDealloc, useSplitCall, useJSLint, useAutoCall, callSelectorsMissingTrailingSemicolon, canSetOnBoxedObjects, logAllExceptions;
- (id)init;
- (id)initWithGlobalContext:(JSGlobalContextRef)ctx;
+ (id)sharedController;
+ (id)controllerFromContext:(JSContextRef)ctx;
+ (BOOL)hasSharedController;
- (JSGlobalContextRef)ctx;
+ (void)hazardReport;
+ (NSString*)runningArchitecture;
+ (void)updateCustomCallPaths;
- (void)accomodateWebKitInspector;
//
// Evaluation
//
- (id)eval:(NSString*)script;
- (id)callFunction:(NSString*)name;
- (id)callFunction:(NSString*)name withArguments:(NSArray*)arguments;
- (BOOL)hasFunction:(NSString*)name;
- (BOOL)isSyntaxValid:(NSString*)script;
- (BOOL)evalJSFile:(NSString*)path;
- (BOOL)evalJSFile:(NSString*)path toJSValueRef:(JSValueRef*)returnValue;
- (JSValueRef)evalJSString:(NSString*)script;
- (JSValueRef)evalJSString:(NSString*)script withScriptPath:(NSString*)path;
- (JSValueRef)callJSFunction:(JSValueRef)function withArguments:(NSArray*)arguments;
- (JSValueRef)callJSFunctionNamed:(NSString*)functionName withArguments:arguments, ... NS_REQUIRES_NIL_TERMINATION;
- (JSValueRef)callJSFunctionNamed:(NSString*)functionName withArgumentsArray:(NSArray*)arguments;
- (JSObjectRef)JSFunctionNamed:(NSString*)functionName;
- (BOOL)hasJSFunctionNamed:(NSString*)functionName;
- (NSString*)expandJSMacros:(NSString*)script path:(NSString*)path;
- (NSString*)expandJSMacros:(NSString*)script path:(NSString*)path errors:(NSMutableArray*)array;
- (BOOL)isSyntaxValid:(NSString*)script error:(NSString**)error;
- (BOOL)setObject:(id)object withName:(NSString*)name;
- (BOOL)setObject:(id)object withName:(NSString*)name attributes:(JSPropertyAttributes)attributes;
- (BOOL)setObjectNoRetain:(id)object withName:(NSString*)name attributes:(JSPropertyAttributes)attributes;
- (id)objectWithName:(NSString*)name;
- (BOOL)removeObjectWithName:(NSString*)name;
// Get ObjC and raw values from Javascript
- (id)unboxJSValueRef:(JSValueRef)jsValue;
- (BOOL)toBool:(JSValueRef)value;
- (double)toDouble:(JSValueRef)value;
- (int)toInt:(JSValueRef)value;
- (NSString*)toString:(JSValueRef)value;
// Wrapper for unboxJSValueRef
- (id)toObject:(JSValueRef)value;
//
// Framework
//
- (BOOL)loadFrameworkWithName:(NSString*)name;
- (BOOL)loadFrameworkWithName:(NSString*)frameworkName inPath:(NSString*)path;
//
// Garbage collection
//
+ (void)garbageCollect;
- (void)garbageCollect;
- (void)unlinkAllReferences;
+ (void)upJSCocoaPrivateObjectCount;
+ (void)downJSCocoaPrivateObjectCount;
+ (int)JSCocoaPrivateObjectCount;
+ (void)upJSValueProtectCount;
+ (void)downJSValueProtectCount;
+ (int)JSValueProtectCount;
+ (void)logInstanceStats;
- (id)instanceStats;
- (void)logBoxedObjects;
//
// Class inspection (shortcuts to JSCocoaLib)
//
+ (id)rootclasses;
+ (id)classes;
+ (id)protocols;
+ (id)imageNames;
+ (id)methods;
+ (id)runtimeReport;
+ (id)explainMethodEncoding:(id)encoding;
//
// Class handling
//
+ (BOOL)overloadInstanceMethod:(NSString*)methodName class:(Class)class jsFunction:(JSValueRefAndContextRef)valueAndContext;
+ (BOOL)overloadClassMethod:(NSString*)methodName class:(Class)class jsFunction:(JSValueRefAndContextRef)valueAndContext;
+ (BOOL)addClassMethod:(NSString*)methodName class:(Class)class jsFunction:(JSValueRefAndContextRef)valueAndContext encoding:(char*)encoding;
+ (BOOL)addInstanceMethod:(NSString*)methodName class:(Class)class jsFunction:(JSValueRefAndContextRef)valueAndContext encoding:(char*)encoding;
// Tests
- (int)runTests:(NSString*)path;
- (int)runTests:(NSString*)path withSelector:(SEL)sel;
//
// Autorelease pool
//
+ (void)allocAutoreleasePool;
+ (void)deallocAutoreleasePool;
//
// 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;
//
// Various internals
//
//+ (JSObjectRef)jsCocoaPrivateObjectInContext:(JSContextRef)ctx;
- (JSObjectRef)newPrivateObject;
- (JSObjectRef)newPrivateFunction;
+ (NSMutableArray*)parseObjCMethodEncoding:(const char*)typeEncoding;
+ (NSMutableArray*)parseCFunctionEncoding:(NSString*)xml functionName:(NSString**)functionNamePlaceHolder;
//+ (void)ensureJSValueIsObjectAfterInstanceAutocall:(JSValueRef)value inContext:(JSContextRef)ctx;
- (NSString*)formatJSException:(JSValueRef)exception;
- (id)selectorForJSFunction:(JSObjectRef)function;
- (const char*)typeEncodingOfMethod:(NSString*)methodName class:(NSString*)className;
+ (const char*)typeEncodingOfMethod:(NSString*)methodName class:(NSString*)className;
@end
//
// JSCocoa delegate methods
//
//
// Error reporting
//
@interface NSObject (JSCocoaControllerDelegateMethods)
- (void) JSCocoa:(JSCocoaController*)controller hadError:(NSString*)error onLineNumber:(NSInteger)lineNumber atSourceURL:(id)url;
- (void) safeDealloc;
//
// Getting
//
// Check if getting property is allowed
- (BOOL) JSCocoa:(JSCocoaController*)controller canGetProperty:(NSString*)propertyName ofObject:(id)object inContext:(JSContextRef)ctx exception:(JSValueRef*)exception;
// Custom handler for getting properties
// Return a custom JSValueRef to bypass JSCocoa
// Return NULL to let JSCocoa handle getProperty
// Return JSValueMakeNull() to return a Javascript null
- (JSValueRef) JSCocoa:(JSCocoaController*)controller getProperty:(NSString*)propertyName ofObject:(id)object inContext:(JSContextRef)ctx exception:(JSValueRef*)exception;
//
// Setting
//
// Check if setting property is allowed
- (BOOL) JSCocoa:(JSCocoaController*)controller canSetProperty:(NSString*)propertyName ofObject:(id)object toValue:(JSValueRef)value inContext:(JSContextRef)ctx exception:(JSValueRef*)exception;
// Custom handler for setting properties
// Return YES to indicate you handled setting
// Return NO to let JSCocoa handle setProperty
- (BOOL) JSCocoa:(JSCocoaController*)controller setProperty:(NSString*)propertyName ofObject:(id)object toValue:(JSValueRef)value inContext:(JSContextRef)ctx exception:(JSValueRef*)exception;
//
// Calling
//
// Check if calling a C function is allowed
- (BOOL) JSCocoa:(JSCocoaController*)controller canCallFunction:(NSString*)functionName argumentCount:(size_t)argumentCount arguments:(JSValueRef*)arguments inContext:(JSContextRef)ctx exception:(JSValueRef*)exception;
// Check if calling an ObjC method is allowed
- (BOOL) JSCocoa:(JSCocoaController*)controller canCallMethod:(NSString*)methodName ofObject:(id)object argumentCount:(size_t)argumentCount arguments:(JSValueRef*)arguments inContext:(JSContextRef)ctx exception:(JSValueRef*)exception;
// Custom handler for calling
// Return YES to indicate you handled calling
// Return NO to let JSCocoa handle calling
- (JSValueRef) JSCocoa:(JSCocoaController*)controller callMethod:(NSString*)methodName ofObject:(id)callee privateObject:(JSCocoaPrivateObject*)thisPrivateObject argumentCount:(size_t)argumentCount arguments:(JSValueRef*)arguments inContext:(JSContextRef)localCtx exception:(JSValueRef*)exception;
//
// Getting global properties (classes, structures, C function names, enums via OSXObject_getProperty)
//
// Check if getting property is allowed
- (BOOL) JSCocoa:(JSCocoaController*)controller canGetGlobalProperty:(NSString*)propertyName inContext:(JSContextRef)ctx exception:(JSValueRef*)exception;
// Custom handler for getting properties
// Return a custom JSValueRef to bypass JSCocoa
// Return NULL to let JSCocoa handle getProperty
// Return JSValueMakeNull() to return a Javascript null
- (JSValueRef) JSCocoa:(JSCocoaController*)controller getGlobalProperty:(NSString*)propertyName inContext:(JSContextRef)ctx exception:(JSValueRef*)exception;
//
// Returning values to Javascript
//
// Called before returning any value to Javascript : return a new value or the original one
//- (JSValueRef) JSCocoa:(JSCocoaController*)controller willReturnValue:(JSValueRef)value inContext:(JSContextRef)ctx exception:(JSValueRef*)exception;
//
// Evaling
//
// Check if file can be loaded
- (BOOL)JSCocoa:(JSCocoaController*)controller canLoadJSFile:(NSString*)path;
// Check if script can be evaluated
- (BOOL)JSCocoa:(JSCocoaController*)controller canEvaluateScript:(NSString*)script;
// Called before evalJSString, used to modify script about to be evaluated
// Return a custom NSString (eg a macro expanded version of the source)
// Return NULL to let JSCocoa handle evaluation
- (NSString*)JSCocoa:(JSCocoaController*)controller willEvaluateScript:(NSString*)script;
@end
//
// JSCocoa shorthand
//
@interface JSCocoa : JSCocoaController
@end
//
// Boxed object cache : holds one JSObjectRef for each reference to a pointer to an ObjC object
//
@interface BoxedJSObject : NSObject {
JSObjectRef jsObject;
}
- (void)setJSObject:(JSObjectRef)o;
- (JSObjectRef)jsObject;
@end
//
// Helpers
//
id NSStringFromJSValue(JSContextRef ctx, JSValueRef value);
//void* malloc_autorelease(size_t size);
// Convert values between contexts (eg user context and webkit page context)
JSValueRef valueToExternalContext(JSContextRef ctx, JSValueRef value, JSContextRef externalCtx);
// valueOf() is called by Javascript on objects, eg someObject + ' someString'
JSValueRef valueOfCallback(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception);
//
// From PyObjC : when to call objc_msgSend_stret, for structure return
// Depending on structure size & architecture, structures are returned as function first argument (done transparently by ffi) or via registers
//
#if defined(__ppc__)
# define SMALL_STRUCT_LIMIT 4
#elif defined(__ppc64__)
# define SMALL_STRUCT_LIMIT 8
#elif defined(__i386__)
# define SMALL_STRUCT_LIMIT 8
#elif defined(__x86_64__)
# define SMALL_STRUCT_LIMIT 16
#elif TARGET_OS_IPHONE
// TOCHECK
# define SMALL_STRUCT_LIMIT 4
#else
# error "Unsupported MACOSX platform"
#endif
// Stored in boxedobjects to access a list of methods, properties, ...
#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.
*/

5035
JSCocoa/JSCocoaController.m Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,97 @@
//
// JSCocoaFFIArgument.h
// JSCocoa
//
// Created by Patrick Geiller on 14/07/08.
// Copyright 2008 __MyCompanyName__. All rights reserved.
//
#if !TARGET_IPHONE_SIMULATOR && !TARGET_OS_IPHONE
#import <Cocoa/Cocoa.h>
#import <JavaScriptCore/JavaScriptCore.h>
#define MACOSX
#include <ffi/ffi.h>
#endif
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
#import "iPhone/libffi/ffi.h"
#endif
@interface JSCocoaFFIArgument : NSObject {
char typeEncoding;
NSString* structureTypeEncoding;
NSString* pointerTypeEncoding;
void* ptr;
ffi_type structureType;
id customData;
BOOL isReturnValue;
BOOL ownsStorage;
BOOL isOutArgument;
}
- (NSString*)typeDescription;
- (BOOL)setTypeEncoding:(char)encoding;
- (BOOL)setTypeEncoding:(char)encoding withCustomStorage:(void*)storagePtr;
- (void)setStructureTypeEncoding:(NSString*)encoding;
- (void)setStructureTypeEncoding:(NSString*)encoding withCustomStorage:(void*)storagePtr;
- (void)setPointerTypeEncoding:(NSString*)encoding;
+ (int)sizeOfTypeEncoding:(char)encoding;
+ (int)alignmentOfTypeEncoding:(char)encoding;
+ (ffi_type*)ffi_typeForTypeEncoding:(char)encoding;
+ (int)sizeOfStructure:(NSString*)encoding;
+ (NSArray*)typeEncodingsFromStructureTypeEncoding:(NSString*)structureTypeEncoding;
+ (NSArray*)typeEncodingsFromStructureTypeEncoding:(NSString*)structureTypeEncoding parsedCount:(NSInteger*)count;
+ (NSString*)structureNameFromStructureTypeEncoding:(NSString*)structureTypeEncoding;
+ (NSString*)structureFullTypeEncodingFromStructureTypeEncoding:(NSString*)structureTypeEncoding;
+ (NSString*)structureFullTypeEncodingFromStructureName:(NSString*)structureName;
+ (NSString*)structureTypeEncodingDescription:(NSString*)structureTypeEncoding;
+ (BOOL)fromJSValueRef:(JSValueRef)value inContext:(JSContextRef)ctx typeEncoding:(char)typeEncoding fullTypeEncoding:(NSString*)fullTypeEncoding fromStorage:(void*)ptr;
+ (BOOL)toJSValueRef:(JSValueRef*)value inContext:(JSContextRef)ctx typeEncoding:(char)typeEncoding fullTypeEncoding:(NSString*)fullTypeEncoding fromStorage:(void*)ptr;
+ (NSInteger)structureToJSValueRef:(JSValueRef*)value inContext:(JSContextRef)ctx fromCString:(char*)c fromStorage:(void**)storage;
+ (NSInteger)structureToJSValueRef:(JSValueRef*)value inContext:(JSContextRef)ctx fromCString:(char*)c fromStorage:(void**)ptr initialValues:(JSValueRef*)initialValues initialValueCount:(NSInteger)initialValueCount convertedValueCount:(NSInteger*)convertedValueCount;
+ (NSInteger)structureFromJSObjectRef:(JSObjectRef)value inContext:(JSContextRef)ctx inParentJSValueRef:(JSValueRef)parentValue fromCString:(char*)c fromStorage:(void**)ptr;
+ (void)alignPtr:(void**)ptr accordingToEncoding:(char)encoding;
+ (void)advancePtr:(void**)ptr accordingToEncoding:(char)encoding;
- (void*)allocateStorage;
- (void*)allocatePointerStorage;
- (void**)storage;
- (void**)rawStoragePointer;
- (char)typeEncoding;
- (NSString*)structureTypeEncoding;
- (id)pointerTypeEncoding;
- (void)setIsReturnValue:(BOOL)v;
- (BOOL)isReturnValue;
- (void)setIsOutArgument:(BOOL)v;
- (BOOL)isOutArgument;
- (BOOL)fromJSValueRef:(JSValueRef)value inContext:(JSContextRef)ctx;
- (BOOL)toJSValueRef:(JSValueRef*)value inContext:(JSContextRef)ctx;
+ (BOOL)boxObject:(id)o toJSValueRef:(JSValueRef*)value inContext:(JSContextRef)ctx;
+ (BOOL)unboxJSValueRef:(JSValueRef)value toObject:(id*)o inContext:(JSContextRef)ctx;
+ (BOOL)unboxJSArray:(JSObjectRef)value toObject:(id*)o inContext:(JSContextRef)ctx;
+ (BOOL)unboxJSHash:(JSObjectRef)value toObject:(id*)o inContext:(JSContextRef)ctx;
- (ffi_type*)ffi_type;
@end

1357
JSCocoa/JSCocoaFFIArgument.m Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,45 @@
//
// JSCocoaFFIClosure.h
// JSCocoa
//
// Created by Patrick Geiller on 29/07/08.
// Copyright 2008 __MyCompanyName__. All rights reserved.
//
#if !TARGET_IPHONE_SIMULATOR && !TARGET_OS_IPHONE
#import <Cocoa/Cocoa.h>
#import <JavaScriptCore/JavaScriptCore.h>
#define MACOSX
#import <ffi/ffi.h>
#endif
#import "JSCocoaFFIArgument.h"
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
#import "iPhone/libffi/ffi.h"
#endif
@interface JSCocoaFFIClosure : NSObject {
JSValueRef jsFunction;
// ##UNSURE This might cause a crash if we're registered in a non global context that will have been destroyed when we JSValueUnprotect the function
JSContextRef ctx;
ffi_cif cif;
#if !TARGET_OS_IPHONE
ffi_closure* closure;
#endif
ffi_type** argTypes;
NSMutableArray* encodings;
JSObjectRef jsThisObject;
BOOL isObjC;
}
- (IMP)setJSFunction:(JSValueRef)fn inContext:(JSContextRef)ctx argumentEncodings:(NSMutableArray*)argumentEncodings objC:(BOOL)objC;
- (void*)functionPointer;
- (void)calledByClosureWithArgs:(void**)args returnValue:(void*)returnValue;
@end

213
JSCocoa/JSCocoaFFIClosure.m Normal file
View File

@ -0,0 +1,213 @@
//
// JSCocoaFFIClosure.m
// JSCocoa
//
// Created by Patrick Geiller on 29/07/08.
// Copyright 2008 __MyCompanyName__. All rights reserved.
//
#import "JSCocoaFFIClosure.h"
#import "JSCocoaController.h"
#include <sys/mman.h> // for mmap()
@implementation JSCocoaFFIClosure
//
// Common closure function, calling back closure object
//
void closure_function(ffi_cif* cif, void* resp, void** args, void* userdata)
{
[(id)userdata calledByClosureWithArgs:args returnValue:resp];
}
- (id)init
{
self = [super init];
argTypes = NULL;
encodings = NULL;
jsFunction = NULL;
return self;
}
//
// Cleanup : called by dealloc and finalize
//
- (void)cleanUp
{
if (encodings) [encodings release];
if (argTypes) free(argTypes);
if (jsFunction)
{
JSValueUnprotect(ctx, jsFunction);
[JSCocoaController downJSValueProtectCount];
}
#if !TARGET_OS_IPHONE
if (munmap(closure, sizeof(closure)) == -1) NSLog(@"ffi closure munmap failed");
#endif
}
- (void)dealloc
{
// NSLog(@"deallocing closure %p IMP=%p", self, closure);
[self cleanUp];
[super dealloc];
}
- (void)finalize
{
[self cleanUp];
[super finalize];
}
- (void*)functionPointer
{
#if !TARGET_OS_IPHONE
return closure;
#else
return NULL;
#endif
}
//
// Bind a js function to closure. We'll jsValueProtect that function from GC.
//
- (IMP)setJSFunction:(JSValueRef)fn inContext:(JSContextRef)context argumentEncodings:(NSMutableArray*)argumentEncodings objC:(BOOL)objC
{
#if !TARGET_OS_IPHONE
if ([argumentEncodings count] == 0) return NULL;
encodings = argumentEncodings;
[encodings retain];
isObjC = objC;
unsigned int i, argumentCount = (unsigned int)([argumentEncodings count]-1);
argTypes = malloc(sizeof(ffi_type*)*argumentCount);
for (i=0; i<argumentCount; i++)
{
JSCocoaFFIArgument* arg = [argumentEncodings objectAtIndex:i+1];
argTypes[i] = [arg ffi_type];
}
if ((closure = mmap(NULL, sizeof(ffi_closure), PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0)) == (void*)-1)
{
NSLog(@"ffi closure mmap failed");
return NULL;
}
id returnValue = [argumentEncodings objectAtIndex:0];
ffi_status prep_status = ffi_prep_cif(&cif, FFI_DEFAULT_ABI, argumentCount, [returnValue ffi_type], argTypes);
if (prep_status != FFI_OK)
{
NSLog(@"ffi_prep_cif failed");
return NULL;
}
if (ffi_prep_closure(closure, &cif, closure_function, (void *)self) != FFI_OK)
{
NSLog(@"ffi_prep_closure failed");
return NULL;
}
if (mprotect(closure, sizeof(closure), PROT_READ | PROT_EXEC) == -1)
{
NSLog(@"ffi closure mprotect failed");
return NULL;
}
jsFunction = fn;
ctx = context;
// Protect function from GC
JSValueProtect(ctx, jsFunction);
[JSCocoaController upJSValueProtectCount];
return (IMP)closure;
#else
return NULL;
#endif
}
//
// Called by ffi
//
- (void)calledByClosureWithArgs:(void**)closureArgs returnValue:(void*)returnValue
{
JSObjectRef jsFunctionObject = JSValueToObject(ctx, jsFunction, NULL);
JSValueRef exception = NULL;
// ## Only objC for now. Need to test C function pointers.
// Argument count is encodings count minus return value
NSUInteger i, idx = 0, effectiveArgumentCount = [encodings count]-1;
// Skip self and selector
if (isObjC)
{
effectiveArgumentCount -= 2;
idx = 2;
}
// Convert arguments
JSValueRef* args = NULL;
if (effectiveArgumentCount)
{
args = malloc(effectiveArgumentCount*sizeof(JSValueRef));
for (i=0; i<effectiveArgumentCount; i++, idx++)
{
// +1 to skip return value
id encodingObject = [encodings objectAtIndex:idx+1];
id arg = [[JSCocoaFFIArgument alloc] init];
char encoding = [encodingObject typeEncoding];
if (encoding == '{') [arg setStructureTypeEncoding:[encodingObject structureTypeEncoding] withCustomStorage:*(void**)&closureArgs[idx]];
else [arg setTypeEncoding:[encodingObject typeEncoding] withCustomStorage:closureArgs[idx]];
args[i] = NULL;
[arg toJSValueRef:&args[i] inContext:ctx];
[arg release];
}
}
JSObjectRef jsThis = NULL;
// Create 'this'
if (isObjC)
jsThis = [[JSCocoa controllerFromContext:ctx] boxObject:*(void**)closureArgs[0]];
// Call !
JSValueRef jsReturnValue = JSObjectCallAsFunction(ctx, jsFunctionObject, jsThis, effectiveArgumentCount, args, &exception);
// Convert return value if it's not void
char encoding = [[encodings objectAtIndex:0] typeEncoding];
if (jsReturnValue && encoding != 'v')
{
[JSCocoaFFIArgument fromJSValueRef:jsReturnValue inContext:ctx typeEncoding:encoding fullTypeEncoding:[[encodings objectAtIndex:0] structureTypeEncoding] fromStorage:returnValue];
#ifdef __BIG_ENDIAN__
// As ffi always uses a sizeof(long) return value (even for chars and shorts), do some shifting
int size = [JSCocoaFFIArgument sizeOfTypeEncoding:encoding];
int paddedSize = sizeof(long);
long v;
if (size > 0 && size < paddedSize && paddedSize == 4)
{
v = *(long*)returnValue;
v = CFSwapInt32(v);
*(long*)returnValue = v;
}
#endif
}
if (effectiveArgumentCount) free(args);
if (exception)
{
@throw [NSException exceptionWithName:@"JSCocoa exception"
reason:[[JSCocoaController controllerFromContext:ctx] formatJSException:exception]
userInfo:nil];
}
}
@end

98
JSCocoa/JSCocoaLib.h Normal file
View File

@ -0,0 +1,98 @@
//
// JSCocoaLib.h
// JSCocoa
//
// Created by Patrick Geiller on 21/12/08.
// Copyright 2008 __MyCompanyName__. All rights reserved.
//
#if !TARGET_IPHONE_SIMULATOR && !TARGET_OS_IPHONE
#import <Cocoa/Cocoa.h>
#endif
#import "JSCocoa.h"
@class JSCocoaMemoryBuffer;
@interface JSCocoaOutArgument : NSObject
{
JSCocoaFFIArgument* arg;
JSCocoaMemoryBuffer* buffer;
int bufferIndex;
}
- (BOOL)mateWithJSCocoaFFIArgument:(JSCocoaFFIArgument*)arg;
- (JSValueRef)outJSValueRefInContext:(JSContextRef)ctx;
@end
@interface JSCocoaMemoryBuffer : NSObject
{
void* buffer;
int bufferSize;
// NSString holding types
id typeString;
// Indicates whether types are aligned.
// types not aligned (DEFAULT)
// size('fcf') = 4 + 1 + 4 = 9
// types aligned
// size('fcf') = 4 + 4(align) + 4 = 12
BOOL alignTypes;
}
+ (id)bufferWithTypes:(id)types;
- (id)initWithTypes:(id)types;
//- (id)initWithTypes:(id)types andValues:(id)values;
//- (id)initWithMemoryBuffers:(id)buffers;
- (void*)pointerForIndex:(NSUInteger)index;
- (char)typeAtIndex:(NSUInteger)index;
- (JSValueRef)valueAtIndex:(NSUInteger)index inContext:(JSContextRef)ctx;
- (BOOL)setValue:(JSValueRef)jsValue atIndex:(NSUInteger)index inContext:(JSContextRef)ctx;
- (NSUInteger)typeCount;
@end
@interface JSCocoaLib : NSObject
+ (id)rootclasses;
+ (id)classes;
+ (id)protocols;
+ (id)imageNames;
+ (id)methods;
+ (id)runtimeReport;
@end
@interface NSObject(ClassWalker)
+ (id)__classImage;
- (id)__classImage;
+ (id)__derivationPath;
- (id)__derivationPath;
+ (NSUInteger)__derivationLevel;
- (NSUInteger)__derivationLevel;
+ (id)__ownMethods;
- (id)__ownMethods;
+ (id)__methods;
- (id)__methods;
+ (id)__subclasses;
- (id)__subclasses;
+ (id)__subclassTree;
- (id)__subclassTree;
+ (id)__ownIvars;
- (id)__ownIvars;
+ (id)__ivars;
- (id)__ivars;
+ (id)__ownProperties;
- (id)__ownProperties;
+ (id)__properties;
- (id)__properties;
+ (id)__ownProtocols;
- (id)__ownProtocols;
+ (id)__protocols;
- (id)__protocols;
@end

830
JSCocoa/JSCocoaLib.m Normal file
View File

@ -0,0 +1,830 @@
//
// JSCocoaLib.m
// JSCocoa
//
// Created by Patrick Geiller on 21/12/08.
// Copyright 2008 __MyCompanyName__. All rights reserved.
//
#import "JSCocoaLib.h"
//
// Handles out arguments of functions and methods.
// eg NSOpenGLGetVersion(int*, int*) asks for two pointers to int.
// JSCocoaOutArgument will alloc the memory through JSCocoaFFIArgument and get the result back to Javascript (check out value in JSCocoaController)
//
@implementation JSCocoaOutArgument
- (id)init
{
self = [super init];
arg = nil;
buffer = nil;
return self;
}
- (void)cleanUp
{
[arg release];
[buffer release];
}
- (void)dealloc
{
[self cleanUp];
[super dealloc];
}
- (void)finalize
{
[self cleanUp];
[super finalize];
}
//
// convert the out value to a JSValue
//
- (JSValueRef)outJSValueRefInContext:(JSContextRef)ctx
{
JSValueRef jsValue = NULL;
[arg toJSValueRef:&jsValue inContext:ctx];
return jsValue;
}
// Called from Javascript to extract the resulting value as an object (valueOfCallback returns a string)
- (JSValueRefAndContextRef)outValue
{
JSValueRefAndContextRef r;
id jsc = nil;
object_getInstanceVariable(self, "__jsCocoaController", (void**)&jsc);
if (!jsc) return r;
r.ctx = [jsc ctx];
r.value = [self outJSValueRefInContext:r.ctx];
return r;
}
//
// JSCocoaOutArgument holds a JSCocoaFFIArgument around.
// it stays alive after ffi_call and can be queried by Javascript for type modifier values.
//
- (BOOL)mateWithJSCocoaFFIArgument:(JSCocoaFFIArgument*)_arg
{
// If holding a memory buffer, use its pointer
if (buffer)
{
arg = _arg;
[arg retain];
void* ptr = [buffer pointerForIndex:bufferIndex];
if (!ptr) return NO;
[arg setTypeEncoding:[arg typeEncoding] withCustomStorage:ptr];
return YES;
}
// Standard pointer
void* p = [_arg allocatePointerStorage];
if (!p) return NO;
// Zero out storage
*(void**)p = NULL;
arg = _arg;
[arg retain];
return YES;
}
- (BOOL)mateWithMemoryBuffer:(id)b atIndex:(int)idx
{
if (!b || ![b isKindOfClass:[JSCocoaMemoryBuffer class]]) return NSLog(@"mateWithMemoryBuffer called without a memory buffer (%@)", b), NO;
buffer = b;
[buffer retain];
bufferIndex = idx;
return YES;
}
@end
//
// Instead of malloc(sizeof(float)*4), JSCocoaMemoryBuffer expects 'ffff' as an init string.
// The buffer can be manipulated like an array (buffer[2] = 0.5)
// * it can be filled, calling methods to copy data in it
// - (NSBezierPathElement)elementAtIndex:(NSInteger)index associatedPoints:(NSPointArray)points;
// * it can be used as data source, calling methods to copy data from it
// - (void)setAssociatedPoints:(NSPointArray)points atIndex:(NSInteger)index;
//
@implementation JSCocoaMemoryBuffer
+ (id)bufferWithTypes:(id)types
{
return [[[JSCocoaMemoryBuffer alloc] initWithTypes:types] autorelease];
}
- (id)initWithTypes:(id)_types
{
self = [super init];
buffer = NULL;
// Copy types string
typeString = [NSString stringWithString:_types];
[typeString retain];
// Compute buffer size
const char* types = [typeString UTF8String];
NSUInteger l = [typeString length];
bufferSize = 0;
for (int i=0; i<l; i++)
{
int size = [JSCocoaFFIArgument sizeOfTypeEncoding:types[i]];
if (size == -1) return NSLog(@"JSCocoaMemoryBuffer initWithTypes : unknown type %c", types[i]), self;
bufferSize += size;
}
if (bufferSize == 0) {
NSLog(@"initWithTypes has no types");
return NULL;
}
// Malloc
// NSLog(@"mallocing %d bytes for %@", bufferSize, typeString);
buffer = malloc(bufferSize);
memset(buffer, bufferSize, 1);
return self;
}
- (void)dealloc
{
if (buffer) free(buffer);
[typeString release];
[super dealloc];
}
- (void)finalize
{
if (buffer) free(buffer);
[super finalize];
}
//
// Returns pointer for index without any padding
//
- (void*)pointerForIndex:(NSUInteger)idx
{
const char* types = [typeString UTF8String];
if (idx >= [typeString length]) return NULL;
void* pointedValue = buffer;
for (int i=0; i<idx; i++)
{
// NSLog(@"advancing %c", types[i]);
[JSCocoaFFIArgument advancePtr:&pointedValue accordingToEncoding:types[i]];
}
return pointedValue;
}
- (char)typeAtIndex:(NSUInteger)idx
{
if (idx >= [typeString length]) return '\0';
return [typeString UTF8String][idx];
}
- (NSUInteger)typeCount
{
return [typeString length];
}
-(BOOL)referenceObject:(id)o usingPointerAtIndex:(NSUInteger)idx
{
if ([self typeAtIndex:idx] != '^') return NO;
void* v = *(void**)[self pointerForIndex:idx];
if (!v) return NO;
*(id*)v = o;
return YES;
}
- (id)dereferenceObjectAtIndex:(NSUInteger)idx
{
if ([self typeAtIndex:idx] != '^') return nil;
void* v = *(void**)[self pointerForIndex:idx];
if (!v) return NULL;
id o = *(id*)v;
return o;
return *(id*)v;
}
//
// Using JSValueRefAndContextRef as input to get the current context in which to create the return value
//
- (JSValueRef)valueAtIndex:(NSUInteger)idx inContext:(JSContextRef)ctx
{
char typeEncoding = [self typeAtIndex:idx];
void* pointedValue = [self pointerForIndex:idx];
if (!pointedValue) return JSValueMakeUndefined(ctx);
JSValueRef returnValue;
[JSCocoaFFIArgument toJSValueRef:&returnValue inContext:ctx typeEncoding:typeEncoding fullTypeEncoding:nil fromStorage:pointedValue];
return returnValue;
}
- (BOOL)setValue:(JSValueRef)jsValue atIndex:(NSUInteger)idx inContext:(JSContextRef)ctx
{
char typeEncoding = [self typeAtIndex:idx];
void* pointedValue = [self pointerForIndex:idx];
if (!pointedValue) return NO;
[JSCocoaFFIArgument fromJSValueRef:jsValue inContext:ctx typeEncoding:typeEncoding fullTypeEncoding:nil fromStorage:pointedValue];
return YES;
}
@end
@implementation JSCocoaLib
//
// Class list
// Some classes are skipped as adding them to an array crashes (Zombie, classes derived from Object or NSProxy)
//
+ (NSArray*)classes
{
int classCount = objc_getClassList(nil, 0);
Class* classList = malloc(sizeof(Class)*classCount);
objc_getClassList(classList, classCount);
NSMutableArray* classArray = [NSMutableArray array];
for (int i=0; i<classCount; i++)
{
id class = classList[i];
const char* name= class_getName(class);
if (!name) continue;
id className = [NSString stringWithUTF8String:name];
id superclass = class_getSuperclass(class);
id superclassName = superclass ? [NSString stringWithUTF8String:class_getName(superclass)] : @"";
// Check if this class inherits from NSProxy. isKindOfClass crashes, so use raw ObjC api.
BOOL isKindOfNSProxy = NO;
id c = class;
while (c)
{
if ([[NSString stringWithUTF8String:class_getName(c)] isEqualToString:@"NSProxy"]) isKindOfNSProxy = YES;
c = class_getSuperclass(c);
}
// Skip classes crashing when added to an NSArray
if ([className hasPrefix:@"_NSZombie_"]
|| [className isEqualToString:@"Object"]
|| [superclassName isEqualToString:@"Object"]
|| [className isEqualToString:@"NSMessageBuilder"]
|| [className isEqualToString:@"NSLeafProxy"]
|| [className isEqualToString:@"__NSGenericDeallocHandler"]
|| isKindOfNSProxy
)
{
continue;
}
[classArray addObject:class];
}
free(classList);
return classArray;
}
+ (NSArray*)rootclasses
{
id classes = [self classes];
NSMutableArray* classArray = [NSMutableArray array];
for (id class in classes)
{
id superclass = class_getSuperclass(class);
if (superclass) continue;
[classArray addObject:class];
}
return classArray;
}
//
// Return an array of { name : imageName, classNames : [className, className, ...] }
//
+ (id)imageNames
{
id array = [NSMutableArray array];
unsigned int imageCount;
const char** imageNames = objc_copyImageNames(&imageCount);
for (int i=0; i<imageCount; i++)
{
const char* cname = imageNames[i];
// Gather image class names
id array2 = [NSMutableArray array];
unsigned int classCount;
const char** classNames = objc_copyClassNamesForImage(cname, &classCount);
for (int j=0; j<classCount; j++)
[array2 addObject:[NSString stringWithUTF8String:classNames[j]]];
free(classNames);
// Hash of name and classNames
id name = [NSString stringWithUTF8String:cname];
id hash = [NSDictionary dictionaryWithObjectsAndKeys:
name, @"name",
array2, @"classNames",
nil];
[array addObject:hash];
}
free(imageNames);
return array;
}
//
// Return protocols and their associated methods
//
+ (id)protocols
{
#if NS_BLOCKS_AVAILABLE
id array = [NSMutableArray array];
unsigned int protocolCount;
Protocol** protocols = objc_copyProtocolList(&protocolCount);
for (int i=0; i<protocolCount; i++)
{
// array2 is modified by the following block
__block id array2 = [NSMutableArray array];
Protocol* p = protocols[i];
// Common block for copying protocol method descriptions
void (^b)(BOOL, BOOL) = ^(BOOL isRequiredMethod, BOOL isInstanceMethod) {
unsigned int descriptionCount;
struct objc_method_description* methodDescriptions = protocol_copyMethodDescriptionList(p, isRequiredMethod, isInstanceMethod, &descriptionCount);
for (int j=0; j<descriptionCount; j++)
{
struct objc_method_description d = methodDescriptions[j];
id name = NSStringFromSelector(d.name);
id encoding = [NSString stringWithUTF8String:d.types];
id isRequired = [NSNumber numberWithBool:isRequiredMethod];
id type = isInstanceMethod ? @"instance" : @"class";
id hash = [NSDictionary dictionaryWithObjectsAndKeys:
name, @"name",
encoding, @"encoding",
isRequired, @"isRequired",
type, @"type",
nil];
[array2 addObject:hash];
}
if (methodDescriptions) free(methodDescriptions);
};
// Copy all methods, going through required, non-required, class, instance methods
b(YES, YES);
b(YES, NO);
b(NO, YES);
b(NO, NO);
// Main object : { name : protocolName, methods : [{ name, encoding, isRequired, type }, ...]
id name = [NSString stringWithUTF8String:protocol_getName(p)];
id hash = [NSDictionary dictionaryWithObjectsAndKeys:
name, @"name",
array2, @"methods",
nil];
[array addObject:hash];
}
free(protocols);
return array;
#else
return nil;
#endif
}
+ (id)methods
{
id classes = [self classes];
id methods = [NSMutableArray array];
for (id class in classes)
[methods addObjectsFromArray:[class __ownMethods]];
return methods;
}
//
// Runtime report
// Report EVERYTHING
// classes
// { className : { name
// superclassName
// derivationPath
// subclasses
// methods
// protocols
// ivars
// properties
// }
// protocols
// { protocolName : { name
// methods
// }
// imageNames
// { imageName : { name
// classNames : [className1, className2, ...]
// }
//
+ (id)runtimeReport
{
/*
id classList = [self classes];
id protocols = [self protocols];
id imageNames = [self imageNames];
id classes = [NSMutableDictionary dictionary];
int classCount = [classList count];
// for (id class in classList)
for (int i=0; i<classCount; i++)
{
id class = [classList objectAtIndex:i];
id className = [class description];
NSLog(@"%d/%d %@", i, (classCount-1), className);
id superclass = [class superclass];
id superclassName = superclass ? [NSString stringWithUTF8String:class_getName(superclass)] : nil;
//NSLog(@"%@ (%d/%d)", className, i, classCount-1);
id hash = [NSDictionary dictionaryWithObjectsAndKeys:
className, @"name",
superclassName, @"superclassName",
[class __derivationPath], @"derivationPath",
[class __methods], @"methods",
[class __protocols], @"protocols",
[class __ivars], @"ivars",
[class __properties], @"properties",
nil];
[classes setObject:hash forKey:className];
}
id dict = [NSDictionary dictionaryWithObjectsAndKeys:
classes, @"classes",
protocols, @"protocols",
imageNames, @"imageNames",
nil];
*/
// This happens on the ObjC side, NOT in jsc.
// There are 2500 classes to dump, this takes a while.
// The memory hog is also on the ObjC side, happening during [dict description]
return @"Disabled for now, as the resulting hash hangs the app while goring memory";
}
@end
//
// Runtime information
//
@implementation NSObject(ClassWalker)
//
// Class name (description might have been overriden, and classes don't seem to travel well over NSDistantObject)
//
- (id)__className
{
return [[self class] description];
}
//
// Returns which framework containing the class
//
+ (id)__classImage
{
const char* name = class_getImageName(self);
if (!name) return nil;
return [NSString stringWithUTF8String:name];
}
- (id)__classImage
{
return [[self class] __classImage];
}
//
// Derivation path
// derivationPath(NSButton) = NSObject, NSResponder, NSView, NSControl, NSButton
//
+ (id)__derivationPath
{
int level = -1;
id class = self;
id classes = [NSMutableArray array];
while (class)
{
[classes insertObject:class atIndex:0];
level++;
class = [class superclass];
}
return classes;
}
- (id)__derivationPath
{
return [[self class] __derivationPath];
}
//
// Derivation level
//
+ (NSUInteger)__derivationLevel
{
return [[self __derivationPath] count]-1;
}
- (NSUInteger)__derivationLevel
{
return [[self class] __derivationLevel];
}
//
// Methods
//
// Copy all class or instance (type) methods of a class in an array
static id copyMethods(Class class, NSMutableArray* array, NSString* type)
{
if ([type isEqualToString:@"class"]) class = objc_getMetaClass(class_getName(class));
unsigned int methodCount;
Method* methods = class_copyMethodList(class, &methodCount);
for (int i=0; i<methodCount; i++)
{
Method m = methods[i];
Dl_info info;
dladdr(method_getImplementation(m), &info);
id name = NSStringFromSelector(method_getName(m));
id encoding = [NSString stringWithUTF8String:method_getTypeEncoding(m)];
id framework= [NSString stringWithUTF8String:info.dli_fname];
id hash = [NSDictionary dictionaryWithObjectsAndKeys:
name, @"name",
encoding, @"encoding",
type, @"type",
class, @"class",
framework, @"framework",
nil];
[array addObject:hash];
}
free(methods);
return array;
}
+ (id)__ownMethods
{
id methods = [NSMutableArray array];
copyMethods([self class], methods, @"class");
copyMethods([self class], methods, @"instance");
return methods;
}
- (id)__ownMethods
{
return [[self class] __ownMethods];
}
+ (id)__methods
{
id classes = [self __derivationPath];
id methods = [NSMutableArray array];
for (id class in classes)
[methods addObjectsFromArray:[class __ownMethods]];
return methods;
}
- (id)__methods
{
return [[self class] __methods];
}
//
// Subclasses
//
// Recursively go breadth first all a class' subclasses
static void populateSubclasses(Class class, NSMutableArray* array, NSMutableDictionary* subclassesHash)
{
// Add ourselves
[array addObject:class];
id className = [NSString stringWithUTF8String:class_getName(class)];
id subclasses = [subclassesHash objectForKey:className];
for (id subclass in subclasses)
{
populateSubclasses(subclass, array, subclassesHash);
}
}
// Build a hash of className : [direct subclasses] then walk it down recursively.
+ (id)__subclasses
{
#if NS_BLOCKS_AVAILABLE
id classes = [JSCocoaLib classes];
id subclasses = [NSMutableArray array];
id subclassesHash = [NSMutableDictionary dictionary];
for (id class in classes)
{
id superclass = [class superclass];
if (!superclass) continue;
id superclassName = [NSString stringWithUTF8String:class_getName(superclass)];
id subclassesArray = [subclassesHash objectForKey:superclassName];
if (!subclassesArray)
{
subclassesArray = [NSMutableArray array];
[subclassesHash setObject:subclassesArray forKey:superclassName];
}
[subclassesArray addObject:class];
}
// (Optional) sort by class name
for (id className in subclassesHash)
{
id subclassesArray = [subclassesHash objectForKey:className];
[subclassesArray sortUsingComparator:
^(id a, id b)
{
// Case insensitive compare + remove underscores for sorting (yields [..., NSStatusBarButton, _NSThemeWidget, NSToolbarButton] )
return [[[a description] stringByReplacingOccurrencesOfString:@"_" withString:@""]
compare:[[b description] stringByReplacingOccurrencesOfString:@"_" withString:@""] options:NSCaseInsensitiveSearch];
}];
}
populateSubclasses(self, subclasses, subclassesHash);
return subclasses;
#else
return nil;
#endif
}
- (id)__subclasses
{
return [[self class] __subclasses];
}
// Returns a string showing subclasses, prefixed with as many spaces as their derivation level
+ (id)__subclassTree
{
id subclasses = [self __subclasses];
id str = [NSMutableString string];
for (id subclass in subclasses)
{
NSUInteger level = [subclass __derivationLevel];
for (int i=0; i<level; i++)
[str appendString:@" "];
[str appendString:[NSString stringWithUTF8String:class_getName(subclass)]];
[str appendString:@"\n"];
}
return str;
}
- (id)__subclassTree
{
return [[self class] __subclassTree];
}
//
// ivars
//
+ (id)__ownIvars
{
unsigned int ivarCount;
Ivar* ivars = class_copyIvarList(self, &ivarCount);
id array = [NSMutableArray array];
for (int i=0; i<ivarCount; i++)
{
Ivar ivar = ivars[i];
id name = [NSString stringWithUTF8String:ivar_getName(ivar)];
id encoding = [NSString stringWithUTF8String:ivar_getTypeEncoding(ivar)];
id offset = [NSNumber numberWithLong:ivar_getOffset(ivar)];
id hash = [NSDictionary dictionaryWithObjectsAndKeys:
name, @"name",
encoding, @"encoding",
offset, @"offset",
self, @"class",
nil];
[array addObject:hash];
}
free(ivars);
return array;
}
- (id)__ownIvars
{
return [[self class] __ownIvars];
}
+ (id)__ivars
{
id classes = [self __derivationPath];
id ivars = [NSMutableArray array];
for (id class in classes)
[ivars addObjectsFromArray:[class __ownIvars]];
return ivars;
}
- (id)__ivars
{
return [[self class] __ivars];
}
//
// Properties
//
+ (id)__ownProperties
{
unsigned int propertyCount;
objc_property_t* properties = class_copyPropertyList(self, &propertyCount);
id array = [NSMutableArray array];
for (int i=0; i<propertyCount; i++)
{
objc_property_t property = properties[i];
id name = [NSString stringWithUTF8String:property_getName(property)];
id attributes = [NSString stringWithUTF8String:property_getAttributes(property)];
id hash = [NSDictionary dictionaryWithObjectsAndKeys:
name, @"name",
attributes, @"attributes",
self, @"class",
nil];
[array addObject:hash];
}
free(properties);
return array;
}
- (id)__ownProperties
{
return [[self class] __ownProperties];
}
+ (id)__properties
{
id classes = [self __derivationPath];
id properties = [NSMutableArray array];
for (id class in classes)
[properties addObjectsFromArray:[class __ownProperties]];
return properties;
}
- (id)__properties
{
return [[self class] __properties];
}
//
// Protocols
//
+ (id)__ownProtocols
{
unsigned int protocolCount;
Protocol** protocols = class_copyProtocolList(self, &protocolCount);
id array = [NSMutableArray array];
for (int i=0; i<protocolCount; i++)
{
id name = [NSString stringWithUTF8String:protocol_getName(protocols[i])];
id hash = [NSDictionary dictionaryWithObjectsAndKeys:
name, @"name",
self, @"class",
nil];
[array addObject:hash];
}
free(protocols);
return array;
}
- (id)__ownProtocols
{
return [[self class] __ownProtocols];
}
+ (id)__protocols
{
id classes = [self __derivationPath];
id protocols = [NSMutableArray array];
for (id class in classes)
[protocols addObjectsFromArray:[class __ownProtocols]];
return protocols;
}
- (id)__protocols
{
return [[self class] __protocols];
}
@end

View File

@ -0,0 +1,92 @@
//
// JSCocoaPrivateObject.h
// JSCocoa
//
// Created by Patrick Geiller on 09/07/08.
// Copyright 2008 __MyCompanyName__. All rights reserved.
//
#if !TARGET_IPHONE_SIMULATOR && !TARGET_OS_IPHONE
#import <Cocoa/Cocoa.h>
#import <JavaScriptCore/JavaScriptCore.h>
#endif
#import <mach-o/dyld.h>
#import <dlfcn.h>
//#import <objc/objc-class.h>
#import <objc/runtime.h>
#import <objc/message.h>
//
// Boxing object
//
// type
// @ ObjC object
// struct C struct
// method ObjC method name
// function C function
// rawPointer raw C pointer (_C_PTR)
// jsFunction Javascript function
// jsValueRef raw jsvalue
// externalJSValueRef jsvalue coming from an external context (eg, a WebView)
//
@interface JSCocoaPrivateObject : NSObject {
NSString* type;
NSString* xml;
NSString* methodName;
NSString* structureName;
NSString* declaredType;
void* rawPointer;
id object;
Method method;
JSValueRef jsValue;
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 uses.
//
// Disabled because retaining the context crashes in 32 bits, but works in 64 bit.
// May be reenabled someday.
// JSContextGroupRef contextGroup;
BOOL isAutoCall;
BOOL retainObject;
// Disabled because of a crash on i386. Release globalContext last.
// BOOL retainContext;
}
@property (copy) NSString* type;
@property (copy) NSString* xml;
@property (copy) NSString* methodName;
@property (copy) NSString* structureName;
@property (copy) NSString* declaredType;
@property BOOL isAutoCall;
//- (void)setPtr:(void*)ptrValue;
//- (void*)ptr;
- (void)setObject:(id)o;
- (void)setObjectNoRetain:(id)o;
- (BOOL)retainObject;
- (id)object;
- (void)setMethod:(Method)m;
- (Method)method;
- (void)setJSValueRef:(JSValueRef)v ctx:(JSContextRef)ctx;
- (JSValueRef)jsValueRef;
- (void)setCtx:(JSContextRef)ctx;
- (JSContextRef)ctx;
- (void)setExternalJSValueRef:(JSValueRef)v ctx:(JSContextRef)ctx;
- (void*)rawPointer;
- (void)setRawPointer:(void*)rp encoding:(id)encoding;
- (id)rawPointerEncoding;
@end

View File

@ -0,0 +1,236 @@
//
// JSCocoaPrivateObject.m
// JSCocoa
//
// Created by Patrick Geiller on 09/07/08.
// Copyright 2008 __MyCompanyName__. All rights reserved.
//
#import "JSCocoaPrivateObject.h"
#import "JSCocoaController.h"
@implementation JSCocoaPrivateObject
@synthesize type, xml, declaredType, methodName, structureName, isAutoCall;
- (id)init
{
self = [super init];
type = xml = declaredType = methodName = nil;
object = nil;
isAutoCall = NO;
jsValue = NULL;
retainObject= YES;
rawPointer = NULL;
ctx = NULL;
// retainContext = NO;
externalJSValueIndex = 0;
[JSCocoaController upJSCocoaPrivateObjectCount];
return self;
}
- (void)cleanUp
{
[JSCocoaController downJSCocoaPrivateObjectCount];
if (object && retainObject)
{
// NSLog(@"commented downBoxedJSObjectCount");
// [JSCocoaController downBoxedJSObjectCount:object];
// NSLog(@"releasing %@(%d)", [object class], [object retainCount]);
// if ([object isKindOfClass:[JSCocoaController class]])
// [object autorelease];
// else
[object release];
}
if (jsValue)
{
if (!externalJSValueIndex) JSValueUnprotect(ctx, jsValue);
[JSCocoaController downJSValueProtectCount];
// If holding a value from an external context, remove it from the GC-safe hash and release context.
if (externalJSValueIndex)
{
JSStringRef scriptJS = JSStringCreateWithUTF8CString("delete __gcprotect[arguments[0]]");
JSObjectRef fn = JSObjectMakeFunction(ctx, NULL, 0, NULL, scriptJS, NULL, 1, NULL);
JSStringRelease(scriptJS);
JSValueRef jsNumber = JSValueMakeNumber(ctx, externalJSValueIndex);
JSValueRef exception = NULL;
JSObjectCallAsFunction(ctx, fn, NULL, 1, (JSValueRef*)&jsNumber, &exception);
// JSGlobalContextRelease((JSGlobalContextRef)ctx);
if (exception)
NSLog(@"Got an exception while trying to release externalJSValueRef %p of context %p", jsValue, ctx);
}
}
/*
if (retainContext)
{
NSLog(@"releasing %p", ctx);
JSContextGroupRelease(contextGroup);
// JSGlobalContextRelease((JSGlobalContextRef)ctx);
}
*/
// Release properties
[type release];
[xml release];
[methodName release];
[structureName release];
[declaredType release];
}
- (void)dealloc
{
[self cleanUp];
[super dealloc];
}
- (void)finalize
{
[self cleanUp];
[super finalize];
}
- (void)setObject:(id)o
{
// if (object && retainObject)
// [object release];
object = o;
if (object && [object retainCount] == -1) return;
[object retain];
}
- (void)setObjectNoRetain:(id)o
{
object = o;
retainObject = NO;
}
- (BOOL)retainObject
{
return retainObject;
}
- (id)object
{
return object;
}
- (void)setMethod:(Method)m
{
method = m;
}
- (Method)method
{
return method;
}
- (void)setJSValueRef:(JSValueRef)v ctx:(JSContextRef)c
{
// While autocalling we'll get a NULL value when boxing a void return type - just skip JSValueProtect
if (!v)
{
// NSLog(@"setJSValueRef: NULL value");
jsValue = 0;
return;
}
jsValue = v;
// ctx = c;
// Register global context (this would crash the launcher as JSValueUnprotect was called on a destroyed context)
ctx = [[JSCocoaController controllerFromContext:c] ctx];
JSValueProtect(ctx, jsValue);
[JSCocoaController upJSValueProtectCount];
}
- (JSValueRef)jsValueRef
{
return jsValue;
}
- (void)setCtx:(JSContextRef)_ctx {
ctx = _ctx;
}
- (JSContextRef)ctx
{
return ctx;
}
- (void)setExternalJSValueRef:(JSValueRef)v ctx:(JSContextRef)c
{
if (!v)
{
jsValue = 0;
return;
}
jsValue = v;
ctx = c;
// Register value in a global hash to protect it from GC. This sucks but JSValueProtect() fails.
JSStringRef scriptJS = JSStringCreateWithUTF8CString("if (!('__gcprotect' in this)) { __gcprotect = {}; __gcprotectidx = 1; } __gcprotect[__gcprotectidx] = arguments[0]; return __gcprotectidx++ ");
JSObjectRef fn = JSObjectMakeFunction(ctx, NULL, 0, NULL, scriptJS, NULL, 1, NULL);
JSStringRelease(scriptJS);
JSValueRef exception = NULL;
JSValueRef result = JSObjectCallAsFunction(ctx, fn, NULL, 1, (JSValueRef*)&jsValue, &exception);
if (exception) return;
// Use hash index as key, will be used to remove value from hash upon deletion.
externalJSValueIndex = (unsigned int)JSValueToNumber(ctx, result, &exception);
if (exception) return;
// JSGlobalContextRetain((JSGlobalContextRef)ctx);
[JSCocoaController upJSValueProtectCount];
}
- (void*)rawPointer
{
return rawPointer;
}
- (void)setRawPointer:(void*)rp encoding:(id)encoding
{
rawPointer = rp;
// NSLog(@"RAWPOINTER=%@", encoding);
declaredType = encoding;
[declaredType retain];
}
- (id)rawPointerEncoding
{
return declaredType;
}
- (id)description {
id extra = @"";
if ([type isEqualToString:@"rawPointer"])
extra = [NSString stringWithFormat:@" rawPointer=%p declaredType=%@", rawPointer, declaredType];
return [NSString stringWithFormat:@"<%@: %p holding %@%@>",
[self class],
self,
type,
extra
];
}
+ (id)description {
return @"<JSCocoaPrivateObject class>";
}
- (id)dereferencedObject {
if (![type isEqualToString:@"rawPointer"] || !rawPointer)
return nil;
return *(void**)rawPointer;
}
- (BOOL)referenceObject:(id)o {
if (![type isEqualToString:@"rawPointer"])
return NO;
*(id*)rawPointer = o;
return YES;
}
@end

1055
JSCocoa/class.js Normal file

File diff suppressed because it is too large Load Diff

5686
JSCocoa/jslint-jscocoa.js Normal file

File diff suppressed because it is too large Load Diff

1
main.m
View File

@ -8,6 +8,7 @@
#import <Cocoa/Cocoa.h>
#import <WebKit/WebKit.h>
#import "JSCocoa.h"
int main(int argc, char *argv[])
{