13277327ad9c8c92de41b44e004e21f425e23715
[WebKit-https.git] / Source / JavaScriptCore / runtime / Butterfly.h
1 /*
2  * Copyright (C) 2012 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #ifndef Butterfly_h
27 #define Butterfly_h
28
29 #include "IndexingHeader.h"
30 #include "PropertyOffset.h"
31 #include "PropertyStorage.h"
32 #include <wtf/Noncopyable.h>
33 #include <wtf/Platform.h>
34
35 namespace JSC {
36
37 class JSGlobalData;
38 class CopyVisitor;
39 struct ArrayStorage;
40
41 template <typename T> struct ContiguousData {
42     ContiguousData()
43         : m_data(0)
44 #if !ASSERT_DISABLED
45         , m_length(0)
46 #endif
47     {
48     }
49     ContiguousData(T* data, size_t length)
50         : m_data(data)
51 #if !ASSERT_DISABLED
52         , m_length(length)
53 #endif
54     {
55         UNUSED_PARAM(length);
56     }
57
58     const T& operator[](size_t index) const { ASSERT(index < m_length); return m_data[index]; }
59     T& operator[](size_t index) { ASSERT(index < m_length); return m_data[index]; }
60
61     T* data() const { return m_data; }
62 #if !ASSERT_DISABLED
63     size_t length() const { return m_length; }
64 #endif
65
66 private:
67     T* m_data;
68 #if !ASSERT_DISABLED
69     size_t m_length;
70 #endif
71 };
72
73 typedef ContiguousData<double> ContiguousDoubles;
74 typedef ContiguousData<WriteBarrier<Unknown> > ContiguousJSValues;
75
76 class Butterfly {
77     WTF_MAKE_NONCOPYABLE(Butterfly);
78 private:
79     Butterfly() { } // Not instantiable.
80 public:
81     
82     static size_t totalSize(size_t preCapacity, size_t propertyCapacity, bool hasIndexingHeader, size_t indexingPayloadSizeInBytes)
83     {
84         ASSERT(indexingPayloadSizeInBytes ? hasIndexingHeader : true);
85         ASSERT(sizeof(EncodedJSValue) == sizeof(IndexingHeader));
86         return (preCapacity + propertyCapacity) * sizeof(EncodedJSValue) + (hasIndexingHeader ? sizeof(IndexingHeader) : 0) + indexingPayloadSizeInBytes;
87     }
88
89     static Butterfly* fromBase(void* base, size_t preCapacity, size_t propertyCapacity)
90     {
91         return reinterpret_cast<Butterfly*>(static_cast<EncodedJSValue*>(base) + preCapacity + propertyCapacity + 1);
92     }
93     
94     // This method is here not just because it's handy, but to remind you that
95     // the whole point of butterflies is to do evil pointer arithmetic.
96     static Butterfly* fromPointer(char* ptr)
97     {
98         return reinterpret_cast<Butterfly*>(ptr);
99     }
100     
101     char* pointer() { return reinterpret_cast<char*>(this); }
102     
103     static ptrdiff_t offsetOfIndexingHeader() { return IndexingHeader::offsetOfIndexingHeader(); }
104     static ptrdiff_t offsetOfPublicLength() { return offsetOfIndexingHeader() + IndexingHeader::offsetOfPublicLength(); }
105     static ptrdiff_t offsetOfVectorLength() { return offsetOfIndexingHeader() + IndexingHeader::offsetOfVectorLength(); }
106     
107     static Butterfly* createUninitialized(JSGlobalData&, size_t preCapacity, size_t propertyCapacity, bool hasIndexingHeader, size_t indexingPayloadSizeInBytes);
108
109     static Butterfly* create(JSGlobalData&, size_t preCapacity, size_t propertyCapacity, bool hasIndexingHeader, const IndexingHeader&, size_t indexingPayloadSizeInBytes);
110     static Butterfly* create(JSGlobalData&, Structure*);
111     static Butterfly* createUninitializedDuringCollection(CopyVisitor&, size_t preCapacity, size_t propertyCapacity, bool hasIndexingHeader, size_t indexingPayloadSizeInBytes);
112     
113     IndexingHeader* indexingHeader() { return IndexingHeader::from(this); }
114     const IndexingHeader* indexingHeader() const { return IndexingHeader::from(this); }
115     PropertyStorage propertyStorage() { return indexingHeader()->propertyStorage(); }
116     ConstPropertyStorage propertyStorage() const { return indexingHeader()->propertyStorage(); }
117     
118     uint32_t publicLength() { return indexingHeader()->publicLength(); }
119     uint32_t vectorLength() { return indexingHeader()->vectorLength(); }
120     void setPublicLength(uint32_t value) { indexingHeader()->setPublicLength(value); }
121     void setVectorLength(uint32_t value) { indexingHeader()->setVectorLength(value); }
122     
123     template<typename T>
124     T* indexingPayload() { return reinterpret_cast<T*>(this); }
125     ArrayStorage* arrayStorage() { return indexingPayload<ArrayStorage>(); }
126     ContiguousJSValues contiguousInt32() { return ContiguousJSValues(indexingPayload<WriteBarrier<Unknown> >(), vectorLength()); }
127
128     ContiguousDoubles contiguousDouble() { return ContiguousDoubles(indexingPayload<double>(), vectorLength()); }
129     ContiguousJSValues contiguous() { return ContiguousJSValues(indexingPayload<WriteBarrier<Unknown> >(), vectorLength()); }
130     
131     static Butterfly* fromContiguous(WriteBarrier<Unknown>* contiguous)
132     {
133         return reinterpret_cast<Butterfly*>(contiguous);
134     }
135     static Butterfly* fromContiguous(double* contiguous)
136     {
137         return reinterpret_cast<Butterfly*>(contiguous);
138     }
139     
140     static ptrdiff_t offsetOfPropertyStorage() { return -static_cast<ptrdiff_t>(sizeof(IndexingHeader)); }
141     static int indexOfPropertyStorage()
142     {
143         ASSERT(sizeof(IndexingHeader) == sizeof(EncodedJSValue));
144         return -1;
145     }
146
147     void* base(size_t preCapacity, size_t propertyCapacity) { return propertyStorage() - propertyCapacity - preCapacity; }
148     void* base(Structure*);
149
150     static Butterfly* createOrGrowArrayRight(Butterfly*, JSGlobalData&, Structure* oldStructure, size_t propertyCapacity, bool hadIndexingHeader, size_t oldIndexingPayloadSizeInBytes, size_t newIndexingPayloadSizeInBytes); 
151
152     // The butterfly reallocation methods perform the reallocation itself but do not change any
153     // of the meta-data to reflect that the reallocation occurred. Note that this set of
154     // methods is not exhaustive and is not intended to encapsulate all possible allocation
155     // modes of butterflies - there are code paths that allocate butterflies by calling
156     // directly into Heap::tryAllocateStorage.
157     Butterfly* growPropertyStorage(JSGlobalData&, size_t preCapacity, size_t oldPropertyCapacity, bool hasIndexingHeader, size_t indexingPayloadSizeInBytes, size_t newPropertyCapacity);
158     Butterfly* growPropertyStorage(JSGlobalData&, Structure* oldStructure, size_t oldPropertyCapacity, size_t newPropertyCapacity);
159     Butterfly* growPropertyStorage(JSGlobalData&, Structure* oldStructure, size_t newPropertyCapacity);
160     Butterfly* growArrayRight(JSGlobalData&, Structure* oldStructure, size_t propertyCapacity, bool hadIndexingHeader, size_t oldIndexingPayloadSizeInBytes, size_t newIndexingPayloadSizeInBytes); // Assumes that preCapacity is zero, and asserts as much.
161     Butterfly* growArrayRight(JSGlobalData&, Structure*, size_t newIndexingPayloadSizeInBytes);
162     Butterfly* resizeArray(JSGlobalData&, size_t propertyCapacity, bool oldHasIndexingHeader, size_t oldIndexingPayloadSizeInBytes, size_t newPreCapacity, bool newHasIndexingHeader, size_t newIndexingPayloadSizeInBytes);
163     Butterfly* resizeArray(JSGlobalData&, Structure*, size_t newPreCapacity, size_t newIndexingPayloadSizeInBytes); // Assumes that you're not changing whether or not the object has an indexing header.
164     Butterfly* unshift(Structure*, size_t numberOfSlots);
165     Butterfly* shift(Structure*, size_t numberOfSlots);
166 };
167
168 } // namespace JSC
169
170 #endif // Butterfly_h
171