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
34namespace JSC {
35
36class VM;
37class CopyVisitor;
38struct ArrayStorage;
39
40template <typename T> struct ContiguousData {
41 ContiguousData()
42 : m_data(0)
43#if !ASSERT_DISABLED
44 , m_length(0)
45#endif
46 {
47 }
48 ContiguousData(T* data, size_t length)
49 : m_data(data)
50#if !ASSERT_DISABLED
51 , m_length(length)
52#endif
53 {
54 UNUSED_PARAM(length);
55 }
56
57 const T& operator[](size_t index) const { ASSERT(index < m_length); return m_data[index]; }
58 T& operator[](size_t index) { ASSERT(index < m_length); return m_data[index]; }
59
60 T* data() const { return m_data; }
61#if !ASSERT_DISABLED
62 size_t length() const { return m_length; }
63#endif
64
65private:
66 T* m_data;
67#if !ASSERT_DISABLED
68 size_t m_length;
69#endif
70};
71
72typedef ContiguousData<double> ContiguousDoubles;
73typedef ContiguousData<WriteBarrier<Unknown>> ContiguousJSValues;
74
75class Butterfly {
76 WTF_MAKE_NONCOPYABLE(Butterfly);
77private:
78 Butterfly() { } // Not instantiable.
79public:
80
81 static size_t totalSize(size_t preCapacity, size_t propertyCapacity, bool hasIndexingHeader, size_t indexingPayloadSizeInBytes)
82 {
83 ASSERT(indexingPayloadSizeInBytes ? hasIndexingHeader : true);
84 ASSERT(sizeof(EncodedJSValue) == sizeof(IndexingHeader));
85 return (preCapacity + propertyCapacity) * sizeof(EncodedJSValue) + (hasIndexingHeader ? sizeof(IndexingHeader) : 0) + indexingPayloadSizeInBytes;
86 }
87
88 static Butterfly* fromBase(void* base, size_t preCapacity, size_t propertyCapacity)
89 {
90 return reinterpret_cast<Butterfly*>(static_cast<EncodedJSValue*>(base) + preCapacity + propertyCapacity + 1);
91 }
92
93 // This method is here not just because it's handy, but to remind you that
94 // the whole point of butterflies is to do evil pointer arithmetic.
95 static Butterfly* fromPointer(char* ptr)
96 {
97 return reinterpret_cast<Butterfly*>(ptr);
98 }
99
100 char* pointer() { return reinterpret_cast<char*>(this); }
101
102 static ptrdiff_t offsetOfIndexingHeader() { return IndexingHeader::offsetOfIndexingHeader(); }
103 static ptrdiff_t offsetOfArrayBuffer() { return offsetOfIndexingHeader() + IndexingHeader::offsetOfArrayBuffer(); }
104 static ptrdiff_t offsetOfPublicLength() { return offsetOfIndexingHeader() + IndexingHeader::offsetOfPublicLength(); }
105 static ptrdiff_t offsetOfVectorLength() { return offsetOfIndexingHeader() + IndexingHeader::offsetOfVectorLength(); }
106
107 static Butterfly* createUninitialized(VM&, JSCell* intendedOwner, size_t preCapacity, size_t propertyCapacity, bool hasIndexingHeader, size_t indexingPayloadSizeInBytes);
108
109 static Butterfly* create(VM&, JSCell* intendedOwner, size_t preCapacity, size_t propertyCapacity, bool hasIndexingHeader, const IndexingHeader&, size_t indexingPayloadSizeInBytes);
110 static Butterfly* create(VM&, JSCell* intendedOwner, 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_ptr<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(
151 Butterfly*, VM&, JSCell* intendedOwner, Structure* oldStructure,
152 size_t propertyCapacity, bool hadIndexingHeader,
153 size_t oldIndexingPayloadSizeInBytes, size_t newIndexingPayloadSizeInBytes);
154
155 // The butterfly reallocation methods perform the reallocation itself but do not change any
156 // of the meta-data to reflect that the reallocation occurred. Note that this set of
157 // methods is not exhaustive and is not intended to encapsulate all possible allocation
158 // modes of butterflies - there are code paths that allocate butterflies by calling
159 // directly into Heap::tryAllocateStorage.
160 static Butterfly* createOrGrowPropertyStorage(Butterfly*, VM&, JSCell* intendedOwner, Structure*, size_t oldPropertyCapacity, size_t newPropertyCapacity);
161 Butterfly* growArrayRight(VM&, JSCell* intendedOwner, Structure* oldStructure, size_t propertyCapacity, bool hadIndexingHeader, size_t oldIndexingPayloadSizeInBytes, size_t newIndexingPayloadSizeInBytes); // Assumes that preCapacity is zero, and asserts as much.
162 Butterfly* growArrayRight(VM&, JSCell* intendedOwner, Structure*, size_t newIndexingPayloadSizeInBytes);
163 Butterfly* resizeArray(VM&, JSCell* intendedOwner, size_t propertyCapacity, bool oldHasIndexingHeader, size_t oldIndexingPayloadSizeInBytes, size_t newPreCapacity, bool newHasIndexingHeader, size_t newIndexingPayloadSizeInBytes);
164 Butterfly* resizeArray(VM&, JSCell* intendedOwner, Structure*, size_t newPreCapacity, size_t newIndexingPayloadSizeInBytes); // Assumes that you're not changing whether or not the object has an indexing header.
165 Butterfly* unshift(Structure*, size_t numberOfSlots);
166 Butterfly* shift(Structure*, size_t numberOfSlots);
167};
168
169} // namespace JSC
170
171#endif // Butterfly_h
172
173