Some question(s) about compilers and static allocation

Hi,
Often I wonder about this or that point of code and how or if the compiler optimizes it. Not really relevant with my small progress but I always had an interest in technical details.
So I might as well use this thread to ask.
I wondered for instance, how things like

t: array (1..10) of access constant String := [new String'("a"), new String'("bbb"), others => null]

were handled. Because while it uses an allocator… the value is statistically known, and constant ensures there will be no change, nothing dynamic.
So is the heap used, or does the compiler knows to use static data lined up in a row, like an array except using a table of pointers instead of a starting point and an offset (although I don’t know how normal arrays are handled in Ada, or if there is even a standard).

new uses the global pool (heap) unless you tell it not to.

In the past I’ve used something like this, which results in static data (the code was created by a tool).

pragma Restrictions (No_Elaboration_Code);
package Array_Of_Strings is

   Friend : aliased constant String := "friend";
   Enemy  : aliased constant String := "enemy";

   Strings : constant array (Natural range <>) of access constant String
     := (0 => Friend'Access,
         1 => Enemy'Access);

end Array_Of_Strings;

Ah ! using access to constant types is cheating ! However it does make an array with components of variable length. But what does that have to do with pragma Restrictions (No_Elaboration_Code);
?

Is there a pragma to not use the heap when the variable is constant and the expression static ?

Well if the compiler decided not to make the array at compile time (statically) then it would use elaboration code to do so. Setting the pragma there helps catch if the compiler tries to make it at runtime for the example.

In a real world example you may want elaboration code or other things in the package (and would leave out the pragma in those cases), but for this example you want to ensure it is generated statically, so the pragma helps catch it if not.

2 Likes

You can also use static expression functions if you are ok using strings instead of access to strings and the strings can be different sizes as well. You can use the function syntactically identical to an array in Ada since both use parenthesis.

    subtype String_Index is Positive range 1 .. 12;
    function Strings(Index : String_Index) return String is
        (case Index is
            when  1 => "H",
            when  2 => "e",
            when  3 => "l",
            when  4 => "l",
            when  5 => "o",
            when  6 => " ",
            when  7 => "W",
            when  8 => "o",
            when  9 => "r",
            when 10 => "l",
            when 11 => "d",
            when 12 => "!!!!")
    with Static;   -- Notice the aspect here!!

That is guaranteed to be compile time eligible per the RM (See sections 4.9 and 6.8 linked below) while constant variables are not. However, a good compiler will do either as compile time, so this is just an optional way of doing things:

NOTE: You have to pass in a static index to get a guaranteed static string out. If you pass a variable index in, then all guarantees of being static are dropped. That’s so you can use a static expression in both a static context and a runtime context without issue. So for example Strings(1) will return a static string while Strings(Variable_Index) may or may not return a static string based on how Variable_index is declared and your compiler.

Static: Static Expressions and Static Subtypes
Static Aspect: Expression Functions

2 Likes

Beats me. This is hilariously counter-intuitive ! I find the function so cool, and I’d rather do without any reference to pointers whenever possible so thanks.

Actually, for access constant the compiler can do other things. In particular, the Green Hills AdaMulti and the PTC ObjectAda compilers, I believe, will statically allocate the content designated by an access constant, if the designated value is compile-time known. GNAT will always use the heap, I believe.

1 Like