Bug 3490 – DMD Never Inlines Functions that Could Throw
Status
RESOLVED
Resolution
FIXED
Severity
normal
Priority
P2
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2009-11-09T06:26:00Z
Last change time
2014-03-18T13:21:54Z
Keywords
bounty, performance
Assigned to
nobody
Creator
dsimcha
Comments
Comment #0 by dsimcha — 2009-11-09T06:26:18Z
Here's an absurdly simple test program. enforceStuff() does not get inlined, as the disassembly below shows. I couldn't find anything about exceptions in inline.c, but if this doesn't get inlined, I assume nothing that could throw ever does.
This severely affects the performance of std.range, since Andrei uses enforce() all over the place, causing lots of stuff not to be inlined. For example, I read disassemblies involving std.range.Take and it seems like Take.popFront() and Take.front() are never inlined.
void main() {
enforceStuff(1);
}
void enforceStuff(uint num) { // Not inlined.
if(num == 0) {
throw new Exception("");
}
}
Disassembly of main():
__Dmain PROC NEAR
; COMDEF __Dmain
push eax ; 0000 _ 50
mov eax, 1 ; 0001 _ B8, 00000001
call _D5test812enforceStuffFkZv ; 0006 _ E8, 00000000(rel)
xor eax, eax ; 000B _ 31. C0
pop ecx ; 000D _ 59
ret ; 000E _ C3
__Dmain ENDP
Comment #1 by ary — 2009-11-09T06:32:37Z
Here's why:
int Statement::inlineCost(InlineCostState *ics)
{
return COST_MAX; // default is we can't inline it
}
and ThrowStatement never overrides it.
Comment #2 by leandro.lucarella — 2010-07-08T06:54:15Z
I'm marking this a a blocker of bug 859 so there is a single bug to track all
the inlining issues. Please do the same if you open more bugs associated to
inlining, or post them directly in bug 859.
Comment #3 by braddr — 2010-07-08T22:47:07Z
undoing false dependency
Comment #4 by leandro.lucarella — 2010-07-09T06:14:20Z
(In reply to comment #3)
> undoing false dependency
Can you elaborate a little on why having bug 859 as a tracker of all missing inline oportunities is a bad thing?
Thanks
Comment #5 by bus_dbugzilla — 2014-03-12T07:54:51Z
While DMD still doesn't inline functions that (directly) contain a "throw" statement, the original poster's issues with std.range and emplace have largely been addressed several versions ago (at least as far back as 2.060, maybe more):
- Many uses of enforce in std.range, such as the ones in Take, have been replaced by asserts.
- Functions like Take.popFront() and Take.front() are inlined (likely due to the switch to assert).
- Some of the enforce functions (except for errnoEnforce and the enforce that takes a lazy Throwable as a param) are inlineable because they don't use "throw" directly. Instead, they call the private helper "bailOut" which does the actual throwing. The "bailOut" function isn't inlineable, but that shouldn't be a problem since it only gets called when the condition fails.
Comment #6 by bus_dbugzilla — 2014-03-12T08:30:21Z