...

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
    10TEXT 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
    28TEXT runtime·mstart(SB),NOSPLIT|TOPFRAME,$0
    29	CALL	runtime·mstart0(SB)
    30	RET // not reached
    31
    32DATA  runtime·mainPC+0(SB)/8,$runtime·main(SB)
    33GLOBL runtime·mainPC(SB),RODATA,$8
    34
    35// func checkASM() bool
    36TEXT ·checkASM(SB), NOSPLIT, $0-1
    37	MOVB $1, ret+0(FP)
    38	RET
    39
    40TEXT 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.
    68TEXT 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())
   115TEXT 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		CALLNORESUME runtime·abort(SB)
   144	End
   145
   146	// switch:
   147
   148	// save state in g->sched. Pretend to
   149	// be systemstack_switch if the G stack is scanned.
   150	MOVD $runtime·systemstack_switch(SB), g_sched+gobuf_pc(g)
   151
   152	MOVD SP, g_sched+gobuf_sp(g)
   153
   154	// switch to g0
   155	MOVD R2, g
   156
   157	// make it look like mstart called systemstack on g0, to stop traceback
   158	I64Load (g_sched+gobuf_sp)(R2)
   159	I64Const $8
   160	I64Sub
   161	Set R3
   162
   163	MOVD $runtime·mstart(SB), 0(R3)
   164	MOVD R3, SP
   165
   166	// call fn
   167	MOVD R0, CTXT
   168
   169	Get CTXT
   170	I32WrapI64
   171	I64Load $0
   172	CALL
   173
   174	// switch back to g
   175	MOVD g_m(g), R1
   176	MOVD m_curg(R1), R2
   177	MOVD R2, g
   178	MOVD g_sched+gobuf_sp(R2), SP
   179	MOVD $0, g_sched+gobuf_sp(R2)
   180	RET
   181
   182TEXT runtime·systemstack_switch(SB), NOSPLIT, $0-0
   183	RET
   184
   185TEXT runtime·abort(SB),NOSPLIT|NOFRAME,$0-0
   186	UNDEF
   187
   188// AES hashing not implemented for wasm
   189TEXT runtime·memhash(SB),NOSPLIT|NOFRAME,$0-32
   190	JMP	runtime·memhashFallback(SB)
   191TEXT runtime·strhash(SB),NOSPLIT|NOFRAME,$0-24
   192	JMP	runtime·strhashFallback(SB)
   193TEXT runtime·memhash32(SB),NOSPLIT|NOFRAME,$0-24
   194	JMP	runtime·memhash32Fallback(SB)
   195TEXT runtime·memhash64(SB),NOSPLIT|NOFRAME,$0-24
   196	JMP	runtime·memhash64Fallback(SB)
   197
   198TEXT runtime·return0(SB), NOSPLIT, $0-0
   199	MOVD $0, RET0
   200	RET
   201
   202TEXT runtime·asminit(SB), NOSPLIT, $0-0
   203	// No per-thread init.
   204	RET
   205
   206TEXT ·publicationBarrier(SB), NOSPLIT, $0-0
   207	RET
   208
   209TEXT runtime·procyield(SB), NOSPLIT, $0-0 // FIXME
   210	RET
   211
   212TEXT runtime·breakpoint(SB), NOSPLIT, $0-0
   213	UNDEF
   214
   215// func switchToCrashStack0(fn func())
   216TEXT runtime·switchToCrashStack0(SB), NOSPLIT, $0-8
   217	MOVD fn+0(FP), CTXT	// context register
   218	MOVD	g_m(g), R2	// curm
   219
   220	// set g to gcrash
   221	MOVD	$runtime·gcrash(SB), g	// g = &gcrash
   222	MOVD	R2, g_m(g)	// g.m = curm
   223	MOVD	g, m_g0(R2)	// curm.g0 = g
   224
   225	// switch to crashstack
   226	I64Load (g_stack+stack_hi)(g)
   227	I64Const $(-4*8)
   228	I64Add
   229	I32WrapI64
   230	Set SP
   231
   232	// call target function
   233	Get CTXT
   234	I32WrapI64
   235	I64Load $0
   236	CALL
   237
   238	// should never return
   239	CALL	runtime·abort(SB)
   240	UNDEF
   241
   242// Called during function prolog when more stack is needed.
   243//
   244// The traceback routines see morestack on a g0 as being
   245// the top of a stack (for example, morestack calling newstack
   246// calling the scheduler calling newm calling gc), so we must
   247// record an argument size. For that purpose, it has no arguments.
   248TEXT runtime·morestack(SB), NOSPLIT, $0-0
   249	// R1 = g.m
   250	MOVD g_m(g), R1
   251
   252	// R2 = g0
   253	MOVD m_g0(R1), R2
   254
   255	// Set g->sched to context in f.
   256	NOP	SP	// tell vet SP changed - stop checking offsets
   257	MOVD 0(SP), g_sched+gobuf_pc(g)
   258	MOVD $8(SP), g_sched+gobuf_sp(g) // f's SP
   259	MOVD CTXT, g_sched+gobuf_ctxt(g)
   260
   261	// Cannot grow scheduler stack (m->g0).
   262	Get g
   263	Get R2
   264	I64Eq
   265	If
   266		CALLNORESUME runtime·badmorestackg0(SB)
   267		CALLNORESUME runtime·abort(SB)
   268	End
   269
   270	// Cannot grow signal stack (m->gsignal).
   271	Get g
   272	I64Load m_gsignal(R1)
   273	I64Eq
   274	If
   275		CALLNORESUME runtime·badmorestackgsignal(SB)
   276		CALLNORESUME runtime·abort(SB)
   277	End
   278
   279	// Called from f.
   280	// Set m->morebuf to f's caller.
   281	MOVD 8(SP), m_morebuf+gobuf_pc(R1)
   282	MOVD $16(SP), m_morebuf+gobuf_sp(R1) // f's caller's SP
   283	MOVD g, m_morebuf+gobuf_g(R1)
   284
   285	// Call newstack on m->g0's stack.
   286	MOVD R2, g
   287	MOVD g_sched+gobuf_sp(R2), SP
   288	CALL runtime·newstack(SB)
   289	UNDEF // crash if newstack returns
   290
   291// morestack but not preserving ctxt.
   292TEXT runtime·morestack_noctxt(SB),NOSPLIT,$0
   293	MOVD $0, CTXT
   294	JMP runtime·morestack(SB)
   295
   296TEXT ·asmcgocall(SB), NOSPLIT, $0-0
   297	UNDEF
   298
   299#define DISPATCH(NAME, MAXSIZE) \
   300	Get R0; \
   301	I64Const $MAXSIZE; \
   302	I64LeU; \
   303	If; \
   304		JMP NAME(SB); \
   305	End
   306
   307TEXT ·reflectcall(SB), NOSPLIT, $0-48
   308	I64Load fn+8(FP)
   309	I64Eqz
   310	If
   311		CALLNORESUME runtime·sigpanic<ABIInternal>(SB)
   312	End
   313
   314	MOVW frameSize+32(FP), R0
   315
   316	DISPATCH(runtime·call16, 16)
   317	DISPATCH(runtime·call32, 32)
   318	DISPATCH(runtime·call64, 64)
   319	DISPATCH(runtime·call128, 128)
   320	DISPATCH(runtime·call256, 256)
   321	DISPATCH(runtime·call512, 512)
   322	DISPATCH(runtime·call1024, 1024)
   323	DISPATCH(runtime·call2048, 2048)
   324	DISPATCH(runtime·call4096, 4096)
   325	DISPATCH(runtime·call8192, 8192)
   326	DISPATCH(runtime·call16384, 16384)
   327	DISPATCH(runtime·call32768, 32768)
   328	DISPATCH(runtime·call65536, 65536)
   329	DISPATCH(runtime·call131072, 131072)
   330	DISPATCH(runtime·call262144, 262144)
   331	DISPATCH(runtime·call524288, 524288)
   332	DISPATCH(runtime·call1048576, 1048576)
   333	DISPATCH(runtime·call2097152, 2097152)
   334	DISPATCH(runtime·call4194304, 4194304)
   335	DISPATCH(runtime·call8388608, 8388608)
   336	DISPATCH(runtime·call16777216, 16777216)
   337	DISPATCH(runtime·call33554432, 33554432)
   338	DISPATCH(runtime·call67108864, 67108864)
   339	DISPATCH(runtime·call134217728, 134217728)
   340	DISPATCH(runtime·call268435456, 268435456)
   341	DISPATCH(runtime·call536870912, 536870912)
   342	DISPATCH(runtime·call1073741824, 1073741824)
   343	JMP runtime·badreflectcall(SB)
   344
   345#define CALLFN(NAME, MAXSIZE) \
   346TEXT NAME(SB), WRAPPER, $MAXSIZE-48; \
   347	NO_LOCAL_POINTERS; \
   348	MOVW stackArgsSize+24(FP), R0; \
   349	\
   350	Get R0; \
   351	I64Eqz; \
   352	Not; \
   353	If; \
   354		Get SP; \
   355		I64Load stackArgs+16(FP); \
   356		I32WrapI64; \
   357		I64Load stackArgsSize+24(FP); \
   358		I32WrapI64; \
   359		MemoryCopy; \
   360	End; \
   361	\
   362	MOVD f+8(FP), CTXT; \
   363	Get CTXT; \
   364	I32WrapI64; \
   365	I64Load $0; \
   366	CALL; \
   367	\
   368	I64Load32U stackRetOffset+28(FP); \
   369	Set R0; \
   370	\
   371	MOVD stackArgsType+0(FP), RET0; \
   372	\
   373	I64Load stackArgs+16(FP); \
   374	Get R0; \
   375	I64Add; \
   376	Set RET1; \
   377	\
   378	Get SP; \
   379	I64ExtendI32U; \
   380	Get R0; \
   381	I64Add; \
   382	Set RET2; \
   383	\
   384	I64Load32U stackArgsSize+24(FP); \
   385	Get R0; \
   386	I64Sub; \
   387	Set RET3; \
   388	\
   389	CALL callRet<>(SB); \
   390	RET
   391
   392// callRet copies return values back at the end of call*. This is a
   393// separate function so it can allocate stack space for the arguments
   394// to reflectcallmove. It does not follow the Go ABI; it expects its
   395// arguments in registers.
   396TEXT callRet<>(SB), NOSPLIT, $40-0
   397	NO_LOCAL_POINTERS
   398	MOVD RET0, 0(SP)
   399	MOVD RET1, 8(SP)
   400	MOVD RET2, 16(SP)
   401	MOVD RET3, 24(SP)
   402	MOVD $0,   32(SP)
   403	CALL runtime·reflectcallmove(SB)
   404	RET
   405
   406CALLFN(·call16, 16)
   407CALLFN(·call32, 32)
   408CALLFN(·call64, 64)
   409CALLFN(·call128, 128)
   410CALLFN(·call256, 256)
   411CALLFN(·call512, 512)
   412CALLFN(·call1024, 1024)
   413CALLFN(·call2048, 2048)
   414CALLFN(·call4096, 4096)
   415CALLFN(·call8192, 8192)
   416CALLFN(·call16384, 16384)
   417CALLFN(·call32768, 32768)
   418CALLFN(·call65536, 65536)
   419CALLFN(·call131072, 131072)
   420CALLFN(·call262144, 262144)
   421CALLFN(·call524288, 524288)
   422CALLFN(·call1048576, 1048576)
   423CALLFN(·call2097152, 2097152)
   424CALLFN(·call4194304, 4194304)
   425CALLFN(·call8388608, 8388608)
   426CALLFN(·call16777216, 16777216)
   427CALLFN(·call33554432, 33554432)
   428CALLFN(·call67108864, 67108864)
   429CALLFN(·call134217728, 134217728)
   430CALLFN(·call268435456, 268435456)
   431CALLFN(·call536870912, 536870912)
   432CALLFN(·call1073741824, 1073741824)
   433
   434TEXT runtime·goexit(SB), NOSPLIT|TOPFRAME, $0-0
   435	NOP // first PC of goexit is skipped
   436	CALL runtime·goexit1(SB) // does not return
   437	UNDEF
   438
   439TEXT runtime·cgocallback(SB), NOSPLIT, $0-24
   440	UNDEF
   441
   442// gcWriteBarrier informs the GC about heap pointer writes.
   443//
   444// gcWriteBarrier does NOT follow the Go ABI. It accepts the
   445// number of bytes of buffer needed as a wasm argument
   446// (put on the TOS by the caller, lives in local R0 in this body)
   447// and returns a pointer to the buffer space as a wasm result
   448// (left on the TOS in this body, appears on the wasm stack
   449// in the caller).
   450TEXT gcWriteBarrier<>(SB), NOSPLIT, $0
   451	Loop
   452		// R3 = g.m
   453		MOVD g_m(g), R3
   454		// R4 = p
   455		MOVD m_p(R3), R4
   456		// R5 = wbBuf.next
   457		MOVD p_wbBuf+wbBuf_next(R4), R5
   458
   459		// Increment wbBuf.next
   460		Get R5
   461		Get R0
   462		I64Add
   463		Set R5
   464
   465		// Is the buffer full?
   466		Get R5
   467		I64Load (p_wbBuf+wbBuf_end)(R4)
   468		I64LeU
   469		If
   470			// Commit to the larger buffer.
   471			MOVD R5, p_wbBuf+wbBuf_next(R4)
   472
   473			// Make return value (the original next position)
   474			Get R5
   475			Get R0
   476			I64Sub
   477
   478			Return
   479		End
   480
   481		// Flush
   482		CALLNORESUME runtime·wbBufFlush(SB)
   483
   484		// Retry
   485		Br $0
   486	End
   487
   488TEXT runtime·gcWriteBarrier1<ABIInternal>(SB),NOSPLIT,$0
   489	I64Const $8
   490	Call	gcWriteBarrier<>(SB)
   491	Return
   492TEXT runtime·gcWriteBarrier2<ABIInternal>(SB),NOSPLIT,$0
   493	I64Const $16
   494	Call	gcWriteBarrier<>(SB)
   495	Return
   496TEXT runtime·gcWriteBarrier3<ABIInternal>(SB),NOSPLIT,$0
   497	I64Const $24
   498	Call	gcWriteBarrier<>(SB)
   499	Return
   500TEXT runtime·gcWriteBarrier4<ABIInternal>(SB),NOSPLIT,$0
   501	I64Const $32
   502	Call	gcWriteBarrier<>(SB)
   503	Return
   504TEXT runtime·gcWriteBarrier5<ABIInternal>(SB),NOSPLIT,$0
   505	I64Const $40
   506	Call	gcWriteBarrier<>(SB)
   507	Return
   508TEXT runtime·gcWriteBarrier6<ABIInternal>(SB),NOSPLIT,$0
   509	I64Const $48
   510	Call	gcWriteBarrier<>(SB)
   511	Return
   512TEXT runtime·gcWriteBarrier7<ABIInternal>(SB),NOSPLIT,$0
   513	I64Const $56
   514	Call	gcWriteBarrier<>(SB)
   515	Return
   516TEXT runtime·gcWriteBarrier8<ABIInternal>(SB),NOSPLIT,$0
   517	I64Const $64
   518	Call	gcWriteBarrier<>(SB)
   519	Return
   520
   521TEXT wasm_pc_f_loop(SB),NOSPLIT,$0
   522// Call the function for the current PC_F. Repeat until PAUSE != 0 indicates pause or exit.
   523// The WebAssembly stack may unwind, e.g. when switching goroutines.
   524// The Go stack on the linear memory is then used to jump to the correct functions
   525// with this loop, without having to restore the full WebAssembly stack.
   526// It is expected to have a pending call before entering the loop, so check PAUSE first.
   527	Get PAUSE
   528	I32Eqz
   529	If
   530	loop:
   531		Loop
   532			// Get PC_B & PC_F from -8(SP)
   533			Get SP
   534			I32Const $8
   535			I32Sub
   536			I32Load16U $0 // PC_B
   537
   538			Get SP
   539			I32Const $8
   540			I32Sub
   541			I32Load16U $2 // PC_F
   542
   543			CallIndirect $0
   544			Drop
   545
   546			Get PAUSE
   547			I32Eqz
   548			BrIf loop
   549		End
   550	End
   551
   552	I32Const $0
   553	Set PAUSE
   554
   555	Return
   556
   557TEXT wasm_export_lib(SB),NOSPLIT,$0
   558	UNDEF

View as plain text