WIP: fast replacement for rb_gc_register_address/rb_gc_unregister_address.

This commit is contained in:
Matthias Koefferlein 2017-06-05 23:26:10 +02:00
parent 1bc0243c0a
commit a5d9bbb3d1
5 changed files with 192 additions and 12 deletions

View File

@ -1356,6 +1356,9 @@ rba_init (RubyInterpreterPrivateData *d)
{
VALUE module = rb_define_module ("RBA");
// initialize the locked object vault as a fast replacement for rb_gc_register_address/rb_gc_unregister_address.
rba::make_locked_object_vault (module);
// save all constants for later (we cannot declare them while we are still producing classes
// because of the enum representative classes and enum constants are important)
std::vector <RubyConstDescriptor> constants;

View File

@ -33,6 +33,131 @@
namespace rba
{
// --------------------------------------------------------------------------
// Implementation of the locked object vault
class LockedObjectVault
{
public:
static void init (VALUE module, const char *name);
LockedObjectVault ();
~LockedObjectVault ();
static LockedObjectVault *instance ()
{
return mp_instance;
}
void add (VALUE object);
void remove (VALUE object);
void mark_this ();
private:
std::set<VALUE> m_objects;
static VALUE m_klass;
static VALUE m_instance;
static LockedObjectVault *mp_instance;
static void free (void *p);
static void mark (void *p);
static VALUE alloc (VALUE klass);
};
VALUE LockedObjectVault::m_klass = Qnil;
VALUE LockedObjectVault::m_instance = Qnil;
LockedObjectVault *LockedObjectVault::mp_instance = 0;
LockedObjectVault::LockedObjectVault ()
{
mp_instance = this;
}
LockedObjectVault::~LockedObjectVault ()
{
if (mp_instance == this) {
mp_instance = 0;
}
}
void
LockedObjectVault::add (VALUE object)
{
m_objects.insert (object);
}
void
LockedObjectVault::remove (VALUE object)
{
m_objects.erase (object);
}
void
LockedObjectVault::mark_this ()
{
for (std::set<VALUE>::iterator o = m_objects.begin (); o != m_objects.end (); ++o) {
rb_gc_mark (*o);
}
}
void
LockedObjectVault::mark (void *p)
{
((LockedObjectVault *) p)->mark_this ();
}
void
LockedObjectVault::free (void *p)
{
delete ((LockedObjectVault *) p);
}
VALUE
LockedObjectVault::alloc (VALUE klass)
{
tl_assert (TYPE (klass) == T_CLASS);
LockedObjectVault *vault = new LockedObjectVault ();
return Data_Wrap_Struct (klass, &LockedObjectVault::mark, &LockedObjectVault::free, vault);
}
void
LockedObjectVault::init (VALUE module, const char *name)
{
if (m_instance != Qnil) {
return;
}
m_klass = rb_define_class_under (module, name, rb_cObject);
rb_define_alloc_func (m_klass, LockedObjectVault::alloc);
m_instance = rba_class_new_instance_checked (0, 0, m_klass);
rb_gc_register_address (&m_instance);
}
void
make_locked_object_vault (VALUE module)
{
LockedObjectVault::init (module, "RBALockedObjectVault");
}
void
gc_lock_object (VALUE value)
{
if (LockedObjectVault::instance ()) {
LockedObjectVault::instance ()->add (value);
}
}
void
gc_unlock_object (VALUE value)
{
if (LockedObjectVault::instance ()) {
LockedObjectVault::instance ()->remove (value);
}
}
// --------------------------------------------------------------------------
/**
@ -260,7 +385,7 @@ Proxy::detach ()
gsi_object->status_changed_event ().remove (this, &Proxy::object_status_changed);
}
if (!m_owned && m_self != Qnil) {
rb_gc_unregister_address (&m_self);
gc_unlock_object (m_self);
}
}
@ -442,7 +567,7 @@ Proxy::release ()
if (!m_owned) {
if (cls->is_managed () && m_self != Qnil) {
rb_gc_unregister_address (&m_self);
gc_unlock_object (m_self);
}
m_owned = true;
}
@ -475,7 +600,7 @@ Proxy::keep_internal ()
m_owned = false;
tl_assert (m_self != Qnil);
if (m_cls_decl->is_managed ()) {
rb_gc_register_address (&m_self);
gc_lock_object (m_self);
}
}
}
@ -522,7 +647,7 @@ Proxy::set (void *obj, bool owned, bool const_ref, bool can_destroy, VALUE self)
gsi_object->status_changed_event ().add (this, &Proxy::object_status_changed);
if (! m_owned) {
rb_gc_register_address (&m_self);
gc_lock_object (m_self);
}
}

View File

@ -198,6 +198,31 @@ VALUE ruby_cls (const gsi::ClassBase *cls);
*/
bool is_registered (const gsi::ClassBase *gsi_cls);
/**
* @brief Locks the Ruby object against destruction by the GC
*
* After calling this function, the object given by value is no longer
* managed by the GC. This is equivalent to rb_gc_register_address, but
* faster.
*/
void gc_lock_object (VALUE value);
/**
* @brief Unlocks the Ruby object against destruction by the GC
*
* After calling this function, the object given by value is no longer
* managed by the GC. This is equivalent to rb_gc_unregister_address, but
* faster.
*/
void gc_unlock_object (VALUE value);
/**
* @brief Makes the locked object vault required for gc_lock_object and gc_unlock_object
*
* This function needs to be called by the interpreter initially.
*/
void make_locked_object_vault (VALUE module);
}
#endif

View File

@ -47,12 +47,12 @@ public:
RubyBasedStringAdaptor (VALUE value)
{
m_string = rba_safe_string_value (value);
rb_gc_register_address (&m_string);
gc_lock_object (m_string);
}
~RubyBasedStringAdaptor ()
{
rb_gc_unregister_address (&m_string);
gc_unlock_object (m_string);
}
virtual const char *c_str () const
@ -691,12 +691,12 @@ struct reader<gsi::VoidType>
RubyBasedVariantAdaptor::RubyBasedVariantAdaptor (VALUE var)
: m_var (var)
{
rb_gc_register_address (&m_var);
gc_lock_object (m_var);
}
RubyBasedVariantAdaptor::~RubyBasedVariantAdaptor ()
{
rb_gc_unregister_address (&m_var);
gc_unlock_object (m_var);
}
tl::Variant RubyBasedVariantAdaptor::var () const
@ -739,12 +739,12 @@ void RubyBasedVectorAdaptorIterator::inc ()
RubyBasedVectorAdaptor::RubyBasedVectorAdaptor (VALUE array, const gsi::ArgType *ainner)
: mp_ainner (ainner), m_array (array)
{
rb_gc_register_address (&m_array);
gc_lock_object (m_array);
}
RubyBasedVectorAdaptor::~RubyBasedVectorAdaptor ()
{
rb_gc_unregister_address (&m_array);
gc_unlock_object (m_array);
}
gsi::VectorAdaptorIterator *RubyBasedVectorAdaptor::create_iterator () const
@ -815,12 +815,12 @@ void RubyBasedMapAdaptorIterator::inc ()
RubyBasedMapAdaptor::RubyBasedMapAdaptor (VALUE hash, const gsi::ArgType *ainner, const gsi::ArgType *ainner_k)
: mp_ainner (ainner), mp_ainner_k (ainner_k), m_hash (hash)
{
rb_gc_register_address (&m_hash);
gc_lock_object (m_hash);
}
RubyBasedMapAdaptor::~RubyBasedMapAdaptor()
{
rb_gc_unregister_address (&m_hash);
gc_unlock_object (m_hash);
}
gsi::MapAdaptorIterator *RubyBasedMapAdaptor::create_iterator () const

View File

@ -1075,6 +1075,33 @@ class DBLayout_TestClass < TestBase
end
# Slow cleanup test
def test_13
n = 1000
w = 10000
ly = RBA::Layout::new
l1 = ly.layer(1, 0)
top = ly.create_cell("TOP")
n.times do |ix|
$stdout.puts("#{ix}/#{n}")
$stdout.flush
n.times do |iy|
x = ix * w
y = iy * w
cell = ly.create_cell("X#{ix}Y#{iy}")
cell.shapes(l1).insert(RBA::Box::new(0, 0, w, w))
top.insert(RBA::CellInstArray::new(cell.cell_index, RBA::Trans::new(RBA::Point::new(ix * w, iy * w))))
end
end
# took forever:
ly._destroy
end
end
load("test_epilogue.rb")