Commit f0712f94 authored by mhahnenberg@apple.com's avatar mhahnenberg@apple.com

Objective-C API: Need a way to use the Objective-C JavaScript API with WebKit

https://bugs.webkit.org/show_bug.cgi?id=106059

Source/JavaScriptCore: 

Reviewed by Geoffrey Garen.
        
* API/JSBase.h: Renamed enable flag for API.
* API/JSBlockAdaptor.h: Using new flag.
* API/JSBlockAdaptor.mm: Ditto.
* API/JSContext.h: Add convenience C API conversion function for JSGlobalContextRef.
* API/JSContext.mm: 
(-[JSContext JSGlobalContextRef]): Implementation of C API convenience function.
(-[JSContext initWithVirtualMachine:]): We don't use the m_apiData field any more.
(-[JSContext initWithGlobalContextRef:]): init method for allocating new JSContexts given a JSGlobalContextRef.
(-[JSContext dealloc]): No more m_apiData.
(-[JSContext wrapperForObjCObject:]): Renamed wrapperForObject. 
(-[JSContext wrapperForJSObject:]): Fetches or allocates the JSValue for the specified JSValueRef in this JSContext.
(+[JSContext contextWithGlobalContextRef:]): Helper function to grab the lightweight JSContext wrapper for a given
JSGlobalContextRef from the global wrapper cache or allocate a new one if there isn't already one.
* API/JSContextInternal.h: New flag, new method declaration for initWithGlobalContextRef.
* API/JSExport.h: New flag.
* API/JSValue.h: New flag and new C API convenience method.
* API/JSValue.mm:
(-[JSValue JSValueRef]): Implementation of the C API convenience method.
(objectToValueWithoutCopy):
(+[JSValue valueWithValue:inContext:]): We now ask the JSContext for an Objective-C JSValue wrapper, which it can cache
in its internal JSWrapperMap.
* API/JSValueInternal.h:
* API/JSVirtualMachine.h:
* API/JSVirtualMachine.mm: Added global cache that maps JSContextGroupRef -> JSVirtualMachine lightweight wrappers.
(wrapperCacheLock):
(initWrapperCache):
(+[JSVMWrapperCache addWrapper:forJSContextGroupRef:]):
(+[JSVMWrapperCache wrapperForJSContextGroupRef:]):
(-[JSVirtualMachine init]):
(-[JSVirtualMachine initWithContextGroupRef:]):
(-[JSVirtualMachine dealloc]):
(+[JSVirtualMachine virtualMachineWithContextGroupRef:]):
(-[JSVirtualMachine contextForGlobalContextRef:]):
(-[JSVirtualMachine addContext:forGlobalContextRef:]):
* API/JSVirtualMachineInternal.h:
* API/JSWrapperMap.h:
* API/JSWrapperMap.mm:
(-[JSObjCClassInfo allocateConstructorAndPrototypeWithSuperClassInfo:]): We use the JSObjectSetPrototype C API call because 
setting the __proto__ property causes all sorts of bad things to happen behind the scenes, which can cause crashes based on 
when it gets called.
(-[JSWrapperMap initWithContext:]):
(-[JSWrapperMap jsWrapperForObject:]):
(-[JSWrapperMap objcWrapperForJSValueRef:]):
* API/JavaScriptCore.h:
* API/ObjCCallbackFunction.h:
* API/ObjCCallbackFunction.mm:
(ObjCCallbackFunction::ObjCCallbackFunction): We never actually should have retained the target in the case that we had a 
block as a callback. Blocks are initially allocated on the stack and are only moved to the heap if we call their copy method.
Retaining the block on the stack was a bad idea because if that stack frame ever went away and we called the block later, 
we'd crash and burn.
(ObjCCallbackFunction::setContext): We need a new setter for when the weak reference to a JSContext inside an ObjCCallbackFunction
disappears, we can allocate a new one in its place.
(ObjCCallbackFunction):
(objCCallbackFunctionCallAsFunction): Reset the callback's context if it's ever destroyed.
(objCCallbackFunctionForInvocation): Again, don't set the __proto__ property because it uses black magic that can cause us to crash
depending on when this is called.
(objCCallbackFunctionForBlock): Here is where we copy the block to the heap when we're first creating the callback object for it.
* API/tests/testapi.c:
(main):
* API/tests/testapi.mm: We're going to get rid of the automatic block conversion, since that is causing leaks. I changed it 
here in this test just so that it wouldn't mask any other potential leaks. Also modified some of the tests since JSContexts are 
just lightweight wrappers now, we're not guaranteed to get the same pointer back from the call to [JSValue context] as the one 
that the value was created in.
(-[TestObject callback:]):
* JavaScriptCore.xcodeproj/project.pbxproj:
* runtime/JSGlobalData.cpp:
(JSC::JSGlobalData::JSGlobalData): No more m_apiData.
* runtime/JSGlobalData.h: Ditto.
* runtime/JSGlobalObject.cpp:
(JSC::JSGlobalObject::JSGlobalObject): Ditto.
* runtime/JSGlobalObject.h:

Source/WebCore: 

Reviewed by Geoffrey Garen.

* WebCore.exp.in:
* bindings/js/JSDOMWindowShell.cpp:
(WebCore::JSDOMWindowShell::setWindow): Since we're basically abandoning a JSDOMWindow here, we call
garbageCollectSoon().
* bindings/js/JSDOMWindowShell.h:
* bindings/js/ScriptController.h: New function to get the JSContext for the global object of the current main world.
* bindings/js/ScriptControllerMac.mm: 
(WebCore::ScriptController::javaScriptContext): Ditto.
* bindings/objc/WebScriptObject.h: Added ifdef guards. Also new convenience conversion function for the JSC Obj-C API.
* bindings/objc/WebScriptObject.mm: JSC::JSValue and JSValue conflict with one another, so we have to be more specific.
(-[WebScriptObject _globalContextRef]): Useful helper function for getting the JSGlobalContextRef of a particular WebScriptObject.
(-[WebScriptObject callWebScriptMethod:withArguments:]):
(-[WebScriptObject evaluateWebScript:]):
(-[WebScriptObject valueForKey:]):
(-[WebScriptObject webScriptValueAtIndex:]):
(+[WebScriptObject _convertValueToObjcValue:JSC::originRootObject:rootObject:]):
(-[WebScriptObject JSValue]): Implementation of convenience WebScriptObject conversion function to new Objective-C API.
* bindings/objc/WebScriptObjectPrivate.h:

Source/WebKit/mac: 

Reviewed by Geoffrey Garen.

Addition of appropriate delegate callbacks and support to the WebKit API.

* WebCoreSupport/WebFrameLoaderClient.mm:
* WebView/WebDelegateImplementationCaching.h:
(WebFrameLoadDelegateImplementationCache):
* WebView/WebFrame.h:
* WebView/WebFrame.mm:
(-[WebFrame _stringByEvaluatingJavaScriptFromString:forceUserGesture:]):
(-[WebFrame _stringByEvaluatingJavaScriptFromString:withGlobalObject:inScriptWorld:]):
(-[WebFrame _javaScriptContextForScriptWorld:]):
(-[WebFrame javaScriptContext]):
* WebView/WebFrameLoadDelegate.h:
* WebView/WebFramePrivate.h:
* WebView/WebScriptDebugDelegate.mm:
(-[WebScriptCallFrame _convertValueToObjcValue:JSC::]):
(-[WebScriptCallFrame exception]):
(-[WebScriptCallFrame evaluateWebScript:]):
* WebView/WebScriptWorld.h:
* WebView/WebScriptWorld.mm:
(+[WebScriptWorld scriptWorldForJavaScriptContext:]):
* WebView/WebView.mm:
(-[WebView _cacheFrameLoadDelegateImplementations]):
(aeDescFromJSValue):
(-[WebView aeDescByEvaluatingJavaScriptFromString:]):
(-[WebView _computedStyleIncludingVisitedInfo:forElement:]):

