]> git.saurik.com Git - apple/javascriptcore.git/blobdiff - API/JSVirtualMachine.mm
JavaScriptCore-7600.1.4.16.1.tar.gz
[apple/javascriptcore.git] / API / JSVirtualMachine.mm
index 6bada34a6f218b7e905fdc33fda5494c9f5ae9ef..26e709ae16e7b5fe84f39b31c441534a5d79003c 100644 (file)
 #if JSC_OBJC_API_ENABLED
 
 #import "APICast.h"
-#import "APIShims.h"
+#import "JSManagedValueInternal.h"
 #import "JSVirtualMachine.h"
 #import "JSVirtualMachineInternal.h"
 #import "JSWrapperMap.h"
+#import "SlotVisitorInlines.h"
+#import <mutex>
+#import <wtf/NeverDestroyed.h>
 
 static NSMapTable *globalWrapperCache = 0;
 
-static Mutex& wrapperCacheLock()
+static std::mutex& wrapperCacheMutex()
 {
-    DEFINE_STATIC_LOCAL(Mutex, mutex, ());
+    static NeverDestroyed<std::mutex> mutex;
+
     return mutex;
 }
 
@@ -67,13 +71,13 @@ static NSMapTable *wrapperCache()
 
 + (void)addWrapper:(JSVirtualMachine *)wrapper forJSContextGroupRef:(JSContextGroupRef)group
 {
-    MutexLocker locker(wrapperCacheLock());
+    std::lock_guard<std::mutex> lock(wrapperCacheMutex());
     NSMapInsert(wrapperCache(), group, wrapper);
 }
 
 + (JSVirtualMachine *)wrapperForJSContextGroupRef:(JSContextGroupRef)group
 {
-    MutexLocker locker(wrapperCacheLock());
+    std::lock_guard<std::mutex> lock(wrapperCacheMutex());
     return static_cast<JSVirtualMachine *>(NSMapGet(wrapperCache(), group));
 }
 
@@ -83,9 +87,10 @@ static NSMapTable *wrapperCache()
     JSContextGroupRef m_group;
     NSMapTable *m_contextCache;
     NSMapTable *m_externalObjectGraph;
+    NSMapTable *m_externalRememberedSet;
 }
 
-- (id)init
+- (instancetype)init
 {
     JSContextGroupRef group = JSContextGroupCreate();
     self = [self initWithContextGroupRef:group];
@@ -94,7 +99,7 @@ static NSMapTable *wrapperCache()
     return self;
 }
 
-- (id)initWithContextGroupRef:(JSContextGroupRef)group
+- (instancetype)initWithContextGroupRef:(JSContextGroupRef)group
 {
     self = [super init];
     if (!self)
@@ -109,6 +114,9 @@ static NSMapTable *wrapperCache()
     NSPointerFunctionsOptions weakIDOptions = NSPointerFunctionsWeakMemory | NSPointerFunctionsObjectPersonality;
     NSPointerFunctionsOptions strongIDOptions = NSPointerFunctionsStrongMemory | NSPointerFunctionsObjectPersonality;
     m_externalObjectGraph = [[NSMapTable alloc] initWithKeyOptions:weakIDOptions valueOptions:strongIDOptions capacity:0];
+
+    NSPointerFunctionsOptions integerOptions = NSPointerFunctionsOpaqueMemory | NSPointerFunctionsIntegerPersonality;
+    m_externalRememberedSet = [[NSMapTable alloc] initWithKeyOptions:weakIDOptions valueOptions:integerOptions capacity:0];
    
     [JSVMWrapperCache addWrapper:self forJSContextGroupRef:group];
  
@@ -120,6 +128,7 @@ static NSMapTable *wrapperCache()
     JSContextGroupRelease(m_group);
     [m_contextCache release];
     [m_externalObjectGraph release];
+    [m_externalRememberedSet release];
     [super dealloc];
 }
 
@@ -141,16 +150,33 @@ static id getInternalObjcObject(id object)
     return object;
 }
 
