예제 #1
0
        private void PInvokeEmitGlobals()
        {
            // Add ThunkPointers global, which contains the addresses of our thunk functions
            var thunkPointers = LLVM.AddGlobal(module, LLVM.ArrayType(intPtrLLVM, 4096), "ThunkPointers");

            if (TestMode)
            {
                LLVM.SetInitializer(thunkPointers, LLVM.ConstNull(LLVM.GetElementType(LLVM.TypeOf(thunkPointers))));
                return;
            }

            ValueRef[] thunkPointersData = new ValueRef[PInvokeThunkCount];
            for (int i = 0; i < PInvokeThunkCount; ++i)
            {
                thunkPointersData[i] = LLVM.AddGlobal(module, LLVM.GetElementType(intPtrLLVM), string.Format("thunk{0}", i));
            }
            LLVM.SetInitializer(thunkPointers, LLVM.ConstArray(intPtrLLVM, thunkPointersData));

            // Add TLS variable for storing current thunk ID
            var thunkCurrentId = LLVM.AddGlobal(module, int32LLVM, "ThunkCurrentId");

            LLVM.SetThreadLocal(thunkCurrentId, true);

            var pinvokeThunks = PInvokeEmitThunks();

            LLVM.SetModuleInlineAsm(module, pinvokeThunks.ToString());
        }
 public static LLVMValueRef EmitGlobal(LLVMModuleRef module, FieldDesc field, NameMangler nameMangler)
 {
     if (field.IsStatic)
     {
         if (s_staticFieldMapping.TryGetValue(field, out LLVMValueRef existingValue))
         {
             return(existingValue);
         }
         else
         {
             var valueType = LLVM.ArrayType(LLVM.Int8Type(), (uint)field.FieldType.GetElementSize().AsInt);
             var llvmValue = LLVM.AddGlobal(module, valueType, nameMangler.GetMangledFieldName(field).ToString());
             LLVM.SetLinkage(llvmValue, LLVMLinkage.LLVMInternalLinkage);
             LLVM.SetInitializer(llvmValue, GetConstZeroArray(field.FieldType.GetElementSize().AsInt));
             if (field.IsThreadStatic)
             {
                 LLVM.SetThreadLocal(llvmValue, LLVMMisc.True);
             }
             s_staticFieldMapping.Add(field, llvmValue);
             return(llvmValue);
         }
     }
     else
     {
         throw new NotImplementedException();
     }
 }
예제 #3
0
        private ValueRef CreateStringConstant(string str, bool utf16, bool nullTerminate)
        {
            ValueRef stringConstantData;

            // Create string data global
            if (utf16)
            {
                var utf16String = str.Select(x => LLVM.ConstInt(LLVM.Int16TypeInContext(context), x, false));
                if (nullTerminate)
                {
                    utf16String = utf16String.Concat(new[] { LLVM.ConstNull(LLVM.Int16TypeInContext(context)) });
                }

                stringConstantData = LLVM.ConstArray(LLVM.Int16TypeInContext(context), utf16String.ToArray());
            }
            else // utf8
            {
                stringConstantData = LLVM.ConstStringInContext(context, str, (uint)str.Length, !nullTerminate);
            }

            var stringConstantDataGlobal = LLVM.AddGlobal(module, LLVM.TypeOf(stringConstantData), ".str");

            // Cast from i8-array to i8*
            LLVM.SetInitializer(stringConstantDataGlobal, stringConstantData);
            var zero = LLVM.ConstInt(int32Type, 0, false);

            stringConstantDataGlobal = LLVM.ConstInBoundsGEP(stringConstantDataGlobal, new[] { zero, zero });

            return(stringConstantDataGlobal);
        }
예제 #4
0
        public LlvmGlobal CreateGlobal(string identifier, LlvmType type)
        {
            // Create and wrap the global value reference.
            LlvmGlobal reference = new LlvmGlobal(LLVM.AddGlobal(this.reference, type.Unwrap(), identifier));

            // Return the reference.
            return(reference);
        }
예제 #5
0
        public LLVMValueRef GetGlobal(string name, LLVMTypeRef type)
        {
            if (_globals.ContainsKey(name))
            {
                return(_globals[name]);
            }

            LLVMValueRef @ref = LLVM.AddGlobal(Module, type, name);

            _globals[name] = @ref;
            return(@ref);
        }
예제 #6
0
        void CompileString(StringExpression expr)
        {
            var strlen = (uint)expr.Value.Length;
            var arr    = LLVM.ArrayType(LLVM.Int8Type(), strlen + 1);
            var val    = LLVM.AddGlobal(LLVMModule, arr, "string");

            LLVM.SetLinkage(val, LLVMLinkage.LLVMInternalLinkage);
            LLVM.SetGlobalConstant(val, true);
            var str = LLVM.ConstString(expr.Value, strlen, false);

            LLVM.SetInitializer(val, str);
            Stack.Push(Symbol.CreateAnonymous(val, SpecialValue.String));
        }
예제 #7
0
        private void GenSymbol(Symbol sym)
        {
            if (sym?.Type == null)
            {
                throw new ArgumentException();
            }

            var type = types.Get(sym.Type);

            var value = LLVM.AddGlobal(module, type, sym.Name.ID);

            // LLVM.SetInitializer(value, LLVM.ConstAllOnes(type));
            symbols.Add(sym, value);
        }
예제 #8
0
파일: Compiler.cs 프로젝트: uppi/SharpLang
        public void PrepareAssembly(AssemblyDefinition assembly)
        {
            this.assembly = assembly;

            RegisterExternalTypes();

            // Resolve corlib assembly
            corlib = assembly.MainModule.Import(typeof(void)).Resolve().Module.Assembly;

            // Prepare LLVM context, module and data layouts
            context = LLVM.GetGlobalContext();
            module  = LLVM.ModuleCreateWithName(assembly.Name.Name);

            // Prepare system types, for easier access
            InitializeCommonTypes();

            // TODO: Choose appropriate triple depending on target
            var target = LLVM.GetTarget(runtimeModule);

            LLVM.SetTarget(module, target);

            // Initialize ABI
            abi = new DefaultABI(context, targetData);

            // Prepare LLVM builders
            builder       = LLVM.CreateBuilderInContext(context);
            builder2      = LLVM.CreateBuilderInContext(context);
            builderAlloca = LLVM.CreateBuilderInContext(context);

            InitializeDebug();

            if (!TestMode)
            {
                // Register SharpLangModule objects for each module
                metadataPerModule = new Dictionary <Mono.Cecil.ModuleDefinition, ValueRef>();
                var mangledModuleName     = Regex.Replace(assembly.Name.Name + ".sharplangmodule", @"(\W)", "_");
                var sharpLangModuleGlobal = LLVM.AddGlobal(module, sharpLangModuleType.ObjectTypeLLVM, mangledModuleName);
                metadataPerModule[assembly.MainModule] = sharpLangModuleGlobal;

                // Generate extern globals for SharpLangModule instances of other modules
                foreach (var referencedAssembly in referencedAssemblies)
                {
                    mangledModuleName = Regex.Replace(referencedAssembly.Name.Name + ".sharplangmodule", @"(\W)", "_");
                    var externalSharpLangModuleGlobal = LLVM.AddGlobal(module, sharpLangModuleType.ObjectTypeLLVM, mangledModuleName);
                    LLVM.SetLinkage(externalSharpLangModuleGlobal, Linkage.ExternalLinkage);
                    metadataPerModule[referencedAssembly.MainModule] = externalSharpLangModuleGlobal;
                }
            }
        }
예제 #9
0
        /// <summary>
        /// Declares a static field.
        /// </summary>
        /// <param name="fieldDef">The static field definition</param>
        public void DeclareField(FieldDefinition fieldDef)
        {
            var globalType  = typeLookup.GetLLVMTypeRef(fieldDef.FieldType);
            var globalValue = LLVM.AddGlobal(moduleRef, globalType, fieldDef.FullName);

            fieldMap.Add(fieldDef, globalValue);

            // TODO: optimize using InitialValue?

            /*System.Console.WriteLine(fieldDef.InitialValue);
             * foreach(byte b in fieldDef.InitialValue)
             *  System.Console.WriteLine(b);*/

            LLVM.SetInitializer(globalValue, LLVM.ConstNull(globalType));
        }
예제 #10
0
        public LLVMValueRef Emit(LLVMModuleRef context)
        {
            // Create the global variable.
            LLVMValueRef globalVar = LLVM.AddGlobal(context, Type.Emit(), Name);

            // Set the linkage to common.
            globalVar.SetLinkage(LLVMLinkage.LLVMCommonLinkage);

            // Assign value if applicable.
            if (Value != null)
            {
                globalVar.SetInitializer(Value.Emit());
            }

            return(globalVar);
        }
예제 #11
0
파일: GlobalVar.cs 프로젝트: BowsiePup/Ion
        public LLVMValueRef Emit(PipeContext <Module> context)
        {
            // Create the global variable.
            LLVMValueRef globalVar = LLVM.AddGlobal(context.Target.Target, this.Type.Emit(), this.Identifier);

            // Set the linkage to common.
            globalVar.SetLinkage(LLVMLinkage.LLVMCommonLinkage);

            // Assign value if applicable.
            if (this.Value != null)
            {
                globalVar.SetInitializer(this.Value.Emit());
            }

            return(globalVar);
        }
예제 #12
0
        private void EmitLdstr(List <StackValue> stack, string operand)
        {
            var stringType = GetType(corlib.MainModule.GetType(typeof(string).FullName));

            // Create string data global
            var stringConstantData       = LLVM.ConstStringInContext(context, operand, (uint)operand.Length, true);
            var stringConstantDataGlobal = LLVM.AddGlobal(module, LLVM.TypeOf(stringConstantData), string.Empty);

            // Cast from i8-array to i8*
            LLVM.SetInitializer(stringConstantDataGlobal, stringConstantData);
            var zero = LLVM.ConstInt(int32Type, 0, false);

            stringConstantDataGlobal = LLVM.ConstInBoundsGEP(stringConstantDataGlobal, new[] { zero, zero });

            // Create string
            var stringConstant = LLVM.ConstNamedStruct(stringType.DefaultType,
                                                       new[] { LLVM.ConstIntToPtr(LLVM.ConstInt(int64Type, (ulong)operand.Length, false), intPtrType), stringConstantDataGlobal });

            // Push on stack
            stack.Add(new StackValue(StackValueType.Value, stringType, stringConstant));
        }
예제 #13
0
        private LLVMValueRef GetTypeMetadataTable(IType type, ModuleBuilder module)
        {
            var name = "vtable_" + module.Mangler.Mangle(type, true);

            if (!typesWithMeta.Add(type))
            {
                return(LLVM.GetNamedGlobal(module.Module, name));
            }

            // Compose the vtable's contents.
            var entries = new List <LLVMValueRef>();

            // A unique type tag.
            entries.Add(GetTypeTagValue(type, module));
            // Virtual function addresses.
            foreach (var method in GetVTableLayout(type))
            {
                if (method.IsAbstract())
                {
                    entries.Add(LLVM.ConstNull(LLVM.PointerType(module.GetFunctionPrototype(method), 0)));
                }
                else
                {
                    entries.Add(module.DeclareMethod(method));
                }
            }

            var metadataTableContents = LLVM.ConstStructInContext(
                module.Context,
                entries.ToArray(),
                false);
            var metadataTable = LLVM.AddGlobal(module.Module, metadataTableContents.TypeOf(), name);

            metadataTable.SetInitializer(metadataTableContents);
            metadataTable.SetLinkage(LLVMLinkage.LLVMInternalLinkage);
            metadataTable.SetGlobalConstant(true);
            return(metadataTable);
        }
