Wednesday, May 30, 2007

DN4DP#12: Record Helpers

This post continues the series of The Delphi Language Chapter teasers from Jon Shemitz’ .NET 2.0 for Delphi Programmers book. The previous post explained how destructors and Free works in .NET. This one covers record helpers.

Note that I do not get any royalties from the book and I highly recommend that you get your own copy – for instance at Amazon.

"Record Helpers

Just as you can have class helpers to inject methods for a specific class (and its descendants) you can now also declare record helpers for a specific record type (or any value type defined in a .NET assembly). The syntax and capability is basically the same as for class helpers, but with class replaced with record.

type
TMyRecord = record
Field: string;
procedure Foo;
end;

TMyRecordHelper = record helper for TMyRecord
procedure Bar;
end;


Note: The record helper feature is mostly undocumented in Delphi 2006. It is currently used in the Borland.Delphi.System unit to inject methods into the System types Decimal, DateTime and Double that would otherwise not be available on the Compact Framework platform."

DN4DP#11: The try-finally-Free pattern

This post continues the series of The Delphi Language Chapter teasers from Jon Shemitz’ .NET 2.0 for Delphi Programmers book. Last time we covered class helpers and why they were invented. This post looks in more detail at the TObjectHelper class helper and the Free method.

Note that I do not get any royalties from the book and I highly recommend that you get your own copy – for instance at Amazon.

"The try-finally-Free pattern

The Borland.Delphi.System unit declares the TObjectHelper class helper that injects methods like Free and ClassName into all classes (including FCL classes). The Free method is special and implements deterministic disposing of unmanaged resources by calling IDispose.Disposable (if it is implemented by the class).

procedure TObjectHelper.Free;
begin
if (Self <> nil) and (Self is IDisposable) then
begin
// ...
(Self as IDisposable).Dispose;
end;
end;

To complete the cycle, the compiler effectively transforms an overridden Destroy destructor into an implementation of the IDisposable interface.

type 
TFoo = class
public
destructor Destroy; override;
end;

This is transformed by the compiler into the equivalent of

type 
TFoo = class(TObject, IDisposable)
public
procedure IDisposable.Dispose = Destroy;
procedure Destroy;
end;

This means that the traditional Delphi pattern of calling Free to clean up and writing a destructor to implement the clean up will have the same semantics in .NET. The difference is that actually deallocating the memory allocated by objects is deferred to the garbage collector. It can be argued that if all your destructors do is freeing the memory of other nested objects, calling Free and implementing destructors in .NET is pure overhead. The counter-argument is that if any of the sub-objects implements a resource releasing IDisposable.Dispose (now or in the future), this is the correct way of doing things. "

DN4DP#10: With a little help from your friends

This post continues the series of The Delphi Language Chapter teasers from Jon Shemitz’ .NET 2.0 for Delphi Programmers book. Last time we looked at how you can import identifiers that happens to conflict with Pascal keywords. This post includes the section on class helpers.

Note that I do not get any royalties from the book and I highly recommend that you get your own copy – for instance at Amazon.

"With a little help from your friends

When Borland started to port the Delphi compiler, RTL and VCL to the .NET platform, they soon faced a problem. While the object model and naming conventions of the FCL classes and methods were strikingly similar with native Delphi, some common methods (such as Free and ClassName) were missing from the .NET classes. Basically, Borland had three options;

Not content with becoming a shadow, and not willing to break everybody’s existing, clean object oriented code, they decided to invent something. And they invented class helpers. A class helper is a compiler trick used to inject new members into an existing class and all its descendants.

With this solution TObject is defined as a type-alias for System.Object and it has an accompanying class helper, TObjectHelper, which injects[1] the missing methods into TObject and all its descendants. The effect is that the Free and ClassName methods are now available for all Delphi and .NET classes. Similar tricks have been done to implement VCL for .NET classes such as TPersistent, TComponent and Variant.

To define a class helper you use the syntax

type
TMyClassHelper = class helper(TBaseClassHelper) for TExternalClass
procedure NewInjectedMethod;
end;

where TBaseClassHelper is the name of an optional class helper that you inherit from. This is useful when you want to help an already helped class.

A class helper can contain instance methods, class methods and class fields, but you cannot add instance fields. This limitation can be circumvented by using a class var HashTable keyed by the Self instance implicitly received by the class helper methods. In some cases you can reuse the helped object's general storage mechanism. For instance, the TComponentHelper uses the Site property of Component to store the per-component properties Tag, Components and Owner.

Here is an excerpt from the ClassHelpers project that shows all the different kind of members that can be injected.

type 
TMyClassHelper = class helper(TObjectHelper) for TExternalClass
private
class constructor Create; overload;
class var
FNewClassVar: string;
public
constructor NewConstructor(const AName: string);
procedure NewInjectedMethod;
procedure NewVirtualMethod; virtual;
procedure NewDynamicMethod; dynamic;
class procedure NewClassMethod;
class procedure NewVirtualClassMethod; virtual;
class procedure NewClassStaticMethod; static;
property NewProperty: integer read GetNewProperty write SetNewProperty;
class property NewClassProperty: string read FNewClassVar
write SetNewClassProperty;
end;


Caution: In general, class helpers can be useful to close the gap between different platforms or component sets, but should normally not be used as a design element. If you have full control of a class, you should not inject methods into it by using a class helper; you should change the class itself (or derive from or aggregate it).





[1] For all the gory details, read Marcel van Brakel’s in-depth article Delphi for .NET Class Helpers Inside Out in The Delphi Magazine issue 108 (August 2004).




"


Update: C# has since (in the 3.0 beta version) adopted a similar technique called Extension Methods.

Saturday, May 19, 2007

DN4DP#9: Escaping keywords

This post continues the series of The Delphi Language Chapter teasers from Jon Shemitz’ .NET 2.0 for Delphi Programmers book. Last time we covered the internationalization of Pascal identifiers. This time we will see how you can use imported identifiers that conflict with Pascal keywords.

