Title: [228306] trunk/Source
Revision
228306
Author
[email protected]
Date
2018-02-08 18:13:01 -0800 (Thu, 08 Feb 2018)

Log Message

Experiment with alternative implementation of memcpy/memset
https://bugs.webkit.org/show_bug.cgi?id=182563

Reviewed by Michael Saboff and Mark Lam.
        
Source/bmalloc:

Add a faster x86_64-specific implementation of memcpy and memset. Ideally, this would just be
implemented in WTF, but we have to copy it into bmalloc since bmalloc sits below WTF on the
stack.

* bmalloc/Algorithm.h:
(bmalloc::fastCopy):
(bmalloc::fastZeroFill):
* bmalloc/Allocator.cpp:
(bmalloc::Allocator::reallocate):
* bmalloc/Bits.h:
(bmalloc::BitsWordOwner::operator=):
(bmalloc::BitsWordOwner::clearAll):
(bmalloc::BitsWordOwner::set):
* bmalloc/IsoPageInlines.h:
(bmalloc::IsoPage<Config>::IsoPage):
* bmalloc/Vector.h:
(bmalloc::Vector<T>::reallocateBuffer):

Source/_javascript_Core:

This adopts new fastCopy/fastZeroFill calls for calls to memcpy/memset that do not take a
constant size argument.

* assembler/AssemblerBuffer.h:
(JSC::AssemblerBuffer::append):
* runtime/ArrayBuffer.cpp:
(JSC::ArrayBufferContents::tryAllocate):
(JSC::ArrayBufferContents::copyTo):
(JSC::ArrayBuffer::createInternal):
* runtime/ArrayBufferView.h:
(JSC::ArrayBufferView::zeroRangeImpl):
* runtime/ArrayConventions.cpp:
* runtime/ArrayConventions.h:
(JSC::clearArray):
* runtime/ArrayPrototype.cpp:
(JSC::arrayProtoPrivateFuncConcatMemcpy):
* runtime/ButterflyInlines.h:
(JSC::Butterfly::tryCreate):
(JSC::Butterfly::createOrGrowPropertyStorage):
(JSC::Butterfly::growArrayRight):
(JSC::Butterfly::resizeArray):
* runtime/GenericTypedArrayViewInlines.h:
(JSC::GenericTypedArrayView<Adaptor>::create):
* runtime/JSArray.cpp:
(JSC::JSArray::appendMemcpy):
(JSC::JSArray::fastSlice):
* runtime/JSArrayBufferView.cpp:
(JSC::JSArrayBufferView::ConstructionContext::ConstructionContext):
* runtime/JSGenericTypedArrayViewInlines.h:
(JSC::JSGenericTypedArrayView<Adaptor>::set):
* runtime/JSObject.cpp:
(JSC::JSObject::constructConvertedArrayStorageWithoutCopyingElements):
(JSC::JSObject::shiftButterflyAfterFlattening):
* runtime/PropertyTable.cpp:
(JSC::PropertyTable::PropertyTable):

Source/WTF:

Adds a faster x86_64-specific implementation of memcpy and memset. These versions go by
different names than memcpy/memset and have a different API:
        
WTF::fastCopy<T>(T* dst, T* src, size_t N): copies N values of type T from src to dst.
WTF::fastZeroFill(T* dst, size_T N): writes N * sizeof(T) zeroes to dst.
        
There are also *Bytes variants that take void* for dst and src and size_t numBytes. Those are
most appropriate in places where the code is already computing bytes.
        
These will just call memcpy/memset on platforms where the optimized versions are not supported.
        
These new functions are not known to the compiler to be memcpy/memset. This has the effect that
the compiler will not try to replace them with anything else. This could be good or bad:
        
- It's *good* if the size is *not known* at compile time. In that case, by my benchmarks, these
  versions are faster than either the memcpy/memset call or whatever else the compiler could
  emit. This is because of a combination of inlining and the algorithm itself (see below).
        
- It's *bad* if the size is *known* at compile time. In that case, the compiler could
  potentially emit a fully unrolled memcpy/memset. That might not happen if the size is large
  (even if it's known), but in this patch I avoid replacing any memcpy/memset calls when the
  size is a constant. In particular, this totally avoids the call overhead -- if the size is
  small, then the compiler will emit a nice inlined copy or set. If the size is large, then the
  most optimal thing to do is emit the shortest piece of code possible, and that's a call to
  memcpy/memset.
        
It's unfortunate that you have to choose between them on your own. One way to avoid that might
have been to override the memcpy/memset symbols, so that the compiler can still do its
reasoning. But that's not quite right, since then we would lose inlining in the unknonw-size
case. Also, it's possible that for some unknown-size cases, the compiler could choose to emit
something on its own because it might think that some property of aliasing or alignment could
help it. I think it's a bit better to use our own copy/set implementations even in those cases.
Another way that I tried avoiding this is to detect inside fastCopy/fastZeroFill if the size is
constant. But there is no good way to do that in C++. There is a builtin for doing that inside a
macro, but that feels janky, so I didn't want to do it in this patch.
        
The reason why these new fastCopy/fastZeroFill functions are faster is that:
        
- They can be inlined. There is no function call. Only a few registers get clobbered. So, the
  impact on the quality of the code surrounding the memcpy/memset is smaller.
        
- They use type information to select the implementation. For sizes that are multiples of 2, 4,
  or 8, the resulting code performs dramatically better on small arrays than memcpy because it
  uses fewer cycles. The difference is greatest for 2 and 4 byte types, since memcpy usually
  handles small arrays by tiering from a 8-byte word copy loop to a byte copy loop. So, for 2
  or 4 byte arrays, we use an algorithm that tiers from 8-byte word down to a 2-byte or 4-byte
  (depending on type) copy loop. So, for example, when copying a 16-bit string that has 1, 2, or
  3 characters, this means doing 1, 2, or 3 word copies rather than 2, 4, or 6 byte copies. For
  8-byte types, the resulting savings are mainly that there is no check to see if a tier-down to
  the byte-copy loop is needed -- so really that means reducing code size. 1-byte types don't
  get this inherent advantage over memcpy/memset, but they still benefit from all of the other
  advantages of these functions. Of course, this advantage isn't inherent to our approach. The
  compiler could also notice that the arguments to memcpy/memset have some alignment properties.
  It could do it even more generally than we do - for example a copy over bytes where the size
  is a multiple of 4 can use the 4-byte word algorithm. But based on my tests, the compiler does
  not do this (even though it does other things, like turn a memset call with a zero value
  argument into a bzero call).
        
- They use a very nicely written word copy/set loop for small arrays. I spent a lot of time
  getting the assembly just right. When we use memcpy/memset, sometimes we would optimize the
  call by having a fast path word copy loop for small sizes. That's not necessary with this
  implementation, since the assembly copy loop gets inlined.
        
- They use `rep movs` or `rep stos` for copies of 200 bytes or more. This decision benchmarks
  poorly on every synthetic memcpy/memset benchmark I have built, and so unsurprisingly, it's
  not what system memcpy/memset does. Most system memcpy/memset implementations end up doing
  some SSE for medium-sized copies,. However, I previously found that this decision is bad for
  one of the memset calls in GC (see clearArray() and friends in ArrayConventions.h|cpp) - I was
  able to make the overhead of that call virtually disappear by doing `rep stos` more
  aggressively. The theory behind this change is that it's not just the GC that prefers smaller
  `rep` threshold and no SSE. I am betting that `rep`ing more is better when the heap gets
  chaotic and the data being copied is used in interesting ways -- hence, synthetic
  memcpy/memset benchmarks think it's bad (they don't do enough chaotic memory accesses) while
  it's good for real-world uses. Also, when I previously worked on JVMs, I had found that the
  best memcpy/memset heuristics when dealing with GC'd objects in a crazy heap were different
  than any memcpy/memset in any system library.
        
This appears to be a 0.9% speed-up on PLT. I'm not sure if it's more because of the inlining or
the `rep`. I think it's both. I'll leave figuring out the exact tuning for future patches.

* wtf/BitVector.cpp:
(WTF::BitVector::setSlow):
(WTF::BitVector::clearAll):
(WTF::BitVector::resizeOutOfLine):
* wtf/BitVector.h:
(WTF::BitVector::wordCount):
(WTF::BitVector::OutOfLineBits::numWords const):
* wtf/ConcurrentBuffer.h:
(WTF::ConcurrentBuffer::growExact):
* wtf/FastBitVector.h:
(WTF::FastBitVectorWordOwner::operator=):
(WTF::FastBitVectorWordOwner::clearAll):
(WTF::FastBitVectorWordOwner::set):
* wtf/FastCopy.h: Added.
(WTF::fastCopy):
(WTF::fastCopyBytes):
* wtf/FastMalloc.cpp:
(WTF::fastZeroedMalloc):
(WTF::fastStrDup):
(WTF::tryFastZeroedMalloc):
* wtf/FastZeroFill.h: Added.
(WTF::fastZeroFill):
(WTF::fastZeroFillBytes):
* wtf/MD5.cpp:
* wtf/OSAllocator.h:
(WTF::OSAllocator::reallocateCommitted):
* wtf/StringPrintStream.cpp:
(WTF::StringPrintStream::increaseSize):
* wtf/Vector.h:
* wtf/persistence/PersistentDecoder.cpp:
(WTF::Persistence::Decoder::decodeFixedLengthData):
* wtf/persistence/PersistentEncoder.cpp:
(WTF::Persistence::Encoder::encodeFixedLengthData):
* wtf/text/CString.cpp:
(WTF::CString::init):
(WTF::CString::copyBufferIfNeeded):
* wtf/text/LineBreakIteratorPoolICU.h:
(WTF::LineBreakIteratorPool::makeLocaleWithBreakKeyword):
* wtf/text/StringBuilder.cpp:
(WTF::StringBuilder::allocateBuffer):
(WTF::StringBuilder::append):
* wtf/text/StringConcatenate.h:
* wtf/text/StringImpl.h:
(WTF::StringImpl::copyCharacters):
* wtf/text/icu/UTextProvider.cpp:
(WTF::uTextCloneImpl):
* wtf/text/icu/UTextProviderLatin1.cpp:
(WTF::uTextLatin1Clone):
(WTF::openLatin1UTextProvider):
* wtf/threads/Signals.cpp:

Modified Paths

Added Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (228305 => 228306)


