1
1
mirror of https://github.com/kanaka/mal.git synced 2024-09-21 02:27:10 +03:00
mal/ada.2
Nicolas Boulenguez 5a07bb5331 ada.2: fix memory leaks with garbage collection. Various simplifications.
Cyclic references were never deallocated by reference conuting.
Symbols cannot create cyclic structures and are less frequent (one
allocation per symbol), keep reference counting for them.

This slightly improves performances even though many previous
optimizations are removed (environment stack, reuse of memory).

Step caching hash of symbols. This does not seem to improve
performances. Hashing them instead of ordering them does.

Define Repl in the step file instead of globally. Move the eval
built-in function from core into the step file.

When possible, pass Ada records instead of explicit pointers.

In the reader, construct more objects directly as described in the MAL
process, reserve the buffer for sequences and maps

In eval, iterate on vectors without delegation. The increased
complexity was not improving performances.  Keep demonstrating Ada
type-safe genericity for maps, where iterating outside Types.Maps
would be less easy and/or efficient.

In quasiquote_list, concatenate in one buffer instead of allocating a
list for each element. The buffer may be reallocated behind the
curtain, but not once per element anymore.

In environments, illustrate tail call optimization when recursion is
more readable than a loop.
2019-03-31 19:06:00 +02:00
..
core.adb ada.2: fix memory leaks with garbage collection. Various simplifications. 2019-03-31 19:06:00 +02:00
core.ads ada.2: fix memory leaks with garbage collection. Various simplifications. 2019-03-31 19:06:00 +02:00
Dockerfile ada.2: add Dockerfile from kanaka 2019-03-17 14:15:41 +01:00
envs.adb ada.2: fix memory leaks with garbage collection. Various simplifications. 2019-03-31 19:06:00 +02:00
envs.ads ada.2: fix memory leaks with garbage collection. Various simplifications. 2019-03-31 19:06:00 +02:00
err.adb ada.2: fix reference count for envs and IO error propagation for slurp. 2019-03-27 08:19:15 +01:00
err.ads ada.2: fix reference count for envs and IO error propagation for slurp. 2019-03-27 08:19:15 +01:00
eval_cb.ads ada2: rename to ada.2 2019-03-10 01:25:07 +01:00
garbage_collected.adb ada.2: fix memory leaks with garbage collection. Various simplifications. 2019-03-31 19:06:00 +02:00
garbage_collected.ads ada.2: fix memory leaks with garbage collection. Various simplifications. 2019-03-31 19:06:00 +02:00
Makefile ada.2: fix memory leaks with garbage collection. Various simplifications. 2019-03-31 19:06:00 +02:00
printer.adb ada.2: fix memory leaks with garbage collection. Various simplifications. 2019-03-31 19:06:00 +02:00
printer.ads ada.2: spring cleaning before final pull request. 2019-03-17 14:03:38 +01:00
reader.adb ada.2: fix memory leaks with garbage collection. Various simplifications. 2019-03-31 19:06:00 +02:00
reader.ads ada.2: spring cleaning before final pull request. 2019-03-17 14:03:38 +01:00
readline.adb ada2: rename to ada.2 2019-03-10 01:25:07 +01:00
readline.ads ada2: rename to ada.2 2019-03-10 01:25:07 +01:00
README ada.2: fix memory leaks with garbage collection. Various simplifications. 2019-03-31 19:06:00 +02:00
run ada2: rename to ada.2 2019-03-10 01:25:07 +01:00
step0_repl.adb ada2: rename to ada.2 2019-03-10 01:25:07 +01:00
step1_read_print.adb ada.2: fix memory leaks with garbage collection. Various simplifications. 2019-03-31 19:06:00 +02:00
step2_eval.adb ada.2: fix memory leaks with garbage collection. Various simplifications. 2019-03-31 19:06:00 +02:00
step3_env.adb ada.2: fix memory leaks with garbage collection. Various simplifications. 2019-03-31 19:06:00 +02:00
step4_if_fn_do.adb ada.2: fix memory leaks with garbage collection. Various simplifications. 2019-03-31 19:06:00 +02:00
step5_tco.adb ada.2: fix memory leaks with garbage collection. Various simplifications. 2019-03-31 19:06:00 +02:00
step6_file.adb ada.2: fix memory leaks with garbage collection. Various simplifications. 2019-03-31 19:06:00 +02:00
step7_quote.adb ada.2: fix memory leaks with garbage collection. Various simplifications. 2019-03-31 19:06:00 +02:00
step8_macros.adb ada.2: fix memory leaks with garbage collection. Various simplifications. 2019-03-31 19:06:00 +02:00
step9_try.adb ada.2: fix memory leaks with garbage collection. Various simplifications. 2019-03-31 19:06:00 +02:00
stepa_mal.adb ada.2: fix memory leaks with garbage collection. Various simplifications. 2019-03-31 19:06:00 +02:00
types-atoms.adb ada.2: fix memory leaks with garbage collection. Various simplifications. 2019-03-31 19:06:00 +02:00
types-atoms.ads ada.2: fix memory leaks with garbage collection. Various simplifications. 2019-03-31 19:06:00 +02:00
types-builtins.adb ada.2: fix memory leaks with garbage collection. Various simplifications. 2019-03-31 19:06:00 +02:00
types-builtins.ads ada.2: fix memory leaks with garbage collection. Various simplifications. 2019-03-31 19:06:00 +02:00
types-fns.adb ada.2: fix memory leaks with garbage collection. Various simplifications. 2019-03-31 19:06:00 +02:00
types-fns.ads ada.2: fix memory leaks with garbage collection. Various simplifications. 2019-03-31 19:06:00 +02:00
types-mal.adb ada.2: fix memory leaks with garbage collection. Various simplifications. 2019-03-31 19:06:00 +02:00
types-mal.ads ada.2: fix memory leaks with garbage collection. Various simplifications. 2019-03-31 19:06:00 +02:00
types-maps.adb ada.2: fix memory leaks with garbage collection. Various simplifications. 2019-03-31 19:06:00 +02:00
types-maps.ads ada.2: fix memory leaks with garbage collection. Various simplifications. 2019-03-31 19:06:00 +02:00
types-sequences.adb ada.2: fix memory leaks with garbage collection. Various simplifications. 2019-03-31 19:06:00 +02:00
types-sequences.ads ada.2: fix memory leaks with garbage collection. Various simplifications. 2019-03-31 19:06:00 +02:00
types-symbols-names.ads ada.2: spring cleaning before final pull request. 2019-03-17 14:03:38 +01:00
types-symbols.adb ada.2: fix memory leaks with garbage collection. Various simplifications. 2019-03-31 19:06:00 +02:00
types-symbols.ads ada.2: fix memory leaks with garbage collection. Various simplifications. 2019-03-31 19:06:00 +02:00
types.ads ada.2: spring cleaning before final pull request. 2019-03-17 14:03:38 +01:00

