Strings need to be in some kind of gigacage
authorfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 30 Aug 2017 17:46:55 +0000 (17:46 +0000)
committerfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 30 Aug 2017 17:46:55 +0000 (17:46 +0000)
https://bugs.webkit.org/show_bug.cgi?id=174924

Reviewed by Oliver Hunt.
Source/bmalloc:

This adds a StringGigacage.

* bmalloc/Gigacage.cpp:
* bmalloc/Gigacage.h:
(Gigacage::name):
(Gigacage::basePtr):
(Gigacage::forEachKind):
* bmalloc/HeapKind.h:
(bmalloc::isGigacage):
(bmalloc::gigacageKind):
(bmalloc::heapKind):

Source/JavaScriptCore:

* runtime/JSString.cpp:
(JSC::JSRopeString::resolveRopeToAtomicString const):
(JSC::JSRopeString::resolveRope const):
* runtime/JSString.h:
(JSC::JSString::create):
(JSC::JSString::createHasOtherOwner):
* runtime/JSStringBuilder.h:
* runtime/VM.h:
(JSC::VM::gigacageAuxiliarySpace):

Source/WebCore:

No new tests because no new behavior.

* html/canvas/CanvasRenderingContext2D.cpp:
(WebCore::normalizeSpaces):

Source/WTF:

This makes all strings allocations come from the string gigacage. Because we expect string allocation
to be a hot path, I created specialized allocation paths for the string gigacage. These paths are
accessible via <wtf/text/StringMalloc.h>. However, those paths are equivalent to saying
Gigacage::malloc and friends with the Gigacage::String kind.

* WTF.xcodeproj/project.pbxproj:
* wtf/CMakeLists.txt:
* wtf/Deque.h:
* wtf/FastMalloc.cpp:
(WTF::fastFree):
* wtf/FastMalloc.h:
(WTF::FastMalloc::malloc):
(WTF::FastMalloc::tryMalloc):
(WTF::FastMalloc::realloc):
(WTF::FastMalloc::free):
* wtf/Forward.h:
* wtf/Gigacage.cpp:
(Gigacage::tryMalloc):
* wtf/Gigacage.h:
(Gigacage::name):
* wtf/Vector.h:
(WTF::VectorBufferBase::allocateBuffer):
(WTF::VectorBufferBase::tryAllocateBuffer):
(WTF::VectorBufferBase::reallocateBuffer):
(WTF::VectorBufferBase::deallocateBuffer):
(WTF::Malloc>::Vector):
(WTF::=):
(WTF::Malloc>::contains const):
(WTF::Malloc>::findMatching const):
(WTF::Malloc>::find const):
(WTF::Malloc>::reverseFind const):
(WTF::Malloc>::appendIfNotContains):
(WTF::Malloc>::fill):
(WTF::Malloc>::appendRange):
(WTF::Malloc>::expandCapacity):
(WTF::Malloc>::tryExpandCapacity):
(WTF::Malloc>::resize):
(WTF::Malloc>::resizeToFit):
(WTF::Malloc>::shrink):
(WTF::Malloc>::grow):
(WTF::Malloc>::asanSetInitialBufferSizeTo):
(WTF::Malloc>::asanSetBufferSizeToFullCapacity):
(WTF::Malloc>::asanBufferSizeWillChangeTo):
(WTF::Malloc>::reserveCapacity):
(WTF::Malloc>::tryReserveCapacity):
(WTF::Malloc>::reserveInitialCapacity):
(WTF::Malloc>::shrinkCapacity):
(WTF::Malloc>::append):
(WTF::Malloc>::tryAppend):
(WTF::Malloc>::constructAndAppend):
(WTF::Malloc>::tryConstructAndAppend):
(WTF::Malloc>::appendSlowCase):
(WTF::Malloc>::constructAndAppendSlowCase):
(WTF::Malloc>::tryConstructAndAppendSlowCase):
(WTF::Malloc>::uncheckedAppend):
(WTF::Malloc>::appendVector):
(WTF::Malloc>::insert):
(WTF::Malloc>::insertVector):
(WTF::Malloc>::remove):
(WTF::Malloc>::removeFirst):
(WTF::Malloc>::removeFirstMatching):
(WTF::Malloc>::removeAll):
(WTF::Malloc>::removeAllMatching):
(WTF::Malloc>::reverse):
(WTF::Malloc>::map const):
(WTF::Malloc>::releaseBuffer):
(WTF::Malloc>::checkConsistency):
(WTF::swap):
(WTF::operator==):
(WTF::operator!=):
(WTF::removeRepeatedElements):
(WTF::minCapacity>::Vector): Deleted.
(WTF::minCapacity>::contains const): Deleted.
(WTF::minCapacity>::findMatching const): Deleted.
(WTF::minCapacity>::find const): Deleted.
(WTF::minCapacity>::reverseFind const): Deleted.
(WTF::minCapacity>::appendIfNotContains): Deleted.
(WTF::minCapacity>::fill): Deleted.
(WTF::minCapacity>::appendRange): Deleted.
(WTF::minCapacity>::expandCapacity): Deleted.
(WTF::minCapacity>::tryExpandCapacity): Deleted.
(WTF::minCapacity>::resize): Deleted.
(WTF::minCapacity>::resizeToFit): Deleted.
(WTF::minCapacity>::shrink): Deleted.
(WTF::minCapacity>::grow): Deleted.
(WTF::minCapacity>::asanSetInitialBufferSizeTo): Deleted.
(WTF::minCapacity>::asanSetBufferSizeToFullCapacity): Deleted.
(WTF::minCapacity>::asanBufferSizeWillChangeTo): Deleted.
(WTF::minCapacity>::reserveCapacity): Deleted.
(WTF::minCapacity>::tryReserveCapacity): Deleted.
(WTF::minCapacity>::reserveInitialCapacity): Deleted.
(WTF::minCapacity>::shrinkCapacity): Deleted.
(WTF::minCapacity>::append): Deleted.
(WTF::minCapacity>::tryAppend): Deleted.
(WTF::minCapacity>::constructAndAppend): Deleted.
(WTF::minCapacity>::tryConstructAndAppend): Deleted.
(WTF::minCapacity>::appendSlowCase): Deleted.
(WTF::minCapacity>::constructAndAppendSlowCase): Deleted.
(WTF::minCapacity>::tryConstructAndAppendSlowCase): Deleted.
(WTF::minCapacity>::uncheckedAppend): Deleted.
(WTF::minCapacity>::appendVector): Deleted.
(WTF::minCapacity>::insert): Deleted.
(WTF::minCapacity>::insertVector): Deleted.
(WTF::minCapacity>::remove): Deleted.
(WTF::minCapacity>::removeFirst): Deleted.
(WTF::minCapacity>::removeFirstMatching): Deleted.
(WTF::minCapacity>::removeAll): Deleted.
(WTF::minCapacity>::removeAllMatching): Deleted.
(WTF::minCapacity>::reverse): Deleted.
(WTF::minCapacity>::map const): Deleted.
(WTF::minCapacity>::releaseBuffer): Deleted.
(WTF::minCapacity>::checkConsistency): Deleted.
* wtf/text/AtomicStringImpl.h:
* wtf/text/CString.cpp:
(WTF::CStringBuffer::createUninitialized):
* wtf/text/CString.h:
* wtf/text/StringBuffer.h:
(WTF::StringBuffer::StringBuffer):
(WTF::StringBuffer::~StringBuffer):
(WTF::StringBuffer::resize):
* wtf/text/StringImpl.cpp:
(WTF::StringImpl::~StringImpl):
(WTF::StringImpl::destroy):
(WTF::StringImpl::createUninitializedInternalNonEmpty):
(WTF::StringImpl::reallocateInternal):
(WTF::StringImpl::releaseAssertCaged const):
* wtf/text/StringImpl.h:
(WTF::StringImpl::createSubstringSharingImpl):
(WTF::StringImpl::tryCreateUninitialized):
(WTF::StringImpl::adopt):
(WTF::StringImpl::bufferOwnership const):
(WTF::StringImpl::assertCaged const):
* wtf/text/StringMalloc.cpp: Added.
(WTF::tryStringMalloc):
(WTF::stringMalloc):
(WTF::stringRealloc):
(WTF::stringFree):
* wtf/text/StringMalloc.h: Added.
(WTF::StringMalloc::malloc):
(WTF::StringMalloc::tryMalloc):
(WTF::StringMalloc::realloc):
(WTF::StringMalloc::free):
* wtf/text/StringVector.h: Added.
* wtf/text/SymbolImpl.h:
* wtf/text/UniquedStringImpl.h:
* wtf/text/WTFString.h:
(WTF::String::adopt):
(WTF::String::assertCaged const):
(WTF::String::releaseAssertCaged const):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@221384 268f45cc-cd09-0410-ab3c-d52691b4dbfc

42 files changed:
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/runtime/JSString.cpp
Source/JavaScriptCore/runtime/JSString.h
Source/JavaScriptCore/runtime/JSStringBuilder.h
Source/JavaScriptCore/runtime/VM.h
Source/WTF/ChangeLog
Source/WTF/WTF.xcodeproj/project.pbxproj
Source/WTF/wtf/CMakeLists.txt
Source/WTF/wtf/Deque.h
Source/WTF/wtf/FastMalloc.h
Source/WTF/wtf/Forward.h
Source/WTF/wtf/Gigacage.cpp
Source/WTF/wtf/Gigacage.h
Source/WTF/wtf/Vector.h
Source/WTF/wtf/text/AtomicStringImpl.h
Source/WTF/wtf/text/CString.cpp
Source/WTF/wtf/text/CString.h
Source/WTF/wtf/text/StringBuffer.h
Source/WTF/wtf/text/StringImpl.cpp
Source/WTF/wtf/text/StringImpl.h
Source/WTF/wtf/text/StringMalloc.cpp [new file with mode: 0644]
Source/WTF/wtf/text/StringMalloc.h [new file with mode: 0644]
Source/WTF/wtf/text/StringVector.h [new file with mode: 0644]
Source/WTF/wtf/text/SymbolImpl.h
Source/WTF/wtf/text/UniquedStringImpl.h
Source/WTF/wtf/text/WTFString.h
Source/WebCore/ChangeLog
Source/WebCore/Modules/indexeddb/server/IDBSerialization.cpp
Source/WebCore/bindings/js/SerializedScriptValue.cpp
Source/WebCore/html/canvas/CanvasRenderingContext2D.cpp
Source/WebCore/html/parser/HTMLTreeBuilder.cpp
Source/WebCore/platform/URLParser.cpp
Source/WebCore/platform/URLParser.h
Source/WebCore/platform/graphics/FourCC.cpp
Source/WebCore/platform/graphics/ca/GraphicsLayerCA.cpp
Source/WebCore/platform/text/LocaleICU.cpp
Source/WebCore/platform/text/mac/TextCodecMac.cpp
Source/WebCore/platform/win/FileSystemWin.cpp
Source/bmalloc/ChangeLog
Source/bmalloc/bmalloc/Gigacage.cpp
Source/bmalloc/bmalloc/Gigacage.h
Source/bmalloc/bmalloc/HeapKind.h

index eb8cfd5..71b5616 100644 (file)
@@ -1,3 +1,20 @@
+2017-08-22  Filip Pizlo  <fpizlo@apple.com>
+
+        Strings need to be in some kind of gigacage
+        https://bugs.webkit.org/show_bug.cgi?id=174924
+
+        Reviewed by Oliver Hunt.
+
+        * runtime/JSString.cpp:
+        (JSC::JSRopeString::resolveRopeToAtomicString const):
+        (JSC::JSRopeString::resolveRope const):
+        * runtime/JSString.h:
+        (JSC::JSString::create):
+        (JSC::JSString::createHasOtherOwner):
+        * runtime/JSStringBuilder.h:
+        * runtime/VM.h:
+        (JSC::VM::gigacageAuxiliarySpace):
+
 2017-08-30  Oleksandr Skachkov  <gskachkov@gmail.com>
 
         [ESNext] Async iteration - Implement async iteration statement: for-await-of
index 34813a2..04969f3 100644 (file)
@@ -178,30 +178,34 @@ void JSRopeString::resolveRopeInternal16NoSubstring(UChar* buffer) const
 
 void JSRopeString::resolveRopeToAtomicString(ExecState* exec) const
 {
-    if (length() > maxLengthForOnStackResolve) {
-        resolveRope(exec);
-        m_value = AtomicString(m_value);
-        setIs8Bit(m_value.impl()->is8Bit());
-        return;
-    }
+    [&] () {
+        if (length() > maxLengthForOnStackResolve) {
+            resolveRope(exec);
+            m_value = AtomicString(m_value);
+            setIs8Bit(m_value.impl()->is8Bit());
+            return;
+        }
 
-    if (is8Bit()) {
-        LChar buffer[maxLengthForOnStackResolve];
-        resolveRopeInternal8(buffer);
-        m_value = AtomicString(buffer, length());
-        setIs8Bit(m_value.impl()->is8Bit());
-    } else {
-        UChar buffer[maxLengthForOnStackResolve];
-        resolveRopeInternal16(buffer);
-        m_value = AtomicString(buffer, length());
-        setIs8Bit(m_value.impl()->is8Bit());
-    }
+        if (is8Bit()) {
+            LChar buffer[maxLengthForOnStackResolve];
+            resolveRopeInternal8(buffer);
+            m_value = AtomicString(buffer, length());
+            setIs8Bit(m_value.impl()->is8Bit());
+        } else {
+            UChar buffer[maxLengthForOnStackResolve];
+            resolveRopeInternal16(buffer);
+            m_value = AtomicString(buffer, length());
+            setIs8Bit(m_value.impl()->is8Bit());
+        }
 
-    clearFibers();
+        clearFibers();
 
-    // If we resolved a string that didn't previously exist, notify the heap that we've grown.
-    if (m_value.impl()->hasOneRef())
-        Heap::heap(this)->reportExtraMemoryAllocated(m_value.impl()->cost());
+        // If we resolved a string that didn't previously exist, notify the heap that we've grown.
+        if (m_value.impl()->hasOneRef())
+            Heap::heap(this)->reportExtraMemoryAllocated(m_value.impl()->cost());
+    }();
+    
+    m_value.releaseAssertCaged();
 }
 
 void JSRopeString::clearFibers() const
@@ -248,17 +252,32 @@ RefPtr<AtomicStringImpl> JSRopeString::resolveRopeToExistingAtomicString(ExecSta
 
 void JSRopeString::resolveRope(ExecState* exec) const
 {
-    ASSERT(isRope());
-    
-    if (isSubstring()) {
-        ASSERT(!substringBase()->isRope());
-        m_value = substringBase()->m_value.substringSharingImpl(substringOffset(), length());
-        substringBase().clear();
-        return;
-    }
-    
-    if (is8Bit()) {
-        LChar* buffer;
+    [&] () {
+        ASSERT(isRope());
+        
+        if (isSubstring()) {
+            ASSERT(!substringBase()->isRope());
+            m_value = substringBase()->m_value.substringSharingImpl(substringOffset(), length());
+            substringBase().clear();
+            return;
+        }
+        
+        if (is8Bit()) {
+            LChar* buffer;
+            if (auto newImpl = StringImpl::tryCreateUninitialized(length(), buffer)) {
+                Heap::heap(this)->reportExtraMemoryAllocated(newImpl->cost());
+                m_value = WTFMove(newImpl);
+            } else {
+                outOfMemory(exec);
+                return;
+            }
+            resolveRopeInternal8NoSubstring(buffer);
+            clearFibers();
+            ASSERT(!isRope());
+            return;
+        }
+        
+        UChar* buffer;
         if (auto newImpl = StringImpl::tryCreateUninitialized(length(), buffer)) {
             Heap::heap(this)->reportExtraMemoryAllocated(newImpl->cost());
             m_value = WTFMove(newImpl);
@@ -266,24 +285,13 @@ void JSRopeString::resolveRope(ExecState* exec) const
             outOfMemory(exec);
             return;
         }
-        resolveRopeInternal8NoSubstring(buffer);
+        
+        resolveRopeInternal16NoSubstring(buffer);
         clearFibers();
         ASSERT(!isRope());
-        return;
-    }
+    }();
 
-    UChar* buffer;
-    if (auto newImpl = StringImpl::tryCreateUninitialized(length(), buffer)) {
-        Heap::heap(this)->reportExtraMemoryAllocated(newImpl->cost());
-        m_value = WTFMove(newImpl);
-    } else {
-        outOfMemory(exec);
-        return;
-    }
-
-    resolveRopeInternal16NoSubstring(buffer);
-    clearFibers();
-    ASSERT(!isRope());
+    m_value.releaseAssertCaged();
 }
 
 // Overview: These functions convert a JSString from holding a string in rope form
index ab54572..e604184 100644 (file)
@@ -139,6 +139,7 @@ protected:
 public:
     static JSString* create(VM& vm, Ref<StringImpl>&& value)
     {
+        value->assertCaged();
         unsigned length = value->length();
         size_t cost = value->cost();
         JSString* newString = new (NotNull, allocateCell<JSString>(vm.heap)) JSString(vm, WTFMove(value));
@@ -147,6 +148,7 @@ public:
     }
     static JSString* createHasOtherOwner(VM& vm, Ref<StringImpl>&& value)
     {
+        value->assertCaged();
         size_t length = value->length();
         JSString* newString = new (NotNull, allocateCell<JSString>(vm.heap)) JSString(vm, WTFMove(value));
         newString->finishCreation(vm, length);
index 9b4294a..3b77a45 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009, 2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2009-2017 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,7 @@
 
 #include "ExceptionHelpers.h"
 #include "JSString.h"
-#include <wtf/Vector.h>
+#include <wtf/text/StringVector.h>
 
 namespace JSC {
 
@@ -113,8 +113,8 @@ private:
         m_is8Bit = false;
     }
 
-    Vector<LChar, 64, UnsafeVectorOverflow> buffer8;
-    Vector<UChar, 64, UnsafeVectorOverflow> buffer16;
+    StringVector<LChar, 64, UnsafeVectorOverflow> buffer8;
+    StringVector<UChar, 64, UnsafeVectorOverflow> buffer16;
     bool m_okay;
     bool m_is8Bit;
 };
index 96fc9ed..28a3336 100644 (file)
@@ -308,6 +308,8 @@ public:
             return primitiveGigacageAuxiliarySpace;
         case Gigacage::JSValue:
             return jsValueGigacageAuxiliarySpace;
+        case Gigacage::String:
+            break;
         }
         RELEASE_ASSERT_NOT_REACHED();
         return primitiveGigacageAuxiliarySpace;
index 7e6df92..5ae9d4f 100644 (file)
@@ -1,3 +1,160 @@
+2017-08-22  Filip Pizlo  <fpizlo@apple.com>
+
+        Strings need to be in some kind of gigacage
+        https://bugs.webkit.org/show_bug.cgi?id=174924
+
+        Reviewed by Oliver Hunt.
+        
+        This makes all strings allocations come from the string gigacage. Because we expect string allocation
+        to be a hot path, I created specialized allocation paths for the string gigacage. These paths are
+        accessible via <wtf/text/StringMalloc.h>. However, those paths are equivalent to saying
+        Gigacage::malloc and friends with the Gigacage::String kind.
+
+        * WTF.xcodeproj/project.pbxproj:
+        * wtf/CMakeLists.txt:
+        * wtf/Deque.h:
+        * wtf/FastMalloc.cpp:
+        (WTF::fastFree):
+        * wtf/FastMalloc.h:
+        (WTF::FastMalloc::malloc):
+        (WTF::FastMalloc::tryMalloc):
+        (WTF::FastMalloc::realloc):
+        (WTF::FastMalloc::free):
+        * wtf/Forward.h:
+        * wtf/Gigacage.cpp:
+        (Gigacage::tryMalloc):
+        * wtf/Gigacage.h:
+        (Gigacage::name):
+        * wtf/Vector.h:
+        (WTF::VectorBufferBase::allocateBuffer):
+        (WTF::VectorBufferBase::tryAllocateBuffer):
+        (WTF::VectorBufferBase::reallocateBuffer):
+        (WTF::VectorBufferBase::deallocateBuffer):
+        (WTF::Malloc>::Vector):
+        (WTF::=):
+        (WTF::Malloc>::contains const):
+        (WTF::Malloc>::findMatching const):
+        (WTF::Malloc>::find const):
+        (WTF::Malloc>::reverseFind const):
+        (WTF::Malloc>::appendIfNotContains):
+        (WTF::Malloc>::fill):
+        (WTF::Malloc>::appendRange):
+        (WTF::Malloc>::expandCapacity):
+        (WTF::Malloc>::tryExpandCapacity):
+        (WTF::Malloc>::resize):
+        (WTF::Malloc>::resizeToFit):
+        (WTF::Malloc>::shrink):
+        (WTF::Malloc>::grow):
+        (WTF::Malloc>::asanSetInitialBufferSizeTo):
+        (WTF::Malloc>::asanSetBufferSizeToFullCapacity):
+        (WTF::Malloc>::asanBufferSizeWillChangeTo):
+        (WTF::Malloc>::reserveCapacity):
+        (WTF::Malloc>::tryReserveCapacity):
+        (WTF::Malloc>::reserveInitialCapacity):
+        (WTF::Malloc>::shrinkCapacity):
+        (WTF::Malloc>::append):
+        (WTF::Malloc>::tryAppend):
+        (WTF::Malloc>::constructAndAppend):
+        (WTF::Malloc>::tryConstructAndAppend):
+        (WTF::Malloc>::appendSlowCase):
+        (WTF::Malloc>::constructAndAppendSlowCase):
+        (WTF::Malloc>::tryConstructAndAppendSlowCase):
+        (WTF::Malloc>::uncheckedAppend):
+        (WTF::Malloc>::appendVector):
+        (WTF::Malloc>::insert):
+        (WTF::Malloc>::insertVector):
+        (WTF::Malloc>::remove):
+        (WTF::Malloc>::removeFirst):
+        (WTF::Malloc>::removeFirstMatching):
+        (WTF::Malloc>::removeAll):
+        (WTF::Malloc>::removeAllMatching):
+        (WTF::Malloc>::reverse):
+        (WTF::Malloc>::map const):
+        (WTF::Malloc>::releaseBuffer):
+        (WTF::Malloc>::checkConsistency):
+        (WTF::swap):
+        (WTF::operator==):
+        (WTF::operator!=):
+        (WTF::removeRepeatedElements):
+        (WTF::minCapacity>::Vector): Deleted.
+        (WTF::minCapacity>::contains const): Deleted.
+        (WTF::minCapacity>::findMatching const): Deleted.
+        (WTF::minCapacity>::find const): Deleted.
+        (WTF::minCapacity>::reverseFind const): Deleted.
+        (WTF::minCapacity>::appendIfNotContains): Deleted.
+        (WTF::minCapacity>::fill): Deleted.
+        (WTF::minCapacity>::appendRange): Deleted.
+        (WTF::minCapacity>::expandCapacity): Deleted.
+        (WTF::minCapacity>::tryExpandCapacity): Deleted.
+        (WTF::minCapacity>::resize): Deleted.
+        (WTF::minCapacity>::resizeToFit): Deleted.
+        (WTF::minCapacity>::shrink): Deleted.
+        (WTF::minCapacity>::grow): Deleted.
+        (WTF::minCapacity>::asanSetInitialBufferSizeTo): Deleted.
+        (WTF::minCapacity>::asanSetBufferSizeToFullCapacity): Deleted.
+        (WTF::minCapacity>::asanBufferSizeWillChangeTo): Deleted.
+        (WTF::minCapacity>::reserveCapacity): Deleted.
+        (WTF::minCapacity>::tryReserveCapacity): Deleted.
+        (WTF::minCapacity>::reserveInitialCapacity): Deleted.
+        (WTF::minCapacity>::shrinkCapacity): Deleted.
+        (WTF::minCapacity>::append): Deleted.
+        (WTF::minCapacity>::tryAppend): Deleted.
+        (WTF::minCapacity>::constructAndAppend): Deleted.
+        (WTF::minCapacity>::tryConstructAndAppend): Deleted.
+        (WTF::minCapacity>::appendSlowCase): Deleted.
+        (WTF::minCapacity>::constructAndAppendSlowCase): Deleted.
+        (WTF::minCapacity>::tryConstructAndAppendSlowCase): Deleted.
+        (WTF::minCapacity>::uncheckedAppend): Deleted.
+        (WTF::minCapacity>::appendVector): Deleted.
+        (WTF::minCapacity>::insert): Deleted.
+        (WTF::minCapacity>::insertVector): Deleted.
+        (WTF::minCapacity>::remove): Deleted.
+        (WTF::minCapacity>::removeFirst): Deleted.
+        (WTF::minCapacity>::removeFirstMatching): Deleted.
+        (WTF::minCapacity>::removeAll): Deleted.
+        (WTF::minCapacity>::removeAllMatching): Deleted.
+        (WTF::minCapacity>::reverse): Deleted.
+        (WTF::minCapacity>::map const): Deleted.
+        (WTF::minCapacity>::releaseBuffer): Deleted.
+        (WTF::minCapacity>::checkConsistency): Deleted.
+        * wtf/text/AtomicStringImpl.h:
+        * wtf/text/CString.cpp:
+        (WTF::CStringBuffer::createUninitialized):
+        * wtf/text/CString.h:
+        * wtf/text/StringBuffer.h:
+        (WTF::StringBuffer::StringBuffer):
+        (WTF::StringBuffer::~StringBuffer):
+        (WTF::StringBuffer::resize):
+        * wtf/text/StringImpl.cpp:
+        (WTF::StringImpl::~StringImpl):
+        (WTF::StringImpl::destroy):
+        (WTF::StringImpl::createUninitializedInternalNonEmpty):
+        (WTF::StringImpl::reallocateInternal):
+        (WTF::StringImpl::releaseAssertCaged const):
+        * wtf/text/StringImpl.h:
+        (WTF::StringImpl::createSubstringSharingImpl):
+        (WTF::StringImpl::tryCreateUninitialized):
+        (WTF::StringImpl::adopt):
+        (WTF::StringImpl::bufferOwnership const):
+        (WTF::StringImpl::assertCaged const):
+        * wtf/text/StringMalloc.cpp: Added.
+        (WTF::tryStringMalloc):
+        (WTF::stringMalloc):
+        (WTF::stringRealloc):
+        (WTF::stringFree):
+        * wtf/text/StringMalloc.h: Added.
+        (WTF::StringMalloc::malloc):
+        (WTF::StringMalloc::tryMalloc):
+        (WTF::StringMalloc::realloc):
+        (WTF::StringMalloc::free):
+        * wtf/text/StringVector.h: Added.
+        * wtf/text/SymbolImpl.h:
+        * wtf/text/UniquedStringImpl.h:
+        * wtf/text/WTFString.h:
+        (WTF::String::adopt):
+        (WTF::String::assertCaged const):
+        (WTF::String::releaseAssertCaged const):
+
 2017-08-28  Yusuke Suzuki  <utatane.tea@gmail.com>
 
         [JSC] Use table based approach for JSON.stringify's Quote
