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 ButterflyInlines_h 27#define ButterflyInlines_h 28 29#include "ArrayStorage.h" 30#include "Butterfly.h" 31#include "CopiedSpaceInlines.h" 32#include "CopyVisitor.h" 33#include "VM.h" 34#include "Structure.h" 35 36namespace JSC { 37 38inline Butterfly* Butterfly::createUninitialized(VM& vm, JSCell* intendedOwner, size_t preCapacity, size_t propertyCapacity, bool hasIndexingHeader, size_t indexingPayloadSizeInBytes) 39{ 40 void* temp; 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); 44 return result; 45} 46 47inline Butterfly* Butterfly::create(VM& vm, JSCell* intendedOwner, size_t preCapacity, size_t propertyCapacity, bool hasIndexingHeader, const IndexingHeader& indexingHeader, size_t indexingPayloadSizeInBytes) 48{ 49 Butterfly* result = createUninitialized( 50 vm, intendedOwner, preCapacity, propertyCapacity, hasIndexingHeader, 51 indexingPayloadSizeInBytes); 52 if (hasIndexingHeader) 53 *result->indexingHeader() = indexingHeader; 54 return result; 55} 56 57inline Butterfly* Butterfly::create(VM& vm, JSCell* intendedOwner, Structure* structure) 58{ 59 return create( 60 vm, intendedOwner, 0, structure->outOfLineCapacity(), 61 structure->hasIndexingHeader(intendedOwner), IndexingHeader(), 0); 62} 63 64inline Butterfly* Butterfly::createUninitializedDuringCollection(CopyVisitor& visitor, size_t preCapacity, size_t propertyCapacity, bool hasIndexingHeader, size_t indexingPayloadSizeInBytes) 65{ 66 size_t size = totalSize(preCapacity, propertyCapacity, hasIndexingHeader, indexingPayloadSizeInBytes); 67 Butterfly* result = fromBase( 68 visitor.allocateNewSpace(size), 69 preCapacity, propertyCapacity); 70 return result; 71} 72 73inline void* Butterfly::base(Structure* structure) 74{ 75 return base(indexingHeader()->preCapacity(structure), structure->outOfLineCapacity()); 76} 77 78inline Butterfly* Butterfly::createOrGrowPropertyStorage( 79 Butterfly* oldButterfly, VM& vm, JSCell* intendedOwner, Structure* structure, size_t oldPropertyCapacity, size_t newPropertyCapacity) 80{ 81 RELEASE_ASSERT(newPropertyCapacity > oldPropertyCapacity); 82 if (!oldButterfly) 83 return create(vm, intendedOwner, 0, newPropertyCapacity, false, IndexingHeader(), 0); 84 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); 90 memcpy( 91 result->propertyStorage() - oldPropertyCapacity, 92 oldButterfly->propertyStorage() - oldPropertyCapacity, 93 totalSize(0, oldPropertyCapacity, hasIndexingHeader, indexingPayloadSizeInBytes)); 94 return result; 95} 96 97inline 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) 101{ 102 if (!oldButterfly) { 103 return create( 104 vm, intendedOwner, 0, propertyCapacity, true, IndexingHeader(), 105 newIndexingPayloadSizeInBytes); 106 } 107 return oldButterfly->growArrayRight( 108 vm, intendedOwner, oldStructure, propertyCapacity, hadIndexingHeader, 109 oldIndexingPayloadSizeInBytes, newIndexingPayloadSizeInBytes); 110} 111 112inline Butterfly* Butterfly::growArrayRight( 113 VM& vm, JSCell* intendedOwner, Structure* oldStructure, size_t propertyCapacity, 114 bool hadIndexingHeader, size_t oldIndexingPayloadSizeInBytes, 115 size_t newIndexingPayloadSizeInBytes) 116{ 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)) 123 return 0; 124 return fromBase(theBase, 0, propertyCapacity); 125} 126 127inline Butterfly* Butterfly::growArrayRight( 128 VM& vm, JSCell* intendedOwner, Structure* oldStructure, 129 size_t newIndexingPayloadSizeInBytes) 130{ 131 return growArrayRight( 132 vm, intendedOwner, oldStructure, oldStructure->outOfLineCapacity(), 133 oldStructure->hasIndexingHeader(intendedOwner), 134 indexingHeader()->indexingPayloadSizeInBytes(oldStructure), 135 newIndexingPayloadSizeInBytes); 136} 137 138inline 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) 142{ 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, 147 // not the capacity. 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); 154 return result; 155} 156 157inline Butterfly* Butterfly::resizeArray( 158 VM& vm, JSCell* intendedOwner, Structure* structure, size_t newPreCapacity, 159 size_t newIndexingPayloadSizeInBytes) 160{ 161 bool hasIndexingHeader = structure->hasIndexingHeader(intendedOwner); 162 return resizeArray( 163 vm, intendedOwner, structure->outOfLineCapacity(), hasIndexingHeader, 164 indexingHeader()->indexingPayloadSizeInBytes(structure), newPreCapacity, 165 hasIndexingHeader, newIndexingPayloadSizeInBytes); 166} 167 168inline Butterfly* Butterfly::unshift(Structure* structure, size_t numberOfSlots) 169{ 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). 180 memmove( 181 propertyStorage() - numberOfSlots - propertyCapacity, 182 propertyStorage() - propertyCapacity, 183 sizeof(EncodedJSValue) * propertyCapacity + sizeof(IndexingHeader) + ArrayStorage::sizeFor(0)); 184 return IndexingHeader::fromEndOf(propertyStorage() - numberOfSlots)->butterfly(); 185} 186 187inline Butterfly* Butterfly::shift(Structure* structure, size_t numberOfSlots) 188{ 189 ASSERT(hasAnyArrayStorage(structure->indexingType())); 190 unsigned propertyCapacity = structure->outOfLineCapacity(); 191 // FIXME: See comment in unshift(), above. 192 memmove( 193 propertyStorage() - propertyCapacity + numberOfSlots, 194 propertyStorage() - propertyCapacity, 195 sizeof(EncodedJSValue) * propertyCapacity + sizeof(IndexingHeader) + ArrayStorage::sizeFor(0)); 196 return IndexingHeader::fromEndOf(propertyStorage() + numberOfSlots)->butterfly(); 197} 198 199} // namespace JSC 200 201#endif // ButterflyInlines_h 202 203