Jump to content

Mahdi Safsafi

Members
  • Content Count

    249
  • Joined

  • Last visited

  • Days Won

    6

Everything posted by Mahdi Safsafi

  1. Mahdi Safsafi

    GExperts supports even more laziness

    Yes it comes very handy and it would be much more powerful when it supports class inheritance check(ignoring all exceptions that descent from a particular class). One thing worth to mention, Thomas told me that he managed to make it works on all Delphi versions >= 2005.
  2. Mahdi Safsafi

    Update: C++Builder and Platforms Support

    @Kas Ob. Well I was referring to the decision. The chance to improve quality is higher when you only focus on one thing.
  3. Mahdi Safsafi

    Update: C++Builder and Platforms Support

    IMO, this is the right decision. What do you think guys ?
  4. Mahdi Safsafi

    Translation of C headers.

    Good point Attila. It also makes comparing c code against Delphi code much easy.
  5. Mahdi Safsafi

    Translation of C headers.

    Not IDA ... its x64dbg 🙂
  6. Mahdi Safsafi

    Translation of C headers.

    I really don't know. Well I never tried to consume Delphi stuff from c/c++ mostly because c/c++ has a much native frameworks than Delphi ... However I do consume c/c++ stuff from Delphi.
  7. Mahdi Safsafi

    Translation of C headers.

    Those are not stored inside vtable ... you need to skip them(don't declare them). Exactly! That's my bad man ... I'm a little bit bad at explaining since I'm not a native English speaker. First step, add all methods in the order they declared(skip all overloaded versions but keep the original). second step for each added method "A" add just after it "A" all its overloaded versions in the order they declared too. Here is how your vtable looks like.
  8. Mahdi Safsafi

    Translation of C headers.

    Basically vtable respects the order in which functions are declared. But here the overloading is tweaking. Try to respect both the order and overloading name. The below code should demonstrate what I mean. // SetAttributeValue declared first ... we put it first function SetAttributeValue(name: LPWSTR; _type: D2D1_SVG_ATTRIBUTE_STRING_TYPE; value: LPWSTR): HResult; overload; stdcall; // then we put all overloaded methods SetAttributeValue but in the order they were declared: function SetAttributeValue(name: LPWSTR; _type: D2D1_SVG_ATTRIBUTE_POD_TYPE; value: Pointer; valueSizeInBytes: UINT32): HResult; overload; stdcall; // SetAttributeValue2 function SetAttributeValue(name: LPWSTR; value: ID2D1SvgAttribute): HResult; overload; stdcall; // SetAttributeValue3 // GetAttributeValue comes after SetAttributeValue: function GetAttributeValue(name: LPWSTR; _type: D2D1_SVG_ATTRIBUTE_STRING_TYPE; out value: PWideChar; valueCount: UINT32): HResult; overload; stdcall; // overloaded2 first and then overloaded3 function GetAttributeValue(name: LPWSTR; _type: D2D1_SVG_ATTRIBUTE_POD_TYPE; value: Pointer; valueSizeInBytes: UINT32): HResult; overload; stdcall; // overloaded2 function GetAttributeValue(name: LPWSTR; const riid: TGUID; var value: Pointer): HResult; overload; stdcall; // overloaded3 PS: I got the smile SVG 🙂
  9. Mahdi Safsafi

    Translation of C headers.

    @pyscripter I believe you're wrong on $78 ! its for an overloaded GetAttributeValue function (not SetAttributeValue). So your code is calling an overloaded version of GetAttributeValue instead of SetAttributeValue.
  10. Mahdi Safsafi

    Help with string extraction function

    Yes you're absolutely right ... I don't really know how the post ended like this. Anyway, it was really nice to have this little discussion with you. Thanks for your time and the valuable information/material you provide.
  11. Mahdi Safsafi

    Help with string extraction function

    Secret ? no, they're publicly published (agner, intel/amd doc, optimization guide, paper, LLVM, ...). I read them and experiment things my self and when I have no things to do I compare results on different compilers. Sometime, when I'm lucky, I find an already benchmark that lists the results. Error happens a lot specially when porting code from/to another platform ... but I deeply inspects the error and try to learn from it : why it happened ? a workaround ? how to avoid it?.
  12. Mahdi Safsafi

    Help with string extraction function

    Yes, I use several compilers (not limited to Delphi) and I can sadly tell you that Pascal compilers didn't evolved in a good way like other compilers. Its not about whether you like them or not. In fact for me, I don't find any issue using low level stuff pointer or assembly. But today, I try to be much wise and choose the best friendly way for the compiler. What are you missing is that today sophisticated compiler in many case can do better job than you can do by using low level stuff like assembly or pointer. gcc for example is able to recognize a pattern (while do) that calculates bits count and replace this loop by a single instruction. It can reorder things for you when it detects that you're misusing some functionality: see this SO. A compiler could generate much better code only when it can understood your code. If you manage to write a hard code that your compiler can't understand it wan't be optimized correctly. Here is a simple example to show what would happen when the compiler does not understand your code: both swap/swap2 function do the same job but one is decrementing i and the other one is incrementing i. and both log the result using a for loop. The interesting part is that unlike swap, the two loop of swap2 were merged together __declspec(noinline) void swap(short int* src, int* dst, int count) { short int* p = src; int* r = dst; int i = count; // loop 1 while (i--) { *r++ = swapint(*p++); } // loop 2 for (int i = 0; i < count; i++) printf("%d = %d\n", i, dst[i]); return ; } __declspec(noinline) void swap2(short int* src, int* dst, int count) { short int* p = src; int* r = dst; int i = count; // compiler merged/combined the two loop ! while (i++ != count) { *r++ = swapint(*p++); } for (int i = 0; i < count; i++) printf("%d = %d\n", i, dst[i]); return; } int main() { short int src[10] = { 1,2,3,4,5 }; int dst[10] = { 0 }; swap(&src[0], &dst[0], 10); swap2(&src[0], &dst[0], 10); return 0; }
  13. Mahdi Safsafi

    GExperts supports even more laziness

    WaitForDebugEvent function is called from the debug loop thread but DoShowException function is called from another thread. A fraction of eye before DoShowException is called, WaitForDebugEvent may receive a debug event exception which may override FDebugEvent variable and you may end up processing the new exception and missing the old one. Using a list of FDebugEvent will guarantee that for each exception, you have a valid associated FDebugEvent struct. I don't know if there is a better way to work around without using a list of FDebugEvent. If you find a better way, please let me know. Apart from that, are you making any progress ? did the non-WaitForDebugEvent-method worked for all new Delphi versions ?
  14. Mahdi Safsafi

    TLabel in a TTitleBarPanel??

    I think that the right thing is to report it as a false positive at BD.
  15. Mahdi Safsafi

    Just-in-time compiling for Delphi's Regular Expressions

    @pyscripter I just made a benchmark against Perl regex. Yes its weird to compare a compiler vs interpreter ... but Perl beats Delphi own & study regex. However it failed to bit jit regex. A script and detailed result are attached. Benchmark.rar
  16. @pyscripter Here is the x86 function. But its really weird, the original version shipped with Delphi declares it as empty and it works. I don't understand why it crashed with you when you defined it as empty. @Kas Ob's point is very interesting. I didn't read the configuration's documentation. But he definitely did ... Perhaps he is right. I suggest that you check with him that point. And who knows ... you may not need to use chkstk. chkstk.txt
  17. Wow ... that's a 100mb !
  18. Yeah I know that, I early proposed to you to use MSVC for x64 and bcc32c for x86. Sadly bcc32c (at least the free version) is build on an old LLVM compiler. Good luck ! if you need some help let me know.
  19. From what I understood from your comment, you're going to compile using MSVC and then use some tools to convert the output ? why not give bcc32c a chance ? if it does not work ... you can simply use plan B.
  20. @pyscripter Anyway I compiled (using CLANG) a simple c code that I tweaked to use chkstk. and then I dumped the function and edited it to be compatible with Delphi : procedure chkstk(); asm .NOFRAME sub rsp, $10 mov [rsp], r10 mov [rsp+8], r11 xor r11,r11 lea r10, [rsp+$18] sub r10,rax cmovb r10,r11 mov r11, qword ptr gs:[$10] cmp r10,r11 db $f2 jae @@L1 and r10w,$F000 @@L2: lea r11, [r11-$1000] mov byte [r11],0 cmp r10,r11 db $f2 jne @@L2 @@L1: mov r10, [rsp] mov r11, [rsp+8] add rsp, $10 db $f2 ret end; EDIT: I didn't pay attention to the GAS syntax for branch and interpreted it as hex ... My bad.
  21. I'd help ... I'm just checking other options.
  22. Yes disabling stack check will not suppress ___chkstk_ms. Only /GsX will do provided that this option is supported by your compiler and X is higher than probe size. Now. are you sure that the crash comes from ___chkstk_ms ? also have you disabled other runtime check ?
  23. 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.
  24. 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.
  25. Can you please explain more. Im unable to understand what you exactly mean? Better to give an example.. So I can catch.
×