[Vm-dev] OSVM on WebAssembly

Manuel Leuenberger maenuleu at gmail.com
Fri Jul 8 16:46:02 UTC 2022


Hi Eliot,

Thanks for the explanation. I started looking into the return bytecode 348, but I could not find something suspicious. So I started logging more and then I saw a dim light:

> Error in loading dynamic library /SecurityPlugin: Error: need to see wasm magic number
> Error in loading dynamic library /SecurityPlugin.so: Error: need to see wasm magic number
> Error in loading dynamic library /libSecurityPlugin.so: Error: need to see wasm magic number
> Error in loading dynamic library SecurityPlugin: Error: need to see wasm magic number
> Error in loading dynamic library SecurityPlugin.so: Error: need to see wasm magic number

It finds libSecurityPlugin.so. But it only works as an external plugin, won't find it as an internal plugin. Weird, but it continues.

> sqImageFileClose ftruncate: Invalid argument

Opening the image file seems to work, and this is only a warning. Probably some Emscripten-specific ftruncate is needed.

> stateMachinePolicy != UNDEFINED 364

Assertion failed in heartbeat clock. I assume this is fine, as it happens only in the beginning

> Smalltalk stack dump:
>   0xaa2fec WorkingSession class(Behavior)>new 0x172b9f0: a(n) WorkingSession
>   0xaa300c SessionManager>newSession 0x177d300: a(n) SessionManager
>   0xaa302c SessionManager>installNewSession 0x177d300: a(n) SessionManager
>   0xaa3050 SessionManager>launchSnapshot:andQuit: 0x177d300: a(n) SessionManager
>  0x43276f8 s [] in SessionManager>snapshot:andQuit:
>  0x43278a0 s [] in FullBlockClosure(BlockClosure)>newProcess

This looks good!

> currentBytecode = 464
> currentBytecode = 320
> currentBytecode = 332
> currentBytecode = 401
> currentBytecode = 272
> currentBytecode = 380
> currentBytecode = 332
> currentBytecode = 384
> (localPrimIndex > 0xFF) && (localPrimIndex < 520) 5814
> localPrimIndex = 253

Assertion failed in interpreter. Oddly close to 0xFF...

> currentBytecode = 385
> localPrimIndex = 256
> currentBytecode = 348
> Smalltalk stack dump:
>   0xaa2fc4 MessageNotUnderstood class(Behavior)>new 0x1728360: a(n) MessageNotUnderstood
>   0xaa2fe8 SmallInteger(Object)>doesNotUnderstand: manager: 0xfffffff1=-8

Bottom of stack missing, assume it is SessionManager>>#newSession

newSession
	| aWorkingSession |
	aWorkingSession := WorkingSession new.
	aWorkingSession manager: self.
	^ aWorkingSession

#new seemed to have worked, but not #manager:.
Not sure how to interpret the 0xfffffff1=-8, and is SmallInteger always the receiver type in the interpreter stack?

> currentBytecode = 332
> currentBytecode = 384
> (localPrimIndex > 0xFF) && (localPrimIndex < 520) 5814
> localPrimIndex = 253

253 again. But where is it coming from?

> currentBytecode = 385
> localPrimIndex = 256
> currentBytecode = 348
> Smalltalk stack dump:
>   0xaa2f98 MessageNotUnderstood class(Behavior)>new 0x1728360: a(n) MessageNotUnderstood
>   0xaa2fbc SmallInteger(Object)>doesNotUnderstand: message: 0xfffffff1=-8
>   0xaa2fe8 SmallInteger(Object)>doesNotUnderstand: manager: 0xfffffff1=-8
>   0xaa300c SessionManager>newSession 0x177d300: a(n) SessionManager
>   0xaa302c SessionManager>installNewSession 0x177d300: a(n) SessionManager
>   0xaa3050 SessionManager>launchSnapshot:andQuit: 0x177d300: a(n) SessionManager
>  0x43276f8 s [] in SessionManager>snapshot:andQuit:
>  0x43278a0 s [] in FullBlockClosure(BlockClosure)>newProcess

Once it reaches #doesNotUnderstand:, we are in an infinite loop.

