SqueakJS named primitives in the interpreter module

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

SqueakJS named primitives in the interpreter module

David T. Lewis
 
For named primitives, we can load and run a primitive function from a specific
module, as in the case of <primitive: 'primitiveFileSize' module: 'FilePlugin'>.

We can also load a primitive with module name unspecified, as in the case of
<primitive: 'primitiveScreenDepth'>. In that case we load and run the function
from the main interpreter module.

I want to implement the anonymous named primitive #primitiveUtcWithOffset in
SqueakJS, but I am a total JavaScript noob so I am looking for an example of
some other anonymous named primitive to use as a pattern.

At first glance, I do not see any anonymous named primitives implemented in vm.js,
so I want to ask - does the basic functionality of looking up and executing e.g.
#primitiveScreenDepth from the <primitive: 'primitiveScreenDepth'> pragma work?

For reference, here are the named primitives in the anonymous module as
referenced from methods in Squeak trunk.

     ( Pragma allSubInstances
         select: [:e | ( e keyword = #primitive:
                 and: [ e numArgs = 1 ] )
                     and: [ e arguments first isInteger not ] ] )
             collect: [ :e | e arguments first asSymbol ].

TIA,
Dave

Reply | Threaded
Open this post in threaded view
|

Re: SqueakJS named primitives in the interpreter module

Bert Freudenberg
 
On Thu, Jan 19, 2017 at 3:55 AM, David T. Lewis <[hidden email]> wrote:

For named primitives, we can load and run a primitive function from a specific
module, as in the case of <primitive: 'primitiveFileSize' module: 'FilePlugin'>.

We can also load a primitive with module name unspecified, as in the case of
<primitive: 'primitiveScreenDepth'>. In that case we load and run the function
from the main interpreter module.

I want to implement the anonymous named primitive #primitiveUtcWithOffset in
SqueakJS, but I am a total JavaScript noob so I am looking for an example of
some other anonymous named primitive to use as a pattern.

At first glance, I do not see any anonymous named primitives implemented in vm.js,

Indeed, SqueakJS does not implement any of the currently used module-less named primitives.

It does, however, implement some obsolete ones, e.g. 'm23PrimitiveTransformPoint' which was later moved to Matrix2x3Plugin.

The lookup is quite trivial: If you specify an empty module name, it just looks up the method in the VM's primitive handler class itself, instead of a named module. E.g. in SqueakJS you could call the beep primitive either by index or by name, <primitive: 140> works as well as <primitive: 'primitiveBeep'>.
 
so I want to ask - does the basic functionality of looking up and executing e.g.
#primitiveScreenDepth from the <primitive: 'primitiveScreenDepth'> pragma work?

Yes. Simply name your JavaScript method 'primitiveUtcWithOffset' and put it in the 'Squeak.Primitives' class. I'd suggest putting it in the 'time' section https://github.com/bertfreudenberg/SqueakJS/blob/432dafd615a8e48019dbfc5e62a6599e4648ca3b/vm.js#L6486

Note that quite a few indexed primitives do not exist as a full method. E.g. prim 135 is currently implemented as

case 135: return this.popNandPushIfOK(1, this.millisecondClockValue());

basically to reduce tedious boiler-plate code. Just in case you're wondering why some of the primitives appear to be missing ;)

- Bert  - 

PS: makeStArray: might prove useful
Reply | Threaded
Open this post in threaded view
|

Re: SqueakJS named primitives in the interpreter module

David T. Lewis
 
Thank you Bert,

On Thu, Jan 19, 2017 at 02:19:25PM +0100, Bert Freudenberg wrote:

>  
> On Thu, Jan 19, 2017 at 3:55 AM, David T. Lewis <[hidden email]> wrote:
>
> >
> > For named primitives, we can load and run a primitive function from a
> > specific
> > module, as in the case of <primitive: 'primitiveFileSize' module:
> > 'FilePlugin'>.
> >
> > We can also load a primitive with module name unspecified, as in the case
> > of
> > <primitive: 'primitiveScreenDepth'>. In that case we load and run the
> > function
> > from the main interpreter module.
> >
> > I want to implement the anonymous named primitive #primitiveUtcWithOffset
> > in
> > SqueakJS, but I am a total JavaScript noob so I am looking for an example
> > of
> > some other anonymous named primitive to use as a pattern.
> >
> > At first glance, I do not see any anonymous named primitives implemented
> > in vm.js,
> >
>
> Indeed, SqueakJS does not implement any of the currently used module-less
> named primitives.
>
> It does, however, implement some obsolete ones, e.g. '
> m23PrimitiveTransformPoint' which was later moved to Matrix2x3Plugin.
>
> The lookup is quite trivial: If you specify an empty module name, it just
> looks up the method in the VM's primitive handler class itself, instead of
> a named module. E.g. in SqueakJS you could call the beep primitive either
> by index or by name, <primitive: 140> works as well as <primitive:
> 'primitiveBeep'>.
>

