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