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/README.md +275 -255
- package/cli.js +8 -51
- package/index.js +166 -31
- package/{src/host.js → interop.js} +291 -88
- package/module/array.js +181 -71
- package/module/collection.js +222 -8
- package/module/console.js +1 -1
- package/module/core.js +251 -118
- package/module/date.js +9 -5
- package/module/function.js +11 -1
- package/module/json.js +361 -55
- package/module/math.js +551 -128
- package/module/number.js +390 -227
- package/module/object.js +252 -34
- package/module/regex.js +123 -16
- package/module/schema.js +15 -1
- package/module/string.js +540 -96
- package/module/timer.js +1 -1
- package/module/typedarray.js +674 -57
- package/package.json +10 -7
- package/src/abi/array.js +89 -0
- package/src/abi/index.js +35 -0
- package/src/abi/number.js +137 -0
- package/src/abi/object.js +57 -0
- package/src/abi/string.js +529 -0
- package/src/analyze.js +1870 -485
- package/src/assemble.js +27 -12
- package/src/autoload.js +13 -1
- package/src/compile.js +446 -179
- package/src/ctx.js +85 -18
- package/src/emit.js +662 -196
- package/src/infer.js +548 -0
- package/src/ir.js +291 -23
- package/src/jzify.js +786 -94
- package/src/narrow.js +433 -251
- package/src/optimize.js +126 -122
- package/src/plan.js +703 -34
- package/src/prepare.js +822 -150
- package/src/resolve.js +85 -0
- package/src/vectorize.js +99 -18
- package/src/ast.js +0 -160
- package/src/auto-config.js +0 -120
- package/src/fuse.js +0 -159
package/src/assemble.js
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
15
|
import { parse as parseWat } from 'watr'
|
|
16
|
-
import { ctx, inc, resolveIncludes, PTR, LAYOUT } from './ctx.js'
|
|
16
|
+
import { ctx, inc, resolveIncludes, err, PTR, LAYOUT } from './ctx.js'
|
|
17
17
|
|
|
18
18
|
// Stdlib WAT templates are fixed text (or feature-keyed text from a factory) —
|
|
19
19
|
// `parseWat` of the same string always yields the same tree. Parsing is the
|
|
@@ -34,7 +34,7 @@ const parseTemplate = (str) => {
|
|
|
34
34
|
return cloneTemplate(tmpl)
|
|
35
35
|
}
|
|
36
36
|
import { T, VAL, analyzeValTypes } from './analyze.js'
|
|
37
|
-
import { optimizeFunc, hoistConstantPool, specializeMkptr, specializePtrBase, sortStrPoolByFreq, arenaRewindModule } from './optimize.js'
|
|
37
|
+
import { optimizeFunc, collectVolatileGlobals, hoistConstantPool, specializeMkptr, specializePtrBase, sortStrPoolByFreq, arenaRewindModule } from './optimize.js'
|
|
38
38
|
import { emit } from './emit.js'
|
|
39
39
|
import { mkPtrIR, MAX_CLOSURE_ARITY, MEM_OPS, findBodyStart } from './ir.js'
|
|
40
40
|
|
|
@@ -46,11 +46,15 @@ const TAG_SHIFT_BIG = BigInt(LAYOUT.TAG_SHIFT)
|
|
|
46
46
|
const AUX_SHIFT_BIG = BigInt(LAYOUT.AUX_SHIFT)
|
|
47
47
|
const SSO_BIT_BIG = BigInt(LAYOUT.SSO_BIT)
|
|
48
48
|
|
|
49
|
-
|
|
49
|
+
// memory[1020] holds the heap pointer only for shared memory (wasm globals are
|
|
50
|
+
// per-instance — see module/core.js comment). Non-shared memory uses $__heap.
|
|
51
|
+
const heapUsesMem = () => ctx.memory.shared
|
|
52
|
+
|
|
53
|
+
const heapGetIR = () => heapUsesMem()
|
|
50
54
|
? ['i32.load', ['i32.const', 1020]]
|
|
51
55
|
: ['global.get', '$__heap']
|
|
52
56
|
|
|
53
|
-
const heapSetIR = value =>
|
|
57
|
+
const heapSetIR = value => heapUsesMem()
|
|
54
58
|
? ['i32.store', ['i32.const', 1020], value]
|
|
55
59
|
: ['global.set', '$__heap', value]
|
|
56
60
|
|
|
@@ -128,7 +132,7 @@ function applyArenaRewind(func, fn, safeCallees) {
|
|
|
128
132
|
|
|
129
133
|
export function buildStartFn(ast, sec, closureFuncs, compilePendingClosures) {
|
|
130
134
|
ctx.func.locals = new Map()
|
|
131
|
-
ctx.func.
|
|
135
|
+
ctx.func.localReps = null
|
|
132
136
|
ctx.func.boxed = new Map()
|
|
133
137
|
ctx.func.stack = []
|
|
134
138
|
ctx.func.current = { params: [], results: [] }
|
|
@@ -152,7 +156,7 @@ export function buildStartFn(ast, sec, closureFuncs, compilePendingClosures) {
|
|
|
152
156
|
const beforeLateClosures = closureFuncs.length
|
|
153
157
|
const startCtx = {
|
|
154
158
|
locals: ctx.func.locals,
|
|
155
|
-
|
|
159
|
+
localReps: ctx.func.localReps,
|
|
156
160
|
boxed: ctx.func.boxed,
|
|
157
161
|
stack: ctx.func.stack,
|
|
158
162
|
current: ctx.func.current,
|
|
@@ -184,17 +188,24 @@ export function buildStartFn(ast, sec, closureFuncs, compilePendingClosures) {
|
|
|
184
188
|
|
|
185
189
|
const schemaInit = []
|
|
186
190
|
const hasJpObj = ctx.core.includes.has('__jp_obj') || ctx.core.includes.has('__jp')
|
|
187
|
-
const
|
|
188
|
-
|
|
191
|
+
const hasStringify = ctx.core.includes.has('__stringify')
|
|
192
|
+
// Empty object literals register a `[]` schema so their schemaId indexes a
|
|
193
|
+
// valid list entry. But __dyn_get already guards `$__schema_tbl == 0`, so a
|
|
194
|
+
// table holding only empty schemas is pure dead weight there. __json_obj has
|
|
195
|
+
// no such guard — it must read the table whenever stringify is in play.
|
|
196
|
+
const tblConsumed = hasStringify ||
|
|
189
197
|
ctx.core.includes.has('__dyn_get') ||
|
|
190
198
|
ctx.core.includes.has('__dyn_get_t') ||
|
|
191
199
|
ctx.core.includes.has('__dyn_get_t_h') ||
|
|
192
200
|
ctx.core.includes.has('__dyn_get_expr_t_h') ||
|
|
193
201
|
ctx.core.includes.has('__dyn_get_any') ||
|
|
194
202
|
ctx.core.includes.has('__dyn_get_any_t') ||
|
|
203
|
+
ctx.core.includes.has('__dyn_get_any_t_h') ||
|
|
195
204
|
ctx.core.includes.has('__dyn_get_expr') ||
|
|
196
205
|
ctx.core.includes.has('__dyn_get_expr_t') ||
|
|
197
|
-
ctx.core.includes.has('__dyn_get_or')
|
|
206
|
+
ctx.core.includes.has('__dyn_get_or')
|
|
207
|
+
const needsSchemaTbl = (ctx.schema.list.length && tblConsumed &&
|
|
208
|
+
(hasStringify || ctx.schema.list.some(s => s.length > 0))) ||
|
|
198
209
|
hasJpObj
|
|
199
210
|
if (needsSchemaTbl) {
|
|
200
211
|
const nSchemas = ctx.schema.list.length
|
|
@@ -419,7 +430,7 @@ export function pullStdlib(sec) {
|
|
|
419
430
|
ctx.core.includes.delete(name)
|
|
420
431
|
}
|
|
421
432
|
}
|
|
422
|
-
for (const n of ctx.core.includes) if (!ctx.core.stdlib[n])
|
|
433
|
+
for (const n of ctx.core.includes) if (!ctx.core.stdlib[n]) err(`internal: stdlib '${n}' was requested but never registered (this is a jz bug — feature pulled in something it can't deliver)`)
|
|
423
434
|
sec.stdlib.push(...[...ctx.core.includes].map(n => parseTemplate(stdlibStr(n))))
|
|
424
435
|
}
|
|
425
436
|
|
|
@@ -454,7 +465,9 @@ export function optimizeModule(sec) {
|
|
|
454
465
|
}
|
|
455
466
|
// Build global name→type map from ctx.scope.globalTypes (keys without $) for promoteGlobals
|
|
456
467
|
const globalTypesMap = ctx.scope.globalTypes ? new Map([...ctx.scope.globalTypes].map(([k, v]) => [`$${k}`, v])) : null
|
|
457
|
-
|
|
468
|
+
const allFuncs = [...sec.funcs, ...sec.stdlib, ...sec.start]
|
|
469
|
+
const volatileGlobals = collectVolatileGlobals(allFuncs)
|
|
470
|
+
for (const s of allFuncs) optimizeFunc(s, cfg, globalTypesMap, volatileGlobals)
|
|
458
471
|
if (!cfg || cfg.arenaRewind !== false) {
|
|
459
472
|
const safeCallees = arenaRewindModule([...sec.funcs, ...sec.stdlib, ...sec.start])
|
|
460
473
|
const fnByName = new Map()
|
|
@@ -487,7 +500,9 @@ export function optimizeModule(sec) {
|
|
|
487
500
|
const dataLen = ctx.runtime.data?.length || 0
|
|
488
501
|
if (dataLen > 1024 && !ctx.memory.shared) {
|
|
489
502
|
const heapBase = (dataLen + 7) & ~7
|
|
490
|
-
|
|
503
|
+
// Non-shared memory always carries a $__heap global — start it past the
|
|
504
|
+
// static data so the bump allocator never overwrites a literal.
|
|
505
|
+
ctx.scope.globals.set('__heap', `(global $__heap (export "__heap") (mut i32) (i32.const ${heapBase}))`)
|
|
491
506
|
ctx.scope.globalTypes.set('__heap', 'i32')
|
|
492
507
|
if (ctx.scope.globals.has('__heap_start')) {
|
|
493
508
|
ctx.scope.globals.set('__heap_start', `(global $__heap_start (mut i32) (i32.const ${heapBase}))`)
|
package/src/autoload.js
CHANGED
|
@@ -36,9 +36,12 @@ export const OP_MODULES = {
|
|
|
36
36
|
'in': ['core', 'collection', 'string'],
|
|
37
37
|
'==': ['core', 'string'],
|
|
38
38
|
'!=': ['core', 'string'],
|
|
39
|
+
'===': ['core', 'string'],
|
|
40
|
+
'!==': ['core', 'string'],
|
|
39
41
|
'typeof': ['core', 'string'],
|
|
40
42
|
'[': ['core', 'array'],
|
|
41
43
|
'{': ['core', 'object', 'string', 'collection'],
|
|
44
|
+
'delete': ['core', 'collection', 'string'],
|
|
42
45
|
'//': ['core', 'string', 'regex'],
|
|
43
46
|
'**': ['math'],
|
|
44
47
|
}
|
|
@@ -50,6 +53,8 @@ export const CALL_MODULES = dict({
|
|
|
50
53
|
BigUint64Array: ['core', 'typedarray'],
|
|
51
54
|
parseFloat: ['number', 'string'],
|
|
52
55
|
parseInt: ['number', 'string'],
|
|
56
|
+
encodeURIComponent: ['core', 'string', 'number'],
|
|
57
|
+
decodeURIComponent: ['core', 'string', 'number'],
|
|
53
58
|
String: ['core', 'string', 'number'],
|
|
54
59
|
Number: ['number', 'string'],
|
|
55
60
|
Boolean: ['number'],
|
|
@@ -60,10 +65,13 @@ export const CALL_MODULES = dict({
|
|
|
60
65
|
'console.log': ['core', 'string', 'number', 'console'],
|
|
61
66
|
'console.warn': ['core', 'string', 'number', 'console'],
|
|
62
67
|
'console.error': ['core', 'string', 'number', 'console'],
|
|
63
|
-
'Object.fromEntries': ['collection', 'string'],
|
|
68
|
+
'Object.fromEntries': ['core', 'object', 'collection', 'string'],
|
|
64
69
|
'Object.keys': ['core', 'object', 'string'],
|
|
70
|
+
'Object.getOwnPropertyNames': ['core', 'object', 'string'],
|
|
65
71
|
'Object.values': ['core', 'object', 'string'],
|
|
66
72
|
'Object.entries': ['core', 'object', 'string'],
|
|
73
|
+
'Object.hasOwn': ['core', 'object', 'string', 'collection'],
|
|
74
|
+
'Object.freeze': ['core', 'object'],
|
|
67
75
|
'Object.assign': ['core', 'object'],
|
|
68
76
|
'Object.create': ['core', 'object'],
|
|
69
77
|
'Object.defineProperty': ['core', 'object'],
|
|
@@ -85,6 +93,10 @@ export const CALL_MODULES = dict({
|
|
|
85
93
|
'Int8Array.from': ['core', 'typedarray', 'array'],
|
|
86
94
|
'Uint8Array.from': ['core', 'typedarray', 'array'],
|
|
87
95
|
'ArrayBuffer.isView': ['core', 'typedarray'],
|
|
96
|
+
// instanceof Map / Set / TypedArray predicates (synthesized by jzify).
|
|
97
|
+
'__is_map': ['core', 'collection'],
|
|
98
|
+
'__is_set': ['core', 'collection'],
|
|
99
|
+
'__is_typed': ['core', 'typedarray'],
|
|
88
100
|
})
|
|
89
101
|
|
|
90
102
|
export const GENERIC_METHOD_MODULES = dict({
|