<!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>[225913] trunk</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/225913">225913</a></dd>
<dt>Author</dt> <dd>keith_miller@apple.com</dd>
<dt>Date</dt> <dd>2017-12-14 11:11:49 -0800 (Thu, 14 Dec 2017)</dd>
</dl>

<h3>Log Message</h3>
<pre>JSObjects should have a mask for loading indexed properties
https://bugs.webkit.org/show_bug.cgi?id=180768

Reviewed by Mark Lam.

JSTests:

* stress/int16-put-by-val-in-and-out-of-bounds.js:
(test):

Source/JavaScriptCore:

This patch adds a new member to JSObject that holds an indexing
mask.  The indexing mask is bitwise anded with the index used to
load a property.  If for whatever reason an attacker is able to
clobber the vectorLength of our butterfly they still won't be able
to read substantially past the end of the buttefly. For
performance reasons we don't use the indexing masking for
TypedArrays. Since TypedArrays are already gigacaged the risk of
wild reads is still restricted.

This patch is a <1% regression on Speedometer and ~3% regression
on JetStream in my testing.

* assembler/MacroAssembler.h:
(JSC::MacroAssembler::urshiftPtr):
* bytecode/AccessCase.cpp:
(JSC::AccessCase::generateImpl):
* dfg/DFGAbstractHeap.h:
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::emitAllocateRawObject):
(JSC::DFG::SpeculativeJIT::compileDoublePutByVal):
(JSC::DFG::SpeculativeJIT::compileNewFunctionCommon):
(JSC::DFG::SpeculativeJIT::compileCreateActivation):
(JSC::DFG::SpeculativeJIT::compileCreateDirectArguments):
(JSC::DFG::SpeculativeJIT::compileArraySlice):
(JSC::DFG::SpeculativeJIT::compileNukeStructureAndSetButterfly):
(JSC::DFG::SpeculativeJIT::compileNewStringObject):
(JSC::DFG::SpeculativeJIT::compileNewTypedArray):
* dfg/DFGSpeculativeJIT.h:
(JSC::DFG::SpeculativeJIT::emitAllocateJSObject):
(JSC::DFG::SpeculativeJIT::emitAllocateJSObjectWithKnownSize):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
(JSC::DFG::SpeculativeJIT::compileAllocateNewArrayWithSize):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
(JSC::DFG::SpeculativeJIT::compileAllocateNewArrayWithSize):
* ftl/FTLAbstractHeap.cpp:
(JSC::FTL::IndexedAbstractHeap::baseIndex):
* ftl/FTLAbstractHeap.h:
* ftl/FTLAbstractHeapRepository.h:
* ftl/FTLLowerDFGToB3.cpp:
(JSC::FTL::DFG::LowerDFGToB3::compileAtomicsReadModifyWrite):
(JSC::FTL::DFG::LowerDFGToB3::compileGetByVal):
(JSC::FTL::DFG::LowerDFGToB3::compileCreateActivation):
(JSC::FTL::DFG::LowerDFGToB3::compileNewFunction):
(JSC::FTL::DFG::LowerDFGToB3::compileCreateDirectArguments):
(JSC::FTL::DFG::LowerDFGToB3::compileNewStringObject):
(JSC::FTL::DFG::LowerDFGToB3::compileNewTypedArray):
(JSC::FTL::DFG::LowerDFGToB3::compileMaterializeNewObject):
(JSC::FTL::DFG::LowerDFGToB3::compileMaterializeCreateActivation):
(JSC::FTL::DFG::LowerDFGToB3::maskedIndex):
(JSC::FTL::DFG::LowerDFGToB3::computeButterflyIndexingMask):
(JSC::FTL::DFG::LowerDFGToB3::allocateObject):
(JSC::FTL::DFG::LowerDFGToB3::allocateVariableSizedObject):
(JSC::FTL::DFG::LowerDFGToB3::allocateJSArray):
(JSC::FTL::DFG::LowerDFGToB3::pointerIntoTypedArray):
* ftl/FTLOutput.h:
(JSC::FTL::Output::baseIndex):
* jit/AssemblyHelpers.h:
(JSC::AssemblyHelpers::emitComputeButterflyIndexingMask):
(JSC::AssemblyHelpers::nukeStructureAndStoreButterfly):
(JSC::AssemblyHelpers::emitAllocateJSObject):
(JSC::AssemblyHelpers::emitAllocateJSObjectWithKnownSize):
(JSC::AssemblyHelpers::emitAllocateVariableSizedJSObject):
(JSC::AssemblyHelpers::emitAllocateDestructibleObject):
(JSC::AssemblyHelpers::storeButterfly): Deleted.
* jit/JITOpcodes.cpp:
(JSC::JIT::emit_op_new_object):
(JSC::JIT::emit_op_create_this):
* jit/JITOpcodes32_64.cpp:
(JSC::JIT::emit_op_new_object):
(JSC::JIT::emit_op_create_this):
* jit/JITPropertyAccess.cpp:
(JSC::JIT::emitDoubleLoad):
(JSC::JIT::emitContiguousLoad):
(JSC::JIT::emitArrayStorageLoad):
* llint/LowLevelInterpreter32_64.asm:
* llint/LowLevelInterpreter64.asm:
* runtime/ArrayStorage.h:
(JSC::ArrayStorage::availableVectorLength):
* runtime/Butterfly.h:
(JSC::ContiguousData::ContiguousData):
(JSC::ContiguousData::at const):
(JSC::ContiguousData::at):
(JSC::Butterfly::publicLength const):
(JSC::Butterfly::vectorLength const):
(JSC::Butterfly::computeIndexingMaskForVectorLength):
(JSC::Butterfly::computeIndexingMask):
(JSC::Butterfly::contiguousInt32):
(JSC::ContiguousData::operator[] const): Deleted.
(JSC::ContiguousData::operator[]): Deleted.
(JSC::Butterfly::publicLength): Deleted.
(JSC::Butterfly::vectorLength): Deleted.
* runtime/ButterflyInlines.h:
(JSC::ContiguousData<T>::at const):
(JSC::ContiguousData<T>::at):
* runtime/ClonedArguments.cpp:
(JSC::ClonedArguments::createEmpty):
* runtime/JSArray.cpp:
(JSC::JSArray::tryCreateUninitializedRestricted):
(JSC::JSArray::appendMemcpy):
(JSC::JSArray::setLength):
(JSC::JSArray::pop):
(JSC::JSArray::fastSlice):
(JSC::JSArray::shiftCountWithArrayStorage):
(JSC::JSArray::shiftCountWithAnyIndexingType):
(JSC::JSArray::unshiftCountWithAnyIndexingType):
(JSC::JSArray::fillArgList):
(JSC::JSArray::copyToArguments):
* runtime/JSArrayBufferView.cpp:
(JSC::JSArrayBufferView::JSArrayBufferView):
* runtime/JSArrayInlines.h:
(JSC::JSArray::pushInline):
* runtime/JSFixedArray.h:
(JSC::JSFixedArray::createFromArray):
* runtime/JSGenericTypedArrayViewInlines.h:
(JSC::JSGenericTypedArrayView<Adaptor>::slowDownAndWasteMemory):
* runtime/JSObject.cpp:
(JSC::JSObject::getOwnPropertySlotByIndex):
(JSC::JSObject::putByIndex):
(JSC::JSObject::createInitialInt32):
(JSC::JSObject::createInitialDouble):
(JSC::JSObject::createInitialContiguous):
(JSC::JSObject::convertUndecidedToInt32):
(JSC::JSObject::convertUndecidedToDouble):
(JSC::JSObject::convertUndecidedToContiguous):
(JSC::JSObject::convertInt32ToDouble):
(JSC::JSObject::convertInt32ToArrayStorage):
(JSC::JSObject::convertDoubleToContiguous):
(JSC::JSObject::convertDoubleToArrayStorage):
(JSC::JSObject::convertContiguousToArrayStorage):
(JSC::JSObject::createInitialForValueAndSet):
(JSC::JSObject::deletePropertyByIndex):
(JSC::JSObject::getOwnPropertyNames):
(JSC::JSObject::putByIndexBeyondVectorLengthWithoutAttributes):
(JSC::JSObject::countElements):
(JSC::JSObject::ensureLengthSlow):
(JSC::JSObject::reallocateAndShrinkButterfly):
(JSC::JSObject::getEnumerableLength):
* runtime/JSObject.h:
(JSC::JSObject::canGetIndexQuickly):
(JSC::JSObject::getIndexQuickly):
(JSC::JSObject::tryGetIndexQuickly const):
(JSC::JSObject::setIndexQuickly):
(JSC::JSObject::initializeIndex):
(JSC::JSObject::initializeIndexWithoutBarrier):
(JSC::JSObject::butterflyIndexingMaskOffset):
(JSC::JSObject::butterflyIndexingMask const):
(JSC::JSObject::setButterflyWithIndexingMask):
(JSC::JSObject::setButterfly):
(JSC::JSObject::nukeStructureAndSetButterfly):
(JSC::JSObject::JSObject):
* runtime/RegExpMatchesArray.h:
(JSC::tryCreateUninitializedRegExpMatchesArray):
* runtime/Structure.cpp:
(JSC::Structure::flattenDictionaryStructure):

Source/WebCore:

* bindings/js/JSDOMConvertSequences.h:
(WebCore::Detail::NumericSequenceConverter::convertArray):
(WebCore::Detail::SequenceConverter::convertArray):

Source/WTF:

Add a clz that wraps the builtin clz intrinisics provided by
various compilers. The clz function by default assumes that
the input may be zero. On X86 this makes a difference because not
all CPUs have LZCNT and BSR has undefined behavior on zero. On ARM,
the zero check gets optimized away, regardless.