--- trunk/Source/_javascript_Core/ChangeLog	2018-02-09 01:58:23 UTC (rev 228305)
+++ trunk/Source/_javascript_Core/ChangeLog	2018-02-09 02:13:01 UTC (rev 228306)
@@ -1,3 +1,46 @@
+2018-02-08  Filip Pizlo  <[email protected]>
+
+        Experiment with alternative implementation of memcpy/memset
+        https://bugs.webkit.org/show_bug.cgi?id=182563
+
+        Reviewed by Michael Saboff and Mark Lam.
+        
+        This adopts new fastCopy/fastZeroFill calls for calls to memcpy/memset that do not take a
+        constant size argument.
+
+        * assembler/AssemblerBuffer.h:
+        (JSC::AssemblerBuffer::append):
+        * runtime/ArrayBuffer.cpp:
+        (JSC::ArrayBufferContents::tryAllocate):
+        (JSC::ArrayBufferContents::copyTo):
+        (JSC::ArrayBuffer::createInternal):
+        * runtime/ArrayBufferView.h:
+        (JSC::ArrayBufferView::zeroRangeImpl):
+        * runtime/ArrayConventions.cpp:
+        * runtime/ArrayConventions.h:
+        (JSC::clearArray):
+        * runtime/ArrayPrototype.cpp:
+        (JSC::arrayProtoPrivateFuncConcatMemcpy):
+        * runtime/ButterflyInlines.h:
+        (JSC::Butterfly::tryCreate):
+        (JSC::Butterfly::createOrGrowPropertyStorage):
+        (JSC::Butterfly::growArrayRight):
+        (JSC::Butterfly::resizeArray):
+        * runtime/GenericTypedArrayViewInlines.h:
+        (JSC::GenericTypedArrayView<Adaptor>::create):
+        * runtime/JSArray.cpp:
+        (JSC::JSArray::appendMemcpy):
+        (JSC::JSArray::fastSlice):
+        * runtime/JSArrayBufferView.cpp:
+        (JSC::JSArrayBufferView::ConstructionContext::ConstructionContext):
+        * runtime/JSGenericTypedArrayViewInlines.h:
+        (JSC::JSGenericTypedArrayView<Adaptor>::set):
+        * runtime/JSObject.cpp:
+        (JSC::JSObject::constructConvertedArrayStorageWithoutCopyingElements):
+        (JSC::JSObject::shiftButterflyAfterFlattening):
+        * runtime/PropertyTable.cpp:
+        (JSC::PropertyTable::PropertyTable):
+
 2018-02-08  Don Olmstead  <[email protected]>
 
         Remove _javascript_Core/ForwardingHeaders directory

Modified: trunk/Source/_javascript_Core/assembler/AssemblerBuffer.h (228305 => 228306)


--- trunk/Source/_javascript_Core/assembler/AssemblerBuffer.h	2018-02-09 01:58:23 UTC (rev 228305)
+++ trunk/Source/_javascript_Core/assembler/AssemblerBuffer.h	2018-02-09 02:13:01 UTC (rev 228306)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008, 2012, 2014 Apple Inc. All rights reserved.
+ * Copyright (C) 2008-2018 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -276,7 +276,7 @@
             if (!isAvailable(size))
                 grow(size);
 
-            memcpy(m_storage.buffer() + m_index, data, size);
+            fastCopyBytes(m_storage.buffer() + m_index, data, size);
             m_index += size;
         }
 

Modified: trunk/Source/_javascript_Core/heap/LargeAllocation.cpp (228305 => 228306)


--- trunk/Source/_javascript_Core/heap/LargeAllocation.cpp	2018-02-09 01:58:23 UTC (rev 228305)
+++ trunk/Source/_javascript_Core/heap/LargeAllocation.cpp	2018-02-09 02:13:01 UTC (rev 228306)
@@ -45,7 +45,7 @@
         return nullptr;
     
     // Make sure that the padding does not contain useful things.
-    memset(static_cast<char*>(space) + sizeBeforeDistancing, 0, distancing);
+    fastZeroFillBytes(static_cast<char*>(space) + sizeBeforeDistancing, distancing);
     
     if (scribbleFreeCells())
         scribble(space, size);

Modified: trunk/Source/_javascript_Core/heap/MarkedBlock.cpp (228305 => 228306)


--- trunk/Source/_javascript_Core/heap/MarkedBlock.cpp	2018-02-09 01:58:23 UTC (rev 228305)
+++ trunk/Source/_javascript_Core/heap/MarkedBlock.cpp	2018-02-09 02:13:01 UTC (rev 228306)
@@ -493,7 +493,7 @@
     if (m_securityOriginToken == securityOriginToken)
         return;
     
-    memset(&block(), 0, endAtom * atomSize);
+    fastZeroFillBytes(&block(), endAtom * atomSize);
     m_securityOriginToken = securityOriginToken;
 }
 

Modified: trunk/Source/_javascript_Core/runtime/ArrayBuffer.cpp (228305 => 228306)


--- trunk/Source/_javascript_Core/runtime/ArrayBuffer.cpp	2018-02-09 01:58:23 UTC (rev 228305)
+++ trunk/Source/_javascript_Core/runtime/ArrayBuffer.cpp	2018-02-09 02:13:01 UTC (rev 228306)
@@ -113,7 +113,7 @@
     }
     
     if (policy == ZeroInitialize)
-        memset(m_data.get(), 0, size);
+        fastZeroFillBytes(m_data.get(), size);
 
     m_sizeInBytes = numElements * elementByteSize;
     m_destructor = [] (void* p) { Gigacage::free(Gigacage::Primitive, p); };
@@ -141,7 +141,7 @@
     other.tryAllocate(m_sizeInBytes, sizeof(char), ArrayBufferContents::DontInitialize);
     if (!other.m_data)
         return;
-    memcpy(other.m_data.get(), m_data.get(), m_sizeInBytes);
+    fastCopyBytes(other.m_data.get(), m_data.get(), m_sizeInBytes);
     other.m_sizeInBytes = m_sizeInBytes;
 }
 
@@ -246,7 +246,7 @@
 {
     ASSERT(!byteLength || source);
     auto buffer = adoptRef(*new ArrayBuffer(WTFMove(contents)));
-    memcpy(buffer->data(), source, byteLength);
+    fastCopyBytes(buffer->data(), source, byteLength);
     return buffer;
 }
 

Modified: trunk/Source/_javascript_Core/runtime/ArrayBufferView.h (228305 => 228306)


--- trunk/Source/_javascript_Core/runtime/ArrayBufferView.h	2018-02-09 01:58:23 UTC (rev 228305)
+++ trunk/Source/_javascript_Core/runtime/ArrayBufferView.h	2018-02-09 02:13:01 UTC (rev 228306)
@@ -215,7 +215,7 @@
     }
     
     uint8_t* base = static_cast<uint8_t*>(baseAddress());
-    memset(base + byteOffset, 0, rangeByteLength);
+    fastZeroFillBytes(base + byteOffset, rangeByteLength);
     return true;
 }
 

Modified: trunk/Source/_javascript_Core/runtime/ArrayConventions.cpp (228305 => 228306)


--- trunk/Source/_javascript_Core/runtime/ArrayConventions.cpp	2018-02-09 01:58:23 UTC (rev 228305)
+++ trunk/Source/_javascript_Core/runtime/ArrayConventions.cpp	2018-02-09 02:13:01 UTC (rev 228306)
@@ -31,21 +31,6 @@
 namespace JSC {
 
 #if USE(JSVALUE64)
-void clearArrayMemset(WriteBarrier<Unknown>* base, unsigned count)
-{
-#if CPU(X86_64) && COMPILER(GCC_OR_CLANG)
-    uint64_t zero = 0;
-    asm volatile (
-        "rep stosq\n\t"
-        : "+D"(base), "+c"(count)
-        : "a"(zero)
-        : "memory"
-        );
-#else // not CPU(X86_64)
-    memset(base, 0, count * sizeof(WriteBarrier<Unknown>));
-#endif // generic CPU
-}
-
 void clearArrayMemset(double* base, unsigned count)
 {
 #if CPU(X86_64) && COMPILER(GCC_OR_CLANG)

Modified: trunk/Source/_javascript_Core/runtime/ArrayConventions.h (228305 => 228306)


--- trunk/Source/_javascript_Core/runtime/ArrayConventions.h	2018-02-09 01:58:23 UTC (rev 228305)
+++ trunk/Source/_javascript_Core/runtime/ArrayConventions.h	2018-02-09 02:13:01 UTC (rev 228306)
@@ -117,7 +117,6 @@
 }
 
 #if USE(JSVALUE64)
-JS_EXPORT_PRIVATE void clearArrayMemset(WriteBarrier<Unknown>* base, unsigned count);
 JS_EXPORT_PRIVATE void clearArrayMemset(double* base, unsigned count);
 #endif // USE(JSVALUE64)
 
@@ -124,15 +123,11 @@
 ALWAYS_INLINE void clearArray(WriteBarrier<Unknown>* base, unsigned count)
 {
 #if USE(JSVALUE64)
-    const unsigned minCountForMemset = 100;
-    if (count >= minCountForMemset) {
-        clearArrayMemset(base, count);
-        return;
-    }
-#endif
-    
+    fastZeroFill(base, count);
+#else
     for (unsigned i = count; i--;)
         base[i].clear();
+#endif
 }
 
 ALWAYS_INLINE void clearArray(double* base, unsigned count)

Modified: trunk/Source/_javascript_Core/runtime/ArrayPrototype.cpp (228305 => 228306)


--- trunk/Source/_javascript_Core/runtime/ArrayPrototype.cpp	2018-02-09 01:58:23 UTC (rev 228305)
+++ trunk/Source/_javascript_Core/runtime/ArrayPrototype.cpp	2018-02-09 02:13:01 UTC (rev 228306)
@@ -1341,19 +1341,18 @@
     
     if (type == ArrayWithDouble) {
         double* buffer = result->butterfly()->contiguousDouble().data();
-        memcpy(buffer, firstButterfly->contiguousDouble().data(), sizeof(JSValue) * firstArraySize);
-        memcpy(buffer + firstArraySize, secondButterfly->contiguousDouble().data(), sizeof(JSValue) * secondArraySize);
+        fastCopy(buffer, firstButterfly->contiguousDouble().data(), firstArraySize);
+        fastCopy(buffer + firstArraySize, secondButterfly->contiguousDouble().data(), secondArraySize);
     } else if (type != ArrayWithUndecided) {
         WriteBarrier<Unknown>* buffer = result->butterfly()->contiguous().data();
         
         auto copy = [&] (unsigned offset, void* source, unsigned size, IndexingType type) {
             if (type != ArrayWithUndecided) {
-                memcpy(buffer + offset, source, sizeof(JSValue) * size);
+                fastCopy(buffer + offset, static_cast<WriteBarrier<Unknown>*>(source), size);
                 return;
             }
             
-            for (unsigned i = size; i--;)
-                buffer[i + offset].clear();
+            clearArray(buffer + offset, size);
         };
         
         copy(0, firstButterfly->contiguous().data(), firstArraySize, firstType);

Modified: trunk/Source/_javascript_Core/runtime/ButterflyInlines.h (228305 => 228306)


--- trunk/Source/_javascript_Core/runtime/ButterflyInlines.h	2018-02-09 01:58:23 UTC (rev 228305)
+++ trunk/Source/_javascript_Core/runtime/ButterflyInlines.h	2018-02-09 02:13:01 UTC (rev 228306)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012-2017 Apple Inc. All rights reserved.
+ * Copyright (C) 2012-2018 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -93,7 +93,7 @@
     Butterfly* result = fromBase(base, preCapacity, propertyCapacity);
     if (hasIndexingHeader)
         *result->indexingHeader() = indexingHeader;
-    memset(result->propertyStorage() - propertyCapacity, 0, propertyCapacity * sizeof(EncodedJSValue));
+    fastZeroFill(result->propertyStorage() - propertyCapacity, propertyCapacity);
     return result;
 }
 
@@ -129,14 +129,13 @@
     bool hasIndexingHeader = structure->hasIndexingHeader(intendedOwner);
     Butterfly* result = createUninitialized(
         vm, intendedOwner, preCapacity, newPropertyCapacity, hasIndexingHeader, indexingPayloadSizeInBytes);
-    memcpy(
+    fastCopyBytes(
         result->propertyStorage() - oldPropertyCapacity,
         oldButterfly->propertyStorage() - oldPropertyCapacity,
         totalSize(0, oldPropertyCapacity, hasIndexingHeader, indexingPayloadSizeInBytes));
-    memset(
+    fastZeroFill(
         result->propertyStorage() - newPropertyCapacity,
-        0,
-        (newPropertyCapacity - oldPropertyCapacity) * sizeof(EncodedJSValue));
+        newPropertyCapacity - oldPropertyCapacity);
     return result;
 }
 
@@ -168,8 +167,7 @@
     void* newBase = vm.jsValueGigacageAuxiliarySpace.allocateNonVirtual(vm, newSize, nullptr, AllocationFailureMode::ReturnNull);
     if (!newBase)
         return nullptr;
-    // FIXME: This probably shouldn't be a memcpy.
-    memcpy(newBase, theBase, oldSize);
+    fastCopyBytes(newBase, theBase, oldSize);
     return fromBase(newBase, 0, propertyCapacity);
 }
 
