github.com/c12o16h1/go/src@v0.0.0-20200114212001-5a151c0f00ed/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, $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 // AES hashing not implemented for wasm 180 TEXT runtime·memhash(SB),NOSPLIT|NOFRAME,$0-32 181 JMP runtime·memhashFallback(SB) 182 TEXT runtime·strhash(SB),NOSPLIT|NOFRAME,$0-24 183 JMP runtime·strhashFallback(SB) 184 TEXT runtime·memhash32(SB),NOSPLIT|NOFRAME,$0-24 185 JMP runtime·memhash32Fallback(SB) 186 TEXT runtime·memhash64(SB),NOSPLIT|NOFRAME,$0-24 187 JMP runtime·memhash64Fallback(SB) 188 189 TEXT runtime·return0(SB), NOSPLIT, $0-0 190 MOVD $0, RET0 191 RET 192 193 TEXT runtime·jmpdefer(SB), NOSPLIT, $0-16 194 MOVD fv+0(FP), CTXT 195 196 Get CTXT 197 I64Eqz 198 If 199 CALLNORESUME runtime·sigpanic(SB) 200 End 201 202 // caller sp after CALL 203 I64Load argp+8(FP) 204 I64Const $8 205 I64Sub 206 I32WrapI64 207 Set SP 208 209 // decrease PC_B by 1 to CALL again 210 Get SP 211 I32Load16U (SP) 212 I32Const $1 213 I32Sub 214 I32Store16 $0 215 216 // but first run the deferred function 217 Get CTXT 218 I32WrapI64 219 I64Load $0 220 JMP 221 222 TEXT runtime·asminit(SB), NOSPLIT, $0-0 223 // No per-thread init. 224 RET 225 226 TEXT ·publicationBarrier(SB), NOSPLIT, $0-0 227 RET 228 229 TEXT runtime·procyield(SB), NOSPLIT, $0-0 // FIXME 230 RET 231 232 TEXT runtime·breakpoint(SB), NOSPLIT, $0-0 233 UNDEF 234 235 // Called during function prolog when more stack is needed. 236 // 237 // The traceback routines see morestack on a g0 as being 238 // the top of a stack (for example, morestack calling newstack 239 // calling the scheduler calling newm calling gc), so we must 240 // record an argument size. For that purpose, it has no arguments. 241 TEXT runtime·morestack(SB), NOSPLIT, $0-0 242 // R1 = g.m 243 MOVD g_m(g), R1 244 245 // R2 = g0 246 MOVD m_g0(R1), R2 247 248 // Cannot grow scheduler stack (m->g0). 249 Get g 250 Get R1 251 I64Eq 252 If 253 CALLNORESUME runtime·badmorestackg0(SB) 254 End 255 256 // Cannot grow signal stack (m->gsignal). 257 Get g 258 I64Load m_gsignal(R1) 259 I64Eq 260 If 261 CALLNORESUME runtime·badmorestackgsignal(SB) 262 End 263 264 // Called from f. 265 // Set m->morebuf to f's caller. 266 NOP SP // tell vet SP changed - stop checking offsets 267 MOVD 8(SP), m_morebuf+gobuf_pc(R1) 268 MOVD $16(SP), m_morebuf+gobuf_sp(R1) // f's caller's SP 269 MOVD g, m_morebuf+gobuf_g(R1) 270 271 // Set g->sched to context in f. 272 MOVD 0(SP), g_sched+gobuf_pc(g) 273 MOVD g, g_sched+gobuf_g(g) 274 MOVD $8(SP), g_sched+gobuf_sp(g) // f's SP 275 MOVD CTXT, g_sched+gobuf_ctxt(g) 276 277 // Call newstack on m->g0's stack. 278 MOVD R2, g 279 MOVD g_sched+gobuf_sp(R2), SP 280 CALL runtime·newstack(SB) 281 UNDEF // crash if newstack returns 282 283 // morestack but not preserving ctxt. 284 TEXT runtime·morestack_noctxt(SB),NOSPLIT,$0 285 MOVD $0, CTXT 286 JMP runtime·morestack(SB) 287 288 TEXT ·asmcgocall(SB), NOSPLIT, $0-0 289 UNDEF 290 291 TEXT ·cgocallback_gofunc(SB), NOSPLIT, $16-32 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-32 303 I64Load fn+8(FP) 304 I64Eqz 305 If 306 CALLNORESUME runtime·sigpanic(SB) 307 End 308 309 MOVW argsize+24(FP), R0 310 311 DISPATCH(runtime·call32, 32) 312 DISPATCH(runtime·call64, 64) 313 DISPATCH(runtime·call128, 128) 314 DISPATCH(runtime·call256, 256) 315 DISPATCH(runtime·call512, 512) 316 DISPATCH(runtime·call1024, 1024) 317 DISPATCH(runtime·call2048, 2048) 318 DISPATCH(runtime·call4096, 4096) 319 DISPATCH(runtime·call8192, 8192) 320 DISPATCH(runtime·call16384, 16384) 321 DISPATCH(runtime·call32768, 32768) 322 DISPATCH(runtime·call65536, 65536) 323 DISPATCH(runtime·call131072, 131072) 324 DISPATCH(runtime·call262144, 262144) 325 DISPATCH(runtime·call524288, 524288) 326 DISPATCH(runtime·call1048576, 1048576) 327 DISPATCH(runtime·call2097152, 2097152) 328 DISPATCH(runtime·call4194304, 4194304) 329 DISPATCH(runtime·call8388608, 8388608) 330 DISPATCH(runtime·call16777216, 16777216) 331 DISPATCH(runtime·call33554432, 33554432) 332 DISPATCH(runtime·call67108864, 67108864) 333 DISPATCH(runtime·call134217728, 134217728) 334 DISPATCH(runtime·call268435456, 268435456) 335 DISPATCH(runtime·call536870912, 536870912) 336 DISPATCH(runtime·call1073741824, 1073741824) 337 JMP runtime·badreflectcall(SB) 338 339 #define CALLFN(NAME, MAXSIZE) \ 340 TEXT NAME(SB), WRAPPER, $MAXSIZE-32; \ 341 NO_LOCAL_POINTERS; \ 342 MOVW argsize+24(FP), R0; \ 343 \ 344 Get R0; \ 345 I64Eqz; \ 346 Not; \ 347 If; \ 348 Get SP; \ 349 I64Load argptr+16(FP); \ 350 I32WrapI64; \ 351 I64Load argsize+24(FP); \ 352 I64Const $3; \ 353 I64ShrU; \ 354 I32WrapI64; \ 355 Call runtime·wasmMove(SB); \ 356 End; \ 357 \ 358 MOVD f+8(FP), CTXT; \ 359 Get CTXT; \ 360 I32WrapI64; \ 361 I64Load $0; \ 362 CALL; \ 363 \ 364 I64Load32U retoffset+28(FP); \ 365 Set R0; \ 366 \ 367 MOVD argtype+0(FP), RET0; \ 368 \ 369 I64Load argptr+16(FP); \ 370 Get R0; \ 371 I64Add; \ 372 Set RET1; \ 373 \ 374 Get SP; \ 375 I64ExtendI32U; \ 376 Get R0; \ 377 I64Add; \ 378 Set RET2; \ 379 \ 380 I64Load32U argsize+24(FP); \ 381 Get R0; \ 382 I64Sub; \ 383 Set RET3; \ 384 \ 385 CALL callRet<>(SB); \ 386 RET 387 388 // callRet copies return values back at the end of call*. This is a 389 // separate function so it can allocate stack space for the arguments 390 // to reflectcallmove. It does not follow the Go ABI; it expects its 391 // arguments in registers. 392 TEXT callRet<>(SB), NOSPLIT, $32-0 393 NO_LOCAL_POINTERS 394 MOVD RET0, 0(SP) 395 MOVD RET1, 8(SP) 396 MOVD RET2, 16(SP) 397 MOVD RET3, 24(SP) 398 CALL runtime·reflectcallmove(SB) 399 RET 400 401 CALLFN(·call32, 32) 402 CALLFN(·call64, 64) 403 CALLFN(·call128, 128) 404 CALLFN(·call256, 256) 405 CALLFN(·call512, 512) 406 CALLFN(·call1024, 1024) 407 CALLFN(·call2048, 2048) 408 CALLFN(·call4096, 4096) 409 CALLFN(·call8192, 8192) 410 CALLFN(·call16384, 16384) 411 CALLFN(·call32768, 32768) 412 CALLFN(·call65536, 65536) 413 CALLFN(·call131072, 131072) 414 CALLFN(·call262144, 262144) 415 CALLFN(·call524288, 524288) 416 CALLFN(·call1048576, 1048576) 417 CALLFN(·call2097152, 2097152) 418 CALLFN(·call4194304, 4194304) 419 CALLFN(·call8388608, 8388608) 420 CALLFN(·call16777216, 16777216) 421 CALLFN(·call33554432, 33554432) 422 CALLFN(·call67108864, 67108864) 423 CALLFN(·call134217728, 134217728) 424 CALLFN(·call268435456, 268435456) 425 CALLFN(·call536870912, 536870912) 426 CALLFN(·call1073741824, 1073741824) 427 428 TEXT runtime·goexit(SB), NOSPLIT, $0-0 429 NOP // first PC of goexit is skipped 430 CALL runtime·goexit1(SB) // does not return 431 UNDEF 432 433 TEXT runtime·cgocallback(SB), NOSPLIT, $32-32 434 UNDEF 435 436 // gcWriteBarrier performs a heap pointer write and informs the GC. 437 // 438 // gcWriteBarrier does NOT follow the Go ABI. It has two WebAssembly parameters: 439 // R0: the destination of the write (i64) 440 // R1: the value being written (i64) 441 TEXT runtime·gcWriteBarrier(SB), NOSPLIT, $16 442 // R3 = g.m 443 MOVD g_m(g), R3 444 // R4 = p 445 MOVD m_p(R3), R4 446 // R5 = wbBuf.next 447 MOVD p_wbBuf+wbBuf_next(R4), R5 448 449 // Record value 450 MOVD R1, 0(R5) 451 // Record *slot 452 MOVD (R0), 8(R5) 453 454 // Increment wbBuf.next 455 Get R5 456 I64Const $16 457 I64Add 458 Set R5 459 MOVD R5, p_wbBuf+wbBuf_next(R4) 460 461 Get R5 462 I64Load (p_wbBuf+wbBuf_end)(R4) 463 I64Eq 464 If 465 // Flush 466 MOVD R0, 0(SP) 467 MOVD R1, 8(SP) 468 CALLNORESUME runtime·wbBufFlush(SB) 469 End 470 471 // Do the write 472 MOVD R1, (R0) 473 474 RET