Example #1
0
        public Function(Type declaringType, MethodReference methodReference, TypeRef functionType, ValueRef generatedValue, FunctionSignature signature)
        {
            Signature = signature;
            DeclaringType = declaringType;
            MethodReference = methodReference;
            FunctionType = functionType;
            GeneratedValue = generatedValue;
            VirtualSlot = -1;

            MethodDefinition = methodReference.Resolve();

            ParameterTypes = signature.ParameterTypes.Select(x => x.Type).ToArray();

            // Generate function type when being called from vtable/IMT (if it applies)
            // If declaring type is a value type, needs to unbox "this" for virtual method
            if (DeclaringType.TypeDefinitionCecil.IsValueType
                && (MethodDefinition.Attributes & MethodAttributes.Virtual) != 0)
            {
                bool hasStructValueReturn = signature.ReturnType.ABIParameterInfo.Kind == ABIParameterInfoKind.Indirect;

                // Create function type with boxed "this"
                var argumentCount = LLVM.CountParamTypes(FunctionType);
                var argumentTypes = new TypeRef[argumentCount];
                LLVM.GetParamTypes(FunctionType, argumentTypes);
                // Change first type to boxed "this"
                var thisIndex = hasStructValueReturn ? 1 : 0;
                argumentTypes[thisIndex] = LLVM.PointerType(DeclaringType.ObjectTypeLLVM, 0);
                VirtualFunctionType = LLVM.FunctionType(LLVM.GetReturnType(FunctionType), argumentTypes, LLVM.IsFunctionVarArg(FunctionType));
            }
            else
            {
                VirtualFunctionType = FunctionType;
            }
        }
Example #2
0
 public Function(Type declaringType, MethodReference methodReference, TypeRef functionType, ValueRef generatedValue, Type returnType, Type[] parameterTypes)
 {
     Signature = new FunctionSignature(returnType, parameterTypes);
     DeclaringType = declaringType;
     MethodReference = methodReference;
     FunctionType = functionType;
     GeneratedValue = generatedValue;
     VirtualSlot = -1;
 }
Example #3
0
        private void EmitCall(List <StackValue> stack, FunctionSignature targetMethod, ValueRef overrideMethod)
        {
            // Build argument list
            var targetNumParams = targetMethod.ParameterTypes.Length;
            var args            = new ValueRef[targetNumParams];

            for (int index = 0; index < targetNumParams; index++)
            {
                // TODO: Casting/implicit conversion?
                var stackItem = stack[stack.Count - targetNumParams + index];
                args[index] = ConvertFromStackToLocal(targetMethod.ParameterTypes[index], stackItem);
            }

            // Remove arguments from stack
            stack.RemoveRange(stack.Count - targetNumParams, targetNumParams);

            // Invoke method
            var actualMethod = overrideMethod;
            var call         = LLVM.BuildCall(builder, actualMethod, args, string.Empty);

            // Mark method as needed (if non-virtual call)
            if (LLVM.IsAGlobalVariable(actualMethod).Value != IntPtr.Zero)
            {
                LLVM.SetLinkage(actualMethod, Linkage.ExternalLinkage);
            }

            // Push return result on stack
            if (targetMethod.ReturnType.TypeReference.MetadataType != MetadataType.Void)
            {
                // Convert return value from local to stack value
                var returnValue = ConvertFromLocalToStack(targetMethod.ReturnType, call);

                // Add value to stack
                stack.Add(new StackValue(targetMethod.ReturnType.StackType, targetMethod.ReturnType, returnValue));
            }
        }
