Unreviewed, revert r243617.
authorysuzuki@apple.com <ysuzuki@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 11 Jul 2019 09:42:22 +0000 (09:42 +0000)
committerysuzuki@apple.com <ysuzuki@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 11 Jul 2019 09:42:22 +0000 (09:42 +0000)
https://bugs.webkit.org/show_bug.cgi?id=196341

Mark pointed out that JSVirtualMachine can be gone in the other thread while we are executing GC constraint-solving.
This patch does not account that JavaScriptCore.framework is multi-thread safe: JSVirtualMachine wrapper can be destroyed,
and [JSVirtualMachine dealloc] can be executed in any threads while the VM is retained and used in the other thread (e.g.
destroyed from AutoReleasePool in some thread).

* API/JSContext.mm:
(-[JSContext initWithVirtualMachine:]):
(-[JSContext dealloc]):
(-[JSContext initWithGlobalContextRef:]):
(-[JSContext wrapperMap]):
(+[JSContext contextWithJSGlobalContextRef:]):
* API/JSVirtualMachine.mm:
(initWrapperCache):
(wrapperCache):
(+[JSVMWrapperCache addWrapper:forJSContextGroupRef:]):
(+[JSVMWrapperCache wrapperForJSContextGroupRef:]):
(-[JSVirtualMachine initWithContextGroupRef:]):
(-[JSVirtualMachine dealloc]):
(+[JSVirtualMachine virtualMachineWithContextGroupRef:]):
(-[JSVirtualMachine contextForGlobalContextRef:]):
(-[JSVirtualMachine addContext:forGlobalContextRef:]):
(scanExternalObjectGraph):
(scanExternalRememberedSet):
* API/JSVirtualMachineInternal.h:
* runtime/JSGlobalObject.h:
(JSC::JSGlobalObject::setWrapperMap):
(JSC::JSGlobalObject::setAPIWrapper): Deleted.
(JSC::JSGlobalObject::apiWrapper const): Deleted.
* runtime/VM.h:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@247346 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/JavaScriptCore/API/JSContext.mm
Source/JavaScriptCore/API/JSVirtualMachine.mm
Source/JavaScriptCore/API/JSVirtualMachineInternal.h
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/runtime/JSGlobalObject.h
Source/JavaScriptCore/runtime/VM.h

index 094c937..41cae4f 100644 (file)
     };
 
     [self ensureWrapperMap];
-
-    toJSGlobalObject(m_context)->setAPIWrapper((__bridge void*)self);
+    [m_virtualMachine addContext:self forGlobalContextRef:m_context];
 
     return self;
 }
 
 - (void)dealloc
 {
-    toJSGlobalObject(m_context)->setAPIWrapper((__bridge void*)nil);
     m_exception.clear();
     JSGlobalContextRelease(m_context);
     [m_virtualMachine release];
         context.exception = exceptionValue;
     };
 