Note that I do not get any royalties from the book and I highly recommend that you get your own copy – for instance at Amazon.

"Escaping keywords

All programming languages have certain keywords reserved - meaning they cannot be used as user defined identifiers. However, since .NET is inherently a multi programming language platform, each language needs to have a mechanism to import and use any identifier.

In Delphi, you can prefix an identifier with an ampersand (&) to have it interpreted as an identifier and not a language keyword. All Delphi keywords (or reserved words) are listed in the online documentation.

If the keyword identifier is the name of a type, you can often avoid using the escape character by fully qualifying the type name with its namespace. From the EscapingKeywords project

var 
T1: &Type;
T2: System.Type;
A1: &Array;
A2: System.Array;

If the keyword identifier is a member of an instance you must use the escape character. For instance

var 
HR: HttpResponse;
begin
//...
HR.&End;

If you are in the mood you can even declare your own type or member identifiers that are keywords. One silly example is

type 
&resourcestring = string;
&Begin = class
&for: &resourcestring;
procedure &Goto(&if: &resourcestring; &is: &resourcestring);
function &End: &resourcestring;
end;




Tip:    The ampersand (&) escape can also be used to turn off Delphi's special mapping of the Create identifier to a constructor. To call a method called Create you must use &Create.


"

Friday, May 18, 2007

Use the full FastMM! Consider donating!

A few years ago, it would be interesting to ask what memory manager (MM) you are using in your Delphi projects. You had the old-in-the-tooth in-the-box 32-bit Delphi RTM MM that was the default MM in Delphi 2 through Delphi 7, simple wrappers around Win32 API HeapAlloc, freeware alternatives such as MultiMM, RecyclerMM, PSD, AAHpDeFr, Bucket, and commercial alternatives such as SmartHeap, Nexus MM and BigBrain.

The winner takes it all

Then (after many rounds in the FastCode newsgroups), Pierre le Riche's FastMM appeared as the winner - it is the best memory manager overall. It is a tricky balancing act of trying to achieve high performance, low memory usage, low fragmentation, good multi-thread performance, good multi-processor performance, and working well with all kinds of application behavior profiles. Batch programs, services, GUI programs, databases and web servers all have very different memory usage needs - a good memory manager needs to work well with all of them.

In most cases FastMM will be the best solution - and if not the best, it will be very close. As you know by now FastMM4 is the default MM in both Delphi 2006 and Delphi 2007. That is, it is a slightly reduced version that does not have the extended debug features that is available in the full version that you can download for free here. With the right defines in the FastMM4Options.inc file you can get full stack trace for memory leaks, detection of heap corruption, using freed blocks, calling virtual methods of freed objects, double frees and so on. If you are serious about finding and fixing problems in your projects early, you should use the full version with the debug options turned on during development and alpha testing.

Donations

We have been doing so for some time for our own products now - that's why I decided it was about time to give a little token of our appreciation back to Pierre. We used  the FastMM donation page on SourceForge to donate a symbolic amount - it is by no means proportional to the benefit we get from FastMM or the amount of work Pierre has put down, but hopefully it gives Pierre a good feeling ;).

I encourage each one of you to consider to do the same - at least after you have started to use FastMM and see the major benefits it gives.

You can make your donation here.

Wednesday, May 16, 2007

Hack#17: Virtual class variables, Part II

In Part I of this blog post we introduced the concept of virtual class variables - a feature currently (Delphi 2007) lacking from Object Pascal (and most other languages). We also covered a potential syntax and suggested some compiler implementation details. In this post we will continue by looking at some hacks to try and implement the functionality of virtual class fields manually by using some clever tricks and hacks. The original idea is Patrick van Logchem's.

Hacking a solution

While we wait for CodeGear to eventually implement (or not) support for these virtual class fields, what should we do? This is where my little email conversation with Patrick van Logchem of everyangle.com comes into play. From his original email to me: 

 [...] Anyway, I discovered Delphi got class variables since version 2005, but I needed something a bit more specific: Class-specific variables. This is not a standard language construct, because a class var is just another type of global; not much use in my case - I want this:

TClass1 =  class(TObject)
public
// written once, read _very_ frequently

class property Variable: Type;
end;

TClass2 = class(TClass1);
and then TClass1.Variable <> TClass2.Variable. In words: when declaring a variable of this kind, the class itself and  all its derived classes should have their own version of this  variable.

This matches exactly the virtual class vars we have been discussing in Part I. Not content with the missing language support, Patrick did what any true hacker would have done - he devised his own solution. Patrick continues:



I haven't found a clean language-construct for such a simple requirement, so I started hacking. To make this work, I (ab-)use a slot in the VMT as a variable! Here a slightly edited cut-'n-paste of our production code:

type
PClass = ^TClass;
// this class contains important meta-data,
// accessed _very_ frequently
TClassInfo = class(TObject);

TBasicObject = class(TObject)
strict private
procedure VMT_Placeholder1; virtual;
protected
class procedure SetClassInfo(const aClassInfo: TClassInfo);
public
class procedure InitVMTPlaceholders; virtual;
function GetClassInfo: TClassInfo; inline;
// Strange: Inlining of class methods doesn't work (yet)!
class function ClassGetClassInfo: TClassInfo; inline;
end;

PBasicObjectOverlay = ^RBasicObjectOverlay;
RBasicObjectOverlay = packed record
OurClassInfo: TClassInfo;
end;

procedure PatchCodeDWORD(Code: PDWORD; Value: DWORD);
// Self-modifying code - change one DWORD in the code segment
var
RestoreProtection, Ignore: DWORD;
begin
if VirtualProtect(Code, SizeOf(Code^), PAGE_EXECUTE_READWRITE,
RestoreProtection) then
begin
Code^ := Value;
VirtualProtect(Code, SizeOf(Code^), RestoreProtection, Ignore);
FlushInstructionCache(GetCurrentProcess, Code, SizeOf(Code^));
end;
end;