index c9218f5..d4f48c1 100644 (file)
@@ -21,6 +21,7 @@
 /* End PBXAggregateTarget section */
 
 /* Begin PBXBuildFile section */
+               0F0F526B1F421FF8004A452C /* StringMalloc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F0F52691F421FF8004A452C /* StringMalloc.cpp */; };
                0F30BA901E78708E002CA847 /* GlobalVersion.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F30BA8A1E78708E002CA847 /* GlobalVersion.cpp */; };
                0F43D8F11DB5ADDC00108FB6 /* AutomaticThread.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F43D8EF1DB5ADDC00108FB6 /* AutomaticThread.cpp */; };
                0F5BF1761F23D49A0029D91D /* Gigacage.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F5BF1741F23D49A0029D91D /* Gigacage.cpp */; };
 
 /* Begin PBXFileReference section */
                0F0D85B317234CB100338210 /* NoLock.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NoLock.h; sourceTree = "<group>"; };
+               0F0F52691F421FF8004A452C /* StringMalloc.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = StringMalloc.cpp; sourceTree = "<group>"; };
+               0F0F526A1F421FF8004A452C /* StringMalloc.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = StringMalloc.h; sourceTree = "<group>"; };
                0F0FCDDD1DD167F900CCAB53 /* LockAlgorithm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LockAlgorithm.h; sourceTree = "<group>"; };
                0F2AC5601E89F70C0001EE3F /* Range.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Range.h; sourceTree = "<group>"; };
                0F2AC5621E8A01490001EE3F /* IndexKeyType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IndexKeyType.h; sourceTree = "<group>"; };
                0F30BA8E1E78708E002CA847 /* LoggingHashSet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LoggingHashSet.h; sourceTree = "<group>"; };
                0F30BA8F1E78708E002CA847 /* LoggingHashTraits.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LoggingHashTraits.h; sourceTree = "<group>"; };
                0F31DD701F1308BC0072EB4A /* LockAlgorithmInlines.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LockAlgorithmInlines.h; sourceTree = "<group>"; };
+               0F348C7D1F47AA9D003CFEF2 /* StringVector.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = StringVector.h; sourceTree = "<group>"; };
                0F3501631BB258C800F0A2A3 /* WeakRandom.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WeakRandom.h; sourceTree = "<group>"; };
                0F43D8EF1DB5ADDC00108FB6 /* AutomaticThread.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AutomaticThread.cpp; sourceTree = "<group>"; };
                0F43D8F01DB5ADDC00108FB6 /* AutomaticThread.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AutomaticThread.h; sourceTree = "<group>"; };
                                A8A47327151A825B004123FF /* StringHash.h */,
                                A8A47328151A825B004123FF /* StringImpl.cpp */,
                                A8A47329151A825B004123FF /* StringImpl.h */,
+                               0F0F52691F421FF8004A452C /* StringMalloc.cpp */,
+                               0F0F526A1F421FF8004A452C /* StringMalloc.h */,
                                A8A4732A151A825B004123FF /* StringOperators.h */,
+                               0F348C7D1F47AA9D003CFEF2 /* StringVector.h */,
                                93F1993D19D7958D00C2390B /* StringView.cpp */,
                                1A6EB1DF187D0BD30030126F /* StringView.h */,
                                F72BBDB107FA424886178B9E /* SymbolImpl.cpp */,
                                515F794E1CFC9F4A00CCED93 /* CrossThreadCopier.cpp in Sources */,
                                A8A4739A151A825B004123FF /* CryptographicallyRandomNumber.cpp in Sources */,
                                E15556F518A0CC18006F48FB /* CryptographicUtilities.cpp in Sources */,
+                               0F0F526B1F421FF8004A452C /* StringMalloc.cpp in Sources */,
                                A8A47439151A825B004123FF /* CString.cpp in Sources */,
                                A8A4739C151A825B004123FF /* CurrentTime.cpp in Sources */,
                                A8A4739E151A825B004123FF /* DataLog.cpp in Sources */,
index 4909602..3a6ce9e 100644 (file)
@@ -182,6 +182,8 @@ set(WTF_HEADERS
     text/StringCommon.h
     text/StringHash.h
     text/StringImpl.h
+    text/StringMalloc.h
+    text/StringVector.h
     text/StringView.h
     text/SymbolImpl.h
     text/SymbolRegistry.h
@@ -286,6 +288,7 @@ set(WTF_SOURCES
     text/StringBuilder.cpp
     text/StringBuilderJSON.cpp
     text/StringImpl.cpp
+    text/StringMalloc.cpp
     text/StringView.cpp
     text/SymbolImpl.cpp
     text/SymbolRegistry.cpp
index 252b081..1be99d8 100644 (file)
@@ -113,7 +113,7 @@ public:
 private:
     friend class DequeIteratorBase<T, inlineCapacity>;
 
-    typedef VectorBuffer<T, inlineCapacity> Buffer;
+    typedef VectorBuffer<T, inlineCapacity, FastMalloc> Buffer;
     typedef VectorTypeOperations<T> TypeOperations;
     typedef DequeIteratorBase<T, inlineCapacity> IteratorBase;
 
index 1fde332..209dc75 100644 (file)
@@ -129,6 +129,22 @@ public:
 template<typename T, typename U> inline bool operator==(const FastAllocator<T>&, const FastAllocator<U>&) { return true; }
 template<typename T, typename U> inline bool operator!=(const FastAllocator<T>&, const FastAllocator<U>&) { return false; }
 
+struct FastMalloc {
+    static void* malloc(size_t size) { return fastMalloc(size); }
+    
+    static void* tryMalloc(size_t size)
+    {
+        auto result = tryFastMalloc(size);
+        void* realResult;
+        if (result.getValue(realResult))
+            return realResult;
+        return nullptr;
+    }
+    
+    static void* realloc(void* p, size_t size) { return fastRealloc(p, size); }
+    
+    static void free(void* p) { fastFree(p); }
+};
 
 } // namespace WTF
 
@@ -136,6 +152,8 @@ template<typename T, typename U> inline bool operator!=(const FastAllocator<T>&,
 using WTF::fastSetMaxSingleAllocationSize;
 #endif
 
+using WTF::FastAllocator;
+using WTF::FastMalloc;
 using WTF::isFastMallocEnabled;
 using WTF::fastCalloc;
 using WTF::fastFree;
@@ -151,7 +169,6 @@ using WTF::tryFastMalloc;
 using WTF::tryFastZeroedMalloc;
 using WTF::fastAlignedMalloc;
 using WTF::fastAlignedFree;
-using WTF::FastAllocator;
 
 #if COMPILER(GCC_OR_CLANG) && OS(DARWIN)
 #define WTF_PRIVATE_INLINE __private_extern__ inline __attribute__((always_inline))
index 6fbcbee..7f3ee42 100644 (file)
@@ -37,7 +37,7 @@ template<typename T> class RefPtr;
 template<typename T> class StringBuffer;
 
 template<typename... T> class Variant;
-template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity> class Vector;
+template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity, typename Malloc> class Vector;
 
 class AtomicString;
 class AtomicStringImpl;
index d3401c3..ea3ecc6 100644 (file)
@@ -40,11 +40,7 @@ namespace Gigacage {
 
 void* tryMalloc(Kind, size_t size)
 {
-    auto result = tryFastMalloc(size);
-    void* realResult;
-    if (result.getValue(realResult))
-        return realResult;
-    return nullptr;
+    return FastMalloc::tryMalloc(size);
 }
 
 void* tryAllocateVirtualPages(Kind, size_t size)
index 4b14bfb..7111830 100644 (file)
@@ -40,7 +40,8 @@ namespace Gigacage {
 
 enum Kind {
     Primitive,
-    JSValue
+    JSValue,
+    String
 };
 
 inline void ensureGigacage() { }
@@ -63,6 +64,8 @@ ALWAYS_INLINE const char* name(Kind kind)
         return "Primitive";
     case JSValue:
         return "JSValue";
+    case String:
+        return "String";
     }
     RELEASE_ASSERT_NOT_REACHED();
     return nullptr;
index ba2a570..cf9c7fb 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright (C) 2005, 2006, 2007, 2008, 2014 Apple Inc. All rights reserved.
+ *  Copyright (C) 2005-2017 Apple Inc. All rights reserved.
  *
  *  This library is free software; you can redistribute it and/or
  *  modify it under the terms of the GNU Library General Public
@@ -254,7 +254,7 @@ struct VectorTypeOperations
     }
 };
 
-template<typename T>
+template<typename T, typename Malloc>
 class VectorBufferBase {
     WTF_MAKE_NONCOPYABLE(VectorBufferBase);
 public:
@@ -265,7 +265,7 @@ public:
             CRASH();
         size_t sizeToAllocate = newCapacity * sizeof(T);
         m_capacity = sizeToAllocate / sizeof(T);
-        m_buffer = static_cast<T*>(fastMalloc(sizeToAllocate));
+        m_buffer = static_cast<T*>(Malloc::malloc(sizeToAllocate));
     }
 
     bool tryAllocateBuffer(size_t newCapacity)
@@ -275,13 +275,12 @@ public:
             return false;
 
         size_t sizeToAllocate = newCapacity * sizeof(T);
-        T* newBuffer;
-        if (tryFastMalloc(sizeToAllocate).getValue(newBuffer)) {
-            m_capacity = sizeToAllocate / sizeof(T);
-            m_buffer = newBuffer;
-            return true;
-        }
-        return false;
+        T* newBuffer = static_cast<T*>(Malloc::tryMalloc(sizeToAllocate));
+        if (!newBuffer)
+            return false;
+        m_capacity = sizeToAllocate / sizeof(T);
+        m_buffer = newBuffer;
+        return true;
     }
 
     bool shouldReallocateBuffer(size_t newCapacity) const
@@ -296,7 +295,7 @@ public:
             CRASH();
         size_t sizeToAllocate = newCapacity * sizeof(T);
         m_capacity = sizeToAllocate / sizeof(T);
-        m_buffer = static_cast<T*>(fastRealloc(m_buffer, sizeToAllocate));
+        m_buffer = static_cast<T*>(Malloc::realloc(m_buffer, sizeToAllocate));
     }
 
     void deallocateBuffer(T* bufferToDeallocate)
@@ -309,7 +308,7 @@ public:
             m_capacity = 0;
         }
 
-        fastFree(bufferToDeallocate);
+        Malloc::free(bufferToDeallocate);
     }
 
     T* buffer() { return m_buffer; }
@@ -350,13 +349,13 @@ protected:
     unsigned m_size; // Only used by the Vector subclass, but placed here to avoid padding the struct.
 };
 
-template<typename T, size_t inlineCapacity>
+template<typename T, size_t inlineCapacity, typename Malloc>
 class VectorBuffer;
 