Example #4
0
        private void EmitCall(FunctionCompilerContext functionContext, FunctionSignature targetMethod, ValueRef overrideMethod)
        {
            var stack = functionContext.Stack;

            bool hasStructValueReturn = targetMethod.ReturnType.ABIParameterInfo.Kind == ABIParameterInfoKind.Indirect;

            // Build argument list
            var targetNumParams = targetMethod.ParameterTypes.Length;
            var args = new ValueRef[targetNumParams + (hasStructValueReturn ? 1 : 0)];
            for (int index = 0; index < targetNumParams; index++)
            {
                var llvmIndex = index + (hasStructValueReturn ? 1 : 0);
                var parameterType = targetMethod.ParameterTypes[index];

                // TODO: Casting/implicit conversion?
                var stackItem = stack[stack.Count - targetNumParams + index];
                args[llvmIndex] = ConvertFromStackToLocal(parameterType.Type, stackItem);

                if (stackItem.StackType == StackValueType.Value)
                {
                    switch (parameterType.ABIParameterInfo.Kind)
                    {
                        case ABIParameterInfoKind.Direct:
                            args[llvmIndex] = LLVM.BuildLoad(builder, args[llvmIndex], string.Empty);
                            break;
                        case ABIParameterInfoKind.Indirect:
                            // Make a copy of indirect aggregate values
                            args[llvmIndex] = LoadValue(stackItem.Type.StackType, args[llvmIndex], InstructionFlags.None);
                            break;
                        case ABIParameterInfoKind.Coerced:
                            // Coerce to integer type
                            args[llvmIndex] = LLVM.BuildPointerCast(builder, args[llvmIndex], LLVM.PointerType(parameterType.ABIParameterInfo.CoerceType, 0), string.Empty);
                            args[llvmIndex] = LLVM.BuildLoad(builder, args[llvmIndex], string.Empty);
                            break;
                        default:
                            throw new ArgumentOutOfRangeException();
                    }
                }
            }

            // Remove arguments from stack
            stack.RemoveRange(stack.Count - targetNumParams, targetNumParams);

            // Prepare return value storage (in case of struct)
            if (hasStructValueReturn)
            {
                // Allocate storage
                args[0] = LLVM.BuildAlloca(builderAlloca, targetMethod.ReturnType.Type.DefaultTypeLLVM, string.Empty);
            }

            // Invoke method
            ValueRef callResult;
            var actualMethod = overrideMethod;

            callResult = GenerateInvoke(functionContext, actualMethod, args);
            switch (targetMethod.CallingConvention)
            {
                case MethodCallingConvention.StdCall:
                    LLVM.SetInstructionCallConv(callResult, (uint)CallConv.X86StdcallCallConv);
                    break;
                case MethodCallingConvention.FastCall:
                    LLVM.SetInstructionCallConv(callResult, (uint)CallConv.X86FastcallCallConv);
                    break;
            }

            // Mark method as needed (if non-virtual call)
            if (LLVM.IsAGlobalVariable(actualMethod).Value != IntPtr.Zero)
            {
                LLVM.SetLinkage(actualMethod, Linkage.ExternalLinkage);
            }

            // Push return result on stack
            if (targetMethod.ReturnType.Type.TypeReferenceCecil.MetadataType != MetadataType.Void)
            {
                ValueRef returnValue;
                if (targetMethod.ReturnType.Type.StackType == StackValueType.Value)
                {
                    switch (targetMethod.ReturnType.ABIParameterInfo.Kind)
                    {
                        case ABIParameterInfoKind.Direct:
                            returnValue = LLVM.BuildAlloca(builderAlloca, targetMethod.ReturnType.Type.DefaultTypeLLVM, string.Empty);
                            LLVM.BuildStore(builder, callResult, returnValue);
                            break;
                        case ABIParameterInfoKind.Indirect:
                            returnValue = args[0];
                            break;
                        case ABIParameterInfoKind.Coerced:
                            returnValue = LLVM.BuildAlloca(builderAlloca, targetMethod.ReturnType.Type.DefaultTypeLLVM, string.Empty);
                            var returnValueCasted = LLVM.BuildPointerCast(builder, returnValue, LLVM.PointerType(targetMethod.ReturnType.ABIParameterInfo.CoerceType, 0), string.Empty);
                            LLVM.BuildStore(builder, callResult, returnValueCasted);
                            break;
                        default:
                            throw new ArgumentOutOfRangeException();
                    }
                }
                else
                {
                    returnValue = callResult;
                }

                // Convert return value from local to stack value
                returnValue = ConvertFromLocalToStack(targetMethod.ReturnType.Type, returnValue);

                // Add value to stack
                stack.Add(new StackValue(targetMethod.ReturnType.Type.StackType, targetMethod.ReturnType.Type, returnValue));
            }

            // Apply attributes to the call instruction
            ApplyCallAttributes(targetMethod, callResult);
        }
