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