Title: [287220] trunk
Revision
287220
Author
[email protected]
Date
2021-12-18 02:17:05 -0800 (Sat, 18 Dec 2021)

Log Message

[WTF] Introduce TrailingArray
https://bugs.webkit.org/show_bug.cgi?id=234201

Reviewed by Darin Adler.

Source/_javascript_Core:

Use ThreadSafeRefCountedFixedVector in ObjectPropertyConditionSet and Wasm::LLIntCallees.

* bytecode/CodeBlock.h:
(JSC::CodeBlock::baselineJITConstantPool):
* bytecode/ObjectPropertyConditionSet.cpp:
(JSC::ObjectPropertyConditionSet::mergedWith const):
(JSC::ObjectPropertyConditionSet::dumpInContext const):
(JSC::ObjectPropertyConditionSet::isValidAndWatchable const):
* bytecode/ObjectPropertyConditionSet.h:
(JSC::ObjectPropertyConditionSet::invalid):
(JSC::ObjectPropertyConditionSet::create):
(JSC::ObjectPropertyConditionSet::isValid const):
(JSC::ObjectPropertyConditionSet::size const):
(JSC::ObjectPropertyConditionSet::begin const):
(JSC::ObjectPropertyConditionSet::end const):
(JSC::ObjectPropertyConditionSet::ObjectPropertyConditionSet): Deleted.
(JSC::ObjectPropertyConditionSet::releaseRawPointer): Deleted.
(JSC::ObjectPropertyConditionSet::adoptRawPointer): Deleted.
(JSC::ObjectPropertyConditionSet::fromRawPointer): Deleted.
(JSC::ObjectPropertyConditionSet::Data::Data): Deleted.
* jit/JIT.cpp:
(JSC::JIT::compileAndLinkWithoutFinalizing):
* jit/JITInlines.h:
(JSC::JIT::loadConstant):
* llint/LLIntOffsetsExtractor.cpp:
* llint/LowLevelInterpreter.asm:
* llint/LowLevelInterpreter32_64.asm:
* llint/LowLevelInterpreter64.asm:
* wasm/WasmCallee.h:
(JSC::Wasm::LLIntCallees::create): Deleted.
(JSC::Wasm::LLIntCallees::at const): Deleted.
(JSC::Wasm::LLIntCallees::data const): Deleted.
(JSC::Wasm::LLIntCallees::LLIntCallees): Deleted.
* wasm/WasmCodeBlock.cpp:
(JSC::Wasm::CodeBlock::create):
(JSC::Wasm::CodeBlock::CodeBlock):
* wasm/WasmCodeBlock.h:
* wasm/WasmModule.cpp:
(JSC::Wasm::Module::Module):
(JSC::Wasm::Module::getOrCreateCodeBlock):
* wasm/WasmModule.h:

Source/WTF:

This patch implements TrailingArray<Derived, T>, which allows us to implement class
with trailing array easily. By using this, we implement EmbeddedFixedVector and RefCountedFixedVector.
Plus, we replace underlying implementation of FixedVector from RefCountedArray to EmbeddedFixedVector
since ref-counting is not necessary. This is great for swapping: while RefCountedArray will decrease ref
and touching memory when destryoing, EmbeddedFixedVector does not, so we can keep memory untouched if
EmbeddedFixedVector's T is POD when destroying.

In a subsequent patch, we will remove RefCountedArray and use RefCountedFixedVector since RefCountedFixedVector
is following normal Ref / RefPtr protocol, so easy to understand the semantics.

* WTF.xcodeproj/project.pbxproj:
* wtf/CMakeLists.txt:
* wtf/EmbeddedFixedVector.h: Added.
* wtf/FixedVector.h:
(WTF::FixedVector::FixedVector):
(WTF::FixedVector::operator=):
(WTF::FixedVector::size const):
(WTF::FixedVector::isEmpty const):
(WTF::FixedVector::byteSize const):
(WTF::FixedVector::data):
(WTF::FixedVector::begin):
(WTF::FixedVector::end):
(WTF::FixedVector::rbegin):
(WTF::FixedVector::rend):
(WTF::FixedVector::rbegin const):
(WTF::FixedVector::rend const):
(WTF::FixedVector::at):
(WTF::FixedVector::at const):
(WTF::FixedVector::operator[]):
(WTF::FixedVector::operator[] const):
(WTF::FixedVector::fill):
(WTF::FixedVector::operator!= const):
(WTF::FixedVector::operator== const):
(WTF::FixedVector::swap):
(WTF::FixedVector::getStorage):
* wtf/RefCountedFixedVector.h: Added.
* wtf/TrailingArray.h: Added.
(WTF::TrailingArray::TrailingArray):
(WTF::TrailingArray::~TrailingArray):
(WTF::TrailingArray::allocationSize):
(WTF::TrailingArray::size const):
(WTF::TrailingArray::isEmpty const):
(WTF::TrailingArray::byteSize const):
(WTF::TrailingArray::data):
(WTF::TrailingArray::data const):
(WTF::TrailingArray::begin):
(WTF::TrailingArray::end):
(WTF::TrailingArray::begin const):
(WTF::TrailingArray::end const):
(WTF::TrailingArray::cbegin const):
(WTF::TrailingArray::cend const):
(WTF::TrailingArray::rbegin):
(WTF::TrailingArray::rend):
(WTF::TrailingArray::rbegin const):
(WTF::TrailingArray::rend const):
(WTF::TrailingArray::crbegin const):
(WTF::TrailingArray::crend const):
(WTF::TrailingArray::at):
(WTF::TrailingArray::at const):
(WTF::TrailingArray::operator[]):
(WTF::TrailingArray::operator[] const):
(WTF::TrailingArray::first):
(WTF::TrailingArray::first const):
(WTF::TrailingArray::last):
(WTF::TrailingArray::last const):
(WTF::TrailingArray::fill):
(WTF::TrailingArray::offsetOfSize):
(WTF::TrailingArray::offsetOfData):

Tools:

* TestWebKitAPI/CMakeLists.txt:
* TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
* TestWebKitAPI/Tests/WTF/EmbeddedFixedVector.cpp: Added.
(TestWebKitAPI::TEST):
(TestWebKitAPI::DestructorObserver::DestructorObserver):
(TestWebKitAPI::DestructorObserver::~DestructorObserver):
(TestWebKitAPI::DestructorObserver::operator=):
* TestWebKitAPI/Tests/WTF/FixedVector.cpp:
(TestWebKitAPI::TEST):
* TestWebKitAPI/Tests/WTF/RefCountedFixedVector.cpp: Added.
(TestWebKitAPI::TEST):
(TestWebKitAPI::DestructorObserver::DestructorObserver):
(TestWebKitAPI::DestructorObserver::~DestructorObserver):
(TestWebKitAPI::DestructorObserver::operator=):

Modified Paths

Added Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (287219 => 287220)


--- trunk/Source/_javascript_Core/ChangeLog	2021-12-18 05:45:31 UTC (rev 287219)
+++ trunk/Source/_javascript_Core/ChangeLog	2021-12-18 10:17:05 UTC (rev 287220)
@@ -1,3 +1,52 @@
+2021-12-17  Yusuke Suzuki  <[email protected]>
+
+        [WTF] Introduce TrailingArray
+        https://bugs.webkit.org/show_bug.cgi?id=234201
+
+        Reviewed by Darin Adler.
+
+        Use ThreadSafeRefCountedFixedVector in ObjectPropertyConditionSet and Wasm::LLIntCallees.
+
+        * bytecode/CodeBlock.h:
+        (JSC::CodeBlock::baselineJITConstantPool):
+        * bytecode/ObjectPropertyConditionSet.cpp:
+        (JSC::ObjectPropertyConditionSet::mergedWith const):
+        (JSC::ObjectPropertyConditionSet::dumpInContext const):
+        (JSC::ObjectPropertyConditionSet::isValidAndWatchable const):
+        * bytecode/ObjectPropertyConditionSet.h:
+        (JSC::ObjectPropertyConditionSet::invalid):
+        (JSC::ObjectPropertyConditionSet::create):
+        (JSC::ObjectPropertyConditionSet::isValid const):
+        (JSC::ObjectPropertyConditionSet::size const):
+        (JSC::ObjectPropertyConditionSet::begin const):
+        (JSC::ObjectPropertyConditionSet::end const):
+        (JSC::ObjectPropertyConditionSet::ObjectPropertyConditionSet): Deleted.
+        (JSC::ObjectPropertyConditionSet::releaseRawPointer): Deleted.
+        (JSC::ObjectPropertyConditionSet::adoptRawPointer): Deleted.
+        (JSC::ObjectPropertyConditionSet::fromRawPointer): Deleted.
+        (JSC::ObjectPropertyConditionSet::Data::Data): Deleted.
+        * jit/JIT.cpp:
+        (JSC::JIT::compileAndLinkWithoutFinalizing):
+        * jit/JITInlines.h:
+        (JSC::JIT::loadConstant):
+        * llint/LLIntOffsetsExtractor.cpp:
+        * llint/LowLevelInterpreter.asm:
+        * llint/LowLevelInterpreter32_64.asm:
+        * llint/LowLevelInterpreter64.asm:
+        * wasm/WasmCallee.h:
+        (JSC::Wasm::LLIntCallees::create): Deleted.
+        (JSC::Wasm::LLIntCallees::at const): Deleted.
+        (JSC::Wasm::LLIntCallees::data const): Deleted.
+        (JSC::Wasm::LLIntCallees::LLIntCallees): Deleted.
+        * wasm/WasmCodeBlock.cpp:
+        (JSC::Wasm::CodeBlock::create):
+        (JSC::Wasm::CodeBlock::CodeBlock):
+        * wasm/WasmCodeBlock.h:
+        * wasm/WasmModule.cpp:
+        (JSC::Wasm::Module::Module):
+        (JSC::Wasm::Module::getOrCreateCodeBlock):
+        * wasm/WasmModule.h:
+
 2021-12-17  Saam Barati  <[email protected]>
 
         Use IRC by default on arm64

Modified: trunk/Source/_javascript_Core/bytecode/CodeBlock.h (287219 => 287220)


--- trunk/Source/_javascript_Core/bytecode/CodeBlock.h	2021-12-18 05:45:31 UTC (rev 287219)
+++ trunk/Source/_javascript_Core/bytecode/CodeBlock.h	2021-12-18 10:17:05 UTC (rev 287220)
@@ -557,7 +557,7 @@
     void* baselineJITConstantPool()
     {
         RELEASE_ASSERT(m_jitData && jitType() == JITType::BaselineJIT);
-        return m_jitData->m_jitConstantPool.data();
+        return m_jitData->m_jitConstantPool.storage();
     }
 #endif
     size_t numberOfUnlinkedSwitchJumpTables() const { return m_unlinkedCode->numberOfUnlinkedSwitchJumpTables(); }

Modified: trunk/Source/_javascript_Core/bytecode/ObjectPropertyConditionSet.cpp (287219 => 287220)


--- trunk/Source/_javascript_Core/bytecode/ObjectPropertyConditionSet.cpp	2021-12-18 05:45:31 UTC (rev 287219)
+++ trunk/Source/_javascript_Core/bytecode/ObjectPropertyConditionSet.cpp	2021-12-18 10:17:05 UTC (rev 287220)
@@ -105,7 +105,7 @@
     Vector<ObjectPropertyCondition> result;
     
     if (!isEmpty())
-        result.append(m_data->m_vector.begin(), m_data->m_vector.size());
+        result.append(m_data->begin(), m_data->size());
     
     for (const ObjectPropertyCondition& newCondition : other) {
         bool foundMatch = false;
@@ -175,7 +175,7 @@
     
     out.print("[");
     if (m_data)
-        out.print(listDumpInContext(m_data->m_vector, context));
+        out.print(listDumpInContext(*m_data, context));
     out.print("]");
 }
 
@@ -189,7 +189,7 @@
     if (!isValid())
         return false;
 
-    for (auto& condition : m_data->m_vector) {
+    for (auto& condition : *m_data) {
         if (!condition.isWatchable())
             return false;
     }

Modified: trunk/Source/_javascript_Core/bytecode/ObjectPropertyConditionSet.h (287219 => 287220)


--- trunk/Source/_javascript_Core/bytecode/ObjectPropertyConditionSet.h	2021-12-18 05:45:31 UTC (rev 287219)
+++ trunk/Source/_javascript_Core/bytecode/ObjectPropertyConditionSet.h	2021-12-18 10:17:05 UTC (rev 287220)
@@ -27,8 +27,8 @@
 
 #include "ObjectPropertyCondition.h"
 #include <wtf/FastMalloc.h>
-#include <wtf/FixedVector.h>
 #include <wtf/Hasher.h>
+#include <wtf/RefCountedFixedVector.h>
 #include <wtf/Vector.h>
 
 namespace JSC {
@@ -43,12 +43,15 @@
 
 class ObjectPropertyConditionSet {
 public:
-    ObjectPropertyConditionSet() { }
+    using Conditions = ThreadSafeRefCountedFixedVector<ObjectPropertyCondition>;
+
+    ObjectPropertyConditionSet() = default;
     
     static ObjectPropertyConditionSet invalid()
     {
         ObjectPropertyConditionSet result;
-        result.m_data = adoptRef(new Data());
+        result.m_data = Conditions::create(0);
+        ASSERT(!result.isValid());
         return result;
     }
     
@@ -58,37 +61,37 @@
             return ObjectPropertyConditionSet();
         
         ObjectPropertyConditionSet result;
-        result.m_data = adoptRef(new Data());
-        result.m_data->m_vector = FixedVector<ObjectPropertyCondition>(WTFMove(vector));
+        result.m_data = Conditions::createFromVector(WTFMove(vector));
+        ASSERT(result.isValid());
         return result;
     }
     
     bool isValid() const
     {
-        return !m_data || !m_data->m_vector.isEmpty();
+        return !m_data || !m_data->isEmpty();
     }
 
     bool isValidAndWatchable() const;
 
-    size_t size() const { return m_data ? m_data->m_vector.size() : 0; }
+    size_t size() const { return m_data ? m_data->size() : 0; }
     bool isEmpty() const
     {
         return !m_data;
     }
-    
-    typedef const ObjectPropertyCondition* iterator;
-    
-    iterator begin() const
+
+    using const_iterator = Conditions::const_iterator;
+
+    const_iterator begin() const
     {
         if (!m_data)
             return nullptr;
-        return m_data->m_vector.begin();
+        return m_data->cbegin();
     }
-    iterator end() const
+    const_iterator end() const
     {
         if (!m_data)
             return nullptr;
-        return m_data->m_vector.end();
+        return m_data->cend();
     }
 
     unsigned hash() const
@@ -151,45 +154,15 @@
     
     void dumpInContext(PrintStream&, DumpContext*) const;
     void dump(PrintStream&) const;
-    
-    // Helpers for using this in a union.
-    void* releaseRawPointer()
-    {
-        return static_cast<void*>(m_data.leakRef());
-    }
-    static ObjectPropertyConditionSet adoptRawPointer(void* rawPointer)
-    {
-        ObjectPropertyConditionSet result;
-        result.m_data = adoptRef(static_cast<Data*>(rawPointer));
-        return result;
-    }
-    static ObjectPropertyConditionSet fromRawPointer(void* rawPointer)
-    {
-        ObjectPropertyConditionSet result;
-        result.m_data = static_cast<Data*>(rawPointer);
-        return result;
-    }
 
-    // FIXME: Everything below here should be private, but cannot be because of a bug in VS.
-    
     // Internally, this represents Invalid using a pointer to a Data that has an empty vector.
     
     // FIXME: This could be made more compact by having it internally use a vector that just has
     // the non-uid portion of ObjectPropertyCondition, and then requiring that the callers of all
     // of the APIs supply the uid.
-    
-    class Data : public ThreadSafeRefCounted<Data> {
-        WTF_MAKE_NONCOPYABLE(Data);
-        WTF_MAKE_FAST_ALLOCATED;
-        
-    public:
-        Data() { }
-        
-        FixedVector<ObjectPropertyCondition> m_vector;
-    };
-    
+
 private:
-    RefPtr<Data> m_data;
+    RefPtr<Conditions> m_data;
 };
 
 ObjectPropertyCondition generateConditionForSelfEquivalence(

Modified: trunk/Source/_javascript_Core/jit/JIT.cpp (287219 => 287220)


--- trunk/Source/_javascript_Core/jit/JIT.cpp	2021-12-18 05:45:31 UTC (rev 287219)
+++ trunk/Source/_javascript_Core/jit/JIT.cpp	2021-12-18 10:17:05 UTC (rev 287220)
@@ -798,7 +798,7 @@
                     continue;
                 int offset = CallFrame::argumentOffsetIncludingThis(argument) * static_cast<int>(sizeof(Register));
                 loadValue(Address(callFrameRegister, offset), jsRegT10);
-                storeValue(jsRegT10, Address(regT2, argument * sizeof(ValueProfile) + ValueProfile::offsetOfFirstBucket()));
+                storeValue(jsRegT10, Address(regT2, FixedVector<ValueProfile>::Storage::offsetOfData() + argument * sizeof(ValueProfile) + ValueProfile::offsetOfFirstBucket()));
             }
         }
     }

Modified: trunk/Source/_javascript_Core/jit/JITInlines.h (287219 => 287220)


--- trunk/Source/_javascript_Core/jit/JITInlines.h	2021-12-18 05:45:31 UTC (rev 287219)
+++ trunk/Source/_javascript_Core/jit/JITInlines.h	2021-12-18 10:17:05 UTC (rev 287220)
@@ -505,7 +505,7 @@
 
 ALWAYS_INLINE void JIT::loadConstant(JITConstantPool::Constant constantIndex, GPRReg result)
 {
-    loadPtr(Address(s_constantsGPR, static_cast<uintptr_t>(constantIndex) * sizeof(void*)), result);
+    loadPtr(Address(s_constantsGPR, FixedVector<void*>::Storage::offsetOfData() + static_cast<uintptr_t>(constantIndex) * sizeof(void*)), result);
 }
 
 ALWAYS_INLINE void JIT::loadGlobalObject(GPRReg result)

Modified: trunk/Source/_javascript_Core/llint/LLIntOffsetsExtractor.cpp (287219 => 287220)


--- trunk/Source/_javascript_Core/llint/LLIntOffsetsExtractor.cpp	2021-12-18 05:45:31 UTC (rev 287219)
+++ trunk/Source/_javascript_Core/llint/LLIntOffsetsExtractor.cpp	2021-12-18 10:17:05 UTC (rev 287220)
@@ -87,8 +87,13 @@
     // These types are useful since we can't use '<...>' syntax in LLInt offsets extraction. e.g. Vector<int>::m_data
     using Vector = WTF::Vector<int>;
     using JSInternalFieldObjectImpl = JSC::JSInternalFieldObjectImpl<>;
-    using FixedVector = WTF::FixedVector<int>;
-    using RefCountedArray = WTF::RefCountedArray<int>;
+    using ValueProfileFixedVector = WTF::FixedVector<ValueProfile>;
+    using BinaryArithProfileFixedVector = FixedVector<BinaryArithProfile>;
+    using UnaryArithProfileFixedVector = FixedVector<UnaryArithProfile>;
+    using UnlinkedSimpleJumpTableFixedVector = FixedVector<UnlinkedSimpleJumpTable>;
+    using UnlinkedStringJumpTableFixedVector = FixedVector<UnlinkedStringJumpTable>;
+    using Int32FixedVector = FixedVector<int32_t>;
+    using VoidPointerFixedVector = FixedVector<void*>;
 
 public:
     static const int64_t* dummy();

Modified: trunk/Source/_javascript_Core/llint/LowLevelInterpreter.asm (287219 => 287220)


--- trunk/Source/_javascript_Core/llint/LowLevelInterpreter.asm	2021-12-18 05:45:31 UTC (rev 287219)
+++ trunk/Source/_javascript_Core/llint/LowLevelInterpreter.asm	2021-12-18 10:17:05 UTC (rev 287220)
@@ -628,8 +628,6 @@
 const VectorBufferOffset = Vector::m_buffer
 const VectorSizeOffset = Vector::m_size
 
-const RefCountedArrayStorageNonNullSizeOffset = -(constexpr (RefCountedArray::Header::size())) + RefCountedArray::Header::length
-
 # Some common utilities.
 macro crash()
     if C_LOOP or C_LOOP_WIN
@@ -1682,10 +1680,11 @@
     addp -profileArgSkip, t0
     assert(macro (ok) bpgteq t0, 0, ok end)
     btpz t0, .argumentProfileDone
-    loadp CodeBlock::m_argumentValueProfiles + FixedVector::m_storage + RefCountedArray::m_data[t1], t3
+    loadp CodeBlock::m_argumentValueProfiles + ValueProfileFixedVector::m_storage[t1], t3
     btpz t3, .argumentProfileDone # When we can't JIT, we don't allocate any argument value profiles.
     mulp sizeof ValueProfile, t0, t2 # Aaaaahhhh! Need strength reduction!
     lshiftp 3, t0 # offset of last JSValue arguments on the stack.
+    addp (constexpr (ValueProfileFixedVector::Storage::offsetOfData())), t3
     addp t2, t3 # pointer to end of ValueProfile array in the value profile array.
 .argumentProfileLoop:
     if JSVALUE64
@@ -2615,7 +2614,7 @@
         # Baseline uses LLInt's PB register for its JIT constant pool.
         loadp CodeBlock[cfr], PB
         loadp CodeBlock::m_jitData[PB], PB
-        loadp CodeBlock::JITData::m_jitConstantPool[PB], PB
+        loadp CodeBlock::JITData::m_jitConstantPool + VoidPointerFixedVector::m_storage[PB], PB
     end
 
     macro setupReturnToBaselineAfterCheckpointExitIfNeeded()
@@ -2730,8 +2729,8 @@
     getu(size, opcodeStruct, m_profileIndex, scratch1)
     loadp CodeBlock[cfr], scratch2
     loadp CodeBlock::m_unlinkedCode[scratch2], scratch2
-    loadp UnlinkedCodeBlock::m_unaryArithProfiles + FixedVector::m_storage + RefCountedArray::m_data[scratch2], scratch2
-    orh type, UnaryArithProfile::m_bits[scratch2, scratch1, 2]
+    loadp UnlinkedCodeBlock::m_unaryArithProfiles + UnaryArithProfileFixedVector::m_storage[scratch2], scratch2
+    orh type, (constexpr (UnaryArithProfileFixedVector::Storage::offsetOfData())) + UnaryArithProfile::m_bits[scratch2, scratch1, 2]
 end
 
 macro updateBinaryArithProfile(size, opcodeStruct, type, scratch1, scratch2)
@@ -2738,8 +2737,8 @@
     getu(size, opcodeStruct, m_profileIndex, scratch1)
     loadp CodeBlock[cfr], scratch2
     loadp CodeBlock::m_unlinkedCode[scratch2], scratch2
-    loadp UnlinkedCodeBlock::m_binaryArithProfiles + FixedVector::m_storage + RefCountedArray::m_data[scratch2], scratch2
-    orh type, BinaryArithProfile::m_bits[scratch2, scratch1, 2]
+    loadp UnlinkedCodeBlock::m_binaryArithProfiles + BinaryArithProfileFixedVector::m_storage[scratch2], scratch2
+    orh type, (constexpr (BinaryArithProfileFixedVector::Storage::offsetOfData())) + BinaryArithProfile::m_bits[scratch2, scratch1, 2]
 end
 
 // FIXME: We should not need the X86_64_WIN condition here, since WEBASSEMBLY should already be false on Windows

Modified: trunk/Source/_javascript_Core/llint/LowLevelInterpreter32_64.asm (287219 => 287220)


--- trunk/Source/_javascript_Core/llint/LowLevelInterpreter32_64.asm	2021-12-18 05:45:31 UTC (rev 287219)
+++ trunk/Source/_javascript_Core/llint/LowLevelInterpreter32_64.asm	2021-12-18 10:17:05 UTC (rev 287220)
@@ -2099,14 +2099,15 @@
     loadp CodeBlock::m_unlinkedCode[t2], t2
     loadp UnlinkedCodeBlock::m_rareData[t2], t2
     muli sizeof UnlinkedSimpleJumpTable, t3
-    loadp UnlinkedCodeBlock::RareData::m_unlinkedSwitchJumpTables + FixedVector::m_storage + RefCountedArray::m_data[t2], t2
+    loadp UnlinkedCodeBlock::RareData::m_unlinkedSwitchJumpTables + UnlinkedSimpleJumpTableFixedVector::m_storage[t2], t2
+    addp (constexpr (UnlinkedSimpleJumpTableFixedVector::Storage::offsetOfData())), t2
     addp t3, t2
     bineq t1, Int32Tag, .opSwitchImmNotInt
     subi UnlinkedSimpleJumpTable::m_min[t2], t0
-    loadp UnlinkedSimpleJumpTable::m_branchOffsets + FixedVector::m_storage + RefCountedArray::m_data[t2], t2
+    loadp UnlinkedSimpleJumpTable::m_branchOffsets + Int32FixedVector::m_storage[t2], t2
     btpz t2, .opSwitchImmFallThrough
-    biaeq t0, RefCountedArrayStorageNonNullSizeOffset[t2], .opSwitchImmFallThrough
-    loadi [t2, t0, 4], t1
+    biaeq t0, Int32FixedVector::Storage::m_size[t2], .opSwitchImmFallThrough
+    loadi (constexpr (Int32FixedVector::Storage::offsetOfData()))[t2, t0, 4], t1
     btiz t1, .opSwitchImmFallThrough
     dispatchIndirect(t1)
 