@@ -199,7 +197,7 @@
     size_t size = std::min(
         totalSize(0, propertyCapacity, oldHasIndexingHeader, oldIndexingPayloadSizeInBytes),
         totalSize(0, propertyCapacity, newHasIndexingHeader, newIndexingPayloadSizeInBytes));
-    memcpy(to, from, size);
+    fastCopyBytes(to, from, size);
     return result;
 }
 

Modified: trunk/Source/_javascript_Core/runtime/GenericTypedArrayViewInlines.h (228305 => 228306)


--- trunk/Source/_javascript_Core/runtime/GenericTypedArrayViewInlines.h	2018-02-09 01:58:23 UTC (rev 228305)
+++ trunk/Source/_javascript_Core/runtime/GenericTypedArrayViewInlines.h	2018-02-09 02:13:01 UTC (rev 228306)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013, 2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2013-2018 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -52,7 +52,7 @@
     const typename Adaptor::Type* array, unsigned length)
 {
     RefPtr<GenericTypedArrayView> result = create(length);
-    memcpy(result->data(), array, length * sizeof(typename Adaptor::Type));
+    fastCopy(result->data(), array, length);
     return result;
 }
 

Modified: trunk/Source/_javascript_Core/runtime/JSArray.cpp (228305 => 228306)


--- trunk/Source/_javascript_Core/runtime/JSArray.cpp	2018-02-09 01:58:23 UTC (rev 228305)
+++ trunk/Source/_javascript_Core/runtime/JSArray.cpp	2018-02-09 02:13:01 UTC (rev 228306)
@@ -553,9 +553,9 @@
                 butterfly->contiguousInt32().at(this, i).setWithoutWriteBarrier(JSValue());
         }
     } else if (type == ArrayWithDouble)
-        memcpy(butterfly()->contiguousDouble().data() + startIndex, otherArray->butterfly()->contiguousDouble().data(), sizeof(JSValue) * otherLength);
+        fastCopy(butterfly()->contiguousDouble().data() + startIndex, otherArray->butterfly()->contiguousDouble().data(), otherLength);
     else
-        memcpy(butterfly()->contiguous().data() + startIndex, otherArray->butterfly()->contiguous().data(), sizeof(JSValue) * otherLength);
+        fastCopy(butterfly()->contiguous().data() + startIndex, otherArray->butterfly()->contiguous().data(), otherLength);
 
     return true;
 }
@@ -761,9 +761,9 @@
 
         auto& resultButterfly = *resultArray->butterfly();
         if (arrayType == ArrayWithDouble)
-            memcpy(resultButterfly.contiguousDouble().data(), butterfly()->contiguousDouble().data() + startIndex, sizeof(JSValue) * count);
+            fastCopy(resultButterfly.contiguousDouble().data(), butterfly()->contiguousDouble().data() + startIndex, count);
         else
-            memcpy(resultButterfly.contiguous().data(), butterfly()->contiguous().data() + startIndex, sizeof(JSValue) * count);
+            fastCopy(resultButterfly.contiguous().data(), butterfly()->contiguous().data() + startIndex, count);
         resultButterfly.setPublicLength(count);
 
         return resultArray;

Modified: trunk/Source/_javascript_Core/runtime/JSArrayBufferView.cpp (228305 => 228306)


--- trunk/Source/_javascript_Core/runtime/JSArrayBufferView.cpp	2018-02-09 01:58:23 UTC (rev 228305)
+++ trunk/Source/_javascript_Core/runtime/JSArrayBufferView.cpp	2018-02-09 02:13:01 UTC (rev 228306)
@@ -94,7 +94,7 @@
     if (!m_vector)
         return;
     if (mode == ZeroFill)
-        memset(m_vector.get(), 0, size);
+        fastZeroFillBytes(m_vector.get(), size);
     
     vm.heap.reportExtraMemoryAllocated(static_cast<size_t>(length) * elementSize);
     

Modified: trunk/Source/_javascript_Core/runtime/JSGenericTypedArrayViewInlines.h (228305 => 228306)


--- trunk/Source/_javascript_Core/runtime/JSGenericTypedArrayViewInlines.h	2018-02-09 01:58:23 UTC (rev 228305)
+++ trunk/Source/_javascript_Core/runtime/JSGenericTypedArrayViewInlines.h	2018-02-09 02:13:01 UTC (rev 228306)
@@ -246,7 +246,7 @@
 
     const ClassInfo* ci = object->classInfo(vm);
     if (ci->typedArrayStorageType == Adaptor::typeValue) {
-        // The super fast case: we can just memcpy since we're the same type.
+        // The super fast case: we can just memmove since we're the same type.
         JSGenericTypedArrayView* other = jsCast<JSGenericTypedArrayView*>(object);
         length = std::min(length, other->length());
         

Modified: trunk/Source/_javascript_Core/runtime/JSObject.cpp (228305 => 228306)


--- trunk/Source/_javascript_Core/runtime/JSObject.cpp	2018-02-09 01:58:23 UTC (rev 228305)
+++ trunk/Source/_javascript_Core/runtime/JSObject.cpp	2018-02-09 02:13:01 UTC (rev 228306)
@@ -1178,10 +1178,10 @@
     Butterfly* newButterfly = Butterfly::createUninitialized(
         vm, this, 0, propertyCapacity, true, ArrayStorage::sizeFor(neededLength));
     
-    memcpy(
+    fastCopy(
         newButterfly->propertyStorage() - propertySize,
         m_butterfly->propertyStorage() - propertySize,
-        propertySize * sizeof(EncodedJSValue));
+        propertySize);
     
     ArrayStorage* newStorage = newButterfly->arrayStorage();
     newStorage->setVectorLength(neededLength);
@@ -3580,7 +3580,7 @@
     void* currentBase = oldButterfly->base(0, outOfLineCapacityAfter);
     void* newBase = newButterfly->base(0, outOfLineCapacityAfter);
 
-    memcpy(newBase, currentBase, Butterfly::totalSize(0, outOfLineCapacityAfter, hasIndexingHeader, indexingPayloadSizeInBytes));
+    fastCopyBytes(newBase, currentBase, Butterfly::totalSize(0, outOfLineCapacityAfter, hasIndexingHeader, indexingPayloadSizeInBytes));
     
     setButterfly(vm, newButterfly);
 }

Modified: trunk/Source/_javascript_Core/runtime/PropertyTable.cpp (228305 => 228306)