Comparison with the first Ada implementation.
--

The first implementation was deliberately compatible with all Ada
compilers, while this one illustrates various Ada 2020 features:
assertions, preconditions, invariants, initial assignment for limited
types, limited imports, indexing aspects...

The variant MAL type is implemented with a discriminant instead of
object-style dispatching.  This allows more static and dynamic checks,
but also two crucial performance improvements:
* Nil, boolean, integers and pointers to built-in functions are passed
  by value without dynamic allocation.
* Lists are implemented as C-style arrays, and most of them can be
  allocated on the stack.

Another difference is that a minimal form of garbage collecting is
implemented, removing objects not referenced from the main
environment. Reference counting is convenient for symbols or strings,
but never deallocates cyclic structures. The implementation collects
garbage after each Read-Eval-Print cycle. It would be much more
difficult to collect garbage inside scripts. If this is ever done, it
would be better to reimplement load-file in Ada and run a cycle after
each root evaluation.

The eventual performances compete with C-style languages, allthough
all user input is checked (implicit language-defined checks like array
bounds and discriminant consistency are only enabled during tests).

Notes for contributors that do not fit in a specific package.
--

* All packages can call Eval back via a reference in the Eval_Cb
  package, set during startup. I am interested in a prettier solution
  ensuring a valid value during elaboration.
  Note that generic packages cannot export access values.

* Symbol pointers are non null, new variables must be assigned
  immediately. This is usually enforced by a hidden discriminant, but
  here we want the type to become a field inside Types.Mal.T. So the
  check happens at run time with a private invariant.

  The finalize procedure may be called twice, so it does nothing when
  the reference count is zero, meaning that we are reaching Finalize
  recursively.

* In implementations with reference counting, a consistent object
  (that will be deallocated automatically) must be built before any
  exception is raised by user code (for example the 'map' built-in
  function may run user code).  Garbage collection simplifies a lot
  this kind of situations.

* Each module encapsulating dynamic allocation counts allocations and
  deallocations. With debugging options, a failure is reported if
  - too many deallocation happen (via a numeric range check)
  - all storage is not freed (via a dedicated call from the step file)

  The main program only checks that the garbage collector removes all
  allocations at the end of execution.

Debugging
--

Uncaught exceptions are reported with an execution trace (excluding
TCO cycles).  This has become possible in step9, but has been
backported to former steps as this is really handy for debugging.

Some environment variables increase verbosity.
# dbgread= ./stepAmal     trace reader recursion
# dbgeval= ./stepAmal     trace eval recursion (including TCO)