public static bool IsPodType(this TypeReference typeRef)
        {
            TypeDefinition type = typeRef.Resolve();

            if (type.IsCppBasicType() || type.IsEnum)
            {
                return(true);
            }

            var typeResolver = TypeResolver.For(typeRef);

            foreach (var f in type.Fields)
            {
                var fieldType = typeResolver.Resolve(f.FieldType);
                if (fieldType.MetadataType == MetadataType.String || fieldType.IsDynamicArray())
                {
                    return(false);
                }
                bool recursiveIsPodType = IsPodType(fieldType);
                if (!recursiveIsPodType)
                {
                    return(false);
                }
            }

            return(true);
        }
        public static bool IsManagedType(this TypeReference typeRef)
        {
            // We must check this before calling Resolve() as cecil loses this property otherwise
            if (typeRef.IsPointer)
            {
                return(false);
            }

            if (typeRef.IsArray || typeRef.IsGenericParameter)
            {
                return(true);
            }

            var type = typeRef.Resolve();

            if (type.IsDynamicArray())
            {
                return(true);
            }

            TypeDefinition fixedSpecialType = type.FixedSpecialType();

            if (fixedSpecialType != null)
            {
                if (fixedSpecialType.MetadataType == MetadataType.String)
                {
                    return(true);
                }
                return(false);
            }

            if (type.IsEnum)
            {
                return(false);
            }

            if (type.IsValueType)
            {
                // if none of the above check the type's fields
                var typeResolver = TypeResolver.For(typeRef);
                foreach (var field in type.Fields)
                {
                    if (field.IsStatic)
                    {
                        continue;
                    }

                    var fieldType = typeResolver.Resolve(field.FieldType);
                    if (fieldType.IsManagedType())
                    {
                        return(true);
                    }
                }

                return(false);
            }

            return(true);
        }
        private static ulong HashType(TypeReference typeRef, Dictionary <TypeReference, ulong> cache)
        {
            var hash         = HashTypeName(typeRef);
            var typeResolver = TypeResolver.For(typeRef);
            var typeDef      = typeRef.Resolve();

            // UnityEngine objects have their own serialization mechanism so exclude hashing the type's
            // internals and just hash its name which is stable and important to how Entities will serialize
            if (typeRef.IsArray || typeRef.IsGenericParameter || typeRef.IsPointer || typeDef.IsPrimitive || typeDef.IsEnum || typeDef.IsUnityEngineObject() || WorkaroundTypeNames.Contains(typeRef.FullName))
            {
                return(hash);
            }

            foreach (var field in typeDef.Fields)
            {
                if (!field.IsStatic) // statics have no effect on data layout
                {
                    var fieldTypeRef = typeResolver.ResolveFieldType(field);

                    // Classes can have cyclical type definitions so prevent recursion if we've seen the type already
                    if (!cache.TryGetValue(fieldTypeRef, out ulong fieldTypeHash))
                    {
                        // Classes can have cyclical type definitions so to prevent a potential stackoverflow
                        // we make all future occurence of fieldType resolve to the hash of its field type name
                        cache.Add(fieldTypeRef, HashTypeName(fieldTypeRef));
                        fieldTypeHash       = HashType(fieldTypeRef, cache);
                        cache[fieldTypeRef] = fieldTypeHash;
                    }

                    if (field.HasLayoutInfo)
                    {
                        var offset = field.Offset;
                        hash = CombineFNV1A64(hash, (ulong)offset);
                    }
                    hash = CombineFNV1A64(hash, fieldTypeHash);
                }
            }

            // TODO: Enable this. Currently IL2CPP gives totally inconsistent results to Mono.

            /*
             * if (typeDef.HasLayoutInfo)
             * {
             *  var explicitSize = typeDef.ClassSize;
             *  if (explicitSize > 0)
             *      hash = CombineFNV1A64(hash, (ulong)explicitSize);
             *
             *  // Todo: Enable this. We cannot support Pack at the moment since a type's Packing will
             *  // change based on its field's explicit packing which will fail for Tiny mscorlib
             *  // as it's not in sync with dotnet
             *  //var packingSize = typeDef.PackingSize;
             *  //if (packingSize > 0)
             *  //    hash = CombineFNV1A64(hash, (ulong)packingSize);
             * }
             */

            return(hash);
        }
