Skip to content

Commit

Permalink
Merge r241449 - Create a randomized free list for new StructureIDs on…
Browse files Browse the repository at this point in the history
… StructureIDTable resize.

https://bugs.webkit.org/show_bug.cgi?id=194566
<rdar://problem/47975502>

Reviewed by Michael Saboff.

Also isolate 32-bit implementation of StructureIDTable out more so the 64-bit
implementation is a little easier to read.

This patch appears to be perf neutral on JetStream2 (as run from the command line).

* runtime/StructureIDTable.cpp:
(JSC::StructureIDTable::StructureIDTable):
(JSC::StructureIDTable::makeFreeListFromRange):
(JSC::StructureIDTable::resize):
(JSC::StructureIDTable::allocateID):
(JSC::StructureIDTable::deallocateID):
* runtime/StructureIDTable.h:
(JSC::StructureIDTable::get):
(JSC::StructureIDTable::deallocateID):
(JSC::StructureIDTable::allocateID):
(JSC::StructureIDTable::flushOldTables):
  • Loading branch information
Mark Lam authored and carlosgcampos committed Feb 14, 2019
1 parent d588079 commit 0e442cf
Show file tree
Hide file tree
Showing 3 changed files with 116 additions and 36 deletions.
25 changes: 25 additions & 0 deletions Source/JavaScriptCore/ChangeLog
@@ -1,3 +1,28 @@
2019-02-13 Mark Lam <mark.lam@apple.com>

Create a randomized free list for new StructureIDs on StructureIDTable resize.
https://bugs.webkit.org/show_bug.cgi?id=194566
<rdar://problem/47975502>

Reviewed by Michael Saboff.

Also isolate 32-bit implementation of StructureIDTable out more so the 64-bit
implementation is a little easier to read.

This patch appears to be perf neutral on JetStream2 (as run from the command line).

* runtime/StructureIDTable.cpp:
(JSC::StructureIDTable::StructureIDTable):
(JSC::StructureIDTable::makeFreeListFromRange):
(JSC::StructureIDTable::resize):
(JSC::StructureIDTable::allocateID):
(JSC::StructureIDTable::deallocateID):
* runtime/StructureIDTable.h:
(JSC::StructureIDTable::get):
(JSC::StructureIDTable::deallocateID):
(JSC::StructureIDTable::allocateID):
(JSC::StructureIDTable::flushOldTables):

2019-02-13 Tadeu Zagallo <tzagallo@apple.com>

VariableLengthObject::allocate<T> should initialize objects
Expand Down
92 changes: 65 additions & 27 deletions Source/JavaScriptCore/runtime/StructureIDTable.cpp
Expand Up @@ -31,14 +31,71 @@

namespace JSC {

#if USE(JSVALUE64)

StructureIDTable::StructureIDTable()
: m_table(makeUniqueArray<StructureOrOffset>(s_initialSize))
, m_size(0)
, m_capacity(s_initialSize)
{
// We pre-allocate the first offset so that the null Structure
// can still be represented as the StructureID '0'.
allocateID(0);
table()[0].structure = nullptr;

makeFreeListFromRange(1, m_capacity - 1);
ASSERT(m_size == m_capacity);
}

void StructureIDTable::makeFreeListFromRange(uint32_t first, uint32_t last)
{
ASSERT(!m_firstFreeOffset);
ASSERT(!m_lastFreeOffset);

// Put all the new IDs on the free list sequentially.
uint32_t head = first;
uint32_t tail = last;
for (uint32_t i = first; i < last; ++i)
table()[i].offset = i + 1;
table()[last].offset = 0;

// Randomize the free list.
uint32_t size = last - first + 1;
uint32_t maxIterations = (size * 2) / 3;
for (uint32_t count = 0; count < maxIterations; ++count) {
// Move a random pick either to the head or the tail of the free list.
uint32_t random = m_weakRandom.getUint32();
uint32_t nodeBefore = first + (random % size);
uint32_t pick = table()[nodeBefore].offset;
if (pick) {
uint32_t nodeAfter = table()[pick].offset;
table()[nodeBefore].offset = nodeAfter;
if ((random & 1) || !nodeAfter) {
// Move to the head.
table()[pick].offset = head;
head = pick;
if (!nodeAfter)
tail = nodeBefore;
} else {
// Move to the tail.
table()[pick].offset = 0;
table()[tail].offset = pick;
tail = pick;
}
}
}

// Cut list in half and swap halves.
uint32_t cut = first + (m_weakRandom.getUint32() % size);
uint32_t afterCut = table()[cut].offset;
if (afterCut) {
table()[tail].offset = head;
tail = cut;
head = afterCut;
table()[cut].offset = 0;
}

m_firstFreeOffset = head;
m_lastFreeOffset = tail;
m_size = m_capacity;
}

void StructureIDTable::resize(size_t newCapacity)
Expand All @@ -60,6 +117,8 @@ void StructureIDTable::resize(size_t newCapacity)

// Update the capacity.
m_capacity = newCapacity;

makeFreeListFromRange(m_size, m_capacity - 1);
}

