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
, 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(size
, &temp
));
43 Butterfly
* result
= fromBase(temp
, preCapacity
, propertyCapacity
);
47 inline Butterfly
* Butterfly::create(VM
& vm
, size_t preCapacity
, size_t propertyCapacity
, bool hasIndexingHeader
, const IndexingHeader
& indexingHeader
, size_t indexingPayloadSizeInBytes
)
49 Butterfly
* result
= createUninitialized(
50 vm
, preCapacity
, propertyCapacity
, hasIndexingHeader
, indexingPayloadSizeInBytes
);
51 if (hasIndexingHeader
)
52 *result
->indexingHeader() = indexingHeader
;
56 inline Butterfly
* Butterfly::create(VM
& vm
, Structure
* structure
)
58 return create(vm
, 0, structure
->outOfLineCapacity(), hasIndexingHeader(structure
->indexingType()), IndexingHeader(), 0);
61 inline Butterfly
* Butterfly::createUninitializedDuringCollection(CopyVisitor
& visitor
, size_t preCapacity
, size_t propertyCapacity
, bool hasIndexingHeader
, size_t indexingPayloadSizeInBytes
)
63 size_t size
= totalSize(preCapacity
, propertyCapacity
, hasIndexingHeader
, indexingPayloadSizeInBytes
);
64 Butterfly
* result
= fromBase(
65 visitor
.allocateNewSpace(size
),
66 preCapacity
, propertyCapacity
);
70 inline void* Butterfly::base(Structure
* structure
)
72 return base(indexingHeader()->preCapacity(structure
), structure
->outOfLineCapacity());
75 inline Butterfly
* Butterfly::growPropertyStorage(VM
& vm
, size_t preCapacity
, size_t oldPropertyCapacity
, bool hasIndexingHeader
, size_t indexingPayloadSizeInBytes
, size_t newPropertyCapacity
)
77 RELEASE_ASSERT(newPropertyCapacity
> oldPropertyCapacity
);
78 Butterfly
* result
= createUninitialized(
79 vm
, preCapacity
, newPropertyCapacity
, hasIndexingHeader
, indexingPayloadSizeInBytes
);
81 result
->propertyStorage() - oldPropertyCapacity
,
82 propertyStorage() - oldPropertyCapacity
,
83 totalSize(0, oldPropertyCapacity
, hasIndexingHeader
, indexingPayloadSizeInBytes
));
87 inline Butterfly
* Butterfly::growPropertyStorage(VM
& vm
, Structure
* structure
, size_t oldPropertyCapacity
, size_t newPropertyCapacity
)
89 return growPropertyStorage(
90 vm
, indexingHeader()->preCapacity(structure
), oldPropertyCapacity
,
91 hasIndexingHeader(structure
->indexingType()),
92 indexingHeader()->indexingPayloadSizeInBytes(structure
), newPropertyCapacity
);
95 inline Butterfly
* Butterfly::growPropertyStorage(VM
& vm
, Structure
* oldStructure
, size_t newPropertyCapacity
)
97 return growPropertyStorage(
98 vm
, oldStructure
, oldStructure
->outOfLineCapacity(), newPropertyCapacity
);
101 inline Butterfly
* Butterfly::createOrGrowArrayRight(Butterfly
* oldButterfly
, VM
& vm
, Structure
* oldStructure
, size_t propertyCapacity
, bool hadIndexingHeader
, size_t oldIndexingPayloadSizeInBytes
, size_t newIndexingPayloadSizeInBytes
)
104 return create(vm
, 0, propertyCapacity
, true, IndexingHeader(), newIndexingPayloadSizeInBytes
);
105 return oldButterfly
->growArrayRight(vm
, oldStructure
, propertyCapacity
, hadIndexingHeader
, oldIndexingPayloadSizeInBytes
, newIndexingPayloadSizeInBytes
);
108 inline Butterfly
* Butterfly::growArrayRight(VM
& vm
, Structure
* oldStructure
, size_t propertyCapacity
, bool hadIndexingHeader
, size_t oldIndexingPayloadSizeInBytes
, size_t newIndexingPayloadSizeInBytes
)
110 ASSERT_UNUSED(oldStructure
, !indexingHeader()->preCapacity(oldStructure
));
111 ASSERT_UNUSED(oldStructure
, hadIndexingHeader
== hasIndexingHeader(oldStructure
->indexingType()));
112 void* theBase
= base(0, propertyCapacity
);
113 size_t oldSize
= totalSize(0, propertyCapacity
, hadIndexingHeader
, oldIndexingPayloadSizeInBytes
);
114 size_t newSize
= totalSize(0, propertyCapacity
, true, newIndexingPayloadSizeInBytes
);
115 if (!vm
.heap
.tryReallocateStorage(&theBase
, oldSize
, newSize
))
117 return fromBase(theBase
, 0, propertyCapacity
);
120 inline Butterfly
* Butterfly::growArrayRight(VM
& vm
, Structure
* oldStructure
, size_t newIndexingPayloadSizeInBytes
)
122 return growArrayRight(
123 vm
, oldStructure
, oldStructure
->outOfLineCapacity(),
124 hasIndexingHeader(oldStructure
->indexingType()),
125 indexingHeader()->indexingPayloadSizeInBytes(oldStructure
), newIndexingPayloadSizeInBytes
);
128 inline Butterfly
* Butterfly::resizeArray(VM
& vm
, size_t propertyCapacity
, bool oldHasIndexingHeader
, size_t oldIndexingPayloadSizeInBytes
, size_t newPreCapacity
, bool newHasIndexingHeader
, size_t newIndexingPayloadSizeInBytes
)
130 Butterfly
* result
= createUninitialized(
131 vm
, newPreCapacity
, propertyCapacity
, newHasIndexingHeader
, newIndexingPayloadSizeInBytes
);
132 // FIXME: This could be made much more efficient if we used the property size,
134 void* to
= result
->propertyStorage() - propertyCapacity
;
135 void* from
= propertyStorage() - propertyCapacity
;
136 size_t size
= std::min(
137 totalSize(0, propertyCapacity
, oldHasIndexingHeader
, oldIndexingPayloadSizeInBytes
),
138 totalSize(0, propertyCapacity
, newHasIndexingHeader
, newIndexingPayloadSizeInBytes
));
139 memcpy(to
, from
, size
);
143 inline Butterfly
* Butterfly::resizeArray(VM
& vm
, Structure
* structure
, size_t newPreCapacity
, size_t newIndexingPayloadSizeInBytes
)
145 bool hasIndexingHeader
= JSC::hasIndexingHeader(structure
->indexingType());
147 vm
, structure
->outOfLineCapacity(), hasIndexingHeader
,
148 indexingHeader()->indexingPayloadSizeInBytes(structure
), newPreCapacity
,
149 hasIndexingHeader
, newIndexingPayloadSizeInBytes
);
152 inline Butterfly
* Butterfly::unshift(Structure
* structure
, size_t numberOfSlots
)
154 ASSERT(hasArrayStorage(structure
->indexingType()));
155 ASSERT(numberOfSlots
<= indexingHeader()->preCapacity(structure
));
156 unsigned propertyCapacity
= structure
->outOfLineCapacity();
157 // FIXME: It would probably be wise to rewrite this as a loop since (1) we know in which
158 // direction we're moving memory so we don't need the extra check of memmove and (2) we're
159 // moving a small amount of memory in the common case so the throughput of memmove won't
160 // amortize the overhead of calling it. And no, we cannot rely on the C++ compiler to
161 // inline memmove (particularly since the size argument is likely to be variable), nor can
162 // we rely on the compiler to recognize the ordering of the pointer arguments (since
163 // propertyCapacity is variable and could cause wrap-around as far as the compiler knows).
165 propertyStorage() - numberOfSlots
- propertyCapacity
,
166 propertyStorage() - propertyCapacity
,
167 sizeof(EncodedJSValue
) * propertyCapacity
+ sizeof(IndexingHeader
) + ArrayStorage::sizeFor(0));
168 return IndexingHeader::fromEndOf(propertyStorage() - numberOfSlots
)->butterfly();
171 inline Butterfly
* Butterfly::shift(Structure
* structure
, size_t numberOfSlots
)
173 ASSERT(hasArrayStorage(structure
->indexingType()));
174 unsigned propertyCapacity
= structure
->outOfLineCapacity();
175 // FIXME: See comment in unshift(), above.
177 propertyStorage() - propertyCapacity
+ numberOfSlots
,
178 propertyStorage() - propertyCapacity
,
179 sizeof(EncodedJSValue
) * propertyCapacity
+ sizeof(IndexingHeader
) + ArrayStorage::sizeFor(0));
180 return IndexingHeader::fromEndOf(propertyStorage() + numberOfSlots
)->butterfly();
185 #endif // ButterflyInlines_h