class procedure TBasicObject.InitVMTPlaceholders;
begin
// First, check if the VMT-mapping came thru the compiler alright :
if Pointer(ClassGetClassInfo) = Addr(TBasicObject.VMT_Placeholder1) then
begin
// Now, empty the variable default,
// very important for later code !
PatchCodeDWORD(@PBasicObjectOverlay(Self).OurClassInfo, DWORD(nil));

// Now check that we see a cleaned up variable :
Assert(ClassGetClassInfo = nil, 'Failed cleaning VMT of ' + ClassName);
end
else
// When there's no original content anymore, this initialization
// has already been done - there _has_ to be a nil here :
Assert(ClassGetClassInfo = nil,
'Illegal value when checking initialized VMT of ' + ClassName);
end;

function TBasicObject.GetClassInfo: TClassInfo;
begin
Result := PBasicObjectOverlay(PClass(Self)^).OurClassInfo;
end;

class function TBasicObject.ClassGetClassInfo: TClassInfo;
begin
Result := PBasicObjectOverlay(Self).OurClassInfo;
end;

class procedure TBasicObject.SetClassInfo(const aClassInfo: TClassInfo);
begin
PatchCodeDWORD(@PBasicObjectOverlay(Self).OurClassInfo, DWORD(aClassInfo));
end;

procedure TBasicObject.VMT_Placeholder1;
begin
// This method may never be called!
// It only exists to occupy a space in the VMT!
Assert(False);
// This line prevents warnings about unused symbols
// (until the compiler detects endless recursive loops)...
VMT_Placeholder1;
end;

initialization
// call this for any derived class too
TBasicObject.InitVMTPlaceholders;
end.

The nicest thing about this solution is, that an inlined call to GetClassInfo results in only 2 opcodes:

  MOV EAX, [EAX]    // Go from instance to VMT
MOV EAX, [EAX+12] // read from the VMT at some offset (!)

You can't get it any faster than that!


Yes, that does look like impressively fast code!


Analyzing the Hack


Lets pause a little and analyze exactly what Patrick's hack is doing. The first thing to note is that he introduces a base class, TBasicObject,  that all other classes that wants the per-class class storage should inherit from (directly or indirectly). The base class then does something peculiar - it declares a strict private virtual method (called VMT_Placeholder1) that can never be overridden. This is because it is never meant to be overridden - in fact it is not even intended to ever be called - it is only there to take up place and reserve a slot in the class' (and all derived classes') VMT (virtual method table - see here and here for details).


Reserving space in the VMT


Why would he want to waste space in the VMT? To reserve space that can be used to store per-class data, of course! The whole point of this exercise is to have the instance function GetClassInfo (and the corresponding class function ClassGetClassInfo) return an instance of a user defined class TClassInfo that contains per-class meta-data (class attributes á la .NET, if you like) useful to the programmer. Lets look closer at the implementation of this function.

function TBasicObject.GetClassInfo: TClassInfo;
begin
Result := PBasicObjectOverlay(PClass(Self)^).OurClassInfo;
end;

There is some funky looking type casts going on here. This is an instance function so the implicit Self parameter represents the TObject (or in this case, TBasicObject) instance that the method is being called on. As we already know, the first 4 bytes of the instance memory block contains a TClass - which is implemented as a pointer to the VMT of the class. The PClass(Self)^ cast first dereferences the instance pointer and picks up a copy of the VMT pointer. The VMT contains an array of the normal user-defined virtual methods of the class (at negative offsets we find the special TObject virtual methods and the magic VMT fields - details here).


Casting Magic


A TClass reference is opaque in the sense that you cannot explicitly dereference it in code - however the compiler does it all the time when you are calling virtual methods or accessing members such as ClassName. The code above takes the TClass value and casts it into a RBasicObjectOverlay record pointer. This record contains a single 4-byte field, OurClassInfo, that has the same type as the meta class object we want to access, TClassInfo. Since the VMT_Placeholder1 method is the first virtual method in TBasicObject, and since TBasicObject inherits from TObject (that has no "normal" (i.e. positive VMT offset) virtual methods), the OurClassInfo field access above just happens to match the VMT slot for VMT_Placeholder1. Got that?


Doing the compiler's work


The trouble is, of course, is that the VMT_Placeholder1 VMT slot does not contain the reference of a TClassInfo instance at all. Instead it contains the address of the virtual method implementation code (that will always be equal to @TBasicObject. VMT_Placeholder1 - being strict private, it cannot be overridden, remember?). So we will have to perform a little VMT patching again :-). (I told you this was a hack, right?). We'll divide this task in two parts - from the initialization section of all units that declare one or more TBasicObject descendants should be the code to clear the VMT slot so that it is ready for our purposes.

class procedure TBasicObject.InitVMTPlaceholders;
begin
// First, check if the VMT-mapping came thru the compiler alright :
if Pointer(ClassGetClassInfo) = Addr(TBasicObject.VMT_Placeholder1) then
begin
// Now, empty the variable default,
// very important for later code !
PatchCodeDWORD(@PBasicObjectOverlay(Self).OurClassInfo, DWORD(nil));

// Now check that we see a cleaned up variable :
Assert(ClassGetClassInfo = nil, 'Failed cleaning VMT of ' + ClassName);
end
else
// When there's no original content anymore, this initialization
// has already been done - there _has_ to be a nil here :
Assert(ClassGetClassInfo = nil,
'Illegal value when checking initialized VMT of ' + ClassName);
end;

initialization
// call this for any derived class too
TBasicObject.InitVMTPlaceholders;
end.

First there is some sanity checks, using Asserts, ensuring that the compiler generated value of the VMT slot we're going to patch matches our expectations. If the slot does not contain the static code address of the TBasicObject.VMT_Placeholder1 method, the method has either been overridden, not been compiled into a virtual method, or has received a different slot than we anticipated. Better safe than sorry.


Then we use the PatchCodeDWORD utility routine to do the actual dirty work of patching the VMT slot with a nil value (effectively clearing it). Again we check that the patching went well, raising an Assert exception if it didn't.

Creating a metainfo class


Ok, that's step one. The nil value is in fact assignment compatible as a TClassInfo reference, but you cannot store much data in a nil pointer ;). The next step is to actually create a TClassInfo instance and assign it to the now per-class variable slot we have made available in the VMT. This should only be done once per class - it can be done in the initialization section of the unit, or it could be done by some other startup code in the project. The assignment is done by calling the SetClassInfo class method. Here is a simple example where we have extended the application specific TClassInfo with a single integer field and a constructor to initialize it.

type
TClassInfo = class(TObject)
public
A: integer;
constructor Create(Value: integer);
end;

constructor TClassInfo.Create(Value: integer);
begin
inherited Create;
A := Value;
end;

initialization
TBasicObject.InitVMTPlaceholders;
TBasicObject.SetClassInfo(TClassInfo.Create(42));

Having looked at both the GetClassInfo function and the InitVMTPlaceholders method above, the implementation of SetClassInfo should not be surprising.

class procedure TBasicObject.SetClassInfo(const aClassInfo: TClassInfo);
begin
PatchCodeDWORD(@PBasicObjectOverlay(Self).OurClassInfo, DWORD(aClassInfo));
end;

This code patches the right VMT slot in the code segment with the instance reference of our per-class meta-data instance, TClassInfo. This should only be done once. After this the class-specific TClassInfo can be retrieved using the GetClassInfo function - and we can freely read and write the TClassInfo fields and properties - without any fear of triggering access violations. The TClassInfo instance lives in the dynamic heap, just like any other object instance.


Application level classes


Writing additional classes that supports these per-class TClassInfo variables is easy. Just derive the class from TBasicObject, call InitVMTPlaceholders for the class and assign a new TClassInfo instance using SetClassInfo. Lets rewrite the Apples & Oranges sample from Part I using this new hacking technique.

type
TFruitClassInfo = class(TClassInfo)
{unit} private
var FInstanceCount: integer;
end;
TFruit = class(TBasicObject)
protected
class function FruitClassInfo: TFruitClassInfo; inline;
public
constructor Create;
class function InstanceCount: integer;
end;
TApple = class(TFruit)
end;
TOrange = class(TFruit)
end;

constructor TFruit.Create;
begin
inherited Create;
Inc(FruitClassInfo.FInstanceCount);
end;

class function TFruit.FruitClassInfo: TFruitClassInfo;
begin
Result := ClassGetClassInfo as TFruitClassInfo;
end;

class function TFruit.InstanceCount: integer;
begin
Result := FruitClassInfo.FInstanceCount;
end;

initialization
TFruit.SetClassInfo(TFruitClassInfo.Create);
TApple.SetClassInfo(TFruitClassInfo.Create);
TOrange.SetClassInfo(TFruitClassInfo.Create);
end.

First notice that the code is much simpler now. The InstanceCount function is introduced and fully implemented by the TFruit class - the TApple and TOrange classes do no longer have to help implement it. Because the compiler does not support per-class variables, we see the presence of the hacking code in the initialization section. Note that I was lazy, skipping the checking and overwriting the VMT slot with nil (by calling InitVMTPlaceholders on each class). I like to live dangerously ;)).


We introduce a class that inherits from the generic TClassInfo and adds the variable we need for storage. To get type safe access to this TFruitClassInfo instance, I've also written a class function (FruitClassInfo) that returns it - performing an as-cast in the process.


ClassInfo Design


Depending on your application requirements and homogeneousness of your application classes, you might want to stick to a single TClassInfo class that contains all the fields and properties you need for all classes, or create specific TClassInfo descendents for some classes. Using a single shared class can produce faster code, because you don't need to do the type cast (you could "cheat" by using a faster hard-cast instead of the as-cast).


Inlining gotchas


In addition, the current inlining capability of the compiler seems to prevent class methods from being inlined. That's why you should call the instance method GetClassInfo from time-critical code - this assumes you have a live instance (rather than a static or dynamic class reference) to call it on. As you may be able to read below the striked-out font, I was incorrectly generalizing from one bad sample. In Patrick's code above the TBasicObject.InitVMTPlaceholders calls the inlined class function ClassGetClassInfo, and if you look closely at the generated assembly code, you'll find that the call is not inlined. After I while I spotted the reason; method implementation order. The implementation of an inlined routine must have been "seen" by the compiler before a call to it - otherwise the compiler will not be able to inline it. With the Delphi compiler explicitly (and deliberately) designed to be a single-pass compiler, this is only natural. The compiler cannot output code it hasn't seen yet. This might be biting other people too, so I've updated by inlining post here. If you move the InitVMTPlaceholders below the ClassGetClassInfo, the call will be inlined. Nice to get rid of that little misunderstanding ;).


The performance angle


As Patrick noted in his email, the combination of inlining, the GetClassInfo instance method and the ingenious, but hacky, casting allows the compiler to produce very efficient code when accessing the TClassInfo per-class metadata on an object instance.

ClassInfo := Apple.GetClassInfo;
// With inlinging and optimization enabled
// this compiles into

asm
mov eax,[eax]
mov eax,[eax]
end;

To go from an object instance to the object's class' metainfo TClassInfo only takes two machine code instructions and two memory accesses. The first converts from TObject to TClass, the second picks up the contents of the first VMT slot (i.e. index and offset 0). It doesn't get any faster than this - very impressive! ;)


A cleaner Hack?


I think Patrick knew he had a great hack up his sleeve, but at the same time something was bothering him. Could it be done differently, better or cleaner? It most probably couldn't be made faster. Quoting Patrick again:




But, this functionality shouldn't be so dirty as this to implement - do you know of a cleaner solution than this?


Well, it is possible to write a cleaner solution, but it would probably end up being slower. One way is to use a hash table with the TClass reference as the key - looking up the TClassInfo instance that corresponds to a specific class.


Depending on your point of view you could make it more or less dirty by not using a new VMT slot for this, but instead overwrite and reuse one of the unused magic VMT slots, like the one for automated methods, AutoTable, a relic from Delphi 2 that is generally not used anymore. Here is the VMT pseudo record layout taken from this post.

type
PVmt = ^TVmt;
TVmt = packed record
SelfPtr : TClass;
IntfTable : Pointer;
AutoTable : Pointer;
InitTable : Pointer;
TypeInfo : Pointer;
FieldTable : Pointer;
MethodTable : Pointer;
DynamicTable : Pointer;
ClassName : PShortString;
InstanceSize : PLongint;
Parent : PClass;
SafeCallException : PSafeCallException;
AfterConstruction : PAfterConstruction;
BeforeDestruction : PBeforeDestruction;
Dispatch : PDispatch;
DefaultHandler : PDefaultHandler;
NewInstance : PNewInstance;
FreeInstance : PFreeInstance;
Destroy : PDestroy;
{UserDefinedVirtuals: array[0..999] of procedure;}
end;

The advantage of re-using the AutoTable instead is:



  • You don't need the magic virtual method anymore
  • It is already initialized to nil (except for legacy Delphi 2 code)
  • You can thus use this trick for any class, not just those derived from your TBasicObject

This main disadvantage is that we're using a VMT slot that could conceivably be used, even though the automated section has been deprecated since Delphi 3.


Nostalgia: Delphi 2, COM and automated


It does have the drawback of not being compatible with old Delphi 2 code that uses the automated section. Back in those days, Delphi didn't support COM compatible interfaces - so it had to implement COM objects using abstract classes  with virtual methods that just happened to match COMs requirements. Since Delphi only supported single-inheritance of classes, only a single "interface" could be implemented by a class. If you wanted an object to support multiple COM interfaces, each interface had to be implemented by a separate Delphi class, and you had to manually write QueryInterface methods that would marshall properly between the "interface" (read class) implementations.


The automated section was needed to get late-bound Automation support. The compiler generates special RTTI for automated sections so that the Delphi 2 COM support code could translate method and property name strings into callable entities. In Delphi 3, the COM support was substantially improved with proper support for interfaces and automation support with dual-interfaces (dispinterface). In short, automation section in classes should (hopefully) be rare about now. It may be used by clever code just to get at the automated RTTI for other purposes (a custom script language implementation, for example).


If you need access to full RTTI for (public or published) methods and properties, I would recommend using the more complete and better documented $METHODINFO ON feature instead. Se my posts about that feature here, here, here and here.


A "cleaner" hack - overwriting AutoTable


Changing Patrick's original hack to overwrite the AutoTable in the existing VMT instead of overwriting the VMT slot of a new virtual method, simplifies the code considerably.

type
PClassVars = ^TClassVars;
TClassVars = class(TObject)
public
InstanceCount: integer;
end;

TBasicObject = class(TObject)
protected
class procedure SetClassVars(aClassVars: TClassVars);
public
class function GetClassVars: TClassVars; inline;
function ClassVars: TClassVars; inline;
end;

const
vmtClassVars = System.vmtAutoTable;

function TBasicObject.ClassVars: TClassVars;
begin
Result := PClassVars(PInteger(Self)^ + vmtClassVars)^; // Original code
end;

class function TBasicObject.GetClassVars: TClassVars;
begin
Result := PClassVars(Integer(Self) + vmtClassVars)^;
end;

class procedure TBasicObject.SetClassVars(aClassVars: TClassVars);
begin
PatchCodeDWORD(PDWORD(Integer(Self) + vmtClassVars), DWORD(aClassVars));
end;

We no longer need the artificially created strict private virtual method, nor the method to clear the VMT slot (as we assume that the AutoTable slot is already free). Notice that we use one of the magic constants from the System unit to determine the offset that we will use, vmtAutoTable. From the System unit:

const
...
{ Virtual method table entries }

vmtSelfPtr = -76;
vmtIntfTable = -72;
vmtAutoTable = -68;
vmtInitTable = -64;

Here you see that the AutoTable is at negative offset -68 (or -$44 in hex) from the base TClass pointer. I've also chosen to rename ClassInfo to ClassVars, to reduce confusion with the existing TObject.ClassInfo that returns a pointer to the RTTI of the published properties in the class (and used by the TypInfo unit). The SetClassInfo and ClassInfo methods are non-static class methods (so that they receive the implicit Self: TClass parameter that contains the runtime class reference), while the instance function ClassVar returns the TClassVars instance that holds the per-class variables of the class of the object instance.


To keep the code simple and fast, I've selected to put the InstanceCount field directly in the TClassVars class (instead of creating a descendent class). To add a certain shim of abstraction to the initialization of the ClassVars slot, I've thrown in a simple registration procedure as well.

procedure RegisterClassVarsSupport(const Classes: array of TBasicObjectClass);
var
LClass: TBasicObjectClass;
begin
for LClass in Classes do
if LClass.GetClassVars = nil then
LClass.SetClassVars(TClassVars.Create)
else
raise Exception.CreateFmt(
'Class %s has automated section or duplicated registration', [LClass.ClassName]);
end;

Our fruit example then becomes simpler too.

type
TFruit = class(TBasicObject)
public
constructor Create;
function InstanceCount: integer; inline;
class function ClassInstanceCount: integer; inline;
end;
TApple = class(TFruit)
end;
TOrange = class(TFruit)
end;

constructor TFruit.Create;
begin
inherited Create;
Inc(ClassVars.InstanceCount);
end;

function TFruit.InstanceCount: integer;
begin
Result := ClassVars.InstanceCount;
end;

