2 * Copyright (C) 2012 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
26 #ifndef ButterflyInlines_h
27 #define ButterflyInlines_h
29 #include "ArrayStorage.h"
30 #include "Butterfly.h"
31 #include "CopiedSpaceInlines.h"
32 #include "CopyVisitor.h"
34 #include "Structure.h"
38 inline Butterfly
* Butterfly::createUninitialized(VM
& vm
, JSCell
* intendedOwner
, size_t preCapacity
, size_t propertyCapacity
, bool hasIndexingHeader
, size_t indexingPayloadSizeInBytes
)
41 size_t size
= totalSize(preCapacity
, propertyCapacity
, hasIndexingHeader
, indexingPayloadSizeInBytes
);
42 RELEASE_ASSERT(vm
.heap
.tryAllocateStorage(intendedOwner
, size
, &temp
));
43 Butterfly
* result
= fromBase(temp
, preCapacity
, propertyCapacity
);
47 inline Butterfly
* Butterfly::create(VM
& vm
, JSCell
* intendedOwner
, size_t preCapacity
, size_t propertyCapacity
, bool hasIndexingHeader
, const IndexingHeader
& indexingHeader
, size_t indexingPayloadSizeInBytes
)
49 Butterfly
* result
= createUninitialized(
50 vm
, intendedOwner
, preCapacity
, propertyCapacity
, hasIndexingHeader
,
51 indexingPayloadSizeInBytes
);
52 if (hasIndexingHeader
)
53 *result
->indexingHeader() = indexingHeader
;
57 inline Butterfly
* Butterfly::create(VM
& vm
, JSCell
* intendedOwner
, Structure
* structure
)
60 vm
, intendedOwner
, 0, structure
->outOfLineCapacity(),
61 structure
->hasIndexingHeader(intendedOwner
), IndexingHeader(), 0);
64 inline Butterfly
* Butterfly::createUninitializedDuringCollection(CopyVisitor
& visitor
, size_t preCapacity
, size_t propertyCapacity
, bool hasIndexingHeader
, size_t indexingPayloadSizeInBytes
)
66 size_t size
= totalSize(preCapacity
, propertyCapacity
, hasIndexingHeader
, indexingPayloadSizeInBytes
);
67 Butterfly
* result
= fromBase(
68 visitor
.allocateNewSpace(size
),
69 preCapacity
, propertyCapacity
);
73 inline void* Butterfly::base(Structure
* structure
)
75 return base(indexingHeader()->preCapacity(structure
), structure
->outOfLineCapacity());
78 inline Butterfly
* Butterfly::createOrGrowPropertyStorage(
79 Butterfly
* oldButterfly
, VM
& vm
, JSCell
* intendedOwner
, Structure
* structure
, size_t oldPropertyCapacity
, size_t newPropertyCapacity
)
81 RELEASE_ASSERT(newPropertyCapacity
> oldPropertyCapacity
);
83 return create(vm
, intendedOwner
, 0, newPropertyCapacity
, false, IndexingHeader(), 0);
85 size_t preCapacity
= oldButterfly
->indexingHeader()->preCapacity(structure
);
86 size_t indexingPayloadSizeInBytes
= oldButterfly
->indexingHeader()->indexingPayloadSizeInBytes(structure
);
87 bool hasIndexingHeader
= structure
->hasIndexingHeader(intendedOwner
);
88 Butterfly
* result
= createUninitialized(
89 vm
, intendedOwner
, preCapacity
, newPropertyCapacity
, hasIndexingHeader
, indexingPayloadSizeInBytes
);
91 result
->propertyStorage() - oldPropertyCapacity
,
92 oldButterfly
->propertyStorage() - oldPropertyCapacity
,
93 totalSize(0, oldPropertyCapacity
, hasIndexingHeader
, indexingPayloadSizeInBytes
));
97 inline Butterfly
* Butterfly::createOrGrowArrayRight(
98 Butterfly
* oldButterfly
, VM
& vm
, JSCell
* intendedOwner
, Structure
* oldStructure
,
99 size_t propertyCapacity
, bool hadIndexingHeader
, size_t oldIndexingPayloadSizeInBytes
,
100 size_t newIndexingPayloadSizeInBytes
)
104 vm
, intendedOwner
, 0, propertyCapacity
, true, IndexingHeader(),
105 newIndexingPayloadSizeInBytes
);
107 return oldButterfly
->growArrayRight(
108 vm
, intendedOwner
, oldStructure
, propertyCapacity
, hadIndexingHeader
,
109 oldIndexingPayloadSizeInBytes
, newIndexingPayloadSizeInBytes
);
112 inline Butterfly
* Butterfly::growArrayRight(
113 VM
& vm
, JSCell
* intendedOwner
, Structure
* oldStructure
, size_t propertyCapacity
,
114 bool hadIndexingHeader
, size_t oldIndexingPayloadSizeInBytes
,
115 size_t newIndexingPayloadSizeInBytes
)
117 ASSERT_UNUSED(oldStructure
, !indexingHeader()->preCapacity(oldStructure
));
118 ASSERT_UNUSED(oldStructure
, hadIndexingHeader
== oldStructure
->hasIndexingHeader(intendedOwner
));
119 void* theBase
= base(0, propertyCapacity
);
120 size_t oldSize
= totalSize(0, propertyCapacity
, hadIndexingHeader
, oldIndexingPayloadSizeInBytes
);
121 size_t newSize
= totalSize(0, propertyCapacity
, true, newIndexingPayloadSizeInBytes
);
122 if (!vm
.heap
.tryReallocateStorage(intendedOwner
, &theBase
, oldSize
, newSize
))
124 return fromBase(theBase
, 0, propertyCapacity
);
127 inline Butterfly
* Butterfly::growArrayRight(
128 VM
& vm
, JSCell
* intendedOwner
, Structure
* oldStructure
,
129 size_t newIndexingPayloadSizeInBytes
)
131 return growArrayRight(
132 vm
, intendedOwner
, oldStructure
, oldStructure
->outOfLineCapacity(),
133 oldStructure
->hasIndexingHeader(intendedOwner
),
134 indexingHeader()->indexingPayloadSizeInBytes(oldStructure
),
135 newIndexingPayloadSizeInBytes
);
138 inline Butterfly
* Butterfly::resizeArray(
139 VM
& vm
, JSCell
* intendedOwner
, size_t propertyCapacity
, bool oldHasIndexingHeader
,
140 size_t oldIndexingPayloadSizeInBytes
, size_t newPreCapacity
, bool newHasIndexingHeader
,
141 size_t newIndexingPayloadSizeInBytes
)
143 Butterfly
* result
= createUninitialized(
144 vm
, intendedOwner
, newPreCapacity
, propertyCapacity
, newHasIndexingHeader
,
145 newIndexingPayloadSizeInBytes
);
146 // FIXME: This could be made much more efficient if we used the property size,
148 void* to
= result
->propertyStorage() - propertyCapacity
;
149 void* from
= propertyStorage() - propertyCapacity
;
150 size_t size
= std::min(
151 totalSize(0, propertyCapacity
, oldHasIndexingHeader
, oldIndexingPayloadSizeInBytes
),
152 totalSize(0, propertyCapacity
, newHasIndexingHeader
, newIndexingPayloadSizeInBytes
));
153 memcpy(to
, from
, size
);
157 inline Butterfly
* Butterfly::resizeArray(
158 VM
& vm
, JSCell
* intendedOwner
, Structure
* structure
, size_t newPreCapacity
,
159 size_t newIndexingPayloadSizeInBytes
)
161 bool hasIndexingHeader
= structure
->hasIndexingHeader(intendedOwner
);
163 vm
, intendedOwner
, structure
->outOfLineCapacity(), hasIndexingHeader
,
164 indexingHeader()->indexingPayloadSizeInBytes(structure
), newPreCapacity
,
165 hasIndexingHeader
, newIndexingPayloadSizeInBytes
);
168 inline Butterfly
* Butterfly::unshift(Structure
* structure
, size_t numberOfSlots
)
170 ASSERT(hasAnyArrayStorage(structure
->indexingType()));
171 ASSERT(numberOfSlots
<= indexingHeader()->preCapacity(structure
));
172 unsigned propertyCapacity
= structure
->outOfLineCapacity();
173 // FIXME: It would probably be wise to rewrite this as a loop since (1) we know in which
174 // direction we're moving memory so we don't need the extra check of memmove and (2) we're
175 // moving a small amount of memory in the common case so the throughput of memmove won't
176 // amortize the overhead of calling it. And no, we cannot rely on the C++ compiler to
177 // inline memmove (particularly since the size argument is likely to be variable), nor can
178 // we rely on the compiler to recognize the ordering of the pointer arguments (since
179 // propertyCapacity is variable and could cause wrap-around as far as the compiler knows).
181 propertyStorage() - numberOfSlots
- propertyCapacity
,
182 propertyStorage() - propertyCapacity
,
183 sizeof(EncodedJSValue
) * propertyCapacity
+ sizeof(IndexingHeader
) + ArrayStorage::sizeFor(0));
184 return IndexingHeader::fromEndOf(propertyStorage() - numberOfSlots
)->butterfly();
187 inline Butterfly
* Butterfly::shift(Structure
* structure
, size_t numberOfSlots
)
189 ASSERT(hasAnyArrayStorage(structure
->indexingType()));
190 unsigned propertyCapacity
= structure
->outOfLineCapacity();
191 // FIXME: See comment in unshift(), above.
193 propertyStorage() - propertyCapacity
+ numberOfSlots
,
194 propertyStorage() - propertyCapacity
,
195 sizeof(EncodedJSValue
) * propertyCapacity
+ sizeof(IndexingHeader
) + ArrayStorage::sizeFor(0));
196 return IndexingHeader::fromEndOf(propertyStorage() + numberOfSlots
)->butterfly();
201 #endif // ButterflyInlines_h