[fix] 修复WebGL平台ABI的bug

main
walon 2023-05-26 18:43:01 +08:00
parent 8439e4176d
commit 21b85aa2d3
5 changed files with 309 additions and 206 deletions

View File

@ -19,8 +19,6 @@ namespace HybridCLR.Editor.ABI
{ {
public override bool IsArch32 => false; public override bool IsArch32 => false;
public override bool IsSupportHFA => true;
protected override TypeInfo OptimizeSigType(TypeInfo type, bool returnType) protected override TypeInfo OptimizeSigType(TypeInfo type, bool returnType)
{ {
if (!type.IsGeneralValueType) if (!type.IsGeneralValueType)
@ -42,5 +40,99 @@ namespace HybridCLR.Editor.ABI
} }
return TypeInfo.s_ref; 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<TypeSig> 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;
}
} }
} }

View File

@ -13,10 +13,6 @@ namespace HybridCLR.Editor.ABI
{ {
public abstract bool IsArch32 { get; } 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 TypeInfo GetNativeIntTypeInfo() => IsArch32 ? TypeInfo.s_i4 : TypeInfo.s_i8;
public ValueTypeSizeAligmentCalculator Calculator => IsArch32 ? ValueTypeSizeAligmentCalculator.Caculator32 : ValueTypeSizeAligmentCalculator.Caculator64; public ValueTypeSizeAligmentCalculator Calculator => IsArch32 ? ValueTypeSizeAligmentCalculator.Caculator32 : ValueTypeSizeAligmentCalculator.Caculator64;
@ -24,6 +20,9 @@ namespace HybridCLR.Editor.ABI
private readonly Dictionary<TypeSig, (int, int)> _typeSizeCache = new Dictionary<TypeSig, (int, int)>(TypeEqualityComparer.Instance); private readonly Dictionary<TypeSig, (int, int)> _typeSizeCache = new Dictionary<TypeSig, (int, int)>(TypeEqualityComparer.Instance);
private readonly Dictionary<TypeSig, TypeInfo> _typeInfoCache = new Dictionary<TypeSig, TypeInfo>(TypeEqualityComparer.Instance);
public (int Size, int Aligment) ComputeSizeAndAligment(TypeSig t) public (int Size, int Aligment) ComputeSizeAndAligment(TypeSig t)
{ {
if (_typeSizeCache.TryGetValue(t, out var sizeAndAligment)) if (_typeSizeCache.TryGetValue(t, out var sizeAndAligment))
@ -36,6 +35,16 @@ namespace HybridCLR.Editor.ABI
} }
public TypeInfo CreateTypeInfo(TypeSig type) 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(); type = type.RemovePinnedAndModifiers();
if (type.IsByRef) 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<TypeSig> 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<TypeSig> 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) protected static TypeInfo CreateGeneralValueType(TypeSig type, int size, int aligment)
{ {
System.Diagnostics.Debug.Assert(size % aligment == 0); 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) protected TypeInfo CreateValueType(TypeSig type)
{ {
(int typeSize, int typeAligment) = ComputeSizeAndAligment(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; Debug.Log($"[{GetType().Name}] CustomeValueType:{type} => {typeInfo.CreateSigName()}");
switch (hfaTypeInfo.Count) return typeInfo;
{
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();
}
} }
else else
{ {

View File

@ -10,8 +10,6 @@ namespace HybridCLR.Editor.ABI
{ {
public override bool IsArch32 => true; public override bool IsArch32 => true;
public override bool IsSupportHFA => false;
protected override TypeInfo OptimizeSigType(TypeInfo type, bool returnType) protected override TypeInfo OptimizeSigType(TypeInfo type, bool returnType)
{ {
if (type.PorType > ParamOrReturnType.STRUCTURE_ALIGN1 && type.PorType <= ParamOrReturnType.STRUCTURE_ALIGN4) if (type.PorType > ParamOrReturnType.STRUCTURE_ALIGN1 && type.PorType <= ParamOrReturnType.STRUCTURE_ALIGN4)

View File

@ -1,4 +1,5 @@
using System; 
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
@ -10,8 +11,6 @@ namespace HybridCLR.Editor.ABI
{ {
public override bool IsArch32 => false; public override bool IsArch32 => false;
public override bool IsSupportHFA => false;
protected override TypeInfo OptimizeSigType(TypeInfo type, bool returnType) protected override TypeInfo OptimizeSigType(TypeInfo type, bool returnType)
{ {
if (type.PorType > ParamOrReturnType.STRUCTURE_ALIGN1 && type.PorType <= ParamOrReturnType.STRUCTURE_ALIGN8) if (type.PorType > ParamOrReturnType.STRUCTURE_ALIGN1 && type.PorType <= ParamOrReturnType.STRUCTURE_ALIGN8)

View File

@ -17,11 +17,6 @@ namespace HybridCLR.Editor.ABI
{ {
public override bool IsArch32 => true; public override bool IsArch32 => true;
public override bool IsSupportHFA => false;
public override bool IsSupportWebGLSpecialValueType => true;
protected override TypeInfo OptimizeSigType(TypeInfo type, bool returnType) protected override TypeInfo OptimizeSigType(TypeInfo type, bool returnType)
{ {
//if (type.PorType > ParamOrReturnType.STRUCTURE_ALIGN1 && type.PorType <= ParamOrReturnType.STRUCTURE_ALIGN4) //if (type.PorType > ParamOrReturnType.STRUCTURE_ALIGN1 && type.PorType <= ParamOrReturnType.STRUCTURE_ALIGN4)
@ -30,5 +25,196 @@ namespace HybridCLR.Editor.ABI
//} //}
return type; 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<TypeSig> 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;
}
} }
} }