@@ -2129,7 +2130,8 @@
     loadp CodeBlock::m_unlinkedCode[t2], t2
     loadp UnlinkedCodeBlock::m_rareData[t2], t2
     muli sizeof UnlinkedSimpleJumpTable, t3
-    loadp UnlinkedCodeBlock::RareData::m_unlinkedSwitchJumpTables + FixedVector::m_storage + RefCountedArray::m_data[t2], t2
+    loadp UnlinkedCodeBlock::RareData::m_unlinkedSwitchJumpTables + UnlinkedSimpleJumpTableFixedVector::m_storage[t2], t2
+    addp (constexpr (UnlinkedSimpleJumpTableFixedVector::Storage::offsetOfData())), t2
     addp t3, t2
     bineq t1, CellTag, .opSwitchCharFallThrough
     bbneq JSCell::m_type[t0], StringType, .opSwitchCharFallThrough
@@ -2144,10 +2146,10 @@
     loadb [t0], t0
 .opSwitchCharReady:
     subi UnlinkedSimpleJumpTable::m_min[t2], t0
-    loadp UnlinkedSimpleJumpTable::m_branchOffsets + FixedVector::m_storage + RefCountedArray::m_data[t2], t2
+    loadp UnlinkedSimpleJumpTable::m_branchOffsets + Int32FixedVector::m_storage[t2], t2
     btpz t2, .opSwitchCharFallThrough
-    biaeq t0, RefCountedArrayStorageNonNullSizeOffset[t2], .opSwitchCharFallThrough
-    loadi [t2, t0, 4], t1
+    biaeq t0, Int32FixedVector::Storage::m_size[t2], .opSwitchCharFallThrough
+    loadi (constexpr (Int32FixedVector::Storage::offsetOfData()))[t2, t0, 4], t1
     btiz t1, .opSwitchCharFallThrough
     dispatchIndirect(t1)
 

Modified: trunk/Source/_javascript_Core/llint/LowLevelInterpreter64.asm (287219 => 287220)


--- trunk/Source/_javascript_Core/llint/LowLevelInterpreter64.asm	2021-12-18 05:45:31 UTC (rev 287219)
+++ trunk/Source/_javascript_Core/llint/LowLevelInterpreter64.asm	2021-12-18 10:17:05 UTC (rev 287220)
@@ -2308,14 +2308,15 @@
     loadp CodeBlock::m_unlinkedCode[t2], t2
     loadp UnlinkedCodeBlock::m_rareData[t2], t2
     muli sizeof UnlinkedSimpleJumpTable, t3
-    loadp UnlinkedCodeBlock::RareData::m_unlinkedSwitchJumpTables + FixedVector::m_storage + RefCountedArray::m_data[t2], t2
+    loadp UnlinkedCodeBlock::RareData::m_unlinkedSwitchJumpTables + UnlinkedSimpleJumpTableFixedVector::m_storage[t2], t2
+    addp (constexpr (UnlinkedSimpleJumpTableFixedVector::Storage::offsetOfData())), t2
     addp t3, t2
     bqb t1, numberTag, .opSwitchImmNotInt
     subi UnlinkedSimpleJumpTable::m_min[t2], t1
-    loadp UnlinkedSimpleJumpTable::m_branchOffsets + FixedVector::m_storage + RefCountedArray::m_data[t2], t2
+    loadp UnlinkedSimpleJumpTable::m_branchOffsets + Int32FixedVector::m_storage[t2], t2
     btpz t2, .opSwitchImmFallThrough
-    biaeq t1, RefCountedArrayStorageNonNullSizeOffset[t2], .opSwitchImmFallThrough
-    loadis [t2, t1, 4], t1
+    biaeq t1, Int32FixedVector::Storage::m_size[t2], .opSwitchImmFallThrough
+    loadis (constexpr (Int32FixedVector::Storage::offsetOfData()))[t2, t1, 4], t1
     btiz t1, .opSwitchImmFallThrough
     dispatchIndirect(t1)
 
@@ -2338,7 +2339,8 @@
     loadp CodeBlock::m_unlinkedCode[t2], t2
     loadp UnlinkedCodeBlock::m_rareData[t2], t2
     muli sizeof UnlinkedSimpleJumpTable, t3
-    loadp UnlinkedCodeBlock::RareData::m_unlinkedSwitchJumpTables + FixedVector::m_storage + RefCountedArray::m_data[t2], t2
+    loadp UnlinkedCodeBlock::RareData::m_unlinkedSwitchJumpTables + UnlinkedSimpleJumpTableFixedVector::m_storage[t2], t2
+    addp (constexpr (UnlinkedSimpleJumpTableFixedVector::Storage::offsetOfData())), t2
     addp t3, t2
     btqnz t1, notCellMask, .opSwitchCharFallThrough
     bbneq JSCell::m_type[t1], StringType, .opSwitchCharFallThrough
@@ -2353,10 +2355,10 @@
     loadb [t1], t0
 .opSwitchCharReady:
     subi UnlinkedSimpleJumpTable::m_min[t2], t0
-    loadp UnlinkedSimpleJumpTable::m_branchOffsets + FixedVector::m_storage + RefCountedArray::m_data[t2], t2
+    loadp UnlinkedSimpleJumpTable::m_branchOffsets + Int32FixedVector::m_storage[t2], t2
     btpz t2, .opSwitchCharFallThrough
-    biaeq t0, RefCountedArrayStorageNonNullSizeOffset[t2], .opSwitchCharFallThrough
-    loadis [t2, t0, 4], t1
+    biaeq t0, Int32FixedVector::Storage::m_size[t2], .opSwitchCharFallThrough
+    loadis (constexpr (Int32FixedVector::Storage::offsetOfData()))[t2, t0, 4], t1
     btiz t1, .opSwitchCharFallThrough
     dispatchIndirect(t1)
 

Modified: trunk/Source/_javascript_Core/wasm/WasmCallee.h (287219 => 287220)


--- trunk/Source/_javascript_Core/wasm/WasmCallee.h	2021-12-18 05:45:31 UTC (rev 287219)
+++ trunk/Source/_javascript_Core/wasm/WasmCallee.h	2021-12-18 10:17:05 UTC (rev 287220)
@@ -37,6 +37,7 @@
 #include "WasmLLIntTierUpCounter.h"
 #include "WasmTierUpCount.h"
 #include <wtf/FixedVector.h>
+#include <wtf/RefCountedFixedVector.h>
 #include <wtf/ThreadSafeRefCounted.h>
 
 namespace JSC {
@@ -264,32 +265,8 @@
     MacroAssemblerCodePtr<WasmEntryPtrTag> m_entrypoint;
 };
 
-class LLIntCallees : public ThreadSafeRefCounted<LLIntCallees> {
-public:
-    static Ref<LLIntCallees> create(Vector<Ref<LLIntCallee>>&& llintCallees)
-    {
-        return adoptRef(*new LLIntCallees(WTFMove(llintCallees)));
-    }
+using LLIntCallees = ThreadSafeRefCountedFixedVector<Ref<LLIntCallee>>;
 
-    const Ref<LLIntCallee>& at(unsigned i) const
-    {
-        return m_llintCallees.at(i);
-    }
-
-    const Ref<LLIntCallee>* data() const
-    {
-        return m_llintCallees.data();
-    }
-
-private:
-    LLIntCallees(Vector<Ref<LLIntCallee>>&& llintCallees)
-        : m_llintCallees(WTFMove(llintCallees))
-    {
-    }
-
-    FixedVector<Ref<LLIntCallee>> m_llintCallees;
-};
-
 } } // namespace JSC::Wasm
 
 #endif // ENABLE(WEBASSEMBLY)

Modified: trunk/Source/_javascript_Core/wasm/WasmModule.cpp (287219 => 287220)


--- trunk/Source/_javascript_Core/wasm/WasmModule.cpp	2021-12-18 05:45:31 UTC (rev 287219)
+++ trunk/Source/_javascript_Core/wasm/WasmModule.cpp	2021-12-18 10:17:05 UTC (rev 287220)
@@ -36,7 +36,7 @@
 
 Module::Module(LLIntPlan& plan)
     : m_moduleInformation(plan.takeModuleInformation())
-    , m_llintCallees(LLIntCallees::create(plan.takeCallees()))
+    , m_llintCallees(LLIntCallees::createFromVector(plan.takeCallees()))
     , m_llintEntryThunks(plan.takeEntryThunks())
 {
 }
@@ -91,8 +91,8 @@
     if (!calleeGroup || (calleeGroup->compilationFinished() && !calleeGroup->runnable())) {
         RefPtr<LLIntCallees> llintCallees = nullptr;
         if (Options::useWasmLLInt())
-            llintCallees = m_llintCallees;
-        calleeGroup = CalleeGroup::create(context, mode, const_cast<ModuleInformation&>(moduleInformation()), llintCallees);
+            llintCallees = m_llintCallees.copyRef();
+        calleeGroup = CalleeGroup::create(context, mode, const_cast<ModuleInformation&>(moduleInformation()), WTFMove(llintCallees));
         m_calleeGroups[static_cast<uint8_t>(mode)] = calleeGroup;
     }
     return calleeGroup.releaseNonNull();

Modified: trunk/Source/_javascript_Core/wasm/WasmModule.h (287219 => 287220)


--- trunk/Source/_javascript_Core/wasm/WasmModule.h	2021-12-18 05:45:31 UTC (rev 287219)
+++ trunk/Source/_javascript_Core/wasm/WasmModule.h	2021-12-18 10:17:05 UTC (rev 287220)
@@ -74,7 +74,7 @@
     Module(LLIntPlan&);
     Ref<ModuleInformation> m_moduleInformation;
     RefPtr<CalleeGroup> m_calleeGroups[Wasm::NumberOfMemoryModes];
-    RefPtr<LLIntCallees> m_llintCallees;
+    Ref<LLIntCallees> m_llintCallees;
     MacroAssemblerCodeRef<JITCompilationPtrTag> m_llintEntryThunks;
     Lock m_lock;
 };

Modified: trunk/Source/WTF/ChangeLog (287219 => 287220)


--- trunk/Source/WTF/ChangeLog	2021-12-18 05:45:31 UTC (rev 287219)
+++ trunk/Source/WTF/ChangeLog	2021-12-18 10:17:05 UTC (rev 287220)
@@ -1,3 +1,79 @@
+2021-12-17  Yusuke Suzuki  <[email protected]>
+
+        [WTF] Introduce TrailingArray
+        https://bugs.webkit.org/show_bug.cgi?id=234201
+
+        Reviewed by Darin Adler.
+
+        This patch implements TrailingArray<Derived, T>, which allows us to implement class
+        with trailing array easily. By using this, we implement EmbeddedFixedVector and RefCountedFixedVector.
+        Plus, we replace underlying implementation of FixedVector from RefCountedArray to EmbeddedFixedVector
+        since ref-counting is not necessary. This is great for swapping: while RefCountedArray will decrease ref
+        and touching memory when destryoing, EmbeddedFixedVector does not, so we can keep memory untouched if
+        EmbeddedFixedVector's T is POD when destroying.
+
+        In a subsequent patch, we will remove RefCountedArray and use RefCountedFixedVector since RefCountedFixedVector
+        is following normal Ref / RefPtr protocol, so easy to understand the semantics.
+
+        * WTF.xcodeproj/project.pbxproj:
+        * wtf/CMakeLists.txt:
+        * wtf/EmbeddedFixedVector.h: Added.
+        * wtf/FixedVector.h:
+        (WTF::FixedVector::FixedVector):
+        (WTF::FixedVector::operator=):
+        (WTF::FixedVector::size const):
+        (WTF::FixedVector::isEmpty const):
+        (WTF::FixedVector::byteSize const):
+        (WTF::FixedVector::data):
+        (WTF::FixedVector::begin):
+        (WTF::FixedVector::end):
+        (WTF::FixedVector::rbegin):
+        (WTF::FixedVector::rend):
+        (WTF::FixedVector::rbegin const):
+        (WTF::FixedVector::rend const):
+        (WTF::FixedVector::at):
+        (WTF::FixedVector::at const):
+        (WTF::FixedVector::operator[]):
+        (WTF::FixedVector::operator[] const):
+        (WTF::FixedVector::fill):
+        (WTF::FixedVector::operator!= const):
+        (WTF::FixedVector::operator== const):
+        (WTF::FixedVector::swap):
+        (WTF::FixedVector::getStorage):
+        * wtf/RefCountedFixedVector.h: Added.
+        * wtf/TrailingArray.h: Added.
+        (WTF::TrailingArray::TrailingArray):
+        (WTF::TrailingArray::~TrailingArray):
+        (WTF::TrailingArray::allocationSize):
+        (WTF::TrailingArray::size const):
+        (WTF::TrailingArray::isEmpty const):
+        (WTF::TrailingArray::byteSize const):
+        (WTF::TrailingArray::data):
+        (WTF::TrailingArray::data const):
+        (WTF::TrailingArray::begin):
+        (WTF::TrailingArray::end):
+        (WTF::TrailingArray::begin const):
+        (WTF::TrailingArray::end const):
+        (WTF::TrailingArray::cbegin const):
+        (WTF::TrailingArray::cend const):
+        (WTF::TrailingArray::rbegin):
+        (WTF::TrailingArray::rend):
+        (WTF::TrailingArray::rbegin const):
+        (WTF::TrailingArray::rend const):
+        (WTF::TrailingArray::crbegin const):
+        (WTF::TrailingArray::crend const):
+        (WTF::TrailingArray::at):
+        (WTF::TrailingArray::at const):
+        (WTF::TrailingArray::operator[]):
+        (WTF::TrailingArray::operator[] const):
+        (WTF::TrailingArray::first):
+        (WTF::TrailingArray::first const):
+        (WTF::TrailingArray::last):
+        (WTF::TrailingArray::last const):
+        (WTF::TrailingArray::fill):
+        (WTF::TrailingArray::offsetOfSize):
+        (WTF::TrailingArray::offsetOfData):
+
 2021-12-17  Sihui Liu  <[email protected]>
 
         Add custom copy() method for Ref<T> to CrossThreadCopier

