jz 0.1.1 → 0.2.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 +256 -90
- package/cli.js +34 -8
- package/index.js +100 -14
- package/module/array.js +396 -133
- package/module/collection.js +455 -212
- package/module/console.js +169 -88
- package/module/core.js +246 -144
- package/module/date.js +783 -0
- package/module/function.js +81 -21
- package/module/index.js +2 -1
- package/module/json.js +483 -138
- package/module/math.js +79 -39
- package/module/number.js +188 -78
- package/module/object.js +227 -47
- package/module/regex.js +33 -30
- package/module/schema.js +14 -17
- package/module/string.js +439 -235
- package/module/symbol.js +4 -3
- package/module/timer.js +89 -31
- package/module/typedarray.js +174 -44
- package/package.json +3 -10
- package/src/analyze.js +627 -133
- package/src/autoload.js +15 -7
- package/src/compile.js +399 -70
- package/src/ctx.js +41 -12
- package/src/emit.js +658 -145
- package/src/host.js +244 -51
- package/src/ir.js +87 -31
- package/src/jzify.js +181 -24
- package/src/narrow.js +32 -4
- package/src/optimize.js +628 -42
- package/src/plan.js +1167 -4
- package/src/prepare.js +322 -75
- package/src/vectorize.js +1016 -0
- package/wasi.js +13 -0
- package/src/key.js +0 -73
- package/src/source.js +0 -76
package/module/console.js
CHANGED
|
@@ -1,48 +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 { typed, asF64 } from '../src/ir.js'
|
|
26
|
+
import { typed, asF64, asI64, mkPtrIR, NULL_NAN, UNDEF_NAN } from '../src/ir.js'
|
|
16
27
|
import { emit } from '../src/emit.js'
|
|
17
|
-
import { valTypeOf, VAL } from '../src/analyze.js'
|
|
18
|
-
import {
|
|
19
|
-
import { inc, PTR } from '../src/ctx.js'
|
|
28
|
+
import { valTypeOf, VAL, exprType } from '../src/analyze.js'
|
|
29
|
+
import { inc, PTR, LAYOUT } from '../src/ctx.js'
|
|
20
30
|
|
|
21
|
-
|
|
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) => {
|
|
22
55
|
Object.assign(ctx.core.stdlibDeps, {
|
|
23
56
|
__write_val: ['__ptr_type', '__write_str', '__write_num', '__write_int', '__write_byte', '__static_str'],
|
|
24
57
|
__write_num: ['__ftoa', '__write_str'],
|
|
25
58
|
__write_int: ['__itoa', '__mkstr', '__write_str'],
|
|
26
59
|
__write_str: ['__sso_char', '__str_len'],
|
|
60
|
+
__read_stdin: ['__mkstr'],
|
|
27
61
|
})
|
|
28
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']])
|
|
29
65
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
['import', '"wasi_snapshot_preview1"', '"fd_write"',
|
|
33
|
-
['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']])
|
|
34
68
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
ctx.core.stdlib['__write_str'] = `(func $__write_str (param $fd i32) (param $ptr f64)
|
|
38
|
-
(local $iov i32) (local $type i32) (local $len i32) (local $off i32) (local $buf i32)
|
|
39
|
-
;; 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)
|
|
40
71
|
(local.set $iov (call $__alloc (i32.const 12)))
|
|
41
|
-
(local.set $
|
|
42
|
-
(if (i32.
|
|
72
|
+
(local.set $aux (call $__ptr_aux (local.get $ptr)))
|
|
73
|
+
(if (i32.and (local.get $aux) (i32.const ${LAYOUT.SSO_BIT}))
|
|
43
74
|
(then
|
|
44
|
-
|
|
45
|
-
(local.set $len (call $__ptr_aux (local.get $ptr)))
|
|
75
|
+
(local.set $len (i32.and (local.get $aux) (i32.const 7)))
|
|
46
76
|
(local.set $buf (call $__alloc (local.get $len)))
|
|
47
77
|
(local.set $off (i32.const 0))
|
|
48
78
|
(block $done (loop $loop
|
|
@@ -54,13 +84,11 @@ export default (ctx) => {
|
|
|
54
84
|
(i32.store (local.get $iov) (local.get $buf))
|
|
55
85
|
(i32.store (i32.add (local.get $iov) (i32.const 4)) (local.get $len)))
|
|
56
86
|
(else
|
|
57
|
-
;; Heap string: offset points directly to char data
|
|
58
87
|
(i32.store (local.get $iov) (call $__ptr_offset (local.get $ptr)))
|
|
59
88
|
(i32.store (i32.add (local.get $iov) (i32.const 4)) (call $__str_len (local.get $ptr)))))
|
|
60
89
|
(drop (call $__fd_write (local.get $fd) (local.get $iov) (i32.const 1)
|
|
61
90
|
(i32.add (local.get $iov) (i32.const 8)))))`
|
|
62
91
|
|
|
63
|
-
// __write_byte(fd: i32, byte: i32) — write a single byte (space, newline)
|
|
64
92
|
ctx.core.stdlib['__write_byte'] = `(func $__write_byte (param $fd i32) (param $byte i32)
|
|
65
93
|
(local $iov i32)
|
|
66
94
|
(local.set $iov (call $__alloc (i32.const 13)))
|
|
@@ -70,72 +98,66 @@ export default (ctx) => {
|
|
|
70
98
|
(drop (call $__fd_write (local.get $fd) (local.get $iov) (i32.const 1)
|
|
71
99
|
(i32.add (local.get $iov) (i32.const 8)))))`
|
|
72
100
|
|
|
73
|
-
// __write_num(fd: i32, val: f64) — convert number to string, write to fd
|
|
74
101
|
ctx.core.stdlib['__write_num'] = `(func $__write_num (param $fd i32) (param $val f64)
|
|
75
|
-
(call $__write_str (local.get $fd) (call $__ftoa (local.get $val) (i32.const 0) (i32.const 0))))`
|
|
76
|
-
// __write_int(fd: i32, val: f64) — convert integer to string, write to fd
|
|
77
|
-
// 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)))))`
|
|
78
103
|
ctx.core.stdlib['__write_int'] = `(func $__write_int (param $fd i32) (param $val f64)
|
|
79
104
|
(local $buf i32)
|
|
80
105
|
(local.set $buf (call $__alloc (i32.const 12)))
|
|
81
106
|
(call $__write_str (local.get $fd)
|
|
82
|
-
(call $__mkstr (local.get $buf) (call $__itoa (i32.trunc_sat_f64_s (local.get $val)) (local.get $buf)))))`
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
(local $
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
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)))
|
|
90
117
|
(local.set $type (call $__ptr_type (local.get $val)))
|
|
91
118
|
(if (i32.eqz (local.get $type))
|
|
92
|
-
(then (call $__write_str (local.get $fd) (call $__static_str (i32.const 0))) (return)))
|
|
93
|
-
|
|
94
|
-
(if (i32.or (i32.eq (local.get $type) (i32.const ${PTR.STRING}))
|
|
95
|
-
(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}))
|
|
96
121
|
(then (call $__write_str (local.get $fd) (local.get $val)) (return)))
|
|
97
|
-
|
|
98
|
-
(call $__write_str (local.get $fd) (call $__static_str
|
|
122
|
+
(call $__write_str (local.get $fd) (i64.reinterpret_f64 (call $__static_str
|
|
99
123
|
(if (result i32) (i32.eq (local.get $type) (i32.const 1))
|
|
100
|
-
(then (i32.const 7)) (else (i32.const 8))))))`
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
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')
|
|
118
147
|
}
|
|
119
148
|
|
|
120
|
-
// console.log(...args) — variadic, each arg separated by space, followed by newline.
|
|
121
|
-
// Per-arg dispatch is monomorphized when valTypeOf proves the arg is a string or
|
|
122
|
-
// number — direct __write_str / __write_num skips the polymorphic __write_val
|
|
123
|
-
// helper (and its transitive __ptr_type / __static_str / number-or-string-test
|
|
124
|
-
// arms), which is the entire stdlib floor for size-conscious benches.
|
|
125
149
|
const makeConsole = (method, fd) => {
|
|
126
150
|
ctx.core.emit[`console.${method}`] = (...args) => {
|
|
151
|
+
needFdWrite()
|
|
127
152
|
inc('__write_byte')
|
|
128
153
|
const ir = []
|
|
129
154
|
const writePart = (part) => {
|
|
130
|
-
// Empty string segments (template boundaries) write nothing.
|
|
131
155
|
if (Array.isArray(part) && part[0] === 'str' && part[1] === '') return
|
|
132
156
|
const vt = valTypeOf(part)
|
|
133
157
|
if (vt === VAL.STRING) {
|
|
134
158
|
inc('__write_str')
|
|
135
|
-
ir.push(['call', '$__write_str', ['i32.const', fd],
|
|
159
|
+
ir.push(['call', '$__write_str', ['i32.const', fd], asI64(emit(part))])
|
|
136
160
|
} else if (vt === VAL.NUMBER) {
|
|
137
|
-
// Integer-valued numbers use __write_int (__itoa) instead of __write_num (__ftoa).
|
|
138
|
-
// exprType sees i32 for literals, bitwise ops, .length on arrays, Math.imul, etc.
|
|
139
161
|
if (exprType(part, ctx.func.locals) === 'i32') {
|
|
140
162
|
inc('__write_int')
|
|
141
163
|
ir.push(['call', '$__write_int', ['i32.const', fd], asF64(emit(part))])
|
|
@@ -145,17 +167,17 @@ export default (ctx) => {
|
|
|
145
167
|
}
|
|
146
168
|
} else {
|
|
147
169
|
inc('__write_val')
|
|
148
|
-
ir.push(['call', '$__write_val', ['i32.const', fd],
|
|
170
|
+
ir.push(['call', '$__write_val', ['i32.const', fd], asI64(emit(part))])
|
|
149
171
|
}
|
|
150
172
|
}
|
|
151
173
|
for (let i = 0; i < args.length; i++) {
|
|
152
|
-
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]])
|
|
153
175
|
const parts = flattenTemplateConcat(args[i])
|
|
154
176
|
if (parts) for (const p of parts) writePart(p)
|
|
155
177
|
else writePart(args[i])
|
|
156
178
|
}
|
|
157
|
-
ir.push(['call', '$__write_byte', ['i32.const', fd], ['i32.const', 10]])
|
|
158
|
-
ir.push(['f64.const', 0])
|
|
179
|
+
ir.push(['call', '$__write_byte', ['i32.const', fd], ['i32.const', 10]])
|
|
180
|
+
ir.push(['f64.const', 0])
|
|
159
181
|
return typed(['block', ['result', 'f64'], ...ir], 'f64')
|
|
160
182
|
}
|
|
161
183
|
}
|
|
@@ -164,29 +186,88 @@ export default (ctx) => {
|
|
|
164
186
|
makeConsole('warn', 2)
|
|
165
187
|
makeConsole('error', 2)
|
|
166
188
|
|
|
167
|
-
|
|
189
|
+
const needClock = () => addImportOnce(ctx, 'wasi_snapshot_preview1', 'clock_time_get',
|
|
190
|
+
['func', '$__clock_time_get', ['param', 'i32'], ['param', 'i64'], ['param', 'i32'], ['result', 'i32']])
|
|
168
191
|
|
|
169
|
-
ctx.module.imports.push(
|
|
170
|
-
['import', '"wasi_snapshot_preview1"', '"clock_time_get"',
|
|
171
|
-
['func', '$__clock_time_get', ['param', 'i32'], ['param', 'i64'], ['param', 'i32'], ['result', 'i32']]])
|
|
172
|
-
|
|
173
|
-
// __time_ms(clock_id) → f64 milliseconds
|
|
174
|
-
// clock_time_get writes i64 nanoseconds to memory, we convert to f64 ms
|
|
175
192
|
ctx.core.stdlib['__time_ms'] = `(func $__time_ms (param $clock i32) (result f64)
|
|
176
193
|
(drop (call $__clock_time_get (local.get $clock) (i64.const 1000) (i32.const 0)))
|
|
177
194
|
(f64.div (f64.convert_i64_u (i64.load (i32.const 0))) (f64.const 1000000)))`
|
|
178
195
|
|
|
179
196
|
ctx.core.emit['Date.now'] = () => {
|
|
197
|
+
needClock()
|
|
180
198
|
inc('__time_ms')
|
|
181
|
-
return typed(['call', '$__time_ms', ['i32.const', 0]], 'f64')
|
|
199
|
+
return typed(['call', '$__time_ms', ['i32.const', 0]], 'f64')
|
|
182
200
|
}
|
|
183
|
-
|
|
184
201
|
ctx.core.emit['performance.now'] = () => {
|
|
202
|
+
needClock()
|
|
185
203
|
inc('__time_ms')
|
|
186
|
-
return typed(['call', '$__time_ms', ['i32.const', 1]], 'f64')
|
|
204
|
+
return typed(['call', '$__time_ms', ['i32.const', 1]], 'f64')
|
|
187
205
|
}
|
|
206
|
+
ctx.core.emit['console.now'] = ctx.core.emit['Date.now']
|
|
207
|
+
ctx.core.emit['console.perfNow'] = ctx.core.emit['performance.now']
|
|
208
|
+
}
|
|
188
209
|
|
|
189
|
-
|
|
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
|
+
}
|
|
190
266
|
ctx.core.emit['console.now'] = ctx.core.emit['Date.now']
|
|
191
267
|
ctx.core.emit['console.perfNow'] = ctx.core.emit['performance.now']
|
|
192
268
|
}
|
|
269
|
+
|
|
270
|
+
export default (ctx) => {
|
|
271
|
+
if (ctx.transform.host === 'wasi') setupWasi(ctx)
|
|
272
|
+
else setupJsHost(ctx)
|
|
273
|
+
}
|