mirror of
				https://github.com/golang/go.git
				synced 2025-11-04 10:40:57 +00:00 
			
		
		
		
	
		
			
	
	
		
			80 lines
		
	
	
	
		
			2.1 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
		
		
			
		
	
	
			80 lines
		
	
	
	
		
			2.1 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| 
								 | 
							
								// 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
							 | 
						||
| 
								 | 
							
								}
							 |