Permalink
Browse files

Introduce correct types for Boehm GC

ASObject is derived from class gc, soall objects are allocated in garbage
collected memory.
std containers that stores pointer or smart references to objects uses
traceable_allocator: the GC knows about the memory but will not manage
it. This is good for testing, since only real leaks will be reported by
the GC, but it's actually wrong for production since objects linked in
cycles will not be freed by the GC. All containers should be moved to
gc_allocator.
There is a custom gc_traceable class declared is gc_support.h that is
used for classes that contains object pointers but do not need to be
GCed themselves. For example CairoTokenRenderer.
  • Loading branch information...
1 parent b17ea7a commit 97fbade2aa2a1cb33542c95ce6c05edc229dc93e @alexp-sssup alexp-sssup committed Apr 6, 2012
View
@@ -156,7 +156,7 @@ struct variable
class variables_map
{
public:
- std::multimap<tiny_string,variable> Variables;
+ std::multimap<tiny_string,variable,std::less<tiny_string>,traceable_allocator<std::pair<const tiny_string, variable>>> Variables;
typedef std::multimap<tiny_string,variable>::iterator var_iterator;
typedef std::multimap<tiny_string,variable>::const_iterator const_var_iterator;
std::vector<var_iterator> slots_vars;
@@ -205,7 +205,7 @@ class variables_map
class Manager
{
private:
- std::vector<ASObject*> available;
+ std::vector<ASObject*, traceable_allocator<ASObject*>> available;
uint32_t maxCache;
public:
Manager(uint32_t m):maxCache(m){}
@@ -219,8 +219,7 @@ enum METHOD_TYPE { NORMAL_METHOD=0, SETTER_METHOD=1, GETTER_METHOD=2 };
//for toPrimitive
enum TP_HINT { NO_HINT, NUMBER_HINT, STRING_HINT };
-
-class ASObject
+class ASObject: public gc
{
friend class Manager;
friend class ABCVm;
@@ -188,7 +188,7 @@ class ExternalCallEvent;
/**
* ExtCallback specialization for IFunctions
*/
-class DLL_PUBLIC ExtASCallback : public ExtCallback
+class DLL_PUBLIC ExtASCallback : public ExtCallback, public gc_traceable
{
public:
ExtASCallback(IFunction* _func) : func(_func), result(NULL), funcWasCalled(false) { func->incRef(); }
@@ -184,7 +184,7 @@ class ITextureUploadable
The base class for render jobs based on cairo
Stores an internal copy of the data to be rendered
*/
-class CairoRenderer: public ITextureUploadable, public IThreadJob
+class CairoRenderer: public ITextureUploadable, public IThreadJob, public gc_traceable
{
protected:
virtual ~CairoRenderer();
@@ -361,6 +361,11 @@ void RenderThread::init()
void RenderThread::worker()
{
+ GC_stack_base stackBase;
+ stackBase.mem_base = &stackBase;
+ int ret=GC_register_my_thread(&stackBase);
+ cerr << "RET " << ret << endl;
+ assert(ret==0);
setTLSSys(m_sys);
/* set TLS variable for getRenderThread() */
g_static_private_set(&renderThread, this, NULL);
@@ -452,6 +457,7 @@ void RenderThread::worker()
prevUploadJob->uploadFence();
for(auto i=uploadJobs.begin(); i != uploadJobs.end(); ++i)
(*i)->uploadFence();
+ GC_unregister_my_thread();
}
void RenderThread::deinit()
View
@@ -29,6 +29,7 @@
#include <iostream>
// TODO: This should be reworked to use CMake feature detection where possible
+#include "gc_support.h"
/* gettext support */
#include <locale.h>
#include <libintl.h>
View
@@ -257,7 +257,7 @@ int main(int argc, char* argv[])
SystemState::staticInit();
EngineData::startGTKMain();
//NOTE: see SystemState declaration
- SystemState* sys = new SystemState(fileSize);
+ SystemState* sys = new (NoGC) SystemState(fileSize);
ParseThread* pt = new ParseThread(f, sys);
setTLSSys(sys);
sys->setDownloadedPath(fileName);
@@ -37,9 +37,15 @@ EngineData::~EngineData()
/* gtk main loop handling */
static void gtk_main_runner()
{
+ GC_stack_base stackBase;
+ stackBase.mem_base = &stackBase;
+ int ret=GC_register_my_thread(&stackBase);
+ cerr << "RET " << ret << endl;
+ assert(ret==0);
gdk_threads_enter();
gtk_main();
gdk_threads_leave();
+ GC_unregister_my_thread();
}
Thread* EngineData::gtkThread = NULL;
View
@@ -1403,6 +1403,11 @@ void ABCContext::runScriptInit(unsigned int i, ASObject* g)
void ABCVm::Run(ABCVm* th)
{
+ GC_stack_base stackBase;
+ stackBase.mem_base = &stackBase;
+ int ret=GC_register_my_thread(&stackBase);
+ cerr << "RET " << ret << endl;
+ assert(ret==0);
//Spin wait until the VM is aknowledged by the SystemState
setTLSSys(th->m_sys);
while(getVm()!=th);
@@ -1478,6 +1483,10 @@ void ABCVm::Run(ABCVm* th)
//Flush the invalidation queue
th->m_sys->flushInvalidationQueue();
profile->accountTime(chronometer.checkpoint());
+ Locker l(th->event_queue_mutex);
+ //GC_enable();
+ GC_gcollect();
+ //GC_disable();
}
catch(LightsparkException& e)
{
@@ -1507,6 +1516,7 @@ void ABCVm::Run(ABCVm* th)
th->ex->clearAllGlobalMappings();
delete th->module;
}
+ GC_unregister_my_thread();
}
/* This breaks the lock on all enqueued events to prevent deadlocking */
View
@@ -432,7 +432,8 @@ friend class method_info;
//Event handling
volatile bool shuttingdown;
- std::deque<std::pair<_NR<EventDispatcher>,_R<Event> > > events_queue;
+ typedef std::pair<_NR<EventDispatcher>,_R<Event>> eventType;
+ std::deque<eventType, traceable_allocator<eventType>> events_queue;
void handleEvent(std::pair<_NR<EventDispatcher>,_R<Event> > e);
void signalEventWaiters();
void buildClassAndBindTag(const std::string& s, _R<DictionaryTag> t);
@@ -1285,7 +1285,7 @@ void ABCVm::getLex(call_context* th, int n)
{
multiname* name=th->context->getMultiname(n,th);
LOG(LOG_CALLS, _("getLex: ") << *name );
- vector<scope_entry>::reverse_iterator it=th->scope_stack.rbegin();
+ auto it=th->scope_stack.rbegin();
// o will be a reference owned by this function (or NULL). At
// the end the reference will be handed over to the runtime
// stack.
@@ -1353,7 +1353,7 @@ ASObject* ABCVm::findProperty(call_context* th, multiname* name)
{
LOG(LOG_CALLS, _("findProperty ") << *name );
- vector<scope_entry>::reverse_iterator it=th->scope_stack.rbegin();
+ auto it=th->scope_stack.rbegin();
bool found=false;
ASObject* ret=NULL;
for(;it!=th->scope_stack.rend();++it)
@@ -1388,7 +1388,7 @@ ASObject* ABCVm::findPropStrict(call_context* th, multiname* name)
{
LOG(LOG_CALLS, _("findPropStrict ") << *name );
- vector<scope_entry>::reverse_iterator it=th->scope_stack.rbegin();
+ auto it=th->scope_stack.rbegin();
bool found=false;
ASObject* ret=NULL;
@@ -1807,7 +1807,7 @@ void ABCVm::getDescendants(call_context* th, int n)
ASObject* obj=th->runtime_stack_pop();
//The name must be a QName
assert_and_throw(name->name_type==multiname::NAME_STRING);
- vector<_R<XML> > ret;
+ XML::XMLVector ret;
//TODO: support multiname and namespaces
if(obj->getClass()==Class<XML>::getClass())
{
@@ -1878,7 +1878,7 @@ void ABCVm::newClassRecursiveLink(Class_base* target, Class_base* c)
if(c->super)
newClassRecursiveLink(target, c->super.getPtr());
- const vector<Class_base*>& interfaces=c->getInterfaces();
+ const Class_base::interfacesVector& interfaces=c->getInterfaces();
for(unsigned int i=0;i<interfaces.size();i++)
{
LOG(LOG_CALLS,_("Linking with interface ") << interfaces[i]->class_name);
@@ -1935,7 +1935,8 @@ void ABCVm::newClass(call_context* th, int n)
ret->setDeclaredMethodByQName("toString",AS3,Class<IFunction>::getFunction(Class_base::_toString),NORMAL_METHOD,false);
- ret->class_scope=th->scope_stack;
+ assert(ret->class_scope.empty());
+ ret->class_scope.insert(ret->class_scope.end(),th->scope_stack.begin(),th->scope_stack.end());
LOG(LOG_CALLS,_("Building class traits"));
for(unsigned int i=0;i<th->context->classes[n].trait_count;i++)
@@ -2128,7 +2129,7 @@ ASObject* ABCVm::newFunction(call_context* th, int n)
method_info* m=&th->context->methods[n];
SyntheticFunction* f=Class<IFunction>::getSyntheticFunction(m);
- f->func_scope=th->scope_stack;
+ f->acquireScope(th->scope_stack);
//Bind the function to null, as this is not a class method
f->bind(NullRef,-1);
@@ -53,7 +53,7 @@ struct call_context
ABCContext* context;
uint32_t locals_size;
uint32_t max_stack;
- std::vector<scope_entry> scope_stack;
+ std::vector<scope_entry, traceable_allocator<scope_entry>> scope_stack;
int initialScopeStack;
method_info* mi;
/* This is the function's inClass that is currently executing. It is used
@@ -81,7 +81,7 @@ class Class_inherit:public Class_base
return tag || bindedToRoot;
}
//Closure stack
- std::vector<scope_entry> class_scope;
+ std::vector<scope_entry, traceable_allocator<scope_entry>> class_scope;
};
/* helper function: does Class<ASObject>::getInstances(), but solves forward declaration problem */
@@ -233,7 +233,7 @@ class DisplayObjectContainer: public InteractiveObject
protected:
void requestInvalidation();
//This is shared between RenderThread and VM
- std::list < _R<DisplayObject> > dynamicDisplayList;
+ std::list <_R<DisplayObject>, traceable_allocator<_R<DisplayObject>>> dynamicDisplayList;
//The lock should only be taken when doing write operations
//As the RenderThread only reads, it's safe to read without the lock
mutable Mutex mutexDisplayList;
@@ -628,7 +628,8 @@ friend class ParserThread;
private:
Spinlock framesLoadedLock;
uint32_t framesLoaded;
- std::map<uint32_t,_NR<IFunction> > frameScripts;
+ std::map<uint32_t,_NR<IFunction>, std::less<uint32_t>,
+ traceable_allocator<std::pair<const uint32_t,_NR<IFunction>>>> frameScripts;
std::vector<Scene_data> scenes;
public:
RunState state;
@@ -400,7 +400,7 @@ void EventDispatcher::buildTraits(ASObject* o)
void EventDispatcher::dumpHandlers()
{
- std::map<tiny_string,list<listener> >::iterator it=handlers.begin();
+ std::map<tiny_string, listenerList >::iterator it=handlers.begin();
for(;it!=handlers.end();++it)
LOG(LOG_INFO, it->first);
}
@@ -435,7 +435,7 @@ ASFUNCTIONBODY(EventDispatcher,addEventListener)
{
Locker l(th->handlersMutex);
//Search if any listener is already registered for the event
- list<listener>& listeners=th->handlers[eventName];
+ listenerList& listeners=th->handlers[eventName];
if(find(listeners.begin(),listeners.end(),make_pair(f,useCapture))!=listeners.end())
{
LOG(LOG_CALLS,_("Weird event reregistration"));
@@ -474,7 +474,7 @@ ASFUNCTIONBODY(EventDispatcher,removeEventListener)
{
Locker l(th->handlersMutex);
- map<tiny_string, list<listener> >::iterator h=th->handlers.find(eventName);
+ map<tiny_string, listenerList >::iterator h=th->handlers.find(eventName);
if(h==th->handlers.end())
{
LOG(LOG_CALLS,_("Event not found"));
@@ -554,7 +554,7 @@ void EventDispatcher::handleEvent(_R<Event> e)
check();
e->check();
Locker l(handlersMutex);
- map<tiny_string, list<listener> >::iterator h=handlers.find(e->type);
+ map<tiny_string, listenerList >::iterator h=handlers.find(e->type);
if(h==handlers.end())
{
LOG(LOG_CALLS,_("Not handled event ") << e->type);
@@ -564,7 +564,7 @@ void EventDispatcher::handleEvent(_R<Event> e)
LOG(LOG_CALLS, _("Handling event ") << h->first);
//Create a temporary copy of the listeners, as the list can be modified during the calls
- vector<listener> tmpListener(h->second.begin(),h->second.end());
+ vector<listener, traceable_allocator<listener>> tmpListener(h->second.begin(), h->second.end());
l.release();
//TODO: check, ok we should also bind the level
for(unsigned int i=0;i<tmpListener.size();i++)
@@ -287,7 +287,8 @@ class EventDispatcher: public ASObject, public IEventDispatcher
{
private:
Mutex handlersMutex;
- std::map<tiny_string,std::list<listener> > handlers;
+ typedef std::list<listener, traceable_allocator<listener>> listenerList;
+ std::map<tiny_string,listenerList> handlers;
public:
EventDispatcher();
void finalize();
@@ -47,7 +47,7 @@ class Capabilities: public ASObject
class ApplicationDomain: public ASObject
{
private:
- std::vector<Global*> globalScopes;
+ std::vector<Global*, traceable_allocator<Global*> > globalScopes;
public:
ApplicationDomain(){}
void finalize();
@@ -190,7 +190,8 @@ class Dictionary: public ASObject
{
friend class ABCVm;
private:
- std::map<_R<ASObject>,_R<ASObject> > data;
+ std::map<_R<ASObject>,_R<ASObject>,std::less<_R<ASObject>>,
+ traceable_allocator<std::pair<const _R<ASObject>, _R<ASObject>>>> data;
public:
Dictionary(){}
void finalize();
@@ -349,7 +349,7 @@ ASFUNCTIONBODY(Array, _reverse)
{
Array* th = static_cast<Array*>(obj);
- std::map<uint32_t, data_slot> tmp = std::map<uint32_t, data_slot>(th->data);
+ std::map<uint32_t, data_slot> tmp(th->data.begin(),th->data.end());
uint32_t size = th->size();
th->data.clear();
std::map<uint32_t, data_slot>::iterator it=tmp.begin();
@@ -46,7 +46,8 @@ friend class ABCVm;
CLASSBUILDABLE(Array);
protected:
uint64_t currentsize;
- std::map<uint32_t,data_slot> data;
+ std::map<uint32_t,data_slot,std::less<uint32_t>,
+ traceable_allocator<std::pair<const uint32_t, data_slot>>> data;
void outofbounds() const;
Array();
~Array();
@@ -152,7 +152,7 @@ ASFUNCTIONBODY(Vector,_concat)
Vector* ret= (Vector*)obj->getClass()->getInstance(true,NULL,0);
// copy values into new Vector
ret->vec.resize(th->size(), NULL);
- std::vector<ASObject*>::iterator it=th->vec.begin();
+ auto it=th->vec.begin();
uint32_t index = 0;
for(;it != th->vec.end();++it)
{
@@ -167,7 +167,7 @@ ASFUNCTIONBODY(Vector,_concat)
{
Vector* arg=static_cast<Vector*>(args[i]);
ret->vec.resize(index+arg->size(), NULL);
- std::vector<ASObject*>::iterator it=arg->vec.begin();
+ auto it=arg->vec.begin();
for(;it != arg->vec.end();++it)
{
if (*it)
@@ -438,7 +438,7 @@ ASFUNCTIONBODY(Vector, _reverse)
{
Vector* th = static_cast<Vector*>(obj);
- std::vector<ASObject*> tmp = std::vector<ASObject*>(th->vec);
+ std::vector<ASObject*> tmp(th->vec.begin(), th->vec.end());
uint32_t size = th->size();
th->vec.clear();
th->vec.resize(size, NULL);
@@ -30,7 +30,7 @@ class Vector: public ASObject
{
Type* vec_type;
bool fixed;
- std::vector<ASObject*> vec;
+ std::vector<ASObject*, traceable_allocator<ASObject*>> vec;
int capIndex(int i) const;
class sortComparatorWrapper
{
Oops, something went wrong.

0 comments on commit 97fbade

Please sign in to comment.