--- trunk/Source/_javascript_Core/runtime/PropertyTable.cpp	2018-02-09 01:58:23 UTC (rev 228305)
+++ trunk/Source/_javascript_Core/runtime/PropertyTable.cpp	2018-02-09 02:13:01 UTC (rev 228306)
@@ -74,7 +74,7 @@
 {
     ASSERT(isPowerOf2(m_indexSize));
 
-    memcpy(m_index, other.m_index, dataSize());
+    fastCopyBytes(m_index, other.m_index, dataSize());
 
     iterator end = this->end();
     for (iterator iter = begin(); iter != end; ++iter)

Modified: trunk/Source/WTF/ChangeLog (228305 => 228306)


--- trunk/Source/WTF/ChangeLog	2018-02-09 01:58:23 UTC (rev 228305)
+++ trunk/Source/WTF/ChangeLog	2018-02-09 02:13:01 UTC (rev 228306)
@@ -1,3 +1,141 @@
+2018-02-08  Filip Pizlo  <[email protected]>
+
+        Experiment with alternative implementation of memcpy/memset
+        https://bugs.webkit.org/show_bug.cgi?id=182563
+
+        Reviewed by Michael Saboff and Mark Lam.
+        
+        Adds a faster x86_64-specific implementation of memcpy and memset. These versions go by
+        different names than memcpy/memset and have a different API:
+        
+        WTF::fastCopy<T>(T* dst, T* src, size_t N): copies N values of type T from src to dst.
+        WTF::fastZeroFill(T* dst, size_T N): writes N * sizeof(T) zeroes to dst.
+        
+        There are also *Bytes variants that take void* for dst and src and size_t numBytes. Those are
+        most appropriate in places where the code is already computing bytes.
+        
+        These will just call memcpy/memset on platforms where the optimized versions are not supported.
+        
+        These new functions are not known to the compiler to be memcpy/memset. This has the effect that
+        the compiler will not try to replace them with anything else. This could be good or bad:
+        
+        - It's *good* if the size is *not known* at compile time. In that case, by my benchmarks, these
+          versions are faster than either the memcpy/memset call or whatever else the compiler could
+          emit. This is because of a combination of inlining and the algorithm itself (see below).
+        
+        - It's *bad* if the size is *known* at compile time. In that case, the compiler could
+          potentially emit a fully unrolled memcpy/memset. That might not happen if the size is large
+          (even if it's known), but in this patch I avoid replacing any memcpy/memset calls when the
+          size is a constant. In particular, this totally avoids the call overhead -- if the size is
+          small, then the compiler will emit a nice inlined copy or set. If the size is large, then the
+          most optimal thing to do is emit the shortest piece of code possible, and that's a call to
+          memcpy/memset.
+        
+        It's unfortunate that you have to choose between them on your own. One way to avoid that might
+        have been to override the memcpy/memset symbols, so that the compiler can still do its
+        reasoning. But that's not quite right, since then we would lose inlining in the unknonw-size
+        case. Also, it's possible that for some unknown-size cases, the compiler could choose to emit
+        something on its own because it might think that some property of aliasing or alignment could
+        help it. I think it's a bit better to use our own copy/set implementations even in those cases.
+        Another way that I tried avoiding this is to detect inside fastCopy/fastZeroFill if the size is
+        constant. But there is no good way to do that in C++. There is a builtin for doing that inside a
+        macro, but that feels janky, so I didn't want to do it in this patch.
+        
+        The reason why these new fastCopy/fastZeroFill functions are faster is that:
+        
+        - They can be inlined. There is no function call. Only a few registers get clobbered. So, the
+          impact on the quality of the code surrounding the memcpy/memset is smaller.
+        
+        - They use type information to select the implementation. For sizes that are multiples of 2, 4,
+          or 8, the resulting code performs dramatically better on small arrays than memcpy because it
+          uses fewer cycles. The difference is greatest for 2 and 4 byte types, since memcpy usually
+          handles small arrays by tiering from a 8-byte word copy loop to a byte copy loop. So, for 2
+          or 4 byte arrays, we use an algorithm that tiers from 8-byte word down to a 2-byte or 4-byte
+          (depending on type) copy loop. So, for example, when copying a 16-bit string that has 1, 2, or
+          3 characters, this means doing 1, 2, or 3 word copies rather than 2, 4, or 6 byte copies. For
+          8-byte types, the resulting savings are mainly that there is no check to see if a tier-down to
+          the byte-copy loop is needed -- so really that means reducing code size. 1-byte types don't
+          get this inherent advantage over memcpy/memset, but they still benefit from all of the other
+          advantages of these functions. Of course, this advantage isn't inherent to our approach. The
+          compiler could also notice that the arguments to memcpy/memset have some alignment properties.
+          It could do it even more generally than we do - for example a copy over bytes where the size
+          is a multiple of 4 can use the 4-byte word algorithm. But based on my tests, the compiler does
+          not do this (even though it does other things, like turn a memset call with a zero value
+          argument into a bzero call).
+        
+        - They use a very nicely written word copy/set loop for small arrays. I spent a lot of time
+          getting the assembly just right. When we use memcpy/memset, sometimes we would optimize the
+          call by having a fast path word copy loop for small sizes. That's not necessary with this
+          implementation, since the assembly copy loop gets inlined.
+        
+        - They use `rep movs` or `rep stos` for copies of 200 bytes or more. This decision benchmarks
+          poorly on every synthetic memcpy/memset benchmark I have built, and so unsurprisingly, it's
+          not what system memcpy/memset does. Most system memcpy/memset implementations end up doing
+          some SSE for medium-sized copies,. However, I previously found that this decision is bad for
+          one of the memset calls in GC (see clearArray() and friends in ArrayConventions.h|cpp) - I was
+          able to make the overhead of that call virtually disappear by doing `rep stos` more
+          aggressively. The theory behind this change is that it's not just the GC that prefers smaller
+          `rep` threshold and no SSE. I am betting that `rep`ing more is better when the heap gets
+          chaotic and the data being copied is used in interesting ways -- hence, synthetic
+          memcpy/memset benchmarks think it's bad (they don't do enough chaotic memory accesses) while
+          it's good for real-world uses. Also, when I previously worked on JVMs, I had found that the
+          best memcpy/memset heuristics when dealing with GC'd objects in a crazy heap were different
+          than any memcpy/memset in any system library.
+        
+        This appears to be a 0.9% speed-up on PLT. I'm not sure if it's more because of the inlining or
+        the `rep`. I think it's both. I'll leave figuring out the exact tuning for future patches.
+
+        * wtf/BitVector.cpp:
+        (WTF::BitVector::setSlow):
+        (WTF::BitVector::clearAll):
+        (WTF::BitVector::resizeOutOfLine):
+        * wtf/BitVector.h:
+        (WTF::BitVector::wordCount):
+        (WTF::BitVector::OutOfLineBits::numWords const):
+        * wtf/ConcurrentBuffer.h:
+        (WTF::ConcurrentBuffer::growExact):
+        * wtf/FastBitVector.h:
+        (WTF::FastBitVectorWordOwner::operator=):
+        (WTF::FastBitVectorWordOwner::clearAll):
+        (WTF::FastBitVectorWordOwner::set):
+        * wtf/FastCopy.h: Added.
+        (WTF::fastCopy):
+        (WTF::fastCopyBytes):
+        * wtf/FastMalloc.cpp:
+        (WTF::fastZeroedMalloc):
+        (WTF::fastStrDup):
+        (WTF::tryFastZeroedMalloc):
+        * wtf/FastZeroFill.h: Added.
+        (WTF::fastZeroFill):
+        (WTF::fastZeroFillBytes):
+        * wtf/MD5.cpp:
+        * wtf/OSAllocator.h:
+        (WTF::OSAllocator::reallocateCommitted):
+        * wtf/StringPrintStream.cpp:
+        (WTF::StringPrintStream::increaseSize):
+        * wtf/Vector.h:
+        * wtf/persistence/PersistentDecoder.cpp:
+        (WTF::Persistence::Decoder::decodeFixedLengthData):
+        * wtf/persistence/PersistentEncoder.cpp:
+        (WTF::Persistence::Encoder::encodeFixedLengthData):
+        * wtf/text/CString.cpp:
+        (WTF::CString::init):
+        (WTF::CString::copyBufferIfNeeded):
+        * wtf/text/LineBreakIteratorPoolICU.h:
+        (WTF::LineBreakIteratorPool::makeLocaleWithBreakKeyword):
+        * wtf/text/StringBuilder.cpp:
+        (WTF::StringBuilder::allocateBuffer):
+        (WTF::StringBuilder::append):
+        * wtf/text/StringConcatenate.h:
+        * wtf/text/StringImpl.h:
+        (WTF::StringImpl::copyCharacters):
+        * wtf/text/icu/UTextProvider.cpp:
+        (WTF::uTextCloneImpl):
+        * wtf/text/icu/UTextProviderLatin1.cpp:
+        (WTF::uTextLatin1Clone):
+        (WTF::openLatin1UTextProvider):
+        * wtf/threads/Signals.cpp:
+
 2018-02-06  Darin Adler  <[email protected]>
 
         Event improvements

Modified: trunk/Source/WTF/WTF.xcodeproj/project.pbxproj (228305 => 228306)


--- trunk/Source/WTF/WTF.xcodeproj/project.pbxproj	2018-02-09 01:58:23 UTC (rev 228305)
+++ trunk/Source/WTF/WTF.xcodeproj/project.pbxproj	2018-02-09 02:13:01 UTC (rev 228306)
@@ -206,6 +206,8 @@
 		0F5F3D681F3FEBA600B115A2 /* CagedUniquePtr.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CagedUniquePtr.h; sourceTree = "<group>"; };
 		0F60F32D1DFCBD1B00416D6C /* LockedPrintStream.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LockedPrintStream.cpp; sourceTree = "<group>"; };
 		0F60F32E1DFCBD1B00416D6C /* LockedPrintStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LockedPrintStream.h; sourceTree = "<group>"; };
+		0F62A8A6202CCC14007B8623 /* FastCopy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FastCopy.h; sourceTree = "<group>"; };
+		0F62A8A7202CCC15007B8623 /* FastZeroFill.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FastZeroFill.h; sourceTree = "<group>"; };
 		0F66B2801DC97BAB004A1D3F /* ClockType.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ClockType.cpp; sourceTree = "<group>"; };
 		0F66B2811DC97BAB004A1D3F /* ClockType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ClockType.h; sourceTree = "<group>"; };
 		0F66B2821DC97BAB004A1D3F /* MonotonicTime.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MonotonicTime.cpp; sourceTree = "<group>"; };
@@ -864,9 +866,11 @@
 				A8A4729F151A825A004123FF /* ExportMacros.h */,
 				0F7C5FB51D885CF20044F5E2 /* FastBitVector.cpp */,
 				0FD81AC4154FB22E00983E72 /* FastBitVector.h */,
+				0F62A8A6202CCC14007B8623 /* FastCopy.h */,
 				A8A472A1151A825A004123FF /* FastMalloc.cpp */,
 				A8A472A2151A825A004123FF /* FastMalloc.h */,
 				0F79C7C31E73511800EB34D1 /* FastTLS.h */,
+				0F62A8A7202CCC15007B8623 /* FastZeroFill.h */,
 				B38FD7BC168953E80065C969 /* FeatureDefines.h */,
 				0F9D335B165DBA73005AD387 /* FilePrintStream.cpp */,
 				0F9D335C165DBA73005AD387 /* FilePrintStream.h */,

Modified: trunk/Source/WTF/wtf/BitVector.cpp (228305 => 228306)


--- trunk/Source/WTF/wtf/BitVector.cpp	2018-02-09 01:58:23 UTC (rev 228305)
+++ trunk/Source/WTF/wtf/BitVector.cpp	2018-02-09 02:13:01 UTC (rev 228306)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 2011-2018 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -29,7 +29,9 @@
 #include <algorithm>
 #include <string.h>
 #include <wtf/Assertions.h>
+#include <wtf/FastCopy.h>
 #include <wtf/FastMalloc.h>
+#include <wtf/FastZeroFill.h>
 #include <wtf/StdLibExtras.h>
 
 namespace WTF {
@@ -41,7 +43,7 @@
         newBitsOrPointer = other.m_bitsOrPointer;
     else {
         OutOfLineBits* newOutOfLineBits = OutOfLineBits::create(other.size());
-        memcpy(newOutOfLineBits->bits(), other.bits(), byteCount(other.size()));
+        fastCopy(newOutOfLineBits->bits(), other.bits(), wordCount(other.size()));
         newBitsOrPointer = bitwise_cast<uintptr_t>(newOutOfLineBits) >> 1;
     }
     if (!isInline() && !isEmptyOrDeletedValue())
@@ -69,7 +71,7 @@
     if (isInline())
         m_bitsOrPointer = makeInlineBits(0);
     else
-        memset(outOfLineBits()->bits(), 0, byteCount(size()));
+        fastZeroFill(outOfLineBits()->bits(), wordCount(size()));
 }
 
 BitVector::OutOfLineBits* BitVector::OutOfLineBits::create(size_t numBits)
@@ -93,14 +95,14 @@
     if (isInline()) {
         // Make sure that all of the bits are zero in case we do a no-op resize.
         *newOutOfLineBits->bits() = m_bitsOrPointer & ~(static_cast<uintptr_t>(1) << maxInlineBits());
-        memset(newOutOfLineBits->bits() + 1, 0, (newNumWords - 1) * sizeof(void*));
+        fastZeroFill(newOutOfLineBits->bits() + 1, newNumWords - 1);
     } else {
         if (numBits > size()) {
             size_t oldNumWords = outOfLineBits()->numWords();
-            memcpy(newOutOfLineBits->bits(), outOfLineBits()->bits(), oldNumWords * sizeof(void*));
-            memset(newOutOfLineBits->bits() + oldNumWords, 0, (newNumWords - oldNumWords) * sizeof(void*));
+            fastCopy(newOutOfLineBits->bits(), outOfLineBits()->bits(), oldNumWords);
+            fastZeroFill(newOutOfLineBits->bits() + oldNumWords, newNumWords - oldNumWords);
         } else
-            memcpy(newOutOfLineBits->bits(), outOfLineBits()->bits(), newOutOfLineBits->numWords() * sizeof(void*));
+            fastCopy(newOutOfLineBits->bits(), outOfLineBits()->bits(), newOutOfLineBits->numWords());
         OutOfLineBits::destroy(outOfLineBits());
     }
     m_bitsOrPointer = bitwise_cast<uintptr_t>(newOutOfLineBits) >> 1;

Modified: trunk/Source/WTF/wtf/BitVector.h (228305 => 228306)


--- trunk/Source/WTF/wtf/BitVector.h	2018-02-09 01:58:23 UTC (rev 228305)
+++ trunk/Source/WTF/wtf/BitVector.h	2018-02-09 02:13:01 UTC (rev 228306)
@@ -354,6 +354,11 @@
         return (bitCount + 7) >> 3;
     }
 