예제 #14
0
        public LLVMValueRef DefineStaticField(IField field)
        {
            LLVMValueRef result;

            if (fieldDecls.TryGetValue(field, out result))
            {
                return(result);
            }

            if (!field.IsStatic)
            {
                throw new InvalidOperationException($"Cannot define non-static field '{field.FullName}' as a global.");
            }

            var type = ImportType(field.FieldType);
            var name = Mangler.Mangle(field, true);

            result = LLVM.AddGlobal(Module, type, name);
            result.SetInitializer(LLVM.ConstNull(type));
            result.SetLinkage(GetLinkageForLocal(field));
            fieldDecls[field] = result;
            return(result);
        }
예제 #15
0
        /// <summary>
        /// Creates the LLVM types.
        /// </summary>
        private void createTypes()
        {
            string typeName = NameHelper.CreateTypeName(mType);

            foreach (KeyValuePair <TypeDefinition, Dictionary <string, int> > names in mNameTable)
            {
                string name = string.Format("vtable_{0}_part_{1}", typeName, NameHelper.CreateTypeName(names.Key));
                Dictionary <string, int> idDict = names.Value;

                // Initialize to pointers.
                TypeRef[] types = new TypeRef[idDict.Count];
                for (int i = 0; i < names.Value.Count; i++)
                {
                    types[i] = TypeHelper.VoidPtr;
                }

                TypeRef  type   = LLVM.StructTypeInContext(mCompiler.ModuleContext, types, false);
                ValueRef global = LLVM.AddGlobal(mCompiler.Module, type, name);
                LLVM.SetLinkage(global, Linkage.PrivateLinkage);

                mGeneratedTable.Add(names.Key, new Tuple <TypeRef, ValueRef>(type, global));
            }
        }
예제 #16
0
        public override int VisitMemberVariableDeclarationStatement([NotNull] ClepsParser.MemberVariableDeclarationStatementContext context)
        {
            string className    = String.Join(".", CurrentNamespaceAndClass);
            bool   isStatic     = context.STATIC() != null;
            string variableName = context.FieldName.Name.Text;

            if (ClassManager.DoesClassContainMember(className, variableName))
            {
                string errorMessage = String.Format("Class {0} has multiple definitions of member {1}", className, variableName);
                Status.AddError(new CompilerError(FileName, context.Start.Line, context.Start.Column, errorMessage));
                //Don't process this member
                return(-1);
            }

            ClepsParser.TypenameContext variableTypeContext = context.typename();
            ClepsType clepsVariableType = ClepsType.GetBasicType(variableTypeContext);

            // only static members are defined immediately. member variables are defined at the at end of parsing a class
            if (isStatic)
            {
                string      fullyQualifiedName = String.Format("{0}.{1}", className, variableName);
                LLVMTypeRef?llvmMemberType     = ClepsLLVMTypeConvertorInst.GetLLVMTypeOrNull(clepsVariableType);

                if (llvmMemberType == null)
                {
                    string errorMessage = String.Format("Type {0} was not found", clepsVariableType.GetTypeName());
                    Status.AddError(new CompilerError(FileName, context.Start.Line, context.Start.Column, errorMessage));
                    return(-1);
                }

                LLVM.AddGlobal(Module, llvmMemberType.Value, fullyQualifiedName);
            }

            ClassManager.AddNewMember(className, variableName, isStatic, clepsVariableType);
            return(0);
        }
예제 #17
0
        /// <summary>
        /// Compiles the specified class.
        /// </summary>
        /// <param name="typeReference">The type definition.</param>
        /// <returns></returns>
        private Class GetClass(Type type)
        {
            bool processClass  = false;
            bool processFields = false;
            var  typeReference = type.TypeReference;

            switch (typeReference.MetadataType)
            {
            case MetadataType.ByReference:
            case MetadataType.Void:
            case MetadataType.Pointer:
                // Should return something similar to IntPtr?
                return(null);

            case MetadataType.Boolean:
            case MetadataType.Char:
            case MetadataType.Byte:
            case MetadataType.SByte:
            case MetadataType.Int16:
            case MetadataType.UInt16:
            case MetadataType.Int32:
            case MetadataType.UInt32:
            case MetadataType.Int64:
            case MetadataType.UInt64:
            case MetadataType.IntPtr:
            case MetadataType.UIntPtr:
            case MetadataType.Single:
            case MetadataType.Double:
            {
                processClass  = true;
                processFields = true;
                break;
            }

            case MetadataType.Array:
            case MetadataType.String:
            case MetadataType.TypedByReference:
            case MetadataType.ValueType:
            case MetadataType.Class:
            case MetadataType.Object:
            case MetadataType.GenericInstance:
            {
                // Process class and instance fields
                processClass  = true;
                processFields = true;
                break;
            }

            default:
                throw new NotImplementedException();
            }

            // Create class version (boxed version with VTable)
            var boxedType = type.ObjectType;
            var dataType  = type.DataType;
            var valueType = type.ValueType;

            if (type.Class != null)
            {
                return(type.Class);
            }

            var @class = type.Class = new Class(type);

            if (processClass)
            {
                var baseType       = GetBaseTypeDefinition(typeReference);
                var typeDefinition = GetMethodTypeDefinition(typeReference);

                var fieldTypes = new List <TypeRef>(typeDefinition.Fields.Count);

                var parentClass = baseType != null?GetClass(ResolveGenericsVisitor.Process(typeReference, baseType)) : null;

                // Add parent class
                if (parentClass != null)
                {
                    @class.BaseType = parentClass;

                    // Add parent virtual methods
                    @class.VirtualTable.AddRange(parentClass.VirtualTable.TakeWhile(x => x.MethodReference.Resolve().IsVirtual));
                    foreach (var @interface in parentClass.Interfaces)
                    {
                        @class.Interfaces.Add(@interface);
                    }

                    @class.Depth = parentClass.Depth + 1;
                }

                if (typeReference is ArrayType)
                {
                    var elementType = ResolveGenericsVisitor.Process(typeReference, ((ArrayType)typeReference).ElementType);

                    // Array types implicitely inherits from IList<T>, ICollection<T>, IReadOnlyList<T>, IReadOnlyCollection<T> and IEnumerable<T>
                    foreach (var interfaceType in new[] { typeof(IList <>), typeof(ICollection <>), typeof(IReadOnlyCollection <>), typeof(IReadOnlyList <>), typeof(IEnumerable <>) })
                    {
                        var @interfaceGeneric = corlib.MainModule.GetType(interfaceType.FullName);
                        var @interface        = @interfaceGeneric.MakeGenericInstanceType(elementType);
                        @class.Interfaces.Add(GetClass(@interface));
                    }
                }

                // Build methods slots
                // TODO: This will trigger their compilation, but maybe we might want to defer that later
                // (esp. since vtable is not built yet => recursion issues)
                PrepareClassMethods(type);

                if (typeDefinition.IsInterface)
                {
                    // Interface: No need for vtable, we can just use object's one
                    var vtableGlobal = GetClass(assembly.MainModule.Import(typeof(object))).GeneratedRuntimeTypeInfoGlobal;
                    LLVM.StructSetBody(boxedType, new[] { LLVM.TypeOf(vtableGlobal), valueType }, false);
                    @class.GeneratedRuntimeTypeInfoGlobal = vtableGlobal;
                }
                else
                {
                    // Get parent type RTTI
                    var parentRuntimeTypeInfoType = parentClass != null
                        ? LLVM.TypeOf(parentClass.GeneratedRuntimeTypeInfoGlobal)
                        : intPtrType;

                    // Build vtable
                    var vtableType = LLVM.StructTypeInContext(context, @class.VirtualTable.Select(x => LLVM.TypeOf(x.GeneratedValue)).ToArray(), false);

                    foreach (var @interface in typeDefinition.Interfaces)
                    {
                        var resolvedInterface = ResolveGenericsVisitor.Process(typeReference, @interface);
                        @class.Interfaces.Add(GetClass(resolvedInterface));

                        // TODO: Add any inherited interface inherited by the resolvedInterface as well
                    }

                    // Build static fields
                    foreach (var field in typeDefinition.Fields)
                    {
                        if (!field.IsStatic)
                        {
                            continue;
                        }

                        var fieldType = CreateType(assembly.MainModule.Import(ResolveGenericsVisitor.Process(typeReference, field.FieldType)));
                        @class.Fields.Add(field, new Field(field, @class, fieldType, fieldTypes.Count));
                        fieldTypes.Add(fieldType.DefaultType);
                    }

                    var staticFieldsType = LLVM.StructTypeInContext(context, fieldTypes.ToArray(), false);
                    fieldTypes.Clear(); // Reused for non-static fields after

                    var runtimeTypeInfoType = LLVM.StructTypeInContext(context, new []
                    {
                        parentRuntimeTypeInfoType,
                        int32Type,
                        int32Type,
                        LLVM.PointerType(intPtrType, 0),
                        LLVM.PointerType(intPtrType, 0),
                        LLVM.Int1TypeInContext(context),
                        LLVM.ArrayType(intPtrType, InterfaceMethodTableSize),
                        vtableType,
                        staticFieldsType,
                    }, false);

                    var runtimeTypeInfoGlobal = LLVM.AddGlobal(module, runtimeTypeInfoType, typeReference.MangledName() + ".rtti");
                    @class.GeneratedRuntimeTypeInfoGlobal = runtimeTypeInfoGlobal;

                    if (@class.Type.IsLocal)
                    {
                        BuildRuntimeType(@class);
                    }
                    else
                    {
                        LLVM.SetLinkage(runtimeTypeInfoGlobal, Linkage.ExternalWeakLinkage);
                    }

                    LLVM.StructSetBody(boxedType, new[] { LLVM.TypeOf(runtimeTypeInfoGlobal), valueType }, false);
                }

                // Prepare class initializer
                if (@class.StaticCtor != null || typeDefinition.Methods.Any(x => x.HasPInvokeInfo))
                {
                    //  void EnsureClassInitialized()
                    //  {
                    //      //lock (initMutex) < TODO: not implemented yet
                    //      {
                    //          if (!classInitialized)
                    //          {
                    //              InitializeClass();
                    //              classInitialized = true;
                    //          }
                    //      }
                    //  }
                    var initTypeFunction = LLVM.AddFunction(module, typeReference.MangledName() + "_inittype", LLVM.FunctionType(LLVM.VoidTypeInContext(context), new TypeRef[0], false));
                    var block            = LLVM.AppendBasicBlockInContext(context, initTypeFunction, string.Empty);
                    LLVM.PositionBuilderAtEnd(builder2, block);

                    // Check if class is initialized
                    var indices = new[]
                    {
                        LLVM.ConstInt(int32Type, 0, false),                                                 // Pointer indirection
                        LLVM.ConstInt(int32Type, (int)RuntimeTypeInfoFields.TypeInitialized, false),        // Type initialized flag
                    };

                    var classInitializedAddress = LLVM.BuildInBoundsGEP(builder2, @class.GeneratedRuntimeTypeInfoGlobal, indices, string.Empty);
                    var classInitialized        = LLVM.BuildLoad(builder2, classInitializedAddress, string.Empty);

                    var typeNeedInitBlock = LLVM.AppendBasicBlockInContext(context, initTypeFunction, string.Empty);
                    var nextBlock         = LLVM.AppendBasicBlockInContext(context, initTypeFunction, string.Empty);

                    LLVM.BuildCondBr(builder2, classInitialized, nextBlock, typeNeedInitBlock);

                    // Initialize class (first time)
                    LLVM.PositionBuilderAtEnd(builder2, typeNeedInitBlock);

                    // Static ctor
                    if (@class.StaticCtor != null)
                    {
                        LLVM.BuildCall(builder2, @class.StaticCtor.GeneratedValue, new ValueRef[0], string.Empty);
                    }

                    // TODO: PInvoke initialization
                    foreach (var pinvokeModule in typeDefinition.Methods.Where(x => x.HasPInvokeInfo).GroupBy(x => x.PInvokeInfo.Module))
                    {
                        var libraryName = CreateStringConstant(pinvokeModule.Key.Name, false, true);
                        var pinvokeLoadLibraryResult = LLVM.BuildCall(builder2, pinvokeLoadLibraryFunction, new[] { libraryName }, string.Empty);

                        foreach (var method in pinvokeModule)
                        {
                            var entryPoint = CreateStringConstant(method.PInvokeInfo.EntryPoint, false, true);
                            var pinvokeGetProcAddressResult = LLVM.BuildCall(builder2, pinvokeGetProcAddressFunction,
                                                                             new[]
                            {
                                pinvokeLoadLibraryResult,
                                entryPoint,
                            }, string.Empty);

                            // TODO: Resolve method using generic context.
                            indices = new[]
                            {
                                LLVM.ConstInt(int32Type, 0, false),                                         // Pointer indirection
                                LLVM.ConstInt(int32Type, (int)RuntimeTypeInfoFields.VirtualTable, false),   // Access vtable
                                LLVM.ConstInt(int32Type, (ulong)GetFunction(method).VirtualSlot, false),    // Access specific vtable slot
                            };

                            // Get vtable slot and cast to proper type
                            var vtableSlot = LLVM.BuildInBoundsGEP(builder2, @class.GeneratedRuntimeTypeInfoGlobal, indices, string.Empty);
                            pinvokeGetProcAddressResult = LLVM.BuildPointerCast(builder2, pinvokeGetProcAddressResult, LLVM.GetElementType(LLVM.TypeOf(vtableSlot)), string.Empty);

                            // Store value
                            LLVM.BuildStore(builder2, pinvokeGetProcAddressResult, vtableSlot);
                        }
                    }

                    // Set flag so that it won't be initialized again
                    LLVM.BuildStore(builder2, LLVM.ConstInt(LLVM.Int1TypeInContext(context), 1, false), classInitializedAddress);
                    LLVM.BuildBr(builder2, nextBlock);

                    LLVM.PositionBuilderAtEnd(builder2, nextBlock);
                    LLVM.BuildRetVoid(builder2);

                    @class.InitializeType = initTypeFunction;
                }

                // Sometime, GetType might already define DataType (for standard CLR types such as int, enum, string, array, etc...).
                // In that case, do not process fields.
                if (processFields && LLVM.GetTypeKind(valueType) == TypeKind.StructTypeKind && LLVM.IsOpaqueStruct(valueType))
                {
                    // Build actual type data (fields)
                    // Add fields and vtable slots from parent class
                    if (parentClass != null && type.StackType == StackValueType.Object)
                    {
                        fieldTypes.Add(parentClass.Type.DataType);
                    }

                    // Special cases: Array
                    if (typeReference.MetadataType == MetadataType.Array)
                    {
                        // String: length (native int) + first element pointer
                        var arrayType   = (ArrayType)typeReference;
                        var elementType = CreateType(arrayType.ElementType);
                        fieldTypes.Add(intPtrType);
                        fieldTypes.Add(LLVM.PointerType(elementType.DefaultType, 0));
                    }
                    else
                    {
                        foreach (var field in typeDefinition.Fields)
                        {
                            if (field.IsStatic)
                            {
                                continue;
                            }

                            var fieldType = CreateType(assembly.MainModule.Import(ResolveGenericsVisitor.Process(typeReference, field.FieldType)));
                            @class.Fields.Add(field, new Field(field, @class, fieldType, fieldTypes.Count));
                            fieldTypes.Add(fieldType.DefaultType);
                        }
                    }

                    LLVM.StructSetBody(valueType, fieldTypes.ToArray(), false);
                }
            }

            return(@class);
        }
예제 #18
0
        public ModuleRef GenerateModule()
        {
            LLVM.DIBuilderCreateCompileUnit(debugBuilder,
                                            0x4, // DW_LANG_C_plus_plus
                                            "file", "directory", "SharpLang", false, string.Empty, 1, string.Empty);

            LLVM.AddModuleFlag(module, "Dwarf Version", 4);
            LLVM.AddModuleFlag(module, "Debug Info Version", 1);

            // Process methods
            while (classesToGenerate.Count > 0)
            {
                var classToGenerate = classesToGenerate.Dequeue();
                if (classToGenerate.IsLocal)
                {
                    PrepareClassMethods(classToGenerate);
                }
            }

            // Generate code
            while (methodsToCompile.Count > 0)
            {
                var methodToCompile = methodsToCompile.Dequeue();
                //Console.WriteLine("Compiling {0}", methodToCompile.Key.FullName);
                CompileFunction(methodToCompile.Key, methodToCompile.Value);
            }

            // Prepare global module constructor
            var globalCtorFunctionType = LLVM.FunctionType(LLVM.VoidTypeInContext(context), new TypeRef[0], false);
            var globalCtor             = LLVM.AddFunction(module, "initializeSharpLangModule", globalCtorFunctionType);

            LLVM.SetLinkage(globalCtor, Linkage.PrivateLinkage);
            LLVM.PositionBuilderAtEnd(builder, LLVM.AppendBasicBlockInContext(context, globalCtor, string.Empty));

            if (!TestMode)
            {
                // Emit metadata
                var metadataBytes = ReadMetadata(assembly.MainModule.FullyQualifiedName);
                var metadataData  = CreateDataConstant(metadataBytes);

                var metadataGlobal = LLVM.AddGlobal(module, LLVM.TypeOf(metadataData), "metadata");
                LLVM.SetInitializer(metadataGlobal, metadataData);
                LLVM.SetLinkage(metadataGlobal, Linkage.PrivateLinkage);


                // Use metadata to initialize a SharpLangModule, that will be created at module load time using a global ctor
                sharpLangModuleType = GetType(corlib.MainModule.GetType("System.SharpLangModule"), TypeState.VTableEmitted);
                sharpLangTypeType   = GetType(corlib.MainModule.GetType("System.SharpLangTypeDefinition"), TypeState.VTableEmitted); // Was only StackComplete until now

                // Get ctor for SharpLangModule and SharpLangType
                var moduleCtor = sharpLangModuleType.Class.Functions.First(x => x.DeclaringType == sharpLangModuleType && x.MethodReference.Resolve().IsConstructor);

                var registerTypeMethod = sharpLangModuleType.Class.Functions.First(x => x.DeclaringType == sharpLangModuleType && x.MethodReference.Name == "RegisterType");
                var sortTypesMethod    = sharpLangModuleType.Class.Functions.First(x => x.DeclaringType == sharpLangModuleType && x.MethodReference.Name == "SortTypes");

                // Initialize SharpLangModule instance:
                //   new SharpLangModule(moduleName, metadataStart, metadataLength)
                var sharpLangModuleGlobal = metadataPerModule[assembly.MainModule];
                var functionContext       = new FunctionCompilerContext(globalCtor);
                functionContext.Stack = new List <StackValue>();
                functionContext.Stack.Add(new StackValue(StackValueType.Object, sharpLangModuleType, sharpLangModuleGlobal));
                functionContext.Stack.Add(new StackValue(StackValueType.NativeInt, intPtr, metadataGlobal));
                functionContext.Stack.Add(new StackValue(StackValueType.Int32, int32, LLVM.ConstInt(int32LLVM, (ulong)metadataBytes.Length, false)));

                // Setup initial value (note: VTable should be valid)
                LLVM.SetLinkage(sharpLangModuleGlobal, Linkage.ExternalLinkage);
                LLVM.SetInitializer(sharpLangModuleGlobal, SetupVTableConstant(LLVM.ConstNull(sharpLangModuleType.ObjectTypeLLVM), sharpLangModuleType.Class));
                metadataPerModule[assembly.MainModule] = sharpLangModuleGlobal;

                EmitCall(functionContext, moduleCtor.Signature, moduleCtor.GeneratedValue);

                // Register types
                foreach (var type in types)
                {
                    var @class = type.Value.Class;

                    // Skip incomplete types
                    if (@class == null || [email protected])
                    {
                        continue;
                    }

                    // Skip if no RTTI initializer
                    if (LLVM.GetInitializer(@class.GeneratedEETypeRuntimeLLVM) == ValueRef.Empty)
                    {
                        continue;
                    }

                    // Skip if interface (fake RTTI pointer)
                    if (type.Value.TypeDefinitionCecil.IsInterface)
                    {
                        continue;
                    }

                    functionContext.Stack.Add(new StackValue(StackValueType.NativeInt, intPtr, LLVM.ConstPointerCast(@class.GeneratedEETypeRuntimeLLVM, intPtrLLVM)));
                    EmitCall(functionContext, registerTypeMethod.Signature, registerTypeMethod.GeneratedValue);
                }

                // Sort and remove duplicates after adding all our types
                // TODO: Somehow sort everything before insertion at compile time?
                EmitCall(functionContext, sortTypesMethod.Signature, sortTypesMethod.GeneratedValue);

                LLVM.BuildRetVoid(builder);
            }
            else
            {
                LLVM.BuildRetVoid(builder);
            }

            // Prepare global ctors
            {
                var globalCtorType    = LLVM.StructTypeInContext(context, new[] { int32LLVM, LLVM.PointerType(globalCtorFunctionType, 0) }, true);
                var globalCtorsGlobal = LLVM.AddGlobal(module, LLVM.ArrayType(globalCtorType, 1), "llvm.global_ctors");
                LLVM.SetLinkage(globalCtorsGlobal, Linkage.AppendingLinkage);
                LLVM.SetInitializer(globalCtorsGlobal,
                                    LLVM.ConstArray(globalCtorType, new [] {
                    LLVM.ConstNamedStruct(globalCtorType, new[]
                    {
                        LLVM.ConstInt(int32LLVM, (ulong)65536, false),
                        globalCtor,
                    })
                }));
            }

            // Emit "main" which will call the assembly entry point (if any)
            Function entryPoint;

            if (assembly.EntryPoint != null && functions.TryGetValue(assembly.EntryPoint, out entryPoint))
            {
                var mainFunctionType = LLVM.FunctionType(int32LLVM, new TypeRef[0], false);
                var mainFunction     = LLVM.AddFunction(module, "main", mainFunctionType);
                LLVM.SetLinkage(mainFunction, Linkage.ExternalLinkage);
                LLVM.PositionBuilderAtEnd(builder, LLVM.AppendBasicBlockInContext(context, mainFunction, string.Empty));

                var parameters = (entryPoint.ParameterTypes.Length > 0)
                        ? new[] { LLVM.ConstPointerNull(entryPoint.ParameterTypes[0].DefaultTypeLLVM) }
                        : new ValueRef[0];

                LLVM.BuildCall(builder, entryPoint.GeneratedValue, parameters, string.Empty);
                LLVM.BuildRet(builder, LLVM.ConstInt(int32LLVM, 0, false));
            }

            LLVM.DIBuilderFinalize(debugBuilder);
            LLVM.DIBuilderDispose(debugBuilder);
            LLVM.DisposeBuilder(builder);

            return(module);
        }
