jz 0.4.0 → 0.5.1

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/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
- const heapGetIR = () => ctx.memory.shared
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 => ctx.memory.shared
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.repByLocal = null
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
- repByLocal: ctx.func.repByLocal,
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 needsSchemaTbl = (ctx.schema.list.length && (
188
- ctx.core.includes.has('__stringify') ||
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]) console.error("MISSING 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
- for (const s of [...sec.funcs, ...sec.stdlib, ...sec.start]) optimizeFunc(s, cfg, globalTypesMap)
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
- ctx.scope.globals.set('__heap', `(global $__heap (mut i32) (i32.const ${heapBase}))`)
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({