X-Git-Url: https://git.saurik.com/apple/javascriptcore.git/blobdiff_plain/93a3786624b2768d89bfa27e46598dc64e2fb70a..ed1e77d3adeb83d26fd1dfb16dd84cabdcefd250:/API/JSVirtualMachine.mm?ds=sidebyside diff --git a/API/JSVirtualMachine.mm b/API/JSVirtualMachine.mm index 6bada34..d4995ad 100644 --- a/API/JSVirtualMachine.mm +++ b/API/JSVirtualMachine.mm @@ -30,16 +30,21 @@ #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 +#import +#import static NSMapTable *globalWrapperCache = 0; -static Mutex& wrapperCacheLock() +static std::mutex& wrapperCacheMutex() { - DEFINE_STATIC_LOCAL(Mutex, mutex, ()); + static NeverDestroyed mutex; + return mutex; } @@ -67,13 +72,13 @@ static NSMapTable *wrapperCache() + (void)addWrapper:(JSVirtualMachine *)wrapper forJSContextGroupRef:(JSContextGroupRef)group { - MutexLocker locker(wrapperCacheLock()); + std::lock_guard lock(wrapperCacheMutex()); NSMapInsert(wrapperCache(), group, wrapper); } + (JSVirtualMachine *)wrapperForJSContextGroupRef:(JSContextGroupRef)group { - MutexLocker locker(wrapperCacheLock()); + std::lock_guard lock(wrapperCacheMutex()); return static_cast(NSMapGet(wrapperCache(), group)); } @@ -83,9 +88,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 +100,7 @@ static NSMapTable *wrapperCache() return self; } -- (id)initWithContextGroupRef:(JSContextGroupRef)group +- (instancetype)initWithContextGroupRef:(JSContextGroupRef)group { self = [super init]; if (!self) @@ -109,6 +115,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 +129,7 @@ static NSMapTable *wrapperCache() JSContextGroupRelease(m_group); [m_contextCache release]; [m_externalObjectGraph release]; + [m_externalRememberedSet release]; [super dealloc]; } @@ -141,16 +151,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 +187,23 @@ static id getInternalObjcObject(id object) [m_externalObjectGraph setObject:ownedObjects forKey:owner]; [ownedObjects release]; } - NSMapInsert(ownedObjects, object, reinterpret_cast(reinterpret_cast(NSMapGet(ownedObjects, object)) + 1)); + + size_t count = reinterpret_cast(NSMapGet(ownedObjects, object)); + NSMapInsert(ownedObjects, object, reinterpret_cast(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 +218,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 +256,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 +280,27 @@ void scanExternalObjectGraph(JSC::VM& vm, JSC::SlotVisitor& visitor, void* root) visitor.addOpaqueRoot(nextRoot); NSMapTable *ownedObjects = [externalObjectGraph objectForKey:static_cast(nextRoot)]; - id ownedObject; - NSEnumerator *enumerator = [ownedObjects keyEnumerator]; - while ((ownedObject = [enumerator nextObject])) { - ASSERT(reinterpret_cast(NSMapGet(ownedObjects, ownedObject)) == 1); + for (id ownedObject in ownedObjects) stack.append(static_cast(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