summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/runtime/MapData.h
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2016-04-10 09:28:39 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2016-04-10 09:28:39 +0000
commit32761a6cee1d0dee366b885b7b9c777e67885688 (patch)
treed6bec92bebfb216f4126356e55518842c2f476a1 /Source/JavaScriptCore/runtime/MapData.h
parenta4e969f4965059196ca948db781e52f7cfebf19e (diff)
downloadWebKitGtk-tarball-32761a6cee1d0dee366b885b7b9c777e67885688.tar.gz
webkitgtk-2.4.11webkitgtk-2.4.11
Diffstat (limited to 'Source/JavaScriptCore/runtime/MapData.h')
-rw-r--r--Source/JavaScriptCore/runtime/MapData.h239
1 files changed, 128 insertions, 111 deletions
diff --git a/Source/JavaScriptCore/runtime/MapData.h b/Source/JavaScriptCore/runtime/MapData.h
index 6a4cc2ca0..9c2bb559f 100644
--- a/Source/JavaScriptCore/runtime/MapData.h
+++ b/Source/JavaScriptCore/runtime/MapData.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013, 2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2013 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -26,69 +26,43 @@
#ifndef MapData_h
#define MapData_h
-#include "CopyBarrier.h"
#include "JSCell.h"
-#include "WeakGCMapInlines.h"
+#include "Structure.h"
#include <wtf/HashFunctions.h>
#include <wtf/HashMap.h>
#include <wtf/MathExtras.h>
-#include <wtf/RefCounted.h>
-#include <wtf/RefPtr.h>
-#include <wtf/Vector.h>
namespace JSC {
-class ExecState;
-class VM;
-
-template<typename Entry, typename JSIterator>
-class MapDataImpl {
+class MapData : public JSCell {
public:
- enum : int32_t {
- minimumMapSize = 8
- };
-
- class IteratorData {
- public:
- friend class MapDataImpl;
-
- IteratorData(const MapDataImpl*);
- bool next(WTF::KeyValuePair<JSValue, JSValue>&);
-
- // This function is called while packing a map's backing store. The
- // passed-in index is the new index the entry would have after packing.
- void didRemoveEntry(int32_t packedIndex)
- {
- if (isFinished())
- return;
-
- if (m_index <= packedIndex)
- return;
-
- --m_index;
- }
-
- void didRemoveAllEntries()
- {
- if (isFinished())
- return;
- m_index = 0;
- }
-
- void finish()
- {
- m_index = -1;
- }
+ typedef JSCell Base;
+
+ struct const_iterator {
+ const_iterator(const MapData*);
+ ~const_iterator();
+ const WTF::KeyValuePair<JSValue, JSValue> operator*() const;
+ JSValue key() const { RELEASE_ASSERT(!atEnd()); return m_mapData->m_entries[m_index].key.get(); }
+ JSValue value() const { RELEASE_ASSERT(!atEnd()); return m_mapData->m_entries[m_index].value.get(); }
+ void operator++() { ASSERT(!atEnd()); internalIncrement(); }
+ static const_iterator end(const MapData*);
+ bool operator!=(const const_iterator& other);
+ bool operator==(const const_iterator& other);
+ void finish() { m_index = std::numeric_limits<int32_t>::max(); }
+
+ bool ensureSlot();
private:
- bool ensureSlot() const;
- bool isFinished() const { return m_index == -1; }
- int32_t refreshCursor() const;
-
- const MapDataImpl* m_mapData;
- mutable int32_t m_index;
+ // This is a bit gnarly. We use an index of -1 to indicate the
+ // "end()" iterator. By casting to unsigned we can immediately
+ // test if both iterators are at the end of their iteration.
+ // We need this in order to keep the common case (eg. iter != end())
+ // fast.
+ bool atEnd() const { return static_cast<size_t>(m_index) >= static_cast<size_t>(m_mapData->m_size); }
+ void internalIncrement();
+ const MapData* m_mapData;
+ int32_t m_index;
};
- STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(IteratorData);
struct KeyType {
ALWAYS_INLINE KeyType() { }
@@ -96,37 +70,63 @@ public:
JSValue value;
};
- MapDataImpl(VM&, JSCell* owner);
+ static MapData* create(VM& vm)
+ {
+ MapData* mapData = new (NotNull, allocateCell<MapData>(vm.heap)) MapData(vm);
+ mapData->finishCreation(vm);
+ return mapData;
+ }
- void set(ExecState*, JSCell* owner, KeyType, JSValue);
- JSValue get(ExecState*, KeyType);
- bool remove(ExecState*, KeyType);
- bool contains(ExecState*, KeyType);
- size_t size(ExecState*) const { return m_size - m_deletedCount; }
+ static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(vm, globalObject, prototype, TypeInfo(CompoundType, StructureFlags), info());
+ }
- IteratorData createIteratorData(JSIterator*);
+ static const bool needsDestruction = true;
+ static const bool hasImmortalStructure = true;
- void clear();
+ JS_EXPORT_PRIVATE void set(CallFrame*, KeyType, JSValue);
+ JSValue get(CallFrame*, KeyType);
+ bool remove(CallFrame*, KeyType);
+ bool contains(CallFrame*, KeyType);
+ size_t size(CallFrame*) const { return m_size - m_deletedCount; }
- void visitChildren(JSCell* owner, SlotVisitor&);
- void copyBackingStore(CopyVisitor&, CopyToken);
+ const_iterator begin() const { return const_iterator(this); }
+ const_iterator end() const { return const_iterator::end(this); }
- size_t capacityInBytes() const { return m_capacity * sizeof(Entry); }
+ void clear();
+
+ DECLARE_INFO;
+ static const unsigned StructureFlags = OverridesVisitChildren | Base::StructureFlags;
private:
typedef WTF::UnsignedWithZeroKeyHashTraits<int32_t> IndexTraits;
+ // Our marking functions expect Entry to maintain this layout, and have all
+ // fields be WriteBarrier<Unknown>
+ struct Entry {
+ WriteBarrier<Unknown> key;
+ WriteBarrier<Unknown> value;
+ };
+
typedef HashMap<JSCell*, int32_t, typename WTF::DefaultHash<JSCell*>::Hash, WTF::HashTraits<JSCell*>, IndexTraits> CellKeyedMap;
typedef HashMap<EncodedJSValue, int32_t, EncodedJSValueHash, EncodedJSValueHashTraits, IndexTraits> ValueKeyedMap;
typedef HashMap<StringImpl*, int32_t, typename WTF::DefaultHash<StringImpl*>::Hash, WTF::HashTraits<StringImpl*>, IndexTraits> StringKeyedMap;
- typedef HashMap<SymbolImpl*, int32_t, typename WTF::PtrHash<SymbolImpl*>, WTF::HashTraits<SymbolImpl*>, IndexTraits> SymbolKeyedMap;
- ALWAYS_INLINE Entry* find(ExecState*, KeyType);
- ALWAYS_INLINE Entry* add(ExecState*, JSCell* owner, KeyType);
- template <typename Map, typename Key> ALWAYS_INLINE Entry* add(ExecState*, JSCell* owner, Map&, Key, KeyType);
+ size_t capacityInBytes() { return m_capacity * sizeof(Entry); }
+
+ MapData(VM&);
+ static void destroy(JSCell*);
+ static void visitChildren(JSCell*, SlotVisitor&);
+ static void copyBackingStore(JSCell*, CopyVisitor&, CopyToken);
- ALWAYS_INLINE bool shouldPack() const { return m_deletedCount; }
- CheckedBoolean ensureSpaceForAppend(ExecState*, JSCell* owner);
+
+ ALWAYS_INLINE Entry* find(CallFrame*, KeyType);
+ ALWAYS_INLINE Entry* add(CallFrame*, KeyType);
+ template <typename Map, typename Key> ALWAYS_INLINE Entry* add(CallFrame*, Map&, Key, KeyType);
+
+ ALWAYS_INLINE bool shouldPack() const { return m_deletedCount && !m_iteratorCount; }
+ CheckedBoolean ensureSpaceForAppend(CallFrame*);
ALWAYS_INLINE void replaceAndPackBackingStore(Entry* destination, int32_t newSize);
ALWAYS_INLINE void replaceBackingStore(Entry* destination, int32_t newSize);
@@ -134,34 +134,31 @@ private:
CellKeyedMap m_cellKeyedTable;
ValueKeyedMap m_valueKeyedTable;
StringKeyedMap m_stringKeyedTable;
- SymbolKeyedMap m_symbolKeyedTable;
int32_t m_capacity;
int32_t m_size;
int32_t m_deletedCount;
- JSCell* m_owner;
- CopyBarrier<Entry> m_entries;
- WeakGCMap<JSIterator*, JSIterator> m_iterators;
+ mutable int32_t m_iteratorCount;
+ Entry* m_entries;
};
-template<typename Entry, typename JSIterator>
-ALWAYS_INLINE MapDataImpl<Entry, JSIterator>::MapDataImpl(VM& vm, JSCell* owner)
- : m_capacity(0)
- , m_size(0)
- , m_deletedCount(0)
- , m_owner(owner)
- , m_iterators(vm)
+ALWAYS_INLINE void MapData::clear()
{
+ m_valueKeyedTable.clear();
+ m_stringKeyedTable.clear();
+ m_capacity = 0;
+ m_size = 0;
+ m_deletedCount = 0;
+ m_entries = 0;
}
-template<typename Entry, typename JSIterator>
-ALWAYS_INLINE MapDataImpl<Entry, JSIterator>::KeyType::KeyType(JSValue v)
+ALWAYS_INLINE MapData::KeyType::KeyType(JSValue v)
{
if (!v.isDouble()) {
value = v;
return;
}
double d = v.asDouble();
- if (std::isnan(d)) {
+ if (std::isnan(d) || (std::signbit(d) && d == 0.0)) {
value = v;
return;
}
@@ -173,45 +170,65 @@ ALWAYS_INLINE MapDataImpl<Entry, JSIterator>::KeyType::KeyType(JSValue v)
value = jsNumber(i);
}
-template<typename Entry, typename JSIterator>
-ALWAYS_INLINE MapDataImpl<Entry, JSIterator>::IteratorData::IteratorData(const MapDataImpl<Entry, JSIterator>* mapData)
+ALWAYS_INLINE void MapData::const_iterator::internalIncrement()
+{
+ Entry* entries = m_mapData->m_entries;
+ size_t index = m_index + 1;
+ size_t end = m_mapData->m_size;
+ while (index < end && !entries[index].key)
+ index++;
+ m_index = index;
+}
+
+ALWAYS_INLINE bool MapData::const_iterator::ensureSlot()
+{
+ // When an iterator exists outside of host cost it is possible for
+ // the containing map to be modified
+ Entry* entries = m_mapData->m_entries;
+ size_t index = m_index;
+ size_t end = m_mapData->m_size;
+ if (index < end && entries[index].key)
+ return true;
+ internalIncrement();
+ return static_cast<size_t>(m_index) < end;
+}
+
+ALWAYS_INLINE MapData::const_iterator::const_iterator(const MapData* mapData)
: m_mapData(mapData)
- , m_index(0)
+ , m_index(-1)
{
+ internalIncrement();
}
-template<typename Entry, typename JSIterator>
-ALWAYS_INLINE bool MapDataImpl<Entry, JSIterator>::IteratorData::next(WTF::KeyValuePair<JSValue, JSValue>& pair)
+ALWAYS_INLINE MapData::const_iterator::~const_iterator()
{
- if (!ensureSlot())
- return false;
- Entry* entry = &m_mapData->m_entries.get(m_mapData->m_owner)[m_index];
- pair = WTF::KeyValuePair<JSValue, JSValue>(entry->key().get(), entry->value().get());
- m_index += 1;
- return true;
+ m_mapData->m_iteratorCount--;
}
-// This is a bit gnarly. We use an index of -1 to indicate the
-// finished state. By casting to unsigned we can immediately
-// test if both iterators are at the end of their iteration.
-template<typename Entry, typename JSIterator>
-ALWAYS_INLINE bool MapDataImpl<Entry, JSIterator>::IteratorData::ensureSlot() const
+ALWAYS_INLINE const WTF::KeyValuePair<JSValue, JSValue> MapData::const_iterator::operator*() const
{
- int32_t index = refreshCursor();
- return static_cast<size_t>(index) < static_cast<size_t>(m_mapData->m_size);
+ Entry* entry = &m_mapData->m_entries[m_index];
+ return WTF::KeyValuePair<JSValue, JSValue>(entry->key.get(), entry->value.get());
}
-template<typename Entry, typename JSIterator>
-ALWAYS_INLINE int32_t MapDataImpl<Entry, JSIterator>::IteratorData::refreshCursor() const
+ALWAYS_INLINE MapData::const_iterator MapData::const_iterator::end(const MapData* mapData)
{
- if (isFinished())
- return m_index;
+ const_iterator result(mapData);
+ result.m_index = -1;
+ return result;
+}
- Entry* entries = m_mapData->m_entries.get(m_mapData->m_owner);
- size_t end = m_mapData->m_size;
- while (static_cast<size_t>(m_index) < end && !entries[m_index].key())
- m_index++;
- return m_index;
+ALWAYS_INLINE bool MapData::const_iterator::operator!=(const const_iterator& other)
+{
+ ASSERT(other.m_mapData == m_mapData);
+ if (atEnd() && other.atEnd())
+ return false;
+ return m_index != other.m_index;
+}
+
+ALWAYS_INLINE bool MapData::const_iterator::operator==(const const_iterator& other)
+{
+ return !(*this != other);
}
}