Bug 141809 - [JSObjCClassInfo reallocateConstructorAndOrPrototype] should also reallocate super class prototype chain
Summary: [JSObjCClassInfo reallocateConstructorAndOrPrototype] should also reallocate ...
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: JavaScriptCore (show other bugs)
Version: 528+ (Nightly build)
Hardware: Unspecified Unspecified
: P2 Normal
Assignee: Mark Lam
URL:
Keywords: InRadar
Depends on:
Blocks:
 
Reported: 2015-02-19 13:36 PST by Mark Lam
Modified: 2015-02-20 13:53 PST (History)
8 users (show)

See Also:


Attachments
the patch. (6.42 KB, patch)
2015-02-19 13:53 PST, Mark Lam
mhahnenb: review+
Details | Formatted Diff | Diff
take 2: with Geoff's and Mark's suggestions applied. (19.80 KB, patch)
2015-02-20 11:27 PST, Mark Lam
no flags Details | Formatted Diff | Diff
take 3: with -allocateConstructorAndPrototype returning a prototype constructor pair (19.86 KB, patch)
2015-02-20 12:51 PST, Mark Lam
mark.lam: review-
Details | Formatted Diff | Diff
take 4: with consistent constructor and prototype ordering in pair. (19.86 KB, patch)
2015-02-20 12:59 PST, Mark Lam
ggaren: review+
Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Mark Lam 2015-02-19 13:36:33 PST
A ObjC class that implement the JSExport protocol will have a JS prototype chain and constructor automatically synthesized for its JS wrapper object.  However, if there are no more instances of that ObjC class reachable by a GC root scan, then its synthesized prototype chain and constructors may be released by the GC.  If a new instance of that ObjC class is instantiated, then [JSObjCClassInfo reallocateConstructorAndOrPrototype] should re-construct the prototype chain and constructor (if they were released).  However, the current implementation only re-constructs the immediate prototype, but not every other prototype object upstream in the prototype chain.

The fix is to have [JSObjCClassInfo reallocateConstructorAndOrPrototype] recurse and call itself for the super class if the super class' prototype is not initialized (implying that the super class also needs to re-construct its prototype and constructor).
Comment 1 Mark Lam 2015-02-19 13:37:32 PST
<rdar://problem/19679557>
Comment 2 Mark Lam 2015-02-19 13:53:42 PST
Created attachment 246917 [details]
the patch.
Comment 3 WebKit Commit Bot 2015-02-19 13:56:17 PST
Attachment 246917 [details] did not pass style-queue:


ERROR: Source/JavaScriptCore/API/tests/testapi.mm:1436:  Place brace on its own line for function definitions.  [whitespace/braces] [4]
ERROR: Source/JavaScriptCore/API/tests/testapi.mm:1440:  Multi-line string ("...") found.  This lint script doesn't do well with such strings, and may give bogus warnings.  They're ugly and unnecessary, and you should use concatenation instead".  [readability/multiline_string] [5]
ERROR: Source/JavaScriptCore/API/tests/testapi.mm:1454:  Multi line control clauses should use braces.  [whitespace/braces] [4]
ERROR: Source/JavaScriptCore/API/tests/testapi.mm:1468:  Multi-line string ("...") found.  This lint script doesn't do well with such strings, and may give bogus warnings.  They're ugly and unnecessary, and you should use concatenation instead".  [readability/multiline_string] [5]
Total errors found: 4 in 3 files


