Prev: online shopping
Next: python admin abuse complaint
From: Tim Bradshaw on 2 Feb 2010 18:14 On 2010-02-02 23:01:30 +0000, Kaz Kylheku said: > In this case, you have to know that this is going on and that you cannot > declare that the returned object has dynamic extent. Yes, that was my point, and in particular that it can know that this is not happening for LIST (so the original case works, since it can work out that it can treat the results of LIST as "otherwise unreachble", but it is very hard (well, impossible in general) for it to know this for user code. --tim
From: D Herring on 2 Feb 2010 23:09 On 02/02/2010 10:54 AM, Frode V. Fjeld wrote: > pjb(a)informatimago.com (Pascal J. Bourguignon) writes: > >> Yes, inlineness is irrelevant here. > > I tried your example, and (as I expected) it only crashed when the > function was inlined. On your implementation, yes. But the CLHS is very clear that an explicit inline simply makes it easier for the compiler to move this optimization to the call site. A sufficiently smart compiler could do this even without the inline; it just has to be responsible for recompiling all call sites if an out-of-line function definition changes. - Daniel
From: Frode V. Fjeld on 3 Feb 2010 03:26 In article <82aavrskg8.fsf(a)netfonds.no>, "Frode V. Fjeld" <frode(a)netfonds.no> wrote: >> [...] However, Pascal's original example was this: >> >> (defun definer (x) >> (list x)) >> >> (declaim (inline caller)) >> >> (defun caller (&rest args) >> (declare (dynamic-extent args) >> (optimize (speed 3) (debug 0) (safety 0) >> (compilation-speed 0))) >> (apply #'definer args)) >> >> (defun test () >> (caller (list 0))) >> >> The question as I understand it is whether the last (list 0) can be >> stack-allocated. Paul Khuong <pvk(a)pvk.ca> writes: > [...] In Costanza's orignal example, it is because of inlining that > SBCL can assume that the &rest list in CALLER has been declared > dynamic-extent. However, even without inlining, a sufficiently > flexible runtime would allow for the exact same optimisation. I agree of course that the &rest list as such is dynamic-extent. However I disagree very much that this declaration should be able to engulf the (list 0) form (without sufficient escape analysis, which is a separate issue). > The bug lies not in our compilers but in our assumptions. Our assumptions about the letter of CLHS, you mean? I'm not entirely convinced that the CLHS is as you describe it. But if it is, my opinion is that this is an example of where one should follow not the letter but the spirit of the language, which in this case is that a dynamic-extent should be strictly contained in its lexical scope. This in order to maintain the "modularity" of functions, that I don't expect to be broken e.g. by a mere inline declaration, as Pascal's example highlights. > What you object to is fairly clearly described as the intent and > meaning of dynamic-extent declarations in the CLHS. Where, precisely? I fail to see anything relevant on the dynamic-extent reference page. I suspect that the CLHS fails to address the perhaps somewhat esoteric problem we're dealing with here. > The OP's common misunderstanding does however make a strong argument > for some extension providing a LEXICALLY-DYNAMIC-EXTENT declaration. I'd rather prefer an extension DANGEROUSLY-VIRAL-DYNAMIC-EXTENT :-) -- Frode V. Fjeld
From: Pascal Costanza on 3 Feb 2010 03:52 On 02/02/2010 17:38, Paul Khuong wrote: > In article<82aavrskg8.fsf(a)netfonds.no>, > "Frode V. Fjeld"<frode(a)netfonds.no> wrote: > >> Paul Khuong<pvk(a)pvk.ca> writes: >> >>> At the time the&rest list is bound, everything it contains is >>> "otherwise accessible". >> >> Agreed, my statement was quite mistaken. Thanks for the explanation. > > [...] > >> I agree wrt. your example. However, Pascal's original example was this: >> >> (defun definer (x) >> (list x)) >> >> (declaim (inline caller)) >> >> (defun caller (&rest args) >> (declare (dynamic-extent args) >> (optimize (speed 3) (debug 0) (safety 0) >> (compilation-speed 0))) >> (apply #'definer args)) >> >> (defun test () >> (caller (list 0))) >> >> The question as I understand it is whether the last (list 0) can be >> stack-allocated. This form is outside the (lexical) scope of the >> dynamic-extent declaration. I suspect what happens is that inlining >> "caller" causes (list 0) to be treated as it's in that lexical scope? So >> if there was no inlining, there would be no error? > > This is a side-effect of inlining. As the CLHS points out, the limit is > only what static analyses and the runtime allow you to guarantee. > > (defun g (x) (declare (dynamic-extent x)) ...) > (defun f () (g (list 1 2 3))) > > Most compilers would probably not stack allocate the argument to g > in f because it would be a modularity violation for the compiler to > assume facts about g from within f. Only an implementation that was > willing to be responsible for recompiling f if the definition of g > changed incompatibly could legitimately stack allocate the list > argument to g in f. > > Here, because of, e.g., automatic recompilation, F can assume that G's > one argument has been declared dynamic-extent. In Costanza's orignal > example, it is because of inlining that SBCL can assume that the&rest > list in CALLER has been declared dynamic-extent. However, even without > inlining, a sufficiently flexible runtime would allow for the exact same > optimisation. The bug lies not in our compilers but in our assumptions. Ok, understood by now. Thanks a lot for your excellent explanations. But this effectively means that I can never use dynamic-extent declarations for &rest arguments, can I? (defun foo (... &rest args) (declare (dynamic-extent args)) ...) Since it is always possible that client code calls this with freshly allocated data: (foo ... (list 1) (list 2)) And since compilers are allowed to cross module (function) boundaries when optimizing for dynamic-extent, this is never safe. Or are there circumstances where I can use dynamic-extent for &rest args safely? Pascal -- My website: http://p-cos.net Common Lisp Document Repository: http://cdr.eurolisp.org Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: Pascal Costanza on 3 Feb 2010 03:58
On 03/02/2010 09:26, Frode V. Fjeld wrote: > In article<82aavrskg8.fsf(a)netfonds.no>, > "Frode V. Fjeld"<frode(a)netfonds.no> wrote: > >>> [...] However, Pascal's original example was this: >>> >>> (defun definer (x) >>> (list x)) >>> >>> (declaim (inline caller)) >>> >>> (defun caller (&rest args) >>> (declare (dynamic-extent args) >>> (optimize (speed 3) (debug 0) (safety 0) >>> (compilation-speed 0))) >>> (apply #'definer args)) >>> >>> (defun test () >>> (caller (list 0))) >>> >>> The question as I understand it is whether the last (list 0) can be >>> stack-allocated. > > Paul Khuong<pvk(a)pvk.ca> writes: > >> [...] In Costanza's orignal example, it is because of inlining that >> SBCL can assume that the&rest list in CALLER has been declared >> dynamic-extent. However, even without inlining, a sufficiently >> flexible runtime would allow for the exact same optimisation. > > I agree of course that the&rest list as such is dynamic-extent. However > I disagree very much that this declaration should be able to engulf the > (list 0) form (without sufficient escape analysis, which is a separate > issue). > >> The bug lies not in our compilers but in our assumptions. > > Our assumptions about the letter of CLHS, you mean? I'm not entirely > convinced that the CLHS is as you describe it. But if it is, my opinion > is that this is an example of where one should follow not the letter but > the spirit of the language, which in this case is that a dynamic-extent > should be strictly contained in its lexical scope. This in order to > maintain the "modularity" of functions, that I don't expect to be broken > e.g. by a mere inline declaration, as Pascal's example highlights. > >> What you object to is fairly clearly described as the intent and >> meaning of dynamic-extent declarations in the CLHS. > > Where, precisely? I fail to see anything relevant on the dynamic-extent > reference page. I suspect that the CLHS fails to address the perhaps > somewhat esoteric problem we're dealing with here. There is an example in the entry for dynamic-extent. Look for the paragraph starting with "Most compilers would probably not stack allocate the argument to g in f [...]" I agree that it should have stated "Compilers must not stack allocate [...]" here, but that's not what the specification says. I agree with you, though, that dynamic-extent for arguments to functions thus becomes practically useless, as far as I can tell. Pascal -- My website: http://p-cos.net Common Lisp Document Repository: http://cdr.eurolisp.org Closer to MOP & ContextL: http://common-lisp.net/project/closer/ |