jz 0.1.0 → 0.2.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 +221 -62
- package/cli.js +34 -8
- package/index.js +133 -14
- package/module/array.js +399 -131
- package/module/collection.js +457 -212
- package/module/console.js +170 -87
- package/module/core.js +247 -143
- package/module/date.js +691 -0
- package/module/function.js +84 -23
- package/module/index.js +2 -1
- package/module/json.js +485 -138
- package/module/math.js +81 -40
- package/module/number.js +189 -83
- package/module/object.js +228 -46
- package/module/regex.js +34 -30
- package/module/schema.js +17 -18
- package/module/string.js +483 -227
- package/module/symbol.js +6 -4
- package/module/timer.js +90 -32
- package/module/typedarray.js +176 -44
- package/package.json +5 -10
- package/src/analyze.js +639 -124
- package/src/autoload.js +183 -0
- package/src/compile.js +448 -1083
- package/src/ctx.js +42 -12
- package/src/emit.js +646 -147
- package/src/host.js +273 -68
- package/src/ir.js +81 -31
- package/src/jzify.js +220 -36
- package/src/narrow.js +956 -0
- package/src/optimize.js +628 -42
- package/src/plan.js +1233 -0
- package/src/prepare.js +438 -256
- package/src/vectorize.js +1016 -0
- package/wasi.js +23 -4
package/module/console.js
CHANGED
|
@@ -1,46 +1,78 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Console + clocks module — two host-mode lowerings.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* `host: 'js'` (default): emit `env.print(val: i64, fd: i32, sep: i32)` and
|
|
5
|
+
* `env.now(clock: i32) -> f64`. The JS host (src/host.js) wires both
|
|
6
|
+
* automatically — `print` reads the NaN-boxed value via `mem.read`, so
|
|
7
|
+
* stringification happens host-side (no __ftoa / __write_str / __write_val
|
|
8
|
+
* stdlib in the binary). `sep`: 10=newline, 32=space, 0=no separator.
|
|
9
|
+
* `clock`: 0=Date.now (epoch ms), 1=performance.now (monotonic ms).
|
|
7
10
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
+
* The val param is i64 (not f64): V8 (notably node 22 on x64) intermittently
|
|
12
|
+
* canonicalizes f64 NaN payloads at the wasm→JS boundary, collapsing the
|
|
13
|
+
* high-mantissa discriminator bits and corrupting NaN-boxed pointers. i64
|
|
14
|
+
* is integer-typed and preserves all 64 bits exactly. Host reinterprets the
|
|
15
|
+
* bits as f64 with a DataView before calling mem.read.
|
|
11
16
|
*
|
|
12
|
-
*
|
|
17
|
+
* `host: 'wasi'`: emit `wasi_snapshot_preview1.fd_write` + `clock_time_get`.
|
|
18
|
+
* Output runs natively on wasmtime/wasmer/deno and on browsers/Node via the
|
|
19
|
+
* tiny `jz/wasi` polyfill auto-applied by the `jz()` runtime.
|
|
20
|
+
*
|
|
21
|
+
* console.log/warn/error: variadic. fd=1 for log, fd=2 for warn/error.
|
|
22
|
+
*
|
|
23
|
+
* @module console
|
|
13
24
|
*/
|
|
14
25
|
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
26
|
+
import { typed, asF64, asI64, mkPtrIR, NULL_NAN, UNDEF_NAN } from '../src/ir.js'
|
|
27
|
+
import { emit } from '../src/emit.js'
|
|
28
|
+
import { valTypeOf, VAL, exprType } from '../src/analyze.js'
|
|
29
|
+
import { inc, PTR, LAYOUT } from '../src/ctx.js'
|
|
18
30
|
|
|
19
|
-
|
|
31
|
+
const addImportOnce = (ctx, mod, name, fn) => {
|
|
32
|
+
if (ctx.module.imports.some(i => i[1] === `"${mod}"` && i[2] === `"${name}"`)) return
|
|
33
|
+
ctx.module.imports.push(['import', `"${mod}"`, `"${name}"`, fn])
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Template-literal concat chains (`a${x}b`) lower to ['()', ['.', X, 'concat'], Y]
|
|
37
|
+
// in prepare. Walking left from the chain root recovers the parts in order; if the
|
|
38
|
+
// base is a `['str', ...]` it's a template-shaped chain (vs an arbitrary user
|
|
39
|
+
// .concat call). Returning the parts lets console.log skip __str_concat/__to_str
|
|
40
|
+
// entirely — biquad's only string churn is the perf-summary line.
|
|
41
|
+
const flattenTemplateConcat = (node) => {
|
|
42
|
+
const parts = []
|
|
43
|
+
let n = node
|
|
44
|
+
while (Array.isArray(n) && n[0] === '()' && n.length === 3 &&
|
|
45
|
+
Array.isArray(n[1]) && n[1][0] === '.' && n[1][2] === 'concat') {
|
|
46
|
+
parts.unshift(n[2])
|
|
47
|
+
n = n[1][1]
|
|
48
|
+
}
|
|
49
|
+
if (!(Array.isArray(n) && n[0] === 'str')) return null
|
|
50
|
+
parts.unshift(n)
|
|
51
|
+
return parts
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const setupWasi = (ctx) => {
|
|
20
55
|
Object.assign(ctx.core.stdlibDeps, {
|
|
21
56
|
__write_val: ['__ptr_type', '__write_str', '__write_num', '__write_int', '__write_byte', '__static_str'],
|
|
22
57
|
__write_num: ['__ftoa', '__write_str'],
|
|
23
58
|
__write_int: ['__itoa', '__mkstr', '__write_str'],
|
|
24
59
|
__write_str: ['__sso_char', '__str_len'],
|
|
60
|
+
__read_stdin: ['__mkstr'],
|
|
25
61
|
})
|
|
26
62
|
|
|
63
|
+
const needFdWrite = () => addImportOnce(ctx, 'wasi_snapshot_preview1', 'fd_write',
|
|
64
|
+
['func', '$__fd_write', ['param', 'i32'], ['param', 'i32'], ['param', 'i32'], ['param', 'i32'], ['result', 'i32']])
|
|
27
65
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
['import', '"wasi_snapshot_preview1"', '"fd_write"',
|
|
31
|
-
['func', '$__fd_write', ['param', 'i32'], ['param', 'i32'], ['param', 'i32'], ['param', 'i32'], ['result', 'i32']]])
|
|
66
|
+
const needFdRead = () => addImportOnce(ctx, 'wasi_snapshot_preview1', 'fd_read',
|
|
67
|
+
['func', '$__fd_read', ['param', 'i32'], ['param', 'i32'], ['param', 'i32'], ['param', 'i32'], ['result', 'i32']])
|
|
32
68
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
ctx.core.stdlib['__write_str'] = `(func $__write_str (param $fd i32) (param $ptr f64)
|
|
36
|
-
(local $iov i32) (local $type i32) (local $len i32) (local $off i32) (local $buf i32)
|
|
37
|
-
;; Allocate iov (8 bytes: ptr + len) + nwritten (4 bytes)
|
|
69
|
+
ctx.core.stdlib['__write_str'] = `(func $__write_str (param $fd i32) (param $ptr i64)
|
|
70
|
+
(local $iov i32) (local $aux i32) (local $len i32) (local $off i32) (local $buf i32)
|
|
38
71
|
(local.set $iov (call $__alloc (i32.const 12)))
|
|
39
|
-
(local.set $
|
|
40
|
-
(if (i32.
|
|
72
|
+
(local.set $aux (call $__ptr_aux (local.get $ptr)))
|
|
73
|
+
(if (i32.and (local.get $aux) (i32.const ${LAYOUT.SSO_BIT}))
|
|
41
74
|
(then
|
|
42
|
-
|
|
43
|
-
(local.set $len (call $__ptr_aux (local.get $ptr)))
|
|
75
|
+
(local.set $len (i32.and (local.get $aux) (i32.const 7)))
|
|
44
76
|
(local.set $buf (call $__alloc (local.get $len)))
|
|
45
77
|
(local.set $off (i32.const 0))
|
|
46
78
|
(block $done (loop $loop
|
|
@@ -52,13 +84,11 @@ export default (ctx) => {
|
|
|
52
84
|
(i32.store (local.get $iov) (local.get $buf))
|
|
53
85
|
(i32.store (i32.add (local.get $iov) (i32.const 4)) (local.get $len)))
|
|
54
86
|
(else
|
|
55
|
-
;; Heap string: offset points directly to char data
|
|
56
87
|
(i32.store (local.get $iov) (call $__ptr_offset (local.get $ptr)))
|
|
57
88
|
(i32.store (i32.add (local.get $iov) (i32.const 4)) (call $__str_len (local.get $ptr)))))
|
|
58
89
|
(drop (call $__fd_write (local.get $fd) (local.get $iov) (i32.const 1)
|
|
59
90
|
(i32.add (local.get $iov) (i32.const 8)))))`
|
|
60
91
|
|
|
61
|
-
// __write_byte(fd: i32, byte: i32) — write a single byte (space, newline)
|
|
62
92
|
ctx.core.stdlib['__write_byte'] = `(func $__write_byte (param $fd i32) (param $byte i32)
|
|
63
93
|
(local $iov i32)
|
|
64
94
|
(local.set $iov (call $__alloc (i32.const 13)))
|
|
@@ -68,72 +98,66 @@ export default (ctx) => {
|
|
|
68
98
|
(drop (call $__fd_write (local.get $fd) (local.get $iov) (i32.const 1)
|
|
69
99
|
(i32.add (local.get $iov) (i32.const 8)))))`
|
|
70
100
|
|
|
71
|
-
// __write_num(fd: i32, val: f64) — convert number to string, write to fd
|
|
72
101
|
ctx.core.stdlib['__write_num'] = `(func $__write_num (param $fd i32) (param $val f64)
|
|
73
|
-
(call $__write_str (local.get $fd) (call $__ftoa (local.get $val) (i32.const 0) (i32.const 0))))`
|
|
74
|
-
// __write_int(fd: i32, val: f64) — convert integer to string, write to fd
|
|
75
|
-
// Skips __ftoa (~600 B) for values proven integer by exprType.
|
|
102
|
+
(call $__write_str (local.get $fd) (i64.reinterpret_f64 (call $__ftoa (local.get $val) (i32.const 0) (i32.const 0)))))`
|
|
76
103
|
ctx.core.stdlib['__write_int'] = `(func $__write_int (param $fd i32) (param $val f64)
|
|
77
104
|
(local $buf i32)
|
|
78
105
|
(local.set $buf (call $__alloc (i32.const 12)))
|
|
79
106
|
(call $__write_str (local.get $fd)
|
|
80
|
-
(call $__mkstr (local.get $buf) (call $__itoa (i32.trunc_sat_f64_s (local.get $val)) (local.get $buf)))))`
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
(local $
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
107
|
+
(i64.reinterpret_f64 (call $__mkstr (local.get $buf) (call $__itoa (i32.trunc_sat_f64_s (local.get $val)) (local.get $buf))))))`
|
|
108
|
+
ctx.core.stdlib['__write_val'] = `(func $__write_val (param $fd i32) (param $val i64)
|
|
109
|
+
(local $type i32) (local $f f64)
|
|
110
|
+
(local.set $f (f64.reinterpret_i64 (local.get $val)))
|
|
111
|
+
(if (f64.eq (local.get $f) (local.get $f))
|
|
112
|
+
(then (call $__write_num (local.get $fd) (local.get $f)) (return)))
|
|
113
|
+
(if (i64.eq (local.get $val) (i64.const ${NULL_NAN}))
|
|
114
|
+
(then (call $__write_str (local.get $fd) (i64.reinterpret_f64 (call $__static_str (i32.const 5)))) (return)))
|
|
115
|
+
(if (i64.eq (local.get $val) (i64.const ${UNDEF_NAN}))
|
|
116
|
+
(then (call $__write_str (local.get $fd) (i64.reinterpret_f64 (call $__static_str (i32.const 6)))) (return)))
|
|
88
117
|
(local.set $type (call $__ptr_type (local.get $val)))
|
|
89
118
|
(if (i32.eqz (local.get $type))
|
|
90
|
-
(then (call $__write_str (local.get $fd) (call $__static_str (i32.const 0))) (return)))
|
|
91
|
-
|
|
92
|
-
(if (i32.or (i32.eq (local.get $type) (i32.const ${PTR.STRING}))
|
|
93
|
-
(i32.eq (local.get $type) (i32.const ${PTR.SSO})))
|
|
119
|
+
(then (call $__write_str (local.get $fd) (i64.reinterpret_f64 (call $__static_str (i32.const 0)))) (return)))
|
|
120
|
+
(if (i32.eq (local.get $type) (i32.const ${PTR.STRING}))
|
|
94
121
|
(then (call $__write_str (local.get $fd) (local.get $val)) (return)))
|
|
95
|
-
|
|
96
|
-
(call $__write_str (local.get $fd) (call $__static_str
|
|
122
|
+
(call $__write_str (local.get $fd) (i64.reinterpret_f64 (call $__static_str
|
|
97
123
|
(if (result i32) (i32.eq (local.get $type) (i32.const 1))
|
|
98
|
-
(then (i32.const 7)) (else (i32.const 8))))))`
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
124
|
+
(then (i32.const 7)) (else (i32.const 8)))))))`
|
|
125
|
+
|
|
126
|
+
ctx.core.stdlib['__read_stdin'] = `(func $__read_stdin (result f64)
|
|
127
|
+
(local $iov i32) (local $nio i32) (local $buf i32) (local $total i32) (local $n i32)
|
|
128
|
+
(local.set $iov (call $__alloc (i32.const 8)))
|
|
129
|
+
(local.set $nio (call $__alloc (i32.const 4)))
|
|
130
|
+
(local.set $buf (call $__alloc (i32.const 65536)))
|
|
131
|
+
(local.set $total (i32.const 0))
|
|
132
|
+
(block $eof (loop $read
|
|
133
|
+
(i32.store (local.get $iov) (i32.add (local.get $buf) (local.get $total)))
|
|
134
|
+
(i32.store offset=4 (local.get $iov) (i32.sub (i32.const 65536) (local.get $total)))
|
|
135
|
+
(drop (call $__fd_read (i32.const 0) (local.get $iov) (i32.const 1) (local.get $nio)))
|
|
136
|
+
(local.set $n (i32.load (local.get $nio)))
|
|
137
|
+
(br_if $eof (i32.eqz (local.get $n)))
|
|
138
|
+
(local.set $total (i32.add (local.get $total) (local.get $n)))
|
|
139
|
+
(br_if $eof (i32.ge_s (local.get $total) (i32.const 65536)))
|
|
140
|
+
(br $read)))
|
|
141
|
+
(call $__mkstr (local.get $buf) (local.get $total)))`
|
|
142
|
+
|
|
143
|
+
ctx.core.emit['readStdin'] = () => {
|
|
144
|
+
needFdRead()
|
|
145
|
+
inc('__read_stdin')
|
|
146
|
+
return typed(['call', '$__read_stdin'], 'f64')
|
|
116
147
|
}
|
|
117
148
|
|
|
118
|
-
// console.log(...args) — variadic, each arg separated by space, followed by newline.
|
|
119
|
-
// Per-arg dispatch is monomorphized when valTypeOf proves the arg is a string or
|
|
120
|
-
// number — direct __write_str / __write_num skips the polymorphic __write_val
|
|
121
|
-
// helper (and its transitive __ptr_type / __static_str / number-or-string-test
|
|
122
|
-
// arms), which is the entire stdlib floor for size-conscious benches.
|
|
123
149
|
const makeConsole = (method, fd) => {
|
|
124
150
|
ctx.core.emit[`console.${method}`] = (...args) => {
|
|
151
|
+
needFdWrite()
|
|
125
152
|
inc('__write_byte')
|
|
126
153
|
const ir = []
|
|
127
154
|
const writePart = (part) => {
|
|
128
|
-
// Empty string segments (template boundaries) write nothing.
|
|
129
155
|
if (Array.isArray(part) && part[0] === 'str' && part[1] === '') return
|
|
130
156
|
const vt = valTypeOf(part)
|
|
131
157
|
if (vt === VAL.STRING) {
|
|
132
158
|
inc('__write_str')
|
|
133
|
-
ir.push(['call', '$__write_str', ['i32.const', fd],
|
|
159
|
+
ir.push(['call', '$__write_str', ['i32.const', fd], asI64(emit(part))])
|
|
134
160
|
} else if (vt === VAL.NUMBER) {
|
|
135
|
-
// Integer-valued numbers use __write_int (__itoa) instead of __write_num (__ftoa).
|
|
136
|
-
// exprType sees i32 for literals, bitwise ops, .length on arrays, Math.imul, etc.
|
|
137
161
|
if (exprType(part, ctx.func.locals) === 'i32') {
|
|
138
162
|
inc('__write_int')
|
|
139
163
|
ir.push(['call', '$__write_int', ['i32.const', fd], asF64(emit(part))])
|
|
@@ -143,17 +167,17 @@ export default (ctx) => {
|
|
|
143
167
|
}
|
|
144
168
|
} else {
|
|
145
169
|
inc('__write_val')
|
|
146
|
-
ir.push(['call', '$__write_val', ['i32.const', fd],
|
|
170
|
+
ir.push(['call', '$__write_val', ['i32.const', fd], asI64(emit(part))])
|
|
147
171
|
}
|
|
148
172
|
}
|
|
149
173
|
for (let i = 0; i < args.length; i++) {
|
|
150
|
-
if (i > 0) ir.push(['call', '$__write_byte', ['i32.const', fd], ['i32.const', 32]])
|
|
174
|
+
if (i > 0) ir.push(['call', '$__write_byte', ['i32.const', fd], ['i32.const', 32]])
|
|
151
175
|
const parts = flattenTemplateConcat(args[i])
|
|
152
176
|
if (parts) for (const p of parts) writePart(p)
|
|
153
177
|
else writePart(args[i])
|
|
154
178
|
}
|
|
155
|
-
ir.push(['call', '$__write_byte', ['i32.const', fd], ['i32.const', 10]])
|
|
156
|
-
ir.push(['f64.const', 0])
|
|
179
|
+
ir.push(['call', '$__write_byte', ['i32.const', fd], ['i32.const', 10]])
|
|
180
|
+
ir.push(['f64.const', 0])
|
|
157
181
|
return typed(['block', ['result', 'f64'], ...ir], 'f64')
|
|
158
182
|
}
|
|
159
183
|
}
|
|
@@ -162,29 +186,88 @@ export default (ctx) => {
|
|
|
162
186
|
makeConsole('warn', 2)
|
|
163
187
|
makeConsole('error', 2)
|
|
164
188
|
|
|
165
|
-
|
|
189
|
+
const needClock = () => addImportOnce(ctx, 'wasi_snapshot_preview1', 'clock_time_get',
|
|
190
|
+
['func', '$__clock_time_get', ['param', 'i32'], ['param', 'i64'], ['param', 'i32'], ['result', 'i32']])
|
|
166
191
|
|
|
167
|
-
ctx.module.imports.push(
|
|
168
|
-
['import', '"wasi_snapshot_preview1"', '"clock_time_get"',
|
|
169
|
-
['func', '$__clock_time_get', ['param', 'i32'], ['param', 'i64'], ['param', 'i32'], ['result', 'i32']]])
|
|
170
|
-
|
|
171
|
-
// __time_ms(clock_id) → f64 milliseconds
|
|
172
|
-
// clock_time_get writes i64 nanoseconds to memory, we convert to f64 ms
|
|
173
192
|
ctx.core.stdlib['__time_ms'] = `(func $__time_ms (param $clock i32) (result f64)
|
|
174
193
|
(drop (call $__clock_time_get (local.get $clock) (i64.const 1000) (i32.const 0)))
|
|
175
194
|
(f64.div (f64.convert_i64_u (i64.load (i32.const 0))) (f64.const 1000000)))`
|
|
176
195
|
|
|
177
196
|
ctx.core.emit['Date.now'] = () => {
|
|
197
|
+
needClock()
|
|
178
198
|
inc('__time_ms')
|
|
179
|
-
return typed(['call', '$__time_ms', ['i32.const', 0]], 'f64')
|
|
199
|
+
return typed(['call', '$__time_ms', ['i32.const', 0]], 'f64')
|
|
180
200
|
}
|
|
181
|
-
|
|
182
201
|
ctx.core.emit['performance.now'] = () => {
|
|
202
|
+
needClock()
|
|
183
203
|
inc('__time_ms')
|
|
184
|
-
return typed(['call', '$__time_ms', ['i32.const', 1]], 'f64')
|
|
204
|
+
return typed(['call', '$__time_ms', ['i32.const', 1]], 'f64')
|
|
185
205
|
}
|
|
206
|
+
ctx.core.emit['console.now'] = ctx.core.emit['Date.now']
|
|
207
|
+
ctx.core.emit['console.perfNow'] = ctx.core.emit['performance.now']
|
|
208
|
+
}
|
|
186
209
|
|
|
187
|
-
|
|
210
|
+
const setupJsHost = (ctx) => {
|
|
211
|
+
const needPrint = () => addImportOnce(ctx, 'env', 'print',
|
|
212
|
+
['func', '$__print', ['param', 'i64'], ['param', 'i32'], ['param', 'i32']])
|
|
213
|
+
const needNow = () => addImportOnce(ctx, 'env', 'now',
|
|
214
|
+
['func', '$__now', ['param', 'i32'], ['result', 'f64']])
|
|
215
|
+
|
|
216
|
+
// Empty SSO string ("") for zero-arg console.log() — host reads as "".
|
|
217
|
+
const emptyStr = () => mkPtrIR(PTR.STRING, LAYOUT.SSO_BIT, 0)
|
|
218
|
+
const asI64Bits = (e) => ['i64.reinterpret_f64', asF64(emit(e))]
|
|
219
|
+
|
|
220
|
+
const makeConsole = (method, fd) => {
|
|
221
|
+
ctx.core.emit[`console.${method}`] = (...args) => {
|
|
222
|
+
needPrint()
|
|
223
|
+
// Each segment carries its trailing separator (0=none, 32=space, 10=newline).
|
|
224
|
+
// Template-concat chains (`a${x}b`) flatten to per-`${}` segments — the host
|
|
225
|
+
// stringifies, so jz drops __str_concat/__to_str entirely.
|
|
226
|
+
const segments = []
|
|
227
|
+
for (let i = 0; i < args.length; i++) {
|
|
228
|
+
const before = segments.length
|
|
229
|
+
const flat = flattenTemplateConcat(args[i])
|
|
230
|
+
const sub = flat || [args[i]]
|
|
231
|
+
for (const p of sub) {
|
|
232
|
+
if (Array.isArray(p) && p[0] === 'str' && p[1] === '') continue
|
|
233
|
+
segments.push({ expr: asI64Bits(p), sep: 0 })
|
|
234
|
+
}
|
|
235
|
+
// Empty arg (`console.log('', 'a')`) still needs to mark its boundary
|
|
236
|
+
// so the inter-arg space lands in the right place.
|
|
237
|
+
if (segments.length === before) segments.push({ expr: ['i64.reinterpret_f64', emptyStr()], sep: 0 })
|
|
238
|
+
if (i < args.length - 1) segments[segments.length - 1].sep = 32
|
|
239
|
+
}
|
|
240
|
+
const ir = []
|
|
241
|
+
if (segments.length === 0) {
|
|
242
|
+
ir.push(['call', '$__print', ['i64.reinterpret_f64', emptyStr()], ['i32.const', fd], ['i32.const', 10]])
|
|
243
|
+
} else {
|
|
244
|
+
segments[segments.length - 1].sep = 10
|
|
245
|
+
for (const { expr, sep } of segments) {
|
|
246
|
+
ir.push(['call', '$__print', expr, ['i32.const', fd], ['i32.const', sep]])
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
ir.push(['f64.const', 0])
|
|
250
|
+
return typed(['block', ['result', 'f64'], ...ir], 'f64')
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
makeConsole('log', 1)
|
|
255
|
+
makeConsole('warn', 2)
|
|
256
|
+
makeConsole('error', 2)
|
|
257
|
+
|
|
258
|
+
ctx.core.emit['Date.now'] = () => {
|
|
259
|
+
needNow()
|
|
260
|
+
return typed(['call', '$__now', ['i32.const', 0]], 'f64')
|
|
261
|
+
}
|
|
262
|
+
ctx.core.emit['performance.now'] = () => {
|
|
263
|
+
needNow()
|
|
264
|
+
return typed(['call', '$__now', ['i32.const', 1]], 'f64')
|
|
265
|
+
}
|
|
188
266
|
ctx.core.emit['console.now'] = ctx.core.emit['Date.now']
|
|
189
267
|
ctx.core.emit['console.perfNow'] = ctx.core.emit['performance.now']
|
|
190
268
|
}
|
|
269
|
+
|
|
270
|
+
export default (ctx) => {
|
|
271
|
+
if (ctx.transform.host === 'wasi') setupWasi(ctx)
|
|
272
|
+
else setupJsHost(ctx)
|
|
273
|
+
}
|