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









Ellery Newcomer <ellery-newcomer utulsa.edu> 