Re: [Pharo-dev] About ~= and ~~

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
11 messages Options
Reply | Threaded
Open this post in threaded view
|

Re: [Pharo-dev] About ~= and ~~

Clément Béra
 
Hi,

Support for primitive 169 for Object>>#~~ has been in the VM for a while. The default implementation in Squeak 5 uses this primitive for example.

I've just added today (VMMaker commit 2003) support for inlined #~~ like #== (including JIT support, branch pipelining, etc.). If one puts #~~ in the specialObjectsArray at the location of #blockCopy:, the bytecode compiler generates the special send bytecode for #~~ leading to improved performance and consistency between #== and #~~.

With today's update, the VM supports 3 inlined operations without any type checks: #==, #~~ and #class. It is possible to disable such optimisations in the bytecode compiler (In Pharo #class inlining is disabled there for example). Eliot would like to add support to disable these operations at VM level as a VM command line parameter too, and we may do it in the future.

Now this is for the VM support. It's up to the Pharo/Squeak/other community to decide what behavior they want in their runtime for these 3 selectors. 

In my opinion, I believe that #~~ should be consistent with #==, hence they should be both inlined or both sends to primitives. I don't like the current situation in Pharo nor in Squeak. 

Now when we look for solutions, we see that one of #== and #~~ needs to be a primitive (it's essential), hence it makes sense to have both Object>>#== and Object>>#~~ as primitives (with the primitive pragma in the method body). The inlining of #== and #~~ is arguable and I let the community decide what they believe is best for their runtime, though I would rather have the same behavior for both selectors.

Cheers

On Wed, Nov 23, 2016 at 2:39 PM, Aliaksei Syrel <[hidden email]> wrote:
Hi

It is been a while...
So, do we want to replace ~~ with a primitive? :)

Cheers
Alex



--
View this message in context: http://forum.world.st/About-and-tp3898409p4924391.html
Sent from the Pharo Smalltalk Developers mailing list archive at Nabble.com.


Reply | Threaded
Open this post in threaded view
|

Re: [Pharo-dev] About ~= and ~~

Eliot Miranda-2
 
Hi Clément, Hi All,

On Thu, Nov 24, 2016 at 5:09 AM, Clément Bera <[hidden email]> wrote:
 
Hi,

Support for primitive 169 for Object>>#~~ has been in the VM for a while. The default implementation in Squeak 5 uses this primitive for example.

I've just added today (VMMaker commit 2003) support for inlined #~~ like #== (including JIT support, branch pipelining, etc.). If one puts #~~ in the specialObjectsArray at the location of #blockCopy:, the bytecode compiler generates the special send bytecode for #~~ leading to improved performance and consistency between #== and #~~.

With today's update, the VM supports 3 inlined operations without any type checks: #==, #~~ and #class. It is possible to disable such optimisations in the bytecode compiler (In Pharo #class inlining is disabled there for example). Eliot would like to add support to disable these operations at VM level as a VM command line parameter too, and we may do it in the future.

Now this is for the VM support. It's up to the Pharo/Squeak/other community to decide what behavior they want in their runtime for these 3 selectors. 

In my opinion, I believe that #~~ should be consistent with #==, hence they should be both inlined or both sends to primitives. I don't like the current situation in Pharo nor in Squeak. 

Now when we look for solutions, we see that one of #== and #~~ needs to be a primitive (it's essential), hence it makes sense to have both Object>>#== and Object>>#~~ as primitives (with the primitive pragma in the method body). The inlining of #== and #~~ is arguable and I let the community decide what they believe is best for their runtime, though I would rather have the same behavior for both selectors.

In addition, for proxies, it makes sense to allow the system to not inline the primitives.  Let me explain.  The primitives for #== and #~~, just like any other primitives, are found by message sends.  However, a set of 32 "special" selectors, which comprise some arithmetic selectors (#+, #- etc) and comparison selectors (#< #<= etc) and some frequent selectors #(at: #next #value #== etc) are subject to inlining with no sends (see Smalltalk specialSelectoers for the full set).

The first sixteen are arithmetic and comparison, and the interpreter gains performance by implementing these byte codes to test for SmallIntegers and Floats, and performing the arithmetic directly without a send, and for the comparisons, performing the comparison and any immediately following conditional branch.  The JIT performs these optimisations too.  But these short-cuts (static type prediction in the official terminology) are safe because they apply only to SmallInteger and Float.

