digitalmars.D.learn - spurious gc allocation
- Ellery Newcomer (37/37) Nov 07 2013 hello all.
- Benjamin Thaut (7/44) Nov 07 2013 The problem is that you define the struct Thing as a inner struct. Inner...
- Timon Gehr (3/4) Nov 08 2013 struct Thing only exists in the decompiled version, not in the original
- Ellery Newcomer (38/44) Nov 08 2013 I've reduced it to the following:
- lomereiter (11/11) Nov 09 2013 Indeed, disassembly reveals an allocation (with all three
- Ellery Newcomer (4/15) Nov 09 2013 oh, I see, it's the delegate doing that. that's helpful.
- bearophile (30/31) Nov 09 2013 I only see the class instance allocation in the main(). I use two
hello all. I have a class member function that essentially looks like this: ThisNode* _InsertAllBut(int value) { ThisNode* node = MallocAllocator.allocate!(ThisNode)(1); node.value = value; node_count++; return node; } I compile it on x86_64 and the compiler inserts a gc allocation. I decompiled it, and it looks like it does this: ThisNode* _InsertAllBut(int value) { struct Thing { typeof(this) thing1; ThisNode* thing2; int thing3; } Thing* rbp28 = _d_allocmemory(0x14); rbp28.thing1 = this; rbp28.thing3 = value; if (this == 0) { // not wasting my time figuring out _d_assert_msg's calling conventions r8d = 0x137c; rcx = something pointing to "src/multi_index.d"; rdi = {length associated with rsi}; rsi = something pointing to "null this"; rdx = {length associated with rcx}; _d_assert_msg(); } invariant._d_invariant(this); rbp28.thing2 = MallocAllocator.allocate(1); rbp28.thing2.value = rbp28.thing3; this.nodecount ++; return rbp28.thing2; } So. Why the heck is it using heap space for stack space? How the heck am I supposed to call this from within a destructor?
Nov 07 2013
Am 08.11.2013 06:19, schrieb Ellery Newcomer:hello all. I have a class member function that essentially looks like this: ThisNode* _InsertAllBut(int value) { ThisNode* node = MallocAllocator.allocate!(ThisNode)(1); node.value = value; node_count++; return node; } I compile it on x86_64 and the compiler inserts a gc allocation. I decompiled it, and it looks like it does this: ThisNode* _InsertAllBut(int value) { struct Thing { typeof(this) thing1; ThisNode* thing2; int thing3; } Thing* rbp28 = _d_allocmemory(0x14); rbp28.thing1 = this; rbp28.thing3 = value; if (this == 0) { // not wasting my time figuring out _d_assert_msg's calling conventions r8d = 0x137c; rcx = something pointing to "src/multi_index.d"; rdi = {length associated with rsi}; rsi = something pointing to "null this"; rdx = {length associated with rcx}; _d_assert_msg(); } invariant._d_invariant(this); rbp28.thing2 = MallocAllocator.allocate(1); rbp28.thing2.value = rbp28.thing3; this.nodecount ++; return rbp28.thing2; } So. Why the heck is it using heap space for stack space? How the heck am I supposed to call this from within a destructor?The problem is that you define the struct Thing as a inner struct. Inner structs have references to the outer class instance they have been created from. If you want a plain old struct you have to write static struct Thing { ... } Kind Regards Benjamin Thaut
Nov 07 2013
On 11/08/2013 07:12 AM, Benjamin Thaut wrote:The problem is that you define the struct Thing as a inner struct.struct Thing only exists in the decompiled version, not in the original source. So far it looks like a bug to me.
Nov 08 2013
On 11/08/2013 06:19 AM, Timon Gehr wrote:On 11/08/2013 07:12 AM, Benjamin Thaut wrote:I've reduced it to the following: a.d: class C { void _InsertAllBut(int v) { int* node = null; enum mutable = __traits(compiles, {node.value ;}); } } test.d: import a; void main () { C c = new C(); c._InsertAllBut(1); } compile: dmd test.d a.d order doesn't seem to matter, works with -m32 and -m64, apparently I am running dmd v2.063-devel-e23c785 objdump -d --disassembler-options=intel test | ddemangle shows me ... 0000000000417888 <void a.C._InsertAllBut(int)>: 417888: 55 push rbp 417889: 48 8b ec mov rbp,rsp 41788c: 48 83 ec 38 sub rsp,0x38 417890: 53 push rbx 417891: 48 89 7d f0 mov QWORD PTR [rbp-0x10],rdi 417895: 48 bf 10 00 00 00 00 movabs rdi,0x10 41789c: 00 00 00 41789f: e8 10 22 00 00 call 419ab4 <_d_allocmemory> 4178a4: 48 89 45 e0 mov QWORD PTR [rbp-0x20],rax 4178a8: 48 8b 4d f0 mov rcx,QWORD PTR [rbp-0x10] 4178ac: 48 89 08 mov QWORD PTR [rax],rcx 4178af: 48 85 c9 test rcx,rcx ... can anyone confirm?The problem is that you define the struct Thing as a inner struct.struct Thing only exists in the decompiled version, not in the original source. So far it looks like a bug to me.
Nov 08 2013
Indeed, disassembly reveals an allocation (with all three compilers => it's the front-end which generates this crap). I guess the compiler incorrectly treats { node.value; } as a delegate and copies the node to GC heap. void foo() { int* node = null; enum mutable = __traits(compiles, {node.value ;}); } void main() { foo(); }
Nov 09 2013
On 11/09/2013 12:35 AM, lomereiter wrote:Indeed, disassembly reveals an allocation (with all three compilers => it's the front-end which generates this crap).ouch.I guess the compiler incorrectly treats { node.value; } as a delegate and copies the node to GC heap. void foo() { int* node = null; enum mutable = __traits(compiles, {node.value ;}); } void main() { foo(); }oh, I see, it's the delegate doing that. that's helpful. https://d.puremagic.com/issues/show_bug.cgi?id=11483
Nov 09 2013
Ellery Newcomer:can anyone confirm?I only see the class instance allocation in the main(). I use two modules, with your code. I compile on Windows 32, using no compilation flags, and I see this asm, with obj2asm: _D1a1C13_InsertAllButMFiZv: push EAX push EAX mov [ESP],0 add ESP,8 ret 4 __Dmain: L0: mov EAX,offset FLAT:_D1a1C7__ClassZ push EAX call near ptr __d_newclass push 1 mov ECX,[EAX] call dword ptr 014h[ECX] xor EAX,EAX add ESP,4 ret _main: L0: mov EAX,offset FLAT:__Dmain push EAX push dword ptr 0Ch[ESP] push dword ptr 0Ch[ESP] call near ptr __d_run_main add ESP,0Ch ret Bye, bearophile
Nov 09 2013