Bug 196392 - [JSC] JSWrapperMap should not use Objective-C Weak map (NSMapTable with NSPointerFunctionsWeakMemory) for m_cachedObjCWrappers
Summary: [JSC] JSWrapperMap should not use Objective-C Weak map (NSMapTable with NSPoi...
Status: REOPENED
Alias: None
Product: WebKit
Classification: Unclassified
Component: JavaScriptCore (show other bugs)
Version: WebKit Nightly Build
Hardware: Unspecified Unspecified
: P2 Normal
Assignee: Yusuke Suzuki
URL:
Keywords: InRadar
Depends on: 196952
Blocks:
  Show dependency treegraph
 
Reported: 2019-03-28 23:58 PDT by Yusuke Suzuki
Modified: 2019-04-15 19:17 PDT (History)
7 users (show)

See Also:


Attachments
Patch (8.40 KB, patch)
2019-03-29 00:06 PDT, Yusuke Suzuki
no flags Details | Formatted Diff | Diff
Patch (11.18 KB, patch)
2019-03-29 16:12 PDT, Yusuke Suzuki
sbarati: review+
Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Yusuke Suzuki 2019-03-28 23:58:03 PDT
We do not use Objective-C weak semantics here. Objective-C JSValue has a dealloc function, and JSValue is tightly coupled to JSContext (it has _context field).
So JSValue is only stored in one wrapper map held by JSContext (JSWrapperMap). So, we can manage lifetime just unregistering itself from JSWrapperMap in [JSValue dealloc].
Why we would like to avoid Objective-C weak semantics is that it allocates much memory. In very simple hello_world case, we create 4 JSValue wrappers, and it consumes 10KB for weak semantics.
Comment 1 Yusuke Suzuki 2019-03-29 00:06:27 PDT
Created attachment 366254 [details]
Patch

WIP
Comment 2 Yusuke Suzuki 2019-03-29 16:12:35 PDT
Created attachment 366320 [details]
Patch
Comment 3 Yusuke Suzuki 2019-03-29 16:35:49 PDT
Comment on attachment 366320 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=366320&action=review

> Source/JavaScriptCore/API/JSContext.mm:374
> +    JSC::JSLockHolder locker(toJS(m_context));

It is not necessary since we just drop Hash table entry, which contains a pointer, and do nothing on this pointer. I'll remove this lock.
Comment 4 Saam Barati 2019-03-29 16:55:01 PDT
Comment on attachment 366320 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=366320&action=review

> Source/JavaScriptCore/API/JSWrapperMap.mm:604
> +    void* m_wrapper { nullptr };

As you mentioned, let's use __unsafe_unretained
Comment 5 Yusuke Suzuki 2019-03-29 18:29:13 PDT
Comment on attachment 366320 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=366320&action=review

Thanks!

>> Source/JavaScriptCore/API/JSWrapperMap.mm:604
>> +    void* m_wrapper { nullptr };
> 
> As you mentioned, let's use __unsafe_unretained

Fixed.
Comment 6 Yusuke Suzuki 2019-03-29 18:30:37 PDT
Committed r243672: <https://trac.webkit.org/changeset/243672>
Comment 7 Radar WebKit Bug Importer 2019-03-29 18:36:34 PDT
<rdar://problem/49443020>
Comment 8 WebKit Commit Bot 2019-04-15 19:09:01 PDT
Re-opened since this is blocked by bug 196952
Comment 9 Yusuke Suzuki 2019-04-15 19:17:29 PDT
I rolled out this patch for now. The problem was this patch does not account that JSC.framework is thread-safe. JSC VM can be used multiple threads, and JSC framework takes appropriate lock internally. And [JSValue release] can be called in one thread while the other thread uses it. So the problem happens when,

1. Thread A calls [JSValue release].
2. Thread A is now in [JSValue dealloc], and about to unregister JSValue from wrapper map.
3. Thread B gets the JSValue from the wrapper map.
4. Thread A unregisters the JSValue, and destroy it.
5. Thread B uses the destroyed JSValue.

Appropriate fix in this patch's direction would be like, defining custom [JSValue release] and unregister it from wrapper map and destroy it in an atomic manner.
But since this introduces a lot of complexity, for now, I've just reverted this patch.