> currentBytecode = 501
> currentBytecode = 339
> currentBytecode = 320
> currentBytecode = 401
> currentBytecode = 272
> currentBytecode = 380
> currentBytecode = 332
> currentBytecode = 384
> (localPrimIndex > 0xFF) && (localPrimIndex < 520) 5814
> localPrimIndex = 253
> currentBytecode = 385
> localPrimIndex = 256
> currentBytecode = 348
> Smalltalk stack dump:
>   0xaa2f6c MessageNotUnderstood class(Behavior)>new 0x1728360: a(n) MessageNotUnderstood
>   0xaa2f90 SmallInteger(Object)>doesNotUnderstand: message: 0xfffffff1=-8
>   0xaa2fbc SmallInteger(Object)>doesNotUnderstand: message: 0xfffffff1=-8
>   0xaa2fe8 SmallInteger(Object)>doesNotUnderstand: manager: 0xfffffff1=-8
>   0xaa300c SessionManager>newSession 0x177d300: a(n) SessionManager
>   0xaa302c SessionManager>installNewSession 0x177d300: a(n) SessionManager
>   0xaa3050 SessionManager>launchSnapshot:andQuit: 0x177d300: a(n) SessionManager
>  0x43276f8 s [] in SessionManager>snapshot:andQuit:
>  0x43278a0 s [] in FullBlockClosure(BlockClosure)>newProcess

My suspicion is a 32bit/64bit type issue. I also saw a few segfaults in the past, but not recently, and not reproducible.
Anybody has a clue on what I should look at next?

Cheers,
Manuel

> On 27 Jun 2022, at 23:31, Eliot Miranda <eliot.miranda at gmail.com> wrote:
> 
> Hi Manuel,
> 
>    cool beans!
> 
> On Mon, Jun 27, 2022 at 3:54 AM Manuel Leuenberger <maenuleu at gmail.com <mailto:maenuleu at 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 <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.
> 
>  <https://github.com/maenu/opensmalltalk-vm/tree/Cog/building/minheadless.cmake/x86/pharo.stack.spur.wasm#current-issues>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.
>  
> 
>  <https://github.com/maenu/opensmalltalk-vm/tree/Cog/building/minheadless.cmake/x86/pharo.stack.spur.wasm#build--run>Build & Run
> 
>  <https://github.com/maenu/opensmalltalk-vm/tree/Cog/building/minheadless.cmake/x86/pharo.stack.spur.wasm#1-install-emscripten>1. Install Emscripten
> 
> I installed Emscripten SDK <https://emscripten.org/docs/getting_started/downloads.html> to get an all-in-one package.
> 
>  <https://github.com/maenu/opensmalltalk-vm/tree/Cog/building/minheadless.cmake/x86/pharo.stack.spur.wasm#2-grab-an-image>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 <https://get.pharo.org/32/90> | bash
>  <https://github.com/maenu/opensmalltalk-vm/tree/Cog/building/minheadless.cmake/x86/pharo.stack.spur.wasm#3-build-vm>3. Build VM
> 
> ./mvm_configure_variant debug Debug && make -C debug install
> 
>  <https://github.com/maenu/opensmalltalk-vm/tree/Cog/building/minheadless.cmake/x86/pharo.stack.spur.wasm#4-run-a-web-server>4. Run a web server
> 
> emrun --port 9090 --serve_root ../../../../ --no_browser .
> 
>  <https://github.com/maenu/opensmalltalk-vm/tree/Cog/building/minheadless.cmake/x86/pharo.stack.spur.wasm#5-launch-vm>5. Launch VM
> 
> http://localhost:9090/building/minheadless.cmake/x86/pharo.stack.spur.wasm/debug/dist/squeak.html <http://localhost:9090/building/minheadless.cmake/x86/pharo.stack.spur.wasm/debug/dist/squeak.html>
>  <https://github.com/maenu/opensmalltalk-vm/tree/Cog/building/minheadless.cmake/x86/pharo.stack.spur.wasm#6-inspect-running-vm>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.
> 
>  <https://github.com/maenu/opensmalltalk-vm/tree/Cog/building/minheadless.cmake/x86/pharo.stack.spur.wasm#resources>Resources
> 
> Inspect WebAssembly (at the bottom) <https://webassembly.org/getting-started/developers-guide/>
> Emscripten doc (Porting) <https://emscripten.org/docs/porting/index.html>
> Emscripten settings <https://emsettings.surma.technology/>
> 
> 
> 
> -- 
> _,,,^..^,,,_
> best, Eliot

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.squeakfoundation.org/pipermail/vm-dev/attachments/20220708/7b1aa3a6/attachment-0001.html>


More information about the Vm-dev mailing list