Commit db731edf authored by mhahnenberg@apple.com's avatar mhahnenberg@apple.com
Browse files

Objective-C API: Need a good way to reference event handlers without causing cycles

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

Reviewed by Geoffrey Garen.

JSManagedValue is like a special kind of weak value. When you create a JSManagedValue, you can
supply an Objective-C object as its "owner". As long as the Objective-C owner object remains
alive and its wrapper remains accessible to the JSC garbage collector (e.g. by being marked by 
the global object), the reference to the JavaScript value is strong. As soon as the Objective-C
owner is deallocated or its wrapper becomes inaccessible to the garbage collector, the reference
becomes weak.

If you do not supply an owner or you use the weakValueWithValue: convenience class method, the
returned JSManagedValue behaves as a normal weak reference.

This new class allows clients to maintain references to JavaScript values in the Objective-C
heap without creating reference cycles/leaking memory.

* API/JSAPIWrapperObject.cpp: Added.
(JSC):
(JSC::::createStructure):
(JSC::JSAPIWrapperObject::JSAPIWrapperObject): This is a special JSObject for the Objective-C API that knows
for the purposes of garbage collection/marking that it wraps an opaque Objective-C object.
(JSC::JSAPIWrapperObject::visitChildren): We add the pointer to the wrapped Objective-C object to the set of
opaque roots so that the weak handle owner for JSManagedValues can find it later.
* API/JSAPIWrapperObject.h: Added.
(JSC):
(JSAPIWrapperObject):
(JSC::JSAPIWrapperObject::wrappedObject):
(JSC::JSAPIWrapperObject::setWrappedObject):
* API/JSBase.cpp:
(JSSynchronousGarbageCollect):
* API/JSBasePrivate.h:
* API/JSCallbackObject.cpp:
(JSC):
* API/JSCallbackObject.h:
(JSC::JSCallbackObject::destroy): Moved this to the header so that we don't get link errors with JSAPIWrapperObject.
* API/JSContext.mm:
(-[JSContext initWithVirtualMachine:]): We weren't adding manually allocated/initialized JSVirtualMachine objects to 
the global cache of virtual machines. The init methods handle this now rather than contextWithGlobalContextRef, since 
not everyone is guaranteed to use the latter.
(-[JSContext initWithGlobalContextRef:]):
(+[JSContext contextWithGlobalContextRef:]):
* API/JSManagedValue.h: Added.
* API/JSManagedValue.mm: Added.
(JSManagedValueHandleOwner):
(managedValueHandleOwner):
(+[JSManagedValue weakValueWithValue:]):
(+[JSManagedValue managedValueWithValue:owner:]):
(-[JSManagedValue init]): We explicitly call the ARC entrypoints to initialize/get the weak owner field since we don't 
use ARC when building our framework.
(-[JSManagedValue initWithValue:]):
(-[JSManagedValue initWithValue:owner:]):
(-[JSManagedValue dealloc]):
(-[JSManagedValue value]):
(-[JSManagedValue weakOwner]):
(JSManagedValueHandleOwner::isReachableFromOpaqueRoots): If the Objective-C owner is still alive (i.e. loading the weak field
returns non-nil) and that value was added to the set of opaque roots by the wrapper for that Objective-C owner, then the the 
JSObject to which the JSManagedObject refers is still alive.
* API/JSObjectRef.cpp: We have to add explicit checks for the JSAPIWrapperObject, just like the other types of JSCallbackObjects.
(JSObjectGetPrivate):
(JSObjectSetPrivate):
(JSObjectGetPrivateProperty):
(JSObjectSetPrivateProperty):
(JSObjectDeletePrivateProperty):
* API/JSValue.mm:
(objectToValueWithoutCopy):
* API/JSValueRef.cpp:
(JSValueIsObjectOfClass):
* API/JSVirtualMachine.mm:
(-[JSVirtualMachine initWithContextGroupRef:]):
(+[JSVirtualMachine virtualMachineWithContextGroupRef:]):
* API/JSWrapperMap.mm:
(wrapperFinalize):
(makeWrapper): This is our own internal version of JSObjectMake which creates JSAPIWrapperObjects, the Obj-C API 
version of JSCallbackObjects.
(createObjectWithCustomBrand):
(-[JSObjCClassInfo wrapperForObject:]):
(tryUnwrapObjcObject):
* API/JavaScriptCore.h:
* API/tests/testapi.mm: Added new tests for the strong and weak uses of JSManagedValue in the context of an 
onclick handler for an Objective-C object inserted into a JSContext.
(-[TextXYZ setWeakOnclick:]):
(-[TextXYZ setOnclick:]):
(-[TextXYZ weakOnclick]):
(-[TextXYZ onclick]):
(-[TextXYZ click]):
* CMakeLists.txt: Various build system additions.
* GNUmakefile.list.am:
* JavaScriptCore.gypi:
* JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj:
* JavaScriptCore.xcodeproj/project.pbxproj:
* runtime/JSGlobalObject.cpp: Added the new canonical Structure for the JSAPIWrapperObject class.
(JSC::JSGlobalObject::reset):
(JSC):
(JSC::JSGlobalObject::visitChildren):
* runtime/JSGlobalObject.h:
(JSGlobalObject):
(JSC::JSGlobalObject::objcWrapperObjectStructure):


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@145119 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent e500c3e7
/*
* Copyright (C) 2013 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
#include "JSAPIWrapperObject.h"
#include "JSCJSValueInlines.h"
#include "JSCallbackObject.h"
#include "JSCellInlines.h"
#include "SlotVisitorInlines.h"
#include "Structure.h"
#include "StructureInlines.h"
namespace JSC {
template <> const ClassInfo JSCallbackObject<JSAPIWrapperObject>::s_info = { "EnumerableCallbackObject", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSCallbackObject) };
template<> const bool JSCallbackObject<JSAPIWrapperObject>::needsDestruction = true;
template <>
Structure* JSCallbackObject<JSAPIWrapperObject>::createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue proto)
{
return Structure::create(globalData, globalObject, proto, TypeInfo(ObjectType, StructureFlags), &s_info);
}
JSAPIWrapperObject::JSAPIWrapperObject(JSGlobalData& globalData, Structure* structure)
: Base(globalData, structure)
, m_wrappedObject(0)
{
}
void JSAPIWrapperObject::visitChildren(JSCell* cell, JSC::SlotVisitor& visitor)
{
JSAPIWrapperObject* thisObject = JSC::jsCast<JSAPIWrapperObject*>(cell);
COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag);
Base::visitChildren(cell, visitor);
if (thisObject->wrappedObject())
visitor.addOpaqueRoot(thisObject->wrappedObject());
}
} // namespace JSC
/*
* Copyright (C) 2013 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef JSAPIWrapperObject_h
#define JSAPIWrapperObject_h
#include "JSBase.h"
#include "JSDestructibleObject.h"
#include "WeakReferenceHarvester.h"
namespace JSC {
class JSAPIWrapperObject : public JSDestructibleObject {
public:
typedef JSDestructibleObject Base;
static void visitChildren(JSCell*, JSC::SlotVisitor&);
void* wrappedObject() { return m_wrappedObject; }
void setWrappedObject(void* wrappedObject) { m_wrappedObject = wrappedObject; }
protected:
static const unsigned StructureFlags = OverridesVisitChildren | Base::StructureFlags;
JSAPIWrapperObject(JSGlobalData&, Structure*);
private:
void* m_wrappedObject;
};
} // namespace JSC
#endif // JSAPIWrapperObject_h
......@@ -110,3 +110,15 @@ void JSReportExtraMemoryCost(JSContextRef ctx, size_t size)
APIEntryShim entryShim(exec);
exec->globalData().heap.reportExtraMemoryCost(size);
}
JS_EXPORT void JSSynchronousGarbageCollectForDebugging(JSContextRef);
void JSSynchronousGarbageCollectForDebugging(JSContextRef ctx)
{
if (!ctx)
return;
ExecState* exec = toJS(ctx);
APIEntryShim entryShim(exec);
exec->globalData().heap.collectAllGarbage();
}
......@@ -61,12 +61,6 @@ Structure* JSCallbackObject<JSGlobalObject>::createStructure(JSGlobalData& globa
return Structure::create(globalData, globalObject, proto, TypeInfo(GlobalObjectType, StructureFlags), &s_info);
}
template <class Parent>
void JSCallbackObject<Parent>::destroy(JSCell* cell)
{
static_cast<JSCallbackObject*>(cell)->JSCallbackObject::~JSCallbackObject();
}
void JSCallbackObjectData::finalize(Handle<Unknown> handle, void* context)
{
JSClassRef jsClass = static_cast<JSClassRef>(context);
......
......@@ -136,7 +136,10 @@ public:
static JSCallbackObject<Parent>* create(JSGlobalData&, JSClassRef, Structure*);
static const bool needsDestruction;
static void destroy(JSCell*);
static void destroy(JSCell* cell)
{
static_cast<JSCallbackObject*>(cell)->JSCallbackObject::~JSCallbackObject();
}
void setPrivate(void* data);
void* getPrivate();
......
......@@ -26,6 +26,7 @@
#include "config.h"
#import "APICast.h"
#import "APIShims.h"
#import "JSContextInternal.h"
#import "JSGlobalObject.h"
#import "JSValueInternal.h"
......@@ -72,6 +73,8 @@
context.exception = exceptionValue;
};
[m_virtualMachine addContext:self forGlobalContextRef:m_context];
return self;
}
......@@ -187,6 +190,8 @@
context.exception = exceptionValue;
};
[m_virtualMachine addContext:self forGlobalContextRef:m_context];
return self;
}
......@@ -254,10 +259,8 @@
{
JSVirtualMachine *virtualMachine = [JSVirtualMachine virtualMachineWithContextGroupRef:toRef(&toJS(globalContext)->globalData())];
JSContext *context = [virtualMachine contextForGlobalContextRef:globalContext];
if (!context) {
if (!context)
context = [[[JSContext alloc] initWithGlobalContextRef:globalContext] autorelease];
[virtualMachine addContext:context forGlobalContextRef:globalContext];
}
return context;
}
......
/*
* Copyright (C) 2013 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef JSManagedValue_h
#define JSManagedValue_h
#import <JavaScriptCore/JSBase.h>
#if JSC_OBJC_API_ENABLED
@class JSValue;
@class JSContext;
NS_CLASS_AVAILABLE(10_9, NA)
@interface JSManagedValue : NSObject
+ (JSManagedValue *)managedValueWithValue:(JSValue *)value;
+ (JSManagedValue *)managedValueWithValue:(JSValue *)value owner:(id)owner;
- (id)initWithValue:(JSValue *)value;
- (id)initWithValue:(JSValue *)value owner:(id)owner;
- (JSValue *)value;
@end
#endif // JSC_OBJC_API_ENABLED
#endif // JSManagedValue_h
/*
* Copyright (C) 2013 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "config.h"
#import "JSManagedValue.h"
#if JSC_OBJC_API_ENABLED
#import "APICast.h"
#import "Heap.h"
#import "JSCJSValueInlines.h"
#import "JSContextInternal.h"
#import "JSValueInternal.h"
#import "Weak.h"
#import "WeakHandleOwner.h"
#import "ObjcRuntimeExtras.h"
class JSManagedValueHandleOwner : public JSC::WeakHandleOwner {
public:
virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&);
};
static JSManagedValueHandleOwner* managedValueHandleOwner()
{
DEFINE_STATIC_LOCAL(JSManagedValueHandleOwner, jsManagedValueHandleOwner, ());
return &jsManagedValueHandleOwner;
}
@interface JSManagedValue (Internal)
- (id)weakOwner;
@end
@implementation JSManagedValue {
JSC::Weak<JSC::JSObject> m_value;
id m_weakOwner;
}
+ (JSManagedValue *)managedValueWithValue:(JSValue *)value
{
return [[[self alloc] initWithValue:value] autorelease];
}
+ (JSManagedValue *)managedValueWithValue:(JSValue *)value owner:(id)owner
{
return [[[self alloc] initWithValue:value owner:owner] autorelease];
}
- (id)init
{
return [self initWithValue:nil owner:nil];
}
- (id)initWithValue:(JSValue *)value
{
return [self initWithValue:value owner:nil];
}
- (id)initWithValue:(JSValue *)value owner:(id)owner
{
self = [super init];
if (!self)
return nil;
if (!value || !JSValueIsObject([value.context globalContextRef], [value JSValueRef])) {
JSC::Weak<JSC::JSObject> weak;
m_value.swap(weak);
} else {
JSC::JSObject* object = toJS(const_cast<OpaqueJSValue*>([value JSValueRef]));
JSC::Weak<JSC::JSObject> weak(object, managedValueHandleOwner(), self);
m_value.swap(weak);
}
objc_initWeak(&m_weakOwner, owner);
return self;
}
- (void)dealloc
{
objc_destroyWeak(&m_weakOwner);
[super dealloc];
}
- (JSValue *)value
{
if (!m_value)
return nil;
JSC::JSObject* object = m_value.get();
JSContext *context = [JSContext contextWithGlobalContextRef:toGlobalRef(object->structure()->globalObject()->globalExec())];
return [JSValue valueWithValue:toRef(object) inContext:context];
}
@end
@implementation JSManagedValue (Internal)
- (id)weakOwner
{
return objc_loadWeak(&m_weakOwner);
}
@end
bool JSManagedValueHandleOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor& visitor)
{
JSManagedValue *managedValue = static_cast<JSManagedValue *>(context);
id weakOwner = [managedValue weakOwner];
if (!weakOwner)
return false;
return visitor.containsOpaqueRoot(weakOwner);
}
#endif // JSC_OBJC_API_ENABLED
......@@ -37,6 +37,7 @@
#include "FunctionConstructor.h"
#include "Identifier.h"
#include "InitializeThreading.h"
#include "JSAPIWrapperObject.h"
#include "JSArray.h"
#include "JSCallbackConstructor.h"
#include "JSCallbackFunction.h"
......@@ -345,6 +346,8 @@ void* JSObjectGetPrivate(JSObjectRef object)
return jsCast<JSCallbackObject<JSGlobalObject>*>(jsObject)->getPrivate();
if (jsObject->inherits(&JSCallbackObject<JSDestructibleObject>::s_info))
return jsCast<JSCallbackObject<JSDestructibleObject>*>(jsObject)->getPrivate();
if (jsObject->inherits(&JSCallbackObject<JSAPIWrapperObject>::s_info))
return jsCast<JSCallbackObject<JSAPIWrapperObject>*>(jsObject)->getPrivate();
return 0;
}
......@@ -361,6 +364,10 @@ bool JSObjectSetPrivate(JSObjectRef object, void* data)
jsCast<JSCallbackObject<JSDestructibleObject>*>(jsObject)->setPrivate(data);
return true;
}
if (jsObject->inherits(&JSCallbackObject<JSAPIWrapperObject>::s_info)) {
jsCast<JSCallbackObject<JSAPIWrapperObject>*>(jsObject)->setPrivate(data);
return true;
}
return false;
}
......@@ -376,6 +383,8 @@ JSValueRef JSObjectGetPrivateProperty(JSContextRef ctx, JSObjectRef object, JSSt
result = jsCast<JSCallbackObject<JSGlobalObject>*>(jsObject)->getPrivateProperty(name);
else if (jsObject->inherits(&JSCallbackObject<JSDestructibleObject>::s_info))
result = jsCast<JSCallbackObject<JSDestructibleObject>*>(jsObject)->getPrivateProperty(name);
else if (jsObject->inherits(&JSCallbackObject<JSAPIWrapperObject>::s_info))
result = jsCast<JSCallbackObject<JSAPIWrapperObject>*>(jsObject)->getPrivateProperty(name);
return toRef(exec, result);
}
......@@ -394,6 +403,10 @@ bool JSObjectSetPrivateProperty(JSContextRef ctx, JSObjectRef object, JSStringRe
jsCast<JSCallbackObject<JSDestructibleObject>*>(jsObject)->setPrivateProperty(exec->globalData(), name, jsValue);
return true;
}
if (jsObject->inherits(&JSCallbackObject<JSAPIWrapperObject>::s_info)) {
jsCast<JSCallbackObject<JSAPIWrapperObject>*>(jsObject)->setPrivateProperty(exec->globalData(), name, jsValue);
return true;
}
return false;
}
......@@ -411,6 +424,10 @@ bool JSObjectDeletePrivateProperty(JSContextRef ctx, JSObjectRef object, JSStrin
jsCast<JSCallbackObject<JSDestructibleObject>*>(jsObject)->deletePrivateProperty(name);
return true;
}
if (jsObject->inherits(&JSCallbackObject<JSAPIWrapperObject>::s_info)) {
jsCast<JSCallbackObject<JSAPIWrapperObject>*>(jsObject)->deletePrivateProperty(name);
return true;
}
return false;
}
......
......@@ -892,6 +892,13 @@ static ObjcContainerConvertor::Task objectToValueWithoutCopy(JSContext *context,
JSObjectRef result = JSObjectMakeDate(contextRef, 1, &argument, 0);
return (ObjcContainerConvertor::Task){ object, result, ContainerNone };
}
if ([object isKindOfClass:[JSManagedValue class]]) {
JSValue *value = [static_cast<JSManagedValue *>(object) value];
if (!value)
return (ObjcContainerConvertor::Task) { object, JSValueMakeUndefined(contextRef), ContainerNone };
return (ObjcContainerConvertor::Task){ object, value->m_value, ContainerNone };
}
}
return (ObjcContainerConvertor::Task){ object, valueInternalValue([context wrapperForObjCObject:object]), ContainerNone };
......
......@@ -28,6 +28,7 @@
#include "APICast.h"
#include "APIShims.h"
#include "JSAPIWrapperObject.h"
#include "JSCallbackObject.h"
#include <runtime/JSCJSValue.h>
......@@ -148,6 +149,8 @@ bool JSValueIsObjectOfClass(JSContextRef ctx, JSValueRef value, JSClassRef jsCla
return jsCast<JSCallbackObject<JSGlobalObject>*>(o)->inherits(jsClass);
if (o->inherits(&JSCallbackObject<JSDestructibleObject>::s_info))
return jsCast<JSCallbackObject<JSDestructibleObject>*>(o)->inherits(jsClass);
if (o->inherits(&JSCallbackObject<JSAPIWrapperObject>::s_info))
return jsCast<JSCallbackObject<JSAPIWrapperObject>*>(o)->inherits(jsClass);
}
return false;
}
......
......@@ -101,7 +101,9 @@ static NSMapTable *wrapperCache()
NSPointerFunctionsOptions keyOptions = NSPointerFunctionsOpaqueMemory | NSPointerFunctionsOpaquePersonality;
NSPointerFunctionsOptions valueOptions = NSPointerFunctionsWeakMemory | NSPointerFunctionsObjectPersonality;
m_contextCache = [[NSMapTable alloc] initWithKeyOptions:keyOptions valueOptions:valueOptions capacity:0];
[JSVMWrapperCache addWrapper:self forJSContextGroupRef:group];
return self;
}
......@@ -123,10 +125,8 @@ JSContextGroupRef getGroupFromVirtualMachine(JSVirtualMachine *virtualMachine)
+ (JSVirtualMachine *)virtualMachineWithContextGroupRef:(JSContextGroupRef)group
{
JSVirtualMachine *virtualMachine = [JSVMWrapperCache wrapperForJSContextGroupRef:group];
if (!virtualMachine) {
if (!virtualMachine)
virtualMachine = [[[JSVirtualMachine alloc] initWithContextGroupRef:group] autorelease];
[JSVMWrapperCache addWrapper:virtualMachine forJSContextGroupRef:group];
}
return virtualMachine;
}
......
......@@ -29,6 +29,9 @@
#if JSC_OBJC_API_ENABLED
#import "APICast.h"
#import "APIShims.h"
#import "JSAPIWrapperObject.h"
#import "JSCallbackObject.h"
#import "JSContextInternal.h"
#import "JSWrapperMap.h"
#import "ObjCCallbackFunction.h"
......@@ -48,7 +51,8 @@
static void wrapperFinalize(JSObjectRef object)
{
[(id)JSObjectGetPrivate(object) release];
JSC::JSAPIWrapperObject* wrapperObject = JSC::jsCast<JSC::JSAPIWrapperObject*>(toJS(object));
[(id)wrapperObject->wrappedObject() release];
}
// All wrapper objects and constructor objects derive from this type, so we can detect & unwrap Objective-C instances/Classes.
......@@ -114,17 +118,31 @@ done:
return result;
}
static JSObjectRef makeWrapper(JSContextRef ctx, JSClassRef jsClass, id wrappedObject)
{
JSC::ExecState* exec = toJS(ctx);
JSC::APIEntryShim entryShim(exec);
ASSERT(jsClass);
JSC::JSCallbackObject<JSC::JSAPIWrapperObject>* object = JSC::JSCallbackObject<JSC::JSAPIWrapperObject>::create(exec, exec->lexicalGlobalObject(), exec->lexicalGlobalObject()->objcWrapperObjectStructure(), jsClass, 0);
object->setWrappedObject(wrappedObject);
if (JSC::JSObject* prototype = jsClass->prototype(exec))
object->setPrototype(exec->globalData(), prototype);
return toRef(object);
}
// Make an object that is in all ways a completely vanilla JavaScript object,
// other than that it has a native brand set that will be displayed by the default
// Object.prototype.toString conversion.
static JSValue *createObjectWithCustomBrand(JSContext *context, NSString *brand, JSClassRef parentClass = 0, void* privateData = 0)
static JSValue *createObjectWithCustomBrand(JSContext *context, NSString *brand, JSClassRef parentClass = 0, Class cls = 0)
{
JSClassDefinition definition;
definition = kJSClassDefinitionEmpty;
definition.className = [brand UTF8String];
definition.parentClass = parentClass;
JSClassRef classRef = JSClassCreate(&definition);
JSObjectRef result = JSObjectMake([context globalContextRef], classRef, privateData);
JSObjectRef result = makeWrapper([context globalContextRef], classRef, cls);
JSClassRelease(classRef);
return [[JSValue alloc] initWithValue:result inContext:context];
}
......@@ -407,7 +425,7 @@ static void copyPrototypeProperties(JSContext *context, Class objcClass, Protoco
[self reallocateConstructorAndOrPrototype];
ASSERT(!!m_prototype);
JSObjectRef wrapper = JSObjectMake([m_context globalContextRef], m_classRef, [object retain]);
JSObjectRef wrapper = makeWrapper([m_context globalContextRef], m_classRef, [object retain]);
JSObjectSetPrototype([m_context globalContextRef], wrapper, toRef(m_prototype.get()));
return [JSValue valueWithValue:wrapper inContext:m_context];
}
......@@ -511,7 +529,7 @@ id tryUnwrapObjcObject(JSGlobalContextRef context, JSValueRef value)
JSObjectRef object = JSValueToObject(context, value, &exception);
ASSERT(!exception);
if (JSValueIsObjectOfClass(context, object, wrapperClass()))
return (id)JSObjectGetPrivate(object);
return (id)JSC::jsCast<JSC::JSAPIWrapperObject*>(toJS(object))->wrappedObject();
if (id target = tryUnwrapBlock(context, object))
return target;
return nil;
......
......@@ -33,6 +33,7 @@
#import "JSContext.h"
#import "JSValue.h"
#import "JSManagedValue.h"
#import "JSVirtualMachine.h"
#import "JSExport.h"
......
......@@ -23,7 +23,9 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "JavaScriptCore.h"
#import <JavaScriptCore/JavaScriptCore.h>
void JSSynchronousGarbageCollectForDebugging(JSContextRef);