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.
- package/README.md +288 -314
- package/bench/README.md +319 -0
- package/bench/bench.svg +112 -0
- package/cli.js +32 -24
- package/index.js +177 -55
- package/interop.js +88 -159
- package/jz.svg +5 -0
- package/jzify/arguments.js +97 -0
- package/jzify/bundler.js +382 -0
- package/jzify/classes.js +328 -0
- package/jzify/hoist-vars.js +177 -0
- package/jzify/index.js +51 -0
- package/jzify/names.js +37 -0
- package/jzify/switch.js +106 -0
- package/jzify/transform.js +349 -0
- package/layout.js +179 -0
- package/module/array.js +322 -153
- package/module/collection.js +603 -145
- package/module/console.js +55 -43
- package/module/core.js +281 -142
- package/module/date.js +15 -3
- package/module/function.js +73 -6
- package/module/index.js +2 -1
- package/module/json.js +226 -61
- package/module/math.js +461 -185
- package/module/number.js +306 -60
- package/module/object.js +448 -184
- package/module/regex.js +255 -25
- package/module/schema.js +24 -6
- package/module/simd.js +85 -0
- package/module/string.js +591 -220
- package/module/symbol.js +1 -1
- package/module/timer.js +9 -14
- package/module/typedarray.js +45 -48
- package/package.json +41 -12
- package/src/abi/index.js +39 -23
- package/src/abi/string.js +38 -41
- package/src/ast.js +460 -0
- package/src/autoload.js +26 -24
- package/src/bridge.js +111 -0
- package/src/compile/analyze-scans.js +661 -0
- package/src/compile/analyze.js +1565 -0
- package/src/compile/emit-assign.js +408 -0
- package/src/compile/emit.js +3201 -0
- package/src/compile/flow-types.js +103 -0
- package/src/{compile.js → compile/index.js} +497 -125
- package/src/{infer.js → compile/infer.js} +27 -98
- package/src/{narrow.js → compile/narrow.js} +302 -96
- package/src/compile/plan/advise.js +316 -0
- package/src/compile/plan/common.js +150 -0
- package/src/compile/plan/index.js +118 -0
- package/src/compile/plan/inline.js +679 -0
- package/src/compile/plan/literals.js +984 -0
- package/src/compile/plan/loops.js +472 -0
- package/src/compile/plan/scope.js +573 -0
- package/src/compile/program-facts.js +404 -0
- package/src/ctx.js +176 -58
- package/src/ir.js +540 -171
- package/src/kind-traits.js +105 -0
- package/src/kind.js +462 -0
- package/src/op-policy.js +57 -0
- package/src/{optimize.js → optimize/index.js} +1106 -446
- package/src/optimize/vectorize.js +1874 -0
- package/src/param-reps.js +65 -0
- package/src/parse.js +44 -0
- package/src/{prepare.js → prepare/index.js} +600 -205
- package/src/reps.js +115 -0
- package/src/resolve.js +12 -3
- package/src/static.js +199 -0
- package/src/type.js +647 -0
- package/src/{assemble.js → wat/assemble.js} +86 -48
- package/src/wat/optimize.js +3760 -0
- package/transform.js +21 -0
- package/wasi.js +47 -5
- package/src/analyze.js +0 -3818
- package/src/emit.js +0 -2997
- package/src/jzify.js +0 -1553
- package/src/plan.js +0 -2132
- package/src/vectorize.js +0 -1088
- /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 '
|
|
47
|
-
import {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
} from '
|
|
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 (
|
|
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
|
|
86
|
+
// === paramReps lattice =====================================================
|
|
84
87
|
//
|
|
85
|
-
//
|
|
86
|
-
//
|
|
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 (
|
|
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 (
|
|
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)
|
|
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 =========================================
|