Overloading Lazy Vs. Non-Lazy

Lars T. Kyllingstad public at kyllingen.NOSPAMnet
Fri Aug 13 06:51:05 PDT 2010


On Fri, 13 Aug 2010 09:21:00 -0400, Steven Schveighoffer wrote:

> On Thu, 12 Aug 2010 16:47:40 -0400, dsimcha <dsimcha at yahoo.com> wrote:
> 
>> == Quote from Don (nospam at nospam.com)'s article
>>> Steven Schveighoffer wrote:
>>> > On Thu, 12 Aug 2010 02:00:00 -0400, Brad Roberts
>>> <braddr at puremagic.com>
>>> > wrote:
>>> >
>>> >> On 8/11/2010 6:19 AM, dsimcha wrote:
>>> >>> An issue that's come up here several times before is that
>>> >>> enforce() effectively disables inlining of the function it's used
>>> >>> in.  From reading some
>>> >>> disassemblies, the reason seems to be because of all the ASM code
>>> that's
>>> >>> required for lazy parameters.  I wonder if either of the following
>>> is
>>> >>> feasible:
>>> >>>
>>> >>> 1.  When a function takes a lazy parameter, the compiler
>>> automatically
>>> >>> generates two versions under the hood:  One that actually takes a
>>> >>> non-lazy
>>> >>> parameter and is used when the value is known at compile time and
>>> >>> another that
>>> >>> works like current lazy functions.  The only problem here is that
>>> >>> this might
>>> >>> create issues when using function pointers/delegates.
>>> >>>
>>> >>> 2.  Allow overloading of lazy and non-lazy functions, with the
>>> >>> rule that the
>>> >>> lazy version gets called whenever the value must be computed at
>>> >>> runtime and
>>> >>> the non-lazy version gets called if the value is statically known
>>> and
>>> >>> thus
>>> >>> there's no evaluation to speak of.
>>> >>
>>> >> It's the throw that blocks inlining right now.  Lazy might also
>>> >> disable inlining
>>> >> too, I haven't looked for that case.  Either way, that's purely a
>>> >> quality of
>>> >> implementation issue.  I don't think it'd be a good idea to bend
>>> >> the library all
>>> >> that much to work around that kind of limitation.  It's something
>>> that
>>> >> will get
>>> >> better as time permits.
>>> >
>>> > Well, there's something to be said about preventing the bloated
>>> > generation of code that accompanies lazy.
>>> Inlining a lazy function that only returns a compile-time constant
>>> could inline very nicely. The delegate would disappear completely.
>>
>> Just to clarify:  enforce() calls a function called bailOut() if
>> necessary that
>> actually does the throwing.  This of course is not inlined w.r.t.
>> enforce().
>> However, the lazy parameter also prevents inlining of enforce() itself
>> and
>> generates a ton of code at the ASM level.
>>
>> Don is right, though.  In principle, when a statically known delegate D
>> (lazy is
>> just syntactic sugar for delegates) that returns a statically known
>> constant is
>> passed to a statically known function F, D can be inlined w.r.t. F and
>> F can be
>> inlined w.r.t. its caller.
>>
>> The problem, though, is that F needs to be inlined first so that the
>> compiler can
>> optimize F w.r.t. the parameters passed to it from a specific caller.
>> However, F
>> won't look worth inlining until the compiler realizes that it can
>> inline D w.r.t.
>> F.  Therefore, the compiler would need an inliner that uses something
>> more
>> sophisticated than a simple greedy algorithm to discover this
>> optimization
>> opportunity.
> 
> In principle, we should be able to inline enforce.  Great.  When is this
> going to happen?  Well, we can inline all calls to enforce *today* if we
> simply remove the lazy attribute, and apply a lazy version in a small
> number of places.  I think it's worth doing it, because the inlining
> fixes are not going to happen for a while.  It's easy to switch it back
> once we can inline trivial lazy parameters.
> 
> -Steve

I agree.  A quick grep of the phobos sources shows that in the vast 
majority of cases, enforce() gets called either without a message or just 
with a string literal.

-Lars


More information about the Digitalmars-d mailing list