示例#4
0
        public static TypeReference GetResolvedDeclaringType(this FieldDefinition field, TypeReference type)
        {
            while (!type.Resolve().Fields.Contains(field))
            {
                type = TypeResolver.For(type).Resolve(type.Resolve().BaseType);
            }

            return(type);
        }
示例#5
0
        public static TypeReference GetResolvedDeclaringType(this PropertyDefinition property, TypeReference type)
        {
            while (!type.Resolve().Properties.Contains(property))
            {
                type = TypeResolver.For(type).Resolve(type.Resolve().BaseType);
            }

            return(type);
        }
        FieldInfoLookUp GenerateFieldInfos(TypeReference typeRef)
        {
            var lookup = new FieldInfoLookUp()
            {
                Index = m_FieldGenInfos.Count(),
                Count = 0
            };

            if (!m_FieldInfoMap.ContainsKey(typeRef))
            {
                var resolver = TypeResolver.For(typeRef);
                var typeDef  = typeRef.Resolve();

                // Push the component into the fieldInfoTypeList
                m_FieldTypes.Add(typeRef);
                foreach (var field in typeDef.Fields)
                {
                    if (field.IsStatic)
                    {
                        continue;
                    }

                    var fieldType          = resolver.ResolveFieldType(field);
                    var sanitizedFieldName = SanitizeFieldName(field.Name);

                    var fieldInfo = new FieldGenInfo
                    {
                        Offset    = TypeUtils.GetFieldOffset(field.Name, typeRef, ArchBits),
                        FieldName = sanitizedFieldName,
                        FieldType = fieldType
                    };

                    m_FieldGenInfos.Add(fieldInfo);
                    m_FieldTypes.Add(fieldType);
                    m_FieldNames.Add(sanitizedFieldName);
                    lookup.Count++;
                }
                m_FieldInfoMap.Add(typeRef, lookup);

                // Now that we have added info for the top-level, recurse until all nested fields have fieldInfo
                foreach (var field in typeDef.Fields)
                {
                    if (field.IsStatic)
                    {
                        continue;
                    }

                    var fieldType = resolver.ResolveFieldType(field);
                    GenerateFieldInfos(fieldType);
                }
            }

            return(lookup);
        }
示例#7
0
        static IEnumerable <List <FieldReference> > IterateJobFields(TypeReference type,
                                                                     Func <FieldReference, bool> shouldYieldFilter,
                                                                     Func <FieldReference, bool> shouldRecurseFilter,
                                                                     List <FieldReference> fieldPath)
        {
            // The incoming `type` should be a full generic instance.  This genericResolver
            // will help us resolve the generic parameters of any of its fields
            var genericResolver = TypeResolver.For(type);

            foreach (var typeField in type.Resolve().Fields)
            {
                // Early out the statics: (may add an option to change this later. But see next comment.)
                // Excluding statics covers:
                // 1) enums which infinitely recurse because the values in the enum are of the same enum type
                // 2) statics which infinitely recurse themselves (Such as vector3.zero.zero.zero.zero)
                if (typeField.IsStatic)
                {
                    continue;
                }

                // The fully generic-resolved field reference.  This is the reference that's needed
                // as a Ldfld(a) reference.
                var genericResolvedFieldType = genericResolver.ResolveFieldType(typeField);

                var shouldYield   = shouldYieldFilter?.Invoke(typeField) ?? true;
                var shouldRecurse = shouldRecurseFilter?.Invoke(typeField) ?? true;

                if (!shouldYield && !shouldRecurse)
                {
                    continue;
                }

                var f = genericResolver.Resolve(typeField);
                fieldPath.Add(f);

                // yield the current field path
                if (shouldYield)
                {
                    yield return(fieldPath);
                }

                // only recurse into things that are straight values; no pointers or byref values
                if (shouldRecurse && typeField.FieldType.IsValueType && !typeField.FieldType.IsPrimitive)
                {
                    // make sure we iterate the FieldType with all generic params resolved
                    foreach (var fr in IterateJobFields(genericResolvedFieldType, shouldYieldFilter, shouldRecurseFilter, fieldPath))
                    {
                        yield return(fr);
                    }
                }

                fieldPath.RemoveAt(fieldPath.Count - 1);
            }
        }