Example #5
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", LLVM.DIGetDebugMetadataVersion());

            // 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 globalCtorSignature = new FunctionSignature(abi, @void, new Type[0], MethodCallingConvention.Default, null);
            var globalCtorFunctionType = CreateFunctionTypeLLVM(globalCtorSignature);
            var globalCtor = LLVM.AddFunction(module, "initializeSharpLangModule", globalCtorFunctionType);
            LLVM.SetLinkage(globalCtor, Linkage.PrivateLinkage);
            LLVM.PositionBuilderAtEnd(builder, LLVM.AppendBasicBlockInContext(context, globalCtor, string.Empty));

            Function entryPoint = null;
            if (assembly.EntryPoint != null)
                functions.TryGetValue(assembly.EntryPoint, out entryPoint);

            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, globalCtorSignature);
                functionContext.Stack = new FunctionStack();
                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);
                }

                // Register unmanaged delegate callbacks
                var delegateWrappers = assembly.MainModule.GetType("DelegateWrappers");
                if (delegateWrappers != null)
                {
                    var marshalHelper = GetType(corlib.MainModule.GetType("SharpLang.Marshalling.MarshalHelper"), TypeState.VTableEmitted);
                    var marshalHelperRegisterDelegateWrapper = marshalHelper.Class.Functions.First(x => x.DeclaringType == marshalHelper && x.MethodReference.Name == "RegisterDelegateWrapper");

                    foreach (var delegateWrapper in delegateWrappers.Methods)
                    {
                        var method = GetFunction(delegateWrapper);

                        // Determine delegate type from MarshalFunctionAttribute
                        var marshalFunctionAttribute = method.MethodDefinition.CustomAttributes.First(x => x.AttributeType.FullName == "SharpLang.Marshalling.MarshalFunctionAttribute");
                        var delegateType = GetType((TypeReference)marshalFunctionAttribute.ConstructorArguments[0].Value, TypeState.VTableEmitted);

                        // TODO: Rename those method, and set their linking to linkonce so that it can be merged?
                        // Of course, we would also need to make sure it works when called from external assemblies

                        functionContext.Stack.Add(new StackValue(StackValueType.NativeInt, intPtr, LLVM.ConstPointerCast(delegateType.Class.GeneratedEETypeRuntimeLLVM, intPtrLLVM)));
                        EmitLdftn(functionContext.Stack, method);
                        EmitCall(functionContext, marshalHelperRegisterDelegateWrapper.Signature, marshalHelperRegisterDelegateWrapper.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)
            if (entryPoint != null)
	        {
                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));

                // Emit PInvoke Thunks and Globals needed in entry point module
                PInvokeEmitGlobals();
	        }

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

            return module;
        }
Example #6
0
        private void EmitCall(FunctionCompilerContext functionContext, FunctionSignature targetMethod, ValueRef overrideMethod)
        {
            var stack = functionContext.Stack;

            // Build argument list
            var targetNumParams = targetMethod.ParameterTypes.Length;
            var args = new ValueRef[targetNumParams];
            for (int index = 0; index < targetNumParams; index++)
            {
                // TODO: Casting/implicit conversion?
                var stackItem = stack[stack.Count - targetNumParams + index];
                args[index] = ConvertFromStackToLocal(targetMethod.ParameterTypes[index], stackItem);
            }

            // Remove arguments from stack
            stack.RemoveRange(stack.Count - targetNumParams, targetNumParams);

            // Invoke method
            ValueRef callResult;
            var actualMethod = overrideMethod;

            callResult = GenerateInvoke(functionContext, actualMethod, args);

            // Mark method as needed (if non-virtual call)
            if (LLVM.IsAGlobalVariable(actualMethod).Value != IntPtr.Zero)
            {
                LLVM.SetLinkage(actualMethod, Linkage.ExternalLinkage);
            }

            // Push return result on stack
            if (targetMethod.ReturnType.TypeReference.MetadataType != MetadataType.Void)
            {
                // Convert return value from local to stack value
                var returnValue = ConvertFromLocalToStack(targetMethod.ReturnType, callResult);

                // Add value to stack
                stack.Add(new StackValue(targetMethod.ReturnType.StackType, targetMethod.ReturnType, returnValue));
            }
        }
