<!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>[181806] 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/181806">181806</a></dd>
<dt>Author</dt> <dd>mark.lam@apple.com</dd>
<dt>Date</dt> <dd>2015-03-20 11:08:29 -0700 (Fri, 20 Mar 2015)</dd>
</dl>

<h3>Log Message</h3>
<pre>JSCallbackObject&lt;JSGlobalObject&gt; should not destroy its JSCallbackObjectData before all its finalizers have been called.
&lt;https://webkit.org/b/142846&gt;

Reviewed by Geoffrey Garen.

Currently, JSCallbackObject&lt;JSGlobalObject&gt; registers weak finalizers via 2 mechanisms:
1. JSCallbackObject&lt;Parent&gt;::init() registers a weak finalizer for all JSClassRef
   that a JSCallbackObject references.
2. JSCallbackObject&lt;JSGlobalObject&gt;::create() registers a finalizer via
   vm.heap.addFinalizer() which destroys the JSCallbackObject.

The first finalizer is implemented as a virtual function of a JSCallbackObjectData
instance that will be destructed if the 2nd finalizer is called.  Hence, if the
2nd finalizer if called first, the later invocation of the 1st finalizer will
result in a crash.

This patch fixes the issue by eliminating the finalizer registration in init().
Instead, we'll have the JSCallbackObject destructor call all the JSClassRef finalizers
if needed.  This ensures that these finalizers are called before the JSCallbackObject
is destructor.

Also added assertions to a few Heap functions because JSCell::classInfo() expects
all objects that are allocated from MarkedBlock::Normal blocks to be derived from
JSDestructibleObject.  These assertions will help us catch violations of this
expectation earlier.

