]> git.saurik.com Git - apple/javascriptcore.git/blobdiff - API/JSManagedValue.mm
JavaScriptCore-7601.1.46.3.tar.gz
[apple/javascriptcore.git] / API / JSManagedValue.mm
index 0a01f22ba3c53df3cbb492a53aa6acbc90d8b4ed..a72d19b1bfb099b16ed90ace1a133a1b8383a156 100644 (file)
 
 #import "APICast.h"
 #import "Heap.h"
-#import "JSCJSValueInlines.h"
 #import "JSContextInternal.h"
 #import "JSValueInternal.h"
 #import "Weak.h"
 #import "WeakHandleOwner.h"
 #import "ObjcRuntimeExtras.h"
+#import "JSCInlines.h"
+#import <wtf/spi/cocoa/NSMapTableSPI.h>
 
 class JSManagedValueHandleOwner : public JSC::WeakHandleOwner {
 public:
-    virtual void finalize(JSC::Handle<JSC::Unknown>, void* context);
-    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&);
+    virtual void finalize(JSC::Handle<JSC::Unknown>, void* context) override;
+    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&) override;
 };
 
 static JSManagedValueHandleOwner* managedValueHandleOwner()
 {
-    DEFINE_STATIC_LOCAL(JSManagedValueHandleOwner, jsManagedValueHandleOwner, ());
+    DEPRECATED_DEFINE_STATIC_LOCAL(JSManagedValueHandleOwner, jsManagedValueHandleOwner, ());
     return &jsManagedValueHandleOwner;
 }
 
@@ -168,7 +169,9 @@ private:
 
 @implementation JSManagedValue {
     JSC::Weak<JSC::JSGlobalObject> m_globalObject;
+    RefPtr<JSC::JSLock> m_lock;
     WeakValueRef m_weakValue;
+    NSMapTable *m_owners;
 }
 
 + (JSManagedValue *)managedValueWithValue:(JSValue *)value
@@ -176,12 +179,19 @@ private:
     return [[[self alloc] initWithValue:value] autorelease];
 }
 
-- (id)init
++ (JSManagedValue *)managedValueWithValue:(JSValue *)value andOwner:(id)owner
+{
+    JSManagedValue *managedValue = [[self alloc] initWithValue:value];
+    [value.context.virtualMachine addManagedReference:managedValue withOwner:owner];
+    return [managedValue autorelease];
+}
+
+- (instancetype)init
 {
     return [self initWithValue:nil];
 }
 
-- (id)initWithValue:(JSValue *)value
+- (instancetype)initWithValue:(JSValue *)value
 {
     self = [super init];
     if (!self)
@@ -195,6 +205,12 @@ private:
     JSC::Weak<JSC::JSGlobalObject> weak(globalObject, managedValueHandleOwner(), self);
     m_globalObject.swap(weak);
 
+    m_lock = &exec->vm().apiLock();
+
+    NSPointerFunctionsOptions weakIDOptions = NSPointerFunctionsWeakMemory | NSPointerFunctionsObjectPersonality;
+    NSPointerFunctionsOptions integerOptions = NSPointerFunctionsOpaqueMemory | NSPointerFunctionsIntegerPersonality;
+    m_owners = [[NSMapTable alloc] initWithKeyOptions:weakIDOptions valueOptions:integerOptions capacity:1];
+
     JSC::JSValue jsValue = toJS(exec, [value JSValueRef]);
     if (jsValue.isObject())
         m_weakValue.setObject(JSC::jsCast<JSC::JSObject*>(jsValue.asCell()), self);
@@ -205,8 +221,52 @@ private:
     return self;
 }
 
+- (void)dealloc
+{
+    JSVirtualMachine *virtualMachine = [[[self value] context] virtualMachine];
+    if (virtualMachine) {
+        NSMapTable *copy = [m_owners copy];
+        for (id owner in [copy keyEnumerator]) {
+            size_t count = reinterpret_cast<size_t>(NSMapGet(m_owners, owner));
+            while (count--)
+                [virtualMachine removeManagedReference:self withOwner:owner];
+        }
+        [copy release];
+    }
+
+    [self disconnectValue];
+    [m_owners release];
+    [super dealloc];
+}
+
+- (void)didAddOwner:(id)owner
+{
+    size_t count = reinterpret_cast<size_t>(NSMapGet(m_owners, owner));
+    NSMapInsert(m_owners, owner, reinterpret_cast<void*>(count + 1));
+}
+
+- (void)didRemoveOwner:(id)owner
+{
+    size_t count = reinterpret_cast<size_t>(NSMapGet(m_owners, owner));
+
+    if (!count)
+        return;
+
+    if (count == 1) {
+        NSMapRemove(m_owners, owner);
+        return;
+    }
+
+    NSMapInsert(m_owners, owner, reinterpret_cast<void*>(count - 1));
+}
+
 - (JSValue *)value
 {
+    WTF::Locker<JSC::JSLock> locker(m_lock.get());
+    if (!m_lock->vm())
+        return nil;
+
+    JSC::JSLockHolder apiLocker(m_lock->vm());
     if (!m_globalObject)
         return nil;
     if (m_weakValue.isClear())