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  }