Example #7
0
        public Function(Type declaringType, MethodReference methodReference, TypeRef functionType, ValueRef generatedValue, FunctionSignature signature)
        {
            Signature       = signature;
            DeclaringType   = declaringType;
            MethodReference = methodReference;
            FunctionType    = functionType;
            GeneratedValue  = generatedValue;
            VirtualSlot     = -1;

            MethodDefinition = methodReference.Resolve();

            ParameterTypes = signature.ParameterTypes.Select(x => x.Type).ToArray();

            // Generate function type when being called from vtable/IMT (if it applies)
            // If declaring type is a value type, needs to unbox "this" for virtual method
            if (DeclaringType.TypeDefinitionCecil.IsValueType &&
                (MethodDefinition.Attributes & MethodAttributes.Virtual) != 0)
            {
                bool hasStructValueReturn = signature.ReturnType.ABIParameterInfo.Kind == ABIParameterInfoKind.Indirect;

                // Create function type with boxed "this"
                var argumentCount = LLVM.CountParamTypes(FunctionType);
                var argumentTypes = new TypeRef[argumentCount];
                LLVM.GetParamTypes(FunctionType, argumentTypes);
                // Change first type to boxed "this"
                var thisIndex = hasStructValueReturn ? 1 : 0;
                argumentTypes[thisIndex] = LLVM.PointerType(DeclaringType.ObjectTypeLLVM, 0);
                VirtualFunctionType      = LLVM.FunctionType(LLVM.GetReturnType(FunctionType), argumentTypes, LLVM.IsFunctionVarArg(FunctionType));
            }
            else
            {
                VirtualFunctionType = FunctionType;
            }
        }