Source/WTF: 

Reviewed by Geoffrey Garen.

* wtf/FeatureDefines.h: Added enable flag for JSC Objective-C API so it can be used in
export files.

Tools: 

Reviewed by Geoffrey Garen.

Added new tests for the WebKit API portion of the JSC Objective-C API.

* TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
* TestWebKitAPI/Tests/mac/JSContextBackForwardCache1.html: Added.
* TestWebKitAPI/Tests/mac/JSContextBackForwardCache2.html: Added.
* TestWebKitAPI/Tests/mac/WebViewDidCreateJavaScriptContext.mm: Added.
(-[MyConsole log:]):
(-[MyConsole printHelloWorld]):
(-[MyConsole add:to:]):
(-[DidCreateJavaScriptContextFrameLoadDelegate webView:didFinishLoadForFrame:]):
(-[DidCreateJavaScriptContextFrameLoadDelegate webView:didCreateJavaScriptContext:forFrame:]):
(TestWebKitAPI):
(TestWebKitAPI::TEST):


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@143637 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent fbab9c3e
......@@ -140,7 +140,8 @@ JS_EXPORT void JSGarbageCollect(JSContextRef ctx);
#endif
/* Enable the Objective-C API for platforms with a modern runtime. */
#undef JS_OBJC_API_ENABLED
#define JS_OBJC_API_ENABLED (defined(__clang__) && defined(__APPLE__) && defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090 && !defined(__i386__))
#if !defined(JSC_OBJC_API_ENABLED)
#define JSC_OBJC_API_ENABLED (defined(__clang__) && defined(__APPLE__) && defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090 && !defined(__i386__))
#endif
#endif /* JSBase_h */
......@@ -25,7 +25,7 @@
#import <JavaScriptCore/JavaScriptCore.h>
#if JS_OBJC_API_ENABLED
#if JSC_OBJC_API_ENABLED
@interface JSBlockAdaptor : NSObject
......
......@@ -26,7 +26,7 @@
#include "config.h"
#import "JavaScriptCore.h"
#if JS_OBJC_API_ENABLED
#if JSC_OBJC_API_ENABLED
#import "APICast.h"
#import "APIShims.h"
......
......@@ -23,9 +23,12 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef JSContext_h
#define JSContext_h
#include <JavaScriptCore/JavaScript.h>
#if JS_OBJC_API_ENABLED
#if JSC_OBJC_API_ENABLED
@class JSVirtualMachine, JSValue;
......@@ -49,6 +52,10 @@ NS_CLASS_AVAILABLE(10_9, NA)
// Evaluate a string of JavaScript code.
- (JSValue *)evaluateScript:(NSString *)script;
// Return the C API version of this context. This function is for convenience
// at the boundaries when converting code from the C API to the Objective-C API.
- (JSGlobalContextRef)globalContextRef;
// This method retrieves the global object of the JavaScript execution context.
// Instances of JSContext originating from WebKit will return a reference to the
// WindowProxy object.
......@@ -114,3 +121,5 @@ NS_CLASS_AVAILABLE(10_9, NA)
@end
#endif
#endif // JSContext_h
......@@ -37,7 +37,7 @@
#import "StrongInlines.h"
#import <wtf/HashSet.h>
#if JS_OBJC_API_ENABLED
#if JSC_OBJC_API_ENABLED
@implementation JSContext {
JSVirtualMachine *m_virtualMachine;
......@@ -48,6 +48,11 @@
@synthesize exceptionHandler;
- (JSGlobalContextRef)globalContextRef
{
return m_context;
}
- (id)init
{
return [self initWithVirtualMachine:[[[JSVirtualMachine alloc] init] autorelease]];
......@@ -67,7 +72,6 @@
context.exception = exceptionValue;
};
toJS(m_context)->lexicalGlobalObject()->m_apiData = self;
return self;
}
......@@ -167,6 +171,25 @@
@implementation JSContext(Internal)
- (id)initWithGlobalContextRef:(JSGlobalContextRef)context
{
self = [super init];
if (!self)
return nil;
JSC::JSGlobalObject* globalObject = toJS(context)->lexicalGlobalObject();
m_virtualMachine = [[JSVirtualMachine virtualMachineWithContextGroupRef:toRef(&globalObject->globalData())] retain];
ASSERT(m_virtualMachine);
m_context = JSGlobalContextRetain(context);
m_wrapperMap = [[JSWrapperMap alloc] initWithContext:self];
self.exceptionHandler = ^(JSContext *context, JSValue *exceptionValue) {
context.exception = exceptionValue;
};
return self;
}
JSGlobalContextRef contextInternalContext(JSContext *context)
{
return context->m_context;
......@@ -174,7 +197,6 @@ JSGlobalContextRef contextInternalContext(JSContext *context)
- (void)dealloc
{
toJS(m_context)->lexicalGlobalObject()->m_apiData = 0;
[m_wrapperMap release];
JSGlobalContextRelease(m_context);
[m_virtualMachine release];
......@@ -220,11 +242,28 @@ JSGlobalContextRef contextInternalContext(JSContext *context)
[self release];
}
- (JSValue *)wrapperForObject:(id)object
- (JSValue *)wrapperForObjCObject:(id)object
{
// Lock access to m_wrapperMap
JSC::JSLockHolder lock(toJS(m_context));
return [m_wrapperMap wrapperForObject:object];
return [m_wrapperMap jsWrapperForObject:object];
}
- (JSValue *)wrapperForJSObject:(JSValueRef)value
{
JSC::JSLockHolder lock(toJS(m_context));
return [m_wrapperMap objcWrapperForJSValueRef:value];
}
+ (JSContext *)contextWithGlobalContextRef:(JSGlobalContextRef)globalContext
{
JSVirtualMachine *virtualMachine = [JSVirtualMachine virtualMachineWithContextGroupRef:toRef(&toJS(globalContext)->globalData())];
JSContext *context = [virtualMachine contextForGlobalContextRef:globalContext];
if (!context) {
context = [[[JSContext alloc] initWithGlobalContextRef:globalContext] autorelease];
[virtualMachine addContext:context forGlobalContextRef:globalContext];
}
return context;
}
@end
......
......@@ -23,11 +23,14 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef JSContextInternal_h
#define JSContextInternal_h
#import <JavaScriptCore/JavaScriptCore.h>
#if JS_OBJC_API_ENABLED
#if JSC_OBJC_API_ENABLED
#import "JSContext.h"
#import <JavaScriptCore/JSContext.h>
struct CallbackData {
CallbackData *next;
......@@ -56,7 +59,9 @@ private:
@interface JSContext(Internal)
JSGlobalContextRef contextInternalContext(JSContext *);
- (id)initWithGlobalContextRef:(JSGlobalContextRef)context;
JS_EXPORT_PRIVATE JSGlobalContextRef contextInternalContext(JSContext *);
- (void)notifyException:(JSValueRef)exception;
- (JSValue *)valueFromNotifyException:(JSValueRef)exception;
......@@ -65,10 +70,15 @@ JSGlobalContextRef contextInternalContext(JSContext *);
- (void)beginCallbackWithData:(CallbackData *)callbackData thisValue:(JSValueRef)thisValue argumentCount:(size_t)argumentCount arguments:(const JSValueRef *)arguments;
- (void)endCallbackWithData:(CallbackData *)callbackData;
- (JSValue *)wrapperForObject:(id)object;
- (JSValue *)wrapperForObjCObject:(id)object;
- (JSValue *)wrapperForJSObject:(JSValueRef)value;
+ (JSContext *)contextWithGlobalContextRef:(JSGlobalContextRef)globalContext;
@property (readonly, retain) JSWrapperMap *wrapperMap;
@end
#endif
#endif // JSContextInternal_h
......@@ -25,7 +25,7 @@
#import <JavaScriptCore/JavaScriptCore.h>
#if JS_OBJC_API_ENABLED
#if JSC_OBJC_API_ENABLED
// When a JavaScript value is created from an instance of an Objective-C class
// for which no copying conversion is specified a JavaScript wrapper object will
......
......@@ -23,7 +23,10 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#if JS_OBJC_API_ENABLED
#ifndef JSValue_h
#define JSValue_h
#if JSC_OBJC_API_ENABLED
@class JSContext;
......@@ -102,6 +105,10 @@ NS_CLASS_AVAILABLE(10_9, NA)
+ (JSValue *)valueWithNullInContext:(JSContext *)context;
+ (JSValue *)valueWithUndefinedInContext:(JSContext *)context;
// Return the C API version of this value. This function is for convenience
// at the boundaries when converting code from the C API to the Objective-C API.
- (JSValueRef)JSValueRef;
// Convert this value to a corresponding Objective-C object, according to the
// conversion specified above.
- (id)toObject;
......@@ -292,3 +299,4 @@ JS_EXPORT extern NSString * const JSPropertyDescriptorSetKey;
#endif
#endif // JSValue_h
......@@ -24,7 +24,6 @@
*/
#include "config.h"
//#import "JSValue.h"
#import "APICast.h"
#import "APIShims.h"
......@@ -45,7 +44,7 @@
#import <wtf/text/WTFString.h>
#import <wtf/text/StringHash.h>
#if JS_OBJC_API_ENABLED
#if JSC_OBJC_API_ENABLED
NSString * const JSPropertyDescriptorWritableKey = @"writable";
NSString * const JSPropertyDescriptorEnumerableKey = @"enumerable";
......@@ -58,6 +57,11 @@ NSString * const JSPropertyDescriptorSetKey = @"set";
JSValueRef m_value;
}
- (JSValueRef)JSValueRef
{
return m_value;
}
+ (JSValue *)valueWithObject:(id)value inContext:(JSContext *)context
{
return [JSValue valueWithValue:objectToValue(context, value) inContext:context];
......@@ -890,7 +894,7 @@ static ObjcContainerConvertor::Task objectToValueWithoutCopy(JSContext *context,
}
}
return (ObjcContainerConvertor::Task){ object, valueInternalValue([context wrapperForObject:object]), ContainerNone };
return (ObjcContainerConvertor::Task){ object, valueInternalValue([context wrapperForObjCObject:object]), ContainerNone };
}
JSValueRef objectToValue(JSContext *context, id object)
......@@ -941,7 +945,7 @@ JSValueRef valueInternalValue(JSValue * value)
+ (JSValue *)valueWithValue:(JSValueRef)value inContext:(JSContext *)context
{
return [[[JSValue alloc] initWithValue:value inContext:context] autorelease];
return [context wrapperForJSObject:value];
}
- (JSValue *)initWithValue:(JSValueRef)value inContext:(JSContext *)context
......
......@@ -23,10 +23,13 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef JSValueInternal_h
#define JSValueInternal_h
#import <JavaScriptCore/JavaScriptCore.h>
#import "JSValue.h"
#import <JavaScriptCore/JSValue.h>
#if JS_OBJC_API_ENABLED
#if JSC_OBJC_API_ENABLED
@interface JSValue(Internal)
......@@ -52,3 +55,5 @@ NSInvocation *typeToValueInvocationFor(const char* encodedType);
NSInvocation *valueToTypeInvocationFor(const char* encodedType);
#endif
#endif // JSValueInternal_h
......@@ -25,7 +25,7 @@
#import <JavaScriptCore/JavaScriptCore.h>
#if JS_OBJC_API_ENABLED
#if JSC_OBJC_API_ENABLED
// An instance of JSVirtualMachine represents a single JavaScript "object space"
// or set of execution resources. Thread safety is supported by locking the
......
......@@ -27,23 +27,81 @@
#import "JavaScriptCore.h"
#if JS_OBJC_API_ENABLED
#if JSC_OBJC_API_ENABLED
#import "APICast.h"
#import "JSVirtualMachineInternal.h"
static NSMapTable *globalWrapperCache = 0;
static Mutex& wrapperCacheLock()
{
DEFINE_STATIC_LOCAL(Mutex, mutex, ());
return mutex;
}
static void initWrapperCache()
{
ASSERT(!globalWrapperCache);
NSPointerFunctionsOptions keyOptions = NSPointerFunctionsOpaqueMemory | NSPointerFunctionsOpaquePersonality;
NSPointerFunctionsOptions valueOptions = NSPointerFunctionsWeakMemory | NSPointerFunctionsObjectPersonality;
globalWrapperCache = [[NSMapTable alloc] initWithKeyOptions:keyOptions valueOptions:valueOptions capacity:0];
}
static NSMapTable *wrapperCache()
{
if (!globalWrapperCache)
initWrapperCache();
return globalWrapperCache;
}
@interface JSVMWrapperCache : NSObject
+ (void)addWrapper:(JSVirtualMachine *)wrapper forJSContextGroupRef:(JSContextGroupRef)group;
+ (JSVirtualMachine *)wrapperForJSContextGroupRef:(JSContextGroupRef)group;
@end
@implementation JSVMWrapperCache
+ (void)addWrapper:(JSVirtualMachine *)wrapper forJSContextGroupRef:(JSContextGroupRef)group
{
MutexLocker locker(wrapperCacheLock());
NSMapInsert(wrapperCache(), group, wrapper);
}
+ (JSVirtualMachine *)wrapperForJSContextGroupRef:(JSContextGroupRef)group
{
MutexLocker locker(wrapperCacheLock());
return static_cast<JSVirtualMachine *>(NSMapGet(wrapperCache(), group));
}
@end
@implementation JSVirtualMachine {
JSContextGroupRef m_group;
NSMapTable *m_contextCache;
}
- (id)init
{
JSContextGroupRef group = JSContextGroupCreate();
self = [self initWithContextGroupRef:group];
// The extra JSContextGroupRetain is balanced here.
JSContextGroupRelease(group);
return self;
}
- (id)initWithContextGroupRef:(JSContextGroupRef)group
{
self = [super init];
if (!self)
return nil;
m_group = JSContextGroupCreate();
toJS(m_group)->m_apiData = self;
m_group = JSContextGroupRetain(group);
NSPointerFunctionsOptions keyOptions = NSPointerFunctionsOpaqueMemory | NSPointerFunctionsOpaquePersonality;
NSPointerFunctionsOptions valueOptions = NSPointerFunctionsWeakMemory | NSPointerFunctionsObjectPersonality;
m_contextCache = [[NSMapTable alloc] initWithKeyOptions:keyOptions valueOptions:valueOptions capacity:0];
return self;
}
......@@ -53,7 +111,6 @@
- (void)dealloc
{
toJS(m_group)->m_apiData = 0;
JSContextGroupRelease(m_group);
[super dealloc];
}
......@@ -63,7 +120,28 @@ JSContextGroupRef getGroupFromVirtualMachine(JSVirtualMachine *virtualMachine)
return virtualMachine->m_group;
}
+ (JSVirtualMachine *)virtualMachineWithContextGroupRef:(JSContextGroupRef)group
{
JSVirtualMachine *virtualMachine = [JSVMWrapperCache wrapperForJSContextGroupRef:group];
if (!virtualMachine) {
virtualMachine = [[[JSVirtualMachine alloc] initWithContextGroupRef:group] autorelease];
[JSVMWrapperCache addWrapper:virtualMachine forJSContextGroupRef:group];
}
return virtualMachine;
}
- (JSContext *)contextForGlobalContextRef:(JSGlobalContextRef)globalContext
{
return static_cast<JSContext *>(NSMapGet(m_contextCache, globalContext));
}
- (void)addContext:(JSContext *)wrapper forGlobalContextRef:(JSGlobalContextRef)globalContext
{
NSMapInsert(m_contextCache, globalContext, wrapper);
}
@end
#endif
......@@ -23,15 +23,25 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "JSVirtualMachine.h"
#ifndef JSVirtualMachineInternal_h
#define JSVirtualMachineInternal_h
#import <JavaScriptCore/JSVirtualMachine.h>
#import <JavaScriptCore/JavaScriptCore.h>
#if JS_OBJC_API_ENABLED
#if JSC_OBJC_API_ENABLED
@interface JSVirtualMachine(Internal)
JSContextGroupRef getGroupFromVirtualMachine(JSVirtualMachine *);
+ (JSVirtualMachine *)virtualMachineWithContextGroupRef:(JSContextGroupRef)group;
- (JSContext *)contextForGlobalContextRef:(JSGlobalContextRef)globalContext;
- (void)addContext:(JSContext *)wrapper forGlobalContextRef:(JSGlobalContextRef)globalContext;
@end
#endif
#endif // JSVirtualMachineInternal_h
......@@ -27,13 +27,15 @@
#import <JSValueInternal.h>
#import <objc/objc-runtime.h>
#if JS_OBJC_API_ENABLED
#if JSC_OBJC_API_ENABLED
@interface JSWrapperMap : NSObject
- (id)initWithContext:(JSContext *)context;
- (JSValue *)wrapperForObject:(id)object;
- (JSValue *)jsWrapperForObject:(id)object;
- (JSValue *)objcWrapperForJSValueRef:(JSValueRef)value;
@end
......
......@@ -26,7 +26,7 @@
#include "config.h"
#import "JavaScriptCore.h"
#if JS_OBJC_API_ENABLED
#if JSC_OBJC_API_ENABLED
#import "APICast.h"
#import "JSContextInternal.h"
......@@ -382,7 +382,7 @@ static void copyPrototypeProperties(JSContext *context, Class objcClass, Protoco
});
// Set [Prototype].
prototype[@"__proto__"] = [JSValue valueWithValue:toRef(superClassInfo->m_prototype.get()) inContext:m_context];
JSObjectSetPrototype(contextInternalContext(m_context), toRef(m_prototype.get()), toRef(superClassInfo->m_prototype.get()));
[constructor release];
[prototype release];
......@@ -425,7 +425,8 @@ static void copyPrototypeProperties(JSContext *context, Class objcClass, Protoco
@implementation JSWrapperMap {
JSContext *m_context;
NSMutableDictionary *m_classMap;
JSC::WeakGCMap<id, JSC::JSObject> m_cachedWrappers;
JSC::WeakGCMap<id, JSC::JSObject> m_cachedJSWrappers;
NSMapTable *m_cachedObjCWrappers;
}
- (id)initWithContext:(JSContext *)context
......@@ -434,6 +435,10 @@ static void copyPrototypeProperties(JSContext *context, Class objcClass, Protoco
if (!self)
return nil;
NSPointerFunctionsOptions keyOptions = NSPointerFunctionsOpaqueMemory | NSPointerFunctionsOpaquePersonality;
NSPointerFunctionsOptions valueOptions = NSPointerFunctionsWeakMemory | NSPointerFunctionsObjectPersonality;
m_cachedObjCWrappers = [[NSMapTable alloc] initWithKeyOptions:keyOptions valueOptions:valueOptions capacity:0];
m_context = context;
m_classMap = [[NSMutableDictionary alloc] init];
return self;
......@@ -461,9 +466,9 @@ static void copyPrototypeProperties(JSContext *context, Class objcClass, Protoco
return m_classMap[cls] = [[[JSObjCClassInfo alloc] initWithContext:m_context forClass:cls superClassInfo:[self classInfoForClass:class_getSuperclass(cls)]] autorelease];
}
- (JSValue *)wrapperForObject:(id)object
- (JSValue *)jsWrapperForObject:(id)object
{
JSC::JSObject* jsWrapper = m_cachedWrappers.get(object);
JSC::JSObject* jsWrapper = m_cachedJSWrappers.get(object);
if (jsWrapper)
return [JSValue valueWithValue:toRef(jsWrapper) inContext:m_context];
......@@ -482,7 +487,17 @@ static void copyPrototypeProperties(JSContext *context, Class objcClass, Protoco
// but still, would probably nicer if we made it so that only one associated object was required, broadcasting object dealloc.
JSC::ExecState* exec = toJS(contextInternalContext(m_context));
jsWrapper = toJS(exec, valueInternalValue(wrapper)).toObject(exec);
m_cachedWrappers.set(object, jsWrapper);
m_cachedJSWrappers.set(object, jsWrapper);
return wrapper;
}
- (JSValue *)objcWrapperForJSValueRef:(JSValueRef)value
{
JSValue *wrapper = static_cast<JSValue *>(NSMapGet(m_cachedObjCWrappers, value));
if (!wrapper) {
wrapper = [[[JSValue alloc] initWithValue:value inContext:m_context] autorelease];
NSMapInsert(m_cachedObjCWrappers, value, wrapper);
}
return wrapper;
}
......
......@@ -29,7 +29,7 @@
#include <JavaScriptCore/JavaScript.h>
#include <JavaScriptCore/JSStringRefCF.h>
#if defined(__OBJC__) && JS_OBJC_API_ENABLED
#if defined(__OBJC__) && JSC_OBJC_API_ENABLED
#import "JSContext.h"
#import "JSValue.h"
......
......@@ -25,7 +25,7 @@
#import <JavaScriptCore/JavaScriptCore.h>
#if JS_OBJC_API_ENABLED
#if JSC_OBJC_API_ENABLED
JSObjectRef objCCallbackFunctionForMethod(JSContext *, Class, Protocol *, BOOL isInstanceMethod, SEL, const char* types);
JSObjectRef objCCallbackFunctionForBlock(JSContext *, id);
......
......@@ -26,12 +26,15 @@
#include "config.h"
#import "JavaScriptCore.h"
#if JS_OBJC_API_ENABLED
#if JSC_OBJC_API_ENABLED
#import "APICast.h"
#import "APIShims.h"
#import "Error.h"
#import "JSBlockAdaptor.h"
#import "JSCJSValueInlines.h"
#import "JSCell.h"
#import "JSCellInlines.h"
#import "JSContextInternal.h"
#import "JSWrapperMap.h"
#import "JSValueInternal.h"
......@@ -426,8 +429,6 @@ public:
, m_result(result)
{
ASSERT(type != CallbackInstanceMethod || instanceClass);
if (m_type != CallbackInstanceMethod)
[[m_invocation.get() target] retain];
}
~ObjCCallbackFunction()
......@@ -444,6 +445,12 @@ public:
return m_context.get();
}
void setContext(JSContext *context)
{
ASSERT(!m_context.get());
m_context.set(context);
}
id wrappedBlock()
{
return m_type == CallbackBlock ? [m_invocation target] : nil;
......@@ -474,11 +481,8 @@ static JSValueRef objCCallbackFunctionCallAsFunction(JSContextRef callerContext,
ObjCCallbackFunction* callback = static_cast<ObjCCallbackFunction*>(JSObjectGetPrivate(function));
JSContext *context = callback->context();
if (!context) {
// FIXME: https://bugs.webkit.org/show_bug.cgi?id=105894
// Rather than requiring that the context be retained, it would probably be more
// appropriate to use a new JSContext instance (creating one if necessary).
*exception = toRef(JSC::createTypeError(toJS(callerContext), "Objective-C callback function context released"));