diff --git a/Editor/MethodBridge/Generator.cs b/Editor/MethodBridge/Generator.cs index d80005d..bb9f56e 100644 --- a/Editor/MethodBridge/Generator.cs +++ b/Editor/MethodBridge/Generator.cs @@ -187,32 +187,210 @@ namespace HybridCLR.Editor.MethodBridge } } - public void Generate() + + private List _managed2NativeMethodList0; + private List _native2ManagedMethodList0; + private List _adjustThunkMethodList0; + + private List _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(); + 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 fields; + public string signature; + } + + private readonly Dictionary _analyzeTypeInfos = new Dictionary(); + + private readonly Dictionary _signature2Type = new Dictionary(); + + private AnalyzeTypeInfo CalculateAnalyzeTypeInfoBasic(TypeInfo typeInfo) + { + TypeSig type = typeInfo.Klass; + TypeDef typeDef = type.ToTypeDefOrRef().ResolveTypeDefThrow(); + + List 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(); + + 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(); + 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 _managed2NativeMethodList; + private List _native2ManagedMethodList; + private List _adjustThunkMethodList; + + private List 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 ToUniqueOrderedList(List methods) + { + var methodMap = new SortedDictionary(); + 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); List lines = new List(20_0000); - List managed2NativeMethodList = _managed2nativeMethodSet.ToList(); - managed2NativeMethodList.Sort((a, b) => string.CompareOrdinal(a.Sig, b.Sig)); - - List native2ManagedMethodList = _native2managedMethodSet.ToList(); - native2ManagedMethodList.Sort((a, b) => string.CompareOrdinal(a.Sig, b.Sig)); - - List 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(); - CollectStructDefs(managed2NativeMethodList, structTypeSet); - CollectStructDefs(native2ManagedMethodList, structTypeSet); - CollectStructDefs(adjustThunkMethodList, structTypeSet); - List structTypes = structTypeSet.ToList(); - structTypes.Sort((a, b) => a.TypeId - b.TypeId); - var classInfos = new List(); var classTypeSet = new HashSet(); foreach (var type in structTypes) @@ -220,32 +398,31 @@ namespace HybridCLR.Editor.MethodBridge GenerateClassInfo(type, classTypeSet, classInfos); } - CheckUnique(structTypes.Select(t => ToFullName(t.Klass))); - CheckUnique(structTypes.Select(t => t.CreateSigName())); - 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); } - GenerateManaged2NativeStub(managed2NativeMethodList, lines); + GenerateManaged2NativeStub(_managed2NativeMethodList, lines); - foreach (var method in native2ManagedMethodList) + foreach (var method in _native2ManagedMethodList) { GenerateNative2ManagedMethod(method, lines); } - GenerateNative2ManagedStub(native2ManagedMethodList, lines); + GenerateNative2ManagedStub(_native2ManagedMethodList, lines); - foreach (var method in adjustThunkMethodList) + foreach (var method in _adjustThunkMethodList) { GenerateAdjustThunkMethod(method, lines); } - GenerateAdjustThunkStub(adjustThunkMethodList, lines); + GenerateAdjustThunkStub(_adjustThunkMethodList, lines); frr.Replace("CODE", string.Join("\n", lines)); @@ -254,6 +431,13 @@ namespace HybridCLR.Editor.MethodBridge frr.Commit(_outputFile); } + public void Generate() + { + CollectTypesAndMethods(); + OptimizationTypesAndMethods(); + GenerateCode(); + } + private void CollectStructDefs(List methods, HashSet structTypes) { foreach (var method in methods) @@ -324,7 +508,7 @@ namespace HybridCLR.Editor.MethodBridge } TypeSig fieldType = ctx != null ? MetaUtil.Inflate(field.FieldType, ctx) : field.FieldType; fieldType = MetaUtil.ToShareTypeSig(corLibTypes, fieldType); - var fieldTypeInfo = _typeCreator.CreateTypeInfo(fieldType); + var fieldTypeInfo = ToIsomorphicType(_typeCreator.CreateTypeInfo(fieldType)); if (fieldTypeInfo.IsStruct) { GenerateClassInfo(fieldTypeInfo, typeSet, classInfos); @@ -497,7 +681,8 @@ namespace HybridCLR.Editor.MethodBridge lines.Add("FullName2Signature hybridclr::interpreter::g_fullName2SignatureStub[] = {"); 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("};");