| // run |
| |
| // Copyright 2016 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| // Previously, cmd/compile would rewrite |
| // |
| // check(unsafe.Pointer(testMeth(1).Pointer()), unsafe.Pointer(testMeth(2).Pointer())) |
| // |
| // to |
| // |
| // var autotmp_1 uintptr = testMeth(1).Pointer() |
| // var autotmp_2 uintptr = testMeth(2).Pointer() |
| // check(unsafe.Pointer(autotmp_1), unsafe.Pointer(autotmp_2)) |
| // |
| // However, that means autotmp_1 is the only reference to the int |
| // variable containing the value "1", but it's not a pointer type, |
| // so it was at risk of being garbage collected by the evaluation of |
| // testMeth(2).Pointer(), even though package unsafe's documentation |
| // says the original code was allowed. |
| // |
| // Now cmd/compile rewrites it to |
| // |
| // var autotmp_1 unsafe.Pointer = unsafe.Pointer(testMeth(1).Pointer()) |
| // var autotmp_2 unsafe.Pointer = unsafe.Pointer(testMeth(2).Pointer()) |
| // check(autotmp_1, autotmp_2) |
| // |
| // to ensure the pointed-to variables are visible to the GC. |
| |
| package main |
| |
| import ( |
| "fmt" |
| "reflect" |
| "runtime" |
| "unsafe" |
| ) |
| |
| func main() { |
| // Test all the different ways we can invoke reflect.Value.Pointer. |
| |
| // Direct method invocation. |
| check(unsafe.Pointer(testMeth(1).Pointer()), unsafe.Pointer(testMeth(2).Pointer())) |
| |
| // Invocation via method expression. |
| check(unsafe.Pointer(reflect.Value.Pointer(testMeth(1))), unsafe.Pointer(reflect.Value.Pointer(testMeth(2)))) |
| |
| // Invocation via interface. |
| check(unsafe.Pointer(testInter(1).Pointer()), unsafe.Pointer(testInter(2).Pointer())) |
| |
| // Invocation via method value. |
| check(unsafe.Pointer(testFunc(1)()), unsafe.Pointer(testFunc(2)())) |
| } |
| |
| func check(p, q unsafe.Pointer) { |
| a, b := *(*int)(p), *(*int)(q) |
| if a != 1 || b != 2 { |
| fmt.Printf("got %v, %v; expected 1, 2\n", a, b) |
| } |
| } |
| |
| func testMeth(x int) reflect.Value { |
| // Force GC to run. |
| runtime.GC() |
| return reflect.ValueOf(&x) |
| } |
| |
| type Pointerer interface { |
| Pointer() uintptr |
| } |
| |
| func testInter(x int) Pointerer { |
| return testMeth(x) |
| } |
| |
| func testFunc(x int) func() uintptr { |
| return testMeth(x).Pointer |
| } |