-    toJSGlobalObject(m_context)->setAPIWrapper((__bridge void*)self);
+    [m_virtualMachine addContext:self forGlobalContextRef:m_context];
 
     return self;
 }
 
 - (JSWrapperMap *)wrapperMap
 {
-    return toJSGlobalObject(m_context)->wrapperMap();
+    return toJS(m_context)->lexicalGlobalObject()->wrapperMap();
 }
 
 - (JSValue *)wrapperForJSObject:(JSValueRef)value
 
 + (JSContext *)contextWithJSGlobalContextRef:(JSGlobalContextRef)globalContext
 {
-    JSContext *context = (__bridge JSContext *)toJSGlobalObject(globalContext)->apiWrapper();
+    JSVirtualMachine *virtualMachine = [JSVirtualMachine virtualMachineWithContextGroupRef:toRef(&toJS(globalContext)->vm())];
+    JSContext *context = [virtualMachine contextForGlobalContextRef:globalContext];
     if (!context)
         context = [[[JSContext alloc] initWithGlobalContextRef:globalContext] autorelease];
     return context;
index 62eef4d..d1b6b94 100644 (file)
 #import <wtf/BlockPtr.h>
 #import <wtf/Lock.h>
 
+static NSMapTable *globalWrapperCache = 0;
+
+static Lock wrapperCacheMutex;
+
+static void initWrapperCache()
+{
+    ASSERT(!globalWrapperCache);
+    NSPointerFunctionsOptions keyOptions = NSPointerFunctionsOpaqueMemory | NSPointerFunctionsOpaquePersonality;
+    NSPointerFunctionsOptions valueOptions = NSPointerFunctionsWeakMemory | NSPointerFunctionsObjectPersonality;
+    globalWrapperCache = [[NSMapTable alloc] initWithKeyOptions:keyOptions valueOptions:valueOptions capacity:0];
+}
+
+static NSMapTable *wrapperCache()
+{
+    if (!globalWrapperCache)
+        initWrapperCache();
+    return globalWrapperCache;
+}
+
+@interface JSVMWrapperCache : NSObject
++ (void)addWrapper:(JSVirtualMachine *)wrapper forJSContextGroupRef:(JSContextGroupRef)group;
++ (JSVirtualMachine *)wrapperForJSContextGroupRef:(JSContextGroupRef)group;
+@end
+
+@implementation JSVMWrapperCache
+
++ (void)addWrapper:(JSVirtualMachine *)wrapper forJSContextGroupRef:(JSContextGroupRef)group
+{
+    std::lock_guard<Lock> lock(wrapperCacheMutex);
+    NSMapInsert(wrapperCache(), group, (__bridge void*)wrapper);
+}
+
++ (JSVirtualMachine *)wrapperForJSContextGroupRef:(JSContextGroupRef)group
+{
+    std::lock_guard<Lock> lock(wrapperCacheMutex);
+    return (__bridge JSVirtualMachine *)NSMapGet(wrapperCache(), group);
+}
+
+@end
+
 @implementation JSVirtualMachine {
     JSContextGroupRef m_group;
     Lock m_externalDataMutex;
+    NSMapTable *m_contextCache;
     NSMapTable *m_externalObjectGraph;
     NSMapTable *m_externalRememberedSet;
 }
     
     m_group = JSContextGroupRetain(group);
     
+    NSPointerFunctionsOptions keyOptions = NSPointerFunctionsOpaqueMemory | NSPointerFunctionsOpaquePersonality;
+    NSPointerFunctionsOptions valueOptions = NSPointerFunctionsWeakMemory | NSPointerFunctionsObjectPersonality;
+    m_contextCache = [[NSMapTable alloc] initWithKeyOptions:keyOptions valueOptions:valueOptions capacity:0];
+    
     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];
