I'm using Delphi 2009. In my program, I have been working very hard to optimize all my Delphi code for speed and memory use, especially my Unicode string handling.
I have the following statement:
Result := Result + GetFirstLastName(IndiID, 1);
When I debug that line, upon return from the GetFirstLastName function, it traces into the routine _UStrArrayClr in the System unit:
procedure _UStrArrayClr(var StrArray; Count: Integer);
asm
JMP _LStrArrayClr
end;
This calls _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}
and runs through the loop once for each character, and on exit from there it calls _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;
and runs through the whole of that routine.
My "Result" is a string and is thus Unicode. And my GetFirstLastName returns a string which is Unicode. No conversion of character set should be needed.
I can't really tell what these System procedures are doing, but they are adding a lot of overhead to my routine.
What are they doing? Are they necessary? If they aren't necessary, how can I prevent the compiler from calling those routines?