From 21b85aa2d3ea4406998fb84a95f6faa36026f4c3 Mon Sep 17 00:00:00 2001 From: walon Date: Fri, 26 May 2023 18:43:01 +0800 Subject: [PATCH] =?UTF-8?q?[fix]=20=E4=BF=AE=E5=A4=8DWebGL=E5=B9=B3?= =?UTF-8?q?=E5=8F=B0ABI=E7=9A=84bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Editor/ABI/TypeCreatorArm64.cs | 96 +++++++++++- Editor/ABI/TypeCreatorBase.cs | 216 +++------------------------ Editor/ABI/TypeCreatorUniversal32.cs | 2 - Editor/ABI/TypeCreatorUniversal64.cs | 5 +- Editor/ABI/TypeCreatorWebGL32.cs | 196 +++++++++++++++++++++++- 5 files changed, 309 insertions(+), 206 deletions(-) diff --git a/Editor/ABI/TypeCreatorArm64.cs b/Editor/ABI/TypeCreatorArm64.cs index 6e1f83e..0d86f7c 100644 --- a/Editor/ABI/TypeCreatorArm64.cs +++ b/Editor/ABI/TypeCreatorArm64.cs @@ -19,8 +19,6 @@ namespace HybridCLR.Editor.ABI { public override bool IsArch32 => false; - public override bool IsSupportHFA => true; - protected override TypeInfo OptimizeSigType(TypeInfo type, bool returnType) { if (!type.IsGeneralValueType) @@ -42,5 +40,99 @@ namespace HybridCLR.Editor.ABI } return TypeInfo.s_ref; } + + + private static bool IsNotHFAFastCheck(int typeSize) + { + return typeSize % 4 != 0 || typeSize > 32; + } + + private static bool ComputHFATypeInfo0(TypeSig type, HFATypeInfo typeInfo) + { + TypeDef typeDef = type.ToTypeDefOrRef().ResolveTypeDefThrow(); + + List klassInst = type.ToGenericInstSig()?.GenericArguments?.ToList(); + GenericArgumentContext ctx = klassInst != null ? new GenericArgumentContext(klassInst, null) : null; + + var fields = typeDef.Fields;// typeDef.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); + foreach (FieldDef field in fields) + { + if (field.IsStatic) + { + continue; + } + TypeSig ftype = ctx != null ? MetaUtil.Inflate(field.FieldType, ctx) : field.FieldType; + switch (ftype.ElementType) + { + case ElementType.R4: + case ElementType.R8: + { + if (ftype == typeInfo.Type || typeInfo.Type == null) + { + typeInfo.Type = ftype; + ++typeInfo.Count; + } + else + { + return false; + } + break; + } + case ElementType.ValueType: + { + if (!ComputHFATypeInfo0(ftype, typeInfo)) + { + return false; + } + break; + } + case ElementType.GenericInst: + { + if (!ftype.IsValueType || !ComputHFATypeInfo0(ftype, typeInfo)) + { + return false; + } + break; + } + default: return false; + } + } + return typeInfo.Count <= 4; + } + + private static bool ComputHFATypeInfo(TypeSig type, int typeSize, out HFATypeInfo typeInfo) + { + typeInfo = new HFATypeInfo(); + if (IsNotHFAFastCheck(typeSize)) + { + return false; + } + bool ok = ComputHFATypeInfo0(type, typeInfo); + if (ok && typeInfo.Count >= 1 && typeInfo.Count <= 4) + { + int fieldSize = typeInfo.Type.ElementType == ElementType.R4 ? 4 : 8; + return typeSize == fieldSize * typeInfo.Count; + } + return false; + } + + protected override bool TryCreateCustomValueTypeInfo(TypeSig type, int typeSize, int typeAligment, out TypeInfo typeInfo) + { + if (ComputHFATypeInfo(type, typeSize, out HFATypeInfo hfaTypeInfo)) + { + bool isFloat = hfaTypeInfo.Type.ElementType == ElementType.R4; + switch (hfaTypeInfo.Count) + { + case 1: typeInfo = isFloat ? TypeInfo.s_r4 : TypeInfo.s_r8; break; + case 2: typeInfo = isFloat ? TypeInfo.s_vf2 : TypeInfo.s_vd2; break; + case 3: typeInfo = isFloat ? TypeInfo.s_vf3 : TypeInfo.s_vd3; break; + case 4: typeInfo = isFloat ? TypeInfo.s_vf4 : TypeInfo.s_vd4; break; + default: throw new NotSupportedException(); + } + return true; + } + typeInfo = null; + return false; + } } } diff --git a/Editor/ABI/TypeCreatorBase.cs b/Editor/ABI/TypeCreatorBase.cs index 24e081f..b96bdc2 100644 --- a/Editor/ABI/TypeCreatorBase.cs +++ b/Editor/ABI/TypeCreatorBase.cs @@ -13,10 +13,6 @@ namespace HybridCLR.Editor.ABI { public abstract bool IsArch32 { get; } - public virtual bool IsSupportHFA => false; - - public virtual bool IsSupportWebGLSpecialValueType => false; - public TypeInfo GetNativeIntTypeInfo() => IsArch32 ? TypeInfo.s_i4 : TypeInfo.s_i8; public ValueTypeSizeAligmentCalculator Calculator => IsArch32 ? ValueTypeSizeAligmentCalculator.Caculator32 : ValueTypeSizeAligmentCalculator.Caculator64; @@ -24,6 +20,9 @@ namespace HybridCLR.Editor.ABI private readonly Dictionary _typeSizeCache = new Dictionary(TypeEqualityComparer.Instance); + + private readonly Dictionary _typeInfoCache = new Dictionary(TypeEqualityComparer.Instance); + public (int Size, int Aligment) ComputeSizeAndAligment(TypeSig t) { if (_typeSizeCache.TryGetValue(t, out var sizeAndAligment)) @@ -36,6 +35,16 @@ namespace HybridCLR.Editor.ABI } public TypeInfo CreateTypeInfo(TypeSig type) + { + if (!_typeInfoCache.TryGetValue(type, out var typeInfo)) + { + typeInfo = CreateTypeInfo0(type); + _typeInfoCache.Add(type, typeInfo); + } + return new TypeInfo(typeInfo.PorType, typeInfo.Size); + } + + TypeInfo CreateTypeInfo0(TypeSig type) { type = type.RemovePinnedAndModifiers(); if (type.IsByRef) @@ -103,175 +112,6 @@ namespace HybridCLR.Editor.ABI } } - private static bool IsNotHFAFastCheck(int typeSize) - { - return typeSize % 4 != 0 || typeSize > 32; - } - - private static bool ComputHFATypeInfo0(TypeSig type, HFATypeInfo typeInfo) - { - TypeDef typeDef = type.ToTypeDefOrRef().ResolveTypeDefThrow(); - - List klassInst = type.ToGenericInstSig()?.GenericArguments?.ToList(); - GenericArgumentContext ctx = klassInst != null ? new GenericArgumentContext(klassInst, null) : null; - - var fields = typeDef.Fields;// typeDef.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); - foreach (FieldDef field in fields) - { - if (field.IsStatic) - { - continue; - } - TypeSig ftype = ctx != null ? MetaUtil.Inflate(field.FieldType, ctx) : field.FieldType; - switch (ftype.ElementType) - { - case ElementType.R4: - case ElementType.R8: - { - if (ftype == typeInfo.Type || typeInfo.Type == null) - { - typeInfo.Type = ftype; - ++typeInfo.Count; - } - else - { - return false; - } - break; - } - case ElementType.ValueType: - { - if (!ComputHFATypeInfo0(ftype, typeInfo)) - { - return false; - } - break; - } - case ElementType.GenericInst: - { - if (!ftype.IsValueType || !ComputHFATypeInfo0(ftype, typeInfo)) - { - return false; - } - break; - } - default: return false; - } - } - return typeInfo.Count <= 4; - } - - private static bool ComputHFATypeInfo(TypeSig type, int typeSize, out HFATypeInfo typeInfo) - { - typeInfo = new HFATypeInfo(); - if (IsNotHFAFastCheck(typeSize)) - { - return false; - } - bool ok = ComputHFATypeInfo0(type, typeInfo); - if (ok && typeInfo.Count >= 1 && typeInfo.Count <= 4) - { - int fieldSize = typeInfo.Type.ElementType == ElementType.R4 ? 4 : 8; - return typeSize == fieldSize * typeInfo.Count; - } - return false; - } - - public static bool TryComputSingletonStruct(TypeSig type, out SingletonStruct result) - { - result = new SingletonStruct(); - return TryComputSingletonStruct0(type, result) && result.Type != null; - } - - public static bool TryComputSingletonStruct0(TypeSig type, SingletonStruct result) - { - TypeDef typeDef = type.ToTypeDefOrRef().ResolveTypeDefThrow(); - if (typeDef.IsEnum) - { - if (result.Type == null) - { - result.Type = typeDef.GetEnumUnderlyingType(); - return true; - } - else - { - return false; - } - } - - List klassInst = type.ToGenericInstSig()?.GenericArguments?.ToList(); - GenericArgumentContext ctx = klassInst != null ? new GenericArgumentContext(klassInst, null) : null; - - var fields = typeDef.Fields;// typeDef.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); - foreach (FieldDef field in fields) - { - if (field.IsStatic) - { - continue; - } - TypeSig ftype = ctx != null ? MetaUtil.Inflate(field.FieldType, ctx) : field.FieldType; - - switch (ftype.ElementType) - { - case ElementType.TypedByRef: return false; - case ElementType.ValueType: - { - if (!TryComputSingletonStruct0(ftype, result)) - { - return false; - } - break; - } - case ElementType.GenericInst: - { - if (!ftype.IsValueType) - { - goto default; - } - if (!TryComputSingletonStruct0(ftype, result)) - { - return false; - } - break; - } - default: - { - if (result.Type != null) - { - return false; - } - result.Type = ftype; - break; - } - } - } - - return true; - } - - public static bool IsWebGLSpeicalValueType(TypeSig type) - { - TypeDef typeDef = type.ToTypeDefOrRef().ResolveTypeDefThrow(); - if (typeDef.IsEnum) - { - return false; - } - var fields = typeDef.Fields;// typeDef.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); - if (fields.Count == 0) - { - return true; - } - if (fields.All(f => f.IsStatic)) - { - return true; - } - if (typeDef.IsExplicitLayout && fields.Count(f => !f.IsStatic) > 1) - { - return true; - } - return false; - } - protected static TypeInfo CreateGeneralValueType(TypeSig type, int size, int aligment) { System.Diagnostics.Debug.Assert(size % aligment == 0); @@ -285,31 +125,19 @@ namespace HybridCLR.Editor.ABI } } + protected virtual bool TryCreateCustomValueTypeInfo(TypeSig type, int typeSize, int typeAligment, out TypeInfo typeInfo) + { + typeInfo = null; + return false; + } + protected TypeInfo CreateValueType(TypeSig type) { (int typeSize, int typeAligment) = ComputeSizeAndAligment(type); - if (IsSupportHFA && ComputHFATypeInfo(type, typeSize, out HFATypeInfo hfaTypeInfo)) + if (TryCreateCustomValueTypeInfo(type, typeSize, typeAligment, out var typeInfo)) { - bool isFloat = hfaTypeInfo.Type.ElementType == ElementType.R4; - switch (hfaTypeInfo.Count) - { - case 1: return isFloat ? TypeInfo.s_r4 : TypeInfo.s_r8; - case 2: return isFloat ? TypeInfo.s_vf2 : TypeInfo.s_vd2; - case 3: return isFloat ? TypeInfo.s_vf3 : TypeInfo.s_vd3; - case 4: return isFloat ? TypeInfo.s_vf4 : TypeInfo.s_vd4; - default: throw new NotSupportedException(); - } - } - if (IsSupportWebGLSpecialValueType && IsWebGLSpeicalValueType(type)) - { - switch (typeAligment) - { - case 1: return new TypeInfo(ParamOrReturnType.SPECIAL_STRUCTURE_ALIGN1, typeSize); - case 2: return new TypeInfo(ParamOrReturnType.SPECIAL_STRUCTURE_ALIGN2, typeSize); - case 4: return new TypeInfo(ParamOrReturnType.SPECIAL_STRUCTURE_ALIGN4, typeSize); - case 8: return new TypeInfo(ParamOrReturnType.SPECIAL_STRUCTURE_ALIGN8, typeSize); - default: throw new NotSupportedException(); - } + Debug.Log($"[{GetType().Name}] CustomeValueType:{type} => {typeInfo.CreateSigName()}"); + return typeInfo; } else { diff --git a/Editor/ABI/TypeCreatorUniversal32.cs b/Editor/ABI/TypeCreatorUniversal32.cs index a3ffb48..4d19fe2 100644 --- a/Editor/ABI/TypeCreatorUniversal32.cs +++ b/Editor/ABI/TypeCreatorUniversal32.cs @@ -10,8 +10,6 @@ namespace HybridCLR.Editor.ABI { public override bool IsArch32 => true; - public override bool IsSupportHFA => false; - protected override TypeInfo OptimizeSigType(TypeInfo type, bool returnType) { if (type.PorType > ParamOrReturnType.STRUCTURE_ALIGN1 && type.PorType <= ParamOrReturnType.STRUCTURE_ALIGN4) diff --git a/Editor/ABI/TypeCreatorUniversal64.cs b/Editor/ABI/TypeCreatorUniversal64.cs index ec6fd6b..69a8288 100644 --- a/Editor/ABI/TypeCreatorUniversal64.cs +++ b/Editor/ABI/TypeCreatorUniversal64.cs @@ -1,4 +1,5 @@ -using System; + +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -10,8 +11,6 @@ namespace HybridCLR.Editor.ABI { public override bool IsArch32 => false; - public override bool IsSupportHFA => false; - protected override TypeInfo OptimizeSigType(TypeInfo type, bool returnType) { if (type.PorType > ParamOrReturnType.STRUCTURE_ALIGN1 && type.PorType <= ParamOrReturnType.STRUCTURE_ALIGN8) diff --git a/Editor/ABI/TypeCreatorWebGL32.cs b/Editor/ABI/TypeCreatorWebGL32.cs index b4e18ec..c1cd39c 100644 --- a/Editor/ABI/TypeCreatorWebGL32.cs +++ b/Editor/ABI/TypeCreatorWebGL32.cs @@ -17,11 +17,6 @@ namespace HybridCLR.Editor.ABI { public override bool IsArch32 => true; - public override bool IsSupportHFA => false; - - public override bool IsSupportWebGLSpecialValueType => true; - - protected override TypeInfo OptimizeSigType(TypeInfo type, bool returnType) { //if (type.PorType > ParamOrReturnType.STRUCTURE_ALIGN1 && type.PorType <= ParamOrReturnType.STRUCTURE_ALIGN4) @@ -30,5 +25,196 @@ namespace HybridCLR.Editor.ABI //} return type; } + + private static bool IsEmptyOrSpeicalValueType(TypeSig type) + { + TypeDef typeDef = type.ToTypeDefOrRef().ResolveTypeDefThrow(); + if (typeDef.IsEnum) + { + return false; + } + var fields = typeDef.Fields;// typeDef.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); + if (fields.Count == 0) + { + return true; + } + if (fields.All(f => f.IsStatic)) + { + return true; + } + if (typeDef.IsExplicitLayout && fields.Count(f => !f.IsStatic) > 1) + { + return true; + } + return false; + } + + public static bool TryComputSingletonStructTypeInfo(TypeSig type, int typeAligment, int typeSize, out TypeInfo typeInfo) + { + typeInfo = null; + if (typeAligment > 8 || typeSize > 8) + { + return false; + } + var ss = new SingletonStruct(); + if (!TryComputSingletonStruct0(type, ss) || ss.Type == null) + { + return false; + } + if (ss.Type.IsByRef) + { + typeInfo = TypeInfo.s_i4; + return true; + } + switch (ss.Type.ElementType) + { + case ElementType.Boolean: + case ElementType.Char: + case ElementType.I1: + case ElementType.U1: + case ElementType.I2: + case ElementType.U2: + case ElementType.I4: + case ElementType.U4: + case ElementType.I: + case ElementType.U: + case ElementType.String: + case ElementType.Ptr: + case ElementType.Class: + case ElementType.Array: + case ElementType.GenericInst: + case ElementType.FnPtr: + case ElementType.Object: + case ElementType.SZArray: + { + if (typeAligment <= 4 && typeSize <= 4) + { + typeInfo = TypeInfo.s_i4; + } + break; + } + case ElementType.I8: + case ElementType.U8: + { + if (typeAligment <= 8 && typeSize <= 8) + { + typeInfo = TypeInfo.s_i8; + } + break; + } + case ElementType.R4: + { + if (typeAligment <= 4 && typeSize <= 4) + { + typeInfo = TypeInfo.s_r4; + } + break; + } + case ElementType.R8: + { + if (typeAligment <= 8 && typeSize <= 8) + { + typeInfo = TypeInfo.s_r8; + } + break; + } + default: return false; + } + return typeInfo != null; + } + + public static bool TryComputSingletonStruct(TypeSig type, out SingletonStruct result) + { + result = new SingletonStruct(); + return TryComputSingletonStruct0(type, result) && result.Type != null; + } + + public static bool TryComputSingletonStruct0(TypeSig type, SingletonStruct result) + { + TypeDef typeDef = type.ToTypeDefOrRef().ResolveTypeDefThrow(); + if (typeDef.IsEnum) + { + if (result.Type == null) + { + result.Type = typeDef.GetEnumUnderlyingType(); + return true; + } + else + { + return false; + } + } + + List klassInst = type.ToGenericInstSig()?.GenericArguments?.ToList(); + GenericArgumentContext ctx = klassInst != null ? new GenericArgumentContext(klassInst, null) : null; + + var fields = typeDef.Fields;// typeDef.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); + foreach (FieldDef field in fields) + { + if (field.IsStatic) + { + continue; + } + TypeSig ftype = ctx != null ? MetaUtil.Inflate(field.FieldType, ctx) : field.FieldType; + + switch (ftype.ElementType) + { + case ElementType.TypedByRef: return false; + case ElementType.ValueType: + { + if (!TryComputSingletonStruct0(ftype, result)) + { + return false; + } + break; + } + case ElementType.GenericInst: + { + if (!ftype.IsValueType) + { + goto default; + } + if (!TryComputSingletonStruct0(ftype, result)) + { + return false; + } + break; + } + default: + { + if (result.Type != null) + { + return false; + } + result.Type = ftype; + break; + } + } + } + + return true; + } + + protected override bool TryCreateCustomValueTypeInfo(TypeSig type, int typeSize, int typeAligment, out TypeInfo typeInfo) + { + typeInfo = null; + if (IsEmptyOrSpeicalValueType(type)) + { + switch (typeAligment) + { + case 1: typeInfo = new TypeInfo(ParamOrReturnType.SPECIAL_STRUCTURE_ALIGN1, typeSize); break; + case 2: typeInfo = new TypeInfo(ParamOrReturnType.SPECIAL_STRUCTURE_ALIGN2, typeSize); break; + case 4: typeInfo = new TypeInfo(ParamOrReturnType.SPECIAL_STRUCTURE_ALIGN4, typeSize); break; + case 8: typeInfo = new TypeInfo(ParamOrReturnType.SPECIAL_STRUCTURE_ALIGN8, typeSize); break; + default: throw new NotSupportedException(); + } + return true; + } + if (TryComputSingletonStructTypeInfo(type, typeAligment, typeSize, out typeInfo)) + { + return true; + } + return false; + } } }