github.com/twelsh-aw/go/src@v0.0.0-20230516233729-a56fe86a7c81/runtime/asm_wasm.s (about) 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 // func checkASM() bool 36 TEXT ·checkASM(SB), NOSPLIT, $0-1 37 MOVB $1, ret+0(FP) 38 RET 39 40 TEXT 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. 68 TEXT 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()) 115 TEXT 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 End 144 145 // switch: 146 147 // save state in g->sched. Pretend to 148 // be systemstack_switch if the G stack is scanned. 149 MOVD $runtime·systemstack_switch(SB), g_sched+gobuf_pc(g) 150 151 MOVD SP, g_sched+gobuf_sp(g) 152 153 // switch to g0 154 MOVD R2, g 155 156 // make it look like mstart called systemstack on g0, to stop traceback 157 I64Load (g_sched+gobuf_sp)(R2) 158 I64Const $8 159 I64Sub 160 Set R3 161 162 MOVD $runtime·mstart(SB), 0(R3) 163 MOVD R3, SP 164 165 // call fn 166 MOVD R0, CTXT 167 168 Get CTXT 169 I32WrapI64 170 I64Load $0 171 CALL 172 173 // switch back to g 174 MOVD g_m(g), R1 175 MOVD m_curg(R1), R2 176 MOVD R2, g 177 MOVD g_sched+gobuf_sp(R2), SP 178 MOVD $0, g_sched+gobuf_sp(R2) 179 RET 180 181 TEXT runtime·systemstack_switch(SB), NOSPLIT, $0-0 182 RET 183 184 // AES hashing not implemented for wasm 185 TEXT runtime·memhash(SB),NOSPLIT|NOFRAME,$0-32 186 JMP runtime·memhashFallback(SB) 187 TEXT runtime·strhash(SB),NOSPLIT|NOFRAME,$0-24 188 JMP runtime·strhashFallback(SB) 189 TEXT runtime·memhash32(SB),NOSPLIT|NOFRAME,$0-24 190 JMP runtime·memhash32Fallback(SB) 191 TEXT runtime·memhash64(SB),NOSPLIT|NOFRAME,$0-24 192 JMP runtime·memhash64Fallback(SB) 193 194 TEXT runtime·return0(SB), NOSPLIT, $0-0 195 MOVD $0, RET0 196 RET 197 198 TEXT runtime·asminit(SB), NOSPLIT, $0-0 199 // No per-thread init. 200 RET 201 202 TEXT ·publicationBarrier(SB), NOSPLIT, $0-0 203 RET 204 205 TEXT runtime·procyield(SB), NOSPLIT, $0-0 // FIXME 206 RET 207 208 TEXT runtime·breakpoint(SB), NOSPLIT, $0-0 209 UNDEF 210 211 // Called during function prolog when more stack is needed. 212 // 213 // The traceback routines see morestack on a g0 as being 214 // the top of a stack (for example, morestack calling newstack 215 // calling the scheduler calling newm calling gc), so we must 216 // record an argument size. For that purpose, it has no arguments. 217 TEXT runtime·morestack(SB), NOSPLIT, $0-0 218 // R1 = g.m 219 MOVD g_m(g), R1 220 221 // R2 = g0 222 MOVD m_g0(R1), R2 223 224 // Cannot grow scheduler stack (m->g0). 225 Get g 226 Get R1 227 I64Eq 228 If 229 CALLNORESUME runtime·badmorestackg0(SB) 230 End 231 232 // Cannot grow signal stack (m->gsignal). 233 Get g 234 I64Load m_gsignal(R1) 235 I64Eq 236 If 237 CALLNORESUME runtime·badmorestackgsignal(SB) 238 End 239 240 // Called from f. 241 // Set m->morebuf to f's caller. 242 NOP SP // tell vet SP changed - stop checking offsets 243 MOVD 8(SP), m_morebuf+gobuf_pc(R1) 244 MOVD $16(SP), m_morebuf+gobuf_sp(R1) // f's caller's SP 245 MOVD g, m_morebuf+gobuf_g(R1) 246 247 // Set g->sched to context in f. 248 MOVD 0(SP), g_sched+gobuf_pc(g) 249 MOVD $8(SP), g_sched+gobuf_sp(g) // f's SP 250 MOVD CTXT, g_sched+gobuf_ctxt(g) 251 252 // Call newstack on m->g0's stack. 253 MOVD R2, g 254 MOVD g_sched+gobuf_sp(R2), SP 255 CALL runtime·newstack(SB) 256 UNDEF // crash if newstack returns 257 258 // morestack but not preserving ctxt. 259 TEXT runtime·morestack_noctxt(SB),NOSPLIT,$0 260 MOVD $0, CTXT 261 JMP runtime·morestack(SB) 262 263 TEXT ·asmcgocall(SB), NOSPLIT, $0-0 264 UNDEF 265 266 #define DISPATCH(NAME, MAXSIZE) \ 267 Get R0; \ 268 I64Const $MAXSIZE; \ 269 I64LeU; \ 270 If; \ 271 JMP NAME(SB); \ 272 End 273 274 TEXT ·reflectcall(SB), NOSPLIT, $0-48 275 I64Load fn+8(FP) 276 I64Eqz 277 If 278 CALLNORESUME runtime·sigpanic<ABIInternal>(SB) 279 End 280 281 MOVW frameSize+32(FP), R0 282 283 DISPATCH(runtime·call16, 16) 284 DISPATCH(runtime·call32, 32) 285 DISPATCH(runtime·call64, 64) 286 DISPATCH(runtime·call128, 128) 287 DISPATCH(runtime·call256, 256) 288 DISPATCH(runtime·call512, 512) 289 DISPATCH(runtime·call1024, 1024) 290 DISPATCH(runtime·call2048, 2048) 291 DISPATCH(runtime·call4096, 4096) 292 DISPATCH(runtime·call8192, 8192) 293 DISPATCH(runtime·call16384, 16384) 294 DISPATCH(runtime·call32768, 32768) 295 DISPATCH(runtime·call65536, 65536) 296 DISPATCH(runtime·call131072, 131072) 297 DISPATCH(runtime·call262144, 262144) 298 DISPATCH(runtime·call524288, 524288) 299 DISPATCH(runtime·call1048576, 1048576) 300 DISPATCH(runtime·call2097152, 2097152) 301 DISPATCH(runtime·call4194304, 4194304) 302 DISPATCH(runtime·call8388608, 8388608) 303 DISPATCH(runtime·call16777216, 16777216) 304 DISPATCH(runtime·call33554432, 33554432) 305 DISPATCH(runtime·call67108864, 67108864) 306 DISPATCH(runtime·call134217728, 134217728) 307 DISPATCH(runtime·call268435456, 268435456) 308 DISPATCH(runtime·call536870912, 536870912) 309 DISPATCH(runtime·call1073741824, 1073741824) 310 JMP runtime·badreflectcall(SB) 311 312 #define CALLFN(NAME, MAXSIZE) \ 313 TEXT NAME(SB), WRAPPER, $MAXSIZE-48; \ 314 NO_LOCAL_POINTERS; \ 315 MOVW stackArgsSize+24(FP), R0; \ 316 \ 317 Get R0; \ 318 I64Eqz; \ 319 Not; \ 320 If; \ 321 Get SP; \ 322 I64Load stackArgs+16(FP); \ 323 I32WrapI64; \ 324 I64Load stackArgsSize+24(FP); \ 325 I32WrapI64; \ 326 MemoryCopy; \ 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 informs the GC about heap pointer writes. 410 // 411 // gcWriteBarrier does NOT follow the Go ABI. It accepts the 412 // number of bytes of buffer needed as a wasm argument 413 // (put on the TOS by the caller, lives in local R0 in this body) 414 // and returns a pointer to the buffer space as a wasm result 415 // (left on the TOS in this body, appears on the wasm stack 416 // in the caller). 417 TEXT gcWriteBarrier<>(SB), NOSPLIT, $0 418 Loop 419 // R3 = g.m 420 MOVD g_m(g), R3 421 // R4 = p 422 MOVD m_p(R3), R4 423 // R5 = wbBuf.next 424 MOVD p_wbBuf+wbBuf_next(R4), R5 425 426 // Increment wbBuf.next 427 Get R5 428 Get R0 429 I64Add 430 Set R5 431 432 // Is the buffer full? 433 Get R5 434 I64Load (p_wbBuf+wbBuf_end)(R4) 435 I64LeU 436 If 437 // Commit to the larger buffer. 438 MOVD R5, p_wbBuf+wbBuf_next(R4) 439 440 // Make return value (the original next position) 441 Get R5 442 Get R0 443 I64Sub 444 445 Return 446 End 447 448 // Flush 449 CALLNORESUME runtime·wbBufFlush(SB) 450 451 // Retry 452 Br $0 453 End 454 455 TEXT runtime·gcWriteBarrier1<ABIInternal>(SB),NOSPLIT,$0 456 I64Const $8 457 Call gcWriteBarrier<>(SB) 458 Return 459 TEXT runtime·gcWriteBarrier2<ABIInternal>(SB),NOSPLIT,$0 460 I64Const $16 461 Call gcWriteBarrier<>(SB) 462 Return 463 TEXT runtime·gcWriteBarrier3<ABIInternal>(SB),NOSPLIT,$0 464 I64Const $24 465 Call gcWriteBarrier<>(SB) 466 Return 467 TEXT runtime·gcWriteBarrier4<ABIInternal>(SB),NOSPLIT,$0 468 I64Const $32 469 Call gcWriteBarrier<>(SB) 470 Return 471 TEXT runtime·gcWriteBarrier5<ABIInternal>(SB),NOSPLIT,$0 472 I64Const $40 473 Call gcWriteBarrier<>(SB) 474 Return 475 TEXT runtime·gcWriteBarrier6<ABIInternal>(SB),NOSPLIT,$0 476 I64Const $48 477 Call gcWriteBarrier<>(SB) 478 Return 479 TEXT runtime·gcWriteBarrier7<ABIInternal>(SB),NOSPLIT,$0 480 I64Const $56 481 Call gcWriteBarrier<>(SB) 482 Return 483 TEXT runtime·gcWriteBarrier8<ABIInternal>(SB),NOSPLIT,$0 484 I64Const $64 485 Call gcWriteBarrier<>(SB) 486 Return 487 488 TEXT wasm_pc_f_loop(SB),NOSPLIT,$0 489 // Call the function for the current PC_F. Repeat until PAUSE != 0 indicates pause or exit. 490 // The WebAssembly stack may unwind, e.g. when switching goroutines. 491 // The Go stack on the linear memory is then used to jump to the correct functions 492 // with this loop, without having to restore the full WebAssembly stack. 493 // It is expected to have a pending call before entering the loop, so check PAUSE first. 494 Get PAUSE 495 I32Eqz 496 If 497 loop: 498 Loop 499 // Get PC_B & PC_F from -8(SP) 500 Get SP 501 I32Const $8 502 I32Sub 503 I32Load16U $0 // PC_B 504 505 Get SP 506 I32Const $8 507 I32Sub 508 I32Load16U $2 // PC_F 509 510 CallIndirect $0 511 Drop 512 513 Get PAUSE 514 I32Eqz 515 BrIf loop 516 End 517 End 518 519 I32Const $0 520 Set PAUSE 521 522 Return 523 524 TEXT wasm_export_lib(SB),NOSPLIT,$0 525 UNDEF