Jump to content

Mahdi Safsafi

Members
  • Content Count

    383
  • Joined

  • Last visited

  • Days Won

    10

Everything posted by Mahdi Safsafi

  1. Hello there, In the previous topic about Strange behavior for literals @Lars Fosdal asked himself a very interesting question about typed-constant. I quote : In this topic, I'll try to answer the following questions: - What is a typed-constant ? - How internally is handled by the compiler ? - Why a typed-constant can't act as a compile-time constant ? - What's the relationship between typed-constant and optimization ? What's a typed constant ? It is a constant that has a type associated with it. const NotTypedConstant = StaticExpression; const TypedConstant : ConstantType = StaticExpression; // e.g: const A = 5; // not typed constant. const B: Integer = 5; // typed constant. As you can see, all constants must be initialized with a static expression (an expression that the compiler can evaluate at compile time). However, no-typed-constant can be used in static expression, but a typed-constant can't ! const A = 5; // Ok. B = A + 1; // Ok. C: Integer = B; // Ok. D: Integer = C; // Error. Wondering why ? this is because the compiler is seeing C and D as variables (not static-compile-time constant) and it treats them same way as it does with pure variables ! You may think that this kind of behavior is unacceptable ? In fact there is a good reason for that ! How internally is handled by the compiler ? Please, consider the following example : // ---------------------------- Unit1 ---------------------------- unit Unit1; interface // public constants: const MIN = 0; MAX = 1000; MyData: array [MIN .. MAX] of Integer = (...); implementation // ... end. // ---------------------------- Unit2 ---------------------------- unit Unit2; interface implementation uses Unit1; // using Unit1. function ValidateData : Boolean; begin var First := MyData[MIN]; // first item. var Last := MyData[MAX]; // last item. // ... end; end. Would not be just perfect to be able to declare First and Last as constants ? const First: Integer = MyData[MIN]; const Last : Integer = MyData[MAX]; // or const First = MyData[MIN]; const Last = MyData[MAX]; This is not possible ! because when compiling Unit1, the compiler produce a .dcu file that contains two things : an interface and an implementation (obj) section for Unit1: // ---------------------------- Unit1.dcu ---------------------------- // Note that a .dcu file is a binary format ... I'm just using text format for demonstration ! interface section: // static-compile-time constant with definition: // ---------------------------------------------- const MIN = 0; const MAX = 1000; // constant WITHOUT definition: // ----------------------------- const MyData: array [MIN .. MAX] of Integer; implementation section: DataSection: MyData = [0, 1, ...]; ... CodeSection: ... When compiling Unit2. the compiler sees uses Unit1; and opens Unit1.dcu file and only going to read the interface section. Meaning the compiler only sees the declaration of MyData, but does not know about the data itself (data inside MyData): // unit2: // ------ // knowing the type and size of MyData is more important than knowing whats inside var value : Integer := MyData[MAX + 100]; // Error violating MyData bounds. Now, because the compiler does not know about the data. MyData can't be used in a static expression. However you can query it's type and size: // Unit2 const First = MyData[MIN]; // error. compiler does not know what MyData holds. const Size = SizeOf(MyData); // Ok. compiler knows the type and size. Why a typed-constant can't act as a compile-time constant ? Now, if the compiler is able to read the implementation section from the .dcu file, it will also able to access/read MyData definition and allows using typed-constant inside a static expression ... and much better, it will do a very good job for optimization (constant folding && constant propagation). Excited ? Don't be ! If it does such a thing... It will certainly come at a cost of compilation time : a very long compilation time ! That's because for each unit, the compiler must read both section (interface and implementation) and must process all the data inside the implementation section. Delphi is a fast compiler and allowing the use of typed-constant inside a static-expression will break that theory. What's the relationship between typed-constant and optimization ? So, Is Delphi typed-constant behavior correct ? From my point of view yes ! Is Delphi handling it smoothly ? Absolutely no !!! In fact the compiler does not do any kind of optimization (constant folding & propagation) even if the definition is available (constant declared in the same unit) : implementation {$O+} // this is a private declaration. compiler can access to the definition ! const MyData: array [0 .. 3] of Integer = (5, 16, 7, 10); var First: Integer; initialization // since it can access to the definition, it can generate much better code for : // First := MyData[0]; // mov reg, 5 // MyData[0] = 5. // but it just generated : // mov reg, [@MyData + offset] // ... end. The sad reason behind the above generated code is that typed-constant in Delphi is volatile ! Improving optimization: 1) Always declaring ordinal type as a non-typed-constant whenever its possible : const First = ...; // compile time constant. const Last = ...; // compile time constant. const MyData: array [MIN .. MAX] of Integer = (First, ..., Last); 2) Using a Link-Time-Code-Generation (LTCG*): This is some how hard to implement but definitely is the best way to improve optimization one for all ! This gives a full view of the program ... meaning the code-generator will have much opportunity to do function in-lining, constant folding & propagation, ... The good thing, its just an option (so you can just use it when doing a Release build). LTCG* = is not supported by Delphi. Perhaps its supported with C++Builder (I'm not sure about that). If anyone has a clean info, please make a comment. Conclusion: The purpose of typed-constants is to hold a non-ordinal-data(array, record, ...), and a way to share data between units and speed-up compilation-time. For ordinal-type (integer,...), you should always use a non-typed-constant.
  2. Thank you both. Now Im understanding what are you referring to. I guess that flat bst would be much great than. http://bannalia.blogspot.com/2015/06/cache-friendly-binary-search.html?m=1#:~:text=June 25%2C 2015-,Cache-friendly binary search,behind classes such as Boost. In addition to what you pointed out, there is another important factor: branch misprediction : http://databasearchitects.blogspot.com/2015/09/trying-to-speed-up-binary-search.html?m=1#:~:text=The performance of binary search,for the large data sets.
  3. Can you please explain more. Im unable to understand what you exactly mean? Better to give an example.. So I can catch.
  4. Mahdi Safsafi

    Book: Delphi Quick Syntax Reference

    Why the heck im not aware about this? Looks good but is it always up to date? I mean the last change made was on 2019. Please consider maintaining it... We really need such project.
  5. Mahdi Safsafi

    Help with string extraction function

    I'm sure you miss understood my comment ! I quote from my comment where I answered Anders What I was referring to is a cause consequence: Compiler understood better code that does not use pointer ... its able to detects some patterns and optimize them like what gcc does. Pointers on the other side are hard to understand(volatility, nullability, mutability, ...) ... yes could be optimized but the chance of optimizing a code that does not use pointer is much higher. See Gather-scatter (vector addressing) to understand clearly what are you missing when using pointer instead of integer access. CPU also detects patterns such memory access patterns and optimize them. Another important thing : yes there is no difference for mov ecx, [eax+edx]/mov ecx, [eax]. But keep in mind that this is not applicable for all instructions ! An example : MPX extension. Just to make thing clear, I'm not talking about optimization on Delphi. Rather ... a general concept for modern compiler.
  6. Mahdi Safsafi

    FastMM - Fragmentation Analysis?

    Even so, there are other requirements like LastErrorCode. a logic may call GetLastError after calling HeapAlloc. FastMM doesn't probably use SetLastError and even if it does ... does it emulate HeapAlloc behavior ? Having some thought is really good. You just need to do it right in a way that you don't waste your valuable time.
  7. Mahdi Safsafi

    FastMM - Fragmentation Analysis?

    Literally you're no longer coding ... you're gambling. If some function X expects 32 byte alignment from OS and somehow you managed to redirect the call to FastMM that yields 16B aligned memory ... what would be you expectation ? Don't waste you time on doing something that is theoretically invalid.
  8. Mahdi Safsafi

    FastMM - Fragmentation Analysis?

    My bad ... I must be very slow at understanding. Yes the timestamp/size is interesting here ! I wan't do such a thing! After all FastMM is relying on OS Api. Beside do you have any guarantee that those calls do not imply some constraints like expecting the allocated memory to be filled with zero or expecting the memory to be allocated at certain range ? or assuming some memory access right ?, or ... Moreover, the purpose of memory management is to handle small/medium size. for large block, you should call OS Api instead. Its likely that doing this will ends up on having an unpredictable/undefined behavior. So you should leave OS stuff to the OS memory manager.
  9. Mahdi Safsafi

    FastMM - Fragmentation Analysis?

    Yes possibly true. Knowing if there is a leak is somehow easy to implement but tracing it is the problem. To give a nice report about the leak you need to hook every external function that may allocate memory such CreateSolidBrush and hook every function that release the memory such DeleteObject ... How many Api are there ? Besides, your engine needs to allocate data too. For each called function that allocates memory, an X bytes of stack must be saved for later report (trace)! As you can see this is not something easy to implement if you just consider the amount of Win32Api function that may allocate ! I truly respect the way you're thinking but in my opinion, no ! they're not obliged to do that ! Memory leak report/detection is just a sugar for the RTL. They're paid to maintain/extend standard not to implement sugar stuff(that's why 3rd party exists).
  10. Mahdi Safsafi

    Help with string extraction function

    As I mentioned before, Compiler is much able to understand integer behavior over pointer behavior. CPU can also be smart to prefetch next data for you on the background.
  11. Mahdi Safsafi

    Help with string extraction function

    As I mentioned before, Compiler is much able to understand integer behavior over pointer behavior. CPU can also be smart to prefetch next data for you on the background.
  12. Mahdi Safsafi

    FastMM - Fragmentation Analysis?

    FastMM is not aware about external allocated resource such VirtualAlloc/. A non closed handle can leak too. Try to use madExcept as its more aware about many external allocation.
  13. Mahdi Safsafi

    Help with string extraction function

    Yes I know that. The code was just a snippet from the paper I read to point out about emitting if branch. Event if the variable is not static ... Some language takes contract as seriously : assert(i > 0); 😉
  14. Mahdi Safsafi

    Help with string extraction function

    @Stefan Glienke @Arnaud Bouchez Ok, I did some research on that and found that I was wrong. In fact there is more benefits about using inversion loop(Sadly it does not apply to Delphi): var i: Integer; begin // legacy loop: for i := 0 to 10 - 1 do begin dosomething(i); end; // loop inversion: i := 0; if (i < 10) then // this branch can be emited if i holds at compile time. begin repeat dosomething(i); inc(i); until (i = 10); end; end; There is a good paper : Generalizing loop-invariant code motion in a real-world compiler by Paul Colea that describes many loop optimization. @Kas Ob you may be interested on reading this paper.
  15. WOW ! Most of time I use HxD. Thanks. There are some other utilities like COFF2OMF. it takes a coff object(msvc) and convert it to omf (delphi). I didn't use them but probably can work for you.
  16. @pyscripter Yes this is correct. and it has a lazy form too : const __imp_VirtualAlloc: Pointer = @VirtualAlloc; __imp_VirtualFree: Pointer = @VirtualFree; Now to your linking issue. your best choice is to use a dll. If that is not an option, you can compile your c code for x86 using bcc32c and link the output with delphi. I did this several time and it works. EMB offers c/c++ compiler tool chain at no cost (only for x86). https://www.embarcadero.com/free-tools/ccompiler/ Use MSVC to compile for x64 and link (probably it already worked for you). If bcc32c is not an option, you can manually edit the generated object output(which I don't recommend) : use a hex editor and replace all imported function of your object file : // Replace '@' by '_' or better by a char that is not widely used. And make sure that the new name is not used elsewhere. // you are a scripter man ... you can write a script that do the work for you. __imp__VirtualAlloc@16 => __imp__VirtualAlloc_16 __imp__VirtualFree@12 => __imp__VirtualFree_12 // ---------------- delphi -------------- const __imp__VirtualAlloc_16: Pointer = @VirtualAlloc; __imp__VirtualFree_12: Pointer = @VirtualFree;
  17. Mahdi Safsafi

    GExperts supports even more laziness

    @dummzeuch I made some debugging and was able to get much more information about the exception. On the attached file you will find a lot of useful stuff plus some comment for clarification. I hope, you will find it useful for GExperts. ExceptionFilter.pas
  18. Mahdi Safsafi

    GExperts supports even more laziness

    Yeah I missed that.
  19. Mahdi Safsafi

    GExperts supports even more laziness

    Filtering is based on regex ... does using '.*' counts ?
  20. Mahdi Safsafi

    GExperts supports even more laziness

    Almost forget that information. Thanks.
  21. Mahdi Safsafi

    GExperts supports even more laziness

    Very good. Just wondering does this behavior occur only on D2005? Or all older versions too?
  22. Mahdi Safsafi

    GExperts supports even more laziness

    Free and much important for me it is open source. I've a lot of respect for people that are behind great open source projects: FPC/Lazarus, JEDI, S4D, Fast/ScaleMM, HxD, ... and GExperts is no exception. I learned a lot from open source community. The least thing I can do is to provide feedback/help as long as its not beyond my knowledge. Thanks for your time and effort to keep GExpers shining. This is very kindness from you. Thanks man !
  23. Mahdi Safsafi

    GExperts supports even more laziness

    Sorry about that I miss understand your comment. I did some static disasm (no debugging) for the file you send me and it appeared that offset to DbgObj.Param has changed too 0x3C instead of 0x40. and for Param.FResume its 0x99 instead of 0xA1(you know that already). Try again with (0x3C, 0x99) and tell me if it works.
  24. Mahdi Safsafi

    GExperts supports even more laziness

    Just assume its 0x99 on D2006 and under... If it works than its 0x99. If it doesn't, send me win32debugideXxx. Bpl file for D2006... I'll take a look but I don't promise you anything as I only can do disassembling.
×