* API/JSCallbackObject.cpp:
(JSC::JSCallbackObjectData::finalize): Deleted.
* API/JSCallbackObject.h:
(JSC::JSCallbackObjectData::~JSCallbackObjectData):
* API/JSCallbackObjectFunctions.h:
(JSC::JSCallbackObject&lt;Parent&gt;::~JSCallbackObject):
(JSC::JSCallbackObject&lt;Parent&gt;::init):
* API/tests/GlobalContextWithFinalizerTest.cpp: Added.
(finalize):
(testGlobalContextWithFinalizer):
* API/tests/GlobalContextWithFinalizerTest.h: Added.
* API/tests/testapi.c:
(main):
* JavaScriptCore.vcxproj/testapi/testapi.vcxproj:
* JavaScriptCore.vcxproj/testapi/testapi.vcxproj.filters:
* JavaScriptCore.xcodeproj/project.pbxproj:
* heap/HeapInlines.h:
(JSC::Heap::allocateObjectOfType):
(JSC::Heap::subspaceForObjectOfType):
(JSC::Heap::allocatorForObjectOfType):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreAPIJSCallbackObjectcpp">trunk/Source/JavaScriptCore/API/JSCallbackObject.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreAPIJSCallbackObjecth">trunk/Source/JavaScriptCore/API/JSCallbackObject.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreAPIJSCallbackObjectFunctionsh">trunk/Source/JavaScriptCore/API/JSCallbackObjectFunctions.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreAPIteststestapic">trunk/Source/JavaScriptCore/API/tests/testapi.c</a></li>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreJavaScriptCorevcxprojtestapitestapivcxproj">trunk/Source/JavaScriptCore/JavaScriptCore.vcxproj/testapi/testapi.vcxproj</a></li>
<li><a href="#trunkSourceJavaScriptCoreJavaScriptCorevcxprojtestapitestapivcxprojfilters">trunk/Source/JavaScriptCore/JavaScriptCore.vcxproj/testapi/testapi.vcxproj.filters</a></li>
<li><a href="#trunkSourceJavaScriptCoreJavaScriptCorexcodeprojprojectpbxproj">trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapHeapInlinesh">trunk/Source/JavaScriptCore/heap/HeapInlines.h</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreAPItestsGlobalContextWithFinalizerTestcpp">trunk/Source/JavaScriptCore/API/tests/GlobalContextWithFinalizerTest.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreAPItestsGlobalContextWithFinalizerTesth">trunk/Source/JavaScriptCore/API/tests/GlobalContextWithFinalizerTest.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceJavaScriptCoreAPIJSCallbackObjectcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/API/JSCallbackObject.cpp (181805 => 181806)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/API/JSCallbackObject.cpp        2015-03-20 17:53:31 UTC (rev 181805)
+++ trunk/Source/JavaScriptCore/API/JSCallbackObject.cpp        2015-03-20 18:08:29 UTC (rev 181806)
</span><span class="lines">@@ -61,15 +61,4 @@
</span><span class="cx">     return Structure::create(vm, globalObject, proto, TypeInfo(GlobalObjectType, StructureFlags), info()); 
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void JSCallbackObjectData::finalize(Handle&lt;Unknown&gt; handle, void* context)
-{
-    JSClassRef jsClass = static_cast&lt;JSClassRef&gt;(context);
-    JSObjectRef thisRef = toRef(static_cast&lt;JSObject*&gt;(handle.get().asCell()));
-    
-    for (; jsClass; jsClass = jsClass-&gt;parentClass)
-        if (JSObjectFinalizeCallback finalize = jsClass-&gt;finalize)
-            finalize(thisRef);
-    WeakSet::deallocate(WeakImpl::asWeakImpl(handle.slot()));
-}
-    
</del><span class="cx"> } // namespace JSC
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreAPIJSCallbackObjecth"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/API/JSCallbackObject.h (181805 => 181806)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/API/JSCallbackObject.h        2015-03-20 17:53:31 UTC (rev 181805)
+++ trunk/Source/JavaScriptCore/API/JSCallbackObject.h        2015-03-20 18:08:29 UTC (rev 181806)
</span><span class="lines">@@ -33,7 +33,7 @@
</span><span class="cx"> 
</span><span class="cx"> namespace JSC {
</span><span class="cx"> 
</span><del>-struct JSCallbackObjectData : WeakHandleOwner {
</del><ins>+struct JSCallbackObjectData {
</ins><span class="cx">     JSCallbackObjectData(void* privateData, JSClassRef jsClass)
</span><span class="cx">         : privateData(privateData)
</span><span class="cx">         , jsClass(jsClass)
</span><span class="lines">@@ -41,7 +41,7 @@
</span><span class="cx">         JSClassRetain(jsClass);
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    virtual ~JSCallbackObjectData()
</del><ins>+    ~JSCallbackObjectData()
</ins><span class="cx">     {
</span><span class="cx">         JSClassRelease(jsClass);
</span><span class="cx">     }
</span><span class="lines">@@ -109,7 +109,6 @@
</span><span class="cx">         PrivatePropertyMap m_propertyMap;
</span><span class="cx">     };
</span><span class="cx">     std::unique_ptr&lt;JSPrivatePropertyMap&gt; m_privateProperties;
</span><del>-    virtual void finalize(Handle&lt;Unknown&gt;, void*) override;
</del><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx">     
</span><span class="lines">@@ -125,6 +124,8 @@
</span><span class="cx"> public:
</span><span class="cx">     typedef Parent Base;
</span><span class="cx"> 
</span><ins>+    ~JSCallbackObject();
+
</ins><span class="cx">     static JSCallbackObject* create(ExecState* exec, JSGlobalObject* globalObject, Structure* structure, JSClassRef classRef, void* data)
</span><span class="cx">     {
</span><span class="cx">         ASSERT_UNUSED(globalObject, !structure-&gt;globalObject() || structure-&gt;globalObject() == globalObject);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreAPIJSCallbackObjectFunctionsh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/API/JSCallbackObjectFunctions.h (181805 => 181806)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/API/JSCallbackObjectFunctions.h        2015-03-20 17:53:31 UTC (rev 181805)
+++ trunk/Source/JavaScriptCore/API/JSCallbackObjectFunctions.h        2015-03-20 18:08:29 UTC (rev 181806)
</span><span class="lines">@@ -74,6 +74,16 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> template &lt;class Parent&gt;
</span><ins>+JSCallbackObject&lt;Parent&gt;::~JSCallbackObject()
+{
+    JSObjectRef thisRef = toRef(static_cast&lt;JSObject*&gt;(this));
+    for (JSClassRef jsClass = classRef(); jsClass; jsClass = jsClass-&gt;parentClass) {
+        if (JSObjectFinalizeCallback finalize = jsClass-&gt;finalize)
+            finalize(thisRef);
+    }
+}
+    
+template &lt;class Parent&gt;
</ins><span class="cx"> void JSCallbackObject&lt;Parent&gt;::finishCreation(ExecState* exec)
</span><span class="cx"> {
</span><span class="cx">     Base::finishCreation(exec-&gt;vm());
</span><span class="lines">@@ -109,13 +119,6 @@
</span><span class="cx">         JSObjectInitializeCallback initialize = initRoutines[i];
</span><span class="cx">         initialize(toRef(exec), toRef(this));
</span><span class="cx">     }
</span><del>-
-    for (JSClassRef jsClassPtr = classRef(); jsClassPtr; jsClassPtr = jsClassPtr-&gt;parentClass) {
-        if (jsClassPtr-&gt;finalize) {
-            WeakSet::allocate(this, m_callbackObjectData.get(), classRef());
-            break;
-        }
-    }
</del><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> template &lt;class Parent&gt;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreAPItestsGlobalContextWithFinalizerTestcpp"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/API/tests/GlobalContextWithFinalizerTest.cpp (0 => 181806)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/API/tests/GlobalContextWithFinalizerTest.cpp                                (rev 0)
+++ trunk/Source/JavaScriptCore/API/tests/GlobalContextWithFinalizerTest.cpp        2015-03-20 18:08:29 UTC (rev 181806)
</span><span class="lines">@@ -0,0 +1,56 @@
</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.
+ */
+
+#include &quot;config.h&quot;
+#include &quot;GlobalContextWithFinalizerTest.h&quot;
+
+#include &quot;JavaScriptCore.h&quot;
+#include &lt;wtf/DataLog.h&gt;
+
+static bool failed = true;
+
+static void finalize(JSObjectRef)
+{
+    failed = false;
+}
+
+int testGlobalContextWithFinalizer()
+{
+    JSClassDefinition def = kJSClassDefinitionEmpty;
+    def.className = &quot;testClass&quot;;
+    def.finalize = finalize;
+    JSClassRef classRef = JSClassCreate(&amp;def);
+    
+    JSGlobalContextRef ref = JSGlobalContextCreateInGroup(nullptr, classRef);
+    JSGlobalContextRelease(ref);
+    JSClassRelease(classRef);
+
+    if (failed)
+        printf(&quot;FAIL: JSGlobalContextRef did not call its JSClassRef finalizer.\n&quot;);
+    else
+        printf(&quot;PASS: JSGlobalContextRef called its JSClassRef finalizer as expected.\n&quot;);
+
+    return failed;
+}
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoreAPItestsGlobalContextWithFinalizerTesth"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/API/tests/GlobalContextWithFinalizerTest.h (0 => 181806)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/API/tests/GlobalContextWithFinalizerTest.h                                (rev 0)
+++ trunk/Source/JavaScriptCore/API/tests/GlobalContextWithFinalizerTest.h        2015-03-20 18:08:29 UTC (rev 181806)
</span><span class="lines">@@ -0,0 +1,42 @@
</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.
+ */
+
+#ifndef GlobalContextWithFinalizerTest_h
+#define GlobalContextWithFinalizerTest_h
+
+#include &quot;JSContextRefPrivate.h&quot;
+
+#ifdef __cplusplus
+extern &quot;C&quot; {
+#endif
+
+/* Returns 1 if failures were encountered.  Else, returns 0. */
+int testGlobalContextWithFinalizer();
+    
+#ifdef __cplusplus
+} /* extern &quot;C&quot; */
+#endif
+
+#endif /* GlobalContextWithFinalizerTest_h */
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoreAPIteststestapic"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/API/tests/testapi.c (181805 => 181806)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/API/tests/testapi.c        2015-03-20 17:53:31 UTC (rev 181805)
+++ trunk/Source/JavaScriptCore/API/tests/testapi.c        2015-03-20 18:08:29 UTC (rev 181806)
</span><span class="lines">@@ -41,6 +41,7 @@
</span><span class="cx"> 
</span><span class="cx"> #include &quot;CompareAndSwapTest.h&quot;
</span><span class="cx"> #include &quot;CustomGlobalObjectClassTest.h&quot;
</span><ins>+#include &quot;GlobalContextWithFinalizerTest.h&quot;
</ins><span class="cx"> 
</span><span class="cx"> #if OS(DARWIN)
</span><span class="cx"> #include &quot;ExecutionTimeLimitTest.h&quot;
</span><span class="lines">@@ -1856,6 +1857,7 @@
</span><span class="cx"> #if OS(DARWIN)
</span><span class="cx">     failed = testExecutionTimeLimit(&amp;context) || failed;
</span><span class="cx"> #endif /* OS(DARWIN) */
</span><ins>+    failed = testGlobalContextWithFinalizer() || failed;
</ins><span class="cx"> 
</span><span class="cx">     // Clear out local variables pointing at JSObjectRefs to allow their values to be collected
</span><span class="cx">     function = NULL;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (181805 => 181806)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2015-03-20 17:53:31 UTC (rev 181805)
+++ trunk/Source/JavaScriptCore/ChangeLog        2015-03-20 18:08:29 UTC (rev 181806)
</span><span class="lines">@@ -1,3 +1,52 @@
</span><ins>+2015-03-19  Mark Lam  &lt;mark.lam@apple.com&gt;
+
+        JSCallbackObject&lt;JSGlobalObject&gt; should not destroy its JSCallbackObjectData before all its finalizers have been called.
+        &lt;https://webkit.org/b/142846&gt;
+
+        Reviewed by Geoffrey Garen.
+
+        Currently, JSCallbackObject&lt;JSGlobalObject&gt; registers weak finalizers via 2 mechanisms:
+        1. JSCallbackObject&lt;Parent&gt;::init() registers a weak finalizer for all JSClassRef
+           that a JSCallbackObject references.
+        2. JSCallbackObject&lt;JSGlobalObject&gt;::create() registers a finalizer via
+           vm.heap.addFinalizer() which destroys the JSCallbackObject.
+
+        The first finalizer is implemented as a virtual function of a JSCallbackObjectData
+        instance that will be destructed if the 2nd finalizer is called.  Hence, if the
+        2nd finalizer if called first, the later invocation of the 1st finalizer will
+        result in a crash.
+
+        This patch fixes the issue by eliminating the finalizer registration in init().
+        Instead, we'll have the JSCallbackObject destructor call all the JSClassRef finalizers
+        if needed.  This ensures that these finalizers are called before the JSCallbackObject
+        is destructor.
+
+        Also added assertions to a few Heap functions because JSCell::classInfo() expects
+        all objects that are allocated from MarkedBlock::Normal blocks to be derived from
+        JSDestructibleObject.  These assertions will help us catch violations of this
+        expectation earlier.
+
+        * API/JSCallbackObject.cpp:
+        (JSC::JSCallbackObjectData::finalize): Deleted.
+        * API/JSCallbackObject.h:
+        (JSC::JSCallbackObjectData::~JSCallbackObjectData):
+        * API/JSCallbackObjectFunctions.h:
+        (JSC::JSCallbackObject&lt;Parent&gt;::~JSCallbackObject):
+        (JSC::JSCallbackObject&lt;Parent&gt;::init):
+        * API/tests/GlobalContextWithFinalizerTest.cpp: Added.
+        (finalize):
+        (testGlobalContextWithFinalizer):
+        * API/tests/GlobalContextWithFinalizerTest.h: Added.
+        * API/tests/testapi.c:
+        (main):
+        * JavaScriptCore.vcxproj/testapi/testapi.vcxproj:
+        * JavaScriptCore.vcxproj/testapi/testapi.vcxproj.filters:
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * heap/HeapInlines.h:
+        (JSC::Heap::allocateObjectOfType):
+        (JSC::Heap::subspaceForObjectOfType):
+        (JSC::Heap::allocatorForObjectOfType):
+
</ins><span class="cx"> 2015-03-19  Andreas Kling  &lt;akling@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         JSCallee unnecessarily overrides a bunch of things in the method table.
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreJavaScriptCorevcxprojtestapitestapivcxproj"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/JavaScriptCore.vcxproj/testapi/testapi.vcxproj (181805 => 181806)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/JavaScriptCore.vcxproj/testapi/testapi.vcxproj        2015-03-20 17:53:31 UTC (rev 181805)
+++ trunk/Source/JavaScriptCore/JavaScriptCore.vcxproj/testapi/testapi.vcxproj        2015-03-20 18:08:29 UTC (rev 181806)
</span><span class="lines">@@ -296,6 +296,8 @@
</span><span class="cx">     &lt;ClInclude Include=&quot;..\..\API\tests\CompareAndSwapTest.h&quot; /&gt;
</span><span class="cx">     &lt;ClCompile Include=&quot;..\..\API\tests\CustomGlobalObjectClassTest.c&quot; /&gt;
</span><span class="cx">     &lt;ClInclude Include=&quot;..\..\API\tests\CustomGlobalObjectClassTest.h&quot; /&gt;
</span><ins>+    &lt;ClCompile Include=&quot;..\..\API\tests\GlobalContextWithFinalizerTest.cpp&quot; /&gt;
+    &lt;ClInclude Include=&quot;..\..\API\tests\GlobalContextWithFinalizerTest.h&quot; /&gt;
</ins><span class="cx">   &lt;/ItemGroup&gt;
</span><span class="cx">   &lt;Import Project=&quot;$(VCTargetsPath)\Microsoft.Cpp.targets&quot; /&gt;
</span><span class="cx">   &lt;ImportGroup Label=&quot;ExtensionTargets&quot;&gt;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreJavaScriptCorevcxprojtestapitestapivcxprojfilters"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/JavaScriptCore.vcxproj/testapi/testapi.vcxproj.filters (181805 => 181806)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/JavaScriptCore.vcxproj/testapi/testapi.vcxproj.filters        2015-03-20 17:53:31 UTC (rev 181805)
+++ trunk/Source/JavaScriptCore/JavaScriptCore.vcxproj/testapi/testapi.vcxproj.filters        2015-03-20 18:08:29 UTC (rev 181806)
</span><span class="lines">@@ -12,5 +12,7 @@
</span><span class="cx">     &lt;ClInclude Include=&quot;..\..\API\tests\CompareAndSwapTest.h&quot; /&gt;
</span><span class="cx">     &lt;ClCompile Include=&quot;..\..\API\tests\CustomGlobalObjectClassTest.c&quot; /&gt;
</span><span class="cx">     &lt;ClInclude Include=&quot;..\..\API\tests\CustomGlobalObjectClassTest.h&quot; /&gt;
</span><ins>+    &lt;ClCompile Include=&quot;..\..\API\tests\GlobalContextWithFinalizerTest.cpp&quot; /&gt;
+    &lt;ClInclude Include=&quot;..\..\API\tests\GlobalContextWithFinalizerTest.h&quot; /&gt;
</ins><span class="cx">   &lt;/ItemGroup&gt;
</span><span class="cx"> &lt;/Project&gt;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreJavaScriptCorexcodeprojprojectpbxproj"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj (181805 => 181806)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj        2015-03-20 17:53:31 UTC (rev 181805)
+++ trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj        2015-03-20 18:08:29 UTC (rev 181806)
</span><span class="lines">@@ -1612,6 +1612,7 @@
</span><span class="cx">                 E49DC16C12EF294E00184A1F /* SourceProviderCache.h in Headers */ = {isa = PBXBuildFile; fileRef = E49DC15112EF272200184A1F /* SourceProviderCache.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 E49DC16D12EF295300184A1F /* SourceProviderCacheItem.h in Headers */ = {isa = PBXBuildFile; fileRef = E49DC14912EF261A00184A1F /* SourceProviderCacheItem.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 FE0D4A061AB8DD0A002F54BF /* ExecutionTimeLimitTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE0D4A041AB8DD0A002F54BF /* ExecutionTimeLimitTest.cpp */; };
</span><ins>+                FE0D4A091ABA2437002F54BF /* GlobalContextWithFinalizerTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE0D4A071ABA2437002F54BF /* GlobalContextWithFinalizerTest.cpp */; };
</ins><span class="cx">                 FE20CE9D15F04A9500DF3430 /* LLIntCLoop.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE20CE9B15F04A9500DF3430 /* LLIntCLoop.cpp */; };
</span><span class="cx">                 FE20CE9E15F04A9500DF3430 /* LLIntCLoop.h in Headers */ = {isa = PBXBuildFile; fileRef = FE20CE9C15F04A9500DF3430 /* LLIntCLoop.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 FE4A331F15BD2E07006F54F3 /* VMInspector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE4A331D15BD2E07006F54F3 /* VMInspector.cpp */; };
</span><span class="lines">@@ -3360,6 +3361,8 @@
</span><span class="cx">                 F692A8870255597D01FF60F7 /* JSCJSValue.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSCJSValue.cpp; sourceTree = &quot;&lt;group&gt;&quot;; tabWidth = 8; };
</span><span class="cx">                 FE0D4A041AB8DD0A002F54BF /* ExecutionTimeLimitTest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ExecutionTimeLimitTest.cpp; path = API/tests/ExecutionTimeLimitTest.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 FE0D4A051AB8DD0A002F54BF /* ExecutionTimeLimitTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ExecutionTimeLimitTest.h; path = API/tests/ExecutionTimeLimitTest.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><ins>+                FE0D4A071ABA2437002F54BF /* GlobalContextWithFinalizerTest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = GlobalContextWithFinalizerTest.cpp; path = API/tests/GlobalContextWithFinalizerTest.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
+                FE0D4A081ABA2437002F54BF /* GlobalContextWithFinalizerTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GlobalContextWithFinalizerTest.h; path = API/tests/GlobalContextWithFinalizerTest.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</ins><span class="cx">                 FE20CE9B15F04A9500DF3430 /* LLIntCLoop.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LLIntCLoop.cpp; path = llint/LLIntCLoop.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 FE20CE9C15F04A9500DF3430 /* LLIntCLoop.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LLIntCLoop.h; path = llint/LLIntCLoop.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 FE4A331D15BD2E07006F54F3 /* VMInspector.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = VMInspector.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="lines">@@ -3747,6 +3750,8 @@
</span><span class="cx">                                 C288B2DD18A54D3E007BE40B /* DateTests.mm */,
</span><span class="cx">                                 FE0D4A041AB8DD0A002F54BF /* ExecutionTimeLimitTest.cpp */,
</span><span class="cx">                                 FE0D4A051AB8DD0A002F54BF /* ExecutionTimeLimitTest.h */,
</span><ins>+                                FE0D4A071ABA2437002F54BF /* GlobalContextWithFinalizerTest.cpp */,
+                                FE0D4A081ABA2437002F54BF /* GlobalContextWithFinalizerTest.h */,
</ins><span class="cx">                                 C2181FC018A948FB0025A235 /* JSExportTests.h */,
</span><span class="cx">                                 C2181FC118A948FB0025A235 /* JSExportTests.mm */,
</span><span class="cx">                                 65570F581AA4C00A009B3C23 /* Regress141275.h */,
</span><span class="lines">@@ -6787,6 +6792,7 @@
</span><span class="cx">                         isa = PBXSourcesBuildPhase;
</span><span class="cx">                         buildActionMask = 2147483647;
</span><span class="cx">                         files = (
</span><ins>+                                FE0D4A091ABA2437002F54BF /* GlobalContextWithFinalizerTest.cpp in Sources */,
</ins><span class="cx">                                 65570F5A1AA4C3EA009B3C23 /* Regress141275.mm in Sources */,
</span><span class="cx">                                 C29ECB031804D0ED00D2CBB4 /* CurrentThisInsideBlockGetterTest.mm in Sources */,
</span><span class="cx">                                 FEB51F6C1A97B688001F921C /* Regress141809.mm in Sources */,
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapHeapInlinesh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/HeapInlines.h (181805 => 181806)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/HeapInlines.h        2015-03-20 17:53:31 UTC (rev 181805)
+++ trunk/Source/JavaScriptCore/heap/HeapInlines.h        2015-03-20 18:08:29 UTC (rev 181806)
</span><span class="lines">@@ -29,6 +29,8 @@
</span><span class="cx"> #include &quot;Heap.h&quot;
</span><span class="cx"> #include &quot;JSCell.h&quot;
</span><span class="cx"> #include &quot;Structure.h&quot;
</span><ins>+#include &lt;type_traits&gt;
+#include &lt;wtf/Assertions.h&gt;
</ins><span class="cx"> 
</span><span class="cx"> namespace JSC {
</span><span class="cx"> 
</span><span class="lines">@@ -237,6 +239,9 @@
</span><span class="cx"> template&lt;typename ClassType&gt;
</span><span class="cx"> void* Heap::allocateObjectOfType(size_t bytes)
</span><span class="cx"> {
</span><ins>+    // JSCell::classInfo() expects objects allocated with normal destructor to derive from JSDestructibleObject.
+    ASSERT((!ClassType::needsDestruction || ClassType::hasImmortalStructure || std::is_convertible&lt;ClassType, JSDestructibleObject&gt;::value));
+
</ins><span class="cx">     if (ClassType::needsDestruction &amp;&amp; ClassType::hasImmortalStructure)
</span><span class="cx">         return allocateWithImmortalStructureDestructor(bytes);
</span><span class="cx">     if (ClassType::needsDestruction)
</span><span class="lines">@@ -247,6 +252,9 @@
</span><span class="cx"> template&lt;typename ClassType&gt;
</span><span class="cx"> MarkedSpace::Subspace&amp; Heap::subspaceForObjectOfType()
</span><span class="cx"> {
</span><ins>+    // JSCell::classInfo() expects objects allocated with normal destructor to derive from JSDestructibleObject.
+    ASSERT((!ClassType::needsDestruction || ClassType::hasImmortalStructure || std::is_convertible&lt;ClassType, JSDestructibleObject&gt;::value));
+    
</ins><span class="cx">     if (ClassType::needsDestruction &amp;&amp; ClassType::hasImmortalStructure)
</span><span class="cx">         return subspaceForObjectsWithImmortalStructure();
</span><span class="cx">     if (ClassType::needsDestruction)
</span><span class="lines">@@ -257,6 +265,9 @@
</span><span class="cx"> template&lt;typename ClassType&gt;
</span><span class="cx"> MarkedAllocator&amp; Heap::allocatorForObjectOfType(size_t bytes)
</span><span class="cx"> {
</span><ins>+    // JSCell::classInfo() expects objects allocated with normal destructor to derive from JSDestructibleObject.
+    ASSERT((!ClassType::needsDestruction || ClassType::hasImmortalStructure || std::is_convertible&lt;ClassType, JSDestructibleObject&gt;::value));
+    
</ins><span class="cx">     if (ClassType::needsDestruction &amp;&amp; ClassType::hasImmortalStructure)
</span><span class="cx">         return allocatorForObjectWithImmortalStructureDestructor(bytes);
</span><span class="cx">     if (ClassType::needsDestruction)
</span></span></pre>
</div>
</div>

</body>
</html>