Diff
Modified: trunk/Source/_javascript_Core/API/APIShims.h (159350 => 159351)
--- trunk/Source/_javascript_Core/API/APIShims.h 2013-11-15 19:51:26 UTC (rev 159350)
+++ trunk/Source/_javascript_Core/API/APIShims.h 2013-11-15 19:53:30 UTC (rev 159351)
@@ -83,18 +83,39 @@
class APICallbackShim {
public:
APICallbackShim(ExecState* exec)
- : m_dropAllLocks(exec->vm().exclusiveThread ? 0 : exec)
+ : m_dropAllLocks(shouldDropAllLocks(exec->vm()) ? exec : nullptr)
, m_vm(&exec->vm())
{
wtfThreadData().resetCurrentIdentifierTable();
}
+ APICallbackShim(VM& vm)
+ : m_dropAllLocks(shouldDropAllLocks(vm) ? &vm : nullptr)
+ , m_vm(&vm)
+ {
+ wtfThreadData().resetCurrentIdentifierTable();
+ }
+
~APICallbackShim()
{
wtfThreadData().setCurrentIdentifierTable(m_vm->identifierTable);
}
private:
+ static bool shouldDropAllLocks(VM& vm)
+ {
+ if (vm.exclusiveThread)
+ return false;
+
+ // If the VM is in the middle of being destroyed then we don't want to resurrect it
+ // by allowing DropAllLocks to ref it. By this point the APILock has already been
+ // released anyways, so it doesn't matter that DropAllLocks is a no-op.
+ if (!vm.refCount())
+ return false;
+
+ return true;
+ }
+
JSLock::DropAllLocks m_dropAllLocks;
VM* m_vm;
};
Modified: trunk/Source/_javascript_Core/API/JSAPIWrapperObject.mm (159350 => 159351)
--- trunk/Source/_javascript_Core/API/JSAPIWrapperObject.mm 2013-11-15 19:51:26 UTC (rev 159350)
+++ trunk/Source/_javascript_Core/API/JSAPIWrapperObject.mm 2013-11-15 19:53:30 UTC (rev 159351)
@@ -26,6 +26,7 @@
#include "config.h"
#include "JSAPIWrapperObject.h"
+#include "DelayedReleaseScope.h"
#include "JSCJSValueInlines.h"
#include "JSCallbackObject.h"
#include "JSCellInlines.h"
@@ -53,7 +54,8 @@
JSC::JSAPIWrapperObject* wrapperObject = JSC::jsCast<JSC::JSAPIWrapperObject*>(handle.get().asCell());
if (!wrapperObject->wrappedObject())
return;
- [static_cast<id>(wrapperObject->wrappedObject()) release];
+
+ JSC::Heap::heap(wrapperObject)->releaseSoon(adoptNS(static_cast<id>(wrapperObject->wrappedObject())));
JSC::WeakSet::deallocate(JSC::WeakImpl::asWeakImpl(handle.slot()));
}
Modified: trunk/Source/_javascript_Core/API/ObjCCallbackFunction.mm (159350 => 159351)
--- trunk/Source/_javascript_Core/API/ObjCCallbackFunction.mm 2013-11-15 19:51:26 UTC (rev 159350)
+++ trunk/Source/_javascript_Core/API/ObjCCallbackFunction.mm 2013-11-15 19:53:30 UTC (rev 159351)
@@ -31,6 +31,7 @@
#import "APICallbackFunction.h"
#import "APICast.h"
#import "APIShims.h"
+#import "DelayedReleaseScope.h"
#import "Error.h"
#import "JSCJSValueInlines.h"
#import "JSCell.h"
@@ -405,12 +406,12 @@
ASSERT((type != CallbackInstanceMethod && type != CallbackInitMethod) || instanceClass);
}
- ~ObjCCallbackFunctionImpl()
+ void destroy(Heap& heap)
{
- // We need to explicity release the target since we didn't call
+ // We need to explicitly release the target since we didn't call
// -retainArguments on m_invocation (and we don't want to do so).
if (m_type == CallbackBlock || m_type == CallbackClassMethod)
- [[m_invocation.get() target] release];
+ heap.releaseSoon(adoptNS([m_invocation.get() target]));
[m_instanceClass release];
}
@@ -520,7 +521,9 @@
void ObjCCallbackFunction::destroy(JSCell* cell)
{
- static_cast<ObjCCallbackFunction*>(cell)->ObjCCallbackFunction::~ObjCCallbackFunction();
+ ObjCCallbackFunction& function = *jsCast<ObjCCallbackFunction*>(cell);
+ function.impl()->destroy(*Heap::heap(cell));
+ function.~ObjCCallbackFunction();
}
Modified: trunk/Source/_javascript_Core/API/tests/testapi.mm (159350 => 159351)
--- trunk/Source/_javascript_Core/API/tests/testapi.mm 2013-11-15 19:51:26 UTC (rev 159350)
+++ trunk/Source/_javascript_Core/API/tests/testapi.mm 2013-11-15 19:53:30 UTC (rev 159351)
@@ -182,54 +182,43 @@
@end
@interface TinyDOMNode : NSObject<TinyDOMNode>
-+ (JSVirtualMachine *)sharedVirtualMachine;
-+ (void)clearSharedVirtualMachine;
@end
@implementation TinyDOMNode {
NSMutableArray *m_children;
+ JSVirtualMachine *m_sharedVirtualMachine;
}
-static JSVirtualMachine *sharedInstance = nil;
-
-+ (JSVirtualMachine *)sharedVirtualMachine
+- (id)initWithVirtualMachine:(JSVirtualMachine *)virtualMachine
{
- if (!sharedInstance)
- sharedInstance = [[JSVirtualMachine alloc] init];
- return sharedInstance;
-}
-
-+ (void)clearSharedVirtualMachine
-{
- sharedInstance = nil;
-}
-
-- (id)init
-{
self = [super init];
if (!self)
return nil;
m_children = [[NSMutableArray alloc] initWithCapacity:0];
+ m_sharedVirtualMachine = virtualMachine;
+#if !__has_feature(objc_arc)
+ [m_sharedVirtualMachine retain];
+#endif
return self;
}
- (void)dealloc
{
- NSEnumerator *enumerator = [m_children objectEnumerator];
- id nextChild;
- while ((nextChild = [enumerator nextObject]))
- [[TinyDOMNode sharedVirtualMachine] removeManagedReference:nextChild withOwner:self];
+ for (TinyDOMNode *child in m_children)
+ [m_sharedVirtualMachine removeManagedReference:child withOwner:self];
#if !__has_feature(objc_arc)
+ [m_children release];
+ [m_sharedVirtualMachine release];
[super dealloc];
#endif
}
- (void)appendChild:(TinyDOMNode *)child
{
- [[TinyDOMNode sharedVirtualMachine] addManagedReference:child withOwner:self];
+ [m_sharedVirtualMachine addManagedReference:child withOwner:self];
[m_children addObject:child];
}
@@ -249,7 +238,7 @@
{
if (index >= [m_children count])
return;
- [[TinyDOMNode sharedVirtualMachine] removeManagedReference:[m_children objectAtIndex:index] withOwner:self];
+ [m_sharedVirtualMachine removeManagedReference:[m_children objectAtIndex:index] withOwner:self];
[m_children removeObjectAtIndex:index];
}
@@ -424,6 +413,47 @@
return self;
}
@end
+
+static bool evilAllocationObjectWasDealloced = false;
+
+@interface EvilAllocationObject : NSObject
+- (JSValue *)doEvilThingsWithContext:(JSContext *)context;
+@end
+
+@implementation EvilAllocationObject {
+ JSContext *m_context;
+}
+- (id)initWithContext:(JSContext *)context
+{
+ self = [super init];
+ if (!self)
+ return nil;
+
+ m_context = context;
+
+ return self;
+}
+- (void)dealloc
+{
+ [self doEvilThingsWithContext:m_context];
+ evilAllocationObjectWasDealloced = true;
+}
+
+- (JSValue *)doEvilThingsWithContext:(JSContext *)context
+{
+ return [context evaluateScript:@" \
+ (function() { \
+ var a = []; \
+ var sum = 0; \
+ for (var i = 0; i < 10000; ++i) { \
+ sum += i; \
+ a[i] = sum; \
+ } \
+ return sum; \
+ })()"];
+}
+@end
+
static void checkResult(NSString *description, bool passed)
{
NSLog(@"TEST: \"%@\": %@", description, passed ? @"PASSED" : @"FAILED");
@@ -958,12 +988,11 @@
}
@autoreleasepool {
- JSVirtualMachine *vm = [TinyDOMNode sharedVirtualMachine];
- JSContext *context = [[JSContext alloc] initWithVirtualMachine:vm];
- TinyDOMNode *root = [[TinyDOMNode alloc] init];
+ JSContext *context = [[JSContext alloc] init];
+ TinyDOMNode *root = [[TinyDOMNode alloc] initWithVirtualMachine:context.virtualMachine];
TinyDOMNode *lastNode = root;
for (NSUInteger i = 0; i < 3; i++) {
- TinyDOMNode *newNode = [[TinyDOMNode alloc] init];
+ TinyDOMNode *newNode = [[TinyDOMNode alloc] initWithVirtualMachine:context.virtualMachine];
[lastNode appendChild:newNode];
lastNode = newNode;
}
@@ -985,17 +1014,14 @@
JSValue *myCustomProperty = [context evaluateScript:@"getLastNodeInChain(root).myCustomProperty"];
checkResult(@"My custom property == 42", [myCustomProperty isNumber] && [myCustomProperty toInt32] == 42);
-
- [TinyDOMNode clearSharedVirtualMachine];
}
@autoreleasepool {
- JSVirtualMachine *vm = [TinyDOMNode sharedVirtualMachine];
- JSContext *context = [[JSContext alloc] initWithVirtualMachine:vm];
- TinyDOMNode *root = [[TinyDOMNode alloc] init];
+ JSContext *context = [[JSContext alloc] init];
+ TinyDOMNode *root = [[TinyDOMNode alloc] initWithVirtualMachine:context.virtualMachine];
TinyDOMNode *lastNode = root;
for (NSUInteger i = 0; i < 3; i++) {
- TinyDOMNode *newNode = [[TinyDOMNode alloc] init];
+ TinyDOMNode *newNode = [[TinyDOMNode alloc] initWithVirtualMachine:context.virtualMachine];
[lastNode appendChild:newNode];
lastNode = newNode;
}
@@ -1020,8 +1046,6 @@
JSValue *myCustomProperty = [context evaluateScript:@"getLastNodeInChain(root).myCustomProperty"];
checkResult(@"duplicate calls to addManagedReference don't cause things to die", [myCustomProperty isNumber] && [myCustomProperty toInt32] == 42);
-
- [TinyDOMNode clearSharedVirtualMachine];
}
@autoreleasepool {
@@ -1161,6 +1185,17 @@
checkResult(@"Returning instance of ClassE from ClassD's init has correct class", [d isInstanceOf:context[@"ClassE"]]);
}
+ @autoreleasepool {
+ JSContext *context = [[JSContext alloc] init];
+ @autoreleasepool {
+ EvilAllocationObject *evilObject = [[EvilAllocationObject alloc] initWithContext:context];
+ context[@"evilObject"] = evilObject;
+ context[@"evilObject"] = nil;
+ }
+ JSSynchronousGarbageCollectForDebugging([context JSGlobalContextRef]);
+ checkResult(@"EvilAllocationObject was successfully dealloced without crashing", evilAllocationObjectWasDealloced);
+ }
+
currentThisInsideBlockGetterTest();
}
Modified: trunk/Source/_javascript_Core/ChangeLog (159350 => 159351)
--- trunk/Source/_javascript_Core/ChangeLog 2013-11-15 19:51:26 UTC (rev 159350)
+++ trunk/Source/_javascript_Core/ChangeLog 2013-11-15 19:53:30 UTC (rev 159351)
@@ -1,3 +1,54 @@
+2013-11-14 Mark Hahnenberg <mhahnenb...@apple.com>
+
+ -dealloc callbacks from wrapped Objective-C objects can happen at bad times
+ https://bugs.webkit.org/show_bug.cgi?id=123821
+
+ Reviewed by Darin Adler.
+
+ Currently with the JSC Obj-C API, JS wrappers for client Obj-C objects retain their associated Obj-C
+ object. When they are swept, they release their Obj-C objects which can trigger a call to that
+ object's -dealloc method. These -dealloc methods can then call back into the same VM, which is not
+ allowed during sweeping or VM shutdown.
+
+ We can handle this case by creating our own pool of Obj-C objects to be released when it is safe to do so.
+ This is accomplished by using DelayedReleaseScope, an RAII-style object that will retain all objects
+ that are unsafe to release until the end of the DelayedReleaseScope.
+
+ * API/APIShims.h:
+ (JSC::APICallbackShim::APICallbackShim):
+ (JSC::APICallbackShim::vmForDropAllLocks):
+ (JSC::APICallbackShim::execForDropAllLocks):
+ * API/JSAPIWrapperObject.mm:
+ (JSAPIWrapperObjectHandleOwner::finalize):
+ * API/ObjCCallbackFunction.mm:
+ (JSC::ObjCCallbackFunctionImpl::destroy):
+ (JSC::ObjCCallbackFunction::destroy):
+ * API/tests/testapi.mm:
+ (-[TinyDOMNode initWithVirtualMachine:]):
+ (-[TinyDOMNode dealloc]):
+ (-[TinyDOMNode appendChild:]):
+ (-[TinyDOMNode removeChildAtIndex:]):
+ (-[EvilAllocationObject initWithContext:]):
+ (-[EvilAllocationObject dealloc]):
+ (-[EvilAllocationObject doEvilThingsWithContext:]):
+ * _javascript_Core.xcodeproj/project.pbxproj:
+ * heap/DelayedReleaseScope.h: Added.
+ (JSC::DelayedReleaseScope::DelayedReleaseScope):
+ (JSC::DelayedReleaseScope::~DelayedReleaseScope):
+ (JSC::DelayedReleaseScope::releaseSoon):
+ (JSC::MarkedSpace::releaseSoon):
+ * heap/Heap.cpp:
+ (JSC::Heap::collectAllGarbage):
+ * heap/Heap.h:
+ (JSC::Heap::releaseSoon):
+ * heap/MarkedAllocator.cpp:
+ (JSC::MarkedAllocator::allocateSlowCase):
+ * heap/MarkedSpace.cpp:
+ (JSC::MarkedSpace::MarkedSpace):
+ (JSC::MarkedSpace::lastChanceToFinalize):
+ (JSC::MarkedSpace::sweep):
+ * heap/MarkedSpace.h:
+
2013-11-15 Michael Saboff <msab...@apple.com>
REGRESSION (r158586): callToJavaScript needs to save return PC to Sentinel frame
Modified: trunk/Source/_javascript_Core/GNUmakefile.list.am (159350 => 159351)
--- trunk/Source/_javascript_Core/GNUmakefile.list.am 2013-11-15 19:51:26 UTC (rev 159350)
+++ trunk/Source/_javascript_Core/GNUmakefile.list.am 2013-11-15 19:53:30 UTC (rev 159351)
@@ -486,8 +486,9 @@
Source/_javascript_Core/heap/CopyWorkList.h \
Source/_javascript_Core/heap/ConservativeRoots.cpp \
Source/_javascript_Core/heap/ConservativeRoots.h \
- Source/_javascript_Core/heap/DeferGC.cpp \
+ Source/_javascript_Core/heap/DeferGC.cpp \
Source/_javascript_Core/heap/DeferGC.h \
+ Source/_javascript_Core/heap/DelayedReleaseScope.h \
Source/_javascript_Core/heap/GCAssertions.h \
Source/_javascript_Core/heap/GCIncomingRefCounted.h \
Source/_javascript_Core/heap/GCIncomingRefCountedInlines.h \
Modified: trunk/Source/_javascript_Core/_javascript_Core.vcxproj/_javascript_Core.vcxproj (159350 => 159351)
--- trunk/Source/_javascript_Core/_javascript_Core.vcxproj/_javascript_Core.vcxproj 2013-11-15 19:51:26 UTC (rev 159350)
+++ trunk/Source/_javascript_Core/_javascript_Core.vcxproj/_javascript_Core.vcxproj 2013-11-15 19:53:30 UTC (rev 159351)
@@ -936,6 +936,7 @@
<ClInclude Include="..\heap\CopyVisitorInlines.h" />
<ClInclude Include="..\heap\CopyWorkList.h" />
<ClInclude Include="..\heap\DeferGC.h" />
+ <ClInclude Include="..\heap\DelayedReleaseScope.h" />
<ClInclude Include="..\heap\GCAssertions.h" />
<ClInclude Include="..\heap\GCThread.h" />
<ClInclude Include="..\heap\GCThreadSharedData.h" />
Modified: trunk/Source/_javascript_Core/_javascript_Core.vcxproj/_javascript_Core.vcxproj.filters (159350 => 159351)
--- trunk/Source/_javascript_Core/_javascript_Core.vcxproj/_javascript_Core.vcxproj.filters 2013-11-15 19:51:26 UTC (rev 159350)
+++ trunk/Source/_javascript_Core/_javascript_Core.vcxproj/_javascript_Core.vcxproj.filters 2013-11-15 19:53:30 UTC (rev 159351)
@@ -1559,6 +1559,9 @@
<ClInclude Include="..\heap\DeferGC.h">
<Filter>heap</Filter>
</ClInclude>
+ <ClInclude Include="..\heap\DelayedReleaseScpe.h">
+ <Filter>heap</Filter>
+ </ClInclude>
<ClInclude Include="..\heap\GCAssertions.h">
<Filter>heap</Filter>
</ClInclude>
Modified: trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj (159350 => 159351)
--- trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj 2013-11-15 19:51:26 UTC (rev 159350)
+++ trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj 2013-11-15 19:53:30 UTC (rev 159351)
@@ -705,6 +705,7 @@
1ACF7377171CA6FB00C9BB1E /* Weak.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ACF7376171CA6FB00C9BB1E /* Weak.cpp */; };
2600B5A6152BAAA70091EE5F /* JSStringJoiner.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2600B5A4152BAAA70091EE5F /* JSStringJoiner.cpp */; };
2600B5A7152BAAA70091EE5F /* JSStringJoiner.h in Headers */ = {isa = PBXBuildFile; fileRef = 2600B5A5152BAAA70091EE5F /* JSStringJoiner.h */; };
+ 2A2825D018341F2D0087FBA9 /* DelayedReleaseScope.h in Headers */ = {isa = PBXBuildFile; fileRef = 2A2825CF18341F2D0087FBA9 /* DelayedReleaseScope.h */; };
2A48D1911772365B00C65A5F /* APICallbackFunction.h in Headers */ = {isa = PBXBuildFile; fileRef = C211B574176A224D000E2A23 /* APICallbackFunction.h */; };
2A6F462617E959CE00C45C98 /* HeapOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 2A6F462517E959CE00C45C98 /* HeapOperation.h */; settings = {ATTRIBUTES = (Private, ); }; };
2A7A58EF1808A4C40020BDF7 /* DeferGC.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2A7A58EE1808A4C40020BDF7 /* DeferGC.cpp */; };
@@ -1957,6 +1958,7 @@
1CAA8B4B0D32C39A0041BCFF /* _javascript_Core.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = _javascript_Core.h; sourceTree = "<group>"; };
2600B5A4152BAAA70091EE5F /* JSStringJoiner.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSStringJoiner.cpp; sourceTree = "<group>"; };
2600B5A5152BAAA70091EE5F /* JSStringJoiner.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSStringJoiner.h; sourceTree = "<group>"; };
+ 2A2825CF18341F2D0087FBA9 /* DelayedReleaseScope.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DelayedReleaseScope.h; sourceTree = "<group>"; };
2A6F462517E959CE00C45C98 /* HeapOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HeapOperation.h; sourceTree = "<group>"; };
2A7A58EE1808A4C40020BDF7 /* DeferGC.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DeferGC.cpp; sourceTree = "<group>"; };
2AD8932917E3868F00668276 /* HeapIterationScope.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HeapIterationScope.h; sourceTree = "<group>"; };
@@ -3094,6 +3096,7 @@
14150132154BB13F005D8C98 /* WeakSetInlines.h */,
0FC8150814043BCA00CFA603 /* WriteBarrierSupport.cpp */,
0FC8150914043BD200CFA603 /* WriteBarrierSupport.h */,
+ 2A2825CF18341F2D0087FBA9 /* DelayedReleaseScope.h */,
);
path = heap;
sourceTree = "<group>";
@@ -4745,6 +4748,7 @@
C22B31B9140577D700DB475A /* SamplingCounter.h in Headers */,
1429D8860ED21C3D00B89619 /* SamplingTool.h in Headers */,
0F24E55217EE274900ABB217 /* ScratchRegisterAllocator.h in Headers */,
+ 2A2825D018341F2D0087FBA9 /* DelayedReleaseScope.h in Headers */,
A7299DA617D12858005F5FF9 /* SetConstructor.h in Headers */,
A7299DA217D12848005F5FF9 /* SetPrototype.h in Headers */,
86AE64AA135E5E1C00963012 /* SH4Assembler.h in Headers */,
Added: trunk/Source/_javascript_Core/heap/DelayedReleaseScope.h (0 => 159351)
--- trunk/Source/_javascript_Core/heap/DelayedReleaseScope.h (rev 0)
+++ trunk/Source/_javascript_Core/heap/DelayedReleaseScope.h 2013-11-15 19:53:30 UTC (rev 159351)
@@ -0,0 +1,85 @@
+/*
+ * 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
+ * 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 DelayedReleaseScope_h
+#define DelayedReleaseScope_h
+
+#include "APIShims.h"
+#include "MarkedSpace.h"
+
+namespace JSC {
+
+#if USE(CF)
+
+class DelayedReleaseScope {
+public:
+ DelayedReleaseScope(MarkedSpace& markedSpace)
+ : m_markedSpace(markedSpace)
+ {
+ ASSERT(!m_markedSpace.m_currentDelayedReleaseScope);
+ m_markedSpace.m_currentDelayedReleaseScope = this;
+ }
+
+ ~DelayedReleaseScope()
+ {
+ ASSERT(m_markedSpace.m_currentDelayedReleaseScope == this);
+ m_markedSpace.m_currentDelayedReleaseScope = nullptr;
+
+ APICallbackShim callbackShim(*m_markedSpace.m_heap->vm());
+ m_delayedReleaseObjects.clear();
+ }
+
+ template <typename T>
+ void releaseSoon(RetainPtr<T>&& object)
+ {
+ m_delayedReleaseObjects.append(std::move(object));
+ }
+
+private:
+ MarkedSpace& m_markedSpace;
+ Vector<RetainPtr<CFTypeRef>> m_delayedReleaseObjects;
+};
+
+template <typename T>
+inline void MarkedSpace::releaseSoon(RetainPtr<T>&& object)
+{
+ ASSERT(m_currentDelayedReleaseScope);
+ m_currentDelayedReleaseScope->releaseSoon(std::move(object));
+}
+
+#else // USE(CF)
+
+class DelayedReleaseScope {
+public:
+ DelayedReleaseScope(MarkedSpace&)
+ {
+ }
+};
+
+#endif // USE(CF)
+
+} // namespace JSC
+
+#endif // DelayedReleaseScope_h
Modified: trunk/Source/_javascript_Core/heap/Heap.cpp (159350 => 159351)
--- trunk/Source/_javascript_Core/heap/Heap.cpp 2013-11-15 19:51:26 UTC (rev 159350)
+++ trunk/Source/_javascript_Core/heap/Heap.cpp 2013-11-15 19:53:30 UTC (rev 159351)
@@ -27,6 +27,7 @@
#include "CopiedSpaceInlines.h"
#include "CopyVisitorInlines.h"
#include "DFGWorklist.h"
+#include "DelayedReleaseScope.h"
#include "GCActivityCallback.h"
#include "GCIncomingRefCountedSetInlines.h"
#include "HeapIterationScope.h"
@@ -729,6 +730,7 @@
if (!m_isSafeToCollect)
return;
+ DelayedReleaseScope delayedReleaseScope(m_objectSpace);
collect(DoSweep);
}
Modified: trunk/Source/_javascript_Core/heap/Heap.h (159350 => 159351)
--- trunk/Source/_javascript_Core/heap/Heap.h 2013-11-15 19:51:26 UTC (rev 159350)
+++ trunk/Source/_javascript_Core/heap/Heap.h 2013-11-15 19:53:30 UTC (rev 159351)
@@ -186,6 +186,10 @@
bool isDeferred() const { return !!m_deferralDepth; }
+#if USE(CF)
+ template<typename T> void releaseSoon(RetainPtr<T>&&);
+#endif
+
private:
friend class CodeBlock;
friend class CopiedBlock;
@@ -468,6 +472,14 @@
return m_blockAllocator;
}
+#if USE(CF)
+ template <typename T>
+ inline void Heap::releaseSoon(RetainPtr<T>&& object)
+ {
+ m_objectSpace.releaseSoon(std::move(object));
+ }
+#endif
+
} // namespace JSC
#endif // Heap_h
Modified: trunk/Source/_javascript_Core/heap/MarkedAllocator.cpp (159350 => 159351)
--- trunk/Source/_javascript_Core/heap/MarkedAllocator.cpp 2013-11-15 19:51:26 UTC (rev 159350)
+++ trunk/Source/_javascript_Core/heap/MarkedAllocator.cpp 2013-11-15 19:53:30 UTC (rev 159351)
@@ -1,6 +1,7 @@
#include "config.h"
#include "MarkedAllocator.h"
+#include "DelayedReleaseScope.h"
#include "GCActivityCallback.h"
#include "Heap.h"
#include "IncrementalSweeper.h"
@@ -77,6 +78,7 @@
void* MarkedAllocator::allocateSlowCase(size_t bytes)
{
ASSERT(m_heap->vm()->currentThreadIsHoldingAPILock());
+ DelayedReleaseScope delayedReleaseScope(*m_markedSpace);
#if COLLECT_ON_EVERY_ALLOCATION
if (!m_heap->isDeferred())
m_heap->collectAllGarbage();
Modified: trunk/Source/_javascript_Core/heap/MarkedSpace.cpp (159350 => 159351)
--- trunk/Source/_javascript_Core/heap/MarkedSpace.cpp 2013-11-15 19:51:26 UTC (rev 159350)
+++ trunk/Source/_javascript_Core/heap/MarkedSpace.cpp 2013-11-15 19:53:30 UTC (rev 159351)
@@ -21,6 +21,7 @@
#include "config.h"
#include "MarkedSpace.h"
+#include "DelayedReleaseScope.h"
#include "IncrementalSweeper.h"
#include "JSGlobalObject.h"
#include "JSLock.h"
@@ -81,6 +82,7 @@
: m_heap(heap)
, m_capacity(0)
, m_isIterating(false)
+ , m_currentDelayedReleaseScope(nullptr)
{
for (size_t cellSize = preciseStep; cellSize <= preciseCutoff; cellSize += preciseStep) {
allocatorFor(cellSize).init(heap, this, cellSize, MarkedBlock::None);
@@ -111,12 +113,14 @@
void MarkedSpace::lastChanceToFinalize()
{
+ DelayedReleaseScope delayedReleaseScope(*this);
stopAllocating();
forEachBlock<LastChanceToFinalize>();
}
void MarkedSpace::sweep()
{
+ ASSERT(m_currentDelayedReleaseScope);
m_heap->sweeper()->willFinishSweeping();
forEachBlock<Sweep>();
}
Modified: trunk/Source/_javascript_Core/heap/MarkedSpace.h (159350 => 159351)
--- trunk/Source/_javascript_Core/heap/MarkedSpace.h 2013-11-15 19:51:26 UTC (rev 159350)
+++ trunk/Source/_javascript_Core/heap/MarkedSpace.h 2013-11-15 19:53:30 UTC (rev 159351)
@@ -36,6 +36,7 @@
namespace JSC {
+class DelayedReleaseScope;
class Heap;
class HeapIterationScope;
class JSCell;
@@ -114,7 +115,12 @@
bool isPagedOut(double deadline);
+#if USE(CF)
+ template<typename T> void releaseSoon(RetainPtr<T>&&);
+#endif
+
private:
+ friend class DelayedReleaseScope;
friend class LLIntOffsetsExtractor;
template<typename Functor> void forEachAllocator(Functor&);
@@ -144,6 +150,8 @@
size_t m_capacity;
bool m_isIterating;
MarkedBlockSet m_blocks;
+
+ DelayedReleaseScope* m_currentDelayedReleaseScope;
};
template<typename Functor> inline typename Functor::ReturnType MarkedSpace::forEachLiveCell(HeapIterationScope&, Functor& functor)