github.com/ice-blockchain/go/src@v0.0.0-20240403114104-1564d284e521/runtime/abi_test.go (about) 1 // Copyright 2021 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 //go:build goexperiment.regabiargs 6 7 // This file contains tests specific to making sure the register ABI 8 // works in a bunch of contexts in the runtime. 9 10 package runtime_test 11 12 import ( 13 "internal/abi" 14 "internal/testenv" 15 "os" 16 "os/exec" 17 "runtime" 18 "runtime/internal/atomic" 19 "strings" 20 "testing" 21 "time" 22 ) 23 24 var regConfirmRun atomic.Int32 25 26 //go:registerparams 27 func regFinalizerPointer(v *TintPointer) (int, float32, [10]byte) { 28 regConfirmRun.Store(int32(*(*int)(v.p))) 29 return 5151, 4.0, [10]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} 30 } 31 32 //go:registerparams 33 func regFinalizerIface(v Tinter) (int, float32, [10]byte) { 34 regConfirmRun.Store(int32(*(*int)(v.(*TintPointer).p))) 35 return 5151, 4.0, [10]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} 36 } 37 38 // TintPointer has a pointer member to make sure that it isn't allocated by the 39 // tiny allocator, so we know when its finalizer will run 40 type TintPointer struct { 41 p *Tint 42 } 43 44 func (*TintPointer) m() {} 45 46 func TestFinalizerRegisterABI(t *testing.T) { 47 testenv.MustHaveExec(t) 48 49 // Actually run the test in a subprocess because we don't want 50 // finalizers from other tests interfering. 51 if os.Getenv("TEST_FINALIZER_REGABI") != "1" { 52 cmd := testenv.CleanCmdEnv(exec.Command(os.Args[0], "-test.run=^TestFinalizerRegisterABI$", "-test.v")) 53 cmd.Env = append(cmd.Env, "TEST_FINALIZER_REGABI=1") 54 out, err := cmd.CombinedOutput() 55 if !strings.Contains(string(out), "PASS\n") || err != nil { 56 t.Fatalf("%s\n(exit status %v)", string(out), err) 57 } 58 return 59 } 60 61 // Optimistically clear any latent finalizers from e.g. the testing 62 // package before continuing. 63 // 64 // It's possible that a finalizer only becomes available to run 65 // after this point, which would interfere with the test and could 66 // cause a crash, but because we're running in a separate process 67 // it's extremely unlikely. 68 runtime.GC() 69 runtime.GC() 70 71 // fing will only pick the new IntRegArgs up if it's currently 72 // sleeping and wakes up, so wait for it to go to sleep. 73 success := false 74 for i := 0; i < 100; i++ { 75 if runtime.FinalizerGAsleep() { 76 success = true 77 break 78 } 79 time.Sleep(20 * time.Millisecond) 80 } 81 if !success { 82 t.Fatal("finalizer not asleep?") 83 } 84 85 argRegsBefore := runtime.SetIntArgRegs(abi.IntArgRegs) 86 defer runtime.SetIntArgRegs(argRegsBefore) 87 88 tests := []struct { 89 name string 90 fin any 91 confirmValue int 92 }{ 93 {"Pointer", regFinalizerPointer, -1}, 94 {"Interface", regFinalizerIface, -2}, 95 } 96 for i := range tests { 97 test := &tests[i] 98 t.Run(test.name, func(t *testing.T) { 99 x := &TintPointer{p: new(Tint)} 100 *x.p = (Tint)(test.confirmValue) 101 runtime.SetFinalizer(x, test.fin) 102 103 runtime.KeepAlive(x) 104 105 // Queue the finalizer. 106 runtime.GC() 107 runtime.GC() 108 109 if !runtime.BlockUntilEmptyFinalizerQueue(int64(time.Second)) { 110 t.Fatal("finalizer failed to execute") 111 } 112 if got := int(regConfirmRun.Load()); got != test.confirmValue { 113 t.Fatalf("wrong finalizer executed? got %d, want %d", got, test.confirmValue) 114 } 115 }) 116 } 117 }