Objective-C API: Need a good way to reference event handlers without causing cycles
authormhahnenberg@apple.com <mhahnenberg@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 7 Mar 2013 20:43:05 +0000 (20:43 +0000)
committermhahnenberg@apple.com <mhahnenberg@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 7 Mar 2013 20:43:05 +0000 (20:43 +0000)
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: https://svn.webkit.org/repository/webkit/trunk@145119 268f45cc-cd09-0410-ab3c-d52691b4dbfc

24 files changed:
Source/JavaScriptCore/API/JSAPIWrapperObject.cpp [new file with mode: 0644]
Source/JavaScriptCore/API/JSAPIWrapperObject.h [new file with mode: 0644]
Source/JavaScriptCore/API/JSBase.cpp
Source/JavaScriptCore/API/JSCallbackObject.cpp
Source/JavaScriptCore/API/JSCallbackObject.h
Source/JavaScriptCore/API/JSContext.mm
Source/JavaScriptCore/API/JSManagedValue.h [new file with mode: 0644]
Source/JavaScriptCore/API/JSManagedValue.mm [new file with mode: 0644]
Source/JavaScriptCore/API/JSObjectRef.cpp
Source/JavaScriptCore/API/JSValue.mm
Source/JavaScriptCore/API/JSValueRef.cpp
Source/JavaScriptCore/API/JSVirtualMachine.mm
Source/JavaScriptCore/API/JSWrapperMap.mm
Source/JavaScriptCore/API/JavaScriptCore.h
Source/JavaScriptCore/API/tests/testapi.mm
Source/JavaScriptCore/CMakeLists.txt
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/GNUmakefile.list.am
Source/JavaScriptCore/JavaScriptCore.gypi
Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj
Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
Source/JavaScriptCore/Target.pri
Source/JavaScriptCore/runtime/JSGlobalObject.cpp
Source/JavaScriptCore/runtime/JSGlobalObject.h

diff --git a/Source/JavaScriptCore/API/JSAPIWrapperObject.cpp b/Source/JavaScriptCore/API/JSAPIWrapperObject.cpp
new file mode 100644 (file)
index 0000000..86fdd11
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * 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
diff --git a/Source/JavaScriptCore/API/JSAPIWrapperObject.h b/Source/JavaScriptCore/API/JSAPIWrapperObject.h
new file mode 100644 (file)
index 0000000..2b92554
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * 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
index d9886f2..f411eb4 100644 (file)
@@ -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();
+}
index e8c2975..9cb815a 100644 (file)
@@ -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);
index 3acf2ef..795bde8 100644 (file)
@@ -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();
index 2512cd3..83397da 100644 (file)
@@ -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;
 }
 
         context.exception = exceptionValue;
     };
 
+    [m_virtualMachine addContext:self forGlobalContextRef:m_context];
+
     return self;
 }
 
 {
     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;
 }
 
diff --git a/Source/JavaScriptCore/API/JSManagedValue.h b/Source/JavaScriptCore/API/JSManagedValue.h
new file mode 100644 (file)
index 0000000..389e113
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * 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
diff --git a/Source/JavaScriptCore/API/JSManagedValue.mm b/Source/JavaScriptCore/API/JSManagedValue.mm
new file mode 100644 (file)
index 0000000..d9f6310
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * 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
index 13b8933..112915e 100644 (file)
@@ -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;
 }
 
index 6958f68..3354935 100644 (file)
@@ -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 };
index 73b517d..db9e004 100644 (file)
@@ -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;
 }
index 37f8c5c..5688815 100644 (file)
@@ -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;
 }
 
index abde97c..bf8af0a 100644 (file)
@@ -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;
index d19cae2..40bea9c 100644 (file)
@@ -33,6 +33,7 @@
 
 #import "JSContext.h"
 #import "JSValue.h"
+#import "JSManagedValue.h"
 #import "JSVirtualMachine.h"
 #import "JSExport.h"
 
index e064a4c..018a06f 100644 (file)
@@ -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);
 
 extern "C" bool _Block_has_signature(id);
 extern "C" const char * _Block_signature(id);
@@ -101,6 +103,8 @@ bool testXYZTested = false;
 @protocol TextXYZ <JSExport>
 @property int x;
 @property (readonly) int y;
+@property JSValue *onclick;
+@property JSValue *weakOnclick;
 - (void)test:(NSString *)message;
 @end
 
@@ -108,9 +112,13 @@ bool testXYZTested = false;
 @property int x;
 @property int y;
 @property int z;
