PDA

View Full Version : What gets compiled?



pstudio
31-07-2007, 02:11 PM
So I've been programming for 8 years now, and I've never thought about this before until now. If we have a simple unit with a class like this:


Unit Example;

interface

type
TSomething = class(TObject)
private
//whatever
public
procedure SomeThingA;
procedure SomeThingB;
end;

procedure whatever;

implementation

//implementation of the procedures. None of the above procedures calls each other

My question is: if I use the Unit Example in a project and never uses the procedure whatever will the compiler be smart enough to not compile the procedure? And more interesting for me. If I use the class TSomething in a project but never uses procedure SomeThingB, will the compiler then compile procedure SomeThingB into the exe?

NecroDOME
31-07-2007, 05:32 PM
You can check it by setting a breakpoint in the implementation. If the breakpoint is valid, it is compiled!

cronodragon
31-07-2007, 06:04 PM
I tried something different. For my debugger routines I placed a conditional compiler directive that left the procedure empty, expecting Delphi to remove the calls, so I won't have to add conditional directives to remove each call of the procedure... but doesn't work, Delphi doesn't remove calls to empty procedures. :P

JernejL
31-07-2007, 07:49 PM
tell delphi to generate a detailed map of segments, then check in the .map file.

Setharian
01-08-2007, 07:39 AM
newer versions of Delphi leave out all unused code...FPC has smart-linking also....so answer to your question - newer compilers do not compile unused code...

pstudio
01-08-2007, 01:46 PM
Well, that's what I thought, but I may just try out some of the other guys sugestions to see if it really is true. It could be interesting to see how well the compiler does it's job of not compiling what isn't needed.

tpascal
01-08-2007, 03:25 PM
I have not checked this my self, but i understand that "procedure whatever" if never used then is never compiled. Variables defined but never used are not compiled neither; however much likely this is not true with procedure and variables inside a class.

If you define a record type:

mytype = record
a:word;
b:integer;
c:string;
end;

var
K:mytype;


Just becouse you never used field K.b in any place in your whole program dosent mean that the compiler "edited" your record structure. Well i am sure same happen with variables and procedures inside classes; the compiler could cut the whole class if never used but i dout it will cut class elements from in.

pstudio
01-08-2007, 04:32 PM
I wouldn't expect the compiler to drop vars, but it may.
However if I for example make a class that can load something (let's say a picture), and write 20 different procedures to load an image, but I'm only using one of those procedures in an application (but may use an other procedure in an other app) it would simply be a waste of space to compile the remaining 19 procedures. I would expect my compiler to be smart enough to see through my code and only compile what is needed.

tpascal
01-08-2007, 11:26 PM
I dont know who write this article, but:

http://delphicikk.atw.hu/listaz.php?id=2251&oldal=54

from that article.



Virtuals Defeat Smart Linking

When the Delphi compiler/linker produces an .EXE, the procedures, variables, and static methods that are not referenced by "live" code (code that is actually used) will be left out of the .EXE file. This process is called smart linking, and is a great improvement over normal linkers that merely copy all code into the .EXE regardless of whether it's actually needed. The result of smart linking is a smaller .EXE on disk that requires less memory to run.

Smart Linking Rule for Virtuals. If the type information of a class is touched (for example, by constructing an instance) by live code, all the virtual methods of the class and its ancestors will be linked into the .EXE, regardless of whether the program actually uses the virtual methods.

For the compiler, keeping track of whether an individual procedure is ever used in a program is relatively simple; figuring out whether a virtual method is used requires a great deal more analysis of the descendants and ancestors of the class. It's not impossible to devise a scheme to determine if a particular virtual method is never used in any descendants of a class type, but such a scheme would certainly require a lot more CPU cycles than normal smart linking, and the resulting reduction in code size would rarely be dramatic. For these reasons (lots of work, greatly reduced compile/link speed, and diminishing returns), adding smart linking of virtual methods to the Delphi linker has not been a high priority for Borland.

If your class has a number of utility methods that you don't expect to use all the time, leaving them static will allow the smart linker to omit them from the final .EXE if they are not used by your program.

Note that including virtual methods involves more than just the bytes of code in the method bodies. Anything that a virtual method uses or calls (including static methods) must also be linked into the .EXE, as well as anything those routines use, etc. Through this cascade effect, one method could potentially drag hundreds of other routines into the .EXE, sometimes at a cost of hundreds of thousands of bytes of additional code and data. If most of these support routines are used only by your unused virtual method, you have a lot of deadwood in your .EXE.

The best general strategy to keep unused virtual methods - and their associated deadwood - under control, is to declare virtual methods sparingly. It's easier to promote an existing static method to virtual when a clear need arises, rather than trying to demote virtual methods down to statics at some late stage of your development cycle.


From what i read, seem in your example dosomthingA and dosomthingB are not compiled if they are not used, only the virtual method remain whatever are used or not.


There are more interesting reading in that article.



I understand your example of having a lot procedures in your class that could be uncompiled if they are not needed, but that is not the point about classes; classes are not a repository of function/procedures, (it is not a library of functions) but it is a nice structure/scheme for handle a repetitive task in a elegant and flexible way; if your class has too much procedures not used everytime then most likely the class was bad dessigned.

Mirage
02-08-2007, 04:25 AM
For these reasons (lots of work, greatly reduced compile/link speed, and diminishing returns), adding smart linking of virtual methods to the Delphi linker has not been a high priority for Borland.

I think there is another reason. Suppose somewhere in VCL is a "unused" virtual method in some base class. And then someone wrote a component that inherits this base class and overrides above mentioned "unused" method. What we get when the overridden implementation will call inherited implementation? If the compiler is "smart" enough to exclude the "unused" method we get something like access violation or incorrect processor instruction.


It's not impossible to devise a scheme to determine if a particular virtual method is never used in any descendants of a class type

It IS impossible because not all of descendants are even exists at compilation time. The author forgot that Delphi is a component-driven environment. ;)
So I don't think it's a good idea to exclude "unused" virtual methods.

It's better to use objects instead of classes (and KOL instead of VCL) if you want to get a small application.

cronodragon
02-08-2007, 01:40 PM
Yes, with virtuals being removed it won't be possible this trick:


the API

type TTestClass = class
procedure DoStuff; virtual; abstract;
end;



The DLL

type TTestClassImp = class(TTestClass)
procedure DoStuff; override;
end;




Taken from: http://www.pascalgamedevelopment.com/viewtopic.php?p=33814

Setharian
02-08-2007, 07:10 PM
well this "trick" is totaly unsafe and shouldn't be used....2 different versions of the same compiler (or 2 different compilers for the same language :) ) "might" handle virtual method calls differently (VMT slot at a different offset)...if you want such behaviour, use interfaces instead - they will work the way expected on all compilers in the same manner (not taking into account calling convention or compiler/language-specific types)...