+    static size_t wordCount(uintptr_t bits)
+    {
+        return (bits + bitsInPointer() - 1) / bitsInPointer();
+    }
+    
     static uintptr_t makeInlineBits(uintptr_t bits)
     {
         ASSERT(!(bits & (static_cast<uintptr_t>(1) << maxInlineBits())));
@@ -418,7 +423,7 @@
     class OutOfLineBits {
     public:
         size_t numBits() const { return m_numBits; }
-        size_t numWords() const { return (m_numBits + bitsInPointer() - 1) / bitsInPointer(); }
+        size_t numWords() const { return wordCount(m_numBits); }
         uintptr_t* bits() { return bitwise_cast<uintptr_t*>(this + 1); }
         const uintptr_t* bits() const { return bitwise_cast<const uintptr_t*>(this + 1); }
         

Modified: trunk/Source/WTF/wtf/CMakeLists.txt (228305 => 228306)


--- trunk/Source/WTF/wtf/CMakeLists.txt	2018-02-09 01:58:23 UTC (rev 228305)
+++ trunk/Source/WTF/wtf/CMakeLists.txt	2018-02-09 02:13:01 UTC (rev 228306)
@@ -59,8 +59,10 @@
     Expected.h
     ExportMacros.h
     FastBitVector.h
+    FastCopy.h
     FastMalloc.h
     FastTLS.h
+    FastZeroFill.h
     FeatureDefines.h
     FilePrintStream.h
     FlipBytes.h

Modified: trunk/Source/WTF/wtf/ConcurrentBuffer.h (228305 => 228306)


--- trunk/Source/WTF/wtf/ConcurrentBuffer.h	2018-02-09 01:58:23 UTC (rev 228305)
+++ trunk/Source/WTF/wtf/ConcurrentBuffer.h	2018-02-09 02:13:01 UTC (rev 228306)
@@ -26,6 +26,7 @@
 #pragma once
 
 #include <wtf/Atomics.h>
+#include <wtf/FastCopy.h>
 #include <wtf/FastMalloc.h>
 #include <wtf/HashFunctions.h>
 #include <wtf/Lock.h>
@@ -65,7 +66,7 @@
         Array* newArray = createArray(newSize);
         // This allows us to do ConcurrentBuffer<std::unique_ptr<>>.
         if (array)
-            memcpy(newArray->data, array->data, sizeof(T) * array->size);
+            fastCopy(newArray->data, array->data, array->size);
         for (size_t i = array ? array->size : 0; i < newSize; ++i)
             new (newArray->data + i) T();
         WTF::storeStoreFence();

Modified: trunk/Source/WTF/wtf/FastBitVector.h (228305 => 228306)


--- trunk/Source/WTF/wtf/FastBitVector.h	2018-02-09 01:58:23 UTC (rev 228305)
+++ trunk/Source/WTF/wtf/FastBitVector.h	2018-02-09 02:13:01 UTC (rev 228306)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012, 2013, 2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2012-2018 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -27,7 +27,9 @@
 
 #include <string.h>
 #include <wtf/Atomics.h>
+#include <wtf/FastCopy.h>
 #include <wtf/FastMalloc.h>
+#include <wtf/FastZeroFill.h>
 #include <wtf/PrintStream.h>
 #include <wtf/StdLibExtras.h>
 
@@ -95,7 +97,7 @@
         if (arrayLength() != other.arrayLength())
             setEqualsSlow(other);
         else {
-            memcpy(m_words, other.m_words, arrayLength() * sizeof(uint32_t));
+            fastCopy(m_words, other.m_words, arrayLength());
             m_numBits = other.m_numBits;
         }
         return *this;
@@ -115,13 +117,13 @@
     
     void clearAll()
     {
-        memset(m_words, 0, arrayLength() * sizeof(uint32_t));
+        fastZeroFill(m_words, arrayLength());
     }
     
     void set(const FastBitVectorWordOwner& other)
     {
         ASSERT_WITH_SECURITY_IMPLICATION(m_numBits == other.m_numBits);
-        memcpy(m_words, other.m_words, arrayLength() * sizeof(uint32_t));
+        fastCopy(m_words, other.m_words, arrayLength());
     }
     
     size_t numBits() const

Added: trunk/Source/WTF/wtf/FastCopy.h (0 => 228306)


--- trunk/Source/WTF/wtf/FastCopy.h	                        (rev 0)
+++ trunk/Source/WTF/wtf/FastCopy.h	2018-02-09 02:13:01 UTC (rev 228306)
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2018 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#pragma once
+
+#include <wtf/StdLibExtras.h>
+
+namespace WTF {
+
+template<typename T>
+void fastCopy(T* dst, const T* src, size_t length)
+{
+#if CPU(X86_64) && COMPILER(GCC_OR_CLANG)
+    uint64_t tmp = 0;
+    size_t count = length * sizeof(T);
+    if (!(sizeof(T) % sizeof(uint64_t))) {
+        asm volatile (
+            "cmpq $200, %%rcx\n\t"
+            "jb 1f\n\t"
+            "shrq $3, %%rcx\n\t"
+            "rep movsq\n\t"
+            "jmp 2f\n\t"
+            "3:\n\t"
+            "movq (%%rsi, %%rcx), %%rax\n\t"
+            "movq %%rax, (%%rdi, %%rcx)\n\t"
+            "1:\n\t"
+            "subq $8, %%rcx\n\t"
+            "jae 3b\n\t"
+            "2:\n\t"
+            : "+D"(dst), "+S"(src), "+c"(count), "+a"(tmp)
+            :
+            : "memory"
+            );
+        return;
+    }
+    if (!(sizeof(T) % sizeof(uint32_t))) {
+        asm volatile (
+            "cmpq $200, %%rcx\n\t"
+            "jb 1f\n\t"
+            "shrq $2, %%rcx\n\t"
+            "rep movsl\n\t"
+            "jmp 2f\n\t"
+            "3:\n\t"
+            "movq (%%rsi, %%rcx), %%rax\n\t"
+            "movq %%rax, (%%rdi, %%rcx)\n\t"
+            "1:\n\t"
+            "subq $8, %%rcx\n\t"
+            "jae 3b\n\t"
+            "cmpq $-8, %%rcx\n\t"
+            "je 2f\n\t"
+            "addq $4, %%rcx\n\t" // FIXME: This isn't really a loop. https://bugs.webkit.org/show_bug.cgi?id=182617
+            "4:\n\t"
+            "movl (%%rsi, %%rcx), %%eax\n\t"
+            "movl %%eax, (%%rdi, %%rcx)\n\t"
+            "subq $4, %%rcx\n\t"
+            "jae 4b\n\t"
+            "2:\n\t"
+            : "+D"(dst), "+S"(src), "+c"(count), "+a"(tmp)
+            :
+            : "memory"
+            );
+        return;
+    }
+    if (!(sizeof(T) % sizeof(uint16_t))) {
+        asm volatile (
+            "cmpq $200, %%rcx\n\t"
+            "jb 1f\n\t"
+            "shrq $1, %%rcx\n\t"
+            "rep movsw\n\t"
+            "jmp 2f\n\t"
+            "3:\n\t"
+            "movq (%%rsi, %%rcx), %%rax\n\t"
+            "movq %%rax, (%%rdi, %%rcx)\n\t"
+            "1:\n\t"
+            "subq $8, %%rcx\n\t"
+            "jae 3b\n\t"
+            "cmpq $-8, %%rcx\n\t"
+            "je 2f\n\t"
+            "addq $6, %%rcx\n\t"
+            "4:\n\t"
+            "movw (%%rsi, %%rcx), %%ax\n\t"
+            "movw %%ax, (%%rdi, %%rcx)\n\t"
+            "subq $2, %%rcx\n\t"
+            "jae 4b\n\t"
+            "2:\n\t"
+            : "+D"(dst), "+S"(src), "+c"(count), "+a"(tmp)
+            :
+            : "memory"
+            );
+        return;
+    }
+    asm volatile (
+        "cmpq $200, %%rcx\n\t"
+        "jb 1f\n\t"
+        "rep movsb\n\t"
+        "jmp 2f\n\t"
+        "3:\n\t"
+        "movq (%%rsi, %%rcx), %%rax\n\t"
+        "movq %%rax, (%%rdi, %%rcx)\n\t"
+        "1:\n\t"
+        "subq $8, %%rcx\n\t"
+        "jae 3b\n\t"
+        "cmpq $-8, %%rcx\n\t"
+        "je 2f\n\t"
+        "addq $7, %%rcx\n\t"
+        "4:\n\t"
+        "movb (%%rsi, %%rcx), %%al\n\t"
+        "movb %%al, (%%rdi, %%rcx)\n\t"
+        "subq $1, %%rcx\n\t"
+        "jae 4b\n\t"
+        "2:\n\t"
+        : "+D"(dst), "+S"(src), "+c"(count), "+a"(tmp)
+        :
+        : "memory"
+        );
+#else
+    memcpy(dst, src, length * sizeof(T));
+#endif
+}
+
+inline void fastCopyBytes(void* dst, const void* src, size_t bytes)
+{
+    fastCopy(static_cast<char*>(dst), static_cast<const char*>(src), bytes);
+}
+
+} // namespace WTF
+
+using WTF::fastCopy;
+using WTF::fastCopyBytes;

Modified: trunk/Source/WTF/wtf/FastMalloc.cpp (228305 => 228306)


--- trunk/Source/WTF/wtf/FastMalloc.cpp	2018-02-09 01:58:23 UTC (rev 228305)
+++ trunk/Source/WTF/wtf/FastMalloc.cpp	2018-02-09 02:13:01 UTC (rev 228306)
@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2005, 2007, Google Inc. All rights reserved.
- * Copyright (C) 2005-2017 Apple Inc. All rights reserved.
+ * Copyright (C) 2005-2018 Apple Inc. All rights reserved.
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
@@ -31,6 +31,8 @@
 #include <limits>
 #include <string.h>
 #include <wtf/DataLog.h>
+#include <wtf/FastCopy.h>
+#include <wtf/FastZeroFill.h>
 
 #if OS(WINDOWS)
 #include <windows.h>
@@ -78,7 +80,7 @@
 void* fastZeroedMalloc(size_t n) 
 {
     void* result = fastMalloc(n);
-    memset(result, 0, n);
+    fastZeroFillBytes(result, n);
     return result;
 }
 
@@ -86,7 +88,7 @@
 {
     size_t len = strlen(src) + 1;
     char* dup = static_cast<char*>(fastMalloc(len));
-    memcpy(dup, src, len);
+    fastCopy(dup, src, len);
     return dup;
 }
 
@@ -95,7 +97,7 @@
     void* result;
     if (!tryFastMalloc(n).getValue(result))
         return 0;
-    memset(result, 0, n);
+    fastZeroFillBytes(result, n);
     return result;
 }
 

Added: trunk/Source/WTF/wtf/FastZeroFill.h (0 => 228306)


--- trunk/Source/WTF/wtf/FastZeroFill.h	                        (rev 0)
+++ trunk/Source/WTF/wtf/FastZeroFill.h	2018-02-09 02:13:01 UTC (rev 228306)
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2018 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#pragma once
+
+#include <wtf/StdLibExtras.h>
+
+namespace WTF {
+
+template<typename T>
+void fastZeroFill(T* dst, size_t length)
+{
+#if CPU(X86_64) && COMPILER(GCC_OR_CLANG)
+    uint64_t zero = 0;
+    size_t count = length * sizeof(T);
+    if (!(sizeof(T) % sizeof(uint64_t))) {
+        asm volatile (
+            "cmpq $200, %%rcx\n\t"
+            "jb 1f\n\t"
+            "shrq $3, %%rcx\n\t"
+            "rep stosq\n\t"
+            "jmp 2f\n\t"
+            "3:\n\t"
+            "movq %%rax, (%%rdi, %%rcx)\n\t"
+            "1:\n\t"
+            "subq $8, %%rcx\n\t"
+            "jae 3b\n\t"
+            "2:\n\t"
+            : "+D"(dst), "+c"(count)
+            : "a"(zero)
+            : "memory"
+            );
+        return;
+    }
+    if (!(sizeof(T) % sizeof(uint32_t))) {
+        asm volatile (
+            "cmpq $200, %%rcx\n\t"
+            "jb 1f\n\t"
+            "shrq $2, %%rcx\n\t"
+            "rep stosl\n\t"
+            "jmp 2f\n\t"
+            "3:\n\t"
+            "movq %%rax, (%%rdi, %%rcx)\n\t"
+            "1:\n\t"
+            "subq $8, %%rcx\n\t"
+            "jae 3b\n\t"
+            "cmpq $-8, %%rcx\n\t"
+            "je 2f\n\t"
+            "addq $4, %%rcx\n\t" // FIXME: This isn't really a loop. https://bugs.webkit.org/show_bug.cgi?id=182617
+            "4:\n\t"
+            "movl %%eax, (%%rdi, %%rcx)\n\t"
+            "subq $4, %%rcx\n\t"
+            "jae 4b\n\t"
+            "2:\n\t"
+            : "+D"(dst), "+c"(count)
+            : "a"(zero)
+            : "memory"
+            );
+        return;
+    }
+    if (!(sizeof(T) % sizeof(uint16_t))) {
+        asm volatile (
+            "cmpq $200, %%rcx\n\t"
+            "jb 1f\n\t"
+            "shrq $1, %%rcx\n\t"
+            "rep stosw\n\t"
+            "jmp 2f\n\t"
+            "3:\n\t"
+            "movq %%rax, (%%rdi, %%rcx)\n\t"
+            "1:\n\t"
+            "subq $8, %%rcx\n\t"
+            "jae 3b\n\t"
+            "cmpq $-8, %%rcx\n\t"
+            "je 2f\n\t"
+            "addq $6, %%rcx\n\t"
+            "4:\n\t"
+            "movw %%ax, (%%rdi, %%rcx)\n\t"
+            "subq $2, %%rcx\n\t"
+            "jae 4b\n\t"
+            "2:\n\t"
+            : "+D"(dst), "+c"(count)
+            : "a"(zero)
+            : "memory"
+            );
+        return;
+    }
+    asm volatile (
+        "cmpq $200, %%rcx\n\t"
+        "jb 1f\n\t"
+        "rep stosb\n\t"
+        "jmp 2f\n\t"
+        "3:\n\t"
+        "movq %%rax, (%%rdi, %%rcx)\n\t"
+        "1:\n\t"
+        "subq $8, %%rcx\n\t"
+        "jae 3b\n\t"
+        "cmpq $-8, %%rcx\n\t"
+        "je 2f\n\t"
+        "addq $7, %%rcx\n\t"
+        "4:\n\t"
+        "movb %%al, (%%rdi, %%rcx)\n\t"
+        "sub $1, %%rcx\n\t"
+        "jae 4b\n\t"
+        "2:\n\t"
+        : "+D"(dst), "+c"(count)
+        : "a"(zero)
+        : "memory"
+        );
+#else
+    memset(dst, 0, length * sizeof(T));
+#endif
+}
+
+inline void fastZeroFillBytes(void* dst, size_t bytes)
+{
+    fastZeroFill(static_cast<char*>(dst), bytes);
+}
+
+} // namespace WTF
+
+using WTF::fastZeroFill;
+using WTF::fastZeroFillBytes;

Modified: trunk/Source/WTF/wtf/OSAllocator.h (228305 => 228306)


--- trunk/Source/WTF/wtf/OSAllocator.h	2018-02-09 01:58:23 UTC (rev 228305)
+++ trunk/Source/WTF/wtf/OSAllocator.h	2018-02-09 02:13:01 UTC (rev 228306)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2010-2018 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -27,6 +27,7 @@
 #define OSAllocator_h
 
 #include <algorithm>
+#include <wtf/FastCopy.h>
 #include <wtf/VMTags.h>
 
 namespace WTF {
@@ -90,7 +91,7 @@
 inline T* OSAllocator::reallocateCommitted(T* oldBase, size_t oldSize, size_t newSize, Usage usage, bool writable, bool executable)
 {
     void* newBase = reserveAndCommit(newSize, usage, writable, executable);
-    memcpy(newBase, oldBase, std::min(oldSize, newSize));
+    fastCopyBytes(newBase, oldBase, std::min(oldSize, newSize));
     decommitAndRelease(oldBase, oldSize);
     return static_cast<T*>(newBase);
 }

Modified: trunk/Source/WTF/wtf/StringPrintStream.cpp (228305 => 228306)


--- trunk/Source/WTF/wtf/StringPrintStream.cpp	2018-02-09 01:58:23 UTC (rev 228305)
+++ trunk/Source/WTF/wtf/StringPrintStream.cpp	2018-02-09 02:13:01 UTC (rev 228306)
@@ -28,6 +28,7 @@
 
 #include <stdarg.h>
 #include <stdio.h>
+#include <wtf/FastCopy.h>
 #include <wtf/FastMalloc.h>
 
 namespace WTF {
@@ -119,7 +120,7 @@
     // fastRealloc will just do malloc+free anyway. Also, this simplifies the code since
     // we can't realloc the inline buffer.
     char* newBuffer = static_cast<char*>(fastMalloc(m_size));
-    memcpy(newBuffer, m_buffer, m_next + 1);
+    fastCopy(newBuffer, m_buffer, m_next + 1);
     if (m_buffer != m_inlineBuffer)
         fastFree(m_buffer);
     m_buffer = newBuffer;

Modified: trunk/Source/WTF/wtf/Vector.h (228305 => 228306)


--- trunk/Source/WTF/wtf/Vector.h	2018-02-09 01:58:23 UTC (rev 228305)
+++ trunk/Source/WTF/wtf/Vector.h	2018-02-09 02:13:01 UTC (rev 228306)
@@ -27,7 +27,9 @@
 #include <type_traits>
 #include <utility>
 #include <wtf/CheckedArithmetic.h>
+#include <wtf/FastCopy.h>
 #include <wtf/FastMalloc.h>
+#include <wtf/FastZeroFill.h>
 #include <wtf/Forward.h>
 #include <wtf/MallocPtr.h>
 #include <wtf/MathExtras.h>
@@ -86,7 +88,7 @@
 {
     static void initialize(T* begin, T* end) 
     {
-        memset(begin, 0, reinterpret_cast<char*>(end) - reinterpret_cast<char*>(begin));
+        fastZeroFill(begin, end - begin);
     }
 };
 
@@ -126,7 +128,7 @@
 {
     static void move(const T* src, const T* srcEnd, T* dst) 
     {
-        memcpy(dst, src, reinterpret_cast<const char*>(srcEnd) - reinterpret_cast<const char*>(src));
+        fastCopy(dst, src, srcEnd - src);
     }
     static void moveOverlapping(const T* src, const T* srcEnd, T* dst) 
     {

Modified: trunk/Source/WTF/wtf/persistence/PersistentDecoder.cpp (228305 => 228306)


--- trunk/Source/WTF/wtf/persistence/PersistentDecoder.cpp	2018-02-09 01:58:23 UTC (rev 228305)
+++ trunk/Source/WTF/wtf/persistence/PersistentDecoder.cpp	2018-02-09 02:13:01 UTC (rev 228306)
@@ -52,7 +52,7 @@
     if (!bufferIsLargeEnoughToContain(size))
         return false;
 
-    memcpy(data, m_bufferPosition, size);
+    fastCopy(data, m_bufferPosition, size);
     m_bufferPosition += size;
 
     Encoder::updateChecksumForData(m_sha1, data, size);

Modified: trunk/Source/WTF/wtf/persistence/PersistentEncoder.cpp (228305 => 228306)


--- trunk/Source/WTF/wtf/persistence/PersistentEncoder.cpp	2018-02-09 01:58:23 UTC (rev 228305)
+++ trunk/Source/WTF/wtf/persistence/PersistentEncoder.cpp	2018-02-09 02:13:01 UTC (rev 228306)
@@ -58,7 +58,7 @@
     updateChecksumForData(m_sha1, data, size);
 
     uint8_t* buffer = grow(size);
-    memcpy(buffer, data, size);
+    fastCopy(buffer, data, size);
 }
 
 template<typename Type>

Modified: trunk/Source/WTF/wtf/text/CString.cpp (228305 => 228306)


--- trunk/Source/WTF/wtf/text/CString.cpp	2018-02-09 01:58:23 UTC (rev 228305)
+++ trunk/Source/WTF/wtf/text/CString.cpp	2018-02-09 02:13:01 UTC (rev 228306)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2003-2017 Apple Inc. All rights reserved.
+ * Copyright (C) 2003-2018 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -28,6 +28,7 @@
 #include "CString.h"
 
 #include <string.h>
+#include <wtf/FastCopy.h>
 #include <wtf/text/StringHasher.h>
 #include <wtf/text/StringMalloc.h>
 
@@ -66,7 +67,7 @@
     ASSERT(str);
 
     m_buffer = CStringBuffer::createUninitialized(length);
-    memcpy(m_buffer->mutableData(), str, length); 
+    fastCopy(m_buffer->mutableData(), str, length); 
     m_buffer->mutableData()[length] = '\0';
 }
 
@@ -96,7 +97,7 @@
     RefPtr<CStringBuffer> buffer = WTFMove(m_buffer);
     size_t length = buffer->length();
     m_buffer = CStringBuffer::createUninitialized(length);
-    memcpy(m_buffer->mutableData(), buffer->data(), length + 1);
+    fastCopy(m_buffer->mutableData(), buffer->data(), length + 1);
 }
 
 bool CString::isSafeToSendToAnotherThread() const

Modified: trunk/Source/WTF/wtf/text/LineBreakIteratorPoolICU.h (228305 => 228306)


--- trunk/Source/WTF/wtf/text/LineBreakIteratorPoolICU.h	2018-02-09 01:58:23 UTC (rev 228305)
+++ trunk/Source/WTF/wtf/text/LineBreakIteratorPoolICU.h	2018-02-09 02:13:01 UTC (rev 228306)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011 Apple Inc. All Rights Reserved.
+ * Copyright (C) 2011-2018 Apple Inc. All Rights Reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -26,6 +26,8 @@
 #pragma once
 
 #include <unicode/uloc.h>
+#include <wtf/FastCopy.h>
+#include <wtf/FastZeroFill.h>
 #include <wtf/HashMap.h>
 #include <wtf/NeverDestroyed.h>
 #include <wtf/ThreadSpecific.h>
@@ -51,7 +53,7 @@
         if (!utf8Locale.length())
             return locale;
         Vector<char> scratchBuffer(utf8Locale.length() + 11, 0);
-        memcpy(scratchBuffer.data(), utf8Locale.data(), utf8Locale.length());
+        fastCopy(scratchBuffer.data(), utf8Locale.data(), utf8Locale.length());
 
         const char* keywordValue = nullptr;
         switch (mode) {
@@ -75,7 +77,7 @@
             return AtomicString::fromUTF8(scratchBuffer.data(), lengthNeeded);
         if (status == U_BUFFER_OVERFLOW_ERROR) {
             scratchBuffer.grow(lengthNeeded + 1);
-            memset(scratchBuffer.data() + utf8Locale.length(), 0, scratchBuffer.size() - utf8Locale.length());
+            fastZeroFill(scratchBuffer.data() + utf8Locale.length(), scratchBuffer.size() - utf8Locale.length());
             status = U_ZERO_ERROR;
             int32_t lengthNeeded2 = uloc_setKeywordValue("lb", keywordValue, scratchBuffer.data(), scratchBuffer.size(), &status);
             if (!U_SUCCESS(status) || lengthNeeded != lengthNeeded2)

Modified: trunk/Source/WTF/wtf/text/StringBuilder.cpp (228305 => 228306)


--- trunk/Source/WTF/wtf/text/StringBuilder.cpp	2018-02-09 01:58:23 UTC (rev 228305)
+++ trunk/Source/WTF/wtf/text/StringBuilder.cpp	2018-02-09 02:13:01 UTC (rev 228306)
@@ -99,7 +99,7 @@
     ASSERT(m_is8Bit);
     // Copy the existing data into a new buffer, set result to point to the end of the existing data.
     auto buffer = StringImpl::createUninitialized(requiredLength, m_bufferCharacters8);
-    memcpy(m_bufferCharacters8, currentCharacters, static_cast<size_t>(m_length) * sizeof(LChar)); // This can't overflow.
+    fastCopy(m_bufferCharacters8, currentCharacters, m_length);
     
     // Update the builder state.
     m_buffer = WTFMove(buffer);
@@ -114,7 +114,7 @@
     ASSERT(!m_is8Bit);
     // Copy the existing data into a new buffer, set result to point to the end of the existing data.
     auto buffer = StringImpl::createUninitialized(requiredLength, m_bufferCharacters16);
-    memcpy(m_bufferCharacters16, currentCharacters, static_cast<size_t>(m_length) * sizeof(UChar)); // This can't overflow.
+    fastCopy(m_bufferCharacters16, currentCharacters, m_length);
     
     // Update the builder state.
     m_buffer = WTFMove(buffer);
@@ -276,10 +276,10 @@
             allocateBufferUpConvert(m_string.isNull() ? 0 : m_string.characters8(), expandedCapacity(capacity(), requiredLength));
         }
 
-        memcpy(m_bufferCharacters16 + m_length, characters, static_cast<size_t>(length) * sizeof(UChar));
+        fastCopy(m_bufferCharacters16 + m_length, characters, length);
         m_length = requiredLength;
     } else
-        memcpy(appendUninitialized<UChar>(length), characters, static_cast<size_t>(length) * sizeof(UChar));
+        fastCopy(appendUninitialized<UChar>(length), characters, length);
     ASSERT(m_buffer->length() >= m_length);
 }
 
@@ -291,13 +291,7 @@
 
     if (m_is8Bit) {
         LChar* dest = appendUninitialized<LChar>(length);
-        if (length > 8)
-            memcpy(dest, characters, static_cast<size_t>(length) * sizeof(LChar));
-        else {
-            const LChar* end = characters + length;
-            while (characters < end)
-                *(dest++) = *(characters++);
-        }
+        fastCopy(dest, characters, length);
     } else {
         UChar* dest = appendUninitialized<UChar>(length);
         const LChar* end = characters + length;

Modified: trunk/Source/WTF/wtf/text/StringConcatenate.h (228305 => 228306)


--- trunk/Source/WTF/wtf/text/StringConcatenate.h	2018-02-09 01:58:23 UTC (rev 228305)
+++ trunk/Source/WTF/wtf/text/StringConcatenate.h	2018-02-09 02:13:01 UTC (rev 228306)
@@ -27,6 +27,7 @@
 #define StringConcatenate_h
 
 #include <string.h>
+#include <wtf/FastCopy.h>
 
 #ifndef AtomicString_h
 #include <wtf/text/AtomicString.h>
@@ -157,7 +158,7 @@
 
     void writeTo(UChar* destination) const
     {
-        memcpy(destination, m_characters, m_length * sizeof(UChar));
+        fastCopy(destination, m_characters, m_length);
     }
 
     String toString() const { return String(m_characters, m_length); }

Modified: trunk/Source/WTF/wtf/text/StringImpl.h (228305 => 228306)


--- trunk/Source/WTF/wtf/text/StringImpl.h	2018-02-09 01:58:23 UTC (rev 228305)
+++ trunk/Source/WTF/wtf/text/StringImpl.h	2018-02-09 02:13:01 UTC (rev 228306)
@@ -1066,7 +1066,7 @@
         *destination = *source;
         return;
     }
-    memcpy(destination, source, numCharacters * sizeof(CharacterType));
+    fastCopy(destination, source, numCharacters);
 }
 
 ALWAYS_INLINE void StringImpl::copyCharacters(UChar* destination, const LChar* source, unsigned numCharacters)

