jz 0.1.0 → 0.1.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.
@@ -7,7 +7,9 @@
7
7
  * @module typed
8
8
  */
9
9
 
10
- import { emit, typed, asF64, asI32, valTypeOf, lookupValType, VAL, UNDEF_NAN, allocPtr, mkPtrIR, ptrOffsetIR, temp, tempI32 } from '../src/compile.js'
10
+ import { typed, asF64, asI32, UNDEF_NAN, allocPtr, mkPtrIR, ptrOffsetIR, temp, tempI32 } from '../src/ir.js'
11
+ import { emit } from '../src/emit.js'
12
+ import { valTypeOf, lookupValType, VAL } from '../src/analyze.js'
11
13
  import { inc, PTR } from '../src/ctx.js'
12
14
 
13
15
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jz",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Modern functional JS compiling to WASM",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -25,10 +25,12 @@
25
25
  "test:segments": "nice -n 15 node scripts/test-segments.mjs 3000 files",
26
26
  "test:prefixes": "nice -n 15 node scripts/test-segments.mjs 3000 prefix",
27
27
  "test262": "node test/test262.js",
28
+ "test262:builtins": "node test/test262-builtins.js",
28
29
  "test262:runner": "node test/runner.js",
29
30
  "dev": "node cli.js",
30
31
  "build": "node cli.js compile examples/*.js",
31
32
  "bench": "node bench/bench.mjs",
33
+ "bench:compile": "node scripts/bench-compile.mjs",
32
34
  "bench:biquad": "node bench/bench.mjs biquad",
33
35
  "test:bench-pin": "node test/bench-pin.js"
34
36
  },
@@ -43,7 +45,7 @@
43
45
  "author": "Dmitry Iv",
44
46
  "license": "MIT",
45
47
  "dependencies": {
46
- "subscript": "^10.3.3",
48
+ "subscript": "^10.3.5",
47
49
  "watr": "^4.5.1"
48
50
  },
