github.com/tencent/goom@v1.0.1/internal/proxy/interface.go (about) 1 // Package proxy 封装了给各种类型的代理(或叫 patch)中间层 2 // 负责比如外部传如私有函数名转换成 uintptr,trampoline 初始化,并发 proxy 等 3 package proxy 4 5 import ( 6 "reflect" 7 "unsafe" 8 9 "github.com/tencent/goom/erro" 10 "github.com/tencent/goom/internal/hack" 11 "github.com/tencent/goom/internal/iface" 12 ) 13 14 // Interface 构造接口代理,自动生成接口实现的桩指令织入到内存中 15 // ifaceVar 接口类型变量(指针类型) 16 // ctx 接口代理上下文 17 // method 代理模板方法名 18 // apply 代理函数, 代理函数的第一个参数类型必须是*IContext 19 // proxy 动态代理函数, 用于反射的方式回调, proxy 参数会覆盖 apply 参数值 20 // return error 异常 21 func Interface(ifaceVar interface{}, ctx *iface.IContext, method string, imp interface{}, proxy iface.PFunc) error { 22 interfaceType := reflect.TypeOf(ifaceVar) 23 if interfaceType.Kind() != reflect.Ptr { 24 return erro.NewIllegalParamTypeError("interface Var", interfaceType.String(), "ptr") 25 } 26 27 typ := interfaceType.Elem() 28 if typ.Kind() != reflect.Interface { 29 return erro.NewIllegalParamTypeError("interface Var", typ.String(), "interface") 30 } 31 32 // check args len match 33 argLen := reflect.TypeOf(imp).NumIn() 34 funcTabIndex := methodIndexOf(typ, method) 35 maxLen := typ.Method(funcTabIndex).Type.NumIn() 36 if maxLen >= argLen { 37 cause := erro.NewArgsNotMatchError(imp, argLen, maxLen+1) 38 return erro.NewIllegalParamCError("interface As()", reflect.ValueOf(imp).String(), cause) 39 } 40 41 // 首次调用备份 iface 42 gen := hack.UnpackEFace(ifaceVar).Data 43 iface.BackUpTo(ctx, gen) 44 45 // mock 接口方法 46 var itabFunc = iface.GenCallableMethod(ctx, imp, proxy) 47 // 上下文中查找接口代理对象的缓存 48 ifaceCacheKey := typ.PkgPath() + "/" + typ.String() 49 if fakeIface, ok := ctx.Cached(ifaceCacheKey); ok && !ctx.Canceled() { 50 // 添加代理函数到 funcTab 51 fakeIface.Tab.Fun[funcTabIndex] = itabFunc 52 fakeIface.Data = unsafe.Pointer(ctx) 53 applyIfaceTo(fakeIface, gen) 54 } else { 55 // 构造 iface 对象 56 fakeIface = iface.MakeInterface(ctx, funcTabIndex, itabFunc, typ) 57 ctx.Cache(ifaceCacheKey, fakeIface) 58 applyIfaceTo(fakeIface, gen) 59 } 60 return nil 61 } 62 63 func methodIndexOf(typ reflect.Type, method string) int { 64 funcTabIndex := 0 65 // 根据方法名称获取到方法的 index 66 for i := 0; i < typ.NumMethod(); i++ { 67 if method == typ.Method(i).Name { 68 funcTabIndex = i 69 break 70 } 71 } 72 return funcTabIndex 73 } 74 75 // applyIfaceTo 应用到变量 76 func applyIfaceTo(ifaceVar *hack.Iface, gen unsafe.Pointer) { 77 // 伪造的 interface 赋值到指针变量 78 *(*hack.Iface)(gen) = *ifaceVar 79 }