Diff
Modified: trunk/Source/_javascript_Core/ChangeLog (190562 => 190563)
--- trunk/Source/_javascript_Core/ChangeLog 2015-10-05 17:18:26 UTC (rev 190562)
+++ trunk/Source/_javascript_Core/ChangeLog 2015-10-05 17:22:20 UTC (rev 190563)
@@ -1,3 +1,141 @@
+2015-10-05 Geoffrey Garen <[email protected]>
+
+ JSC::SlotVisitor should not be a hot mess
+ https://bugs.webkit.org/show_bug.cgi?id=149798
+
+ Reviewed by Andreas Kling.
+
+ I had to debug JSC::SlotVisitor the other day. It was hard to follow.
+ Let's make it easy to follow.
+
+ * heap/Heap.cpp:
+ (JSC::Heap::markRoots):
+ (JSC::Heap::resetVisitors):
+ (JSC::Heap::objectCount):
+ (JSC::Heap::addToRememberedSet):
+ (JSC::Heap::collectAndSweep):
+ * heap/Heap.h: Deleted the string hash-consing code. It
+ was dead code.
+
+ Since no benchmark noticed the commit that broke this feature, perhaps
+ it's not worth having.
+
+ Either way, the best thing to do with dead code is to delete it.
+ It's still there in svn if we ever want to pick it up again.
+
+ * heap/HeapRootVisitor.h:
+ (JSC::HeapRootVisitor::visit):
+ (JSC::HeapRootVisitor::visitor): Removed the private append functions
+ for unsafe pointers and switched HeapRootVisitor over to the public
+ specially named functions for unsafe pointers.
+
+ In future, we should either remove the public specially named functions
+ or remove HeapRootVisitor, since they serve the same purpose. At least
+ for now we don't have pairs of functions on SlotVisitor that do the
+ exact same thing.
+
+ * heap/SlotVisitor.cpp:
+ (JSC::validate): Moved this static function to the top of the file.
+
+ (JSC::SlotVisitor::SlotVisitor):
+ (JSC::SlotVisitor::didStartMarking):
+ (JSC::SlotVisitor::reset): More hash cons removal.
+
+ (JSC::SlotVisitor::append):
+
+ (JSC::SlotVisitor::setMarkedAndAppendToMarkStack):
+ (JSC::SlotVisitor::appendToMarkStack): Renamed these functions to
+ distinguish them from the up-front helper functions that just do type
+ conversions. These are the functions that actually do stuff.
+
+ Moved these functions out of line to make it easier to set breakpoints,
+ and to enable code changes for debugging, like printf and synchronous
+ marking, without recompiling the world.
+
+ setMarkedAndAppendToMarkStack is roughly 258 bytes long (not including
+ function prologue and epilogue), so inlining it was probably not a
+ great idea in the first place.
+
+ (JSC::SlotVisitor::donateKnownParallel):
+ (JSC::SlotVisitor::drain):
+ (JSC::SlotVisitor::drainFromShared): Removed some stack probing code.
+ It was also dead.
+
+ (JSC::SlotVisitor::addOpaqueRoot):
+ (JSC::SlotVisitor::containsOpaqueRoot):
+ (JSC::SlotVisitor::containsOpaqueRootTriState):
+ (JSC::SlotVisitor::opaqueRootCount):
+ (JSC::SlotVisitor::mergeOpaqueRootsIfNecessary):
+ (JSC::SlotVisitor::mergeOpaqueRootsIfProfitable):
+ (JSC::SlotVisitor::donate):
+ (JSC::SlotVisitor::donateAndDrain):
+ (JSC::SlotVisitor::copyLater):
+ (JSC::SlotVisitor::mergeOpaqueRoots):
+ (JSC::SlotVisitor::harvestWeakReferences):
+ (JSC::SlotVisitor::finalizeUnconditionalFinalizers):
+ (JSC::SlotVisitor::dump): Moved more code out-of-line. These code paths
+ are not hot and/or not small, so we need more evidence before we inline
+ them. The SlotVisitor headers are included everywhere, so we should
+ make them include less.
+
+ Removed "internal" from all function names because it wasn't applied in
+ any consistent way that would mean anything.
+
+ (JSC::JSString::tryHashConsLock): Deleted.
+ (JSC::JSString::releaseHashConsLock): Deleted.
+ (JSC::JSString::shouldTryHashCons): Deleted.
+ (JSC::SlotVisitor::internalAppend): Deleted.
+ (JSC::SlotVisitor::validate): Deleted.
+
+ * heap/SlotVisitor.h:
+ (JSC::SlotVisitor::resetChildCount): Deleted.
+ (JSC::SlotVisitor::childCount): Deleted.
+ (JSC::SlotVisitor::incrementChildCount): Deleted. Removed this child
+ count thing. It was dead code.
+
+ * heap/SlotVisitorInlines.h:
+ (JSC::SlotVisitor::appendUnbarrieredPointer):
+ (JSC::SlotVisitor::appendUnbarrieredReadOnlyPointer):
+ (JSC::SlotVisitor::appendUnbarrieredValue):
+ (JSC::SlotVisitor::appendUnbarrieredReadOnlyValue): Some renaming and un-inlining.
+
+ (JSC::SlotVisitor::appendUnbarrieredWeak): Don't null check our input.
+ The one true place where null checking happens is our out-of-line
+ code. All inline functions do only type conversions.
+
+ (JSC::SlotVisitor::append):
+ (JSC::SlotVisitor::appendValues):
+ (JSC::SlotVisitor::addWeakReferenceHarvester):
+ (JSC::SlotVisitor::addUnconditionalFinalizer):
+ (JSC::SlotVisitor::reportExtraMemoryVisited): Some renaming and un-inlining.
+
+ (JSC::SlotVisitor::internalAppend): Deleted.
+ (JSC::SlotVisitor::unconditionallyAppend): Deleted.
+ (JSC::SlotVisitor::addOpaqueRoot): Deleted.
+ (JSC::SlotVisitor::containsOpaqueRoot): Deleted.
+ (JSC::SlotVisitor::containsOpaqueRootTriState): Deleted.
+ (JSC::SlotVisitor::opaqueRootCount): Deleted.
+ (JSC::SlotVisitor::mergeOpaqueRootsIfNecessary): Deleted.
+ (JSC::SlotVisitor::mergeOpaqueRootsIfProfitable): Deleted.
+ (JSC::SlotVisitor::donate): Deleted.
+ (JSC::SlotVisitor::donateAndDrain): Deleted.
+ (JSC::SlotVisitor::copyLater): Deleted.
+
+ * runtime/JSString.h:
+ (JSC::JSString::finishCreation):
+ (JSC::JSString::setIs8Bit):
+ (JSC::JSString::isHashConsSingleton): Deleted.
+ (JSC::JSString::clearHashConsSingleton): Deleted.
+ (JSC::JSString::setHashConsSingleton): Deleted. More hash cons removal.
+
+ * runtime/VM.cpp:
+ (JSC::VM::VM):
+ * runtime/VM.h:
+ (JSC::VM::currentThreadIsHoldingAPILock):
+ (JSC::VM::apiLock):
+ (JSC::VM::haveEnoughNewStringsToHashCons): Deleted.
+ (JSC::VM::resetNewStringsSinceLastHashCons): Deleted. More hash cons removal.
+
2015-10-04 Filip Pizlo <[email protected]>
Inline cache repatching should be throttled if it happens a lot
Modified: trunk/Source/_javascript_Core/heap/Heap.cpp (190562 => 190563)
--- trunk/Source/_javascript_Core/heap/Heap.cpp 2015-10-05 17:18:26 UTC (rev 190562)
+++ trunk/Source/_javascript_Core/heap/Heap.cpp 2015-10-05 17:22:20 UTC (rev 190563)
@@ -543,8 +543,6 @@
if (m_operationInProgress == FullCollection)
m_opaqueRoots.clear();
- m_shouldHashCons = m_vm->haveEnoughNewStringsToHashCons();
-
m_parallelMarkersShouldExit = false;
m_helperClient.setFunction(
@@ -895,10 +893,6 @@
ASSERT(m_sharedMarkStack.isEmpty());
m_weakReferenceHarvesters.removeAll();
- if (m_shouldHashCons) {
- m_vm->resetNewStringsSinceLastHashCons();
- m_shouldHashCons = false;
- }
}
size_t Heap::objectCount()
@@ -1017,7 +1011,7 @@
if (isRemembered(cell))
return;
const_cast<JSCell*>(cell)->setRemembered(true);
- m_slotVisitor.unconditionallyAppend(const_cast<JSCell*>(cell));
+ m_slotVisitor.appendToMarkStack(const_cast<JSCell*>(cell));
}
void Heap::collectAndSweep(HeapOperation collectionType)
Modified: trunk/Source/_javascript_Core/heap/Heap.h (190562 => 190563)
--- trunk/Source/_javascript_Core/heap/Heap.h 2015-10-05 17:18:26 UTC (rev 190562)
+++ trunk/Source/_javascript_Core/heap/Heap.h 2015-10-05 17:22:20 UTC (rev 190563)
@@ -423,8 +423,6 @@
HashMap<void*, std::function<void()>> m_weakGCMaps;
- bool m_shouldHashCons { false };
-
Lock m_markingMutex;
Condition m_markingConditionVariable;
MarkStackArray m_sharedMarkStack;
Modified: trunk/Source/_javascript_Core/heap/HeapRootVisitor.h (190562 => 190563)
--- trunk/Source/_javascript_Core/heap/HeapRootVisitor.h 2015-10-05 17:18:26 UTC (rev 190562)
+++ trunk/Source/_javascript_Core/heap/HeapRootVisitor.h 2015-10-05 17:22:20 UTC (rev 190563)
@@ -58,22 +58,23 @@
inline void HeapRootVisitor::visit(JSValue* slot)
{
- m_visitor.append(slot);
+ m_visitor.appendUnbarrieredValue(slot);
}
inline void HeapRootVisitor::visit(JSValue* slot, size_t count)
{
- m_visitor.append(slot, count);
+ for (size_t i = 0; i < count; ++i)
+ m_visitor.appendUnbarrieredValue(&slot[i]);
}
inline void HeapRootVisitor::visit(JSString** slot)
{
- m_visitor.append(reinterpret_cast<JSCell**>(slot));
+ m_visitor.appendUnbarrieredPointer(slot);
}
inline void HeapRootVisitor::visit(JSCell** slot)
{
- m_visitor.append(slot);
+ m_visitor.appendUnbarrieredPointer(slot);
}
inline SlotVisitor& HeapRootVisitor::visitor()
Modified: trunk/Source/_javascript_Core/heap/SlotVisitor.cpp (190562 => 190563)
--- trunk/Source/_javascript_Core/heap/SlotVisitor.cpp 2015-10-05 17:18:26 UTC (rev 190562)
+++ trunk/Source/_javascript_Core/heap/SlotVisitor.cpp 2015-10-05 17:22:20 UTC (rev 190563)
@@ -28,6 +28,7 @@
#include "SlotVisitorInlines.h"
#include "ConservativeRoots.h"
+#include "CopiedBlockInlines.h"
#include "CopiedSpace.h"
#include "CopiedSpaceInlines.h"
#include "JSArray.h"
@@ -37,10 +38,39 @@
#include "JSString.h"
#include "JSCInlines.h"
#include <wtf/Lock.h>
-#include <wtf/StackStats.h>
namespace JSC {
+#if ENABLE(GC_VALIDATION)
+static void validate(JSCell* cell)
+{
+ RELEASE_ASSERT(cell);
+
+ if (!cell->structure()) {
+ dataLogF("cell at %p has a null structure\n" , cell);
+ CRASH();
+ }
+
+ // Both the cell's structure, and the cell's structure's structure should be the Structure Structure.
+ // I hate this sentence.
+ if (cell->structure()->structure()->JSCell::classInfo() != cell->structure()->JSCell::classInfo()) {
+ const char* parentClassName = 0;
+ const char* ourClassName = 0;
+ if (cell->structure()->structure() && cell->structure()->structure()->JSCell::classInfo())
+ parentClassName = cell->structure()->structure()->JSCell::classInfo()->className;
+ if (cell->structure()->JSCell::classInfo())
+ ourClassName = cell->structure()->JSCell::classInfo()->className;
+ dataLogF("parent structure (%p <%s>) of cell at %p doesn't match cell's structure (%p <%s>)\n",
+ cell->structure()->structure(), parentClassName, cell, cell->structure(), ourClassName);
+ CRASH();
+ }
+
+ // Make sure we can walk the ClassInfo chain
+ const ClassInfo* info = cell->classInfo();
+ do { } while ((info = info->parentClass));
+}
+#endif
+
SlotVisitor::SlotVisitor(Heap& heap)
: m_stack()
, m_bytesVisited(0)
@@ -48,7 +78,6 @@
, m_visitCount(0)
, m_isInParallelMode(false)
, m_heap(heap)
- , m_shouldHashCons(false)
#if !ASSERT_DISABLED
, m_isCheckingForDefaultMarkViolation(false)
, m_isDraining(false)
@@ -65,8 +94,6 @@
{
if (heap()->operationInProgress() == FullCollection)
ASSERT(m_opaqueRoots.isEmpty()); // Should have merged by now.
-
- m_shouldHashCons = m_heap.m_shouldHashCons;
}
void SlotVisitor::reset()
@@ -75,10 +102,6 @@
m_bytesCopied = 0;
m_visitCount = 0;
ASSERT(m_stack.isEmpty());
- if (m_shouldHashCons) {
- m_uniqueStrings.clear();
- m_shouldHashCons = false;
- }
}
void SlotVisitor::clearMarkStack()
@@ -88,18 +111,51 @@
void SlotVisitor::append(ConservativeRoots& conservativeRoots)
{
- StackStats::probe();
JSCell** roots = conservativeRoots.roots();
size_t size = conservativeRoots.size();
for (size_t i = 0; i < size; ++i)
- internalAppend(0, roots[i]);
+ append(roots[i]);
}
-ALWAYS_INLINE static void visitChildren(SlotVisitor& visitor, const JSCell* cell)
+void SlotVisitor::append(JSValue value)
{
- StackStats::probe();
+ if (!value || !value.isCell())
+ return;
+ setMarkedAndAppendToMarkStack(value.asCell());
+}
+void SlotVisitor::setMarkedAndAppendToMarkStack(JSCell* cell)
+{
+ ASSERT(!m_isCheckingForDefaultMarkViolation);
+ if (!cell)
+ return;
+
+#if ENABLE(GC_VALIDATION)
+ validate(cell);
+#endif
+
+ if (Heap::testAndSetMarked(cell) || !cell->structure()) {
+ ASSERT(cell->structure());
+ return;
+ }
+
+ cell->setMarked();
+ appendToMarkStack(cell);
+}
+
+void SlotVisitor::appendToMarkStack(JSCell* cell)
+{
ASSERT(Heap::isMarked(cell));
+ ASSERT(!cell->isZapped());
+
+ m_visitCount++;
+ m_bytesVisited += MarkedBlock::blockFor(cell)->cellSize();
+ m_stack.append(cell);
+}
+
+ALWAYS_INLINE static void visitChildren(SlotVisitor& visitor, const JSCell* cell)
+{
+ ASSERT(Heap::isMarked(cell));
if (isJSString(cell)) {
JSString::visitChildren(const_cast<JSCell*>(cell), visitor);
@@ -121,7 +177,6 @@
void SlotVisitor::donateKnownParallel()
{
- StackStats::probe();
// NOTE: Because we re-try often, we can afford to be conservative, and
// assume that donating is not profitable.
@@ -148,7 +203,6 @@
void SlotVisitor::drain()
{
- StackStats::probe();
ASSERT(m_isInParallelMode);
while (!m_stack.isEmpty()) {
@@ -163,7 +217,6 @@
void SlotVisitor::drainFromShared(SharedDrainMode sharedDrainMode)
{
- StackStats::probe();
ASSERT(m_isInParallelMode);
ASSERT(Options::numberOfGCMarkers());
@@ -228,133 +281,118 @@
}
}
-void SlotVisitor::mergeOpaqueRoots()
+void SlotVisitor::addOpaqueRoot(void* root)
{
- StackStats::probe();
- ASSERT(!m_opaqueRoots.isEmpty()); // Should only be called when opaque roots are non-empty.
- {
- std::lock_guard<Lock> lock(m_heap.m_opaqueRootsMutex);
- for (auto* root : m_opaqueRoots)
- m_heap.m_opaqueRoots.add(root);
+ if (Options::numberOfGCMarkers() == 1) {
+ // Put directly into the shared HashSet.
+ m_heap.m_opaqueRoots.add(root);
+ return;
}
- m_opaqueRoots.clear();
+ // Put into the local set, but merge with the shared one every once in
+ // a while to make sure that the local sets don't grow too large.
+ mergeOpaqueRootsIfProfitable();
+ m_opaqueRoots.add(root);
}
-ALWAYS_INLINE bool JSString::tryHashConsLock()
+bool SlotVisitor::containsOpaqueRoot(void* root) const
{
- unsigned currentFlags = m_flags;
-
- if (currentFlags & HashConsLock)
- return false;
-
- unsigned newFlags = currentFlags | HashConsLock;
-
- if (!WTF::weakCompareAndSwap(&m_flags, currentFlags, newFlags))
- return false;
-
- WTF::memoryBarrierAfterLock();
- return true;
+ ASSERT(!m_isInParallelMode);
+ ASSERT(m_opaqueRoots.isEmpty());
+ return m_heap.m_opaqueRoots.contains(root);
}
-ALWAYS_INLINE void JSString::releaseHashConsLock()
+TriState SlotVisitor::containsOpaqueRootTriState(void* root) const
{
- WTF::memoryBarrierBeforeUnlock();
- m_flags &= ~HashConsLock;
+ if (m_opaqueRoots.contains(root))
+ return TrueTriState;
+ std::lock_guard<Lock> lock(m_heap.m_opaqueRootsMutex);
+ if (m_heap.m_opaqueRoots.contains(root))
+ return TrueTriState;
+ return MixedTriState;
}
-ALWAYS_INLINE bool JSString::shouldTryHashCons()
+int SlotVisitor::opaqueRootCount()
{
- return ((length() > 1) && !isRope() && !isHashConsSingleton());
+ ASSERT(!m_isInParallelMode);
+ ASSERT(m_opaqueRoots.isEmpty());
+ return m_heap.m_opaqueRoots.size();
}
-ALWAYS_INLINE void SlotVisitor::internalAppend(void* from, JSValue* slot)
+void SlotVisitor::mergeOpaqueRootsIfNecessary()
{
- // This internalAppend is only intended for visits to object and array backing stores.
- // as it can change the JSValue pointed to be the argument when the original JSValue
- // is a string that contains the same contents as another string.
-
- StackStats::probe();
- ASSERT(slot);
- JSValue value = *slot;
- ASSERT(value);
- if (!value.isCell())
+ if (m_opaqueRoots.isEmpty())
return;
-
- JSCell* cell = value.asCell();
- if (!cell)
+ mergeOpaqueRoots();
+}
+
+void SlotVisitor::mergeOpaqueRootsIfProfitable()
+{
+ if (static_cast<unsigned>(m_opaqueRoots.size()) < Options::opaqueRootMergeThreshold())
return;
+ mergeOpaqueRoots();
+}
+
+void SlotVisitor::donate()
+{
+ ASSERT(m_isInParallelMode);
+ if (Options::numberOfGCMarkers() == 1)
+ return;
+
+ donateKnownParallel();
+}
- validate(cell);
+void SlotVisitor::donateAndDrain()
+{
+ donate();
+ drain();
+}
- if (m_shouldHashCons && cell->isString()) {
- JSString* string = jsCast<JSString*>(cell);
- if (string->shouldTryHashCons() && string->tryHashConsLock()) {
- UniqueStringMap::AddResult addResult = m_uniqueStrings.add(string->string().impl(), value);
- if (addResult.isNewEntry)
- string->setHashConsSingleton();
- else {
- JSValue existingJSValue = addResult.iterator->value;
- if (value != existingJSValue)
- jsCast<JSString*>(existingJSValue.asCell())->clearHashConsSingleton();
- *slot = existingJSValue;
- string->releaseHashConsLock();
- return;
- }
- string->releaseHashConsLock();
- }
+void SlotVisitor::copyLater(JSCell* owner, CopyToken token, void* ptr, size_t bytes)
+{
+ ASSERT(bytes);
+ CopiedBlock* block = CopiedSpace::blockFor(ptr);
+ if (block->isOversize()) {
+ ASSERT(bytes <= block->size());
+ // FIXME: We should be able to shrink the allocation if bytes went below the block size.
+ // For now, we just make sure that our accounting of how much memory we are actually using
+ // is correct.
+ // https://bugs.webkit.org/show_bug.cgi?id=144749
+ bytes = block->size();
+ m_heap.m_storageSpace.pin(block);
}
- internalAppend(from, cell);
+ ASSERT(heap()->m_storageSpace.contains(block));
+
+ LockHolder locker(&block->workListLock());
+ if (heap()->operationInProgress() == FullCollection || block->shouldReportLiveBytes(locker, owner)) {
+ m_bytesCopied += bytes;
+ block->reportLiveBytes(locker, owner, token, bytes);
+ }
}
+
+void SlotVisitor::mergeOpaqueRoots()
+{
+ ASSERT(!m_opaqueRoots.isEmpty()); // Should only be called when opaque roots are non-empty.
+ {
+ std::lock_guard<Lock> lock(m_heap.m_opaqueRootsMutex);
+ for (auto* root : m_opaqueRoots)
+ m_heap.m_opaqueRoots.add(root);
+ }
+ m_opaqueRoots.clear();
+}
void SlotVisitor::harvestWeakReferences()
{
- StackStats::probe();
for (WeakReferenceHarvester* current = m_heap.m_weakReferenceHarvesters.head(); current; current = current->next())
current->visitWeakReferences(*this);
}
void SlotVisitor::finalizeUnconditionalFinalizers()
{
- StackStats::probe();
while (m_heap.m_unconditionalFinalizers.hasNext())
m_heap.m_unconditionalFinalizers.removeNext()->finalizeUnconditionally();
}
-#if ENABLE(GC_VALIDATION)
-void SlotVisitor::validate(JSCell* cell)
-{
- RELEASE_ASSERT(cell);
-
- if (!cell->structure()) {
- dataLogF("cell at %p has a null structure\n" , cell);
- CRASH();
- }
-
- // Both the cell's structure, and the cell's structure's structure should be the Structure Structure.
- // I hate this sentence.
- if (cell->structure()->structure()->JSCell::classInfo() != cell->structure()->JSCell::classInfo()) {
- const char* parentClassName = 0;
- const char* ourClassName = 0;
- if (cell->structure()->structure() && cell->structure()->structure()->JSCell::classInfo())
- parentClassName = cell->structure()->structure()->JSCell::classInfo()->className;
- if (cell->structure()->JSCell::classInfo())
- ourClassName = cell->structure()->JSCell::classInfo()->className;
- dataLogF("parent structure (%p <%s>) of cell at %p doesn't match cell's structure (%p <%s>)\n",
- cell->structure()->structure(), parentClassName, cell, cell->structure(), ourClassName);
- CRASH();
- }
-
- // Make sure we can walk the ClassInfo chain
- const ClassInfo* info = cell->classInfo();
- do { } while ((info = info->parentClass));
-}
-#else
-void SlotVisitor::validate(JSCell*)
-{
-}
-#endif
-
void SlotVisitor::dump(PrintStream&) const
{
for (const JSCell* cell : markStack())
Modified: trunk/Source/_javascript_Core/heap/SlotVisitor.h (190562 => 190563)
--- trunk/Source/_javascript_Core/heap/SlotVisitor.h 2015-10-05 17:18:26 UTC (rev 190562)
+++ trunk/Source/_javascript_Core/heap/SlotVisitor.h 2015-10-05 17:22:20 UTC (rev 190563)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011, 2012, 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2011, 2012, 2013, 2015 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -31,9 +31,6 @@
#include "MarkStack.h"
#include "OpaqueRootSet.h"
-#include <wtf/HashSet.h>
-#include <wtf/text/StringHash.h>
-
namespace JSC {
class ConservativeRoots;
@@ -46,8 +43,11 @@
template<typename T> class WriteBarrierBase;
class SlotVisitor {
- WTF_MAKE_NONCOPYABLE(SlotVisitor); WTF_MAKE_FAST_ALLOCATED;
+ WTF_MAKE_NONCOPYABLE(SlotVisitor);
+ WTF_MAKE_FAST_ALLOCATED;
+
friend class HeapRootVisitor; // Allowed to mark a JSValue* or JSCell** directly.
+ friend class Heap;
public:
SlotVisitor(Heap&);
@@ -75,10 +75,9 @@
template<typename T>
void appendUnbarrieredReadOnlyPointer(T*);
void appendUnbarrieredReadOnlyValue(JSValue);
- void unconditionallyAppend(JSCell*);
- void addOpaqueRoot(void*);
- bool containsOpaqueRoot(void*) const;
+ JS_EXPORT_PRIVATE void addOpaqueRoot(void*);
+ JS_EXPORT_PRIVATE bool containsOpaqueRoot(void*) const;
TriState containsOpaqueRootTriState(void*) const;
int opaqueRootCount();
@@ -109,25 +108,16 @@
void addWeakReferenceHarvester(WeakReferenceHarvester*);
void addUnconditionalFinalizer(UnconditionalFinalizer*);
- inline void resetChildCount() { m_logChildCount = 0; }
- inline unsigned childCount() { return m_logChildCount; }
- inline void incrementChildCount() { m_logChildCount++; }
-
void dump(PrintStream&) const;
private:
friend class ParallelModeEnabler;
- JS_EXPORT_PRIVATE static void validate(JSCell*);
+ JS_EXPORT_PRIVATE void append(JSValue); // This is private to encourage clients to use WriteBarrier<T>.
- void append(JSValue*);
- void append(JSValue*, size_t count);
- void append(JSCell**);
+ JS_EXPORT_PRIVATE void setMarkedAndAppendToMarkStack(JSCell*);
+ void appendToMarkStack(JSCell*);
- void internalAppend(void* from, JSCell*);
- void internalAppend(void* from, JSValue);
- void internalAppend(void* from, JSValue*);
-
JS_EXPORT_PRIVATE void mergeOpaqueRoots();
void mergeOpaqueRootsIfNecessary();
void mergeOpaqueRootsIfProfitable();
@@ -144,12 +134,6 @@
Heap& m_heap;
- bool m_shouldHashCons; // Local per-thread copy of shared flag for performance reasons
- typedef HashMap<StringImpl*, JSValue> UniqueStringMap;
- UniqueStringMap m_uniqueStrings;
-
- unsigned m_logChildCount;
-
public:
#if !ASSERT_DISABLED
bool m_isCheckingForDefaultMarkViolation;
Modified: trunk/Source/_javascript_Core/heap/SlotVisitorInlines.h (190562 => 190563)
--- trunk/Source/_javascript_Core/heap/SlotVisitorInlines.h 2015-10-05 17:18:26 UTC (rev 190562)
+++ trunk/Source/_javascript_Core/heap/SlotVisitorInlines.h 2015-10-05 17:22:20 UTC (rev 190563)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012, 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2012, 2013, 2015 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,124 +26,60 @@
#ifndef SlotVisitorInlines_h
#define SlotVisitorInlines_h
-#include "CopiedBlockInlines.h"
-#include "CopiedSpaceInlines.h"
-#include "Options.h"
#include "SlotVisitor.h"
#include "Weak.h"
#include "WeakInlines.h"
namespace JSC {
-ALWAYS_INLINE void SlotVisitor::append(JSValue* slot, size_t count)
-{
- for (size_t i = 0; i < count; ++i) {
- JSValue& value = slot[i];
- internalAppend(&value, value);
- }
-}
-
template<typename T>
inline void SlotVisitor::appendUnbarrieredPointer(T** slot)
{
ASSERT(slot);
- JSCell* cell = *slot;
- internalAppend(slot, cell);
+ append(*slot);
}
template<typename T>
inline void SlotVisitor::appendUnbarrieredReadOnlyPointer(T* cell)
{
- internalAppend(0, cell);
+ append(cell);
}
-ALWAYS_INLINE void SlotVisitor::append(JSValue* slot)
+inline void SlotVisitor::appendUnbarrieredValue(JSValue* slot)
{
ASSERT(slot);
- internalAppend(slot, *slot);
+ append(*slot);
}
-ALWAYS_INLINE void SlotVisitor::appendUnbarrieredValue(JSValue* slot)
+inline void SlotVisitor::appendUnbarrieredReadOnlyValue(JSValue value)
{
- ASSERT(slot);
- internalAppend(slot, *slot);
+ append(value);
}
-ALWAYS_INLINE void SlotVisitor::appendUnbarrieredReadOnlyValue(JSValue value)
-{
- internalAppend(0, value);
-}
-
-ALWAYS_INLINE void SlotVisitor::append(JSCell** slot)
-{
- ASSERT(slot);
- internalAppend(slot, *slot);
-}
-
template<typename T>
-ALWAYS_INLINE void SlotVisitor::appendUnbarrieredWeak(Weak<T>* weak)
+inline void SlotVisitor::appendUnbarrieredWeak(Weak<T>* weak)
{
ASSERT(weak);
- if (weak->get())
- internalAppend(0, weak->get());
+ append(weak->get());
}
-ALWAYS_INLINE void SlotVisitor::internalAppend(void* from, JSValue value)
+template<typename T>
+inline void SlotVisitor::append(WriteBarrierBase<T>* slot)
{
- if (!value || !value.isCell())
- return;
- internalAppend(from, value.asCell());
+ append(slot->get());
}
-ALWAYS_INLINE void SlotVisitor::internalAppend(void* from, JSCell* cell)
+template<typename Iterator>
+inline void SlotVisitor::append(Iterator begin, Iterator end)
{
- ASSERT(!m_isCheckingForDefaultMarkViolation);
- if (!cell)
- return;
-#if ENABLE(ALLOCATION_LOGGING)
- dataLogF("JSC GC noticing reference from %p to %p.\n", from, cell);
-#else
- UNUSED_PARAM(from);
-#endif
-#if ENABLE(GC_VALIDATION)
- validate(cell);
-#endif
- if (Heap::testAndSetMarked(cell) || !cell->structure()) {
- ASSERT(cell->structure());
- return;
- }
-
- cell->setMarked();
- m_bytesVisited += MarkedBlock::blockFor(cell)->cellSize();
-
- unconditionallyAppend(cell);
-}
-
-ALWAYS_INLINE void SlotVisitor::unconditionallyAppend(JSCell* cell)
-{
- ASSERT(Heap::isMarked(cell));
- m_visitCount++;
-
- // Should never attempt to mark something that is zapped.
- ASSERT(!cell->isZapped());
-
- m_stack.append(cell);
-}
-
-template<typename T> inline void SlotVisitor::append(WriteBarrierBase<T>* slot)
-{
- internalAppend(slot, *slot->slot());
-}
-
-template<typename Iterator> inline void SlotVisitor::append(Iterator begin, Iterator end)
-{
for (auto it = begin; it != end; ++it)
append(&*it);
}
-ALWAYS_INLINE void SlotVisitor::appendValues(WriteBarrierBase<Unknown>* barriers, size_t count)
+inline void SlotVisitor::appendValues(WriteBarrierBase<Unknown>* barriers, size_t count)
{
- append(barriers->slot(), count);
+ for (size_t i = 0; i < count; ++i)
+ append(&barriers[i]);
}
inline void SlotVisitor::addWeakReferenceHarvester(WeakReferenceHarvester* weakReferenceHarvester)
@@ -156,95 +92,6 @@
m_heap.m_unconditionalFinalizers.addThreadSafe(unconditionalFinalizer);
}
-inline void SlotVisitor::addOpaqueRoot(void* root)
-{
- if (Options::numberOfGCMarkers() == 1) {
- // Put directly into the shared HashSet.
- m_heap.m_opaqueRoots.add(root);
- return;
- }
- // Put into the local set, but merge with the shared one every once in
- // a while to make sure that the local sets don't grow too large.
- mergeOpaqueRootsIfProfitable();
- m_opaqueRoots.add(root);
-}
-
-inline bool SlotVisitor::containsOpaqueRoot(void* root) const
-{
- ASSERT(!m_isInParallelMode);
- ASSERT(m_opaqueRoots.isEmpty());
- return m_heap.m_opaqueRoots.contains(root);
-}
-
-inline TriState SlotVisitor::containsOpaqueRootTriState(void* root) const
-{
- if (m_opaqueRoots.contains(root))
- return TrueTriState;
- std::lock_guard<Lock> lock(m_heap.m_opaqueRootsMutex);
- if (m_heap.m_opaqueRoots.contains(root))
- return TrueTriState;
- return MixedTriState;
-}
-
-inline int SlotVisitor::opaqueRootCount()
-{
- ASSERT(!m_isInParallelMode);
- ASSERT(m_opaqueRoots.isEmpty());
- return m_heap.m_opaqueRoots.size();
-}
-
-inline void SlotVisitor::mergeOpaqueRootsIfNecessary()
-{
- if (m_opaqueRoots.isEmpty())
- return;
- mergeOpaqueRoots();
-}
-
-inline void SlotVisitor::mergeOpaqueRootsIfProfitable()
-{
- if (static_cast<unsigned>(m_opaqueRoots.size()) < Options::opaqueRootMergeThreshold())
- return;
- mergeOpaqueRoots();
-}
-
-inline void SlotVisitor::donate()
-{
- ASSERT(m_isInParallelMode);
- if (Options::numberOfGCMarkers() == 1)
- return;
-
- donateKnownParallel();
-}
-
-inline void SlotVisitor::donateAndDrain()
-{
- donate();
- drain();
-}
-
-inline void SlotVisitor::copyLater(JSCell* owner, CopyToken token, void* ptr, size_t bytes)
-{
- ASSERT(bytes);
- CopiedBlock* block = CopiedSpace::blockFor(ptr);
- if (block->isOversize()) {
- ASSERT(bytes <= block->size());
- // FIXME: We should be able to shrink the allocation if bytes went below the block size.
- // For now, we just make sure that our accounting of how much memory we are actually using
- // is correct.
- // https://bugs.webkit.org/show_bug.cgi?id=144749
- bytes = block->size();
- m_heap.m_storageSpace.pin(block);
- }
-
- ASSERT(heap()->m_storageSpace.contains(block));
-
- LockHolder locker(&block->workListLock());
- if (heap()->operationInProgress() == FullCollection || block->shouldReportLiveBytes(locker, owner)) {
- m_bytesCopied += bytes;
- block->reportLiveBytes(locker, owner, token, bytes);
- }
-}
-
inline void SlotVisitor::reportExtraMemoryVisited(JSCell* owner, size_t size)
{
heap()->reportExtraMemoryVisited(owner, size);
Modified: trunk/Source/_javascript_Core/runtime/DirectArguments.cpp (190562 => 190563)
--- trunk/Source/_javascript_Core/runtime/DirectArguments.cpp 2015-10-05 17:18:26 UTC (rev 190562)
+++ trunk/Source/_javascript_Core/runtime/DirectArguments.cpp 2015-10-05 17:22:20 UTC (rev 190563)
@@ -27,6 +27,7 @@
#include "DirectArguments.h"
#include "CodeBlock.h"
+#include "CopiedBlockInlines.h"
#include "CopyVisitorInlines.h"
#include "GenericArgumentsInlines.h"
#include "JSCInlines.h"
Modified: trunk/Source/_javascript_Core/runtime/JSMap.cpp (190562 => 190563)
--- trunk/Source/_javascript_Core/runtime/JSMap.cpp 2015-10-05 17:18:26 UTC (rev 190562)
+++ trunk/Source/_javascript_Core/runtime/JSMap.cpp 2015-10-05 17:22:20 UTC (rev 190563)
@@ -26,6 +26,7 @@
#include "config.h"
#include "JSMap.h"
+#include "CopiedBlockInlines.h"
#include "JSCJSValueInlines.h"
#include "JSMapIterator.h"
#include "MapDataInlines.h"
Modified: trunk/Source/_javascript_Core/runtime/JSObject.cpp (190562 => 190563)
--- trunk/Source/_javascript_Core/runtime/JSObject.cpp 2015-10-05 17:18:26 UTC (rev 190562)
+++ trunk/Source/_javascript_Core/runtime/JSObject.cpp 2015-10-05 17:22:20 UTC (rev 190563)
@@ -25,6 +25,7 @@
#include "JSObject.h"
#include "ButterflyInlines.h"
+#include "CopiedBlockInlines.h"
#include "CopiedSpaceInlines.h"
#include "CopyVisitor.h"
#include "CopyVisitorInlines.h"
Modified: trunk/Source/_javascript_Core/runtime/JSSet.cpp (190562 => 190563)
--- trunk/Source/_javascript_Core/runtime/JSSet.cpp 2015-10-05 17:18:26 UTC (rev 190562)
+++ trunk/Source/_javascript_Core/runtime/JSSet.cpp 2015-10-05 17:22:20 UTC (rev 190563)
@@ -26,6 +26,7 @@
#include "config.h"
#include "JSSet.h"
+#include "CopiedBlockInlines.h"
#include "JSCJSValueInlines.h"
#include "JSSetIterator.h"
#include "MapDataInlines.h"
Modified: trunk/Source/_javascript_Core/runtime/JSString.h (190562 => 190563)
--- trunk/Source/_javascript_Core/runtime/JSString.h 2015-10-05 17:18:26 UTC (rev 190562)
+++ trunk/Source/_javascript_Core/runtime/JSString.h 2015-10-05 17:22:20 UTC (rev 190563)
@@ -108,7 +108,6 @@
Base::finishCreation(vm);
m_length = length;
setIs8Bit(m_value.impl()->is8Bit());
- vm.m_newStringsSinceLastHashCons++;
}
void finishCreation(VM& vm, size_t length, size_t cost)
@@ -118,7 +117,6 @@
m_length = length;
setIs8Bit(m_value.impl()->is8Bit());
Heap::heap(this)->reportExtraMemoryAllocated(cost);
- vm.m_newStringsSinceLastHashCons++;
}
protected:
@@ -127,7 +125,6 @@
Base::finishCreation(vm);
m_length = 0;
setIs8Bit(true);
- vm.m_newStringsSinceLastHashCons++;
}
public:
@@ -191,8 +188,6 @@
static void visitChildren(JSCell*, SlotVisitor&);
enum {
- HashConsLock = 1u << 2,
- IsHashConsSingleton = 1u << 1,
Is8Bit = 1u
};
@@ -209,12 +204,6 @@
else
m_flags &= ~Is8Bit;
}
- bool shouldTryHashCons();
- bool isHashConsSingleton() const { return m_flags & IsHashConsSingleton; }
- void clearHashConsSingleton() { m_flags &= ~IsHashConsSingleton; }
- void setHashConsSingleton() { m_flags |= IsHashConsSingleton; }
- bool tryHashConsLock();
- void releaseHashConsLock();
mutable unsigned m_flags;
Modified: trunk/Source/_javascript_Core/runtime/JSTypedArrays.cpp (190562 => 190563)
--- trunk/Source/_javascript_Core/runtime/JSTypedArrays.cpp 2015-10-05 17:18:26 UTC (rev 190562)
+++ trunk/Source/_javascript_Core/runtime/JSTypedArrays.cpp 2015-10-05 17:22:20 UTC (rev 190563)
@@ -26,6 +26,7 @@
#include "config.h"
#include "JSTypedArrays.h"
+#include "CopiedBlockInlines.h"
#include "CopyVisitorInlines.h"
#include "GenericTypedArrayViewInlines.h"
#include "JSGenericTypedArrayViewInlines.h"
Modified: trunk/Source/_javascript_Core/runtime/VM.cpp (190562 => 190563)
--- trunk/Source/_javascript_Core/runtime/VM.cpp 2015-10-05 17:18:26 UTC (rev 190562)
+++ trunk/Source/_javascript_Core/runtime/VM.cpp 2015-10-05 17:22:20 UTC (rev 190563)
@@ -166,7 +166,6 @@
#if ENABLE(REGEXP_TRACING)
, m_rtTraceList(new RTTraceList())
#endif
- , m_newStringsSinceLastHashCons(0)
#if ENABLE(ASSEMBLER)
, m_canUseAssembler(enableAssembler(executableAllocator))
#endif
Modified: trunk/Source/_javascript_Core/runtime/VM.h (190562 => 190563)
--- trunk/Source/_javascript_Core/runtime/VM.h 2015-10-05 17:18:26 UTC (rev 190562)
+++ trunk/Source/_javascript_Core/runtime/VM.h 2015-10-05 17:22:20 UTC (rev 190563)
@@ -538,13 +538,6 @@
void setInitializingObjectClass(const ClassInfo*);
#endif
- unsigned m_newStringsSinceLastHashCons;
-
- static const unsigned s_minNumberOfNewStringsToHashCons = 100;
-
- bool haveEnoughNewStringsToHashCons() { return m_newStringsSinceLastHashCons > s_minNumberOfNewStringsToHashCons; }
- void resetNewStringsSinceLastHashCons() { m_newStringsSinceLastHashCons = 0; }
-
bool currentThreadIsHoldingAPILock() const { return m_apiLock->currentThreadIsHoldingLock(); }
JSLock& apiLock() { return *m_apiLock; }