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

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) ...@@ -110,3 +110,15 @@ void JSReportExtraMemoryCost(JSContextRef ctx, size_t size)
APIEntryShim entryShim(exec); APIEntryShim entryShim(exec);
exec->globalData().heap.reportExtraMemoryCost(size); 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 ...@@ -61,12 +61,6 @@ Structure* JSCallbackObject<JSGlobalObject>::createStructure(JSGlobalData& globa
return Structure::create(globalData, globalObject, proto, TypeInfo(GlobalObjectType, StructureFlags), &s_info); 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) void JSCallbackObjectData::finalize(Handle<Unknown> handle, void* context)
{ {
JSClassRef jsClass = static_cast<JSClassRef>(context); JSClassRef jsClass = static_cast<JSClassRef>(context);
......
...@@ -136,7 +136,10 @@ public: ...@@ -136,7 +136,10 @@ public:
static JSCallbackObject<Parent>* create(JSGlobalData&, JSClassRef, Structure*); static JSCallbackObject<Parent>* create(JSGlobalData&, JSClassRef, Structure*);
static const bool needsDestruction; static const bool needsDestruction;
static void destroy(JSCell*); static void destroy(JSCell* cell)
{
static_cast<JSCallbackObject*>(cell)->JSCallbackObject::~JSCallbackObject();
}
void setPrivate(void* data); void setPrivate(void* data);
void* getPrivate(); void* getPrivate();
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include "config.h" #include "config.h"
#import "APICast.h" #import "APICast.h"
#import "APIShims.h"
#import "JSContextInternal.h" #import "JSContextInternal.h"
#import "JSGlobalObject.h" #import "JSGlobalObject.h"
#import "JSValueInternal.h" #import "JSValueInternal.h"
...@@ -72,6 +73,8 @@ ...@@ -72,6 +73,8 @@
context.exception = exceptionValue; context.exception = exceptionValue;
}; };
[m_virtualMachine addContext:self forGlobalContextRef:m_context];
return self; return self;
} }
...@@ -187,6 +190,8 @@ ...@@ -187,6 +190,8 @@
context.exception = exceptionValue; context.exception = exceptionValue;
}; };
[m_virtualMachine addContext:self forGlobalContextRef:m_context];
return self; return self;
} }
...@@ -254,10 +259,8 @@ ...@@ -254,10 +259,8 @@
{ {
JSVirtualMachine *virtualMachine = [JSVirtualMachine virtualMachineWithContextGroupRef:toRef(&toJS(globalContext)->globalData())]; JSVirtualMachine *virtualMachine = [JSVirtualMachine virtualMachineWithContextGroupRef:toRef(&toJS(globalContext)->globalData())];
JSContext *context = [virtualMachine contextForGlobalContextRef:globalContext]; JSContext *context = [virtualMachine contextForGlobalContextRef:globalContext];
if (!context) { if (!context)
context = [[[JSContext alloc] initWithGlobalContextRef:globalContext] autorelease]; context = [[[JSContext alloc] initWithGlobalContextRef:globalContext] autorelease];
[virtualMachine addContext:context forGlobalContextRef:globalContext];
}
return context; 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 @@ ...@@ -37,6 +37,7 @@
#include "FunctionConstructor.h" #include "FunctionConstructor.h"
#include "Identifier.h" #include "Identifier.h"
#include "InitializeThreading.h" #include "InitializeThreading.h"
#include "JSAPIWrapperObject.h"
#include "JSArray.h" #include "JSArray.h"
#include "JSCallbackConstructor.h" #include "JSCallbackConstructor.h"
#include "JSCallbackFunction.h" #include "JSCallbackFunction.h"
...@@ -345,6 +346,8 @@ void* JSObjectGetPrivate(JSObjectRef object) ...@@ -345,6 +346,8 @@ void* JSObjectGetPrivate(JSObjectRef object)
return jsCast<JSCallbackObject<JSGlobalObject>*>(jsObject)->getPrivate(); return jsCast<JSCallbackObject<JSGlobalObject>*>(jsObject)->getPrivate();
if (jsObject->inherits(&JSCallbackObject<JSDestructibleObject>::s_info)) if (jsObject->inherits(&JSCallbackObject<JSDestructibleObject>::s_info))
return jsCast<JSCallbackObject<JSDestructibleObject>*>(jsObject)->getPrivate(); return jsCast<JSCallbackObject<JSDestructibleObject>*>(jsObject)->getPrivate();
if (jsObject->inherits(&JSCallbackObject<JSAPIWrapperObject>::s_info))
return jsCast<JSCallbackObject<JSAPIWrapperObject>*>(jsObject)->getPrivate();
return 0; return 0;
} }
...@@ -361,6 +364,10 @@ bool JSObjectSetPrivate(JSObjectRef object, void* data) ...@@ -361,6 +364,10 @@ bool JSObjectSetPrivate(JSObjectRef object, void* data)
jsCast<JSCallbackObject<JSDestructibleObject>*>(jsObject)->setPrivate(data); jsCast<JSCallbackObject<JSDestructibleObject>*>(jsObject)->setPrivate(data);
return true; return true;
} }
if (jsObject->inherits(&JSCallbackObject<JSAPIWrapperObject>::s_info)) {
jsCast<JSCallbackObject<JSAPIWrapperObject>*>(jsObject)->setPrivate(data);
return true;
}
return false; return false;
} }
...@@ -376,6 +383,8 @@ JSValueRef JSObjectGetPrivateProperty(JSContextRef ctx, JSObjectRef object, JSSt ...@@ -376,6 +383,8 @@ JSValueRef JSObjectGetPrivateProperty(JSContextRef ctx, JSObjectRef object, JSSt
result = jsCast<JSCallbackObject<JSGlobalObject>*>(jsObject)->getPrivateProperty(name); result = jsCast<JSCallbackObject<JSGlobalObject>*>(jsObject)->getPrivateProperty(name);
else if (jsObject->inherits(&JSCallbackObject<JSDestructibleObject>::s_info)) else if (jsObject->inherits(&JSCallbackObject<JSDestructibleObject>::s_info))
result = jsCast<JSCallbackObject<JSDestructibleObject>*>(jsObject)->getPrivateProperty(name); 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); return toRef(exec, result);
} }
...@@ -394,6 +403,10 @@ bool JSObjectSetPrivateProperty(JSContextRef ctx, JSObjectRef object, JSStringRe ...@@ -394,6 +403,10 @@ bool JSObjectSetPrivateProperty(JSContextRef ctx, JSObjectRef object, JSStringRe
jsCast<JSCallbackObject<JSDestructibleObject>*>(jsObject)->setPrivateProperty(exec->globalData(), name, jsValue); jsCast<JSCallbackObject<JSDestructibleObject>*>(jsObject)->setPrivateProperty(exec->globalData(), name, jsValue);
return true; return true;
} }
if (jsObject->inherits(&JSCallbackObject<JSAPIWrapperObject>::s_info)) {
jsCast<JSCallbackObject<JSAPIWrapperObject>*>(jsObject)->setPrivateProperty(exec->globalData(), name, jsValue);
return true;
}
return false; return false;
} }
...@@ -411,6 +424,10 @@ bool JSObjectDeletePrivateProperty(JSContextRef ctx, JSObjectRef object, JSStrin ...@@ -411,6 +424,10 @@ bool JSObjectDeletePrivateProperty(JSContextRef ctx, JSObjectRef object, JSStrin
jsCast<JSCallbackObject<JSDestructibleObject>*>(jsObject)->deletePrivateProperty(name); jsCast<JSCallbackObject<JSDestructibleObject>*>(jsObject)->deletePrivateProperty(name);
return true; return true;
} }
if (jsObject->inherits(&JSCallbackObject<JSAPIWrapperObject>::s_info)) {
jsCast<JSCallbackObject<JSAPIWrapperObject>*>(jsObject)->deletePrivateProperty(name);
return true;
}
return false; return false;
} }
......
...@@ -892,6 +892,13 @@ static ObjcContainerConvertor::Task objectToValueWithoutCopy(JSContext *context, ...@@ -892,6 +892,13 @@ static ObjcContainerConvertor::Task objectToValueWithoutCopy(JSContext *context,
JSObjectRef result = JSObjectMakeDate(contextRef, 1, &argument, 0); JSObjectRef result = JSObjectMakeDate(contextRef, 1, &argument, 0);
return (ObjcContainerConvertor::Task){ object, result, ContainerNone }; 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 }; return (ObjcContainerConvertor::Task){ object, valueInternalValue([context wrapperForObjCObject:object]), ContainerNone };
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include "APICast.h" #include "APICast.h"
#include "APIShims.h" #include "APIShims.h"
#include "JSAPIWrapperObject.h"
#include "JSCallbackObject.h" #include "JSCallbackObject.h"
#include <runtime/JSCJSValue.h> #include <runtime/JSCJSValue.h>
...@@ -148,6 +149,8 @@ bool JSValueIsObjectOfClass(JSContextRef ctx, JSValueRef value, JSClassRef jsCla ...@@ -148,6 +149,8 @@ bool JSValueIsObjectOfClass(JSContextRef ctx, JSValueRef value, JSClassRef jsCla
return jsCast<JSCallbackObject<JSGlobalObject>*>(o)->inherits(jsClass); return jsCast<JSCallbackObject<JSGlobalObject>*>(o)->inherits(jsClass);
if (o->inherits(&JSCallbackObject<JSDestructibleObject>::s_info)) if (o->inherits(&JSCallbackObject<JSDestructibleObject>::s_info))
return jsCast<JSCallbackObject<JSDestructibleObject>*>(o)->inherits(jsClass); return jsCast<JSCallbackObject<JSDestructibleObject>*>(o)->inherits(jsClass);
if (o->inherits(&JSCallbackObject<JSAPIWrapperObject>::s_info))
return jsCast<JSCallbackObject<JSAPIWrapperObject>*>(o)->inherits(jsClass);
} }
return false; return false;
} }
......
...@@ -101,7 +101,9 @@ static NSMapTable *wrapperCache() ...@@ -101,7 +101,9 @@ static NSMapTable *wrapperCache()
NSPointerFunctionsOptions keyOptions = NSPointerFunctionsOpaqueMemory | NSPointerFunctionsOpaquePersonality; NSPointerFunctionsOptions keyOptions = NSPointerFunctionsOpaqueMemory | NSPointerFunctionsOpaquePersonality;
NSPointerFunctionsOptions valueOptions = NSPointerFunctionsWeakMemory | NSPointerFunctionsObjectPersonality; NSPointerFunctionsOptions valueOptions = NSPointerFunctionsWeakMemory | NSPointerFunctionsObjectPersonality;
m_contextCache = [[NSMapTable alloc] initWithKeyOptions:keyOptions valueOptions:valueOptions capacity:0]; m_contextCache = [[NSMapTable alloc] initWithKeyOptions:keyOptions valueOptions:valueOptions capacity:0];
[JSVMWrapperCache addWrapper:self forJSContextGroupRef:group];
return self; return self;
} }
...@@ -123,10 +125,8 @@ JSContextGroupRef getGroupFromVirtualMachine(JSVirtualMachine *virtualMachine) ...@@ -123,10 +125,8 @@ JSContextGroupRef getGroupFromVirtualMachine(JSVirtualMachine *virtualMachine)
+ (JSVirtualMachine *)virtualMachineWithContextGroupRef:(JSContextGroupRef)group + (JSVirtualMachine *)virtualMachineWithContextGroupRef:(JSContextGroupRef)group
{ {
JSVirtualMachine *virtualMachine = [JSVMWrapperCache wrapperForJSContextGroupRef:group]; JSVirtualMachine *virtualMachine = [JSVMWrapperCache wrapperForJSContextGroupRef:group];
if (!virtualMachine) { if (!virtualMachine)
virtualMachine = [[[JSVirtualMachine alloc] initWithContextGroupRef:group] autorelease]; virtualMachine = [[[JSVirtualMachine alloc] initWithContextGroupRef:group] autorelease];
[JSVMWrapperCache addWrapper:virtualMachine forJSContextGroupRef:group];
}
return virtualMachine; return virtualMachine;
} }
......
...@@ -29,6 +29,9 @@ ...@@ -29,6 +29,9 @@
#if JSC_OBJC_API_ENABLED #if JSC_OBJC_API_ENABLED
#import "APICast.h" #import "APICast.h"
#import "APIShims.h"
#import "JSAPIWrapperObject.h"
#import "JSCallbackObject.h"
#import "JSContextInternal.h" #import "JSContextInternal.h"
#import "JSWrapperMap.h" #import "JSWrapperMap.h"
#import "ObjCCallbackFunction.h" #import "ObjCCallbackFunction.h"
...@@ -48,7 +51,8 @@ ...@@ -48,7 +51,8 @@
static void wrapperFinalize(JSObjectRef object) 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. // All wrapper objects and constructor objects derive from this type, so we can detect & unwrap Objective-C instances/Classes.
...@@ -114,17 +118,31 @@ done: ...@@ -114,17 +118,31 @@ done: