Beispiel #1
0
        /// <summary>
        /// Emits a newobj 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)
        {
            MethodReference ctor    = (MethodReference)instruction.Operand;
            TypeDefinition  objType = ctor.DeclaringType.Resolve();
            TypeRef         type    = TypeHelper.GetTypeRefFromType(ctor.DeclaringType);

            ValueRef objPtr;
            bool     ptr = (objType.IsClass && !objType.IsValueType);

            if (ptr)
            {
                // This type is a class, therefor we have a specialised "newobj" method.
                objPtr = LLVM.BuildCall(builder, context.Compiler.Lookup.GetNewobjMethod(ctor.DeclaringType.Resolve()), new ValueRef[0], "newobj");
            }
            else
            {
                // Not a class, allocate on stack.
                objPtr = LLVM.BuildAlloca(builder, type, "newobj");
            }

            // Constructor.
            ValueRef?ctorFunc = context.Compiler.Lookup.GetFunction(NameHelper.CreateMethodName(ctor));

            if (!ctorFunc.HasValue)
            {
                throw new Exception("Constructor not found: " + ctor);
            }

            // Get .ctor parameters.
            int paramCount = 1 + ctor.Parameters.Count;

            ValueRef[] values = new ValueRef[paramCount];
            values[0] = objPtr;
            for (int i = paramCount - 1; i >= 1; i--)
            {
                StackElement element = context.CurrentStack.Pop();
                values[i] = element.Value;

                // Cast needed?
                TypeRef paramType = TypeHelper.GetTypeRefFromType(ctor.Parameters[i - 1].ParameterType);
                if (element.Type != paramType)
                {
                    CastHelper.HelpIntAndPtrCast(builder, ref values[i], ref element.Type, paramType, "ctorcallcast");
                }
            }

            // Call .ctor.
            LLVM.BuildCall(builder, ctorFunc.Value, values, string.Empty);

            // Load and push object on stack.
            ValueRef obj = (ptr) ? objPtr : LLVM.BuildLoad(builder, objPtr, "obj");

            context.CurrentStack.Push(new StackElement(obj, ctor.DeclaringType, type));
        }
Beispiel #2
0
        /// <summary>
        /// Compiles a method.
        /// </summary>
        /// <param name="methodDef">The method definition.</param>
        public void Compile(MethodDefinition methodDef)
        {
            string   methodName = NameHelper.CreateMethodName(methodDef);
            ValueRef?function   = mCompiler.Lookup.GetFunction(methodName);

            // It is possible we didn't create a declaration because we don't want to generate this method.
            // In that case, don't continue.
            if (!function.HasValue)
            {
                return;
            }

            // A method has internal linkage if one (or both) of the following is true:
            // 1) The method is a private method.
            // 2) The compiler got an option to set the linkage of instance methods to internal.
            if (!methodDef.IsStatic && (methodDef.IsPrivate || mCompiler.Options.InstanceMethodInternalLinkage))
            {
                LLVM.SetLinkage(function.Value, Linkage.InternalLinkage);
                if (mCompiler.Options.InternalMethodsFastCC)
                {
                    LLVM.SetFunctionCallConv(function.Value, 8);
                }
            }

            // Only generate if it has a body.
            if (!methodDef.HasBody || methodDef.Body.CodeSize == 0)
            {
                LLVM.SetLinkage(function.Value, Linkage.ExternalLinkage);
                return;
            }

            // Compile instructions.
            MethodContext      ctx     = new MethodContext(mCompiler, methodDef, function.Value);
            InstructionEmitter emitter = new InstructionEmitter(ctx);

            try
            {
                emitter.EmitInstructions(mCompiler.CodeGen);
                mCompiler.VerifyAndOptimizeFunction(function.Value);
            }
            catch (Exception e)
            {
                Logger.LogError("Exception inside method {0}: {1}", methodDef, e.Message);
                Logger.LogDetail("----------");
                Logger.LogInfo(e.StackTrace);
            }
        }
Beispiel #3
0
        /// <summary>
        /// Creates the declaration for a method.
        /// </summary>
        /// <param name="methodDef">The method definition.</param>
        public void CreateDeclaration(MethodDefinition methodDef)
        {
            string methodName = NameHelper.CreateMethodName(methodDef);
            int    paramCount = methodDef.Parameters.Count;

            // CIL runtime method?
            if (methodDef.IsRuntime && !mRuntimeCompiler.MustHandleMethod(methodDef))
            {
                return;
            }

            // If we expect an instance reference as first argument, then we need to make sure our for loop has an offset.
            int offset = 0;

            if (methodDef.HasThis)
            {
                paramCount++;
                offset = 1;
            }

            // Fill in arguments.
            TypeRef[] argTypes = new TypeRef[paramCount];
            for (int i = offset; i < paramCount; i++)
            {
                TypeReference type = methodDef.Parameters[i - offset].ParameterType;
                argTypes[i] = TypeHelper.GetTypeRefFromType(type);
            }

            // If needed, fill in the instance reference.
            if (methodDef.HasThis)
            {
                argTypes[0] = TypeHelper.GetTypeRefFromType(methodDef.DeclaringType);

                // We need to pass the valuetype as a pointer because we need to modify its contents in the constructor.
                if (methodDef.DeclaringType.IsValueType)
                {
                    argTypes[0] = LLVM.PointerType(argTypes[0], 0);
                }
            }

            // Create LLVM function type and add function to the lookup table.
            TypeRef  functionType = LLVM.FunctionType(TypeHelper.GetTypeRefFromType(methodDef.ReturnType), argTypes, false);
            ValueRef function     = LLVM.AddFunction(mCompiler.Module, methodName, functionType);

            mCompiler.Lookup.AddFunction(methodName, function);
        }
Beispiel #4
0
        /// <summary>
        /// Compiles the init cctors method.
        /// </summary>
        private void compileInitCctorsMethod()
        {
            TypeRef    type    = LLVM.FunctionType(TypeHelper.Void, new TypeRef[0], false);
            ValueRef   func    = LLVM.AddFunction(Module, "initCctors", type);
            BuilderRef builder = LLVM.CreateBuilderInContext(ModuleContext);

            LLVM.PositionBuilderAtEnd(builder, LLVM.AppendBasicBlockInContext(ModuleContext, func, string.Empty));

            MethodDefinition[] cctors = Lookup.GetStaticConstructors();
            foreach (MethodDefinition method in cctors)
            {
                LLVM.BuildCall(builder, Lookup.GetFunction(NameHelper.CreateMethodName(method)).Value, new ValueRef[0], string.Empty);
            }

            LLVM.BuildRetVoid(builder);

            LLVM.DisposeBuilder(builder);
        }
Beispiel #5
0
        /// <summary>
        /// Emits a ldftn 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)
        {
            MethodDefinition method  = (MethodDefinition)instruction.Operand;
            ValueRef         result  = LLVM.BuildIntToPtr(builder, context.Compiler.Lookup.GetFunction(NameHelper.CreateMethodName(method)).Value, TypeHelper.NativeIntType, "ldftn");
            StackElement     element = new StackElement(result, typeof(IntPtr).GetTypeReference(), TypeHelper.NativeIntType);

            context.CurrentStack.Push(element);
        }
Beispiel #6
0
        /// <summary>
        /// Emits a callvirt 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)
        {
            MethodReference methodRef        = (MethodReference)instruction.Operand;
            TypeRef         returnType       = TypeHelper.GetTypeRefFromType(methodRef.ReturnType);
            Lookup          lookup           = context.Compiler.Lookup;
            bool            needsVirtualCall = lookup.NeedsVirtualCall(methodRef.DeclaringType);

            // Build parameter value and types arrays.
            int paramCount = 1 + methodRef.Parameters.Count;

            // Get the method, if it is null, create a new empty one, otherwise reference it.
            string   methodName = NameHelper.CreateMethodName(methodRef);
            ValueRef?func       = lookup.GetFunction(methodName);

            // Process arguments.
            // Note: backwards for loop because stack is backwards!
            ValueRef[] argVals    = new ValueRef[paramCount];
            TypeRef[]  paramTypes = new TypeRef[paramCount];
            for (int i = paramCount - 1; i >= 0; i--)
            {
                TypeReference type;
                StackElement  element = context.CurrentStack.Pop();
                argVals[i] = element.Value;

                // Get type of parameter.
                if (i == 0)
                {
                    type = methodRef.DeclaringType;
                }
                else
                {
                    type = methodRef.Parameters[i - 1].ParameterType;
                }

                paramTypes[i] = TypeHelper.GetTypeRefFromType(type);
                if (type.IsValueType && i == 0)
                {
                    paramTypes[i] = LLVM.PointerType(paramTypes[i], 0);
                }

                // Cast needed?
                if (element.Type != paramTypes[i])
                {
                    CastHelper.HelpIntAndPtrCast(builder, ref argVals[i], ref element.Type, paramTypes[i], "callvirtcast");
                }
            }

            // Function does not exist, create a declaration for the function.
            TypeRef functionType = LLVM.FunctionType(returnType, paramTypes, false);

            if (!func.HasValue)
            {
                func = LLVM.AddFunction(context.Compiler.Module, methodName, functionType);
                context.Compiler.Lookup.AddFunction(methodName, func.Value);
            }

            // Call.
            ValueRef method;

            if (needsVirtualCall && !lookup.IsMethodUnique(methodRef))
            {
                // We need a virtual call.
                TypeDefinition methodParent = methodRef.DeclaringType.Resolve();
                TypeRef        funcPtrType  = LLVM.PointerType(functionType, 0);
                VTable         vTable       = lookup.GetVTable(methodParent);
                ValueRef       methodGep;

                // Two cases:
                // 1) The parent of the method is an interface.
                //    In this case, we need to first get the VTable from the indirection table.
                // 2) The parent of the method is a class.
                //    In this case, we can directly now the offset to the VTable from the object pointer.

                if (!methodParent.IsInterface)
                {
                    uint     index          = lookup.GetClassVTableIndex(methodParent);
                    ValueRef vTableGep      = LLVM.BuildInBoundsGEP(builder, argVals[0], new ValueRef[] { LLVM.ConstInt(TypeHelper.Int32, 0, false), LLVM.ConstInt(TypeHelper.Int32, index, false) }, "vtablegep");
                    ValueRef vTableInstance = LLVM.BuildLoad(builder, vTableGep, "vtable");
                    methodGep = LLVM.BuildInBoundsGEP(builder, vTableInstance, new ValueRef[] { LLVM.ConstInt(TypeHelper.Int32, 0, false), LLVM.ConstInt(TypeHelper.Int32, (uint)vTable.GetMethodIndex(methodParent, methodRef), false) }, "methodgep");
                }
                else
                {
                    uint index = lookup.GetInterfaceID(methodParent);

                    ValueRef indirectionGep = LLVM.BuildInBoundsGEP(builder, argVals[0], new ValueRef[] { LLVM.ConstInt(TypeHelper.Int32, 0, false) }, "indirectiongep");
                    indirectionGep = LLVM.BuildPointerCast(builder, indirectionGep, LLVM.PointerType(LLVM.PointerType(LLVM.PointerType(TypeHelper.VoidPtr, 0), 0), 0), string.Empty);
                    ValueRef indirectionTable = LLVM.BuildLoad(builder, indirectionGep, "indirectiontable");
                    ValueRef vTableGep        = LLVM.BuildInBoundsGEP(builder, indirectionTable, new ValueRef[] { LLVM.ConstInt(TypeHelper.Int32, index, false) }, "vtablegep");
                    ValueRef vTableInstance   = LLVM.BuildLoad(builder, vTableGep, "vtable");
                    methodGep = LLVM.BuildInBoundsGEP(builder, vTableInstance, new ValueRef[] { LLVM.ConstInt(TypeHelper.Int32, (uint)vTable.GetMethodIndex(methodParent, methodRef), false) }, "methodgep");
                }

                // Indirect call.
                ValueRef methodPtr = LLVM.BuildLoad(builder, methodGep, "methodptr");
                method = LLVM.BuildPointerCast(builder, methodPtr, funcPtrType, "method");
            }
            else
            {
                // We can call it directly without VTable lookup.
                method = func.Value;
            }

            ValueRef retVal = LLVM.BuildCall(builder, method, argVals, string.Empty);

            if (instruction.HasPrefix(Code.Tail))
            {
                LLVM.SetTailCall(retVal, true);
            }

            // Push return value on stack if it has one.
            if (methodRef.ReturnType.MetadataType != MetadataType.Void)
            {
                context.CurrentStack.Push(new StackElement(retVal, methodRef.ReturnType));
            }
        }
Beispiel #7
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);
            }
        }
Beispiel #8
0
        /// <summary>
        /// Emits a call 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)
        {
            MethodReference methodRef  = (MethodReference)instruction.Operand;
            TypeRef         returnType = TypeHelper.GetTypeRefFromType(methodRef.ReturnType);

            // Check for special cases.
            if (instruction.Previous != null && instruction.Previous.OpCode.Code == Code.Ldtoken)
            {
                emitFromLdtoken(instruction, context, builder);
                return;
            }
            // Call System.Object::.ctor() ?
            else if (methodRef.FullName == "System.Void System.Object::.ctor()")
            {
                // Delete object reference from stack and ignore this.
                context.CurrentStack.Pop();
                return;
            }

            // Build parameter value and types arrays.
            int paramCount = methodRef.Parameters.Count;

            if (methodRef.HasThis)
            {
                paramCount++;
            }

            // Get the method, if it is null, create a new empty one, otherwise reference it.
            string   methodName = NameHelper.CreateMethodName(methodRef);
            ValueRef?func       = context.Compiler.Lookup.GetFunction(methodName);

            // Process arguments.
            // Note: backwards for loop because stack is backwards!
            ValueRef[] argVals    = new ValueRef[paramCount];
            TypeRef[]  paramTypes = new TypeRef[paramCount];
            for (int i = paramCount - 1; i >= 0; i--)
            {
                TypeReference type;
                StackElement  element = context.CurrentStack.Pop();
                argVals[i] = element.Value;

                // Note: the instance pointer is not included in the parameters explicitely.
                if (methodRef.HasThis)
                {
                    if (i == 0)
                    {
                        type = methodRef.DeclaringType;
                    }
                    else
                    {
                        type = methodRef.Parameters[i - 1].ParameterType;
                    }
                }
                else
                {
                    type = methodRef.Parameters[i].ParameterType;
                }

                paramTypes[i] = TypeHelper.GetTypeRefFromType(type);
                if (type.IsValueType && methodRef.HasThis && i == 0)
                {
                    paramTypes[i] = LLVM.PointerType(paramTypes[i], 0);
                }

                // Cast needed?
                if (element.Type != paramTypes[i])
                {
                    CastHelper.HelpIntAndPtrCast(builder, ref argVals[i], ref element.Type, paramTypes[i], "callcast");
                }
            }

            // Function does not exist, create a declaration for the function.
            if (!func.HasValue)
            {
                TypeRef functionType = LLVM.FunctionType(returnType, paramTypes, false);
                func = LLVM.AddFunction(context.Compiler.Module, methodName, functionType);
                context.Compiler.Lookup.AddFunction(methodName, func.Value);
            }

            // Call.
            ValueRef retVal = LLVM.BuildCall(builder, func.Value, argVals, string.Empty);

            if (instruction.HasPrefix(Code.Tail))
            {
                LLVM.SetTailCall(retVal, true);
            }

            // Push return value on stack if it has one.
            if (methodRef.ReturnType.MetadataType != MetadataType.Void)
            {
                context.CurrentStack.Push(new StackElement(retVal, methodRef.ReturnType));
            }
        }