private static LLVMAbi PickLLVMAbi(ITypeMember Member, LLVMAssembly DeclaringAssembly) { var abiName = LLVMAttributes.GetAbiName(Member); if (abiName != null) { switch (abiName.ToLowerInvariant()) { case "c": return(DeclaringAssembly.ExternalAbi); case "c++": case "c#": return(DeclaringAssembly.Abi); default: throw new InvalidDataException( LLVMAttributes.AbiAttributeName + " specified unknown ABI '" + abiName + "'"); } } else if (Member.IsStatic && IsImportedMember(Member)) { return(DeclaringAssembly.ExternalAbi); } else { return(DeclaringAssembly.Abi); } }
/// <inheritdoc/> protected override Tuple <IAssembly, IEnumerable <IAssembly> > RewriteAssemblies( Tuple <IAssembly, IEnumerable <IAssembly> > MainAndOtherAssemblies, IBinder Binder, ICompilerLog Log) { // In addition to emitting LLVM IR from managed code, flame-llvm must also // set up an environment in which managed code can run. Part of this // environment is the 'main' function: managed code expects an entry point // to look like this: `void|int Main(|string[])`, whereas a C 'main' function // must have the following signature: `int main(int, byte**)`. // // To bridge this divide, we'll generate a 'main' function and use that to // call the entry point. var originalAsm = MainAndOtherAssemblies.Item1; var originalEntryPoint = originalAsm.GetEntryPoint(); if (originalEntryPoint == null) { // We can't rewrite the entry point of an assembly that doesn't // have an entry point. return(MainAndOtherAssemblies); } // Generate the following class: // // public static class __entry_point // { // [#builtin_abi("C")] // [#builtin_llvm_linkage(external)] // public static int main(int argc, byte** argv) // { // try // { // var parsedArgs = Environment.Initialize(argc, argv); // return actual_entry_point(...); // // --or-- // actual_entry_point(...); // return 0; // } // catch (Exception ex) // { // Environment.HandleFatalException(ex); // return 1; // } // } // } var mainAsm = new DescribedAssembly( originalAsm.Name, originalAsm.AssemblyVersion, Binder.Environment); var epType = new DescribedType(new SimpleName("__entry_point"), mainAsm); epType.AddAttribute(PrimitiveAttributes.Instance.StaticTypeAttribute); var mainThunk = new DescribedBodyMethod( new SimpleName("main"), epType, PrimitiveTypes.Int32, true); mainThunk.AddAttribute(new LLVMLinkageAttribute(LLVMLinkage.LLVMExternalLinkage)); mainThunk.AddAttribute(LLVMAttributes.CreateAbiAttribute("C")); mainThunk.AddParameter(new DescribedParameter("argc", PrimitiveTypes.Int32)); mainThunk.AddParameter( new DescribedParameter( "argv", PrimitiveTypes.UInt8 .MakePointerType(PointerKind.TransientPointer) .MakePointerType(PointerKind.TransientPointer))); if (originalEntryPoint.HasSameSignature(mainThunk)) { // We don't have to rewrite the entry point if the existing entry point // already has the expected form. return(MainAndOtherAssemblies); } var epCall = CreateEntryPointCall(originalEntryPoint, mainThunk, Binder); mainThunk.Body = epCall.Type.GetIsInteger() ? (IStatement) new ReturnStatement( new StaticCastExpression(epCall, PrimitiveTypes.Int32).Simplify()) : new BlockStatement(new IStatement[] { new ExpressionStatement(epCall), new ReturnStatement(new IntegerExpression(0)) }); var handleExceptionMethod = BindEnvironmentHandleFatalExceptionMethod(Binder); if (handleExceptionMethod != null) { var exceptionParam = handleExceptionMethod.Parameters.Single <IParameter>(); var catchClause = new CatchClause( new DescribedVariableMember( exceptionParam.Name, exceptionParam.ParameterType)); catchClause.Body = new BlockStatement(new IStatement[] { new ExpressionStatement( new InvocationExpression( handleExceptionMethod, null, new IExpression[] { catchClause.ExceptionVariable.CreateGetExpression() })), new ReturnStatement(new IntegerExpression(1)) }); mainThunk.Body = new TryStatement( mainThunk.Body, new CatchClause[] { catchClause }); } epType.AddMethod(mainThunk); mainAsm.AddType(epType); mainAsm.EntryPoint = mainThunk; return(new Tuple <IAssembly, IEnumerable <IAssembly> >( mainAsm, new IAssembly[] { originalAsm }.Concat <IAssembly>(MainAndOtherAssemblies.Item2))); }