* wtf/StdLibExtras.h:
(std::clz):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkJSTestsChangeLog">trunk/JSTests/ChangeLog</a></li>
<li><a href="#trunkJSTestsstressint16putbyvalinandoutofboundsjs">trunk/JSTests/stress/int16-put-by-val-in-and-out-of-bounds.js</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>
<li><a href="#trunkSourceJavaScriptCoreassemblerMacroAssemblerh">trunk/Source/JavaScriptCore/assembler/MacroAssembler.h</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecodeAccessCasecpp">trunk/Source/JavaScriptCore/bytecode/AccessCase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGAbstractHeaph">trunk/Source/JavaScriptCore/dfg/DFGAbstractHeap.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGClobberizeh">trunk/Source/JavaScriptCore/dfg/DFGClobberize.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGSpeculativeJITcpp">trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGSpeculativeJITh">trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGSpeculativeJIT32_64cpp">trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGSpeculativeJIT64cpp">trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLAbstractHeapcpp">trunk/Source/JavaScriptCore/ftl/FTLAbstractHeap.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLAbstractHeaph">trunk/Source/JavaScriptCore/ftl/FTLAbstractHeap.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLAbstractHeapRepositoryh">trunk/Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLLowerDFGToB3cpp">trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLOutputh">trunk/Source/JavaScriptCore/ftl/FTLOutput.h</a></li>
<li><a href="#trunkSourceJavaScriptCorejitAssemblyHelpersh">trunk/Source/JavaScriptCore/jit/AssemblyHelpers.h</a></li>
<li><a href="#trunkSourceJavaScriptCorejitJITOpcodescpp">trunk/Source/JavaScriptCore/jit/JITOpcodes.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorejitJITOpcodes32_64cpp">trunk/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorejitJITPropertyAccesscpp">trunk/Source/JavaScriptCore/jit/JITPropertyAccess.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorellintLowLevelInterpreter32_64asm">trunk/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm</a></li>
<li><a href="#trunkSourceJavaScriptCorellintLowLevelInterpreter64asm">trunk/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeArrayStorageh">trunk/Source/JavaScriptCore/runtime/ArrayStorage.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeButterflyh">trunk/Source/JavaScriptCore/runtime/Butterfly.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeButterflyInlinesh">trunk/Source/JavaScriptCore/runtime/ButterflyInlines.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeClonedArgumentscpp">trunk/Source/JavaScriptCore/runtime/ClonedArguments.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSArraycpp">trunk/Source/JavaScriptCore/runtime/JSArray.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSArrayBufferViewcpp">trunk/Source/JavaScriptCore/runtime/JSArrayBufferView.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSArrayInlinesh">trunk/Source/JavaScriptCore/runtime/JSArrayInlines.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSFixedArrayh">trunk/Source/JavaScriptCore/runtime/JSFixedArray.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSGenericTypedArrayViewInlinesh">trunk/Source/JavaScriptCore/runtime/JSGenericTypedArrayViewInlines.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSObjectcpp">trunk/Source/JavaScriptCore/runtime/JSObject.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSObjecth">trunk/Source/JavaScriptCore/runtime/JSObject.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeRegExpMatchesArrayh">trunk/Source/JavaScriptCore/runtime/RegExpMatchesArray.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeStructurecpp">trunk/Source/JavaScriptCore/runtime/Structure.cpp</a></li>
<li><a href="#trunkSourceWTFChangeLog">trunk/Source/WTF/ChangeLog</a></li>
<li><a href="#trunkSourceWTFwtfStdLibExtrash">trunk/Source/WTF/wtf/StdLibExtras.h</a></li>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCorebindingsjsJSDOMConvertSequencesh">trunk/Source/WebCore/bindings/js/JSDOMConvertSequences.h</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkJSTestsstressflatteningprototyperemovebutterflyjs">trunk/JSTests/stress/flattening-prototype-remove-butterfly.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkJSTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/JSTests/ChangeLog (225912 => 225913)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/ChangeLog  2017-12-14 19:10:54 UTC (rev 225912)
+++ trunk/JSTests/ChangeLog     2017-12-14 19:11:49 UTC (rev 225913)
</span><span class="lines">@@ -1,3 +1,13 @@
</span><ins>+2017-12-13  Keith Miller  <keith_miller@apple.com>
+
+        JSObjects should have a mask for loading indexed properties
+        https://bugs.webkit.org/show_bug.cgi?id=180768
+
+        Reviewed by Mark Lam.
+
+        * stress/int16-put-by-val-in-and-out-of-bounds.js:
+        (test):
+
</ins><span class="cx"> 2017-12-13  Saam Barati  <sbarati@apple.com>
</span><span class="cx"> 
</span><span class="cx">         Arrow functions need their own structure because they have different properties than sloppy functions
</span></span></pre></div>
<a id="trunkJSTestsstressflatteningprototyperemovebutterflyjs"></a>
<div class="addfile"><h4>Added: trunk/JSTests/stress/flattening-prototype-remove-butterfly.js (0 => 225913)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/stress/flattening-prototype-remove-butterfly.js                            (rev 0)
+++ trunk/JSTests/stress/flattening-prototype-remove-butterfly.js       2017-12-14 19:11:49 UTC (rev 225913)
</span><span class="lines">@@ -0,0 +1,23 @@
</span><ins>+// Create an object with inline capacity 1.
+let obj = { foo: 1 };
+
+// Make it into a dictionary.
+delete obj.foo;
+
+// Get us to allocate out of line capacity.
+obj.foo = 1;
+obj.bar = 2;
+
+// Delete the inline property.
+delete obj.foo;
+
+let o = Object.create(obj);
+
+function foo() {
+    return o.toString();
+}
+noInline(foo);
+
+// Flatten into an empty butterfly.
+for (let i = 0; i < 10000; i++)
+    foo();
</ins></span></pre></div>
<a id="trunkJSTestsstressint16putbyvalinandoutofboundsjs"></a>
<div class="modfile"><h4>Modified: trunk/JSTests/stress/int16-put-by-val-in-and-out-of-bounds.js (225912 => 225913)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/stress/int16-put-by-val-in-and-out-of-bounds.js    2017-12-14 19:10:54 UTC (rev 225912)
+++ trunk/JSTests/stress/int16-put-by-val-in-and-out-of-bounds.js       2017-12-14 19:11:49 UTC (rev 225913)
</span><span class="lines">@@ -9,7 +9,7 @@
</span><span class="cx">     foo(a);
</span><span class="cx">     var result = a[42];
</span><span class="cx">     if (result != expected)
</span><del>-        throw "Error: bad value at a[42]: " + result;
</del><ins>+        throw new Error("bad value at a[42]: " + result);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> for (var i = 0; i < 100000; ++i) {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (225912 => 225913)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog    2017-12-14 19:10:54 UTC (rev 225912)
+++ trunk/Source/JavaScriptCore/ChangeLog       2017-12-14 19:11:49 UTC (rev 225913)
</span><span class="lines">@@ -1,3 +1,169 @@
</span><ins>+2017-12-13  Keith Miller  <keith_miller@apple.com>
+
+        JSObjects should have a mask for loading indexed properties
+        https://bugs.webkit.org/show_bug.cgi?id=180768
+
+        Reviewed by Mark Lam.
+
+        This patch adds a new member to JSObject that holds an indexing
+        mask.  The indexing mask is bitwise anded with the index used to
+        load a property.  If for whatever reason an attacker is able to
+        clobber the vectorLength of our butterfly they still won't be able
+        to read substantially past the end of the buttefly. For
+        performance reasons we don't use the indexing masking for
+        TypedArrays. Since TypedArrays are already gigacaged the risk of
+        wild reads is still restricted.
+
+        This patch is a <1% regression on Speedometer and ~3% regression
+        on JetStream in my testing.
+
+        * assembler/MacroAssembler.h:
+        (JSC::MacroAssembler::urshiftPtr):
+        * bytecode/AccessCase.cpp:
+        (JSC::AccessCase::generateImpl):
+        * dfg/DFGAbstractHeap.h:
+        * dfg/DFGClobberize.h:
+        (JSC::DFG::clobberize):
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::emitAllocateRawObject):
+        (JSC::DFG::SpeculativeJIT::compileDoublePutByVal):
+        (JSC::DFG::SpeculativeJIT::compileNewFunctionCommon):
+        (JSC::DFG::SpeculativeJIT::compileCreateActivation):
+        (JSC::DFG::SpeculativeJIT::compileCreateDirectArguments):
+        (JSC::DFG::SpeculativeJIT::compileArraySlice):
+        (JSC::DFG::SpeculativeJIT::compileNukeStructureAndSetButterfly):
+        (JSC::DFG::SpeculativeJIT::compileNewStringObject):
+        (JSC::DFG::SpeculativeJIT::compileNewTypedArray):
+        * dfg/DFGSpeculativeJIT.h:
+        (JSC::DFG::SpeculativeJIT::emitAllocateJSObject):
+        (JSC::DFG::SpeculativeJIT::emitAllocateJSObjectWithKnownSize):
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        (JSC::DFG::SpeculativeJIT::compileAllocateNewArrayWithSize):
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        (JSC::DFG::SpeculativeJIT::compileAllocateNewArrayWithSize):
+        * ftl/FTLAbstractHeap.cpp:
+        (JSC::FTL::IndexedAbstractHeap::baseIndex):
+        * ftl/FTLAbstractHeap.h:
+        * ftl/FTLAbstractHeapRepository.h:
+        * ftl/FTLLowerDFGToB3.cpp:
+        (JSC::FTL::DFG::LowerDFGToB3::compileAtomicsReadModifyWrite):
+        (JSC::FTL::DFG::LowerDFGToB3::compileGetByVal):
+        (JSC::FTL::DFG::LowerDFGToB3::compileCreateActivation):
+        (JSC::FTL::DFG::LowerDFGToB3::compileNewFunction):
+        (JSC::FTL::DFG::LowerDFGToB3::compileCreateDirectArguments):
+        (JSC::FTL::DFG::LowerDFGToB3::compileNewStringObject):
+        (JSC::FTL::DFG::LowerDFGToB3::compileNewTypedArray):
+        (JSC::FTL::DFG::LowerDFGToB3::compileMaterializeNewObject):
+        (JSC::FTL::DFG::LowerDFGToB3::compileMaterializeCreateActivation):
+        (JSC::FTL::DFG::LowerDFGToB3::maskedIndex):
+        (JSC::FTL::DFG::LowerDFGToB3::computeButterflyIndexingMask):
+        (JSC::FTL::DFG::LowerDFGToB3::allocateObject):
+        (JSC::FTL::DFG::LowerDFGToB3::allocateVariableSizedObject):
+        (JSC::FTL::DFG::LowerDFGToB3::allocateJSArray):
+        (JSC::FTL::DFG::LowerDFGToB3::pointerIntoTypedArray):
+        * ftl/FTLOutput.h:
+        (JSC::FTL::Output::baseIndex):
+        * jit/AssemblyHelpers.h:
+        (JSC::AssemblyHelpers::emitComputeButterflyIndexingMask):
+        (JSC::AssemblyHelpers::nukeStructureAndStoreButterfly):
+        (JSC::AssemblyHelpers::emitAllocateJSObject):
+        (JSC::AssemblyHelpers::emitAllocateJSObjectWithKnownSize):
+        (JSC::AssemblyHelpers::emitAllocateVariableSizedJSObject):
+        (JSC::AssemblyHelpers::emitAllocateDestructibleObject):
+        (JSC::AssemblyHelpers::storeButterfly): Deleted.
+        * jit/JITOpcodes.cpp:
+        (JSC::JIT::emit_op_new_object):
+        (JSC::JIT::emit_op_create_this):
+        * jit/JITOpcodes32_64.cpp:
+        (JSC::JIT::emit_op_new_object):
+        (JSC::JIT::emit_op_create_this):
+        * jit/JITPropertyAccess.cpp:
+        (JSC::JIT::emitDoubleLoad):
+        (JSC::JIT::emitContiguousLoad):
+        (JSC::JIT::emitArrayStorageLoad):
+        * llint/LowLevelInterpreter32_64.asm:
+        * llint/LowLevelInterpreter64.asm:
+        * runtime/ArrayStorage.h:
+        (JSC::ArrayStorage::availableVectorLength):
+        * runtime/Butterfly.h:
+        (JSC::ContiguousData::ContiguousData):
+        (JSC::ContiguousData::at const):
+        (JSC::ContiguousData::at):
+        (JSC::Butterfly::publicLength const):
+        (JSC::Butterfly::vectorLength const):
+        (JSC::Butterfly::computeIndexingMaskForVectorLength):
+        (JSC::Butterfly::computeIndexingMask):
+        (JSC::Butterfly::contiguousInt32):
+        (JSC::ContiguousData::operator[] const): Deleted.
+        (JSC::ContiguousData::operator[]): Deleted.
+        (JSC::Butterfly::publicLength): Deleted.
+        (JSC::Butterfly::vectorLength): Deleted.
+        * runtime/ButterflyInlines.h:
+        (JSC::ContiguousData<T>::at const):
+        (JSC::ContiguousData<T>::at):
+        * runtime/ClonedArguments.cpp:
+        (JSC::ClonedArguments::createEmpty):
+        * runtime/JSArray.cpp:
+        (JSC::JSArray::tryCreateUninitializedRestricted):
+        (JSC::JSArray::appendMemcpy):
+        (JSC::JSArray::setLength):
+        (JSC::JSArray::pop):
+        (JSC::JSArray::fastSlice):
+        (JSC::JSArray::shiftCountWithArrayStorage):
+        (JSC::JSArray::shiftCountWithAnyIndexingType):
+        (JSC::JSArray::unshiftCountWithAnyIndexingType):
+        (JSC::JSArray::fillArgList):
+        (JSC::JSArray::copyToArguments):
+        * runtime/JSArrayBufferView.cpp:
+        (JSC::JSArrayBufferView::JSArrayBufferView):
+        * runtime/JSArrayInlines.h:
+        (JSC::JSArray::pushInline):
+        * runtime/JSFixedArray.h:
+        (JSC::JSFixedArray::createFromArray):
+        * runtime/JSGenericTypedArrayViewInlines.h:
+        (JSC::JSGenericTypedArrayView<Adaptor>::slowDownAndWasteMemory):
+        * runtime/JSObject.cpp:
+        (JSC::JSObject::getOwnPropertySlotByIndex):
+        (JSC::JSObject::putByIndex):
+        (JSC::JSObject::createInitialInt32):
+        (JSC::JSObject::createInitialDouble):
+        (JSC::JSObject::createInitialContiguous):
+        (JSC::JSObject::convertUndecidedToInt32):
+        (JSC::JSObject::convertUndecidedToDouble):
+        (JSC::JSObject::convertUndecidedToContiguous):
+        (JSC::JSObject::convertInt32ToDouble):
+        (JSC::JSObject::convertInt32ToArrayStorage):
+        (JSC::JSObject::convertDoubleToContiguous):
+        (JSC::JSObject::convertDoubleToArrayStorage):
+        (JSC::JSObject::convertContiguousToArrayStorage):
+        (JSC::JSObject::createInitialForValueAndSet):
+        (JSC::JSObject::deletePropertyByIndex):
+        (JSC::JSObject::getOwnPropertyNames):
+        (JSC::JSObject::putByIndexBeyondVectorLengthWithoutAttributes):
+        (JSC::JSObject::countElements):
+        (JSC::JSObject::ensureLengthSlow):
+        (JSC::JSObject::reallocateAndShrinkButterfly):
+        (JSC::JSObject::getEnumerableLength):
+        * runtime/JSObject.h:
+        (JSC::JSObject::canGetIndexQuickly):
+        (JSC::JSObject::getIndexQuickly):
+        (JSC::JSObject::tryGetIndexQuickly const):
+        (JSC::JSObject::setIndexQuickly):
+        (JSC::JSObject::initializeIndex):
+        (JSC::JSObject::initializeIndexWithoutBarrier):
+        (JSC::JSObject::butterflyIndexingMaskOffset):
+        (JSC::JSObject::butterflyIndexingMask const):
+        (JSC::JSObject::setButterflyWithIndexingMask):
+        (JSC::JSObject::setButterfly):
+        (JSC::JSObject::nukeStructureAndSetButterfly):
+        (JSC::JSObject::JSObject):
+        * runtime/RegExpMatchesArray.h:
+        (JSC::tryCreateUninitializedRegExpMatchesArray):
+        * runtime/Structure.cpp:
+        (JSC::Structure::flattenDictionaryStructure):
+
</ins><span class="cx"> 2017-12-14  David Kilzer  <ddkilzer@apple.com>
</span><span class="cx"> 
</span><span class="cx">         REGRESSION (r225799/r225887): Remove duplicate entries for JSCPoisonedPtr.h in Xcode project
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreJavaScriptCorexcodeprojprojectpbxproj"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj (225912 => 225913)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj     2017-12-14 19:10:54 UTC (rev 225912)
+++ trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj        2017-12-14 19:11:49 UTC (rev 225913)
</span><span class="lines">@@ -1008,6 +1008,7 @@
</span><span class="cx">          536B319C1F735E7D0037FC33 /* UnifiedSource134.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 536B31971F735E5B0037FC33 /* UnifiedSource134.cpp */; };
</span><span class="cx">          536B319D1F735E7D0037FC33 /* UnifiedSource135.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 536B31991F735E5D0037FC33 /* UnifiedSource135.cpp */; };
</span><span class="cx">          536B319E1F735F160037FC33 /* LowLevelInterpreter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F4680C714BBB16900BFE272 /* LowLevelInterpreter.cpp */; };
</span><ins>+               5370806B1FE232DF00299E44 /* JSArrayBufferView.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2B66BB17B6B5AB00A7AE3F /* JSArrayBufferView.h */; };
</ins><span class="cx">           5370B4F61BF26205005C40FC /* AdaptiveInferredPropertyValueWatchpointBase.h in Headers */ = {isa = PBXBuildFile; fileRef = 5370B4F41BF25EA2005C40FC /* AdaptiveInferredPropertyValueWatchpointBase.h */; };
</span><span class="cx">          5381B9391E60E97D0090F794 /* WasmFaultSignalHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = 5381B9381E60E97D0090F794 /* WasmFaultSignalHandler.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">          53917E7B1B7906FA000EBD33 /* JSGenericTypedArrayViewPrototypeFunctions.h in Headers */ = {isa = PBXBuildFile; fileRef = 53917E7A1B7906E4000EBD33 /* JSGenericTypedArrayViewPrototypeFunctions.h */; };
</span><span class="lines">@@ -7993,6 +7994,7 @@
</span><span class="cx">                  files = (
</span><span class="cx">                          A72701B90DADE94900E548D7 /* ExceptionHelpers.h in Headers */,
</span><span class="cx">                          144005CB0A5338D10005F061 /* JSNode.h in Headers */,
</span><ins>+                               5370806B1FE232DF00299E44 /* JSArrayBufferView.h in Headers */,
</ins><span class="cx">                           144007570A5370D20005F061 /* JSNodeList.h in Headers */,
</span><span class="cx">                          144005CC0A5338F80005F061 /* Node.h in Headers */,
</span><span class="cx">                          1440074A0A536CC20005F061 /* NodeList.h in Headers */,
</span><span class="lines">@@ -8867,7 +8869,7 @@
</span><span class="cx">                          148CD1D8108CF902008163C6 /* JSContextRefPrivate.h in Headers */,
</span><span class="cx">                          FE2B0B731FD9EF700075DA5F /* JSCPoison.h in Headers */,
</span><span class="cx">                          FE2B0B691FD227E00075DA5F /* JSCPoisonedPtr.h in Headers */,
</span><del>-                               A72028B81797601E0098028C /* JSCTestRunnerUtils.h in Headers */,
</del><ins>+                                A72028B81797601E0098028C /* JSCTestRunnerUtils.h in Headers */,
</ins><span class="cx">                           72AAF7CE1D0D31B3005E60BE /* JSCustomGetterSetterFunction.h in Headers */,
</span><span class="cx">                          0F2B66EC17B6B5AB00A7AE3F /* JSDataView.h in Headers */,
</span><span class="cx">                          0F2B66EE17B6B5AB00A7AE3F /* JSDataViewPrototype.h in Headers */,
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreassemblerMacroAssemblerh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/assembler/MacroAssembler.h (225912 => 225913)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/assembler/MacroAssembler.h   2017-12-14 19:10:54 UTC (rev 225912)
+++ trunk/Source/JavaScriptCore/assembler/MacroAssembler.h      2017-12-14 19:11:49 UTC (rev 225913)
</span><span class="lines">@@ -592,6 +592,11 @@
</span><span class="cx">         urshift32(trustedImm32ForShift(imm), srcDest);
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    void urshiftPtr(RegisterID shiftAmmount, RegisterID srcDest)
+    {
+        urshift32(shiftAmmount, srcDest);
+    }
+
</ins><span class="cx">     void negPtr(RegisterID dest)
</span><span class="cx">     {
</span><span class="cx">         neg32(dest);
</span><span class="lines">@@ -906,6 +911,11 @@
</span><span class="cx">         urshift64(trustedImm32ForShift(imm), srcDest);
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    void urshiftPtr(RegisterID shiftAmmount, RegisterID srcDest)
+    {
+        urshift64(shiftAmmount, srcDest);
+    }
+
</ins><span class="cx">     void negPtr(RegisterID dest)
</span><span class="cx">     {
</span><span class="cx">         neg64(dest);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodeAccessCasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecode/AccessCase.cpp (225912 => 225913)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/AccessCase.cpp      2017-12-14 19:10:54 UTC (rev 225912)
+++ trunk/Source/JavaScriptCore/bytecode/AccessCase.cpp 2017-12-14 19:11:49 UTC (rev 225913)
</span><span class="lines">@@ -1062,6 +1062,8 @@
</span><span class="cx">         }
</span><span class="cx">         
</span><span class="cx">         if (allocatingInline) {
</span><ins>+            // If we were to have any indexed properties, then we would need to update the indexing mask on the base object.
+            RELEASE_ASSERT(!newStructure()->couldHaveIndexingHeader());
</ins><span class="cx">             // We set the new butterfly and the structure last. Doing it this way ensures that
</span><span class="cx">             // whatever we had done up to this point is forgotten if we choose to branch to slow
</span><span class="cx">             // path.
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGAbstractHeaph"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGAbstractHeap.h (225912 => 225913)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGAbstractHeap.h        2017-12-14 19:10:54 UTC (rev 225912)
+++ trunk/Source/JavaScriptCore/dfg/DFGAbstractHeap.h   2017-12-14 19:11:49 UTC (rev 225913)
</span><span class="lines">@@ -58,6 +58,7 @@
</span><span class="cx">     macro(JSCell_typeInfoFlags) \
</span><span class="cx">     macro(JSCell_typeInfoType) \
</span><span class="cx">     macro(JSObject_butterfly) \
</span><ins>+    macro(JSObject_butterflyMask) \
</ins><span class="cx">     macro(JSPropertyNameEnumerator_cachedPropertyNames) \
</span><span class="cx">     macro(RegExpObject_lastIndex) \
</span><span class="cx">     macro(NamedProperties) \
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGClobberizeh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGClobberize.h (225912 => 225913)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGClobberize.h  2017-12-14 19:10:54 UTC (rev 225912)
+++ trunk/Source/JavaScriptCore/dfg/DFGClobberize.h     2017-12-14 19:11:49 UTC (rev 225913)
</span><span class="lines">@@ -561,6 +561,7 @@
</span><span class="cx">         read(JSCell_indexingType);
</span><span class="cx">         read(JSCell_structureID);
</span><span class="cx">         read(JSObject_butterfly);
</span><ins>+        read(JSObject_butterflyMask);
</ins><span class="cx">         read(Butterfly_publicLength);
</span><span class="cx">         read(IndexedDoubleProperties);
</span><span class="cx">         read(IndexedInt32Properties);
</span><span class="lines">@@ -576,6 +577,7 @@
</span><span class="cx">         read(JSCell_indexingType);
</span><span class="cx">         read(JSCell_structureID);
</span><span class="cx">         read(JSObject_butterfly);
</span><ins>+        read(JSObject_butterflyMask);
</ins><span class="cx">         read(Butterfly_publicLength);
</span><span class="cx">         switch (node->arrayMode().type()) {
</span><span class="cx">         case Array::Double:
</span><span class="lines">@@ -1109,6 +1111,7 @@
</span><span class="cx">         write(JSCell_structureID);
</span><span class="cx">         write(JSCell_indexingType);
</span><span class="cx">         write(JSObject_butterfly);
</span><ins>+        write(JSObject_butterflyMask);
</ins><span class="cx">         write(Watchpoint_fire);
</span><span class="cx">         return;
</span><span class="cx">         
</span><span class="lines">@@ -1160,6 +1163,7 @@
</span><span class="cx">     case MultiGetByOffset: {
</span><span class="cx">         read(JSCell_structureID);
</span><span class="cx">         read(JSObject_butterfly);
</span><ins>+        read(JSObject_butterflyMask);
</ins><span class="cx">         AbstractHeap heap(NamedProperties, node->multiGetByOffsetData().identifierNumber);
</span><span class="cx">         read(heap);
</span><span class="cx">         // FIXME: We cannot def() for MultiGetByOffset because CSE is not smart enough to decay it
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGSpeculativeJITcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp (225912 => 225913)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp    2017-12-14 19:10:54 UTC (rev 225912)
+++ trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp       2017-12-14 19:11:49 UTC (rev 225913)
</span><span class="lines">@@ -109,7 +109,7 @@
</span><span class="cx">     size += outOfLineCapacity * sizeof(JSValue);
</span><span class="cx"> 
</span><span class="cx">     m_jit.move(TrustedImmPtr(0), storageGPR);
</span><del>-    
</del><ins>+
</ins><span class="cx">     if (size) {
</span><span class="cx">         if (MarkedAllocator* allocator = m_jit.vm()->jsValueGigacageAuxiliarySpace.allocatorForNonVirtual(size, AllocatorForMode::AllocatorIfExists)) {
</span><span class="cx">             m_jit.move(TrustedImmPtr(allocator), scratchGPR);
</span><span class="lines">@@ -129,7 +129,8 @@
</span><span class="cx">     MarkedAllocator* allocatorPtr = subspaceFor<JSFinalObject>(*m_jit.vm())->allocatorForNonVirtual(allocationSize, AllocatorForMode::AllocatorIfExists);
</span><span class="cx">     if (allocatorPtr) {
</span><span class="cx">         m_jit.move(TrustedImmPtr(allocatorPtr), scratchGPR);
</span><del>-        emitAllocateJSObject(resultGPR, allocatorPtr, scratchGPR, TrustedImmPtr(structure), storageGPR, scratch2GPR, slowCases);
</del><ins>+        uint32_t mask = Butterfly::computeIndexingMaskForVectorLength(vectorLength);
+        emitAllocateJSObject(resultGPR, allocatorPtr, scratchGPR, TrustedImmPtr(structure), storageGPR, TrustedImm32(mask), scratch2GPR, slowCases);
</ins><span class="cx">         m_jit.emitInitializeInlineStorage(resultGPR, structure->inlineCapacity());
</span><span class="cx">     } else
</span><span class="cx">         slowCases.append(m_jit.jump());
</span><span class="lines">@@ -2083,7 +2084,7 @@
</span><span class="cx">         
</span><span class="cx">         m_jit.add32(TrustedImm32(1), propertyReg, temporaryReg);
</span><span class="cx">         m_jit.store32(temporaryReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength()));
</span><del>-        
</del><ins>+
</ins><span class="cx">         inBounds.link(&m_jit);
</span><span class="cx">     }
</span><span class="cx">     
</span><span class="lines">@@ -6740,9 +6741,12 @@
</span><span class="cx">     noResult(node);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-template <typename ClassType> void SpeculativeJIT::compileNewFunctionCommon(GPRReg resultGPR, RegisteredStructure structure, GPRReg scratch1GPR, GPRReg scratch2GPR, GPRReg scopeGPR, MacroAssembler::JumpList& slowPath, size_t size, FunctionExecutable* executable, ptrdiff_t offsetOfScopeChain, ptrdiff_t offsetOfExecutable, ptrdiff_t offsetOfRareData)
</del><ins>+template <typename ClassType>
+void SpeculativeJIT::compileNewFunctionCommon(GPRReg resultGPR, RegisteredStructure structure, GPRReg scratch1GPR, GPRReg scratch2GPR, GPRReg scopeGPR, MacroAssembler::JumpList& slowPath, size_t size, FunctionExecutable* executable, ptrdiff_t offsetOfScopeChain, ptrdiff_t offsetOfExecutable, ptrdiff_t offsetOfRareData)
</ins><span class="cx"> {
</span><del>-    emitAllocateJSObjectWithKnownSize<ClassType>(resultGPR, TrustedImmPtr(structure), TrustedImmPtr(0), scratch1GPR, scratch2GPR, slowPath, size);
</del><ins>+    auto butterfly = TrustedImmPtr(nullptr);
+    auto mask = TrustedImm32(0);
+    emitAllocateJSObjectWithKnownSize<ClassType>(resultGPR, TrustedImmPtr(structure), butterfly, mask, scratch1GPR, scratch2GPR, slowPath, size);
</ins><span class="cx">     
</span><span class="cx">     m_jit.storePtr(scopeGPR, JITCompiler::Address(resultGPR, offsetOfScopeChain));
</span><span class="cx">     m_jit.storePtr(TrustedImmPtr::weakPointer(m_jit.graph(), executable), JITCompiler::Address(resultGPR, offsetOfExecutable));
</span><span class="lines">@@ -6951,8 +6955,10 @@
</span><span class="cx">     GPRReg scratch2GPR = scratch2.gpr();
</span><span class="cx">         
</span><span class="cx">     JITCompiler::JumpList slowPath;
</span><ins>+    auto butterfly = TrustedImmPtr(nullptr);
+    auto mask = TrustedImm32(0);
</ins><span class="cx">     emitAllocateJSObjectWithKnownSize<JSLexicalEnvironment>(
</span><del>-        resultGPR, TrustedImmPtr(structure), TrustedImmPtr(0), scratch1GPR, scratch2GPR,
</del><ins>+        resultGPR, TrustedImmPtr(structure), butterfly, mask, scratch1GPR, scratch2GPR,
</ins><span class="cx">         slowPath, JSLexicalEnvironment::allocationSize(table));
</span><span class="cx">         
</span><span class="cx">     // Don't need a memory barriers since we just fast-created the activation, so the
</span><span class="lines">@@ -7029,8 +7035,10 @@
</span><span class="cx">     // size statically.
</span><span class="cx">     JITCompiler::JumpList slowPath;
</span><span class="cx">     if (lengthIsKnown) {
</span><ins>+        auto butterfly = TrustedImmPtr(nullptr);
+        auto mask = TrustedImm32(0);
</ins><span class="cx">         emitAllocateJSObjectWithKnownSize<DirectArguments>(
</span><del>-            resultGPR, TrustedImmPtr(structure), TrustedImmPtr(0), scratch1GPR, scratch2GPR,
</del><ins>+            resultGPR, TrustedImmPtr(structure), butterfly, mask, scratch1GPR, scratch2GPR,
</ins><span class="cx">             slowPath, DirectArguments::allocationSize(std::max(knownLength, minCapacity)));
</span><span class="cx">             
</span><span class="cx">         m_jit.store32(
</span><span class="lines">@@ -7687,23 +7695,28 @@
</span><span class="cx"> 
</span><span class="cx">         done.link(&m_jit);
</span><span class="cx"> 
</span><del>-        {
</del><ins>+        MacroAssembler::JumpList slowCases;
+        m_jit.move(TrustedImmPtr(0), storageResultGPR);
+        // X86 only has 6 GP registers, which is not enough for the fast case here. At least without custom code, which is not currently worth the extra code maintenance.
+        if (!isX86() || isX86_64()) {
</ins><span class="cx">             GPRTemporary scratch(this);
</span><span class="cx">             GPRTemporary scratch2(this);
</span><ins>+            GPRTemporary indexingMask(this);
</ins><span class="cx">             GPRReg scratchGPR = scratch.gpr();
</span><span class="cx">             GPRReg scratch2GPR = scratch2.gpr();
</span><ins>+            GPRReg indexingMaskGPR = indexingMask.gpr();
</ins><span class="cx"> 
</span><del>-            MacroAssembler::JumpList slowCases;
-            m_jit.move(TrustedImmPtr(0), storageResultGPR);
-
</del><span class="cx">             emitAllocateButterfly(storageResultGPR, sizeGPR, scratchGPR, scratch2GPR, resultGPR, slowCases);
</span><span class="cx">             emitInitializeButterfly(storageResultGPR, sizeGPR, emptyValueRegs, scratchGPR);
</span><del>-            emitAllocateJSObject<JSArray>(resultGPR, tempValue, storageResultGPR, scratchGPR, scratch2GPR, slowCases);
</del><ins>+            m_jit.emitComputeButterflyIndexingMask(sizeGPR, scratch2GPR, indexingMaskGPR);
+            emitAllocateJSObject<JSArray>(resultGPR, tempValue, storageResultGPR, indexingMaskGPR, scratchGPR, scratch2GPR, slowCases);
</ins><span class="cx">             m_jit.mutatorFence(*m_jit.vm());
</span><ins>+        } else {
+            slowCases.append(m_jit.jump());
+        }
</ins><span class="cx"> 
</span><del>-            addSlowPathGenerator(std::make_unique<CallArrayAllocatorWithVariableStructureVariableSizeSlowPathGenerator>(
-                slowCases, this, operationNewArrayWithSize, resultGPR, tempValue, sizeGPR, storageResultGPR));
-        }
</del><ins>+        addSlowPathGenerator(std::make_unique<CallArrayAllocatorWithVariableStructureVariableSizeSlowPathGenerator>(
+            slowCases, this, operationNewArrayWithSize, resultGPR, tempValue, sizeGPR, storageResultGPR));
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     GPRTemporary temp4(this);
</span><span class="lines">@@ -8524,10 +8537,10 @@
</span><span class="cx"> {
</span><span class="cx">     SpeculateCellOperand base(this, node->child1());
</span><span class="cx">     StorageOperand storage(this, node->child2());
</span><del>-    
</del><ins>+
</ins><span class="cx">     GPRReg baseGPR = base.gpr();
</span><span class="cx">     GPRReg storageGPR = storage.gpr();
</span><del>-    
</del><ins>+
</ins><span class="cx">     m_jit.nukeStructureAndStoreButterfly(*m_jit.vm(), storageGPR, baseGPR);
</span><span class="cx">     
</span><span class="cx">     noResult(node);
</span><span class="lines">@@ -8997,9 +9010,11 @@
</span><span class="cx">     GPRReg scratch2GPR = scratch2.gpr();
</span><span class="cx">     
</span><span class="cx">     JITCompiler::JumpList slowPath;
</span><del>-    
</del><ins>+
+    auto butterfly = TrustedImmPtr(nullptr);
+    auto mask = TrustedImm32(0);
</ins><span class="cx">     emitAllocateJSObject<StringObject>(
</span><del>-        resultGPR, TrustedImmPtr(node->structure()), TrustedImmPtr(0), scratch1GPR, scratch2GPR,
</del><ins>+        resultGPR, TrustedImmPtr(node->structure()), butterfly, mask, scratch1GPR, scratch2GPR,
</ins><span class="cx">         slowPath);
</span><span class="cx">     
</span><span class="cx">     m_jit.storePtr(
</span><span class="lines">@@ -9081,9 +9096,11 @@
</span><span class="cx">         MacroAssembler::BaseIndex(storageGPR, scratchGPR, MacroAssembler::TimesFour));
</span><span class="cx">     m_jit.branchTest32(MacroAssembler::NonZero, scratchGPR).linkTo(loop, &m_jit);
</span><span class="cx">     done.link(&m_jit);
</span><del>-    
</del><ins>+
+    auto butterfly = TrustedImmPtr(nullptr);
+    auto mask = TrustedImm32(0);
</ins><span class="cx">     emitAllocateJSObject<JSArrayBufferView>(
</span><del>-        resultGPR, TrustedImmPtr(structure), TrustedImmPtr(0), scratchGPR, scratchGPR2,
</del><ins>+        resultGPR, TrustedImmPtr(structure), butterfly, mask, scratchGPR, scratchGPR2,
</ins><span class="cx">         slowCases);
</span><span class="cx">     
</span><span class="cx">     m_jit.storePtr(
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGSpeculativeJITh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h (225912 => 225913)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h      2017-12-14 19:10:54 UTC (rev 225912)
+++ trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h 2017-12-14 19:11:49 UTC (rev 225913)
</span><span class="lines">@@ -3056,29 +3056,29 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     // Allocator for an object of a specific size.
</span><del>-    template <typename StructureType, typename StorageType> // StructureType and StorageType can be GPR or ImmPtr.
</del><ins>+    template <typename StructureType, typename StorageType, typename MaskType> // StructureType, StorageType and, MaskType can be GPR or ImmPtr.
</ins><span class="cx">     void emitAllocateJSObject(
</span><span class="cx">         GPRReg resultGPR, MarkedAllocator* allocator, GPRReg allocatorGPR, StructureType structure,
</span><del>-        StorageType storage, GPRReg scratchGPR, MacroAssembler::JumpList& slowPath)
</del><ins>+        StorageType storage, MaskType mask, GPRReg scratchGPR, MacroAssembler::JumpList& slowPath)
</ins><span class="cx">     {
</span><span class="cx">         m_jit.emitAllocateJSObject(
</span><del>-            resultGPR, allocator, allocatorGPR, structure, storage, scratchGPR, slowPath);
</del><ins>+            resultGPR, allocator, allocatorGPR, structure, storage, mask, scratchGPR, slowPath);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    template <typename ClassType, typename StructureType, typename StorageType> // StructureType and StorageType can be GPR or ImmPtr.
</del><ins>+    template <typename ClassType, typename StructureType, typename StorageType, typename MaskType> // StructureType, StorageType and, MaskType can be GPR or ImmPtr.
</ins><span class="cx">     void emitAllocateJSObjectWithKnownSize(
</span><del>-        GPRReg resultGPR, StructureType structure, StorageType storage, GPRReg scratchGPR1,
</del><ins>+        GPRReg resultGPR, StructureType structure, StorageType storage, MaskType mask, GPRReg scratchGPR1,
</ins><span class="cx">         GPRReg scratchGPR2, MacroAssembler::JumpList& slowPath, size_t size)
</span><span class="cx">     {
</span><del>-        m_jit.emitAllocateJSObjectWithKnownSize<ClassType>(*m_jit.vm(), resultGPR, structure, storage, scratchGPR1, scratchGPR2, slowPath, size);
</del><ins>+        m_jit.emitAllocateJSObjectWithKnownSize<ClassType>(*m_jit.vm(), resultGPR, structure, storage, mask, scratchGPR1, scratchGPR2, slowPath, size);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     // Convenience allocator for a built-in object.
</span><del>-    template <typename ClassType, typename StructureType, typename StorageType> // StructureType and StorageType can be GPR or ImmPtr.
-    void emitAllocateJSObject(GPRReg resultGPR, StructureType structure, StorageType storage,
</del><ins>+    template <typename ClassType, typename StructureType, typename StorageType, typename MaskType> // StructureType, StorageType and, MaskType can be GPR or ImmPtr.
+    void emitAllocateJSObject(GPRReg resultGPR, StructureType structure, StorageType storage, MaskType mask,
</ins><span class="cx">         GPRReg scratchGPR1, GPRReg scratchGPR2, MacroAssembler::JumpList& slowPath)
</span><span class="cx">     {
</span><del>-        m_jit.emitAllocateJSObject<ClassType>(*m_jit.vm(), resultGPR, structure, storage, scratchGPR1, scratchGPR2, slowPath);
</del><ins>+        m_jit.emitAllocateJSObject<ClassType>(*m_jit.vm(), resultGPR, structure, storage, mask, scratchGPR1, scratchGPR2, slowPath);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     template <typename ClassType, typename StructureType> // StructureType and StorageType can be GPR or ImmPtr.
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGSpeculativeJIT32_64cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp (225912 => 225913)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp       2017-12-14 19:10:54 UTC (rev 225912)
+++ trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp  2017-12-14 19:11:49 UTC (rev 225913)
</span><span class="lines">@@ -4086,7 +4086,9 @@
</span><span class="cx">         m_jit.loadPtr(JITCompiler::Address(rareDataGPR, FunctionRareData::offsetOfObjectAllocationProfile() + ObjectAllocationProfile::offsetOfAllocator()), allocatorGPR);
</span><span class="cx">         m_jit.loadPtr(JITCompiler::Address(rareDataGPR, FunctionRareData::offsetOfObjectAllocationProfile() + ObjectAllocationProfile::offsetOfStructure()), structureGPR);
</span><span class="cx">         slowPath.append(m_jit.branchTestPtr(MacroAssembler::Zero, allocatorGPR));
</span><del>-        emitAllocateJSObject(resultGPR, nullptr, allocatorGPR, structureGPR, TrustedImmPtr(0), scratchGPR, slowPath);
</del><ins>+        auto butterfly = TrustedImmPtr(nullptr);
+        auto mask = TrustedImm32(0);
+        emitAllocateJSObject(resultGPR, nullptr, allocatorGPR, structureGPR, butterfly, mask, scratchGPR, slowPath);
</ins><span class="cx"> 
</span><span class="cx">         m_jit.loadPtr(JITCompiler::Address(calleeGPR, JSFunction::offsetOfRareData()), rareDataGPR);
</span><span class="cx">         m_jit.load32(JITCompiler::Address(rareDataGPR, FunctionRareData::offsetOfObjectAllocationProfile() + ObjectAllocationProfile::offsetOfInlineCapacity()), inlineCapacityGPR);
</span><span class="lines">@@ -4114,7 +4116,9 @@
</span><span class="cx">         MarkedAllocator* allocatorPtr = subspaceFor<JSFinalObject>(*m_jit.vm())->allocatorForNonVirtual(allocationSize, AllocatorForMode::AllocatorIfExists);
</span><span class="cx"> 
</span><span class="cx">         m_jit.move(TrustedImmPtr(allocatorPtr), allocatorGPR);
</span><del>-        emitAllocateJSObject(resultGPR, allocatorPtr, allocatorGPR, TrustedImmPtr(structure), TrustedImmPtr(0), scratchGPR, slowPath);
</del><ins>+        auto butterfly = TrustedImmPtr(nullptr);
+        auto mask = TrustedImm32(0);
+        emitAllocateJSObject(resultGPR, allocatorPtr, allocatorGPR, TrustedImmPtr(structure), butterfly, mask, scratchGPR, slowPath);
</ins><span class="cx">         m_jit.emitInitializeInlineStorage(resultGPR, structure->inlineCapacity());
</span><span class="cx"> 
</span><span class="cx">         addSlowPathGenerator(slowPathCall(slowPath, this, operationNewObject, resultGPR, structure));
</span><span class="lines">@@ -5749,8 +5753,13 @@
</span><span class="cx">     emitInitializeButterfly(storageGPR, sizeGPR, emptyValueRegs, resultGPR);
</span><span class="cx">             
</span><span class="cx">     RegisteredStructure structure = m_jit.graph().registerStructure(globalObject->arrayStructureForIndexingTypeDuringAllocation(indexingType));
</span><del>-    emitAllocateJSObject<JSArray>(resultGPR, TrustedImmPtr(structure), storageGPR, scratchGPR, scratch2GPR, slowCases);
-            
</del><ins>+
+    // X86 doesn't have enough registers to support compute the indexing mask before creating the object. So we do this hack...
+    auto mask = TrustedImm32(0);
+    emitAllocateJSObject<JSArray>(resultGPR, TrustedImmPtr(structure), storageGPR, mask, scratchGPR, scratch2GPR, slowCases);
+    m_jit.emitComputeButterflyIndexingMask(sizeGPR, scratchGPR, scratch2GPR);
+    m_jit.store32(scratch2GPR, MacroAssembler::Address(resultGPR, JSObject::butterflyIndexingMaskOffset()));
+
</ins><span class="cx">     addSlowPathGenerator(std::make_unique<CallArrayAllocatorWithVariableSizeSlowPathGenerator>(
</span><span class="cx">         slowCases, this, operationNewArrayWithSize, resultGPR,
</span><span class="cx">         structure,
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGSpeculativeJIT64cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp (225912 => 225913)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp  2017-12-14 19:10:54 UTC (rev 225912)
+++ trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp     2017-12-14 19:11:49 UTC (rev 225913)
</span><span class="lines">@@ -2754,12 +2754,14 @@
</span><span class="cx">         case Array::Int32:
</span><span class="cx">         case Array::Contiguous: {
</span><span class="cx">             if (node->arrayMode().isInBounds()) {
</span><ins>+                SpeculateCellOperand base(this, node->child1());
</ins><span class="cx">                 SpeculateStrictInt32Operand property(this, node->child2());
</span><span class="cx">                 StorageOperand storage(this, node->child3());
</span><del>-                
</del><ins>+
+                GPRReg baseReg = base.gpr();
</ins><span class="cx">                 GPRReg propertyReg = property.gpr();
</span><span class="cx">                 GPRReg storageReg = storage.gpr();
</span><del>-                
</del><ins>+
</ins><span class="cx">                 if (!m_compileOkay)
</span><span class="cx">                     return;
</span><span class="cx">                 
</span><span class="lines">@@ -2766,6 +2768,8 @@
</span><span class="cx">                 speculationCheck(OutOfBounds, JSValueRegs(), 0, m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength())));
</span><span class="cx">                 
</span><span class="cx">                 GPRTemporary result(this);
</span><ins>+
+                m_jit.and32(MacroAssembler::Address(baseReg, JSObject::butterflyIndexingMaskOffset()), propertyReg);
</ins><span class="cx">                 m_jit.load64(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight), result.gpr());
</span><span class="cx">                 if (node->arrayMode().isSaneChain()) {
</span><span class="cx">                     ASSERT(node->arrayMode().type() == Array::Contiguous);
</span><span class="lines">@@ -2799,7 +2803,8 @@
</span><span class="cx">             MacroAssembler::JumpList slowCases;
</span><span class="cx">             
</span><span class="cx">             slowCases.append(m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength())));
</span><del>-            
</del><ins>+
+            m_jit.and32(MacroAssembler::Address(baseReg, JSObject::butterflyIndexingMaskOffset()), propertyReg);
</ins><span class="cx">             m_jit.load64(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight), resultReg);
</span><span class="cx">             slowCases.append(m_jit.branchTest64(MacroAssembler::Zero, resultReg));
</span><span class="cx">             
</span><span class="lines">@@ -2814,22 +2819,27 @@
</span><span class="cx"> 
</span><span class="cx">         case Array::Double: {
</span><span class="cx">             if (node->arrayMode().isInBounds()) {
</span><ins>+                SpeculateCellOperand base(this, node->child1());
</ins><span class="cx">                 SpeculateStrictInt32Operand property(this, node->child2());
</span><span class="cx">                 StorageOperand storage(this, node->child3());
</span><del>-            
</del><ins>+
+                GPRReg baseReg = base.gpr();
</ins><span class="cx">                 GPRReg propertyReg = property.gpr();
</span><span class="cx">                 GPRReg storageReg = storage.gpr();
</span><del>-            
</del><ins>+
</ins><span class="cx">                 if (!m_compileOkay)
</span><span class="cx">                     return;
</span><del>-            
</del><ins>+
+                FPRTemporary result(this);
+                FPRReg resultReg = result.fpr();
+
</ins><span class="cx">                 speculationCheck(OutOfBounds, JSValueRegs(), 0, m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength())));
</span><del>-            
-                FPRTemporary result(this);
-                m_jit.loadDouble(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight), result.fpr());
</del><ins>+
+                m_jit.and32(MacroAssembler::Address(baseReg, JSObject::butterflyIndexingMaskOffset()), propertyReg);
+                m_jit.loadDouble(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight), resultReg);
</ins><span class="cx">                 if (!node->arrayMode().isSaneChain())
</span><del>-                    speculationCheck(LoadFromHole, JSValueRegs(), 0, m_jit.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered, result.fpr(), result.fpr()));
-                doubleResult(result.fpr(), node);
</del><ins>+                    speculationCheck(LoadFromHole, JSValueRegs(), 0, m_jit.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered, resultReg, resultReg));
+                doubleResult(resultReg, node);
</ins><span class="cx">                 break;
</span><span class="cx">             }
</span><span class="cx"> 
</span><span class="lines">@@ -2852,7 +2862,8 @@
</span><span class="cx">             MacroAssembler::JumpList slowCases;
</span><span class="cx">             
</span><span class="cx">             slowCases.append(m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength())));
</span><del>-            
</del><ins>+
+            m_jit.and32(MacroAssembler::Address(baseReg, JSObject::butterflyIndexingMaskOffset()), propertyReg);
</ins><span class="cx">             m_jit.loadDouble(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight), tempReg);
</span><span class="cx">             slowCases.append(m_jit.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered, tempReg, tempReg));
</span><span class="cx">             boxDouble(tempReg, resultReg);
</span><span class="lines">@@ -3011,10 +3022,7 @@
</span><span class="cx">         
</span><span class="cx">         if (alreadyHandled)
</span><span class="cx">             break;
</span><del>-        
-        // FIXME: the base may not be necessary for some array access modes. But we have to
-        // keep it alive to this point, so it's likely to be in a register anyway. Likely
-        // no harm in locking it here.
</del><ins>+
</ins><span class="cx">         SpeculateCellOperand base(this, child1);
</span><span class="cx">         SpeculateStrictInt32Operand property(this, child2);
</span><span class="cx">         
</span><span class="lines">@@ -3070,10 +3078,10 @@
</span><span class="cx">                 
</span><span class="cx">                 m_jit.add32(TrustedImm32(1), propertyReg, temporaryReg);
</span><span class="cx">                 m_jit.store32(temporaryReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength()));
</span><del>-                
</del><ins>+
</ins><span class="cx">                 inBounds.link(&m_jit);
</span><span class="cx">             }
</span><del>-            
</del><ins>+
</ins><span class="cx">             m_jit.store64(valueReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight));
</span><span class="cx"> 
</span><span class="cx">             base.use();
</span><span class="lines">@@ -4290,7 +4298,9 @@
</span><span class="cx"> 
</span><span class="cx">         slowPath.append(m_jit.branchTestPtr(MacroAssembler::Zero, allocatorGPR));
</span><span class="cx"> 
</span><del>-        emitAllocateJSObject(resultGPR, nullptr, allocatorGPR, structureGPR, TrustedImmPtr(0), scratchGPR, slowPath);
</del><ins>+        auto butterfly = TrustedImmPtr(nullptr);
+        auto mask = TrustedImm32(0);
+        emitAllocateJSObject(resultGPR, nullptr, allocatorGPR, structureGPR, butterfly, mask, scratchGPR, slowPath);
</ins><span class="cx">         
</span><span class="cx">         m_jit.loadPtr(JITCompiler::Address(calleeGPR, JSFunction::offsetOfRareData()), rareDataGPR);
</span><span class="cx">         m_jit.load32(JITCompiler::Address(rareDataGPR, FunctionRareData::offsetOfObjectAllocationProfile() + ObjectAllocationProfile::offsetOfInlineCapacity()), inlineCapacityGPR);
</span><span class="lines">@@ -4319,7 +4329,9 @@
</span><span class="cx">         MarkedAllocator* allocatorPtr = subspaceFor<JSFinalObject>(*m_jit.vm())->allocatorForNonVirtual(allocationSize, AllocatorForMode::AllocatorIfExists);
</span><span class="cx"> 
</span><span class="cx">         m_jit.move(TrustedImmPtr(allocatorPtr), allocatorGPR);
</span><del>-        emitAllocateJSObject(resultGPR, allocatorPtr, allocatorGPR, TrustedImmPtr(structure), TrustedImmPtr(0), scratchGPR, slowPath);
</del><ins>+        auto butterfly = TrustedImmPtr(nullptr);
+        auto mask = TrustedImm32(0);
+        emitAllocateJSObject(resultGPR, allocatorPtr, allocatorGPR, TrustedImmPtr(structure), butterfly, mask, scratchGPR, slowPath);
</ins><span class="cx">         m_jit.emitInitializeInlineStorage(resultGPR, structure->inlineCapacity());
</span><span class="cx">         m_jit.mutatorFence(*m_jit.vm());
</span><span class="cx"> 
</span><span class="lines">@@ -6238,10 +6250,12 @@
</span><span class="cx"> void SpeculativeJIT::compileAllocateNewArrayWithSize(JSGlobalObject* globalObject, GPRReg resultGPR, GPRReg sizeGPR, IndexingType indexingType, bool shouldConvertLargeSizeToArrayStorage)
</span><span class="cx"> {
</span><span class="cx">     GPRTemporary storage(this);
</span><ins>+    GPRTemporary indexingMask(this);
</ins><span class="cx">     GPRTemporary scratch(this);
</span><span class="cx">     GPRTemporary scratch2(this);
</span><span class="cx">     
</span><span class="cx">     GPRReg storageGPR = storage.gpr();
</span><ins>+    GPRReg indexingMaskGPR = indexingMask.gpr();
</ins><span class="cx">     GPRReg scratchGPR = scratch.gpr();
</span><span class="cx">     GPRReg scratch2GPR = scratch2.gpr();
</span><span class="cx">     
</span><span class="lines">@@ -6259,11 +6273,12 @@
</span><span class="cx">     else
</span><span class="cx">         m_jit.move(TrustedImm64(JSValue::encode(JSValue())), scratchGPR);
</span><span class="cx">     emitInitializeButterfly(storageGPR, sizeGPR, JSValueRegs(scratchGPR), scratch2GPR);
</span><ins>+    m_jit.emitComputeButterflyIndexingMask(sizeGPR, scratchGPR, indexingMaskGPR);
</ins><span class="cx"> 
</span><span class="cx">     RegisteredStructure structure = m_jit.graph().registerStructure(globalObject->arrayStructureForIndexingTypeDuringAllocation(indexingType));
</span><ins>+
+    emitAllocateJSObject<JSArray>(resultGPR, TrustedImmPtr(structure), storageGPR, indexingMaskGPR, scratchGPR, scratch2GPR, slowCases);
</ins><span class="cx">     
</span><del>-    emitAllocateJSObject<JSArray>(resultGPR, TrustedImmPtr(structure), storageGPR, scratchGPR, scratch2GPR, slowCases);
-    
</del><span class="cx">     m_jit.mutatorFence(*m_jit.vm());
</span><span class="cx">     
</span><span class="cx">     addSlowPathGenerator(std::make_unique<CallArrayAllocatorWithVariableSizeSlowPathGenerator>(
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLAbstractHeapcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLAbstractHeap.cpp (225912 => 225913)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLAbstractHeap.cpp      2017-12-14 19:10:54 UTC (rev 225912)
+++ trunk/Source/JavaScriptCore/ftl/FTLAbstractHeap.cpp 2017-12-14 19:11:49 UTC (rev 225913)
</span><span class="lines">@@ -140,11 +140,13 @@
</span><span class="cx"> {
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-TypedPointer IndexedAbstractHeap::baseIndex(Output& out, LValue base, LValue index, JSValue indexAsConstant, ptrdiff_t offset)
</del><ins>+TypedPointer IndexedAbstractHeap::baseIndex(Output& out, LValue base, LValue index, JSValue indexAsConstant, ptrdiff_t offset, LValue mask)
</ins><span class="cx"> {
</span><span class="cx">     if (indexAsConstant.isInt32())
</span><span class="cx">         return out.address(base, at(indexAsConstant.asInt32()), offset);
</span><span class="cx"> 
</span><ins>+    if (mask)
+        index = out.bitAnd(mask, index);
</ins><span class="cx">     LValue result = out.add(base, out.mul(index, out.constIntPtr(m_elementSize)));
</span><span class="cx">     
</span><span class="cx">     return TypedPointer(atAnyIndex(), out.addPtr(result, m_offset + offset));
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLAbstractHeaph"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLAbstractHeap.h (225912 => 225913)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLAbstractHeap.h        2017-12-14 19:10:54 UTC (rev 225912)
+++ trunk/Source/JavaScriptCore/ftl/FTLAbstractHeap.h   2017-12-14 19:11:49 UTC (rev 225913)
</span><span class="lines">@@ -133,7 +133,7 @@
</span><span class="cx">     
</span><span class="cx">     const AbstractHeap& operator[](ptrdiff_t index) { return at(index); }
</span><span class="cx">     
</span><del>-    TypedPointer baseIndex(Output& out, LValue base, LValue index, JSValue indexAsConstant = JSValue(), ptrdiff_t offset = 0);
</del><ins>+    TypedPointer baseIndex(Output& out, LValue base, LValue index, JSValue indexAsConstant = JSValue(), ptrdiff_t offset = 0, LValue mask = nullptr);
</ins><span class="cx">     
</span><span class="cx">     void dump(PrintStream&) const;
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLAbstractHeapRepositoryh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.h (225912 => 225913)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.h      2017-12-14 19:10:54 UTC (rev 225912)
+++ trunk/Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.h 2017-12-14 19:11:49 UTC (rev 225913)
</span><span class="lines">@@ -72,6 +72,7 @@
</span><span class="cx">     macro(JSFunction_scope, JSFunction::offsetOfScopeChain()) \
</span><span class="cx">     macro(JSFunction_rareData, JSFunction::offsetOfRareData()) \
</span><span class="cx">     macro(JSObject_butterfly, JSObject::butterflyOffset()) \
</span><ins>+    macro(JSObject_butterflyMask, JSObject::butterflyIndexingMaskOffset()) \
</ins><span class="cx">     macro(JSPropertyNameEnumerator_cachedInlineCapacity, JSPropertyNameEnumerator::cachedInlineCapacityOffset()) \
</span><span class="cx">     macro(JSPropertyNameEnumerator_cachedPropertyNamesVector, JSPropertyNameEnumerator::cachedPropertyNamesVectorOffset()) \
</span><span class="cx">     macro(JSPropertyNameEnumerator_cachedStructureID, JSPropertyNameEnumerator::cachedStructureIDOffset()) \
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLLowerDFGToB3cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp (225912 => 225913)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp      2017-12-14 19:10:54 UTC (rev 225912)
+++ trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp 2017-12-14 19:11:49 UTC (rev 225913)
</span><span class="lines">@@ -3145,7 +3145,7 @@
</span><span class="cx">             setJSValue(result);
</span><span class="cx">             return;
</span><span class="cx">         }
</span><del>-        
</del><ins>+
</ins><span class="cx">         LValue index = lowInt32(indexEdge);
</span><span class="cx">         LValue args[2];
</span><span class="cx">         for (unsigned i = numExtraArgs; i--;)
</span><span class="lines">@@ -3663,7 +3663,7 @@
</span><span class="cx">             
</span><span class="cx">             LBasicBlock lastNext = m_out.appendTo(fastCase, slowCase);
</span><span class="cx"> 
</span><del>-            LValue fastResultValue = m_out.load64(baseIndex(heap, storage, index, m_node->child2()));
</del><ins>+            LValue fastResultValue = m_out.load64(maskedIndex(heap, storage, index, base, m_node->child2()));
</ins><span class="cx">             ValueFromBlock fastResult = m_out.anchor(fastResultValue);
</span><span class="cx">             m_out.branch(
</span><span class="cx">                 m_out.isZero64(fastResultValue), rarely(slowCase), usually(continuation));
</span><span class="lines">@@ -3679,6 +3679,7 @@
</span><span class="cx">         }
</span><span class="cx">             
</span><span class="cx">         case Array::Double: {
</span><ins>+            LValue base = lowCell(m_node->child1());
</ins><span class="cx">             LValue index = lowInt32(m_node->child2());
</span><span class="cx">             LValue storage = lowStorage(m_node->child3());
</span><span class="cx">             
</span><span class="lines">@@ -3686,7 +3687,7 @@
</span><span class="cx">             
</span><span class="cx">             if (m_node->arrayMode().isInBounds()) {
</span><span class="cx">                 LValue result = m_out.loadDouble(
</span><del>-                    baseIndex(heap, storage, index, m_node->child2()));
</del><ins>+                    maskedIndex(heap, storage, index, base, m_node->child2()));
</ins><span class="cx">                 
</span><span class="cx">                 if (!m_node->arrayMode().isSaneChain()) {
</span><span class="cx">                     speculate(
</span><span class="lines">@@ -3696,9 +3697,7 @@
</span><span class="cx">                 setDouble(result);
</span><span class="cx">                 break;
</span><span class="cx">             }
</span><del>-            
-            LValue base = lowCell(m_node->child1());
-            
</del><ins>+
</ins><span class="cx">             LBasicBlock inBounds = m_out.newBlock();
</span><span class="cx">             LBasicBlock boxPath = m_out.newBlock();
</span><span class="cx">             LBasicBlock slowCase = m_out.newBlock();
</span><span class="lines">@@ -3711,7 +3710,7 @@
</span><span class="cx">             
</span><span class="cx">             LBasicBlock lastNext = m_out.appendTo(inBounds, boxPath);
</span><span class="cx">             LValue doubleValue = m_out.loadDouble(
</span><del>-                baseIndex(heap, storage, index, m_node->child2()));
</del><ins>+                maskedIndex(heap, storage, index, base, m_node->child2()));
</ins><span class="cx">             m_out.branch(
</span><span class="cx">                 m_out.doubleNotEqualOrUnordered(doubleValue, doubleValue),
</span><span class="cx">                 rarely(slowCase), usually(boxPath));
</span><span class="lines">@@ -3854,6 +3853,7 @@
</span><span class="cx"> 
</span><span class="cx">         case Array::ArrayStorage:
</span><span class="cx">         case Array::SlowPutArrayStorage: {
</span><ins>+            LValue base = lowCell(m_node->child1());
</ins><span class="cx">             LValue index = lowInt32(m_node->child2());
</span><span class="cx">             LValue storage = lowStorage(m_node->child3());
</span><span class="cx"> 
</span><span class="lines">@@ -3860,14 +3860,12 @@
</span><span class="cx">             IndexedAbstractHeap& heap = m_heaps.ArrayStorage_vector;
</span><span class="cx"> 
</span><span class="cx">             if (m_node->arrayMode().isInBounds()) {
</span><del>-                LValue result = m_out.load64(baseIndex(heap, storage, index, m_node->child2()));
</del><ins>+                LValue result = m_out.load64(maskedIndex(heap, storage, index, base, m_node->child2()));
</ins><span class="cx">                 speculate(LoadFromHole, noValue(), 0, m_out.isZero64(result));
</span><span class="cx">                 setJSValue(result);
</span><span class="cx">                 break;
</span><span class="cx">             }
</span><span class="cx"> 
</span><del>-            LValue base = lowCell(m_node->child1());
-
</del><span class="cx">             LBasicBlock inBounds = m_out.newBlock();
</span><span class="cx">             LBasicBlock slowCase = m_out.newBlock();
</span><span class="cx">             LBasicBlock continuation = m_out.newBlock();
</span><span class="lines">@@ -3877,7 +3875,7 @@
</span><span class="cx">                 rarely(slowCase), usually(inBounds));
</span><span class="cx"> 
</span><span class="cx">             LBasicBlock lastNext = m_out.appendTo(inBounds, slowCase);
</span><del>-            LValue result = m_out.load64(baseIndex(heap, storage, index, m_node->child2()));
</del><ins>+            LValue result = m_out.load64(maskedIndex(heap, storage, index, base, m_node->child2()));
</ins><span class="cx">             ValueFromBlock fastResult = m_out.anchor(result);
</span><span class="cx">             m_out.branch(
</span><span class="cx">                 m_out.isZero64(result),
</span><span class="lines">@@ -4693,7 +4691,7 @@
</span><span class="cx">         LBasicBlock lastNext = m_out.insertNewBlocksBefore(slowPath);
</span><span class="cx">         
</span><span class="cx">         LValue fastObject = allocateObject<JSLexicalEnvironment>(
</span><del>-            JSLexicalEnvironment::allocationSize(table), structure, m_out.intPtrZero, slowPath);
</del><ins>+            JSLexicalEnvironment::allocationSize(table), structure, m_out.intPtrZero, m_out.int32Zero, slowPath);
</ins><span class="cx">         
</span><span class="cx">         // We don't need memory barriers since we just fast-created the activation, so the
</span><span class="cx">         // activation must be young.
</span><span class="lines">@@ -4772,10 +4770,10 @@
</span><span class="cx">         LBasicBlock lastNext = m_out.insertNewBlocksBefore(slowPath);
</span><span class="cx">         
</span><span class="cx">         LValue fastObject =
</span><del>-            isGeneratorFunction ? allocateObject<JSGeneratorFunction>(structure, m_out.intPtrZero, slowPath) :
-            isAsyncFunction ? allocateObject<JSAsyncFunction>(structure, m_out.intPtrZero, slowPath) :
-            isAsyncGeneratorFunction ? allocateObject<JSAsyncGeneratorFunction>(structure, m_out.intPtrZero, slowPath) :
-            allocateObject<JSFunction>(structure, m_out.intPtrZero, slowPath);
</del><ins>+            isGeneratorFunction ? allocateObject<JSGeneratorFunction>(structure, m_out.intPtrZero, m_out.int32Zero, slowPath) :
+            isAsyncFunction ? allocateObject<JSAsyncFunction>(structure, m_out.intPtrZero, m_out.int32Zero, slowPath) :
+            isAsyncGeneratorFunction ? allocateObject<JSAsyncGeneratorFunction>(structure, m_out.intPtrZero, m_out.int32Zero, slowPath) :
+            allocateObject<JSFunction>(structure, m_out.intPtrZero, m_out.int32Zero, slowPath);
</ins><span class="cx">         
</span><span class="cx">         
</span><span class="cx">         // We don't need memory barriers since we just fast-created the function, so it
</span><span class="lines">@@ -4838,7 +4836,7 @@
</span><span class="cx">         if (length.isKnown) {
</span><span class="cx">             fastObject = allocateObject<DirectArguments>(
</span><span class="cx">                 DirectArguments::allocationSize(std::max(length.known, minCapacity)), structure,
</span><del>-                m_out.intPtrZero, slowPath);
</del><ins>+                m_out.intPtrZero, m_out.int32Zero, slowPath);
</ins><span class="cx">         } else {
</span><span class="cx">             LValue size = m_out.add(
</span><span class="cx">                 m_out.shl(length.value, m_out.constInt32(3)),
</span><span class="lines">@@ -4849,7 +4847,7 @@
</span><span class="cx">                 size, m_out.constInt32(DirectArguments::allocationSize(minCapacity)));
</span><span class="cx">             
</span><span class="cx">             fastObject = allocateVariableSizedObject<DirectArguments>(
</span><del>-                m_out.zeroExtPtr(size), structure, m_out.intPtrZero, slowPath);
</del><ins>+                m_out.zeroExtPtr(size), structure, m_out.intPtrZero, m_out.int32Zero, slowPath);
</ins><span class="cx">         }
</span><span class="cx">         
</span><span class="cx">         m_out.store32(length.value, fastObject, m_heaps.DirectArguments_length);
</span><span class="lines">@@ -5021,7 +5019,7 @@
</span><span class="cx"> 
</span><span class="cx">         LBasicBlock lastNext = m_out.insertNewBlocksBefore(slowCase);
</span><span class="cx"> 
</span><del>-        LValue fastResultValue = allocateObject<StringObject>(structure, m_out.intPtrZero, slowCase);
</del><ins>+        LValue fastResultValue = allocateObject<StringObject>(structure, m_out.intPtrZero, m_out.int32Zero, slowCase);
</ins><span class="cx">         m_out.storePtr(m_out.constIntPtr(PoisonedClassInfoPtr(StringObject::info()).bits()), fastResultValue, m_heaps.JSDestructibleObject_classInfo);
</span><span class="cx">         m_out.store64(string, fastResultValue, m_heaps.JSWrapperObject_internalValue);
</span><span class="cx">         mutatorFence();
</span><span class="lines">@@ -5549,7 +5547,7 @@
</span><span class="cx">             ValueFromBlock haveStorage = m_out.anchor(storage);
</span><span class="cx"> 
</span><span class="cx">             LValue fastResultValue =
</span><del>-                allocateObject<JSArrayBufferView>(structure, m_out.intPtrZero, slowCase);
</del><ins>+                allocateObject<JSArrayBufferView>(structure, m_out.intPtrZero, m_out.int32Zero, slowCase);
</ins><span class="cx"> 
</span><span class="cx">             m_out.storePtr(storage, fastResultValue, m_heaps.JSArrayBufferView_vector);
</span><span class="cx">             m_out.store32(size, fastResultValue, m_heaps.JSArrayBufferView_length);
</span><span class="lines">@@ -9822,9 +9820,10 @@
</span><span class="cx">                     m_out.int64Zero, m_heaps.properties.atAnyNumber());
</span><span class="cx"> 
</span><span class="cx">                 m_out.store32(vectorLength, fastButterflyValue, m_heaps.Butterfly_vectorLength);
</span><del>-                
</del><ins>+
+                LValue mask = computeButterflyIndexingMask(vectorLength);
</ins><span class="cx">                 LValue fastObjectValue = allocateObject(
</span><del>-                    m_out.constIntPtr(cellAllocator), structure, fastButterflyValue, slowPath);
</del><ins>+                    m_out.constIntPtr(cellAllocator), structure, fastButterflyValue, mask, slowPath);
</ins><span class="cx"> 
</span><span class="cx">                 ValueFromBlock fastObject = m_out.anchor(fastObjectValue);
</span><span class="cx">                 ValueFromBlock fastButterfly = m_out.anchor(fastButterflyValue);
</span><span class="lines">@@ -10031,7 +10030,7 @@
</span><span class="cx">         LBasicBlock lastNext = m_out.insertNewBlocksBefore(slowPath);
</span><span class="cx"> 
</span><span class="cx">         LValue fastObject = allocateObject<JSLexicalEnvironment>(
</span><del>-            JSLexicalEnvironment::allocationSize(table), structure, m_out.intPtrZero, slowPath);
</del><ins>+            JSLexicalEnvironment::allocationSize(table), structure, m_out.intPtrZero, m_out.int32Zero, slowPath);
</ins><span class="cx"> 
</span><span class="cx">         m_out.storePtr(scope, fastObject, m_heaps.JSScope_next);
</span><span class="cx">         m_out.storePtr(weakPointer(table), fastObject, m_heaps.JSSymbolTableObject_symbolTable);
</span><span class="lines">@@ -10952,6 +10951,13 @@
</span><span class="cx">             heap, storage, m_out.zeroExtPtr(index), provenValue(edge), offset);
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    TypedPointer maskedIndex(IndexedAbstractHeap& heap, LValue storage, LValue index, LValue baseObject, Edge edge, ptrdiff_t offset = 0)
+    {
+        LValue mask = m_out.zeroExtPtr(m_out.load32(baseObject, m_heaps.JSObject_butterflyMask));
+        return m_out.baseIndex(
+            heap, storage, m_out.zeroExtPtr(index), provenValue(edge), offset, mask);
+    }
+
</ins><span class="cx">     template<typename IntFunctor, typename DoubleFunctor>
</span><span class="cx">     void compare(
</span><span class="cx">         const IntFunctor& intFunctor, const DoubleFunctor& doubleFunctor,
</span><span class="lines">@@ -11864,6 +11870,11 @@
</span><span class="cx">         m_out.store32(blob, object, m_heaps.JSCell_usefulBytes);
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    LValue computeButterflyIndexingMask(LValue vectorLength)
+    {
+        return m_out.lShr(m_out.zeroExt(m_out.constInt32(-1), Int64), m_out.ctlz32(vectorLength));
+    }
+
</ins><span class="cx">     template <typename StructureType>
</span><span class="cx">     LValue allocateCell(LValue allocator, StructureType structure, LBasicBlock slowPath)
</span><span class="cx">     {
</span><span class="lines">@@ -11872,12 +11883,12 @@
</span><span class="cx">         return result;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    LValue allocateObject(LValue allocator, RegisteredStructure structure, LValue butterfly, LBasicBlock slowPath)
</del><ins>+    LValue allocateObject(LValue allocator, RegisteredStructure structure, LValue butterfly, LValue indexingMask, LBasicBlock slowPath)
</ins><span class="cx">     {
</span><del>-        return allocateObject(allocator, weakStructure(structure), butterfly, slowPath);
</del><ins>+        return allocateObject(allocator, weakStructure(structure), butterfly, indexingMask, slowPath);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    LValue allocateObject(LValue allocator, LValue structure, LValue butterfly, LBasicBlock slowPath)
</del><ins>+    LValue allocateObject(LValue allocator, LValue structure, LValue butterfly, LValue indexingMask, LBasicBlock slowPath)
</ins><span class="cx">     {
</span><span class="cx">         LValue result = allocateCell(allocator, structure, slowPath);
</span><span class="cx">         if (structure->hasIntPtr()) {
</span><span class="lines">@@ -11900,22 +11911,23 @@
</span><span class="cx">         }
</span><span class="cx">         
</span><span class="cx">         m_out.storePtr(butterfly, result, m_heaps.JSObject_butterfly);
</span><ins>+        m_out.store32(m_out.castToInt32(indexingMask), result, m_heaps.JSObject_butterflyMask);
</ins><span class="cx">         return result;
</span><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     template<typename ClassType, typename StructureType>
</span><span class="cx">     LValue allocateObject(
</span><del>-        size_t size, StructureType structure, LValue butterfly, LBasicBlock slowPath)
</del><ins>+        size_t size, StructureType structure, LValue butterfly, LValue indexingMask, LBasicBlock slowPath)
</ins><span class="cx">     {
</span><span class="cx">         MarkedAllocator* allocator = subspaceFor<ClassType>(vm())->allocatorForNonVirtual(size, AllocatorForMode::AllocatorIfExists);
</span><del>-        return allocateObject(m_out.constIntPtr(allocator), structure, butterfly, slowPath);
</del><ins>+        return allocateObject(m_out.constIntPtr(allocator), structure, butterfly, indexingMask, slowPath);
</ins><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     template<typename ClassType, typename StructureType>
</span><del>-    LValue allocateObject(StructureType structure, LValue butterfly, LBasicBlock slowPath)
</del><ins>+    LValue allocateObject(StructureType structure, LValue butterfly, LValue indexingMask, LBasicBlock slowPath)
</ins><span class="cx">     {
</span><span class="cx">         return allocateObject<ClassType>(
</span><del>-            ClassType::allocationSize(0), structure, butterfly, slowPath);
</del><ins>+            ClassType::allocationSize(0), structure, butterfly, indexingMask, slowPath);
</ins><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     LValue allocatorForSize(LValue subspace, LValue size, LBasicBlock slowPath)
</span><span class="lines">@@ -11968,11 +11980,11 @@
</span><span class="cx">     
</span><span class="cx">     template<typename ClassType>
</span><span class="cx">     LValue allocateVariableSizedObject(
</span><del>-        LValue size, RegisteredStructure structure, LValue butterfly, LBasicBlock slowPath)
</del><ins>+        LValue size, RegisteredStructure structure, LValue butterfly, LValue butterflyIndexingMask, LBasicBlock slowPath)
</ins><span class="cx">     {
</span><span class="cx">         LValue allocator = allocatorForSize(
</span><span class="cx">             *subspaceFor<ClassType>(vm()), size, slowPath);
</span><del>-        return allocateObject(allocator, structure, butterfly, slowPath);
</del><ins>+        return allocateObject(allocator, structure, butterfly, butterflyIndexingMask, slowPath);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     template<typename ClassType>
</span><span class="lines">@@ -11999,7 +12011,7 @@
</span><span class="cx">         LBasicBlock lastNext = m_out.insertNewBlocksBefore(slowPath);
</span><span class="cx">         
</span><span class="cx">         ValueFromBlock fastResult = m_out.anchor(allocateObject(
</span><del>-            m_out.constIntPtr(allocator), structure, m_out.intPtrZero, slowPath));
</del><ins>+            m_out.constIntPtr(allocator), structure, m_out.intPtrZero, m_out.int32Zero, slowPath));
</ins><span class="cx">         
</span><span class="cx">         m_out.jump(continuation);
</span><span class="cx">         
</span><span class="lines">@@ -12114,9 +12126,10 @@
</span><span class="cx">             butterfly);
</span><span class="cx">         
</span><span class="cx">         ValueFromBlock haveButterfly = m_out.anchor(butterfly);
</span><del>-        
-        LValue object = allocateObject<JSArray>(structure, butterfly, failCase);
</del><span class="cx"> 
</span><ins>+        LValue mask = computeButterflyIndexingMask(vectorLength);
+        LValue object = allocateObject<JSArray>(structure, butterfly, mask, failCase);
+
</ins><span class="cx">         ValueFromBlock fastResult = m_out.anchor(object);
</span><span class="cx">         ValueFromBlock fastButterfly = m_out.anchor(butterfly);
</span><span class="cx">         m_out.jump(continuation);
</span><span class="lines">@@ -13015,13 +13028,13 @@
</span><span class="cx">     
</span><span class="cx">     TypedPointer pointerIntoTypedArray(LValue storage, LValue index, TypedArrayType type)
</span><span class="cx">     {
</span><ins>+        LValue offset = m_out.shl(m_out.zeroExtPtr(index), m_out.constIntPtr(logElementSize(type)));
</ins><span class="cx">         return TypedPointer(
</span><span class="cx">             m_heaps.typedArrayProperties,
</span><span class="cx">             m_out.add(
</span><span class="cx">                 storage,
</span><del>-                m_out.shl(
-                    m_out.zeroExtPtr(index),
-                    m_out.constIntPtr(logElementSize(type)))));
</del><ins>+                offset
+            ));
</ins><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     LValue loadFromIntTypedArray(TypedPointer pointer, TypedArrayType type)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLOutputh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLOutput.h (225912 => 225913)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLOutput.h      2017-12-14 19:10:54 UTC (rev 225912)
+++ trunk/Source/JavaScriptCore/ftl/FTLOutput.h 2017-12-14 19:11:49 UTC (rev 225913)
</span><span class="lines">@@ -303,9 +303,9 @@
</span><span class="cx">     {
</span><span class="cx">         return TypedPointer(heap, baseIndex(base, index, scale, offset));
</span><span class="cx">     }
</span><del>-    TypedPointer baseIndex(IndexedAbstractHeap& heap, LValue base, LValue index, JSValue indexAsConstant = JSValue(), ptrdiff_t offset = 0)
</del><ins>+    TypedPointer baseIndex(IndexedAbstractHeap& heap, LValue base, LValue index, JSValue indexAsConstant = JSValue(), ptrdiff_t offset = 0, LValue mask = nullptr)
</ins><span class="cx">     {
</span><del>-        return heap.baseIndex(*this, base, index, indexAsConstant, offset);
</del><ins>+        return heap.baseIndex(*this, base, index, indexAsConstant, offset, mask);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     TypedPointer absolute(const void* address);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitAssemblyHelpersh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/AssemblyHelpers.h (225912 => 225913)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/AssemblyHelpers.h        2017-12-14 19:10:54 UTC (rev 225912)
+++ trunk/Source/JavaScriptCore/jit/AssemblyHelpers.h   2017-12-14 19:11:49 UTC (rev 225913)
</span><span class="lines">@@ -1354,24 +1354,27 @@
</span><span class="cx">         UNUSED_PARAM(scratch);
</span><span class="cx"> #endif
</span><span class="cx">     }
</span><del>-    
-    void storeButterfly(VM& vm, GPRReg butterfly, GPRReg object)
</del><ins>+
+    void emitComputeButterflyIndexingMask(GPRReg vectorLengthGPR, GPRReg scratchGPR, GPRReg resultGPR)
</ins><span class="cx">     {
</span><del>-        if (isX86()) {
-            storePtr(butterfly, Address(object, JSObject::butterflyOffset()));
-            return;
</del><ins>+        ASSERT(scratchGPR != resultGPR);
+        Jump done;
+        if (isX86() && !isX86_64()) {
+            Jump nonZero = branchTest32(NonZero, vectorLengthGPR);
+            move(TrustedImm32(0), resultGPR);
+            done = jump();
+            nonZero.link(this);
</ins><span class="cx">         }
</span><del>-        
-        Jump ok = jumpIfMutatorFenceNotNeeded(vm);
-        storeFence();
-        storePtr(butterfly, Address(object, JSObject::butterflyOffset()));
-        storeFence();
-        Jump done = jump();
-        ok.link(this);
-        storePtr(butterfly, Address(object, JSObject::butterflyOffset()));
-        done.link(this);
</del><ins>+        // If vectorLength == 0 then clz will return 32 on both ARM and x86. On 64-bit systems, we can then do a 64-bit right shift on a 32-bit -1 to get a 0 mask for zero vectorLength. On 32-bit ARM, shift masks with 0xff, which means it will still create a 0 mask.
+        countLeadingZeros32(vectorLengthGPR, scratchGPR);
+        move(TrustedImm32(-1), resultGPR);
+        urshiftPtr(scratchGPR, resultGPR);
+        if (done.isSet())
+            done.link(this);
</ins><span class="cx">     }
</span><del>-    
</del><ins>+
+    // If for whatever reason the butterfly is going to change vector length this function does NOT
+    // update the indexing mask.
</ins><span class="cx">     void nukeStructureAndStoreButterfly(VM& vm, GPRReg butterfly, GPRReg object)
</span><span class="cx">     {
</span><span class="cx">         if (isX86()) {
</span><span class="lines">@@ -1379,7 +1382,7 @@
</span><span class="cx">             storePtr(butterfly, Address(object, JSObject::butterflyOffset()));
</span><span class="cx">             return;
</span><span class="cx">         }
</span><del>-        
</del><ins>+
</ins><span class="cx">         Jump ok = jumpIfMutatorFenceNotNeeded(vm);
</span><span class="cx">         or32(TrustedImm32(bitwise_cast<int32_t>(nukedStructureIDBit())), Address(object, JSCell::structureIDOffset()));
</span><span class="cx">         storeFence();
</span><span class="lines">@@ -1560,16 +1563,17 @@
</span><span class="cx">         emitStoreStructureWithTypeInfo(structure, resultGPR, scratchGPR);
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    template<typename StructureType, typename StorageType>
-    void emitAllocateJSObject(GPRReg resultGPR, MarkedAllocator* allocator, GPRReg allocatorGPR, StructureType structure, StorageType storage, GPRReg scratchGPR, JumpList& slowPath)
</del><ins>+    template<typename StructureType, typename StorageType, typename MaskType>
+    void emitAllocateJSObject(GPRReg resultGPR, MarkedAllocator* allocator, GPRReg allocatorGPR, StructureType structure, StorageType storage, MaskType mask, GPRReg scratchGPR, JumpList& slowPath)
</ins><span class="cx">     {
</span><span class="cx">         emitAllocateJSCell(resultGPR, allocator, allocatorGPR, structure, scratchGPR, slowPath);
</span><span class="cx">         storePtr(storage, Address(resultGPR, JSObject::butterflyOffset()));
</span><ins>+        store32(mask, Address(resultGPR, JSObject::butterflyIndexingMaskOffset()));
</ins><span class="cx">     }
</span><span class="cx">     
</span><del>-    template<typename ClassType, typename StructureType, typename StorageType>
</del><ins>+    template<typename ClassType, typename StructureType, typename StorageType, typename MaskType>
</ins><span class="cx">     void emitAllocateJSObjectWithKnownSize(
</span><del>-        VM& vm, GPRReg resultGPR, StructureType structure, StorageType storage, GPRReg scratchGPR1,
</del><ins>+        VM& vm, GPRReg resultGPR, StructureType structure, StorageType storage, MaskType mask, GPRReg scratchGPR1,
</ins><span class="cx">         GPRReg scratchGPR2, JumpList& slowPath, size_t size)
</span><span class="cx">     {
</span><span class="cx">         MarkedAllocator* allocator = subspaceFor<ClassType>(vm)->allocatorForNonVirtual(size, AllocatorForMode::AllocatorIfExists);
</span><span class="lines">@@ -1578,13 +1582,13 @@
</span><span class="cx">             return;
</span><span class="cx">         }
</span><span class="cx">         move(TrustedImmPtr(allocator), scratchGPR1);
</span><del>-        emitAllocateJSObject(resultGPR, allocator, scratchGPR1, structure, storage, scratchGPR2, slowPath);
</del><ins>+        emitAllocateJSObject(resultGPR, allocator, scratchGPR1, structure, storage, mask, scratchGPR2, slowPath);
</ins><span class="cx">     }
</span><span class="cx">     
</span><del>-    template<typename ClassType, typename StructureType, typename StorageType>
-    void emitAllocateJSObject(VM& vm, GPRReg resultGPR, StructureType structure, StorageType storage, GPRReg scratchGPR1, GPRReg scratchGPR2, JumpList& slowPath)
</del><ins>+    template<typename ClassType, typename StructureType, typename StorageType, typename MaskType>
+    void emitAllocateJSObject(VM& vm, GPRReg resultGPR, StructureType structure, StorageType storage, MaskType mask, GPRReg scratchGPR1, GPRReg scratchGPR2, JumpList& slowPath)
</ins><span class="cx">     {
</span><del>-        emitAllocateJSObjectWithKnownSize<ClassType>(vm, resultGPR, structure, storage, scratchGPR1, scratchGPR2, slowPath, ClassType::allocationSize(0));
</del><ins>+        emitAllocateJSObjectWithKnownSize<ClassType>(vm, resultGPR, structure, storage, mask, scratchGPR1, scratchGPR2, slowPath, ClassType::allocationSize(0));
</ins><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     // allocationSize can be aliased with any of the other input GPRs. If it's not aliased then it
</span><span class="lines">@@ -1616,7 +1620,8 @@
</span><span class="cx">     void emitAllocateVariableSizedJSObject(VM& vm, GPRReg resultGPR, StructureType structure, GPRReg allocationSize, GPRReg scratchGPR1, GPRReg scratchGPR2, JumpList& slowPath)
</span><span class="cx">     {
</span><span class="cx">         emitAllocateVariableSizedCell<ClassType>(vm, resultGPR, structure, allocationSize, scratchGPR1, scratchGPR2, slowPath);
</span><del>-        storePtr(TrustedImmPtr(0), Address(resultGPR, JSObject::butterflyOffset()));
</del><ins>+        storePtr(TrustedImmPtr(nullptr), Address(resultGPR, JSObject::butterflyOffset()));
+        store32(TrustedImm32(0), Address(resultGPR, JSObject::butterflyIndexingMaskOffset()));
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     void emitConvertValueToBoolean(VM&, JSValueRegs value, GPRReg result, GPRReg scratchIfShouldCheckMasqueradesAsUndefined, FPRReg, FPRReg, bool shouldCheckMasqueradesAsUndefined, JSGlobalObject*, bool negateResult = false);
</span><span class="lines">@@ -1624,7 +1629,9 @@
</span><span class="cx">     template<typename ClassType>
</span><span class="cx">     void emitAllocateDestructibleObject(VM& vm, GPRReg resultGPR, Structure* structure, GPRReg scratchGPR1, GPRReg scratchGPR2, JumpList& slowPath)
</span><span class="cx">     {
</span><del>-        emitAllocateJSObject<ClassType>(vm, resultGPR, TrustedImmPtr(structure), TrustedImmPtr(0), scratchGPR1, scratchGPR2, slowPath);
</del><ins>+        auto butterfly = TrustedImmPtr(nullptr);
+        auto mask = TrustedImm32(0);
+        emitAllocateJSObject<ClassType>(vm, resultGPR, TrustedImmPtr(structure), butterfly, mask, scratchGPR1, scratchGPR2, slowPath);
</ins><span class="cx">         storePtr(TrustedImmPtr(PoisonedClassInfoPtr(structure->classInfo()).bits()), Address(resultGPR, JSDestructibleObject::classInfoOffset()));
</span><span class="cx">     }
</span><span class="cx">     
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitJITOpcodescpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/JITOpcodes.cpp (225912 => 225913)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/JITOpcodes.cpp   2017-12-14 19:10:54 UTC (rev 225912)
+++ trunk/Source/JavaScriptCore/jit/JITOpcodes.cpp      2017-12-14 19:11:49 UTC (rev 225913)
</span><span class="lines">@@ -91,7 +91,9 @@
</span><span class="cx">     if (allocator)
</span><span class="cx">         addSlowCase(Jump());
</span><span class="cx">     JumpList slowCases;
</span><del>-    emitAllocateJSObject(resultReg, allocator, allocatorReg, TrustedImmPtr(structure), TrustedImmPtr(0), scratchReg, slowCases);
</del><ins>+    auto butterfly = TrustedImmPtr(nullptr);
+    auto mask = TrustedImm32(0);
+    emitAllocateJSObject(resultReg, allocator, allocatorReg, TrustedImmPtr(structure), butterfly, mask, scratchReg, slowCases);
</ins><span class="cx">     emitInitializeInlineStorage(resultReg, structure->inlineCapacity());
</span><span class="cx">     addSlowCase(slowCases);
</span><span class="cx">     emitPutVirtualRegister(currentInstruction[1].u.operand);
</span><span class="lines">@@ -774,7 +776,9 @@
</span><span class="cx">     hasSeenMultipleCallees.link(this);
</span><span class="cx"> 
</span><span class="cx">     JumpList slowCases;
</span><del>-    emitAllocateJSObject(resultReg, nullptr, allocatorReg, structureReg, TrustedImmPtr(0), scratchReg, slowCases);
</del><ins>+    auto butterfly = TrustedImmPtr(nullptr);
+    auto mask = TrustedImm32(0);
+    emitAllocateJSObject(resultReg, nullptr, allocatorReg, structureReg, butterfly, mask, scratchReg, slowCases);
</ins><span class="cx">     emitGetVirtualRegister(callee, scratchReg);
</span><span class="cx">     loadPtr(Address(scratchReg, JSFunction::offsetOfRareData()), scratchReg);
</span><span class="cx">     load32(Address(scratchReg, FunctionRareData::offsetOfObjectAllocationProfile() + ObjectAllocationProfile::offsetOfInlineCapacity()), scratchReg);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitJITOpcodes32_64cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp (225912 => 225913)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp      2017-12-14 19:10:54 UTC (rev 225912)
+++ trunk/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp 2017-12-14 19:11:49 UTC (rev 225913)
</span><span class="lines">@@ -89,7 +89,9 @@
</span><span class="cx">     if (allocator)
</span><span class="cx">         addSlowCase(Jump());
</span><span class="cx">     JumpList slowCases;
</span><del>-    emitAllocateJSObject(resultReg, allocator, allocatorReg, TrustedImmPtr(structure), TrustedImmPtr(0), scratchReg, slowCases);
</del><ins>+    auto butterfly = TrustedImmPtr(nullptr);
+    auto mask = TrustedImm32(0);
+    emitAllocateJSObject(resultReg, allocator, allocatorReg, TrustedImmPtr(structure), butterfly, mask, scratchReg, slowCases);
</ins><span class="cx">     emitInitializeInlineStorage(resultReg, structure->inlineCapacity());
</span><span class="cx">     addSlowCase(slowCases);
</span><span class="cx">     emitStoreCell(currentInstruction[1].u.operand, resultReg);
</span><span class="lines">@@ -864,7 +866,9 @@
</span><span class="cx">     hasSeenMultipleCallees.link(this);
</span><span class="cx"> 
</span><span class="cx">     JumpList slowCases;
</span><del>-    emitAllocateJSObject(resultReg, nullptr, allocatorReg, structureReg, TrustedImmPtr(0), scratchReg, slowCases);
</del><ins>+    auto butterfly = TrustedImmPtr(nullptr);
+    auto mask = TrustedImm32(0);
+    emitAllocateJSObject(resultReg, nullptr, allocatorReg, structureReg, butterfly, mask, scratchReg, slowCases);
</ins><span class="cx">     addSlowCase(slowCases);
</span><span class="cx">     emitStoreCell(currentInstruction[1].u.operand, resultReg);
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitJITPropertyAccesscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/JITPropertyAccess.cpp (225912 => 225913)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/JITPropertyAccess.cpp    2017-12-14 19:10:54 UTC (rev 225912)
+++ trunk/Source/JavaScriptCore/jit/JITPropertyAccess.cpp       2017-12-14 19:11:49 UTC (rev 225913)
</span><span class="lines">@@ -174,6 +174,7 @@
</span><span class="cx">     badType = patchableBranch32(NotEqual, regT2, TrustedImm32(DoubleShape));
</span><span class="cx">     loadPtr(Address(regT0, JSObject::butterflyOffset()), regT2);
</span><span class="cx">     slowCases.append(branch32(AboveOrEqual, regT1, Address(regT2, Butterfly::offsetOfPublicLength())));
</span><ins>+    and32(Address(regT0, JSObject::butterflyIndexingMaskOffset()), regT1);
</ins><span class="cx">     loadDouble(BaseIndex(regT2, regT1, TimesEight), fpRegT0);
</span><span class="cx">     slowCases.append(branchDouble(DoubleNotEqualOrUnordered, fpRegT0, fpRegT0));
</span><span class="cx">     
</span><span class="lines">@@ -187,6 +188,7 @@
</span><span class="cx">     badType = patchableBranch32(NotEqual, regT2, TrustedImm32(expectedShape));
</span><span class="cx">     loadPtr(Address(regT0, JSObject::butterflyOffset()), regT2);
</span><span class="cx">     slowCases.append(branch32(AboveOrEqual, regT1, Address(regT2, Butterfly::offsetOfPublicLength())));
</span><ins>+    and32(Address(regT0, JSObject::butterflyIndexingMaskOffset()), regT1);
</ins><span class="cx">     load64(BaseIndex(regT2, regT1, TimesEight), regT0);
</span><span class="cx">     slowCases.append(branchTest64(Zero, regT0));
</span><span class="cx">     
</span><span class="lines">@@ -203,6 +205,7 @@
</span><span class="cx">     loadPtr(Address(regT0, JSObject::butterflyOffset()), regT2);
</span><span class="cx">     slowCases.append(branch32(AboveOrEqual, regT1, Address(regT2, ArrayStorage::vectorLengthOffset())));
</span><span class="cx"> 
</span><ins>+    and32(Address(regT0, JSObject::butterflyIndexingMaskOffset()), regT1);
</ins><span class="cx">     load64(BaseIndex(regT2, regT1, TimesEight, ArrayStorage::vectorOffset()), regT0);
</span><span class="cx">     slowCases.append(branchTest64(Zero, regT0));
</span><span class="cx">     
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorellintLowLevelInterpreter32_64asm"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm (225912 => 225913)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm   2017-12-14 19:10:54 UTC (rev 225912)
+++ trunk/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm      2017-12-14 19:11:49 UTC (rev 225913)
</span><span class="lines">@@ -1581,9 +1581,10 @@
</span><span class="cx">     andi IndexingShapeMask, t2
</span><span class="cx">     bieq t2, Int32Shape, .opGetByValIsContiguous
</span><span class="cx">     bineq t2, ContiguousShape, .opGetByValNotContiguous
</span><ins>+
</ins><span class="cx"> .opGetByValIsContiguous:
</span><del>-    
</del><span class="cx">     biaeq t1, -sizeof IndexingHeader + IndexingHeader::u.lengths.publicLength[t3], .opGetByValOutOfBounds
</span><ins>+    andi JSObject::m_butterflyIndexingMask[t0], t1
</ins><span class="cx">     loadi TagOffset[t3, t1, 8], t2
</span><span class="cx">     loadi PayloadOffset[t3, t1, 8], t1
</span><span class="cx">     jmp .opGetByValDone
</span><span class="lines">@@ -1591,6 +1592,7 @@
</span><span class="cx"> .opGetByValNotContiguous:
</span><span class="cx">     bineq t2, DoubleShape, .opGetByValNotDouble
</span><span class="cx">     biaeq t1, -sizeof IndexingHeader + IndexingHeader::u.lengths.publicLength[t3], .opGetByValOutOfBounds
</span><ins>+    andi JSObject::m_butterflyIndexingMask[t0], t1
</ins><span class="cx">     loadd [t3, t1, 8], ft0
</span><span class="cx">     bdnequn ft0, ft0, .opGetByValSlow
</span><span class="cx">     # FIXME: This could be massively optimized.
</span><span class="lines">@@ -1602,6 +1604,7 @@
</span><span class="cx">     subi ArrayStorageShape, t2
</span><span class="cx">     bia t2, SlowPutArrayStorageShape - ArrayStorageShape, .opGetByValSlow
</span><span class="cx">     biaeq t1, -sizeof IndexingHeader + IndexingHeader::u.lengths.vectorLength[t3], .opGetByValOutOfBounds
</span><ins>+    andi JSObject::m_butterflyIndexingMask[t0], t1
</ins><span class="cx">     loadi ArrayStorage::m_vector + TagOffset[t3, t1, 8], t2
</span><span class="cx">     loadi ArrayStorage::m_vector + PayloadOffset[t3, t1, 8], t1
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorellintLowLevelInterpreter64asm"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm (225912 => 225913)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm      2017-12-14 19:10:54 UTC (rev 225912)
+++ trunk/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm 2017-12-14 19:11:49 UTC (rev 225913)
</span><span class="lines">@@ -1500,9 +1500,10 @@
</span><span class="cx">     andi IndexingShapeMask, t2
</span><span class="cx">     bieq t2, Int32Shape, .opGetByValIsContiguous
</span><span class="cx">     bineq t2, ContiguousShape, .opGetByValNotContiguous
</span><ins>+
</ins><span class="cx"> .opGetByValIsContiguous:
</span><del>-
</del><span class="cx">     biaeq t1, -sizeof IndexingHeader + IndexingHeader::u.lengths.publicLength[t3], .opGetByValOutOfBounds
</span><ins>+    andi JSObject::m_butterflyIndexingMask[t0], t1
</ins><span class="cx">     loadisFromInstruction(1, t0)
</span><span class="cx">     loadq [t3, t1, 8], t2
</span><span class="cx">     btqz t2, .opGetByValOutOfBounds
</span><span class="lines">@@ -1511,7 +1512,8 @@
</span><span class="cx"> .opGetByValNotContiguous:
</span><span class="cx">     bineq t2, DoubleShape, .opGetByValNotDouble
</span><span class="cx">     biaeq t1, -sizeof IndexingHeader + IndexingHeader::u.lengths.publicLength[t3], .opGetByValOutOfBounds
</span><del>-    loadis 8[PB, PC, 8], t0
</del><ins>+    andi JSObject::m_butterflyIndexingMask[t0], t1
+    loadisFromInstruction(1 ,t0)
</ins><span class="cx">     loadd [t3, t1, 8], ft0
</span><span class="cx">     bdnequn ft0, ft0, .opGetByValOutOfBounds
</span><span class="cx">     fd2q ft0, t2
</span><span class="lines">@@ -1522,6 +1524,7 @@
</span><span class="cx">     subi ArrayStorageShape, t2
</span><span class="cx">     bia t2, SlowPutArrayStorageShape - ArrayStorageShape, .opGetByValNotIndexedStorage
</span><span class="cx">     biaeq t1, -sizeof IndexingHeader + IndexingHeader::u.lengths.vectorLength[t3], .opGetByValOutOfBounds
</span><ins>+    andi JSObject::m_butterflyIndexingMask[t0], t1
</ins><span class="cx">     loadisFromInstruction(1, t0)
</span><span class="cx">     loadq ArrayStorage::m_vector[t3, t1, 8], t2
</span><span class="cx">     btqz t2, .opGetByValOutOfBounds
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeArrayStorageh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/ArrayStorage.h (225912 => 225913)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/ArrayStorage.h       2017-12-14 19:10:54 UTC (rev 225912)
+++ trunk/Source/JavaScriptCore/runtime/ArrayStorage.h  2017-12-14 19:11:49 UTC (rev 225913)
</span><span class="lines">@@ -81,14 +81,6 @@
</span><span class="cx"> 
</span><span class="cx">     ContiguousJSValues vector() { return ContiguousJSValues(m_vector, vectorLength()); }
</span><span class="cx"> 
</span><del>-    WriteBarrier<SparseArrayValueMap> m_sparseMap;
-    unsigned m_indexBias;
-    unsigned m_numValuesInVector;
-#if USE(JSVALUE32_64)
-    uintptr_t m_padding;
-#endif
-    WriteBarrier<Unknown> m_vector[1];
-    
</del><span class="cx">     static ptrdiff_t lengthOffset() { return Butterfly::offsetOfPublicLength(); }
</span><span class="cx">     static ptrdiff_t vectorLengthOffset() { return Butterfly::offsetOfVectorLength(); }
</span><span class="cx">     static ptrdiff_t numValuesInVectorOffset() { return OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector); }
</span><span class="lines">@@ -95,46 +87,46 @@
</span><span class="cx">     static ptrdiff_t vectorOffset() { return OBJECT_OFFSETOF(ArrayStorage, m_vector); }
</span><span class="cx">     static ptrdiff_t indexBiasOffset() { return OBJECT_OFFSETOF(ArrayStorage, m_indexBias); }
</span><span class="cx">     static ptrdiff_t sparseMapOffset() { return OBJECT_OFFSETOF(ArrayStorage, m_sparseMap); }
</span><del>-    
</del><ins>+
</ins><span class="cx">     static size_t sizeFor(unsigned vectorLength)
</span><span class="cx">     {
</span><span class="cx">         return ArrayStorage::vectorOffset() + vectorLength * sizeof(WriteBarrier<Unknown>);
</span><span class="cx">     }
</span><del>-    
</del><ins>+
</ins><span class="cx">     static size_t totalSizeFor(unsigned indexBias, size_t propertyCapacity, unsigned vectorLength)
</span><span class="cx">     {
</span><span class="cx">         return Butterfly::totalSize(indexBias, propertyCapacity, true, sizeFor(vectorLength));
</span><span class="cx">     }
</span><del>-    
</del><ins>+
</ins><span class="cx">     size_t totalSize(size_t propertyCapacity) const
</span><span class="cx">     {
</span><span class="cx">         return totalSizeFor(m_indexBias, propertyCapacity, vectorLength());
</span><span class="cx">     }
</span><del>-    
</del><ins>+
</ins><span class="cx">     size_t totalSize(Structure* structure) const
</span><span class="cx">     {
</span><span class="cx">         return totalSize(structure->outOfLineCapacity());
</span><span class="cx">     }
</span><del>-    
</del><ins>+
</ins><span class="cx">     static unsigned availableVectorLength(unsigned indexBias, size_t propertyCapacity, unsigned vectorLength)
</span><span class="cx">     {
</span><span class="cx">         size_t cellSize = MarkedSpace::optimalSizeFor(totalSizeFor(indexBias, propertyCapacity, vectorLength));
</span><del>-        
</del><ins>+
</ins><span class="cx">         vectorLength = (cellSize - totalSizeFor(indexBias, propertyCapacity, 0)) / sizeof(WriteBarrier<Unknown>);
</span><span class="cx"> 
</span><span class="cx">         return vectorLength;
</span><span class="cx">     }
</span><del>-    
</del><ins>+
</ins><span class="cx">     static unsigned availableVectorLength(unsigned indexBias, Structure* structure, unsigned vectorLength)
</span><span class="cx">     {
</span><span class="cx">         return availableVectorLength(indexBias, structure->outOfLineCapacity(), vectorLength);
</span><span class="cx">     }
</span><del>-    
</del><ins>+
</ins><span class="cx">     unsigned availableVectorLength(size_t propertyCapacity, unsigned vectorLength)
</span><span class="cx">     {
</span><span class="cx">         return availableVectorLength(m_indexBias, propertyCapacity, vectorLength);
</span><span class="cx">     }
</span><del>-    
</del><ins>+
</ins><span class="cx">     unsigned availableVectorLength(Structure* structure, unsigned vectorLength)
</span><span class="cx">     {
</span><span class="cx">         return availableVectorLength(structure->outOfLineCapacity(), vectorLength);
</span><span class="lines">@@ -145,21 +137,29 @@
</span><span class="cx">         vectorLength = std::max(BASE_ARRAY_STORAGE_VECTOR_LEN, vectorLength);
</span><span class="cx">         return availableVectorLength(indexBias, propertyCapacity, vectorLength);
</span><span class="cx">     }
</span><del>-    
</del><ins>+
</ins><span class="cx">     static unsigned optimalVectorLength(unsigned indexBias, Structure* structure, unsigned vectorLength)
</span><span class="cx">     {
</span><span class="cx">         return optimalVectorLength(indexBias, structure->outOfLineCapacity(), vectorLength);
</span><span class="cx">     }
</span><del>-    
</del><ins>+
</ins><span class="cx">     unsigned optimalVectorLength(size_t propertyCapacity, unsigned vectorLength)
</span><span class="cx">     {
</span><span class="cx">         return optimalVectorLength(m_indexBias, propertyCapacity, vectorLength);
</span><span class="cx">     }
</span><del>-    
</del><ins>+
</ins><span class="cx">     unsigned optimalVectorLength(Structure* structure, unsigned vectorLength)
</span><span class="cx">     {
</span><span class="cx">         return optimalVectorLength(structure->outOfLineCapacity(), vectorLength);
</span><span class="cx">     }
</span><ins>+
+    WriteBarrier<SparseArrayValueMap> m_sparseMap;
+    unsigned m_indexBias;
+    unsigned m_numValuesInVector;
+#if USE(JSVALUE32_64)
+    uintptr_t m_padding;
+#endif
+    WriteBarrier<Unknown> m_vector[1];
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> } // namespace JSC
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeButterflyh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/Butterfly.h (225912 => 225913)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/Butterfly.h  2017-12-14 19:10:54 UTC (rev 225912)
+++ trunk/Source/JavaScriptCore/runtime/Butterfly.h     2017-12-14 19:11:49 UTC (rev 225913)
</span><span class="lines">@@ -36,14 +36,9 @@
</span><span class="cx"> class CopyVisitor;
</span><span class="cx"> struct ArrayStorage;
</span><span class="cx"> 
</span><del>-template <typename T> struct ContiguousData {
-    ContiguousData()
-        : m_data(0)
-#if !ASSERT_DISABLED
-        , m_length(0)
-#endif
-    {
-    }
</del><ins>+template <typename T>
+struct ContiguousData {
+    ContiguousData() = default;
</ins><span class="cx">     ContiguousData(T* data, size_t length)
</span><span class="cx">         : m_data(data)
</span><span class="cx"> #if !ASSERT_DISABLED
</span><span class="lines">@@ -53,9 +48,12 @@
</span><span class="cx">         UNUSED_PARAM(length);
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    const T& operator[](size_t index) const { ASSERT(index < m_length); return m_data[index]; }
-    T& operator[](size_t index) { ASSERT(index < m_length); return m_data[index]; }
</del><ins>+    const T& at(const uint32_t mask, size_t index) const { ASSERT(index < m_length); return m_data[index & mask]; }
+    T& at(const uint32_t mask, size_t index) { ASSERT(index < m_length);  return m_data[index & mask]; }
</ins><span class="cx"> 
</span><ins>+    const T& at(const JSObject* base, size_t index) const;
+    T& at(const JSObject* base, size_t index);
+
</ins><span class="cx">     T* data() const { return m_data; }
</span><span class="cx"> #if !ASSERT_DISABLED
</span><span class="cx">     size_t length() const { return m_length; }
</span><span class="lines">@@ -62,9 +60,9 @@
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><span class="cx"> private:
</span><del>-    T* m_data;
</del><ins>+    T* m_data { nullptr };
</ins><span class="cx"> #if !ASSERT_DISABLED
</span><del>-    size_t m_length;
</del><ins>+    size_t m_length { 0 };
</ins><span class="cx"> #endif
</span><span class="cx"> };
</span><span class="cx"> 
</span><span class="lines">@@ -120,16 +118,18 @@
</span><span class="cx">     PropertyStorage propertyStorage() { return indexingHeader()->propertyStorage(); }
</span><span class="cx">     ConstPropertyStorage propertyStorage() const { return indexingHeader()->propertyStorage(); }
</span><span class="cx">     
</span><del>-    uint32_t publicLength() { return indexingHeader()->publicLength(); }
-    uint32_t vectorLength() { return indexingHeader()->vectorLength(); }
</del><ins>+    uint32_t publicLength() const { return indexingHeader()->publicLength(); }
+    uint32_t vectorLength() const { return indexingHeader()->vectorLength(); }
</ins><span class="cx">     void setPublicLength(uint32_t value) { indexingHeader()->setPublicLength(value); }
</span><span class="cx">     void setVectorLength(uint32_t value) { indexingHeader()->setVectorLength(value); }
</span><del>-    
</del><ins>+
+    static uint32_t computeIndexingMaskForVectorLength(uint32_t vectorLength) { return static_cast<uint64_t>(static_cast<uint32_t>(-1)) >> std::clz(vectorLength); }
+    uint32_t computeIndexingMask() const { return computeIndexingMaskForVectorLength(vectorLength()); }
+
</ins><span class="cx">     template<typename T>
</span><span class="cx">     T* indexingPayload() { return reinterpret_cast_ptr<T*>(this); }
</span><span class="cx">     ArrayStorage* arrayStorage() { return indexingPayload<ArrayStorage>(); }
</span><span class="cx">     ContiguousJSValues contiguousInt32() { return ContiguousJSValues(indexingPayload<WriteBarrier<Unknown>>(), vectorLength()); }
</span><del>-
</del><span class="cx">     ContiguousDoubles contiguousDouble() { return ContiguousDoubles(indexingPayload<double>(), vectorLength()); }
</span><span class="cx">     ContiguousJSValues contiguous() { return ContiguousJSValues(indexingPayload<WriteBarrier<Unknown>>(), vectorLength()); }
</span><span class="cx">     
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeButterflyInlinesh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/ButterflyInlines.h (225912 => 225913)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/ButterflyInlines.h   2017-12-14 19:10:54 UTC (rev 225912)
+++ trunk/Source/JavaScriptCore/runtime/ButterflyInlines.h      2017-12-14 19:11:49 UTC (rev 225913)
</span><span class="lines">@@ -27,11 +27,28 @@
</span><span class="cx"> 
</span><span class="cx"> #include "ArrayStorage.h"
</span><span class="cx"> #include "Butterfly.h"
</span><ins>+#include "JSObject.h"
</ins><span class="cx"> #include "VM.h"
</span><span class="cx"> #include "Structure.h"
</span><span class="cx"> 
</span><span class="cx"> namespace JSC {
</span><span class="cx"> 
</span><ins>+template<typename T>
+const T& ContiguousData<T>::at(const JSObject* base, size_t index) const
+{
+    ASSERT(index < m_length);
+    ASSERT(base->butterflyIndexingMask() >= length());
+    return m_data[index & base->butterflyIndexingMask()];
+}
+
+template<typename T>
+T& ContiguousData<T>::at(const JSObject* base, size_t index)
+{
+    ASSERT(index < m_length);
+    ASSERT(base->butterflyIndexingMask() >= length());
+    return m_data[index & base->butterflyIndexingMask()];
+}
+
</ins><span class="cx"> ALWAYS_INLINE unsigned Butterfly::availableContiguousVectorLength(size_t propertyCapacity, unsigned vectorLength)
</span><span class="cx"> {
</span><span class="cx">     size_t cellSize = totalSize(0, propertyCapacity, true, sizeof(EncodedJSValue) * vectorLength);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeClonedArgumentscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/ClonedArguments.cpp (225912 => 225913)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/ClonedArguments.cpp  2017-12-14 19:10:54 UTC (rev 225912)
+++ trunk/Source/JavaScriptCore/runtime/ClonedArguments.cpp     2017-12-14 19:11:49 UTC (rev 225913)
</span><span class="lines">@@ -61,7 +61,7 @@
</span><span class="cx">             return 0;
</span><span class="cx"> 
</span><span class="cx">         for (unsigned i = length; i < vectorLength; ++i)
</span><del>-            butterfly->contiguous()[i].clear();
</del><ins>+            butterfly->contiguous().at(std::numeric_limits<uint32_t>::max(), i).clear();
</ins><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     ClonedArguments* result =
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSArraycpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSArray.cpp (225912 => 225913)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSArray.cpp  2017-12-14 19:10:54 UTC (rev 225912)
+++ trunk/Source/JavaScriptCore/runtime/JSArray.cpp     2017-12-14 19:11:49 UTC (rev 225913)
</span><span class="lines">@@ -90,10 +90,10 @@
</span><span class="cx">         unsigned i = (createUninitialized ? initialLength : 0);
</span><span class="cx">         if (hasDouble(indexingType)) {
</span><span class="cx">             for (; i < vectorLength; ++i)
</span><del>-                butterfly->contiguousDouble()[i] = PNaN;
</del><ins>+                butterfly->contiguousDouble().at(std::numeric_limits<uint32_t>::max(), i) = PNaN;
</ins><span class="cx">         } else if (LIKELY(!hasUndecided(indexingType))) {
</span><span class="cx">             for (; i < vectorLength; ++i)
</span><del>-                butterfly->contiguous()[i].clear();
</del><ins>+                butterfly->contiguous().at(std::numeric_limits<uint32_t>::max(), i).clear();
</ins><span class="cx">         }
</span><span class="cx">     } else {
</span><span class="cx">         static const unsigned indexBias = 0;
</span><span class="lines">@@ -540,10 +540,10 @@
</span><span class="cx">         auto* butterfly = this->butterfly();
</span><span class="cx">         if (type == ArrayWithDouble) {
</span><span class="cx">             for (unsigned i = startIndex; i < newLength; ++i)
</span><del>-                butterfly->contiguousDouble()[i] = PNaN;
</del><ins>+                butterfly->contiguousDouble().at(this, i) = PNaN;
</ins><span class="cx">         } else {
</span><span class="cx">             for (unsigned i = startIndex; i < newLength; ++i)
</span><del>-                butterfly->contiguousInt32()[i].setWithoutWriteBarrier(JSValue());
</del><ins>+                butterfly->contiguousInt32().at(this, i).setWithoutWriteBarrier(JSValue());
</ins><span class="cx">         }
</span><span class="cx">     } else if (type == ArrayWithDouble)
</span><span class="cx">         memcpy(butterfly()->contiguousDouble().data() + startIndex, otherArray->butterfly()->contiguousDouble().data(), sizeof(JSValue) * otherLength);
</span><span class="lines">@@ -603,10 +603,10 @@
</span><span class="cx"> 
</span><span class="cx">         if (indexingType() == ArrayWithDouble) {
</span><span class="cx">             for (unsigned i = butterfly->publicLength(); i-- > newLength;)
</span><del>-                butterfly->contiguousDouble()[i] = PNaN;
</del><ins>+                butterfly->contiguousDouble().at(this, i) = PNaN;
</ins><span class="cx">         } else {
</span><span class="cx">             for (unsigned i = butterfly->publicLength(); i-- > newLength;)
</span><del>-                butterfly->contiguous()[i].clear();
</del><ins>+                butterfly->contiguous().at(this, i).clear();
</ins><span class="cx">         }
</span><span class="cx">         butterfly->setPublicLength(newLength);
</span><span class="cx">         return true;
</span><span class="lines">@@ -648,9 +648,9 @@
</span><span class="cx">             return jsUndefined();
</span><span class="cx">         
</span><span class="cx">         RELEASE_ASSERT(length < butterfly->vectorLength());
</span><del>-        JSValue value = butterfly->contiguous()[length].get();
</del><ins>+        JSValue value = butterfly->contiguous().at(this, length).get();
</ins><span class="cx">         if (value) {
</span><del>-            butterfly->contiguous()[length].clear();
</del><ins>+            butterfly->contiguous().at(this, length).clear();
</ins><span class="cx">             butterfly->setPublicLength(length);
</span><span class="cx">             return value;
</span><span class="cx">         }
</span><span class="lines">@@ -664,9 +664,9 @@
</span><span class="cx">             return jsUndefined();
</span><span class="cx">         
</span><span class="cx">         RELEASE_ASSERT(length < butterfly->vectorLength());
</span><del>-        double value = butterfly->contiguousDouble()[length];
</del><ins>+        double value = butterfly->contiguousDouble().at(this, length);
</ins><span class="cx">         if (value == value) {
</span><del>-            butterfly->contiguousDouble()[length] = PNaN;
</del><ins>+            butterfly->contiguousDouble().at(this, length) = PNaN;
</ins><span class="cx">             butterfly->setPublicLength(length);
</span><span class="cx">             return JSValue(JSValue::EncodeAsDouble, value);
</span><span class="cx">         }
</span><span class="lines">@@ -754,9 +754,9 @@
</span><span class="cx"> 
</span><span class="cx">         auto& resultButterfly = *resultArray->butterfly();
</span><span class="cx">         if (arrayType == ArrayWithDouble)
</span><del>-            memcpy(resultButterfly.contiguousDouble().data(), m_butterfly->contiguousDouble().data() + startIndex, sizeof(JSValue) * count);
</del><ins>+            memcpy(resultButterfly.contiguousDouble().data(), butterfly()->contiguousDouble().data() + startIndex, sizeof(JSValue) * count);
</ins><span class="cx">         else
</span><del>-            memcpy(resultButterfly.contiguous().data(), m_butterfly->contiguous().data() + startIndex, sizeof(JSValue) * count);
</del><ins>+            memcpy(resultButterfly.contiguous().data(), butterfly()->contiguous().data() + startIndex, sizeof(JSValue) * count);
</ins><span class="cx">         resultButterfly.setPublicLength(count);
</span><span class="cx"> 
</span><span class="cx">         return resultArray;
</span><span class="lines">@@ -834,7 +834,7 @@
</span><span class="cx">         // Adjust the Butterfly and the index bias. We only need to do this here because we're changing
</span><span class="cx">         // the start of the Butterfly, which needs to point at the first indexed property in the used
</span><span class="cx">         // portion of the vector.
</span><del>-        Butterfly* butterfly = m_butterfly->shift(structure(), count);
</del><ins>+        Butterfly* butterfly = this->butterfly()->shift(structure(), count);
</ins><span class="cx">         setButterfly(vm, butterfly);
</span><span class="cx">         storage = butterfly->arrayStorage();
</span><span class="cx">         storage->m_indexBias += count;
</span><span class="lines">@@ -906,12 +906,12 @@
</span><span class="cx">         unsigned end = oldLength - count;
</span><span class="cx">         if (this->structure(vm)->holesMustForwardToPrototype(vm, this)) {
</span><span class="cx">             for (unsigned i = startIndex; i < end; ++i) {
</span><del>-                JSValue v = butterfly->contiguous()[i + count].get();
</del><ins>+                JSValue v = butterfly->contiguous().at(this, i + count).get();
</ins><span class="cx">                 if (UNLIKELY(!v)) {
</span><span class="cx">                     startIndex = i;
</span><span class="cx">                     return shiftCountWithArrayStorage(vm, startIndex, count, ensureArrayStorage(vm));
</span><span class="cx">                 }
</span><del>-                butterfly->contiguous()[i].setWithoutWriteBarrier(v);
</del><ins>+                butterfly->contiguous().at(this, i).setWithoutWriteBarrier(v);
</ins><span class="cx">             }
</span><span class="cx">         } else {
</span><span class="cx">             memmove(butterfly->contiguous().data() + startIndex, 
</span><span class="lines">@@ -920,7 +920,7 @@
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         for (unsigned i = end; i < oldLength; ++i)
</span><del>-            butterfly->contiguous()[i].clear();
</del><ins>+            butterfly->contiguous().at(this, i).clear();
</ins><span class="cx">         
</span><span class="cx">         butterfly->setPublicLength(oldLength - count);
</span><span class="cx"> 
</span><span class="lines">@@ -947,12 +947,12 @@
</span><span class="cx">         unsigned end = oldLength - count;
</span><span class="cx">         if (this->structure(vm)->holesMustForwardToPrototype(vm, this)) {
</span><span class="cx">             for (unsigned i = startIndex; i < end; ++i) {
</span><del>-                double v = butterfly->contiguousDouble()[i + count];
</del><ins>+                double v = butterfly->contiguousDouble().at(this, i + count);
</ins><span class="cx">                 if (UNLIKELY(v != v)) {
</span><span class="cx">                     startIndex = i;
</span><span class="cx">                     return shiftCountWithArrayStorage(vm, startIndex, count, ensureArrayStorage(vm));
</span><span class="cx">                 }
</span><del>-                butterfly->contiguousDouble()[i] = v;
</del><ins>+                butterfly->contiguousDouble().at(this, i) = v;
</ins><span class="cx">             }
</span><span class="cx">         } else {
</span><span class="cx">             memmove(butterfly->contiguousDouble().data() + startIndex,
</span><span class="lines">@@ -960,7 +960,7 @@
</span><span class="cx">                 sizeof(JSValue) * (end - startIndex));
</span><span class="cx">         }
</span><span class="cx">         for (unsigned i = end; i < oldLength; ++i)
</span><del>-            butterfly->contiguousDouble()[i] = PNaN;
</del><ins>+            butterfly->contiguousDouble().at(this, i) = PNaN;
</ins><span class="cx">         
</span><span class="cx">         butterfly->setPublicLength(oldLength - count);
</span><span class="cx">         return true;
</span><span class="lines">@@ -1063,7 +1063,7 @@
</span><span class="cx">         // We have to check for holes before we start moving things around so that we don't get halfway 
</span><span class="cx">         // through shifting and then realize we should have been in ArrayStorage mode.
</span><span class="cx">         for (unsigned i = oldLength; i-- > startIndex;) {
</span><del>-            JSValue v = butterfly->contiguous()[i].get();
</del><ins>+            JSValue v = butterfly->contiguous().at(this, i).get();
</ins><span class="cx">             if (UNLIKELY(!v)) {
</span><span class="cx">                 scope.release();
</span><span class="cx">                 return unshiftCountWithArrayStorage(exec, startIndex, count, ensureArrayStorage(vm));
</span><span class="lines">@@ -1071,9 +1071,9 @@
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         for (unsigned i = oldLength; i-- > startIndex;) {
</span><del>-            JSValue v = butterfly->contiguous()[i].get();
</del><ins>+            JSValue v = butterfly->contiguous().at(this, i).get();
</ins><span class="cx">             ASSERT(v);
</span><del>-            butterfly->contiguous()[i + count].setWithoutWriteBarrier(v);
</del><ins>+            butterfly->contiguous().at(this, i + count).setWithoutWriteBarrier(v);
</ins><span class="cx">         }
</span><span class="cx">         
</span><span class="cx">         // Our memmoving of values around in the array could have concealed some of them from
</span><span class="lines">@@ -1107,7 +1107,7 @@
</span><span class="cx">         // We have to check for holes before we start moving things around so that we don't get halfway 
</span><span class="cx">         // through shifting and then realize we should have been in ArrayStorage mode.
</span><span class="cx">         for (unsigned i = oldLength; i-- > startIndex;) {
</span><del>-            double v = butterfly->contiguousDouble()[i];
</del><ins>+            double v = butterfly->contiguousDouble().at(this, i);
</ins><span class="cx">             if (UNLIKELY(v != v)) {
</span><span class="cx">                 scope.release();
</span><span class="cx">                 return unshiftCountWithArrayStorage(exec, startIndex, count, ensureArrayStorage(vm));
</span><span class="lines">@@ -1115,9 +1115,9 @@
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         for (unsigned i = oldLength; i-- > startIndex;) {
</span><del>-            double v = butterfly->contiguousDouble()[i];
</del><ins>+            double v = butterfly->contiguousDouble().at(this, i);
</ins><span class="cx">             ASSERT(v == v);
</span><del>-            butterfly->contiguousDouble()[i + count] = v;
</del><ins>+            butterfly->contiguousDouble().at(this, i + count) = v;
</ins><span class="cx">         }
</span><span class="cx">         
</span><span class="cx">         // NOTE: we're leaving being garbage in the part of the array that we shifted out
</span><span class="lines">@@ -1168,7 +1168,7 @@
</span><span class="cx">         vector = 0;
</span><span class="cx">         vectorEnd = 0;
</span><span class="cx">         for (; i < butterfly->publicLength(); ++i) {
</span><del>-            double v = butterfly->contiguousDouble()[i];
</del><ins>+            double v = butterfly->contiguousDouble().at(this, i);
</ins><span class="cx">             if (v != v)
</span><span class="cx">                 break;
</span><span class="cx">             args.append(JSValue(JSValue::EncodeAsDouble, v));
</span><span class="lines">@@ -1241,7 +1241,7 @@
</span><span class="cx">         vectorEnd = 0;
</span><span class="cx">         for (; i < butterfly->publicLength(); ++i) {
</span><span class="cx">             ASSERT(i < butterfly->vectorLength());
</span><del>-            double v = butterfly->contiguousDouble()[i];
</del><ins>+            double v = butterfly->contiguousDouble().at(this, i);
</ins><span class="cx">             if (v != v)
</span><span class="cx">                 break;
</span><span class="cx">             exec->r(firstElementDest + i - offset) = JSValue(JSValue::EncodeAsDouble, v);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSArrayBufferViewcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSArrayBufferView.cpp (225912 => 225913)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSArrayBufferView.cpp        2017-12-14 19:10:54 UTC (rev 225912)
+++ trunk/Source/JavaScriptCore/runtime/JSArrayBufferView.cpp   2017-12-14 19:11:49 UTC (rev 225913)
</span><span class="lines">@@ -127,10 +127,13 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> JSArrayBufferView::JSArrayBufferView(VM& vm, ConstructionContext& context)
</span><del>-    : Base(vm, context.structure(), context.butterfly())
</del><ins>+    : Base(vm, context.structure(), nullptr)
</ins><span class="cx">     , m_length(context.length())
</span><span class="cx">     , m_mode(context.mode())
</span><span class="cx"> {
</span><ins>+    // Typed Arrays don't participate in indexing masks due to performance concerns. This isn't too big of a deal because
+    // they are gigacaged.
+    setButterflyWithIndexingMask(vm, context.butterfly(), 0);
</ins><span class="cx">     m_vector.setWithoutBarrier(context.vector());
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSArrayInlinesh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSArrayInlines.h (225912 => 225913)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSArrayInlines.h     2017-12-14 19:10:54 UTC (rev 225912)
+++ trunk/Source/JavaScriptCore/runtime/JSArrayInlines.h        2017-12-14 19:11:49 UTC (rev 225913)
</span><span class="lines">@@ -114,7 +114,7 @@
</span><span class="cx">         unsigned length = butterfly->publicLength();
</span><span class="cx">         ASSERT(length <= butterfly->vectorLength());
</span><span class="cx">         if (length < butterfly->vectorLength()) {
</span><del>-            butterfly->contiguousInt32()[length].setWithoutWriteBarrier(value);
</del><ins>+            butterfly->contiguousInt32().at(this, length).setWithoutWriteBarrier(value);
</ins><span class="cx">             butterfly->setPublicLength(length + 1);
</span><span class="cx">             return;
</span><span class="cx">         }
</span><span class="lines">@@ -135,7 +135,7 @@
</span><span class="cx">         unsigned length = butterfly->publicLength();
</span><span class="cx">         ASSERT(length <= butterfly->vectorLength());
</span><span class="cx">         if (length < butterfly->vectorLength()) {
</span><del>-            butterfly->contiguous()[length].set(vm, this, value);
</del><ins>+            butterfly->contiguous().at(this, length).set(vm, this, value);
</ins><span class="cx">             butterfly->setPublicLength(length + 1);
</span><span class="cx">             return;
</span><span class="cx">         }
</span><span class="lines">@@ -170,7 +170,7 @@
</span><span class="cx">         unsigned length = butterfly->publicLength();
</span><span class="cx">         ASSERT(length <= butterfly->vectorLength());
</span><span class="cx">         if (length < butterfly->vectorLength()) {
</span><del>-            butterfly->contiguousDouble()[length] = valueAsDouble;
</del><ins>+            butterfly->contiguousDouble().at(this, length) = valueAsDouble;
</ins><span class="cx">             butterfly->setPublicLength(length + 1);
</span><span class="cx">             return;
</span><span class="cx">         }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSFixedArrayh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSFixedArray.h (225912 => 225913)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSFixedArray.h       2017-12-14 19:10:54 UTC (rev 225912)
+++ trunk/Source/JavaScriptCore/runtime/JSFixedArray.h  2017-12-14 19:11:49 UTC (rev 225913)
</span><span class="lines">@@ -81,7 +81,7 @@
</span><span class="cx"> 
</span><span class="cx">         if (indexingType == ContiguousShape || indexingType == Int32Shape) {
</span><span class="cx">             for (unsigned i = 0; i < length; i++) {
</span><del>-                JSValue value = array->butterfly()->contiguous()[i].get();
</del><ins>+                JSValue value = array->butterfly()->contiguous().at(array, i).get();
</ins><span class="cx">                 value = !!value ? value : jsUndefined();
</span><span class="cx">                 result->buffer()[i].set(vm, result, value);
</span><span class="cx">             }
</span><span class="lines">@@ -90,7 +90,7 @@
</span><span class="cx"> 
</span><span class="cx">         if (indexingType == DoubleShape) {
</span><span class="cx">             for (unsigned i = 0; i < length; i++) {
</span><del>-                double d = array->butterfly()->contiguousDouble()[i];
</del><ins>+                double d = array->butterfly()->contiguousDouble().at(array, i);
</ins><span class="cx">                 JSValue value = std::isnan(d) ? jsUndefined() : JSValue(JSValue::EncodeAsDouble, d);
</span><span class="cx">                 result->buffer()[i].set(vm, result, value);
</span><span class="cx">             }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSGenericTypedArrayViewInlinesh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSGenericTypedArrayViewInlines.h (225912 => 225913)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSGenericTypedArrayViewInlines.h     2017-12-14 19:10:54 UTC (rev 225912)
+++ trunk/Source/JavaScriptCore/runtime/JSGenericTypedArrayViewInlines.h        2017-12-14 19:11:49 UTC (rev 225913)
</span><span class="lines">@@ -559,12 +559,11 @@
</span><span class="cx">     VM& vm = *heap->vm();
</span><span class="cx">     DeferGCForAWhile deferGC(*heap);
</span><span class="cx">     
</span><del>-    ASSERT(!thisObject->hasIndexingHeader());
-    
</del><span class="cx">     RELEASE_ASSERT(!thisObject->hasIndexingHeader());
</span><del>-    thisObject->m_butterfly.set(vm, thisObject, Butterfly::createOrGrowArrayRight(
</del><ins>+    ASSERT(!thisObject->butterflyIndexingMask());
+    thisObject->setButterflyWithIndexingMask(vm, Butterfly::createOrGrowArrayRight(
</ins><span class="cx">         thisObject->butterfly(), vm, thisObject, thisObject->structure(),
</span><del>-        thisObject->structure()->outOfLineCapacity(), false, 0, 0));
</del><ins>+        thisObject->structure()->outOfLineCapacity(), false, 0, 0), 0);
</ins><span class="cx"> 
</span><span class="cx">     RefPtr<ArrayBuffer> buffer;
</span><span class="cx">     
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSObjectcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSObject.cpp (225912 => 225913)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSObject.cpp 2017-12-14 19:10:54 UTC (rev 225912)
+++ trunk/Source/JavaScriptCore/runtime/JSObject.cpp    2017-12-14 19:11:49 UTC (rev 225913)
</span><span class="lines">@@ -589,7 +589,7 @@
</span><span class="cx">         if (i >= butterfly->vectorLength())
</span><span class="cx">             return false;
</span><span class="cx">         
</span><del>-        JSValue value = butterfly->contiguous()[i].get();
</del><ins>+        JSValue value = butterfly->contiguous().at(thisObject, i).get();
</ins><span class="cx">         if (value) {
</span><span class="cx">             slot.setValue(thisObject, static_cast<unsigned>(PropertyAttribute::None), value);
</span><span class="cx">             return true;
</span><span class="lines">@@ -603,7 +603,7 @@
</span><span class="cx">         if (i >= butterfly->vectorLength())
</span><span class="cx">             return false;
</span><span class="cx">         
</span><del>-        double value = butterfly->contiguousDouble()[i];
</del><ins>+        double value = butterfly->contiguousDouble().at(thisObject, i);
</ins><span class="cx">         if (value == value) {
</span><span class="cx">             slot.setValue(thisObject, static_cast<unsigned>(PropertyAttribute::None), JSValue(JSValue::EncodeAsDouble, value));
</span><span class="cx">             return true;
</span><span class="lines">@@ -861,7 +861,7 @@
</span><span class="cx">         Butterfly* butterfly = thisObject->butterfly();
</span><span class="cx">         if (propertyName >= butterfly->vectorLength())
</span><span class="cx">             break;
</span><del>-        butterfly->contiguous()[propertyName].set(vm, thisObject, value);
</del><ins>+        butterfly->contiguous().at(thisObject, propertyName).set(vm, thisObject, value);
</ins><span class="cx">         if (propertyName >= butterfly->publicLength())
</span><span class="cx">             butterfly->setPublicLength(propertyName + 1);
</span><span class="cx">         return true;
</span><span class="lines">@@ -882,7 +882,7 @@
</span><span class="cx">         Butterfly* butterfly = thisObject->butterfly();
</span><span class="cx">         if (propertyName >= butterfly->vectorLength())
</span><span class="cx">             break;
</span><del>-        butterfly->contiguousDouble()[propertyName] = valueAsDouble;
</del><ins>+        butterfly->contiguousDouble().at(thisObject, propertyName) = valueAsDouble;
</ins><span class="cx">         if (propertyName >= butterfly->publicLength())
</span><span class="cx">             butterfly->setPublicLength(propertyName + 1);
</span><span class="cx">         return true;
</span><span class="lines">@@ -1049,8 +1049,9 @@
</span><span class="cx"> {
</span><span class="cx">     DeferGC deferGC(vm.heap);
</span><span class="cx">     Butterfly* newButterfly = createInitialIndexedStorage(vm, length);
</span><ins>+    uint32_t mask = newButterfly->computeIndexingMask();
</ins><span class="cx">     for (unsigned i = newButterfly->vectorLength(); i--;)
</span><del>-        newButterfly->contiguousInt32()[i].setWithoutWriteBarrier(JSValue());
</del><ins>+        newButterfly->contiguous().at(mask, i).setWithoutWriteBarrier(JSValue());
</ins><span class="cx">     StructureID oldStructureID = this->structureID();
</span><span class="cx">     Structure* oldStructure = vm.getStructure(oldStructureID);
</span><span class="cx">     Structure* newStructure = Structure::nonPropertyTransition(vm, oldStructure, NonPropertyTransition::AllocateInt32);
</span><span class="lines">@@ -1063,8 +1064,9 @@
</span><span class="cx"> {
</span><span class="cx">     DeferGC deferGC(vm.heap);
</span><span class="cx">     Butterfly* newButterfly = createInitialIndexedStorage(vm, length);
</span><ins>+    uint32_t mask = newButterfly->computeIndexingMask();
</ins><span class="cx">     for (unsigned i = newButterfly->vectorLength(); i--;)
</span><del>-        newButterfly->contiguousDouble()[i] = PNaN;
</del><ins>+        newButterfly->contiguousDouble().at(mask, i) = PNaN;
</ins><span class="cx">     StructureID oldStructureID = this->structureID();
</span><span class="cx">     Structure* oldStructure = vm.getStructure(oldStructureID);
</span><span class="cx">     Structure* newStructure = Structure::nonPropertyTransition(vm, oldStructure, NonPropertyTransition::AllocateDouble);
</span><span class="lines">@@ -1077,8 +1079,9 @@
</span><span class="cx"> {
</span><span class="cx">     DeferGC deferGC(vm.heap);
</span><span class="cx">     Butterfly* newButterfly = createInitialIndexedStorage(vm, length);
</span><ins>+    uint32_t mask = newButterfly->computeIndexingMask();
</ins><span class="cx">     for (unsigned i = newButterfly->vectorLength(); i--;)
</span><del>-        newButterfly->contiguous()[i].setWithoutWriteBarrier(JSValue());
</del><ins>+        newButterfly->contiguous().at(mask, i).setWithoutWriteBarrier(JSValue());
</ins><span class="cx">     StructureID oldStructureID = this->structureID();
</span><span class="cx">     Structure* oldStructure = vm.getStructure(oldStructureID);
</span><span class="cx">     Structure* newStructure = Structure::nonPropertyTransition(vm, oldStructure, NonPropertyTransition::AllocateContiguous);
</span><span class="lines">@@ -1134,7 +1137,7 @@
</span><span class="cx"> 
</span><span class="cx">     Butterfly* butterfly = this->butterfly();
</span><span class="cx">     for (unsigned i = butterfly->vectorLength(); i--;)
</span><del>-        butterfly->contiguousInt32()[i].setWithoutWriteBarrier(JSValue());
</del><ins>+        butterfly->contiguous().at(this, i).setWithoutWriteBarrier(JSValue());
</ins><span class="cx"> 
</span><span class="cx">     setStructure(vm, Structure::nonPropertyTransition(vm, structure(vm), NonPropertyTransition::AllocateInt32));
</span><span class="cx">     return m_butterfly->contiguousInt32();
</span><span class="lines">@@ -1146,7 +1149,7 @@
</span><span class="cx"> 
</span><span class="cx">     Butterfly* butterfly = m_butterfly.get();
</span><span class="cx">     for (unsigned i = butterfly->vectorLength(); i--;)
</span><del>-        butterfly->contiguousDouble()[i] = PNaN;
</del><ins>+        butterfly->contiguousDouble().at(this, i) = PNaN;
</ins><span class="cx">     
</span><span class="cx">     setStructure(vm, Structure::nonPropertyTransition(vm, structure(vm), NonPropertyTransition::AllocateDouble));
</span><span class="cx">     return m_butterfly->contiguousDouble();
</span><span class="lines">@@ -1158,7 +1161,7 @@
</span><span class="cx"> 
</span><span class="cx">     Butterfly* butterfly = m_butterfly.get();
</span><span class="cx">     for (unsigned i = butterfly->vectorLength(); i--;)
</span><del>-        butterfly->contiguous()[i].setWithoutWriteBarrier(JSValue());
</del><ins>+        butterfly->contiguous().at(this, i).setWithoutWriteBarrier(JSValue());
</ins><span class="cx"> 
</span><span class="cx">     WTF::storeStoreFence();
</span><span class="cx">     setStructure(vm, Structure::nonPropertyTransition(vm, structure(vm), NonPropertyTransition::AllocateContiguous));
</span><span class="lines">@@ -1220,7 +1223,7 @@
</span><span class="cx"> 
</span><span class="cx">     Butterfly* butterfly = m_butterfly.get();
</span><span class="cx">     for (unsigned i = butterfly->vectorLength(); i--;) {
</span><del>-        WriteBarrier<Unknown>* current = &butterfly->contiguousInt32()[i];
</del><ins>+        WriteBarrier<Unknown>* current = &butterfly->contiguous().at(this, i);
</ins><span class="cx">         double* currentAsDouble = bitwise_cast<double*>(current);
</span><span class="cx">         JSValue v = current->get();
</span><span class="cx">         // NOTE: Since this may be used during initialization, v could be garbage. If it's garbage,
</span><span class="lines">@@ -1253,7 +1256,7 @@
</span><span class="cx">     ArrayStorage* newStorage = constructConvertedArrayStorageWithoutCopyingElements(vm, vectorLength);
</span><span class="cx">     Butterfly* butterfly = m_butterfly.get();
</span><span class="cx">     for (unsigned i = 0; i < vectorLength; i++) {
</span><del>-        JSValue v = butterfly->contiguous()[i].get();
</del><ins>+        JSValue v = butterfly->contiguous().at(this, i).get();
</ins><span class="cx">         newStorage->m_vector[i].setWithoutWriteBarrier(v);
</span><span class="cx">         if (v)
</span><span class="cx">             newStorage->m_numValuesInVector++;
</span><span class="lines">@@ -1278,7 +1281,7 @@
</span><span class="cx"> 
</span><span class="cx">     Butterfly* butterfly = m_butterfly.get();
</span><span class="cx">     for (unsigned i = butterfly->vectorLength(); i--;) {
</span><del>-        double* current = &butterfly->contiguousDouble()[i];
</del><ins>+        double* current = &butterfly->contiguousDouble().at(this, i);
</ins><span class="cx">         WriteBarrier<Unknown>* currentAsValue = bitwise_cast<WriteBarrier<Unknown>*>(current);
</span><span class="cx">         double value = *current;
</span><span class="cx">         if (value != value) {
</span><span class="lines">@@ -1303,7 +1306,7 @@
</span><span class="cx">     ArrayStorage* newStorage = constructConvertedArrayStorageWithoutCopyingElements(vm, vectorLength);
</span><span class="cx">     Butterfly* butterfly = m_butterfly.get();
</span><span class="cx">     for (unsigned i = 0; i < vectorLength; i++) {
</span><del>-        double value = butterfly->contiguousDouble()[i];
</del><ins>+        double value = butterfly->contiguousDouble().at(this, i);
</ins><span class="cx">         if (value != value) {
</span><span class="cx">             newStorage->m_vector[i].clear();
</span><span class="cx">             continue;
</span><span class="lines">@@ -1334,7 +1337,7 @@
</span><span class="cx">     ArrayStorage* newStorage = constructConvertedArrayStorageWithoutCopyingElements(vm, vectorLength);
</span><span class="cx">     Butterfly* butterfly = m_butterfly.get();
</span><span class="cx">     for (unsigned i = 0; i < vectorLength; i++) {
</span><del>-        JSValue v = butterfly->contiguous()[i].get();
</del><ins>+        JSValue v = butterfly->contiguous().at(this, i).get();
</ins><span class="cx">         newStorage->m_vector[i].setWithoutWriteBarrier(v);
</span><span class="cx">         if (v)
</span><span class="cx">             newStorage->m_numValuesInVector++;
</span><span class="lines">@@ -1356,6 +1359,7 @@
</span><span class="cx">     
</span><span class="cx">     if (vm.heap.mutatorShouldBeFenced()) {
</span><span class="cx">         auto locker = holdLock(*this);
</span><ins>+        m_butterflyIndexingMask = newStorage->butterfly()->computeIndexingMask();
</ins><span class="cx">         setStructureIDDirectly(nuke(structureID()));
</span><span class="cx">         WTF::storeStoreFence();
</span><span class="cx">         m_butterfly.set(vm, this, newStorage->butterfly());
</span><span class="lines">@@ -1362,6 +1366,7 @@
</span><span class="cx">         WTF::storeStoreFence();
</span><span class="cx">         setStructure(vm, newStructure);
</span><span class="cx">     } else {
</span><ins>+        m_butterflyIndexingMask = newStorage->butterfly()->computeIndexingMask();
</ins><span class="cx">         m_butterfly.set(vm, this, newStorage->butterfly());
</span><span class="cx">         setStructure(vm, newStructure);
</span><span class="cx">     }
</span><span class="lines">@@ -1394,7 +1399,7 @@
</span><span class="cx"> void JSObject::createInitialForValueAndSet(VM& vm, unsigned index, JSValue value)
</span><span class="cx"> {
</span><span class="cx">     if (value.isInt32()) {
</span><del>-        createInitialInt32(vm, index + 1)[index].set(vm, this, value);
</del><ins>+        createInitialInt32(vm, index + 1).at(this, index).set(vm, this, value);
</ins><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx">     
</span><span class="lines">@@ -1401,12 +1406,12 @@
</span><span class="cx">     if (value.isDouble()) {
</span><span class="cx">         double doubleValue = value.asNumber();
</span><span class="cx">         if (doubleValue == doubleValue) {
</span><del>-            createInitialDouble(vm, index + 1)[index] = doubleValue;
</del><ins>+            createInitialDouble(vm, index + 1).at(this, index) = doubleValue;
</ins><span class="cx">             return;
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    createInitialContiguous(vm, index + 1)[index].set(vm, this, value);
</del><ins>+    createInitialContiguous(vm, index + 1).at(this, index).set(vm, this, value);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void JSObject::convertInt32ForValue(VM& vm, JSValue value)
</span><span class="lines">@@ -1876,7 +1881,7 @@
</span><span class="cx">         Butterfly* butterfly = thisObject->butterfly();
</span><span class="cx">         if (i >= butterfly->vectorLength())
</span><span class="cx">             return true;
</span><del>-        butterfly->contiguous()[i].clear();
</del><ins>+        butterfly->contiguous().at(thisObject, i).clear();
</ins><span class="cx">         return true;
</span><span class="cx">     }
</span><span class="cx">         
</span><span class="lines">@@ -1884,7 +1889,7 @@
</span><span class="cx">         Butterfly* butterfly = thisObject->butterfly();
</span><span class="cx">         if (i >= butterfly->vectorLength())
</span><span class="cx">             return true;
</span><del>-        butterfly->contiguousDouble()[i] = PNaN;
</del><ins>+        butterfly->contiguousDouble().at(thisObject, i) = PNaN;
</ins><span class="cx">         return true;
</span><span class="cx">     }
</span><span class="cx">         
</span><span class="lines">@@ -2185,7 +2190,7 @@
</span><span class="cx">             Butterfly* butterfly = object->butterfly();
</span><span class="cx">             unsigned usedLength = butterfly->publicLength();
</span><span class="cx">             for (unsigned i = 0; i < usedLength; ++i) {
</span><del>-                if (!butterfly->contiguous()[i])
</del><ins>+                if (!butterfly->contiguous().at(object, i))
</ins><span class="cx">                     continue;
</span><span class="cx">                 propertyNames.add(i);
</span><span class="cx">             }
</span><span class="lines">@@ -2196,7 +2201,7 @@
</span><span class="cx">             Butterfly* butterfly = object->butterfly();
</span><span class="cx">             unsigned usedLength = butterfly->publicLength();
</span><span class="cx">             for (unsigned i = 0; i < usedLength; ++i) {
</span><del>-                double value = butterfly->contiguousDouble()[i];
</del><ins>+                double value = butterfly->contiguousDouble().at(object, i);
</ins><span class="cx">                 if (value != value)
</span><span class="cx">                     continue;
</span><span class="cx">                 propertyNames.add(i);
</span><span class="lines">@@ -2630,7 +2635,7 @@
</span><span class="cx">     switch (indexingShape) {
</span><span class="cx">     case Int32Shape:
</span><span class="cx">         ASSERT(value.isInt32());
</span><del>-        butterfly->contiguousInt32()[i].setWithoutWriteBarrier(value);
</del><ins>+        butterfly->contiguous().at(this, i).setWithoutWriteBarrier(value);
</ins><span class="cx">         return true;
</span><span class="cx">         
</span><span class="cx">     case DoubleShape: {
</span><span class="lines">@@ -2637,12 +2642,12 @@
</span><span class="cx">         ASSERT(value.isNumber());
</span><span class="cx">         double valueAsDouble = value.asNumber();
</span><span class="cx">         ASSERT(valueAsDouble == valueAsDouble);
</span><del>-        butterfly->contiguousDouble()[i] = valueAsDouble;
</del><ins>+        butterfly->contiguousDouble().at(this, i) = valueAsDouble;
</ins><span class="cx">         return true;
</span><span class="cx">     }
</span><span class="cx">         
</span><span class="cx">     case ContiguousShape:
</span><del>-        butterfly->contiguous()[i].set(vm, this, value);
</del><ins>+        butterfly->contiguous().at(this, i).set(vm, this, value);
</ins><span class="cx">         return true;
</span><span class="cx">         
</span><span class="cx">     default:
</span><span class="lines">@@ -3079,12 +3084,12 @@
</span><span class="cx">         switch (indexingShape) {
</span><span class="cx">         case Int32Shape:
</span><span class="cx">         case ContiguousShape:
</span><del>-            if (butterfly->contiguous()[i])
</del><ins>+            if (butterfly->contiguous().at(this, i))
</ins><span class="cx">                 numValues++;
</span><span class="cx">             break;
</span><span class="cx">             
</span><span class="cx">         case DoubleShape: {
</span><del>-            double value = butterfly->contiguousDouble()[i];
</del><ins>+            double value = butterfly->contiguousDouble().at(this, i);
</ins><span class="cx">             if (value == value)
</span><span class="cx">                 numValues++;
</span><span class="cx">             break;
</span><span class="lines">@@ -3223,11 +3228,13 @@
</span><span class="cx"> 
</span><span class="cx">     if (newButterfly) {
</span><span class="cx">         butterfly->setVectorLength(newVectorLength);
</span><ins>+        m_butterflyIndexingMask = newButterfly->computeIndexingMask();
</ins><span class="cx">         WTF::storeStoreFence();
</span><span class="cx">         m_butterfly.set(vm, this, newButterfly);
</span><span class="cx">     } else {
</span><span class="cx">         WTF::storeStoreFence();
</span><span class="cx">         butterfly->setVectorLength(newVectorLength);
</span><ins>+        m_butterflyIndexingMask = m_butterfly->computeIndexingMask();
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     return true;
</span><span class="lines">@@ -3242,10 +3249,12 @@
</span><span class="cx"> 
</span><span class="cx">     DeferGC deferGC(vm.heap);
</span><span class="cx">     Butterfly* newButterfly = butterfly()->resizeArray(vm, this, structure(), 0, ArrayStorage::sizeFor(length));
</span><ins>+    m_butterflyIndexingMask = newButterfly->computeIndexingMask();
</ins><span class="cx">     newButterfly->setVectorLength(length);
</span><span class="cx">     newButterfly->setPublicLength(length);
</span><span class="cx">     WTF::storeStoreFence();
</span><span class="cx">     m_butterfly.set(vm, this, newButterfly);
</span><ins>+
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> Butterfly* JSObject::allocateMoreOutOfLineStorage(VM& vm, size_t oldSize, size_t newSize)
</span><span class="lines">@@ -3591,7 +3600,7 @@
</span><span class="cx">         Butterfly* butterfly = object->butterfly();
</span><span class="cx">         unsigned usedLength = butterfly->publicLength();
</span><span class="cx">         for (unsigned i = 0; i < usedLength; ++i) {
</span><del>-            if (!butterfly->contiguous()[i])
</del><ins>+            if (!butterfly->contiguous().at(object, i))
</ins><span class="cx">                 return 0;
</span><span class="cx">         }
</span><span class="cx">         return usedLength;
</span><span class="lines">@@ -3601,7 +3610,7 @@
</span><span class="cx">         Butterfly* butterfly = object->butterfly();
</span><span class="cx">         unsigned usedLength = butterfly->publicLength();
</span><span class="cx">         for (unsigned i = 0; i < usedLength; ++i) {
</span><del>-            double value = butterfly->contiguousDouble()[i];
</del><ins>+            double value = butterfly->contiguousDouble().at(object, i);
</ins><span class="cx">             if (value != value)
</span><span class="cx">                 return 0;
</span><span class="cx">         }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSObjecth"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSObject.h (225912 => 225913)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSObject.h   2017-12-14 19:10:54 UTC (rev 225912)
+++ trunk/Source/JavaScriptCore/runtime/JSObject.h      2017-12-14 19:11:49 UTC (rev 225913)
</span><span class="lines">@@ -262,11 +262,11 @@
</span><span class="cx">             return false;
</span><span class="cx">         case ALL_INT32_INDEXING_TYPES:
</span><span class="cx">         case ALL_CONTIGUOUS_INDEXING_TYPES:
</span><del>-            return i < butterfly->vectorLength() && butterfly->contiguous()[i];
</del><ins>+            return i < butterfly->vectorLength() && butterfly->contiguous().at(this, i);
</ins><span class="cx">         case ALL_DOUBLE_INDEXING_TYPES: {
</span><span class="cx">             if (i >= butterfly->vectorLength())
</span><span class="cx">                 return false;
</span><del>-            double value = butterfly->contiguousDouble()[i];
</del><ins>+            double value = butterfly->contiguousDouble().at(this, i);
</ins><span class="cx">             if (value != value)
</span><span class="cx">                 return false;
</span><span class="cx">             return true;
</span><span class="lines">@@ -284,11 +284,11 @@
</span><span class="cx">         Butterfly* butterfly = this->butterfly();
</span><span class="cx">         switch (indexingType()) {
</span><span class="cx">         case ALL_INT32_INDEXING_TYPES:
</span><del>-            return jsNumber(butterfly->contiguous()[i].get().asInt32());
</del><ins>+            return jsNumber(butterfly->contiguous().at(this, i).get().asInt32());
</ins><span class="cx">         case ALL_CONTIGUOUS_INDEXING_TYPES:
</span><del>-            return butterfly->contiguous()[i].get();
</del><ins>+            return butterfly->contiguous().at(this, i).get();
</ins><span class="cx">         case ALL_DOUBLE_INDEXING_TYPES:
</span><del>-            return JSValue(JSValue::EncodeAsDouble, butterfly->contiguousDouble()[i]);
</del><ins>+            return JSValue(JSValue::EncodeAsDouble, butterfly->contiguousDouble().at(this, i));
</ins><span class="cx">         case ALL_ARRAY_STORAGE_INDEXING_TYPES:
</span><span class="cx">             return butterfly->arrayStorage()->m_vector[i].get();
</span><span class="cx">         default:
</span><span class="lines">@@ -306,7 +306,7 @@
</span><span class="cx">             break;
</span><span class="cx">         case ALL_INT32_INDEXING_TYPES:
</span><span class="cx">             if (i < butterfly->publicLength()) {
</span><del>-                JSValue result = butterfly->contiguous()[i].get();
</del><ins>+                JSValue result = butterfly->contiguous().at(this, i).get();
</ins><span class="cx">                 ASSERT(result.isInt32() || !result);
</span><span class="cx">                 return result;
</span><span class="cx">             }
</span><span class="lines">@@ -313,12 +313,12 @@
</span><span class="cx">             break;
</span><span class="cx">         case ALL_CONTIGUOUS_INDEXING_TYPES:
</span><span class="cx">             if (i < butterfly->publicLength())
</span><del>-                return butterfly->contiguous()[i].get();
</del><ins>+                return butterfly->contiguous().at(this, i).get();
</ins><span class="cx">             break;
</span><span class="cx">         case ALL_DOUBLE_INDEXING_TYPES: {
</span><span class="cx">             if (i >= butterfly->publicLength())
</span><span class="cx">                 break;
</span><del>-            double result = butterfly->contiguousDouble()[i];
</del><ins>+            double result = butterfly->contiguousDouble().at(this, i);
</ins><span class="cx">             if (result != result)
</span><span class="cx">                 break;
</span><span class="cx">             return JSValue(JSValue::EncodeAsDouble, result);
</span><span class="lines">@@ -388,7 +388,7 @@
</span><span class="cx">         }
</span><span class="cx">         case ALL_CONTIGUOUS_INDEXING_TYPES: {
</span><span class="cx">             ASSERT(i < butterfly->vectorLength());
</span><del>-            butterfly->contiguous()[i].set(vm, this, v);
</del><ins>+            butterfly->contiguous().at(this, i).set(vm, this, v);
</ins><span class="cx">             if (i >= butterfly->publicLength())
</span><span class="cx">                 butterfly->setPublicLength(i + 1);
</span><span class="cx">             break;
</span><span class="lines">@@ -404,7 +404,7 @@
</span><span class="cx">                 convertDoubleToContiguousWhilePerformingSetIndex(vm, i, v);
</span><span class="cx">                 return;
</span><span class="cx">             }
</span><del>-            butterfly->contiguousDouble()[i] = value;
</del><ins>+            butterfly->contiguousDouble().at(this, i) = value;
</ins><span class="cx">             if (i >= butterfly->publicLength())
</span><span class="cx">                 butterfly->setPublicLength(i + 1);
</span><span class="cx">             break;
</span><span class="lines">@@ -454,7 +454,7 @@
</span><span class="cx">         case ALL_CONTIGUOUS_INDEXING_TYPES: {
</span><span class="cx">             ASSERT(i < butterfly->publicLength());
</span><span class="cx">             ASSERT(i < butterfly->vectorLength());
</span><del>-            butterfly->contiguous()[i].set(vm, this, v);
</del><ins>+            butterfly->contiguous().at(this, i).set(vm, this, v);
</ins><span class="cx">             break;
</span><span class="cx">         }
</span><span class="cx">         case ALL_DOUBLE_INDEXING_TYPES: {
</span><span class="lines">@@ -469,7 +469,7 @@
</span><span class="cx">                 convertDoubleToContiguousWhilePerformingSetIndex(vm, i, v);
</span><span class="cx">                 return;
</span><span class="cx">             }
</span><del>-            butterfly->contiguousDouble()[i] = value;
</del><ins>+            butterfly->contiguousDouble().at(this, i) = value;
</ins><span class="cx">             break;
</span><span class="cx">         }
</span><span class="cx">         case ALL_ARRAY_STORAGE_INDEXING_TYPES: {
</span><span class="lines">@@ -508,7 +508,7 @@
</span><span class="cx">         case ALL_CONTIGUOUS_INDEXING_TYPES: {
</span><span class="cx">             ASSERT(i < butterfly->publicLength());
</span><span class="cx">             ASSERT(i < butterfly->vectorLength());
</span><del>-            butterfly->contiguous()[i].setWithoutWriteBarrier(v);
</del><ins>+            butterfly->contiguous().at(this, i).setWithoutWriteBarrier(v);
</ins><span class="cx">             break;
</span><span class="cx">         }
</span><span class="cx">         case ALL_DOUBLE_INDEXING_TYPES: {
</span><span class="lines">@@ -517,7 +517,7 @@
</span><span class="cx">             RELEASE_ASSERT(v.isNumber());
</span><span class="cx">             double value = v.asNumber();
</span><span class="cx">             RELEASE_ASSERT(value == value);
</span><del>-            butterfly->contiguousDouble()[i] = value;
</del><ins>+            butterfly->contiguousDouble().at(this, i) = value;
</ins><span class="cx">             break;
</span><span class="cx">         }
</span><span class="cx">         case ALL_ARRAY_STORAGE_INDEXING_TYPES: {
</span><span class="lines">@@ -770,6 +770,9 @@
</span><span class="cx">     // Call this if you do need to change the structure, or if you changed something about a structure
</span><span class="cx">     // in-place.
</span><span class="cx">     void nukeStructureAndSetButterfly(VM&, StructureID, Butterfly*);
</span><ins>+
+    // Call this only if you are a JSGenericTypedArrayView or are clearing the butterfly.
+    void setButterflyWithIndexingMask(VM&, Butterfly*, uint32_t indexingMask);
</ins><span class="cx">     
</span><span class="cx">     void setStructure(VM&, Structure*);
</span><span class="cx"> 
</span><span class="lines">@@ -858,6 +861,8 @@
</span><span class="cx">     {
</span><span class="cx">         return OBJECT_OFFSETOF(JSObject, m_butterfly);
</span><span class="cx">     }
</span><ins>+    static ptrdiff_t butterflyIndexingMaskOffset() { return OBJECT_OFFSETOF(JSObject, m_butterflyIndexingMask); }
+    uintptr_t butterflyIndexingMask() const { return m_butterflyIndexingMask; }
</ins><span class="cx">         
</span><span class="cx">     void* butterflyAddress()
</span><span class="cx">     {
</span><span class="lines">@@ -885,7 +890,7 @@
</span><span class="cx"> 
</span><span class="cx">     // To instantiate objects you likely want JSFinalObject, below.
</span><span class="cx">     // To create derived types you likely want JSNonFinalObject, below.
</span><del>-    JSObject(VM&, Structure*, Butterfly* = 0);
</del><ins>+    JSObject(VM&, Structure*, Butterfly* = nullptr);
</ins><span class="cx">     
</span><span class="cx">     // Visits the butterfly unless there is a race. Returns the structure if there was no race.
</span><span class="cx">     Structure* visitButterfly(SlotVisitor&);
</span><span class="lines">@@ -1051,12 +1056,8 @@
</span><span class="cx"> 
</span><span class="cx">     PropertyOffset prepareToPutDirectWithoutTransition(VM&, PropertyName, unsigned attributes, StructureID, Structure*);
</span><span class="cx"> 
</span><del>-protected:
</del><span class="cx">     AuxiliaryBarrier<Butterfly*> m_butterfly;
</span><del>-#if USE(JSVALUE32_64)
-private:
-    uint32_t m_padding;
-#endif
</del><ins>+    uint32_t m_butterflyIndexingMask { 0 };
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> // JSNonFinalObject is a type of JSObject that has some internal storage,
</span><span class="lines">@@ -1247,8 +1248,26 @@
</span><span class="cx">     JSCell::setStructure(vm, structure);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+inline void JSObject::setButterflyWithIndexingMask(VM& vm, Butterfly* butterfly, uint32_t indexingMask)
+{
+    // These are the only two current use cases for this.
+    ASSERT(structure()->hijacksIndexingHeader() || !butterfly);
+    m_butterflyIndexingMask = indexingMask;
+    if (isX86() || vm.heap.mutatorShouldBeFenced()) {
+        WTF::storeStoreFence();
+        m_butterfly.set(vm, this, butterfly);
+        WTF::storeStoreFence();
+        return;
+    }
+
+    m_butterfly.set(vm, this, butterfly);
+}
+
</ins><span class="cx"> inline void JSObject::setButterfly(VM& vm, Butterfly* butterfly)
</span><span class="cx"> {
</span><ins>+    ASSERT(!structure()->hijacksIndexingHeader());
+    m_butterflyIndexingMask = butterfly->computeIndexingMask();
+    ASSERT(m_butterflyIndexingMask >= butterfly->vectorLength());
</ins><span class="cx">     if (isX86() || vm.heap.mutatorShouldBeFenced()) {
</span><span class="cx">         WTF::storeStoreFence();
</span><span class="cx">         m_butterfly.set(vm, this, butterfly);
</span><span class="lines">@@ -1255,12 +1274,15 @@
</span><span class="cx">         WTF::storeStoreFence();
</span><span class="cx">         return;
</span><span class="cx">     }
</span><del>-    
</del><ins>+
</ins><span class="cx">     m_butterfly.set(vm, this, butterfly);
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> inline void JSObject::nukeStructureAndSetButterfly(VM& vm, StructureID oldStructureID, Butterfly* butterfly)
</span><span class="cx"> {
</span><ins>+    ASSERT(!vm.getStructure(oldStructureID)->hijacksIndexingHeader());
+    m_butterflyIndexingMask = butterfly->computeIndexingMask();
+    ASSERT(m_butterflyIndexingMask >= butterfly->vectorLength());
</ins><span class="cx">     if (isX86() || vm.heap.mutatorShouldBeFenced()) {
</span><span class="cx">         setStructureIDDirectly(nuke(oldStructureID));
</span><span class="cx">         WTF::storeStoreFence();
</span><span class="lines">@@ -1268,7 +1290,7 @@
</span><span class="cx">         WTF::storeStoreFence();
</span><span class="cx">         return;
</span><span class="cx">     }
</span><del>-    
</del><ins>+
</ins><span class="cx">     m_butterfly.set(vm, this, butterfly);
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -1301,6 +1323,8 @@
</span><span class="cx">     : JSCell(vm, structure)
</span><span class="cx">     , m_butterfly(vm, this, butterfly)
</span><span class="cx"> {
</span><ins>+    if (butterfly)
+        m_butterflyIndexingMask = butterfly->computeIndexingMask();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> inline JSValue JSObject::getPrototypeDirect(VM& vm) const
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeRegExpMatchesArrayh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/RegExpMatchesArray.h (225912 => 225913)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/RegExpMatchesArray.h 2017-12-14 19:10:54 UTC (rev 225912)
+++ trunk/Source/JavaScriptCore/runtime/RegExpMatchesArray.h    2017-12-14 19:11:49 UTC (rev 225913)
</span><span class="lines">@@ -51,7 +51,7 @@
</span><span class="cx"> 
</span><span class="cx">     unsigned i = (createUninitialized ? initialLength : 0);
</span><span class="cx">     for (; i < vectorLength; ++i)
</span><del>-        butterfly->contiguous()[i].clear();
</del><ins>+        butterfly->contiguous().at(std::numeric_limits<uint32_t>::max(), i).clear();
</ins><span class="cx"> 
</span><span class="cx">     JSArray* result = JSArray::createWithButterfly(vm, deferralContext, structure, butterfly);
</span><span class="cx">     scope.notifyAllocated(result, createUninitialized);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeStructurecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/Structure.cpp (225912 => 225913)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/Structure.cpp        2017-12-14 19:10:54 UTC (rev 225912)
+++ trunk/Source/JavaScriptCore/runtime/Structure.cpp   2017-12-14 19:11:49 UTC (rev 225913)
</span><span class="lines">@@ -799,7 +799,7 @@
</span><span class="cx">         // If the object had a Butterfly but after flattening/compacting we no longer have need of it,
</span><span class="cx">         // we need to zero it out because the collector depends on the Structure to know the size for copying.
</span><span class="cx">         if (!afterOutOfLineCapacity && !this->hasIndexingHeader(object))
</span><del>-            object->setButterfly(vm, nullptr);
</del><ins>+            object->setButterflyWithIndexingMask(vm, nullptr, 0);
</ins><span class="cx">         // If the object was down-sized to the point where the base of the Butterfly is no longer within the 
</span><span class="cx">         // first CopiedBlock::blockSize bytes, we'll get the wrong answer if we try to mask the base back to 
</span><span class="cx">         // the CopiedBlock header. To prevent this case we need to memmove the Butterfly down.
</span></span></pre></div>
<a id="trunkSourceWTFChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/ChangeLog (225912 => 225913)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/ChangeLog       2017-12-14 19:10:54 UTC (rev 225912)
+++ trunk/Source/WTF/ChangeLog  2017-12-14 19:11:49 UTC (rev 225913)
</span><span class="lines">@@ -1,3 +1,19 @@
</span><ins>+2017-12-13  Keith Miller  <keith_miller@apple.com>
+
+        JSObjects should have a mask for loading indexed properties
+        https://bugs.webkit.org/show_bug.cgi?id=180768
+
+        Reviewed by Mark Lam.
+
+        Add a clz that wraps the builtin clz intrinisics provided by
+        various compilers. The clz function by default assumes that
+        the input may be zero. On X86 this makes a difference because not
+        all CPUs have LZCNT and BSR has undefined behavior on zero. On ARM,
+        the zero check gets optimized away, regardless.
+
+        * wtf/StdLibExtras.h:
+        (std::clz):
+
</ins><span class="cx"> 2017-12-12  Yusuke Suzuki  <utatane.tea@gmail.com>
</span><span class="cx"> 
</span><span class="cx">         REGRESSION(r225769): Build errors with constexpr std::tie on older gcc
</span></span></pre></div>
<a id="trunkSourceWTFwtfStdLibExtrash"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/wtf/StdLibExtras.h (225912 => 225913)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/wtf/StdLibExtras.h      2017-12-14 19:10:54 UTC (rev 225912)
+++ trunk/Source/WTF/wtf/StdLibExtras.h 2017-12-14 19:11:49 UTC (rev 225913)
</span><span class="lines">@@ -548,6 +548,23 @@
</span><span class="cx"> __IN_PLACE_INLINE_VARIABLE constexpr in_place_index_t<I> in_place_index { };
</span><span class="cx"> #endif // __cplusplus < 201703L
</span><span class="cx"> 
</span><ins>+enum class ZeroStatus {
+    MayBeZero,
+    NonZero
+};
+
+constexpr size_t clz(uint32_t value, ZeroStatus mightBeZero = ZeroStatus::MayBeZero)
+{
+    if (mightBeZero == ZeroStatus::MayBeZero && value) {
+#if COMPILER(MSVC)
+        return __lzcnt(value);
+#else
+        return __builtin_clz(value);
+#endif
+    }
+    return 32;
+}
+
</ins><span class="cx"> } // namespace std
</span><span class="cx"> 
</span><span class="cx"> #define WTFMove(value) std::move<WTF::CheckMoveParameter>(value)
</span></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (225912 => 225913)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog   2017-12-14 19:10:54 UTC (rev 225912)
+++ trunk/Source/WebCore/ChangeLog      2017-12-14 19:11:49 UTC (rev 225913)
</span><span class="lines">@@ -1,3 +1,14 @@
</span><ins>+2017-12-13  Keith Miller  <keith_miller@apple.com>
+
+        JSObjects should have a mask for loading indexed properties
+        https://bugs.webkit.org/show_bug.cgi?id=180768
+
+        Reviewed by Mark Lam.
+
+        * bindings/js/JSDOMConvertSequences.h:
+        (WebCore::Detail::NumericSequenceConverter::convertArray):
+        (WebCore::Detail::SequenceConverter::convertArray):
+
</ins><span class="cx"> 2017-12-13  Antoine Quint  <graouts@apple.com>
</span><span class="cx"> 
</span><span class="cx">         [Web Animations] Implement the play() and pause() methods on Animation
</span></span></pre></div>
<a id="trunkSourceWebCorebindingsjsJSDOMConvertSequencesh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/bindings/js/JSDOMConvertSequences.h (225912 => 225913)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/bindings/js/JSDOMConvertSequences.h 2017-12-14 19:10:54 UTC (rev 225912)
+++ trunk/Source/WebCore/bindings/js/JSDOMConvertSequences.h    2017-12-14 19:11:49 UTC (rev 225913)
</span><span class="lines">@@ -92,7 +92,7 @@
</span><span class="cx">     {
</span><span class="cx">         if (indexingType == JSC::Int32Shape) {
</span><span class="cx">             for (unsigned i = 0; i < length; i++) {
</span><del>-                auto indexValue = array->butterfly()->contiguousInt32()[i].get();
</del><ins>+                auto indexValue = array->butterfly()->contiguousInt32().at(array, i).get();
</ins><span class="cx">                 ASSERT(!indexValue || indexValue.isInt32());
</span><span class="cx">                 if (!indexValue)
</span><span class="cx">                     result.uncheckedAppend(0);
</span><span class="lines">@@ -104,7 +104,7 @@
</span><span class="cx"> 
</span><span class="cx">         ASSERT(indexingType == JSC::DoubleShape);
</span><span class="cx">         for (unsigned i = 0; i < length; i++) {
</span><del>-            auto doubleValue = array->butterfly()->contiguousDouble()[i];
</del><ins>+            auto doubleValue = array->butterfly()->contiguousDouble().at(array, i);
</ins><span class="cx">             if (std::isnan(doubleValue))
</span><span class="cx">                 result.uncheckedAppend(0);
</span><span class="cx">             else {
</span><span class="lines">@@ -210,7 +210,7 @@
</span><span class="cx"> 
</span><span class="cx">         if (indexingType == JSC::ContiguousShape) {
</span><span class="cx">             for (unsigned i = 0; i < length; i++) {
</span><del>-                auto indexValue = array->butterfly()->contiguous()[i].get();
</del><ins>+                auto indexValue = array->butterfly()->contiguous().at(array, i).get();
</ins><span class="cx">                 if (!indexValue)
</span><span class="cx">                     indexValue = JSC::jsUndefined();
</span><span class="cx"> 
</span></span></pre>
</div>
</div>

</body>
</html>