<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[180452] trunk/Source/JavaScriptCore</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/180452">180452</a></dd>
<dt>Author</dt> <dd>mark.lam@apple.com</dd>
<dt>Date</dt> <dd>2015-02-20 13:51:37 -0800 (Fri, 20 Feb 2015)</dd>
</dl>

<h3>Log Message</h3>
<pre>[JSObjCClassInfo reallocateConstructorAndOrPrototype] should also reallocate super class prototype chain.
&lt;https://webkit.org/b/141809&gt;

Reviewed by Geoffrey Garen.

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
JS 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 subsequently
instantiated, then [JSObjCClassInfo reallocateConstructorAndOrPrototype]
should re-construct the prototype chain and constructor (if they were
previously released).  However, the current implementation only
re-constructs the immediate prototype, but not every other prototype
object upstream in the prototype chain.

To fix this, we do the following:
1. We no longer allocate the JSObjCClassInfo's prototype and constructor
   eagerly.  Hence, -initWithContext:forClass: will no longer call
   -allocateConstructorAndPrototypeWithSuperClassInfo:.
2. Instead, we'll always access the prototype and constructor thru
   accessor methods.  The accessor methods will call
   -allocateConstructorAndPrototype: if needed.
3. -allocateConstructorAndPrototype: will fetch the needed superClassInfo
   from the JSWrapperMap itself.  This makes it so that we no longer
   need to pass the superClassInfo all over.
4. -allocateConstructorAndPrototype: will get the super class prototype
   by invoking -prototype: on the superClassInfo, thereby allowing the
   super class to allocate its prototype and constructor if needed and
   fixing the issue in this bug.

5. Also removed the GC warning comments, and ensured that needed JS
   objects are kept alive by having a local var pointing to it from the
   stack (which makes a GC root).

