Troubles with immutable arrays

bearophile bearophileHUGS at lycos.com
Mon Jul 23 06:29:18 PDT 2012


After a discussion in D.learn started by someone else, after a 
suggestion of mine Timon Gehr has added a bug report:

http://d.puremagic.com/issues/show_bug.cgi?id=8400

But the bug was fixed in the opposite way of what I was thinking.

The problem was that the length of global immutable arrays arrays 
is seen as a compile-time constant.
Instead of fixing that, Issue 8400 has done the opposite, now 
even the lenght of local immutable arrays is seen sometimes as a 
compile-time constant, and example:


int[] foo(in int n) pure nothrow {
     int[] a;
     foreach (i; 0 .. n)
         a ~= i * 10;
     return a;
}
void main() {
     import core.stdc.stdio: printf;
     immutable int[] A = foo(5);
     int[A.length] B;
     printf("%zd\n", B.length);
}



The asm, compiled with -release:

_D4temp3fooFNaNbxiZAi   comdat
L0:     enter   018h,0
         push    EBX
         push    ESI
         mov dword ptr -018h[EBP],0
         mov dword ptr -014h[EBP],0
         mov dword ptr -010h[EBP],0
         mov -0Ch[EBP],EAX
L1E:        mov EAX,-010h[EBP]
         cmp EAX,-0Ch[EBP]
         jge L48
         lea ECX,-010h[EBP]
         mov EDX,[ECX]
         lea EBX,[EDX*4][EDX]
         add EBX,EBX
         push    EBX
         lea ESI,-018h[EBP]
         push    ESI
         mov EAX,offset FLAT:_D11TypeInfo_Ai6__initZ
         push    EAX
         call    near ptr __d_arrayappendcT
         add ESP,0Ch
         inc dword ptr -010h[EBP]
         jmp short   L1E
L48:        mov EDX,-014h[EBP]
         mov EAX,-018h[EBP]
         pop ESI
         pop EBX
         leave
         ret

__Dmain comdat
L0:     enter   018h,0
         push    EBX
         push    ESI
         push    5
         mov EAX,offset FLAT:_D11TypeInfo_Ai6__initZ
         push    EAX
         call    near ptr __d_arrayliteralTX
         mov dword ptr [EAX],0
         mov dword ptr 4[EAX],0Ah
         mov dword ptr 8[EAX],014h
         mov dword ptr 0Ch[EAX],01Eh
         mov dword ptr 010h[EAX],028h
         mov ECX,EAX
         mov EBX,5
         lea EDX,-018h[EBP]
         xor EAX,EAX
         mov [EDX],EAX
         mov 4[EDX],EAX
         mov 8[EDX],EAX
         mov 0Ch[EDX],EAX
         mov 010h[EDX],EAX
         push    5
         mov ESI,offset FLAT:_DATA
         push    ESI
         call    near ptr _printf
         xor EAX,EAX
         add ESP,010h
         pop ESI
         pop EBX
         leave
         ret



This code too compiles, so A is sometimes computed at run-time 
and sometimes at compile-time:

int[] foo(in int n) pure nothrow {
     int[] a;
     foreach (i; 0 .. n)
         a ~= i * 10;
     return a;
}
void main() {
     import core.stdc.stdio: printf;
     int n = 5;
     immutable int[] A = foo(n);
}



Now immutable arrays are sometimes seen as enums. I think this is 
a problem. I think in D compile-time is run only if it's 
evaluated in a context where compile-time values are required. 
But now the situation is more muddy, because knowing n at 
compile-time is not a way to ask A to be computed at compile-time.

Another problem is that compile-time arrays in many situations 
are not efficient, they gets copied every time you use them, and 
I think that __d_arrayliteralTX performs a heap allocation. So 
now both enum and immutable arrays perform heap allocations every 
time you use them, but only in some situations.

I think this is a messy situation, I think the fix for bug 8400 
should be undone, and I think Issue 8400 should be fixed the 
other way, turning global immutable arrays too into run-time 
entities.

The bug was fixed by Hara and accepted by Walter, both of them 
are very intelligent, so maybe I am just very wrong :-)

Bye,
bearophile


More information about the Digitalmars-d mailing list