github.com/twelsh-aw/go/src@v0.0.0-20230516233729-a56fe86a7c81/runtime/asm_wasm.s (about)

     1  // Copyright 2018 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  #include "go_asm.h"
     6  #include "go_tls.h"
     7  #include "funcdata.h"
     8  #include "textflag.h"
     9  
    10  TEXT runtime·rt0_go(SB), NOSPLIT|NOFRAME|TOPFRAME, $0
    11  	// save m->g0 = g0
    12  	MOVD $runtime·g0(SB), runtime·m0+m_g0(SB)
    13  	// save m0 to g0->m
    14  	MOVD $runtime·m0(SB), runtime·g0+g_m(SB)
    15  	// set g to g0
    16  	MOVD $runtime·g0(SB), g
    17  	CALLNORESUME runtime·check(SB)
    18  #ifdef GOOS_js
    19  	CALLNORESUME runtime·args(SB)
    20  #endif
    21  	CALLNORESUME runtime·osinit(SB)
    22  	CALLNORESUME runtime·schedinit(SB)
    23  	MOVD $runtime·mainPC(SB), 0(SP)
    24  	CALLNORESUME runtime·newproc(SB)
    25  	CALL runtime·mstart(SB) // WebAssembly stack will unwind when switching to another goroutine
    26  	UNDEF
    27  
    28  TEXT runtime·mstart(SB),NOSPLIT|TOPFRAME,$0
    29  	CALL	runtime·mstart0(SB)
    30  	RET // not reached
    31  
    32  DATA  runtime·mainPC+0(SB)/8,$runtime·main(SB)
    33  GLOBL runtime·mainPC(SB),RODATA,$8
    34  
    35  // func checkASM() bool
    36  TEXT ·checkASM(SB), NOSPLIT, $0-1
    37  	MOVB $1, ret+0(FP)
    38  	RET
    39  
    40  TEXT runtime·gogo(SB), NOSPLIT, $0-8
    41  	MOVD buf+0(FP), R0
    42  	MOVD gobuf_g(R0), R1
    43  	MOVD 0(R1), R2	// make sure g != nil
    44  	MOVD R1, g
    45  	MOVD gobuf_sp(R0), SP
    46  
    47  	// Put target PC at -8(SP), wasm_pc_f_loop will pick it up
    48  	Get SP
    49  	I32Const $8
    50  	I32Sub
    51  	I64Load gobuf_pc(R0)
    52  	I64Store $0
    53  
    54  	MOVD gobuf_ret(R0), RET0
    55  	MOVD gobuf_ctxt(R0), CTXT
    56  	// clear to help garbage collector
    57  	MOVD $0, gobuf_sp(R0)
    58  	MOVD $0, gobuf_ret(R0)
    59  	MOVD $0, gobuf_ctxt(R0)
    60  
    61  	I32Const $1
    62  	Return
    63  
    64  // func mcall(fn func(*g))
    65  // Switch to m->g0's stack, call fn(g).
    66  // Fn must never return. It should gogo(&g->sched)
    67  // to keep running g.
    68  TEXT runtime·mcall(SB), NOSPLIT, $0-8
    69  	// CTXT = fn
    70  	MOVD fn+0(FP), CTXT
    71  	// R1 = g.m
    72  	MOVD g_m(g), R1
    73  	// R2 = g0
    74  	MOVD m_g0(R1), R2
    75  
    76  	// save state in g->sched
    77  	MOVD 0(SP), g_sched+gobuf_pc(g)     // caller's PC
    78  	MOVD $fn+0(FP), g_sched+gobuf_sp(g) // caller's SP
    79  
    80  	// if g == g0 call badmcall
    81  	Get g
    82  	Get R2
    83  	I64Eq
    84  	If
    85  		JMP runtime·badmcall(SB)
    86  	End
    87  
    88  	// switch to g0's stack
    89  	I64Load (g_sched+gobuf_sp)(R2)
    90  	I64Const $8
    91  	I64Sub
    92  	I32WrapI64
    93  	Set SP
    94  
    95  	// set arg to current g
    96  	MOVD g, 0(SP)
    97  
    98  	// switch to g0
    99  	MOVD R2, g
   100  
   101  	// call fn
   102  	Get CTXT
   103  	I32WrapI64
   104  	I64Load $0
   105  	CALL
   106  
   107  	Get SP
   108  	I32Const $8
   109  	I32Add
   110  	Set SP
   111  
   112  	JMP runtime·badmcall2(SB)
   113  
   114  // func systemstack(fn func())
   115  TEXT runtime·systemstack(SB), NOSPLIT, $0-8
   116  	// R0 = fn
   117  	MOVD fn+0(FP), R0
   118  	// R1 = g.m
   119  	MOVD g_m(g), R1
   120  	// R2 = g0
   121  	MOVD m_g0(R1), R2
   122  
   123  	// if g == g0
   124  	Get g
   125  	Get R2
   126  	I64Eq
   127  	If
   128  		// no switch:
   129  		MOVD R0, CTXT
   130  
   131  		Get CTXT
   132  		I32WrapI64
   133  		I64Load $0
   134  		JMP
   135  	End
   136  
   137  	// if g != m.curg
   138  	Get g
   139  	I64Load m_curg(R1)
   140  	I64Ne
   141  	If
   142  		CALLNORESUME runtime·badsystemstack(SB)
   143  	End
   144  
   145  	// switch:
   146  
   147  	// save state in g->sched. Pretend to
   148  	// be systemstack_switch if the G stack is scanned.
   149  	MOVD $runtime·systemstack_switch(SB), g_sched+gobuf_pc(g)
   150  
   151  	MOVD SP, g_sched+gobuf_sp(g)
   152  
   153  	// switch to g0
   154  	MOVD R2, g
   155  
   156  	// make it look like mstart called systemstack on g0, to stop traceback
   157  	I64Load (g_sched+gobuf_sp)(R2)
   158  	I64Const $8
   159  	I64Sub
   160  	Set R3
   161  
   162  	MOVD $runtime·mstart(SB), 0(R3)
   163  	MOVD R3, SP
   164  
   165  	// call fn
   166  	MOVD R0, CTXT
   167  
   168  	Get CTXT
   169  	I32WrapI64
   170  	I64Load $0
   171  	CALL
   172  
   173  	// switch back to g
   174  	MOVD g_m(g), R1
   175  	MOVD m_curg(R1), R2
   176  	MOVD R2, g
   177  	MOVD g_sched+gobuf_sp(R2), SP
   178  	MOVD $0, g_sched+gobuf_sp(R2)
   179  	RET
   180  
   181  TEXT runtime·systemstack_switch(SB), NOSPLIT, $0-0
   182  	RET
   183  
   184  // AES hashing not implemented for wasm
   185  TEXT runtime·memhash(SB),NOSPLIT|NOFRAME,$0-32
   186  	JMP	runtime·memhashFallback(SB)
   187  TEXT runtime·strhash(SB),NOSPLIT|NOFRAME,$0-24
   188  	JMP	runtime·strhashFallback(SB)
   189  TEXT runtime·memhash32(SB),NOSPLIT|NOFRAME,$0-24
   190  	JMP	runtime·memhash32Fallback(SB)
   191  TEXT runtime·memhash64(SB),NOSPLIT|NOFRAME,$0-24
   192  	JMP	runtime·memhash64Fallback(SB)
   193  
   194  TEXT runtime·return0(SB), NOSPLIT, $0-0
   195  	MOVD $0, RET0
   196  	RET
   197  
   198  TEXT runtime·asminit(SB), NOSPLIT, $0-0
   199  	// No per-thread init.
   200  	RET
   201  
   202  TEXT ·publicationBarrier(SB), NOSPLIT, $0-0
   203  	RET
   204  
   205  TEXT runtime·procyield(SB), NOSPLIT, $0-0 // FIXME
   206  	RET
   207  
   208  TEXT runtime·breakpoint(SB), NOSPLIT, $0-0
   209  	UNDEF
   210  
   211  // Called during function prolog when more stack is needed.
   212  //
   213  // The traceback routines see morestack on a g0 as being
   214  // the top of a stack (for example, morestack calling newstack
   215  // calling the scheduler calling newm calling gc), so we must
   216  // record an argument size. For that purpose, it has no arguments.
   217  TEXT runtime·morestack(SB), NOSPLIT, $0-0
   218  	// R1 = g.m
   219  	MOVD g_m(g), R1
   220  
   221  	// R2 = g0
   222  	MOVD m_g0(R1), R2
   223  
   224  	// Cannot grow scheduler stack (m->g0).
   225  	Get g
   226  	Get R1
   227  	I64Eq
   228  	If
   229  		CALLNORESUME runtime·badmorestackg0(SB)
   230  	End
   231  
   232  	// Cannot grow signal stack (m->gsignal).
   233  	Get g
   234  	I64Load m_gsignal(R1)
   235  	I64Eq
   236  	If
   237  		CALLNORESUME runtime·badmorestackgsignal(SB)
   238  	End
   239  
   240  	// Called from f.
   241  	// Set m->morebuf to f's caller.
   242  	NOP	SP	// tell vet SP changed - stop checking offsets
   243  	MOVD 8(SP), m_morebuf+gobuf_pc(R1)
   244  	MOVD $16(SP), m_morebuf+gobuf_sp(R1) // f's caller's SP
   245  	MOVD g, m_morebuf+gobuf_g(R1)
   246  
   247  	// Set g->sched to context in f.
   248  	MOVD 0(SP), g_sched+gobuf_pc(g)
   249  	MOVD $8(SP), g_sched+gobuf_sp(g) // f's SP
   250  	MOVD CTXT, g_sched+gobuf_ctxt(g)
   251  
   252  	// Call newstack on m->g0's stack.
   253  	MOVD R2, g
   254  	MOVD g_sched+gobuf_sp(R2), SP
   255  	CALL runtime·newstack(SB)
   256  	UNDEF // crash if newstack returns
   257  
   258  // morestack but not preserving ctxt.
   259  TEXT runtime·morestack_noctxt(SB),NOSPLIT,$0
   260  	MOVD $0, CTXT
   261  	JMP runtime·morestack(SB)
   262  
   263  TEXT ·asmcgocall(SB), NOSPLIT, $0-0
   264  	UNDEF
   265  
   266  #define DISPATCH(NAME, MAXSIZE) \
   267  	Get R0; \
   268  	I64Const $MAXSIZE; \
   269  	I64LeU; \
   270  	If; \
   271  		JMP NAME(SB); \
   272  	End
   273  
   274  TEXT ·reflectcall(SB), NOSPLIT, $0-48
   275  	I64Load fn+8(FP)
   276  	I64Eqz
   277  	If
   278  		CALLNORESUME runtime·sigpanic<ABIInternal>(SB)
   279  	End
   280  
   281  	MOVW frameSize+32(FP), R0
   282  
   283  	DISPATCH(runtime·call16, 16)
   284  	DISPATCH(runtime·call32, 32)
   285  	DISPATCH(runtime·call64, 64)
   286  	DISPATCH(runtime·call128, 128)
   287  	DISPATCH(runtime·call256, 256)
   288  	DISPATCH(runtime·call512, 512)
   289  	DISPATCH(runtime·call1024, 1024)
   290  	DISPATCH(runtime·call2048, 2048)
   291  	DISPATCH(runtime·call4096, 4096)
   292  	DISPATCH(runtime·call8192, 8192)
   293  	DISPATCH(runtime·call16384, 16384)
   294  	DISPATCH(runtime·call32768, 32768)
   295  	DISPATCH(runtime·call65536, 65536)
   296  	DISPATCH(runtime·call131072, 131072)
   297  	DISPATCH(runtime·call262144, 262144)
   298  	DISPATCH(runtime·call524288, 524288)
   299  	DISPATCH(runtime·call1048576, 1048576)
   300  	DISPATCH(runtime·call2097152, 2097152)
   301  	DISPATCH(runtime·call4194304, 4194304)
   302  	DISPATCH(runtime·call8388608, 8388608)
   303  	DISPATCH(runtime·call16777216, 16777216)
   304  	DISPATCH(runtime·call33554432, 33554432)
   305  	DISPATCH(runtime·call67108864, 67108864)
   306  	DISPATCH(runtime·call134217728, 134217728)
   307  	DISPATCH(runtime·call268435456, 268435456)
   308  	DISPATCH(runtime·call536870912, 536870912)
   309  	DISPATCH(runtime·call1073741824, 1073741824)
   310  	JMP runtime·badreflectcall(SB)
   311  
   312  #define CALLFN(NAME, MAXSIZE) \
   313  TEXT NAME(SB), WRAPPER, $MAXSIZE-48; \
   314  	NO_LOCAL_POINTERS; \
   315  	MOVW stackArgsSize+24(FP), R0; \
   316  	\
   317  	Get R0; \
   318  	I64Eqz; \
   319  	Not; \
   320  	If; \
   321  		Get SP; \
   322  		I64Load stackArgs+16(FP); \
   323  		I32WrapI64; \
   324  		I64Load stackArgsSize+24(FP); \
   325  		I32WrapI64; \
   326  		MemoryCopy; \
   327  	End; \
   328  	\
   329  	MOVD f+8(FP), CTXT; \
   330  	Get CTXT; \
   331  	I32WrapI64; \
   332  	I64Load $0; \
   333  	CALL; \
   334  	\
   335  	I64Load32U stackRetOffset+28(FP); \
   336  	Set R0; \
   337  	\
   338  	MOVD stackArgsType+0(FP), RET0; \
   339  	\
   340  	I64Load stackArgs+16(FP); \
   341  	Get R0; \
   342  	I64Add; \
   343  	Set RET1; \
   344  	\
   345  	Get SP; \
   346  	I64ExtendI32U; \
   347  	Get R0; \
   348  	I64Add; \
   349  	Set RET2; \
   350  	\
   351  	I64Load32U stackArgsSize+24(FP); \
   352  	Get R0; \
   353  	I64Sub; \
   354  	Set RET3; \
   355  	\
   356  	CALL callRet<>(SB); \
   357  	RET
   358  
   359  // callRet copies return values back at the end of call*. This is a
   360  // separate function so it can allocate stack space for the arguments
   361  // to reflectcallmove. It does not follow the Go ABI; it expects its
   362  // arguments in registers.
   363  TEXT callRet<>(SB), NOSPLIT, $40-0
   364  	NO_LOCAL_POINTERS
   365  	MOVD RET0, 0(SP)
   366  	MOVD RET1, 8(SP)
   367  	MOVD RET2, 16(SP)
   368  	MOVD RET3, 24(SP)
   369  	MOVD $0,   32(SP)
   370  	CALL runtime·reflectcallmove(SB)
   371  	RET
   372  
   373  CALLFN(·call16, 16)
   374  CALLFN(·call32, 32)
   375  CALLFN(·call64, 64)
   376  CALLFN(·call128, 128)
   377  CALLFN(·call256, 256)
   378  CALLFN(·call512, 512)
   379  CALLFN(·call1024, 1024)
   380  CALLFN(·call2048, 2048)
   381  CALLFN(·call4096, 4096)
   382  CALLFN(·call8192, 8192)
   383  CALLFN(·call16384, 16384)
   384  CALLFN(·call32768, 32768)
   385  CALLFN(·call65536, 65536)
   386  CALLFN(·call131072, 131072)
   387  CALLFN(·call262144, 262144)
   388  CALLFN(·call524288, 524288)
   389  CALLFN(·call1048576, 1048576)
   390  CALLFN(·call2097152, 2097152)
   391  CALLFN(·call4194304, 4194304)
   392  CALLFN(·call8388608, 8388608)
   393  CALLFN(·call16777216, 16777216)
   394  CALLFN(·call33554432, 33554432)
   395  CALLFN(·call67108864, 67108864)
   396  CALLFN(·call134217728, 134217728)
   397  CALLFN(·call268435456, 268435456)
   398  CALLFN(·call536870912, 536870912)
   399  CALLFN(·call1073741824, 1073741824)
   400  
   401  TEXT runtime·goexit(SB), NOSPLIT|TOPFRAME, $0-0
   402  	NOP // first PC of goexit is skipped
   403  	CALL runtime·goexit1(SB) // does not return
   404  	UNDEF
   405  
   406  TEXT runtime·cgocallback(SB), NOSPLIT, $0-24
   407  	UNDEF
   408  
   409  // gcWriteBarrier informs the GC about heap pointer writes.
   410  //
   411  // gcWriteBarrier does NOT follow the Go ABI. It accepts the
   412  // number of bytes of buffer needed as a wasm argument
   413  // (put on the TOS by the caller, lives in local R0 in this body)
   414  // and returns a pointer to the buffer space as a wasm result
   415  // (left on the TOS in this body, appears on the wasm stack
   416  // in the caller).
   417  TEXT gcWriteBarrier<>(SB), NOSPLIT, $0
   418  	Loop
   419  		// R3 = g.m
   420  		MOVD g_m(g), R3
   421  		// R4 = p
   422  		MOVD m_p(R3), R4
   423  		// R5 = wbBuf.next
   424  		MOVD p_wbBuf+wbBuf_next(R4), R5
   425  
   426  		// Increment wbBuf.next
   427  		Get R5
   428  		Get R0
   429  		I64Add
   430  		Set R5
   431  
   432  		// Is the buffer full?
   433  		Get R5
   434  		I64Load (p_wbBuf+wbBuf_end)(R4)
   435  		I64LeU
   436  		If
   437  			// Commit to the larger buffer.
   438  			MOVD R5, p_wbBuf+wbBuf_next(R4)
   439  
   440  			// Make return value (the original next position)
   441  			Get R5
   442  			Get R0
   443  			I64Sub
   444  
   445  			Return
   446  		End
   447  
   448  		// Flush
   449  		CALLNORESUME runtime·wbBufFlush(SB)
   450  
   451  		// Retry
   452  		Br $0
   453  	End
   454  
   455  TEXT runtime·gcWriteBarrier1<ABIInternal>(SB),NOSPLIT,$0
   456  	I64Const $8
   457  	Call	gcWriteBarrier<>(SB)
   458  	Return
   459  TEXT runtime·gcWriteBarrier2<ABIInternal>(SB),NOSPLIT,$0
   460  	I64Const $16
   461  	Call	gcWriteBarrier<>(SB)
   462  	Return
   463  TEXT runtime·gcWriteBarrier3<ABIInternal>(SB),NOSPLIT,$0
   464  	I64Const $24
   465  	Call	gcWriteBarrier<>(SB)
   466  	Return
   467  TEXT runtime·gcWriteBarrier4<ABIInternal>(SB),NOSPLIT,$0
   468  	I64Const $32
   469  	Call	gcWriteBarrier<>(SB)
   470  	Return
   471  TEXT runtime·gcWriteBarrier5<ABIInternal>(SB),NOSPLIT,$0
   472  	I64Const $40
   473  	Call	gcWriteBarrier<>(SB)
   474  	Return
   475  TEXT runtime·gcWriteBarrier6<ABIInternal>(SB),NOSPLIT,$0
   476  	I64Const $48
   477  	Call	gcWriteBarrier<>(SB)
   478  	Return
   479  TEXT runtime·gcWriteBarrier7<ABIInternal>(SB),NOSPLIT,$0
   480  	I64Const $56
   481  	Call	gcWriteBarrier<>(SB)
   482  	Return
   483  TEXT runtime·gcWriteBarrier8<ABIInternal>(SB),NOSPLIT,$0
   484  	I64Const $64
   485  	Call	gcWriteBarrier<>(SB)
   486  	Return
   487  
   488  TEXT wasm_pc_f_loop(SB),NOSPLIT,$0
   489  // Call the function for the current PC_F. Repeat until PAUSE != 0 indicates pause or exit.
   490  // The WebAssembly stack may unwind, e.g. when switching goroutines.
   491  // The Go stack on the linear memory is then used to jump to the correct functions
   492  // with this loop, without having to restore the full WebAssembly stack.
   493  // It is expected to have a pending call before entering the loop, so check PAUSE first.
   494  	Get PAUSE
   495  	I32Eqz
   496  	If
   497  	loop:
   498  		Loop
   499  			// Get PC_B & PC_F from -8(SP)
   500  			Get SP
   501  			I32Const $8
   502  			I32Sub
   503  			I32Load16U $0 // PC_B
   504  
   505  			Get SP
   506  			I32Const $8
   507  			I32Sub
   508  			I32Load16U $2 // PC_F
   509  
   510  			CallIndirect $0
   511  			Drop
   512  
   513  			Get PAUSE
   514  			I32Eqz
   515  			BrIf loop
   516  		End
   517  	End
   518  
   519  	I32Const $0
   520  	Set PAUSE
   521  
   522  	Return
   523  
   524  TEXT wasm_export_lib(SB),NOSPLIT,$0
   525  	UNDEF