-
-    toJS(group)->m_apiWrapper = (__bridge void*)self;
+   
+    [JSVMWrapperCache addWrapper:self forJSContextGroupRef:group];
  
     return self;
 }
 
 - (void)dealloc
 {
-    toJS(m_group)->m_apiWrapper = (__bridge void*)nil;
     JSContextGroupRelease(m_group);
+    [m_contextCache release];
     [m_externalObjectGraph release];
     [m_externalRememberedSet release];
     [super dealloc];
@@ -192,13 +237,22 @@ JSContextGroupRef getGroupFromVirtualMachine(JSVirtualMachine *virtualMachine)
 
 + (JSVirtualMachine *)virtualMachineWithContextGroupRef:(JSContextGroupRef)group
 {
-    auto* vm = toJS(group);
-    JSVirtualMachine *virtualMachine = (__bridge JSVirtualMachine *)vm->m_apiWrapper;
+    JSVirtualMachine *virtualMachine = [JSVMWrapperCache wrapperForJSContextGroupRef:group];
     if (!virtualMachine)
         virtualMachine = [[[JSVirtualMachine alloc] initWithContextGroupRef:group] autorelease];
     return virtualMachine;
 }
 
+- (JSContext *)contextForGlobalContextRef:(JSGlobalContextRef)globalContext
+{
+    return (__bridge JSContext *)NSMapGet(m_contextCache, globalContext);
+}
+
+- (void)addContext:(JSContext *)wrapper forGlobalContextRef:(JSGlobalContextRef)globalContext
+{
+    NSMapInsert(m_contextCache, globalContext, (__bridge void*)wrapper);
+}
+
 - (Lock&)externalDataMutex
 {
     return m_externalDataMutex;
@@ -263,7 +317,7 @@ JSContextGroupRef getGroupFromVirtualMachine(JSVirtualMachine *virtualMachine)
 static void scanExternalObjectGraph(JSC::VM& vm, JSC::SlotVisitor& visitor, void* root, bool lockAcquired)
 {
     @autoreleasepool {
-        JSVirtualMachine *virtualMachine = (__bridge JSVirtualMachine *)vm.m_apiWrapper;
+        JSVirtualMachine *virtualMachine = [JSVMWrapperCache wrapperForJSContextGroupRef:toRef(&vm)];
         if (!virtualMachine)
             return;
         NSMapTable *externalObjectGraph = [virtualMachine externalObjectGraph];
@@ -301,7 +355,7 @@ void scanExternalObjectGraph(JSC::VM& vm, JSC::SlotVisitor& visitor, void* root)
 void scanExternalRememberedSet(JSC::VM& vm, JSC::SlotVisitor& visitor)
 {
     @autoreleasepool {
-        JSVirtualMachine *virtualMachine = (__bridge JSVirtualMachine *)vm.m_apiWrapper;
+        JSVirtualMachine *virtualMachine = [JSVMWrapperCache wrapperForJSContextGroupRef:toRef(&vm)];
         if (!virtualMachine)
             return;
         Lock& externalDataMutex = [virtualMachine externalDataMutex];
index ee86b61..b533482 100644 (file)
@@ -44,6 +44,8 @@ JSContextGroupRef getGroupFromVirtualMachine(JSVirtualMachine *);
 
 + (JSVirtualMachine *)virtualMachineWithContextGroupRef:(JSContextGroupRef)group;
 
+- (JSContext *)contextForGlobalContextRef:(JSGlobalContextRef)globalContext;
+- (void)addContext:(JSContext *)wrapper forGlobalContextRef:(JSGlobalContextRef)globalContext;
 - (JSC::VM&)vm;
 
 - (BOOL)isWebThreadAware;
index 3cc87d6..ad34109 100644 (file)
@@ -1,3 +1,38 @@
+2019-07-11  Yusuke Suzuki  <ysuzuki@apple.com>
+
+        Unreviewed, revert r243617.
+        https://bugs.webkit.org/show_bug.cgi?id=196341
+
+        Mark pointed out that JSVirtualMachine can be gone in the other thread while we are executing GC constraint-solving.
+        This patch does not account that JavaScriptCore.framework is multi-thread safe: JSVirtualMachine wrapper can be destroyed,
+        and [JSVirtualMachine dealloc] can be executed in any threads while the VM is retained and used in the other thread (e.g.
+        destroyed from AutoReleasePool in some thread).
+
+        * API/JSContext.mm:
+        (-[JSContext initWithVirtualMachine:]):
+        (-[JSContext dealloc]):
+        (-[JSContext initWithGlobalContextRef:]):
+        (-[JSContext wrapperMap]):
+        (+[JSContext contextWithJSGlobalContextRef:]):
+        * API/JSVirtualMachine.mm:
+        (initWrapperCache):
+        (wrapperCache):
+        (+[JSVMWrapperCache addWrapper:forJSContextGroupRef:]):
+        (+[JSVMWrapperCache wrapperForJSContextGroupRef:]):
+        (-[JSVirtualMachine initWithContextGroupRef:]):
+        (-[JSVirtualMachine dealloc]):
+        (+[JSVirtualMachine virtualMachineWithContextGroupRef:]):
+        (-[JSVirtualMachine contextForGlobalContextRef:]):
+        (-[JSVirtualMachine addContext:forGlobalContextRef:]):
+        (scanExternalObjectGraph):
+        (scanExternalRememberedSet):
+        * API/JSVirtualMachineInternal.h:
+        * runtime/JSGlobalObject.h:
+        (JSC::JSGlobalObject::setWrapperMap):
+        (JSC::JSGlobalObject::setAPIWrapper): Deleted.
+        (JSC::JSGlobalObject::apiWrapper const): Deleted.
+        * runtime/VM.h:
+
 2019-07-10  Tadeu Zagallo  <tzagallo@apple.com>
 
         Optimize join of large empty arrays
index 02607c9..dbc2ef0 100644 (file)
@@ -1010,8 +1010,6 @@ public:
 #if JSC_OBJC_API_ENABLED
     JSWrapperMap* wrapperMap() const { return m_wrapperMap.get(); }
     void setWrapperMap(JSWrapperMap* map) { m_wrapperMap = map; }
-    void setAPIWrapper(void* apiWrapper) { m_apiWrapper = apiWrapper; }
-    void* apiWrapper() const { return m_apiWrapper; }
 #endif
 #ifdef JSC_GLIB_API_ENABLED
     WrapperMap* wrapperMap() const { return m_wrapperMap.get(); }
@@ -1054,7 +1052,6 @@ private:
     bool m_needsSiteSpecificQuirks { false };
 #if JSC_OBJC_API_ENABLED
     RetainPtr<JSWrapperMap> m_wrapperMap;
-    void* m_apiWrapper { nullptr };
 #endif
 #ifdef JSC_GLIB_API_ENABLED
     std::unique_ptr<WrapperMap> m_wrapperMap;
index 901497b..82462e1 100644 (file)
@@ -833,10 +833,6 @@ public:
     RTTraceList* m_rtTraceList;
 #endif
 
-#if JSC_OBJC_API_ENABLED
-    void* m_apiWrapper { nullptr };
-#endif
-
     JS_EXPORT_PRIVATE void resetDateCache();
 
     RegExpCache* regExpCache() { return m_regExpCache; }