If any of these errors are false positives, please file a bug against check-webkit-style.
Comment 4 Mark Lam 2015-02-19 13:57:51 PST
(In reply to comment #3)
> Attachment 246917 [details] did not pass style-queue:
> ...
> Total errors found: 4 in 3 files

I think the style bot is just not smart enough to understand these.
Comment 5 Mark Hahnenberg 2015-02-19 16:35:35 PST
Comment on attachment 246917 [details]
the patch.

r=me. I know it's kind of a PITA, but separating these API tests out into their own files reduces build times and makes it easier to figure out which ones are regressing without the risk of having any dirty state between tests. There's already a couple larger tests/groups of tests that are separate (e.g. JSExportTests.mm). It might make sense to move this out of the monolithic test function and into one of those smaller groups or maybe its own thing.
Comment 6 Geoffrey Garen 2015-02-19 16:54:43 PST
Comment on attachment 246917 [details]
the patch.

I think this patch is fine, but I think it would be even better to make this code less brittle, since we've had two very similar serious GC bugs in this code.

Is there a way for -classInfoForClass: to always return a full prototype chain, with callers not needing to check for a null one, and also to remove the need for comments and workarounds regarding GC in this file?

For example: Perhaps we can make -classInfoForClass: always return a fully constructed prototype chain in a stack-allocated smart pointer that defers garbage collection. Or, more simply, perhaps callers of -classInfoForClass: should defer garbage collection, and pass the DeferGC pointer to the method in order to prove they have done so. Or -classInfoForClass: could return a pair of <JSObjCClassInfo*, JSC::Strong<JSObject*>>, where the second value was the prototype that needed protection from GC.
Comment 7 Geoffrey Garen 2015-02-19 17:05:11 PST
Concrete proposal:

(1) -[JSObjCClassInfo initWithContext:...] drops the superClassInfo parameter, and stops calling -allocateConstructorAndPrototypeWithSuperClassInfo:.

(2) Methods of JSObjcClassInfo -- -wrapperForObject:, and -constructor -- do not use the m_ weak data members, and instead call helpers to access those members.

(3) Helpers allocate object graphs if needed and return a JSObject* for the resulting constructor or prototype chain.

(4) Remove all comments about GC. The GC problem is solved by a GC root, which is how GC problems should be solved.
Comment 8 Mark Lam 2015-02-20 11:27:03 PST
Created attachment 246978 [details]
take 2: with Geoff's and Mark's suggestions applied.

In this patch, -prototype: returns a JSC::JSObject* while -constructor: still returns a JSValue* (which is inconsistent).

Technically, -constructor: plus many other methods and static functions can just work with and return JSC::JSObject* instead of JSValue* as well.  They should defer the allocation of the ObjC JSValue* until the latest possible moment.  However, to keep this patch to its bare minimum, I will defer that change to a later patch.
Comment 9 WebKit Commit Bot 2015-02-20 11:28:15 PST
Attachment 246978 [details] did not pass style-queue:


ERROR: Source/JavaScriptCore/API/tests/Regress141809.mm:81:  Place brace on its own line for function definitions.  [whitespace/braces] [4]
ERROR: Source/JavaScriptCore/API/tests/Regress141809.mm:85:  Multi-line string ("...") found.  This lint script doesn't do well with such strings, and may give bogus warnings.  They're ugly and unnecessary, and you should use concatenation instead".  [readability/multiline_string] [5]
ERROR: Source/JavaScriptCore/API/tests/Regress141809.mm:99:  Multi line control clauses should use braces.  [whitespace/braces] [4]
ERROR: Source/JavaScriptCore/API/tests/Regress141809.mm:113:  Multi-line string ("...") found.  This lint script doesn't do well with such strings, and may give bogus warnings.  They're ugly and unnecessary, and you should use concatenation instead".  [readability/multiline_string] [5]
Total errors found: 4 in 6 files


If any of these errors are false positives, please file a bug against check-webkit-style.
Comment 10 Geoffrey Garen 2015-02-20 11:40:53 PST
Comment on attachment 246978 [details]
take 2: with Geoff's and Mark's suggestions applied.

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

> Source/JavaScriptCore/API/JSWrapperMap.mm:529
> +        [self allocateConstructorAndPrototype];
> +        constructor = m_constructor.get();

I think it's still dangerous to separate the allocate from the load. We want "allocate and load" to be an atomic operation that returns a GC root so that it's impossible for anyone to write a line of code that allocates, GCs, and then loads, causing a error.

The best way to do this is probably to have allocateConstructorAndPrototype return an std::pair<JSObject*, JSObject*> holding the constructor and prototype.

So you would do:

JSC::JSObject* constructor = m_constructor.get();
if (!constructor)
    constructor = [self allocateConstructorAndPrototype].first;
Comment 11 Mark Lam 2015-02-20 12:51:11 PST
Created attachment 246988 [details]
take 3: with -allocateConstructorAndPrototype returning a prototype constructor pair
Comment 12 WebKit Commit Bot 2015-02-20 12:53:09 PST
Attachment 246988 [details] did not pass style-queue:


ERROR: Source/JavaScriptCore/API/tests/Regress141809.mm:81:  Place brace on its own line for function definitions.  [whitespace/braces] [4]
ERROR: Source/JavaScriptCore/API/tests/Regress141809.mm:85:  Multi-line string ("...") found.  This lint script doesn't do well with such strings, and may give bogus warnings.  They're ugly and unnecessary, and you should use concatenation instead".  [readability/multiline_string] [5]
ERROR: Source/JavaScriptCore/API/tests/Regress141809.mm:99:  Multi line control clauses should use braces.  [whitespace/braces] [4]
ERROR: Source/JavaScriptCore/API/tests/Regress141809.mm:113:  Multi-line string ("...") found.  This lint script doesn't do well with such strings, and may give bogus warnings.  They're ugly and unnecessary, and you should use concatenation instead".  [readability/multiline_string] [5]
Total errors found: 4 in 6 files


If any of these errors are false positives, please file a bug against check-webkit-style.
Comment 13 Mark Lam 2015-02-20 12:53:24 PST
Comment on attachment 246988 [details]
take 3: with -allocateConstructorAndPrototype returning a prototype constructor pair

I'm going to swap the order of the constructor and prototype in the pair to be more intuitive.
Comment 14 Mark Lam 2015-02-20 12:59:45 PST
Created attachment 246991 [details]
take 4: with consistent constructor and prototype ordering in pair.
Comment 15 WebKit Commit Bot 2015-02-20 13:01:29 PST
Attachment 246991 [details] did not pass style-queue:


ERROR: Source/JavaScriptCore/API/tests/Regress141809.mm:81:  Place brace on its own line for function definitions.  [whitespace/braces] [4]
ERROR: Source/JavaScriptCore/API/tests/Regress141809.mm:85:  Multi-line string ("...") found.  This lint script doesn't do well with such strings, and may give bogus warnings.  They're ugly and unnecessary, and you should use concatenation instead".  [readability/multiline_string] [5]
ERROR: Source/JavaScriptCore/API/tests/Regress141809.mm:99:  Multi line control clauses should use braces.  [whitespace/braces] [4]
ERROR: Source/JavaScriptCore/API/tests/Regress141809.mm:113:  Multi-line string ("...") found.  This lint script doesn't do well with such strings, and may give bogus warnings.  They're ugly and unnecessary, and you should use concatenation instead".  [readability/multiline_string] [5]
Total errors found: 4 in 6 files


If any of these errors are false positives, please file a bug against check-webkit-style.
Comment 16 Mark Lam 2015-02-20 13:06:13 PST
Comment on attachment 246991 [details]
take 4: with consistent constructor and prototype ordering in pair.

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

> Source/JavaScriptCore/API/tests/Regress141809.mm:2
> + * Copyright (C) 2014 Apple Inc. All rights reserved.

Eeek.  Should 2015.  Will fix before commit.

Will also update header for testapi.mm to say 2013-2015, because there were also changes in 2014 though the header only said 2013.
Ditto for JSWrapperMap.mm.
Comment 17 Geoffrey Garen 2015-02-20 13:43:25 PST
Comment on attachment 246991 [details]
take 4: with consistent constructor and prototype ordering in pair.

r=me
Comment 18 Mark Lam 2015-02-20 13:53:25 PST
Thanks for the reviews.  Landed in r180452: <http://trac.webkit.org/r180452>.