Ignore:
Timestamp:
Nov 15, 2013, 11:53:30 AM (12 years ago)
Author:
[email protected]
Message:

-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:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/API/ObjCCallbackFunction.mm

    r158695 r159351  
    3232#import "APICast.h"
    3333#import "APIShims.h"
     34#import "DelayedReleaseScope.h"
    3435#import "Error.h"
    3536#import "JSCJSValueInlines.h"
     
    406407    }
    407408
    408     ~ObjCCallbackFunctionImpl()
    409     {
    410         // We need to explicity release the target since we didn't call
     409    void destroy(Heap& heap)
     410    {
     411        // We need to explicitly release the target since we didn't call
    411412        // -retainArguments on m_invocation (and we don't want to do so).
    412413        if (m_type == CallbackBlock || m_type == CallbackClassMethod)
    413             [[m_invocation.get() target] release];
     414            heap.releaseSoon(adoptNS([m_invocation.get() target]));
    414415        [m_instanceClass release];
    415416    }
     
    521522void ObjCCallbackFunction::destroy(JSCell* cell)
    522523{
    523     static_cast<ObjCCallbackFunction*>(cell)->ObjCCallbackFunction::~ObjCCallbackFunction();
     524    ObjCCallbackFunction& function = *jsCast<ObjCCallbackFunction*>(cell);
     525    function.impl()->destroy(*Heap::heap(cell));
     526    function.~ObjCCallbackFunction();
    524527}
    525528
Note: See TracChangeset for help on using the changeset viewer.