- Revision
- 256468
- Author
- [email protected]
- Date
- 2020-02-12 12:32:28 -0800 (Wed, 12 Feb 2020)
Log Message
[JSC] Compact StructureTransitionTable
https://bugs.webkit.org/show_bug.cgi?id=207616
Reviewed by Mark Lam.
Some of StructureTransitionTable are shown as very large HashMap and we can compact it by encoding key.
We leverage 48bit pointers and 8byte alignment of UniquedStringImpl* to encode other parameters into it.
* runtime/Structure.cpp:
(JSC::StructureTransitionTable::contains const):
(JSC::StructureTransitionTable::get const):
(JSC::StructureTransitionTable::add):
* runtime/Structure.h:
* runtime/StructureTransitionTable.h:
(JSC::StructureTransitionTable::Hash::Key::Key):
(JSC::StructureTransitionTable::Hash::Key::isHashTableDeletedValue const):
(JSC::StructureTransitionTable::Hash::Key::impl const):
(JSC::StructureTransitionTable::Hash::Key::isAddition const):
(JSC::StructureTransitionTable::Hash::Key::attributes const):
(JSC::StructureTransitionTable::Hash::Key::operator==):
(JSC::StructureTransitionTable::Hash::Key::operator!=):
(JSC::StructureTransitionTable::Hash::hash):
(JSC::StructureTransitionTable::Hash::equal):
Modified Paths
Diff
Modified: trunk/Source/_javascript_Core/ChangeLog (256467 => 256468)
--- trunk/Source/_javascript_Core/ChangeLog 2020-02-12 20:07:25 UTC (rev 256467)
+++ trunk/Source/_javascript_Core/ChangeLog 2020-02-12 20:32:28 UTC (rev 256468)
@@ -1,5 +1,31 @@
2020-02-12 Yusuke Suzuki <[email protected]>
+ [JSC] Compact StructureTransitionTable
+ https://bugs.webkit.org/show_bug.cgi?id=207616
+
+ Reviewed by Mark Lam.
+
+ Some of StructureTransitionTable are shown as very large HashMap and we can compact it by encoding key.
+ We leverage 48bit pointers and 8byte alignment of UniquedStringImpl* to encode other parameters into it.
+
+ * runtime/Structure.cpp:
+ (JSC::StructureTransitionTable::contains const):
+ (JSC::StructureTransitionTable::get const):
+ (JSC::StructureTransitionTable::add):
+ * runtime/Structure.h:
+ * runtime/StructureTransitionTable.h:
+ (JSC::StructureTransitionTable::Hash::Key::Key):
+ (JSC::StructureTransitionTable::Hash::Key::isHashTableDeletedValue const):
+ (JSC::StructureTransitionTable::Hash::Key::impl const):
+ (JSC::StructureTransitionTable::Hash::Key::isAddition const):
+ (JSC::StructureTransitionTable::Hash::Key::attributes const):
+ (JSC::StructureTransitionTable::Hash::Key::operator==):
+ (JSC::StructureTransitionTable::Hash::Key::operator!=):
+ (JSC::StructureTransitionTable::Hash::hash):
+ (JSC::StructureTransitionTable::Hash::equal):
+
+2020-02-12 Yusuke Suzuki <[email protected]>
+
[JSC] Make RegExpCache small
https://bugs.webkit.org/show_bug.cgi?id=207619
Modified: trunk/Source/_javascript_Core/runtime/Structure.cpp (256467 => 256468)
--- trunk/Source/_javascript_Core/runtime/Structure.cpp 2020-02-12 20:07:25 UTC (rev 256467)
+++ trunk/Source/_javascript_Core/runtime/Structure.cpp 2020-02-12 20:32:28 UTC (rev 256468)
@@ -93,7 +93,7 @@
Structure* transition = singleTransition();
return transition && transition->m_transitionPropertyName == rep && transition->transitionPropertyAttributes() == attributes && transition->isPropertyDeletionTransition() == !isAddition;
}
- return map()->get(std::make_tuple(rep, attributes, isAddition));
+ return map()->get(StructureTransitionTable::Hash::Key(rep, attributes, isAddition));
}
inline Structure* StructureTransitionTable::get(UniquedStringImpl* rep, unsigned attributes, bool isAddition) const
@@ -102,7 +102,7 @@
Structure* transition = singleTransition();
return (transition && transition->m_transitionPropertyName == rep && transition->transitionPropertyAttributes() == attributes && transition->isPropertyDeletionTransition() == !isAddition) ? transition : 0;
}
- return map()->get(std::make_tuple(rep, attributes, isAddition));
+ return map()->get(StructureTransitionTable::Hash::Key(rep, attributes, isAddition));
}
void StructureTransitionTable::add(VM& vm, Structure* structure)
@@ -123,11 +123,7 @@
}
// Add the structure to the map.
-
- // Newer versions of the STL have an std::make_pair function that takes rvalue references.
- // When either of the parameters are bitfields, the C++ compiler will try to bind them as lvalues, which is invalid. To work around this, use unary "+" to make the parameter an rvalue.
- // See https://bugs.webkit.org/show_bug.cgi?id=59261 for more details
- map()->set(std::make_tuple(structure->m_transitionPropertyName.get(), +structure->transitionPropertyAttributes(), !structure->isPropertyDeletionTransition()), structure);
+ map()->set(StructureTransitionTable::Hash::Key(structure->m_transitionPropertyName.get(), structure->transitionPropertyAttributes(), !structure->isPropertyDeletionTransition()), structure);
}
void Structure::dumpStatistics()
Modified: trunk/Source/_javascript_Core/runtime/Structure.h (256467 => 256468)
--- trunk/Source/_javascript_Core/runtime/Structure.h 2020-02-12 20:07:25 UTC (rev 256467)
+++ trunk/Source/_javascript_Core/runtime/Structure.h 2020-02-12 20:32:28 UTC (rev 256468)
@@ -678,6 +678,7 @@
#define DEFINE_BITFIELD(type, lowerName, upperName, width, offset) \
static constexpr uint32_t s_##lowerName##Shift = offset;\
static constexpr uint32_t s_##lowerName##Mask = ((1 << (width - 1)) | ((1 << (width - 1)) - 1));\
+ static constexpr uint32_t s_bitWidthOf##upperName = width;\
type lowerName() const { return static_cast<type>((m_bitField >> offset) & s_##lowerName##Mask); }\
void set##upperName(type newValue) \
{\
@@ -703,6 +704,8 @@
DEFINE_BITFIELD(bool, hasUnderscoreProtoPropertyExcludingOriginalProto, HasUnderscoreProtoPropertyExcludingOriginalProto, 1, 29);
DEFINE_BITFIELD(bool, isPropertyDeletionTransition, IsPropertyDeletionTransition, 1, 30);
+ static_assert(s_bitWidthOfTransitionPropertyAttributes <= sizeof(TransitionPropertyAttributes) * 8);
+
private:
friend class LLIntOffsetsExtractor;
Modified: trunk/Source/_javascript_Core/runtime/StructureTransitionTable.h (256467 => 256468)
--- trunk/Source/_javascript_Core/runtime/StructureTransitionTable.h 2020-02-12 20:07:25 UTC (rev 256467)
+++ trunk/Source/_javascript_Core/runtime/StructureTransitionTable.h 2020-02-12 20:32:28 UTC (rev 256468)
@@ -52,6 +52,7 @@
Seal,
Freeze
};
+using TransitionPropertyAttributes = uint16_t;
inline unsigned toAttributes(NonPropertyTransition transition)
{
@@ -143,8 +144,74 @@
static constexpr intptr_t UsingSingleSlotFlag = 1;
+#if CPU(ADDRESS64)
struct Hash {
- typedef std::tuple<UniquedStringImpl*, unsigned, bool> Key;
+ // Logically, Key is a tuple of (1) UniquedStringImpl*, (2) unsigned attributes, and (3) bool isAddition.
+ // We encode (2) and (3) into (1)'s empty bits since a pointer is 48bit and lower 3 bits are usable because of alignment.
+ struct Key {
+ friend struct Hash;
+ static_assert(WTF_OS_CONSTANT_EFFECTIVE_ADDRESS_WIDTH <= 48);
+ static constexpr uintptr_t isAdditionMask = 1ULL;
+ static constexpr uintptr_t stringMask = ((1ULL << 48) - 1) & (~isAdditionMask);
+ static constexpr unsigned attributesShift = 48;
+ static constexpr uintptr_t hashTableDeletedValue = 0x2;
+ static_assert(sizeof(TransitionPropertyAttributes) * 8 <= 16);
+ static_assert(hashTableDeletedValue < alignof(UniquedStringImpl));
+
+ // Highest 16 bits are for TransitionPropertyAttributes.
+ // Lowest 1 bit is for isAddition flag.
+ // Remaining bits are for UniquedStringImpl*.
+ Key(UniquedStringImpl* impl, unsigned attributes, bool isAddition)
+ : m_encodedData(bitwise_cast<uintptr_t>(impl) | (static_cast<uintptr_t>(attributes) << attributesShift) | (static_cast<uintptr_t>(isAddition) & isAdditionMask))
+ {
+ ASSERT(impl == this->impl());
+ ASSERT(isAddition == this->isAddition());
+ ASSERT(attributes == this->attributes());
+ }
+
+ Key() = default;
+
+ Key(WTF::HashTableDeletedValueType)
+ : m_encodedData(hashTableDeletedValue)
+ { }
+
+ bool isHashTableDeletedValue() const { return m_encodedData == hashTableDeletedValue; }
+
+ UniquedStringImpl* impl() const { return bitwise_cast<UniquedStringImpl*>(m_encodedData & stringMask); }
+ bool isAddition() const { return m_encodedData & isAdditionMask; }
+ unsigned attributes() const { return m_encodedData >> attributesShift; }
+
+ friend bool operator==(const Key& a, const Key& b)
+ {
+ return a.m_encodedData == b.m_encodedData;
+ }
+
+ friend bool operator!=(const Key& a, const Key& b)
+ {
+ return a.m_encodedData != b.m_encodedData;
+ }
+
+ private:
+ uintptr_t m_encodedData { 0 };
+ };
+ using KeyTraits = SimpleClassHashTraits<Key>;
+
+ static unsigned hash(const Key& p)
+ {
+ return IntHash<uintptr_t>::hash(p.m_encodedData);
+ }
+
+ static bool equal(const Key& a, const Key& b)
+ {
+ return a == b;
+ }
+
+ static constexpr bool safeToCompareToEmptyOrDeleted = true;
+ };
+#else
+ struct Hash {
+ using Key = std::tuple<UniquedStringImpl*, unsigned, bool>;
+ using KeyTraits = HashTraits<Key>;
static unsigned hash(const Key& p)
{
@@ -158,8 +225,9 @@
static constexpr bool safeToCompareToEmptyOrDeleted = true;
};
+#endif
- typedef WeakGCMap<Hash::Key, Structure, Hash> TransitionMap;
+ typedef WeakGCMap<Hash::Key, Structure, Hash, Hash::KeyTraits> TransitionMap;
public:
StructureTransitionTable()