示例#8
0
        internal static void GetFieldOffsetsOfRecurse(Func <FieldReference, TypeReference, bool> match, int offset, TypeReference type, List <int> list, int bits)
        {
            int in_type_offset = 0;
            var typeResolver   = TypeResolver.For(type);

            foreach (var f in type.Resolve().Fields)
            {
                if (f.IsStatic)
                {
                    continue;
                }

                uint alignUp(uint a, uint align) => (a + ((align - a) % align));
                int valueOr1(int v) => Math.Max(v, 1);

                TypeUtils.AlignAndSize resize(TypeUtils.AlignAndSize s) => new TypeUtils.AlignAndSize(
                    valueOr1(s.align),
                    valueOr1(s.size));

                var fieldReference = typeResolver.Resolve(f);
                var fieldType      = typeResolver.Resolve(f.FieldType);

                var tinfo = resize(TypeUtils.AlignAndSizeOfType(fieldType, bits));
                if (f.Offset != -1)
                {
                    in_type_offset = f.Offset;
                }
                else
                {
                    in_type_offset = (int)alignUp((uint)in_type_offset, (uint)tinfo.align);
                }

                if (fieldType.IsDynamicArray() && match(fieldReference, fieldType.DynamicArrayElementType()))
                {
                    // +1 so that we have a way to indicate an Array<Entity> at position 0
                    // fixup code subtracts 1
                    list.Add(-(offset + in_type_offset + 1));
                }
                else if (match(fieldReference, fieldType))
                {
                    list.Add(offset + in_type_offset);
                }
                else if (fieldType.IsValueType && !fieldType.IsPrimitive)
                {
                    GetFieldOffsetsOfRecurse(match, offset + in_type_offset, fieldType, list, bits);
                }

                in_type_offset += tinfo.size;
            }
        }
        static MethodDefinition CreateGetValueMethod(Context context, TypeReference containerType, TypeReference memberType, IMetadataTokenProvider member)
        {
            var method = new MethodDefinition
                         (
                @name: "GetValue",
                @attributes: MethodAttributes.Public |
                MethodAttributes.HideBySig |
                MethodAttributes.Virtual |
                MethodAttributes.ReuseSlot,
                @returnType: memberType
                         )
            {
                Body = { InitLocals = true }
            };

            var containerParameter = new ParameterDefinition("container", ParameterAttributes.None, new ByReferenceType(containerType));

            method.Parameters.Add(containerParameter);

            var il = method.Body.GetILProcessor();

            il.Emit(OpCodes.Ldarg_1); // container

            if (!containerType.IsValueType)
            {
                il.Emit(OpCodes.Ldind_Ref);
            }

            if (member is FieldDefinition field)
            {
                var resolvedDeclaringType = field.GetResolvedDeclaringType(containerType);
                var reference             = TypeResolver.For(resolvedDeclaringType).Resolve(field).CreateImportedType(context.Module);

                il.Emit(OpCodes.Ldfld, reference);
            }
            else if (member is PropertyDefinition property)
            {
                var resolvedDeclaringType = property.GetResolvedDeclaringType(containerType);
                var getMethod             = property.GetMethod.MakeGenericHostMethod(resolvedDeclaringType);
                getMethod.ReturnType = getMethod.ReturnType.CreateImportedType(context.Module);

                il.Emit(containerType != resolvedDeclaringType ? OpCodes.Callvirt : OpCodes.Call, context.Module.ImportReference(getMethod));
            }

            il.Emit(OpCodes.Ret);

            return(method);
        }
        public static int GetFieldOffset(string fieldName, TypeReference typeRefToLookIn, int archBits)
        {
            int in_type_offset  = 0;
            var typeResolver    = TypeResolver.For(typeRefToLookIn);
            var typeDefToLookIn = typeRefToLookIn.Resolve();

            foreach (var f in typeDefToLookIn.Fields)
            {
                if (f.IsStatic)
                {
                    continue;
                }

                uint alignUp(uint a, uint align) => (a + ((align - a) % align));
                int valueOr1(int v) => Math.Max(v, 1);

                TypeUtils.AlignAndSize resize(TypeUtils.AlignAndSize s) => new TypeUtils.AlignAndSize(
                    valueOr1(s.align),
                    valueOr1(s.size));

                var fieldReference = typeResolver.Resolve(f);
                var fieldType      = typeResolver.Resolve(f.FieldType);

                var tinfo = resize(TypeUtils.AlignAndSizeOfType(fieldType, archBits));
                if (f.Offset != -1)
                {
                    in_type_offset = f.Offset;
                }
                else
                {
                    in_type_offset = (int)alignUp((uint)in_type_offset, (uint)tinfo.align);
                }

                if (fieldName == f.Name)
                {
                    break;
                }

                in_type_offset += tinfo.size;
            }

            return(in_type_offset);
        }
