Faking constructors! An overview of object layout.
Christopher Wright
dhasenan at gmail.com
Sun Dec 2 19:00:57 PST 2007
I can fake constructors so they work as long as you don't cast to
interfaces.
The way Walter has casting to interfaces is pretty clever. An object is
laid out in memory like so:
vtbl ptr
guts
The guts are laid out as follows:
super.guts
this.tupleof
interface-0
interface-1...
interface-n is a pointer to an Interface struct. (This seems to be the
only way of accessing these structs.)
Then, in order to cast something to interface n, you just increment the
pointer to interface-n.
The awkward part is finding if you can cast to a particular interface,
since the interface array for each type doesn't contain the interfaces
that base classes implement. You have to go through each interface that
this class implements directly to see if they are or inherit from the
target, and you have to repeat that for each base class up to Object.
This means that, in order to fake constructors, you have to do something
like:
// (public domain)
T create(T)() {
void** _this = cast(void**)malloc(__traits(classInstanceSize, T));
*_this = T.classinfo.vtbl.ptr;
setInterfaces(_this, T.classinfo);
T ret = *cast(T*)&this;
// gc.setTypeInfo might do this
if (typeid(T).flags == 1)
gc.hasPointers(_this);
else
gc.hasNoPointers(_this);
// call constructor?
return ret;
}
void setInterfaces(void** _this, ClassInfo type) {
if (type.base !is null) {
setInterfaces(_this, type.base);
}
foreach (iface; type.interfaces) {
// This should work but doesn't: according to the spec, for an
// interface, vtbl[0] is a ptr to the Interface struct, but it's
// not, which means the only way to get the Interface ptr is by
// using a constructor -- begging the question.
auto ptr = iface.classinfo.vtbl[0];
*(_this + (iface.offset / (void*).sizeof)) = ptr;
}
}
I had to reverse engineer this. Don't let this happen to you! Now that
there exists <http://digitalmars.com/d/phobos/object.html>, you need
never do this again! Just four easy payments of $19.95.
Well, okay, the spec doesn't say straight out that Classinfo.interfaces
only includes those immediately implemented by this class. Other than
that, it's in the spec.
I thought this might be useful, in case someone else is doing stuff with
proxying objects and the like.
More information about the Digitalmars-d-learn
mailing list