Modified: trunk/Source/WTF/WTF.xcodeproj/project.pbxproj (287219 => 287220)


--- trunk/Source/WTF/WTF.xcodeproj/project.pbxproj	2021-12-18 05:45:31 UTC (rev 287219)
+++ trunk/Source/WTF/WTF.xcodeproj/project.pbxproj	2021-12-18 10:17:05 UTC (rev 287220)
@@ -758,6 +758,8 @@
 		E339C163244B4E8700359DA9 /* DataRef.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DataRef.h; sourceTree = "<group>"; };
 		E33D5F871FBED66700BF625E /* RecursableLambda.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RecursableLambda.h; sourceTree = "<group>"; };
 		E34CD0D022810A020020D299 /* Packed.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Packed.h; sourceTree = "<group>"; };
+		E3538D4C276220880075DA50 /* EmbeddedFixedVector.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = EmbeddedFixedVector.h; sourceTree = "<group>"; };
+		E3538D4D276220880075DA50 /* TrailingArray.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TrailingArray.h; sourceTree = "<group>"; };
 		E360C7642127B85B00C90F0E /* UnalignedAccess.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UnalignedAccess.h; sourceTree = "<group>"; };
 		E360C7652127B85C00C90F0E /* Unexpected.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Unexpected.h; sourceTree = "<group>"; };
 		E36895CB23A445CD008DD4C8 /* PackedRef.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PackedRef.h; sourceTree = "<group>"; };
@@ -781,6 +783,7 @@
 		E3E0F04F26197157004640FC /* FixedVector.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FixedVector.h; sourceTree = "<group>"; };
 		E3E158251EADA53C004A079D /* SystemFree.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SystemFree.h; sourceTree = "<group>"; };
 		E3E64F0B22813428001E55B4 /* Nonmovable.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Nonmovable.h; sourceTree = "<group>"; };
+		E3E8162F2764799300BAA45B /* RefCountedFixedVector.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RefCountedFixedVector.h; sourceTree = "<group>"; };
 		E419F2E623AB9E2300B26129 /* VectorHash.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VectorHash.h; sourceTree = "<group>"; };
 		E431CC4A21187ADB000C8A07 /* DispatchSPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DispatchSPI.h; sourceTree = "<group>"; };
 		E4A0AD371A96245500536DF6 /* WorkQueue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WorkQueue.cpp; sourceTree = "<group>"; };
@@ -1071,6 +1074,7 @@
 				A8A47280151A825A004123FF /* DoublyLinkedList.h */,
 				A8A47297151A825A004123FF /* dtoa.cpp */,
 				A8A47298151A825A004123FF /* dtoa.h */,
+				E3538D4C276220880075DA50 /* EmbeddedFixedVector.h */,
 				5338EBA423AB04D100382662 /* EnumClassOperatorOverloads.h */,
 				1AEA88E11D6BBCF400E5AD64 /* EnumTraits.h */,
 				AD7C434A1DD2A4A70026888B /* Expected.h */,
@@ -1267,6 +1271,7 @@
 				A8A472FF151A825B004123FF /* RefCounted.h */,
 				0FA6F39020CC61EB00A03DCD /* RefCountedArray.cpp */,
 				A8A47300151A825B004123FF /* RefCountedArray.h */,
+				E3E8162F2764799300BAA45B /* RefCountedFixedVector.h */,
 				A8A47301151A825B004123FF /* RefCountedLeakCounter.cpp */,
 				A8A47302151A825B004123FF /* RefCountedLeakCounter.h */,
 				86F46F5F1A2840EE00CCBF22 /* RefCounter.h */,
@@ -1357,6 +1362,7 @@
 				0F7075F31FBF537A00489AF0 /* TimingScope.h */,
 				553071C91C40427200384898 /* TinyLRUCache.h */,
 				0FED67B51B22D4D80066CE15 /* TinyPtrSet.h */,
+				E3538D4D276220880075DA50 /* TrailingArray.h */,
 				521CC6B324A277C2004377D6 /* TranslatedProcess.cpp */,
 				2D1F2F462498F73300C63A83 /* TranslatedProcess.h */,
 				149EF16216BBFE0D000A4331 /* TriState.h */,

Modified: trunk/Source/WTF/wtf/CMakeLists.txt (287219 => 287220)


--- trunk/Source/WTF/wtf/CMakeLists.txt	2021-12-18 05:45:31 UTC (rev 287219)
+++ trunk/Source/WTF/wtf/CMakeLists.txt	2021-12-18 10:17:05 UTC (rev 287220)
@@ -62,6 +62,7 @@
     DisallowCType.h
     Dominators.h
     DoublyLinkedList.h
+    EmbeddedFixedVector.h
     EnumClassOperatorOverloads.h
     EnumTraits.h
     Expected.h
@@ -219,6 +220,7 @@
     Ref.h
     RefCounted.h
     RefCountedArray.h
+    RefCountedFixedVector.h
     RefCountedLeakCounter.h
     RefCounter.h
     RefPtr.h
@@ -289,6 +291,7 @@
     TimingScope.h
     TinyLRUCache.h
     TinyPtrSet.h
+    TrailingArray.h
     TranslatedProcess.h
     TriState.h
     TypeCasts.h

Added: trunk/Source/WTF/wtf/EmbeddedFixedVector.h (0 => 287220)


--- trunk/Source/WTF/wtf/EmbeddedFixedVector.h	                        (rev 0)
+++ trunk/Source/WTF/wtf/EmbeddedFixedVector.h	2021-12-18 10:17:05 UTC (rev 287220)
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2021 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/Noncopyable.h>
+#include <wtf/Nonmovable.h>
+#include <wtf/TrailingArray.h>
+#include <wtf/UniqueRef.h>
+
+namespace WTF {
+
+template<typename T>
+class EmbeddedFixedVector final : public TrailingArray<EmbeddedFixedVector<T>, T> {
+    WTF_MAKE_FAST_ALLOCATED(EmbeddedFixedVector);
+    WTF_MAKE_NONCOPYABLE(EmbeddedFixedVector);
+    WTF_MAKE_NONMOVABLE(EmbeddedFixedVector);
+public:
+    using Base = TrailingArray<EmbeddedFixedVector<T>, T>;
+
+    static UniqueRef<EmbeddedFixedVector> create(unsigned size)
+    {
+        return UniqueRef { *new (NotNull, fastMalloc(Base::allocationSize(size))) EmbeddedFixedVector(size) };
+    }
+
+    template<typename InputIterator>
+    static UniqueRef<EmbeddedFixedVector> create(InputIterator first, InputIterator last)
+    {
+        unsigned size = Checked<uint32_t> { std::distance(first, last) };
+        return UniqueRef { *new (NotNull, fastMalloc(Base::allocationSize(size))) EmbeddedFixedVector(size, first, last) };
+    }
+
+    template<size_t inlineCapacity, typename OverflowHandler>
+    static UniqueRef<EmbeddedFixedVector> createFromVector(const Vector<T, inlineCapacity, OverflowHandler>& other)
+    {
+        unsigned size = Checked<uint32_t> { other.size() }.value();
+        return UniqueRef { *new (NotNull, fastMalloc(Base::allocationSize(size))) EmbeddedFixedVector(size, other.begin(), other.end()) };
+    }
+
+    template<size_t inlineCapacity, typename OverflowHandler>
+    static UniqueRef<EmbeddedFixedVector> createFromVector(Vector<T, inlineCapacity, OverflowHandler>&& other)
+    {
+        Vector<T, inlineCapacity, OverflowHandler> container = WTFMove(other);
+        unsigned size = Checked<uint32_t> { container.size() }.value();
+        return UniqueRef { *new (NotNull, fastMalloc(Base::allocationSize(size))) EmbeddedFixedVector(size, std::move_iterator { container.begin() }, std::move_iterator { container.end() }) };
+    }
+
+    UniqueRef<EmbeddedFixedVector> clone() const
+    {
+        return create(Base::begin(), Base::end());
+    }
+
+    bool operator!=(const EmbeddedFixedVector& other) const
+    {
+        return !(*this == other);
+    }
+
+    bool operator==(const EmbeddedFixedVector& other) const
+    {
+        if (Base::size() != other.size())
+            return false;
+        for (unsigned i = 0; i < Base::size(); ++i) {
+            if (Base::at(i) != other.at(i))
+                return false;
+        }
+        return true;
+    }
+
+private:
+    explicit EmbeddedFixedVector(unsigned size)
+        : Base(size)
+    {
+    }
+
+    template<typename InputIterator>
+    EmbeddedFixedVector(unsigned size, InputIterator first, InputIterator last)
+        : Base(size, first, last)
+    {
+    }
+};
+
+} // namespace WTF
+
+using WTF::EmbeddedFixedVector;

Modified: trunk/Source/WTF/wtf/FixedVector.h (287219 => 287220)


--- trunk/Source/WTF/wtf/FixedVector.h	2021-12-18 05:45:31 UTC (rev 287219)
+++ trunk/Source/WTF/wtf/FixedVector.h	2021-12-18 10:17:05 UTC (rev 287220)
@@ -25,6 +25,7 @@
 
 #pragma once
 
