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.
- package/README.md +64 -72
- package/index.js +38 -8
- package/module/array.js +7 -2
- package/module/collection.js +3 -1
- package/module/console.js +3 -1
- package/module/core.js +3 -1
- package/module/function.js +4 -3
- package/module/json.js +3 -1
- package/module/math.js +2 -1
- package/module/number.js +3 -7
- package/module/object.js +3 -1
- package/module/regex.js +2 -1
- package/module/schema.js +3 -1
- package/module/string.js +63 -6
- package/module/symbol.js +2 -1
- package/module/timer.js +2 -2
- package/module/typedarray.js +3 -1
- package/package.json +4 -2
- package/src/analyze.js +28 -7
- package/src/autoload.js +175 -0
- package/src/compile.js +58 -1022
- package/src/ctx.js +1 -0
- package/src/emit.js +16 -6
- package/src/host.js +38 -26
- package/src/jzify.js +45 -18
- package/src/key.js +73 -0
- package/src/narrow.js +928 -0
- package/src/plan.js +105 -0
- package/src/prepare.js +151 -215
- package/src/source.js +76 -0
- package/wasi.js +10 -4
package/module/typedarray.js
CHANGED
|
@@ -7,7 +7,9 @@
|
|
|
7
7
|
* @module typed
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
import {
|
|
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.
|
|
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.
|
|
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
|
-
|
|
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)
|
|
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
|
-
|
|
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
|
}
|
package/src/autoload.js
ADDED
|
@@ -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
|
+
}
|