class function TFruit.ClassInstanceCount: integer;
begin
Result := GetClassVars.InstanceCount;
end;

initialization
RegisterClassVarsSupport([TFruit, TApple, TOrange]);
end.

The test code stays the same as before. A quick look at the generated machine code for going from an object instance, via the object's TClass reference to the TClassVar slot in the VMT and finally referencing an integer field (InstanceCount) is impressive.

Count := Apple.ClassInstanceCount;
asm
mov eax,[esi]
add eax,-$44
mov eax,[eax]
mov ebx,[eax+$04]
end;

Only four instructions. Notice that this is one instruction more than the virtual method slot hack we started with. The main reason for this is that the vmtAutoTable is at a negative offset in the VMT, while the user-defined virtual method is at a positive offset. Currently, it does not seem to be a way to force the compiler to put the constant offset calculation inside the memory referencing mov reg, mem opcode - for negative offsets. The ideal would be if the compiler could generate the following machine code instead.

Count := Apple.ClassInstanceCount;
asm
mov eax,[esi]
mov eax,[eax-$44]
mov ebx,[eax+$04]
end;

Here the subtraction of the $44 constant has been put into the opcode itself and this is smaller and faster than explicitly modifying the register. We may be looking into this issue in a later post.


Also notice that while all class VMTs have AutoTable fields, we are still using a TBasicObject class that the TFruit class is inheriting from. We may be looking at different ways of (trying to) overcome this restriction later. The blog post is running long enough already - most of you must be sleeping by now - and besides, Windows Live Writer will not let me edit in HTML mode any more (for inserting the HTML code snippets that Delphi2HTML generates for me) - seems like it has an incredibly silly 32 KB limit on editing HTML (hey, what is this, 1982??!). OTHO, it saved you from an even longer post ;)).


I'll just give Patrick the word again here at the end of the article:



I've now switched over to using vmtAutoTable completely, as you suggested. I've already applied it to all the classes we had older hacks for, and it did wonders for the speed of our query-engine, so thanks!


Well, thanks to you Patrick for sharing your ideas and hack with us! It's very interesting, but is only a small part of the puzzle. From our small email conversation, it is clear that Patrick and his colleagues in Every Angle are really a smart bunch. They have developed a very impressing architecture specialized for their extreme requirements. You can check the high-level descriptions of their SAP database analytics and data mining products here.


On a more technical level it suffices to say that they use custom and extremely compact and fast data structures, tricks and hacks to be able to represent millions and millions of objects within the constraints of a 32-bit Windows system. Throw in the use of Physical Address Extensions, storing per-class information in "virtual" class vars to reduce object instance size, creation of classes and their VMTs dynamically at runtime (!!), pointer packing, multithreading, the list just goes on and on.


Maybe we can convince Patrick to start a blog of his own, to share some of his ideas and techniques - alas, much of it may be company confidential.

Monday, May 07, 2007

DN4DP#8: Unicode identifiers

This post continues the series of The Delphi Language Chapter teasers from Jon Shemitz’ .NET 2.0 for Delphi Programmers book. Last time we included the section on the new inlining support of the compiler. This post briefly covers the internationalization of Pascal identifiers (Klingon code, anyone?).

Note that I do not get any royalties from the book and I highly recommend that you get your own copy – for instance at Amazon.

"Unicode identifiers

Traditional Pascal and Delphi has restricted identifier names to be lower and upper case ASCII letters (a-z), underscore and digits. In .NET all strings are Unicode and identifiers can use Unicode characters, including national characters, such as the Norwegian Æ, Ø and Å.

Delphi now supports Unicode characters in identifiers, as long as the source file is encoded in a Unicode format (UTF-8 or UTC2). Identifiers that end up in RTTI data (unit names, class names and published members) must still be pure ASCII - the main reason is to avoid breaking code that read RTTI strings.

type
TUnicodeClass = class
private
FAntallÅr: integer;
public
procedure SetAntallÅr(const Value: integer);
property AntallÅr: integer read FAntallÅr write SetAntallÅr;
end;

procedure TestÆØÅ;
var
Unicode: TUnicodeClass;
begin
Unicode := UnicodeClass.Create;
Unicode.AntallÅr := 42;
end;




Tip To change the encoding of a source file to UTF-8, right-click in the Delphi editor and select File Format | UTF-8, then save it.




"

Friday, May 04, 2007

Hack#17: Virtual class variables, Part I

[Note: This blog post was inspired by an email conversation I had with Patrick van Logchem - more details on this in Part II]

Proper Object Pascal support for class var variables was first introduced in Delphi 8 for .NET and later in Delphi 2005 for Win32. Functionally class vars in Object Pascal (and most other languages, for that matter) work like class-scoped global variables, i.e. their lifetime is global and there is only one copy of the variable per declaration. Indeed, before having access to proper class variables, most Delphi programmers would use a global variable hidden in the implementation section of the unit that declares the class instead.

Poor man's class variables

For instance, let say you want to keep track of the number of instances that has been created of a specific class. In Delphi 7 and earlier you might have written:

type
TFruit = class
public
constructor Create;
class function InstanceCount: integer;
end;
 
implementation
 
var
FInstanceCount: integer;
 
constructor TFruit.Create;
begin
inherited Create;
Inc(FInstanceCount);
end;
 
class function TFruit.InstanceCount: integer;
begin
Result := FInstanceCount;
end;

Here the FInstanceCount global variable is used as a poor-man's class variable. It is incremented in the constructor and we use a class function to return its value. [Yes, a more robust implementation would probably override NewInstance and FreeInstance to increment and decrement the counter, respectively - and we should probably make them thread-safe, but we're trying to keep things simple here - HV].


Language support for class variables


Fast-forward to Delphi 2007 and we can rewrite the code using a class var instead (class vars have been supported since Delphi 8 for .NET).