+- (void)click;
 @end
 
-@implementation TextXYZ
+@implementation TextXYZ {
+    JSManagedValue *m_weakOnclickHandler;
+    JSManagedValue *m_onclickHandler;
+}
 @synthesize x;
 @synthesize y;
 @synthesize z;
@@ -118,6 +126,31 @@ bool testXYZTested = false;
 {
     testXYZTested = [message isEqual:@"test"] && x == 13 & y == 4 && z == 5;
 }
+- (void)setWeakOnclick:(JSValue *)value
+{
+    m_weakOnclickHandler = [JSManagedValue managedValueWithValue:value];
+}
+
+- (void)setOnclick:(JSValue *)value
+{
+    m_onclickHandler = [JSManagedValue managedValueWithValue:value owner:self];
+}
+- (JSValue *)weakOnclick
+{
+    return [m_weakOnclickHandler value];
+}
+- (JSValue *)onclick
+{
+    return [m_onclickHandler value];
+}
+- (void)click
+{
+    if (!m_onclickHandler)
+        return;
+
+    JSValue *function = [m_onclickHandler value];
+    [function callWithArguments:[NSArray array]];
+}
 @end
 
 static void checkResult(NSString *description, bool passed)
@@ -493,6 +526,60 @@ void testObjectiveCAPI()
         JSValue *result = [context1 evaluateScript:@"passValueBetweenContexts"];
         checkResult(@"[value isEqualToObject:result]", [value isEqualToObject:result]);
     }
+
+    @autoreleasepool {
+        JSContext *context = [[JSContext alloc] init];
+        TextXYZ *testXYZ = [[TextXYZ alloc] init];
+
+        @autoreleasepool {
+            context[@"testXYZ"] = testXYZ;
+
+            [context evaluateScript:@" \
+                didClick = false; \
+                testXYZ.onclick = function() { \
+                    didClick = true; \
+                }; \
+                 \
+                testXYZ.weakOnclick = function() { \
+                    return 'foo'; \
+                }; \
+            "];
+        }
+
+        @autoreleasepool {
+            [testXYZ click];
+            JSValue *result = [context evaluateScript:@"didClick"];
+            checkResult(@"Event handler onclick", [result toBool]);
+        }
+
+        JSSynchronousGarbageCollectForDebugging([context globalContextRef]);
+
+        @autoreleasepool {
+            JSValue *result = [context evaluateScript:@"testXYZ.onclick"];
+            checkResult(@"onclick still around after GC", !([result isNull] || [result isUndefined]));
+        }
+
+
+        @autoreleasepool {
+            JSValue *result = [context evaluateScript:@"testXYZ.weakOnclick"];
+            checkResult(@"weakOnclick not around after GC", [result isNull] || [result isUndefined]);
+        }
+
+        @autoreleasepool {
+            [context evaluateScript:@" \
+                didClick = false; \
+                testXYZ = null; \
+            "];
+        }
+
+        JSSynchronousGarbageCollectForDebugging([context globalContextRef]);
+
+        @autoreleasepool {
+            [testXYZ click];
+            JSValue *result = [context evaluateScript:@"didClick"];
+            checkResult(@"Event handler onclick doesn't fire", ![result toBool]);
+        }
+    }
 }
 
 #else
index b4cebbf..b573ce1 100644 (file)
@@ -24,6 +24,7 @@ set(JavaScriptCore_INCLUDE_DIRECTORIES
 )
 
 set(JavaScriptCore_SOURCES
+    API/JSAPIWrapperObject.cpp
     API/JSBase.cpp
     API/JSCallbackConstructor.cpp
     API/JSCallbackFunction.cpp
index 1315edf..d1b99d8 100644 (file)
@@ -1,3 +1,105 @@
+2013-03-05  Mark Hahnenberg  <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):
+
 2013-03-06  Filip Pizlo  <fpizlo@apple.com>
 
         ConvertThis should be turned into Identity based on predictions in Fixup, rather than based on proofs in ConstantFolding
index 4fe334b..08f0cf9 100644 (file)
@@ -36,6 +36,8 @@ javascriptcore_built_nosources += \
 javascriptcore_sources += \
        Source/JavaScriptCore/API/APICast.h \
        Source/JavaScriptCore/API/APIShims.h \
