What data does a TObject contain?
Asked Answered
N

3

9

TObject.InstanceSize returns 8, yet TObject doesn't declare any data members. According to the implementation of TObject.ClassType, the first 4 bytes can be explained as a pointer to the object's TClass metadata. Anyone know what the other 4 bytes of overhead are there for?

EDIT: Apparently this is specific to D2009. In older versions, it's only 4 bytes.

Nola answered 24/3, 2009 at 20:1 Comment(0)
T
12

In Delphi 2009, there is the ability to have a reference to a synchronization monitor. See:

class function TMonitor.GetFieldAddress(AObject: TObject): PPMonitor;
class function TMonitor.GetMonitor(AObject: TObject): PMonitor;

...in System.pas

Also, there is still a pointer to the VMT. (Virtual Method Table.) From Delphi in a Nutshell:

The TObject class declares several methods and one special, hidden field to store a reference to the object's class. This hidden field points to the class's virtual method table (VMT). Every class has a unique VMT and all objects of that class share the class's VMT.

Terrain answered 24/3, 2009 at 20:12 Comment(8)
That's the same thing, actually. A class's TClass reference points to its VMT. So it's the same 4 bytes. What are the other 4?Nola
(It's worth noting that that book was written 9 years ago. Maybe there was only one hidden field back then. Now there appears to be two of them.)Nola
There's also a synchronization monitor in D2009. I'll update.Terrain
Oh, is that specific to D2009? Hmm... interesting. If I'm reading this right, it looks like the last 4 bytes for the TMonitor come after the object's data, whereas the TClass pointer comes before it. Is that right?Nola
Looks like was added in D2009: blogs.embarcadero.com/abauer/2008/02/19/38856 See links in that post for full details.Terrain
I wrote a longer explanation of this here: blogs.teamb.com/craigstuntz/2009/03/25/38138Terrain
@CraigStuntz - there is some kind of backup of that article?Pettitoes
@rigel community.embarcadero.com/blogs/entry/…Terrain
D
3

An object contains entries for all its fields, plus extra space to hold a pointer to the virtual-method table. The VMT holds more than just virtual-method pointers. I explain more about the VMT at my Web site, including a diagram.

Apparently, Delphi 2009 introduces another hidden field in addition to the VMT pointer to hold the synchronization monitor. You can determine whether it is added at the beginning or at the end of the class with some simple code:

type
  TTest = class
    FField: Integer;
  end;

var
  obj: TTest;
  ObjAddr, FieldAddr: Cardinal;
begin
  Assert(TTest.InstanceSize = 12);
  obj := TTest.Create;
  ObjAddr := Cardinal(obj);
  FieldAddr := Cardinal(@(obj.FField));
  writeln(FieldAddr - ObjAddr);
end.

If it prints the value 4, then the monitor field must be at the end of the object because 4 only accounts for the size of the VMT pointer. If it prints the value 8, then the monitor field must be at the start, adjacent to the VMT pointer.

I expect you'll find the monitor at the start. Otherwise, it means that the layout of the descendant object isn't simply the layout of the base object with all the new fields appended. It would mean the offset of the monitor field depends on the run-time type of the object, and that makes the implementation more complicated.

When a class implements an interface, the object layout includes more hidden fields. The fields contain pointers to the object's interface-reference value. When you have an IUnknown reference to an object, the pointer it holds isn't the same as the pointer to the object's VMT field, which is what you have with an ordinary object reference. The IUnknown pointer value will be the address of the hidden field. I've written more about the layout of classes that implement interfaces.

Dazzle answered 24/3, 2009 at 21:0 Comment(7)
Nope. GetInterfaceTable is a class function based off an offset from the VMT location. Take a look at the implementation of TMonitor.GetFieldAddress. Looks like it's dependent on the run-time type, exactly like you described.Nola
GetInterfaceTable fetches something different, separate from the interface reference. The interface table is shared by all instances of a class, just like the VMT. The interface reference isn't shared by other instances. Read my article for more about the layout of interfaced classes.Dazzle
I can't check the source for TMonitor.GetFieldAddress; I don't have Delphi 2009.Dazzle
Interesting. So each interface adds another hidden pointer. Even so, TObject itself doesn't implement any interfaces. But that's a cool fact to know. Thanks!Nola
The monitor reference is always at the end of the instance. It is added to the size of the instance after the class is done being laid out.Gerfalcon
Yeah, thought so. Any particular reason for that?Nola
It doesn't change the existing object layout so anything that depended upon a particular object layout would still work. For example, you can still create a COM interface using a class and that requires a certain class instance layout.Gerfalcon
L
-1

Just in case somebody is wondering why Craig Stuntz' answer was accpepted, see his last comment on that answer:

Looks like was added in D2009: http://blogs.embarcadero.com/abauer/2008/02/19/38856 See links in that post for full details.

Link no longer available, but the wayback-machine has it:

https://web.archive.org/web/20160409224957/blogs.embarcadero.com/abauer/2008/02/19/38856

Lovell answered 25/3, 2009 at 6:40 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.