github.com/ice-blockchain/go/src@v0.0.0-20240403114104-1564d284e521/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 CALLNORESUME runtime·abort(SB) 144 End 145 146 // switch: 147 148 // save state in g->sched. Pretend to 149 // be systemstack_switch if the G stack is scanned. 150 MOVD $runtime·systemstack_switch(SB), g_sched+gobuf_pc(g) 151 152 MOVD SP, g_sched+gobuf_sp(g) 153 154 // switch to g0 155 MOVD R2, g 156 157 // make it look like mstart called systemstack on g0, to stop traceback 158 I64Load (g_sched+gobuf_sp)(R2) 159 I64Const $8 160 I64Sub 161 Set R3 162 163 MOVD $runtime·mstart(SB), 0(R3) 164 MOVD R3, SP 165 166 // call fn 167 MOVD R0, CTXT 168 169 Get CTXT 170 I32WrapI64 171 I64Load $0 172 CALL 173 174 // switch back to g 175 MOVD g_m(g), R1 176 MOVD m_curg(R1), R2 177 MOVD R2, g 178 MOVD g_sched+gobuf_sp(R2), SP 179 MOVD $0, g_sched+gobuf_sp(R2) 180 RET 181 182 TEXT runtime·systemstack_switch(SB), NOSPLIT, $0-0 183 RET 184 185 TEXT runtime·abort(SB),NOSPLIT|NOFRAME,$0-0 186 UNDEF 187 188 // AES hashing not implemented for wasm 189 TEXT runtime·memhash(SB),NOSPLIT|NOFRAME,$0-32 190 JMP runtime·memhashFallback(SB) 191 TEXT runtime·strhash(SB),NOSPLIT|NOFRAME,$0-24 192 JMP runtime·strhashFallback(SB) 193 TEXT runtime·memhash32(SB),NOSPLIT|NOFRAME,$0-24 194 JMP runtime·memhash32Fallback(SB) 195 TEXT runtime·memhash64(SB),NOSPLIT|NOFRAME,$0-24 196 JMP runtime·memhash64Fallback(SB) 197 198 TEXT runtime·return0(SB), NOSPLIT, $0-0 199 MOVD $0, RET0 200 RET 201 202 TEXT runtime·asminit(SB), NOSPLIT, $0-0 203 // No per-thread init. 204 RET 205 206 TEXT ·publicationBarrier(SB), NOSPLIT, $0-0 207 RET 208 209 TEXT runtime·procyield(SB), NOSPLIT, $0-0 // FIXME 210 RET 211 212 TEXT runtime·breakpoint(SB), NOSPLIT, $0-0 213 UNDEF 214 215 // func switchToCrashStack0(fn func()) 216 TEXT runtime·switchToCrashStack0(SB), NOSPLIT, $0-8 217 MOVD fn+0(FP), CTXT // context register 218 MOVD g_m(g), R2 // curm 219 220 // set g to gcrash 221 MOVD $runtime·gcrash(SB), g // g = &gcrash 222 MOVD R2, g_m(g) // g.m = curm 223 MOVD g, m_g0(R2) // curm.g0 = g 224 225 // switch to crashstack 226 I64Load (g_stack+stack_hi)(g) 227 I64Const $(-4*8) 228 I64Add 229 I32WrapI64 230 Set SP 231 232 // call target function 233 Get CTXT 234 I32WrapI64 235 I64Load $0 236 CALL 237 238 // should never return 239 CALL runtime·abort(SB) 240 UNDEF 241 242 // Called during function prolog when more stack is needed. 243 // 244 // The traceback routines see morestack on a g0 as being 245 // the top of a stack (for example, morestack calling newstack 246 // calling the scheduler calling newm calling gc), so we must 247 // record an argument size. For that purpose, it has no arguments. 248 TEXT runtime·morestack(SB), NOSPLIT, $0-0 249 // R1 = g.m 250 MOVD g_m(g), R1 251 252 // R2 = g0 253 MOVD m_g0(R1), R2 254 255 // Set g->sched to context in f. 256 NOP SP // tell vet SP changed - stop checking offsets 257 MOVD 0(SP), g_sched+gobuf_pc(g) 258 MOVD $8(SP), g_sched+gobuf_sp(g) // f's SP 259 MOVD CTXT, g_sched+gobuf_ctxt(g) 260 261 // Cannot grow scheduler stack (m->g0). 262 Get g 263 Get R2 264 I64Eq 265 If 266 CALLNORESUME runtime·badmorestackg0(SB) 267 CALLNORESUME runtime·abort(SB) 268 End 269 270 // Cannot grow signal stack (m->gsignal). 271 Get g 272 I64Load m_gsignal(R1) 273 I64Eq 274 If 275 CALLNORESUME runtime·badmorestackgsignal(SB) 276 CALLNORESUME runtime·abort(SB) 277 End 278 279 // Called from f. 280 // Set m->morebuf to f's caller. 281 MOVD 8(SP), m_morebuf+gobuf_pc(R1) 282 MOVD $16(SP), m_morebuf+gobuf_sp(R1) // f's caller's SP 283 MOVD g, m_morebuf+gobuf_g(R1) 284 285 // Call newstack on m->g0's stack. 286 MOVD R2, g 287 MOVD g_sched+gobuf_sp(R2), SP 288 CALL runtime·newstack(SB) 289 UNDEF // crash if newstack returns 290 291 // morestack but not preserving ctxt. 292 TEXT runtime·morestack_noctxt(SB),NOSPLIT,$0 293 MOVD $0, CTXT 294 JMP runtime·morestack(SB) 295 296 TEXT ·asmcgocall(SB), NOSPLIT, $0-0 297 UNDEF 298 299 #define DISPATCH(NAME, MAXSIZE) \ 300 Get R0; \ 301 I64Const $MAXSIZE; \ 302 I64LeU; \ 303 If; \ 304 JMP NAME(SB); \ 305 End 306 307 TEXT ·reflectcall(SB), NOSPLIT, $0-48 308 I64Load fn+8(FP) 309 I64Eqz 310 If 311 CALLNORESUME runtime·sigpanic<ABIInternal>(SB) 312 End 313 314 MOVW frameSize+32(FP), R0 315 316 DISPATCH(runtime·call16, 16) 317 DISPATCH(runtime·call32, 32) 318 DISPATCH(runtime·call64, 64) 319 DISPATCH(runtime·call128, 128) 320 DISPATCH(runtime·call256, 256) 321 DISPATCH(runtime·call512, 512) 322 DISPATCH(runtime·call1024, 1024) 323 DISPATCH(runtime·call2048, 2048) 324 DISPATCH(runtime·call4096, 4096) 325 DISPATCH(runtime·call8192, 8192) 326 DISPATCH(runtime·call16384, 16384) 327 DISPATCH(runtime·call32768, 32768) 328 DISPATCH(runtime·call65536, 65536) 329 DISPATCH(runtime·call131072, 131072) 330 DISPATCH(runtime·call262144, 262144) 331 DISPATCH(runtime·call524288, 524288) 332 DISPATCH(runtime·call1048576, 1048576) 333 DISPATCH(runtime·call2097152, 2097152) 334 DISPATCH(runtime·call4194304, 4194304) 335 DISPATCH(runtime·call8388608, 8388608) 336 DISPATCH(runtime·call16777216, 16777216) 337 DISPATCH(runtime·call33554432, 33554432) 338 DISPATCH(runtime·call67108864, 67108864) 339 DISPATCH(runtime·call134217728, 134217728) 340 DISPATCH(runtime·call268435456, 268435456) 341 DISPATCH(runtime·call536870912, 536870912) 342 DISPATCH(runtime·call1073741824, 1073741824) 343 JMP runtime·badreflectcall(SB) 344 345 #define CALLFN(NAME, MAXSIZE) \ 346 TEXT NAME(SB), WRAPPER, $MAXSIZE-48; \ 347 NO_LOCAL_POINTERS; \ 348 MOVW stackArgsSize+24(FP), R0; \ 349 \ 350 Get R0; \ 351 I64Eqz; \ 352 Not; \ 353 If; \ 354 Get SP; \ 355 I64Load stackArgs+16(FP); \ 356 I32WrapI64; \ 357 I64Load stackArgsSize+24(FP); \ 358 I32WrapI64; \ 359 MemoryCopy; \ 360 End; \ 361 \ 362 MOVD f+8(FP), CTXT; \ 363 Get CTXT; \ 364 I32WrapI64; \ 365 I64Load $0; \ 366 CALL; \ 367 \ 368 I64Load32U stackRetOffset+28(FP); \ 369 Set R0; \ 370 \ 371 MOVD stackArgsType+0(FP), RET0; \ 372 \ 373 I64Load stackArgs+16(FP); \ 374 Get R0; \ 375 I64Add; \ 376 Set RET1; \ 377 \ 378 Get SP; \ 379 I64ExtendI32U; \ 380 Get R0; \ 381 I64Add; \ 382 Set RET2; \ 383 \ 384 I64Load32U stackArgsSize+24(FP); \ 385 Get R0; \ 386 I64Sub; \ 387 Set RET3; \ 388 \ 389 CALL callRet<>(SB); \ 390 RET 391 392 // callRet copies return values back at the end of call*. This is a 393 // separate function so it can allocate stack space for the arguments 394 // to reflectcallmove. It does not follow the Go ABI; it expects its 395 // arguments in registers. 396 TEXT callRet<>(SB), NOSPLIT, $40-0 397 NO_LOCAL_POINTERS 398 MOVD RET0, 0(SP) 399 MOVD RET1, 8(SP) 400 MOVD RET2, 16(SP) 401 MOVD RET3, 24(SP) 402 MOVD $0, 32(SP) 403 CALL runtime·reflectcallmove(SB) 404 RET 405 406 CALLFN(·call16, 16) 407 CALLFN(·call32, 32) 408 CALLFN(·call64, 64) 409 CALLFN(·call128, 128) 410 CALLFN(·call256, 256) 411 CALLFN(·call512, 512) 412 CALLFN(·call1024, 1024) 413 CALLFN(·call2048, 2048) 414 CALLFN(·call4096, 4096) 415 CALLFN(·call8192, 8192) 416 CALLFN(·call16384, 16384) 417 CALLFN(·call32768, 32768) 418 CALLFN(·call65536, 65536) 419 CALLFN(·call131072, 131072) 420 CALLFN(·call262144, 262144) 421 CALLFN(·call524288, 524288) 422 CALLFN(·call1048576, 1048576) 423 CALLFN(·call2097152, 2097152) 424 CALLFN(·call4194304, 4194304) 425 CALLFN(·call8388608, 8388608) 426 CALLFN(·call16777216, 16777216) 427 CALLFN(·call33554432, 33554432) 428 CALLFN(·call67108864, 67108864) 429 CALLFN(·call134217728, 134217728) 430 CALLFN(·call268435456, 268435456) 431 CALLFN(·call536870912, 536870912) 432 CALLFN(·call1073741824, 1073741824) 433 434 TEXT runtime·goexit(SB), NOSPLIT|TOPFRAME, $0-0 435 NOP // first PC of goexit is skipped 436 CALL runtime·goexit1(SB) // does not return 437 UNDEF 438 439 TEXT runtime·cgocallback(SB), NOSPLIT, $0-24 440 UNDEF 441 442 // gcWriteBarrier informs the GC about heap pointer writes. 443 // 444 // gcWriteBarrier does NOT follow the Go ABI. It accepts the 445 // number of bytes of buffer needed as a wasm argument 446 // (put on the TOS by the caller, lives in local R0 in this body) 447 // and returns a pointer to the buffer space as a wasm result 448 // (left on the TOS in this body, appears on the wasm stack 449 // in the caller). 450 TEXT gcWriteBarrier<>(SB), NOSPLIT, $0 451 Loop 452 // R3 = g.m 453 MOVD g_m(g), R3 454 // R4 = p 455 MOVD m_p(R3), R4 456 // R5 = wbBuf.next 457 MOVD p_wbBuf+wbBuf_next(R4), R5 458 459 // Increment wbBuf.next 460 Get R5 461 Get R0 462 I64Add 463 Set R5 464 465 // Is the buffer full? 466 Get R5 467 I64Load (p_wbBuf+wbBuf_end)(R4) 468 I64LeU 469 If 470 // Commit to the larger buffer. 471 MOVD R5, p_wbBuf+wbBuf_next(R4) 472 473 // Make return value (the original next position) 474 Get R5 475 Get R0 476 I64Sub 477 478 Return 479 End 480 481 // Flush 482 CALLNORESUME runtime·wbBufFlush(SB) 483 484 // Retry 485 Br $0 486 End 487 488 TEXT runtime·gcWriteBarrier1<ABIInternal>(SB),NOSPLIT,$0 489 I64Const $8 490 Call gcWriteBarrier<>(SB) 491 Return 492 TEXT runtime·gcWriteBarrier2<ABIInternal>(SB),NOSPLIT,$0 493 I64Const $16 494 Call gcWriteBarrier<>(SB) 495 Return 496 TEXT runtime·gcWriteBarrier3<ABIInternal>(SB),NOSPLIT,$0 497 I64Const $24 498 Call gcWriteBarrier<>(SB) 499 Return 500 TEXT runtime·gcWriteBarrier4<ABIInternal>(SB),NOSPLIT,$0 501 I64Const $32 502 Call gcWriteBarrier<>(SB) 503 Return 504 TEXT runtime·gcWriteBarrier5<ABIInternal>(SB),NOSPLIT,$0 505 I64Const $40 506 Call gcWriteBarrier<>(SB) 507 Return 508 TEXT runtime·gcWriteBarrier6<ABIInternal>(SB),NOSPLIT,$0 509 I64Const $48 510 Call gcWriteBarrier<>(SB) 511 Return 512 TEXT runtime·gcWriteBarrier7<ABIInternal>(SB),NOSPLIT,$0 513 I64Const $56 514 Call gcWriteBarrier<>(SB) 515 Return 516 TEXT runtime·gcWriteBarrier8<ABIInternal>(SB),NOSPLIT,$0 517 I64Const $64 518 Call gcWriteBarrier<>(SB) 519 Return 520 521 TEXT wasm_pc_f_loop(SB),NOSPLIT,$0 522 // Call the function for the current PC_F. Repeat until PAUSE != 0 indicates pause or exit. 523 // The WebAssembly stack may unwind, e.g. when switching goroutines. 524 // The Go stack on the linear memory is then used to jump to the correct functions 525 // with this loop, without having to restore the full WebAssembly stack. 526 // It is expected to have a pending call before entering the loop, so check PAUSE first. 527 Get PAUSE 528 I32Eqz 529 If 530 loop: 531 Loop 532 // Get PC_B & PC_F from -8(SP) 533 Get SP 534 I32Const $8 535 I32Sub 536 I32Load16U $0 // PC_B 537 538 Get SP 539 I32Const $8 540 I32Sub 541 I32Load16U $2 // PC_F 542 543 CallIndirect $0 544 Drop 545 546 Get PAUSE 547 I32Eqz 548 BrIf loop 549 End 550 End 551 552 I32Const $0 553 Set PAUSE 554 555 Return 556 557 TEXT wasm_export_lib(SB),NOSPLIT,$0 558 UNDEF