Example #8
0
        /// <summary>
        /// Creates the function.
        /// </summary>
        /// <param name="method">The method.</param>
        /// <returns></returns>
        Function CreateFunction(MethodReference method)
        {
            Function function;
            if (functions.TryGetValue(method, out function))
                return function;

            var resolvedMethod = method.Resolve();
            var declaringType = GetType(ResolveGenericsVisitor.Process(method, method.DeclaringType), TypeState.Opaque);

            // Check if method is only defined in a parent class (can happen in some rare case, i.e. PCL TypeInfo.get_Assembly()).
            bool hasMatch = MetadataResolver.GetMethod(declaringType.TypeDefinitionCecil.Methods, method.GetElementMethod()) != null;
            if (resolvedMethod != null && !hasMatch)
            {
                var parentType = declaringType.TypeDefinitionCecil.BaseType != null ? ResolveGenericsVisitor.Process(declaringType.TypeReferenceCecil, declaringType.TypeDefinitionCecil.BaseType) : null;
                if (parentType == null)
                    throw new InvalidOperationException(string.Format("Could not find a matching method in any of the type or its parent for {0}", method));

                // Create function with parent type
                // TODO: Maybe we need to replace generic context with parent type?
                var parentMethod = method.ChangeDeclaringType(parentType);
                function = CreateFunction(parentMethod);

                // Register it so that it can be cached
                functions.Add(method, function);
                return function;
            }

            var returnType = GetType(ResolveGenericsVisitor.Process(method, method.ReturnType), TypeState.StackComplete);
            var parameterTypesBuilder = new List<Type>();
            if (method.HasThis)
            {
                var parameterType = declaringType.TypeReferenceCecil;

                // Value type uses ByReference type for this
                if (declaringType.TypeDefinitionCecil.IsValueType)
                    parameterType = parameterType.MakeByReferenceType();

                parameterTypesBuilder.Add(GetType(parameterType, TypeState.StackComplete));
            }
            foreach (var parameter in method.Parameters)
            {
                parameterTypesBuilder.Add(GetType(ResolveGenericsVisitor.Process(method, parameter.ParameterType), TypeState.StackComplete));
            }

            var parameterTypes = parameterTypesBuilder.ToArray();

            // Find calling convention
            var callingConvention = method.CallingConvention;
            PInvokeInfo pinvokeInfo = null;
            if (resolvedMethod != null && resolvedMethod.HasPInvokeInfo)
            {
                pinvokeInfo = resolvedMethod.PInvokeInfo;
                if (resolvedMethod.PInvokeInfo.IsCallConvStdCall || resolvedMethod.PInvokeInfo.IsCallConvWinapi)
                    callingConvention = MethodCallingConvention.StdCall;
                else if (resolvedMethod.PInvokeInfo.IsCallConvFastcall)
                    callingConvention = MethodCallingConvention.FastCall;
            }

            var functionSignature = new FunctionSignature(abi, returnType, parameterTypes, callingConvention, pinvokeInfo);
            var functionType = CreateFunctionTypeLLVM(functionSignature);

            // If we have an external with generic parameters, let's try to do some generic sharing (we can write only one in C++)
            bool isInternal = resolvedMethod != null && ((resolvedMethod.ImplAttributes & MethodImplAttributes.InternalCall) != 0);
            if (isInternal && resolvedMethod.HasGenericParameters && resolvedMethod.GenericParameters.All(x => x.HasReferenceTypeConstraint))
            {
                // Check if this isn't the shareable method (in which case we should do normal processing)
                if (!((GenericInstanceMethod)method).GenericArguments.All(x => MemberEqualityComparer.Default.Equals(x, @object.TypeReferenceCecil)))
                {
                    // Let's share it with default method
                    var sharedGenericInstance = new GenericInstanceMethod(resolvedMethod);
                    foreach (var genericParameter in resolvedMethod.GenericParameters)
                    {
                        sharedGenericInstance.GenericArguments.Add(@object.TypeReferenceCecil);
                    }

                    var sharedMethod = GetFunction(sharedGenericInstance);

                    // Cast shared function to appropriate pointer type
                    var sharedFunctionGlobal = LLVM.ConstPointerCast(sharedMethod.GeneratedValue, LLVM.PointerType(functionType, 0));
                    function = new Function(declaringType, method, functionType, sharedFunctionGlobal, functionSignature);
                    functions.Add(method, function);

                    return function;
                }
            }

            // Determine if type and function is local, and linkage type
            bool isLocal;
            var linkageType = GetLinkageType(method.DeclaringType, out isLocal);
            if (isInternal)
            {
                // Should be switched to non-weak when we have complete implementation of every internal calls
                linkageType = Linkage.ExternalWeakLinkage;
            }
            else if (resolvedMethod != null && resolvedMethod.HasGenericParameters)
            {
                isLocal = true;
                linkageType = Linkage.LinkOnceAnyLinkage;
            }

            bool isRuntime = resolvedMethod != null && ((resolvedMethod.ImplAttributes & MethodImplAttributes.Runtime) != 0);
            bool isInterfaceMethod = declaringType.TypeDefinitionCecil.IsInterface;
            var hasDefinition = resolvedMethod != null && (resolvedMethod.HasBody || isInternal || isRuntime);

            var methodMangledName = Regex.Replace(method.MangledName(), @"(\W)", "_");
            var functionGlobal = hasDefinition
                ? LLVM.AddFunction(module, methodMangledName, functionType)
                : LLVM.ConstPointerNull(LLVM.PointerType(functionType, 0));

            // Interface method uses a global so that we can have a unique pointer to use as IMT key
            if (isInterfaceMethod)
            {
                // For test code only: Use linkonce instead of linkageType so that we know if type was forced
                if (TestMode)
                {
                    isLocal = true;
                    linkageType = Linkage.LinkOnceAnyLinkage;
                }

                functionGlobal = LLVM.AddGlobal(module, LLVM.Int8TypeInContext(context), methodMangledName);
                if (isLocal)
                    LLVM.SetInitializer(functionGlobal, LLVM.ConstNull(LLVM.Int8TypeInContext(context)));
                LLVM.SetLinkage(functionGlobal, linkageType);
            }

            if (hasDefinition)
            {
                ApplyFunctionAttributes(functionSignature, functionGlobal);
            }

            function = new Function(declaringType, method, functionType, functionGlobal, functionSignature);
            functions.Add(method, function);

            if (hasDefinition)
            {
                switch (callingConvention)
                {
                    case MethodCallingConvention.StdCall:
                        LLVM.SetFunctionCallConv(functionGlobal, (uint)CallConv.X86StdcallCallConv);
                        break;
                    case MethodCallingConvention.FastCall:
                        LLVM.SetFunctionCallConv(functionGlobal, (uint)CallConv.X86FastcallCallConv);
                        break;
                }

                if (isLocal && !isInternal)
                {
                    // Need to compile
                    EmitFunction(function);
                }

                // Apply linkage
                LLVM.SetLinkage(functionGlobal, linkageType);
            }

            return function;
        }
