github.com/primecitizens/pcz/std@v0.2.1/ffi/js/callback_js_wasm.s (about) 1 // SPDX-License-Identifier: Apache-2.0 2 // Copyright 2023 The Prime Citizens 3 4 //go:build !noos && js && wasm 5 6 #include "textflag.h" 7 8 // wasm_export_run has wasm signature of (argc i32, argv i32) -> () 9 // 10 // it gets called from JavaScript. 11 // 12 // In the official go std, it is the entrypoint of the js/wasm program. 13 // But in pcz, it is used to handle callbacks. 14 // 15 // R0: argc (i32), heap.Ref<CallbackContext>, if 0, continue paused execution. 16 // R1: argv (i32), optional SP. 17 TEXT wasm_export_run(SB),NOSPLIT|NOFRAME,$0 18 Get R1 19 I32Eqz 20 Not 21 If 22 Get R1 23 Set SP 24 End 25 26 Get R0 27 I32Eqz 28 If 29 // the program is awaiting. 30 Call wasm_pc_f_loop(SB) 31 Return 32 End 33 34 // prepare arg ctx and pLR for handleCallback 35 Get SP 36 I32Const $16 // 8 bytes for args, 8 bytes for LR 37 I32Sub 38 Set SP 39 40 Get SP 41 Get R0 42 I64ExtendI32U 43 I64Store32 $8 // 8(SP) = R0 (= ref ctx) 44 45 Get SP 46 I64Const $wasm_pc_f_loop(SB) 47 I64Store // LR 48 49 I32Const $0 50 Call ·handleCallback(SB) 51 If 52 // the callback issued awaiting, return immediately as PAUSE is set to 1. 53 Return 54 End 55 56 // only loop for async callback, synchronous callbacks (go -> js -> go) 57 // are expected to resume the program on its own. 58 Get PAUSE 59 If 60 Call wasm_pc_f_loop(SB) 61 Else 62 // pop args for `Call ·handleCallback(SB)` (LR already poped by it) 63 Get SP 64 I32Const $8 65 I32Add 66 Set SP 67 End 68 69 Return 70 71 // wasm_pc_f_loop has wasm signature of () -> () 72 // 73 // NOTE: this function is different from the `wasm_pc_f_loop` found in 74 // the standard go runtime. 75 TEXT wasm_pc_f_loop(SB),NOSPLIT|NOFRAME,$0 76 I32Const $0 77 Set PAUSE 78 79 loop: 80 Loop 81 Get SP 82 I32Const $8 83 I32Sub 84 I64Load $0 85 I64Const $wasm_pc_f_loop(SB) 86 I64Eq 87 If 88 // reached end of the loop (callback done), pop the LR and return. 89 Get SP 90 I32Const $8 91 I32Add 92 Set SP 93 94 Return 95 End 96 97 // Get PC_B & PC_F from -8(SP) 98 Get SP 99 I32Const $8 100 I32Sub 101 I32Load16U $0 // PC_B 102 103 Get SP 104 I32Const $8 105 I32Sub 106 I32Load16U $2 // PC_F 107 108 CallIndirect $0 109 I32Eqz 110 BrIf loop 111 End 112 113 Return 114 115 // wasm_export_getsp gets called from JavaScript to retrieve the SP. 116 TEXT wasm_export_getsp(SB),NOSPLIT|NOFRAME,$0 117 Get SP 118 Return 119 120 // func callDispatcher(recv, targetPC uintptr, ctx *CallbackContext, fn uintptr) 121 TEXT ·callDispatcher(SB),NOSPLIT|NOFRAME|TOPFRAME,$0-32 122 skip: 123 Block // $2 124 done: 125 Block // $1 126 entry: 127 Block // $0 128 // TODO(BrTable): currently go asm doesn't support BrTable in assembly text 129 // but emits BrTable automatically. 130 Get PC_B 131 I32Eqz 132 BrIf entry 133 134 Get PC_B 135 I32Const $1 136 I32Eq 137 BrIf done 138 139 Get PC_B 140 I32Const $2 141 I32Eq 142 BrIf skip 143 End // $0 144 145 Get SP 146 I64Const $·callDispatcher+1(SB) 147 I64Store // LR 148 149 I32Const $0 // PC_B 150 151 I64Load 32(SP) // PC = (8/* LR */ + 24 /* offset to last arg fn */)(SP) 152 I32WrapI64 153 I32Const $16 154 I32ShrU // PC_F 155 156 CallIndirect $0 157 BrIf skip 158 End // $1 159 160 // A callback can only be dispatched once, change LR to FIXUP 161 // in handleCallback 162 // so wasm_pc_f_loop doesnt't loop indefinitely 163 Get SP 164 I32Const $8 165 I32Sub 166 // TODO: is there a way to get resume point in go code? 167 // currently we have to compile and dump the assembly to find target 168 // PC_B: 169 // Block_7 (from inner most to out most) calling cb.resolveFn 170 // PC_B = 16 (index of Block_7 in the BrTable). 171 I64Const $·handleCallback+16(SB) 172 I64Store // LR 173 174 I32Const $0 175 Return 176 End // $2 177 178 I32Const $1 179 Return