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