Modified: trunk/Source/WTF/wtf/text/icu/UTextProvider.cpp (228305 => 228306)


--- trunk/Source/WTF/wtf/text/icu/UTextProvider.cpp	2018-02-09 01:58:23 UTC (rev 228305)
+++ trunk/Source/WTF/wtf/text/icu/UTextProvider.cpp	2018-02-09 02:13:01 UTC (rev 228306)
@@ -28,6 +28,7 @@
 
 #include <algorithm>
 #include <string.h>
+#include <wtf/FastCopy.h>
 
 namespace WTF {
 
@@ -55,10 +56,10 @@
     void* extraNew = destination->pExtra;
     int32_t flags = destination->flags;
     int sizeToCopy = std::min(source->sizeOfStruct, destination->sizeOfStruct);
-    memcpy(destination, source, sizeToCopy);
+    fastCopyBytes(destination, source, sizeToCopy);
     destination->pExtra = extraNew;
     destination->flags = flags;
-    memcpy(destination->pExtra, source->pExtra, extraSize);
+    fastCopyBytes(destination->pExtra, source->pExtra, extraSize);
     fixPointer(source, destination, destination->context);
     fixPointer(source, destination, destination->p);
     fixPointer(source, destination, destination->q);

Modified: trunk/Source/WTF/wtf/text/icu/UTextProviderLatin1.cpp (228305 => 228306)


--- trunk/Source/WTF/wtf/text/icu/UTextProviderLatin1.cpp	2018-02-09 01:58:23 UTC (rev 228305)
+++ trunk/Source/WTF/wtf/text/icu/UTextProviderLatin1.cpp	2018-02-09 02:13:01 UTC (rev 228306)
@@ -27,6 +27,7 @@
 #include "UTextProviderLatin1.h"
 
 #include "UTextProvider.h"
+#include <wtf/FastZeroFill.h>
 #include <wtf/text/StringImpl.h>
 
 namespace WTF {
@@ -82,7 +83,7 @@
     result->a = source->a;
     result->pFuncs = &uTextLatin1Funcs;
     result->chunkContents = (UChar*)result->pExtra;
-    memset(const_cast<UChar*>(result->chunkContents), 0, sizeof(UChar) * UTextWithBufferInlineCapacity);
+    fastZeroFill(const_cast<UChar*>(result->chunkContents), UTextWithBufferInlineCapacity);
 
     return result;
 }
@@ -228,7 +229,7 @@
     text->a = length;
     text->pFuncs = &uTextLatin1Funcs;
     text->chunkContents = (UChar*)text->pExtra;
-    memset(const_cast<UChar*>(text->chunkContents), 0, sizeof(UChar) * UTextWithBufferInlineCapacity);
+    fastZeroFill(const_cast<UChar*>(text->chunkContents), UTextWithBufferInlineCapacity);
 
     return text;
 }