Ah, I see. That's exactly what I needed to know.


> > so I want to ask - does the basic functionality of looking up and
> > executing e.g.
> > #primitiveScreenDepth from the <primitive: 'primitiveScreenDepth'> pragma
> > work?
> >
>
> Yes. Simply name your JavaScript method 'primitiveUtcWithOffset' and put it
> in the 'Squeak.Primitives' class. I'd suggest putting it in the 'time'
> section https://github.com/bertfreudenberg/SqueakJS/blob/
> 432dafd615a8e48019dbfc5e62a6599e4648ca3b/vm.js#L6486
>
> Note that quite a few indexed primitives do not exist as a full method.
> E.g. prim 135 is currently implemented as
>
> case 135: return this.popNandPushIfOK(1, this.millisecondClockValue());
>
> basically to reduce tedious boiler-plate code. Just in case you're
> wondering why some of the primitives appear to be missing ;)

Indeed, I can see that you have simplified many of these primitives quite a bit.


> - Bert  -
>
> PS: makeStArray: might prove useful

You have correctly anticipated my next newbie question ;-)

Thanks!
Dave

Reply | Threaded
Open this post in threaded view
|

Re: SqueakJS named primitives in the interpreter module

Bert Freudenberg
 
On Thu, Jan 19, 2017 at 3:08 PM, David T. Lewis <[hidden email]> wrote:
> PS: makeStArray: might prove useful

You have correctly anticipated my next newbie question ;-)

You might have to change makeLargeInt to use pos53BitIntFor() instead of pos32BitIntFor() because microseconds are ... yuge. Should be safe to do, I just didn't need it yet.

- Bert - 

PS: I'm not worried about dates past the year 2185.
Reply | Threaded
Open this post in threaded view
|

Re: SqueakJS named primitives in the interpreter module

David T. Lewis
In reply to this post by Bert Freudenberg
 
On Thu, Jan 19, 2017 at 02:19:25PM +0100, Bert Freudenberg wrote:

>  
> On Thu, Jan 19, 2017 at 3:55 AM, David T. Lewis <[hidden email]> wrote:
>
> >
> > For named primitives, we can load and run a primitive function from a specific
> > module, as in the case of <primitive: 'primitiveFileSize' module: 'FilePlugin'>.
> >
> > We can also load a primitive with module name unspecified, as in the case of
> > <primitive: 'primitiveScreenDepth'>. In that case we load and run the function
> > from the main interpreter module.
> >
> > I want to implement the anonymous named primitive #primitiveUtcWithOffset in
> > SqueakJS, but I am a total JavaScript noob so I am looking for an example of
> > some other anonymous named primitive to use as a pattern.
> >
> > At first glance, I do not see any anonymous named primitives implemented
> > in vm.js,
> >
>
> Indeed, SqueakJS does not implement any of the currently used module-less
> named primitives.
>
> It does, however, implement some obsolete ones, e.g. '
> m23PrimitiveTransformPoint' which was later moved to Matrix2x3Plugin.
>
> The lookup is quite trivial: If you specify an empty module name, it just
> looks up the method in the VM's primitive handler class itself, instead of
> a named module. E.g. in SqueakJS you could call the beep primitive either
> by index or by name, <primitive: 140> works as well as <primitive:
> 'primitiveBeep'>.
>
>
> > so I want to ask - does the basic functionality of looking up and
> > executing e.g.
> > #primitiveScreenDepth from the <primitive: 'primitiveScreenDepth'> pragma
> > work?
> >
>
> Yes. Simply name your JavaScript method 'primitiveUtcWithOffset' and put it
> in the 'Squeak.Primitives' class. I'd suggest putting it in the 'time'
> section https://github.com/bertfreudenberg/SqueakJS/blob/
> 432dafd615a8e48019dbfc5e62a6599e4648ca3b/vm.js#L6486
>
> Note that quite a few indexed primitives do not exist as a full method.
> E.g. prim 135 is currently implemented as
>
> case 135: return this.popNandPushIfOK(1, this.millisecondClockValue());
>
> basically to reduce tedious boiler-plate code. Just in case you're
> wondering why some of the primitives appear to be missing ;)
>
> - Bert  -
>
> PS: makeStArray: might prove useful

Thanks Bert,

I sent a git pull request for the new primitive, so hopefully you can
review it and include it in SqueakJS if it is not too horrible.

To my considerable surprise, DateAndTime>>now seems to be 70 times faster
on SqueakJS when using this primitive along with the enhancements in the
UTCDateAndTime repository.

I am inexperienced with JavaScript and Git, so in case any of this did not
get through, the proposed new function in Squeak.Primitives is:

    primitiveUtcWithOffset: function(argCount) {
        var d = new Date();
        var posixMicroseconds = this.pos53BitIntFor(d.getTime() * 1000);
        var offset = -60 * d.getTimezoneOffset();
        if (argCount > 0) {
            // either an Array or a DateAndTime in new UTC format with two ivars
            var stWordIndexableObject = this.vm.stackValue(0);
            stWordIndexableObject.pointers[0] = posixMicroseconds;
            stWordIndexableObject.pointers[1] = offset;
            this.popNandPushIfOK(argCount + 1, stWordIndexableObject);
            return true;
        }
        var timeAndOffset = [
            posixMicroseconds,
            offset,
        ];
        this.popNandPushIfOK(argCount + 1, this.makeStArray(timeAndOffset));
        return true;
    },

Dave

Reply | Threaded
Open this post in threaded view
|

Re: SqueakJS named primitives in the interpreter module

Bert Freudenberg
 
On Sat, Jan 21, 2017 at 5:06 AM, David T. Lewis <[hidden email]> wrote:

I sent a git pull request for the new primitive, so hopefully you can
review it and include it in SqueakJS if it is not too horrible.

Awesome! Merged.

To my considerable surprise, DateAndTime>>now seems to be 70 times faster
on SqueakJS when using this primitive along with the enhancements in the
UTCDateAndTime repository.

Well, emulating a primitive is a lot more expensive on a slow VM like SqueakJS still is. So I'm not too, surprised, but happy nonetheless :)
 
I am inexperienced with JavaScript and Git, so in case any of this did not
get through, the proposed new function in Squeak.Primitives is:

    primitiveUtcWithOffset: function(argCount) {
        var d = new Date();
        var posixMicroseconds = this.pos53BitIntFor(d.getTime() * 1000);
        var offset = -60 * d.getTimezoneOffset();
        if (argCount > 0) {
            // either an Array or a DateAndTime in new UTC format with two ivars
            var stWordIndexableObject = this.vm.stackValue(0);
            stWordIndexableObject.pointers[0] = posixMicroseconds;
            stWordIndexableObject.pointers[1] = offset;
            this.popNandPushIfOK(argCount + 1, stWordIndexableObject);
            return true;
        }
        var timeAndOffset = [
            posixMicroseconds,
            offset,
        ];
        this.popNandPushIfOK(argCount + 1, this.makeStArray(timeAndOffset));
        return true;
    },
 
It looks fine. We could try to incorporate the microsecondClock function, but if milliseconds are good enough then this will do.

- Bert -
Reply | Threaded
Open this post in threaded view
|

Re: SqueakJS named primitives in the interpreter modulej

David T. Lewis
 
On Mon, Jan 23, 2017 at 04:17:42PM +0100, Bert Freudenberg wrote:

>  
> On Sat, Jan 21, 2017 at 5:06 AM, David T. Lewis <[hidden email]> wrote:
>
> >
> > I sent a git pull request for the new primitive, so hopefully you can
> > review it and include it in SqueakJS if it is not too horrible.
>
>
> Awesome! Merged.
>
> To my considerable surprise, DateAndTime>>now seems to be 70 times faster
> > on SqueakJS when using this primitive along with the enhancements in the
> > UTCDateAndTime repository.
>
>
> Well, emulating a primitive is a lot more expensive on a slow VM like
> SqueakJS still is. So I'm not too, surprised, but happy nonetheless :)
>

I was comparing DateAndTime class>>now with UTCDateAndTime versus the
DateAndTime class>>now in standard Squeak Chronology. Both of them call
primitives, but the new one is much faster.

Having said that, I can see that other DateAndTime functions are marginally
slower with UTCDateAndTime in SqueakJS. This is due to using large integer
arithmetic with no support from LargeIntegersPlugin. I'm guessing that if
one or two primitives from LargeIntegersPlugin could be implemented in
SqueakJS, it would provide a big performance boost for this particular
use case.