예제 #19
0
        public static void EmitObject(string objectFilePath, IEnumerable <DependencyNode> nodes, NodeFactory factory, WebAssemblyCodegenCompilation compilation, IObjectDumper dumper)
        {
            WebAssemblyObjectWriter objectWriter = new WebAssemblyObjectWriter(objectFilePath, factory, compilation);
            bool succeeded = false;

            try
            {
                //ObjectNodeSection managedCodeSection = null;

                var listOfOffsets = new List <int>();
                foreach (DependencyNode depNode in nodes)
                {
                    ObjectNode node = depNode as ObjectNode;
                    if (node == null)
                    {
                        continue;
                    }

                    if (node.ShouldSkipEmittingObjectNode(factory))
                    {
                        continue;
                    }

                    if (node is EETypeNode)
                    {
                        DefType t           = ((EETypeNode)node).Type.GetClosestDefType();
                        int     iSlot       = GetVTableSlotsCount(factory, t.BaseType);
                        var     pointerSize = factory.Target.PointerSize;
                        foreach (MethodDesc m in factory.VTable(t).Slots)
                        {
                            // set _getslot variable to sizeof(EEType) + iSlot * pointer size
                            string       realSymbolName = factory.NameMangler.GetMangledMethodName(m).ToString();
                            var          globalRefName  = "__getslot__" + realSymbolName;
                            LLVMValueRef slot           = LLVM.GetNamedGlobal(compilation.Module, globalRefName);
                            if (slot.Pointer == IntPtr.Zero)
                            {
                                slot = LLVM.AddGlobal(compilation.Module, LLVM.Int32Type(), globalRefName);
                            }
                            LLVM.SetInitializer(slot, LLVM.ConstInt(LLVM.Int32Type(), (ulong)((EETypeNode.GetVTableOffset(pointerSize) / pointerSize) + iSlot), LLVMMisc.False));
                            LLVM.SetGlobalConstant(slot, LLVMMisc.True);
                            iSlot++;
                        }
                    }

                    objectWriter.StartObjectNode(node);
                    ObjectData nodeContents = node.GetData(factory);

                    if (dumper != null)
                    {
                        dumper.DumpObjectNode(factory.NameMangler, node, nodeContents);
                    }

#if DEBUG
                    foreach (ISymbolNode definedSymbol in nodeContents.DefinedSymbols)
                    {
                        try
                        {
                            _previouslyWrittenNodeNames.Add(definedSymbol.GetMangledName(factory.NameMangler), definedSymbol);
                        }
                        catch (ArgumentException)
                        {
                            ISymbolNode alreadyWrittenSymbol = _previouslyWrittenNodeNames[definedSymbol.GetMangledName(factory.NameMangler)];
                            Debug.Fail("Duplicate node name emitted to file",
                                       $"Symbol {definedSymbol.GetMangledName(factory.NameMangler)} has already been written to the output object file {objectFilePath} with symbol {alreadyWrittenSymbol}");
                        }
                    }
#endif

                    ObjectNodeSection section = node.Section;
                    if (objectWriter.ShouldShareSymbol(node))
                    {
                        section = objectWriter.GetSharedSection(section, ((ISymbolNode)node).GetMangledName(factory.NameMangler));
                    }

                    // Ensure section and alignment for the node.
                    objectWriter.SetSection(section);
                    objectWriter.EmitAlignment(nodeContents.Alignment);

                    objectWriter.ResetByteRunInterruptionOffsets(nodeContents.Relocs);

                    // Build symbol definition map.
                    objectWriter.BuildSymbolDefinitionMap(node, nodeContents.DefinedSymbols);

                    Relocation[] relocs          = nodeContents.Relocs;
                    int          nextRelocOffset = -1;
                    int          nextRelocIndex  = -1;
                    if (relocs.Length > 0)
                    {
                        nextRelocOffset = relocs[0].Offset;
                        nextRelocIndex  = 0;
                    }

                    int i = 0;

                    listOfOffsets.Clear();
                    listOfOffsets.AddRange(objectWriter._byteInterruptionOffsets);

                    int offsetIndex = 0;
                    while (i < nodeContents.Data.Length)
                    {
                        // Emit symbol definitions if necessary
                        objectWriter.EmitSymbolDefinition(i);

                        if (i == nextRelocOffset)
                        {
                            Relocation reloc = relocs[nextRelocIndex];

                            long delta;
                            unsafe
                            {
                                fixed(void *location = &nodeContents.Data[i])
                                {
                                    delta = Relocation.ReadValue(reloc.RelocType, location);
                                }
                            }
                            int size = objectWriter.EmitSymbolReference(reloc.Target, (int)delta, reloc.RelocType);

                            /*
                             * WebAssembly has no thumb
                             * // Emit a copy of original Thumb2 instruction that came from RyuJIT
                             * if (reloc.RelocType == RelocType.IMAGE_REL_BASED_THUMB_MOV32 ||
                             *  reloc.RelocType == RelocType.IMAGE_REL_BASED_THUMB_BRANCH24)
                             * {
                             *  unsafe
                             *  {
                             *      fixed (void* location = &nodeContents.Data[i])
                             *      {
                             *          objectWriter.EmitBytes((IntPtr)location, size);
                             *      }
                             *  }
                             * }*/

                            // Update nextRelocIndex/Offset
                            if (++nextRelocIndex < relocs.Length)
                            {
                                nextRelocOffset = relocs[nextRelocIndex].Offset;
                            }
                            else
                            {
                                // This is the last reloc. Set the next reloc offset to -1 in case the last reloc has a zero size,
                                // which means the reloc does not have vacant bytes corresponding to in the data buffer. E.g,
                                // IMAGE_REL_THUMB_BRANCH24 is a kind of 24-bit reloc whose bits scatte over the instruction that
                                // references it. We do not vacate extra bytes in the data buffer for this kind of reloc.
                                nextRelocOffset = -1;
                            }
                            i += size;
                        }
                        else
                        {
                            while (offsetIndex < listOfOffsets.Count && listOfOffsets[offsetIndex] <= i)
                            {
                                offsetIndex++;
                            }

                            int nextOffset = offsetIndex == listOfOffsets.Count ? nodeContents.Data.Length : listOfOffsets[offsetIndex];

                            unsafe
                            {
                                // Todo: Use Span<T> instead once it's available to us in this repo
                                fixed(byte *pContents = &nodeContents.Data[i])
                                {
                                    objectWriter.EmitBytes((IntPtr)(pContents), nextOffset - i);
                                    i += nextOffset - i;
                                }
                            }
                        }
                    }
                    Debug.Assert(i == nodeContents.Data.Length);

                    // It is possible to have a symbol just after all of the data.
                    objectWriter.EmitSymbolDefinition(nodeContents.Data.Length);
                    objectWriter.DoneObjectNode();
                }

                succeeded = true;
            }
            finally
            {
                objectWriter.Dispose();

                if (!succeeded)
                {
                    // If there was an exception while generating the OBJ file, make sure we don't leave the unfinished
                    // object file around.
                    try
                    {
                        File.Delete(objectFilePath);
                    }
                    catch
                    {
                    }
                }
            }
        }
예제 #20
0
        private void BuildRuntimeType(Class @class)
        {
            if (@class.IsEmitted)
            {
                return;
            }

            @class.IsEmitted = true;

            // Build IMT
            var interfaceMethodTable = new LinkedList <InterfaceMethodTableEntry> [InterfaceMethodTableSize];

            foreach (var @interface in @class.Interfaces)
            {
                foreach (var interfaceMethod in @interface.Type.TypeReference.Resolve().Methods)
                {
                    var resolvedInterfaceMethod = ResolveGenericMethod(@interface.Type.TypeReference, interfaceMethod);

                    // If method is not fully resolved (generic method in interface), ignore it
                    // We are waiting for actual closed uses.
                    if (ResolveGenericsVisitor.ContainsGenericParameters(resolvedInterfaceMethod))
                    {
                        continue;
                    }

                    var resolvedFunction = CecilExtensions.TryMatchMethod(@class, resolvedInterfaceMethod);
                    if (resolvedFunction == null && @class.Type.TypeReference is ArrayType)
                    {
                        var arrayType      = corlib.MainModule.GetType(typeof(Array).FullName);
                        var matchingMethod = (MethodReference)arrayType.Methods.First(x => x.Name.StartsWith("InternalArray_") && x.Name.EndsWith(resolvedInterfaceMethod.Name));
                        if (matchingMethod != null)
                        {
                            if (matchingMethod.HasGenericParameters)
                            {
                                matchingMethod = matchingMethod.MakeGenericMethod(((ArrayType)@class.Type.TypeReference).ElementType);
                            }

                            resolvedFunction = GetFunction(matchingMethod);

                            // Manually emit Array functions locally (until proper mscorlib + generic instantiation exists).
                            EmitFunction(resolvedFunction);
                        }
                    }

                    if (resolvedFunction == null)
                    {
                        throw new InvalidOperationException(string.Format("Could not find matching method for {0} in {1}", resolvedInterfaceMethod, @class));
                    }

                    var isInterface = resolvedFunction.DeclaringType.TypeReference.Resolve().IsInterface;
                    if (!isInterface && resolvedFunction.MethodReference.Resolve().IsVirtual&& resolvedFunction.VirtualSlot != -1)
                    {
                        // We might have found a base virtual method matching this interface method.
                        // Let's get the actual method override for this virtual slot.
                        resolvedFunction = @class.VirtualTable[resolvedFunction.VirtualSlot];
                    }

                    // If method is not found, it could be due to covariance/contravariance
                    if (resolvedFunction == null)
                    {
                        throw new InvalidOperationException("Interface method not found");
                    }

                    var methodId     = GetMethodId(resolvedInterfaceMethod);
                    var imtSlotIndex = (int)(methodId % interfaceMethodTable.Length);

                    var imtSlot = interfaceMethodTable[imtSlotIndex];
                    if (imtSlot == null)
                    {
                        interfaceMethodTable[imtSlotIndex] = imtSlot = new LinkedList <InterfaceMethodTableEntry>();
                    }

                    imtSlot.AddLast(new InterfaceMethodTableEntry
                    {
                        Function  = resolvedFunction,
                        MethodId  = methodId,
                        SlotIndex = imtSlotIndex
                    });
                }
            }
            var interfaceMethodTableConstant = LLVM.ConstArray(intPtrType, interfaceMethodTable.Select(imtSlot =>
            {
                if (imtSlot == null)
                {
                    // No entries: null slot
                    return(LLVM.ConstNull(intPtrType));
                }

                if (imtSlot.Count == 1)
                {
                    // Single entry
                    var imtEntry = imtSlot.First.Value;
                    return(LLVM.ConstPointerCast(imtEntry.Function.GeneratedValue, intPtrType));
                }
                else
                {
                    // Multiple entries, create IMT array with all entries
                    // TODO: Support covariance/contravariance?
                    var imtEntries = LLVM.ConstArray(imtEntryType, imtSlot.Select(imtEntry =>
                    {
                        return(LLVM.ConstNamedStruct(imtEntryType, new[]
                        {
                            LLVM.ConstInt(int32Type, (ulong)imtEntry.MethodId, false),           // i32 functionId
                            LLVM.ConstPointerCast(imtEntry.Function.GeneratedValue, intPtrType), // i8* functionPtr
                        }));
                    })
                                                     .Concat(Enumerable.Repeat(LLVM.ConstNull(imtEntryType), 1)).ToArray()); // Append { 0, 0 } terminator
                    var imtEntryGlobal = LLVM.AddGlobal(module, LLVM.TypeOf(imtEntries), @class.Type.TypeReference.MangledName() + ".imt");
                    LLVM.SetInitializer(imtEntryGlobal, imtEntries);

                    // Add 1 to differentiate between single entry and IMT array
                    return(LLVM.ConstIntToPtr(
                               LLVM.ConstAdd(
                                   LLVM.ConstPtrToInt(imtEntryGlobal, nativeIntType),
                                   LLVM.ConstInt(nativeIntType, 1, false)),
                               intPtrType));
                }
            }).ToArray());


            // Build list of super types
            var superTypes   = new List <Class>(@class.Depth);
            var currentClass = @class;

            while (currentClass != null)
            {
                superTypes.Add(currentClass);
                currentClass = currentClass.BaseType;
            }

            // Reverse so that the list start with most inherited object
            // (allows faster type checking since a given type will always be at a given index)
            superTypes.Reverse();

            // Build super types
            // Helpful for fast is/as checks on class hierarchy
            var superTypeCount  = LLVM.ConstInt(int32Type, (ulong)@class.Depth + 1, false);
            var interfacesCount = LLVM.ConstInt(int32Type, (ulong)@class.Interfaces.Count, false);

            var zero = LLVM.ConstInt(int32Type, 0, false);

            // Super types global
            var superTypesConstantGlobal = LLVM.AddGlobal(module, LLVM.ArrayType(intPtrType, (uint)superTypes.Count),
                                                          @class.Type.TypeReference.MangledName() + ".supertypes");
            var superTypesGlobal = LLVM.ConstInBoundsGEP(superTypesConstantGlobal, new[] { zero, zero });

            // Interface map global
            var interfacesConstantGlobal = LLVM.AddGlobal(module, LLVM.ArrayType(intPtrType, (uint)@class.Interfaces.Count),
                                                          @class.Type.TypeReference.MangledName() + ".interfaces");
            var interfacesGlobal = LLVM.ConstInBoundsGEP(interfacesConstantGlobal, new[] { zero, zero });

            // Build VTable
            var vtableConstant = LLVM.ConstStructInContext(context, @class.VirtualTable.Select(x => x.GeneratedValue).ToArray(), false);

            // Build RTTI
            var runtimeTypeInfoGlobal       = @class.GeneratedRuntimeTypeInfoGlobal;
            var runtimeTypeInfoType         = LLVM.GetElementType(LLVM.TypeOf(runtimeTypeInfoGlobal));
            var runtimeTypeInfoTypeElements = new TypeRef[LLVM.CountStructElementTypes(runtimeTypeInfoType)];

            LLVM.GetStructElementTypes(runtimeTypeInfoType, runtimeTypeInfoTypeElements);
            var runtimeTypeInfoConstant = LLVM.ConstNamedStruct(runtimeTypeInfoType, new[]
            {
                @class.BaseType != null ? @class.BaseType.GeneratedRuntimeTypeInfoGlobal : LLVM.ConstPointerNull(intPtrType),
                superTypeCount,
                interfacesCount,
                superTypesGlobal,
                interfacesGlobal,
                LLVM.ConstInt(LLVM.Int1TypeInContext(context), 0, false), // Class initialized?
                interfaceMethodTableConstant,
                vtableConstant,
                LLVM.ConstNull(runtimeTypeInfoTypeElements[(int)RuntimeTypeInfoFields.StaticFields]),
            });

            LLVM.SetInitializer(runtimeTypeInfoGlobal, runtimeTypeInfoConstant);

            // Build super type list (after RTTI since we need pointer to RTTI)
            var superTypesConstant = LLVM.ConstArray(intPtrType,
                                                     superTypes.Select(superType => LLVM.ConstPointerCast(superType.GeneratedRuntimeTypeInfoGlobal, intPtrType))
                                                     .ToArray());

            LLVM.SetInitializer(superTypesConstantGlobal, superTypesConstant);

            // Build interface map
            var interfacesConstant = LLVM.ConstArray(intPtrType,
                                                     @class.Interfaces.Select(
                                                         @interface => LLVM.ConstPointerCast(@interface.GeneratedRuntimeTypeInfoGlobal, intPtrType)).ToArray());

            LLVM.SetInitializer(interfacesConstantGlobal, interfacesConstant);

            // Mark RTTI as external
            LLVM.SetLinkage(runtimeTypeInfoGlobal, Linkage.ExternalLinkage);
        }
예제 #21
0
        /// <summary>
        /// Compiles the specified class.
        /// </summary>
        /// <param name="typeReference">The type definition.</param>
        /// <returns></returns>
        private Class CreateClass(TypeReference typeReference)
        {
            Class @class;

            if (classes.TryGetValue(typeReference, out @class))
            {
                return(@class);
            }

            bool processFields = false;

            switch (typeReference.MetadataType)
            {
            case MetadataType.Void:
            case MetadataType.Boolean:
            case MetadataType.Char:
            case MetadataType.Byte:
            case MetadataType.SByte:
            case MetadataType.Int16:
            case MetadataType.UInt16:
            case MetadataType.Int32:
            case MetadataType.UInt32:
            case MetadataType.Int64:
            case MetadataType.UInt64:
            case MetadataType.IntPtr:
            case MetadataType.UIntPtr:
            case MetadataType.Single:
            case MetadataType.Double:
            case MetadataType.String:
            {
                break;
            }

            case MetadataType.ValueType:
            case MetadataType.Class:
            case MetadataType.Object:
            case MetadataType.GenericInstance:
            {
                // Process non-static fields
                processFields = true;
                break;
            }

            default:
                throw new NotImplementedException();
            }

            var type = GetType(typeReference);

            // Create class version (boxed version with VTable)
            var boxedType = type.ObjectType;
            var dataType  = type.DataType;
            var stackType = type.StackType;

            @class = new Class(type, typeReference, dataType, boxedType, stackType);
            classes.Add(typeReference, @class);

            if (processFields)
            {
                var typeDefinition = typeReference.Resolve();

                var fieldTypes = new List <TypeRef>(typeDefinition.Fields.Count);

                var parentClass = typeDefinition.BaseType != null?GetClass(ResolveGenericsVisitor.Process(typeReference, typeDefinition.BaseType)) : null;

                // Add parent class
                if (parentClass != null)
                {
                    @class.BaseType = parentClass;

                    // Add parent classes
                    @class.VirtualTable.AddRange(parentClass.VirtualTable);
                    foreach (var @interface in parentClass.Interfaces)
                    {
                        @class.Interfaces.Add(@interface);
                    }
                }

                // Build methods slots
                // TODO: This will trigger their compilation, but maybe we might want to defer that later
                // (esp. since vtable is not built yet => recursion issues)
                CompileClassMethods(@class);

                if (typeDefinition.IsInterface)
                {
                    // Interface: No need for vtable, we can just use object's one
                    var vtableGlobal = GetClass(assembly.MainModule.Import(typeof(object))).GeneratedRuntimeTypeInfoGlobal;
                    LLVM.StructSetBody(boxedType, new[] { LLVM.TypeOf(vtableGlobal), dataType }, false);
                    @class.GeneratedRuntimeTypeInfoGlobal = vtableGlobal;
                }
                else
                {
                    // Get parent type RTTI
                    var runtimeTypeInfoType   = LLVM.PointerType(LLVM.Int8TypeInContext(context), 0);
                    var parentRuntimeTypeInfo = parentClass != null
                        ? LLVM.ConstPointerCast(parentClass.GeneratedRuntimeTypeInfoGlobal, runtimeTypeInfoType)
                        : LLVM.ConstPointerNull(runtimeTypeInfoType);

                    // Build vtable
                    var vtableConstant = LLVM.ConstStructInContext(context, @class.VirtualTable.Select(x => x.GeneratedValue).ToArray(), false);

                    // Build IMT
                    var interfaceMethodTable = new LinkedList <InterfaceMethodTableEntry> [InterfaceMethodTableSize];
                    foreach (var @interface in typeDefinition.Interfaces)
                    {
                        var resolvedInterface = ResolveGenericsVisitor.Process(typeReference, @interface);
                        @class.Interfaces.Add(GetClass(resolvedInterface));

                        // TODO: Add any inherited interface inherited by the resolvedInterface as well
                    }

                    foreach (var @interface in @class.Interfaces)
                    {
                        foreach (var interfaceMethod in @interface.TypeReference.Resolve().Methods)
                        {
                            var resolvedInterfaceMethod = ResolveGenericMethod(@interface.TypeReference, interfaceMethod);

                            var resolvedFunction = CecilExtensions.TryMatchMethod(@class, resolvedInterfaceMethod);

                            // If method is not found, it could be due to covariance/contravariance
                            if (resolvedFunction == null)
                            {
                                throw new InvalidOperationException("Interface method not found");
                            }

                            var methodId     = GetMethodId(resolvedInterfaceMethod);
                            var imtSlotIndex = (int)(methodId % interfaceMethodTable.Length);

                            var imtSlot = interfaceMethodTable[imtSlotIndex];
                            if (imtSlot == null)
                            {
                                interfaceMethodTable[imtSlotIndex] = imtSlot = new LinkedList <InterfaceMethodTableEntry>();
                            }

                            imtSlot.AddLast(new InterfaceMethodTableEntry {
                                Function = resolvedFunction, MethodId = methodId, SlotIndex = imtSlotIndex
                            });
                        }
                    }
                    var interfaceMethodTableConstant = LLVM.ConstArray(imtEntryType, interfaceMethodTable.Select(imtSlot =>
                    {
                        if (imtSlot == null)
                        {
                            // No entries: null slot
                            return(LLVM.ConstNull(imtEntryType));
                        }

                        if (imtSlot.Count > 1)
                        {
                            throw new NotImplementedException("IMT with more than one entry per slot is not implemented yet.");
                        }

                        var imtEntry = imtSlot.First.Value;
                        return(LLVM.ConstNamedStruct(imtEntryType, new[]
                        {
                            LLVM.ConstPointerCast(imtEntry.Function.GeneratedValue, intPtrType),                // i8* functionPtr
                            LLVM.ConstInt(int32Type, (ulong)imtEntry.MethodId, false),                          // i32 functionId
                            LLVM.ConstPointerNull(LLVM.PointerType(imtEntryType, 0)),                           // IMTEntry* nextSlot
                        }));
                    }).ToArray());

                    // Build static fields
                    foreach (var field in typeDefinition.Fields)
                    {
                        if (!field.IsStatic)
                        {
                            continue;
                        }

                        var fieldType = CreateType(assembly.MainModule.Import(ResolveGenericsVisitor.Process(typeReference, field.FieldType)));
                        @class.Fields.Add(field, new Field(field, @class, fieldType, fieldTypes.Count));
                        fieldTypes.Add(fieldType.DefaultType);
                    }

                    var staticFieldsEmpty = LLVM.ConstNull(LLVM.StructTypeInContext(context, fieldTypes.ToArray(), false));
                    fieldTypes.Clear(); // Reused for non-static fields after

                    // Build RTTI
                    var runtimeTypeInfoConstant = LLVM.ConstStructInContext(context, new[] { parentRuntimeTypeInfo, interfaceMethodTableConstant, vtableConstant, staticFieldsEmpty }, false);
                    var vtableGlobal            = LLVM.AddGlobal(module, LLVM.TypeOf(runtimeTypeInfoConstant), string.Empty);
                    LLVM.SetInitializer(vtableGlobal, runtimeTypeInfoConstant);
                    LLVM.StructSetBody(boxedType, new[] { LLVM.TypeOf(vtableGlobal), dataType }, false);
                    @class.GeneratedRuntimeTypeInfoGlobal = vtableGlobal;
                }

                // Build actual type data (fields)
                // Add fields and vtable slots from parent class
                if (parentClass != null && typeReference.MetadataType == MetadataType.Class)
                {
                    fieldTypes.Add(parentClass.DataType);
                }

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

                    var fieldType = CreateType(assembly.MainModule.Import(ResolveGenericsVisitor.Process(typeReference, field.FieldType)));
                    @class.Fields.Add(field, new Field(field, @class, fieldType, fieldTypes.Count));
                    fieldTypes.Add(fieldType.DefaultType);
                }

                LLVM.StructSetBody(dataType, fieldTypes.ToArray(), false);
            }

            return(@class);
        }
예제 #22
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);
            }
        }
예제 #23
0
        /// <summary>
        /// Compiles the specified class.
        /// </summary>
        /// <param name="typeReference">The type definition.</param>
        /// <returns></returns>
        private Class GetClass(Type type)
        {
            bool processClass  = false;
            bool processFields = false;
            var  typeReference = type.TypeReferenceCecil;

            // Need complete type
            GetType(type.TypeReferenceCecil, TypeState.TypeComplete);

            switch (typeReference.MetadataType)
            {
            case MetadataType.ByReference:
            case MetadataType.Void:
            case MetadataType.Pointer:
                // Should return something similar to IntPtr?
                return(null);

            case MetadataType.Boolean:
            case MetadataType.Char:
            case MetadataType.Byte:
            case MetadataType.SByte:
            case MetadataType.Int16:
            case MetadataType.UInt16:
            case MetadataType.Int32:
            case MetadataType.UInt32:
            case MetadataType.Int64:
            case MetadataType.UInt64:
            case MetadataType.IntPtr:
            case MetadataType.UIntPtr:
            case MetadataType.Single:
            case MetadataType.Double:
            {
                processClass = true;
                break;
            }

            case MetadataType.Array:
            case MetadataType.String:
            case MetadataType.TypedByReference:
            case MetadataType.ValueType:
            case MetadataType.Class:
            case MetadataType.Object:
            case MetadataType.GenericInstance:
            {
                // Process class and instance fields
                processClass = true;
                break;
            }

            default:
                throw new NotImplementedException();
            }

            // Create class version (boxed version with VTable)
            var boxedType = type.ObjectTypeLLVM;
            var valueType = type.ValueTypeLLVM;

            if (type.Class != null)
            {
                return(type.Class);
            }

            var @class = type.Class = new Class(type);

            if (processClass)
            {
                var baseType       = GetBaseTypeDefinition(typeReference);
                var typeDefinition = GetMethodTypeDefinition(typeReference);

                var fieldTypes = new List <TypeRef>(typeDefinition.Fields.Count);

                var parentClass = baseType != null?GetClass(ResolveGenericsVisitor.Process(typeReference, baseType)) : null;

                // Add parent class
                if (parentClass != null)
                {
                    @class.BaseType = parentClass;

                    // Add parent virtual methods
                    @class.VirtualTable.AddRange(parentClass.VirtualTable.TakeWhile(x => x.MethodReference.Resolve().IsVirtual));
                    foreach (var @interface in parentClass.Interfaces)
                    {
                        @class.Interfaces.Add(@interface);
                    }

                    @class.Depth = parentClass.Depth + 1;
                }

                if (typeReference is ArrayType)
                {
                    var elementType = ResolveGenericsVisitor.Process(typeReference, ((ArrayType)typeReference).ElementType);

                    // Array types implicitely inherits from IList<T>, ICollection<T>, IReadOnlyList<T>, IReadOnlyCollection<T> and IEnumerable<T>
                    foreach (var interfaceType in new[] { typeof(IList <>), typeof(ICollection <>), typeof(IReadOnlyCollection <>), typeof(IReadOnlyList <>), typeof(IEnumerable <>) })
                    {
                        var @interfaceGeneric = corlib.MainModule.GetType(interfaceType.FullName);
                        var @interface        = @interfaceGeneric.MakeGenericInstanceType(elementType);
                        @class.Interfaces.Add(GetClass(@interface));
                    }
                }

                if (baseType != null && baseType.FullName == typeof(MulticastDelegate).FullName)
                {
                    // Add GetMulticastDispatchMethod runtime class on delegates
                    var getMulticastDispatchMethod = new MethodDefinition("GetMulticastDispatchMethod", MethodAttributes.Private, intPtr.TypeReferenceCecil);
                    getMulticastDispatchMethod.HasThis        = true;
                    getMulticastDispatchMethod.Attributes     = MethodAttributes.HideBySig | MethodAttributes.Virtual | MethodAttributes.Final;
                    getMulticastDispatchMethod.ImplAttributes = MethodImplAttributes.Runtime;
                    typeDefinition.Methods.Add(getMulticastDispatchMethod);
                }

                // Build methods slots
                // TODO: This will trigger their compilation, but maybe we might want to defer that later
                // (esp. since vtable is not built yet => recursion issues)
                PrepareClassMethods(type);

                {
                    // Get parent type RTTI
                    var parentRuntimeTypeInfoType = parentClass != null
                        ? LLVM.TypeOf(parentClass.GeneratedEETypeRuntimeLLVM)
                        : intPtrLLVM;

                    var runtimeTypeInfoFields = new List <TypeRef>
                    {
                        parentRuntimeTypeInfoType,
                        LLVM.Int8TypeInContext(context), // IsConcreteType
                        typeDefLLVM,
                        intPtrLLVM,
                        sharpLangTypeType.DefaultTypeLLVM, // CachedType
                    };

                    bool isConcreteType = IsConcreteType(@class.Type);

                    // Create runtime type (still opaque struct)
                    var runtimeTypeInfoType = LLVM.StructCreateNamed(context, typeReference.MangledName() + ".rtti_type");

                    // Remove invalid characters so that we can easily link against it from C++
                    var mangledRttiName       = Regex.Replace(typeReference.MangledName() + ".rtti", @"(\W)", "_");
                    var runtimeTypeInfoGlobal = LLVM.AddGlobal(module, runtimeTypeInfoType, mangledRttiName);

                    if (typeDefinition.IsInterface)
                    {
                        // Interface use object as execution engine type
                        @class.GeneratedEETypeRuntimeLLVM = GetClass(@object).GeneratedEETypeTokenLLVM;
                    }
                    else
                    {
                        @class.GeneratedEETypeRuntimeLLVM = runtimeTypeInfoGlobal;
                    }

                    @class.GeneratedEETypeTokenLLVM = runtimeTypeInfoGlobal;

                    if (isConcreteType)
                    {
                        // Build vtable
                        @class.VTableTypeLLVM = LLVM.StructCreateNamed(context, typeReference.MangledName() + ".vtable");
                        LLVM.StructSetBody(@class.VTableTypeLLVM, @class.VirtualTable.Select(x => LLVM.PointerType(x.VirtualFunctionType, 0)).ToArray(), false);

                        foreach (var @interface in typeDefinition.Interfaces)
                        {
                            var resolvedInterface = ResolveGenericsVisitor.Process(typeReference, @interface);
                            @class.Interfaces.Add(GetClass(resolvedInterface));

                            // TODO: Add any inherited interface inherited by the resolvedInterface as well
                        }

                        // Build static fields
                        foreach (var field in typeDefinition.Fields)
                        {
                            if (!field.IsStatic)
                            {
                                continue;
                            }

                            var fieldType = GetType(ResolveGenericsVisitor.Process(typeReference, field.FieldType), TypeState.StackComplete);

                            @class.StaticFields.Add(field, new Field(field, type, fieldType, fieldTypes.Count));
                            fieldTypes.Add(fieldType.DefaultTypeLLVM);
                        }

                        var staticFieldsType = LLVM.StructCreateNamed(context, typeReference.MangledName() + ".static");
                        LLVM.StructSetBody(staticFieldsType, fieldTypes.ToArray(), false);
                        fieldTypes.Clear(); // Reused for non-static fields after

                        runtimeTypeInfoFields.AddRange(new[]
                        {
                            int32LLVM,                                            // SuperTypesCount
                            int32LLVM,                                            // InterfacesCount
                            LLVM.PointerType(intPtrLLVM, 0),                      // SuperTypes
                            LLVM.PointerType(intPtrLLVM, 0),                      // InterfaceMap
                            LLVM.Int8TypeInContext(context),                      // TypeInitialized
                            LLVM.Int32TypeInContext(context),                     // ObjectSize
                            LLVM.Int32TypeInContext(context),                     // ElementSize
                            LLVM.ArrayType(intPtrLLVM, InterfaceMethodTableSize), // IMT
                            int32LLVM,                                            // VTableSize
                            @class.VTableTypeLLVM,                                // VTable
                            staticFieldsType,                                     // StaticFields
                        });
                    }

                    LLVM.StructSetBody(runtimeTypeInfoType, runtimeTypeInfoFields.ToArray(), false);
                    LLVM.StructSetBody(boxedType, new[] { LLVM.TypeOf(@class.GeneratedEETypeRuntimeLLVM), valueType }, false);

                    if (@class.Type.IsLocal)
                    {
                        BuildRuntimeType(@class);
                    }

                    // Apply linkage
                    LLVM.SetLinkage(runtimeTypeInfoGlobal, @class.Type.Linkage);
                }

                // Prepare class initializer
                if (@class.StaticCtor != null || typeDefinition.Methods.Any(x => x.HasPInvokeInfo))
                {
                    //  void EnsureClassInitialized()
                    //  {
                    //      //lock (initMutex) < TODO: not implemented yet
                    //      {
                    //          if (!classInitialized)
                    //          {
                    //              classInitialized = true;
                    //              InitializeClass();
                    //          }
                    //      }
                    //  }
                    var initTypeFunction = LLVM.AddFunction(module, typeReference.MangledName() + "_inittype", LLVM.FunctionType(LLVM.VoidTypeInContext(context), new TypeRef[0], false));

                    // TODO: Temporarily emit it multiple time (once per assembly), that should be fixed!
                    LLVM.SetLinkage(initTypeFunction, Linkage.LinkOnceAnyLinkage);

                    var block = LLVM.AppendBasicBlockInContext(context, initTypeFunction, string.Empty);
                    LLVM.PositionBuilderAtEnd(builder2, block);

                    // Check if class is initialized
                    var indices = new[]
                    {
                        LLVM.ConstInt(int32LLVM, 0, false),                                                 // Pointer indirection
                        LLVM.ConstInt(int32LLVM, (int)RuntimeTypeInfoFields.TypeInitialized, false),        // Type initialized flag
                    };

                    var classInitializedAddress = LLVM.BuildInBoundsGEP(builder2, @class.GeneratedEETypeRuntimeLLVM, indices, string.Empty);
                    var classInitialized        = LLVM.BuildLoad(builder2, classInitializedAddress, string.Empty);
                    classInitialized = LLVM.BuildIntCast(builder2, classInitialized, LLVM.Int1TypeInContext(context), string.Empty);

                    var typeNeedInitBlock = LLVM.AppendBasicBlockInContext(context, initTypeFunction, string.Empty);
                    var nextBlock         = LLVM.AppendBasicBlockInContext(context, initTypeFunction, string.Empty);

                    LLVM.BuildCondBr(builder2, classInitialized, nextBlock, typeNeedInitBlock);

                    // Initialize class (first time)
                    LLVM.PositionBuilderAtEnd(builder2, typeNeedInitBlock);

                    // Set flag so that it won't be initialized again
                    LLVM.BuildStore(builder2, LLVM.ConstInt(LLVM.Int8TypeInContext(context), 1, false), classInitializedAddress);

                    // TODO: PInvoke initialization
                    foreach (var pinvokeModule in typeDefinition.Methods.Where(x => x.HasPInvokeInfo).GroupBy(x => x.PInvokeInfo.Module))
                    {
                        var libraryName = CreateStringConstant(pinvokeModule.Key.Name, false, true);
                        var pinvokeLoadLibraryResult = LLVM.BuildCall(builder2, pinvokeLoadLibraryFunctionLLVM, new[] { libraryName }, string.Empty);

                        foreach (var method in pinvokeModule)
                        {
                            var entryPoint = CreateStringConstant(method.PInvokeInfo.EntryPoint, false, true);
                            var pinvokeGetProcAddressResult = LLVM.BuildCall(builder2, pinvokeGetProcAddressFunctionLLVM,
                                                                             new[]
                            {
                                pinvokeLoadLibraryResult,
                                entryPoint,
                                LLVM.ConstInt(int16.DataTypeLLVM, (ushort)method.PInvokeInfo.Attributes, false),
                            }, string.Empty);

                            // TODO: Resolve method using generic context.
                            indices = new[]
                            {
                                LLVM.ConstInt(int32LLVM, 0, false),                                         // Pointer indirection
                                LLVM.ConstInt(int32LLVM, (int)RuntimeTypeInfoFields.VirtualTable, false),   // Access vtable
                                LLVM.ConstInt(int32LLVM, (ulong)GetFunction(method).VirtualSlot, false),    // Access specific vtable slot
                            };

                            // Get vtable slot and cast to proper type
                            var vtableSlot = LLVM.BuildInBoundsGEP(builder2, @class.GeneratedEETypeRuntimeLLVM, indices, string.Empty);
                            pinvokeGetProcAddressResult = LLVM.BuildPointerCast(builder2, pinvokeGetProcAddressResult, LLVM.GetElementType(LLVM.TypeOf(vtableSlot)), string.Empty);

                            // Store value
                            LLVM.BuildStore(builder2, pinvokeGetProcAddressResult, vtableSlot);
                        }
                    }

                    // Static ctor
                    if (@class.StaticCtor != null)
                    {
                        LLVM.BuildCall(builder2, @class.StaticCtor.GeneratedValue, new ValueRef[0], string.Empty);
                    }

                    LLVM.BuildBr(builder2, nextBlock);

                    LLVM.PositionBuilderAtEnd(builder2, nextBlock);
                    LLVM.BuildRetVoid(builder2);

                    @class.InitializeType = initTypeFunction;
                }
            }

            return(@class);
        }
