Commit 013fd88d authored by mhahnenberg@apple.com's avatar mhahnenberg@apple.com

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):


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@128813 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 57d3cca3
......@@ -36,10 +36,10 @@
namespace JSC {
const ClassInfo JSCallbackConstructor::s_info = { "CallbackConstructor", &JSNonFinalObject::s_info, 0, 0, CREATE_METHOD_TABLE(JSCallbackConstructor) };
const ClassInfo JSCallbackConstructor::s_info = { "CallbackConstructor", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSCallbackConstructor) };
JSCallbackConstructor::JSCallbackConstructor(JSGlobalObject* globalObject, Structure* structure, JSClassRef jsClass, JSObjectCallAsConstructorCallback callback)
: JSNonFinalObject(globalObject->globalData(), structure)
: JSDestructibleObject(globalObject->globalData(), structure)
, m_class(jsClass)
, m_callback(callback)
{
......
......@@ -27,13 +27,13 @@
#define JSCallbackConstructor_h
#include "JSObjectRef.h"
#include <runtime/JSObject.h>
#include "runtime/JSDestructibleObject.h"
namespace JSC {
class JSCallbackConstructor : public JSNonFinalObject {
class JSCallbackConstructor : public JSDestructibleObject {
public:
typedef JSNonFinalObject Base;
typedef JSDestructibleObject Base;
static JSCallbackConstructor* create(ExecState* exec, JSGlobalObject* globalObject, Structure* structure, JSClassRef classRef, JSObjectCallAsConstructorCallback callback)
{
......
......@@ -32,15 +32,24 @@
namespace JSC {
ASSERT_CLASS_FITS_IN_CELL(JSCallbackObject<JSNonFinalObject>);
ASSERT_CLASS_FITS_IN_CELL(JSCallbackObject<JSDestructibleObject>);
ASSERT_CLASS_FITS_IN_CELL(JSCallbackObject<JSGlobalObject>);
// Define the two types of JSCallbackObjects we support.
template <> const ClassInfo JSCallbackObject<JSNonFinalObject>::s_info = { "CallbackObject", &JSNonFinalObject::s_info, 0, 0, CREATE_METHOD_TABLE(JSCallbackObject) };
template <> const ClassInfo JSCallbackObject<JSGlobalObject>::s_info = { "CallbackGlobalObject", &JSGlobalObject::s_info, 0, 0, CREATE_METHOD_TABLE(JSCallbackObject) };
template <> const ClassInfo JSCallbackObject<JSDestructibleObject>::s_info = { "CallbackObject", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSCallbackObject) };
template <> const ClassInfo JSCallbackObject<JSGlobalObject>::s_info = { "CallbackGlobalObject", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSCallbackObject) };
template<>
JSCallbackObject<JSGlobalObject>* JSCallbackObject<JSGlobalObject>::create(JSGlobalData& globalData, JSClassRef classRef, Structure* structure)
{
JSCallbackObject<JSGlobalObject>* callbackObject = new (NotNull, allocateCell<JSCallbackObject<JSGlobalObject> >(globalData.heap)) JSCallbackObject(globalData, classRef, structure);
callbackObject->finishCreation(globalData);
globalData.heap.addFinalizer(callbackObject, destroy);
return callbackObject;
}
template <>
Structure* JSCallbackObject<JSNonFinalObject>::createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue proto)
Structure* JSCallbackObject<JSDestructibleObject>::createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue proto)
{
return Structure::create(globalData, globalObject, proto, TypeInfo(ObjectType, StructureFlags), &s_info);
}
......
......@@ -133,13 +133,7 @@ public:
callbackObject->finishCreation(exec);
return callbackObject;
}
static JSCallbackObject* create(JSGlobalData& globalData, JSClassRef classRef, Structure* structure)
{
JSCallbackObject* callbackObject = new (NotNull, allocateCell<JSCallbackObject>(globalData.heap)) JSCallbackObject(globalData, classRef, structure);
callbackObject->finishCreation(globalData);
return callbackObject;
}
static JSCallbackObject<Parent>* create(JSGlobalData&, JSClassRef, Structure*);
void setPrivate(void* data);
void* getPrivate();
......@@ -217,6 +211,8 @@ private:
OwnPtr<JSCallbackObjectData> m_callbackObjectData;
};
NEEDS_DESTRUCTOR(JSCallbackObject<JSGlobalObject>, false);
} // namespace JSC
// include the actual template class implementation
......
......@@ -199,7 +199,7 @@ JSObject* OpaqueJSClass::prototype(ExecState* exec)
return prototype;
// Recursive, but should be good enough for our purposes
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
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
if (parentClass) {
if (JSObject* parentPrototype = parentClass->prototype(exec))
prototype->setPrototype(exec->globalData(), parentPrototype);
......
......@@ -83,7 +83,7 @@ JSObjectRef JSObjectMake(JSContextRef ctx, JSClassRef jsClass, void* data)
if (!jsClass)
return toRef(constructEmptyObject(exec));
JSCallbackObject<JSNonFinalObject>* object = JSCallbackObject<JSNonFinalObject>::create(exec, exec->lexicalGlobalObject(), exec->lexicalGlobalObject()->callbackObjectStructure(), jsClass, data);
JSCallbackObject<JSDestructibleObject>* object = JSCallbackObject<JSDestructibleObject>::create(exec, exec->lexicalGlobalObject(), exec->lexicalGlobalObject()->callbackObjectStructure(), jsClass, data);
if (JSObject* prototype = jsClass->prototype(exec))
object->setPrototype(exec->globalData(), prototype);
......@@ -341,8 +341,8 @@ void* JSObjectGetPrivate(JSObjectRef object)
if (jsObject->inherits(&JSCallbackObject<JSGlobalObject>::s_info))
return jsCast<JSCallbackObject<JSGlobalObject>*>(jsObject)->getPrivate();
if (jsObject->inherits(&JSCallbackObject<JSNonFinalObject>::s_info))
return jsCast<JSCallbackObject<JSNonFinalObject>*>(jsObject)->getPrivate();
if (jsObject->inherits(&JSCallbackObject<JSDestructibleObject>::s_info))
return jsCast<JSCallbackObject<JSDestructibleObject>*>(jsObject)->getPrivate();
return 0;
}
......@@ -355,8 +355,8 @@ bool JSObjectSetPrivate(JSObjectRef object, void* data)
jsCast<JSCallbackObject<JSGlobalObject>*>(jsObject)->setPrivate(data);
return true;
}
if (jsObject->inherits(&JSCallbackObject<JSNonFinalObject>::s_info)) {
jsCast<JSCallbackObject<JSNonFinalObject>*>(jsObject)->setPrivate(data);
if (jsObject->inherits(&JSCallbackObject<JSDestructibleObject>::s_info)) {
jsCast<JSCallbackObject<JSDestructibleObject>*>(jsObject)->setPrivate(data);
return true;
}
......@@ -372,8 +372,8 @@ JSValueRef JSObjectGetPrivateProperty(JSContextRef ctx, JSObjectRef object, JSSt
Identifier name(propertyName->identifier(&exec->globalData()));
if (jsObject->inherits(&JSCallbackObject<JSGlobalObject>::s_info))
result = jsCast<JSCallbackObject<JSGlobalObject>*>(jsObject)->getPrivateProperty(name);
else if (jsObject->inherits(&JSCallbackObject<JSNonFinalObject>::s_info))
result = jsCast<JSCallbackObject<JSNonFinalObject>*>(jsObject)->getPrivateProperty(name);
else if (jsObject->inherits(&JSCallbackObject<JSDestructibleObject>::s_info))
result = jsCast<JSCallbackObject<JSDestructibleObject>*>(jsObject)->getPrivateProperty(name);
return toRef(exec, result);
}
......@@ -388,8 +388,8 @@ bool JSObjectSetPrivateProperty(JSContextRef ctx, JSObjectRef object, JSStringRe
jsCast<JSCallbackObject<JSGlobalObject>*>(jsObject)->setPrivateProperty(exec->globalData(), name, jsValue);
return true;
}
if (jsObject->inherits(&JSCallbackObject<JSNonFinalObject>::s_info)) {
jsCast<JSCallbackObject<JSNonFinalObject>*>(jsObject)->setPrivateProperty(exec->globalData(), name, jsValue);
if (jsObject->inherits(&JSCallbackObject<JSDestructibleObject>::s_info)) {
jsCast<JSCallbackObject<JSDestructibleObject>*>(jsObject)->setPrivateProperty(exec->globalData(), name, jsValue);
return true;
}
return false;
......@@ -405,8 +405,8 @@ bool JSObjectDeletePrivateProperty(JSContextRef ctx, JSObjectRef object, JSStrin
jsCast<JSCallbackObject<JSGlobalObject>*>(jsObject)->deletePrivateProperty(name);
return true;
}
if (jsObject->inherits(&JSCallbackObject<JSNonFinalObject>::s_info)) {
jsCast<JSCallbackObject<JSNonFinalObject>*>(jsObject)->deletePrivateProperty(name);
if (jsObject->inherits(&JSCallbackObject<JSDestructibleObject>::s_info)) {
jsCast<JSCallbackObject<JSDestructibleObject>*>(jsObject)->deletePrivateProperty(name);
return true;
}
return false;
......
......@@ -131,8 +131,8 @@ bool JSValueIsObjectOfClass(JSContextRef ctx, JSValueRef value, JSClassRef jsCla
if (JSObject* o = jsValue.getObject()) {
if (o->inherits(&JSCallbackObject<JSGlobalObject>::s_info))
return jsCast<JSCallbackObject<JSGlobalObject>*>(o)->inherits(jsClass);
if (o->inherits(&JSCallbackObject<JSNonFinalObject>::s_info))
return jsCast<JSCallbackObject<JSNonFinalObject>*>(o)->inherits(jsClass);
if (o->inherits(&JSCallbackObject<JSDestructibleObject>::s_info))
return jsCast<JSCallbackObject<JSDestructibleObject>*>(o)->inherits(jsClass);
}
return false;
}
......
......@@ -57,7 +57,7 @@ void JSWeakObjectMapSet(JSContextRef ctx, JSWeakObjectMapRef map, void* key, JSO
JSObject* obj = toJS(object);
if (!obj)
return;
ASSERT(obj->inherits(&JSCallbackObject<JSGlobalObject>::s_info) || obj->inherits(&JSCallbackObject<JSNonFinalObject>::s_info));
ASSERT(obj->inherits(&JSCallbackObject<JSGlobalObject>::s_info) || obj->inherits(&JSCallbackObject<JSDestructibleObject>::s_info));
map->map().set(exec->globalData(), key, obj);
}
......
This diff is collapsed.
......@@ -533,6 +533,7 @@ javascriptcore_sources += \
Source/JavaScriptCore/runtime/JSCell.h \
Source/JavaScriptCore/runtime/JSDateMath.cpp \
Source/JavaScriptCore/runtime/JSDateMath.h \
Source/JavaScriptCore/runtime/JSDestructibleObject.h \
Source/JavaScriptCore/runtime/JSFunction.cpp \
Source/JavaScriptCore/runtime/JSFunction.h \
Source/JavaScriptCore/runtime/JSBoundFunction.cpp \
......
......@@ -26,7 +26,7 @@
#ifndef JSCTypedArrayStubs_h
#define JSCTypedArrayStubs_h
#include "JSObject.h"
#include "JSDestructibleObject.h"
#include "ObjectPrototype.h"
#include <wtf/Float32Array.h>
#include <wtf/Float64Array.h>
......@@ -42,9 +42,9 @@
namespace JSC {
#define TYPED_ARRAY(name, type) \
class JS##name##Array : public JSNonFinalObject { \
class JS##name##Array : public JSDestructibleObject { \
public: \
typedef JSNonFinalObject Base; \
typedef JSDestructibleObject Base; \
static JS##name##Array* create(JSC::Structure* structure, JSGlobalObject* globalObject, PassRefPtr<name##Array> impl) \
{ \
JS##name##Array* ptr = new (NotNull, JSC::allocateCell<JS##name##Array>(globalObject->globalData().heap)) JS##name##Array(structure, globalObject, impl); \
......
......@@ -841,6 +841,10 @@
RelativePath="..\..\runtime\JSDateMath.h"
>
</File>
<File
RelativePath="..\..\runtime\JSDestructibleObject.h"
>
</File>
<File
RelativePath="..\..\runtime\JSFunction.cpp"
>
......
......@@ -708,6 +708,7 @@
C225494315F7DBAA0065E898 /* SlotVisitor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C225494215F7DBAA0065E898 /* SlotVisitor.cpp */; };
C22B31B9140577D700DB475A /* SamplingCounter.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F77008E1402FDD60078EB39 /* SamplingCounter.h */; settings = {ATTRIBUTES = (Private, ); }; };
C240305514B404E60079EB64 /* CopiedSpace.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C240305314B404C90079EB64 /* CopiedSpace.cpp */; };
C25177F81607D0A6000A233C /* JSDestructibleObject.h in Headers */ = {isa = PBXBuildFile; fileRef = C25177F71607D0A6000A233C /* JSDestructibleObject.h */; settings = {ATTRIBUTES = (Private, ); }; };
C25F8BCD157544A900245B71 /* IncrementalSweeper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C25F8BCB157544A900245B71 /* IncrementalSweeper.cpp */; };
C25F8BCE157544A900245B71 /* IncrementalSweeper.h in Headers */ = {isa = PBXBuildFile; fileRef = C25F8BCC157544A900245B71 /* IncrementalSweeper.h */; settings = {ATTRIBUTES = (Private, ); }; };
C2B916C214DA014E00CBAC86 /* MarkedAllocator.h in Headers */ = {isa = PBXBuildFile; fileRef = C2B916C114DA014E00CBAC86 /* MarkedAllocator.h */; settings = {ATTRIBUTES = (Private, ); }; };
......@@ -1481,6 +1482,7 @@
C21122E015DD9AB300790E3A /* MarkStackInlineMethods.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MarkStackInlineMethods.h; sourceTree = "<group>"; };
C225494215F7DBAA0065E898 /* SlotVisitor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SlotVisitor.cpp; sourceTree = "<group>"; };
C240305314B404C90079EB64 /* CopiedSpace.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CopiedSpace.cpp; sourceTree = "<group>"; };
C25177F71607D0A6000A233C /* JSDestructibleObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSDestructibleObject.h; sourceTree = "<group>"; };
C25F8BCB157544A900245B71 /* IncrementalSweeper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IncrementalSweeper.cpp; sourceTree = "<group>"; };
C25F8BCC157544A900245B71 /* IncrementalSweeper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IncrementalSweeper.h; sourceTree = "<group>"; };
C2B916C114DA014E00CBAC86 /* MarkedAllocator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MarkedAllocator.h; sourceTree = "<group>"; };
......@@ -2043,6 +2045,7 @@
7EF6E0BB0EB7A1EC0079AFAF /* runtime */ = {
isa = PBXGroup;
children = (
C25177F71607D0A6000A233C /* JSDestructibleObject.h */,
0F0CD4C315F6B6B50032F1C0 /* SparseArrayValueMap.cpp */,
0F0CD4C015F1A6040032F1C0 /* PutDirectIndexMode.h */,
0FB7F38915ED8E3800F167B2 /* ArrayConventions.h */,
......@@ -2563,6 +2566,7 @@
86ADD1450FDDEA980006EEC2 /* ARMv7Assembler.h in Headers */,
C2EAD2FC14F0249800A4B159 /* CopiedAllocator.h in Headers */,
C2B916C214DA014E00CBAC86 /* MarkedAllocator.h in Headers */,
C25177F81607D0A6000A233C /* JSDestructibleObject.h in Headers */,
FE20CE9E15F04A9500DF3430 /* LLIntCLoop.h in Headers */,
C21122E215DD9AB300790E3A /* GCThreadSharedData.h in Headers */,
C2160FE715F7E95E00942DFC /* SlotVisitorInlineMethods.h in Headers */,
......
......@@ -2189,12 +2189,14 @@ public:
// It is NOT okay for the structure and the scratch register to be the same thing because if they are then the Structure will
// get clobbered.
template <typename ClassType, bool destructor, typename StructureType>
template <typename ClassType, MarkedBlock::DestructorType destructorType, typename StructureType>
void emitAllocateBasicJSObject(StructureType structure, GPRReg resultGPR, GPRReg scratchGPR, MacroAssembler::JumpList& slowPath)
{
MarkedAllocator* allocator = 0;
if (destructor)
allocator = &m_jit.globalData()->heap.allocatorForObjectWithDestructor(sizeof(ClassType));
if (destructorType == MarkedBlock::Normal)
allocator = &m_jit.globalData()->heap.allocatorForObjectWithNormalDestructor(sizeof(ClassType));
else if (destructorType == MarkedBlock::ImmortalStructure)
allocator = &m_jit.globalData()->heap.allocatorForObjectWithImmortalStructureDestructor(sizeof(ClassType));
else
allocator = &m_jit.globalData()->heap.allocatorForObjectWithoutDestructor(sizeof(ClassType));
......@@ -2216,7 +2218,7 @@ public:
template<typename T>
void emitAllocateJSFinalObject(T structure, GPRReg resultGPR, GPRReg scratchGPR, MacroAssembler::JumpList& slowPath)
{
return emitAllocateBasicJSObject<JSFinalObject, false>(structure, resultGPR, scratchGPR, slowPath);
return emitAllocateBasicJSObject<JSFinalObject, MarkedBlock::None>(structure, resultGPR, scratchGPR, slowPath);
}
#if USE(JSVALUE64)
......
......@@ -830,11 +830,6 @@ void Heap::addCompiledCode(ExecutableBase* executable)
m_compiledCode.append(executable);
}
bool Heap::isSafeToSweepStructures()
{
return !m_sweeper || m_sweeper->structuresCanBeSwept();
}
void Heap::didStartVMShutdown()
{
m_activityCallback->didStartVMShutdown();
......
......@@ -112,7 +112,8 @@ namespace JSC {
MarkedAllocator& firstAllocatorWithoutDestructors() { return m_objectSpace.firstAllocator(); }
MarkedAllocator& allocatorForObjectWithoutDestructor(size_t bytes) { return m_objectSpace.allocatorFor(bytes); }
MarkedAllocator& allocatorForObjectWithDestructor(size_t bytes) { return m_objectSpace.destructorAllocatorFor(bytes); }
MarkedAllocator& allocatorForObjectWithNormalDestructor(size_t bytes) { return m_objectSpace.normalDestructorAllocatorFor(bytes); }
MarkedAllocator& allocatorForObjectWithImmortalStructureDestructor(size_t bytes) { return m_objectSpace.immortalStructureDestructorAllocatorFor(bytes); }
CopiedAllocator& storageAllocator() { return m_storageSpace.allocator(); }
CheckedBoolean tryAllocateStorage(size_t, void**);
CheckedBoolean tryReallocateStorage(void**, size_t, size_t);
......@@ -168,7 +169,6 @@ namespace JSC {
void didAbandon(size_t);
bool isPagedOut(double deadline);
bool isSafeToSweepStructures();
void didStartVMShutdown();
private:
......@@ -184,9 +184,9 @@ namespace JSC {
template<typename T> friend void* allocateCell(Heap&);
template<typename T> friend void* allocateCell(Heap&, size_t);
void* allocateWithDestructor(size_t);
void* allocateWithoutDestructor(size_t);
void* allocateStructure(size_t);
void* allocateWithImmortalStructureDestructor(size_t); // For use with special objects whose Structures never die.
void* allocateWithNormalDestructor(size_t); // For use with objects that inherit directly or indirectly from JSDestructibleObject.
void* allocateWithoutDestructor(size_t); // For use with objects without destructors.
static const size_t minExtraCost = 256;
static const size_t maxExtraCost = 1024 * 1024;
......@@ -361,10 +361,16 @@ namespace JSC {
return forEachProtectedCell(functor);
}
inline void* Heap::allocateWithDestructor(size_t bytes)
inline void* Heap::allocateWithNormalDestructor(size_t bytes)
{
ASSERT(isValidAllocation(bytes));
return m_objectSpace.allocateWithDestructor(bytes);
return m_objectSpace.allocateWithNormalDestructor(bytes);
}
inline void* Heap::allocateWithImmortalStructureDestructor(size_t bytes)
{
ASSERT(isValidAllocation(bytes));
return m_objectSpace.allocateWithImmortalStructureDestructor(bytes);
}
inline void* Heap::allocateWithoutDestructor(size_t bytes)
......@@ -373,11 +379,6 @@ namespace JSC {
return m_objectSpace.allocateWithoutDestructor(bytes);
}
inline void* Heap::allocateStructure(size_t bytes)
{
return m_objectSpace.allocateStructure(bytes);
}
inline CheckedBoolean Heap::tryAllocateStorage(size_t bytes, void** outPtr)
{
return m_storageSpace.tryAllocate(bytes, outPtr);
......
......@@ -48,7 +48,6 @@ static const double sweepTimeMultiplier = 1.0 / sweepTimeTotal;
IncrementalSweeper::IncrementalSweeper(Heap* heap, CFRunLoopRef runLoop)
: HeapTimer(heap->globalData(), runLoop)
, m_currentBlockToSweepIndex(0)
, m_structuresCanBeSwept(false)
{
}
......@@ -72,7 +71,6 @@ void IncrementalSweeper::cancelTimer()
IncrementalSweeper::IncrementalSweeper(Heap* heap)
: HeapTimer(heap->globalData())
, m_currentBlockToSweepIndex(0)
, m_structuresCanBeSwept(false)
{
}
......@@ -119,10 +117,6 @@ void IncrementalSweeper::sweepNextBlock()
{
while (m_currentBlockToSweepIndex < m_blocksToSweep.size()) {
MarkedBlock* block = m_blocksToSweep[m_currentBlockToSweepIndex++];
if (block->onlyContainsStructures())
m_structuresCanBeSwept = true;
else
ASSERT(!m_structuresCanBeSwept);
if (!block->needsSweeping())
continue;
......@@ -139,14 +133,12 @@ void IncrementalSweeper::startSweeping(const HashSet<MarkedBlock*>& blockSnapsho
CopyFunctor functor(m_blocksToSweep);
m_globalData->heap.objectSpace().forEachBlock(functor);
m_currentBlockToSweepIndex = 0;
m_structuresCanBeSwept = false;
scheduleTimer();
}
void IncrementalSweeper::willFinishSweeping()
{
m_currentBlockToSweepIndex = 0;
m_structuresCanBeSwept = true;
m_blocksToSweep.clear();
if (m_globalData)
cancelTimer();
......@@ -156,7 +148,6 @@ void IncrementalSweeper::willFinishSweeping()
IncrementalSweeper::IncrementalSweeper(JSGlobalData* globalData)
: HeapTimer(globalData)
, m_structuresCanBeSwept(false)
{
}
......@@ -171,12 +162,10 @@ IncrementalSweeper* IncrementalSweeper::create(Heap* heap)
void IncrementalSweeper::startSweeping(const HashSet<MarkedBlock*>&)
{
m_structuresCanBeSwept = false;
}
void IncrementalSweeper::willFinishSweeping()
{
m_structuresCanBeSwept = true;
}
void IncrementalSweeper::sweepNextBlock()
......@@ -185,9 +174,4 @@ void IncrementalSweeper::sweepNextBlock()
#endif
bool IncrementalSweeper::structuresCanBeSwept()
{
return m_structuresCanBeSwept;
}
} // namespace JSC
......@@ -56,7 +56,6 @@ public:
void startSweeping(const HashSet<MarkedBlock*>& blockSnapshot);
virtual void doWork();
void sweepNextBlock();
bool structuresCanBeSwept();
void willFinishSweeping();
private:
......@@ -78,7 +77,6 @@ private:
IncrementalSweeper(JSGlobalData*);
#endif
bool m_structuresCanBeSwept;
};
} // namespace JSC
......
......@@ -30,17 +30,6 @@ bool MarkedAllocator::isPagedOut(double deadline)
inline void* MarkedAllocator::tryAllocateHelper(size_t bytes)
{
if (!m_freeList.head) {
if (m_onlyContainsStructures && !m_heap->isSafeToSweepStructures()) {
if (m_currentBlock) {
m_currentBlock->didConsumeFreeList();
m_currentBlock = 0;
}
// We sweep another random block here so that we can make progress
// toward being able to sweep Structures.
m_heap->sweeper()->sweepNextBlock();
return 0;
}
for (MarkedBlock*& block = m_blocksToSweep; block; block = block->next()) {
MarkedBlock::FreeList freeList = block->sweep(MarkedBlock::SweepToFreeList);
if (!freeList.head) {
......@@ -124,13 +113,13 @@ MarkedBlock* MarkedAllocator::allocateBlock(size_t bytes)
if (blockSize == MarkedBlock::blockSize) {
PageAllocationAligned allocation = m_heap->blockAllocator().allocate();
return MarkedBlock::create(allocation, m_heap, cellSize, m_cellsNeedDestruction, m_onlyContainsStructures);
return MarkedBlock::create(allocation, this, cellSize, m_destructorType);
}
PageAllocationAligned allocation = PageAllocationAligned::allocate(blockSize, MarkedBlock::blockSize, OSAllocator::JSGCHeapPages);
if (!static_cast<bool>(allocation))
CRASH();
return MarkedBlock::create(allocation, m_heap, cellSize, m_cellsNeedDestruction, m_onlyContainsStructures);
return MarkedBlock::create(allocation, this, cellSize, m_destructorType);
}
void MarkedAllocator::addBlock(MarkedBlock* block)
......
......@@ -23,8 +23,7 @@ public:
void reset();
void canonicalizeCellLivenessData();
size_t cellSize() { return m_cellSize; }
bool cellsNeedDestruction() { return m_cellsNeedDestruction; }
bool onlyContainsStructures() { return m_onlyContainsStructures; }
MarkedBlock::DestructorType destructorType() { return m_destructorType; }
void* allocate(size_t);
Heap* heap() { return m_heap; }
......@@ -32,7 +31,7 @@ public:
void addBlock(MarkedBlock*);
void removeBlock(MarkedBlock*);
void init(Heap*, MarkedSpace*, size_t cellSize, bool cellsNeedDestruction, bool onlyContainsStructures);
void init(Heap*, MarkedSpace*, size_t cellSize, MarkedBlock::DestructorType);
bool isPagedOut(double deadline);
......@@ -49,8 +48,7 @@ private:
MarkedBlock* m_blocksToSweep;
DoublyLinkedList<MarkedBlock> m_blockList;
size_t m_cellSize;
bool m_cellsNeedDestruction;
bool m_onlyContainsStructures;
MarkedBlock::DestructorType m_destructorType;
Heap* m_heap;
MarkedSpace* m_markedSpace;
};
......@@ -59,20 +57,18 @@ inline MarkedAllocator::MarkedAllocator()
: m_currentBlock(0)
, m_blocksToSweep(0)
, m_cellSize(0)
, m_cellsNeedDestruction(true)
, m_onlyContainsStructures(false)
, m_destructorType(MarkedBlock::None)
, m_heap(0)
, m_markedSpace(0)
{
}
inline void MarkedAllocator::init(Heap* heap, MarkedSpace* markedSpace, size_t cellSize, bool cellsNeedDestruction, bool onlyContainsStructures)
inline void MarkedAllocator::init(Heap* heap, MarkedSpace* markedSpace, size_t cellSize, MarkedBlock::DestructorType destructorType)
{
m_heap = heap;
m_markedSpace = markedSpace;
m_cellSize = cellSize;
m_cellsNeedDestruction = cellsNeedDestruction;
m_onlyContainsStructures = onlyContainsStructures;
m_destructorType = destructorType;
}
inline void* MarkedAllocator::allocate(size_t bytes)
......
......@@ -28,26 +28,26 @@
#include "IncrementalSweeper.h"
#include "JSCell.h"
#include "JSObject.h"
#include "JSDestructibleObject.h"
namespace JSC {
MarkedBlock* MarkedBlock::create(const PageAllocationAligned& allocation, Heap* heap, size_t cellSize, bool cellsNeedDestruction, bool onlyContainsStructures)
MarkedBlock* MarkedBlock::create(const PageAllocationAligned& allocation, MarkedAllocator* allocator, size_t cellSize, DestructorType destructorType)
{
return new (NotNull, allocation.base()) MarkedBlock(allocation, heap, cellSize, cellsNeedDestruction, onlyContainsStructures);
return new (NotNull, allocation.base()) MarkedBlock(allocation, allocator, cellSize, destructorType);
}
MarkedBlock::MarkedBlock(const PageAllocationAligned& allocation, Heap* heap, size_t cellSize, bool cellsNeedDestruction, bool onlyContainsStructures)
MarkedBlock::MarkedBlock(const PageAllocationAligned& allocation, MarkedAllocator* allocator, size_t cellSize, DestructorType destructorType)
: HeapBlock<MarkedBlock>(allocation)
, m_atomsPerCell((cellSize + atomSize - 1) / atomSize)
, m_endAtom(atomsPerBlock - m_atomsPerCell + 1)
, m_cellsNeedDestruction(cellsNeedDestruction)
, m_onlyContainsStructures(onlyContainsStructures)
, m_destructorType(destructorType)
, m_allocator(allocator)
, m_state(New) // All cells start out unmarked.
, m_weakSet(heap->globalData())
, m_weakSet(allocator->heap()->globalData())
{
ASSERT(heap);
ASSERT(allocator);
HEAP_LOG_BLOCK_STATE_TRANSITION(this);
}
......@@ -65,11 +65,11 @@ inline void MarkedBlock::callDestructor(JSCell* cell)
cell->zap();
}
template<MarkedBlock::BlockState blockState, MarkedBlock::SweepMode sweepMode, bool destructorCallNeeded>
template<MarkedBlock::BlockState blockState, MarkedBlock::SweepMode sweepMode, MarkedBlock::DestructorType dtorType>
MarkedBlock::FreeList MarkedBlock::specializedSweep()
{
ASSERT(blockState != Allocated && blockState != FreeListed);
ASSERT(destructorCallNeeded || sweepMode != SweepOnly);
ASSERT(!(dtorType == MarkedBlock::None && sweepMode == SweepOnly));
// This produces a free list that is ordered in reverse through the block.
// This is fine, since the allocation code makes no assumptions about the
......@@ -82,7 +82,7 @@ MarkedBlock::FreeList MarkedBlock::specializedSweep()
JSCell* cell = reinterpret_cast_ptr<JSCell*>(&atoms()[i]);
if (destructorCallNeeded && blockState != New)
if (dtorType != MarkedBlock::None && blockState != New)
callDestructor(cell);
if (sweepMode == SweepToFreeList) {
......@@ -103,21 +103,23 @@ MarkedBlock::FreeList MarkedBlock::sweep(SweepMode sweepMode)
m_weakSet.sweep();
if (sweepMode == SweepOnly && !m_cellsNeedDestruction)
if (sweepMode == SweepOnly && m_destructorType == MarkedBlock::None)
return FreeList();
if (m_cellsNeedDestruction)
return sweepHelper<true>(sweepMode);
return sweepHelper<false>(sweepMode);
if (m_destructorType == MarkedBlock::ImmortalStructure)
return sweepHelper<MarkedBlock::ImmortalStructure>(sweepMode);
if (m_destructorType == MarkedBlock::Normal)
return sweepHelper<MarkedBlock::Normal>(sweepMode);
return sweepHelper<MarkedBlock::None>(sweepMode);
}
template<bool destructorCallNeeded>
template<MarkedBlock::DestructorType dtorType>
MarkedBlock::FreeList MarkedBlock::sweepHelper(SweepMode sweepMode)
{
switch (m_state) {
case New:
ASSERT(sweepMode == SweepToFreeList);
return specializedSweep<New, SweepToFreeList, destructorCallNeeded>();
return specializedSweep<New, SweepToFreeList, dtorType>();
case FreeListed: