Skip to content
  • Allison Karlitskaya's avatar
    gtype: put private data before the instance · 31fde567
    Allison Karlitskaya authored
    Classically, a GTypeInstance has had the following layout:
    
     [[[[GTypeInstance] GObject] TypeA] TypeB] [TypeAPrivate] [TypeBPrivate]
    
    where TypeB is a subclass of TypeA which is a GObject.  Both TypeA and
    TypeB use pivate data.
    
    The main problem with this approach is that the offset between a pointer
    to an instance of TypeA and the TypeAPrivate is not constant: it changes
    depending on the depth of derivation and the size of the instance
    structures of the derived types.  For example, changing the size of the
    TypeB structure in the above example would push the TypeAPrivate further
    along.
    
    This complicates the implementation of g_type_instance_get_private().
    In particular, during object construction when the class pointer to the
    'complete type' of the object is not yet stored in the header of the
    GTypeInstance, we need a lookup table in order to be able to implement
    g_type_instance_get_private() accurately.
    
    We can avoid this problem by storing the private data before the
    structures, in reverse order, like so:
    
      [TypeBPrivate] [TypeAPrivate] [[[[GTypeInstance] GObject] TypeA] TypeB]
    
    Now the distance between TypeA and TypeAPrivate depends only on the size
    of GObject and GTypeInstance, which are static.  Even in the case of
    TypeB, the distance is not statically known but can be determined at
    runtime and is constant (because we will know the size of TypeAPrivate
    by the time we initialise TypeB and it won't change).
    
    This approach requires a slighty dirty trick: allocating extra memory
    _before_ the pointer we return from g_type_create_instance().  The main
    problem with this is that it will cause valgrind to behave very badly,
    reporting almost everything as "possibly lost".
    
    We can correct for this by including a few valgrind client requests in
    order to inform it that the start of the GTypeInstance should be
    considered a block of memory and that pointers to it should mean that
    this block is reachable.  In order to make the private data reachable,
    we also declare it as a block and include an extra pointer from the end
    of the primary block pointing back at it.  All of this is only done if
    we are running under Valgrind.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=698595
    31fde567