Skip to content

Commit d13ec52

Browse files
author
Adrian Cole
committed
Adds once mechanism for Go 1.21 GOOS=js
This adds an alternative to pooling called once. Specifically, this uses a module once per request, and in doing so supports guests who cannot export functions. The implementation adds `await_response` with adapter glue which the host side implements with Go channels. As you can see below, this is far less performant than using the pool model. However, this allows use of Go 1.21 GOOS=wasip1, which does not support pooling because it cannot export host functions. ``` Benchmark/example_log_once Benchmark/example_log_once/example_log_once Benchmark/example_log_once/example_log_once-12 52648 23117 ns/op Benchmark/example_log Benchmark/example_log/example_log Benchmark/example_log/example_log-12 2100068 550.4 ns/op ``` See golang/go#42372 Signed-off-by: Adrian Cole <[email protected]>
1 parent aa4b094 commit d13ec52

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+555
-201
lines changed

Diff for: api/handler/wasm.go

+3
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,9 @@ const (
300300
// TODO: document on http-wasm-abi
301301
FuncWriteBody = "write_body"
302302

303+
// FuncAwaitResponse TODO
304+
FuncAwaitResponse = "await_response"
305+
303306
// FuncGetStatusCode returns the status code produced by FuncNext. This
304307
// requires FeatureBufferResponse.
305308
//

Diff for: examples/log_once.wat

+72
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
;; This example module is written in WebAssembly Text Format to show the
2+
;; how a handler works when the guest compiler doesn't support function
3+
;; exports, such as GOOS=wasip1 in Go 1.21.
4+
(module $log_once
5+
6+
;; log_enabled returns 1 if the $level is enabled. This value may be cached
7+
;; at request granularity.
8+
(import "http_handler" "log_enabled" (func $log_enabled
9+
(param $level i32)
10+
(result (; 0 or enabled(1) ;) i32)))
11+
12+
;; logs a message to the host's logs at the given $level.
13+
(import "http_handler" "log" (func $log
14+
(param $level i32)
15+
(param $buf i32) (param $buf_limit i32)))
16+
17+
(; begin adapter logic
18+
19+
Below is generic and can convert any normal handler to a single synchronous
20+
call, provided $handle_request and $handle_response are not exported. ;)
21+
22+
;; import $await_response, which blocks until the response is ready.
23+
(import "http_handler" "await_response" (func $await_response
24+
(param $ctx_next i64)
25+
(result (; is_error ;) i32)))
26+
27+
;; define a start function that performs a request-response without exports.
28+
;; note: this logic is generic and can convert any exported $handle_request/
29+
;; $handle_response pair to a synchronous call without exports.
30+
(func $start
31+
(local $ctx_next i64)
32+
(local $is_error i32)
33+
(local $ctx i32)
34+
35+
;; ctxNext := handleRequest()
36+
(local.set $ctx_next (call $handle_request))
37+
38+
;; isError := awaitResponse(ctxNext())
39+
(local.set $is_error (call $await_response (local.get $ctx_next)))
40+
41+
;; expected_count = uint32(result >> 32)
42+
(local.set $ctx
43+
(i32.wrap_i64 (i64.shr_u (local.get $ctx_next) (i64.const 32))))
44+
45+
(call $handle_response (local.get $ctx) (local.get $is_error))
46+
)
47+
48+
(; end adapter logic ;)
49+
50+
(memory (export "memory") 1 1 (; 1 page==64KB ;))
51+
(global $message i32 (i32.const 0))
52+
(data (i32.const 0) "hello world")
53+
(global $message_len i32 (i32.const 11))
54+
55+
(func $handle_request (result (; ctx_next ;) i64)
56+
;; We expect debug logging to be disabled. Panic otherwise!
57+
(if (i32.eq
58+
(call $log_enabled (i32.const -1)) ;; log_level_debug
59+
(i32.const 1)) ;; true
60+
(then unreachable))
61+
62+
(call $log
63+
(i32.const 0) ;; log_level_info
64+
(global.get $message)
65+
(global.get $message_len))
66+
67+
;; uint32(ctx_next) == 1 means proceed to the next handler on the host.
68+
(return (i64.const 1)))
69+
70+
;; handle_response is no-op as this is a request-only handler.
71+
(func $handle_response (param $reqCtx i32) (param $is_error i32))
72+
)

0 commit comments

Comments
 (0)