An interpreter for GHC STG written in Haskell itself
🚧 Prana is under construction.
See
test/assets/
under prana-interpreter
for example programs that run with prana.
Milestone | Status | Appraisal |
---|---|---|
Clean STG from GHC | ✔️ | Laborious |
Interpreter prototype for AST | ✔️ | Fairly easy |
Basic test suite for interpreter | ✔️ | Easy |
Move interpreter into prana-interpret library |
✔️ | Easy |
Support all primitive types (Char# etc.) |
✔️ | Fairly straight-forward |
tagToEnum support |
✔️ | Pain in the arse |
Report unimplemented primops when compiling | ✔️ | Straight-forward |
Primops for register types (Word# , Int# , etc.) |
✔️ | Straight-forward |
Primops for arrays (ByteArray# , etc.) |
✔️ | Fairly straight-forward |
Have a sophisticated inspector | – | Fairly straight-forward |
Get code coverage to near 100% | – | Detailed |
Code cleanup | – | Straight-forward |
Milestone | Status | Appraisal |
---|---|---|
FFI support | 🚧 | Requires learning but should design itself |
IO primops | ✔️ | Fairly straight-forward |
Runtime exceptions (raise# ) |
– | Tricky, space for UX design |
Run base package tests | – | Fairly straight-forward |
Add hotswapping support (like Emacs) | – | Requires exploration/experiment |
Threaded runtime/concurrency | – | Could be tricky |
- All the base packages only use static FFI calls, we can ignore dynamic ones for now.
- Wrappers are used in the base packages.
- The following prim calls (custom primops) are used:
- PrimCall "stg_word32ToFloatzh" base
- PrimCall "stg_floatToWord32zh" base
- PrimCall "stg_word64ToDoublezh" base
- PrimCall "stg_doubleToWord64zh" base
Meanwhile, objectDir from DynFlags contains
chris@precision:~/Work/chrisdone/prana$ ls -alh ghc-8.4/libraries/ghc-prim/dist/build
total 14M
drwxr-xr-x 5 chris chris 4.0K May 25 11:54 .
drwxr-xr-x 4 chris chris 4.0K May 25 11:51 ..
drwxr-xr-x 2 chris chris 4.0K May 25 11:47 autogen
drwxrwxr-x 2 chris chris 4.0K Feb 27 18:13 cbits
drwxrwxr-x 2 chris chris 4.0K May 25 11:43 GHC
-rw-rw-r-- 1 chris chris 7.0M May 25 11:41 libHSghc-prim-0.5.2.0-Bfo9y0qb0emG5VRfx5d4mv.a
-rwxrwxr-x 1 chris chris 6.9M May 25 11:51 libHSghc-prim-0.5.2.0-Bfo9y0qb0emG5VRfx5d4mv-ghc8.4.3.so
Which is interesting for two use-cases:
- We could copy the whole .so file alongside our .prana file, and then simply load it up with dlopen() and lookup the C functions.
- Or, alternatively, we could just link together all the cbits (see below) into one ghc-prim.so, along with any additional linker flags for the package.
But my hunch is that it would be much easier to just load up the 7meg .so file.
ghc-8.4/libraries/ghc-prim/dist/build/cbits:
total 96K
drwxrwxr-x 2 chris chris 4.0K Feb 27 18:13 .
drwxr-xr-x 5 chris chris 4.0K May 25 11:54 ..
-rw-rw-r-- 1 chris chris 4.9K Feb 27 18:13 atomic.dyn_o
-rw-rw-r-- 1 chris chris 4.9K Feb 27 18:13 atomic.o
-rw-rw-r-- 1 chris chris 1.4K Feb 27 18:13 bswap.dyn_o
-rw-rw-r-- 1 chris chris 1.4K Feb 27 18:13 bswap.o
-rw-rw-r-- 1 chris chris 1.6K Feb 27 18:13 clz.dyn_o
-rw-rw-r-- 1 chris chris 1.6K Feb 27 18:13 clz.o
-rw-rw-r-- 1 chris chris 1.6K Feb 27 18:13 ctz.dyn_o
-rw-rw-r-- 1 chris chris 1.6K Feb 27 18:13 ctz.o
-rw-rw-r-- 1 chris chris 1.8K Feb 27 18:13 debug.dyn_o
-rw-rw-r-- 1 chris chris 1.8K Feb 27 18:13 debug.o
-rw-rw-r-- 1 chris chris 944 Feb 27 18:13 longlong.dyn_o
-rw-rw-r-- 1 chris chris 944 Feb 27 18:13 longlong.o
-rw-rw-r-- 1 chris chris 1.8K Feb 27 18:13 pdep.dyn_o
-rw-rw-r-- 1 chris chris 1.8K Feb 27 18:13 pdep.o
-rw-rw-r-- 1 chris chris 1.7K Feb 27 18:13 pext.dyn_o
-rw-rw-r-- 1 chris chris 1.7K Feb 27 18:13 pext.o
-rw-rw-r-- 1 chris chris 2.4K Feb 27 18:13 popcnt.dyn_o
-rw-rw-r-- 1 chris chris 2.4K Feb 27 18:13 popcnt.o
-rw-rw-r-- 1 chris chris 1.4K Feb 27 18:13 word2float.dyn_o
-rw-rw-r-- 1 chris chris 1.4K Feb 27 18:13 word2float.o
Demo for ghc-prim:
[6 of 8] Converting GHC.Debug
CCall (CCallSpec (StaticTarget NoSourceText "debugLn" (Just ghc-prim) True) CCallConv PlayRisky)
CCall (CCallSpec (StaticTarget NoSourceText "debugErrLn" (Just ghc-prim) True) CCallConv PlayRisky)
So:
chris@precision:~/Work/chrisdone/prana$ nm -g ghc-8.4/libraries/ghc-prim/dist/build/libHSghc-prim-0.5.2.0-Bfo9y0qb0emG5VRfx5d4mv-ghc8.4.3.so | grep debugLn
00000000003abd60 T debugLn
00000000003dd998 D ghczmprim_GHCziDebug_debugLn_closure
00000000003954c0 T ghczmprim_GHCziDebug_debugLn_info
chris@precision:~/Work/chrisdone/prana$ nm -g ghc-8.4/libraries/ghc-prim/dist/build/libHSghc-prim-0.5.2.0-Bfo9y0qb0emG5VRfx5d4mv-ghc8.4.3.so | grep debugErrLn
00000000003abd70 T debugErrLn
00000000003dd9a8 D ghczmprim_GHCziDebug_debugErrLn_closure
0000000000395568 T ghczmprim_GHCziDebug_debugErrLn_info
Milestone | Status | Appraisal |
---|---|---|
Boot process to compile the wired in packages | 🚧 | Takes work |
Analysis package prana-analysis |
– | Fairly straight-forward |
I now need a reproducible way to build:
ghc-prim
integer-simple
base
DON'T FORGET (2019 Oct 27):
When rebuilding these, run
rm -rf /home/chris/.stack/programs/x86_64-linux/ghc-8.4.3/lib/ghc-8.4.3/prana/
to reset the package index.
ghc-prim
$ stack build && stack ghc -- Setup.hs -v0 && stack exec --no-ghc-package-path -- ./Setup configure -v0 --with-ghc prana-ghc && stack exec --no-ghc-package-path ./Setup build
integer-gmp
$ stack build && stack ghc -- Setup.hs -v0 && stack exec --no-ghc-package-path -- ./Setup configure -v0 --with-ghc prana-ghc && stack exec --no-ghc-package-path ./Setup build
base
valderman/haste-compiler#11 (comment)
$ autoreconf
$ stack build && stack ghc -- Setup.hs -v0 && stack exec --no-ghc-package-path -- ./Setup configure -finteger-gmp -v0 --with-ghc prana-ghc --ghc-options=-O0 && stack exec --no-ghc-package-path -- ./Setup build --ghc-options=-O0
-
custom ghc: commercialhaskell/stack#725 (comment) doesn't work commercialhaskell/stack#725 (comment)
-
But this works via compiler-tools: commercialhaskell/stack#725 (comment)
Stack refuses to build core packages, so we'll have to put that in prana-boot.
I need a check that:
- Literally looks at the list of packages in scope.
- Complains if any of those packages are not built by prana, ask the user to run prana-boot.
That should solve all my issues.
Milestone | Status | Appraisal |
---|---|---|
Move from binary something faster that also works |
– | Takes yak shaving |
Optimization of interpreter | – | Detailed |
Allocation tests | – | Easy |
CPU instruction tests | – | Easy |
Milestone | Status | Appraisal |
---|---|---|
Distributed evaluation | – | Detailed, space for UX design |
strace-like functionality for all primops | – | Pretty easy |
Fuzzing of primops (think: threads, exceptions) | – | Fun, space for UX design |
Prana web service | – | Straight-forward |
JavaScript implementation | – | Takes some work |
Milestone | Status | Appraisal |
---|---|---|
A web UI | – | Takes some work |
Emacs integration | – | Takes some work |
Your-IDE-here | – | ? |
The following are planned to be implemented as standard:
Milestone | Status |
---|---|
Char# |
✔️ |
Int# |
✔️ |
Int8# |
- |
Word8# |
- |
Int16# |
- |
Word16# |
- |
Word# |
✔️ |
Int64# |
✔️ |
Word64# |
✔️ |
Double# |
✔️ |
Float# |
✔️ |
Array# a |
✔️ |
MutableArray# s a |
✔️ |
SmallArray# a |
✔️ |
SmallMutableArray# s a |
✔️ |
ByteArray# |
✔️ |
MutableByteArray# s |
✔️ |
ArrayArray# |
- |
MutableArrayArray# s |
- |
Addr# |
✔️ |
MutVar# s a |
- |
Weak# b |
- |
StablePtr# a |
- |
StableName# a |
- |
The following are needed for IO:
Milestone | Status |
---|---|
State# s |
- |
RealWorld |
- |
ThreadId# |
- |
The following are more exotic types to be implemented later:
Milestone | Status |
---|---|
TVar# s a |
- |
MVar# s a |
- |
Compact# |
- |
The following don't need implementing or won't be implemented:
BCO#
Proxy# a
- The SIMD vector operations
- Handles unboxed tuples as any other type.
Use of libffi may show this
error while loading shared libraries: libffi.so.7: cannot open shared object file: No such file or directory
which is due to this: https://gitlab.haskell.org/ghc/ghc/issues/15397
Workaround, set the same path as your GHC's rts path:
LD_LIBRARY_PATH=/home/chris/.stack/programs/x86_64-linux/ghc-8.4.3/lib/ghc-8.4.3/rts/
which has the libffi.so.7 in it.