示例#11
0
        public static ulong HashType(TypeReference typeRef, int fieldIndex = 0)
        {
            ulong hash         = kFNV1A64OffsetBasis;
            var   typeResolver = TypeResolver.For(typeRef);
            var   typeDef      = typeRef.Resolve();

            foreach (var field in typeDef.Fields)
            {
                if (!field.IsStatic)
                {
                    string fieldName = GetSanitizedFullName(typeResolver.Resolve(field.FieldType));
                    hash = CombineFNV1A64(hash, FNV1A64(fieldName));
                    hash = CombineFNV1A64(hash, FNV1A64(fieldIndex));
                    ++fieldIndex;
                }
            }

            return(hash);
        }
示例#12
0
        public static void IterateFieldsRecurse(Action <FieldReference, TypeReference> processFunc, TypeReference type)
        {
            var typeResolver = TypeResolver.For(type);

            foreach (var f in type.Resolve().Fields)
            {
                var fieldReference = typeResolver.Resolve(f);
                var fieldType      = typeResolver.Resolve(f.FieldType);

                processFunc(fieldReference, fieldType);

                // Excluding statics for recursion covers:
                // 1) enums which infinitely recurse because the values in the enum are of the same enum type
                // 2) statics which infinitely recurse themselves (Such as vector3.zero.zero.zero.zero)
                if (fieldType.IsValueType && !fieldType.IsPrimitive && !f.IsStatic)
                {
                    IterateFieldsRecurse(processFunc, fieldType);
                }
            }
        }
示例#13
0
        public static void ValidateAllowedObjectType(TypeReference typeRef)
        {
            TypeDefinition type = typeRef.Resolve();

            if (typeRef.IsPrimitive || type.IsEnum || typeRef.MetadataType == MetadataType.String)
            {
                return;
            }

            if (AlreadyValidated.Contains(type))
            {
                return;
            }

            AlreadyValidated.Add(type);

            var typeResolver = TypeResolver.For(type);

            foreach (var field in type.Fields)
            {
                ValidateAllowedObjectType(typeResolver.Resolve(field.FieldType));
            }
        }
示例#14
0
 public NativeToManagedInteropMethodBodyWriter(MethodReference managedMethod, MethodReference interopMethod, MarshalType marshalType, bool useUnicodeCharset) : base(interopMethod, managedMethod, new NativeToManagedMarshaler(TypeResolver.For(interopMethod.DeclaringType, interopMethod), marshalType, useUnicodeCharset))
 {
     this._managedMethod = managedMethod;
 }
示例#15
0
        public static void PreprocessTypeFields(TypeReference valuetype, int bits)
        {
            if (bits == 32)
            {
                bits = 0;
            }
            else if (bits == 64)
            {
                bits = 1;
            }

            int  size = 0;
            int  highestFieldAlignment = 0;
            bool isComplex             = false;

            // have we already preprocessed this?
            if (ValueTypeAlignment[bits].ContainsKey(valuetype) &&
                !ValueTypeAlignment[bits][valuetype].IsSentinel)
            {
                return;
            }

            // For each field, calculate its layout as if it was a C++ struct
            //Console.WriteLine($"Type {valuetype}");
            var typeResolver = TypeResolver.For(valuetype);
            var typeDef      = valuetype.Resolve();

            foreach (var fs in typeDef.Fields)
            {
                if (fs.IsStatic)
                {
                    continue;
                }

                var fieldType = typeResolver.Resolve(fs.FieldType);

                var sz = AlignAndSizeOfType(fieldType, bits);
                isComplex = isComplex || fieldType.IsComplex();

                // In C++, all members of a struct must have their own address.
                // If we have a "struct {}" as a member, treat its size as at least one byte.
                sz = new AlignAndSize(sz.align, Math.Max(sz.size, 1));
                highestFieldAlignment = Math.Max(highestFieldAlignment, sz.align);
                size = AlignUp(size, sz.align);
                //Console.WriteLine($"  Field: {fs.Name} ({fs.GetType()}) - offset: {size} alignment {sz.align} sz {sz.size}");
                StructFieldAlignment[bits].Add(typeResolver.Resolve(fs) /*VERIFY*/, new AlignAndSize(sz.align, sz.size, size));

                int offset = fs.Offset;
                if (offset >= 0)
                {
                    size = offset + sz.size;
                }
                else
                {
                    size += sz.size;
                }
            }
            // same min size for outer struct
            size = Math.Max(size, 1);

            // C++ aligns struct sizes up to the highest alignment required
            size = AlignUp(size, highestFieldAlignment);

            // If an explicit size have been provided use that instead
            if (typeDef.IsExplicitLayout && typeDef.ClassSize > 0)
            {
                size = typeDef.ClassSize;
            }

            // Alignment requirements are > 0
            highestFieldAlignment = Math.Max(highestFieldAlignment, 1);

            // If an explict alignment has been provided use that instead
            if (typeDef.IsExplicitLayout && typeDef.PackingSize > 0)
            {
                size = typeDef.PackingSize;
            }

            ValueTypeAlignment[bits].Remove(valuetype);
            ValueTypeAlignment[bits].Add(valuetype, new AlignAndSize(highestFieldAlignment, size, 0, typeDef.Fields.Count == 0));
            //Console.WriteLine($"ValueType: {valuetype.Name} ({valuetype.GetType()}) - alignment {highestFieldAlignment} sz {size}");
            ValueTypeIsComplex[bits].Add(valuetype, isComplex);
        }
        static MethodDefinition CreateSetValueMethod(Context context, TypeReference containerType, TypeReference memberType, IMetadataTokenProvider member, bool isReadOnly)
        {
            var method = new MethodDefinition
                         (
                @name: "SetValue",
                @attributes: MethodAttributes.Public |
                MethodAttributes.HideBySig |
                MethodAttributes.Virtual |
                MethodAttributes.ReuseSlot,
                @returnType: context.ImportReference(typeof(void))
                         )
            {
                Body = { InitLocals = true }
            };

            method.Parameters.Add(new ParameterDefinition("container", ParameterAttributes.None, new ByReferenceType(containerType)));
            method.Parameters.Add(new ParameterDefinition("value", ParameterAttributes.None, memberType));

            var il = method.Body.GetILProcessor();

            if (isReadOnly)
            {
                il.Emit(OpCodes.Ldstr, "Property is ReadOnly");
                il.Emit(OpCodes.Newobj, context.ExceptionConstructor.Value);
                il.Emit(OpCodes.Throw);
            }
            else
            {
                if (member is FieldDefinition field)
                {
                    var resolvedDeclaringType = field.GetResolvedDeclaringType(containerType);
                    var reference             = TypeResolver.For(resolvedDeclaringType).Resolve(field).CreateImportedType(context.Module);

                    il.Emit(OpCodes.Ldarg_1); // container

                    if (!containerType.IsValueType)
                    {
                        il.Emit(OpCodes.Ldind_Ref);
                    }

                    il.Emit(OpCodes.Ldarg_2); // value
                    il.Emit(OpCodes.Stfld, reference);
                    il.Emit(OpCodes.Ret);
                }
                else if (member is PropertyDefinition property)
                {
                    var resolvedDeclaringType = property.GetResolvedDeclaringType(containerType);
                    var setMethod             = property.SetMethod.MakeGenericHostMethod(resolvedDeclaringType);
                    setMethod.Parameters[0].ParameterType = setMethod.Parameters[0].ParameterType.CreateImportedType(context.Module);

                    il.Emit(OpCodes.Ldarg_1); // container

                    if (!containerType.IsValueType)
                    {
                        il.Emit(OpCodes.Ldind_Ref);
                    }

                    il.Emit(OpCodes.Ldarg_2); // value
                    il.Emit(containerType != resolvedDeclaringType ? OpCodes.Callvirt : OpCodes.Call, context.Module.ImportReference(setMethod));
                    il.Emit(OpCodes.Ret);
                }
            }

            return(method);
        }
 public ManagedToNativeInteropMethodBodyWriter(MethodReference interopMethod, MethodReference methodForParameterNames, MarshalType marshalType, bool useUnicodeCharset) : base(interopMethod, methodForParameterNames, new ManagedToNativeMarshaler(TypeResolver.For(interopMethod.DeclaringType, interopMethod), marshalType, useUnicodeCharset))
 {
 }
        static bool IsManagedTypeInternal(TypeReference typeRef, ref bool hasEntityRefs, ref bool hasBlobRefs, HashSet <TypeReference> seenTypes)
        {
            seenTypes.Add(typeRef);
            if (typeRef.IsPointer)
            {
                return(false);
            }

            if (typeRef.IsArray)
            {
                var elementType = typeRef.GetElementType();
                if (elementType.IsEntityType())
                {
                    hasEntityRefs = true;
                }
                else if (elementType.IsBlobAssetReferenceType())
                {
                    hasBlobRefs = true;
                }

                return(true);
            }

            if (typeRef.IsGenericParameter)
            {
                var  gp = (GenericParameter)typeRef;
                bool _ = false, __ = false;
                return(gp.Constraints.FirstOrDefault(c => c.IsManagedType(ref _, ref __)) != null);
            }

            var type = typeRef.Resolve();

            if (type.IsDynamicArray())
            {
                return(true);
            }

            TypeDefinition fixedSpecialType = type.FixedSpecialType();

            if (fixedSpecialType != null)
            {
                if (fixedSpecialType.MetadataType == MetadataType.String)
                {
                    return(true);
                }
                return(false);
            }

            if (type.IsEnum)
            {
                return(false);
            }

            // if none of the above check the type's fields
            bool isManaged    = !type.IsValueType;
            var  typeResolver = TypeResolver.For(typeRef);

            foreach (var field in type.Fields)
            {
                if (field.IsStatic)
                {
                    continue;
                }

                var fieldType = typeResolver.Resolve(field.FieldType);
                if (seenTypes.Contains(fieldType))
                {
                    continue;
                }

                var fieldTypeDef = fieldType.Resolve();

                if (fieldType.IsEntityType())
                {
                    hasEntityRefs = true;
                }
                else if (fieldType.IsBlobAssetReferenceType())
                {
                    hasBlobRefs = true;
                }

                if (!fieldTypeDef.IsSealed)
                {
                    hasEntityRefs = true;
                    hasBlobRefs   = true;
                }

                if (IsManagedTypeInternal(fieldType, ref hasEntityRefs, ref hasBlobRefs, seenTypes))
                {
                    isManaged = true;
                }
            }

            return(isManaged);
        }