+- (bool)isOldExternalObject:(id)object
+{
+    JSC::VM* vm = toJS(m_group);
+    return vm->heap.slotVisitor().containsOpaqueRoot(object);
+}
+
+- (void)addExternalRememberedObject:(id)object
+{
+    ASSERT([self isOldExternalObject:object]);
+    [m_externalRememberedSet setObject:[NSNumber numberWithBool:true] forKey:object];
+}
+
 - (void)addManagedReference:(id)object withOwner:(id)owner
 {    
+    if ([object isKindOfClass:[JSManagedValue class]])
+        [object didAddOwner:owner];
+        
     object = getInternalObjcObject(object);
     owner = getInternalObjcObject(owner);
     
     if (!object || !owner)
         return;
     
-    JSC::APIEntryShim shim(toJS(m_group));
-    
+    JSC::JSLockHolder locker(toJS(m_group));
+    if ([self isOldExternalObject:owner] && ![self isOldExternalObject:object])
+        [self addExternalRememberedObject:owner];
     NSMapTable *ownedObjects = [m_externalObjectGraph objectForKey:owner];
     if (!ownedObjects) {
         NSPointerFunctionsOptions weakIDOptions = NSPointerFunctionsWeakMemory | NSPointerFunctionsObjectPersonality;
@@ -160,18 +186,23 @@ static id getInternalObjcObject(id object)
         [m_externalObjectGraph setObject:ownedObjects forKey:owner];
         [ownedObjects release];
     }
-    NSMapInsert(ownedObjects, object, reinterpret_cast<void*>(reinterpret_cast<size_t>(NSMapGet(ownedObjects, object)) + 1));
+
+    size_t count = reinterpret_cast<size_t>(NSMapGet(ownedObjects, object));
+    NSMapInsert(ownedObjects, object, reinterpret_cast<void*>(count + 1));
 }
 
 - (void)removeManagedReference:(id)object withOwner:(id)owner
 {
+    if ([object isKindOfClass:[JSManagedValue class]])
+        [object didRemoveOwner:owner];
+
     object = getInternalObjcObject(object);
     owner = getInternalObjcObject(owner);
     
     if (!object || !owner)
         return;
     
-    JSC::APIEntryShim shim(toJS(m_group));
+    JSC::JSLockHolder locker(toJS(m_group));
     
     NSMapTable *ownedObjects = [m_externalObjectGraph objectForKey:owner];
     if (!ownedObjects)
@@ -186,8 +217,10 @@ static id getInternalObjcObject(id object)
     if (count == 1)
         NSMapRemove(ownedObjects, object);
 
-    if (![ownedObjects count])
+    if (![ownedObjects count]) {
         [m_externalObjectGraph removeObjectForKey:owner];
+        [m_externalRememberedSet removeObjectForKey:owner];
+    }
 }
 
 @end
@@ -222,6 +255,11 @@ JSContextGroupRef getGroupFromVirtualMachine(JSVirtualMachine *virtualMachine)
     return m_externalObjectGraph;
 }
 
+- (NSMapTable *)externalRememberedSet
+{
+    return m_externalRememberedSet;
+}
+
 @end
 
 void scanExternalObjectGraph(JSC::VM& vm, JSC::SlotVisitor& visitor, void* root)
@@ -241,15 +279,27 @@ void scanExternalObjectGraph(JSC::VM& vm, JSC::SlotVisitor& visitor, void* root)
             visitor.addOpaqueRoot(nextRoot);
             
             NSMapTable *ownedObjects = [externalObjectGraph objectForKey:static_cast<id>(nextRoot)];
-            id ownedObject;
-            NSEnumerator *enumerator = [ownedObjects keyEnumerator];
-            while ((ownedObject = [enumerator nextObject])) {
-                ASSERT(reinterpret_cast<size_t>(NSMapGet(ownedObjects, ownedObject)) == 1);
+            for (id ownedObject in ownedObjects)
                 stack.append(static_cast<void*>(ownedObject));
-            }
         }
     }
 }
 
-#endif
+void scanExternalRememberedSet(JSC::VM& vm, JSC::SlotVisitor& visitor)
+{
+    @autoreleasepool {
+        JSVirtualMachine *virtualMachine = [JSVMWrapperCache wrapperForJSContextGroupRef:toRef(&vm)];
+        if (!virtualMachine)
+            return;
+        NSMapTable *externalObjectGraph = [virtualMachine externalObjectGraph];
+        NSMapTable *externalRememberedSet = [virtualMachine externalRememberedSet];
+        for (id key in externalRememberedSet) {
+            NSMapTable *ownedObjects = [externalObjectGraph objectForKey:key];
+            for (id ownedObject in ownedObjects)
+                scanExternalObjectGraph(vm, visitor, ownedObject);
+        }
+        [externalRememberedSet removeAllObjects];
+    }
+}
 
+#endif // JSC_OBJC_API_ENABLED