Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
161922c
fix(compiler): headerless moves consume their source, own params drop…
marsninja Sep 5, 2026
11bd964
fix(compiler): owned-list layout is a program-wide type decision; pop…
marsninja Sep 5, 2026
f9cd621
feat(compiler): receiver modes for methods, inferred from the body an…
marsninja Sep 5, 2026
3a44999
chore: release-note fragment for #8986; last-use release of optional …
marsninja Sep 5, 2026
6d8d340
feat(compiler): views by inference — archetypes with borrow fields an…
marsninja Sep 5, 2026
d8bedde
fix(compiler): view-archetype detection is syntactic and lazy; receiv…
marsninja Sep 5, 2026
d90d9e3
fix(compiler): a dependency tree owned by another program is adopted …
marsninja Sep 5, 2026
32f7f80
feat(compiler): lin, container stores as moves, errors without unwind…
marsninja Sep 5, 2026
fcb919d
feat(cli)!: the memory profile replaces the gc flag matrix; jac build…
marsninja Sep 5, 2026
d8479bf
Merge upstream main into nogc-profile
marsninja Sep 5, 2026
073f96f
build: the launcher stub builds through jac build --native
marsninja Sep 5, 2026
28a0e0b
feat(compiler): locals infer their ownership state under enforcement,…
marsninja Sep 6, 2026
f098a41
Merge upstream main into nogc-profile
marsninja Sep 6, 2026
7eba6a3
test(native): cross-target tests use push_native_target, jac explain …
marsninja Sep 6, 2026
f34ebdf
Merge remote-tracking branch 'upstream/main' into nogc-profile
marsninja Sep 6, 2026
29432de
Complete ownership profile semantics and share backend infrastructure
marsninja Sep 6, 2026
b6f5cda
Add explicit backend selection to jac run
marsninja Sep 6, 2026
864d8ab
Rewrite Rocket Arena with typed ownership and reliable browser lifecycle
marsninja Sep 6, 2026
0a66eb9
Fix graph lookup and ownership regressions exposed by CI
marsninja Sep 6, 2026
ffa92ef
Fix backend import decisions, type narrowing, and test runtime context
marsninja Sep 6, 2026
dea6874
Respect imported user definitions when classifying builtin calls
marsninja Sep 6, 2026
09f4e4c
Keep graph deletions in the active request and avoid bootstrap cleanu…
marsninja Sep 6, 2026
792d64a
Limit equivalence workers to fit the CI runner memory budget
marsninja Sep 6, 2026
352d407
Merge remote-tracking branch 'upstream/main' into nogc-profile
marsninja Sep 6, 2026
58fb2e5
Bootstrap region cleanup without re-entering the compiler
marsninja Sep 6, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
5 changes: 4 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -495,6 +495,9 @@ jobs:
paths: jaclang/compiler/tests
sealed: ""
iface_verify: "1"
# Source compiler workers peak above 4 GB; four can exhaust this
# 16 GB runner before the pool's per-file recycling can intervene.
jobs: "2"
steps:
- uses: actions/checkout@v5
- uses: ./.github/actions/jac-kit
Expand All @@ -510,7 +513,7 @@ jobs:
run: |
set -uxo pipefail
WORK="$(mktemp -d)"
HOME="$WORK" JAC_TEST_RSS_LOG=1 JAC_TEST_JOBS=auto JAC_TEST_STRICT=1 jac test ${{ matrix.paths }}
HOME="$WORK" JAC_TEST_RSS_LOG=1 JAC_TEST_JOBS=${{ matrix.jobs || 'auto' }} JAC_TEST_STRICT=1 jac test ${{ matrix.paths }}

# Everything except the compiler tests.
test-runtime:
Expand Down
2 changes: 1 addition & 1 deletion jac.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ jaclang_source = "jac" # dir CONTAINING jaclang/, relative to this file
# `jac test` worker count. The generic default is sized from MemAvailable
# assuming ~2 GB per worker, which suits an ordinary project. This repo's
# compiler suite is far heavier: workers running the native/LLVM tests were
# measured at ~4.9 GB PSS average and 7.1 GB peak (they fork `nacompile`
# measured at ~4.9 GB PSS average and 7.1 GB peak (they fork `jac build --native`
# subprocesses), so the generic default over-subscribes here. Pin it.
# JAC_TEST_JOBS overrides this; "0" or "1" runs everything in one process.
test_jobs = "8"
Expand Down
4 changes: 2 additions & 2 deletions jac/_jac_finder.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ def _inherited_dev_source() -> str | None:
"""The dev source a parent jac process exported, if it still holds a tree.

``apply_dev_source_override`` exports ``JAC_DEV_SOURCE`` whenever the loop
engages, so a child jac spawned from any cwd (a ``nacompile`` into a temp
engages, so a child jac spawned from any cwd (a native build into a temp
dir, a desktop build compiling its host) inherits the same compiler instead
of silently falling back to the bundled copy.
"""
Expand Down Expand Up @@ -145,7 +145,7 @@ def apply_dev_source_override() -> None:
stanza.
2. Otherwise, an inherited ``JAC_DEV_SOURCE`` -- exported by a jac process
whose loop engaged, so the children it spawns (``jac test`` running a
``nacompile`` into a temp dir, a desktop build compiling its host) stay
a native build into a temp dir, a desktop build compiling its host) stay
on the same compiler whatever their cwd. Without this a child outside the
repo would silently fall back to the bundled copy.
3. Otherwise, a ``jac_linked_source`` marker baked into a linked dev binary
Expand Down
12 changes: 6 additions & 6 deletions jac/build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ pub fn build(b: *std.Build) void {

// Standalone: harvest a static-musl runtime (libc.a + libzigc.a + compiler-rt
// + crt) from the bundled Zig toolchain into .pbs-build/<osarch>/musl/lib, so
// `jac nacompile` can fully static-link Linux executables against musl with
// `jac build --native` can fully static-link Linux executables against musl with
// NO external toolchain at compile time. Idempotent; Linux only.
if (std.mem.startsWith(u8, host_osarch, "linux-")) {
const vendor_musl = tool.run("payload", &.{ "build-musl", host_osarch, b.pathFromRoot(b.fmt(".pbs-build/{s}/musl/lib", .{host_osarch})), b.graph.zig_exe });
Expand All @@ -229,7 +229,7 @@ pub fn build(b: *std.Build) void {
}

// Arch-parameterized variants: `zig cc -target <arch>-linux-musl` cross-
// compiles musl from any host, so a cross `jac nacompile` and the aarch64 CI
// compiles musl from any host, so a cross `jac build --native` and the aarch64 CI
// lane can static-link without target hardware (#7626 C1).
inline for ([_][]const u8{ "linux-x86_64", "linux-aarch64" }) |cross_osarch| {
const vendor_musl_cross = tool.run("payload", &.{ "build-musl", cross_osarch, b.pathFromRoot(b.fmt(".pbs-build/{s}/musl/lib", .{cross_osarch})), b.graph.zig_exe });
Expand Down Expand Up @@ -272,12 +272,12 @@ pub fn build(b: *std.Build) void {
};

// --- launcher stub: the in-checkout compiler compiles launcher/ natively --
// `--strict` makes any native-seam demotion in the stub's closure a hard
// error: a function demoted to Python-only cannot run before CPython
// A native build treats any native-seam demotion in the stub's closure as
// a hard error: a function demoted to Python-only cannot run before CPython
// exists. (The whole-program type-check gate is not used here: it cannot
// see the bundled per-OS native floors the launcher imports.) Needs the
// LLVMPY_* shim placed in-tree and the target's C floor archives.
const build_stub = tool.run("jac", &.{ "nacompile", "--strict" });
const build_stub = tool.run("jac", &.{ "build", "--native" });
build_stub.addFileArg(b.path("launcher/launcher.jac"));
build_stub.addArg("-o");
const stub = build_stub.addOutputFileArg("jac-stub");
Expand Down Expand Up @@ -382,7 +382,7 @@ pub fn build(b: *std.Build) void {

// Linux: harvest a static-musl runtime for the target and bundle it so
// the shipped binary can fully static-link Linux executables against
// musl at nacompile time -- no glibc/loader dep.
// musl at native build time -- no glibc/loader dep.
if (link_dir == null and std.mem.startsWith(u8, osarch, "linux-")) {
const musl_lib = b.pathFromRoot(b.fmt(".pbs-build/{s}/musl/lib", .{osarch}));
const vendor_musl = tool.run("payload", &.{ "build-musl", osarch, musl_lib, b.graph.zig_exe });
Expand Down
4 changes: 2 additions & 2 deletions jac/examples/chess/demo.sh
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,9 @@ sleep 1
echo
echo "=============================================="
echo "4) Native binary (AOT compile, then run)"
echo "Running: jac nacompile chess.jac then time ./chess -b 20"
echo "Running: jac build --native chess.jac then time ./chess -b 20"
echo "=============================================="
jac nacompile chess.jac
jac build --native chess.jac
_s=$(date +%s.%N); time ./chess -b 20; _e=$(date +%s.%N)
t_native=$(awk "BEGIN{printf \"%.3f\", $_e-$_s}")
echo "interesting..."
Expand Down
4 changes: 2 additions & 2 deletions jac/examples/jaclang_org/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ Its memory story is the point: `[gc] default = "none"` builds it headerless --
no reference counting, no collector, static drops only -- and the build audits
the emitted IR for `__rc_*` machinery, so a wasm that re-entered the RC world
fails to build rather than shipping. The ownership checker's source-level
zero-RC contract (`[gc.enforce]`, E140x hard errors) ships disarmed until a
zero-RC contract (`[memory]`, E140x hard errors) ships disarmed until a
release carries jaseci-labs/jac#7732 -- the 0.34.x checker misfires E1401 on
arena's raylib extern decls; jac.toml says exactly when and how to re-arm
it. Entity pools are index arenas (parallel
Expand All @@ -278,5 +278,5 @@ as an opaque handle; every update pass borrows it `&mut` down the call tree.
The same source also builds headlessly:

```bash
jac nacompile core/site/game/arena.jac --target wasm32 --enforce-nogc --gc none --assert-no-rc
jac build --native core/site/game/arena.jac --target-triple wasm32 --memory nogc
```
46 changes: 46 additions & 0 deletions jac/examples/jaclang_org/core/site/game/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Rocket Arena

WASD moves, mouse/arrows aim, **Space jumps**, and **left click shoots**.
Click the canvas to capture the pointer; Tab/Esc releases it. Key presses are
queued until the next simulation tick, and holding Space does not repeat a jump.

`sim.jac` owns the simulation. Scalar `Enemy`, `Projectile`, and `Spark` records
replace parallel field arrays. Projectile and spark pools are bounded and remove
expired entries by moving the last record into the vacant slot. Enemy slots stay
stable; kill events carry generation numbers so duplicate or stale hits cannot
score twice. The fixed timestep, seeded random stream, and previous positions for
interpolation are independent of rendering.

`Game` owns its state, pools, two event buffers, random generator, and frame/input
state. `Player.tick` and entity methods infer mutating receivers. Event processing
swaps the pending and processing buffers, preserving the explosion/kill/damage
ordering within a tick. `RenderView` borrows only the state rendering needs and
cannot outlive the game.

`arena.jac` adapts input and rendering through `platform_rl.jac`. Its `init` returns
an owned game; `shutdown` consumes it and closes the window. Frame rendering uses
`finally` to balance frame completion. The browser host keeps the Wasm handle at
one explicit boundary; stopping takes that handle before calling shutdown,
cancels animation, removes listeners, and deletes GL resources. Session numbers
prevent stale asynchronous starts, frame callbacks, or stop callbacks from
changing a replacement game. HUD consumers receive scalar values, not Wasm
exports or pointers. Dynamic types are confined to the WebGL/Wasm interfaces.

Run simulation regression tests from the repository root:

```sh
jac test jac/tests/compiler/backends/native/test_arena_simulation.jac
jac test jac/tests/compiler/backends/es/test_arena_host.jac
```

The tests compile the same game source under managed, RC, and nogc memory profiles
and execute it through `jac run --backend python`. They cover jumping and landing,
death reset, pool limits and removal, duplicate/stale events, and a seeded replay
captured from the original simulation. The site's memory profile remains managed;
headerless suitability is validated independently rather than changing memory
policy for the rest of the website.

The host test compiles the actual browser adapter and exercises it with a
controlled Wasm boundary and browser API doubles. It checks scalar HUD values,
keyboard repeat, mouse buttons, pending initialization, stale stop callbacks,
and balanced resource cleanup. It uses the existing bundled JavaScript runtime.
43 changes: 29 additions & 14 deletions jac/examples/jaclang_org/core/site/game/arena.jac
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import from platform_rl {
open_window,
close_window,
should_close,
frame_dt,
key_held,
Expand Down Expand Up @@ -35,6 +36,12 @@ import from platform_rl {
}
import from sim {
Game,
Cmd,
Player,
Stats,
EnemyPool,
ProjectilePool,
SparkPool,
world_new,
sim_tick,
TICK_DT,
Expand All @@ -47,32 +54,40 @@ import from sim {
}
import from gmath { jsin, lerp, clampf }

glob acc: float = 0.0,
prev_mx: float = 0.0,
prev_my: float = 0.0,
mouse_warmup: int = 12,
mouse_sens: float = 0.12,
mouse_captured: bool = False;
obj RenderView {
has cmd: &Cmd,
player: &Player,
stats: &Stats,
enemies: &EnemyPool,
rockets: &ProjectilePool,
shots: &ProjectilePool,
sparks: &SparkPool,
time: float;
}

def sample_input(w: &mut Game, dtf: float);

def draw_enemy_model(ex: float, ey: float, ez: float, k: float);

def draw_enemies(w: &Game, alpha: float);
def draw_enemies(w: &RenderView, alpha: float);

def draw_rockets(w: &RenderView, alpha: float);

def draw_rockets(w: &Game, alpha: float);
def draw_shots(w: &RenderView, alpha: float, rt: float);

def draw_shots(w: &Game, alpha: float, rt: float);
def draw_sparks(w: &RenderView, alpha: float);

def draw_sparks(w: &Game, alpha: float);
def draw_weapon(w: &RenderView, cx: float, cy: float, cz: float, rt: float);

def draw_weapon(w: &Game, cx: float, cy: float, cz: float, rt: float);
def draw_hud(w: &RenderView, rt: float);

def draw_hud(w: &Game, rt: float);
def render(w: &RenderView, alpha: float);

def render(w: &Game, alpha: float);
def init -> own Game;

def init -> Game;
def shutdown(w: own Game) {
close_window();
}

def frame(w: &mut Game) -> bool;

Expand Down
Loading
Loading