9
9
// func rt0_go()
10
10
TEXT runtime·rt0_go(SB),NOSPLIT,$0
11
11
// X2 = stack; A0 = argc; A1 = argv
12
-
13
12
ADD $-24 , X2
14
- MOV A0, 8 (X2) // argc
15
- MOV A1, 16 (X2) // argv
13
+ MOV A0, 8 (X2) // argc
14
+ MOV A1, 16 (X2) // argv
16
15
17
16
// create istack out of the given (operating system) stack.
18
17
// _cgo_init may update stackguard.
@@ -28,10 +27,10 @@ TEXT runtime·rt0_go(SB),NOSPLIT,$0
28
27
MOV _cgo_init(SB), T0
29
28
BEQ T0, ZERO, nocgo
30
29
31
- MOV ZERO, A3 // arg 3: not used
32
- MOV ZERO, A2 // arg 2: not used
30
+ MOV ZERO, A3 // arg 3: not used
31
+ MOV ZERO, A2 // arg 2: not used
33
32
MOV $setg_gcc<>(SB), A1 // arg 1: setg
34
- MOV g, A0 // arg 0: G
33
+ MOV g, A0 // arg 0: G
35
34
JALR RA, T0
36
35
37
36
nocgo:
@@ -313,10 +312,62 @@ TEXT runtime·gosave(SB), NOSPLIT|NOFRAME, $0-8
313
312
CALL runtime·badctxt(SB)
314
313
RET
315
314
315
+ // Save state of caller into g->sched. Smashes X31.
316
+ TEXT gosave<>(SB),NOSPLIT|NOFRAME,$0
317
+ MOV X1, (g_sched+gobuf_pc)(g)
318
+ MOV X2, (g_sched+gobuf_sp)(g)
319
+ MOV ZERO, (g_sched+gobuf_lr)(g)
320
+ MOV ZERO, (g_sched+gobuf_ret)(g)
321
+ // Assert ctxt is zero. See func save.
322
+ MOV (g_sched+gobuf_ctxt)(g), X31
323
+ BEQ ZERO, X31, 2 (PC)
324
+ CALL runtime·badctxt(SB)
325
+ RET
326
+
316
327
// func asmcgocall(fn, arg unsafe.Pointer) int32
328
+ // Call fn(arg) on the scheduler stack,
329
+ // aligned appropriately for the gcc ABI.
330
+ // See cgocall.go for more details.
317
331
TEXT ·asmcgocall(SB),NOSPLIT,$0 -20
318
- // TODO(jsing): Add support for cgo - issue #36641.
319
- WORD $0 // crash
332
+ MOV fn+0 (FP), X5
333
+ MOV arg+8 (FP), X10
334
+
335
+ MOV X2, X8 // save original stack pointer
336
+ MOV g, X9
337
+
338
+ // Figure out if we need to switch to m->g0 stack.
339
+ // We get called to create new OS threads too, and those
340
+ // come in on the m->g0 stack already.
341
+ MOV g_m(g), X6
342
+ MOV m_g0(X6), X7
343
+ BEQ X7, g, g0
344
+
345
+ CALL gosave<>(SB)
346
+ MOV X7, g
347
+ CALL runtime·save_g(SB)
348
+ MOV (g_sched+gobuf_sp)(g), X2
349
+
350
+ // Now on a scheduling stack (a pthread-created stack).
351
+ g0:
352
+ // Save room for two of our pointers.
353
+ ADD $-16 , X2
354
+ MOV X9, 0 (X2) // save old g on stack
355
+ MOV (g_stack+stack_hi)(X9), X9
356
+ SUB X8, X9, X8
357
+ MOV X8, 8 (X2) // save depth in old g stack (can't just save SP, as stack might be copied during a callback)
358
+
359
+ JALR RA, (X5)
360
+
361
+ // Restore g, stack pointer. X10 is return value.
362
+ MOV 0 (X2), g
363
+ CALL runtime·save_g(SB)
364
+ MOV (g_stack+stack_hi)(g), X5
365
+ MOV 8 (X2), X6
366
+ SUB X6, X5, X6
367
+ MOV X6, X2
368
+
369
+ MOVW X10, ret +16 (FP)
370
+ RET
320
371
321
372
// func asminit()
322
373
TEXT runtime·asminit(SB),NOSPLIT|NOFRAME,$0 -0
@@ -444,6 +495,21 @@ CALLFN(·call268435456, 268435456)
444
495
CALLFN(·call536870912, 536870912 )
445
496
CALLFN(·call1073741824, 1073741824 )
446
497
498
+ // Called from cgo wrappers, this function returns g->m->curg.stack.hi.
499
+ // Must obey the gcc calling convention.
500
+ TEXT _cgo_topofstack(SB),NOSPLIT,$8
501
+ // g (X27) and REG_TMP (X31) might be clobbered by load_g.
502
+ // X27 is callee-save in the gcc calling convention, so save it.
503
+ MOV g, savedX27-8 (SP)
504
+
505
+ CALL runtime·load_g(SB)
506
+ MOV g_m(g), X5
507
+ MOV m_curg(X5), X5
508
+ MOV (g_stack+stack_hi)(X5), X10 // return value in X10
509
+
510
+ MOV savedX27-8 (SP), g
511
+ RET
512
+
447
513
// func goexit(neverCallThisFunction)
448
514
// The top-most function running on a goroutine
449
515
// returns to goexit+PCQuantum.
@@ -453,11 +519,111 @@ TEXT runtime·goexit(SB),NOSPLIT|NOFRAME|TOPFRAME,$0-0
453
519
// traceback from goexit1 must hit code range of goexit
454
520
MOV ZERO, ZERO // NOP
455
521
456
- // cgocallback(fn, frame unsafe.Pointer, ctxt uintptr)
522
+ // func cgocallback(fn, frame unsafe.Pointer, ctxt uintptr)
457
523
// See cgocall.go for more details.
458
- TEXT ·cgocallback(SB),NOSPLIT,$0 -24
459
- // TODO(jsing): Add support for cgo - issue #36641.
460
- WORD $0 // crash
524
+ TEXT ·cgocallback(SB),NOSPLIT,$24 -24
525
+ NO_LOCAL_POINTERS
526
+
527
+ // Load m and g from thread-local storage.
528
+ MOVBU runtime·iscgo(SB), X5
529
+ BEQ ZERO, X5, nocgo
530
+ CALL runtime·load_g(SB)
531
+ nocgo:
532
+
533
+ // If g is nil, Go did not create the current thread.
534
+ // Call needm to obtain one for temporary use.
535
+ // In this case, we're running on the thread stack, so there's
536
+ // lots of space, but the linker doesn't know. Hide the call from
537
+ // the linker analysis by using an indirect call.
538
+ BEQ ZERO, g, needm
539
+
540
+ MOV g_m(g), X5
541
+ MOV X5, savedm-8 (SP)
542
+ JMP havem
543
+
544
+ needm:
545
+ MOV g, savedm-8 (SP) // g is zero, so is m.
546
+ MOV $runtime·needm(SB), X6
547
+ JALR RA, X6
548
+
549
+ // Set m->sched.sp = SP, so that if a panic happens
550
+ // during the function we are about to execute, it will
551
+ // have a valid SP to run on the g0 stack.
552
+ // The next few lines (after the havem label)
553
+ // will save this SP onto the stack and then write
554
+ // the same SP back to m->sched.sp. That seems redundant,
555
+ // but if an unrecovered panic happens, unwindm will
556
+ // restore the g->sched.sp from the stack location
557
+ // and then systemstack will try to use it. If we don't set it here,
558
+ // that restored SP will be uninitialized (typically 0) and
559
+ // will not be usable.
560
+ MOV g_m(g), X5
561
+ MOV m_g0(X5), X6
562
+ MOV X2, (g_sched+gobuf_sp)(X6)
563
+
564
+ havem:
565
+ // Now there's a valid m, and we're running on its m->g0.
566
+ // Save current m->g0->sched.sp on stack and then set it to SP.
567
+ // Save current sp in m->g0->sched.sp in preparation for
568
+ // switch back to m->curg stack.
569
+ // NOTE: unwindm knows that the saved g->sched.sp is at 8(X2) aka savedsp-24(SP).
570
+ MOV m_g0(X5), X6
571
+ MOV (g_sched+gobuf_sp)(X6), X7
572
+ MOV X7, savedsp-24 (SP) // must match frame size
573
+ MOV X2, (g_sched+gobuf_sp)(X6)
574
+
575
+ // Switch to m->curg stack and call runtime.cgocallbackg.
576
+ // Because we are taking over the execution of m->curg
577
+ // but *not* resuming what had been running, we need to
578
+ // save that information (m->curg->sched) so we can restore it.
579
+ // We can restore m->curg->sched.sp easily, because calling
580
+ // runtime.cgocallbackg leaves SP unchanged upon return.
581
+ // To save m->curg->sched.pc, we push it onto the curg stack and
582
+ // open a frame the same size as cgocallback's g0 frame.
583
+ // Once we switch to the curg stack, the pushed PC will appear
584
+ // to be the return PC of cgocallback, so that the traceback
585
+ // will seamlessly trace back into the earlier calls.
586
+ MOV m_curg(X5), g
587
+ CALL runtime·save_g(SB)
588
+ MOV (g_sched+gobuf_sp)(g), X6 // prepare stack as X6
589
+ MOV (g_sched+gobuf_pc)(g), X7
590
+ MOV X7, -(24 +8 )(X6) // "saved LR"; must match frame size
591
+ // Gather our arguments into registers.
592
+ MOV fn+0 (FP), X7
593
+ MOV frame+8 (FP), X8
594
+ MOV ctxt+16 (FP), X9
595
+ MOV $-(24 +8 )(X6), X2 // switch stack; must match frame size
596
+ MOV X7, 8 (X2)
597
+ MOV X8, 16 (X2)
598
+ MOV X9, 24 (X2)
599
+ CALL runtime·cgocallbackg(SB)
600
+
601
+ // Restore g->sched (== m->curg->sched) from saved values.
602
+ MOV 0 (X2), X7
603
+ MOV X7, (g_sched+gobuf_pc)(g)
604
+ MOV $(24 +8 )(X2), X6 // must match frame size
605
+ MOV X6, (g_sched+gobuf_sp)(g)
606
+
607
+ // Switch back to m->g0's stack and restore m->g0->sched.sp.
608
+ // (Unlike m->curg, the g0 goroutine never uses sched.pc,
609
+ // so we do not have to restore it.)
610
+ MOV g_m(g), X5
611
+ MOV m_g0(X5), g
612
+ CALL runtime·save_g(SB)
613
+ MOV (g_sched+gobuf_sp)(g), X2
614
+ MOV savedsp-24 (SP), X6 // must match frame size
615
+ MOV X6, (g_sched+gobuf_sp)(g)
616
+
617
+ // If the m on entry was nil, we called needm above to borrow an m
618
+ // for the duration of the call. Since the call is over, return it with dropm.
619
+ MOV savedm-8 (SP), X5
620
+ BNE ZERO, X5, droppedm
621
+ MOV $runtime·dropm(SB), X6
622
+ JALR RA, X6
623
+ droppedm:
624
+
625
+ // Done!
626
+ RET
461
627
462
628
TEXT runtime·breakpoint(SB),NOSPLIT|NOFRAME,$0 -0
463
629
EBREAK
0 commit comments