Thread overview | |||||||||
---|---|---|---|---|---|---|---|---|---|
|
November 08, 2013 spurious gc allocation | ||||
---|---|---|---|---|
| ||||
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? |
November 08, 2013 Re: spurious gc allocation | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ellery Newcomer | 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
|
November 08, 2013 Re: spurious gc allocation | ||||
---|---|---|---|---|
| ||||
Posted in reply to Benjamin Thaut | 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.
|
November 09, 2013 Re: spurious gc allocation | ||||
---|---|---|---|---|
| ||||
Posted in reply to Timon Gehr | On 11/08/2013 06:19 AM, Timon Gehr wrote:
> 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.
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?
|
November 09, 2013 Re: spurious gc allocation | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ellery Newcomer | 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(); } |
November 09, 2013 Re: spurious gc allocation | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ellery Newcomer | 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
|
November 09, 2013 Re: spurious gc allocation | ||||
---|---|---|---|---|
| ||||
Posted in reply to lomereiter | 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 |
Copyright © 1999-2021 by the D Language Foundation