Modified: trunk/Source/WTF/wtf/threads/Signals.cpp (228305 => 228306)


--- trunk/Source/WTF/wtf/threads/Signals.cpp	2018-02-09 01:58:23 UTC (rev 228305)
+++ trunk/Source/WTF/wtf/threads/Signals.cpp	2018-02-09 02:13:01 UTC (rev 228306)
@@ -172,7 +172,7 @@
     Signal signal = fromMachException(exceptionType);
     RELEASE_ASSERT(signal != Signal::Unknown);
 
-    memcpy(outState, inState, inStateCount * sizeof(inState[0]));
+    fastCopy(outState, inState, inStateCount);
     *outStateCount = inStateCount;
 
 #if CPU(X86_64)

Modified: trunk/Source/bmalloc/ChangeLog (228305 => 228306)


--- trunk/Source/bmalloc/ChangeLog	2018-02-09 01:58:23 UTC (rev 228305)
+++ trunk/Source/bmalloc/ChangeLog	2018-02-09 02:13:01 UTC (rev 228306)
@@ -1,3 +1,28 @@
+2018-02-08  Filip Pizlo  <[email protected]>
+
+        Experiment with alternative implementation of memcpy/memset
+        https://bugs.webkit.org/show_bug.cgi?id=182563
+
+        Reviewed by Michael Saboff and Mark Lam.
+        
+        Add a faster x86_64-specific implementation of memcpy and memset. Ideally, this would just be
+        implemented in WTF, but we have to copy it into bmalloc since bmalloc sits below WTF on the
+        stack.
+
+        * bmalloc/Algorithm.h:
+        (bmalloc::fastCopy):
+        (bmalloc::fastZeroFill):
+        * bmalloc/Allocator.cpp:
+        (bmalloc::Allocator::reallocate):
+        * bmalloc/Bits.h:
+        (bmalloc::BitsWordOwner::operator=):
+        (bmalloc::BitsWordOwner::clearAll):
+        (bmalloc::BitsWordOwner::set):
+        * bmalloc/IsoPageInlines.h:
+        (bmalloc::IsoPage<Config>::IsoPage):
+        * bmalloc/Vector.h:
+        (bmalloc::Vector<T>::reallocateBuffer):
+
 2018-02-05  JF Bastien  <[email protected]>
 
         Gigacage: enable only for WebContent process and token executables

Modified: trunk/Source/bmalloc/bmalloc/Algorithm.h (228305 => 228306)


--- trunk/Source/bmalloc/bmalloc/Algorithm.h	2018-02-09 01:58:23 UTC (rev 228305)
+++ trunk/Source/bmalloc/bmalloc/Algorithm.h	2018-02-09 02:13:01 UTC (rev 228306)
@@ -180,6 +180,221 @@
     return false;
 }
 
