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, 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(size, &temp)); 43 Butterfly* result = fromBase(temp, preCapacity, propertyCapacity); 44 return result; 45} 46 47inline Butterfly* Butterfly::create(VM& vm, size_t preCapacity, size_t propertyCapacity, bool hasIndexingHeader, const IndexingHeader& indexingHeader, size_t indexingPayloadSizeInBytes) 48{ 49 Butterfly* result = createUninitialized( 50 vm, preCapacity, propertyCapacity, hasIndexingHeader, indexingPayloadSizeInBytes); 51 if (hasIndexingHeader) 52 *result->indexingHeader() = indexingHeader; 53 return result; 54} 55 56inline Butterfly* Butterfly::create(VM& vm, Structure* structure) 57{ 58 return create(vm, 0, structure->outOfLineCapacity(), hasIndexingHeader(structure->indexingType()), IndexingHeader(), 0); 59} 60 61inline Butterfly* Butterfly::createUninitializedDuringCollection(CopyVisitor& visitor, size_t preCapacity, size_t propertyCapacity, bool hasIndexingHeader, size_t indexingPayloadSizeInBytes) 62{ 63 size_t size = totalSize(preCapacity, propertyCapacity, hasIndexingHeader, indexingPayloadSizeInBytes); 64 Butterfly* result = fromBase( 65 visitor.allocateNewSpace(size), 66 preCapacity, propertyCapacity); 67 return result; 68} 69 70inline void* Butterfly::base(Structure* structure) 71{ 72 return base(indexingHeader()->preCapacity(structure), structure->outOfLineCapacity()); 73} 74 75inline Butterfly* Butterfly::growPropertyStorage(VM& vm, size_t preCapacity, size_t oldPropertyCapacity, bool hasIndexingHeader, size_t indexingPayloadSizeInBytes, size_t newPropertyCapacity) 76{ 77 RELEASE_ASSERT(newPropertyCapacity > oldPropertyCapacity); 78 Butterfly* result = createUninitialized( 79 vm, preCapacity, newPropertyCapacity, hasIndexingHeader, indexingPayloadSizeInBytes); 80 memcpy( 81 result->propertyStorage() - oldPropertyCapacity, 82 propertyStorage() - oldPropertyCapacity, 83 totalSize(0, oldPropertyCapacity, hasIndexingHeader, indexingPayloadSizeInBytes)); 84 return result; 85} 86 87inline Butterfly* Butterfly::growPropertyStorage(VM& vm, Structure* structure, size_t oldPropertyCapacity, size_t newPropertyCapacity) 88{ 89 return growPropertyStorage( 90 vm, indexingHeader()->preCapacity(structure), oldPropertyCapacity, 91 hasIndexingHeader(structure->indexingType()), 92 indexingHeader()->indexingPayloadSizeInBytes(structure), newPropertyCapacity); 93} 94 95inline Butterfly* Butterfly::growPropertyStorage(VM& vm, Structure* oldStructure, size_t newPropertyCapacity) 96{ 97 return growPropertyStorage( 98 vm, oldStructure, oldStructure->outOfLineCapacity(), newPropertyCapacity); 99} 100 101inline Butterfly* Butterfly::createOrGrowArrayRight(Butterfly* oldButterfly, VM& vm, Structure* oldStructure, size_t propertyCapacity, bool hadIndexingHeader, size_t oldIndexingPayloadSizeInBytes, size_t newIndexingPayloadSizeInBytes) 102{ 103 if (!oldButterfly) 104 return create(vm, 0, propertyCapacity, true, IndexingHeader(), newIndexingPayloadSizeInBytes); 105 return oldButterfly->growArrayRight(vm, oldStructure, propertyCapacity, hadIndexingHeader, oldIndexingPayloadSizeInBytes, newIndexingPayloadSizeInBytes); 106} 107 108inline Butterfly* Butterfly::growArrayRight(VM& vm, Structure* oldStructure, size_t propertyCapacity, bool hadIndexingHeader, size_t oldIndexingPayloadSizeInBytes, size_t newIndexingPayloadSizeInBytes) 109{ 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)) 116 return 0; 117 return fromBase(theBase, 0, propertyCapacity); 118} 119 120inline Butterfly* Butterfly::growArrayRight(VM& vm, Structure* oldStructure, size_t newIndexingPayloadSizeInBytes) 121{ 122 return growArrayRight( 123 vm, oldStructure, oldStructure->outOfLineCapacity(), 124 hasIndexingHeader(oldStructure->indexingType()), 125 indexingHeader()->indexingPayloadSizeInBytes(oldStructure), newIndexingPayloadSizeInBytes); 126} 127 128inline Butterfly* Butterfly::resizeArray(VM& vm, size_t propertyCapacity, bool oldHasIndexingHeader, size_t oldIndexingPayloadSizeInBytes, size_t newPreCapacity, bool newHasIndexingHeader, size_t newIndexingPayloadSizeInBytes) 129{ 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, 133 // not the capacity. 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); 140 return result; 141} 142 143inline Butterfly* Butterfly::resizeArray(VM& vm, Structure* structure, size_t newPreCapacity, size_t newIndexingPayloadSizeInBytes) 144{ 145 bool hasIndexingHeader = JSC::hasIndexingHeader(structure->indexingType()); 146 return resizeArray( 147 vm, structure->outOfLineCapacity(), hasIndexingHeader, 148 indexingHeader()->indexingPayloadSizeInBytes(structure), newPreCapacity, 149 hasIndexingHeader, newIndexingPayloadSizeInBytes); 150} 151 152inline Butterfly* Butterfly::unshift(Structure* structure, size_t numberOfSlots) 153{ 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). 164 memmove( 165 propertyStorage() - numberOfSlots - propertyCapacity, 166 propertyStorage() - propertyCapacity, 167 sizeof(EncodedJSValue) * propertyCapacity + sizeof(IndexingHeader) + ArrayStorage::sizeFor(0)); 168 return IndexingHeader::fromEndOf(propertyStorage() - numberOfSlots)->butterfly(); 169} 170 171inline Butterfly* Butterfly::shift(Structure* structure, size_t numberOfSlots) 172{ 173 ASSERT(hasArrayStorage(structure->indexingType())); 174 unsigned propertyCapacity = structure->outOfLineCapacity(); 175 // FIXME: See comment in unshift(), above. 176 memmove( 177 propertyStorage() - propertyCapacity + numberOfSlots, 178 propertyStorage() - propertyCapacity, 179 sizeof(EncodedJSValue) * propertyCapacity + sizeof(IndexingHeader) + ArrayStorage::sizeFor(0)); 180 return IndexingHeader::fromEndOf(propertyStorage() + numberOfSlots)->butterfly(); 181} 182 183} // namespace JSC 184 185#endif // ButterflyInlines_h 186 187