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