public static void TranslateAll( TextWriter logw, string outputPath, bool readSymbols, bool enableCpp, bool enableBundler, TargetPlatforms targetPlatform, DebugInformationOptions debugInformationOptions, IEnumerable <string> assemblyPaths) { var storage = new CodeTextStorage( logw, outputPath, enableCpp, " "); foreach (var aseemblyPath in assemblyPaths) { Translate( logw, storage, readSymbols, enableBundler, targetPlatform, debugInformationOptions, aseemblyPath); } }
public static void Translate( CodeTextStorage storage, bool readSymbols, bool enableBundler, TargetPlatforms targetPlatform, DebugInformationOptions debugInformationOptions, string assemblyPath) { System.Console.WriteLine("IL2C: Preparing assembly: \"{0}\" ...", Path.GetFullPath(assemblyPath)); var translateContext = new TranslateContext(assemblyPath, readSymbols); System.Console.WriteLine(" done."); using (var _ = storage.EnterScope("meta")) { MetadataSerializer metaSerializer = new MetadataSerializer(translateContext); metaSerializer.WriteResult(storage); } using (var _ = storage.EnterScope("include")) { } using (var _ = storage.EnterScope("src")) { } }
public static void Translate( TextWriter logw, CodeTextStorage storage, bool readSymbols, bool enableBundler, TargetPlatforms targetPlatform, DebugInformationOptions debugInformationOptions, string assemblyPath) { logw.Write("IL2C: Preparing assembly: \"{0}\" ...", Path.GetFullPath(assemblyPath)); var translateContext = new TranslateContext(assemblyPath, readSymbols, targetPlatform); var preparedFunctions = AssemblyPreparer.Prepare(translateContext); logw.WriteLine(" done."); using (var _ = storage.EnterScope("include")) { AssemblyWriter.WriteHeader( storage, translateContext, preparedFunctions); } using (var _ = storage.EnterScope("src")) { AssemblyWriter.WriteSourceCode( storage, translateContext, preparedFunctions, enableBundler, debugInformationOptions); } }
public static void WriteSourceCode( CodeTextWriter twSource, TranslateContext translateContext, PreparedInformations prepared, DebugInformationOptions debugInformationOption = DebugInformationOptions.Full) { InternalWriteSourceCode( twSource, translateContext, prepared, debugInformationOption, true); }
public static string[] WriteSourceCode( CodeTextStorage storage, TranslateContext translateContext, PreparedInformations prepared, bool enableBundler, DebugInformationOptions debugInformationOption) { var sourceFilePaths = new List <string>(); var assemblyName = translateContext.Assembly.Name; // Write assembly level common internal header. HeaderWriter.WriteCommonInternalHeader( storage, translateContext, prepared, assemblyName); // Write assembly level common internal source code. sourceFilePaths.Add( SourceCodeWriter.WriteCommonInternalSourceCode( storage, translateContext, prepared, assemblyName)); // Write source code bundler. if (enableBundler) { SourceCodeWriter.WriteBundlerSourceCode( storage, prepared, assemblyName); } using (var _ = storage.EnterScope(assemblyName, false)) { // Write source codes. sourceFilePaths.AddRange( SourceCodeWriter.WriteSourceCodes( storage, translateContext, prepared, debugInformationOption)); } return(sourceFilePaths.ToArray()); }
public static void TranslateAll( TextWriter logw, CodeTextStorage storage, bool readSymbols, bool enableBundler, DebugInformationOptions debugInformationOptions, params string[] assemblyPaths) { TranslateAll( logw, storage, readSymbols, enableBundler, debugInformationOptions, (IEnumerable <string>)assemblyPaths); }
public static void TranslateAll( CodeTextStorage storage, bool readSymbols, bool enableBundler, TargetPlatforms targetPlatform, DebugInformationOptions debugInformationOptions, params string[] assemblyPaths) { TranslateAll( storage, readSymbols, enableBundler, targetPlatform, debugInformationOptions, (IEnumerable <string>)assemblyPaths); }
public static void TranslateAll( TextWriter logw, string outputPath, bool readSymbols, bool enableBundler, TargetPlatforms targetPlatform, DebugInformationOptions debugInformationOptions, params string[] assemblyPaths) { TranslateAll( logw, outputPath, readSymbols, enableBundler, targetPlatform, debugInformationOptions, (IEnumerable <string>)assemblyPaths); }
public static void TranslateAll( TextWriter logw, CodeTextStorage storage, bool readSymbols, bool enableBundler, DebugInformationOptions debugInformationOptions, IEnumerable <string> assemblyPaths) { foreach (var aseemblyPath in assemblyPaths) { Translate( logw, storage, readSymbols, enableBundler, debugInformationOptions, aseemblyPath); } }
public static void TranslateAll( CodeTextStorage storage, bool readSymbols, bool enableBundler, TargetPlatforms targetPlatform, DebugInformationOptions debugInformationOptions, IEnumerable <string> assemblyPaths) { foreach (var aseemblyPath in assemblyPaths) { Translate( storage, readSymbols, enableBundler, targetPlatform, debugInformationOptions, aseemblyPath); } }
public static string[] WriteSourceCodes( CodeTextStorage storage, TranslateContext translateContext, PreparedInformations prepared, DebugInformationOptions debugInformationOption) { IExtractContextHost extractContext = translateContext; var assemblyName = extractContext.Assembly.Name; var typesByDeclaring = prepared.Types. GroupBy(type => type.DeclaringType ?? type). ToDictionary( g => g.Key, g => g.OrderByDependant(translateContext.Assembly).ToArray()); var sourceFiles = new List <string>(); foreach (var targetType in prepared.Types. Where(type => type.DeclaringType == null)) { using (var _ = storage.EnterScope(targetType.ScopeName)) { using (var twSource = storage.CreateSourceCodeWriter(targetType.Name)) { // HACK: Unreal Engine 4 needs include directive with same file name as header extension (ex: foo.c --> foo.h) at first line. if (extractContext.TargetPlatform == TargetPlatforms.UE4) { twSource.WriteLine( "#include \"{0}.h\" // [16-1] Needs for Unreal Engine 4.", targetType.Name); twSource.SplitLine(); } twSource.WriteLine( "// [15-2] This is {0} native code translated by IL2C, do not edit.", assemblyName); twSource.SplitLine(); twSource.WriteLine( "#include <{0}.h>", assemblyName); twSource.WriteLine( "#include <{0}_internal.h>", assemblyName); twSource.SplitLine(); // Write assembly references at the file scope. InternalWriteAssemblyReferences( twSource, translateContext, extractContext, targetType); twSource.WriteLine("#ifdef __cplusplus"); twSource.WriteLine("extern \"C\" {"); twSource.WriteLine("#endif"); twSource.SplitLine(); InternalWriteSourceCode( twSource, extractContext, prepared, targetType, debugInformationOption, typesByDeclaring); twSource.WriteLine("#ifdef __cplusplus"); twSource.WriteLine("}"); twSource.WriteLine("#endif"); twSource.SplitLine(); twSource.Flush(); sourceFiles.Add(twSource.RelatedPath); } // HACK: Unreal Engine 4 needs include directive with same file name as header extension (ex: foo.c --> foo.h) at first line. if (extractContext.TargetPlatform == TargetPlatforms.UE4) { using (var twUE4Header = storage.CreateHeaderWriter(targetType.Name)) { twUE4Header.WriteLine( "// [16-2] This is {0} native code translated by IL2C, do not edit.", assemblyName); twUE4Header.WriteLine( "// It's a dummy header file for helping and using only Unreal Engine 4.", assemblyName); twUE4Header.Flush(); } } } } return(sourceFiles.ToArray()); }
public static string[] WriteSourceCodes( CodeTextStorage storage, TranslateContext translateContext, PreparedInformations prepared, DebugInformationOptions debugInformationOption) { IExtractContextHost extractContext = translateContext; var assemblyName = extractContext.Assembly.Name; var typesByDeclaring = prepared.Types. GroupBy(type => type.DeclaringType ?? type). ToDictionary( g => g.Key, g => g.OrderByDependant(translateContext.Assembly).ToArray()); var sourceFiles = new List <string>(); foreach (var targetType in prepared.Types. Where(type => type.DeclaringType == null)) { using (var _ = storage.EnterScope(targetType.ScopeName)) { using (var twSource = storage.CreateSourceCodeWriter(targetType.Name)) { twSource.WriteLine( "// [15-2] This is {0} native code translated by IL2C, do not edit.", assemblyName); twSource.SplitLine(); twSource.WriteLine( "#include <{0}.h>", assemblyName); twSource.WriteLine( "#include <{0}_internal.h>", assemblyName); twSource.SplitLine(); // Write assembly references at the file scope. InternalWriteAssemblyReferences( twSource, translateContext, extractContext, targetType); twSource.WriteLine("#ifdef __cplusplus"); twSource.WriteLine("extern \"C\" {"); twSource.WriteLine("#endif"); twSource.SplitLine(); InternalWriteSourceCode( twSource, extractContext, prepared, targetType, debugInformationOption, typesByDeclaring); twSource.WriteLine("#ifdef __cplusplus"); twSource.WriteLine("}"); twSource.WriteLine("#endif"); twSource.SplitLine(); twSource.Flush(); sourceFiles.Add(twSource.RelatedPath); } } } return(sourceFiles.ToArray()); }
private static void InternalWriteSourceCode( CodeTextWriter twSource, IExtractContextHost extractContext, PreparedInformations prepared, ITypeInformation targetType, DebugInformationOptions debugInformationOption, IReadOnlyDictionary <ITypeInformation, ITypeInformation[]> typesByDeclaring) { // TODO: invalid sequence for multiple nested types. if (typesByDeclaring.TryGetValue(targetType, out var types)) { foreach (var type in types) { // The nested types have to declare before outer types. if (!type.Equals(targetType)) { InternalWriteSourceCode( twSource, extractContext, prepared, type, debugInformationOption, typesByDeclaring); } twSource.WriteLine("//////////////////////////////////////////////////////////////////////////////////"); twSource.WriteLine( "// [9-1] Type: {0}", targetType.FriendlyName); twSource.SplitLine(); twSource.WriteLine("//////////////////////////////////////////////////////////////////////////////////"); twSource.WriteLine("// [9-2] File scope prototypes:"); twSource.SplitLine(); // Write type members. TypeWriter.WriteMemberDefinitions( twSource, type, field => field.CLanguageMemberScope == MemberScopes.File, method => (method.CLanguageMemberScope == MemberScopes.File) && prepared.Functions.ContainsKey(method)); // All static fields except enum and native value. if (!type.IsEnum) { var staticFields = type.Fields. Where(field => field.IsStatic && (field.NativeValue == null)). ToArray(); if (staticFields.Length >= 1) { twSource.WriteLine("//////////////////////////////////////////////////////////////////////////////////"); twSource.WriteLine("// [9-3] Static field handlers:"); twSource.SplitLine(); var staticFieldsName = type.MangledUniqueName + "_STATIC_FIELDS"; twSource.WriteLine( "static volatile uintptr_t {0}_initializerCount__ = 0;", staticFieldsName); twSource.SplitLine(); twSource.WriteLine( "static struct {0}_DECL__ /* IL2C_STATIC_FIELDS */", staticFieldsName); twSource.WriteLine("{"); var objrefStaticFields = staticFields. Where(field => field.FieldType.IsReferenceType). ToArray(); var valueTypeStaticFields = staticFields. Where(field => field.FieldType.IsValueType && field.FieldType.IsRequiredTraverse). ToArray(); var otherStaticFields = new HashSet <IFieldInformation>(staticFields. Except(objrefStaticFields). Except(valueTypeStaticFields)); using (var _ = twSource.Shift()) { twSource.WriteLine("IL2C_STATIC_FIELDS* pNext__;"); twSource.WriteLine("const uint16_t objRefCount__;"); twSource.WriteLine("const uint16_t valueCount__;"); if (objrefStaticFields.Length >= 1) { twSource.WriteLine("//-------------------- objref"); foreach (var field in objrefStaticFields) { twSource.WriteLine( "{0} {1};", field.FieldType.CLanguageTypeName, field.MangledName); } } if (valueTypeStaticFields.Length >= 1) { twSource.WriteLine("//-------------------- value type"); foreach (var field in valueTypeStaticFields) { twSource.WriteLine( "{0} {1};", field.FieldType.CLanguageTypeName, field.MangledName); } } } twSource.WriteLine( "}} {0}__ = {{ NULL, {1}, {2} }};", staticFieldsName, objrefStaticFields.Length, valueTypeStaticFields.Length); twSource.SplitLine(); foreach (var field in otherStaticFields) { twSource.WriteLine( "static {0} {1};", field.FieldType.CLanguageTypeName, field.MangledUniqueName); } twSource.SplitLine(); foreach (var field in staticFields) { twSource.WriteLine( "{0}* {1}_HANDLER__(void)", field.FieldType.CLanguageTypeName, field.MangledUniqueName); twSource.WriteLine("{"); using (var _ = twSource.Shift()) { // TODO: Have to guard race condition for the multi threading feature. twSource.WriteLine( "if (il2c_unlikely__({0}_initializerCount__ != *il2c_initializer_count))", staticFieldsName); twSource.WriteLine("{"); using (var __ = twSource.Shift()) { twSource.WriteLine( "{0}_initializerCount__ = *il2c_initializer_count;", staticFieldsName); twSource.WriteLine( "il2c_register_static_fields(&{0}__);", staticFieldsName); var typeInitializer = type.DeclaredMethods. FirstOrDefault(method => method.IsConstructor && method.IsStatic); if (typeInitializer != null) { twSource.WriteLine( "{0}();", typeInitializer.CLanguageFunctionFullName); } } twSource.WriteLine("}"); if (otherStaticFields.Contains(field)) { twSource.WriteLine( "return &{0};", field.MangledUniqueName); } else { twSource.WriteLine( "return &{0}__.{1};", staticFieldsName, field.MangledName); } } twSource.WriteLine("}"); twSource.SplitLine(); } } } twSource.WriteLine("//////////////////////////////////////////////////////////////////////////////////"); twSource.WriteLine("// [9-4] Type: {0}", type.FriendlyName); twSource.SplitLine(); // All methods and constructor exclude type initializer foreach (var method in type.DeclaredMethods. Where(method => prepared.Functions.ContainsKey(method))) { FunctionWriter.InternalConvertFromMethod( twSource, extractContext, prepared, method, debugInformationOption); } if (type.IsClass || type.IsValueType) { TypeHelperWriter.InternalConvertTypeHelper( twSource, type); } else if (type.IsInterface) { TypeHelperWriter.InternalConvertTypeHelperForInterface( twSource, type); } twSource.SplitLine(); } } }
public DebugInformationWriteController(IMethodInformation method, DebugInformationOptions mode) { this.mode = mode; this.debug = method.CodeStream.First().Debug.FirstOrDefault(); }
public static void InternalConvertFromMethod( CodeTextWriter tw, IExtractContextHost extractContext, PreparedInformations preparedFunctions, IMethodInformation method, DebugInformationOptions debugInformationOption = DebugInformationOptions.None) { if (method.IsVirtual) { if (method.IsAbstract) { if (!method.DeclaringType.IsInterface) { InternalConvertFromAbstractFunction( tw, method); } return; } } // internalcall or DllImport if (method.IsExtern) { // DllImport var pinvokeInfo = method.PInvokeInfo; if (pinvokeInfo != null) { InternalConvertFromPInvokeFunction( tw, method, pinvokeInfo); return; } // Specialize delegate type methods: if (method.DeclaringType.IsDelegate && !method.DeclaringType.IsAbstract) { // Delegate constructor if (method.IsConstructor) { // Ignore. We have to use the "il2c_new_delegate()" instead this constructor translated body. return; } // Delegate "Invoke" if (method.Name == "Invoke") { InternalConvertFromDelegateInvoker( tw, extractContext, method); return; } } throw new InvalidProgramSequenceException( "Unknown internallcall method declaration. Name={0}", method.FriendlyName); } if (!preparedFunctions.Functions.TryGetValue(method, out var preparedMethod)) { return; } InternalConvertFromFunction( tw, extractContext, preparedMethod, debugInformationOption); }
private static void InternalConvertFromFunction( CodeTextWriter tw, IExtractContextHost extractContext, PreparedMethodInformation preparedMethod, DebugInformationOptions debugInformationOption) { var locals = preparedMethod.Method.LocalVariables; tw.SplitLine(); tw.WriteLine("///////////////////////////////////////"); tw.WriteLine( "// [3] {0}{1}", preparedMethod.Method.IsVirtual ? "Virtual: " : string.Empty, preparedMethod.Method.FriendlyName); var codeStream = preparedMethod.Method.CodeStream; // Write exception filters: if (codeStream.ExceptionHandlers.Length >= 1) { tw.SplitLine(); tw.WriteLine("//-------------------"); tw.WriteLine("// [3-1] Exception filters:"); tw.SplitLine(); for (var handlerIndex = 0; handlerIndex < codeStream.ExceptionHandlers.Length; handlerIndex++) { var handler = codeStream.ExceptionHandlers[handlerIndex]; var filterName = string.Format( "{0}_ExceptionFilter{1}__", preparedMethod.Method.CLanguageFunctionName, handlerIndex); tw.WriteLine( "static int16_t {0}(System_Exception* ex)", filterName); tw.WriteLine("{"); using (var _ = tw.Shift()) { tw.WriteLine("il2c_assert(ex != NULL);"); for (var catchHandlerIndex = 0; catchHandlerIndex < handler.CatchHandlers.Length; catchHandlerIndex++) { var catchHandler = handler.CatchHandlers[catchHandlerIndex]; if (catchHandler.CatchHandlerType == ExceptionCatchHandlerTypes.Catch) { tw.WriteLine( "if (il2c_isinst__(ex, il2c_typeof({0}))) return {1};", catchHandler.CatchType.MangledName, catchHandlerIndex + 1); } } // Write finally block index if contains. var finallyHandler = handler.CatchHandlers. Select((catchHandler, index) => new { catchHandler, index }). FirstOrDefault(entry => entry.catchHandler.CatchHandlerType == ExceptionCatchHandlerTypes.Finally); if (finallyHandler != null) { tw.WriteLine("return IL2C_FILTER_FINALLY; // Not matched (will go to finally)"); } else { tw.WriteLine("return IL2C_FILTER_NOMATCH; // Not matched"); } } tw.WriteLine("}"); } } // Start function: tw.SplitLine(); tw.WriteLine("//-------------------"); tw.WriteLine("// [3-2] Function body:"); tw.SplitLine(); tw.WriteLine(preparedMethod.Method.CLanguageFunctionPrototype); tw.WriteLine("{"); using (var _ = tw.Shift()) { if (!preparedMethod.Method.IsStatic) { tw.WriteLine("il2c_assert(this__ != NULL);"); tw.SplitLine(); } var localDefinitions = preparedMethod.Method.LocalVariables. Where(local => !local.TargetType.IsReferenceType). ToArray(); if (localDefinitions.Length >= 1) { tw.WriteLine("//-------------------"); tw.WriteLine("// [3-3] Local variables (not objref):"); tw.SplitLine(); foreach (var local in localDefinitions) { // HACK: The local variables mark to "volatile." // Because the gcc misread these variables calculated statically (or maybe assigned to the registers) // at compile time with optimization. // It will cause the strange results for exception handling (with sjlj.) tw.WriteLine( "{0}{1} {2};", (codeStream.ExceptionHandlers.Length >= 1) ? "volatile " : string.Empty, local.TargetType.CLanguageTypeName, extractContext.GetSymbolName(local)); } tw.SplitLine(); } var stackDefinitions = preparedMethod.Stacks. Where(stack => !stack.TargetType.IsReferenceType). ToArray(); if (stackDefinitions.Length >= 1) { tw.WriteLine("//-------------------"); tw.WriteLine("// [3-4] Evaluation stacks (not objref):"); tw.SplitLine(); foreach (var stack in stackDefinitions) { tw.WriteLine( "{0} {1};", stack.TargetType.CLanguageTypeName, extractContext.GetSymbolName(stack)); } tw.SplitLine(); } var objRefEntries = locals. Concat(preparedMethod.Stacks). Where(v => v.TargetType.IsReferenceType). // Only objref ToArray(); if (objRefEntries.Length >= 1) { tw.WriteLine("//-------------------"); tw.WriteLine("// [3-5] Setup execution frame:"); tw.SplitLine(); tw.WriteLine( "struct {0}_EXECUTION_FRAME__", preparedMethod.Method.CLanguageFunctionName); tw.WriteLine("{"); using (var __ = tw.Shift()) { tw.WriteLine("uint8_t objRefCount__;"); tw.WriteLine("uint8_t objRefRefCount__;"); tw.WriteLine("IL2C_EXECUTION_FRAME* pNext__;"); foreach (var objRefEntry in objRefEntries) { tw.WriteLine( "{0} {1};", objRefEntry.TargetType.CLanguageTypeName, extractContext.GetSymbolName(objRefEntry)); } } // Important NULL assigner (p = NULL): // Because these variables are pointer (of object reference 'O' type). // So GC will traverse these variables just setup the stack frame. // TODO: https://github.com/kekyo/IL2C/issues/12 tw.WriteLine("}} frame__ = {{ {0}, 0 }};", objRefEntries.Length); tw.WriteLine("il2c_link_execution_frame(&frame__);"); tw.SplitLine(); } tw.WriteLine("//-------------------"); tw.WriteLine("// [3-6] IL body:"); tw.SplitLine(); // Set symbol prefix to make valid access variables. using (var __ = extractContext.BeginLocalVariablePrefix( local => local.TargetType.IsReferenceType ? "frame__." : null)) { // Construct exception handler controller. var exceptionHandlerController = new ExceptionHandlerController( codeStream.ExceptionHandlers, (handler, handlerIndex, nestedIndex) => { var nestedIndexName = string.Format("nest{0}", nestedIndex); extractContext.SetNestedExceptionFrameIndexName(nestedIndexName); // Reached try block: var filterName = string.Format( "{0}_ExceptionFilter{1}__", preparedMethod.Method.CLanguageFunctionName, handlerIndex); tw.WriteLine("il2c_try({0}, {1})", nestedIndexName, filterName); tw.WriteLine("{"); tw.Shift(); }, (handler, handlerIndex, nestedIndex) => { // Reached try end block: tw.Shift(-1); tw.WriteLine("}"); }, (handler, handlerIndex, nestedIndex, catchHandler, catchHandlerIndex) => { var nestedIndexName = extractContext.GetExceptionNestedFrameIndexName(); switch (catchHandler.CatchHandlerType) { case ExceptionCatchHandlerTypes.Catch: // Reached catch block: tw.WriteLine( "il2c_catch({0}, {1}, {2}) // catch ({3})", nestedIndexName, catchHandlerIndex + 1, extractContext.GetSymbolName(preparedMethod.CatchVariables[catchHandler.CatchStart]), catchHandler.CatchType.MangledName); break; case ExceptionCatchHandlerTypes.Finally: // Reached finally block: tw.WriteLine("il2c_finally({0})", nestedIndexName); break; } tw.WriteLine("{"); tw.Shift(); }, (handler, handlerIndex, nestedIndex, catchHandler, catchHandlerIndex) => { // Reached catch end block: tw.Shift(-1); tw.WriteLine("}"); }, (handler, handlerIndex, nestedIndex, parentHandler, parentHandlerIndex, parentNestedIndex) => { var nestedIndexName = extractContext.GetExceptionNestedFrameIndexName(); var parentNestedIndexName = (parentNestedIndex >= 0) ? string.Format("nest{0}", parentNestedIndex) : null; // Write leave bind expressions if needed. // Extract the continuation fromOffset inside at mostly inner exception handler. var bindEntries = preparedMethod.LeaveContinuations. SelectMany(entry => codeStream.ExceptionHandlers. // nested exception handlers: inner --> outer Reverse(). // Is this handler contains leave continuation target? Where(h => entry.Value.fromOffsets.Any(offset => h.ContainsOffset(offset))). // Found. Select(h => new { handler = h, continuationIndex = entry.Key, entry.Value.targetOffset })). // ... is current handler? Where(entry => entry.handler.Equals(handler)). ToArray(); if (bindEntries.Length >= 1) { tw.WriteLine("il2c_leave_to({0})", nestedIndexName); tw.WriteLine("{"); using (var ___ = tw.Shift()) { foreach (var bind in bindEntries) { if ((parentNestedIndex < 0) || codeStream.ExceptionHandlers[parentNestedIndex].ContainsOffset(bind.targetOffset)) { var labelName = preparedMethod.LabelNames[bind.targetOffset]; tw.WriteLine( "il2c_leave_bind({0}, {1}, {2});", nestedIndexName, bind.continuationIndex, labelName); } else { tw.WriteLine( "il2c_leave_through({0}, {1}, {2});", nestedIndexName, bind.continuationIndex, parentNestedIndexName); } } } tw.WriteLine("}"); } // Reached end of entire try block. tw.WriteLine("il2c_end_try({0});", nestedIndexName); extractContext.SetNestedExceptionFrameIndexName(parentNestedIndexName); }); // Traverse code fragments. var canWriteSequencePoint = true; foreach (var ci in codeStream) { // 1: Update the exception handler controller. // (Will write exception related sentences.) exceptionHandlerController.Update(ci); // 2: Write label if available and used. if (preparedMethod.LabelNames.TryGetValue(ci.Offset, out var labelName)) { using (var ___ = tw.Shift(-1)) { tw.WriteLine("{0}:", labelName); } } // 3: Write the line preprocessor directive if available. if (canWriteSequencePoint && ci.Debug.Any()) { var sp = ci.Debug.First(); switch (debugInformationOption) { case DebugInformationOptions.Full: tw.Parent.WriteLine( "#line {0} \"{1}\"", sp.Line, sp.Path.Replace("\\", "\\\\")); break; case DebugInformationOptions.CommentOnly: tw.Parent.WriteLine( "/* {0}({1}): */", sp.Path.Replace("\\", "\\\\"), sp.Line); break; } canWriteSequencePoint = false; } // 4: Generate source code fragments and write. if (debugInformationOption != DebugInformationOptions.None) { // Write debugging information. tw.WriteLine( "/* {0} */", ci); } var sourceCodes = preparedMethod.Generators[ci.Offset](extractContext); foreach (var sourceCode in sourceCodes) { // Dirty hack: // Write unlink execution frame code if cause exiting method. if (sourceCode.StartsWith("return") && (objRefEntries.Length >= 1)) { tw.WriteLine( "il2c_unlink_execution_frame(&frame__);"); } tw.WriteLine( "{0};", sourceCode); canWriteSequencePoint = true; } } if (!exceptionHandlerController.IsFinished) { throw new InvalidProgramSequenceException( "Invalid exception handler range. MethodName={0}, ExceptionHandlers=[{1}]", preparedMethod.Method.FriendlyName, string.Join( ",", codeStream.ExceptionHandlers. Select(handler => string.Format("[{0}]", handler)))); } } } tw.WriteLine("}"); tw.SplitLine(); }
private static void InternalConvertFromFunction( TextWriter tw, IExtractContext extractContext, PreparedFunction preparedFunction, string indent, DebugInformationOptions debugInformationOption) { var locals = preparedFunction.LocalVariables; var functionPrototype = Utilities.GetFunctionPrototypeString( GetFunctionNameByFunctionType(preparedFunction), preparedFunction.ReturnType, preparedFunction.Parameters, extractContext); tw.WriteLine(); tw.WriteLine("///////////////////////////////////////"); tw.WriteLine( "// {0}{1}", (preparedFunction.FunctionType == FunctionTypes.Virtual) ? "Virtual: " : string.Empty, preparedFunction.RawMethodName); tw.WriteLine(); tw.WriteLine(functionPrototype); tw.WriteLine("{"); tw.WriteLine("{0}//-------------------", indent); tw.WriteLine("{0}// Local variables:", indent); tw.WriteLine(); // Important NULL assigner (p = NULL): // Because these variables are pointer (of object reference). // So GC will traverse these variables just setup the stack frame. foreach (var local in preparedFunction.LocalVariables) { tw.WriteLine( "{0}{1} {2}{3};", indent, extractContext.GetCLanguageTypeName(local.TargetType), local.SymbolName, local.TargetType.IsValueType ? string.Empty : " = NULL"); } tw.WriteLine(); tw.WriteLine("{0}//-------------------", indent); tw.WriteLine("{0}// Evaluation stacks:", indent); tw.WriteLine(); foreach (var si in preparedFunction.Stacks) { tw.WriteLine( "{0}{1} {2}{3};", indent, extractContext.GetCLanguageTypeName(si.TargetType), si.SymbolName, si.TargetType.IsValueType ? string.Empty : " = NULL"); } var frameEntries = locals .Concat(preparedFunction.Stacks) .Where(local => !local.TargetType.IsValueType && !local.TargetType.IsPointer) .ToArray(); if (frameEntries.Length >= 1) { tw.WriteLine(); tw.WriteLine("{0}//-------------------", indent); tw.WriteLine("{0}// Setup stack frame:", indent); tw.WriteLine(); tw.WriteLine("{0}struct /* IL2C_EXECUTION_FRAME */", indent); tw.WriteLine("{0}{{", indent); tw.WriteLine("{0}{0}IL2C_EXECUTION_FRAME* pNext;", indent); tw.WriteLine("{0}{0}uint8_t targetCount;", indent); foreach (var frameEntry in frameEntries) { tw.WriteLine( "{0}{0}{1}* p{2};", indent, extractContext.GetCLanguageTypeName(frameEntry.TargetType), frameEntry.SymbolName); } tw.WriteLine("{0}}} __executionFrame__;", indent); tw.WriteLine(); tw.WriteLine("{0}__executionFrame__.targetCount = {1};", indent, frameEntries.Length); foreach (var frameEntry in frameEntries) { tw.WriteLine( "{0}__executionFrame__.p{1} = &{1};", indent, frameEntry.SymbolName); } tw.WriteLine("{0}il2c_link_execution_frame(&__executionFrame__);", indent); } tw.WriteLine(); tw.WriteLine("{0}//-------------------", indent); tw.WriteLine("{0}// IL body:", indent); tw.WriteLine(); var canWriteSequencePoint = true; foreach (var ilBody in preparedFunction.PreparedILBodies) { // Write label if available and used. if (preparedFunction.TryGetLabelName( ilBody.Label, out var labelName)) { tw.WriteLine("{0}:", labelName); } // Write the line preprocessor directive if available. if (canWriteSequencePoint && ilBody.SequencePoints.Any()) { var sp = ilBody.SequencePoints.First(); switch (debugInformationOption) { case DebugInformationOptions.Full: tw.WriteLine( "#line {0} \"{1}\"", sp.StartLine, sp.Document.Url.Replace("\\", "\\\\")); break; case DebugInformationOptions.CommentOnly: tw.WriteLine( "/* {0}({1}): */", sp.Document.Url.Replace("\\", "\\\\"), sp.StartLine); break; } canWriteSequencePoint = false; } if (debugInformationOption != DebugInformationOptions.None) { // Write debugging information. tw.WriteLine( "{0}/* {1} */", indent, ilBody); } // Generate source code fragments and write. var sourceCodes = ilBody.Generator(extractContext); foreach (var sourceCode in sourceCodes) { // Dirty hack: // Write unlink execution frame code if cause exiting method. if (sourceCode.StartsWith("return") && (frameEntries.Length >= 1)) { tw.WriteLine( "{0}il2c_unlink_execution_frame(&__executionFrame__);", indent); } tw.WriteLine( "{0}{1};", indent, sourceCode); canWriteSequencePoint = true; } } tw.WriteLine("}"); }
public static void WriteSourceCode( TextWriter twSource, TranslateContext translateContext, PreparedFunctions preparedFunctions, string indent, DebugInformationOptions debugInformationOption = DebugInformationOptions.Full) { IExtractContext extractContext = translateContext; foreach (var fileName in extractContext.EnumerateRequiredPrivateIncludeFileNames()) { twSource.WriteLine("#include \"{0}\"", fileName); } var assemblyName = extractContext.Assembly.Name.Name; twSource.WriteLine("#include \"{0}.h\"", assemblyName); twSource.WriteLine(); twSource.WriteLine("//////////////////////////////////////////////////////////////////////////////////"); twSource.WriteLine("// Const strings:"); twSource.WriteLine(); foreach (var kv in extractContext.ExtractConstStrings()) { var escaped = Utilities.GetEscapedCString(kv.Value); twSource.WriteLine( "IL2C_CONST_STRING({0}, L\"{1}\");", kv.Key, escaped); } var allTypes = extractContext.Assembly.Modules .SelectMany(module => module.Types) .SelectMany(type => new[] { type }.Concat(type.NestedTypes)) .Where(type => type.IsValidDefinition()) .ToArray(); // All types exclude publics and internals (for file scope prototypes) var types = allTypes .Where(type => !(type.IsPublic || type.IsNestedPublic || type.IsNestedFamily || type.IsNestedFamilyOrAssembly)) .ToArray(); InternalConvertToPrototypes( twSource, types, extractContext, preparedFunctions, method => !(method.IsPublic || method.IsFamily || method.IsFamilyOrAssembly), indent); twSource.WriteLine(); twSource.WriteLine("//////////////////////////////////////////////////////////////////////////////////"); twSource.WriteLine("// Static fields:"); foreach (var type in allTypes.Where(type => !type.IsEnum)) { twSource.WriteLine(); // All static fields foreach (var field in type.Fields .Where(field => field.IsStatic)) { twSource.WriteLine( "{0};", Utilities.GetStaticFieldPrototypeString(field, true, extractContext)); } } twSource.WriteLine(); twSource.WriteLine("//////////////////////////////////////////////////////////////////////////////////"); twSource.WriteLine("// Methods:"); foreach (var type in allTypes.Where(type => !type.IsEnum)) { twSource.WriteLine(); twSource.WriteLine("////////////////////////////////////////////////////////////"); twSource.WriteLine("// Type: {0}", type.GetFullMemberName()); // All methods and constructor exclude type initializer foreach (var method in type.Methods .Where(method => !method.IsConstructor || !method.IsStatic)) { InternalConvertFromMethod( twSource, extractContext, preparedFunctions, method, indent, debugInformationOption); } if (type.IsClass || type.IsValueType) { InternalConvertTypeHelper( twSource, extractContext, type, indent); } else if (type.IsInterface) { InternalConvertTypeHelperForInterface( twSource, type, indent); } } }
public static void InternalConvertFromMethod( CodeTextWriter tw, IExtractContextHost extractContext, PreparedInformations preparedFunctions, IMethodInformation method, DebugInformationOptions debugInformationOption = DebugInformationOptions.None) { if (method.IsVirtual) { if (method.IsAbstract) { if (!method.DeclaringType.IsInterface) { InternalConvertFromAbstractFunction( tw, method); } return; } } // internalcall or DllImport if (method.IsExtern) { // Specialize delegate type methods: if (method.DeclaringType.IsDelegate && !method.DeclaringType.IsAbstract) { // Delegate constructor if (method.IsConstructor) { // Ignore. We have to use the "il2c_new_delegate()" instead this constructor translated body. return; } // Delegate "Invoke" if (method.Name == "Invoke") { InternalConvertFromDelegateInvoker( tw, extractContext, method); return; } } // InternalCall or DllImport InternalConvertFromInternalCallFunction( tw, method); return; } if (!preparedFunctions.Functions.TryGetValue(method, out var preparedMethod)) { return; } InternalConvertFromFunction( tw, extractContext, preparedMethod, debugInformationOption); }
private static void InternalConvertFromFunction( CodeTextWriter tw, IExtractContextHost extractContext, PreparedMethodInformation preparedMethod, DebugInformationOptions debugInformationOption) { var locals = preparedMethod.Method.LocalVariables; tw.WriteLine("///////////////////////////////////////"); tw.WriteLine( "// [3] {0}{1}", preparedMethod.Method.IsVirtual ? "Virtual: " : string.Empty, preparedMethod.Method.FriendlyName); tw.SplitLine(); var codeStream = preparedMethod.Method.CodeStream; var objRefEntries = locals. Concat(preparedMethod.Stacks). Where(v => v.TargetType.IsReferenceType). // Only objref ToArray(); var valueEntries = locals. Concat(preparedMethod.Stacks). Where(v => v.TargetType.IsValueType && v.TargetType.IsRequiredTraverse). ToArray(); // Write declaring exception handlers if (codeStream.ExceptionHandlers.Length >= 1) { InternalConvertExceptionFilter( tw, extractContext, preparedMethod, codeStream); } // Write declaring execution frame if ((objRefEntries.Length >= 1) || (valueEntries.Length >= 1)) { InternalConvertExecutionFrame( tw, extractContext, preparedMethod, objRefEntries, valueEntries); } // Make readable debugging comment, it was splitting and reducing same informations. var debugInformationController = new DebugInformationWriteController( preparedMethod.Method, debugInformationOption); // Start function: tw.WriteLine("//-------------------"); tw.WriteLine("// [3-2] Function body:"); tw.SplitLine(); tw.WriteLine(preparedMethod.Method.CLanguageFunctionPrototype); tw.WriteLine("{"); using (var _ = tw.Shift()) { if (!preparedMethod.Method.IsStatic) { debugInformationController.WriteInformationBeforeCode(tw); tw.WriteLine("il2c_assert(this__ != NULL);"); tw.SplitLine(); } var localDefinitions = preparedMethod.Method.LocalVariables. Where(local => !local.TargetType.IsReferenceType). ToArray(); if (localDefinitions.Length >= 1) { tw.WriteLine("//-------------------"); tw.WriteLine("// [3-3] Local variables (!objref):"); tw.SplitLine(); foreach (var local in localDefinitions) { var name = extractContext.GetSymbolName(local); // HACK: The local variables mark to "volatile." // Because the gcc misread these variables calculated statically (or maybe assigned to the registers) // at compile time with optimization. // It will cause the strange results for exception handling (with sjlj.) // We have to initialize the local variables. if (local.TargetType.IsPrimitive || local.TargetType.IsPointer || local.TargetType.IsByReference) { debugInformationController.WriteInformationBeforeCode(tw); tw.WriteLine( "{0}{1} {2} = {3};", (codeStream.ExceptionHandlers.Length >= 1) ? "volatile " : string.Empty, local.TargetType.CLanguageTypeName, name, Utilities.GetCLanguageExpression(local.TargetType.InternalStaticEmptyValue)); } else { Debug.Assert(local.TargetType.IsValueType); debugInformationController.WriteInformationBeforeCode(tw); tw.WriteLine( "{0}{1} {2};", (codeStream.ExceptionHandlers.Length >= 1) ? "volatile " : string.Empty, local.TargetType.CLanguageTypeName, name); debugInformationController.WriteInformationBeforeCode(tw); tw.WriteLine( "memset({0}&{1}, 0x00, sizeof {1});", (codeStream.ExceptionHandlers.Length >= 1) ? "(void*)" : string.Empty, name); } } tw.SplitLine(); } var stackDefinitions = preparedMethod.Stacks. Where(stack => !stack.TargetType.IsReferenceType). ToArray(); if (stackDefinitions.Length >= 1) { tw.WriteLine("//-------------------"); tw.WriteLine("// [3-4] Evaluation stacks (!objref):"); tw.SplitLine(); foreach (var stack in stackDefinitions) { var name = extractContext.GetSymbolName(stack); debugInformationController.WriteInformationBeforeCode(tw); tw.WriteLine( "{0} {1};", stack.TargetType.CLanguageTypeName, name); // Note: We often don't have to initalize the evaluation stack variables. // Because these variables push value at first usage. // But the value type may contains objref field, // so we have to initialize for value type. if (stack.TargetType.IsRequiredTraverse) { debugInformationController.WriteInformationBeforeCode(tw); tw.WriteLine( "memset(&{0}, 0, sizeof {0});", name); } } tw.SplitLine(); } // Write doing setup execution frame if ((objRefEntries.Length >= 1) || (valueEntries.Length >= 1)) { InternalConvertSetupExecutionFrame( tw, extractContext, preparedMethod, objRefEntries, valueEntries, debugInformationController); } tw.WriteLine("//-------------------"); tw.WriteLine("// [3-6] IL body:"); tw.SplitLine(); // Set symbol prefix to make valid access variables. using (var __ = extractContext.BeginLocalVariablePrefix( local => local.TargetType.IsReferenceType ? "frame__." : null)) { // Construct exception handler controller. var exceptionHandlerController = new ExceptionHandlerController( codeStream.ExceptionHandlers, (handler, handlerIndex, nestedIndex) => { var nestedIndexName = string.Format("nest{0}", nestedIndex); extractContext.SetNestedExceptionFrameIndexName(nestedIndexName); // Reached try block: var filterName = string.Format( "{0}_ExceptionFilter{1}__", preparedMethod.Method.CLanguageFunctionName, handlerIndex); debugInformationController.WriteInformationBeforeCode(tw); tw.WriteLine("il2c_try({0}, {1})", nestedIndexName, filterName); debugInformationController.WriteInformationBeforeCode(tw); tw.WriteLine("{"); tw.Shift(); }, (handler, handlerIndex, nestedIndex) => { // Reached try end block: debugInformationController.WriteInformationBeforeCode(tw); tw.Shift(-1); tw.WriteLine("}"); }, (handler, handlerIndex, nestedIndex, catchHandler, catchHandlerIndex) => { var nestedIndexName = extractContext.GetExceptionNestedFrameIndexName(); switch (catchHandler.CatchHandlerType) { case ExceptionCatchHandlerTypes.Catch: // Reached catch block: debugInformationController.WriteInformationBeforeCode(tw); tw.WriteLine( "il2c_catch({0}, {1}, {2}) // catch ({3})", nestedIndexName, catchHandlerIndex + 1, extractContext.GetSymbolName(preparedMethod.CatchVariables[catchHandler.CatchStart]), catchHandler.CatchType.MangledUniqueName); break; case ExceptionCatchHandlerTypes.Finally: // Reached finally block: debugInformationController.WriteInformationBeforeCode(tw); tw.WriteLine("il2c_finally({0})", nestedIndexName); break; } debugInformationController.WriteInformationBeforeCode(tw); tw.WriteLine("{"); tw.Shift(); }, (handler, handlerIndex, nestedIndex, catchHandler, catchHandlerIndex) => { // Reached catch end block: debugInformationController.WriteInformationBeforeCode(tw); tw.Shift(-1); tw.WriteLine("}"); }, (handler, handlerIndex, nestedIndex, parentHandler, parentHandlerIndex, parentNestedIndex) => { var nestedIndexName = extractContext.GetExceptionNestedFrameIndexName(); var parentNestedIndexName = (parentNestedIndex >= 0) ? string.Format("nest{0}", parentNestedIndex) : null; // Write leave bind expressions if needed. // Extract the continuation fromOffset inside at mostly inner exception handler. var bindEntries = preparedMethod.LeaveContinuations. SelectMany(entry => codeStream.ExceptionHandlers. // nested exception handlers: inner --> outer Reverse(). // Is this handler contains leave continuation target? Where(h => entry.Value.fromOffsets.Any(offset => h.ContainsOffset(offset))). // Found. Select(h => new { handler = h, continuationIndex = entry.Key, entry.Value.targetOffset })). // ... is current handler? Where(entry => entry.handler.Equals(handler)). ToArray(); if (bindEntries.Length >= 1) { debugInformationController.WriteInformationBeforeCode(tw); tw.WriteLine("il2c_leave_to({0})", nestedIndexName); debugInformationController.WriteInformationBeforeCode(tw); tw.WriteLine("{"); using (var ___ = tw.Shift()) { foreach (var bind in bindEntries) { if ((parentNestedIndex < 0) || codeStream.ExceptionHandlers[parentNestedIndex].ContainsOffset(bind.targetOffset)) { var labelName = preparedMethod.LabelNames[bind.targetOffset]; debugInformationController.WriteInformationBeforeCode(tw); tw.WriteLine( "il2c_leave_bind({0}, {1}, {2});", nestedIndexName, bind.continuationIndex, labelName); } else { debugInformationController.WriteInformationBeforeCode(tw); tw.WriteLine( "il2c_leave_through({0}, {1}, {2});", nestedIndexName, bind.continuationIndex, parentNestedIndexName); } } } debugInformationController.WriteInformationBeforeCode(tw); tw.WriteLine("}"); } // Reached end of entire try block. debugInformationController.WriteInformationBeforeCode(tw); tw.WriteLine("il2c_end_try({0});", nestedIndexName); extractContext.SetNestedExceptionFrameIndexName(parentNestedIndexName); }); // Traverse code fragments. foreach (var ci in codeStream) { debugInformationController.SetNextCode(ci); // 1: Update the exception handler controller. // (Will write exception related sentences.) exceptionHandlerController.Update(ci); // 2: Write label if available and used. if (preparedMethod.LabelNames.TryGetValue(ci.Offset, out var labelName)) { using (var ___ = tw.Shift(-1)) { tw.WriteLine("{0}:", labelName); } } // 3: Write source code comment. debugInformationController.WriteCodeComment(tw); // 4: Generate source code fragments and write. var sourceCodes = preparedMethod.Generators[ci.Offset](extractContext); foreach (var sourceCode in sourceCodes) { // DIRTY HACK: // Write unlink execution frame code if cause exiting method. if (sourceCode.StartsWith("return") && ((objRefEntries.Length >= 1) || (valueEntries.Length >= 1))) { debugInformationController.WriteInformationBeforeCode(tw); tw.WriteLine( "il2c_unlink_execution_frame(&frame__);"); } debugInformationController.WriteInformationBeforeCode(tw); tw.WriteLine( "{0};", sourceCode); } } // If last opcode is 'endfinally' and not emitted 'ret', // can't finished for exceptionHandlerController. // We can check and force update the TryFinish method for this situation. exceptionHandlerController.TryFinish(); if (!exceptionHandlerController.IsFinished) { throw new InvalidProgramSequenceException( "Invalid exception handler range. MethodName={0}, ExceptionHandlers=[{1}]", preparedMethod.Method.FriendlyName, string.Join( ",", codeStream.ExceptionHandlers. Select(handler => string.Format("[{0}]", handler)))); } } } debugInformationController.WriteInformationBeforeCode(tw); tw.WriteLine("}"); tw.SplitLine(); }
public static void Translate( TextWriter tw, string assemblyPath, string outputPath, bool readSymbols, bool enableCpp, DebugInformationOptions debugInformationOptions) { tw.Write("IL2C: Preparing assembly: \"{0}\" ...", Path.GetFullPath(assemblyPath)); if (Directory.Exists(outputPath) == false) { try { Directory.CreateDirectory(outputPath); } catch { } } var translateContext = new TranslateContext(assemblyPath, readSymbols); var preparedFunctions = AssemblyPreparer.Prepare(translateContext); tw.WriteLine(" done."); var assemblyName = Path.GetFileNameWithoutExtension(assemblyPath); var filePath = Path.Combine(outputPath, assemblyName); var sourceFilePath = filePath + (enableCpp ? ".cpp" : ".c"); tw.Write("IL2C: Writing source code: \"{0}\" ...", Path.GetFullPath(sourceFilePath)); using (var fsSource = new FileStream( sourceFilePath, FileMode.Create, FileAccess.ReadWrite, FileShare.None)) { var twSource = CodeTextWriter.Create(fsSource, " "); AssemblyWriter.WriteSourceCode( twSource, translateContext, preparedFunctions, debugInformationOptions); twSource.Flush(); } tw.WriteLine(" done."); var headerFilePath = filePath + ".h"; tw.Write("IL2C: Writing header: \"{0}\" ...", Path.GetFullPath(headerFilePath)); using (var fsHeader = new FileStream( headerFilePath, FileMode.Create, FileAccess.ReadWrite, FileShare.None)) { var twHeader = CodeTextWriter.Create(fsHeader, " "); AssemblyWriter.WriteHeader(twHeader, translateContext, preparedFunctions); twHeader.Flush(); } tw.WriteLine(" done."); }
internal static void InternalWriteSourceCode( CodeTextWriter twSource, TranslateContext translateContext, PreparedInformations prepared, DebugInformationOptions debugInformationOption, bool includeAssemblyHeader) { IExtractContextHost extractContext = translateContext; if (includeAssemblyHeader) { foreach (var fileName in extractContext.EnumerateRequiredPrivateIncludeFileNames()) { twSource.WriteLine("#include \"{0}\"", fileName); } twSource.WriteLine("#include \"{0}.h\"", extractContext.Assembly.Name); twSource.SplitLine(); } WriteConstStrings(twSource, translateContext); WriteDeclaredValues(twSource, translateContext); twSource.WriteLine("//////////////////////////////////////////////////////////////////////////////////"); twSource.WriteLine("// [9-2] File scope prototypes:"); twSource.SplitLine(); // All types exclude publics and internals (for file scope prototypes) PrototypeWriter.InternalConvertToPrototypes( twSource, prepared.Types, type => !type.IsCLanguagePublicScope, field => !(field.IsPublic || field.IsFamily || field.IsFamilyOrAssembly), method => (method.IsPublic || method.IsFamily || method.IsFamilyOrAssembly) && prepared.Functions.ContainsKey(method)); twSource.WriteLine("//////////////////////////////////////////////////////////////////////////////////"); twSource.WriteLine("// [9-3] Declare static fields:"); twSource.SplitLine(); foreach (var type in prepared.Types. Where(type => !type.IsEnum)) { // All static fields foreach (var field in type.Fields. Where(field => field.IsStatic)) { twSource.WriteLine( "{0};", field.GetCLanguageStaticPrototype(true)); } twSource.SplitLine(); } foreach (var type in prepared.Types) { twSource.WriteLine("//////////////////////////////////////////////////////////////////////////////////"); twSource.WriteLine("// [9-4] Type: {0}", type.FriendlyName); twSource.SplitLine(); // All methods and constructor exclude type initializer foreach (var method in type.DeclaredMethods) { FunctionWriter.InternalConvertFromMethod( twSource, extractContext, prepared, method, debugInformationOption); } if (type.IsClass || type.IsValueType) { TypeHelperWriter.InternalConvertTypeHelper( twSource, type); } else if (type.IsInterface) { TypeHelperWriter.InternalConvertTypeHelperForInterface( twSource, type); } } twSource.SplitLine(); }
internal static void InternalConvertFromMethod( TextWriter tw, IExtractContext extractContext, PreparedFunctions preparedFunctions, MethodDefinition method, string indent, DebugInformationOptions debugInformationOption = DebugInformationOptions.None) { var methodName = method.GetFullMemberName(); var preparedFunction = preparedFunctions.Functions[method]; // Write method body switch (preparedFunction.FunctionType) { case FunctionTypes.Standard: Debug.Assert(preparedFunction.PreparedILBodies != null); InternalConvertFromFunction( tw, extractContext, preparedFunction, indent, debugInformationOption); break; case FunctionTypes.Virtual: if (preparedFunction.PreparedILBodies != null) { InternalConvertFromFunction( tw, extractContext, preparedFunction, indent, debugInformationOption); } else { InternalConvertFromAbstractFunction( tw, extractContext, preparedFunction, indent); } break; case FunctionTypes.InterfaceVirtual: // Nothing to do break; case FunctionTypes.PInvoke: var pinvokeInfo = method.PInvokeInfo; if (pinvokeInfo == null) { throw new InvalidProgramSequenceException( "Missing DllImport attribute at P/Invoke entry: Method={0}", methodName); } InternalConvertFromPInvokeFunction( tw, extractContext, preparedFunction, pinvokeInfo, indent); break; } }