jz 0.5.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.
Files changed (80) hide show
  1. package/README.md +288 -314
  2. package/bench/README.md +319 -0
  3. package/bench/bench.svg +112 -0
  4. package/cli.js +32 -24
  5. package/index.js +177 -55
  6. package/interop.js +88 -159
  7. package/jz.svg +5 -0
  8. package/jzify/arguments.js +97 -0
  9. package/jzify/bundler.js +382 -0
  10. package/jzify/classes.js +328 -0
  11. package/jzify/hoist-vars.js +177 -0
  12. package/jzify/index.js +51 -0
  13. package/jzify/names.js +37 -0
  14. package/jzify/switch.js +106 -0
  15. package/jzify/transform.js +349 -0
  16. package/layout.js +179 -0
  17. package/module/array.js +322 -153
  18. package/module/collection.js +603 -145
  19. package/module/console.js +55 -43
  20. package/module/core.js +281 -142
  21. package/module/date.js +15 -3
  22. package/module/function.js +73 -6
  23. package/module/index.js +2 -1
  24. package/module/json.js +226 -61
  25. package/module/math.js +461 -185
  26. package/module/number.js +306 -60
  27. package/module/object.js +448 -184
  28. package/module/regex.js +255 -25
  29. package/module/schema.js +24 -6
  30. package/module/simd.js +85 -0
  31. package/module/string.js +591 -220
  32. package/module/symbol.js +1 -1
  33. package/module/timer.js +9 -14
  34. package/module/typedarray.js +45 -48
  35. package/package.json +41 -12
  36. package/src/abi/index.js +39 -23
  37. package/src/abi/string.js +38 -41
  38. package/src/ast.js +460 -0
  39. package/src/autoload.js +26 -24
  40. package/src/bridge.js +111 -0
  41. package/src/compile/analyze-scans.js +661 -0
  42. package/src/compile/analyze.js +1565 -0
  43. package/src/compile/emit-assign.js +408 -0
  44. package/src/compile/emit.js +3201 -0
  45. package/src/compile/flow-types.js +103 -0
  46. package/src/{compile.js → compile/index.js} +497 -125
  47. package/src/{infer.js → compile/infer.js} +27 -98
  48. package/src/{narrow.js → compile/narrow.js} +302 -96
  49. package/src/compile/plan/advise.js +316 -0
  50. package/src/compile/plan/common.js +150 -0
  51. package/src/compile/plan/index.js +118 -0
  52. package/src/compile/plan/inline.js +679 -0
  53. package/src/compile/plan/literals.js +984 -0
  54. package/src/compile/plan/loops.js +472 -0
  55. package/src/compile/plan/scope.js +573 -0
  56. package/src/compile/program-facts.js +404 -0
  57. package/src/ctx.js +176 -58
  58. package/src/ir.js +540 -171
  59. package/src/kind-traits.js +105 -0
  60. package/src/kind.js +462 -0
  61. package/src/op-policy.js +57 -0
  62. package/src/{optimize.js → optimize/index.js} +1106 -446
  63. package/src/optimize/vectorize.js +1874 -0
  64. package/src/param-reps.js +65 -0
  65. package/src/parse.js +44 -0
  66. package/src/{prepare.js → prepare/index.js} +600 -205
  67. package/src/reps.js +115 -0
  68. package/src/resolve.js +12 -3
  69. package/src/static.js +199 -0
  70. package/src/type.js +647 -0
  71. package/src/{assemble.js → wat/assemble.js} +86 -48
  72. package/src/wat/optimize.js +3760 -0
  73. package/transform.js +21 -0
  74. package/wasi.js +47 -5
  75. package/src/analyze.js +0 -3818
  76. package/src/emit.js +0 -2997
  77. package/src/jzify.js +0 -1553
  78. package/src/plan.js +0 -2132
  79. package/src/vectorize.js +0 -1088
  80. /package/src/{codegen.js → wat/codegen.js} +0 -0
@@ -43,12 +43,15 @@
43
43
  * @module src/infer
44
44
  */
45
45
 
46
- import { ctx } from './ctx.js'
47
- import {
48
- VAL, collectParamNames, valTypeOf,
49
- updateRep, updateGlobalRep, analyzeValTypes, analyzeIntCertain,
50
- staticObjectProps, typedElemCtor, ctorFromElemAux, shapeOfObjectLiteralAst,
51
- } from './analyze.js'
46
+ import { ctx } from '../ctx.js'
47
+ import { collectParamNames, ASSIGN_OPS } from '../ast.js'
48
+ import { analyzeValTypes, analyzeIntCertain } from './analyze.js'
49
+ import { staticObjectProps } from '../static.js'
50
+ import { typedElemCtor } from '../type.js'
51
+ import { ctorFromElemAux } from '../../layout.js'
52
+ import { shapeOfObjectLiteralAst, valTypeOf } from '../kind.js'
53
+ import { includeForStringValue } from '../autoload.js'
54
+ import { VAL, updateRep, updateGlobalRep } from '../reps.js'
52
55
 
