Black Lives Matter. Support the Equal Justice Initiative.

Text file src/runtime/asm_wasm.s

Documentation: runtime

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

View as plain text