예제 #24
0
        private void BuildRuntimeType(Class @class)
        {
            if (@class.IsEmitted)
            {
                return;
            }

            //Console.WriteLine("Build type {0}", @class);

            @class.IsEmitted = true;

            var  zero           = LLVM.ConstInt(int32LLVM, 0, false);
            bool isConcreteType = IsConcreteType(@class.Type);

            // Prepare metadata info
            var sharpLangModule = TestMode ? LLVM.ConstNull(intPtrLLVM) : metadataPerModule[@class.Type.TypeDefinitionCecil.Module];
            var extraTypeInfo   = LLVM.ConstNull(intPtrLLVM);

            var elementTypeSize = zero;

            // Build RTTI
            var runtimeTypeInfoGlobal       = @class.GeneratedEETypeTokenLLVM;
            var runtimeTypeInfoType         = LLVM.GetElementType(LLVM.TypeOf(runtimeTypeInfoGlobal));
            var runtimeTypeInfoTypeElements = new TypeRef[LLVM.CountStructElementTypes(runtimeTypeInfoType)];

            LLVM.GetStructElementTypes(runtimeTypeInfoType, runtimeTypeInfoTypeElements);

            var typeSpecification = @class.Type.TypeReferenceCecil as TypeSpecification;

            if (typeSpecification != null)
            {
                if (typeSpecification is ArrayType || typeSpecification is ByReferenceType || typeSpecification is PointerType)
                {
                    // Get element type
                    var elementType = GetType(typeSpecification.ElementType, TypeState.VTableEmitted);
                    elementTypeSize = LLVM.ConstIntCast(LLVM.SizeOf(elementType.DefaultTypeLLVM), int32LLVM, false);
                    extraTypeInfo   = LLVM.ConstPtrToInt(elementType.Class.GeneratedEETypeRuntimeLLVM, nativeIntLLVM);

                    if (typeSpecification is ArrayType)
                    {
                        extraTypeInfo = LLVM.ConstAdd(extraTypeInfo, LLVM.ConstInt(nativeIntLLVM, (int)ExtraTypeKind.Array, false));
                    }
                    else if (typeSpecification is ByReferenceType)
                    {
                        extraTypeInfo = LLVM.ConstAdd(extraTypeInfo, LLVM.ConstInt(nativeIntLLVM, (int)ExtraTypeKind.ByRef, false));
                    }
                    else if (typeSpecification is PointerType)
                    {
                        extraTypeInfo = LLVM.ConstAdd(extraTypeInfo, LLVM.ConstInt(nativeIntLLVM, (int)ExtraTypeKind.Pointer, false));
                    }

                    extraTypeInfo = LLVM.ConstIntToPtr(extraTypeInfo, intPtrLLVM);
                }

                var genericInstanceType = typeSpecification as GenericInstanceType;
                if (genericInstanceType != null)
                {
                    // Build global with array of VTable (one for each generic argument)
                    var genericArgumentsTypes           = genericInstanceType.GenericArguments.Select(x => GetType(x, TypeState.VTableEmitted)).ToArray();
                    var genericArgumentesTypeGlobalType = LLVM.ArrayType(intPtrLLVM, (uint)genericArgumentsTypes.Length + 1);
                    var genericArgumentsTypesGlobal     = LLVM.AddGlobal(module, genericArgumentesTypeGlobalType, @class.Type.TypeReferenceCecil.MangledName() + ".genericarguments");
                    LLVM.SetLinkage(genericArgumentsTypesGlobal, Linkage.PrivateLinkage);
                    LLVM.SetInitializer(genericArgumentsTypesGlobal, LLVM.ConstArray(intPtrLLVM,
                                                                                     genericArgumentsTypes
                                                                                     .Select(x => LLVM.ConstPointerCast(x.Class.GeneratedEETypeTokenLLVM, intPtrLLVM))
                                                                                     .Concat(new[] { LLVM.ConstPointerNull(intPtrLLVM) })
                                                                                     .ToArray()));
                    extraTypeInfo = LLVM.ConstInBoundsGEP(genericArgumentsTypesGlobal, new[] { zero, zero });
                    extraTypeInfo = LLVM.ConstPointerCast(extraTypeInfo, intPtrLLVM);
                }
            }

            var runtimeTypeFields = new List <ValueRef>
            {
                @class.BaseType != null ? @class.BaseType.GeneratedEETypeTokenLLVM : LLVM.ConstPointerNull(intPtrLLVM),
                LLVM.ConstInt(LLVM.Int8TypeInContext(context), isConcreteType ? 1U : 0U, false),
                LLVM.ConstNamedStruct(typeDefLLVM, new[]
                {
                    sharpLangModule,
                    LLVM.ConstInt(int32LLVM, @class.Type.TypeDefinitionCecil.MetadataToken.ToUInt32(), false),
                }),
                extraTypeInfo,
                LLVM.ConstNull(sharpLangTypeType.DefaultTypeLLVM),
            };

            // Prepare the runtime type object
            var mangledTypeName     = Regex.Replace(@class.Type.TypeReferenceCecil.MangledName() + ".sharplangtype", @"(\W)", "_");
            var sharpLangTypeGlobal = LLVM.AddGlobal(module, sharpLangTypeType.ObjectTypeLLVM, mangledTypeName);

            LLVM.SetLinkage(sharpLangTypeGlobal, Linkage.PrivateLinkage);
            LLVM.SetInitializer(sharpLangTypeGlobal, LLVM.ConstNull(sharpLangTypeType.ObjectTypeLLVM));

            if (isConcreteType)
            {
                // Build IMT
                var interfaceMethodTable = new LinkedList <InterfaceMethodTableEntry> [InterfaceMethodTableSize];
                foreach (var @interface in @class.Interfaces)
                {
                    foreach (var interfaceMethod in @interface.Type.TypeReferenceCecil.Resolve().Methods)
                    {
                        var resolvedInterfaceMethod = ResolveGenericMethod(@interface.Type.TypeReferenceCecil, interfaceMethod);

                        // If method is not fully resolved (generic method in interface), ignore it
                        // We are waiting for actual closed uses.
                        if (ResolveGenericsVisitor.ContainsGenericParameters(resolvedInterfaceMethod))
                        {
                            continue;
                        }

                        var resolvedFunction = CecilExtensions.TryMatchMethod(@class, resolvedInterfaceMethod);
                        if (resolvedFunction == null && @class.Type.TypeReferenceCecil is ArrayType)
                        {
                            var arrayType      = corlib.MainModule.GetType(typeof(Array).FullName);
                            var matchingMethod = (MethodReference)arrayType.Methods.First(x => x.Name.StartsWith("InternalArray_") && x.Name.EndsWith(resolvedInterfaceMethod.Name));
                            if (matchingMethod != null)
                            {
                                if (matchingMethod.HasGenericParameters)
                                {
                                    matchingMethod = matchingMethod.MakeGenericMethod(((ArrayType)@class.Type.TypeReferenceCecil).ElementType);
                                }

                                resolvedFunction = GetFunction(matchingMethod);

                                // Manually emit Array functions locally (until proper mscorlib + generic instantiation exists).
                                EmitFunction(resolvedFunction);
                                LLVM.SetLinkage(resolvedFunction.GeneratedValue, Linkage.LinkOnceAnyLinkage);
                            }
                        }

                        if (resolvedFunction == null)
                        {
                            throw new InvalidOperationException(string.Format("Could not find matching method for {0} in {1}", resolvedInterfaceMethod, @class));
                        }

                        var isInterface = resolvedFunction.DeclaringType.TypeReferenceCecil.Resolve().IsInterface;
                        if (!isInterface && resolvedFunction.MethodReference.Resolve().IsVirtual&& resolvedFunction.VirtualSlot != -1)
                        {
                            // We might have found a base virtual method matching this interface method.
                            // Let's get the actual method override for this virtual slot.
                            resolvedFunction = @class.VirtualTable[resolvedFunction.VirtualSlot];
                        }

                        // If method is not found, it could be due to covariance/contravariance
                        if (resolvedFunction == null)
                        {
                            throw new InvalidOperationException("Interface method not found");
                        }

                        var methodId     = GetMethodId(resolvedInterfaceMethod);
                        var imtSlotIndex = (int)(methodId % InterfaceMethodTableSize);

                        var imtSlot = interfaceMethodTable[imtSlotIndex];
                        if (imtSlot == null)
                        {
                            interfaceMethodTable[imtSlotIndex] = imtSlot = new LinkedList <InterfaceMethodTableEntry>();
                        }

                        imtSlot.AddLast(new InterfaceMethodTableEntry
                        {
                            Function = resolvedFunction,
                            MethodId = GetFunction(resolvedInterfaceMethod).GeneratedValue, // Should be a fake global, that we use as IMT key
                        });
                    }
                }
                var interfaceMethodTableConstant = LLVM.ConstArray(intPtrLLVM, interfaceMethodTable.Select(imtSlot =>
                {
                    if (imtSlot == null)
                    {
                        // No entries: null slot
                        return(LLVM.ConstNull(intPtrLLVM));
                    }

                    if (imtSlot.Count == 1)
                    {
                        // Single entry
                        var imtEntry = imtSlot.First.Value;
                        return(LLVM.ConstPointerCast(GetVirtualMethod(imtEntry.Function), intPtrLLVM));
                    }
                    else
                    {
                        // Multiple entries, create IMT array with all entries
                        // TODO: Support covariance/contravariance?
                        var imtEntries = LLVM.ConstArray(imtEntryLLVM, imtSlot.Select(imtEntry =>
                        {
                            return(LLVM.ConstNamedStruct(imtEntryLLVM, new[]
                            {
                                imtEntry.MethodId,                                                      // i8* functionId
                                LLVM.ConstPointerCast(GetVirtualMethod(imtEntry.Function), intPtrLLVM), // i8* functionPtr
                            }));
                        })
                                                         .Concat(Enumerable.Repeat(LLVM.ConstNull(imtEntryLLVM), 1)).ToArray()); // Append { 0, 0 } terminator
                        var imtEntryGlobal = LLVM.AddGlobal(module, LLVM.TypeOf(imtEntries), @class.Type.TypeReferenceCecil.MangledName() + ".imt");
                        LLVM.SetLinkage(imtEntryGlobal, Linkage.PrivateLinkage);
                        LLVM.SetInitializer(imtEntryGlobal, imtEntries);

                        // Add 1 to differentiate between single entry and IMT array
                        return(LLVM.ConstIntToPtr(
                                   LLVM.ConstAdd(
                                       LLVM.ConstPtrToInt(imtEntryGlobal, nativeIntLLVM),
                                       LLVM.ConstInt(nativeIntLLVM, 1, false)),
                                   intPtrLLVM));
                    }
                }).ToArray());


                // Build list of super types
                var superTypes   = new List <Class>(@class.Depth);
                var currentClass = @class;
                while (currentClass != null)
                {
                    superTypes.Add(currentClass);
                    currentClass = currentClass.BaseType;
                }

                // Reverse so that the list start with most inherited object
                // (allows faster type checking since a given type will always be at a given index)
                superTypes.Reverse();

                // Build super types
                // Helpful for fast is/as checks on class hierarchy
                var superTypeCount  = LLVM.ConstInt(int32LLVM, (ulong)@class.Depth + 1, false);
                var interfacesCount = LLVM.ConstInt(int32LLVM, (ulong)@class.Interfaces.Count, false);

                // Super types global
                var superTypesConstantGlobal = LLVM.AddGlobal(module, LLVM.ArrayType(intPtrLLVM, (uint)superTypes.Count),
                                                              @class.Type.TypeReferenceCecil.MangledName() + ".supertypes");
                LLVM.SetLinkage(superTypesConstantGlobal, Linkage.PrivateLinkage);
                var superTypesGlobal = LLVM.ConstInBoundsGEP(superTypesConstantGlobal, new[] { zero, zero });

                // Interface map global
                var interfacesConstantGlobal = LLVM.AddGlobal(module, LLVM.ArrayType(intPtrLLVM, (uint)@class.Interfaces.Count),
                                                              @class.Type.TypeReferenceCecil.MangledName() + ".interfaces");
                LLVM.SetLinkage(interfacesConstantGlobal, Linkage.PrivateLinkage);
                var interfacesGlobal = LLVM.ConstInBoundsGEP(interfacesConstantGlobal, new[] { zero, zero });

                // Build VTable
                var vtableConstant = LLVM.ConstNamedStruct(@class.VTableTypeLLVM, @class.VirtualTable.Select(x => GetVirtualMethod(x)).ToArray());

                var staticFieldsInitializer = LLVM.ConstNamedStruct(runtimeTypeInfoTypeElements[(int)RuntimeTypeInfoFields.StaticFields], @class.StaticFields.Select(field =>
                {
                    var fieldType = field.Value.Type;

                    if ((field.Key.Attributes & FieldAttributes.HasFieldRVA) != 0)
                    {
                        var initialValue = field.Key.InitialValue;

                        // Seems like if type size is 8, it uses int64 as backing type
                        // Maybe at some point it might be better to encode static fields in a big byte array and use casts instead?
                        if (LLVM.GetTypeKind(fieldType.DefaultTypeLLVM) == TypeKind.IntegerTypeKind)
                        {
                            unsafe
                            {
                                fixed(byte *initalValueStart = initialValue)
                                {
                                    if (LLVM.GetIntTypeWidth(fieldType.DefaultTypeLLVM) == 64)
                                    {
                                        return(LLVM.ConstInt(fieldType.DefaultTypeLLVM, *(ulong *)initalValueStart, false));
                                    }
                                    if (LLVM.GetIntTypeWidth(fieldType.DefaultTypeLLVM) == 32)
                                    {
                                        return(LLVM.ConstInt(fieldType.DefaultTypeLLVM, *(uint *)initalValueStart, false));
                                    }
                                }
                            }
                        }

                        // Otherwise, for now we assume that if there was a RVA, it was a type with custom layout (default type is i8[]),
                        // as currently generated by compiler in <PrivateImplementationDetails> class.
                        if (LLVM.GetTypeKind(fieldType.DefaultTypeLLVM) != TypeKind.ArrayTypeKind)
                        {
                            throw new NotSupportedException();
                        }

                        var arrayElementType = LLVM.Int8TypeInContext(context);
                        return(LLVM.ConstArray(arrayElementType, initialValue.Select(x => LLVM.ConstInt(arrayElementType, x, false)).ToArray()));
                    }

                    return(LLVM.ConstNull(fieldType.DefaultTypeLLVM));
                }).ToArray());

                runtimeTypeFields.AddRange(new[]
                {
                    superTypeCount,
                    interfacesCount,
                    superTypesGlobal,
                    interfacesGlobal,
                    LLVM.ConstInt(LLVM.Int8TypeInContext(context), 0, false), // Class initialized?
                    LLVM.ConstIntCast(LLVM.SizeOf(@class.Type.ObjectTypeLLVM), int32LLVM, false),
                    elementTypeSize,
                    interfaceMethodTableConstant,

                    LLVM.ConstInt(int32LLVM, (ulong)@class.VirtualTable.Count, false),
                    vtableConstant,
                    staticFieldsInitializer,
                });

                var runtimeTypeInfoConstant = LLVM.ConstNamedStruct(runtimeTypeInfoType, runtimeTypeFields.ToArray());
                LLVM.SetInitializer(runtimeTypeInfoGlobal, runtimeTypeInfoConstant);

                // Build super type list (after RTTI since we need pointer to RTTI)
                var superTypesConstant = LLVM.ConstArray(intPtrLLVM,
                                                         superTypes.Select(superType => LLVM.ConstPointerCast(superType.GeneratedEETypeTokenLLVM, intPtrLLVM))
                                                         .ToArray());
                LLVM.SetInitializer(superTypesConstantGlobal, superTypesConstant);

                // Build interface map
                var interfacesConstant = LLVM.ConstArray(intPtrLLVM,
                                                         @class.Interfaces.Select(
                                                             @interface => LLVM.ConstPointerCast(@interface.GeneratedEETypeTokenLLVM, intPtrLLVM)).ToArray());
                LLVM.SetInitializer(interfacesConstantGlobal, interfacesConstant);
            }
            else
            {
                // Non-concrete type, create type with current fields
                var runtimeTypeInfoConstant = LLVM.ConstNamedStruct(runtimeTypeInfoType, runtimeTypeFields.ToArray());
                LLVM.SetInitializer(runtimeTypeInfoGlobal, runtimeTypeInfoConstant);
            }

            // Mark RTTI as external
            LLVM.SetLinkage(runtimeTypeInfoGlobal, Linkage.ExternalLinkage);
        }
