[opt] 优化桥接函数生成,将同构的struct映射到同一个结构,减少了30-35%的桥接函数数量
parent
c9ad6880cb
commit
9b269ea4c2
|
@ -187,32 +187,210 @@ namespace HybridCLR.Editor.MethodBridge
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Generate()
|
|
||||||
|
private List<MethodDesc> _managed2NativeMethodList0;
|
||||||
|
private List<MethodDesc> _native2ManagedMethodList0;
|
||||||
|
private List<MethodDesc> _adjustThunkMethodList0;
|
||||||
|
|
||||||
|
private List<TypeInfo> _structTypes0;
|
||||||
|
|
||||||
|
private void CollectTypesAndMethods()
|
||||||
|
{
|
||||||
|
_managed2NativeMethodList0 = _managed2nativeMethodSet.ToList();
|
||||||
|
_managed2NativeMethodList0.Sort((a, b) => string.CompareOrdinal(a.Sig, b.Sig));
|
||||||
|
|
||||||
|
_native2ManagedMethodList0 = _native2managedMethodSet.ToList();
|
||||||
|
_native2ManagedMethodList0.Sort((a, b) => string.CompareOrdinal(a.Sig, b.Sig));
|
||||||
|
|
||||||
|
_adjustThunkMethodList0 = _adjustThunkMethodSet.ToList();
|
||||||
|
_adjustThunkMethodList0.Sort((a, b) => string.CompareOrdinal(a.Sig, b.Sig));
|
||||||
|
|
||||||
|
|
||||||
|
var structTypeSet = new HashSet<TypeInfo>();
|
||||||
|
CollectStructDefs(_managed2NativeMethodList0, structTypeSet);
|
||||||
|
CollectStructDefs(_native2ManagedMethodList0, structTypeSet);
|
||||||
|
CollectStructDefs(_adjustThunkMethodList0, structTypeSet);
|
||||||
|
_structTypes0 = structTypeSet.ToList();
|
||||||
|
_structTypes0.Sort((a, b) => a.TypeId - b.TypeId);
|
||||||
|
|
||||||
|
CheckUnique(_structTypes0.Select(t => ToFullName(t.Klass)));
|
||||||
|
CheckUnique(_structTypes0.Select(t => t.CreateSigName()));
|
||||||
|
|
||||||
|
Debug.LogFormat("== before optimization struct:{3} managed2native:{0} native2managed:{1} adjustThunk:{2}",
|
||||||
|
_managed2NativeMethodList0.Count, _native2ManagedMethodList0.Count, _adjustThunkMethodList0.Count, _structTypes0.Count);
|
||||||
|
}
|
||||||
|
|
||||||
|
private class AnalyzeTypeInfo
|
||||||
|
{
|
||||||
|
public TypeInfo toSharedType;
|
||||||
|
public List<TypeInfo> fields;
|
||||||
|
public string signature;
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly Dictionary<TypeInfo, AnalyzeTypeInfo> _analyzeTypeInfos = new Dictionary<TypeInfo, AnalyzeTypeInfo>();
|
||||||
|
|
||||||
|
private readonly Dictionary<string, TypeInfo> _signature2Type = new Dictionary<string, TypeInfo>();
|
||||||
|
|
||||||
|
private AnalyzeTypeInfo CalculateAnalyzeTypeInfoBasic(TypeInfo typeInfo)
|
||||||
|
{
|
||||||
|
TypeSig type = typeInfo.Klass;
|
||||||
|
TypeDef typeDef = type.ToTypeDefOrRef().ResolveTypeDefThrow();
|
||||||
|
|
||||||
|
List<TypeSig> klassInst = type.ToGenericInstSig()?.GenericArguments?.ToList();
|
||||||
|
GenericArgumentContext ctx = klassInst != null ? new GenericArgumentContext(klassInst, null) : null;
|
||||||
|
|
||||||
|
ClassLayout sa = typeDef.ClassLayout;
|
||||||
|
var analyzeTypeInfo = new AnalyzeTypeInfo();
|
||||||
|
|
||||||
|
// don't share type with explicit layout
|
||||||
|
if (sa != null)
|
||||||
|
{
|
||||||
|
analyzeTypeInfo.toSharedType = typeInfo;
|
||||||
|
analyzeTypeInfo.signature = typeInfo.CreateSigName();
|
||||||
|
_signature2Type.Add(analyzeTypeInfo.signature, typeInfo);
|
||||||
|
return analyzeTypeInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
var fields = analyzeTypeInfo.fields = new List<TypeInfo>();
|
||||||
|
|
||||||
|
foreach (FieldDef field in typeDef.Fields)
|
||||||
|
{
|
||||||
|
if (field.IsStatic)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
TypeSig fieldType = ctx != null ? MetaUtil.Inflate(field.FieldType, ctx) : field.FieldType;
|
||||||
|
fields.Add(GetSharedTypeInfo(fieldType));
|
||||||
|
}
|
||||||
|
return analyzeTypeInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetOrCalculateTypeInfoSignature(TypeInfo typeInfo)
|
||||||
|
{
|
||||||
|
if (!typeInfo.IsStruct)
|
||||||
|
{
|
||||||
|
return typeInfo.CreateSigName();
|
||||||
|
}
|
||||||
|
|
||||||
|
var ati = _analyzeTypeInfos[typeInfo];
|
||||||
|
|
||||||
|
//if (_analyzeTypeInfos.TryGetValue(typeInfo, out var ati))
|
||||||
|
//{
|
||||||
|
// return ati.signature;
|
||||||
|
//}
|
||||||
|
//ati = CalculateAnalyzeTypeInfoBasic(typeInfo);
|
||||||
|
//_analyzeTypeInfos.Add(typeInfo, ati);
|
||||||
|
if (ati.signature != null)
|
||||||
|
{
|
||||||
|
return ati.signature;
|
||||||
|
}
|
||||||
|
|
||||||
|
var sigBuf = new StringBuilder();
|
||||||
|
foreach (var field in ati.fields)
|
||||||
|
{
|
||||||
|
sigBuf.Append(GetOrCalculateTypeInfoSignature(ToIsomorphicType(field)));
|
||||||
|
}
|
||||||
|
return ati.signature = sigBuf.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private TypeInfo ToIsomorphicType(TypeInfo type)
|
||||||
|
{
|
||||||
|
if (!type.IsStruct)
|
||||||
|
{
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
if (!_analyzeTypeInfos.TryGetValue(type, out var ati))
|
||||||
|
{
|
||||||
|
ati = CalculateAnalyzeTypeInfoBasic(type);
|
||||||
|
_analyzeTypeInfos.Add(type, ati);
|
||||||
|
}
|
||||||
|
if (ati.toSharedType == null)
|
||||||
|
{
|
||||||
|
string signature = GetOrCalculateTypeInfoSignature(type);
|
||||||
|
Debug.Assert(signature == ati.signature);
|
||||||
|
if (_signature2Type.TryGetValue(signature, out var sharedType))
|
||||||
|
{
|
||||||
|
// Debug.Log($"[ToIsomorphicType] type:{type.Klass} ==> sharedType:{sharedType.Klass} signature:{signature} ");
|
||||||
|
ati.toSharedType = sharedType;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ati.toSharedType = type;
|
||||||
|
_signature2Type.Add(signature, type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ati.toSharedType;
|
||||||
|
}
|
||||||
|
|
||||||
|
private MethodDesc ToIsomorphicMethod(MethodDesc method)
|
||||||
|
{
|
||||||
|
var paramInfos = new List<ParamInfo>();
|
||||||
|
foreach (var paramInfo in method.ParamInfos)
|
||||||
|
{
|
||||||
|
paramInfos.Add(new ParamInfo() { Type = ToIsomorphicType(paramInfo.Type) });
|
||||||
|
}
|
||||||
|
var mbs = new MethodDesc()
|
||||||
|
{
|
||||||
|
MethodDef = method.MethodDef,
|
||||||
|
ReturnInfo = new ReturnInfo() { Type = ToIsomorphicType(method.ReturnInfo.Type) },
|
||||||
|
ParamInfos = paramInfos,
|
||||||
|
};
|
||||||
|
mbs.Init();
|
||||||
|
return mbs;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<MethodDesc> _managed2NativeMethodList;
|
||||||
|
private List<MethodDesc> _native2ManagedMethodList;
|
||||||
|
private List<MethodDesc> _adjustThunkMethodList;
|
||||||
|
|
||||||
|
private List<TypeInfo> structTypes;
|
||||||
|
|
||||||
|
private void BuildAnalyzeTypeInfos()
|
||||||
|
{
|
||||||
|
foreach (var type in _structTypes0)
|
||||||
|
{
|
||||||
|
ToIsomorphicType(type);
|
||||||
|
}
|
||||||
|
structTypes = _signature2Type.Values.ToList();
|
||||||
|
structTypes.Sort((a, b) => a.TypeId - b.TypeId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<MethodDesc> ToUniqueOrderedList(List<MethodDesc> methods)
|
||||||
|
{
|
||||||
|
var methodMap = new SortedDictionary<string, MethodDesc>();
|
||||||
|
foreach (var method in methods)
|
||||||
|
{
|
||||||
|
var sharedMethod = ToIsomorphicMethod(method);
|
||||||
|
var sig = sharedMethod.Sig;
|
||||||
|
if (!methodMap.TryGetValue(sig, out var _))
|
||||||
|
{
|
||||||
|
methodMap.Add(sig, sharedMethod);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return methodMap.Values.ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void BuildOptimizedMethods()
|
||||||
|
{
|
||||||
|
_managed2NativeMethodList = ToUniqueOrderedList(_managed2NativeMethodList0);
|
||||||
|
_native2ManagedMethodList = ToUniqueOrderedList(_native2ManagedMethodList0);
|
||||||
|
_adjustThunkMethodList = ToUniqueOrderedList(_adjustThunkMethodList0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OptimizationTypesAndMethods()
|
||||||
|
{
|
||||||
|
BuildAnalyzeTypeInfos();
|
||||||
|
BuildOptimizedMethods();
|
||||||
|
Debug.LogFormat("== after optimization struct:{3} managed2native:{0} native2managed:{1} adjustThunk:{2}",
|
||||||
|
_managed2NativeMethodList.Count, _native2ManagedMethodList.Count, _adjustThunkMethodList.Count, structTypes.Count);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GenerateCode()
|
||||||
{
|
{
|
||||||
var frr = new FileRegionReplace(_templateCode);
|
var frr = new FileRegionReplace(_templateCode);
|
||||||
|
|
||||||
List<string> lines = new List<string>(20_0000);
|
List<string> lines = new List<string>(20_0000);
|
||||||
|
|
||||||
List<MethodDesc> managed2NativeMethodList = _managed2nativeMethodSet.ToList();
|
|
||||||
managed2NativeMethodList.Sort((a, b) => string.CompareOrdinal(a.Sig, b.Sig));
|
|
||||||
|
|
||||||
List<MethodDesc> native2ManagedMethodList = _native2managedMethodSet.ToList();
|
|
||||||
native2ManagedMethodList.Sort((a, b) => string.CompareOrdinal(a.Sig, b.Sig));
|
|
||||||
|
|
||||||
List<MethodDesc> adjustThunkMethodList = _adjustThunkMethodSet.ToList();
|
|
||||||
adjustThunkMethodList.Sort((a, b) => string.CompareOrdinal(a.Sig, b.Sig));
|
|
||||||
|
|
||||||
Debug.LogFormat("== managed2native:{0} native2managed:{1} adjustThunk:{2}",
|
|
||||||
managed2NativeMethodList.Count, native2ManagedMethodList.Count, adjustThunkMethodList.Count);
|
|
||||||
|
|
||||||
|
|
||||||
var structTypeSet = new HashSet<TypeInfo>();
|
|
||||||
CollectStructDefs(managed2NativeMethodList, structTypeSet);
|
|
||||||
CollectStructDefs(native2ManagedMethodList, structTypeSet);
|
|
||||||
CollectStructDefs(adjustThunkMethodList, structTypeSet);
|
|
||||||
List<TypeInfo> structTypes = structTypeSet.ToList();
|
|
||||||
structTypes.Sort((a, b) => a.TypeId - b.TypeId);
|
|
||||||
|
|
||||||
var classInfos = new List<ClassInfo>();
|
var classInfos = new List<ClassInfo>();
|
||||||
var classTypeSet = new HashSet<TypeInfo>();
|
var classTypeSet = new HashSet<TypeInfo>();
|
||||||
foreach (var type in structTypes)
|
foreach (var type in structTypes)
|
||||||
|
@ -220,32 +398,31 @@ namespace HybridCLR.Editor.MethodBridge
|
||||||
GenerateClassInfo(type, classTypeSet, classInfos);
|
GenerateClassInfo(type, classTypeSet, classInfos);
|
||||||
}
|
}
|
||||||
|
|
||||||
CheckUnique(structTypes.Select(t => ToFullName(t.Klass)));
|
|
||||||
CheckUnique(structTypes.Select(t => t.CreateSigName()));
|
|
||||||
|
|
||||||
GenerateStructDefines(classInfos, lines);
|
GenerateStructDefines(classInfos, lines);
|
||||||
GenerateStructureSignatureStub(structTypes, lines);
|
|
||||||
|
|
||||||
foreach(var method in managed2NativeMethodList)
|
// use structTypes0 to generate signature
|
||||||
|
GenerateStructureSignatureStub(_structTypes0, lines);
|
||||||
|
|
||||||
|
foreach (var method in _managed2NativeMethodList)
|
||||||
{
|
{
|
||||||
GenerateManaged2NativeMethod(method, lines);
|
GenerateManaged2NativeMethod(method, lines);
|
||||||
}
|
}
|
||||||
|
|
||||||
GenerateManaged2NativeStub(managed2NativeMethodList, lines);
|
GenerateManaged2NativeStub(_managed2NativeMethodList, lines);
|
||||||
|
|
||||||
foreach (var method in native2ManagedMethodList)
|
foreach (var method in _native2ManagedMethodList)
|
||||||
{
|
{
|
||||||
GenerateNative2ManagedMethod(method, lines);
|
GenerateNative2ManagedMethod(method, lines);
|
||||||
}
|
}
|
||||||
|
|
||||||
GenerateNative2ManagedStub(native2ManagedMethodList, lines);
|
GenerateNative2ManagedStub(_native2ManagedMethodList, lines);
|
||||||
|
|
||||||
foreach (var method in adjustThunkMethodList)
|
foreach (var method in _adjustThunkMethodList)
|
||||||
{
|
{
|
||||||
GenerateAdjustThunkMethod(method, lines);
|
GenerateAdjustThunkMethod(method, lines);
|
||||||
}
|
}
|
||||||
|
|
||||||
GenerateAdjustThunkStub(adjustThunkMethodList, lines);
|
GenerateAdjustThunkStub(_adjustThunkMethodList, lines);
|
||||||
|
|
||||||
frr.Replace("CODE", string.Join("\n", lines));
|
frr.Replace("CODE", string.Join("\n", lines));
|
||||||
|
|
||||||
|
@ -254,6 +431,13 @@ namespace HybridCLR.Editor.MethodBridge
|
||||||
frr.Commit(_outputFile);
|
frr.Commit(_outputFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Generate()
|
||||||
|
{
|
||||||
|
CollectTypesAndMethods();
|
||||||
|
OptimizationTypesAndMethods();
|
||||||
|
GenerateCode();
|
||||||
|
}
|
||||||
|
|
||||||
private void CollectStructDefs(List<MethodDesc> methods, HashSet<TypeInfo> structTypes)
|
private void CollectStructDefs(List<MethodDesc> methods, HashSet<TypeInfo> structTypes)
|
||||||
{
|
{
|
||||||
foreach (var method in methods)
|
foreach (var method in methods)
|
||||||
|
@ -324,7 +508,7 @@ namespace HybridCLR.Editor.MethodBridge
|
||||||
}
|
}
|
||||||
TypeSig fieldType = ctx != null ? MetaUtil.Inflate(field.FieldType, ctx) : field.FieldType;
|
TypeSig fieldType = ctx != null ? MetaUtil.Inflate(field.FieldType, ctx) : field.FieldType;
|
||||||
fieldType = MetaUtil.ToShareTypeSig(corLibTypes, fieldType);
|
fieldType = MetaUtil.ToShareTypeSig(corLibTypes, fieldType);
|
||||||
var fieldTypeInfo = _typeCreator.CreateTypeInfo(fieldType);
|
var fieldTypeInfo = ToIsomorphicType(_typeCreator.CreateTypeInfo(fieldType));
|
||||||
if (fieldTypeInfo.IsStruct)
|
if (fieldTypeInfo.IsStruct)
|
||||||
{
|
{
|
||||||
GenerateClassInfo(fieldTypeInfo, typeSet, classInfos);
|
GenerateClassInfo(fieldTypeInfo, typeSet, classInfos);
|
||||||
|
@ -497,7 +681,8 @@ namespace HybridCLR.Editor.MethodBridge
|
||||||
lines.Add("FullName2Signature hybridclr::interpreter::g_fullName2SignatureStub[] = {");
|
lines.Add("FullName2Signature hybridclr::interpreter::g_fullName2SignatureStub[] = {");
|
||||||
foreach (var type in types)
|
foreach (var type in types)
|
||||||
{
|
{
|
||||||
lines.Add($"\t{{\"{ToFullName(type.Klass)}\", \"{type.CreateSigName()}\"}},");
|
TypeInfo isoType = ToIsomorphicType(type);
|
||||||
|
lines.Add($"\t{{\"{ToFullName(type.Klass)}\", \"{isoType.CreateSigName()}\"}},");
|
||||||
}
|
}
|
||||||
lines.Add("\t{ nullptr, nullptr},");
|
lines.Add("\t{ nullptr, nullptr},");
|
||||||
lines.Add("};");
|
lines.Add("};");
|
||||||
|
|
Loading…
Reference in New Issue