digitalmars.D - Does foreach on array literal allocate?
- Bill Baxter (14/14) Dec 04 2008 Does anyone know off the top of their head if code like this allocates
- Sergey Gromov (3/20) Dec 04 2008 AFAIK array iteration never used delegates. Therefore it shouldn't have
- Bill Baxter (5/25) Dec 04 2008 Walter's answer is more what I was after. I wasn't worried about the
- Walter Bright (69/76) Dec 04 2008 Here's how to find out. Compile:
- Bill Baxter (20/31) Dec 04 2008 Thanks for the explanation. Though Obj2Asm is I think part of the EUP, ...
- Walter Bright (4/28) Dec 04 2008 I agree the compiler could do better there. There is a lot of
- Kagamin (2/10) Dec 05 2008 http://d.puremagic.com/issues/show_bug.cgi?id=2356
- Lionello Lunesu (74/89) Dec 04 2008 Short answer: yes, they both allocate memory.
- Lionello Lunesu (2/2) Dec 04 2008 Walter beat me to it! Oh well, it was a nice exercise :)
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
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: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. --bbDoes 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
On Fri, Dec 5, 2008 at 10:37 AM, Walter Bright <newshound1 digitalmars.com> wrote:Bill Baxter wrote:Thanks for the explanation. Though Obj2Asm is I think part of the EUP, right? Maybe I'll get that after all.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: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
Bill Baxter wrote: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.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
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









"Bill Baxter" <wbaxter gmail.com> 