+    Source/JavaScriptCore/API/JSAPIWrapperObject.cpp \
+    Source/JavaScriptCore/API/JSAPIWrapperObject.h \
        Source/JavaScriptCore/API/JSBase.cpp \
        Source/JavaScriptCore/API/JSBasePrivate.h \
        Source/JavaScriptCore/API/JSCallbackConstructor.cpp \
index c27e7d6..274a624 100644 (file)
@@ -36,6 +36,8 @@
             'API/APIShims.h',
             'API/JavaScriptCore.h',
             'API/JavaScript.h',
+            'API/JSAPIWrapperObject.cpp',
+            'API/JSAPIWrapperObject.h',
             'API/JSBase.cpp',
             'API/JSBase.h',
             'API/JSBasePrivate.h',
index 560fb28..435ff0e 100644 (file)
                                >
                        </File>
                        <File
+                               RelativePath="..\..\API\JSAPIWrapperObject.cpp"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\API\JSAPIWrapperObject.h"
+                               >
+                       </File>
+                       <File
                                RelativePath="..\..\API\JSBase.cpp"
                                >
                        </File>
index b221609..b8ef06c 100644 (file)
                C240305514B404E60079EB64 /* CopiedSpace.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C240305314B404C90079EB64 /* CopiedSpace.cpp */; };
                C24D31E2161CD695002AA4DB /* HeapStatistics.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C24D31E0161CD695002AA4DB /* HeapStatistics.cpp */; };
                C24D31E3161CD695002AA4DB /* HeapStatistics.h in Headers */ = {isa = PBXBuildFile; fileRef = C24D31E1161CD695002AA4DB /* HeapStatistics.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               C25D709B16DE99F400FCA6BC /* JSManagedValue.mm in Sources */ = {isa = PBXBuildFile; fileRef = C25D709916DE99F400FCA6BC /* JSManagedValue.mm */; };
+               C25D709C16DE99F400FCA6BC /* JSManagedValue.h in Headers */ = {isa = PBXBuildFile; fileRef = C25D709A16DE99F400FCA6BC /* JSManagedValue.h */; settings = {ATTRIBUTES = (Public, ); }; };
                C25F8BCD157544A900245B71 /* IncrementalSweeper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C25F8BCB157544A900245B71 /* IncrementalSweeper.cpp */; };
                C25F8BCE157544A900245B71 /* IncrementalSweeper.h in Headers */ = {isa = PBXBuildFile; fileRef = C25F8BCC157544A900245B71 /* IncrementalSweeper.h */; settings = {ATTRIBUTES = (Private, ); }; };
                C2A7F688160432D400F76B98 /* JSDestructibleObject.h in Headers */ = {isa = PBXBuildFile; fileRef = C2A7F687160432D400F76B98 /* JSDestructibleObject.h */; settings = {ATTRIBUTES = (Private, ); }; };
                C2C8D02D14A3C6E000578E65 /* CopiedSpaceInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = C2C8D02B14A3C6B200578E65 /* CopiedSpaceInlines.h */; settings = {ATTRIBUTES = (Private, ); }; };
                C2C8D03014A3CEFC00578E65 /* CopiedBlock.h in Headers */ = {isa = PBXBuildFile; fileRef = C2C8D02E14A3CEFC00578E65 /* CopiedBlock.h */; settings = {ATTRIBUTES = (Private, ); }; };
                C2C8D03114A3CEFC00578E65 /* HeapBlock.h in Headers */ = {isa = PBXBuildFile; fileRef = C2C8D02F14A3CEFC00578E65 /* HeapBlock.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               C2CF39C116E15A8100DD69BE /* JSAPIWrapperObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2CF39BF16E15A8100DD69BE /* JSAPIWrapperObject.cpp */; };
