[squeak-dev] compiled squeakjs

Florin Mateoc florin.mateoc at gmail.com
Mon Jan 19 18:03:51 UTC 2015


On 1/19/2015 10:37 AM, Bert Freudenberg wrote:
> Hi Florin,
>
> this sounds extremely interesting. In particular the part about using continuations to model execution flow, that thought had not occurred to me yet. Indeed, non-local returns and interruptability are the hardest to map to JS. I will have to think about this idea a while :)
>
> SqueakJS does compilation, too, by now. It has a (very simple) JIT compiler that compiles bytecodes into equivalent JavaScript, on a method-by-method basis. Read the initial comment at 
> 	https://github.com/bertfreudenberg/SqueakJS/blob/master/jit.js
>
> To see it in action, open your browser's JS console and evaluate "SqueakJS.vm.method.compiled" which is the compiled version of the currently executing method. Or, if you're running a JS profiler, the generated methods will show up in that profile, too, and you can see their source.
>
> This is not a high-performance JIT yet, but it helps a lot compared to the simple interpreter. Here's the numbers on Chrome's V8:
> with JIT: 82315112 bytecodes/sec; 902155 sends/sec
> no JIT:    2775850 bytecodes/sec; 137439 sends/sec
>
> Also interesting - no JIT, before V8 deoptimization kicks in:
>           11494252 bytecodes/sec; 523121 sends/sec
> With the JIT, the code is more distributed, less polymorphic, so V8 can optimize better.
>
> Beware microbenchmarks etc, but it pays hugely to make your code "friendly" for the JS VM. Amber for example, on the same machine in the same browser, reports '2214839.4241417497 bytecodes/sec; 229042.45283018867 sends/sec' even though it directly compiles to JavaScript and does not have full Smalltalk semantics (e.g. no real thisContext, no become). I suspect deoptimization in V8. Indeed, on FireFox it reports '3007518.796992481 bytecodes/sec; 408234.4251766217 sends/sec', which is roughly the same as SqueakJS (40327662 bytecodes/sec; 516034 sends/sec).
>
> So since you're after the highest performance, it may pay off to do some experiments first. 
>
> Btw, here is a very interesting talk about how to make Smalltalk-style method invocation be fast on V8.
> video: http://2014.jsconf.eu/speakers/vyacheslav-egorov-invokedynamic-js.html
> slides: http://mrale.ph/talks/jsconfeu2014/
>
> I did not fully understand your proposal about the object memory layout, and how become would work. Also, allInstances/weak refs and finalization isn't accounted for.
>
> Do you intend this to be a fully compatible VM for Squeak? That was my goal with SqueakJS, performance being secondary (although not unimportant). SqueakJS does fully implement Squeak's execution semantics, including thisContext, non-local return, stack unwinding, DNU, process switching etc. and the object memory semantics too, including allObjects/allInstances, weak refs and finalization.
>
> Your proposed mapping to JS Arrays/Maps etc. seems to imply that it would not be fully compatible, right? Rather a Smalltalk-for-the-web with fewer compromises than Amber? Or is this even only meant as a deployment step, not as a fully self-hosted development environment?
>
> - Bert -
>

Hi Bert,

Thank you for the pointers, I will now have to go do some reading.

The idea for become: goes something like this (I know that standard WeakMaps are not enumerable, but given that
Google/Caja were apparently able to write a WeakMap shim without native support, I hope that code can be used as
inspiration to give us enumerable ones - this would also address the more general requirement for weak
collections/allInstances):
 
assignments, as well as the at:put: and instvarAt:put: primitives, add (if not already there) to the right-hand side
object a WeakMap property "owners". This happens only for non-primitive types. The keys are the owners and the values
are the indexes within the owner where the owned object lives. If there is already a previous object within the owner at
that index, the owner/index pair is removed from the previous object's owners.
At become: time, we iterate the owners and do the replacement


But to address the last part about compatibility:

Having gone through the experience of successfully migrating a huge Smalltalk application to Java (more than 2000
screens, many thousands of classes and millions of lines of code), I think of it as representative enough to be
confident in the general feasibility of the approach, even though we still do not have out of the box a fully automated
translation solution for every particular aspect (anyway, that was not the goal). Furthermore, one aspect of the
migration seemed pretty challenging: since this was an application already deployed in production at many (and vocal)
customers, we wanted to ensure a smooth transition and we did not just want the general functionality to be there but
essentially pixel-identical behavior for the Java incarnation. The original application also had proxies, a way of
applying patching in production, it included the compiler for runtime evaluation (both for patching, debugging and for
evaluating customer-specific scripts).
Now, we did not implement a Smalltalk vm on top of Java, so of course we did not fully implement Smalltalk (VA)
execution semantics. It turns out we did not need to. We achieved through automatic translation over 90% of the
functionality, including the (99%) pixel-identical presentation (we chose SWT as a target UI framework, since it mapped
closely to the original VA UI framework). For the rest we came up with ad-hoc solutions: we implemented something for
the proxies (taking advantage of the specific way they were used in the original application (so no general solution)),
we included the compiler and wrote a Java classloader for patching, we also wrote an inspector with Java runtime
evaluation capabilities. These last ones were just functionally equivalent (the evaluated snippets are Java, not
evaluating/translating on the fly Smalltalk scripts to Java - although that would have been fun). We reimplemented the
db communications layer to use JDBC.
All in all, this was a pragmatic approach and the application behaves the same and runs at the same speed as the
original, so from the point of view of the users, it is essentially the same.

This was a long-winded way of saying that I don't think exact execution semantics are that important. If you think the
pc in a context is part of Smalltalk's semantics, obviously the proposed approach does not address that. Even for a more
ambitious goal (we want to run (almost) any image, not just a specific one, even if huge and complex), I think this is a
place where one can cheat without being caught. Even allObjects/allInstances might not be required, especially that my
understanding is that the main purpose (other than debugging) for allInstances was to allow mutation. I don't think
mutation presents the same challenges in JavaScript.

Regarding mappings, of course one could write Smalltalk code that would catch us, but I think most "normal" usage
patterns could be covered. My goal would be a Smalltalk-for-the-web that could read and run almost any Squeak image (I
would not consider code purposely written to catch us cheating as a unveiling a bug, but I would consider any normal
usage pattern that would not work a bug), allowing self-hosted further development (with hooks for the Smalltalk
compiler to perform the same steps as the ones performed at image read time).


Florin


More information about the Squeak-dev mailing list