Example #9
0
 private void ApplyCallAttributes(FunctionSignature functionSignature, ValueRef functionGlobal)
 {
     // Internally, ApplyFunctionAttributes can also handle call/invoke (this might be split later)
     ApplyFunctionAttributes(functionSignature, functionGlobal);
 }
Example #10
0
        private void ApplyFunctionAttributes(FunctionSignature functionSignature, ValueRef functionGlobal)
        {
            // Apply parameter attributes
            var hasStructValueReturn = functionSignature.ReturnType.ABIParameterInfo.Kind == ABIParameterInfoKind.Indirect;

            // Detect whether it's a function global or a call instruction
            var isCallInst = LLVM.IsACallInst(functionGlobal) != ValueRef.Empty || LLVM.IsAInvokeInst(functionGlobal) != ValueRef.Empty;

            // Apply sret attribute on struct return value
            if (hasStructValueReturn)
            {
                if (isCallInst)
                {
                    LLVM.AddInstrAttribute(functionGlobal, 1, Attribute.StructRetAttribute);
                }
                else
                {
                    var arg = LLVM.GetParam(functionGlobal, 0);
                    LLVM.AddAttribute(arg, Attribute.StructRetAttribute);
                }
            }

            // Apply byval attribute on struct value parameters
            for (int index = 0; index < functionSignature.ParameterTypes.Length; index++)
            {
                var llvmIndex = index + (hasStructValueReturn ? 1 : 0);
                var parameterType = functionSignature.ParameterTypes[index];
                if (parameterType.ABIParameterInfo.Kind == ABIParameterInfoKind.Indirect)
                {
                    if (isCallInst)
                    {
                        LLVM.AddInstrAttribute(functionGlobal, (uint)(llvmIndex + 1), Attribute.ByValAttribute);
                    }
                    else
                    {
                        var arg = LLVM.GetParam(functionGlobal, (uint)llvmIndex);
                        LLVM.AddAttribute(arg, Attribute.ByValAttribute);
                    }
                }
            }
        }