+               C2CF39C216E15A8100DD69BE /* JSAPIWrapperObject.h in Headers */ = {isa = PBXBuildFile; fileRef = C2CF39C016E15A8100DD69BE /* JSAPIWrapperObject.h */; };
                C2D58C3415912FEE0021A844 /* GCActivityCallback.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2D58C3315912FEE0021A844 /* GCActivityCallback.cpp */; };
                C2E526BD1590EF000054E48D /* HeapTimer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2E526BB1590EF000054E48D /* HeapTimer.cpp */; };
                C2E526BE1590EF000054E48D /* HeapTimer.h in Headers */ = {isa = PBXBuildFile; fileRef = C2E526BC1590EF000054E48D /* HeapTimer.h */; settings = {ATTRIBUTES = (Private, ); }; };
                C240305314B404C90079EB64 /* CopiedSpace.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CopiedSpace.cpp; sourceTree = "<group>"; };
                C24D31E0161CD695002AA4DB /* HeapStatistics.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = HeapStatistics.cpp; sourceTree = "<group>"; };
                C24D31E1161CD695002AA4DB /* HeapStatistics.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HeapStatistics.h; sourceTree = "<group>"; };
+               C25D709916DE99F400FCA6BC /* JSManagedValue.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = JSManagedValue.mm; sourceTree = "<group>"; };
+               C25D709A16DE99F400FCA6BC /* JSManagedValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSManagedValue.h; sourceTree = "<group>"; };
                C25F8BCB157544A900245B71 /* IncrementalSweeper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IncrementalSweeper.cpp; sourceTree = "<group>"; };
                C25F8BCC157544A900245B71 /* IncrementalSweeper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IncrementalSweeper.h; sourceTree = "<group>"; };
                C2A7F687160432D400F76B98 /* JSDestructibleObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSDestructibleObject.h; sourceTree = "<group>"; };
                C2C8D02B14A3C6B200578E65 /* CopiedSpaceInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CopiedSpaceInlines.h; sourceTree = "<group>"; };
                C2C8D02E14A3CEFC00578E65 /* CopiedBlock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CopiedBlock.h; sourceTree = "<group>"; };
                C2C8D02F14A3CEFC00578E65 /* HeapBlock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HeapBlock.h; sourceTree = "<group>"; };
+               C2CF39BF16E15A8100DD69BE /* JSAPIWrapperObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSAPIWrapperObject.cpp; sourceTree = "<group>"; };
+               C2CF39C016E15A8100DD69BE /* JSAPIWrapperObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSAPIWrapperObject.h; sourceTree = "<group>"; };
                C2D58C3315912FEE0021A844 /* GCActivityCallback.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GCActivityCallback.cpp; sourceTree = "<group>"; };
                C2E526BB1590EF000054E48D /* HeapTimer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = HeapTimer.cpp; sourceTree = "<group>"; };
                C2E526BC1590EF000054E48D /* HeapTimer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HeapTimer.h; sourceTree = "<group>"; };
                                E124A8F60E555775003091F1 /* OpaqueJSString.cpp */,
                                E124A8F50E555775003091F1 /* OpaqueJSString.h */,
                                5DE3D0F40DD8DDFB00468714 /* WebKitAvailability.h */,
+                               C25D709916DE99F400FCA6BC /* JSManagedValue.mm */,
+                               C25D709A16DE99F400FCA6BC /* JSManagedValue.h */,
+                               C2CF39BF16E15A8100DD69BE /* JSAPIWrapperObject.cpp */,
+                               C2CF39C016E15A8100DD69BE /* JSAPIWrapperObject.h */,
                        );
                        path = API;
                        sourceTree = "<group>";
                        isa = PBXHeadersBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
+                               C25D709C16DE99F400FCA6BC /* JSManagedValue.h in Headers */,
                                860161E30F3A83C100F84710 /* AbstractMacroAssembler.h in Headers */,
                                0F55F0F514D1063C00AC7649 /* AbstractPC.h in Headers */,
                                BC18C3E50E16F5CD00B34460 /* APICast.h in Headers */,
                                BC18C42D0E16F5CD00B34460 /* JSVariableObject.h in Headers */,
                                86E3C615167BABD7006D760A /* JSVirtualMachine.h in Headers */,
                                A7482E93116A7CAD003B0712 /* JSWeakObjectMapRefInternal.h in Headers */,
+                               C2CF39C216E15A8100DD69BE /* JSAPIWrapperObject.h in Headers */,
                                A7482B9311671147003B0712 /* JSWeakObjectMapRefPrivate.h in Headers */,
                                1442566215EDE98D0066A49B /* JSWithScope.h in Headers */,
                                86E3C619167BABEE006D760A /* JSWrapperMap.h in Headers */,
                                0FD3C82614115D4000FD81CB /* DFGDriver.cpp in Sources */,
                                0FF0F19E16B72A0B005DF95B /* DFGEdge.cpp in Sources */,
                                0FBC0AE71496C7C400D4FBDD /* DFGExitProfile.cpp in Sources */,
