Commit ac6f1fd4 authored by mhahnenberg@apple.com's avatar mhahnenberg@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:]):
* JavaScriptCore.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:


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@159351 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 53227d60
......@@ -83,18 +83,39 @@ private:
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;
};
......
......@@ -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 @@ void JSAPIWrapperObjectHandleOwner::finalize(JSC::Handle<JSC::Unknown> handle, v
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()));
}
......
......@@ -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 @@ public:
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 @@ ObjCCallbackFunction* ObjCCallbackFunction::create(JSC::VM& vm, JSC::JSGlobalObj
void ObjCCallbackFunction::destroy(JSCell* cell)
{
static_cast<ObjCCallbackFunction*>(cell)->ObjCCallbackFunction::~ObjCCallbackFunction();
ObjCCallbackFunction& function = *jsCast<ObjCCallbackFunction*>(cell);
function.impl()->destroy(*Heap::heap(cell));
function.~ObjCCallbackFunction();
}
......
......@@ -182,54 +182,43 @@ bool testXYZTested = false;
@end
@interface TinyDOMNode : NSObject<TinyDOMNode>
+ (JSVirtualMachine *)sharedVirtualMachine;
+ (void)clearSharedVirtualMachine;
@end
@implementation TinyDOMNode {
NSMutableArray *m_children;
JSVirtualMachine *m_sharedVirtualMachine;
}
static JSVirtualMachine *sharedInstance = nil;
+ (JSVirtualMachine *)sharedVirtualMachine
{
if (!sharedInstance)
sharedInstance = [[JSVirtualMachine alloc] init];
return sharedInstance;
}
+ (void)clearSharedVirtualMachine
{
sharedInstance = nil;
}
- (id)init
- (id)initWithVirtualMachine:(JSVirtualMachine *)virtualMachine
{
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 @@ static JSVirtualMachine *sharedInstance = nil;
{
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 @@ static JSVirtualMachine *sharedInstance = nil;
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 @@ void testObjectiveCAPI()
}
@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 @@ void testObjectiveCAPI()
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 @@ void testObjectiveCAPI()
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 @@ void testObjectiveCAPI()
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();
}
......
2013-11-14 Mark Hahnenberg <mhahnenberg@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:]):
* JavaScriptCore.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 <msaboff@apple.com>
REGRESSION (r158586): callToJavaScript needs to save return PC to Sentinel frame
......
......@@ -486,8 +486,9 @@ javascriptcore_sources += \
Source/JavaScriptCore/heap/CopyWorkList.h \
Source/JavaScriptCore/heap/ConservativeRoots.cpp \
Source/JavaScriptCore/heap/ConservativeRoots.h \
Source/JavaScriptCore/heap/DeferGC.cpp \
Source/JavaScriptCore/heap/DeferGC.cpp \
Source/JavaScriptCore/heap/DeferGC.h \
Source/JavaScriptCore/heap/DelayedReleaseScope.h \
Source/JavaScriptCore/heap/GCAssertions.h \
Source/JavaScriptCore/heap/GCIncomingRefCounted.h \
Source/JavaScriptCore/heap/GCIncomingRefCountedInlines.h \
......
......@@ -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" />
......
......@@ -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>
......
......@@ -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 /* JavaScriptCore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JavaScriptCore.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 */,
......
/*
* 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
......@@ -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 @@ void Heap::collectAllGarbage()
if (!m_isSafeToCollect)
return;
DelayedReleaseScope delayedReleaseScope(m_objectSpace);
collect(DoSweep);
}
......
......@@ -186,6 +186,10 @@ namespace JSC {
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 @@ namespace JSC {
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
#include "config.h"
#include "MarkedAllocator.h"
#include "DelayedReleaseScope.h"
#include "GCActivityCallback.h"
#include "Heap.h"
#include "IncrementalSweeper.h"
......@@ -77,6 +78,7 @@ inline void* MarkedAllocator::tryAllocate(size_t bytes)
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();
......
......@@ -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 @@ MarkedSpace::MarkedSpace(Heap* heap)
: 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 @@ struct LastChanceToFinalize : MarkedBlock::VoidFunctor {
void MarkedSpace::lastChanceToFinalize()
{
DelayedReleaseScope delayedReleaseScope(*this);
stopAllocating();
forEachBlock<LastChanceToFinalize>();
}
void MarkedSpace::sweep()
{
ASSERT(m_currentDelayedReleaseScope);
m_heap->sweeper()->willFinishSweeping();
forEachBlock<Sweep>();
}
......
......@@ -36,6 +36,7 @@
namespace JSC {
class DelayedReleaseScope;
class Heap;
class HeapIterationScope;
class JSCell;
......@@ -114,7 +115,12 @@ public:
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 @@ private:
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)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment