Changeset 128813 in webkit for trunk/Source/JavaScriptCore/API


Ignore:
Timestamp:
Sep 17, 2012, 3:16:10 PM (13 years ago)
Author:
[email protected]
Message:

Delayed structure sweep can leak structures without bound
https://bugs.webkit.org/show_bug.cgi?id=96546

Reviewed by Gavin Barraclough.

This patch gets rid of the separate Structure allocator in the MarkedSpace and adds two new destructor-only
allocators. We now have separate allocators for our three types of objects: those objects with no destructors,
those objects with destructors and with immortal structures, and those objects with destructors that don't have
immortal structures. All of the objects of the third type (destructors without immortal structures) now
inherit from a new class named JSDestructibleObject (which in turn is a subclass of JSNonFinalObject), which stores
the ClassInfo for these classes at a fixed offset for safe retrieval during sweeping/destruction.

Source/JavaScriptCore:

  • API/JSCallbackConstructor.cpp: Use JSDestructibleObject for JSCallbackConstructor.

(JSC):
(JSC::JSCallbackConstructor::JSCallbackConstructor):

  • API/JSCallbackConstructor.h:

(JSCallbackConstructor):

  • API/JSCallbackObject.cpp: Inherit from JSDestructibleObject for normal JSCallbackObjects and use a finalizer for

JSCallbackObject<JSGlobalObject>, since JSGlobalObject also uses a finalizer.
(JSC):
(JSC::::create): We need to move the create function for JSCallbackObject<JSGlobalObject> out of line so we can add
the finalizer for it. We don't want to add the finalizer is something like finishCreation in case somebody decides
to subclass this. We use this same technique for many other subclasses of JSGlobalObject.
(JSC::::createStructure):

  • API/JSCallbackObject.h:

(JSCallbackObject):
(JSC):

  • API/JSClassRef.cpp: Change all the JSCallbackObject<JSNonFinalObject> to use JSDestructibleObject instead.

(OpaqueJSClass::prototype):

  • API/JSObjectRef.cpp: Ditto.

(JSObjectMake):
(JSObjectGetPrivate):
(JSObjectSetPrivate):
(JSObjectGetPrivateProperty):
(JSObjectSetPrivateProperty):
(JSObjectDeletePrivateProperty):

  • API/JSValueRef.cpp: Ditto.

(JSValueIsObjectOfClass):

  • API/JSWeakObjectMapRefPrivate.cpp: Ditto.
  • JSCTypedArrayStubs.h:

(JSC):

  • JavaScriptCore.xcodeproj/project.pbxproj:
  • dfg/DFGSpeculativeJIT.h: Use the proper allocator type when doing inline allocation in the DFG.

(JSC::DFG::SpeculativeJIT::emitAllocateBasicJSObject):
(JSC::DFG::SpeculativeJIT::emitAllocateJSFinalObject):

  • heap/Heap.cpp:

(JSC):

  • heap/Heap.h: Add accessors for the various types of allocators now. Also remove the isSafeToSweepStructures function

since it's always safe to sweep Structures now.
(JSC::Heap::allocatorForObjectWithNormalDestructor):
(JSC::Heap::allocatorForObjectWithImmortalStructureDestructor):
(Heap):
(JSC::Heap::allocateWithNormalDestructor):
(JSC):
(JSC::Heap::allocateWithImmortalStructureDestructor):

  • heap/IncrementalSweeper.cpp: Remove all the logic to detect when it's safe to sweep Structures from the

IncrementalSweeper since it's always safe to sweep Structures now.
(JSC::IncrementalSweeper::IncrementalSweeper):
(JSC::IncrementalSweeper::sweepNextBlock):
(JSC::IncrementalSweeper::startSweeping):
(JSC::IncrementalSweeper::willFinishSweeping):
(JSC):

  • heap/IncrementalSweeper.h:

(IncrementalSweeper):

  • heap/MarkedAllocator.cpp: Remove the logic that was preventing us from sweeping Structures if it wasn't safe. Add

tracking of the specific destructor type of allocator.
(JSC::MarkedAllocator::tryAllocateHelper):
(JSC::MarkedAllocator::allocateBlock):

  • heap/MarkedAllocator.h:

(JSC::MarkedAllocator::destructorType):
(MarkedAllocator):
(JSC::MarkedAllocator::MarkedAllocator):
(JSC::MarkedAllocator::init):

  • heap/MarkedBlock.cpp: Add all the destructor type stuff to MarkedBlocks so that we do the right thing when sweeping.

We also use the stored destructor type to determine the right thing to do in all JSCell::classInfo() calls.
(JSC::MarkedBlock::create):
(JSC::MarkedBlock::MarkedBlock):
(JSC):
(JSC::MarkedBlock::specializedSweep):
(JSC::MarkedBlock::sweep):
(JSC::MarkedBlock::sweepHelper):

  • heap/MarkedBlock.h:

(JSC):
(JSC::MarkedBlock::allocator):
(JSC::MarkedBlock::destructorType):

  • heap/MarkedSpace.cpp: Add the new destructor allocators to MarkedSpace.

(JSC::MarkedSpace::MarkedSpace):
(JSC::MarkedSpace::resetAllocators):
(JSC::MarkedSpace::canonicalizeCellLivenessData):
(JSC::MarkedSpace::isPagedOut):
(JSC::MarkedSpace::freeBlock):

  • heap/MarkedSpace.h:

(MarkedSpace):
(JSC::MarkedSpace::immortalStructureDestructorAllocatorFor):
(JSC::MarkedSpace::normalDestructorAllocatorFor):
(JSC::MarkedSpace::allocateWithImmortalStructureDestructor):
(JSC::MarkedSpace::allocateWithNormalDestructor):
(JSC::MarkedSpace::forEachBlock):

  • heap/SlotVisitor.cpp: Add include because the symbol was needed in an inlined function.
  • jit/JIT.h: Make sure we use the correct allocator when doing inline allocations in the baseline JIT.
  • jit/JITInlineMethods.h:

(JSC::JIT::emitAllocateBasicJSObject):
(JSC::JIT::emitAllocateJSFinalObject):
(JSC::JIT::emitAllocateJSArray):

  • jsc.cpp:

(GlobalObject::create): Add finalizer here since JSGlobalObject needs to use a finalizer instead of inheriting from
JSDestructibleObject.

  • runtime/Arguments.cpp: Inherit from JSDestructibleObject.

(JSC):

  • runtime/Arguments.h:

(Arguments):
(JSC::Arguments::Arguments):

  • runtime/ErrorPrototype.cpp: Added an assert to make sure we have a trivial destructor.

(JSC):

  • runtime/Executable.h: Indicate that all of the Executable* classes have immortal Structures.

(JSC):

  • runtime/InternalFunction.cpp: Inherit from JSDestructibleObject.

(JSC):
(JSC::InternalFunction::InternalFunction):

  • runtime/InternalFunction.h:

(InternalFunction):

  • runtime/JSCell.h: Added the NEEDS_DESTRUCTOR macro to make it easier for classes to indicate that instead of being

allocated in a destructor MarkedAllocator that they will handle their destruction themselves through the
use of a finalizer.
(JSC):
(HasImmortalStructure): New template to help us determine at compile-time if a particular class
should be allocated in the immortal structure MarkedAllocator. The default value is false. In order
to be allocated in the immortal structure allocator, classes must specialize this template. Also added
a macro to make it easier for classes to specialize the template.
(JSC::allocateCell): Use the appropriate allocator depending on the destructor type.

  • runtime/JSDestructibleObject.h: Added. New class that stores the ClassInfo of any subclass so that it can be

accessed safely when the object is being destroyed.
(JSC):
(JSDestructibleObject):
(JSC::JSDestructibleObject::classInfo):
(JSC::JSDestructibleObject::JSDestructibleObject):
(JSC::JSCell::classInfo): Checks the current MarkedBlock to see where it should get the ClassInfo from so that it's always safe.

  • runtime/JSGlobalObject.cpp: JSGlobalObject now uses a finalizer instead of a destructor so that it can avoid forcing all

of its relatives in the inheritance hierarchy (e.g. JSScope) to use destructors as well.
(JSC::JSGlobalObject::reset):

  • runtime/JSGlobalObject.h:

(JSGlobalObject):
(JSC::JSGlobalObject::createRareDataIfNeeded): Since we always create a finalizer now, we don't have to worry about adding one
for the m_rareData field when it's created.
(JSC::JSGlobalObject::create):
(JSC):

  • runtime/JSGlobalThis.h: Inherit from JSDestructibleObject.

(JSGlobalThis):
(JSC::JSGlobalThis::JSGlobalThis):

  • runtime/JSPropertyNameIterator.h: Has an immortal Structure.

(JSC):

  • runtime/JSScope.cpp:

(JSC):

  • runtime/JSString.h: Has an immortal Structure.

(JSC):

  • runtime/JSWrapperObject.h: Inherit from JSDestructibleObject.

(JSWrapperObject):
(JSC::JSWrapperObject::JSWrapperObject):

  • runtime/MathObject.cpp: Cleaning up some of the inheritance stuff.

(JSC):

  • runtime/NameInstance.h: Inherit from JSDestructibleObject.

(NameInstance):

  • runtime/RegExp.h: Has immortal Structure.

(JSC):

  • runtime/RegExpObject.cpp: Inheritance cleanup.

(JSC):

  • runtime/SparseArrayValueMap.h: Has immortal Structure.

(JSC):

  • runtime/Structure.h: Has immortal Structure.

(JSC):

  • runtime/StructureChain.h: Ditto.

(JSC):

  • runtime/SymbolTable.h: Ditto.

(SharedSymbolTable):
(JSC):

Source/WebCore:

No new tests.

  • ForwardingHeaders/runtime/JSDestructableObject.h: Added.
  • bindings/js/JSDOMWrapper.h: Inherits from JSDestructibleObject.

(JSDOMWrapper):
(WebCore::JSDOMWrapper::JSDOMWrapper):

  • bindings/scripts/CodeGeneratorJS.pm: Add finalizers to anything that inherits from JSGlobalObject,

e.g. JSDOMWindow and JSWorkerContexts. For those classes we also need to use the NEEDS_DESTRUCTOR macro.
(GenerateHeader):

  • bridge/objc/objc_runtime.h: Inherit from JSDestructibleObject.

(ObjcFallbackObjectImp):

  • bridge/objc/objc_runtime.mm:

(Bindings):
(JSC::Bindings::ObjcFallbackObjectImp::ObjcFallbackObjectImp):

  • bridge/runtime_array.cpp: Use a finalizer so that JSArray isn't forced to inherit from JSDestructibleObject.

(JSC):
(JSC::RuntimeArray::destroy):

  • bridge/runtime_array.h:

(JSC::RuntimeArray::create):
(JSC):

  • bridge/runtime_object.cpp: Inherit from JSDestructibleObject.

(Bindings):
(JSC::Bindings::RuntimeObject::RuntimeObject):

  • bridge/runtime_object.h:

(RuntimeObject):

Location:
trunk/Source/JavaScriptCore/API
Files:
8 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/API/JSCallbackConstructor.cpp

    r118616 r128813  
    3737namespace JSC {
    3838
    39 const ClassInfo JSCallbackConstructor::s_info = { "CallbackConstructor", &JSNonFinalObject::s_info, 0, 0, CREATE_METHOD_TABLE(JSCallbackConstructor) };
     39const ClassInfo JSCallbackConstructor::s_info = { "CallbackConstructor", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSCallbackConstructor) };
    4040
    4141JSCallbackConstructor::JSCallbackConstructor(JSGlobalObject* globalObject, Structure* structure, JSClassRef jsClass, JSObjectCallAsConstructorCallback callback)
    42     : JSNonFinalObject(globalObject->globalData(), structure)
     42    : JSDestructibleObject(globalObject->globalData(), structure)
    4343    , m_class(jsClass)
    4444    , m_callback(callback)
  • trunk/Source/JavaScriptCore/API/JSCallbackConstructor.h

    r103243 r128813  
    2828
    2929#include "JSObjectRef.h"
    30 #include <runtime/JSObject.h>
     30#include "runtime/JSDestructibleObject.h"
    3131
    3232namespace JSC {
    3333
    34 class JSCallbackConstructor : public JSNonFinalObject {
     34class JSCallbackConstructor : public JSDestructibleObject {
    3535public:
    36     typedef JSNonFinalObject Base;
     36    typedef JSDestructibleObject Base;
    3737
    3838    static JSCallbackConstructor* create(ExecState* exec, JSGlobalObject* globalObject, Structure* structure, JSClassRef classRef, JSObjectCallAsConstructorCallback callback)
  • trunk/Source/JavaScriptCore/API/JSCallbackObject.cpp

    r118616 r128813  
    3333namespace JSC {
    3434
    35 ASSERT_CLASS_FITS_IN_CELL(JSCallbackObject<JSNonFinalObject>);
     35ASSERT_CLASS_FITS_IN_CELL(JSCallbackObject<JSDestructibleObject>);
    3636ASSERT_CLASS_FITS_IN_CELL(JSCallbackObject<JSGlobalObject>);
    3737
    3838// Define the two types of JSCallbackObjects we support.
    39 template <> const ClassInfo JSCallbackObject<JSNonFinalObject>::s_info = { "CallbackObject", &JSNonFinalObject::s_info, 0, 0, CREATE_METHOD_TABLE(JSCallbackObject) };
    40 template <> const ClassInfo JSCallbackObject<JSGlobalObject>::s_info = { "CallbackGlobalObject", &JSGlobalObject::s_info, 0, 0, CREATE_METHOD_TABLE(JSCallbackObject) };
     39template <> const ClassInfo JSCallbackObject<JSDestructibleObject>::s_info = { "CallbackObject", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSCallbackObject) };
     40template <> const ClassInfo JSCallbackObject<JSGlobalObject>::s_info = { "CallbackGlobalObject", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSCallbackObject) };
     41
     42template<>
     43JSCallbackObject<JSGlobalObject>* JSCallbackObject<JSGlobalObject>::create(JSGlobalData& globalData, JSClassRef classRef, Structure* structure)
     44{
     45    JSCallbackObject<JSGlobalObject>* callbackObject = new (NotNull, allocateCell<JSCallbackObject<JSGlobalObject> >(globalData.heap)) JSCallbackObject(globalData, classRef, structure);
     46    callbackObject->finishCreation(globalData);
     47    globalData.heap.addFinalizer(callbackObject, destroy);
     48    return callbackObject;
     49}
    4150
    4251template <>
    43 Structure* JSCallbackObject<JSNonFinalObject>::createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue proto)
     52Structure* JSCallbackObject<JSDestructibleObject>::createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue proto)
    4453{
    4554    return Structure::create(globalData, globalObject, proto, TypeInfo(ObjectType, StructureFlags), &s_info);
  • trunk/Source/JavaScriptCore/API/JSCallbackObject.h

    r128400 r128813  
    134134        return callbackObject;
    135135    }
    136     static JSCallbackObject* create(JSGlobalData& globalData, JSClassRef classRef, Structure* structure)
    137     {
    138         JSCallbackObject* callbackObject = new (NotNull, allocateCell<JSCallbackObject>(globalData.heap)) JSCallbackObject(globalData, classRef, structure);
    139         callbackObject->finishCreation(globalData);
    140         return callbackObject;
    141     }
    142 
     136    static JSCallbackObject<Parent>* create(JSGlobalData&, JSClassRef, Structure*);
    143137    void setPrivate(void* data);
    144138    void* getPrivate();
     
    218212};
    219213
     214NEEDS_DESTRUCTOR(JSCallbackObject<JSGlobalObject>, false);
     215
    220216} // namespace JSC
    221217
  • trunk/Source/JavaScriptCore/API/JSClassRef.cpp

    r127191 r128813  
    200200
    201201    // Recursive, but should be good enough for our purposes
    202     JSObject* prototype = JSCallbackObject<JSNonFinalObject>::create(exec, exec->lexicalGlobalObject(), exec->lexicalGlobalObject()->callbackObjectStructure(), prototypeClass, &jsClassData); // set jsClassData as the object's private data, so it can clear our reference on destruction
     202    JSObject* prototype = JSCallbackObject<JSDestructibleObject>::create(exec, exec->lexicalGlobalObject(), exec->lexicalGlobalObject()->callbackObjectStructure(), prototypeClass, &jsClassData); // set jsClassData as the object's private data, so it can clear our reference on destruction
    203203    if (parentClass) {
    204204        if (JSObject* parentPrototype = parentClass->prototype(exec))
  • trunk/Source/JavaScriptCore/API/JSObjectRef.cpp

    r128400 r128813  
    8484        return toRef(constructEmptyObject(exec));
    8585
    86     JSCallbackObject<JSNonFinalObject>* object = JSCallbackObject<JSNonFinalObject>::create(exec, exec->lexicalGlobalObject(), exec->lexicalGlobalObject()->callbackObjectStructure(), jsClass, data);
     86    JSCallbackObject<JSDestructibleObject>* object = JSCallbackObject<JSDestructibleObject>::create(exec, exec->lexicalGlobalObject(), exec->lexicalGlobalObject()->callbackObjectStructure(), jsClass, data);
    8787    if (JSObject* prototype = jsClass->prototype(exec))
    8888        object->setPrototype(exec->globalData(), prototype);
     
    342342    if (jsObject->inherits(&JSCallbackObject<JSGlobalObject>::s_info))
    343343        return jsCast<JSCallbackObject<JSGlobalObject>*>(jsObject)->getPrivate();
    344     if (jsObject->inherits(&JSCallbackObject<JSNonFinalObject>::s_info))
    345         return jsCast<JSCallbackObject<JSNonFinalObject>*>(jsObject)->getPrivate();
     344    if (jsObject->inherits(&JSCallbackObject<JSDestructibleObject>::s_info))
     345        return jsCast<JSCallbackObject<JSDestructibleObject>*>(jsObject)->getPrivate();
    346346   
    347347    return 0;
     
    356356        return true;
    357357    }
    358     if (jsObject->inherits(&JSCallbackObject<JSNonFinalObject>::s_info)) {
    359         jsCast<JSCallbackObject<JSNonFinalObject>*>(jsObject)->setPrivate(data);
     358    if (jsObject->inherits(&JSCallbackObject<JSDestructibleObject>::s_info)) {
     359        jsCast<JSCallbackObject<JSDestructibleObject>*>(jsObject)->setPrivate(data);
    360360        return true;
    361361    }
     
    373373    if (jsObject->inherits(&JSCallbackObject<JSGlobalObject>::s_info))
    374374        result = jsCast<JSCallbackObject<JSGlobalObject>*>(jsObject)->getPrivateProperty(name);
    375     else if (jsObject->inherits(&JSCallbackObject<JSNonFinalObject>::s_info))
    376         result = jsCast<JSCallbackObject<JSNonFinalObject>*>(jsObject)->getPrivateProperty(name);
     375    else if (jsObject->inherits(&JSCallbackObject<JSDestructibleObject>::s_info))
     376        result = jsCast<JSCallbackObject<JSDestructibleObject>*>(jsObject)->getPrivateProperty(name);
    377377    return toRef(exec, result);
    378378}
     
    389389        return true;
    390390    }
    391     if (jsObject->inherits(&JSCallbackObject<JSNonFinalObject>::s_info)) {
    392         jsCast<JSCallbackObject<JSNonFinalObject>*>(jsObject)->setPrivateProperty(exec->globalData(), name, jsValue);
     391    if (jsObject->inherits(&JSCallbackObject<JSDestructibleObject>::s_info)) {
     392        jsCast<JSCallbackObject<JSDestructibleObject>*>(jsObject)->setPrivateProperty(exec->globalData(), name, jsValue);
    393393        return true;
    394394    }
     
    406406        return true;
    407407    }
    408     if (jsObject->inherits(&JSCallbackObject<JSNonFinalObject>::s_info)) {
    409         jsCast<JSCallbackObject<JSNonFinalObject>*>(jsObject)->deletePrivateProperty(name);
     408    if (jsObject->inherits(&JSCallbackObject<JSDestructibleObject>::s_info)) {
     409        jsCast<JSCallbackObject<JSDestructibleObject>*>(jsObject)->deletePrivateProperty(name);
    410410        return true;
    411411    }
  • trunk/Source/JavaScriptCore/API/JSValueRef.cpp

    r127958 r128813  
    132132        if (o->inherits(&JSCallbackObject<JSGlobalObject>::s_info))
    133133            return jsCast<JSCallbackObject<JSGlobalObject>*>(o)->inherits(jsClass);
    134         if (o->inherits(&JSCallbackObject<JSNonFinalObject>::s_info))
    135             return jsCast<JSCallbackObject<JSNonFinalObject>*>(o)->inherits(jsClass);
     134        if (o->inherits(&JSCallbackObject<JSDestructibleObject>::s_info))
     135            return jsCast<JSCallbackObject<JSDestructibleObject>*>(o)->inherits(jsClass);
    136136    }
    137137    return false;
  • trunk/Source/JavaScriptCore/API/JSWeakObjectMapRefPrivate.cpp

    r118483 r128813  
    5858    if (!obj)
    5959        return;
    60     ASSERT(obj->inherits(&JSCallbackObject<JSGlobalObject>::s_info) || obj->inherits(&JSCallbackObject<JSNonFinalObject>::s_info));
     60    ASSERT(obj->inherits(&JSCallbackObject<JSGlobalObject>::s_info) || obj->inherits(&JSCallbackObject<JSDestructibleObject>::s_info));
    6161    map->map().set(exec->globalData(), key, obj);
    6262}
Note: See TracChangeset for help on using the changeset viewer.