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