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