<!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>[194612] 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/194612">194612</a></dd>
<dt>Author</dt> <dd>keith_miller@apple.com</dd>
<dt>Date</dt> <dd>2016-01-05 14:49:44 -0800 (Tue, 05 Jan 2016)</dd>
</dl>

<h3>Log Message</h3>
<pre>[ES6] Arrays should be subclassable.
https://bugs.webkit.org/show_bug.cgi?id=152706

Reviewed by Benjamin Poulain.

This patch enables full subclassing of Arrays. We do this by fetching the new.target's prototype property
in the Array constructor and transitioning the old structure to have the new prototype. This method has
two downsides. The first is that we clobber the transition watchpoint on the base structure. The second,
which is currently very significant but should be fixed in a future patch, is that we allocate a new
structure for each new derived class we allocate.

* runtime/ArrayConstructor.cpp:
(JSC::constructArrayWithSizeQuirk):
(JSC::constructWithArrayConstructor):
(JSC::callArrayConstructor):
* runtime/ArrayConstructor.h:
* runtime/JSGlobalObject.h:
(JSC::JSGlobalObject::arrayStructureForIndexingTypeDuringAllocation):
(JSC::JSGlobalObject::arrayStructureForProfileDuringAllocation):
(JSC::constructEmptyArray):
(JSC::constructArray):
(JSC::constructArrayNegativeIndexed):
* runtime/PrototypeMap.h:
* runtime/Structure.h:
* runtime/StructureInlines.h:
(JSC::Structure::createSubclassStructure):
* tests/es6.yaml:
* tests/stress/class-subclassing-array.js: Added.
(A):
(B.prototype.get 1):
(B):
(C):
(test):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeArrayConstructorcpp">trunk/Source/JavaScriptCore/runtime/ArrayConstructor.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeArrayConstructorh">trunk/Source/JavaScriptCore/runtime/ArrayConstructor.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSGlobalObjecth">trunk/Source/JavaScriptCore/runtime/JSGlobalObject.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimePrototypeMaph">trunk/Source/JavaScriptCore/runtime/PrototypeMap.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeStructureh">trunk/Source/JavaScriptCore/runtime/Structure.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeStructureInlinesh">trunk/Source/JavaScriptCore/runtime/StructureInlines.h</a></li>
<li><a href="#trunkSourceJavaScriptCoretestses6yaml">trunk/Source/JavaScriptCore/tests/es6.yaml</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoretestsstressclasssubclassingarrayjs">trunk/Source/JavaScriptCore/tests/stress/class-subclassing-array.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (194611 => 194612)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2016-01-05 22:49:04 UTC (rev 194611)
+++ trunk/Source/JavaScriptCore/ChangeLog        2016-01-05 22:49:44 UTC (rev 194612)
</span><span class="lines">@@ -1,3 +1,39 @@
</span><ins>+2016-01-05  Keith Miller  &lt;keith_miller@apple.com&gt;
+
+        [ES6] Arrays should be subclassable.
+        https://bugs.webkit.org/show_bug.cgi?id=152706
+
+        Reviewed by Benjamin Poulain.
+
+        This patch enables full subclassing of Arrays. We do this by fetching the new.target's prototype property
+        in the Array constructor and transitioning the old structure to have the new prototype. This method has
+        two downsides. The first is that we clobber the transition watchpoint on the base structure. The second,
+        which is currently very significant but should be fixed in a future patch, is that we allocate a new
+        structure for each new derived class we allocate.
+
+        * runtime/ArrayConstructor.cpp:
+        (JSC::constructArrayWithSizeQuirk):
+        (JSC::constructWithArrayConstructor):
+        (JSC::callArrayConstructor):
+        * runtime/ArrayConstructor.h:
+        * runtime/JSGlobalObject.h:
+        (JSC::JSGlobalObject::arrayStructureForIndexingTypeDuringAllocation):
+        (JSC::JSGlobalObject::arrayStructureForProfileDuringAllocation):
+        (JSC::constructEmptyArray):
+        (JSC::constructArray):
+        (JSC::constructArrayNegativeIndexed):
+        * runtime/PrototypeMap.h:
+        * runtime/Structure.h:
+        * runtime/StructureInlines.h:
+        (JSC::Structure::createSubclassStructure):
+        * tests/es6.yaml:
+        * tests/stress/class-subclassing-array.js: Added.
+        (A):
+        (B.prototype.get 1):
+        (B):
+        (C):
+        (test):
+
</ins><span class="cx"> 2016-01-05  Filip Pizlo  &lt;fpizlo@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         regress/script-tests/deltablue-varargs.js.ftl-no-cjit-no-put-stack-validate on FTL B3 gets a B3 validation failure
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeArrayConstructorcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/ArrayConstructor.cpp (194611 => 194612)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/ArrayConstructor.cpp        2016-01-05 22:49:04 UTC (rev 194611)
+++ trunk/Source/JavaScriptCore/runtime/ArrayConstructor.cpp        2016-01-05 22:49:44 UTC (rev 194612)
</span><span class="lines">@@ -75,33 +75,39 @@
</span><span class="cx"> 
</span><span class="cx"> // ------------------------------ Functions ---------------------------
</span><span class="cx"> 
</span><del>-JSObject* constructArrayWithSizeQuirk(ExecState* exec, ArrayAllocationProfile* profile, JSGlobalObject* globalObject, JSValue length)
</del><ins>+JSObject* constructArrayWithSizeQuirk(ExecState* exec, ArrayAllocationProfile* profile, JSGlobalObject* globalObject, JSValue length, JSValue prototype)
</ins><span class="cx"> {
</span><span class="cx">     if (!length.isNumber())
</span><del>-        return constructArrayNegativeIndexed(exec, profile, globalObject, &amp;length, 1);
</del><ins>+        return constructArrayNegativeIndexed(exec, profile, globalObject, &amp;length, 1, prototype);
</ins><span class="cx">     
</span><span class="cx">     uint32_t n = length.toUInt32(exec);
</span><span class="cx">     if (n != length.toNumber(exec))
</span><span class="cx">         return exec-&gt;vm().throwException(exec, createRangeError(exec, ASCIILiteral(&quot;Array size is not a small enough positive integer.&quot;)));
</span><del>-    return constructEmptyArray(exec, profile, globalObject, n);
</del><ins>+    return constructEmptyArray(exec, profile, globalObject, n, prototype);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-static inline JSObject* constructArrayWithSizeQuirk(ExecState* exec, const ArgList&amp; args)
</del><ins>+static inline JSObject* constructArrayWithSizeQuirk(ExecState* exec, const ArgList&amp; args, JSValue prototype)
</ins><span class="cx"> {
</span><span class="cx">     JSGlobalObject* globalObject = asInternalFunction(exec-&gt;callee())-&gt;globalObject();
</span><span class="cx"> 
</span><span class="cx">     // a single numeric argument denotes the array size (!)
</span><span class="cx">     if (args.size() == 1)
</span><del>-        return constructArrayWithSizeQuirk(exec, 0, globalObject, args.at(0));
</del><ins>+        return constructArrayWithSizeQuirk(exec, nullptr, globalObject, args.at(0), prototype);
</ins><span class="cx"> 
</span><span class="cx">     // otherwise the array is constructed with the arguments in it
</span><del>-    return constructArray(exec, 0, globalObject, args);
</del><ins>+    return constructArray(exec, nullptr, globalObject, args, prototype);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> static EncodedJSValue JSC_HOST_CALL constructWithArrayConstructor(ExecState* exec)
</span><span class="cx"> {
</span><span class="cx">     ArgList args(exec);
</span><del>-    return JSValue::encode(constructArrayWithSizeQuirk(exec, args));
</del><ins>+
+    JSValue prototype = JSValue();
+    JSObject* newTarget = exec-&gt;newTarget().getObject();
+    if (newTarget-&gt;classInfo() != ArrayConstructor::info())
+        prototype = newTarget-&gt;get(exec, exec-&gt;propertyNames().prototype);
+
+    return JSValue::encode(constructArrayWithSizeQuirk(exec, args, prototype));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> ConstructType ArrayConstructor::getConstructData(JSCell*, ConstructData&amp; constructData)
</span><span class="lines">@@ -113,7 +119,7 @@
</span><span class="cx"> static EncodedJSValue JSC_HOST_CALL callArrayConstructor(ExecState* exec)
</span><span class="cx"> {
</span><span class="cx">     ArgList args(exec);
</span><del>-    return JSValue::encode(constructArrayWithSizeQuirk(exec, args));
</del><ins>+    return JSValue::encode(constructArrayWithSizeQuirk(exec, args, JSValue()));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> CallType ArrayConstructor::getCallData(JSCell*, CallData&amp; callData)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeArrayConstructorh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/ArrayConstructor.h (194611 => 194612)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/ArrayConstructor.h        2016-01-05 22:49:04 UTC (rev 194611)
+++ trunk/Source/JavaScriptCore/runtime/ArrayConstructor.h        2016-01-05 22:49:44 UTC (rev 194612)
</span><span class="lines">@@ -59,7 +59,7 @@
</span><span class="cx">     static CallType getCallData(JSCell*, CallData&amp;);
</span><span class="cx"> };
</span><span class="cx"> 
</span><del>-JSObject* constructArrayWithSizeQuirk(ExecState*, ArrayAllocationProfile*, JSGlobalObject*, JSValue);
</del><ins>+JSObject* constructArrayWithSizeQuirk(ExecState*, ArrayAllocationProfile*, JSGlobalObject*, JSValue length, JSValue prototype = JSValue());
</ins><span class="cx"> 
</span><span class="cx"> } // namespace JSC
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSGlobalObjecth"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSGlobalObject.h (194611 => 194612)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSGlobalObject.h        2016-01-05 22:49:04 UTC (rev 194611)
+++ trunk/Source/JavaScriptCore/runtime/JSGlobalObject.h        2016-01-05 22:49:44 UTC (rev 194612)
</span><span class="lines">@@ -247,6 +247,7 @@
</span><span class="cx">     // Lists the actual structures used for having these particular indexing shapes.
</span><span class="cx">     WriteBarrier&lt;Structure&gt; m_originalArrayStructureForIndexingShape[NumberOfIndexingShapes];
</span><span class="cx">     // Lists the structures we should use during allocation for these particular indexing shapes.
</span><ins>+    // These structures will differ from the originals list above when we are having a bad time.
</ins><span class="cx">     WriteBarrier&lt;Structure&gt; m_arrayStructureForIndexingShapeDuringAllocation[NumberOfIndexingShapes];
</span><span class="cx"> 
</span><span class="cx">     WriteBarrier&lt;Structure&gt; m_callbackConstructorStructure;
</span><span class="lines">@@ -481,10 +482,14 @@
</span><span class="cx">         ASSERT(indexingType &amp; IsArray);
</span><span class="cx">         return m_arrayStructureForIndexingShapeDuringAllocation[(indexingType &amp; IndexingShapeMask) &gt;&gt; IndexingShapeShift].get();
</span><span class="cx">     }
</span><del>-    Structure* arrayStructureForProfileDuringAllocation(ArrayAllocationProfile* profile) const
</del><ins>+    Structure* arrayStructureForIndexingTypeDuringAllocation(VM&amp; vm, IndexingType indexingType, JSValue prototype) const
</ins><span class="cx">     {
</span><del>-        return arrayStructureForIndexingTypeDuringAllocation(ArrayAllocationProfile::selectIndexingTypeFor(profile));
</del><ins>+        return Structure::createSubclassStructure(vm, arrayStructureForIndexingTypeDuringAllocation(indexingType), prototype);
</ins><span class="cx">     }
</span><ins>+    Structure* arrayStructureForProfileDuringAllocation(VM&amp; vm, ArrayAllocationProfile* profile, JSValue prototype) const
+    {
+        return arrayStructureForIndexingTypeDuringAllocation(vm, ArrayAllocationProfile::selectIndexingTypeFor(profile), prototype);
+    }
</ins><span class="cx">         
</span><span class="cx">     bool isOriginalArrayStructure(Structure* structure)
</span><span class="cx">     {
</span><span class="lines">@@ -721,44 +726,51 @@
</span><span class="cx">     return symbolTableGet(this, propertyName, slot, slotIsWriteable);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-inline JSArray* constructEmptyArray(ExecState* exec, ArrayAllocationProfile* profile, JSGlobalObject* globalObject, unsigned initialLength = 0)
</del><ins>+inline JSArray* constructEmptyArray(ExecState* exec, ArrayAllocationProfile* profile, JSGlobalObject* globalObject, unsigned initialLength = 0, JSValue prototype = JSValue())
</ins><span class="cx"> {
</span><del>-    return ArrayAllocationProfile::updateLastAllocationFor(profile, JSArray::create(exec-&gt;vm(), initialLength &gt;= MIN_ARRAY_STORAGE_CONSTRUCTION_LENGTH ? globalObject-&gt;arrayStructureForIndexingTypeDuringAllocation(ArrayWithArrayStorage) : globalObject-&gt;arrayStructureForProfileDuringAllocation(profile), initialLength));
</del><ins>+    VM&amp; vm = exec-&gt;vm();
+    Structure* structure;
+    if (initialLength &gt;= MIN_ARRAY_STORAGE_CONSTRUCTION_LENGTH)
+        structure = globalObject-&gt;arrayStructureForIndexingTypeDuringAllocation(vm, ArrayWithArrayStorage, prototype);
+    else
+        structure = globalObject-&gt;arrayStructureForProfileDuringAllocation(vm, profile, prototype);
+
+    return ArrayAllocationProfile::updateLastAllocationFor(profile, JSArray::create(vm, structure, initialLength));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-inline JSArray* constructEmptyArray(ExecState* exec, ArrayAllocationProfile* profile, unsigned initialLength = 0)
</del><ins>+inline JSArray* constructEmptyArray(ExecState* exec, ArrayAllocationProfile* profile, unsigned initialLength = 0, JSValue prototype = JSValue())
</ins><span class="cx"> {
</span><del>-    return constructEmptyArray(exec, profile, exec-&gt;lexicalGlobalObject(), initialLength);
</del><ins>+    return constructEmptyArray(exec, profile, exec-&gt;lexicalGlobalObject(), initialLength, prototype);
</ins><span class="cx"> }
</span><span class="cx">  
</span><del>-inline JSArray* constructArray(ExecState* exec, ArrayAllocationProfile* profile, JSGlobalObject* globalObject, const ArgList&amp; values)
</del><ins>+inline JSArray* constructArray(ExecState* exec, ArrayAllocationProfile* profile, JSGlobalObject* globalObject, const ArgList&amp; values, JSValue prototype = JSValue())
</ins><span class="cx"> {
</span><del>-    return ArrayAllocationProfile::updateLastAllocationFor(profile, constructArray(exec, globalObject-&gt;arrayStructureForProfileDuringAllocation(profile), values));
</del><ins>+    return ArrayAllocationProfile::updateLastAllocationFor(profile, constructArray(exec, globalObject-&gt;arrayStructureForProfileDuringAllocation(exec-&gt;vm(), profile, prototype), values));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-inline JSArray* constructArray(ExecState* exec, ArrayAllocationProfile* profile, const ArgList&amp; values)
</del><ins>+inline JSArray* constructArray(ExecState* exec, ArrayAllocationProfile* profile, const ArgList&amp; values, JSValue prototype = JSValue())
</ins><span class="cx"> {
</span><del>-    return constructArray(exec, profile, exec-&gt;lexicalGlobalObject(), values);
</del><ins>+    return constructArray(exec, profile, exec-&gt;lexicalGlobalObject(), values, prototype);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-inline JSArray* constructArray(ExecState* exec, ArrayAllocationProfile* profile, JSGlobalObject* globalObject, const JSValue* values, unsigned length)
</del><ins>+inline JSArray* constructArray(ExecState* exec, ArrayAllocationProfile* profile, JSGlobalObject* globalObject, const JSValue* values, unsigned length, JSValue prototype = JSValue())
</ins><span class="cx"> {
</span><del>-    return ArrayAllocationProfile::updateLastAllocationFor(profile, constructArray(exec, globalObject-&gt;arrayStructureForProfileDuringAllocation(profile), values, length));
</del><ins>+    return ArrayAllocationProfile::updateLastAllocationFor(profile, constructArray(exec, globalObject-&gt;arrayStructureForProfileDuringAllocation(exec-&gt;vm(), profile, prototype), values, length));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-inline JSArray* constructArray(ExecState* exec, ArrayAllocationProfile* profile, const JSValue* values, unsigned length)
</del><ins>+inline JSArray* constructArray(ExecState* exec, ArrayAllocationProfile* profile, const JSValue* values, unsigned length, JSValue prototype = JSValue())
</ins><span class="cx"> {
</span><del>-    return constructArray(exec, profile, exec-&gt;lexicalGlobalObject(), values, length);
</del><ins>+    return constructArray(exec, profile, exec-&gt;lexicalGlobalObject(), values, length, prototype);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-inline JSArray* constructArrayNegativeIndexed(ExecState* exec, ArrayAllocationProfile* profile, JSGlobalObject* globalObject, const JSValue* values, unsigned length)
</del><ins>+inline JSArray* constructArrayNegativeIndexed(ExecState* exec, ArrayAllocationProfile* profile, JSGlobalObject* globalObject, const JSValue* values, unsigned length, JSValue prototype = JSValue())
</ins><span class="cx"> {
</span><del>-    return ArrayAllocationProfile::updateLastAllocationFor(profile, constructArrayNegativeIndexed(exec, globalObject-&gt;arrayStructureForProfileDuringAllocation(profile), values, length));
</del><ins>+    return ArrayAllocationProfile::updateLastAllocationFor(profile, constructArrayNegativeIndexed(exec, globalObject-&gt;arrayStructureForProfileDuringAllocation(exec-&gt;vm(), profile, prototype), values, length));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-inline JSArray* constructArrayNegativeIndexed(ExecState* exec, ArrayAllocationProfile* profile, const JSValue* values, unsigned length)
</del><ins>+inline JSArray* constructArrayNegativeIndexed(ExecState* exec, ArrayAllocationProfile* profile, const JSValue* values, unsigned length, JSValue prototype = JSValue())
</ins><span class="cx"> {
</span><del>-    return constructArrayNegativeIndexed(exec, profile, exec-&gt;lexicalGlobalObject(), values, length);
</del><ins>+    return constructArrayNegativeIndexed(exec, profile, exec-&gt;lexicalGlobalObject(), values, length, prototype);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> inline JSObject* ExecState::globalThisValue() const
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimePrototypeMaph"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/PrototypeMap.h (194611 => 194612)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/PrototypeMap.h        2016-01-05 22:49:04 UTC (rev 194611)
+++ trunk/Source/JavaScriptCore/runtime/PrototypeMap.h        2016-01-05 22:49:44 UTC (rev 194612)
</span><span class="lines">@@ -46,7 +46,7 @@
</span><span class="cx"> 
</span><span class="cx">     JS_EXPORT_PRIVATE Structure* emptyObjectStructureForPrototype(JSObject*, unsigned inlineCapacity);
</span><span class="cx">     void clearEmptyObjectStructureForPrototype(JSObject*, unsigned inlineCapacity);
</span><del>-    void addPrototype(JSObject*);
</del><ins>+    JS_EXPORT_PRIVATE void addPrototype(JSObject*);
</ins><span class="cx">     TriState isPrototype(JSObject*) const; // Returns a conservative estimate.
</span><span class="cx"> 
</span><span class="cx"> private:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeStructureh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/Structure.h (194611 => 194612)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/Structure.h        2016-01-05 22:49:04 UTC (rev 194611)
+++ trunk/Source/JavaScriptCore/runtime/Structure.h        2016-01-05 22:49:44 UTC (rev 194612)
</span><span class="lines">@@ -238,7 +238,7 @@
</span><span class="cx">         return !!(indexingTypeIncludingHistory() &amp; MayHaveIndexedAccessors);
</span><span class="cx">     }
</span><span class="cx">         
</span><del>-    bool anyObjectInChainMayInterceptIndexedAccesses() const;
</del><ins>+    JS_EXPORT_PRIVATE bool anyObjectInChainMayInterceptIndexedAccesses() const;
</ins><span class="cx">     bool holesMustForwardToPrototype(VM&amp;) const;
</span><span class="cx">         
</span><span class="cx">     bool needsSlowPutIndexing() const;
</span><span class="lines">@@ -413,6 +413,7 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     static Structure* createStructure(VM&amp;);
</span><ins>+    JS_EXPORT_PRIVATE static Structure* createSubclassStructure(VM&amp;, Structure* baseStructure, JSValue prototype);
</ins><span class="cx">         
</span><span class="cx">     bool transitionWatchpointSetHasBeenInvalidated() const
</span><span class="cx">     {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeStructureInlinesh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/StructureInlines.h (194611 => 194612)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/StructureInlines.h        2016-01-05 22:49:04 UTC (rev 194611)
+++ trunk/Source/JavaScriptCore/runtime/StructureInlines.h        2016-01-05 22:49:44 UTC (rev 194612)
</span><span class="lines">@@ -27,6 +27,7 @@
</span><span class="cx"> #define StructureInlines_h
</span><span class="cx"> 
</span><span class="cx"> #include &quot;JSArrayBufferView.h&quot;
</span><ins>+#include &quot;JSCJSValueInlines.h&quot;
</ins><span class="cx"> #include &quot;JSGlobalObject.h&quot;
</span><span class="cx"> #include &quot;PropertyMapHashTable.h&quot;
</span><span class="cx"> #include &quot;Structure.h&quot;
</span><span class="lines">@@ -51,6 +52,28 @@
</span><span class="cx">     return structure;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+inline Structure* Structure::createSubclassStructure(VM&amp; vm, Structure* baseStructure, JSValue prototype)
+{
+    if (!prototype)
+        return baseStructure;
+
+    ASSERT(prototype != baseStructure-&gt;m_prototype.get());
+    ASSERT(prototype.isObject() || prototype.isNull());
+
+    if (prototype.isObject())
+        vm.prototypeMap.addPrototype(prototype.getObject());
+
+    // FIXME: This is super bad, not only does this transition the original prototype but it also causes a new structure
+    // to be created each time we allocate a new subclassed object for a builtin. Instead we should allocate a new structure
+    // that is identical other than the new prototype then we should cache it. https://bugs.webkit.org/show_bug.cgi?id=152710
+    Structure* newStructure = changePrototypeTransition(vm, baseStructure, prototype);
+
+    if (hasIndexedProperties(newStructure-&gt;indexingType()) &amp;&amp; newStructure-&gt;anyObjectInChainMayInterceptIndexedAccesses())
+        newStructure-&gt;m_blob.setIndexingType((newStructure-&gt;indexingType() &amp; ~IndexingShapeMask) | SlowPutArrayStorageShape);
+
+    return newStructure;
+}
+
</ins><span class="cx"> inline Structure* Structure::create(VM&amp; vm, Structure* structure, DeferredStructureTransitionWatchpointFire* deferred)
</span><span class="cx"> {
</span><span class="cx">     ASSERT(vm.structureStructure);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoretestses6yaml"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/tests/es6.yaml (194611 => 194612)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/tests/es6.yaml        2016-01-05 22:49:04 UTC (rev 194611)
+++ trunk/Source/JavaScriptCore/tests/es6.yaml        2016-01-05 22:49:44 UTC (rev 194612)
</span><span class="lines">@@ -711,9 +711,9 @@
</span><span class="cx"> - path: es6/well-known_symbols_Symbol.unscopables.js
</span><span class="cx">   cmd: runES6 :normal
</span><span class="cx"> - path: es6/Array_is_subclassable_Array.from.js
</span><del>-  cmd: runES6 :fail
</del><ins>+  cmd: runES6 :normal
</ins><span class="cx"> - path: es6/Array_is_subclassable_Array.of.js
</span><del>-  cmd: runES6 :fail
</del><ins>+  cmd: runES6 :normal
</ins><span class="cx"> - path: es6/Array_is_subclassable_Array.prototype.concat.js
</span><span class="cx">   cmd: runES6 :fail
</span><span class="cx"> - path: es6/Array_is_subclassable_Array.prototype.filter.js
</span><span class="lines">@@ -725,7 +725,7 @@
</span><span class="cx"> - path: es6/Array_is_subclassable_Array.prototype.splice.js
</span><span class="cx">   cmd: runES6 :fail
</span><span class="cx"> - path: es6/Array_is_subclassable_correct_prototype_chain.js
</span><del>-  cmd: runES6 :fail
</del><ins>+  cmd: runES6 :normal
</ins><span class="cx"> - path: es6/Array_static_methods_Array.from_generator_instances.js
</span><span class="cx">   cmd: runES6 :normal
</span><span class="cx"> - path: es6/Array_static_methods_Array.from_generic_iterables.js
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoretestsstressclasssubclassingarrayjs"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/tests/stress/class-subclassing-array.js (0 => 194612)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/tests/stress/class-subclassing-array.js                                (rev 0)
+++ trunk/Source/JavaScriptCore/tests/stress/class-subclassing-array.js        2016-01-05 22:49:44 UTC (rev 194612)
</span><span class="lines">@@ -0,0 +1,35 @@
</span><ins>+// This file tests subclassing arrays.
+
+class A extends Array { }
+class B extends A { get 1() { return 1; } }
+class C extends B { }
+
+function test() {
+
+    a = new A();
+    b = new B();
+    c = new C();
+
+    if (!Array.isArray(a) || !Array.isArray(b) || !Array.isArray(c))
+        throw &quot;subclasses are not arrays&quot;;
+
+    if (!(a instanceof Array &amp;&amp; a instanceof A))
+        throw &quot;b has incorrect prototype chain&quot;;
+
+    if (!(b instanceof Array &amp;&amp; b instanceof A &amp;&amp; b instanceof B))
+        throw &quot;b has incorrect prototype chain&quot;;
+
+    if (!(c instanceof Array &amp;&amp; c instanceof A &amp;&amp; c instanceof B &amp;&amp; c instanceof C))
+        throw &quot;c has incorrect prototype chain&quot;;
+
+    a[1] = 2;
+    b[1] = 2;
+    c[1] = 2;
+
+    if (a[1] !== 2 || b[1] !== 1 || c[1] !== 1)
+        throw &quot;bad indexing type&quot;;
+}
+noInline(test);
+
+for(i = 0; i &lt; 10000; i++)
+    test();
</ins></span></pre>
</div>
</div>

</body>
</html>