Skip to content

Lowent v1.33.0

Choose a tag to compare

@rubidus-api rubidus-api released this 10 Nov 17:37
· 9 commits to main since this release

Lowent is still under active development, and the language design is still changing. Syntax, diagnostic codes and command-line options may change without notice. · 아직 개발 중이고 언어 설계가 계속 바뀝니다. 문법 · 진단 코드 · 명령줄 옵션이 예고 없이 바뀔 수 있습니다.

Lowent v1.33.0 — compiler 1.33.0 · language revision 1.30 (unchanged) · ABI epoch 2026-09-29 (provisional) · still experimental: the language design keeps changing.

An op that sends to actors it spawned itself now stays on the fast native path — and five defects that v1.32.0 had are fixed (two of them gave the same wrong answer on both back ends, so the VM/native comparison could not see them).

Improved

  • spawn send, drain and schedule on actors an op spawned itself compile to plain C. Such an actor lives in a home of its own; a queued message holds the actor's bytes, the handler's fast version and its integer arguments. Messages still waiting when the op returns are delivered to that actor later, as before. Native, per message (same machine, cc -O2, best of 7): spawn send + drain 112–233 ns in v1.32.0 → 19–24 ns; delivery by schedule, two actors, 239–273 ns → 125–163 ns. Not yet on the fast path: try spawn send, handlers with non-integer arguments, actors with a slice in their state, failure restart actors, ops that take an actor as a parameter, and the T0 floor.

Fixed

  • A new actor received the messages of an older one. When an actor still had messages waiting and its record was reclaimed (after a call that returns a number, or when the record pool was compacted), the next spawn reused it and got those messages. The VM, native code and T0 all gave the same wrong answer, so the VM/native comparison could not see it.
  • The call depth limit counts every call in native code, as on the VM. Native code used to count only calls that can reach recursion, so at the very edge of the limit a non-recursive op called at the bottom of a recursion made the VM stop where native code answered (r 127). A handler run by drain or schedule is counted too.
  • Restarting a failure restart actor no longer leaves call depth behind. In native code each restart left the depth of the frames it skipped, so after about a hundred restarts the program stopped with "call depth limit exceeded"; the VM ran to the end.
  • Converting a u64 of 2^63 or more to f64 or f32 gives the nearest floating-point value (canon 6.2.16 (3-1)). It used to be negative on both back ends (cast f64 <u64 2^64−1> was −1.0), also for an untyped literal of that size.
  • Calling an op that takes no argument inside expr (expr n. + z . .) was refused as an internal compiler bug. It is now a value there, as everywhere else.

Known

  • Counting every call costs one comparison per call in recursive programs whose recursion calls small helper ops. In a small recursive benchmark made mostly of such calls it was about a third slower (89 → 121 ms); in the benchmark set it moved only json (+2.7 %, inside the noise of this machine).
  • A native program with worker threads (LOWENT_THREADS) in which a task does a fast-path spawn send was not tested. The tagged path has the same open question.
  • A send that waits (not spawn send) to an actor that is handling a message is unchanged: it calls the handler at once.

Numbers

2,327 regression checks pass; 77 standard library modules; the full project check, the VM/native differential sweep (4,361 ops and 28,980 argument vectors, 0 disagreements) and the remote gcc / clang / 32-bit builds are green.