예제 #25
0
        /// <summary>
        /// Compiles the code for the VTable.
        /// </summary>
        public void Compile()
        {
            // Create the VTable structs for this type containing the method pointers.
            foreach (KeyValuePair <TypeDefinition, Tuple <TypeRef, ValueRef> > pair in mGeneratedTable)
            {
                Dictionary <int, MethodDefinition> lookup = mTable[pair.Key];

                int        i      = 0;
                ValueRef[] values = new ValueRef[lookup.Count];
                foreach (KeyValuePair <int, MethodDefinition> entry in lookup)
                {
                    ValueRef?function = mLookup.GetFunction(NameHelper.CreateMethodName(entry.Value));
                    if (!function.HasValue)
                    {
                        throw new InvalidOperationException("Could not find function for: " + entry.Value);
                    }

                    values[i++] = LLVM.ConstPointerCast(function.Value, TypeHelper.VoidPtr);
                }

                ValueRef initialValues = LLVM.ConstStruct(values, false);
                LLVM.SetInitializer(pair.Value.Item2, initialValues);
            }

            // For each interface type, we want to create a table that links to the corresponding VTables.
            if (Type.HasInterfaces)
            {
                // Create arrays for the element and their types.
                // We know the values and types for the tables that are generated for this type.
                // However, there are spots that will be blank, so we need to fill these with "null".
                int        count         = mLookup.MaxInterfaceID;
                ValueRef[] elementValues = new ValueRef[count];
                TypeRef[]  elementTypes  = new TypeRef[count];

                // Fill default value for blank spots.
                ValueRef nullValue = LLVM.ConstNull(TypeHelper.VoidPtr);
                for (int i = 0; i < count; i++)
                {
                    elementValues[i] = nullValue;
                    elementTypes[i]  = TypeHelper.VoidPtr;
                }

                // Fill in existing values
                TypeDefinition[] allInterfaces = TypeHelper.GetAllInterfaces(Type);
                foreach (TypeDefinition type in allInterfaces)
                {
                    uint id = mLookup.GetInterfaceID(type);
                    Tuple <TypeRef, ValueRef> tuple = mGeneratedTable[type];
                    elementValues[id] = tuple.Item2;
                    elementTypes[id]  = LLVM.PointerType(tuple.Item1, 0);
                }

                // Add a global for this table.
                TypeRef  tableType = LLVM.StructTypeInContext(mCompiler.ModuleContext, elementTypes, false);
                ValueRef table     = LLVM.ConstStruct(elementValues, false);
                ValueRef global    = LLVM.AddGlobal(mCompiler.Module, tableType, string.Format("interface_vtable_table_{0}", Type.FullName));
                LLVM.SetInitializer(global, table);
                LLVM.SetLinkage(global, Linkage.PrivateLinkage);

                // Add indirection table to lookup.
                ValueRef interfaceIndirectionTable = global;
                mLookup.AddInterfaceIndirectionTable(Type, interfaceIndirectionTable);
            }
        }
예제 #26
0
        /// <summary>
        /// Emits an ldtoken instruction.
        /// </summary>
        /// <param name="instruction">The instruction.</param>
        /// <param name="context">The context.</param>
        /// <param name="builder">The builder.</param>
        public void Emit(Instruction instruction, MethodContext context, BuilderRef builder)
        {
            object token = instruction.Operand;

            if (token is FieldReference)
            {
                FieldReference  fieldRef = (FieldReference)token;
                FieldDefinition fieldDef = fieldRef.Resolve();

                // We only support array initialization by "System.Runtime.CompilerServices.RuntimeHelpers.InitializeArray" currently.
                if (instruction.Next.OpCode.Code == Code.Call)
                {
                    MethodReference methodRef = (MethodReference)instruction.Next.Operand;
                    if (methodRef.Name == "InitializeArray" && methodRef.DeclaringType.FullName == "System.Runtime.CompilerServices.RuntimeHelpers")
                    {
                        // Note that the top value on the stack is currently the destination array.
                        // So that means if we have a char[] on the top, we need to interpret the array differently because we treat char as 8-bit...
                        StackElement top            = context.CurrentStack.Peek();
                        bool         isCharArray    = (top.ILType.FullName == "System.Char[]");
                        int          dstArrayLength = (isCharArray) ? (fieldDef.InitialValue.Length / 2) : (fieldDef.InitialValue.Length);
                        ValueRef[]   values         = new ValueRef[dstArrayLength];

                        // CIL creates this array as a byte[].
                        if (isCharArray)
                        {
                            for (int i = 0; i < dstArrayLength; i++)
                            {
                                values[i] = LLVM.ConstInt(TypeHelper.Int8, fieldDef.InitialValue[i * 2], false);
                            }
                        }
                        else
                        {
                            for (int i = 0; i < dstArrayLength; i++)
                            {
                                values[i] = LLVM.ConstInt(TypeHelper.Int8, fieldDef.InitialValue[i], false);
                            }
                        }

                        TypeRef  globalType = LLVM.ArrayType(TypeHelper.Int8, (uint)dstArrayLength);
                        ValueRef global     = LLVM.AddGlobal(context.Compiler.Module, globalType, "initarray");
                        LLVM.SetInitializer(global, LLVM.ConstArray(TypeHelper.Int8, values));

                        // Push the reference and the size.
                        context.CurrentStack.Push(new StackElement(global, null, globalType));
                        ValueRef size = LLVM.ConstInt(TypeHelper.NativeIntType, (ulong)dstArrayLength, false);
                        context.CurrentStack.Push(new StackElement(size, null, TypeHelper.NativeIntType));
                    }
                    else
                    {
                        throw new NotImplementedException("Ldtoken: " + token.GetType() + " not implemented");
                    }
                }
                else
                {
                    throw new NotImplementedException("Ldtoken: " + token.GetType() + " not implemented");
                }
            }
            else
            {
                throw new NotImplementedException("Ldtoken: " + token.GetType() + " not implemented");
            }
        }