>
> > I am inexperienced with JavaScript and Git, so in case any of this did not
> > get through, the proposed new function in Squeak.Primitives is:
> >
> >     primitiveUtcWithOffset: function(argCount) {
> >         var d = new Date();
> >         var posixMicroseconds = this.pos53BitIntFor(d.getTime() * 1000);
> >         var offset = -60 * d.getTimezoneOffset();
> >         if (argCount > 0) {
> >             // either an Array or a DateAndTime in new UTC format with two
> > ivars
> >             var stWordIndexableObject = this.vm.stackValue(0);
> >             stWordIndexableObject.pointers[0] = posixMicroseconds;
> >             stWordIndexableObject.pointers[1] = offset;
> >             this.popNandPushIfOK(argCount + 1, stWordIndexableObject);
> >             return true;
> >         }
> >         var timeAndOffset = [
> >             posixMicroseconds,
> >             offset,
> >         ];
> >         this.popNandPushIfOK(argCount + 1, this.makeStArray(
> > timeAndOffset));
> >         return true;
> >     },
> >
>
> It looks fine. We could try to incorporate the microsecondClock function,
> but if milliseconds are good enough then this will do.
>

I would vote to leave it as milliseconds. It looks to me like performance.now()
is designed for profiling, and it intentionally avoids following clock skew.
That seems right for the microsecondClock() function in SqueakJS, but for
primitiveUtcWithOffset it seems better to directly answer the platform's opinion
of current time and offset, which may legitimately be influenced by clock skew.
If microsecond precision is needed for some reason, it can be added later.

Dave

Reply | Threaded
Open this post in threaded view
|

Re: SqueakJS named primitives in the interpreter modulej

David T. Lewis
 
On Tue, Jan 24, 2017 at 09:46:01PM -0500, David T. Lewis wrote:

> On Mon, Jan 23, 2017 at 04:17:42PM +0100, Bert Freudenberg wrote:
> >  
> > On Sat, Jan 21, 2017 at 5:06 AM, David T. Lewis <[hidden email]> wrote:
> >
> > >
> > > I sent a git pull request for the new primitive, so hopefully you can
> > > review it and include it in SqueakJS if it is not too horrible.
> >
> >
> > Awesome! Merged.
> >
> > To my considerable surprise, DateAndTime>>now seems to be 70 times faster
> > > on SqueakJS when using this primitive along with the enhancements in the
> > > UTCDateAndTime repository.
> >
> >
> > Well, emulating a primitive is a lot more expensive on a slow VM like
> > SqueakJS still is. So I'm not too, surprised, but happy nonetheless :)
> >
>
> I was comparing DateAndTime class>>now with UTCDateAndTime versus the
> DateAndTime class>>now in standard Squeak Chronology. Both of them call
> primitives, but the new one is much faster.
>
> Having said that, I can see that other DateAndTime functions are marginally
> slower with UTCDateAndTime in SqueakJS. This is due to using large integer
> arithmetic with no support from LargeIntegersPlugin. I'm guessing that if
> one or two primitives from LargeIntegersPlugin could be implemented in
> SqueakJS, it would provide a big performance boost for this particular
> use case.

Sorry to reply to my own post, but I need to retract this. The profiler
shows that a big portion of the time is spent in

    LargePositiveInteger(Integer)>>digitDiv:neg:

I mistakenly assumed that primDigitDevNegative was not implemented for
the LargeIntegers module, but that is wrong, I see now that function
primDigitDivNegative() is implemented in the translated plugins. So maybe
it is not an efficient implementation when translated to JavaScript?
I am not sure.

Dave

Reply | Threaded
Open this post in threaded view
|

Re: SqueakJS named primitives in the interpreter modulej

Bert Freudenberg
 
On Wed, Jan 25, 2017 at 4:11 AM, David T. Lewis <[hidden email]> wrote:

Sorry to reply to my own post, but I need to retract this. The profiler
shows that a big portion of the time is spent in

    LargePositiveInteger(Integer)>>digitDiv:neg:

I mistakenly assumed that primDigitDevNegative was not implemented for
the LargeIntegers module, but that is wrong, I see now that function
primDigitDivNegative() is implemented in the translated plugins. So maybe
it is not an efficient implementation when translated to JavaScript?

It certainly is not efficient, and I did not yet try to improve its efficiency, but it is faster than the fallback code:


What is the range of your LargeIntegers? SqueakJS does not implement most of prims 30-37, whereas the C VM at least does so with up to 64 bits IIRC?