type
TFruit = class
private
class var FInstanceCount: integer;
public
constructor Create;
class property InstanceCount: integer read FInstanceCount;
end;
 
implementation
 
constructor TFruit.Create;
begin
inherited Create;
Inc(FInstanceCount);
end;

Note that we have changed the InstanceCount class function into a class property instead. This reduces the amount of code and is more efficient - I covered class var and class property in the D4DNP Chapter 10 extract here.


This change will keep the OOP-purists at ease, but the underlying implementation (the code at the CPU level) stays the same. The class var FInstanceCount is assigned a static address in the global data segment by the linker. The implication of this is that the class var is shared among the TFruit class and all descendant classes.


Naïve assumptions


For instance, a naïve programmer wanting to keep track of the number of apples and oranges created in his application may write something like:

type
TApple = class(TFruit)
// ..
end;
TOrange = class(TFruit)
// ..
end;
 
procedure Test;
var
List: TList;
begin
List := TList.Create;
List.Add(TApple.Create);
List.Add(TApple.Create);
List.Add(TOrange.Create);
Writeln('Apples: ', TApple.InstanceCount);
Writeln('Oranges: ', TOrange.InstanceCount);
readln;
end;

The expected output is 2 apples and 1 orange, but the actual output is:

Apples: 3
Oranges: 3

The reason, of course, is that the class var is shared between the TFruit, TApple and TOrange classes.


Explicit per-class class variables implementation


The most straightforward solution to this problem is to explicitly declare class vars in each descendant class. Then we can use a virtual class function to return the instance count for each class. For instance:

type
TFruit = class
private
class var FInstanceCount: integer;
public
constructor Create;
class function InstanceCount: integer; virtual;
end;
TApple = class(TFruit)
private
class var FInstanceCount: integer;
public
constructor Create;
class function InstanceCount: integer; override;
end;
TOrange = class(TFruit)
private
class var FInstanceCount: integer;
public
constructor Create;
class function InstanceCount: integer; override;
end;
 
implementation
 
constructor TFruit.Create;
begin
inherited Create;
Inc(FInstanceCount);
end;
 
class function TFruit.InstanceCount: integer;
begin
Result := FInstanceCount;
end;
 
constructor TApple.Create;
begin
inherited Create;
Inc(FInstanceCount);
end;
 
class function TApple.InstanceCount: integer;
begin
Result := FInstanceCount;
end;
 
constructor TOrange.Create;
begin
inherited Create;
Inc(FInstanceCount);
end;
 
class function TOrange.InstanceCount: integer;
begin
Result := FInstanceCount;
end;

That's a lot of repetitive code, but at least when we now run the same Test procedure above we get the expected result.

Apples: 2
Oranges: 1

If you want to support this kind of per-class meta information in a large hierarchy of classes (say in a custom business class library), it quickly becomes unwieldy to duplicate this code in every subclass. The InstanceCount property or function is a feature introduced and implemented by the initial base class - so why should all subclasses be required to help implement it?


virtual class variables


What we need is a new language feature - a new kind of class var that is not implemented like a simple global variable, but as a per-class or per-VMT basis. Lets call this imaginary feature virtual class vars - virtual because its value varies with the run-time class - just like a virtual class function implementation varies with the run-time class. An imaginary syntax for this imaginary feature could be:

    class var FInstanceCount: integer; virtual;

This would be the most natural syntax, IMO, but it would require promoting 'virtual' from a simple position sensitive directive to a full fledged reserved keyword. Making it a reserved keyword will break existing code that uses 'virtual' as an identifier, so a more realistic syntax would be one that only uses virtual as a directive, like this:

    class virtual var FInstanceCount: integer;

For the same reason we have the somewhat unintuitive syntax declarations like; class sealed and class abstract. With this imaginary syntax and language feature in place, the following code sample:

type
TFruit = class
private
class virtual var FInstanceCount: integer;
public
constructor Create;
class property InstanceCount: integer read FInstanceCount;
end;
TApple = class(TFruit)
//...
end;
TOrange = class(TFruit)
//...
end;

implementation

constructor TFruit.Create;
begin
inherited Create;
Inc(FInstanceCount);
end;

class function TFruit.InstanceCount: integer;
begin
Result := FInstanceCount;
end;

procedure Test;
var
List: TList;
begin
List := TList.Create;
List.Add(TApple.Create);
List.Add(TApple.Create);
List.Add(TOrange.Create);
Writeln('Apples: ', TApple.InstanceCount);
Writeln('Oranges: ', TOrange.InstanceCount);
readln;
end;

would now output the expected:


Apples: 2
Oranges: 1

An old report


As it happens, I actually made a suggestion to Borland to implement class variables with these per-class semantics way back in 1998 - when Delphi 4 was the current version and plain class var and class property where still four Delphi versions away. Excerpts from my original report (that has been Closed with As Designed ages ago):



Please add proper class fields. This would also support class properties. Suggested syntax:

type
TFoo = class
private
class FBar: integer;
class procedure SetBar(Value: integer);
public
class property Bar: integer read FBar write SetBar;
end;

class procedure TFoo.SetBar(Value: integer);
begin
if Value <> FBar then
begin
FBar := Value;
end;
end;

This feature is very useful when working much with meta-classes. You can kind-of simulate this by using global variables in the implementation section, but it is not what I want. If you use the global-variable approach, all derived classes will share the same variable. This is not ideal.

Each new derived class should have it's own copy of the variable (just like ClassName and InstanceSize are unique for each class). Both idioms might be useful, though. Maybe there should be a separate syntax for the shared class field thing?

  TFoo = class
private
class FBar: integer; const;

Although the suggested syntax is different (and in hindsight, horrid), this is basically the same feature request we discussed above. As we know now, classic shared class vars have been implemented, while per-class virtual class fields have not. I can't say I blame them (Borland/CodeGear) though - demand hasn't been high for this feature, and I don't know of any other language that implements it (do you?).


