jz 0.4.0 → 0.5.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.
package/src/ctx.js CHANGED
@@ -7,6 +7,8 @@
7
7
  * Refactored into focused sub-contexts for better maintainability.
8
8
  */
9
9
 
10
+ import { DEFAULTS as ABI_DEFAULTS } from './abi/index.js'
11
+
10
12
  // === Carrier layout ===
11
13
  // i64 carrier holds either:
12
14
  // - raw f64 number bits (any non-NaN-shape pattern), discriminated by
@@ -26,6 +28,9 @@ export const LAYOUT = {
26
28
  NAN_PREFIX: 0x7FF8, // top 13 bits of any NaN-shape pointer
27
29
  NAN_PREFIX_BITS: 0x7FF8000000000000n, // pre-shifted for i64 OR
28
30
  SSO_BIT: 0x4000, // STRING aux bit 14: 1=inline (≤4 ASCII chars in offset), 0=heap
31
+ SLICE_BIT: 0x2000, // STRING aux bit 13: 1=view (no length header — len in aux[12:0],
32
+ // offset points into a parent buffer), 0=own heap string.
33
+ SLICE_LEN_MASK: 0x1FFF, // aux[12:0] — view length (≤8191; larger slices fall back to copy)
29
34
  }
30
35
 
31
36
  // === Tagged-pointer type codes ===
@@ -84,6 +89,10 @@ export const ctx = {
84
89
  memory: {}, // module memory config (pages, shared)
85
90
  error: {}, // source location carried through emit for err() messages
86
91
  transform: {}, // compile-time options (jzify, etc.)
92
+ abi: {}, // per-type rep lookup (see abi/index.js). { number: rep, string: rep, ... }
93
+ // Set by reset() to the default carrier bundle. Read by codegen sites
94
+ // that delegate rep-specific behavior — today just the optimizer's
95
+ // peephole hook; expanding as per-site narrowing tags individual sites.
87
96
  }
88
97
 
89
98
  /** Create a child scope via shallow flat copy (metacircular-safe: no prototype chain).
@@ -93,17 +102,38 @@ export const derive = (parent) => ({ ...parent })
93
102
  /** Include stdlib names for emission. */
94
103
  export const inc = (...names) => names.forEach(n => ctx.core.includes.add(n))
95
104
 
105
+ /** Wrap an emit handler with a declarative stdlib-dependency list. The deps
106
+ * become data — exposed as `.deps` (tabulatable, analyzable) — and are `inc`'d
107
+ * on every call, while the body `fn` stays a pure `args → IR` builder (also
108
+ * reachable as `.pure`). Emitters with no stdlib needs skip the wrapper and
109
+ * register as plain functions; behaviour is identical either way. */
110
+ export const emitter = (deps, fn) => {
111
+ const run = (...args) => (inc(...deps), fn(...args))
112
+ run.deps = deps
113
+ run.pure = fn
114
+ // Preserve the body's arity: `typeof Math.x` folding keys off emitter `.length`
115
+ // to tell callable builtins (sin) from constant ones (PI). The rest-param
116
+ // wrapper would otherwise report 0 for everything.
117
+ Object.defineProperty(run, 'length', { value: fn.length, configurable: true })
118
+ return run
119
+ }
120
+
96
121
  /** Expand ctx.core.includes transitively via ctx.core.stdlibDeps. Call before WASM assembly.
97
122
  * Each module co-locates its own deps with its stdlib registrations at init time. */
