Hi Manuel,

   cool beans!

On Mon, Jun 27, 2022 at 3:54 AM Manuel Leuenberger <maenuleu@gmail.com> wrote:
 
Hi,

Ever since WebAssembly became a thing, I was wondering if this could become a target for VMs. People are already compiling FFMPEG and other complex tools. So I thought I would try as well.

So here I am to report to whom it may concern: OSVM compiles to WebAssembly, starts up (nearly), then looping infinitely
Meaning: The VM mmaps the image file, loads plugins (SecurityPlugin made EXTERNAL), starts interpreter loop, but then loops the same bytecode sequence forever

Code lives at https://github.com/maenu/opensmalltalk-vm/tree/Cog/building/minheadless.cmake/x86/pharo.stack.spur.wasm if you want to try it out.

Below is the current Readme, including a short list of issues. Maybe some of you could give me a hint?

Cheers,
Manuel

pharo.stack.spur.wasm

Compiles OSVM Stack interpreter to WebAssembly using the Emscripten compiler. Emscripten can be used as a drop-in replacement for gcc/clang and cmake. Based on MinHeadless Linux 32bit sources, as Emscripten provides Linux-like environment (pthreads, nanosleep, dlopen, file system). Check the latest few commits of maenu to see changed files.

Current issues

  • Most adjustments are just putting EMSCRIPTEN in a macro or script. Should be fine, but should be tested to not interfere with other builds.

  • Compiles and runs, but seems to be stuck in initial GC and Heartbeat. Those could be related to incorrect get/set64() implementation.

  • Removed mmap address hint, as it caused errors.

  • Using argv eval '1 + 3' to do a simple eval does not terminate.

  • Interpreter repeats these bytecodes forever (what is this?):


Taking these from e.g. src/spur64.stack/interp.c they are
 
       CASE(112)
        CASE(332) /*76*/
            /* pushReceiverBytecode */
332
        CASE(208)
        CASE(209)
        CASE(210)
        CASE(211)
        CASE(212)
        CASE(213)
        CASE(214)
        CASE(215)
        CASE(216)
        CASE(217)
        CASE(218)
        CASE(219)
        CASE(220)
        CASE(221)
        CASE(222)
        CASE(223)
        CASE(384) /*128*/ i.e. send literal selector 0 with 0 args
        CASE(385) /*129*/
        CASE(386) /*130*/
        CASE(387) /*131*/
        CASE(388) /*132*/
        CASE(389) /*133*/
        CASE(390) /*134*/
        CASE(391) /*135*/
        CASE(392) /*136*/
        CASE(393) /*137*/
        CASE(394) /*138*/
        CASE(395) /*139*/
        CASE(396) /*140*/
        CASE(397) /*141*/
        CASE(398) /*142*/
        CASE(399) /*143*/
            /* sendLiteralSelector0ArgsBytecode */
 
384
 
hence send literal selector 1 with 0 args

385

        CASE(124)
        CASE(348) /*92*/
            /* returnTopFromMethod */
348
 
        CASE(501) /*245*/
            /* longStoreTemporaryVariableBytecode */
501
        CASE(136)
        CASE(339) /*83*/
            /* duplicateTopBytecode */
339
        CASE(16)
        CASE(320) /*64*/
            /* pushTemporaryVariableBytecode */
320
 
        CASE(224)
        CASE(225)
        CASE(226)
        CASE(227)
        CASE(228)
        CASE(229)
        CASE(230)
        CASE(231)
        CASE(232)
        CASE(233)
        CASE(234)
        CASE(235)
        CASE(236)
        CASE(237)
        CASE(238)
        CASE(239)
        CASE(400) /*144*/
        CASE(401) /*145*/ i.e. send literal selector 1 with 1 arg
        CASE(402) /*146*/
        CASE(403) /*147*/
        CASE(404) /*148*/
        CASE(405) /*149*/
        CASE(406) /*150*/
        CASE(407) /*151*/
        CASE(408) /*152*/
        CASE(409) /*153*/
        CASE(410) /*154*/
        CASE(411) /*155*/
        CASE(412) /*156*/
        CASE(413) /*157*/
        CASE(414) /*158*/
        CASE(415) /*159*/
            /* sendLiteralSelector1ArgBytecode */
401
        CASE(64)
        CASE(272) /*16*/
            /* pushLiteralVariableBytecode */
272
         CASE(204)
        CASE(380) /*124*/
            /* bytecodePrimNew */ i.e. a send of #new from the special selector bytecode
380

If I had to guess what's going wrong I'd guess that the return bytecode 348 isn't correctly implemented.
 

Build & Run

1. Install Emscripten

I installed Emscripten SDK to get an all-in-one package.

2. Grab an image

Grab a 32bit Smalltalk image and but it in the image folder. I used Pharo 9.

cd building/minheadless.cmake/x86/pharo.stack.spur.wasm
mkdir image
cd image
curl https://get.pharo.org/32/90 | bash

3. Build VM

./mvm_configure_variant debug Debug && make -C debug install

4. Run a web server

emrun --port 9090 --serve_root ../../../../ --no_browser .

5. Launch VM

http://localhost:9090/building/minheadless.cmake/x86/pharo.stack.spur.wasm/debug/dist/squeak.html

6. Inspect running VM

The VM is compiled with DWARF debug information, which is understood by the Chrome debugger. So we can step through the C sources of the WebAssembly, pretty nifty.

Resources




--
_,,,^..^,,,_
best, Eliot