Jump to content

spbogie

Members
  • Content Count

    1
  • Joined

  • Last visited

Everything posted by spbogie

  1. One reason for using the CreateRes version over the normal Create is to avoid all of the additional code that the compiler generates to load the resource string before passing it to Create. An example to help demonstrate (compiled w/ 10.3.3 in Win32-Release configuration) procedure DoExceptRes; var lRes: Boolean; begin lRes := DoSomething; if not lRes then raise Exception.CreateRes(@MY_RES_STRING); end; 004EA78B 90 nop TestMain.pas.117: lRes := DoSomething; 004EA78C E8F7FFFFFF call DoSomething TestMain.pas.118: if not lRes then 004EA791 84C0 test al,al 004EA793 7516 jnz +22 ; $004ea7ab TestMain.pas.119: raise Exception.CreateRes(@MY_RES_STRING); 004EA795 B9B4A04E00 mov ecx,$004ea0b4 004EA79A B201 mov dl,$01 004EA79C A13C9B4100 mov eax,[$00419b3c] 004EA7A1 E886BFF3FF call Exception.CreateRes 004EA7A6 E8D1F9F1FF call @RaiseExcept TestMain.pas.120: end; 004EA7AB C3 ret procedure DoExcept; var lRes: Boolean; begin lRes := DoSomething; if not lRes then raise Exception.Create(MY_RES_STRING); end; TestMain.pas.125: begin 004EA7AC 55 push ebp 004EA7AD 8BEC mov ebp,esp 004EA7AF 6A00 push $00 004EA7B1 33C0 xor eax,eax 004EA7B3 55 push ebp 004EA7B4 68FFA74E00 push $004ea7ff 004EA7B9 64FF30 push dword ptr fs:[eax] 004EA7BC 648920 mov fs:[eax],esp TestMain.pas.126: lRes := DoSomething; 004EA7BF E8C4FFFFFF call DoSomething TestMain.pas.127: if not lRes then 004EA7C4 84C0 test al,al 004EA7C6 7521 jnz +33 ; $004ea7e9 TestMain.pas.128: raise Exception.Create(MY_RES_STRING); 004EA7C8 8D55FC lea edx,[ebp-$04] 004EA7CB B8B4A04E00 mov eax,$004ea0b4 004EA7D0 E8F755F2FF call LoadResString 004EA7D5 8B4DFC mov ecx,[ebp-$04] 004EA7D8 B201 mov dl,$01 004EA7DA A13C9B4100 mov eax,[$00419b3c] 004EA7DF E814BEF3FF call Exception.Create 004EA7E4 E893F9F1FF call @RaiseExcept TestMain.pas.129: end; 004EA7E9 33C0 xor eax,eax 004EA7EB 5A pop edx 004EA7EC 59 pop ecx 004EA7ED 59 pop ecx 004EA7EE 648910 mov fs:[eax],edx 004EA7F1 6806A84E00 push $004ea806 004EA7F6 8D45FC lea eax,[ebp-$04] 004EA7F9 E88202F2FF call @UStrClr 004EA7FE C3 ret 004EA7FF E998F8F1FF jmp @HandleFinally 004EA804 EBF0 jmp -16 ; $004ea7f6 004EA806 59 pop ecx 004EA807 5D pop ebp 004EA808 C3 ret Note how in the case where we just call Create instead of CreateRes, Delphi needs to generate a call to LoadResString within the context of our procedure in order to actually turn the resourcestring into a value that can be passed into Exception.Create. This isn't really an issue though because it only happens if we're actually going to raise the exception, and CreateRes will ultimately need to do the same thing internally. The issue comes from the fact that Delphi needs somewhere to put the string it gets back from LoadResString before passing it to Exception.Create. To that end it generate an implicit local string variable, and because strings are managed, and local variable have a scope covering the entire procedure lifetime, it wraps the entire body of our procedure into an implicit try...finally to ensure the string is cleaned up. As a result, we will incur the cost of this try...finally scaffold and the call to UStrClr every time we call DoExcept. Even if it never actually raises an Exception. A similar thing applies to the use of CreateFmt vs Create(Format(...)). The compiler will generate an implicit variable to store the result of the call to Format, and you will incur this overhead regardless of whether the actual call to Format ever happens. Whether or not this actually makes a measurable real world difference will depend on your use case, but it is worth being aware of.
×