Of the next sixteen most are there only to save space in a method's literal frame.  Since the byte code encodes the selector directly there is no need to store the selector in the method's literals.  The implementation of all but two (three if we add #~~ to replace #blockCopy: as mentioned above) of these bytecodes is to fetch the selector from the specialSelectors array and do a normal send.

#== and #class are handled specially.  These are inlined without doing a send.  The current Opal compiler in Pharo avoids the inlining of #class by not generating the #class special selector bytecode.  Squeak's compiler still issues the special selector bytecode.  Both generate #== by issuing the #== special selector bytecode, and so #== is never sent.  This is not what's desired for applications that use proxies.  It is fine for simple applications that prefer speed.

One simple thing one can do is prevent inlining for anything other than the arithmetic and comparison operators.  A simple command-line switch, or perhaps better, a flag in the image header, can control whether the VM inlines #class, #== & #~~.  This then allows the compilers to generate the more compact special selector byte codes for these sends, but causes the VM to treat them like the other 13 non-arithmetic special selectors.  Hence they become true sends.  I did this for VisualWorks several years ago and it works well, expect for needing a command-line switch.  The flag in the image header is much more reliable; whether an image should be run with inlining or not is a property of the image, not of a particular VM invocation.

So I suggest that
a) I implement the switch as an image header flag, allowing the inlining of #class, #== and #~~ to be turned off (but keeping inlining on by default)
b) Pharo changes Opal to start issuing the #class special selector send byte code again and turns off inlining of #class, #== and #~~
c) applications that use proxies (in Cuis, Pharo or Squeak) experiment with the setting and see if logic is improved and report back; Squeak and other dialects can then decide what they want as the default, and indeed certain packages could try and set the flag or at least check that the flag is in the desired state 


Cheers

On Wed, Nov 23, 2016 at 2:39 PM, Aliaksei Syrel <[hidden email]> wrote:
Hi

It is been a while...
So, do we want to replace ~~ with a primitive? :)

Cheers
Alex



--
View this message in context: http://forum.world.st/About-and-tp3898409p4924391.html
Sent from the Pharo Smalltalk Developers mailing list archive at Nabble.com.






--
_,,,^..^,,,_
best, Eliot
Reply | Threaded
Open this post in threaded view
|

Re: [Pharo-dev] About ~= and ~~

Eliot Miranda-2
In reply to this post by Clément Béra
 
Hi Peter,

    I'd appreciate it if you used reply to all to keep the conversation thread going.

> On Nov 25, 2016, at 10:31 AM, Peter Uhnak <[hidden email]> wrote:
>
> Out of interest... is the single extra dispatch really that expensive?

Yes, in the common case where the send of #== is followed by a jump, as it is in ifNil:ifNotNil: or == foo ifTrue: etc.  when #== is inclined the following jump is eliminated and the VM jumps on the condition codes for the comparison.  When #== is a real send it answers the true or false objects and the following jump must compare this result against true or false.

Note that Sista will be able to perform the inclining optimisation so we will get the performance back once Sista is deployed.

>
> And speaking of object inequality... I would like to propose "<>" instead of "~=", because I never remember on which side ~ should be..
>
> Peter
>
>> On Wed, Nov 23, 2016 at 05:39:03AM -0800, Aliaksei Syrel wrote:
>> Hi
>>
>> It is been a while...
>> So, do we want to replace ~~ with a primitive? :)
>>
>> Cheers
>> Alex
>>
>>
>>
>> --
>> View this message in context: http://forum.world.st/About-and-tp3898409p4924391.html
>> Sent from the Pharo Smalltalk Developers mailing list archive at Nabble.com.
>>
>
Reply | Threaded
Open this post in threaded view
|

Re: [Pharo-dev] About ~= and ~~

Levente Uzonyi
In reply to this post by Eliot Miranda-2
 
Hi Eliot,

On Fri, 25 Nov 2016, Eliot Miranda wrote:

> Of the next sixteen most are there only to save space in a method's
literal frame.  Since the byte code encodes the selector directly there is
no need to store the selector in the method's literals.  The
implementation of all but two (three if we add #~~ to replace #blockCopy:
as mentioned above) of these bytecodes is to fetch the selector from the
specialSelectors array and do a normal send.

IIRC the byte codes also ensure that there are no suspension points in the
code. If so, removing them would break programs.

Levente
Reply | Threaded
Open this post in threaded view
|

Re: [Pharo-dev] About ~= and ~~

Denis Kudriashov
 

2016-11-26 11:25 GMT+01:00 Levente Uzonyi <[hidden email]>:
IIRC the byte codes also ensure that there are no suspension points in the code. If so, removing them would break programs.

Yes. For example #critical: method relies on it
Reply | Threaded
Open this post in threaded view
|

Re: [Pharo-dev] About ~= and ~~

Clément Béra
In reply to this post by Levente Uzonyi
 
If the send is to a non failing primitive call, there is no suspension point either. So I don't think it would break programs.

On Sat, Nov 26, 2016 at 11:25 AM, Levente Uzonyi <[hidden email]> wrote:

Hi Eliot,

On Fri, 25 Nov 2016, Eliot Miranda wrote:

Of the next sixteen most are there only to save space in a method's
literal frame.  Since the byte code encodes the selector directly there is no need to store the selector in the method's literals.  The implementation of all but two (three if we add #~~ to replace #blockCopy: as mentioned above) of these bytecodes is to fetch the selector from the specialSelectors array and do a normal send.

IIRC the byte codes also ensure that there are no suspension points in the code. If so, removing them would break programs.

Levente

Reply | Threaded
Open this post in threaded view
|

Re: [Pharo-dev] About ~= and ~~

Levente Uzonyi
 
On Sat, 26 Nov 2016, Clément Bera wrote:

> If the send is to a non failing primitive call, there is no suspension
point either. So I don't think it would break programs.

When there's a send, one can override the method, so the guaratee of no
suspension points is gone.

Levente
Reply | Threaded
Open this post in threaded view
|

Re: [Pharo-dev] About ~= and ~~

Eliot Miranda-2
 
Hi Levente,


> On Nov 26, 2016, at 3:02 AM, Levente Uzonyi <[hidden email]> wrote:
>
>> On Sat, 26 Nov 2016, Clément Bera wrote:
>>
>> If the send is to a non failing primitive call, there is no suspension
> point either. So I don't think it would break programs.
>
> When there's a send, one can override the method, so the guaratee of no suspension points is gone.

Right, but as the doctor says, "don't do that". For example, provided that the method is only overridden in exotic classes such as proxy classes, and is not overridden for nil and things like LinkedList, Semaphore and Process then it can still be used without fear of suspension points in the scheduler.

And we can think of adding better concurrency control primitives such as a conditional assignment operator.

> Levente
Reply | Threaded
Open this post in threaded view
|

Re: [Pharo-dev] About ~= and ~~

Levente Uzonyi
 
On Sat, 26 Nov 2016, Eliot Miranda wrote:

>
> Hi Levente,
>
>
>> On Nov 26, 2016, at 3:02 AM, Levente Uzonyi <[hidden email]> wrote:
>>
>>> On Sat, 26 Nov 2016, Clément Bera wrote:
>>>
>>> If the send is to a non failing primitive call, there is no suspension
>> point either. So I don't think it would break programs.
>>
>> When there's a send, one can override the method, so the guaratee of no suspension points is gone.
>
> Right, but as the doctor says, "don't do that". For example, provided that the method is only overridden in exotic classes such as proxy classes, and is not overridden for nil and things like LinkedList, Semaphore and Process then it can still be used without fear of suspension points in the scheduler.
Okay. Let's see a real world example of #== being a message send.
Let's say I have class Proxy which overrides #==.
Let's say myProxy is an instance of Proxy for the value 0.

0 == myProxy "==> false, because 0 is the receiver, and the primitive is used."
myProxy == 0 "==> true, because #== compares the proxied value"

So, how would this support proxies? Did I miss something important?

>
> And we can think of adding better concurrency control primitives such as a conditional assignment operator.

That would be way less flexible than what we have right now.

Levente

>
>> Levente
Reply | Threaded
Open this post in threaded view
|

Re: [Pharo-dev] About ~= and ~~

stepharo
In reply to this post by Eliot Miranda-2
 
On Sat, 26 Nov 2016 17:51:24 +0100, Eliot Miranda  
<[hidden email]> wrote:

> Hi Levente,
>
>
>> On Nov 26, 2016, at 3:02 AM, Levente Uzonyi <[hidden email]>  
>> wrote:
>>
>>> On Sat, 26 Nov 2016, Clément Bera wrote:
>>>
>>> If the send is to a non failing primitive call, there is no suspension
>> point either. So I don't think it would break programs.
>>
>> When there's a send, one can override the method, so the guaratee of no  
>> suspension points is gone.
>
> Right, but as the doctor says, "don't do that". For example, provided  
> that the method is only overridden in exotic classes such as proxy  
> classes, and is not overridden for nil and things like LinkedList,  
> Semaphore and Process then it can still be used without fear of  
> suspension points in the scheduler.
>
> And we can think of adding better concurrency control primitives such as  
> a conditional assignment operator.

Yes I would love that.
It would be so great to have an **EXPLICIT** constructs. It would improve  
the code quality
because relying on the underlying assumptions of the VM implementation  
choice is a lack
of language design in fact.

Stef


>
>> Levente


--
Using Opera's mail client: http://www.opera.com/mail/
Reply | Threaded
Open this post in threaded view
|

Re: [Pharo-dev] About ~= and ~~

stepharo
In reply to this post by Levente Uzonyi
 
On Sat, 26 Nov 2016 19:35:33 +0100, Levente Uzonyi <[hidden email]>  
wrote:

> nd we can think of adding better concurrency control primitives such as  
> a conditional assignment operator.
> That would be way less flexible than what we have right now.

Why that?
Instead on having to know that == is used as a premption point, the  
developer would have
** expression ** and ** ** will mean and do what it does.



--
Using Opera's mail client: http://www.opera.com/mail/