This is just laziness on my part (since the fallback + plugin works), there's no good reason not to implement a fast path for these if the numbers fall within the 53 bit range JS can handle directly. We do have the code for 31 bit SmallInts, so this should be relatively simple.

These prims could even be made to handle arbitrary-sized large ints (in which case the plugin wouldn't even be needed, and it would likely be much faster) but getting the semantics exactly right is not trivial.

- Bert - 
Reply | Threaded
Open this post in threaded view
|

Re: SqueakJS named primitives in the interpreter modulej

Bert Freudenberg
 
On Wed, Jan 25, 2017 at 3:53 PM, Bert Freudenberg <[hidden email]> wrote:

What is the range of your LargeIntegers? SqueakJS does not implement most of prims 30-37,

I meant 20 - 37, the large int arithmetic prims, of course
 
whereas the C VM at least does so with up to 64 bits IIRC?

This is just laziness on my part (since the fallback + plugin works), there's no good reason not to implement a fast path for these if the numbers fall within the 53 bit range JS can handle directly. We do have the code for 31 bit SmallInts, so this should be relatively simple.

If someone wants to give this a shot, it should work along the lines of

case 21: return this.popNandPush53BitIntIfOK(2,this.stackSigned53BitInt(1) + this.stackSigned53BitInt(0)); // primitiveAddLargeIntegers

similar to what is already there for prims 23-28. Don't forget to extend NonSmallInt so you can reuse vm.div / vm.mod.

- Bert -


Reply | Threaded
Open this post in threaded view
|

Re: SqueakJS named primitives in the interpreter modulej

David T. Lewis
In reply to this post by Bert Freudenberg
 
On Wed, Jan 25, 2017 at 03:53:16PM +0100, Bert Freudenberg wrote:

>  
> On Wed, Jan 25, 2017 at 4:11 AM, David T. Lewis <[hidden email]> wrote:
>
> >
> > Sorry to reply to my own post, but I need to retract this. The profiler
> > shows that a big portion of the time is spent in
> >
> >     LargePositiveInteger(Integer)>>digitDiv:neg:
> >
> > I mistakenly assumed that primDigitDevNegative was not implemented for
> > the LargeIntegers module, but that is wrong, I see now that function
> > primDigitDivNegative() is implemented in the translated plugins. So maybe
> > it is not an efficient implementation when translated to JavaScript?
> >
>
> It certainly is not efficient, and I did not yet try to improve its
> efficiency, but it is faster than the fallback code:
>
> https://github.com/bertfreudenberg/SqueakJS/blob/master/plugins/LargeIntegers.js#L1798
>
> What is the range of your LargeIntegers? SqueakJS does not implement most
> of prims 30-37, whereas the C VM at least does so with up to 64 bits IIRC?
> https://github.com/bertfreudenberg/SqueakJS/blob/master/vm.js#L4301
>
> This is just laziness on my part (since the fallback + plugin works),
> there's no good reason not to implement a fast path for these if the
> numbers fall within the 53 bit range JS can handle directly. We do have the
> code for 31 bit SmallInts, so this should be relatively simple.
>
> These prims could even be made to handle arbitrary-sized large ints (in
> which case the plugin wouldn't even be needed, and it would likely be much
> faster) but getting the semantics exactly right is not trivial.
>

The large integers are microseconds since Posix epoch, so currently they
are 51 bits unsigned. They would begin using 52 bits in the year 2041, and
53 bits will not be needed until 2112. So these values should all fit within
a 53 bit direct integer representation in JavaScript.

For what it's worth:

  "UTC microseconds fits in a 53 bit register, with a couple of bits to spare"
  DateAndTime now utcMicroseconds asRegister: 53
  ==> a TwosComplementRegister with value 1485394271578388 (00101010001101111010101001101111010001010100100010100)
 
  "check register overflow, ok"
  (DateAndTime now utcMicroseconds asRegister: 53) overflow ==> false
 
  "52 bits required in 2041"
  DateAndTime utcMicroseconds:16r7FFFFFFFFFFFF offset: 0
  ==> 2041-05-10T11:56:53.685247+00:00

I would not expect any huge demand for optimizing this, after all I am
probably the only person on the planet using UTCDateAndTime ;-)

Interesting to note that the LargeIntegersPlugin assumes a binary world
of 8, 16, 32, 64... but we are now interested in tranlating its primitives
to a runtime with other native word sizes. It may still work, but it is
not likely to be optimal out of the box.

Dave