+#include <wtf/EmbeddedFixedVector.h>
 #include <wtf/RefCountedArray.h>
 
 namespace WTF {
@@ -34,6 +35,7 @@
 template<typename T>
 class FixedVector {
 public:
+    using Storage = EmbeddedFixedVector<T>;
     using iterator = T*;
     using const_iterator = const T*;
     using reverse_iterator = std::reverse_iterator<iterator>;
@@ -41,7 +43,7 @@
 
     FixedVector() = default;
     FixedVector(const FixedVector& other)
-        : m_storage(other.m_storage.clone())
+        : m_storage(other.m_storage ? other.m_storage->clone().moveToUniquePtr() : nullptr)
     { }
     FixedVector(FixedVector&& other) = default;
 
@@ -60,55 +62,58 @@
     }
 
     explicit FixedVector(size_t size)
-        : m_storage(size)
+        : m_storage(size ? Storage::create(size).moveToUniquePtr() : nullptr)
     { }
 
     template<size_t inlineCapacity, typename OverflowHandler>
     explicit FixedVector(const Vector<T, inlineCapacity, OverflowHandler>& other)
-        : m_storage(other)
+        : m_storage(other.isEmpty() ? nullptr : Storage::createFromVector(other).moveToUniquePtr())
     { }
 
     template<size_t inlineCapacity, typename OverflowHandler>
     FixedVector& operator=(const Vector<T, inlineCapacity, OverflowHandler>& other)
     {
-        m_storage = other;
+        m_storage = other.isEmpty() ? nullptr : Storage::createFromVector(other).moveToUniquePtr();
         return *this;
     }
 
     template<size_t inlineCapacity, typename OverflowHandler>
     explicit FixedVector(Vector<T, inlineCapacity, OverflowHandler>&& other)
-        : m_storage(WTFMove(other))
-    { }
+    {
+        Vector<T, inlineCapacity, OverflowHandler> target = WTFMove(other);
+        m_storage = target.isEmpty() ? nullptr : Storage::createFromVector(WTFMove(target)).moveToUniquePtr();
+    }
 
     template<size_t inlineCapacity, typename OverflowHandler>
     FixedVector& operator=(Vector<T, inlineCapacity, OverflowHandler>&& other)
     {
-        m_storage = WTFMove(other);
+        Vector<T, inlineCapacity, OverflowHandler> target = WTFMove(other);
+        m_storage = target.isEmpty() ? nullptr : Storage::createFromVector(WTFMove(target)).moveToUniquePtr();
         return *this;
     }
 
-    size_t size() const { return m_storage.size(); }
-    bool isEmpty() const { return m_storage.isEmpty(); }
-    size_t byteSize() const { return m_storage.byteSize(); }
+    size_t size() const { return m_storage ? m_storage->size() : 0; }
+    bool isEmpty() const { return m_storage ? m_storage->isEmpty() : true; }
+    size_t byteSize() const { return m_storage ? m_storage->byteSize() : 0; }
 
-    T* data() { return m_storage.data(); }
-    iterator begin() { return m_storage.begin(); }
-    iterator end() { return m_storage.end(); }
+    T* data() { return m_storage ? m_storage->data() : nullptr; }
+    iterator begin() { return m_storage ? m_storage->begin() : nullptr; }
+    iterator end() { return m_storage ? m_storage->end() : nullptr; }
 
     const T* data() const { return const_cast<FixedVector*>(this)->data(); }
     const_iterator begin() const { return const_cast<FixedVector*>(this)->begin(); }
     const_iterator end() const { return const_cast<FixedVector*>(this)->end(); }
 
-    reverse_iterator rbegin() { return m_storage.rbegin(); }
-    reverse_iterator rend() { return m_storage.rend(); }
-    const_reverse_iterator rbegin() const { return m_storage.rbegin(); }
-    const_reverse_iterator rend() const { return m_storage.rend(); }
+    reverse_iterator rbegin() { return m_storage ? m_storage->rbegin() : reverse_iterator(nullptr); }
+    reverse_iterator rend() { return m_storage ? m_storage->rend() : reverse_iterator(nullptr); }
+    const_reverse_iterator rbegin() const { return m_storage ? m_storage->rbegin() : const_reverse_iterator(nullptr); }
+    const_reverse_iterator rend() const { return m_storage ? m_storage->rend() : const_reverse_iterator(nullptr); }
 
-    T& at(size_t i) { return m_storage.at(i); }
-    const T& at(size_t i) const { return m_storage.at(i); }
+    T& at(size_t i) { return m_storage->at(i); }
+    const T& at(size_t i) const { return m_storage->at(i); }
 
-    T& operator[](size_t i) { return at(i); }
-    const T& operator[](size_t i) const { return at(i); }
+    T& operator[](size_t i) { return m_storage->at(i); }
+    const T& operator[](size_t i) const { return m_storage->at(i); }
 
     T& first() { return (*this)[0]; }
     const T& first() const { return (*this)[0]; }
@@ -115,21 +120,44 @@
     T& last() { return (*this)[size() - 1]; }
     const T& last() const { return (*this)[size() - 1]; }
 
-    void fill(const T& val) { m_storage.fill(val); }
+    void fill(const T& val)
+    {
+        if (!m_storage)
+            return;
+        m_storage->fill(val);
+    }
 
-    bool operator==(const FixedVector<T>& other) const { return m_storage == other.m_storage; }
+    bool operator!=(const FixedVector<T>& other) const
+    {
+        return !(*this == other);
+    }
 
+    bool operator==(const FixedVector<T>& other) const
+    {
+        if (!m_storage) {
+            if (!other.m_storage)
+                return true;
+            return other.m_storage->isEmpty();
+        }
+        if (!other.m_storage)
+            return m_storage->isEmpty();
+        return *m_storage == *other.m_storage;
+    }
+
     void swap(FixedVector<T>& other)
     {
-        m_storage.swap(other.m_storage);
+        using std::swap;
+        swap(m_storage, other.m_storage);
     }
 
     static ptrdiff_t offsetOfStorage() { return OBJECT_OFFSETOF(FixedVector, m_storage); }
 
+    Storage* storage() { return m_storage.get(); }
+
 private:
     friend class JSC::LLIntOffsetsExtractor;
 
-    RefCountedArray<T> m_storage;
+    std::unique_ptr<Storage> m_storage;
 };
 static_assert(sizeof(FixedVector<int>) == sizeof(int*));
 

Added: trunk/Source/WTF/wtf/RefCountedFixedVector.h (0 => 287220)


--- trunk/Source/WTF/wtf/RefCountedFixedVector.h	                        (rev 0)
+++ trunk/Source/WTF/wtf/RefCountedFixedVector.h	2021-12-18 10:17:05 UTC (rev 287220)
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2021 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 <type_traits>
+#include <wtf/Ref.h>
+#include <wtf/RefCounted.h>
+#include <wtf/ThreadSafeRefCounted.h>
+#include <wtf/TrailingArray.h>
+
+namespace WTF {
+
+template<typename T, bool isThreadSafe>
+class RefCountedFixedVectorBase final : public std::conditional<isThreadSafe, ThreadSafeRefCounted<RefCountedFixedVectorBase<T, isThreadSafe>>, RefCounted<RefCountedFixedVectorBase<T, isThreadSafe>>>::type, public TrailingArray<RefCountedFixedVectorBase<T, isThreadSafe>, T> {
+public:
+    using Base = TrailingArray<RefCountedFixedVectorBase<T, isThreadSafe>, T>;
+
+    static Ref<RefCountedFixedVectorBase> create(unsigned size)
+    {
+        return adoptRef(*new (NotNull, fastMalloc(Base::allocationSize(size))) RefCountedFixedVectorBase(size));
+    }
+
+    template<typename InputIterator>
+    static Ref<RefCountedFixedVectorBase> create(InputIterator first, InputIterator last)
+    {
+        unsigned size = Checked<uint32_t> { std::distance(first, last) };
+        return adoptRef(*new (NotNull, fastMalloc(Base::allocationSize(size))) RefCountedFixedVectorBase(size, first, last));
+    }
+
+    template<size_t inlineCapacity, typename OverflowHandler>
+    static Ref<RefCountedFixedVectorBase> createFromVector(const Vector<T, inlineCapacity, OverflowHandler>& other)
+    {
+        unsigned size = Checked<uint32_t> { other.size() }.value();
+        return adoptRef(*new (NotNull, fastMalloc(Base::allocationSize(size))) RefCountedFixedVectorBase(size, std::begin(other), std::end(other)));
+    }
+
+    template<size_t inlineCapacity, typename OverflowHandler>
+    static Ref<RefCountedFixedVectorBase> createFromVector(Vector<T, inlineCapacity, OverflowHandler>&& other)
+    {
+        Vector<T, inlineCapacity, OverflowHandler> container = WTFMove(other);
+        unsigned size = Checked<uint32_t> { container.size() }.value();
+        return adoptRef(*new (NotNull, fastMalloc(Base::allocationSize(size))) RefCountedFixedVectorBase(size, std::move_iterator { container.begin() }, std::move_iterator { container.end() }));
+    }
+
+    Ref<RefCountedFixedVectorBase> clone() const
+    {
+        return create(Base::begin(), Base::end());
+    }
+
+    bool operator!=(const RefCountedFixedVectorBase& other) const
+    {
+        return !(*this == other);
+    }
+
+    bool operator==(const RefCountedFixedVectorBase& other) const
+    {
+        if (Base::size() != other.size())
+            return false;
+        for (unsigned i = 0; i < Base::size(); ++i) {
+            if (Base::at(i) != other.at(i))
+                return false;
+        }
+        return true;
+    }
+
+private:
+    explicit RefCountedFixedVectorBase(unsigned size)
+        : Base(size)
+    {
+    }
+
+    template<typename InputIterator>
+    RefCountedFixedVectorBase(unsigned size, InputIterator first, InputIterator last)
+        : Base(size, first, last)
+    {
+    }
+};
+
+template<typename T>
+using RefCountedFixedVector = RefCountedFixedVectorBase<T, false>;
+template<typename T>
+using ThreadSafeRefCountedFixedVector = RefCountedFixedVectorBase<T, true>;
+
+} // namespace WTF
+
+using WTF::RefCountedFixedVector;
+using WTF::ThreadSafeRefCountedFixedVector;

Added: trunk/Source/WTF/wtf/TrailingArray.h (0 => 287220)


--- trunk/Source/WTF/wtf/TrailingArray.h	                        (rev 0)
+++ trunk/Source/WTF/wtf/TrailingArray.h	2021-12-18 10:17:05 UTC (rev 287220)
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2021 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 <type_traits>
+#include <wtf/StdLibExtras.h>
+#include <wtf/Vector.h>
+
+namespace WTF {
+
+// TrailingArray offers the feature trailing array in the derived class.
+// We can allocate a memory like the following layout.
+//
+//     [  DerivedClass  ][ Trailing Array ]
+//
+// And trailing array offers appropriate methods for accessing and destructions.
+template<typename Derived, typename T>
+class TrailingArray {
+    WTF_MAKE_NONCOPYABLE(TrailingArray);
+    friend class JSC::LLIntOffsetsExtractor;
+public:
+    using value_type = T;
+    using pointer = T*;
+    using reference = T&;
+    using const_reference = const T&;
+    using const_pointer = const T*;
+    using size_type = unsigned;
+    using difference_type = std::make_signed_t<size_type>;
+    using iterator = T*;
+    using const_iterator = const T*;
+    using reverse_iterator = std::reverse_iterator<iterator>;
+    using const_reverse_iterator = std::reverse_iterator<const_iterator>;
+
+    explicit TrailingArray(unsigned size)
+        : m_size(size)
+    {
+        static_assert(std::is_final_v<Derived>);
+        VectorTypeOperations<T>::initializeIfNonPOD(begin(), end());
+    }
+
+    template<typename InputIterator>
+    TrailingArray(unsigned size, InputIterator first, InputIterator last)
+        : m_size(size)
+    {
+        static_assert(std::is_final_v<Derived>);
+        ASSERT(std::distance(first, last) == size);
+        std::uninitialized_copy(first, last, begin());
+    }
+
+    ~TrailingArray()
+    {
+        VectorTypeOperations<T>::destruct(begin(), end());
+    }
+
+    static constexpr size_t allocationSize(unsigned size)
+    {
+        return offsetOfData() + size * sizeof(T);
+    }
+
+    unsigned size() const { return m_size; }
+    bool isEmpty() const { return !size(); }
+    unsigned byteSize() const { return size() * sizeof(T); }
+
+    pointer data() { return bitwise_cast<T*>(bitwise_cast<uint8_t*>(static_cast<Derived*>(this)) + offsetOfData()); }
+    const_pointer data() const { return bitwise_cast<const T*>(bitwise_cast<const uint8_t*>(static_cast<const Derived*>(this)) + offsetOfData()); }
+
+    iterator begin() { return data(); }
+    iterator end() { return data() + size(); }
+    const_iterator begin() const { return cbegin(); }
+    const_iterator end() const { return cend(); }
+    const_iterator cbegin() const { return data(); }
+    const_iterator cend() const { return data() + size(); }
+
+    reverse_iterator rbegin() { return reverse_iterator(end()); }
+    reverse_iterator rend() { return reverse_iterator(begin()); }
+    const_reverse_iterator rbegin() const { return crbegin(); }
+    const_reverse_iterator rend() const { return crend(); }
+    const_reverse_iterator crbegin() const { return const_reverse_iterator(end()); }
+    const_reverse_iterator crend() const { return const_reverse_iterator(begin()); }
+
+    reference at(unsigned i)
+    {
+        ASSERT(i < size());
+        return begin()[i];
+    }
+
+    const_reference at(unsigned i) const
+    {
+        ASSERT(i < size());
+        return begin()[i];
+    }
+
+    reference operator[](unsigned i) { return at(i); }
+    const_reference operator[](unsigned i) const { return at(i); }
+
+    T& first() { return (*this)[0]; }
+    const T& first() const { return (*this)[0]; }
+    T& last() { return (*this)[size() - 1]; }
+    const T& last() const { return (*this)[size() - 1]; }
+
+    void fill(const T& val)
+    {
+        std::fill(begin(), end(), val);
+    }
+
+    static ptrdiff_t offsetOfSize() { return OBJECT_OFFSETOF(Derived, m_size); }
+    static constexpr ptrdiff_t offsetOfData()
+    {
+        return WTF::roundUpToMultipleOf<alignof(T)>(sizeof(Derived));
+    }
+
+protected:
+    unsigned m_size { 0 };
+};
+
+} // namespace WTF
+
+using WTF::TrailingArray;

Modified: trunk/Tools/ChangeLog (287219 => 287220)


--- trunk/Tools/ChangeLog	2021-12-18 05:45:31 UTC (rev 287219)
+++ trunk/Tools/ChangeLog	2021-12-18 10:17:05 UTC (rev 287220)
@@ -1,5 +1,27 @@
 2021-12-17  Yusuke Suzuki  <[email protected]>
 
+        [WTF] Introduce TrailingArray
+        https://bugs.webkit.org/show_bug.cgi?id=234201
+
+        Reviewed by Darin Adler.
+
+        * TestWebKitAPI/CMakeLists.txt:
+        * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+        * TestWebKitAPI/Tests/WTF/EmbeddedFixedVector.cpp: Added.
+        (TestWebKitAPI::TEST):
+        (TestWebKitAPI::DestructorObserver::DestructorObserver):
+        (TestWebKitAPI::DestructorObserver::~DestructorObserver):
+        (TestWebKitAPI::DestructorObserver::operator=):
+        * TestWebKitAPI/Tests/WTF/FixedVector.cpp:
+        (TestWebKitAPI::TEST):
+        * TestWebKitAPI/Tests/WTF/RefCountedFixedVector.cpp: Added.
+        (TestWebKitAPI::TEST):
+        (TestWebKitAPI::DestructorObserver::DestructorObserver):
+        (TestWebKitAPI::DestructorObserver::~DestructorObserver):
+        (TestWebKitAPI::DestructorObserver::operator=):
+
+2021-12-17  Yusuke Suzuki  <[email protected]>
+
         [JSC] Fix runscript's standalone ability to run
         https://bugs.webkit.org/show_bug.cgi?id=234166
 

Modified: trunk/Tools/TestWebKitAPI/CMakeLists.txt (287219 => 287220)


--- trunk/Tools/TestWebKitAPI/CMakeLists.txt	2021-12-18 05:45:31 UTC (rev 287219)
+++ trunk/Tools/TestWebKitAPI/CMakeLists.txt	2021-12-18 10:17:05 UTC (rev 287220)
@@ -38,6 +38,7 @@
     Tests/WTF/DataMutex.cpp
     Tests/WTF/DateMath.cpp
     Tests/WTF/Deque.cpp
+    Tests/WTF/EmbeddedFixedVector.cpp
     Tests/WTF/EnumTraits.cpp
     Tests/WTF/Expected.cpp
     Tests/WTF/FileSystem.cpp
@@ -74,6 +75,7 @@
     Tests/WTF/PriorityQueue.cpp
     Tests/WTF/RedBlackTree.cpp
     Tests/WTF/Ref.cpp
+    Tests/WTF/RefCountedFixedVector.cpp
     Tests/WTF/RefCounter.cpp
     Tests/WTF/RefLogger.cpp
     Tests/WTF/RefPtr.cpp

Modified: trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj (287219 => 287220)


--- trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj	2021-12-18 05:45:31 UTC (rev 287219)
+++ trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj	2021-12-18 10:17:05 UTC (rev 287220)
@@ -966,6 +966,7 @@
 		E1220DCA155B28AA0013E2FC /* MemoryCacheDisableWithinResourceLoadDelegate.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = E1220DC9155B287D0013E2FC /* MemoryCacheDisableWithinResourceLoadDelegate.html */; };
 		E194E1BD177E53C7009C4D4E /* StopLoadingFromDidReceiveResponse.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = E194E1BC177E534A009C4D4E /* StopLoadingFromDidReceiveResponse.html */; };
 		E302BDAA2404B92400865277 /* CompactRefPtrTuple.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E302BDA92404B92300865277 /* CompactRefPtrTuple.cpp */; };
+		E316D42027647A0200287B16 /* RefCountedFixedVector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E316D41F27647A0200287B16 /* RefCountedFixedVector.cpp */; };
 		E3210519261979F300157C67 /* FixedVector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E3210518261979F300157C67 /* FixedVector.cpp */; };
 		E324A6F02041C82000A76593 /* UniqueArray.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E398BC0F2041C76300387136 /* UniqueArray.cpp */; };
 		E325C90723E3870200BC7D3B /* PictureInPictureSupport.mm in Sources */ = {isa = PBXBuildFile; fileRef = E325C90623E3870200BC7D3B /* PictureInPictureSupport.mm */; };
@@ -975,6 +976,7 @@
 		E355A6322615718F001C1129 /* RobinHoodHashMap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E355A6312615718F001C1129 /* RobinHoodHashMap.cpp */; };
 		E35B908223F60DD0000011FF /* LocalizedDeviceModel.mm in Sources */ = {isa = PBXBuildFile; fileRef = E35B908123F60DD0000011FF /* LocalizedDeviceModel.mm */; };
 		E35FC7B222B82A7300F32F98 /* JSLockTakesWebThreadLock.mm in Sources */ = {isa = PBXBuildFile; fileRef = E35FC7B122B82A6D00F32F98 /* JSLockTakesWebThreadLock.mm */; };
+		E36B87A3276221870059D2F9 /* EmbeddedFixedVector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E36B87A2276221860059D2F9 /* EmbeddedFixedVector.cpp */; };
 		E373D7911F2CF35200C6FAAF /* Signals.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E3953F951F2CF32100A76A2E /* Signals.cpp */; };
 		E38A0D351FD50CC300E98C8B /* Threading.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E38A0D341FD50CBC00E98C8B /* Threading.cpp */; };
 		E38D65CA23A45FAA0063D69A /* PackedRef.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E38D65C823A45FA90063D69A /* PackedRef.cpp */; };
@@ -2890,6 +2892,7 @@
 		E194E1BA177E5145009C4D4E /* StopLoadingFromDidReceiveResponse.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = StopLoadingFromDidReceiveResponse.mm; sourceTree = "<group>"; };
 		E194E1BC177E534A009C4D4E /* StopLoadingFromDidReceiveResponse.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = StopLoadingFromDidReceiveResponse.html; sourceTree = "<group>"; };
 		E302BDA92404B92300865277 /* CompactRefPtrTuple.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CompactRefPtrTuple.cpp; sourceTree = "<group>"; };
+		E316D41F27647A0200287B16 /* RefCountedFixedVector.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RefCountedFixedVector.cpp; sourceTree = "<group>"; };
 		E3210518261979F300157C67 /* FixedVector.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FixedVector.cpp; sourceTree = "<group>"; };
 		E325C90623E3870200BC7D3B /* PictureInPictureSupport.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = PictureInPictureSupport.mm; sourceTree = "<group>"; };
 		E32B549122810AC0008AD702 /* Packed.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Packed.cpp; sourceTree = "<group>"; };
@@ -2898,6 +2901,7 @@
 		E355A6312615718F001C1129 /* RobinHoodHashMap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RobinHoodHashMap.cpp; sourceTree = "<group>"; };
 		E35B908123F60DD0000011FF /* LocalizedDeviceModel.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = LocalizedDeviceModel.mm; sourceTree = "<group>"; };
 		E35FC7B122B82A6D00F32F98 /* JSLockTakesWebThreadLock.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = JSLockTakesWebThreadLock.mm; sourceTree = "<group>"; };
+		E36B87A2276221860059D2F9 /* EmbeddedFixedVector.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = EmbeddedFixedVector.cpp; sourceTree = "<group>"; };
 		E388887020C9098100E632BC /* WorkerPool.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WorkerPool.cpp; sourceTree = "<group>"; };
 		E38A0D341FD50CBC00E98C8B /* Threading.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Threading.cpp; sourceTree = "<group>"; };
 		E38D65C823A45FA90063D69A /* PackedRef.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PackedRef.cpp; sourceTree = "<group>"; };
@@ -4484,6 +4488,7 @@
 				7AA021BA1AB09EA70052953F /* DateMath.cpp */,
 				1A3524A91D627BD40031729B /* DeletedAddressOfOperator.h */,
 				E4A757D3178AEA5B00B5D7A4 /* Deque.cpp */,
+				E36B87A2276221860059D2F9 /* EmbeddedFixedVector.cpp */,
 				1AF7B21D1D6CD12E008C126C /* EnumTraits.cpp */,
 				AD7C434C1DD2A5470026888B /* Expected.cpp */,
 				A310827121F296EC00C28B97 /* FileSystem.cpp */,
@@ -4526,6 +4531,7 @@
 				53EC253F1E96BC80000831B9 /* PriorityQueue.cpp */,
 				0FC6C4CB141027E0005B7F0C /* RedBlackTree.cpp */,
 				93A427AA180DA26400CD24D7 /* Ref.cpp */,
+				E316D41F27647A0200287B16 /* RefCountedFixedVector.cpp */,
 				86BD19971A2DB05B006DCF0A /* RefCounter.cpp */,
 				442BBF681C91CAD90017087F /* RefLogger.cpp */,
 				93A427AD180DA60F00CD24D7 /* RefLogger.h */,
@@ -5265,6 +5271,7 @@
 				5C2C01A82734883600F89D37 /* CrossThreadCopier.cpp in Sources */,
 				7C83DEA91D0A590C00FEBCF3 /* CString.cpp in Sources */,
 				7C83DEAD1D0A590C00FEBCF3 /* Deque.cpp in Sources */,
+				E36B87A3276221870059D2F9 /* EmbeddedFixedVector.cpp in Sources */,
 				1AF7B21F1D6CD14D008C126C /* EnumTraits.cpp in Sources */,
 				AD7C434D1DD2A54E0026888B /* Expected.cpp in Sources */,
 				A310827221F296FF00C28B97 /* FileSystem.cpp in Sources */,
@@ -5306,6 +5313,7 @@
 				53EC25411E96FD87000831B9 /* PriorityQueue.cpp in Sources */,
 				7C83DF131D0A590C00FEBCF3 /* RedBlackTree.cpp in Sources */,
 				7C83DF141D0A590C00FEBCF3 /* Ref.cpp in Sources */,
+				E316D42027647A0200287B16 /* RefCountedFixedVector.cpp in Sources */,
 				7C83DF151D0A590C00FEBCF3 /* RefCounter.cpp in Sources */,
 				7C83DED71D0A590C00FEBCF3 /* RefLogger.cpp in Sources */,
 				7C83DF161D0A590C00FEBCF3 /* RefPtr.cpp in Sources */,

Added: trunk/Tools/TestWebKitAPI/Tests/WTF/EmbeddedFixedVector.cpp (0 => 287220)


