github.com/insolar/vanilla@v0.0.0-20201023172447-248fdf805322/reflectkit/func_code.go (about) 1 // Copyright 2020 Insolar Network Ltd. 2 // All rights reserved. 3 // This material is licensed under the Insolar License version 1.0, 4 // available at https://github.com/insolar/assured-ledger/blob/master/LICENSE.md. 5 6 package reflectkit 7 8 import ( 9 "reflect" 10 "unsafe" 11 ) 12 13 // A faster version (25-35%) to get comparable identity of function's code. 14 // Same to reflect.ValueOf(<func>).Pointer(), but doesn't force heap-escape of the argument. 15 // NB! ONLY works for hard-coded functions. Functions created with reflect will have same code identity. 16 func CodeOf(v interface{}) uintptr { 17 if v == nil { 18 panic("illegal value") 19 } 20 21 ptr, kind := unwrapIface(v) 22 if kind != uint8(reflect.Func)|kindDirectIface { 23 panic("illegal value") 24 } 25 if ptr == nil { 26 return 0 27 } 28 29 // Non-nil func value points at data block. 30 // First word of data block is actual code. 31 return *(*uintptr)(ptr) 32 } 33 34 // const kindMask = (1 << 5) - 1 35 const kindDirectIface = 1 << 5 36 37 func unwrapIface(v interface{}) (word unsafe.Pointer, kind uint8) { 38 type rtype struct { 39 _, _ uintptr 40 _ uint32 41 _, _, _ uint8 42 kind uint8 43 } 44 45 type emptyInterface struct { 46 typ *rtype 47 word unsafe.Pointer 48 } 49 50 iface := (*emptyInterface)(unsafe.Pointer(&v)) 51 return iface.word, iface.typ.kind 52 } 53 54 // A faster version (25-35%) to check for interface nil 55 func IsNil(v interface{}) bool { 56 if v == nil { 57 return true 58 } 59 ptr, kind := unwrapIface(v) 60 return ptr == nil && kind&kindDirectIface != 0 61 } 62 63