-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathffi.js
103 lines (91 loc) · 2.86 KB
/
ffi.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
import {
assert, ptr, dlopen, dlsym, aligned_alloc, wrap_memory,
RTLD_LAZY, RTLD_LOCAL, RTLD_NOLOAD, bind_custom,
compiler, asm, Registers
} from './lib/ffast.js'
function bind_parse (read_buf) {
if (!read_buf.ptr) ptr(read_buf)
const handle = assert(dlopen('./pico.so', 1))
const phr_parse_request_sym = assert(dlsym(handle, 'phr_parse_request2'))
const request_state_ptr = aligned_alloc(8, state_len)
const request_state = wrap_memory(request_state_ptr, state_len, 0)
const dv = new DataView(request_state)
dv.setBigUint64(0, BigInt(read_buf.ptr), true)
asm.reset()
asm.movreg(rsi, rdi)
asm.movabs(request_state_ptr, rsi)
asm.jmp(phr_parse_request_sym)
const fast_addr = compiler.compile(asm.bytes())
asm.reset()
asm.push(rbx)
asm.movreg(rdi, rbx)
// args start at offset 8 in the ffi context
asm.movsrc(rbx, rdi, 8)
asm.movabs(request_state_ptr, rsi)
asm.call(phr_parse_request_sym)
// result goes at offset 0
asm.movdest(rax, rbx, 0)
asm.pop(rbx)
asm.ret()
const slow_addr = compiler.compile(asm.bytes())
return { parse: bind_custom('i32', ['u32'], false, fast_addr, slow_addr) }
}
function bind_gettime () {
const vdso_sym = assert(dlsym(assert(dlopen('linux-vdso.so.1', RTLD_LAZY |
RTLD_LOCAL | RTLD_NOLOAD)), '__vdso_clock_gettime'))
asm.reset()
asm.movabs(CLOCK_BOOTTIME, rdi)
asm.movabs(timespec.ptr, rsi)
asm.jmp(vdso_sym)
const fast_addr = compiler.compile(asm.bytes())
asm.reset()
asm.push(rbx)
asm.movreg(rdi, rbx)
asm.movabs(CLOCK_BOOTTIME, rdi)
asm.movabs(timespec.ptr, rsi)
asm.call(vdso_sym)
asm.movdest(rax, rbx, 0)
asm.pop(rbx)
asm.ret()
const slow_addr = compiler.compile(asm.bytes())
return { gettime: bind_custom('i32', [], false, fast_addr, slow_addr) }
}
const { rdi, rsi, rbx, rax } = Registers
const num_headers = 16
const headers_size = (4 * 8 * num_headers)
const state_len = (6 * 8) + headers_size
const read_buf = ptr(new Uint8Array(16384))
const { parse } = bind_parse(read_buf)
const encoder = new TextEncoder()
const payload = encoder.encode('GET / HTTP/1.1\r\n\r\n')
read_buf.set(payload, 0)
const expected = payload.length
assert(parse(expected) === expected)
const CLOCK_BOOTTIME = 7
const timespec = ptr(new Uint32Array(4))
const { gettime } = bind_gettime()
assert(gettime() === 0)
{
const runs = 60000000
for (let i = 0; i < 5; i++) {
const start = Date.now()
for (let j = 0; j < runs; j++) {
assert(parse(expected) === expected)
}
const elapsed = Date.now() - start
const rate = Math.floor(runs / (elapsed / 1000))
console.log(`parse ${rate}`)
}
}
{
const runs = 60000000
for (let i = 0; i < 5; i++) {
const start = Date.now()
for (let j = 0; j < runs; j++) {
assert(gettime() === 0)
}
const elapsed = Date.now() - start
const rate = Math.floor(runs / (elapsed / 1000))
console.log(`gettime ${rate}`)
}
}