Example #11
0
        private TypeRef CreateFunctionTypeLLVM(FunctionSignature functionSignature)
        {
            // Some extra arguments might be preprended:
            //  - Return value pointer if struct returned by value
            //  - "this" if a class
            bool hasStructValueReturn = functionSignature.ReturnType.ABIParameterInfo.Kind == ABIParameterInfoKind.Indirect;

            var numParams = functionSignature.ParameterTypes.Length;
            var firstArgumentIndex = 0;
            if (hasStructValueReturn)
                firstArgumentIndex++;

            var parameterTypesLLVM = new TypeRef[numParams + (hasStructValueReturn ? 1 : 0)];

            for (int index = 0; index < parameterTypesLLVM.Length; index++)
            {
                FunctionParameterType parameterType;
                if (hasStructValueReturn && index == 0)
                {
                    parameterType = functionSignature.ReturnType;
                }
                else
                {
                    parameterType = functionSignature.ParameterTypes[index - firstArgumentIndex];
                }

                if (parameterType.Type.DefaultTypeLLVM.Value == IntPtr.Zero)
                    throw new InvalidOperationException();

                parameterTypesLLVM[index] = GetFunctionInputParameterTypeLLVM(parameterType);
            }

            return LLVM.FunctionType(hasStructValueReturn ? LLVM.VoidTypeInContext(context) : GetFunctionInputParameterTypeLLVM(functionSignature.ReturnType), parameterTypesLLVM, false);
        }
Example #12
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", LLVM.DIGetDebugMetadataVersion());

            // 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 globalCtorSignature    = new FunctionSignature(abi, @void, new Type[0], MethodCallingConvention.Default, null);
            var globalCtorFunctionType = CreateFunctionTypeLLVM(globalCtorSignature);
            var globalCtor             = LLVM.AddFunction(module, "initializeSharpLangModule", globalCtorFunctionType);

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

            Function entryPoint = null;

            if (assembly.EntryPoint != null)
            {
                functions.TryGetValue(assembly.EntryPoint, out entryPoint);
            }

            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, globalCtorSignature);
                functionContext.Stack = new FunctionStack();
                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);
                }

                // Register unmanaged delegate callbacks
                var delegateWrappers = assembly.MainModule.GetType("DelegateWrappers");
                if (delegateWrappers != null)
                {
                    var marshalHelper = GetType(corlib.MainModule.GetType("SharpLang.Marshalling.MarshalHelper"), TypeState.VTableEmitted);
                    var marshalHelperRegisterDelegateWrapper = marshalHelper.Class.Functions.First(x => x.DeclaringType == marshalHelper && x.MethodReference.Name == "RegisterDelegateWrapper");

                    foreach (var delegateWrapper in delegateWrappers.Methods)
                    {
                        var method = GetFunction(delegateWrapper);

                        // Determine delegate type from MarshalFunctionAttribute
                        var marshalFunctionAttribute = method.MethodDefinition.CustomAttributes.First(x => x.AttributeType.FullName == "SharpLang.Marshalling.MarshalFunctionAttribute");
                        var delegateType             = GetType((TypeReference)marshalFunctionAttribute.ConstructorArguments[0].Value, TypeState.VTableEmitted);

                        // TODO: Rename those method, and set their linking to linkonce so that it can be merged?
                        // Of course, we would also need to make sure it works when called from external assemblies

                        functionContext.Stack.Add(new StackValue(StackValueType.NativeInt, intPtr, LLVM.ConstPointerCast(delegateType.Class.GeneratedEETypeRuntimeLLVM, intPtrLLVM)));
                        EmitLdftn(functionContext.Stack, method);
                        EmitCall(functionContext, marshalHelperRegisterDelegateWrapper.Signature, marshalHelperRegisterDelegateWrapper.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)
            if (entryPoint != null)
            {
                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));

                // Emit PInvoke Thunks and Globals needed in entry point module
                PInvokeEmitGlobals();
            }

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

            return(module);
        }
Example #13
0
 public Function(Type declaringType, MethodReference methodReference, TypeRef functionType, ValueRef generatedValue, FunctionSignature signature)
 {
     Signature       = signature;
     DeclaringType   = declaringType;
     MethodReference = methodReference;
     FunctionType    = functionType;
     GeneratedValue  = generatedValue;
     VirtualSlot     = -1;
 }
Example #14
0
 public FunctionCompilerContext(ValueRef functionGlobal, FunctionSignature signature)
 {
     FunctionGlobal             = functionGlobal;
     FlowingNextInstructionMode = FlowingNextInstructionMode.Implicit;
     Signature = signature;
 }