digitalmars.D - Does foreach on array literal allocate?
- "Bill Baxter" <wbaxter gmail.com> Dec 04 2008
- Sergey Gromov <snake.scaly gmail.com> Dec 04 2008
- Walter Bright <newshound1 digitalmars.com> Dec 04 2008
- Walter Bright <newshound1 digitalmars.com> Dec 04 2008
- Kagamin <spam here.lot> Dec 05 2008
- "Lionello Lunesu" <lionello lunesu.remove.com> Dec 04 2008
- "Lionello Lunesu" <lionello lunesu.remove.com> Dec 04 2008
- "Bill Baxter" <wbaxter gmail.com> Dec 04 2008
- "Bill Baxter" <wbaxter gmail.com> Dec 04 2008
Does anyone know off the top of their head if code like this allocates
or not with current DMD 1.x compilers?
foreach(x; [1, 2, 3, 4])
{
// do something non-allocating with x
}
And is the answer different if the values are only known at runtime? Like here:
void a func(int a1, int a2, int a3)
{
foreach(x; [a1,a2,a3]) {
// do something non-allocating with x
}
}
--bb
Dec 04 2008
Fri, 5 Dec 2008 03:58:39 +0900, Bill Baxter wrote:Does anyone know off the top of their head if code like this allocates or not with current DMD 1.x compilers? foreach(x; [1, 2, 3, 4]) { // do something non-allocating with x } And is the answer different if the values are only known at runtime? Like here: void a func(int a1, int a2, int a3) { foreach(x; [a1,a2,a3]) { // do something non-allocating with x } }
AFAIK array iteration never used delegates. Therefore it shouldn't have been ever allocating, and it shouldn't now.
Dec 04 2008
Bill Baxter wrote:Does anyone know off the top of their head if code like this allocates or not with current DMD 1.x compilers? foreach(x; [1, 2, 3, 4]) { // do something non-allocating with x }
Here's how to find out. Compile: void test() { foreach(x; [1, 2, 3, 4]) { // do something non-allocating with x } } Obj2asm the output: _D5test44testFZv comdat assume CS:_D5test44testFZv L0: enter 8,0 push EBX push 4 push 3 push 2 push 1 push 4 push offset FLAT:_D12TypeInfo_G4i6__initZ call near ptr __d_arrayliteralT mov -8[EBP],EAX lea EAX,010h[EAX] mov -4[EBP],EAX add ESP,018h L25: mov ECX,-8[EBP] cmp ECX,-4[EBP] jae L38 mov EDX,-8[EBP] mov EBX,[EDX] add dword ptr -8[EBP],4 jmp short L25 L38: pop EBX leave ret _D5test44testFZv ends Look up _d_arrayliteralT in the runtime library: extern (C) void* _d_arrayliteralT(TypeInfo ti, size_t length, ...) { auto sizeelem = ti.next.tsize(); // array element size void* result; debug(PRINTF) printf("_d_arrayliteralT(sizeelem = %d, length = %d)\n", sizeelem, length); if (length == 0 || sizeelem == 0) result = null; else { result = gc_malloc(length * sizeelem, !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0); va_list q; va_start!(size_t)(q, length); size_t stacksize = (sizeelem + int.sizeof - 1) & ~(int.sizeof - 1); if (stacksize == sizeelem) { memcpy(result, q, length * sizeelem); } else { for (size_t i = 0; i < length; i++) { memcpy(result + i * sizeelem, q, sizeelem); q += stacksize; } } va_end(q); } return result; } and note the call to gc_malloc().
Dec 04 2008
Bill Baxter wrote:and note the call to gc_malloc().
Bummer.
I agree the compiler could do better there. There is a lot of opportunity for better optimization. I haven't spent time on it because of all the other things that need doing first.Does a static-sized array initializer also allocate? int[4] v = [1,2,3,4]; foreach(x; v) { /// ... } Or maybe this (also) works without allocation? foreach(x; Tuple!(1,2,3,4)) { /// } This kinda code is useful for the case where you have to do the same thing to two or three local variables. You can write a local function to do it, but foreach on a static set of them breaks up the visual flow of the code a little less, I think. --bb
Dec 04 2008
Bill Baxter Wrote:Bummer. Does a static-sized array initializer also allocate? int[4] v = [1,2,3,4]; foreach(x; v) { /// ... }
http://d.puremagic.com/issues/show_bug.cgi?id=2356
Dec 05 2008
Short answer: yes, they both allocate memory.
Long answer:
_d_arrayliteralT from gc.d is used to create an array:
import std.stdio;
void main()
{
foreach(r; [1, 2, 3])
writefln(r);
asm { nop; }
int a,b,c;
foreach(r; [a, b, c])
writefln(r);
}
__Dmain comdat
assume CS:__Dmain
L0: push EBP
mov EBP,ESP
sub ESP,028h
push 3
push 2
push 1
push 3
push offset FLAT:_D12TypeInfo_G3i6__initZ
call near ptr __d_arrayliteralT
mov -024h[EBP],EAX
mov EAX,-024h[EBP]
lea EAX,0Ch[EAX]
mov -020h[EBP],EAX
add ESP,014h
L27: mov EAX,-024h[EBP]
cmp EAX,-020h[EBP]
jae L4D
mov EAX,-024h[EBP]
mov EAX,[EAX]
mov -01Ch[EBP],EAX
push dword ptr -01Ch[EBP]
push offset FLAT:_D12TypeInfo_B1i6__initZ
call near ptr _D3std5stdio8writeflnFYv
add dword ptr -024h[EBP],4
add ESP,8
jmp short L27
L4D: nop
xor EAX,EAX
mov -018h[EBP],EAX
mov -014h[EBP],EAX
mov -010h[EBP],EAX
push dword ptr -010h[EBP]
push dword ptr -014h[EBP]
push dword ptr -018h[EBP]
push 3
push offset FLAT:_D12TypeInfo_G3i6__initZ
call near ptr __d_arrayliteralT
mov -0Ch[EBP],EAX
mov EAX,-0Ch[EBP]
lea EAX,0Ch[EAX]
mov -8[EBP],EAX
add ESP,014h
L7D: mov EAX,-0Ch[EBP]
cmp EAX,-8[EBP]
jae LA3
mov EAX,-0Ch[EBP]
mov EAX,[EAX]
mov -4[EBP],EAX
push dword ptr -4[EBP]
push offset FLAT:_D12TypeInfo_B1i6__initZ
call near ptr _D3std5stdio8writeflnFYv
add dword ptr -0Ch[EBP],4
add ESP,8
jmp short L7D
LA3: mov ESP,EBP
pop EBP
ret
"Bill Baxter" <wbaxter gmail.com> wrote in message
news:mailman.92.1228417124.22690.digitalmars-d puremagic.com...
Does anyone know off the top of their head if code like this allocates
or not with current DMD 1.x compilers?
foreach(x; [1, 2, 3, 4])
{
// do something non-allocating with x
}
And is the answer different if the values are only known at runtime? Like
here:
void a func(int a1, int a2, int a3)
{
foreach(x; [a1,a2,a3]) {
// do something non-allocating with x
}
}
--bb
Dec 04 2008
Walter beat me to it! Oh well, it was a nice exercise :) L.
Dec 04 2008
On Fri, Dec 5, 2008 at 10:31 AM, Sergey Gromov <snake.scaly gmail.com> wrote:Fri, 5 Dec 2008 03:58:39 +0900, Bill Baxter wrote:Does anyone know off the top of their head if code like this allocates or not with current DMD 1.x compilers? foreach(x; [1, 2, 3, 4]) { // do something non-allocating with x } And is the answer different if the values are only known at runtime? Like here: void a func(int a1, int a2, int a3) { foreach(x; [a1,a2,a3]) { // do something non-allocating with x } }
AFAIK array iteration never used delegates. Therefore it shouldn't have been ever allocating, and it shouldn't now.
Walter's answer is more what I was after. I wasn't worried about the D2 delegate allocation stuff, but rather the little array literal would be put on the stack or not. --bb
Dec 04 2008
On Fri, Dec 5, 2008 at 10:37 AM, Walter Bright <newshound1 digitalmars.com> wrote:Bill Baxter wrote:Does anyone know off the top of their head if code like this allocates or not with current DMD 1.x compilers? foreach(x; [1, 2, 3, 4]) { // do something non-allocating with x }
Here's how to find out. Compile:
Thanks for the explanation. Though Obj2Asm is I think part of the EUP, right? Maybe I'll get that after all.and note the call to gc_malloc().
Bummer. Does a static-sized array initializer also allocate? int[4] v = [1,2,3,4]; foreach(x; v) { /// ... } Or maybe this (also) works without allocation? foreach(x; Tuple!(1,2,3,4)) { /// } This kinda code is useful for the case where you have to do the same thing to two or three local variables. You can write a local function to do it, but foreach on a static set of them breaks up the visual flow of the code a little less, I think. --bb
Dec 04 2008









Sergey Gromov <snake.scaly gmail.com> 