53
56
  // === typeof predicate helper ==============================================
54
57
  //
@@ -63,7 +66,7 @@ import {
63
66
  /** Match a `typeof name <op> lit` predicate. Returns `{ name, code, eq }` —
64
67
  * `name` is the typeof's operand binding, `code` is either the raw type
65
68
  * string ('string'|'number'|'function'|…) or the prepare-normalized typeof
66
- * code (-1|-2|-3|-4|-5|-6, see TYPEOF_MAP in prepare.js), and `eq` is true
69
+ * code (TYPEOF in ast.js), and `eq` is true
67
70
  * for `==`/`===` (false for `!=`/`!==`). Returns null when the node isn't a
68
71
  * typeof predicate. */
69
72
  export function typeofPredicate(node) {
@@ -80,91 +83,10 @@ export function typeofPredicate(node) {
80
83
  return { name: typeofSide[1], code, eq: op === '==' || op === '===' }
81
84
  }
82
85
 
83
- // === paramReps lattice primitives ==========================================
86
+ // === paramReps lattice =====================================================
84
87
  //
85
- // `paramReps: Map<funcName, Map<paramIdx, ValueRep>>` is the cross-call fact
86
- // lattice. Evidence sources (body-walk and call-site `infer*`) produce
87
- // raw observations; these primitives apply them with sticky-null poison
88
- // semantics: undefined → observe (set); equal → stay; disagreement → null
89
- // (sticky). null is "no consensus" — readers treat it as missing.
90
- //
91
- // Lifecycle phases (chronological — readers should know which fields are
92
- // valid at which point):
93
- //
94
- // 1. prepare ─ no paramReps yet. AST walk collects callSites with raw
95
- // arg lists; programFacts.paramReps is allocated empty.
96
- //
97
- // 2. collectProgramFacts ─ unchanged paramReps; aggregates module-global
98
- // callSites, valueUsed, hasSchemaLiterals into
99
- // programFacts. paramReps still empty here.
100
- //
101
- // 3. narrowSignatures phase D (call-site lattice) ─
102
- // runCallsiteLattice merges raw call-site facts via
103
- // mergeParamFact for fields: val, schemaId, intConst,
104
- // arrayElemSchema, arrayElemValType, typedCtor, wasm.
105
- // After D, these may be undefined/null/value.
106
- // Sticky-null reachable on any field whose call sites
107
- // disagreed.
108
- //
109
- // 4. validateIntConstParams ─ clears intConst on any param whose body
110
- // contains a write to it (intConst's contract is "no
111
- // writes after the call").
112
- //
113
- // 5. phase E / E2 / E3 (param ABI narrowing) ─
114
- // applyI32ParamSpecialization sets sig.params[k].type
115
- // to 'i32' based on rep.wasm consensus. Then
116
- // applyPointerParamAbi sets rep.ptrKind on
117
- // consistently-OBJECT/ARRAY/etc params; this prepares
118
- // the i32-offset ABI for unboxed pointer params.
119
- //
120
- // 6. phase F (signature fixpoint) ─ clearStickyNull on val + schemaId,
121
- // then re-runs D until stable. New evidence from
122
- // newly-narrowed return types (valResult) can unstick.
123
- //
124
- // 7. phase G (narrowReturnArrayElems) ─ propagates Array<T> element
125
- // facts back through return paths into caller param
126
- // reps. After G, arrayElemSchema/arrayElemValType
127
- // reflect the transitive closure.
128
- //
129
- // 8. phase H (applyTypedPointerParamAbi) ─ sets ptrKind=TYPED + ptrAux
130
- // (elem code) for params whose val converged to TYPED.
131
- // Depends on F having seeded val first.
132
- //
133
- // 9. phase I (resetParamWasmFacts + final i32 spec) ─ last WASM-level
134
- // pass. After H/I, sig.params[k].type and rep.ptrKind
135
- // are frozen for emit.
136
- //
137
- // 10. per-function compile (emit start) ─ each func reads its
138
- // paramReps[name][k] and folds the consensus facts
139
- // into ctx.func.localReps via updateRep. Locals and
140
- // params then share one ValueRep store for the
141
- // remainder of emit.
142
-
143
- /** Per-call-site fact merge into a param's ValueRep field. */
144
- export const mergeParamFact = (rep, key, observed) => {
145
- if (rep[key] === null) return // sticky poison
146
- if (observed == null) { rep[key] = null; return } // unknown → poison
147
- if (rep[key] === undefined) rep[key] = observed
148
- else if (rep[key] !== observed) rep[key] = null
149
- }
150
-
151
- /** Get-or-create per-param rep at (funcName, paramIdx) on a paramReps map. */
152
- export const ensureParamRep = (paramReps, funcName, k) => {
153
- let m = paramReps.get(funcName)
154
- if (!m) { m = new Map(); paramReps.set(funcName, m) }
155
- let r = m.get(k)
156
- if (!r) { r = {}; m.set(k, r) }
157
- return r
158
- }
159
-
160
- /** Reset sticky-null on a single field across all params program-wide.
161
- * Used between fixpoint phases when newly-narrowed facts unblock previously-
162
- * poisoned observations (e.g. valResult set after first pass). */
163
- export const clearStickyNull = (paramReps, key) => {
164
- for (const m of paramReps.values()) for (const r of m.values()) {
165
- if (r[key] === null) r[key] = undefined
166
- }
167
- }
88
+ // Primitives live in src/param-reps.js (cycle-free leaf). Lifecycle phases
89
+ // below document when each field is valid during narrowSignatures.
168
90
 
169
91
  // === Source registry =======================================================
170
92
 
@@ -212,7 +134,7 @@ const STRING_ONLY_METHODS = new Set([
212
134
  'charCodeAt', 'charAt', 'codePointAt', 'startsWith', 'endsWith',
213
135
  'toUpperCase', 'toLowerCase', 'toLocaleLowerCase', 'normalize', 'localeCompare',
214
136
  'padStart', 'padEnd', 'repeat', 'trimStart', 'trimEnd', 'trim',
215
- 'matchAll', 'match', 'replace', 'replaceAll', 'split',
137
+ 'matchAll', 'match', 'replace', 'replaceAll', 'split', 'lastIndexOf',
216
138
  ])
217
139
  const ARRAY_ONLY_POISON = new Set([
218
140
  'push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'fill', 'reverse',
@@ -312,9 +234,6 @@ const isLengthAccess = (n) =>
312
234
  const isIndexAccess = (n) =>
313
235
  Array.isArray(n) && n[0] === '[]' && typeof n[1] === 'string'
314
236
 
315
- const isAssignOp = (op) =>
316
- typeof op === 'string' && (op === '=' || (op.length > 1 && op.endsWith('=') && op !== '==' && op !== '===' && op !== '!=' && op !== '!==' && op !== '<=' && op !== '>='))
317
-
318
237
  const isStringLiteralRhs = (rhs) =>
319
238
  Array.isArray(rhs) && (rhs[0] === 'str' || (rhs[0] == null && typeof rhs[1] === 'string'))
320
239
 
@@ -354,11 +273,11 @@ const notStringEvidence = (body, names) => {
354
273
  markStringy(node[1])
355
274
  }
356
275
  // Index write: `xs[i] = v` or compound `xs[i] op= v`.
357
- if (isAssignOp(op) && isIndexAccess(node[1]) && scope.has(node[1][1]) && !stringy.has(node[1][1])) {
276
+ if (ASSIGN_OPS.has(op) && isIndexAccess(node[1]) && scope.has(node[1][1]) && !stringy.has(node[1][1])) {
358
277
  writes.add(node[1][1])
359
278
  }
360
279
  // Length mutation: `xs.length = n`, `xs.length += k`, `xs.length++`.
361
- if (isAssignOp(op) && isLengthAccess(node[1]) && scope.has(node[1][1]) && !stringy.has(node[1][1])) {
280
+ if (ASSIGN_OPS.has(op) && isLengthAccess(node[1]) && scope.has(node[1][1]) && !stringy.has(node[1][1])) {
362
281
  writes.add(node[1][1])
363
282
  }
364
283
  if ((op === '++' || op === '--') && isLengthAccess(node[1]) && scope.has(node[1][1]) && !stringy.has(node[1][1])) {
@@ -426,7 +345,17 @@ export function recordGlobalRep(name, expr) {
426
345
  // resolve its source schema by walking the global rep's shape tree at the
427
346
  // spread site (see shape walk in analyze.js / resolveSchema in object.js).
428
347
  const sh = shapeOfObjectLiteralAst(expr)
429
- if (sh) updateGlobalRep(name, { jsonShape: sh })
348
+ if (sh) {
349
+ updateGlobalRep(name, { jsonShape: sh })
350
+ // A module-global object is read via __dyn_get (its props live behind a
351
+ // runtime key, not a function-local schema slot), which emits a `['str', key]`
352
+ // node at compile time. Ensure the string module's `str` emitter is bound now
353
+ // — a string-literal-free program (`let g = {l:{a:1}}; export let f = () => g.l`)
354
+ // would otherwise abort late with "Unknown op: str". Scoped to globals that
355
+ // actually capture an object shape, so string-free local-object programs keep
356
+ // their minimal bundle (and golden-size pins).
357
+ includeForStringValue()
358
+ }
430
359
  }
431
360
 
432
361
  // === Call-site argument inference =========================================