+template<typename T>
+void fastCopy(T* dst, T* src, size_t length)
+{
+#if BCPU(X86_64)
+    uint64_t tmp = 0;
+    size_t count = length * sizeof(T);
+    if (!(sizeof(T) % sizeof(uint64_t))) {
+        asm volatile (
+            "cmpq $200, %%rcx\n\t"
+            "jb 1f\n\t"
+            "shrq $3, %%rcx\n\t"
+            "rep movsq\n\t"
+            "jmp 2f\n\t"
+            "3:\n\t"
+            "movq (%%rsi, %%rcx), %%rax\n\t"
+            "movq %%rax, (%%rdi, %%rcx)\n\t"
+            "1:\n\t"
+            "subq $8, %%rcx\n\t"
+            "jae 3b\n\t"
+            "2:\n\t"
+            : "+D"(dst), "+S"(src), "+c"(count), "+a"(tmp)
+            :
+            : "memory"
+            );
+        return;
+    }
+    if (!(sizeof(T) % sizeof(uint32_t))) {
+        asm volatile (
+            "cmpq $200, %%rcx\n\t"
+            "jb 1f\n\t"
+            "shrq $2, %%rcx\n\t"
+            "rep movsl\n\t"
+            "jmp 2f\n\t"
+            "3:\n\t"
+            "movq (%%rsi, %%rcx), %%rax\n\t"
+            "movq %%rax, (%%rdi, %%rcx)\n\t"
+            "1:\n\t"
+            "subq $8, %%rcx\n\t"
+            "jae 3b\n\t"
+            "cmpq $-8, %%rcx\n\t"
+            "je 2f\n\t"
+            "addq $4, %%rcx\n\t" // FIXME: This isn't really a loop. https://bugs.webkit.org/show_bug.cgi?id=182617
+            "4:\n\t"
+            "movl (%%rsi, %%rcx), %%eax\n\t"
+            "movl %%eax, (%%rdi, %%rcx)\n\t"
+            "subq $4, %%rcx\n\t"
+            "jae 4b\n\t"
+            "2:\n\t"
+            : "+D"(dst), "+S"(src), "+c"(count), "+a"(tmp)
+            :
+            : "memory"
+            );
+        return;
+    }
+    if (!(sizeof(T) % sizeof(uint16_t))) {
+        asm volatile (
+            "cmpq $200, %%rcx\n\t"
+            "jb 1f\n\t"
+            "shrq $1, %%rcx\n\t"
+            "rep movsw\n\t"
+            "jmp 2f\n\t"
+            "3:\n\t"
+            "movq (%%rsi, %%rcx), %%rax\n\t"
+            "movq %%rax, (%%rdi, %%rcx)\n\t"
+            "1:\n\t"
+            "subq $8, %%rcx\n\t"
+            "jae 3b\n\t"
+            "cmpq $-8, %%rcx\n\t"
+            "je 2f\n\t"
+            "addq $6, %%rcx\n\t"
+            "4:\n\t"
+            "movw (%%rsi, %%rcx), %%ax\n\t"
+            "movw %%ax, (%%rdi, %%rcx)\n\t"
+            "subq $2, %%rcx\n\t"
+            "jae 4b\n\t"
+            "2:\n\t"
+            : "+D"(dst), "+S"(src), "+c"(count), "+a"(tmp)
+            :
+            : "memory"
+            );
+        return;
+    }
+    asm volatile (
+        "cmpq $200, %%rcx\n\t"
+        "jb 1f\n\t"
+        "rep movsb\n\t"
+        "jmp 2f\n\t"
+        "3:\n\t"
+        "movq (%%rsi, %%rcx), %%rax\n\t"
+        "movq %%rax, (%%rdi, %%rcx)\n\t"
+        "1:\n\t"
+        "subq $8, %%rcx\n\t"
+        "jae 3b\n\t"
+        "cmpq $-8, %%rcx\n\t"
+        "je 2f\n\t"
+        "addq $7, %%rcx\n\t"
+        "4:\n\t"
+        "movb (%%rsi, %%rcx), %%al\n\t"
+        "movb %%al, (%%rdi, %%rcx)\n\t"
+        "subq $1, %%rcx\n\t"
+        "jae 4b\n\t"
+        "2:\n\t"
+        : "+D"(dst), "+S"(src), "+c"(count), "+a"(tmp)
+        :
+        : "memory"
+        );
+#else
+    memcpy(dst, src, length * sizeof(T));
+#endif
+}
+
+template<typename T>
+void fastZeroFill(T* dst, size_t length)
+{
+#if BCPU(X86_64)
+    uint64_t zero = 0;
+    size_t count = length * sizeof(T);
+    if (!(sizeof(T) % sizeof(uint64_t))) {
+        asm volatile (
+            "cmpq $200, %%rcx\n\t"
+            "jb 1f\n\t"
+            "shrq $3, %%rcx\n\t"
+            "rep stosq\n\t"
+            "jmp 2f\n\t"
+            "3:\n\t"
+            "movq %%rax, (%%rdi, %%rcx)\n\t"
+            "1:\n\t"
+            "subq $8, %%rcx\n\t"
+            "jae 3b\n\t"
+            "2:\n\t"
+            : "+D"(dst), "+c"(count)
+            : "a"(zero)
+            : "memory"
+            );
+        return;
+    }
+    if (!(sizeof(T) % sizeof(uint32_t))) {
+        asm volatile (
+            "cmpq $200, %%rcx\n\t"
+            "jb 1f\n\t"
+            "shrq $2, %%rcx\n\t"
+            "rep stosl\n\t"
+            "jmp 2f\n\t"
+            "3:\n\t"
+            "movq %%rax, (%%rdi, %%rcx)\n\t"
+            "1:\n\t"
+            "subq $8, %%rcx\n\t"
+            "jae 3b\n\t"
+            "cmpq $-8, %%rcx\n\t"
+            "je 2f\n\t"
+            "addq $4, %%rcx\n\t" // FIXME: This isn't really a loop. https://bugs.webkit.org/show_bug.cgi?id=182617
+            "4:\n\t"
+            "movl %%eax, (%%rdi, %%rcx)\n\t"
+            "subq $4, %%rcx\n\t"
+            "jae 4b\n\t"
+            "2:\n\t"
+            : "+D"(dst), "+c"(count)
+            : "a"(zero)
+            : "memory"
+            );
+        return;
+    }
+    if (!(sizeof(T) % sizeof(uint16_t))) {
+        asm volatile (
+            "cmpq $200, %%rcx\n\t"
+            "jb 1f\n\t"
+            "shrq $1, %%rcx\n\t"
+            "rep stosw\n\t"
+            "jmp 2f\n\t"
+            "3:\n\t"
+            "movq %%rax, (%%rdi, %%rcx)\n\t"
+            "1:\n\t"
+            "subq $8, %%rcx\n\t"
+            "jae 3b\n\t"
+            "cmpq $-8, %%rcx\n\t"
+            "je 2f\n\t"
+            "addq $6, %%rcx\n\t"
+            "4:\n\t"
+            "movw %%ax, (%%rdi, %%rcx)\n\t"
+            "subq $2, %%rcx\n\t"
+            "jae 4b\n\t"
+            "2:\n\t"
+            : "+D"(dst), "+c"(count)
+            : "a"(zero)
+            : "memory"
+            );
+        return;
+    }
+    asm volatile (
+        "cmpq $200, %%rcx\n\t"
+        "jb 1f\n\t"
+        "rep stosb\n\t"
+        "jmp 2f\n\t"
+        "3:\n\t"
+        "movq %%rax, (%%rdi, %%rcx)\n\t"
+        "1:\n\t"
+        "subq $8, %%rcx\n\t"
+        "jae 3b\n\t"
+        "cmpq $-8, %%rcx\n\t"
+        "je 2f\n\t"
+        "addq $7, %%rcx\n\t"
+        "4:\n\t"
+        "movb %%al, (%%rdi, %%rcx)\n\t"
+        "sub $1, %%rcx\n\t"
+        "jae 4b\n\t"
+        "2:\n\t"
+        : "+D"(dst), "+c"(count)
+        : "a"(zero)
+        : "memory"
+        );
+#else
+    memset(dst, 0, length * sizeof(T));
+#endif
+}
+
 } // namespace bmalloc
 
 #endif // Algorithm_h

Modified: trunk/Source/bmalloc/bmalloc/Allocator.cpp (228305 => 228306)


--- trunk/Source/bmalloc/bmalloc/Allocator.cpp	2018-02-09 01:58:23 UTC (rev 228305)
+++ trunk/Source/bmalloc/bmalloc/Allocator.cpp	2018-02-09 02:13:01 UTC (rev 228306)
@@ -125,7 +125,7 @@
 
     void* result = allocate(newSize);
     size_t copySize = std::min(oldSize, newSize);
-    memcpy(result, object, copySize);
+    fastCopy(static_cast<char*>(result), static_cast<char*>(object), copySize);
     m_deallocator.deallocate(object);
     return result;
 }

Modified: trunk/Source/bmalloc/bmalloc/Bits.h (228305 => 228306)


--- trunk/Source/bmalloc/bmalloc/Bits.h	2018-02-09 01:58:23 UTC (rev 228305)
+++ trunk/Source/bmalloc/bmalloc/Bits.h	2018-02-09 02:13:01 UTC (rev 228306)
@@ -80,7 +80,7 @@
     
     BitsWordOwner& operator=(const BitsWordOwner& other)
     {
-        memcpy(m_words, other.m_words, arrayLength() * sizeof(uint32_t));
+        fastCopy(m_words, other.m_words, arrayLength());
         return *this;
     }
     
@@ -91,12 +91,12 @@
     
     void clearAll()
     {
-        memset(m_words, 0, arrayLength() * sizeof(uint32_t));
+        fastZeroFill(m_words, arrayLength());
     }
     
     void set(const BitsWordOwner& other)
     {
-        memcpy(m_words, other.m_words, arrayLength() * sizeof(uint32_t));
+        fastCopy(m_words, other.m_words, arrayLength());
     }
     
     size_t numBits() const

Modified: trunk/Source/bmalloc/bmalloc/IsoPageInlines.h (228305 => 228306)


--- trunk/Source/bmalloc/bmalloc/IsoPageInlines.h	2018-02-09 01:58:23 UTC (rev 228305)
+++ trunk/Source/bmalloc/bmalloc/IsoPageInlines.h	2018-02-09 02:13:01 UTC (rev 228306)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 Apple Inc. All rights reserved.
+ * Copyright (C) 2017-2018 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -47,7 +47,7 @@
     : m_directory(directory)
     , m_index(index)
 {
-    memset(m_allocBits, 0, sizeof(m_allocBits));
+    fastZeroFill(m_allocBits, bitsArrayLength(numObjects));
 }
 
 template<typename Config>

Modified: trunk/Source/bmalloc/bmalloc/Vector.h (228305 => 228306)


--- trunk/Source/bmalloc/bmalloc/Vector.h	2018-02-09 01:58:23 UTC (rev 228305)
+++ trunk/Source/bmalloc/bmalloc/Vector.h	2018-02-09 02:13:01 UTC (rev 228306)
@@ -203,7 +203,7 @@
     size_t vmSize = bmalloc::vmSize(newCapacity * sizeof(T));
     T* newBuffer = vmSize ? static_cast<T*>(vmAllocate(vmSize)) : nullptr;
     if (m_buffer) {
-        std::memcpy(newBuffer, m_buffer, m_size * sizeof(T));
+        fastCopy(newBuffer, m_buffer, m_size);
         vmDeallocate(m_buffer, bmalloc::vmSize(m_capacity * sizeof(T)));
     }
 
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to