nomen-lang 0.4.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,199 @@
1
+ // Thread — a task running on the shared worker pool (CLOSURE.md
2
+ // Phase 3b). `Thread(fn(args))` constructs a Thread value: the arguments are
3
+ // evaluated eagerly and packed into a task closure (a heap closure
4
+ // descriptor over the pooled-args environment — the same ABI every lambda
5
+ // lowers to); `.start()` submits that closure to the worker pool and yields
6
+ // a `Task<T>` handle; `.detach()` runs it as an unjoinable daemon.
7
+ //
8
+ // Because the construction is a real value, it can be STORED and started
9
+ // later:
10
+ //
11
+ // var t = Thread(work(n))
12
+ // ...later...
13
+ // var Task<uint64> handle = t.start()
14
+ //
15
+ // The pool starts at a configurable size (default 4, via Task.set_pool_size
16
+ // before the first spawn) and grows on demand up to 64 workers when every
17
+ // worker is busy, preventing deadlocks from nested spawns. The pool drains
18
+ // and joins all workers at process exit; Task.shutdown_pool does this
19
+ // explicitly.
20
+ //
21
+ // The pool infrastructure (types, worker loop, submit, shutdown, cancel
22
+ // thread-local) lives in build_spawn_node and is emitted as file-scope C
23
+ // on the first spawn — not in Thread's own methods — so that Thread can be
24
+ // generic without duplicating the pool per instantiation. The construction
25
+ // (`Thread(fn(args))`, the deferred-call special form) is compiler-emitted;
26
+ // `.start()` / `.detach()` are regular methods over the runtime seam.
27
+ //
28
+ // MUST-START: a Thread value that is destroyed without ever being started
29
+ // is a programming error — #destroy reports it and aborts. start/detach
30
+ // (and nursery.start) transfer ownership of the packed task out of the
31
+ // value, so a started Thread destroys as a no-op.
32
+ //
33
+ // See ASYNC.md for the design.
34
+
35
+ // The launch surface's return type (ASYNC.md: the dependency is
36
+ // declared by the library file, not inferred from user-source tokens).
37
+ import Task
38
+
39
+ /**
40
+ * A deferred function call, startable on the shared worker pool
41
+ **/
42
+ pub class Thread<T> : Sendable, Spawnable<T> {
43
+ // The construction hook (ASYNC.md): declares this class's
44
+ // construction as the deferred-call special form — the single argument
45
+ // is a call (args packed eagerly, call deferred) or a zero-arg function
46
+ // value. The compiler matches this member, never the class name; the
47
+ // construction itself is compiler-generated (pack the args, allocate the
48
+ // future machinery, build the instance), so the body is a declaration.
49
+ #spawn = () {
50
+ }
51
+
52
+ // The packed task closure (a `struct nomen_closure *`); owned by this
53
+ // value until start/detach/nursery.start transfers it to the runtime.
54
+ pub var uint64 task = 0
55
+ // Result-slot / cancel-flag / future handles for the (single) launch.
56
+ pub var uint64 result_slot = 0
57
+ pub var uint64 cancel_flag = 0
58
+ pub var uint64 future = 0
59
+ // Must-start flag: set by .start() / .detach() / nursery.start.
60
+ pub var started = false
61
+ // LEXICAL NURSERY CAPTURE (ASYNC.md): the tracking slots of the
62
+ // `async` block that lexically encloses the CONSTRUCTION, or 0 when the
63
+ // construction is outside any block. `.start()` registers the future
64
+ // through these stored pointers, so registration follows the scope that
65
+ // created the deferred call — not the one that happens to start it — and
66
+ // works through an indirect receiver. The pointers address the block's
67
+ // own futures list slots (the block cannot exit until every registered
68
+ // task has finished, so a started-before-exit task never registers into
69
+ // dead storage).
70
+ pub var uint64 nursery_futures = 0
71
+ pub var uint64 nursery_count = 0
72
+ pub var uint64 nursery_cap = 0
73
+
74
+ // Start the deferred call on the shared worker pool and yield the
75
+ // Task<T> handle. Consumes the instance's launch machinery (submit, then
76
+ // register with the construction-time nursery, if any) and zeroes the
77
+ // fields, so #destroy becomes a no-op afterwards. The future's refs
78
+ // account for the trampoline, the returned handle, and the nursery (when
79
+ // captured).
80
+ pub func start = (ref self, move out Task<T>) {
81
+ ```
82
+ #arch: c
83
+ struct nomen_future *_f = (struct nomen_future *)self->future;
84
+ _f->refs = self->nursery_futures ? 3 : 2;
85
+ __nomen_pool_submit((struct nomen_closure *)self->task);
86
+ if (self->nursery_futures) {
87
+ __nomen_nursery_track((void **)self->nursery_futures, (int *)self->nursery_count, (int *)self->nursery_cap, _f);
88
+ }
89
+ ```
90
+ ```
91
+ #arch: aarch64
92
+ // x19 = self. f = self->future (#32); nursery_futures at #48.
93
+ ldr x0, [x19, #32]
94
+ ldr x1, [x19, #48]
95
+ mov w2, #2
96
+ cbz x1, .Lnomen_start_refs
97
+ mov w2, #3
98
+ .Lnomen_start_refs:
99
+ str w2, [x0, #116]
100
+ // __nomen_pool_submit(self->task)
101
+ ldr x0, [x19, #8]
102
+ bl ___nomen_pool_submit
103
+ // if (self->nursery_futures) __nomen_nursery_track(futures, count, cap, f)
104
+ ldr x0, [x19, #48]
105
+ cbz x0, .Lnomen_start_notrack
106
+ ldr x1, [x19, #56]
107
+ ldr x2, [x19, #64]
108
+ ldr x3, [x19, #32]
109
+ bl ___nomen_nursery_track
110
+ .Lnomen_start_notrack:
111
+ ```
112
+ // The handle is a fresh heap Task built through the internal #init;
113
+ // the caller owns it (a discarded statement form is reclaimed at
114
+ // scope exit, releasing its refs share).
115
+ var t = Task<T>()
116
+ t.result_slot = self.result_slot
117
+ t.cancel_flag = self.cancel_flag
118
+ t.future = self.future
119
+ // Transfer the handles out of the instance: the runtime owns
120
+ // everything now, and #destroy must not touch (or must-start-abort).
121
+ self.task = 0
122
+ self.future = 0
123
+ self.result_slot = 0
124
+ self.cancel_flag = 0
125
+ self.started = true
126
+ return t
127
+ }
128
+
129
+ // Run the deferred call on a dedicated detached pthread — the daemon
130
+ // form. Never a pool worker, never joined; process exit kills it
131
+ // mid-execution BY DESIGN. The unused future (a Thread always carries
132
+ // the full machinery) is released — first detaching the closure from it,
133
+ // so the daemon runner owns the closure now.
134
+ pub func detach = (ref self) {
135
+ ```
136
+ #arch: c
137
+ struct nomen_future *_uf = (struct nomen_future *)self->future;
138
+ if (_uf) {
139
+ _uf->owner_args = NULL;
140
+ __nomen_future_release(_uf);
141
+ }
142
+ __nomen_task_detach((struct nomen_closure *)self->task);
143
+ ```
144
+ ```
145
+ #arch: aarch64
146
+ // if (self->future) { owner_args = NULL; release it }
147
+ ldr x0, [x19, #32]
148
+ cbz x0, .Lnomen_detach_nofut
149
+ str xzr, [x0, #136]
150
+ bl ___nomen_future_release
151
+ .Lnomen_detach_nofut:
152
+ // __nomen_task_detach(self->task)
153
+ ldr x0, [x19, #8]
154
+ bl ___nomen_task_detach
155
+ ```
156
+ self.task = 0
157
+ self.future = 0
158
+ self.result_slot = 0
159
+ self.cancel_flag = 0
160
+ self.started = true
161
+ }
162
+
163
+ // Destroying an unstarted Thread is a programming error (the wrapped
164
+ // call would silently never run) — report it and abort. A started
165
+ // Thread owns nothing: the launch transferred the task closure, result
166
+ // slot, cancel flag, and future to the runtime, and cleared the fields.
167
+ pub func #destroy = () {
168
+ ```
169
+ #arch: c
170
+ if (!self->started) {
171
+ __nomen_spawn_must_start_abort();
172
+ }
173
+ if (self->future) {
174
+ __nomen_future_release((struct nomen_future *)self->future);
175
+ self->future = 0;
176
+ self->result_slot = 0;
177
+ self->cancel_flag = 0;
178
+ }
179
+ ```
180
+ ```
181
+ #arch: aarch64
182
+ // if (!self->started) __nomen_spawn_must_start_abort()
183
+ ldrb w0, [x19, #40]
184
+ cbnz w0, .Lthr_started
185
+ bl ___nomen_spawn_must_start_abort
186
+ .Lthr_started:
187
+ // if (self->future) { release it (an unstarted task's future is
188
+ // unshared — refs == 1 — so this tears down slot + flag + future);
189
+ // zero the fields }
190
+ ldr x0, [x19, #32]
191
+ cbz x0, .Lthr_done
192
+ bl ___nomen_future_release
193
+ str xzr, [x19, #32]
194
+ str xzr, [x19, #16]
195
+ str xzr, [x19, #24]
196
+ .Lthr_done:
197
+ ```
198
+ }
199
+ }
@@ -7,7 +7,7 @@
7
7
  * A tree of values connected by parent/child links
8
8
  **/
9
9
  pub struct Tree<T>: Enumerable {
10
- var Buffer<T> values = Buffer<T>()
10
+ var values = Buffer<T>()
11
11
  var lefts = Buffer<int>()
12
12
  var rights = Buffer<int>()
13
13
  var parents = Buffer<int>()