98
123
  export function resolveIncludes() {
99
124
  const graph = ctx.core.stdlibDeps
100
- const queue = [...ctx.core.includes]
101
- while (queue.length) {
102
- const name = queue.pop()
103
- const entry = graph[name]
104
- const deps = typeof entry === 'function' ? entry() : entry
105
- if (deps) for (const dep of deps) {
106
- if (!ctx.core.includes.has(dep)) { ctx.core.includes.add(dep); queue.push(dep) }
125
+ let changed = true
126
+ while (changed) {
127
+ changed = false
128
+ for (const name of [...ctx.core.includes]) {
129
+ const entry = graph[name]
130
+ const deps = typeof entry === 'function' ? entry() : entry
131
+ if (deps) for (const dep of deps) {
132
+ if (!ctx.core.includes.has(dep)) {
133
+ ctx.core.includes.add(dep)
134
+ changed = true
135
+ }
136
+ }
107
137
  }
108
138
  }
109
139
  }
@@ -118,6 +148,10 @@ export function reset(proto, globals) {
118
148
  extImports: new Set(), // __ext_* helpers actually emitted as env imports —
119
149
  // pullStdlib() removes them from `includes` after wiring,
120
150
  // so post-compile auditors (host: 'wasi') read this instead.
151
+ jsstring: new Set(), // `wasm:js-string` builtin names referenced by emitted code.
152
+ // Drained at module-assembly time into `(import "wasm:js-string" "name" …)`
153
+ // nodes; host wires JS-side polyfills via interop's
154
+ // env builder for engines without builtin support.
121
155
  }
122
156
 
123
157
 
@@ -141,7 +175,7 @@ export function reset(proto, globals) {
141
175
  globalTypes: new Map(),
142
176
  globalValTypes: null,
143
177
  globalTypedElem: null,
144
- repByGlobal: null, // Map<name, ValueRep> — module-level pointer reps (TYPED const globals stored as raw i32 offset, etc.)
178
+ globalReps: null, // Map<name, ValueRep> — module-level pointer reps (TYPED const globals stored as raw i32 offset, etc.)
145
179
  consts: null,
146
180
  }
147
181
 
@@ -149,16 +183,24 @@ export function reset(proto, globals) {
149
183
  list: [],
150
184
  names: new Set(), // Set<string> — known func names (list + imported funcs); populated at compile() start
151
185
  map: new Map(), // Map<string, func> — name → func entry; populated at compile() start
186
+ multiProp: new Set(), // Set<"obj.prop"> — function-properties assigned >1× (wrapper composition); suppresses the static fn.prop() direct call
152
187
  exports: {},
153
188
  current: null,
154
189
  locals: new Map(),
155
- repByLocal: null,
156
- refinements: new Map(), // flow-sensitive: name → VAL.* inside a type-guarded branch
190
+ localReps: null,
191
+ refinements: new Map(), // flow-sensitive: name → {val?: VAL.*, notString?: true} inside a type-guarded branch
157
192
  boxed: new Map(),
158
193
  stack: [],
159
194
  uniq: 0,
160
195
  inTry: false,
161
196
  localProps: null,
197
+ // Pass-scoped overlays installed by analyzeBody/observeSlots. While set,
198
+ // `lookupValType`/`typedElemCtor` consult the in-progress fact maps before
199
+ // falling back to global state — lets shorthand `{x}` / typed-array writes
200
+ // observe locals that haven't been promoted to ctx.types yet. Saved/restored
201
+ // by the pass owners so re-entrant analyzeBody calls don't clobber each other.
202
+ localValTypesOverlay: null,
203
+ localTypedElemsOverlay: null,
162
204
  }
163
205
 
164
206
  ctx.types = {
@@ -181,6 +223,21 @@ export function reset(proto, globals) {
181
223
  // returns the slot's kind for `.prop` AST nodes, letting
182
224
  // `+`/`===`/method dispatch elide `__is_str_key` checks
183
225
  // on numeric properties of known shapes.
226
+ slotIntCertain: new Map(), // schemaId → Array<boolean | undefined>
227
+ // undefined: no write observed, true: all observed
228
+ // writes are integer-shaped, false: poisoned by at
229
+ // least one non-int write. Populated by
230
+ // `analyzeSchemaSlotIntCertain` (whole-program
231
+ // walk over `{}` literals + `obj.prop = expr`
232
+ // writes). Read by `ctx.schema.slotIntCertainAt`
233
+ // so Math.floor/toNumF64/intIndexIR consumers fire
234
+ // on `.prop` reads of provably-integer slots.
235
+ inlineArray: new Set(), // schemaId set — schemas whose `Array<S>` instances
236
+ // use the `structInline` SRoA carrier (K f64
237
+ // fields inlined per element, no per-row object).
238
+ // Populated whole-program by `analyzeStructInline`
239
+ // (default-disqualify); read by the array
240
+ // push/index/length codegen.
184
241
  }
185
242
 
186
243
  ctx.closure = {
@@ -199,6 +256,8 @@ export function reset(proto, globals) {
199
256
  strPool: null, // shared-memory: accumulated raw bytes of string literals (no length prefix)
200
257
  strPoolDedup: new Map(), // str → offset in strPool
201
258
  throws: false,
259
+ userThrows: false, // user wrote `throw`/`try`/`catch`/`finally` — keep runtime declared
260
+ // even when all throws are dead-code-eliminated (JS-side ABI contract).
202
261
  }
203
262
 
204
263
  ctx.memory = {
@@ -226,8 +285,15 @@ export function reset(proto, globals) {
226
285
  // instantiation time. 'wasi': error at compile time if any `__ext_*` import
227
286
  // would be emitted, since wasmtime/wasmer hosts have no JS runtime to satisfy
228
287
  // them and silent fallback would corrupt output.
288
+ inspect: false, // when true, compile() additionally populates ctx.inspect with the inferred
289
+ // per-function signatures, locals, and JSON shapes — readable by editor
290
+ // hosts for inlay hints / hover types without re-running the analyzer.
229
291
  }
230
292
 
293
+ // Inspection sink. Populated by compile() only when transform.inspect is true.
294
+ // Shape: { abi, functions: { [name]: { exported, params, results, ptrKind?, locals, callerReps } }, schemas }.
295
+ ctx.inspect = null
296
+
231
297
  // Feature flags: capabilities the compiled module may exercise at runtime.
232
298
  // Set true by producer sites (import points, auto-imports, dynamic call sites).
233
299
  // Read by stdlib template factories and deps graph at resolveIncludes() time to
@@ -243,16 +309,17 @@ export function reset(proto, globals) {
243
309
  // (b) a capability needs an opt-in A/B switch against the default path
244
310
  // (SSO is the planned first user — default string-literal emission
245
311
  // currently forces SSO for ≤4 ASCII chars at string.js:49)
312
+ ctx.abi = ABI_DEFAULTS
313
+
314
+ // Only flags actually read by codegen live here. Hash/regex/json substrates
315
+ // are pulled organically by inc(__*) — no flag mediates them, so no flag exists.
246
316
  ctx.features = {
247
- external: false, // PTR.EXTERNAL possible — opts.imports, HOST_GLOBALS, or __ext_call site. WIRED.
248
- hash: false, // PTR.HASH + __dyn_* substrate. Organic: any inc(__hash_*/__dyn_*) implies on.
317
+ external: false, // PTR.EXTERNAL possible — opts.imports, HOST_GLOBALS, or __ext_call site.
249
318
  sso: true, // ≤4-ASCII string packing. Default on; flip off to A/B the heap-only path.
250
- regex: false, // RegExp literals + methods. Organic via inc(__regex_*).
251
- json: false, // JSON.parse/stringify. Organic via inc(__jp_*/__json_*).
252
- typedarray: false,// Float64Array/Int32Array/etc. Organic via inc(__typed_*) + ctx.closure.floor.
253
- set: false, // Set. Organic via inc(__set_*).
254
- map: false, // Map. Organic via inc(__map_*).
255
- closure: false, // First-class functions. Organic via ctx.closure.table population.
319
+ typedarray: false,// Float64Array/Int32Array/etc. Set on typed-array construction; gates PTR.TYPED dispatch.
320
+ set: false, // Set. Set on Set construction; gates PTR.SET dispatch.
321
+ map: false, // Map. Set on Map construction; gates PTR.MAP dispatch.
322
+ closure: false, // First-class functions. Set when ctx.closure.table is populated.
256
323
  timers: false, // Set by prepare.js when timer module is included
257
324
  blockingTimers: false, // wasmtime CLI: include __timer_loop in _start
258
325
  }