Menai v0.6 has a huge amount of new and updated functionality. Big things are changes to the compiler and the evolution of what will become a very thorough standard library.
Menai v0.6
Menai v0.6 touches on a lot of important themes:
- Adding a standard library
- Reworking the compiler passes to be pure functions and updating the pass manager to use them more effectively
- Significantly improved code generation
- Significantly improved compilation speed
- Cryptographic hashing and CRC32 capabilities for
bytesobjects - A tracing profiler
New features:
- Added
menai-eval, a tool that compiles and evaluates a.menaifile (or an expression from stdin) and prints the result. It can optionally profile the compiler with--cprofileand/or VM execution opcodes with--opcodes, and both may be combined. - Removed
menai-profileasmenai-evaldoes everything it did and more. - Added an approach for implementing negative tests in
menai-test. - Added
bmp-decodeandbmp-encodemodules to read and write BMP image files. - Added
deflate-compressanddeflate-decompressmodules. These compress and decompress using DEFLATE (RFC 1951) compression. - Added
zip-create,zip-entriesandzip-extractmodules. These write/read a ZIP archive's central directory and can process stored and deflated entries. - Added
zlib-compressandzlib-decompressmodules. These compress and decompress a zlib stream (RFC 1950). - Added
png-decodeandpng-encodemodules. These read/write non-interlaced 8-bit PNG image files. - Added a
json-encodemodule to serialize JSON and renamedjson_parsertojson-decode. - Added a
bytes-crc32primitive. This computes the CRC-32/ISO-HDLC checksum of a bytes value as an integer. - Added floating-point bytes primitives:
bytes-read-f32-le/-be,bytes-read-f64-le/-be,bytes-append-f32-le/-be,bytes-append-f64-le/-be,bytes-write-f32-le/-be, andbytes-write-f64-le/-be. These mirror the multi-byte integer operations, encoding and decoding IEEE-754 values. - Reworked the type propagation optimizations. Removed the old implementation and added a new one based on interprocedural analysis. This allows return types to be back propagated to callers and to remove type guards that are provably not necessary.
- Replaced the concept of the "prelude" functions being special global symbols and instead made them a letrec around the user's program. This removes a number of idiosyncracies in the internal design.
- Improved the slot allocator so it eliminates more redundant
MOVEopcodes in self-recursive loops. - Added a loop rotation CFG pass. A self-recursive loop with its test at the top is rotated so the test is evaluated at the bottom.
- Improved the constant type annotations in the disassembler.
- Added cryptographic hashing of
bytesvalues:bytes-hash-sha2-256,bytes-hash-sha2-512,bytes-hash-sha2-512-256(FIPS Pub 180-4) andbytes-hash-sha3-256(FIPS Pub 202). Each takes abytesvalue and returns the raw digest asbytes. - Added binary floating point read, append, and write operations for bytes.
- Added a peephole optimization that inlines an unconditional jump targeting a label immediately followed by a
RETURN. - Added the
RETURN_IF_FALSEandRETURN_IF_TRUEopcodes and a peephole optimization that fuses a conditional jump leading directly to aRETURNinto a single conditional-return instruction. ARETURNblock that becomes unreachable after the fusion is removed. - Added a struct instance folding optimization. A
struct-is-instance?test whose receiver is proven to be a struct of exactly the tested type is folded to#tand its branch re-wired. - Added a tracing/annotating profiler.
menai-eval --annotaterenders every function's disassembly with per-instruction execution counts and shares. - Added support for disassembling a module with
menai-disassemble. - Made constant folding able to create vectors.
- Added missing prelude functions.
- Improved compiler diagnostics and parsing error messages.
- Reworked the module system and introduced the
::special form. - Removed
struct-refandstruct-set-reffrom the language. - Renamed the element access operations for consistency and to remove the mutation connotation of
set,add, andremove. Positional reads are now-nth(string-nth,list-nth,bytes-nth,vector-nth), keyed reads are-get(dict-get,struct-get), additions and replacements are-with(vector-with,dict-with,struct-with,set-with), and removals are-without(set-without,dict-without,list-without). This replacesstring-ref,list-ref,bytes-ref,vector-ref,vector-set,dict-set,struct-set,set-add,set-remove,dict-remove, andlist-remove. - Improved the inliner so it can inline
letrec-containing bodies. - Improved performance of integer bitwise VM operations.
- Improved the algorithmic performance of deflate, inflate and the Sudoku and Rubik's cube benchmarks.
Bug fixes:
- Fixed a slot allocation bug that could emit a branch on a register in the outgoing argument zone.
- Fixed a VM crash when
applyis used with a large argument list. reserved slots corrupted memory. - Fixed a VM stack overflow when freeing a long list. The list finalizer released the tail recursively, using one C stack frame per element, so freeing a list of a few hundred thousand elements overflowed the C stack. Long lists are now freed iteratively.
- Fixed a CFG bug where branch constant propagation could remove a phi node whose result was still used by a branch target.
- Fixed a CFG bug where dead capture elimination failed to remove orphaned
PATCH_CLOSUREinstructions. - Dictionaries created with duplicate keys retained the first value, but should have retained the last one.
- Sets created with dynamic duplicate elements must not contain duplicates!
- Fixed a crash in the closure cycle collector when a dead closure was destroyed twice in one sweep.
- Fixed a problem where desugaring did not correctly honour shadowing of operation names.
- Struct type recognition is now lexically scoped. Two struct types with the same name in different scopes are distinct, and a struct type is not visible outside the binder that declares it.
- Fixed a compiler register usage bug.
- Fixed several soundness bugs in the type analysis, including a phi type-fact bug and a struct field-access rewrite that could omit a required guard.
- Fixed desugaring of
vector-slice. - Fixed inliner shadowing and recursion-checker bugs.
- Fixed a VM crash from deep recursion.
- Fixed non-determinism in the compiler.
- Fixed a type guard problem and regressions in loop-invariant code motion,
MOVEremoval, loop rotation and type propagation.
Internal structure changes:
- Made the compiler purely functional. Every phase is now a pure function over immutable values, and the AST, IR, CFG, VCode and bytecode models are immutable. Each layer has an immutability test.
- Made the CFG an immutable value. Terminators reference blocks by id, predecessors are derived rather than stored, and passes receive a context carrying cross-pass state.
- Reworked the CFG pass manager to run each pass to its own fixed point.
- Renamed the standard library modules to a
format-operationconvention. - Removed the last elements of compiler global state.
- Added ADRs recording the inliner recursion rule, letrec-to-loop conversion, CFG immutability, compiler purity, function provenance through containers, and predicate folding over interprocedural facts.