/// <summary> /// Creates a new test assembly and wraps it in a container. /// </summary> public TestAssemblyContainer() { var testAsm = new DescribedAssembly(new SimpleName("TestAsm").Qualify()); this.Assembly = testAsm; var simpleType = new DescribedType(new SimpleName("SimpleType").Qualify(), testAsm); testAsm.AddType(simpleType); this.SimpleType = simpleType; var nestedType = new DescribedType(new SimpleName("NestedType"), simpleType); simpleType.AddNestedType(nestedType); this.NestedType = nestedType; var genericType1 = new DescribedType(new SimpleName("GenericType", 1).Qualify(), testAsm); genericType1.AddGenericParameter(new DescribedGenericParameter(genericType1, new SimpleName("T"))); testAsm.AddType(genericType1); this.GenericType1 = genericType1; var genericType2 = new DescribedType(new SimpleName("GenericType", 2).Qualify(), testAsm); genericType2.AddGenericParameter(new DescribedGenericParameter(genericType2, new SimpleName("T1"))); genericType2.AddGenericParameter(new DescribedGenericParameter(genericType2, new SimpleName("T2"))); testAsm.AddType(genericType2); this.GenericType2 = genericType2; var namespaceType = new DescribedType( new SimpleName("NamespaceType").Qualify(new SimpleName("TestNamespace")), testAsm); testAsm.AddType(namespaceType); this.NamespaceType = namespaceType; }
/// <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))); }