Skip to content
/ zmach Public

A z-machine interpreter which does dynamic recompilation to javascript

Notifications You must be signed in to change notification settings

kmill/zmach

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

12 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

zmach is a (semi-functional) Javascript-targeting Z-machine emulator.
It only implements version 5 of the machine (i.e., z5 files when they
are named correctly).

The technique is to decompile the bytecode dynamically, recompiling it
as Javascript, using an emscripten-inspired relooper algorithm to generate
(mostly) switch-less code.

The main idea behind this is that by converting full Z-machine
routines into Javascript functions, with arguments and local variables
becoming actual Javascript arguments and local variables, the
Javascript engine's JIT is given a chance to optimize the code.  This
is in contrast to emulators which maintain a separate call stack from
Javascript's native call stack.  One difficulty with this is that the
Z-machine has blocking I/O instructions (for instance, 'aread' for
user input), which browser Javascript has no support for.  The
interesting thing about this particular emulator is its use of the
Javascript call stack despite this difficulty --- the relooper is
there partly to show that this technique gives it access to full
Z-machine routines.

To handle blocking I/O, it implements a method to reify the call stack
as Javascript objects only when this is needed, at the expense of
wrapping function bodies in a try-catch block and storing an integer
into a local variable before call sites.  In other words, it takes the
idea of using continuations to implement cooperative multitasking, but
simulates continuations using try-catch blocks.  When resuming a
continuation, instead of trying to resume the actual functions which
were paused, the emulator calls specially compiled functions which
pick up at exactly where a routine last paused.  As far as I know,
this is a novel technique.  There is a 2007 paper[1] I later came across
with a similar exception-based technique, but it uses the same
function when resuming a continuation, complicating control flow.

In principle, this stack reification technique should also allow
saving a game in Quetzal, but this has not yet been implemented.

The emstripten-inspired relooper is a more streamlined version of
their algorithm.  (However, I've implemented the algorithm
inefficiently.)  At some point I plan on writing about how this works.

The motivation behind this project was to have an excuse to understand
the relooper, and to attempt the context resumption described above.
The full emulator might never be finished.  However, it does seem to
be able to play Zork I and other games without errors now.

To try it out:

1. run "node convert_zcode.js $storyfile.z5", which produces
   "$storyfile.z5.js" (or use your favorite technique for doing base64
   encoding.  Just call "loadData('base64', '$your-base64-string')" in
   the browser.)

2. edit zmach.html to load '$storyfile.z5.js'

3. open zmach.html

[1] Loitsch, Florian.  Exceptional Continuations in
Javascript. Proceedings of the 2007 Workshop on Scheme and Functional
Programming.  http://www.schemeworkshop.org/2007/procPaper4.pdf

About

A z-machine interpreter which does dynamic recompilation to javascript

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published