Я использую Delphi 2009. В своей программе я очень усердно работал, чтобы оптимизировать весь мой код Delphi для скорости и использования памяти, особенно для обработки строк Unicode.
У меня есть следующее утверждение:
Result := Result + GetFirstLastName(IndiID, 1);
Когда я отлаживаю эту строку, по возвращении из функции GetFirstLastName она прослеживает подпрограмму _UStrArrayClr в системном блоке:
procedure _UStrArrayClr(var StrArray; Count: Integer);
asm
JMP _LStrArrayClr
end;
Это вызывает _LStrArrayClr:
procedure _LStrArrayClr(var StrArray; cnt: longint);
{$IFDEF PUREPASCAL}
var
P: Pointer;
begin
P := @StrArray;
while cnt > 0 do
begin
_LStrClr(P^);
Dec(cnt);
Inc(Integer(P), sizeof(Pointer));
end;
end;
{$ELSE}
asm
{ -> EAX pointer to str }
{ EDX cnt }
PUSH EBX
PUSH ESI
MOV EBX,EAX
MOV ESI,EDX
@@loop:
MOV EDX,[EBX] { fetch str }
TEST EDX,EDX { if nil, nothing to do }
JE @@doneEntry
MOV dword ptr [EBX],0 { clear str }
MOV ECX,[EDX-skew].StrRec.refCnt { fetch refCnt }
DEC ECX { if < 0: literal str }
JL @@doneEntry
LOCK DEC [EDX-skew].StrRec.refCnt { threadsafe dec refCount }
JNE @@doneEntry
LEA EAX,[EDX-skew].StrRec.codePage { if refCnt now zero, deallocate}
CALL _FreeMem
@@doneEntry:
ADD EBX,4
DEC ESI
JNE @@loop
POP ESI
POP EBX
end;
{$ENDIF}
и проходит через цикл один раз для каждого символа, а при выходе оттуда он вызывает _UStrCat:
procedure _UStrCat(var Dest: UnicodeString; const Source: UnicodeString);
asm
{ -> EAX pointer to dest }
{ EDX source }
TEST EDX,EDX // Source empty, nop.
JE @@exit
MOV ECX,[EAX] // ECX := Dest
TEST ECX,ECX // Nil source => assignment
JE _UStrAsg
PUSH EBX
PUSH ESI
PUSH EDI
MOV EBX,EAX // EBX := @Dest
MOV ESI,EDX // ESI := Source
CMP ESI,ECX
JE @@appendSelf
CMP [ECX-skew].StrRec.elemSize,2
JE @@destIsUnicode
CALL _EnsureUnicodeString
MOV EDI,EAX
MOV ECX,EAX
@@destIsUnicode:
PUSH 0
CMP [ESI-skew].StrRec.elemSize,2
JE @@sourceIsUnicode
MOV EDI,ECX
MOV EAX,ESI
MOV [ESP],ESI
CALL _UStrAddRef
MOV EAX,ESP
CALL _EnsureUnicodeString
MOV ESI,[ESP]
MOV ECX,EDI
@@sourceIsUnicode:
MOV EDI,[ECX-skew].StrRec.length // EDI := Length(Dest)
MOV EDX,[ESI-skew].StrRec.length // EDX := Length(Source)
ADD EDX,EDI // EDX := (Length(Source) + Length(Dest)) * 2
TEST EDX,$C0000000
JNZ @@lengthOverflow
MOV EAX,EBX
CALL _UStrSetLength // Set length of Dest
MOV EAX,ESI // EAX := Source
MOV ECX,[ESI-skew].StrRec.length // ECX := Length(Source)
@@noTemp:
MOV EDX,[EBX] // EDX := Dest
SHL EDI,1 // EDI to bytes (Length(Dest) * 2)
ADD EDX,EDI // Offset EDX for destination of move
SHL ECX,1 // convert Length(Source) to bytes
CALL Move // Move(Source, Dest + Length(Dest)*2, Length(Source)*2)
MOV EAX,ESP // Need to clear out the temp we may have created above
MOV EDX,[EAX]
TEST EDX,EDX
JE @@tempEmpty
CALL _LStrClr
@@tempEmpty:
POP EAX
POP EDI
POP ESI
POP EBX
RET
@@appendSelf:
CMP [ECX-skew].StrRec.elemSize,2
JE @@selfIsUnicode
MOV EAX,EBX
XOR EDX,EDX
CALL _EnsureUnicodeString
MOV ECX,EAX
MOV EAX,EBX
@@selfIsUnicode:
MOV EDI,[ECX-skew].StrRec.length
MOV EDX,EDI
SHL EDX,1
TEST EDX,$C0000000
JNZ @@lengthOverflow
CALL _UStrSetLength
MOV EAX,[EBX]
MOV ECX,EDI
PUSH 0
JMP @@noTemp
@@lengthOverflow:
JMP _IntOver
@@exit:
end;
и проходит через всю эту рутину.
Мой "Результат" является строкой и, следовательно, Unicode. И мой GetFirstLastName возвращает строку, которая является Unicode. Преобразование набора символов не требуется.
Я не могу точно сказать, что делают эти системные процедуры, но они добавляют много накладных расходов к моей рутине.
Что они делают? Они необходимы? Если они не нужны, как я могу предотвратить вызов этих подпрограмм компилятором?