49
51
  "keywords": [
package/src/analyze.js CHANGED
@@ -237,7 +237,7 @@ export function valTypeOf(expr) {
237
237
  }
238
238
 
239
239
  if (op === '[') return VAL.ARRAY
240
- if (op === 'str') return VAL.STRING
240
+ if (op === 'str' || op === 'strcat') return VAL.STRING
241
241
  if (op === '=>') return VAL.CLOSURE
242
242
  if (op === '//') return VAL.REGEX
243
243
  if (op === '{}' && args[0]?.[0] === ':') return VAL.OBJECT
@@ -1588,7 +1588,11 @@ export function analyzeDynKeys(...roots) {
1588
1588
  }
1589
1589
  for (const r of roots) walk(r)
1590
1590
  if (ctx.func.list) for (const f of ctx.func.list) if (f.body) walk(f.body)
1591
- if (ctx.module.moduleInits) for (const mi of ctx.module.moduleInits) walk(mi)
1591
+ const initFacts = ctx.module.initFacts
1592
+ if (initFacts?.anyDyn) {
1593
+ anyDyn = true
1594
+ for (const v of initFacts.dynVars) dynVars.add(v)
1595
+ }
1592
1596
 
1593
1597
  ctx.types.dynKeyVars = dynVars
1594
1598
  ctx.types.anyDynKey = anyDyn
@@ -1752,6 +1756,7 @@ export function collectProgramFacts(ast) {
1752
1756
  const callSites = []
1753
1757
  const doSchema = ast && ctx.schema.register
1754
1758
  const doArity = !!ctx.closure.make
1759
+ let hasSchemaLiterals = false
1755
1760
  let maxDef = 0, maxCall = 0, hasRest = false, hasSpread = false
1756
1761
  const isLiteralStr = idx => Array.isArray(idx) && idx[0] === 'str' && typeof idx[1] === 'string'
1757
1762
  // Slot-type observation lives in the dedicated `observeProgramSlots` pass below;
@@ -1775,7 +1780,10 @@ export function collectProgramFacts(ast) {
1775
1780
  // to `[':', x, x]`) resolves x's val type via per-function locals, not just globals.
1776
1781
  if (op === '{}' && doSchema) {
1777
1782
  const parsed = staticObjectProps(args)
1778
- if (parsed) ctx.schema.register(parsed.names)
1783
+ if (parsed) {
1784
+ ctx.schema.register(parsed.names)
1785
+ hasSchemaLiterals = true
1786
+ }
1779
1787
  }
1780
1788
  // closure ABI arity
1781
1789
  if (doArity) {
@@ -1837,7 +1845,20 @@ export function collectProgramFacts(ast) {
1837
1845
  }
1838
1846
  walkFacts(ast, true, false, null)
1839
1847
  for (const func of ctx.func.list) if (func.body && !func.raw) walkFacts(func.body, true, false, func)
1840
- if (ctx.module.moduleInits) for (const mi of ctx.module.moduleInits) walkFacts(mi, false, false, null)
1848
+ const initFacts = ctx.module.initFacts
1849
+ if (initFacts) {
1850
+ if (initFacts.anyDyn) {
1851
+ anyDyn = true
1852
+ for (const v of initFacts.dynVars) dynVars.add(v)
1853
+ }
1854
+ if (doArity) {
1855
+ if (initFacts.maxDef > maxDef) maxDef = initFacts.maxDef
1856
+ if (initFacts.maxCall > maxCall) maxCall = initFacts.maxCall
1857
+ if (initFacts.hasRest) hasRest = true
1858
+ if (initFacts.hasSpread) hasSpread = true
1859
+ }
1860
+ if (doSchema && initFacts.hasSchemaLiterals) hasSchemaLiterals = true
1861
+ }
1841
1862
 
1842
1863
  // Slot-type observation pass: walk every `{}` literal with the right scope's
1843
1864
  // valTypes installed as `ctx.func.localValTypesOverlay` so shorthand `{x}`
@@ -1845,12 +1866,12 @@ export function collectProgramFacts(ast) {
1845
1866
  // through valTypeOf → lookupValType. Skips into closures — they're observed via
1846
1867
  // their own func.list entry. The overlay is the per-function analyzeBody.valTypes
1847
1868
  // map (already populated with the same overlay-aware walk).
1848
- if (doSchema) observeProgramSlots(ast)
1869
+ if (doSchema && hasSchemaLiterals) observeProgramSlots(ast)
1849
1870
 
1850
1871
  return {
1851
1872
  dynVars, anyDyn, propMap, valueUsed, callSites,
1852
1873
  maxDef, maxCall, hasRest, hasSpread,
1853
- paramReps,
1874
+ paramReps, hasSchemaLiterals,
1854
1875
  }
1855
1876
  }
1856
1877
 
@@ -1898,7 +1919,7 @@ export function observeProgramSlots(ast) {
1898
1919
  ctx.func.localValTypesOverlay = analyzeBody(func.body).valTypes
1899
1920
  visit(func.body)
1900
1921
  }
1901
- if (ctx.module.moduleInits) {
1922
+ if (ctx.module.initFacts?.hasSchemaLiterals && ctx.module.moduleInits) {
1902
1923
  ctx.func.localValTypesOverlay = null
1903
1924
  for (const mi of ctx.module.moduleInits) visit(mi)
1904
1925
  }
@@ -0,0 +1,175 @@
1
+ /** Runtime module autoload rules used by prepare(). */
2
+
3
+ import { ctx, err } from './ctx.js'
4
+ import * as mods from '../module/index.js'
5
+
6
+ const dict = obj => Object.assign(Object.create(null), obj)
7
+
8
+ export const PROP_MODULES = Object.assign(Object.create(null), {
9
+ push: ['core', 'array'], pop: ['core', 'array'], shift: ['core', 'array'], unshift: ['core', 'array'],
10
+ splice: ['core', 'array'], reverse: ['core', 'array'], sort: ['core', 'array'], fill: ['core', 'array'],
11
+ map: ['core', 'array'], filter: ['core', 'array'], reduce: ['core', 'array'], reduceRight: ['core', 'array'],
12
+ forEach: ['core', 'array'], find: ['core', 'array'], findIndex: ['core', 'array'],
13
+ findLast: ['core', 'array'], findLastIndex: ['core', 'array'],
14
+ every: ['core', 'array'], some: ['core', 'array'], flat: ['core', 'array'], flatMap: ['core', 'array'],
15
+ join: ['core', 'array'], copyWithin: ['core', 'array'], at: ['core', 'array'],
16
+ charAt: ['core', 'string'], charCodeAt: ['core', 'string'], codePointAt: ['core', 'string'],
17
+ toUpperCase: ['core', 'string'], toLowerCase: ['core', 'string'], trim: ['core', 'string'],
18
+ trimStart: ['core', 'string'], trimEnd: ['core', 'string'],
19
+ split: ['core', 'string'], replace: ['core', 'string'], replaceAll: ['core', 'string'],
20
+ repeat: ['core', 'string'], startsWith: ['core', 'string'], endsWith: ['core', 'string'],
21
+ padStart: ['core', 'string'], padEnd: ['core', 'string'], normalize: ['core', 'string'],
22
+ matchAll: ['core', 'string'], match: ['core', 'string'],
23
+ substring: ['core', 'string'], substr: ['core', 'string'],
24
+ add: ['core', 'collection'], clear: ['core', 'collection'],
25
+ slice: ['core', 'string', 'array'], concat: ['core', 'string', 'array'],
26
+ indexOf: ['core', 'string', 'array'], lastIndexOf: ['core', 'string', 'array'],
27
+ includes: ['core', 'string', 'array'],
28
+ length: ['core', 'string', 'array', 'typedarray'],
29
+ })
30
+
31
+ export const OP_MODULES = {
32
+ '?.': ['core', 'string', 'collection'],
33
+ '?.[]': ['core', 'array', 'collection'],
34
+ '?.()': ['core', 'fn'],
35
+ 'u+': ['number', 'string'],
36
+ 'in': ['core', 'collection', 'string'],
37
+ '==': ['core', 'string'],
38
+ '!=': ['core', 'string'],
39
+ 'typeof': ['core', 'string'],
40
+ '[': ['core', 'array'],
41
+ '{': ['core', 'object', 'string', 'collection'],
42
+ '//': ['core', 'string', 'regex'],
43
+ '**': ['math'],
44
+ }
45
+
46
+ export const CALL_MODULES = dict({
47
+ ArrayBuffer: ['core', 'typedarray'],
48
+ DataView: ['core', 'typedarray'],
49
+ BigInt64Array: ['core', 'typedarray'],
50
+ BigUint64Array: ['core', 'typedarray'],
51
+ parseFloat: ['number', 'string'],
52
+ parseInt: ['number', 'string'],
53
+ String: ['core', 'string', 'number'],
54
+ Number: ['number', 'string'],
55
+ Boolean: ['number'],
56
+ TextEncoder: ['core', 'string'],
57
+ TextDecoder: ['core', 'string'],
58
+ Error: ['core', 'string'],
59
+ BigInt: ['number'],
60
+ 'console.log': ['core', 'string', 'number', 'console'],
61
+ 'console.warn': ['core', 'string', 'number', 'console'],
62
+ 'console.error': ['core', 'string', 'number', 'console'],
63
+ 'Object.fromEntries': ['collection', 'string'],
64
+ 'Object.keys': ['string'],
65
+ 'Object.entries': ['string'],
66
+ 'Date.now': ['core', 'console'],
67
+ 'performance.now': ['core', 'console'],
68
+ 'String.fromCharCode': ['core', 'string'],
69
+ 'String.fromCodePoint': ['core', 'string'],
70
+ 'BigInt.asIntN': ['number'],
71
+ 'BigInt.asUintN': ['number'],
72
+ 'Float64Array.from': ['core', 'typedarray', 'array'],
73
+ 'Float32Array.from': ['core', 'typedarray', 'array'],
74
+ 'Int32Array.from': ['core', 'typedarray', 'array'],
75
+ 'Uint32Array.from': ['core', 'typedarray', 'array'],
76
+ 'Int16Array.from': ['core', 'typedarray', 'array'],
77
+ 'Uint16Array.from': ['core', 'typedarray', 'array'],
78
+ 'Int8Array.from': ['core', 'typedarray', 'array'],
79
+ 'Uint8Array.from': ['core', 'typedarray', 'array'],
80
+ 'ArrayBuffer.isView': ['core', 'typedarray'],
81
+ })
82
+
83
+ export const GENERIC_METHOD_MODULES = dict({
84
+ toString: ['core', 'string', 'number'],
85
+ toFixed: ['core', 'string', 'number'],
86
+ toPrecision: ['core', 'string', 'number'],
87
+ toExponential: ['core', 'string', 'number'],
88
+ })
89
+
90
+ export const CTORS = ['Float64Array','Float32Array','Int32Array','Uint32Array','Int16Array','Uint16Array','Int8Array','Uint8Array','BigInt64Array','BigUint64Array','Set','Map']
91
+ export const TYPED_CTORS = ['Float64Array','Float32Array','Int32Array','Uint32Array','Int16Array','Uint16Array','Int8Array','Uint8Array','BigInt64Array','BigUint64Array','ArrayBuffer','DataView']
92
+ export const COLLECTION_CTORS = ['Set', 'Map']
93
+ export const TIMER_NAMES = new Set(['setTimeout', 'clearTimeout', 'setInterval', 'clearInterval'])
94
+
95
+ export const MOD_ALIAS = { Number: 'number', Array: 'array', Object: 'object', Symbol: 'symbol', JSON: 'json', BigInt: 'number', Error: 'core', TextEncoder: 'string', TextDecoder: 'string' }
96
+
97
+ const MOD_DEPS = {
98
+ number: ['core', 'string'],
99
+ string: ['core', 'number'],
100
+ array: ['core'],
101
+ object: ['core'],
102
+ collection: ['core', 'number'],
103
+ symbol: ['core'],
104
+ json: ['core', 'string', 'number', 'collection'],
105
+ console: ['core', 'string', 'number'],
106
+ regex: ['core', 'string', 'array'],
107
+ }
108
+
109
+ export const hasModule = name => Boolean(mods[MOD_ALIAS[name] || name])
110
+
111
+ export const includeMods = (...names) => names.forEach(includeModule)
112
+
113
+ export const includeForOp = op => {
114
+ const modules = OP_MODULES[op]
115
+ if (!modules) return false
116
+ includeMods(...modules)
117
+ return true
118
+ }
119
+
120
+ export const includeForCallableValue = () => includeMods('core', 'fn')
121
+ export const includeForNumericCoercion = () => includeMods('number', 'string')
122
+ export const includeForStringValue = () => includeMods('core', 'string', 'number')
123
+ export const includeForStringOnly = () => includeMods('core', 'string')
124
+ export const includeForArrayLiteral = () => includeMods('core', 'array')
125
+ export const includeForArrayAccess = () => includeMods('core', 'array', 'collection')
126
+ export const includeForArrayPattern = includeForArrayAccess
127
+ export const includeForObjectLiteral = () => includeMods('core', 'object')
128
+ export const includeForObjectPattern = () => includeMods('core', 'object', 'string', 'collection')
129
+ export const includeForKnownKeyIteration = includeForStringOnly
130
+ export const includeForRuntimeKeyIteration = () => includeMods('core', 'string', 'collection')
131
+ export const includeForTimerRuntime = () => {
132
+ ctx.features.timers = true
133
+ includeModule('timer')
134
+ includeModule('fn')
135
+ }
136
+
137
+ export const includeForNamedCall = callee => {
138
+ const modules = CALL_MODULES[callee]
139
+ if (!modules) return false
140
+ includeMods(...modules)
141
+ return true
142
+ }
143
+
144
+ export const includeForGenericMethod = prop => {
145
+ const modules = GENERIC_METHOD_MODULES[prop]
146
+ if (!modules) return false
147
+ includeMods(...modules)
148
+ return true
149
+ }
150
+
151
+ export const includeForProperty = prop => {
152
+ if (prop === 'byteLength' || prop === 'byteOffset' || prop === 'buffer') includeMods('core', 'typedarray')
153
+ if (typeof prop === 'string' && PROP_MODULES[prop]) includeMods(...PROP_MODULES[prop])
154
+ else includeMods('core', 'object', 'array', 'string', 'collection')
155
+ }
156
+
157
+ export const runtimeCtorKind = name =>
158
+ TYPED_CTORS.includes(name) ? 'typedarray' : COLLECTION_CTORS.includes(name) ? 'collection' : null
159
+
160
+ export const includeForRuntimeCtor = name => {
161
+ const kind = runtimeCtorKind(name)
162
+ if (kind === 'typedarray') includeMods('core', 'typedarray')
163
+ else if (kind === 'collection') includeMods('core', 'collection')
164
+ return kind
165
+ }
166
+
167
+ export function includeModule(name) {
168
+ const modName = MOD_ALIAS[name] || name
169
+ const init = mods[modName]
170
+ if (!init) return err(`Module not found: ${name}`)
171
+ if (ctx.module.modules[modName]) return
172
+ ctx.module.modules[modName] = true
173
+ for (const dep of MOD_DEPS[modName] || []) includeModule(dep)
174
+ init(ctx)
175
+ }