]>
git.saurik.com Git - apple/javascriptcore.git/blob - runtime/MapData.cpp
f09e03a2e7a122fe7717531693b7517d438b4063
   2  * Copyright (C) 2013 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. AND ITS CONTRIBUTORS ``AS IS'' 
  14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 
  15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
  16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS 
  17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
  18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
  19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
  20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
  21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
  22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 
  23  * THE POSSIBILITY OF SUCH DAMAGE. 
  29 #include "CopiedAllocator.h" 
  30 #include "CopyVisitorInlines.h" 
  31 #include "ExceptionHelpers.h" 
  32 #include "JSCJSValueInlines.h" 
  33 #include "SlotVisitorInlines.h" 
  35 #include <wtf/CryptographicallyRandomNumber.h> 
  36 #include <wtf/MathExtras.h> 
  41 const ClassInfo 
MapData::s_info 
= { "MapData", 0, 0, 0, CREATE_METHOD_TABLE(MapData
) }; 
  43 static const int32_t minimumMapSize 
= 8; 
  45 MapData::MapData(VM
& vm
) 
  46     : Base(vm
, vm
.mapDataStructure
.get()) 
  55 MapData::Entry
* MapData::find(CallFrame
* callFrame
, KeyType key
) 
  57     if (key
.value
.isString()) { 
  58         auto iter 
= m_stringKeyedTable
.find(asString(key
.value
)->value(callFrame
).impl()); 
  59         if (iter 
== m_stringKeyedTable
.end()) 
  61         return &m_entries
[iter
->value
]; 
  63     if (key
.value
.isCell()) { 
  64         auto iter 
= m_cellKeyedTable
.find(key
.value
.asCell()); 
  65         if (iter 
== m_cellKeyedTable
.end()) 
  67         return &m_entries
[iter
->value
]; 
  70     auto iter 
= m_valueKeyedTable
.find(JSValue::encode(key
.value
)); 
  71     if (iter 
== m_valueKeyedTable
.end()) 
  73     return &m_entries
[iter
->value
]; 
  76 bool MapData::contains(CallFrame
* callFrame
, KeyType key
) 
  78     return find(callFrame
, key
); 
  81 template <typename Map
, typename Key
> MapData::Entry
* MapData::add(CallFrame
* callFrame
, Map
& map
, Key key
, KeyType keyValue
) 
  83     typename 
Map::iterator location 
= map
.find(key
); 
  84     if (location 
!= map
.end()) 
  85         return &m_entries
[location
->value
]; 
  87     if (!ensureSpaceForAppend(callFrame
)) 
  90     auto result 
= map
.add(key
, m_size
); 
  91     RELEASE_ASSERT(result
.isNewEntry
); 
  92     Entry
* entry 
= &m_entries
[m_size
++]; 
  94     entry
->key
.set(callFrame
->vm(), this, keyValue
.value
); 
  98 void MapData::set(CallFrame
* callFrame
, KeyType key
, JSValue value
) 
 100     Entry
* location 
= add(callFrame
, key
); 
 103     location
->value
.set(callFrame
->vm(), this, value
); 
 106 MapData::Entry
* MapData::add(CallFrame
* callFrame
, KeyType key
) 
 108     if (key
.value
.isString()) 
 109         return add(callFrame
, m_stringKeyedTable
, asString(key
.value
)->value(callFrame
).impl(), key
); 
 110     if (key
.value
.isCell()) 
 111         return add(callFrame
, m_cellKeyedTable
, key
.value
.asCell(), key
); 
 112     return add(callFrame
, m_valueKeyedTable
, JSValue::encode(key
.value
), key
); 
 115 JSValue 
MapData::get(CallFrame
* callFrame
, KeyType key
) 
 117     if (Entry
* entry 
= find(callFrame
, key
)) 
 118         return entry
->value
.get(); 
 122 bool MapData::remove(CallFrame
* callFrame
, KeyType key
) 
 125     if (key
.value
.isString()) { 
 126         auto iter 
= m_stringKeyedTable
.find(asString(key
.value
)->value(callFrame
).impl()); 
 127         if (iter 
== m_stringKeyedTable
.end()) 
 129         location 
= iter
->value
; 
 130         m_stringKeyedTable
.remove(iter
); 
 131     } else if (key
.value
.isCell()) { 
 132         auto iter 
= m_cellKeyedTable
.find(key
.value
.asCell()); 
 133         if (iter 
== m_cellKeyedTable
.end()) 
 135         location 
= iter
->value
; 
 136         m_cellKeyedTable
.remove(iter
); 
 138         auto iter 
= m_valueKeyedTable
.find(JSValue::encode(key
.value
)); 
 139         if (iter 
== m_valueKeyedTable
.end()) 
 141         location 
= iter
->value
; 
 142         m_valueKeyedTable
.remove(iter
); 
 144     m_entries
[location
].key
.clear(); 
 145     m_entries
[location
].value
.clear(); 
 150 void MapData::replaceAndPackBackingStore(Entry
* destination
, int32_t newCapacity
) 
 152     ASSERT(shouldPack()); 
 154     RELEASE_ASSERT(newCapacity 
> 0); 
 155     for (int32_t i 
= 0; i 
< m_size
; i
++) { 
 156         Entry
& entry 
= m_entries
[i
]; 
 159         ASSERT(newEnd 
< newCapacity
); 
 160         destination
[newEnd
] = entry
; 
 162         // We overwrite the old entry with a forwarding index for the new entry, 
 163         // so that we can fix up our hash tables below without doing additional 
 165         entry
.value
.setWithoutWriteBarrier(jsNumber(newEnd
)); 
 169     // Fixup for the hashmaps 
 170     for (auto ptr 
= m_valueKeyedTable
.begin(); ptr 
!= m_valueKeyedTable
.end(); ++ptr
) 
 171         ptr
->value 
= m_entries
[ptr
->value
].value
.get().asInt32(); 
 172     for (auto ptr 
= m_cellKeyedTable
.begin(); ptr 
!= m_cellKeyedTable
.end(); ++ptr
) 
 173         ptr
->value 
= m_entries
[ptr
->value
].value
.get().asInt32(); 
 174     for (auto ptr 
= m_stringKeyedTable
.begin(); ptr 
!= m_stringKeyedTable
.end(); ++ptr
) 
 175         ptr
->value 
= m_entries
[ptr
->value
].value
.get().asInt32(); 
 177     ASSERT((m_size 
- newEnd
) == m_deletedCount
); 
 180     m_capacity 
= newCapacity
; 
 182     m_entries 
= destination
; 
 186 void MapData::replaceBackingStore(Entry
* destination
, int32_t newCapacity
) 
 188     ASSERT(!shouldPack()); 
 189     RELEASE_ASSERT(newCapacity 
> 0); 
 190     ASSERT(newCapacity 
>= m_capacity
); 
 191     memcpy(destination
, m_entries
, sizeof(Entry
) * m_size
); 
 192     m_capacity 
= newCapacity
; 
 193     m_entries 
= destination
; 
 196 CheckedBoolean 
MapData::ensureSpaceForAppend(CallFrame
* callFrame
) 
 198     if (m_capacity 
> m_size
) 
 201     size_t requiredSize 
= std::max(m_capacity 
+ (m_capacity 
/ 2) + 1, minimumMapSize
); 
 202     void* newStorage 
= 0; 
 203     DeferGC 
defer(*callFrame
->heap()); 
 204     if (!callFrame
->heap()->tryAllocateStorage(this, requiredSize 
* sizeof(Entry
), &newStorage
)) { 
 205         throwOutOfMemoryError(callFrame
); 
 208     Entry
* newEntries 
= static_cast<Entry
*>(newStorage
); 
 210         replaceAndPackBackingStore(newEntries
, requiredSize
); 
 212         replaceBackingStore(newEntries
, requiredSize
); 
 213     callFrame
->heap()->writeBarrier(this); 
 217 void MapData::visitChildren(JSCell
* cell
, SlotVisitor
& visitor
) 
 219     Base::visitChildren(cell
, visitor
); 
 220     MapData
* thisObject 
= jsCast
<MapData
*>(cell
); 
 221     Entry
* entries 
= thisObject
->m_entries
; 
 224     size_t size 
= thisObject
->m_size
; 
 225     if (thisObject
->m_deletedCount
) { 
 226         for (size_t i 
= 0; i 
< size
; i
++) { 
 229             visitor
.append(&entries
[i
].key
); 
 230             visitor
.append(&entries
[i
].value
); 
 233         visitor
.appendValues(&entries
[0].key
, size 
* (sizeof(Entry
) / sizeof(WriteBarrier
<Unknown
>))); 
 235     visitor
.copyLater(thisObject
, MapBackingStoreCopyToken
, entries
, thisObject
->capacityInBytes()); 
 238 void MapData::copyBackingStore(JSCell
* cell
, CopyVisitor
& visitor
, CopyToken token
) 
 240     MapData
* thisObject 
= jsCast
<MapData
*>(cell
); 
 241     if (token 
== MapBackingStoreCopyToken 
&& visitor
.checkIfShouldCopy(thisObject
->m_entries
)) { 
 242         Entry
* oldEntries 
= thisObject
->m_entries
; 
 243         Entry
* newEntries 
= static_cast<Entry
*>(visitor
.allocateNewSpace(thisObject
->capacityInBytes())); 
 244         if (thisObject
->shouldPack()) 
 245             thisObject
->replaceAndPackBackingStore(newEntries
, thisObject
->m_capacity
); 
 247             thisObject
->replaceBackingStore(newEntries
, thisObject
->m_capacity
); 
 248         visitor
.didCopy(oldEntries
, thisObject
->capacityInBytes()); 
 250     Base::copyBackingStore(cell
, visitor
, token
); 
 253 void MapData::destroy(JSCell
* cell
) 
 255     static_cast<MapData
*>(cell
)->~MapData();