Virtual class var implementation


How could such a language feature be implemented? Well, we know how virtual methods (both instance and class method) are implemented - the compiler assigns a unique slot in the VMT (virtual method table) for each introduced virtual method. There is one VMT for each class. Each virtual method has an associated unique index (that can be retrieved in BASM using the VMTINDEX directive) which can be used to calculate the VMT slot and lookup the code address of the virtual method.


VMT slot per field


What if we extended the VMT to contain one extra slot per declared  virtual class var? This would be a straightforward solution. The main benefit is that the VMT of classes without virtual class var (i.e. 100% of existing classes) would not change at all. The problem is that the VMT is stored in the code-segment - and keeping writable data variables there is Not a Good Idea (tm).


As we have seen in our recent self-modifying code hacks, to avoid access violations and DEP (Data Execution Protection) problems you have to be careful with mixing code and data. Particularly, to write data to the code segment you have to change the access rights of the code page(s) the data resides in. And to be a good citizen you should restore the rights back to the original when you're done, like this helper routine does:

procedure PatchCodeDWORD(Code: PDWORD; Value: DWORD);
// Self-modifying code - change one DWORD in the code segment
var
RestoreProtection, Ignore: DWORD;
begin
if VirtualProtect(Code, SizeOf(Code^), PAGE_EXECUTE_READWRITE,
RestoreProtection) then
begin
Code^ := Value;
VirtualProtect(Code, SizeOf(Code^), RestoreProtection, Ignore);
FlushInstructionCache(GetCurrentProcess, Code, SizeOf(Code^));
end;
end;

And doing this is not thread-safe, of course. If you're really unlucky another thread could come and change the rights again before you get the chance to perform the write operation. So this is not something you want to do every time you change a virtual class var. Strike solution one.


Virtual ClassFieldTable


Doing something to the VMT is a good idea, but storing the actual live data there is not. As usual, adding an extra level of indirection solves the problem. We should extend the VMT with a new magic slot - lets call it ClassFieldTable (its implicit that we're talking about virtual class fields here - otherwise it wouldn't belong in the VMT). This slot points to a record structure in the global data segment. The record contains fields that corresponds to all the virtual class vars that has been declared on the class or inherited from the parent class. Each derived class has a unique copy of this record in the data segment - and the ClassFieldTable slot in the VMT points to the unique copy.


Now we have solved the cannot-write-data-to-code-pages problem. The ClassFieldTable pointer is still part of the VMT and stored in a code page, but it's fixed-up by the linker/loader to point to the correct global record variable and never changes at run-time. An added benefit of using implicitly declared global record variables (i.e. generated by the compiler)for each class' virtual class vars is that we get the compiler magic to finalize managed fields in the record (AnsiString, WideString, interface, Variant and  dynamic array) for free.


Compiler's implementation


Now lets imagine what the compiler would have to do to implement virtual class vars by using some pseudo-code on a variant of the imaginary sample code above. Here is the modified example were all the three classes form a 3-generation inheritance chain and I've added another virtual class var to one of the descendent classes

type
TFruit = class
private
class virtual var FInstanceCount: integer;
public
constructor Create;
class property InstanceCount: integer read FInstanceCount;
end;
TCitrus = class(TFruit)
end;
TOrange = class(TCitrus)
private
class virtual var ClassDescription: string;
end;

And here is the pseudo-code that tries to illustrate what the compiler would do to implement this code sample.

type
TFruit = class
private
class virtual var FInstanceCount: integer;
public
constructor Create;
class property InstanceCount: integer read FInstanceCount;
end;
TCitrus = class(TFruit)
end;
TOrange = class(TCitrus)
private
class virtual var ClassDescription: string;
end;
// Compiler generated types and variables
var
// Global variables used for per-class virtual class fields
FruitClassVars = record
FInstanceCount: integer;
end;
CitrusClassVars = record // inherits field
FInstanceCount: integer;
end;
OrangeClassVars = record // inherits field, introduces new field
FInstanceCount: integer;
ClassDescription: string;
end;
// New VMT slot initialization, generated by compiler:
TFruitVMT = record


ClassVarTable := @FruitClassVars;
end;
TCitrusVMT = record
ClassVarTable := @CitrusClassVars;
end;
TOrangeVMT = record
ClassVarTable := @OrangeClassVars;
end;

It's interesting to see that this closely resembles the implementation suggestion I made some 9 years ago. From the same report I showed an excerpt of above:



How to implement this:



The shared-variable type of class field could be implemented by using a space from the global data segment. The underlying implementation would thus be the same as using a global variable - only the syntax would be more logical (than using an explicit global variable).

The each-class-one-variable type of class field could be implemented by adding two fields to the VMT:

ClassInstanceSize : Integer
ClassInstanceData: Pointer;

The ClassInstanceSize would give the number of bytes allocated for class fields in [the] class. The ClassInstanceData would point to the block of memory containing the class fields. This memory block should be in the global data segment, initialized to all zeros.

At compile-time these fields would be setup while creating the VMT tables. A class that inherits from another class and adds its own fields would have the ClassInstanceSize = Parent.ClassInstanceSize + SizeOf(class fields in this class).


I think now that the ClassInstanzeSize (or ClassVarTableSize) is unnecessary to keep in the VMT. The compiler needs this information in its internal bookkeeping, but it is not strictly needed at runtime. In a way this is the same case as for virtual methods. The compiler keeps track of the number of virtual methods in each class (as part of the compile-time class information stored in the .dcu), but the code it generates does not need it, and thus there is no VirtualMethodCount field in the VMT. The same logic applies to our new virtual class fields and the new ClassVarTable slot.


To be continued...


This post is getting a bit long, so I've decided to split it in two. In Part II we will look at Patrick's hack of implementing a workaround for the lack of proper language level virtual class vars.



Copyright © 2004-2007 by Hallvard Vassbotn