+                               C2CF39C116E15A8100DD69BE /* JSAPIWrapperObject.cpp in Sources */,
                                0F2BDC15151C5D4D00CD8910 /* DFGFixupPhase.cpp in Sources */,
                                86EC9DC71328DF82002B2AD7 /* DFGGraph.cpp in Sources */,
                                86EC9DCB1328DF82002B2AD7 /* DFGJITCompiler.cpp in Sources */,
                                BCCF0D0C0EF0B8A500413C8F /* StructureStubInfo.cpp in Sources */,
                                0F919D2815856773004A4E7D /* SymbolTable.cpp in Sources */,
                                A7386555118697B400540279 /* ThunkGenerators.cpp in Sources */,
+                               C25D709B16DE99F400FCA6BC /* JSManagedValue.mm in Sources */,
                                14A42E3F0F4F60EE00599099 /* TimeoutChecker.cpp in Sources */,
                                0FF4274A158EBE91004CB9FF /* udis86.c in Sources */,
                                0FF42740158EBE8B004CB9FF /* udis86_decode.c in Sources */,
index 44ce273..8fefc65 100644 (file)
@@ -33,6 +33,7 @@ INSTALLDEPS += all
 debug_and_release: INCLUDEPATH += $$JAVASCRIPTCORE_GENERATED_SOURCES_DIR/$$targetSubDir()
 
 SOURCES += \
+    API/JSAPIWrapperObject.cpp \
     API/JSBase.cpp \
     API/JSCallbackConstructor.cpp \
     API/JSCallbackFunction.cpp \
index c0e154e..ca5ae13 100644 (file)
@@ -47,6 +47,7 @@
 #include "FunctionPrototype.h"
 #include "GetterSetter.h"
 #include "Interpreter.h"
+#include "JSAPIWrapperObject.h"
 #include "JSActivation.h"
 #include "JSBoundFunction.h"
 #include "JSCallbackConstructor.h"
@@ -229,6 +230,7 @@ void JSGlobalObject::reset(JSValue prototype)
     m_argumentsStructure.set(exec->globalData(), this, Arguments::createStructure(exec->globalData(), this, m_objectPrototype.get()));
     m_callbackConstructorStructure.set(exec->globalData(), this, JSCallbackConstructor::createStructure(exec->globalData(), this, m_objectPrototype.get()));
     m_callbackObjectStructure.set(exec->globalData(), this, JSCallbackObject<JSDestructibleObject>::createStructure(exec->globalData(), this, m_objectPrototype.get()));
+    m_objcWrapperObjectStructure.set(exec->globalData(), this, JSCallbackObject<JSAPIWrapperObject>::createStructure(exec->globalData(), this, m_objectPrototype.get()));
 
     m_arrayPrototype.set(exec->globalData(), this, ArrayPrototype::create(exec, this, ArrayPrototype::createStructure(exec->globalData(), this, m_objectPrototype.get())));
     
@@ -511,6 +513,7 @@ void JSGlobalObject::visitChildren(JSCell* cell, SlotVisitor& visitor)
     visitor.append(&thisObject->m_callbackConstructorStructure);
     visitor.append(&thisObject->m_callbackFunctionStructure);
     visitor.append(&thisObject->m_callbackObjectStructure);
+    visitor.append(&thisObject->m_objcWrapperObjectStructure);
     visitor.append(&thisObject->m_dateStructure);
     visitor.append(&thisObject->m_nullPrototypeObjectStructure);
     visitor.append(&thisObject->m_errorStructure);
index e5250a3..5888b74 100644 (file)
@@ -141,6 +141,7 @@ protected:
     WriteBarrier<Structure> m_callbackConstructorStructure;
     WriteBarrier<Structure> m_callbackFunctionStructure;
     WriteBarrier<Structure> m_callbackObjectStructure;
+    WriteBarrier<Structure> m_objcWrapperObjectStructure;
     WriteBarrier<Structure> m_dateStructure;
     WriteBarrier<Structure> m_nullPrototypeObjectStructure;
     WriteBarrier<Structure> m_errorStructure;
@@ -300,6 +301,7 @@ public:
     Structure* callbackConstructorStructure() const { return m_callbackConstructorStructure.get(); }
     Structure* callbackFunctionStructure() const { return m_callbackFunctionStructure.get(); }
     Structure* callbackObjectStructure() const { return m_callbackObjectStructure.get(); }
+    Structure* objcWrapperObjectStructure() const { return m_objcWrapperObjectStructure.get(); }
     Structure* dateStructure() const { return m_dateStructure.get(); }
     Structure* nullPrototypeObjectStructure() const { return m_nullPrototypeObjectStructure.get(); }
     Structure* errorStructure() const { return m_errorStructure.get(); }