[prev in list] [next in list] [prev in thread] [next in thread]
List: squeak-dev
Subject: Re: [squeak-dev] Compiler
From: Eliot Miranda <eliot.miranda () gmail ! com>
Date: 2012-06-22 1:10:51
Message-ID: CAC20JE2Kg7c3ZL4sKd5x5gv-ak5YWn1VCdo8Dvjx0WCfhfj5qw () mail ! gmail ! com
[Download RAW message or body]
[Attachment #2 (multipart/alternative)]
On Thu, Jun 21, 2012 at 2:34 PM, Bert Freudenberg <bert@freudenbergs.de>wrote:
>
> On 2012-06-21, at 22:32, Nicolas Cellier wrote:
>
> > 2012/6/21 Bert Freudenberg <bert@freudenbergs.de>:
> >>
> >> On 2012-06-21, at 19:43, Nicolas Cellier wrote:
> >>
> >>> if these are objects rather than literals (that we can expect being
> >>> constant), say for example some instance variable, then can we
> >>> guaranty that the first message won't have any side effect...
> >>>
> >>> (a at: 1) + ( (a at:2) * ( (a at: 1 put: ( ... ) ) + (... ) ) )
> >>>
> >>> Nicolas
> >>
> >> Did you mean to write we can *not* guarantee it?
> >>
> >> I don't think we have to worry about side effects, as long as the
> evaluation order of all expressions remains the same:
> >>
> >> a := {3. 4}.
> >> (a at: 1) + ( (a at: 2) * (a at: 1 put: 5) ).
> >>
> >> is equivalent to
> >>
> >> a := {3. 4}.
> >> t1 := a at: 1.
> >> t2 := a at: 2.
> >> t3 := a at: 1 put: 5.
> >> t4 := t2 * t3.
> >> t5 := t1 + t4.
> >> t5
> >>
> >
> > Agree, but then we're back to our initial problem, above code first
> > push all parameters then perform all the sends, and might overflow the
> > stack limit in-between... We could hack and simulate the stack in such
> > case as I proposed , but I feel it will be really teddious to handle
> > all of current CompiledMethod limitations...
> >
> > Nicolas
>
>
> No, we have worked around the stack limitation. The expanded form uses
> temps, not stack slots. And for more temps you had a solution already :)
>
> The first example needs a stack of size 5, while the second one needs only
> 3.
>
> The maximum stack depth the expanded form needs is the number of arguments
> of the message send with the most arguments, plus 1 for the receiver/result.
>
This is fine. But a 2 bit field could code the logarithm of the context
size, either 16, 32, 64 & 128 slots, or 16, 64, 256 & 1024 slots. I think
that would be more than adequate.
So with 31 bits in the header to play with you'd get e.g.
0: 14 numLiterals (16k literals)
14: 6 numArgs (63 args)
20: 6 numTemps-numArgs (63 temps, temps ~= numTemps + numArgs)
26: 2 context size (16, 64, 256 & 1024 slots)
28: 3 bits flags
But there are lots of other tricks one could play moving some fields into
bytecode. For example, a one byte bytecode that specified 0 temps and a
two byte bytecode that specified how many temps to allocate (up to 255 or
256) would save a further 6 bits, and provide a greater range. Why have
two bytecodes? Most methods have no temps, e.g.:
| noTemps hasTemps |
noTemps := hasTemps := 0.
CompiledMethod allInstancesDo:
[:cm|
cm isQuick ifFalse:
[cm numTemps = cm numArgs ifTrue: [noTemps := noTemps + 1] ifFalse:
[hasTemps := hasTemps + 1]]].
{noTemps. hasTemps } #(65839 24230)
But saving 64k by burning a bytecode might be silly. Depends on how the
bytecode set looks.
>
> - Bert -
>
>
>
>
--
best,
Eliot
[Attachment #5 (text/html)]
<br><br><div class="gmail_quote">On Thu, Jun 21, 2012 at 2:34 PM, Bert Freudenberg \
<span dir="ltr"><<a href="mailto:bert@freudenbergs.de" \
target="_blank">bert@freudenbergs.de</a>></span> wrote:<br><blockquote \
class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc \
solid;padding-left:1ex"> <div class="im"><br>
On 2012-06-21, at 22:32, Nicolas Cellier wrote:<br>
<br>
> 2012/6/21 Bert Freudenberg <<a \
href="mailto:bert@freudenbergs.de">bert@freudenbergs.de</a>>:<br> >><br>
>> On 2012-06-21, at 19:43, Nicolas Cellier wrote:<br>
>><br>
</div><div class="im">>>> if these are objects rather than literals (that we \
can expect being<br> >>> constant), say for example some instance variable, \
then can we<br> >>> guaranty that the first message won't have any side \
effect...<br> >>><br>
>>> (a at: 1) + ( (a at:2) * ( (a at: 1 put: ( ... ) ) + (... ) ) )<br>
>>><br>
>>> Nicolas<br>
>><br>
>> Did you mean to write we can *not* guarantee it?<br>
>><br>
>> I don't think we have to worry about side effects, as long as the \
evaluation order of all expressions remains the same:<br> >><br>
>> a := {3. 4}.<br>
>> (a at: 1) + ( (a at: 2) * (a at: 1 put: 5) ).<br>
>><br>
>> is equivalent to<br>
>><br>
>> a := {3. 4}.<br>
>> t1 := a at: 1.<br>
>> t2 := a at: 2.<br>
>> t3 := a at: 1 put: 5.<br>
>> t4 := t2 * t3.<br>
>> t5 := t1 + t4.<br>
>> t5<br>
>><br>
><br>
> Agree, but then we're back to our initial problem, above code first<br>
> push all parameters then perform all the sends, and might overflow the<br>
> stack limit in-between... We could hack and simulate the stack in such<br>
> case as I proposed , but I feel it will be really teddious to handle<br>
> all of current CompiledMethod limitations...<br>
><br>
> Nicolas<br>
<br>
<br>
</div>No, we have worked around the stack limitation. The expanded form uses temps, \
not stack slots. And for more temps you had a solution already :)<br> <br>
The first example needs a stack of size 5, while the second one needs only 3.<br>
<br>
The maximum stack depth the expanded form needs is the number of arguments of the \
message send with the most arguments, plus 1 for the \
receiver/result.<br></blockquote><div><br></div><div>This is fine. But a 2 bit field \
could code the logarithm of the context size, either 16, 32, 64 & 128 slots, or \
16, 64, 256 & 1024 slots. I think that would be more than adequate.</div> \
<div><br></div><div>So with 31 bits in the header to play with you'd get \
e.g.</div><div>0: 14 numLiterals (16k literals)</div><div>14: 6 numArgs (63 \
args)</div><div>20: 6 numTemps-numArgs (63 temps, temps ~= numTemps + \
numArgs)</div> <div>26: 2 context size (16, 64, 256 & 1024 \
slots)</div><div>28: 3 bits flags</div><div><br></div><div>But there are lots of \
other tricks one could play moving some fields into bytecode. For example, a one \
byte bytecode that specified 0 temps and a two byte bytecode that specified how many \
temps to allocate (up to 255 or 256) would save a further 6 bits, and provide a \
greater range. Why have two bytecodes? Most methods have no temps, e.g.:</div> \
<div><br></div><div><div><div>| noTemps hasTemps |</div><div>noTemps := hasTemps := \
0.</div><div>CompiledMethod allInstancesDo:</div><div><span class="Apple-tab-span" \
style="white-space:pre"> </span>[:cm|</div><div><span class="Apple-tab-span" \
style="white-space:pre"> </span>cm isQuick ifFalse:</div> <div><span \
class="Apple-tab-span" style="white-space:pre"> </span>[cm numTemps = cm numArgs \
ifTrue: [noTemps := noTemps + 1] ifFalse: [hasTemps := hasTemps + \
1]]].</div><div>{noTemps. hasTemps } #(65839 24230)</div></div> \
</div><div><br></div><div>But saving 64k by burning a bytecode might be silly. \
Depends on how the bytecode set looks.</div><div> </div><blockquote \
class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc \
solid;padding-left:1ex">
<span class="HOEnZb"><font color="#888888"><br>
- Bert -<br>
<br>
<br>
<br>
</font></span></blockquote></div><br><br clear="all"><div><br></div>-- \
<br>best,<div>Eliot</div><br>
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic