예제 #1
0
        /// <summary>
        /// Compiles a type.
        /// </summary>
        /// <param name="type">The type.</param>
        public void Compile(TypeDefinition type)
        {
            TypeKind typeKind = getTypeKind(type);

            Logger.LogVerbose(typeKind.GetColor(), "Compiling type {0}", type.FullName);

            // Enums can be fully generated during the declaration pass. Nothing to do.
            if (typeKind == TypeKind.Enum)
            {
                return;
            }

            // Add interface type to lookup?
            if (typeKind == TypeKind.Interface)
            {
                mLookup.AddInterface(type);
            }

            // VTable.
            VTable vtable    = null;
            bool   hasVTable = ((typeKind == TypeKind.Interface) || (typeKind == TypeKind.Class && mCompiler.Lookup.NeedsVirtualCall(type)));

            if (hasVTable)
            {
                vtable = new VTable(mCompiler, type);
                mLookup.AddVTable(vtable);
                vtable.Create();
                vtable.Compile();
            }

            // Create struct for this type.
            TypeRef             data       = mLookup.GetTypeRef(type);
            List <TypeRef>      structData = new List <TypeRef>();
            List <IStructEntry> fields     = mLookup.GetStructLayout(type);

            // Fields.
            ulong          fieldTotalSize = 0;
            TypeDefinition currentType    = type;

            foreach (IStructEntry entry in fields)
            {
                // VTable for a class?
                if (entry.EntryType == StructEntryType.ClassVTable)
                {
                    // Only if there are virtual calls on this type.
                    if (hasVTable)
                    {
                        VTableEntry castedEntry = (VTableEntry)entry;
                        structData.Add(LLVM.PointerType(vtable.GetEntry(castedEntry.Type).Item1, 0));
                    }
                }
                // Entry that points to a table of VTables for interfaces
                else if (entry.EntryType == StructEntryType.InterfaceVTablesTable)
                {
                    structData.Add(TypeHelper.VoidPtr);
                }
                // Field entry
                else /*if(entry.EntryType == StructEntryType.Field)*/
                {
                    FieldDefinition field     = ((StructFieldEntry)entry).Field;
                    TypeRef         fieldType = TypeHelper.GetTypeRefFromType(field.FieldType);
                    currentType = field.DeclaringType;

                    // Static field.
                    if (field.IsStatic)
                    {
                        // Only add it if we don't have it already (is possible when inheriting classes).
                        if (!mLookup.HasStaticField(field))
                        {
                            ValueRef val = LLVM.AddGlobal(mCompiler.Module, fieldType, NameHelper.CreateFieldName(field.FullName));

                            // Note: the initializer may be changed later if the compiler sees that it can be constant.
                            LLVM.SetInitializer(val, LLVM.ConstNull(fieldType));
                            mLookup.AddStaticField(field, val);
                        }
                    }
                    // Field for type instance.
                    else
                    {
                        structData.Add(fieldType);
                        fieldTotalSize += LLVM.SizeOfTypeInBits(mCompiler.TargetData, fieldType) / 8;
                    }
                }
            }

            // Packing?
            bool packed = (type.PackingSize != -1);

            if (type.PackingSize != 1 && type.PackingSize != -1 && type.PackingSize != 0)
            {
                throw new NotImplementedException("The packing size " + type.PackingSize + " is not implemented");
            }

            // Fixed size?
            if (type.ClassSize > 0 && (int)fieldTotalSize < type.ClassSize)
            {
                if (typeKind != TypeKind.Struct)
                {
                    throw new InvalidOperationException("Fixed size not on a struct?!");
                }

                // Note: we treat char as 8-bit. So we need to check if we're dealing with chars.
                int classSize = type.ClassSize;
                if (type.Fields.Count == 1 && type.Fields[0].FieldType.FullName == "System.Char")
                {
                    classSize /= 2;
                }

                // Add bytes until the needed size is reached.
                int needed = classSize - (int)fieldTotalSize;
                for (int i = 0; i < needed; i++)
                {
                    structData.Add(TypeHelper.Int8);
                }
            }

            // Set struct data.
            LLVM.StructSetBody(data, structData.ToArray(), packed);

            // For classes, generate the "newobj" method.
            if (typeKind == TypeKind.Class)
            {
                ValueRef newobjFunc = createNewobjMethod(type);
                mCompiler.Lookup.AddNewobjMethod(type, newobjFunc);
            }
        }