Трансляция объектов в машинный код в Delphi| В статье предпринята попытка проанализировать, ведет ли объектный стиль программирования к существенному замедлению кода по сравнению с процедурным стилем. | | Автор статьи: romix | Редакторы: Последняя редакция №12 от 08.02.07 | История URL: http://kb.mista.ru/article.php?id=472 | |
Для проверки, в какой же именно код транслирует Delphi тот или иной пример, я использовал отладчик SoftICE. Чтобы остановить выполнение на нужном фрагменте кода, я даю SoftICE команду BPX MessageBoxA
(ставлю точку останова на функции MessageBox) и, соответственно, вставляю в свой код на Delphi вызов MessageBox (эта системная функция Windows выводит окно предупреждения). Когда срабатывает "бряк" (breakpoint), я выхожу "наверх" из функции нажатием клавиши F12, после чего пошагово исполняю код нажатием клавиш F8 или F10. В приведенных ниже примерах кода вызов MessageBox, который я использую только для точки останова, помечен синим цветом.
Простейший пример
В этом примере я просто вывожу сообщение (MessageBox) из метода объекта и из процедуры соответственно. Сгенерированный транслятором машинный код почти не отличается, за исключением передачи в регистре eax ссылки (указателя) на объект в случае с применением ООП.
| В объектном стиле |
В процедурном стиле |
program ObjTest;
uses Windows;
type T_TEST = Class
procedure test();
end;
procedure T_TEST.test();
begin
MessageBox(0, 'test', 'test',0);
end;
var obj: T_TEST;
begin
obj:=T_TEST.Create;
obj.Test();
obj.Test();
obj.Free;
end. |
program ObjTest;
uses Windows;
procedure test();
begin
MessageBox(0, 'test', 'test',0);
end;
begin
Test();
Test();
end.
|
mov eax, ebx
call 00403620
mov eax, ebx
call 00403620
...
00403620:
push 00
push 00403640; "test"
push 00403640; "test"
push 00
call User32!MessageBoxA
ret
|
call 00401E90
call 00401E90
...
00401E90:
push 00
push 00403640; "test"
push 00403640; "test"
push 00
call User32!MessageBoxA
ret
|
Складываем два числа
| В объектном стиле |
В процедурном стиле |
program ObjTest;
uses Windows;
type T_TEST = Class
function add(a,b: Integer):Integer;
end;
function T_TEST.add(a,b: Integer):Integer;
begin
MessageBox(0, 'test', 'test',0);
Result:=a+b;
end;
var obj: T_TEST;
begin
obj:=T_TEST.Create;
obj.add(2,3);
obj.add(3,4);
obj.Free;
end. |
program ObjTest;
uses Windows;
function add(a,b: Integer):Integer;
begin
MessageBox(0, 'test', 'test',0);
Result:=a+b;
end;
begin
add(2,3);
add(3,4);
end.
|
mov ecx, 00000004
mov edx, 00000003
mov eax, ebx
call 00403620
...
00403620:
push ebx
push esi
mov esi, ecx
mov ebx, edx
push 00
push 00403640; "test"
push 00403640; "test"
push 00
call User32!MessageBoxA
lea eax, [ebx+esi]
pop esi
pop ebx
ret
|
mov edx, 00000004
mov eax, 00000003
call 00401E90
...
00401E90:
push ebx
push esi
mov esi, edx
mov ebx, eax
push 00
push 00403640; "test"
push 00403640; "test"
push 00
call User32!MessageBoxA
lea eax, [ebx+esi]
pop esi
pop ebx
ret
|
Передаем параметры через переменные или поля классаПеределаем этот же пример так, чтобы числа, которые нужно сложить, передавались не через параметры функции, а через поля класса.
| В объектном стиле | В процедурном стиле |
program ObjTest;
uses Windows;
type T_TEST = Class
a: Integer;
b: Integer;
function add():Integer;
end;
function T_TEST.add():Integer;
begin
MessageBox(0, 'test', 'test',0);
Result:=a+b;
end;
var obj: T_TEST;
begin
obj:=T_TEST.Create;
obj.a:=2;
obj.b:=3;
obj.add();
obj.a:=3;
obj.b:=4;
obj.add();
obj.Free;
end.
|
program ObjTest;
uses Windows;
var
a: Integer;
b: Integer;
function add():Integer;
begin
MessageBox(0, 'test', 'test',0);
Result:=a+b;
end;
begin
a:=2;
b:=3;
add();
a:=3;
b:=4;
add();
end.
|
mov dword ptr[ebx+04], 0000003
mov dword ptr[ebx+08], 0000004
mov eax, ebx
call 00403620
...
00403620:
push ebx
mov ebx, eax
push 00
push 00403640; "test"
push 00403640; "test"
push 00
call User32!MessageBoxA
mov eax, [ebx+04]
add eax, [ebx+08]
pop ebx
ret
|
mov dword ptr[004036EC], 0000003
mov dword ptr004036F0], 0000004
call 00401E90
...
00401E90:
push 00
push 00403640; "test"
push 00403640; "test"
push 00
call User32!MessageBoxA
mov eax, [004036EC]
add eax, [004036F0]
ret
|
ВыводыКак видим в вышеприведенных примерах, различия малосущественны, и оправданы необходимостью передавать дополнительную переменную - ссылку на объект. |