...

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

View as plain text