Modified: trunk/Source/_javascript_Core/ChangeLog (129675 => 129676)
--- trunk/Source/_javascript_Core/ChangeLog 2012-09-26 18:16:45 UTC (rev 129675)
+++ trunk/Source/_javascript_Core/ChangeLog 2012-09-26 18:36:53 UTC (rev 129676)
@@ -1,3 +1,26 @@
+2012-09-26 Michael Saboff <msab...@apple.com>
+
+ Add ability for JSArray::unshiftCount to unshift in middle of an array
+ https://bugs.webkit.org/show_bug.cgi?id=97691
+
+ Reviewed by Filip Pizlo.
+
+ Changed JSArray::unshiftCount and unshiftCountSlowCase to handle unshifting from the middle of an
+ array. Depending on where the unshift point is, either the front part of the array will be moved
+ "left" or the back part will be moved right. Given that unshiftCount only works on contiguous
+ arrays it is safe to use memmove for the moves.
+
+ This change is worth 25% performance improvement on pdfjs. It doesn't seem to have any impact on
+ any other benchmarks.
+
+ * runtime/ArrayPrototype.cpp:
+ (JSC::unshift):
+ * runtime/JSArray.cpp:
+ (JSC::JSArray::unshiftCountSlowCase):
+ (JSC::JSArray::unshiftCount):
+ * runtime/JSArray.h:
+ (JSArray):
+
2012-09-26 Sheriff Bot <webkit.review....@gmail.com>
Unreviewed, rolling out r129592.
Modified: trunk/Source/_javascript_Core/runtime/ArrayPrototype.cpp (129675 => 129676)
--- trunk/Source/_javascript_Core/runtime/ArrayPrototype.cpp 2012-09-26 18:16:45 UTC (rev 129675)
+++ trunk/Source/_javascript_Core/runtime/ArrayPrototype.cpp 2012-09-26 18:36:53 UTC (rev 129676)
@@ -245,9 +245,9 @@
return;
}
- if (!header && isJSArray(thisObj)) {
+ if (isJSArray(thisObj)) {
JSArray* array = asArray(thisObj);
- if (array->length() == length && asArray(thisObj)->unshiftCount(exec, count))
+ if (array->length() == length && array->unshiftCount(exec, header, count))
return;
}
Modified: trunk/Source/_javascript_Core/runtime/JSArray.cpp (129675 => 129676)
--- trunk/Source/_javascript_Core/runtime/JSArray.cpp 2012-09-26 18:16:45 UTC (rev 129675)
+++ trunk/Source/_javascript_Core/runtime/JSArray.cpp 2012-09-26 18:36:53 UTC (rev 129676)
@@ -246,7 +246,7 @@
}
// This method makes room in the vector, but leaves the new space uncleared.
-bool JSArray::unshiftCountSlowCase(JSGlobalData& globalData, unsigned count)
+bool JSArray::unshiftCountSlowCase(JSGlobalData& globalData, bool addToFront, unsigned count)
{
ArrayStorage* storage = ensureArrayStorage(globalData);
Butterfly* butterfly = storage->butterfly();
@@ -254,7 +254,7 @@
unsigned propertySize = structure()->outOfLineSize();
// If not, we should have handled this on the fast path.
- ASSERT(count > storage->m_indexBias);
+ ASSERT(!addToFront || count > storage->m_indexBias);
// Step 1:
// Gather 4 key metrics:
@@ -278,7 +278,7 @@
unsigned desiredCapacity = min(MAX_STORAGE_VECTOR_LENGTH, max(BASE_VECTOR_LEN, requiredVectorLength) << 1);
// Step 2:
- // We're either going to choose to allocate a new ArrayStorage, or we're going to reuse the existing on.
+ // We're either going to choose to allocate a new ArrayStorage, or we're going to reuse the existing one.
void* newAllocBase = 0;
unsigned newStorageCapacity;
@@ -297,11 +297,14 @@
// Work out where we're going to move things to.
// Determine how much of the vector to use as pre-capacity, and how much as post-capacity.
+ // If we're adding to the end, we'll add all the new space to the end.
// If the vector had no free post-capacity (length >= m_vectorLength), don't give it any.
// If it did, we calculate the amount that will remain based on an atomic decay - leave the
// vector with half the post-capacity it had previously.
unsigned postCapacity = 0;
- if (length < storage->vectorLength()) {
+ if (!addToFront)
+ postCapacity = max(newStorageCapacity - requiredVectorLength, count);
+ else if (length < storage->vectorLength()) {
// Atomic decay, + the post-capacity cannot be greater than what is available.
postCapacity = min((storage->vectorLength() - length) >> 1, newStorageCapacity - requiredVectorLength);
// If we're moving contents within the same allocation, the post-capacity is being reduced.
@@ -312,8 +315,12 @@
unsigned newIndexBias = newStorageCapacity - newVectorLength;
Butterfly* newButterfly = Butterfly::fromBase(newAllocBase, newIndexBias, propertyCapacity);
-
- memmove(newButterfly->arrayStorage()->m_vector + count, storage->m_vector, sizeof(JSValue) * usedVectorLength);
+
+ if (addToFront)
+ memmove(newButterfly->arrayStorage()->m_vector + count, storage->m_vector, sizeof(JSValue) * usedVectorLength);
+ else if (newAllocBase != butterfly->base(structure()))
+ memmove(newButterfly->arrayStorage()->m_vector, storage->m_vector, sizeof(JSValue) * usedVectorLength);
+
memmove(newButterfly->propertyStorage() - propertySize, butterfly->propertyStorage() - propertySize, sizeof(JSValue) * propertySize + sizeof(IndexingHeader) + ArrayStorage::sizeFor(0));
newButterfly->arrayStorage()->setVectorLength(newVectorLength);
@@ -529,7 +536,7 @@
}
// Returns true if the unshift can be handled, false to fallback.
-bool JSArray::unshiftCount(ExecState* exec, unsigned count)
+bool JSArray::unshiftCount(ExecState* exec, unsigned startIndex, unsigned count)
{
ArrayStorage* storage = ensureArrayStorage(exec->globalData());
unsigned length = storage->length();
@@ -539,12 +546,18 @@
if (length != storage->m_numValuesInVector || storage->inSparseMode())
return false;
- if (storage->m_indexBias >= count) {
+ bool moveFront = !startIndex || startIndex < length / 2;
+
+ unsigned vectorLength = storage->vectorLength();
+
+ if (moveFront && storage->m_indexBias >= count) {
m_butterfly = storage->butterfly()->unshift(structure(), count);
storage = m_butterfly->arrayStorage();
storage->m_indexBias -= count;
- storage->setVectorLength(storage->vectorLength() + count);
- } else if (unshiftCountSlowCase(exec->globalData(), count))
+ storage->setVectorLength(vectorLength + count);
+ } else if (!moveFront && vectorLength - length >= count)
+ storage = storage->butterfly()->arrayStorage();
+ else if (unshiftCountSlowCase(exec->globalData(), moveFront, count))
storage = arrayStorage();
else {
throwOutOfMemoryError(exec);
@@ -552,8 +565,16 @@
}
WriteBarrier<Unknown>* vector = storage->m_vector;
+
+ if (startIndex) {
+ if (moveFront)
+ memmove(vector, vector + count, startIndex * sizeof(JSValue));
+ else
+ memmove(vector + startIndex + count, vector + startIndex, (length - startIndex) * sizeof(JSValue));
+ }
+
for (unsigned i = 0; i < count; i++)
- vector[i].clear();
+ vector[i + startIndex].clear();
return true;
}
Modified: trunk/Source/_javascript_Core/runtime/JSArray.h (129675 => 129676)
--- trunk/Source/_javascript_Core/runtime/JSArray.h 2012-09-26 18:16:45 UTC (rev 129675)
+++ trunk/Source/_javascript_Core/runtime/JSArray.h 2012-09-26 18:36:53 UTC (rev 129676)
@@ -72,7 +72,7 @@
JSValue pop(ExecState*);
bool shiftCount(ExecState*, unsigned count);
- bool unshiftCount(ExecState*, unsigned count);
+ bool unshiftCount(ExecState*, unsigned, unsigned);
void fillArgList(ExecState*, MarkedArgumentBuffer&);
void copyToArguments(ExecState*, CallFrame*, uint32_t length);
@@ -101,7 +101,7 @@
void setLengthWritable(ExecState*, bool writable);
- bool unshiftCountSlowCase(JSGlobalData&, unsigned count);
+ bool unshiftCountSlowCase(JSGlobalData&, bool, unsigned);
unsigned compactForSorting(JSGlobalData&);
};