Diff
Modified: trunk/Source/_javascript_Core/ChangeLog (123689 => 123690)
--- trunk/Source/_javascript_Core/ChangeLog 2012-07-26 01:05:23 UTC (rev 123689)
+++ trunk/Source/_javascript_Core/ChangeLog 2012-07-26 01:22:59 UTC (rev 123690)
@@ -1,3 +1,36 @@
+2012-07-25 Filip Pizlo <[email protected]>
+
+ JSC GC object copying APIs should allow for greater flexibility
+ https://bugs.webkit.org/show_bug.cgi?id=92316
+
+ Reviewed by Mark Hahnenberg.
+
+ It's now the case that visitChildren() methods can directly pin and allocate in new space during copying.
+ They can also do the copying and marking themselves. This new API is only used for JSObjects for now.
+
+ * _javascript_Core.xcodeproj/project.pbxproj:
+ * heap/MarkStack.cpp:
+ (JSC::SlotVisitor::allocateNewSpaceSlow):
+ (JSC::SlotVisitor::allocateNewSpaceOrPin):
+ (JSC):
+ (JSC::SlotVisitor::copyAndAppend):
+ * heap/MarkStack.h:
+ (MarkStack):
+ (JSC::MarkStack::appendUnbarrieredValue):
+ (JSC):
+ * heap/SlotVisitor.h:
+ * heap/SlotVisitorInlineMethods.h: Added.
+ (JSC):
+ (JSC::SlotVisitor::checkIfShouldCopyAndPinOtherwise):
+ (JSC::SlotVisitor::allocateNewSpace):
+ * runtime/JSObject.cpp:
+ (JSC::JSObject::visitOutOfLineStorage):
+ (JSC):
+ (JSC::JSObject::visitChildren):
+ (JSC::JSFinalObject::visitChildren):
+ * runtime/JSObject.h:
+ (JSObject):
+
2012-07-25 Mark Hahnenberg <[email protected]>
Remove JSObject::m_inheritorID
Modified: trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj (123689 => 123690)
--- trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj 2012-07-26 01:05:23 UTC (rev 123689)
+++ trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj 2012-07-26 01:22:59 UTC (rev 123690)
@@ -949,6 +949,7 @@
0FC8150914043BD200CFA603 /* WriteBarrierSupport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WriteBarrierSupport.h; sourceTree = "<group>"; };
0FC815121405118600CFA603 /* VTableSpectrum.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = VTableSpectrum.cpp; sourceTree = "<group>"; };
0FC815141405118D00CFA603 /* VTableSpectrum.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VTableSpectrum.h; sourceTree = "<group>"; };
+ 0FCB408515C0A3C30048932B /* SlotVisitorInlineMethods.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SlotVisitorInlineMethods.h; sourceTree = "<group>"; };
0FD3C82014115CF800FD81CB /* DFGDriver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGDriver.cpp; path = dfg/DFGDriver.cpp; sourceTree = "<group>"; };
0FD3C82214115D0E00FD81CB /* DFGDriver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGDriver.h; path = dfg/DFGDriver.h; sourceTree = "<group>"; };
0FD81ACF154FB4EB00983E72 /* DFGDominators.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGDominators.cpp; path = dfg/DFGDominators.cpp; sourceTree = "<group>"; };
@@ -1800,6 +1801,7 @@
142D6F0F13539A4100B02E86 /* MarkStack.h */,
1497209014EB831500FEB1B7 /* PassWeak.h */,
14BA78F013AAB88F005B7C2C /* SlotVisitor.h */,
+ 0FCB408515C0A3C30048932B /* SlotVisitorInlineMethods.h */,
142E3132134FF0A600AFADB5 /* Strong.h */,
145722851437E140005FDE26 /* StrongInlines.h */,
141448CC13A1783700F5BA1A /* TinyBloomFilter.h */,
Modified: trunk/Source/_javascript_Core/heap/MarkStack.cpp (123689 => 123690)
--- trunk/Source/_javascript_Core/heap/MarkStack.cpp 2012-07-26 01:05:23 UTC (rev 123689)
+++ trunk/Source/_javascript_Core/heap/MarkStack.cpp 2012-07-26 01:22:59 UTC (rev 123690)
@@ -35,6 +35,7 @@
#include "JSCell.h"
#include "JSObject.h"
#include "ScopeChain.h"
+#include "SlotVisitorInlineMethods.h"
#include "Structure.h"
#include "UString.h"
#include "WriteBarrier.h"
@@ -518,28 +519,25 @@
ASSERT(!m_copiedAllocator.isValid());
}
-void* SlotVisitor::allocateNewSpace(void* ptr, size_t bytes)
+void* SlotVisitor::allocateNewSpaceSlow(size_t bytes)
{
- if (CopiedSpace::isOversize(bytes)) {
- m_shared.m_copiedSpace->pin(CopiedSpace::oversizeBlockFor(ptr));
- return 0;
- }
-
- if (m_shared.m_copiedSpace->isPinned(ptr))
- return 0;
-
- void* result = 0; // Compilers don't realize that this will be assigned.
- if (m_copiedAllocator.tryAllocate(bytes, &result))
- return result;
-
m_shared.m_copiedSpace->doneFillingBlock(m_copiedAllocator.resetCurrentBlock());
m_copiedAllocator.setCurrentBlock(m_shared.m_copiedSpace->allocateBlockForCopyingPhase());
+ void* result = 0;
CheckedBoolean didSucceed = m_copiedAllocator.tryAllocate(bytes, &result);
ASSERT(didSucceed);
return result;
}
+void* SlotVisitor::allocateNewSpaceOrPin(void* ptr, size_t bytes)
+{
+ if (!checkIfShouldCopyAndPinOtherwise(ptr, bytes))
+ return 0;
+
+ return allocateNewSpace(bytes);
+}
+
ALWAYS_INLINE bool JSString::tryHashConstLock()
{
#if ENABLE(PARALLEL_GC)
@@ -616,7 +614,7 @@
void SlotVisitor::copyAndAppend(void** ptr, size_t bytes, JSValue* values, unsigned length)
{
void* oldPtr = *ptr;
- void* newPtr = allocateNewSpace(oldPtr, bytes);
+ void* newPtr = allocateNewSpaceOrPin(oldPtr, bytes);
if (newPtr) {
size_t jsValuesOffset = static_cast<size_t>(reinterpret_cast<char*>(values) - static_cast<char*>(oldPtr));
Modified: trunk/Source/_javascript_Core/heap/MarkStack.h (123689 => 123690)
--- trunk/Source/_javascript_Core/heap/MarkStack.h 2012-07-26 01:05:23 UTC (rev 123689)
+++ trunk/Source/_javascript_Core/heap/MarkStack.h 2012-07-26 01:22:59 UTC (rev 123690)
@@ -253,6 +253,7 @@
template<typename T>
void appendUnbarrieredPointer(T**);
+ void appendUnbarrieredValue(JSValue*);
void addOpaqueRoot(void*);
bool containsOpaqueRoot(void*);
@@ -453,6 +454,12 @@
internalAppend(*slot);
}
+ ALWAYS_INLINE void MarkStack::appendUnbarrieredValue(JSValue* slot)
+ {
+ ASSERT(slot);
+ internalAppend(*slot);
+ }
+
ALWAYS_INLINE void MarkStack::append(JSCell** slot)
{
ASSERT(slot);
Modified: trunk/Source/_javascript_Core/heap/SlotVisitor.h (123689 => 123690)
--- trunk/Source/_javascript_Core/heap/SlotVisitor.h 2012-07-26 01:05:23 UTC (rev 123689)
+++ trunk/Source/_javascript_Core/heap/SlotVisitor.h 2012-07-26 01:22:59 UTC (rev 123690)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 2011, 2012 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -62,11 +62,23 @@
void finalizeUnconditionalFinalizers();
void startCopying();
+
+ // High-level API for copying, appropriate for cases where the object's heap references
+ // fall into a contiguous region of the storage chunk and if the object for which you're
+ // doing copying does not occur frequently.
void copyAndAppend(void**, size_t, JSValue*, unsigned);
+
+ // Low-level API for copying, appropriate for cases where the object's heap references
+ // are discontiguous or if the object occurs frequently enough that you need to focus on
+ // performance. Use this with care as it is easy to shoot yourself in the foot.
+ bool checkIfShouldCopyAndPinOtherwise(void* oldPtr, size_t);
+ void* allocateNewSpace(size_t);
+
void doneCopying();
private:
- void* allocateNewSpace(void*, size_t);
+ void* allocateNewSpaceOrPin(void*, size_t);
+ void* allocateNewSpaceSlow(size_t);
void donateKnownParallel();
Added: trunk/Source/_javascript_Core/heap/SlotVisitorInlineMethods.h (0 => 123690)
--- trunk/Source/_javascript_Core/heap/SlotVisitorInlineMethods.h (rev 0)
+++ trunk/Source/_javascript_Core/heap/SlotVisitorInlineMethods.h 2012-07-26 01:22:59 UTC (rev 123690)
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2012 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef SlotVisitorInlineMethods_h
+#define SlotVisitorInlineMethods_h
+
+#include "CopiedSpaceInlineMethods.h"
+#include "SlotVisitor.h"
+
+namespace JSC {
+
+ALWAYS_INLINE bool SlotVisitor::checkIfShouldCopyAndPinOtherwise(void* oldPtr, size_t bytes)
+{
+ if (CopiedSpace::isOversize(bytes)) {
+ m_shared.m_copiedSpace->pin(CopiedSpace::oversizeBlockFor(oldPtr));
+ return false;
+ }
+
+ if (m_shared.m_copiedSpace->isPinned(oldPtr))
+ return false;
+
+ return true;
+}
+
+ALWAYS_INLINE void* SlotVisitor::allocateNewSpace(size_t bytes)
+{
+ void* result = 0; // Compilers don't realize that this will be assigned.
+ if (LIKELY(m_copiedAllocator.tryAllocate(bytes, &result)))
+ return result;
+
+ result = allocateNewSpaceSlow(bytes);
+ ASSERT(result);
+ return result;
+}
+
+} // namespace JSC
+
+#endif // SlotVisitorInlineMethods_h
+
Modified: trunk/Source/_javascript_Core/runtime/JSObject.cpp (123689 => 123690)
--- trunk/Source/_javascript_Core/runtime/JSObject.cpp 2012-07-26 01:05:23 UTC (rev 123689)
+++ trunk/Source/_javascript_Core/runtime/JSObject.cpp 2012-07-26 01:22:59 UTC (rev 123690)
@@ -38,6 +38,7 @@
#include "Operations.h"
#include "PropertyDescriptor.h"
#include "PropertyNameArray.h"
+#include "SlotVisitorInlineMethods.h"
#include <math.h>
#include <wtf/Assertions.h>
@@ -85,6 +86,31 @@
}
}
+ALWAYS_INLINE void JSObject::visitOutOfLineStorage(SlotVisitor& visitor, PropertyStorage storage, size_t storageSize)
+{
+ ASSERT(storage);
+ ASSERT(storageSize);
+
+ size_t capacity = structure()->outOfLineCapacity();
+ ASSERT(capacity);
+ size_t capacityInBytes = capacity * sizeof(WriteBarrierBase<Unknown>);
+ PropertyStorage baseOfStorage = storage - capacity - 1;
+ if (visitor.checkIfShouldCopyAndPinOtherwise(baseOfStorage, capacityInBytes)) {
+ PropertyStorage newBaseOfStorage = static_cast<PropertyStorage>(visitor.allocateNewSpace(capacityInBytes));
+ PropertyStorage currentTarget = newBaseOfStorage + capacity;
+ PropertyStorage newStorage = currentTarget + 1;
+ PropertyStorage currentSource = storage - 1;
+ for (size_t count = storageSize; count--;) {
+ JSValue value = (--currentSource)->get();
+ ASSERT(value);
+ visitor.appendUnbarrieredValue(&value);
+ (--currentTarget)->setWithoutWriteBarrier(value);
+ }
+ m_outOfLineStorage.set(newStorage, StorageBarrier::Unchecked);
+ } else
+ visitor.appendValues(storage - storageSize - 1, storageSize);
+}
+
void JSObject::visitChildren(JSCell* cell, SlotVisitor& visitor)
{
JSObject* thisObject = jsCast<JSObject*>(cell);
@@ -97,15 +123,8 @@
JSCell::visitChildren(thisObject, visitor);
PropertyStorage storage = thisObject->outOfLineStorage();
- if (storage) {
- size_t storageSize = thisObject->structure()->outOfLineSizeForKnownNonFinalObject();
- size_t capacity = thisObject->structure()->outOfLineCapacity();
- // We have this extra temp here to slake GCC's thirst for the blood of those who dereference type-punned pointers.
- void* temp = storage - capacity - 1;
- visitor.copyAndAppend(&temp, capacity * sizeof(WriteBarrierBase<Unknown>), (storage - storageSize - 1)->slot(), storageSize);
- storage = static_cast<PropertyStorage>(temp) + capacity + 1;
- thisObject->m_outOfLineStorage.set(storage, StorageBarrier::Unchecked);
- }
+ if (storage)
+ thisObject->visitOutOfLineStorage(visitor, storage, thisObject->structure()->outOfLineSizeForKnownNonFinalObject());
#if !ASSERT_DISABLED
visitor.m_isCheckingForDefaultMarkViolation = wasCheckingForDefaultMarkViolation;
@@ -124,15 +143,8 @@
JSCell::visitChildren(thisObject, visitor);
PropertyStorage storage = thisObject->outOfLineStorage();
- if (storage) {
- size_t storageSize = thisObject->structure()->outOfLineSizeForKnownFinalObject();
- size_t capacity = thisObject->structure()->outOfLineCapacity();
- // We have this extra temp here to slake GCC's thirst for the blood of those who dereference type-punned pointers.
- void* temp = storage - capacity - 1;
- visitor.copyAndAppend(&temp, thisObject->structure()->outOfLineCapacity() * sizeof(WriteBarrierBase<Unknown>), (storage - storageSize - 1)->slot(), storageSize);
- storage = static_cast<PropertyStorage>(temp) + capacity + 1;
- thisObject->m_outOfLineStorage.set(storage, StorageBarrier::Unchecked);
- }
+ if (storage)
+ thisObject->visitOutOfLineStorage(visitor, storage, thisObject->structure()->outOfLineSizeForKnownFinalObject());
size_t storageSize = thisObject->structure()->inlineSizeForKnownFinalObject();
visitor.appendValues(thisObject->inlineStorage(), storageSize);
Modified: trunk/Source/_javascript_Core/runtime/JSObject.h (123689 => 123690)
--- trunk/Source/_javascript_Core/runtime/JSObject.h 2012-07-26 01:05:23 UTC (rev 123689)
+++ trunk/Source/_javascript_Core/runtime/JSObject.h 2012-07-26 01:22:59 UTC (rev 123690)
@@ -325,6 +325,8 @@
{
removeDirect(globalData, globalData.m_inheritorIDKey);
}
+
+ void visitOutOfLineStorage(SlotVisitor&, PropertyStorage, size_t storageSize);
private:
friend class LLIntOffsetsExtractor;