* API/JSWrapperMap.mm:
(-[JSObjCClassInfo initWithContext:forClass:]):
(-[JSObjCClassInfo allocateConstructorAndPrototype]):
(-[JSObjCClassInfo wrapperForObject:]):
(-[JSObjCClassInfo constructor]):
(-[JSObjCClassInfo prototype]):
(-[JSWrapperMap classInfoForClass:]):
(-[JSObjCClassInfo initWithContext:forClass:superClassInfo:]): Deleted.
(-[JSObjCClassInfo allocateConstructorAndPrototypeWithSuperClassInfo:]): Deleted.
(-[JSObjCClassInfo reallocateConstructorAndOrPrototype]): Deleted.
* API/tests/Regress141809.h: Added.
* API/tests/Regress141809.mm: Added.
(-[TestClassB name]):
(-[TestClassC name]):
(runRegress141809):
* API/tests/testapi.mm:
* JavaScriptCore.xcodeproj/project.pbxproj:</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreAPIJSWrapperMapmm">trunk/Source/JavaScriptCore/API/JSWrapperMap.mm</a></li>
<li><a href="#trunkSourceJavaScriptCoreAPIteststestapimm">trunk/Source/JavaScriptCore/API/tests/testapi.mm</a></li>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreJavaScriptCorexcodeprojprojectpbxproj">trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreAPItestsRegress141809h">trunk/Source/JavaScriptCore/API/tests/Regress141809.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreAPItestsRegress141809mm">trunk/Source/JavaScriptCore/API/tests/Regress141809.mm</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceJavaScriptCoreAPIJSWrapperMapmm"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/API/JSWrapperMap.mm (180451 => 180452)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/API/JSWrapperMap.mm        2015-02-20 21:39:01 UTC (rev 180451)
+++ trunk/Source/JavaScriptCore/API/JSWrapperMap.mm        2015-02-20 21:51:37 UTC (rev 180452)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2013 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2013-2015 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -364,15 +364,16 @@
</span><span class="cx">     JSC::Weak&lt;JSC::JSObject&gt; m_constructor;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-- (id)initWithContext:(JSContext *)context forClass:(Class)cls superClassInfo:(JSObjCClassInfo*)superClassInfo;
</del><ins>+- (id)initWithContext:(JSContext *)context forClass:(Class)cls;
</ins><span class="cx"> - (JSValue *)wrapperForObject:(id)object;
</span><span class="cx"> - (JSValue *)constructor;
</span><ins>+- (JSC::JSObject *)prototype;
</ins><span class="cx"> 
</span><span class="cx"> @end
</span><span class="cx"> 
</span><span class="cx"> @implementation JSObjCClassInfo
</span><span class="cx"> 
</span><del>-- (id)initWithContext:(JSContext *)context forClass:(Class)cls superClassInfo:(JSObjCClassInfo*)superClassInfo
</del><ins>+- (id)initWithContext:(JSContext *)context forClass:(Class)cls
</ins><span class="cx"> {
</span><span class="cx">     self = [super init];
</span><span class="cx">     if (!self)
</span><span class="lines">@@ -387,8 +388,6 @@
</span><span class="cx">     definition.className = className;
</span><span class="cx">     m_classRef = JSClassCreate(&amp;definition);
</span><span class="cx"> 
</span><del>-    [self allocateConstructorAndPrototypeWithSuperClassInfo:superClassInfo];
-
</del><span class="cx">     return self;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -450,8 +449,12 @@
</span><span class="cx">     return constructorWithCustomBrand(context, [NSString stringWithFormat:@&quot;%sConstructor&quot;, className], cls);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-- (void)allocateConstructorAndPrototypeWithSuperClassInfo:(JSObjCClassInfo*)superClassInfo
</del><ins>+typedef std::pair&lt;JSC::JSObject*, JSC::JSObject*&gt; ConstructorPrototypePair;
+
+- (ConstructorPrototypePair)allocateConstructorAndPrototype
</ins><span class="cx"> {
</span><ins>+    JSObjCClassInfo* superClassInfo = [m_context.wrapperMap classInfoForClass:class_getSuperclass(m_class)];
+
</ins><span class="cx">     ASSERT(!m_constructor || !m_prototype);
</span><span class="cx">     ASSERT((m_class == [NSObject class]) == !superClassInfo);
</span><span class="cx">     if (!superClassInfo) {
</span><span class="lines">@@ -465,11 +468,6 @@
</span><span class="cx">             m_prototype = toJS(JSValueToObject(cContext, valueInternalValue(prototype), 0));
</span><span class="cx">         }
</span><span class="cx">     } else {
</span><del>-        // We need to hold a reference to the superclass prototype here on the stack
-        // to that it won't get GC'ed while we do allocations between now and when we
-        // set it in this class' prototype below.
-        JSC::JSObject* superClassPrototype = superClassInfo-&gt;m_prototype.get();
-
</del><span class="cx">         const char* className = class_getName(m_class);
</span><span class="cx"> 
</span><span class="cx">         // Create or grab the prototype/constructor pair.
</span><span class="lines">@@ -499,17 +497,12 @@
</span><span class="cx">         });
</span><span class="cx"> 
</span><span class="cx">         // Set [Prototype].
</span><ins>+        JSC::JSObject* superClassPrototype = [superClassInfo prototype];
</ins><span class="cx">         JSObjectSetPrototype([m_context JSGlobalContextRef], toRef(m_prototype.get()), toRef(superClassPrototype));
</span><span class="cx">     }
</span><ins>+    return ConstructorPrototypePair(m_constructor.get(), m_prototype.get());
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-- (void)reallocateConstructorAndOrPrototype
-{
-    [self allocateConstructorAndPrototypeWithSuperClassInfo:[m_context.wrapperMap classInfoForClass:class_getSuperclass(m_class)]];
-    // We should not add any code here that can trigger a GC or the prototype and
-    // constructor that we just created may be collected before they can be used.
-}
-
</del><span class="cx"> - (JSValue *)wrapperForObject:(id)object
</span><span class="cx"> {
</span><span class="cx">     ASSERT([object isKindOfClass:m_class]);
</span><span class="lines">@@ -524,12 +517,7 @@
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    if (!m_prototype)
-        [self reallocateConstructorAndOrPrototype];
-    ASSERT(!!m_prototype);
-    // We need to hold a reference to the prototype here on the stack to that it won't
-    // get GC'ed while we create the wrapper below.
-    JSC::JSObject* prototype = m_prototype.get();
</del><ins>+    JSC::JSObject* prototype = [self prototype];
</ins><span class="cx"> 
</span><span class="cx">     JSObjectRef wrapper = makeWrapper([m_context JSGlobalContextRef], m_classRef, object);
</span><span class="cx">     JSObjectSetPrototype([m_context JSGlobalContextRef], wrapper, toRef(prototype));
</span><span class="lines">@@ -538,15 +526,22 @@
</span><span class="cx"> 
</span><span class="cx"> - (JSValue *)constructor
</span><span class="cx"> {
</span><del>-    if (!m_constructor)
-        [self reallocateConstructorAndOrPrototype];
-    ASSERT(!!m_constructor);
-    // If we need to add any code here in the future that can trigger a GC, we should
-    // cache the constructor pointer in a stack local var first so that it is protected
-    // from the GC until it gets used below.
-    return [JSValue valueWithJSValueRef:toRef(m_constructor.get()) inContext:m_context];
</del><ins>+    JSC::JSObject* constructor = m_constructor.get();
+    if (!constructor)
+        constructor = [self allocateConstructorAndPrototype].first;
+    ASSERT(!!constructor);
+    return [JSValue valueWithJSValueRef:toRef(constructor) inContext:m_context];
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+- (JSC::JSObject*)prototype
+{
+    JSC::JSObject* prototype = m_prototype.get();
+    if (!prototype)
+        prototype = [self allocateConstructorAndPrototype].second;
+    ASSERT(!!prototype);
+    return prototype;
+}
+
</ins><span class="cx"> @end
</span><span class="cx"> 
</span><span class="cx"> @implementation JSWrapperMap {
</span><span class="lines">@@ -591,7 +586,7 @@
</span><span class="cx">     if ('_' == *class_getName(cls))
</span><span class="cx">         return m_classMap[cls] = [self classInfoForClass:class_getSuperclass(cls)];
</span><span class="cx"> 
</span><del>-    return m_classMap[cls] = [[[JSObjCClassInfo alloc] initWithContext:m_context forClass:cls superClassInfo:[self classInfoForClass:class_getSuperclass(cls)]] autorelease];
</del><ins>+    return m_classMap[cls] = [[[JSObjCClassInfo alloc] initWithContext:m_context forClass:cls] autorelease];
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> - (JSValue *)jsWrapperForObject:(id)object
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreAPItestsRegress141809h"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/API/tests/Regress141809.h (0 => 180452)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/API/tests/Regress141809.h                                (rev 0)
+++ trunk/Source/JavaScriptCore/API/tests/Regress141809.h        2015-02-20 21:51:37 UTC (rev 180452)
</span><span class="lines">@@ -0,0 +1,34 @@
</span><ins>+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import &lt;Foundation/Foundation.h&gt;
+#import &lt;JavaScriptCore/JavaScriptCore.h&gt;
+
+#if JSC_OBJC_API_ENABLED
+
+void runRegress141809();
+
+#endif // JSC_OBJC_API_ENABLED
+
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoreAPItestsRegress141809mm"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/API/tests/Regress141809.mm (0 => 180452)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/API/tests/Regress141809.mm                                (rev 0)
+++ trunk/Source/JavaScriptCore/API/tests/Regress141809.mm        2015-02-20 21:51:37 UTC (rev 180452)
</span><span class="lines">@@ -0,0 +1,134 @@
</span><ins>+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import &quot;config.h&quot;
+#import &quot;Regress141809.h&quot;
+
+#import &lt;objc/objc.h&gt;
+#import &lt;objc/runtime.h&gt;
+
+#if JSC_OBJC_API_ENABLED
+
+extern &quot;C&quot; void checkResult(NSString *description, bool passed);
+extern &quot;C&quot; void JSSynchronousGarbageCollectForDebugging(JSContextRef);
+
+@protocol TestClassAExports &lt;JSExport&gt;
+@end
+
+@interface TestClassA : NSObject&lt;TestClassAExports&gt;
+@end
+
+@implementation TestClassA
+@end
+
+@protocol TestClassBExports &lt;JSExport&gt;
+- (NSString *)name;
+@end
+
+@interface TestClassB : TestClassA &lt;TestClassBExports&gt;
+@end
+
+@implementation TestClassB
+- (NSString *)name
+{
+    return @&quot;B&quot;;
+}
+@end
+
+@protocol TestClassCExports &lt;JSExport&gt;
+- (NSString *)name;
+@end
+
+@interface TestClassC : TestClassB &lt;TestClassCExports&gt;
+@end
+
+@implementation TestClassC
+- (NSString *)name
+{
+    return @&quot;C&quot;;
+}
+@end
+
+void runRegress141809()
+{
+    // Test that the ObjC API can correctly re-construct the synthesized
+    // prototype and constructor of JS exported ObjC classes.
+    // See &lt;https://webkit.org/b/141809&gt;
+    @autoreleasepool {
+        JSContext *context = [[JSContext alloc] init];
+        context[@&quot;print&quot;] = ^(NSString* str) {
+            NSLog(@&quot;%@&quot;, str);
+        };
+        
+        [context evaluateScript:@&quot;function dumpPrototypes(obj) { \
+            var objDepth = 0; \
+            var currObj = obj; \
+            var objChain = ''; \
+            do { \
+                var propIndex = 0; \
+                var props = ''; \
+                Object.getOwnPropertyNames(currObj).forEach(function(val, idx, array) { \
+                    props += ((propIndex &gt; 0 ? ', ' : '') + val); \
+                    propIndex++; \
+                }); \
+                var str = ''; \
+                if (!objDepth) \
+                    str += 'obj '; \
+                else { \
+                    for (i = 0; i &lt; objDepth; i++) \
+                        str += ' '; \
+                    str += '--&gt; proto '; \
+                } \
+                str += currObj; \
+                if (props) \
+                    str += (' with ' + propIndex + ' props: ' + props); \
+                print(str); \
+                objChain += (str + '\\n'); \
+                objDepth++; \
+                currObj = Object.getPrototypeOf(currObj); \
+            } while (currObj); \
+            return { objDepth: objDepth, objChain: objChain }; \
+        }&quot;];
+        JSValue* dumpPrototypes = context[@&quot;dumpPrototypes&quot;];
+        
+        JSValue* resultBeforeGC = nil;
+        @autoreleasepool {
+            TestClassC* obj = [[TestClassC alloc] init];
+            resultBeforeGC = [dumpPrototypes callWithArguments:@[obj]];
+        }
+        
+        JSSynchronousGarbageCollectForDebugging([context JSGlobalContextRef]);
+        
+        @autoreleasepool {
+            TestClassC* obj = [[TestClassC alloc] init];
+            JSValue* resultAfterGC = [dumpPrototypes callWithArguments:@[obj]];
+            checkResult(@&quot;object and prototype chain depth is 5 deep&quot;, [resultAfterGC[@&quot;objDepth&quot;] toInt32] == 5);
+            checkResult(@&quot;object and prototype chain depth before and after GC matches&quot;, [resultAfterGC[@&quot;objDepth&quot;] toInt32] == [resultBeforeGC[@&quot;objDepth&quot;] toInt32]);
+            checkResult(@&quot;object and prototype chain before and after GC matches&quot;, [[resultAfterGC[@&quot;objChain&quot;] toString] isEqualToString:[resultBeforeGC[@&quot;objChain&quot;] toString]]);
+        }
+    }
+}
+
+#endif // JSC_OBJC_API_ENABLED
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoreAPIteststestapimm"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/API/tests/testapi.mm (180451 => 180452)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/API/tests/testapi.mm        2015-02-20 21:39:01 UTC (rev 180451)
+++ trunk/Source/JavaScriptCore/API/tests/testapi.mm        2015-02-20 21:51:37 UTC (rev 180452)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2013 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2013-2015 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -28,6 +28,7 @@
</span><span class="cx"> #import &quot;CurrentThisInsideBlockGetterTest.h&quot;
</span><span class="cx"> #import &quot;DateTests.h&quot;
</span><span class="cx"> #import &quot;JSExportTests.h&quot;
</span><ins>+#import &quot;Regress141809.h&quot;
</ins><span class="cx"> 
</span><span class="cx"> #import &lt;pthread.h&gt;
</span><span class="cx"> 
</span><span class="lines">@@ -1431,6 +1432,7 @@
</span><span class="cx">     currentThisInsideBlockGetterTest();
</span><span class="cx">     runDateTests();
</span><span class="cx">     runJSExportTests();
</span><ins>+    runRegress141809();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> #else
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (180451 => 180452)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2015-02-20 21:39:01 UTC (rev 180451)
+++ trunk/Source/JavaScriptCore/ChangeLog        2015-02-20 21:51:37 UTC (rev 180452)
</span><span class="lines">@@ -1,3 +1,58 @@
</span><ins>+2015-02-20  Mark Lam  &lt;mark.lam@apple.com&gt;
+
+        [JSObjCClassInfo reallocateConstructorAndOrPrototype] should also reallocate super class prototype chain.
+        &lt;https://webkit.org/b/141809&gt;
+
+        Reviewed by Geoffrey Garen.
+
+        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
+        JS 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 subsequently
+        instantiated, then [JSObjCClassInfo reallocateConstructorAndOrPrototype]
+        should re-construct the prototype chain and constructor (if they were
+        previously released).  However, the current implementation only
+        re-constructs the immediate prototype, but not every other prototype
+        object upstream in the prototype chain.
+
+        To fix this, we do the following:
+        1. We no longer allocate the JSObjCClassInfo's prototype and constructor
+           eagerly.  Hence, -initWithContext:forClass: will no longer call
+           -allocateConstructorAndPrototypeWithSuperClassInfo:.
+        2. Instead, we'll always access the prototype and constructor thru
+           accessor methods.  The accessor methods will call
+           -allocateConstructorAndPrototype: if needed.
+        3. -allocateConstructorAndPrototype: will fetch the needed superClassInfo
+           from the JSWrapperMap itself.  This makes it so that we no longer
+           need to pass the superClassInfo all over.
+        4. -allocateConstructorAndPrototype: will get the super class prototype
+           by invoking -prototype: on the superClassInfo, thereby allowing the
+           super class to allocate its prototype and constructor if needed and
+           fixing the issue in this bug.
+
+        5. Also removed the GC warning comments, and ensured that needed JS
+           objects are kept alive by having a local var pointing to it from the
+           stack (which makes a GC root).
+
+        * API/JSWrapperMap.mm:
+        (-[JSObjCClassInfo initWithContext:forClass:]):
+        (-[JSObjCClassInfo allocateConstructorAndPrototype]):
+        (-[JSObjCClassInfo wrapperForObject:]):
+        (-[JSObjCClassInfo constructor]):
+        (-[JSObjCClassInfo prototype]):
+        (-[JSWrapperMap classInfoForClass:]):
+        (-[JSObjCClassInfo initWithContext:forClass:superClassInfo:]): Deleted.
+        (-[JSObjCClassInfo allocateConstructorAndPrototypeWithSuperClassInfo:]): Deleted.
+        (-[JSObjCClassInfo reallocateConstructorAndOrPrototype]): Deleted.
+        * API/tests/Regress141809.h: Added.
+        * API/tests/Regress141809.mm: Added.
+        (-[TestClassB name]):
+        (-[TestClassC name]):
+        (runRegress141809):
+        * API/tests/testapi.mm:
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+
</ins><span class="cx"> 2015-02-20  Alexey Proskuryakov  &lt;ap@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Remove svn:keywords property.
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreJavaScriptCorexcodeprojprojectpbxproj"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj (180451 => 180452)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj        2015-02-20 21:39:01 UTC (rev 180451)
+++ trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj        2015-02-20 21:51:37 UTC (rev 180452)
</span><span class="lines">@@ -1612,6 +1612,7 @@
</span><span class="cx">                 FE7BA6101A1A7CEC00F1F7B4 /* HeapVerifier.h in Headers */ = {isa = PBXBuildFile; fileRef = FE7BA60E1A1A7CEC00F1F7B4 /* HeapVerifier.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 FEA08620182B7A0400F6D851 /* Breakpoint.h in Headers */ = {isa = PBXBuildFile; fileRef = FEA0861E182B7A0400F6D851 /* Breakpoint.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 FEA08621182B7A0400F6D851 /* DebuggerPrimitives.h in Headers */ = {isa = PBXBuildFile; fileRef = FEA0861F182B7A0400F6D851 /* DebuggerPrimitives.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><ins>+                FEB51F6C1A97B688001F921C /* Regress141809.mm in Sources */ = {isa = PBXBuildFile; fileRef = FEB51F6B1A97B688001F921C /* Regress141809.mm */; };
</ins><span class="cx">                 FEB58C14187B8B160098EF0B /* ErrorHandlingScope.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FEB58C12187B8B160098EF0B /* ErrorHandlingScope.cpp */; };
</span><span class="cx">                 FEB58C15187B8B160098EF0B /* ErrorHandlingScope.h in Headers */ = {isa = PBXBuildFile; fileRef = FEB58C13187B8B160098EF0B /* ErrorHandlingScope.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 FED287B215EC9A5700DA8161 /* LLIntOpcode.h in Headers */ = {isa = PBXBuildFile; fileRef = FED287B115EC9A5700DA8161 /* LLIntOpcode.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="lines">@@ -3345,6 +3346,8 @@
</span><span class="cx">                 FE7BA60E1A1A7CEC00F1F7B4 /* HeapVerifier.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HeapVerifier.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 FEA0861E182B7A0400F6D851 /* Breakpoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Breakpoint.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 FEA0861F182B7A0400F6D851 /* DebuggerPrimitives.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DebuggerPrimitives.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><ins>+                FEB51F6A1A97B688001F921C /* Regress141809.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Regress141809.h; path = API/tests/Regress141809.h; sourceTree = &quot;&lt;group&gt;&quot;; };
+                FEB51F6B1A97B688001F921C /* Regress141809.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = Regress141809.mm; path = API/tests/Regress141809.mm; sourceTree = &quot;&lt;group&gt;&quot;; };
</ins><span class="cx">                 FEB58C12187B8B160098EF0B /* ErrorHandlingScope.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ErrorHandlingScope.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 FEB58C13187B8B160098EF0B /* ErrorHandlingScope.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ErrorHandlingScope.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 FED287B115EC9A5700DA8161 /* LLIntOpcode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LLIntOpcode.h; path = llint/LLIntOpcode.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="lines">@@ -3715,6 +3718,8 @@
</span><span class="cx">                                 C288B2DD18A54D3E007BE40B /* DateTests.mm */,
</span><span class="cx">                                 C2181FC018A948FB0025A235 /* JSExportTests.h */,
</span><span class="cx">                                 C2181FC118A948FB0025A235 /* JSExportTests.mm */,
</span><ins>+                                FEB51F6A1A97B688001F921C /* Regress141809.h */,
+                                FEB51F6B1A97B688001F921C /* Regress141809.mm */,
</ins><span class="cx">                                 144005170A531CB50005F061 /* minidom */,
</span><span class="cx">                                 14BD5A2D0A3E91F600BAF59C /* testapi.c */,
</span><span class="cx">                                 14D857740A4696C80032146C /* testapi.js */,
</span><span class="lines">@@ -6735,6 +6740,7 @@
</span><span class="cx">                         buildActionMask = 2147483647;
</span><span class="cx">                         files = (
</span><span class="cx">                                 C29ECB031804D0ED00D2CBB4 /* CurrentThisInsideBlockGetterTest.mm in Sources */,
</span><ins>+                                FEB51F6C1A97B688001F921C /* Regress141809.mm in Sources */,
</ins><span class="cx">                                 C20328201981979D0088B499 /* CustomGlobalObjectClassTest.c in Sources */,
</span><span class="cx">                                 C288B2DE18A54D3E007BE40B /* DateTests.mm in Sources */,
</span><span class="cx">                                 C2181FC218A948FB0025A235 /* JSExportTests.mm in Sources */,
</span></span></pre>
</div>
</div>

</body>
</html>