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