void StructureIDTable::flushOldTables()
Expand All @@ -69,26 +128,12 @@ void StructureIDTable::flushOldTables()

StructureID StructureIDTable::allocateID(Structure* structure)
{
#if USE(JSVALUE64)
if (!m_firstFreeOffset) {
RELEASE_ASSERT(m_capacity <= UINT_MAX);
if (m_size == m_capacity)
resize(m_capacity * 2);
ASSERT(m_size < m_capacity);

StructureOrOffset newEntry;
newEntry.structure = structure;

if (m_size == s_unusedID) {
m_size++;
return allocateID(structure);
}

StructureID result = m_size;
table()[result] = newEntry;
m_size++;
ASSERT(!isNuked(result));
return result;
ASSERT(m_size == m_capacity);
ASSERT(m_firstFreeOffset);
}

ASSERT(m_firstFreeOffset != s_unusedID);
Expand All @@ -101,15 +146,10 @@ StructureID StructureIDTable::allocateID(Structure* structure)
table()[result].structure = structure;
ASSERT(!isNuked(result));
return result;
#else
ASSERT(!isNuked(structure));
return structure;
#endif
}

void StructureIDTable::deallocateID(Structure* structure, StructureID structureID)
{
#if USE(JSVALUE64)
ASSERT(structureID != s_unusedID);
RELEASE_ASSERT(table()[structureID].structure == structure);

Expand All @@ -129,10 +169,8 @@ void StructureIDTable::deallocateID(Structure* structure, StructureID structureI
table()[m_lastFreeOffset].offset = structureID;
m_lastFreeOffset = structureID;
}
#else
UNUSED_PARAM(structure);
UNUSED_PARAM(structureID);
#endif
}

#endif // USE(JSVALUE64)

} // namespace JSC
35 changes: 26 additions & 9 deletions Source/JavaScriptCore/runtime/StructureIDTable.h
Expand Up @@ -56,7 +56,7 @@ inline StructureID decontaminate(StructureID id)
{
return id & ~nukedStructureIDBit();
}
#else
#else // not USE(JSVALUE64)
typedef Structure* StructureID;

inline StructureID nukedStructureIDBit()
Expand All @@ -78,7 +78,9 @@ inline StructureID decontaminate(StructureID id)
{
return bitwise_cast<StructureID>(bitwise_cast<uintptr_t>(id) & ~bitwise_cast<uintptr_t>(nukedStructureIDBit()));
}
#endif
#endif // not USE(JSVALUE64)

#if USE(JSVALUE64)

class StructureIDTable {
friend class LLIntOffsetsExtractor;
Expand All @@ -97,6 +99,7 @@ class StructureIDTable {

private:
void resize(size_t newCapacity);
void makeFreeListFromRange(uint32_t first, uint32_t last);

union StructureOrOffset {
WTF_MAKE_FAST_ALLOCATED;
Expand All @@ -115,26 +118,40 @@ class StructureIDTable {
uint32_t m_lastFreeOffset { 0 };
UniqueArray<StructureOrOffset> m_table;

size_t m_size;
size_t m_size { 0 };
size_t m_capacity;

WeakRandom m_weakRandom;

#if USE(JSVALUE64)
static const StructureID s_unusedID = unusedPointer;
#endif
};

inline Structure* StructureIDTable::get(StructureID structureID)
{
#if USE(JSVALUE64)
ASSERT_WITH_SECURITY_IMPLICATION(structureID);
ASSERT_WITH_SECURITY_IMPLICATION(!isNuked(structureID));
ASSERT_WITH_SECURITY_IMPLICATION(structureID < m_capacity);
return table()[structureID].structure;
#else
return structureID;
#endif
}

#else // not USE(JSVALUE64)

class StructureIDTable {
friend class LLIntOffsetsExtractor;
public:
StructureIDTable() = default;

Structure* get(StructureID structureID) { return structureID; }
void deallocateID(Structure*, StructureID) { }
StructureID allocateID(Structure* structure)
{
ASSERT(!isNuked(structure));
return structure;
};

void flushOldTables() { }
};

#endif // not USE(JSVALUE64)

} // namespace JSC

0 comments on commit 0e442cf

Please sign in to comment.