-template<typename T>
-class VectorBuffer<T, 0> : private VectorBufferBase<T> {
+template<typename T, typename Malloc>
+class VectorBuffer<T, 0, Malloc> : private VectorBufferBase<T, Malloc> {
 private:
-    typedef VectorBufferBase<T> Base;
+    typedef VectorBufferBase<T, Malloc> Base;
 public:
     VectorBuffer()
     {
@@ -376,7 +375,7 @@ public:
         deallocateBuffer(buffer());
     }
     
-    void swap(VectorBuffer<T, 0>& other, size_t, size_t)
+    void swap(VectorBuffer<T, 0, Malloc>& other, size_t, size_t)
     {
         std::swap(m_buffer, other.m_buffer);
         std::swap(m_capacity, other.m_capacity);
@@ -411,11 +410,11 @@ private:
     using Base::m_capacity;
 };
 
-template<typename T, size_t inlineCapacity>
-class VectorBuffer : private VectorBufferBase<T> {
+template<typename T, size_t inlineCapacity, typename Malloc>
+class VectorBuffer : private VectorBufferBase<T, Malloc> {
     WTF_MAKE_NONCOPYABLE(VectorBuffer);
 private:
-    typedef VectorBufferBase<T> Base;
+    typedef VectorBufferBase<T, Malloc> Base;
 public:
     VectorBuffer()
         : Base(inlineBuffer(), inlineCapacity, 0)
@@ -576,11 +575,11 @@ struct UnsafeVectorOverflow {
     }
 };
 
-template<typename T, size_t inlineCapacity = 0, typename OverflowHandler = CrashOnOverflow, size_t minCapacity = 16>
-class Vector : private VectorBuffer<T, inlineCapacity> {
+template<typename T, size_t inlineCapacity = 0, typename OverflowHandler = CrashOnOverflow, size_t minCapacity = 16, typename Malloc = FastMalloc>
+class Vector : private VectorBuffer<T, inlineCapacity, Malloc> {
     WTF_MAKE_FAST_ALLOCATED;
 private:
-    typedef VectorBuffer<T, inlineCapacity> Base;
+    typedef VectorBuffer<T, inlineCapacity, Malloc> Base;
     typedef VectorTypeOperations<T> TypeOperations;
 
 public:
@@ -633,12 +632,12 @@ public:
     }
 
     Vector(const Vector&);
-    template<size_t otherCapacity, typename otherOverflowBehaviour, size_t otherMinimumCapacity>
-    explicit Vector(const Vector<T, otherCapacity, otherOverflowBehaviour, otherMinimumCapacity>&);
+    template<size_t otherCapacity, typename otherOverflowBehaviour, size_t otherMinimumCapacity, typename OtherMalloc>
+    explicit Vector(const Vector<T, otherCapacity, otherOverflowBehaviour, otherMinimumCapacity, OtherMalloc>&);
 
     Vector& operator=(const Vector&);
-    template<size_t otherCapacity, typename otherOverflowBehaviour, size_t otherMinimumCapacity>
-    Vector& operator=(const Vector<T, otherCapacity, otherOverflowBehaviour, otherMinimumCapacity>&);
+    template<size_t otherCapacity, typename otherOverflowBehaviour, size_t otherMinimumCapacity, typename OtherMalloc>
+    Vector& operator=(const Vector<T, otherCapacity, otherOverflowBehaviour, otherMinimumCapacity, OtherMalloc>&);
 
     Vector(Vector&&);
     Vector& operator=(Vector&&);
@@ -814,8 +813,8 @@ private:
 #endif
 };
 
-template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity>
-Vector<T, inlineCapacity, OverflowHandler, minCapacity>::Vector(const Vector& other)
+template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity, typename Malloc>
+Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>::Vector(const Vector& other)
     : Base(other.capacity(), other.size())
 {
     asanSetInitialBufferSizeTo(other.size());
@@ -824,9 +823,9 @@ Vector<T, inlineCapacity, OverflowHandler, minCapacity>::Vector(const Vector& ot
         TypeOperations::uninitializedCopy(other.begin(), other.end(), begin());
 }
 
-template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity>
-template<size_t otherCapacity, typename otherOverflowBehaviour, size_t otherMinimumCapacity>
-Vector<T, inlineCapacity, OverflowHandler, minCapacity>::Vector(const Vector<T, otherCapacity, otherOverflowBehaviour, otherMinimumCapacity>& other)
+template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity, typename Malloc>
+template<size_t otherCapacity, typename otherOverflowBehaviour, size_t otherMinimumCapacity, typename OtherMalloc>
+Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>::Vector(const Vector<T, otherCapacity, otherOverflowBehaviour, otherMinimumCapacity, OtherMalloc>& other)
     : Base(other.capacity(), other.size())
 {
     asanSetInitialBufferSizeTo(other.size());
@@ -835,8 +834,8 @@ Vector<T, inlineCapacity, OverflowHandler, minCapacity>::Vector(const Vector<T,
         TypeOperations::uninitializedCopy(other.begin(), other.end(), begin());
 }
 
-template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity>
-Vector<T, inlineCapacity, OverflowHandler, minCapacity>& Vector<T, inlineCapacity, OverflowHandler, minCapacity>::operator=(const Vector<T, inlineCapacity, OverflowHandler, minCapacity>& other)
+template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity, typename Malloc>
+Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>& Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>::operator=(const Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>& other)
 {
     if (&other == this)
         return *this;
@@ -860,9 +859,9 @@ Vector<T, inlineCapacity, OverflowHandler, minCapacity>& Vector<T, inlineCapacit
 
 inline bool typelessPointersAreEqual(const void* a, const void* b) { return a == b; }
 
-template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity>
-template<size_t otherCapacity, typename otherOverflowBehaviour, size_t otherMinimumCapacity>
-Vector<T, inlineCapacity, OverflowHandler, minCapacity>& Vector<T, inlineCapacity, OverflowHandler, minCapacity>::operator=(const Vector<T, otherCapacity, otherOverflowBehaviour, otherMinimumCapacity>& other)
+template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity, typename Malloc>
+template<size_t otherCapacity, typename otherOverflowBehaviour, size_t otherMinimumCapacity, typename OtherMalloc>
+Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>& Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>::operator=(const Vector<T, otherCapacity, otherOverflowBehaviour, otherMinimumCapacity, OtherMalloc>& other)
 {
     // If the inline capacities match, we should call the more specific
     // template.  If the inline capacities don't match, the two objects
@@ -886,29 +885,29 @@ Vector<T, inlineCapacity, OverflowHandler, minCapacity>& Vector<T, inlineCapacit
     return *this;
 }
 
-template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity>
-inline Vector<T, inlineCapacity, OverflowHandler, minCapacity>::Vector(Vector<T, inlineCapacity, OverflowHandler, minCapacity>&& other)
+template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity, typename Malloc>
+inline Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>::Vector(Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>&& other)
 {
     swap(other);
 }
 
-template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity>
-inline Vector<T, inlineCapacity, OverflowHandler, minCapacity>& Vector<T, inlineCapacity, OverflowHandler, minCapacity>::operator=(Vector<T, inlineCapacity, OverflowHandler, minCapacity>&& other)
+template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity, typename Malloc>
+inline Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>& Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>::operator=(Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>&& other)
 {
     swap(other);
     return *this;
 }
 
-template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity>
+template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity, typename Malloc>
 template<typename U>
-bool Vector<T, inlineCapacity, OverflowHandler, minCapacity>::contains(const U& value) const
+bool Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>::contains(const U& value) const
 {
     return find(value) != notFound;
 }
 
-template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity>
+template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity, typename Malloc>
 template<typename MatchFunction>
-size_t Vector<T, inlineCapacity, OverflowHandler, minCapacity>::findMatching(const MatchFunction& matches) const
+size_t Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>::findMatching(const MatchFunction& matches) const
 {
     for (size_t i = 0; i < size(); ++i) {
         if (matches(at(i)))
@@ -917,18 +916,18 @@ size_t Vector<T, inlineCapacity, OverflowHandler, minCapacity>::findMatching(con
     return notFound;
 }
 
-template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity>
+template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity, typename Malloc>
 template<typename U>
-size_t Vector<T, inlineCapacity, OverflowHandler, minCapacity>::find(const U& value) const
+size_t Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>::find(const U& value) const
 {
     return findMatching([&](auto& item) {
         return item == value;
     });
 }
 
-template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity>
+template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity, typename Malloc>
 template<typename U>
-size_t Vector<T, inlineCapacity, OverflowHandler, minCapacity>::reverseFind(const U& value) const
+size_t Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>::reverseFind(const U& value) const
 {
     for (size_t i = 1; i <= size(); ++i) {
         const size_t index = size() - i;
@@ -938,9 +937,9 @@ size_t Vector<T, inlineCapacity, OverflowHandler, minCapacity>::reverseFind(cons
     return notFound;
 }
 
-template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity>
+template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity, typename Malloc>
 template<typename U>
-bool Vector<T, inlineCapacity, OverflowHandler, minCapacity>::appendIfNotContains(const U& value)
+bool Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>::appendIfNotContains(const U& value)
 {
     if (contains(value))
         return false;
@@ -948,8 +947,8 @@ bool Vector<T, inlineCapacity, OverflowHandler, minCapacity>::appendIfNotContain
     return true;
 }
 
-template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity>
-void Vector<T, inlineCapacity, OverflowHandler, minCapacity>::fill(const T& val, size_t newSize)
+template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity, typename Malloc>
+void Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>::fill(const T& val, size_t newSize)
 {
     if (size() > newSize)
         shrink(newSize);
@@ -966,22 +965,22 @@ void Vector<T, inlineCapacity, OverflowHandler, minCapacity>::fill(const T& val,
     m_size = newSize;
 }
 
-template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity>
+template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity, typename Malloc>
 template<typename Iterator>
-void Vector<T, inlineCapacity, OverflowHandler, minCapacity>::appendRange(Iterator start, Iterator end)
+void Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>::appendRange(Iterator start, Iterator end)
 {
     for (Iterator it = start; it != end; ++it)
         append(*it);
 }
 
-template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity>
-void Vector<T, inlineCapacity, OverflowHandler, minCapacity>::expandCapacity(size_t newMinCapacity)
+template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity, typename Malloc>
+void Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>::expandCapacity(size_t newMinCapacity)
 {
     reserveCapacity(std::max(newMinCapacity, std::max(static_cast<size_t>(minCapacity), capacity() + capacity() / 4 + 1)));
 }
 
-template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity>
-T* Vector<T, inlineCapacity, OverflowHandler, minCapacity>::expandCapacity(size_t newMinCapacity, T* ptr)
+template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity, typename Malloc>
+T* Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>::expandCapacity(size_t newMinCapacity, T* ptr)
 {
     if (ptr < begin() || ptr >= end()) {
         expandCapacity(newMinCapacity);
@@ -992,14 +991,14 @@ T* Vector<T, inlineCapacity, OverflowHandler, minCapacity>::expandCapacity(size_
     return begin() + index;
 }
 
-template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity>
-bool Vector<T, inlineCapacity, OverflowHandler, minCapacity>::tryExpandCapacity(size_t newMinCapacity)
+template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity, typename Malloc>
+bool Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>::tryExpandCapacity(size_t newMinCapacity)
 {
     return tryReserveCapacity(std::max(newMinCapacity, std::max(static_cast<size_t>(minCapacity), capacity() + capacity() / 4 + 1)));
 }
 
-template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity>
-const T* Vector<T, inlineCapacity, OverflowHandler, minCapacity>::tryExpandCapacity(size_t newMinCapacity, const T* ptr)
+template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity, typename Malloc>
+const T* Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>::tryExpandCapacity(size_t newMinCapacity, const T* ptr)
 {
     if (ptr < begin() || ptr >= end()) {
         if (!tryExpandCapacity(newMinCapacity))
@@ -1012,15 +1011,16 @@ const T* Vector<T, inlineCapacity, OverflowHandler, minCapacity>::tryExpandCapac
     return begin() + index;
 }
 
-template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity> template<typename U>
-inline U* Vector<T, inlineCapacity, OverflowHandler, minCapacity>::expandCapacity(size_t newMinCapacity, U* ptr)
+template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity, typename Malloc>
+template<typename U>
+inline U* Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>::expandCapacity(size_t newMinCapacity, U* ptr)
 {
     expandCapacity(newMinCapacity);
     return ptr;
 }
 
-template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity>
-inline void Vector<T, inlineCapacity, OverflowHandler, minCapacity>::resize(size_t size)
+template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity, typename Malloc>
+inline void Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>::resize(size_t size)
 {
     if (size <= m_size) {
         TypeOperations::destruct(begin() + size, end());
@@ -1036,15 +1036,15 @@ inline void Vector<T, inlineCapacity, OverflowHandler, minCapacity>::resize(size
     m_size = size;
 }
 
-template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity>
-void Vector<T, inlineCapacity, OverflowHandler, minCapacity>::resizeToFit(size_t size)
+template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity, typename Malloc>
+void Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>::resizeToFit(size_t size)
 {
     reserveCapacity(size);
     resize(size);
 }
 
-template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity>
-void Vector<T, inlineCapacity, OverflowHandler, minCapacity>::shrink(size_t size)
+template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity, typename Malloc>
+void Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>::shrink(size_t size)
 {
     ASSERT(size <= m_size);
     TypeOperations::destruct(begin() + size, end());
@@ -1052,8 +1052,8 @@ void Vector<T, inlineCapacity, OverflowHandler, minCapacity>::shrink(size_t size
     m_size = size;
 }
 
-template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity>
-void Vector<T, inlineCapacity, OverflowHandler, minCapacity>::grow(size_t size)
+template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity, typename Malloc>
+void Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>::grow(size_t size)
 {
     ASSERT(size >= m_size);
     if (size > capacity())
@@ -1064,8 +1064,8 @@ void Vector<T, inlineCapacity, OverflowHandler, minCapacity>::grow(size_t size)
     m_size = size;
 }
 
-template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity>
-inline void Vector<T, inlineCapacity, OverflowHandler, minCapacity>::asanSetInitialBufferSizeTo(size_t size)
+template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity, typename Malloc>
+inline void Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>::asanSetInitialBufferSizeTo(size_t size)
 {
 #if ASAN_ENABLED
     if (!buffer())
@@ -1080,8 +1080,8 @@ inline void Vector<T, inlineCapacity, OverflowHandler, minCapacity>::asanSetInit
 #endif
 }
 
-template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity>
-inline void Vector<T, inlineCapacity, OverflowHandler, minCapacity>::asanSetBufferSizeToFullCapacity(size_t size)
+template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity, typename Malloc>
+inline void Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>::asanSetBufferSizeToFullCapacity(size_t size)
 {
 #if ASAN_ENABLED
     if (!buffer())
@@ -1094,8 +1094,8 @@ inline void Vector<T, inlineCapacity, OverflowHandler, minCapacity>::asanSetBuff
 #endif
 }
 
-template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity>
-inline void Vector<T, inlineCapacity, OverflowHandler, minCapacity>::asanBufferSizeWillChangeTo(size_t newSize)
+template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity, typename Malloc>
+inline void Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>::asanBufferSizeWillChangeTo(size_t newSize)
 {
 #if ASAN_ENABLED
     if (!buffer())
@@ -1108,8 +1108,8 @@ inline void Vector<T, inlineCapacity, OverflowHandler, minCapacity>::asanBufferS
 #endif
 }
 
-template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity>
-void Vector<T, inlineCapacity, OverflowHandler, minCapacity>::reserveCapacity(size_t newCapacity)
+template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity, typename Malloc>
+void Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>::reserveCapacity(size_t newCapacity)
 {
     if (newCapacity <= capacity())
         return;
@@ -1127,8 +1127,8 @@ void Vector<T, inlineCapacity, OverflowHandler, minCapacity>::reserveCapacity(si
     Base::deallocateBuffer(oldBuffer);
 }
 
-template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity>
-bool Vector<T, inlineCapacity, OverflowHandler, minCapacity>::tryReserveCapacity(size_t newCapacity)
+template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity, typename Malloc>
+bool Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>::tryReserveCapacity(size_t newCapacity)
 {
     if (newCapacity <= capacity())
         return true;
@@ -1150,8 +1150,8 @@ bool Vector<T, inlineCapacity, OverflowHandler, minCapacity>::tryReserveCapacity
     return true;
 }
 
-template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity>
-inline void Vector<T, inlineCapacity, OverflowHandler, minCapacity>::reserveInitialCapacity(size_t initialCapacity)
+template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity, typename Malloc>
+inline void Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>::reserveInitialCapacity(size_t initialCapacity)
 {
     ASSERT(!m_size);
     ASSERT(capacity() == inlineCapacity);
@@ -1159,8 +1159,8 @@ inline void Vector<T, inlineCapacity, OverflowHandler, minCapacity>::reserveInit
         Base::allocateBuffer(initialCapacity);
 }
 
-template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity>
-void Vector<T, inlineCapacity, OverflowHandler, minCapacity>::shrinkCapacity(size_t newCapacity)
+template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity, typename Malloc>
+void Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>::shrinkCapacity(size_t newCapacity)
 {
     if (newCapacity >= capacity())
         return;
@@ -1190,8 +1190,9 @@ void Vector<T, inlineCapacity, OverflowHandler, minCapacity>::shrinkCapacity(siz
     asanSetInitialBufferSizeTo(size());
 }
 
-template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity> template<typename U>
-void Vector<T, inlineCapacity, OverflowHandler, minCapacity>::append(const U* data, size_t dataSize)
+template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity, typename Malloc>
+template<typename U>
+void Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>::append(const U* data, size_t dataSize)
 {
     size_t newSize = m_size + dataSize;
     if (newSize > capacity()) {
@@ -1206,8 +1207,9 @@ void Vector<T, inlineCapacity, OverflowHandler, minCapacity>::append(const U* da
     m_size = newSize;
 }
 
-template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity> template<typename U>
-bool Vector<T, inlineCapacity, OverflowHandler, minCapacity>::tryAppend(const U* data, size_t dataSize)
+template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity, typename Malloc>
+template<typename U>
+bool Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>::tryAppend(const U* data, size_t dataSize)
 {
     size_t newSize = m_size + dataSize;
     if (newSize > capacity()) {
@@ -1225,8 +1227,9 @@ bool Vector<T, inlineCapacity, OverflowHandler, minCapacity>::tryAppend(const U*
     return true;
 }
 
-template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity> template<typename U>
-ALWAYS_INLINE void Vector<T, inlineCapacity, OverflowHandler, minCapacity>::append(U&& value)
+template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity, typename Malloc>
+template<typename U>
+ALWAYS_INLINE void Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>::append(U&& value)
 {
     if (size() != capacity()) {
         asanBufferSizeWillChangeTo(m_size + 1);
@@ -1238,8 +1241,9 @@ ALWAYS_INLINE void Vector<T, inlineCapacity, OverflowHandler, minCapacity>::appe
     appendSlowCase(std::forward<U>(value));
 }
 
-template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity> template<typename... Args>
-ALWAYS_INLINE void Vector<T, inlineCapacity, OverflowHandler, minCapacity>::constructAndAppend(Args&&... args)
+template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity, typename Malloc>
+template<typename... Args>
+ALWAYS_INLINE void Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>::constructAndAppend(Args&&... args)
 {
     if (size() != capacity()) {
         asanBufferSizeWillChangeTo(m_size + 1);
@@ -1251,8 +1255,9 @@ ALWAYS_INLINE void Vector<T, inlineCapacity, OverflowHandler, minCapacity>::cons
     constructAndAppendSlowCase(std::forward<Args>(args)...);
 }
 
-template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity> template<typename... Args>
-ALWAYS_INLINE bool Vector<T, inlineCapacity, OverflowHandler, minCapacity>::tryConstructAndAppend(Args&&... args)
+template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity, typename Malloc>
+template<typename... Args>
+ALWAYS_INLINE bool Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>::tryConstructAndAppend(Args&&... args)
 {
     if (size() != capacity()) {
         asanBufferSizeWillChangeTo(m_size + 1);
@@ -1264,8 +1269,9 @@ ALWAYS_INLINE bool Vector<T, inlineCapacity, OverflowHandler, minCapacity>::tryC
     return tryConstructAndAppendSlowCase(std::forward<Args>(args)...);
 }
 
-template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity> template<typename U>
-void Vector<T, inlineCapacity, OverflowHandler, minCapacity>::appendSlowCase(U&& value)
+template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity, typename Malloc>
+template<typename U>
+void Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>::appendSlowCase(U&& value)
 {
     ASSERT(size() == capacity());
 
@@ -1278,8 +1284,9 @@ void Vector<T, inlineCapacity, OverflowHandler, minCapacity>::appendSlowCase(U&&
     ++m_size;
 }
 
-template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity> template<typename... Args>
-void Vector<T, inlineCapacity, OverflowHandler, minCapacity>::constructAndAppendSlowCase(Args&&... args)
+template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity, typename Malloc>
+template<typename... Args>
+void Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>::constructAndAppendSlowCase(Args&&... args)
 {
     ASSERT(size() == capacity());
 
@@ -1291,8 +1298,9 @@ void Vector<T, inlineCapacity, OverflowHandler, minCapacity>::constructAndAppend
     ++m_size;
 }
 
-template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity> template<typename... Args>
-bool Vector<T, inlineCapacity, OverflowHandler, minCapacity>::tryConstructAndAppendSlowCase(Args&&... args)
+template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity, typename Malloc>
+template<typename... Args>
+bool Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>::tryConstructAndAppendSlowCase(Args&&... args)
 {
     ASSERT(size() == capacity());
     
@@ -1309,8 +1317,9 @@ bool Vector<T, inlineCapacity, OverflowHandler, minCapacity>::tryConstructAndApp
 // This version of append saves a branch in the case where you know that the
 // vector's capacity is large enough for the append to succeed.
 
-template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity> template<typename U>
-ALWAYS_INLINE void Vector<T, inlineCapacity, OverflowHandler, minCapacity>::uncheckedAppend(U&& value)
+template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity, typename Malloc>
+template<typename U>
+ALWAYS_INLINE void Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>::uncheckedAppend(U&& value)
 {
     ASSERT(size() < capacity());
 
@@ -1321,14 +1330,16 @@ ALWAYS_INLINE void Vector<T, inlineCapacity, OverflowHandler, minCapacity>::unch
     ++m_size;
 }
 
-template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity> template<typename U, size_t otherCapacity>
-inline void Vector<T, inlineCapacity, OverflowHandler, minCapacity>::appendVector(const Vector<U, otherCapacity>& val)
+template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity, typename Malloc>
+template<typename U, size_t otherCapacity>
+inline void Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>::appendVector(const Vector<U, otherCapacity>& val)
 {
     append(val.begin(), val.size());
 }
 
-template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity> template<typename U>
-void Vector<T, inlineCapacity, OverflowHandler, minCapacity>::insert(size_t position, const U* data, size_t dataSize)
+template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity, typename Malloc>
+template<typename U>
+void Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>::insert(size_t position, const U* data, size_t dataSize)
 {
     ASSERT_WITH_SECURITY_IMPLICATION(position <= size());
     size_t newSize = m_size + dataSize;
@@ -1345,8 +1356,9 @@ void Vector<T, inlineCapacity, OverflowHandler, minCapacity>::insert(size_t posi
     m_size = newSize;
 }
  
-template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity> template<typename U>
-inline void Vector<T, inlineCapacity, OverflowHandler, minCapacity>::insert(size_t position, U&& value)
+template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity, typename Malloc>
+template<typename U>
+inline void Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>::insert(size_t position, U&& value)
 {
     ASSERT_WITH_SECURITY_IMPLICATION(position <= size());
 
@@ -1364,14 +1376,15 @@ inline void Vector<T, inlineCapacity, OverflowHandler, minCapacity>::insert(size
     ++m_size;
 }
 
-template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity> template<typename U, size_t c>
-inline void Vector<T, inlineCapacity, OverflowHandler, minCapacity>::insertVector(size_t position, const Vector<U, c>& val)
+template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity, typename Malloc>
+template<typename U, size_t c>
+inline void Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>::insertVector(size_t position, const Vector<U, c>& val)
 {
     insert(position, val.begin(), val.size());
 }
 
-template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity>
-inline void Vector<T, inlineCapacity, OverflowHandler, minCapacity>::remove(size_t position)
+template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity, typename Malloc>
+inline void Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>::remove(size_t position)
 {
     ASSERT_WITH_SECURITY_IMPLICATION(position < size());
     T* spot = begin() + position;
@@ -1381,8 +1394,8 @@ inline void Vector<T, inlineCapacity, OverflowHandler, minCapacity>::remove(size
     --m_size;
 }
 
-template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity>
-inline void Vector<T, inlineCapacity, OverflowHandler, minCapacity>::remove(size_t position, size_t length)
+template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity, typename Malloc>
+inline void Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>::remove(size_t position, size_t length)
 {
     ASSERT_WITH_SECURITY_IMPLICATION(position <= size());
     ASSERT_WITH_SECURITY_IMPLICATION(position + length <= size());
@@ -1394,18 +1407,18 @@ inline void Vector<T, inlineCapacity, OverflowHandler, minCapacity>::remove(size
     m_size -= length;
 }
 
-template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity>
+template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity, typename Malloc>
 template<typename U>
-inline bool Vector<T, inlineCapacity, OverflowHandler, minCapacity>::removeFirst(const U& value)
+inline bool Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>::removeFirst(const U& value)
 {
     return removeFirstMatching([&value] (const T& current) {
         return current == value;
     });
 }
 
-template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity>
+template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity, typename Malloc>
 template<typename MatchFunction>
-inline bool Vector<T, inlineCapacity, OverflowHandler, minCapacity>::removeFirstMatching(const MatchFunction& matches, size_t startIndex)
+inline bool Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>::removeFirstMatching(const MatchFunction& matches, size_t startIndex)
 {
     for (size_t i = startIndex; i < size(); ++i) {
         if (matches(at(i))) {
@@ -1416,18 +1429,18 @@ inline bool Vector<T, inlineCapacity, OverflowHandler, minCapacity>::removeFirst
     return false;
 }
 
-template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity>
+template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity, typename Malloc>
 template<typename U>
-inline unsigned Vector<T, inlineCapacity, OverflowHandler, minCapacity>::removeAll(const U& value)
+inline unsigned Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>::removeAll(const U& value)
 {
     return removeAllMatching([&value] (const T& current) {
         return current == value;
     });
 }
 
-template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity>
+template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity, typename Malloc>
 template<typename MatchFunction>
-inline unsigned Vector<T, inlineCapacity, OverflowHandler, minCapacity>::removeAllMatching(const MatchFunction& matches, size_t startIndex)
+inline unsigned Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>::removeAllMatching(const MatchFunction& matches, size_t startIndex)
 {
     iterator holeBegin = end();
     iterator holeEnd = end();
@@ -1452,15 +1465,16 @@ inline unsigned Vector<T, inlineCapacity, OverflowHandler, minCapacity>::removeA
     return matchCount;
 }
 
-template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity>
-inline void Vector<T, inlineCapacity, OverflowHandler, minCapacity>::reverse()
+template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity, typename Malloc>
+inline void Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>::reverse()
 {
     for (size_t i = 0; i < m_size / 2; ++i)
         std::swap(at(i), at(m_size - 1 - i));
 }
 
-template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity> template<typename MapFunction, typename R>
-inline Vector<R> Vector<T, inlineCapacity, OverflowHandler, minCapacity>::map(MapFunction mapFunction) const
+template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity, typename Malloc>
+template<typename MapFunction, typename R>
+inline Vector<R> Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>::map(MapFunction mapFunction) const
 {
     Vector<R> result;
     result.reserveInitialCapacity(size());
@@ -1469,8 +1483,8 @@ inline Vector<R> Vector<T, inlineCapacity, OverflowHandler, minCapacity>::map(Ma
     return result;
 }
 
-template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity>
-inline MallocPtr<T> Vector<T, inlineCapacity, OverflowHandler, minCapacity>::releaseBuffer()
+template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity, typename Malloc>
+inline MallocPtr<T> Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>::releaseBuffer()
 {
     // FIXME: Find a way to preserve annotations on the returned buffer.
     // ASan requires that all annotations are removed before deallocation,
@@ -1483,7 +1497,7 @@ inline MallocPtr<T> Vector<T, inlineCapacity, OverflowHandler, minCapacity>::rel
         // that means it was using the inline buffer. In that case,
         // we create a brand new buffer so the caller always gets one.
         size_t bytes = m_size * sizeof(T);
-        buffer = adoptMallocPtr(static_cast<T*>(fastMalloc(bytes)));
+        buffer = adoptMallocPtr(static_cast<T*>(Malloc::malloc(bytes)));
         memcpy(buffer.get(), data(), bytes);
     }
     m_size = 0;
@@ -1491,8 +1505,8 @@ inline MallocPtr<T> Vector<T, inlineCapacity, OverflowHandler, minCapacity>::rel
     return buffer;
 }
 
-template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity>
-inline void Vector<T, inlineCapacity, OverflowHandler, minCapacity>::checkConsistency()
+template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity, typename Malloc>
+inline void Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>::checkConsistency()
 {
 #if !ASSERT_DISABLED
     for (size_t i = 0; i < size(); ++i)
@@ -1500,14 +1514,14 @@ inline void Vector<T, inlineCapacity, OverflowHandler, minCapacity>::checkConsis
 #endif
 }
 
-template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity>
-inline void swap(Vector<T, inlineCapacity, OverflowHandler, minCapacity>& a, Vector<T, inlineCapacity, OverflowHandler, minCapacity>& b)
+template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity, typename Malloc>
+inline void swap(Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>& a, Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>& b)
 {
     a.swap(b);
 }
 
-template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity>
-bool operator==(const Vector<T, inlineCapacity, OverflowHandler, minCapacity>& a, const Vector<T, inlineCapacity, OverflowHandler, minCapacity>& b)
+template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity, typename Malloc>
+bool operator==(const Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>& a, const Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>& b)
 {
     if (a.size() != b.size())
         return false;
@@ -1515,8 +1529,8 @@ bool operator==(const Vector<T, inlineCapacity, OverflowHandler, minCapacity>& a
     return VectorTypeOperations<T>::compare(a.data(), b.data(), a.size());
 }
 
-template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity>
-inline bool operator!=(const Vector<T, inlineCapacity, OverflowHandler, minCapacity>& a, const Vector<T, inlineCapacity, OverflowHandler, minCapacity>& b)
+template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity, typename Malloc>
+inline bool operator!=(const Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>& a, const Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>& b)
 {
     return !(a == b);
 }
@@ -1540,8 +1554,8 @@ size_t removeRepeatedElements(VectorType& vector, const Func& func)
     return newSize;
 }
 
-template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity>
-size_t removeRepeatedElements(Vector<T, inlineCapacity, OverflowHandler, minCapacity>& vector)
+template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity, typename Malloc>
+size_t removeRepeatedElements(Vector<T, inlineCapacity, OverflowHandler, minCapacity, Malloc>& vector)
 {
     return removeRepeatedElements(vector, [] (T& a, T& b) { return a == b; });
 }
index 2876376..126319f 100644 (file)
@@ -103,7 +103,7 @@ private:
 #if !ASSERT_DISABLED
 // AtomicStringImpls created from StaticStringImpl will ASSERT
 // in the generic ValueCheck<T>::checkConsistency
-// as they are not allocated by fastMalloc.
+// as they are not allocated by StringMalloc.
 // We don't currently have any way to detect that case
 // so we ignore the consistency check for all AtomicStringImpls*.
 template<> struct
index 21b37eb..735cfc5 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2003, 2006, 2008, 2009, 2010, 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2003-2017 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,6 +29,7 @@
 
 #include <string.h>
 #include <wtf/Hasher.h>
+#include <wtf/text/StringMalloc.h>
 
 namespace WTF {
 
@@ -38,7 +39,7 @@ Ref<CStringBuffer> CStringBuffer::createUninitialized(size_t length)
 
     // The +1 is for the terminating null character.
     size_t size = sizeof(CStringBuffer) + length + 1;
-    CStringBuffer* stringBuffer = static_cast<CStringBuffer*>(fastMalloc(size));
+    CStringBuffer* stringBuffer = static_cast<CStringBuffer*>(stringMalloc(size));
     return adoptRef(*new (NotNull, stringBuffer) CStringBuffer(length));
 }
 
index 4d8d803..bd16f6d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2003, 2006, 2008, 2009, 2010, 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2003-2017 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
 #include <wtf/HashTraits.h>
 #include <wtf/Ref.h>
 #include <wtf/RefCounted.h>
+#include <wtf/text/StringMalloc.h>
 
 namespace WTF {
 
 // CStringBuffer is the ref-counted storage class for the characters in a CString.
 // The data is implicitly allocated 1 character longer than length(), as it is zero-terminated.
 class CStringBuffer : public RefCounted<CStringBuffer> {
+    WTF_MAKE_STRING_ALLOCATED;
 public:
     const char* data() { return mutableData(); }
     size_t length() const { return m_length; }
index f293d33..57a1ea2 100644 (file)
@@ -30,6 +30,7 @@
 #define StringBuffer_h
 
 #include <wtf/Assertions.h>
+#include <wtf/text/StringMalloc.h>
 #include <limits>
 #include <unicode/utypes.h>
 
@@ -41,13 +42,13 @@ class StringBuffer {
 public:
     explicit StringBuffer(unsigned length)
         : m_length(length)
-        , m_data(m_length ? static_cast<CharType*>(fastMalloc((Checked<size_t>(m_length) * sizeof(CharType)).unsafeGet())) : nullptr)
+        , m_data(m_length ? static_cast<CharType*>(stringMalloc((Checked<size_t>(m_length) * sizeof(CharType)).unsafeGet())) : nullptr)
     {
     }
 
     ~StringBuffer()
     {
-        fastFree(m_data);
+        stringFree(m_data);
     }
 
     void shrink(unsigned newLength)
@@ -61,7 +62,7 @@ public:
         if (newLength > m_length) {
             if (newLength > std::numeric_limits<unsigned>::max() / sizeof(UChar))
                 CRASH();
-            m_data = static_cast<UChar*>(fastRealloc(m_data, newLength * sizeof(UChar)));
+            m_data = static_cast<UChar*>(stringRealloc(m_data, newLength * sizeof(UChar)));
         }
         m_length = newLength;
     }
index 5f865a4..32d973e 100644 (file)
@@ -2,7 +2,7 @@
  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
  *           (C) 2001 Dirk Mueller ( mueller@kde.org )
- * Copyright (C) 2003-2009, 2013-2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2003-2017 Apple Inc. All rights reserved.
  * Copyright (C) 2006 Andrew Wellington (proton@wiretapped.net)
  *
  * This library is free software; you can redistribute it and/or
 #include "AtomicString.h"
 #include "StringBuffer.h"
 #include "StringHash.h"
+#include <wtf/Gigacage.h>
 #include <wtf/ProcessID.h>
 #include <wtf/StdLibExtras.h>
 #include <wtf/text/CString.h>
+#include <wtf/text/StringMalloc.h>
 #include <wtf/text/StringView.h>
 #include <wtf/text/SymbolImpl.h>
 #include <wtf/text/SymbolRegistry.h>
@@ -129,7 +131,7 @@ StringImpl::~StringImpl()
     if (ownership == BufferOwned) {
         // We use m_data8, but since it is a union with m_data16 this works either way.
         ASSERT(m_data8);
-        fastFree(const_cast<LChar*>(m_data8));
+        stringFree(const_cast<LChar*>(m_data8));
         return;
     }
 
@@ -141,7 +143,7 @@ StringImpl::~StringImpl()
 void StringImpl::destroy(StringImpl* stringImpl)
 {
     stringImpl->~StringImpl();
-    fastFree(stringImpl);
+    stringFree(stringImpl);
 }
 
 Ref<StringImpl> StringImpl::createFromLiteral(const char* characters, unsigned length)
@@ -192,7 +194,7 @@ inline Ref<StringImpl> StringImpl::createUninitializedInternalNonEmpty(unsigned
     // heap allocation from this call.
     if (length > ((std::numeric_limits<unsigned>::max() - sizeof(StringImpl)) / sizeof(CharType)))
         CRASH();
-    StringImpl* string = static_cast<StringImpl*>(fastMalloc(allocationSize<CharType>(length)));
+    StringImpl* string = static_cast<StringImpl*>(stringMalloc(allocationSize<CharType>(length)));
 
     data = string->tailPointer<CharType>();
     return constructInternal<CharType>(string, length);
@@ -219,12 +221,12 @@ inline Ref<StringImpl> StringImpl::reallocateInternal(Ref<StringImpl>&& original
         return *empty();
     }
 
-    // Same as createUninitialized() except here we use fastRealloc.
+    // Same as createUninitialized() except here we use stringRealloc.
     if (length > ((std::numeric_limits<unsigned>::max() - sizeof(StringImpl)) / sizeof(CharType)))
         CRASH();
 
     originalString->~StringImpl();
-    auto* string = static_cast<StringImpl*>(fastRealloc(&originalString.leakRef(), allocationSize<CharType>(length)));
+    auto* string = static_cast<StringImpl*>(stringRealloc(&originalString.leakRef(), allocationSize<CharType>(length)));
 
     data = string->tailPointer<CharType>();
     return constructInternal<CharType>(string, length);
@@ -2177,4 +2179,14 @@ bool equalIgnoringNullity(const UChar* a, size_t aLength, StringImpl* b)
     return !memcmp(a, b->characters16(), b->length() * sizeof(UChar));
 }
 
+void StringImpl::releaseAssertCaged() const
+{
+    if (isStatic())
+        return;
+    RELEASE_ASSERT(!GIGACAGE_ENABLED || Gigacage::isCaged(Gigacage::String, this));
+    if (bufferOwnership() != BufferOwned)
+        return;
+    RELEASE_ASSERT(!GIGACAGE_ENABLED || Gigacage::isCaged(Gigacage::String, m_data8));
+}
+
 } // namespace WTF
index 96e85d5..286ddd0 100644 (file)
@@ -35,6 +35,8 @@
 #include <wtf/Vector.h>
 #include <wtf/text/ConversionMode.h>
 #include <wtf/text/StringCommon.h>
+#include <wtf/text/StringMalloc.h>
+#include <wtf/text/StringVector.h>
 
 #if USE(CF)
 typedef const struct __CFString * CFStringRef;
@@ -178,7 +180,7 @@ protected:
 };
 
 class StringImpl : private StringImplShape {
-    WTF_MAKE_NONCOPYABLE(StringImpl); WTF_MAKE_FAST_ALLOCATED;
+    WTF_MAKE_NONCOPYABLE(StringImpl); WTF_MAKE_STRING_ALLOCATED;
     friend struct WTF::CStringTranslator;
     template<typename CharacterType> friend struct WTF::HashAndCharactersTranslator;
     friend struct WTF::HashAndUTF8CharactersTranslator;
@@ -193,7 +195,7 @@ class StringImpl : private StringImplShape {
     friend class PrivateSymbolImpl;
     friend class RegisteredSymbolImpl;
     
-private:
+public:
     enum BufferOwnership {
         BufferInternal,
         BufferOwned,
@@ -201,7 +203,6 @@ private:
     };
 
     // The bottom 6 bits in the hash are flags.
-public:
     static constexpr const unsigned s_flagCount = 6;
 private:
     static constexpr const unsigned s_flagMask = (1u << s_flagCount) - 1;
@@ -337,7 +338,7 @@ public:
         auto* ownerRep = ((rep.bufferOwnership() == BufferSubstring) ? rep.substringBuffer() : &rep);
 
         // We allocate a buffer that contains both the StringImpl struct as well as the pointer to the owner string.
-        auto* stringImpl = static_cast<StringImpl*>(fastMalloc(allocationSize<StringImpl*>(1)));
+        auto* stringImpl = static_cast<StringImpl*>(stringMalloc(allocationSize<StringImpl*>(1)));
         if (rep.is8Bit())
             return adoptRef(*new (NotNull, stringImpl) StringImpl(rep.m_data8 + offset, length, *ownerRep));
         return adoptRef(*new (NotNull, stringImpl) StringImpl(rep.m_data16 + offset, length, *ownerRep));
@@ -372,8 +373,8 @@ public:
             output = nullptr;
             return nullptr;
         }
-        StringImpl* resultImpl;
-        if (!tryFastMalloc(allocationSize<T>(length)).getValue(resultImpl)) {
+        StringImpl* resultImpl = static_cast<StringImpl*>(tryStringMalloc(allocationSize<T>(length)));
+        if (!resultImpl) {
             output = nullptr;
             return nullptr;
         }
@@ -395,8 +396,8 @@ public:
     static unsigned maskStringKind() { return s_hashMaskStringKind; }
     static unsigned dataOffset() { return OBJECT_OFFSETOF(StringImpl, m_data8); }
 
-    template<typename CharType, size_t inlineCapacity, typename OverflowHandler>
-    static Ref<StringImpl> adopt(Vector<CharType, inlineCapacity, OverflowHandler>&& vector)
+    template<typename CharType, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity>
+    static Ref<StringImpl> adopt(StringVector<CharType, inlineCapacity, OverflowHandler, minCapacity>&& vector)
     {
         if (size_t size = vector.size()) {
             ASSERT(vector.data());
@@ -757,6 +758,16 @@ public:
     ALWAYS_INLINE static StringStats& stringStats() { return m_stringStats; }
 #endif
 
+    BufferOwnership bufferOwnership() const { return static_cast<BufferOwnership>(m_hashAndFlags & s_hashMaskBufferOwnership); }
+    
+    void assertCaged() const
+    {
+        if (!ASSERT_DISABLED)
+            releaseAssertCaged();
+    }
+    
+    WTF_EXPORT_PRIVATE void releaseAssertCaged() const;
+
 protected:
     ~StringImpl();
 
@@ -846,7 +857,6 @@ private:
     enum class CaseConvertType { Upper, Lower };
     template<CaseConvertType type, typename CharacterType> static Ref<StringImpl> convertASCIICase(StringImpl&, const CharacterType*, unsigned);
 
-    BufferOwnership bufferOwnership() const { return static_cast<BufferOwnership>(m_hashAndFlags & s_hashMaskBufferOwnership); }
     template <class UCharPredicate> Ref<StringImpl> stripMatchedCharacters(UCharPredicate);
     template <typename CharType, class UCharPredicate> Ref<StringImpl> simplifyMatchedCharactersToSpace(UCharPredicate);
     template <typename CharType> static Ref<StringImpl> constructInternal(StringImpl*, unsigned);
@@ -881,7 +891,7 @@ static_assert(sizeof(StringImpl) == sizeof(StaticStringImpl), "");
 #if !ASSERT_DISABLED
 // StringImpls created from StaticStringImpl will ASSERT
 // in the generic ValueCheck<T>::checkConsistency
-// as they are not allocated by fastMalloc.
+// as they are not allocated by stringMalloc.
 // We don't currently have any way to detect that case
 // so we ignore the consistency check for all StringImpl*.
 template<> struct
diff --git a/Source/WTF/wtf/text/StringMalloc.cpp b/Source/WTF/wtf/text/StringMalloc.cpp
new file mode 100644 (file)
index 0000000..b64a32d
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2017 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. 
+ */
+
+#include "config.h"
+#include "StringMalloc.h"
+
+#include <wtf/DataLog.h>
+#include <wtf/FastMalloc.h>
+#include <wtf/Gigacage.h>
+#include <wtf/RawPointer.h>
+
+#if !(defined(USE_SYSTEM_MALLOC) && USE_SYSTEM_MALLOC)
+#include <bmalloc/bmalloc.h>
+#endif
+
+namespace WTF {
+
+#if defined(USE_SYSTEM_MALLOC) && USE_SYSTEM_MALLOC
+void* tryStringMalloc(size_t size)
+{
+    return FastMalloc::tryMalloc(size);
+}
+
+void* stringMalloc(size_t size)
+{
+    return fastMalloc(size);
+}
+
+void* stringRealloc(void* p, size_t size)
+{
+    return fastRealloc(p, size);
+}
+
+void stringFree(void* p)
+{
+    return fastFree(p);
+}
+#else
+void* tryStringMalloc(size_t size)
+{
+    return bmalloc::api::tryMalloc(size, bmalloc::HeapKind::StringGigacage);
+}
+
+void* stringMalloc(size_t size)
+{
+    return bmalloc::api::malloc(size, bmalloc::HeapKind::StringGigacage);
+}
+
+void* stringRealloc(void* p, size_t size)
+{
+    return bmalloc::api::realloc(p, size, bmalloc::HeapKind::StringGigacage);
+}
+
+void stringFree(void* p)
+{
+    if (!p)
+        return;
+    if (UNLIKELY(!Gigacage::isCaged(Gigacage::String, p))) {
+        dataLog("Trying to free string that is not caged: ", RawPointer(p), "\n");
+        RELEASE_ASSERT_NOT_REACHED();
+    }
+    bmalloc::api::free(p, bmalloc::HeapKind::StringGigacage);
+}
+#endif
+
+} // namespace WTF
+
diff --git a/Source/WTF/wtf/text/StringMalloc.h b/Source/WTF/wtf/text/StringMalloc.h
new file mode 100644 (file)
index 0000000..b6b6ad2
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2017 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/FastMalloc.h>
+
+namespace WTF {
+
+WTF_EXPORT_PRIVATE void* tryStringMalloc(size_t);
+WTF_EXPORT_PRIVATE void* stringMalloc(size_t);
+WTF_EXPORT_PRIVATE void* stringRealloc(void*, size_t);
+WTF_EXPORT_PRIVATE void stringFree(void*);
+
+#define WTF_MAKE_STRING_ALLOCATED \
+public: \
+    void* operator new(size_t, void* p) { return p; } \
+    void* operator new[](size_t, void* p) { return p; } \
+    \
+    void* operator new(size_t size) \
+    { \
+        return ::WTF::stringMalloc(size); \
+    } \
+    \
+    void operator delete(void* p) \
+    { \
+        ::WTF::stringFree(p); \
+    } \
+    \
+    void* operator new[](size_t size) \
+    { \
+        return ::WTF::stringMalloc(size); \
+    } \
+    \
+    void operator delete[](void* p) \
+    { \
+        ::WTF::stringFree(p); \
+    } \
+    void* operator new(size_t, NotNullTag, void* location) \
+    { \
+        ASSERT(location); \
+        return location; \
+    } \
+private: \
+typedef int __thisIsHereToForceASemicolonAfterThisMacro
+
+
+struct StringMalloc {
+    static void* malloc(size_t size) { return stringMalloc(size); }
+    static void* tryMalloc(size_t size) { return tryStringMalloc(size); }
+    static void* realloc(void* p, size_t size) { return stringRealloc(p, size); }
+    static void free(void* p) { stringFree(p); }
+};
+
+} // namespace WTF
+
+using WTF::StringMalloc;
+using WTF::stringMalloc;
+using WTF::stringRealloc;
+using WTF::stringFree;
+using WTF::tryStringMalloc;
diff --git a/Source/WTF/wtf/text/StringVector.h b/Source/WTF/wtf/text/StringVector.h
new file mode 100644 (file)
index 0000000..63c611c
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2017 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/Vector.h>
+#include <wtf/text/StringMalloc.h>
+
+namespace WTF {
+
+template<typename T, size_t inlineCapacity = 0, typename OverflowHandler = CrashOnOverflow, size_t minCapacity = 16> using StringVector = Vector<T, inlineCapacity, OverflowHandler, minCapacity, StringMalloc>;
+
+} // namespace WTF
+
+using WTF::StringVector;
index 8c50145..d4c3f66 100644 (file)
@@ -202,7 +202,7 @@ inline RegisteredSymbolImpl* SymbolImpl::asRegisteredSymbolImpl()
 #if !ASSERT_DISABLED
 // SymbolImpls created from StaticStringImpl will ASSERT
 // in the generic ValueCheck<T>::checkConsistency
-// as they are not allocated by fastMalloc.
+// as they are not allocated by stringMalloc.
 // We don't currently have any way to detect that case
 // so we ignore the consistency check for all SymbolImpls*.
 template<> struct
index 09aba85..cdd0343 100644 (file)
@@ -44,7 +44,7 @@ protected:
 #if !ASSERT_DISABLED
 // UniquedStringImpls created from StaticStringImpl will ASSERT
 // in the generic ValueCheck<T>::checkConsistency
-// as they are not allocated by fastMalloc.
+// as they are not allocated by stringMalloc.
 // We don't currently have any way to detect that case
 // so we ignore the consistency check for all UniquedStringImpls*.
 template<> struct
index 2a67322..3a97b16 100644 (file)
@@ -146,8 +146,8 @@ public:
 
     static String adopt(StringBuffer<LChar>&& buffer) { return StringImpl::adopt(WTFMove(buffer)); }
     static String adopt(StringBuffer<UChar>&& buffer) { return StringImpl::adopt(WTFMove(buffer)); }
-    template<typename CharacterType, size_t inlineCapacity, typename OverflowHandler>
-    static String adopt(Vector<CharacterType, inlineCapacity, OverflowHandler>&& vector) { return StringImpl::adopt(WTFMove(vector)); }
+    template<typename CharacterType, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity>
+    static String adopt(StringVector<CharacterType, inlineCapacity, OverflowHandler, minCapacity>&& vector) { return StringImpl::adopt(WTFMove(vector)); }
 
     bool isNull() const { return !m_impl; }
     bool isEmpty() const { return !m_impl || !m_impl->length(); }
@@ -499,6 +499,18 @@ public:
         if (m_impl && m_impl->hasOneRef())
             m_impl = nullptr;
     }
+    
+    void assertCaged() const
+    {
+        if (m_impl)
+            m_impl->assertCaged();
+    }
+
+    void releaseAssertCaged() const
+    {
+        if (m_impl)
+            m_impl->releaseAssertCaged();
+    }
 
 private:
     template <typename CharacterType>
index c5aba77..2c2f188 100644 (file)
@@ -1,3 +1,15 @@
+2017-08-22  Filip Pizlo  <fpizlo@apple.com>
+
+        Strings need to be in some kind of gigacage
+        https://bugs.webkit.org/show_bug.cgi?id=174924
+
+        Reviewed by Oliver Hunt.
+
+        No new tests because no new behavior.
+
+        * html/canvas/CanvasRenderingContext2D.cpp:
+        (WebCore::normalizeSpaces):
+
 2017-08-30  Andy Estes  <aestes@apple.com>
 
         [Mac] Upstream Accessibility-related WebKitSystemInterface functions
index 98d09be..915ef3f 100644 (file)
@@ -326,7 +326,7 @@ static bool decodeKey(const uint8_t*& data, const uint8_t* end, IDBKeyData& resu
         if (static_cast<uint64_t>(end - data) < length * 2)
             return false;
 
-        Vector<UChar> buffer;
+        StringVector<UChar> buffer;
         buffer.reserveInitialCapacity(length);
         for (size_t i = 0; i < length; i++) {
             uint16_t ch;
index 93b890c..96a651f 100644 (file)
@@ -1950,7 +1950,7 @@ private:
         str = String(reinterpret_cast<const UChar*>(ptr), length);
         ptr += length * sizeof(UChar);
 #else
-        Vector<UChar> buffer;
+        StringVector<UChar> buffer;
         buffer.reserveCapacity(length);
         for (unsigned i = 0; i < length; i++) {
             uint16_t ch;
index 281cf0c..fbb4a78 100644 (file)
@@ -2325,7 +2325,7 @@ static void normalizeSpaces(String& text)
         return;
 
     unsigned textLength = text.length();
-    Vector<UChar> charVector(textLength);
+    StringVector<UChar> charVector(textLength);
     StringView(text).getCharactersWithUpconvert(charVector.data());
 
     charVector[i++] = ' ';
index f4f806f..53ea8b0 100644 (file)
@@ -205,7 +205,7 @@ public:
     String takeRemainingWhitespace()
     {
         ASSERT(!isEmpty());
-        Vector<LChar, 8> whitespace;
+        StringVector<LChar, 8> whitespace;
         do {
             UChar character = m_text[0];
             if (isHTMLSpace(character))
index 44fe1f7..154512c 100644 (file)
@@ -533,7 +533,7 @@ bool URLParser::shouldCopyFileURL(CodePointIterator<CharacterType> iterator)
     return !isSlashQuestionOrHash(*iterator);
 }
 
-static void percentEncodeByte(uint8_t byte, Vector<LChar>& buffer)
+static void percentEncodeByte(uint8_t byte, StringVector<LChar>& buffer)
 {
     buffer.append('%');
     buffer.append(upperNibbleToASCIIHexDigit(byte));
@@ -2814,7 +2814,7 @@ auto URLParser::parseURLEncodedForm(StringView input) -> URLEncodedForm
     return output;
 }
 
-static void serializeURLEncodedForm(const String& input, Vector<LChar>& output)
+static void serializeURLEncodedForm(const String& input, StringVector<LChar>& output)
 {
     auto utf8 = input.utf8(StrictConversion);
     const char* data = utf8.data();
@@ -2840,7 +2840,7 @@ String URLParser::serialize(const URLEncodedForm& tuples)
     if (tuples.isEmpty())
         return { };
 
-    Vector<LChar> output;
+    StringVector<LChar> output;
     for (auto& tuple : tuples) {
         if (!output.isEmpty())
             output.append('&');
index 5708a4f..3719e39 100644 (file)
@@ -58,7 +58,7 @@ private:
     friend std::optional<uint16_t> defaultPortForProtocol(StringView);
 
     URL m_url;
-    Vector<LChar> m_asciiBuffer;
+    StringVector<LChar> m_asciiBuffer;
     bool m_urlIsSpecial { false };
     bool m_urlIsFile { false };
     bool m_hostHasPercentOrNonASCII { false };
index d9a8962..98a20dc 100644 (file)
@@ -42,7 +42,7 @@ std::optional<FourCC> FourCC::fromString(const String& stringValue)
 
 String FourCC::toString() const
 {
-    Vector<LChar, 4> data = {
+    StringVector<LChar, 4> data = {
         LChar(value >> 24),
         LChar((value >> 16) & 0xFF),
         LChar((value >> 8) & 0xFF),
index 184361b..f425797 100644 (file)
@@ -2698,7 +2698,7 @@ GraphicsLayerCA::CloneID GraphicsLayerCA::ReplicaState::cloneID() const
     const size_t bitsPerUChar = sizeof(UChar) * 8;
     size_t vectorSize = (depth + bitsPerUChar - 1) / bitsPerUChar;
     
-    Vector<UChar> result(vectorSize);
+    StringVector<UChar> result(vectorSize);
     result.fill(0);
 
     // Create a string from the bit sequence which we can use to identify the clone.
index 88151ea..0052cc4 100644 (file)
@@ -73,7 +73,7 @@ String LocaleICU::decimalSymbol(UNumberFormatSymbol symbol)
     ASSERT(U_SUCCESS(status) || status == U_BUFFER_OVERFLOW_ERROR);
     if (U_FAILURE(status) && status != U_BUFFER_OVERFLOW_ERROR)
         return String();
-    Vector<UChar> buffer(bufferLength);
+    StringVector<UChar> buffer(bufferLength);
     status = U_ZERO_ERROR;
     unum_getSymbol(m_numberFormat, symbol, buffer.data(), bufferLength, &status);
     if (U_FAILURE(status))
@@ -88,7 +88,7 @@ String LocaleICU::decimalTextAttribute(UNumberFormatTextAttribute tag)
     ASSERT(U_SUCCESS(status) || status == U_BUFFER_OVERFLOW_ERROR);
     if (U_FAILURE(status) && status != U_BUFFER_OVERFLOW_ERROR)
         return String();
-    Vector<UChar> buffer(bufferLength);
+    StringVector<UChar> buffer(bufferLength);
     status = U_ZERO_ERROR;
     unum_getTextAttribute(m_numberFormat, tag, buffer.data(), bufferLength, &status);
     ASSERT(U_SUCCESS(status));
@@ -153,7 +153,7 @@ static String getDateFormatPattern(const UDateFormat* dateFormat)
     int32_t length = udat_toPattern(dateFormat, TRUE, 0, 0, &status);
     if (status != U_BUFFER_OVERFLOW_ERROR || !length)
         return emptyString();
-    Vector<UChar> buffer(length);
+    StringVector<UChar> buffer(length);
     status = U_ZERO_ERROR;
     udat_toPattern(dateFormat, TRUE, buffer.data(), length, &status);
     if (U_FAILURE(status))
@@ -175,7 +175,7 @@ std::unique_ptr<Vector<String>> LocaleICU::createLabelVector(const UDateFormat*
         int32_t length = udat_getSymbols(dateFormat, type, startIndex + i, 0, 0, &status);
         if (status != U_BUFFER_OVERFLOW_ERROR)
             return std::make_unique<Vector<String>>();
-        Vector<UChar> buffer(length);
+        StringVector<UChar> buffer(length);
         status = U_ZERO_ERROR;
         udat_getSymbols(dateFormat, type, startIndex + i, buffer.data(), length, &status);
         if (U_FAILURE(status))
@@ -266,7 +266,7 @@ static String getFormatForSkeleton(const char* locale, const UChar* skeleton, in
     status = U_ZERO_ERROR;
     int32_t length = udatpg_getBestPattern(patternGenerator, skeleton, skeletonLength, 0, 0, &status);
     if (status == U_BUFFER_OVERFLOW_ERROR && length) {
-        Vector<UChar> buffer(length);
+        StringVector<UChar> buffer(length);
         status = U_ZERO_ERROR;
         udatpg_getBestPattern(patternGenerator, skeleton, skeletonLength, buffer.data(), length, &status);
         if (U_SUCCESS(status))
index 344b606..74f1807 100644 (file)
@@ -201,7 +201,7 @@ String TextCodecMac::decode(const char* bytes, size_t length, bool flush, bool s
     if (!m_converterTEC && createTECConverter() != noErr)
         return String();
     
-    Vector<UChar> result;
+    StringVector<UChar> result;
 
     const unsigned char* sourcePointer = reinterpret_cast<const unsigned char*>(bytes);
     int sourceLength = length;
index 2d12774..258f19c 100644 (file)
@@ -185,7 +185,7 @@ bool moveFile(const String& oldPath, const String& newPath)
 
 String pathByAppendingComponent(const String& path, const String& component)
 {
-    Vector<UChar> buffer(MAX_PATH);
+    StringVector<UChar> buffer(MAX_PATH);
 
     if (path.length() + 1 > buffer.size())
         return String();
@@ -276,7 +276,7 @@ static String bundleName()
 
 static String storageDirectory(DWORD pathIdentifier)
 {
-    Vector<UChar> buffer(MAX_PATH);
+    StringVector<UChar> buffer(MAX_PATH);
     if (FAILED(SHGetFolderPathW(0, pathIdentifier | CSIDL_FLAG_CREATE, 0, 0, buffer.data())))
         return String();
     buffer.resize(wcslen(buffer.data()));
index 79e8c22..226b00f 100644 (file)
@@ -1,3 +1,22 @@
+2017-08-22  Filip Pizlo  <fpizlo@apple.com>
+
+        Strings need to be in some kind of gigacage
+        https://bugs.webkit.org/show_bug.cgi?id=174924
+
+        Reviewed by Oliver Hunt.
+        
+        This adds a StringGigacage.
+
+        * bmalloc/Gigacage.cpp:
+        * bmalloc/Gigacage.h:
+        (Gigacage::name):
+        (Gigacage::basePtr):
+        (Gigacage::forEachKind):
+        * bmalloc/HeapKind.h:
+        (bmalloc::isGigacage):
+        (bmalloc::gigacageKind):
+        (bmalloc::heapKind):
+
 2017-08-25  Daniel Bates  <dabates@apple.com>
 
         Demarcate code added due to lack of NSDMI for aggregates
index 3381b04..07e67c1 100644 (file)
@@ -36,6 +36,7 @@
 // https://bugs.webkit.org/show_bug.cgi?id=174972
 void* g_primitiveGigacageBasePtr;
 void* g_jsValueGigacageBasePtr;
+void* g_stringGigacageBasePtr;
 
 using namespace bmalloc;
 
index ca67313..be4f88d 100644 (file)
 
 #define PRIMITIVE_GIGACAGE_SIZE 0x800000000llu
 #define JSVALUE_GIGACAGE_SIZE 0x400000000llu
+#define STRING_GIGACAGE_SIZE 0x400000000llu
 
 #define GIGACAGE_SIZE_TO_MASK(size) ((size) - 1)
 
 #define PRIMITIVE_GIGACAGE_MASK GIGACAGE_SIZE_TO_MASK(PRIMITIVE_GIGACAGE_SIZE)
 #define JSVALUE_GIGACAGE_MASK GIGACAGE_SIZE_TO_MASK(JSVALUE_GIGACAGE_SIZE)
+#define STRING_GIGACAGE_MASK GIGACAGE_SIZE_TO_MASK(STRING_GIGACAGE_SIZE)
 
 // FIXME: Consider making this 32GB, in case unsigned 32-bit indices find their way into indexed accesses.
 // https://bugs.webkit.org/show_bug.cgi?id=175062
@@ -47,6 +49,7 @@
 // FIXME: Reconsider this.
 // https://bugs.webkit.org/show_bug.cgi?id=175921
 #define JSVALUE_GIGACAGE_RUNWAY 0
+#define STRING_GIGACAGE_RUNWAY 0
 
 #if BOS(DARWIN) && BCPU(X86_64)
 #define GIGACAGE_ENABLED 1
 
 extern "C" BEXPORT void* g_primitiveGigacageBasePtr;
 extern "C" BEXPORT void* g_jsValueGigacageBasePtr;
+extern "C" BEXPORT void* g_stringGigacageBasePtr;
 
 namespace Gigacage {
 
 enum Kind {
     Primitive,
-    JSValue
+    JSValue,
+    String
 };
 
 BEXPORT void ensureGigacage();
@@ -85,6 +90,8 @@ BINLINE const char* name(Kind kind)
         return "Primitive";
     case JSValue:
         return "JSValue";
+    case String:
+        return "String";
     }
     BCRASH();
     return nullptr;
@@ -97,6 +104,8 @@ BINLINE void*& basePtr(Kind kind)
         return g_primitiveGigacageBasePtr;
     case JSValue:
         return g_jsValueGigacageBasePtr;
+    case String:
+        return g_stringGigacageBasePtr;
     }
     BCRASH();
     return g_primitiveGigacageBasePtr;
@@ -109,6 +118,8 @@ BINLINE size_t size(Kind kind)
         return static_cast<size_t>(PRIMITIVE_GIGACAGE_SIZE);
     case JSValue:
         return static_cast<size_t>(JSVALUE_GIGACAGE_SIZE);
+    case String:
+        return static_cast<size_t>(STRING_GIGACAGE_SIZE);
     }
     BCRASH();
     return 0;
@@ -131,6 +142,8 @@ BINLINE size_t runway(Kind kind)
         return static_cast<size_t>(PRIMITIVE_GIGACAGE_RUNWAY);
     case JSValue:
         return static_cast<size_t>(JSVALUE_GIGACAGE_RUNWAY);
+    case String:
+        return static_cast<size_t>(STRING_GIGACAGE_RUNWAY);
     }
     BCRASH();
     return 0;
@@ -146,6 +159,7 @@ void forEachKind(const Func& func)
 {
     func(Primitive);
     func(JSValue);
+    func(String);
 }
 
 template<typename T>
index 94d4a20..fe8762d 100644 (file)
@@ -34,10 +34,11 @@ namespace bmalloc {
 enum class HeapKind {
     Primary,
     PrimitiveGigacage,
-    JSValueGigacage
+    JSValueGigacage,
+    StringGigacage
 };
 
-static constexpr unsigned numHeaps = 3;
+static constexpr unsigned numHeaps = 4;
 
 BINLINE bool isGigacage(HeapKind heapKind)
 {
@@ -46,6 +47,7 @@ BINLINE bool isGigacage(HeapKind heapKind)
         return false;
     case HeapKind::PrimitiveGigacage:
     case HeapKind::JSValueGigacage:
+    case HeapKind::StringGigacage:
         return true;
     }
     BCRASH();
@@ -62,6 +64,8 @@ BINLINE Gigacage::Kind gigacageKind(HeapKind kind)
         return Gigacage::Primitive;
     case HeapKind::JSValueGigacage:
         return Gigacage::JSValue;
+    case HeapKind::StringGigacage:
+        return Gigacage::String;
     }
     BCRASH();
     return Gigacage::Primitive;
@@ -74,6 +78,8 @@ BINLINE HeapKind heapKind(Gigacage::Kind kind)
         return HeapKind::PrimitiveGigacage;
     case Gigacage::JSValue:
         return HeapKind::JSValueGigacage;
+    case Gigacage::String:
+        return HeapKind::StringGigacage;
     }
     BCRASH();
     return HeapKind::Primary;