--- trunk/Tools/TestWebKitAPI/Tests/WTF/EmbeddedFixedVector.cpp	                        (rev 0)
+++ trunk/Tools/TestWebKitAPI/Tests/WTF/EmbeddedFixedVector.cpp	2021-12-18 10:17:05 UTC (rev 287220)
@@ -0,0 +1,272 @@
+/*
+ * Copyright (C) 2021 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. AND ITS CONTRIBUTORS ``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 ITS 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 "MoveOnly.h"
+#include <wtf/EmbeddedFixedVector.h>
+
+namespace TestWebKitAPI {
+
+TEST(WTF_EmbeddedFixedVector, Empty)
+{
+    auto vector = EmbeddedFixedVector<unsigned>::create(0);
+    EXPECT_TRUE(vector->isEmpty());
+    EXPECT_EQ(0U, vector->size());
+}
+
+TEST(WTF_EmbeddedFixedVector, Iterator)
+{
+    auto intVector = EmbeddedFixedVector<unsigned>::create(4);
+    intVector.get()[0] = 10;
+    intVector.get()[1] = 11;
+    intVector.get()[2] = 12;
+    intVector.get()[3] = 13;
+
+    auto it = intVector->begin();
+    auto end = intVector->end();
+    EXPECT_TRUE(end != it);
+
+    EXPECT_EQ(10U, *it);
+    ++it;
+    EXPECT_EQ(11U, *it);
+    ++it;
+    EXPECT_EQ(12U, *it);
+    ++it;
+    EXPECT_EQ(13U, *it);
+    ++it;
+
+    EXPECT_TRUE(end == it);
+}
+
+TEST(WTF_EmbeddedFixedVector, OverloadedOperatorAmpersand)
+{
+    struct Test {
+    private:
+        Test* operator&() = delete;
+    };
+
+    auto vector = EmbeddedFixedVector<Test>::create(1);
+    vector.get()[0] = Test();
+}
+
+TEST(WTF_EmbeddedFixedVector, Copy)
+{
+    auto vec1 = EmbeddedFixedVector<unsigned>::create(3);
+    vec1.get()[0] = 0;
+    vec1.get()[1] = 1;
+    vec1.get()[2] = 2;
+
+    auto vec2 = EmbeddedFixedVector<unsigned>::create(vec1->begin(), vec1->end());
+    EXPECT_EQ(3U, vec1->size());
+    EXPECT_EQ(3U, vec2->size());
+    for (unsigned i = 0; i < vec1->size(); ++i) {
+        EXPECT_EQ(i, vec1.get()[i]);
+        EXPECT_EQ(i, vec2.get()[i]);
+    }
+    vec1.get()[2] = 42;
+    EXPECT_EQ(42U, vec1.get()[2]);
+    EXPECT_EQ(2U, vec2.get()[2]);
+}
+
+TEST(WTF_EmbeddedFixedVector, CopyVector)
+{
+    auto vec1 = Vector<unsigned>::from(0, 1, 2, 3);
+    EXPECT_EQ(4U, vec1.size());
+    auto vec2 = EmbeddedFixedVector<unsigned>::createFromVector(vec1);
+    EXPECT_EQ(4U, vec1.size());
+    EXPECT_EQ(4U, vec2->size());
+    for (unsigned i = 0; i < vec1.size(); ++i) {
+        EXPECT_EQ(i, vec1[i]);
+        EXPECT_EQ(i, vec2.get()[i]);
+    }
+    vec1[2] = 42;
+    EXPECT_EQ(42U, vec1[2]);
+    EXPECT_EQ(2U, vec2.get()[2]);
+}
+
+TEST(WTF_EmbeddedFixedVector, MoveVector)
+{
+    auto vec1 = Vector<MoveOnly>::from(MoveOnly(0), MoveOnly(1), MoveOnly(2), MoveOnly(3));
+    EXPECT_EQ(4U, vec1.size());
+    auto vec2 = EmbeddedFixedVector<MoveOnly>::createFromVector(WTFMove(vec1));
+    EXPECT_EQ(0U, vec1.size());
+    EXPECT_EQ(4U, vec2->size());
+    for (unsigned index = 0; index < vec2->size(); ++index)
+        EXPECT_EQ(index, vec2.get()[index].value());
+}
+
+TEST(WTF_EmbeddedFixedVector, IteratorFor)
+{
+    auto vec1 = EmbeddedFixedVector<unsigned>::create(3);
+    vec1.get()[0] = 0;
+    vec1.get()[1] = 1;
+    vec1.get()[2] = 2;
+
+    unsigned index = 0;
+    for (auto iter = vec1->begin(); iter != vec1->end(); ++iter) {
+        EXPECT_EQ(index, *iter);
+        ++index;
+    }
+}
+
+TEST(WTF_EmbeddedFixedVector, Reverse)
+{
+    auto vec1 = EmbeddedFixedVector<unsigned>::create(3);
+    vec1.get()[0] = 0;
+    vec1.get()[1] = 1;
+    vec1.get()[2] = 2;
+
+    unsigned index = 0;
+    for (auto iter = vec1->rbegin(); iter != vec1->rend(); ++iter) {
+        ++index;
+        EXPECT_EQ(3U - index, *iter);
+    }
+}
+
+TEST(WTF_EmbeddedFixedVector, Fill)
+{
+    auto vec1 = EmbeddedFixedVector<unsigned>::create(3);
+    vec1->fill(42);
+
+    for (auto& value : vec1.get())
+        EXPECT_EQ(42U, value);
+}
+
+struct DestructorObserver {
+    DestructorObserver() = default;
+
+    DestructorObserver(bool* destructed)
+        : destructed(destructed)
+    {
+    }
+
+    ~DestructorObserver()
+    {
+        if (destructed)
+            *destructed = true;
+    }
+
+    DestructorObserver(DestructorObserver&& other)
+        : destructed(other.destructed)
+    {
+        other.destructed = nullptr;
+    }
+
+    DestructorObserver& operator=(DestructorObserver&& other)
+    {
+        destructed = other.destructed;
+        other.destructed = nullptr;
+        return *this;
+    }
+
+    bool* destructed { nullptr };
+};
+
+TEST(WTF_EmbeddedFixedVector, Destructor)
+{
+    Vector<bool> flags(3, false);
+    {
+        auto vector = EmbeddedFixedVector<DestructorObserver>::create(flags.size());
+        for (unsigned i = 0; i < flags.size(); ++i)
+            vector.get()[i] = DestructorObserver(&flags[i]);
+        for (unsigned i = 0; i < flags.size(); ++i)
+            EXPECT_FALSE(flags[i]);
+    }
+    for (unsigned i = 0; i < flags.size(); ++i)
+        EXPECT_TRUE(flags[i]);
+}
+
+TEST(WTF_EmbeddedFixedVector, DestructorAfterMove)
+{
+    Vector<bool> flags(3, false);
+    {
+        std::unique_ptr<EmbeddedFixedVector<DestructorObserver>> outerVector;
+        {
+            auto vector = EmbeddedFixedVector<DestructorObserver>::create(flags.size());
+            for (unsigned i = 0; i < flags.size(); ++i)
+                vector.get()[i] = DestructorObserver(&flags[i]);
+            for (unsigned i = 0; i < flags.size(); ++i)
+                EXPECT_FALSE(flags[i]);
+            outerVector = vector.moveToUniquePtr();
+        }
+        for (unsigned i = 0; i < flags.size(); ++i)
+            EXPECT_FALSE(flags[i]);
+    }
+    for (unsigned i = 0; i < flags.size(); ++i)
+        EXPECT_TRUE(flags[i]);
+}
+
+TEST(WTF_EmbeddedFixedVector, Basic)
+{
+    std::array<unsigned, 4> array { {
+        0, 1, 2, 3
+    } };
+    {
+        auto vector = EmbeddedFixedVector<unsigned>::create(array.begin(), array.end());
+        EXPECT_EQ(4U, vector->size());
+        EXPECT_EQ(0U, vector->at(0));
+        EXPECT_EQ(1U, vector->at(1));
+        EXPECT_EQ(2U, vector->at(2));
+        EXPECT_EQ(3U, vector->at(3));
+    }
+}
+
+TEST(WTF_EmbeddedFixedVector, Clone)
+{
+    std::array<unsigned, 4> array { {
+        0, 1, 2, 3
+    } };
+    {
+        auto vector = EmbeddedFixedVector<unsigned>::create(array.begin(), array.end());
+        EXPECT_EQ(4U, vector->size());
+        EXPECT_EQ(0U, vector->at(0));
+        EXPECT_EQ(1U, vector->at(1));
+        EXPECT_EQ(2U, vector->at(2));
+        EXPECT_EQ(3U, vector->at(3));
+
+        auto cloned = vector->clone();
+        EXPECT_EQ(4U, cloned->size());
+        EXPECT_EQ(0U, cloned->at(0));
+        EXPECT_EQ(1U, cloned->at(1));
+        EXPECT_EQ(2U, cloned->at(2));
+        EXPECT_EQ(3U, cloned->at(3));
+    }
+}
+
+TEST(WTF_EmbeddedFixedVector, Equal)
+{
+    auto vec1 = EmbeddedFixedVector<unsigned>::create(10);
+    auto vec2 = EmbeddedFixedVector<unsigned>::create(10);
+    for (unsigned i = 0; i < 10; ++i) {
+        vec1.get()[i] = i;
+        vec2.get()[i] = i;
+    }
+    EXPECT_EQ(vec1.get(), vec2.get());
+    vec1.get()[0] = 42;
+    EXPECT_NE(vec1.get(), vec2.get());
+}
+
+}

Modified: trunk/Tools/TestWebKitAPI/Tests/WTF/FixedVector.cpp (287219 => 287220)


--- trunk/Tools/TestWebKitAPI/Tests/WTF/FixedVector.cpp	2021-12-18 05:45:31 UTC (rev 287219)
+++ trunk/Tools/TestWebKitAPI/Tests/WTF/FixedVector.cpp	2021-12-18 10:17:05 UTC (rev 287220)
@@ -86,15 +86,15 @@
     vec1[2] = 2;
 
     FixedVector<unsigned> vec2(vec1);
-    EXPECT_EQ(vec1.size(), 3U);
-    EXPECT_EQ(vec2.size(), 3U);
+    EXPECT_EQ(3U, vec1.size());
+    EXPECT_EQ(3U, vec2.size());
     for (unsigned i = 0; i < vec1.size(); ++i) {
-        EXPECT_EQ(vec1[i], i);
-        EXPECT_EQ(vec2[i], i);
+        EXPECT_EQ(i, vec1[i]);
+        EXPECT_EQ(i, vec2[i]);
     }
     vec1[2] = 42;
-    EXPECT_EQ(vec1[2], 42U);
-    EXPECT_EQ(vec2[2], 2U);
+    EXPECT_EQ(42U, vec1[2]);
+    EXPECT_EQ(2U, vec2[2]);
 }
 
 TEST(WTF_FixedVector, CopyAssign)
@@ -106,15 +106,15 @@
 
     FixedVector<unsigned> vec2;
     vec2 = vec1;
-    EXPECT_EQ(vec1.size(), 3U);
-    EXPECT_EQ(vec2.size(), 3U);
+    EXPECT_EQ(3U, vec1.size());
+    EXPECT_EQ(3U, vec2.size());
     for (unsigned i = 0; i < vec1.size(); ++i) {
-        EXPECT_EQ(vec1[i], i);
-        EXPECT_EQ(vec2[i], i);
+        EXPECT_EQ(i, vec1[i]);
+        EXPECT_EQ(i, vec2[i]);
     }
     vec1[2] = 42;
-    EXPECT_EQ(vec1[2], 42U);
-    EXPECT_EQ(vec2[2], 2U);
+    EXPECT_EQ(42U, vec1[2]);
+    EXPECT_EQ(2U, vec2[2]);
 }
 
 TEST(WTF_FixedVector, Move)
@@ -125,10 +125,10 @@
     vec1[2] = 2;
 
     FixedVector<unsigned> vec2(WTFMove(vec1));
-    EXPECT_EQ(vec1.size(), 0U);
-    EXPECT_EQ(vec2.size(), 3U);
+    EXPECT_EQ(0U, vec1.size());
+    EXPECT_EQ(3U, vec2.size());
     for (unsigned i = 0; i < vec2.size(); ++i)
-        EXPECT_EQ(vec2[i], i);
+        EXPECT_EQ(i, vec2[i]);
 }
 
 TEST(WTF_FixedVector, MoveAssign)
@@ -140,21 +140,21 @@
 
     FixedVector<unsigned> vec2;
     vec2 = WTFMove(vec1);
-    EXPECT_EQ(vec1.size(), 0U);
-    EXPECT_EQ(vec2.size(), 3U);
+    EXPECT_EQ(0U, vec1.size());
+    EXPECT_EQ(3U, vec2.size());
     for (unsigned i = 0; i < vec2.size(); ++i)
-        EXPECT_EQ(vec2[i], i);
+        EXPECT_EQ(i, vec2[i]);
 }
 
 TEST(WTF_FixedVector, MoveVector)
 {
     auto vec1 = Vector<MoveOnly>::from(MoveOnly(0), MoveOnly(1), MoveOnly(2), MoveOnly(3));
-    EXPECT_EQ(vec1.size(), 4U);
+    EXPECT_EQ(4U, vec1.size());
     FixedVector<MoveOnly> vec2(WTFMove(vec1));
-    EXPECT_EQ(vec1.size(), 0U);
-    EXPECT_EQ(vec2.size(), 4U);
+    EXPECT_EQ(0U, vec1.size());
+    EXPECT_EQ(4U, vec2.size());
     for (unsigned index = 0; index < vec2.size(); ++index)
-        EXPECT_EQ(vec2[index].value(), index);
+        EXPECT_EQ(index, vec2[index].value());
 }
 
 TEST(WTF_FixedVector, MoveAssignVector)
@@ -162,13 +162,13 @@
     FixedVector<MoveOnly> vec2;
     {
         auto vec1 = Vector<MoveOnly>::from(MoveOnly(0), MoveOnly(1), MoveOnly(2), MoveOnly(3));
-        EXPECT_EQ(vec1.size(), 4U);
+        EXPECT_EQ(4U, vec1.size());
         vec2 = WTFMove(vec1);
-        EXPECT_EQ(vec1.size(), 0U);
+        EXPECT_EQ(0U, vec1.size());
     }
-    EXPECT_EQ(vec2.size(), 4U);
+    EXPECT_EQ(4U, vec2.size());
     for (unsigned index = 0; index < vec2.size(); ++index)
-        EXPECT_EQ(vec2[index].value(), index);
+        EXPECT_EQ(index, vec2[index].value());
 }
 
 TEST(WTF_FixedVector, Swap)
@@ -180,10 +180,10 @@
 
     FixedVector<unsigned> vec2;
     vec2.swap(vec1);
-    EXPECT_EQ(vec1.size(), 0U);
-    EXPECT_EQ(vec2.size(), 3U);
+    EXPECT_EQ(0U, vec1.size());
+    EXPECT_EQ(3U, vec2.size());
     for (unsigned i = 0; i < vec2.size(); ++i)
-        EXPECT_EQ(vec2[i], i);
+        EXPECT_EQ(i, vec2[i]);
 }
 
 TEST(WTF_FixedVector, IteratorFor)
@@ -195,7 +195,7 @@
 
     unsigned index = 0;
     for (auto iter = vec1.begin(); iter != vec1.end(); ++iter) {
-        EXPECT_EQ(*iter, index);
+        EXPECT_EQ(index, *iter);
         ++index;
     }
 }
@@ -210,7 +210,7 @@
     unsigned index = 0;
     for (auto iter = vec1.rbegin(); iter != vec1.rend(); ++iter) {
         ++index;
-        EXPECT_EQ(*iter, 3U - index);
+        EXPECT_EQ(3U - index, *iter);
     }
 }
 
@@ -220,7 +220,7 @@
     vec1.fill(42);
 
     for (auto& value : vec1)
-        EXPECT_EQ(value, 42U);
+        EXPECT_EQ(42U, value);
 }
 
 struct DestructorObserver {
@@ -293,7 +293,7 @@
         FixedVector<unsigned> vec1(3);
         auto* data1 = vec1.data();
         FixedVector<unsigned> vec2(WTFMove(vec1));
-        EXPECT_EQ(vec2.data(), data1);
+        EXPECT_EQ(data1, vec2.data());
     }
     {
         FixedVector<unsigned> vec1(3);
@@ -300,7 +300,7 @@
         auto* data1 = vec1.data();
         FixedVector<unsigned> vec2;
         vec2 = WTFMove(vec1);
-        EXPECT_EQ(vec2.data(), data1);
+        EXPECT_EQ(data1, vec2.data());
     }
 }
 
@@ -311,8 +311,8 @@
         vec1.append(FixedVector<unsigned>(3));
         auto* data1 = vec1[0].data();
         FixedVector<FixedVector<unsigned>> vec2(WTFMove(vec1));
-        EXPECT_EQ(vec2.size(), 1U);
-        EXPECT_EQ(vec2[0].data(), data1);
+        EXPECT_EQ(1U, vec2.size());
+        EXPECT_EQ(data1, vec2[0].data());
     }
     {
         Vector<FixedVector<unsigned>> vec1;
@@ -320,9 +320,39 @@
         auto* data1 = vec1[0].data();
         FixedVector<FixedVector<unsigned>> vec2;
         vec2 = WTFMove(vec1);
-        EXPECT_EQ(vec2.size(), 1U);
-        EXPECT_EQ(vec2[0].data(), data1);
+        EXPECT_EQ(1U, vec2.size());
+        EXPECT_EQ(data1, vec2[0].data());
     }
 }
 
+TEST(WTF_FixedVector, Offset)
+{
+    EXPECT_EQ(0, FixedVector<unsigned>::offsetOfStorage());
+    EXPECT_EQ(4, FixedVector<unsigned>::Storage::offsetOfData());
+    EXPECT_EQ(0, FixedVector<void*>::offsetOfStorage());
+    EXPECT_EQ(sizeof(void*), static_cast<unsigned>(FixedVector<void*>::Storage::offsetOfData()));
+}
+
+TEST(WTF_FixedVector, Equal)
+{
+    {
+        FixedVector<unsigned> vec1(10);
+        FixedVector<unsigned> vec2(10);
+        for (unsigned i = 0; i < 10; ++i) {
+            vec1[i] = i;
+            vec2[i] = i;
+        }
+        EXPECT_EQ(vec2, vec1);
+        vec1[0] = 42;
+        EXPECT_NE(vec1, vec2);
+    }
+    {
+        FixedVector<unsigned> vec1;
+        FixedVector<unsigned> vec2;
+        FixedVector<unsigned> vec3(0);
+        EXPECT_EQ(vec2, vec1);
+        EXPECT_EQ(vec3, vec1);
+    }
+}
+
 } // namespace TestWebKitAPI

Added: trunk/Tools/TestWebKitAPI/Tests/WTF/RefCountedFixedVector.cpp (0 => 287220)


--- trunk/Tools/TestWebKitAPI/Tests/WTF/RefCountedFixedVector.cpp	                        (rev 0)
+++ trunk/Tools/TestWebKitAPI/Tests/WTF/RefCountedFixedVector.cpp	2021-12-18 10:17:05 UTC (rev 287220)
@@ -0,0 +1,279 @@
+/*
+ * Copyright (C) 2021 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. AND ITS CONTRIBUTORS ``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 ITS 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 "MoveOnly.h"
+#include <wtf/RefCountedFixedVector.h>
+
+namespace TestWebKitAPI {
+
+TEST(WTF_RefCountedFixedVector, Empty)
+{
+    auto vector = RefCountedFixedVector<unsigned>::create(0);
+    EXPECT_TRUE(vector->isEmpty());
+    EXPECT_EQ(0U, vector->size());
+}
+
+TEST(WTF_RefCountedFixedVector, Iterator)
+{
+    auto intVector = RefCountedFixedVector<unsigned>::create(4);
+    intVector.get()[0] = 10;
+    intVector.get()[1] = 11;
+    intVector.get()[2] = 12;
+    intVector.get()[3] = 13;
+
+    auto it = intVector->begin();
+    auto end = intVector->end();
+    EXPECT_TRUE(end != it);
+
+    EXPECT_EQ(10U, *it);
+    ++it;
+    EXPECT_EQ(11U, *it);
+    ++it;
+    EXPECT_EQ(12U, *it);
+    ++it;
+    EXPECT_EQ(13U, *it);
+    ++it;
+
+    EXPECT_TRUE(end == it);
+}
+
+TEST(WTF_RefCountedFixedVector, OverloadedOperatorAmpersand)
+{
+    struct Test {
+    private:
+        Test* operator&() = delete;
+    };
+
+    auto vector = RefCountedFixedVector<Test>::create(1);
+    vector.get()[0] = Test();
+}
+
+TEST(WTF_RefCountedFixedVector, Copy)
+{
+    auto vec1 = RefCountedFixedVector<unsigned>::create(3);
+    vec1.get()[0] = 0;
+    vec1.get()[1] = 1;
+    vec1.get()[2] = 2;
+
+    auto vec2 = RefCountedFixedVector<unsigned>::create(vec1->begin(), vec1->end());
+    EXPECT_EQ(3U, vec1->size());
+    EXPECT_EQ(3U, vec2->size());
+    for (unsigned i = 0; i < vec1->size(); ++i) {
+        EXPECT_EQ(i, vec1.get()[i]);
+        EXPECT_EQ(i, vec2.get()[i]);
+    }
+    vec1.get()[2] = 42;
+    EXPECT_EQ(42U, vec1.get()[2]);
+    EXPECT_EQ(2U, vec2.get()[2]);
+}
+
+TEST(WTF_RefCountedFixedVector, CopyVector)
+{
+    auto vec1 = Vector<unsigned>::from(0, 1, 2, 3);
+    EXPECT_EQ(4U, vec1.size());
+    auto vec2 = RefCountedFixedVector<unsigned>::createFromVector(vec1);
+    EXPECT_EQ(4U, vec1.size());
+    EXPECT_EQ(4U, vec2->size());
+    for (unsigned i = 0; i < vec1.size(); ++i) {
+        EXPECT_EQ(i, vec1[i]);
+        EXPECT_EQ(i, vec2.get()[i]);
+    }
+    vec1[2] = 42;
+    EXPECT_EQ(42U, vec1[2]);
+    EXPECT_EQ(2U, vec2.get()[2]);
+}
+
+TEST(WTF_RefCountedFixedVector, MoveVector)
+{
+    auto vec1 = Vector<MoveOnly>::from(MoveOnly(0), MoveOnly(1), MoveOnly(2), MoveOnly(3));
+    EXPECT_EQ(4U, vec1.size());
+    auto vec2 = RefCountedFixedVector<MoveOnly>::createFromVector(WTFMove(vec1));
+    EXPECT_EQ(0U, vec1.size());
+    EXPECT_EQ(4U, vec2->size());
+    for (unsigned index = 0; index < vec2->size(); ++index)
+        EXPECT_EQ(index, vec2.get()[index].value());
+}
+
+TEST(WTF_RefCountedFixedVector, IteratorFor)
+{
+    auto vec1 = RefCountedFixedVector<unsigned>::create(3);
+    vec1.get()[0] = 0;
+    vec1.get()[1] = 1;
+    vec1.get()[2] = 2;
+
+    unsigned index = 0;
+    for (auto iter = vec1->begin(); iter != vec1->end(); ++iter) {
+        EXPECT_EQ(index, *iter);
+        ++index;
+    }
+}
+
+TEST(WTF_RefCountedFixedVector, Reverse)
+{
+    auto vec1 = RefCountedFixedVector<unsigned>::create(3);
+    vec1.get()[0] = 0;
+    vec1.get()[1] = 1;
+    vec1.get()[2] = 2;
+
+    unsigned index = 0;
+    for (auto iter = vec1->rbegin(); iter != vec1->rend(); ++iter) {
+        ++index;
+        EXPECT_EQ(3U - index, *iter);
+    }
+}
+
+TEST(WTF_RefCountedFixedVector, Fill)
+{
+    auto vec1 = RefCountedFixedVector<unsigned>::create(3);
+    vec1->fill(42);
+
+    for (auto& value : vec1.get())
+        EXPECT_EQ(value, 42U);
+}
+
+struct DestructorObserver {
+    DestructorObserver() = default;
+
+    DestructorObserver(bool* destructed)
+        : destructed(destructed)
+    {
+    }
+
+    ~DestructorObserver()
+    {
+        if (destructed)
+            *destructed = true;
+    }
+
+    DestructorObserver(DestructorObserver&& other)
+        : destructed(other.destructed)
+    {
+        other.destructed = nullptr;
+    }
+
+    DestructorObserver& operator=(DestructorObserver&& other)
+    {
+        destructed = other.destructed;
+        other.destructed = nullptr;
+        return *this;
+    }
+
+    bool* destructed { nullptr };
+};
+
+TEST(WTF_RefCountedFixedVector, Destructor)
+{
+    Vector<bool> flags(3, false);
+    {
+        auto vector = RefCountedFixedVector<DestructorObserver>::create(flags.size());
+        for (unsigned i = 0; i < flags.size(); ++i)
+            vector.get()[i] = DestructorObserver(&flags[i]);
+        for (unsigned i = 0; i < flags.size(); ++i)
+            EXPECT_FALSE(flags[i]);
+    }
+    for (unsigned i = 0; i < flags.size(); ++i)
+        EXPECT_TRUE(flags[i]);
+}
+
+TEST(WTF_RefCountedFixedVector, DestructorAfterMove)
+{
+    Vector<bool> flags(3, false);
+    {
+        RefPtr<RefCountedFixedVector<DestructorObserver>> outerVector;
+        {
+            RefPtr<RefCountedFixedVector<DestructorObserver>> outerVector2;
+            {
+                auto vector = RefCountedFixedVector<DestructorObserver>::create(flags.size());
+                for (unsigned i = 0; i < flags.size(); ++i)
+                    vector.get()[i] = DestructorObserver(&flags[i]);
+                for (unsigned i = 0; i < flags.size(); ++i)
+                    EXPECT_FALSE(flags[i]);
+                outerVector = vector.copyRef();
+                outerVector2 = vector.copyRef();
+            }
+            for (unsigned i = 0; i < flags.size(); ++i)
+                EXPECT_FALSE(flags[i]);
+            EXPECT_EQ(outerVector.get(), outerVector2.get());
+        }
+        for (unsigned i = 0; i < flags.size(); ++i)
+            EXPECT_FALSE(flags[i]);
+    }
+    for (unsigned i = 0; i < flags.size(); ++i)
+        EXPECT_TRUE(flags[i]);
+}
+
+TEST(WTF_RefCountedFixedVector, Basic)
+{
+    std::array<unsigned, 4> array { {
+        0, 1, 2, 3
+    } };
+    {
+        auto vector = RefCountedFixedVector<unsigned>::create(array.begin(), array.end());
+        EXPECT_EQ(4U, vector->size());
+        EXPECT_EQ(0U, vector->at(0));
+        EXPECT_EQ(1U, vector->at(1));
+        EXPECT_EQ(2U, vector->at(2));
+        EXPECT_EQ(3U, vector->at(3));
+    }
+}
+
+TEST(WTF_RefCountedFixedVector, Clone)
+{
+    std::array<unsigned, 4> array { {
+        0, 1, 2, 3
+    } };
+    {
+        auto vector = RefCountedFixedVector<unsigned>::create(array.begin(), array.end());
+        EXPECT_EQ(4U, vector->size());
+        EXPECT_EQ(0U, vector->at(0));
+        EXPECT_EQ(1U, vector->at(1));
+        EXPECT_EQ(2U, vector->at(2));
+        EXPECT_EQ(3U, vector->at(3));
+
+        auto cloned = vector->clone();
+        EXPECT_EQ(4U, cloned->size());
+        EXPECT_EQ(0U, cloned->at(0));
+        EXPECT_EQ(1U, cloned->at(1));
+        EXPECT_EQ(2U, cloned->at(2));
+        EXPECT_EQ(3U, cloned->at(3));
+    }
+}
+
+TEST(WTF_RefCountedFixedVector, Equal)
+{
+    auto vec1 = RefCountedFixedVector<unsigned>::create(10);
+    auto vec2 = RefCountedFixedVector<unsigned>::create(10);
+    for (unsigned i = 0; i < 10; ++i) {
+        vec1.get()[i] = i;
+        vec2.get()[i] = i;
+    }
+    EXPECT_EQ(vec1.get(), vec2.get());
+    vec1.get()[0] = 42;
+    EXPECT_NE(vec1.get(), vec2.get());
+}
+
+}
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to