Text file src/runtime/asm_wasm.s

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

View as plain text