Jump to content

Leaderboard


Popular Content

Showing content with the highest reputation on 06/08/20 in all areas

  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. David Heffernan

    Byte and Integer

    Couldn't take the traffic of tens of devs trying to vote for range checking enabled by default
  3. Stefan Glienke

    Modern TColorDialog

    Afaik the dialog used by Delphi is just what the winapi offers.
  4. David Heffernan

    SendMessage From DLL

    Wait a minute. If its a 64 bit add in then why are you casting the pointer to a 32 bit integer?
  5. Kas Ob.

    SendMessage From DLL

    First Using Integer is dangerous here, though it is not the problem. Second : It is long shot but it might be the cause, check the permission and security setting, i have no idea what Word do have, but from the following 1) "When a message is blocked by UIPI the last error, retrieved with GetLastError, is set to 5 (access denied)." from SendMessage documentation 2) from detailed Remy answer on SO https://stackoverflow.com/questions/40122964/cross-process-postmessage-uipi-restrictions-and-uiaccess-true 3) Windows does have message filter, in case it is Word then Word process can and might be utilizing such filter i can conclude that security and permission might be in play here, right ? so i would recommend : Disable Antivirus's if there any to see if they are interacting here, there is few antivirus that block WM_COPYDATA when send to different process as extra protection, because they can. Check what does Word/Office in security settings have. Try to send different (innocent) message to see if it will be delivered at all. Is that WAR is yours ( dll allocated ) or Word's, may be Word can block different process from reading it process memory as security measure, in this case filtering out WM_COPYDATA, so if you copied the data first, by copy i mean copied the that buffer, but first you might test your dll sending it owns ( any temporary data) using WM_COPYDATA, this step too shed some light on this.
  6. Tom F

    Your RAD Studio 10.4 Sydney issues

    If you're waiting for Raize Konopka KSVC like I am, please vote for this issue: https://quality.embarcadero.com/browse/RSP-29400.
  7. Mahdi Safsafi

    Strange behavior for literals

    @Kas Ob. For programming language, the better way for my opinion is to refuse compiling. On x86, the CPU may just choose to mask the amount and continue execution. On ARM, It's even not possible to encode an amount (as immediate) that violates instruction range ! However when amount is specified as register. CPU masks the amount before processing the instruction: # x86: shl r/m32, amount # amount = amount and RegSizeMask. # aarch32(arm): lsl Rd Rm, 65 # you can not encode it ! lsl Rd, Rm, Rs # Rs = Rs and RegSizeMask. # aarch64: shl Vd, Vn, amount # UNDEFINED if shift > RegSizeMask! While masking the amount is the most popular way ... its still considered as unpredictable behavior and may vary between implementation and all are corrects ! MSVC: const int C = 1 << 100 ; // just warning ... but it compiles and gives 0! int main() { cout << C << endl; // C = 0. }
  8. Cristian Peța

    Your RAD Studio 10.4 Sydney issues

    Fixed (see report).
  9. Vandrovnik

    Strange behavior for literals

    I have asked, what you think is a bug. You have answered and I wrote you, how compiler probably decides the value and that I do not see a bug there. When you want to decide, whether Delphi is wrong with something, first you need a specifiaction saying, what is right. Then you can compare actual result with it. And do testing with current version of Delphi, because even if you find an error in old version, it will probably never be fixed.
  10. Stefan Glienke

    Byte and Integer

    Give some more votes to https://quality.embarcadero.com/browse/RSP-16751 maybe we get it some day...
  11. Dave Nottage

    StoryBoard launch screen - Delphi 10.4

    Renaming the app has the same effect. Certainly saves on having to restart the device 🙂
  12. David Heffernan

    Byte and Integer

    You should enable both range checking and overflow checking. Then you'll see your exceptions.
  13. Lars Fosdal

    Your RAD Studio 10.4 Sydney issues

    What I did to get my favorite color scheme from 10.3 to 10.4 and have it stick. In 10.4, go to Options | User Interface | Editor | Color With the current colors, just click on [Save As] and and give your personal scheme a name. I called mine Lars. This creates a Registry branch, named HKEY_CURRENT_USER\Software\Embarcadero\BDS\21.0\Editor\Highlight\Custom themes\Lars In RegEdit, go to HKEY_CURRENT_USER\Software\Embarcadero\BDS\20.0\Editor\Highlight (i.e. the Rio branch) Export to a file, f.x. MyColors.reg In MyColors.reg, you'll see Windows Registry Editor Version 5.00 [HKEY_CURRENT_USER\Software\Embarcadero\BDS\20.0\Editor\Highlight] [HKEY_CURRENT_USER\Software\Embarcadero\BDS\20.0\Editor\Highlight\Additional search match highlight] ... and so on Now, Open MyColors.reg in Notepad, search for "20.0\Editor\Highlight\" and replace it with "21.0\Editor\Highlight\Custom themes\Lars\". Add the two branch paths for good measure. Windows Registry Editor Version 5.00 [HKEY_CURRENT_USER\Software\Embarcadero\BDS\21.0\Editor\Highlight] [HKEY_CURRENT_USER\Software\Embarcadero\BDS\21.0\Editor\Highlight\Custom themes] [HKEY_CURRENT_USER\Software\Embarcadero\BDS\21.0\Editor\Highlight\Custom themes\Lars] [HKEY_CURRENT_USER\Software\Embarcadero\BDS\21.0\Editor\Highlight\Custom themes\Lars\Additional search match highlight] ... and so on Import the file into the registry, Restart the 10.4, go to Options | User Interface | Editor | Color and pick the custom theme "Lars".
  14. @Yaron I use this library https://github.com/CMCHTPC/DelphiDX12 This was made to be used with FPC firstly, you will see many hints and warnings compiling to Delphi. But it still works for me.
×