From c076f63586cecd68df7060af1f3c62accdbe1adc Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Fri, 2 Oct 2015 11:59:40 -0700 Subject: [PATCH] Wire up CppCodeGen into ILToNative Adding simple conditions to where we need to take different paths today. There is opportunity for better factoring (e.g. move all name manging into separate class). Fix bugs that I have run into along the way. --- src/ILToNative/src/Compiler/AsmWriter.cs | 2 +- src/ILToNative/src/Compiler/Compilation.cs | 158 +++++++++++++----- .../src/Compiler/MethodExtensions.cs | 56 +++++++ src/ILToNative/src/Compiler/Program.cs | 12 +- .../src/Compiler/RegisteredMethod.cs | 2 +- src/ILToNative/src/Compiler/RegisteredType.cs | 1 + .../src/CppCodeGen/ILToCppImporter.cs | 4 +- src/ILToNative/src/ILToNative.csproj | 9 + src/TypeSystem/src/IL/ILProvider.cs | 5 +- src/TypeSystem/src/IL/Stubs/DelegateThunks.cs | 4 +- 10 files changed, 205 insertions(+), 48 deletions(-) create mode 100644 src/ILToNative/src/Compiler/MethodExtensions.cs diff --git a/src/ILToNative/src/Compiler/AsmWriter.cs b/src/ILToNative/src/Compiler/AsmWriter.cs index ae84f56ea54..4026c828d33 100644 --- a/src/ILToNative/src/Compiler/AsmWriter.cs +++ b/src/ILToNative/src/Compiler/AsmWriter.cs @@ -50,7 +50,7 @@ void OutputMethodCode(RegisteredMethod m) Out.Write(mangledName); Out.WriteLine(":"); - var methodCode = m.MethodCode; + var methodCode = (MethodCode)m.MethodCode; Relocation[] relocs = methodCode.Relocs; int currentRelocIndex = 0; diff --git a/src/ILToNative/src/Compiler/Compilation.cs b/src/ILToNative/src/Compiler/Compilation.cs index 34ec7ced62d..3e65a7a3964 100644 --- a/src/ILToNative/src/Compiler/Compilation.cs +++ b/src/ILToNative/src/Compiler/Compilation.cs @@ -17,18 +17,35 @@ namespace ILToNative { + public struct CompilationOptions + { + public bool Cpp; + } + public partial class Compilation { - TypeSystemContext _typeSystemContext; + readonly TypeSystemContext _typeSystemContext; + readonly CompilationOptions _options; Dictionary _registeredTypes = new Dictionary(); Dictionary _registeredMethods = new Dictionary(); Dictionary _registeredFields = new Dictionary(); List _methodsThatNeedsCompilation = null; - public Compilation(TypeSystemContext typeSystemContext) + ILToNative.CppCodeGen.CppWriter _cppWriter = null; + + public Compilation(TypeSystemContext typeSystemContext, CompilationOptions options) { _typeSystemContext = typeSystemContext; + _options = options; + } + + public TypeSystemContext TypeSystemContext + { + get + { + return _typeSystemContext; + } } public TextWriter Log @@ -45,8 +62,23 @@ public TextWriter Out MethodDesc _mainMethod; + internal MethodDesc MainMethod + { + get + { + return _mainMethod; + } + } - RegisteredType GetRegisteredType(TypeDesc type) + internal IEnumerable RegisteredTypes + { + get + { + return _registeredTypes.Values; + } + } + + internal RegisteredType GetRegisteredType(TypeDesc type) { RegisteredType existingRegistration; if (_registeredTypes.TryGetValue(type, out existingRegistration)) @@ -63,7 +95,7 @@ RegisteredType GetRegisteredType(TypeDesc type) return registration; } - RegisteredMethod GetRegisteredMethod(MethodDesc method) + internal RegisteredMethod GetRegisteredMethod(MethodDesc method) { RegisteredMethod existingRegistration; if (_registeredMethods.TryGetValue(method, out existingRegistration)) @@ -77,7 +109,7 @@ RegisteredMethod GetRegisteredMethod(MethodDesc method) return registration; } - RegisteredField GetRegisteredField(FieldDesc field) + internal RegisteredField GetRegisteredField(FieldDesc field) { RegisteredField existingRegistration; if (_registeredFields.TryGetValue(field, out existingRegistration)) @@ -96,8 +128,7 @@ enum SpecialMethodKind Unknown, PInvoke, RuntimeImport, - Intrinsic, - BoundsChecking, + Intrinsic }; SpecialMethodKind DetectSpecialMethodKind(MethodDesc method) @@ -118,11 +149,6 @@ SpecialMethodKind DetectSpecialMethodKind(MethodDesc method) Log.WriteLine("Intrinsic: " + method.ToString()); return SpecialMethodKind.Intrinsic; } - else if (((EcmaMethod)method).HasCustomAttribute("System.Runtime.CompilerServices.BoundsCheckingAttribute")) - { - Log.WriteLine("BoundsChecking: " + method.ToString()); - return SpecialMethodKind.BoundsChecking; - } else if (((EcmaMethod)method).HasCustomAttribute("System.Runtime.InteropServices.NativeCallableAttribute")) { Log.WriteLine("NativeCallable: " + method.ToString()); @@ -166,17 +192,15 @@ void CompileMethods() foreach (MethodDesc method in pendingMethods) { - try + if (_options.Cpp) { - CompileMethod(method); + _cppWriter.CompileMethod(method); } - catch (Exception e) + else { - Log.WriteLine(e.Message + " (" + method + ")"); - - throw new NotImplementedException(); + CompileMethod(method); } - } + } } void ExpandVirtualMethods() @@ -210,7 +234,14 @@ void ExpandVirtualMethods() public void CompileSingleFile(MethodDesc mainMethod) { - _corInfo = new CorInfoImpl(this); + if (_options.Cpp) + { + _cppWriter = new CppCodeGen.CppWriter(this); + } + else + { + _corInfo = new CorInfoImpl(this); + } _mainMethod = mainMethod; AddMethod(mainMethod); @@ -222,7 +253,14 @@ public void CompileSingleFile(MethodDesc mainMethod) ExpandVirtualMethods(); } - OutputCode(); + if (_options.Cpp) + { + _cppWriter.OutputCode(); + } + else + { + OutputCode(); + } } public void AddMethod(MethodDesc method) @@ -232,13 +270,21 @@ public void AddMethod(MethodDesc method) return; reg.IncludedInCompilation = true; - RegisteredType regType = GetRegisteredType(method.OwningType); - reg.Next = regType.Methods; - regType.Methods = reg; - if (_methodsThatNeedsCompilation == null) _methodsThatNeedsCompilation = new List(); _methodsThatNeedsCompilation.Add(method); + + GetMangledMethodName(method); + + if (_options.Cpp) + { + // Precreate name to ensure that all types referenced by signatures are present + GetMangledTypeName(method.OwningType); + var signature = method.Signature; + GetMangledTypeName(signature.ReturnType); + for (int i = 0; i < signature.Length; i++) + GetMangledTypeName(signature[i]); + } } public void AddVirtualSlot(MethodDesc method) @@ -282,9 +328,16 @@ public void AddField(FieldDesc field) if (reg.IncludedInCompilation) return; reg.IncludedInCompilation = true; + + if (_options.Cpp) + { + // Precreate name to ensure that all types referenced by signatures are present + GetMangledTypeName(field.OwningType); + GetMangledTypeName(field.FieldType); + } } - MethodDesc ResolveVirtualMethod(TypeDesc implType, MethodDesc declMethod) + internal MethodDesc ResolveVirtualMethod(TypeDesc implType, MethodDesc declMethod) { // TODO: Proper virtual method resolution string name = declMethod.Name; @@ -301,11 +354,6 @@ MethodDesc ResolveVirtualMethod(TypeDesc implType, MethodDesc declMethod) } } - internal TypeDesc GetWellKnownType(WellKnownType wellKnownType) - { - return _typeSystemContext.GetWellKnownType(wellKnownType); - } - // Turn a name into a valid identifier private static string SanitizeName(string s) { @@ -331,21 +379,44 @@ internal string GetMangledTypeName(TypeDesc type) switch (type.Category) { case TypeFlags.Array: + // mangledName = "Array<" + GetSignatureCPPTypeName(((ArrayType)type).ElementType) + ">"; mangledName = GetMangledTypeName(((ArrayType)type).ElementType) + "__Array"; + if (((ArrayType)type).Rank != 1) + mangledName += "Rank" + ((ArrayType)type).Rank.ToString(); break; case TypeFlags.ByRef: - mangledName = GetMangledTypeName(((ByRefType)type).ParameterType) + "__ByRef"; + if (_options.Cpp) + mangledName = _cppWriter.GetCppSignatureTypeName(((ByRefType)type).ParameterType) + "*"; + else + mangledName = GetMangledTypeName(((ByRefType)type).ParameterType) + "__ByRef"; break; case TypeFlags.Pointer: - mangledName = GetMangledTypeName(((PointerType)type).ParameterType) + "__Pointer"; + if (_options.Cpp) + mangledName = _cppWriter.GetCppSignatureTypeName(((PointerType)type).ParameterType) + "*"; + else + mangledName = GetMangledTypeName(((PointerType)type).ParameterType) + "__Pointer"; break; + default: - // TODO: Include encapsulating type - mangledName = SanitizeName(type.Name); + mangledName = type.Name; + + // Include encapsulating type + TypeDesc def = type.GetTypeDefinition(); + TypeDesc containingType = (def is EcmaType) ? ((EcmaType)def).ContainingType : null; + while (containingType != null) + { + mangledName = containingType.Name + "__" + mangledName; + + containingType = ((EcmaType)containingType).ContainingType; + } + + mangledName = SanitizeName(mangledName); - mangledName = mangledName.Replace(".", "_"); + mangledName = mangledName.Replace(".", _options.Cpp ? "::" : "_"); - if (type.HasInstantiation || _deduplicator.Contains(mangledName)) + // TODO: the special handling for "Interop" is needed due to type name / namespace name clashes; + // find a better solution + if (type.HasInstantiation || _deduplicator.Contains(mangledName) || mangledName == "Interop") mangledName = mangledName + "_" + _unique++; _deduplicator.Add(mangledName); @@ -364,15 +435,16 @@ internal string GetMangledMethodName(MethodDesc method) if (mangledName != null) return mangledName; - RegisteredType owner = GetRegisteredType(method.OwningType); + RegisteredType regType = GetRegisteredType(method.OwningType); mangledName = SanitizeName(method.Name); mangledName = mangledName.Replace(".", "_"); // To handle names like .ctor - mangledName = GetMangledTypeName(method.OwningType) + "__" + mangledName; + if (!_options.Cpp) + mangledName = GetMangledTypeName(method.OwningType) + "__" + mangledName; - RegisteredMethod rm = owner.Methods; + RegisteredMethod rm = regType.Methods; bool dedup = false; while (rm != null) { @@ -385,9 +457,13 @@ internal string GetMangledMethodName(MethodDesc method) rm = rm.Next; } if (dedup) - mangledName = mangledName + "_" + owner.UniqueMethod++; + mangledName = mangledName + "_" + regType.UniqueMethod++; reg.MangledName = mangledName; + + reg.Next = regType.Methods; + regType.Methods = reg; + return mangledName; } diff --git a/src/ILToNative/src/Compiler/MethodExtensions.cs b/src/ILToNative/src/Compiler/MethodExtensions.cs new file mode 100644 index 00000000000..fe70dadfb88 --- /dev/null +++ b/src/ILToNative/src/Compiler/MethodExtensions.cs @@ -0,0 +1,56 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +using Internal.TypeSystem; +using Internal.TypeSystem.Ecma; + +namespace ILToNative +{ + static class MethodExtensions + { + const string RuntimeImportAttributeName = "System.Runtime.RuntimeImportAttribute"; + + public static bool IsRuntimeImport(this EcmaMethod This) + { + return This.HasCustomAttribute(RuntimeImportAttributeName); + } + + public static string GetRuntimeImportEntryPointName(this EcmaMethod This) + { + var metadataReader = This.MetadataReader; + foreach (var attributeHandle in metadataReader.GetMethodDefinition(This.Handle).GetCustomAttributes()) + { + var customAttribute = metadataReader.GetCustomAttribute(attributeHandle); + var constructorHandle = customAttribute.Constructor; + + var constructor = This.Module.GetMethod(constructorHandle); + var type = constructor.OwningType; + + if (type.Name == RuntimeImportAttributeName) + { + if (constructor.Signature.Length != 1 && constructor.Signature.Length != 2) + throw new BadImageFormatException(); + + for (int i = 0; i < constructor.Signature.Length; i++) + if (constructor.Signature[i] != This.Context.GetWellKnownType(WellKnownType.String)) + throw new BadImageFormatException(); + + var attributeBlob = metadataReader.GetBlobReader(customAttribute.Value); + if (attributeBlob.ReadInt16() != 1) + throw new BadImageFormatException(); + + // Skip module name if present + if (constructor.Signature.Length == 2) + attributeBlob.ReadSerializedString(); + + return attributeBlob.ReadSerializedString(); + } + } + + return null; + } + + } +} diff --git a/src/ILToNative/src/Compiler/Program.cs b/src/ILToNative/src/Compiler/Program.cs index ee63bf68dc9..205522e7814 100644 --- a/src/ILToNative/src/Compiler/Program.cs +++ b/src/ILToNative/src/Compiler/Program.cs @@ -23,6 +23,8 @@ class Program Dictionary _inputFilePaths = new Dictionary(StringComparer.OrdinalIgnoreCase); Dictionary _referenceFilePaths = new Dictionary(StringComparer.OrdinalIgnoreCase); + CompilationOptions _options; + CompilerTypeSystemContext _compilerTypeSystemContext; Program() @@ -67,6 +69,10 @@ void ParseCommandLine(string[] args) parser.AppendExpandedPaths(_referenceFilePaths, false); break; + case "cpp": + _options.Cpp = true; + break; + default: throw new CommandLineException("Unrecognized option: " + parser.GetCurrentOption()); } @@ -98,7 +104,7 @@ void SingleFileCompilation() int entryPointToken = entryPointModule.PEReader.PEHeaders.CorHeader.EntryPointTokenOrRelativeVirtualAddress; MethodDesc entryPointMethod = entryPointModule.GetMethod(MetadataTokens.EntityHandle(entryPointToken)); - Compilation compilation = new Compilation(_compilerTypeSystemContext); + Compilation compilation = new Compilation(_compilerTypeSystemContext, _options); compilation.Log = Console.Out; compilation.Out = new StreamWriter(File.Create(_outputPath)); @@ -136,6 +142,9 @@ int Run(string[] args) static int Main(string[] args) { +#if DEBUG + return new Program().Run(args); +#else try { return new Program().Run(args); @@ -145,6 +154,7 @@ static int Main(string[] args) Console.Error.WriteLine("Error: " + e.Message); return 1; } +#endif } } } diff --git a/src/ILToNative/src/Compiler/RegisteredMethod.cs b/src/ILToNative/src/Compiler/RegisteredMethod.cs index f5de81b4b24..41af6bc74ea 100644 --- a/src/ILToNative/src/Compiler/RegisteredMethod.cs +++ b/src/ILToNative/src/Compiler/RegisteredMethod.cs @@ -15,7 +15,7 @@ class RegisteredMethod public string MangledName; - public MethodCode MethodCode; + public Object MethodCode; public RegisteredMethod Next; } diff --git a/src/ILToNative/src/Compiler/RegisteredType.cs b/src/ILToNative/src/Compiler/RegisteredType.cs index 8acc4e577f2..8d121e9851a 100644 --- a/src/ILToNative/src/Compiler/RegisteredType.cs +++ b/src/ILToNative/src/Compiler/RegisteredType.cs @@ -18,6 +18,7 @@ class RegisteredType public int UniqueMethod; public string MangledName; + public string MangledSignatureName; // CppCodeGen specific public RegisteredMethod Methods; diff --git a/src/ILToNative/src/CppCodeGen/ILToCppImporter.cs b/src/ILToNative/src/CppCodeGen/ILToCppImporter.cs index d5a75260077..8ea842939c6 100644 --- a/src/ILToNative/src/CppCodeGen/ILToCppImporter.cs +++ b/src/ILToNative/src/CppCodeGen/ILToCppImporter.cs @@ -628,11 +628,11 @@ void ImportIntrinsicCall(IntrinsicMethodKind intrinsicClassification) var arraySlot = Pop(); var fieldDesc = (TypeSystem.Ecma.EcmaField)fieldSlot.Value.Aux; - int addr = fieldDesc.FieldDefinition.GetRelativeVirtualAddress(); + int addr = fieldDesc.MetadataReader.GetFieldDefinition(fieldDesc.Handle).GetRelativeVirtualAddress(); var memBlock = fieldDesc.Module.PEReader.GetSectionData(addr).GetContent(); var fieldType = (TypeSystem.Ecma.EcmaType)fieldDesc.FieldType; - int size = fieldType.TypeDefinition.GetLayout().Size; + int size = fieldType.MetadataReader.GetTypeDefinition(fieldType.Handle).GetLayout().Size; if (size == 0) throw new NotImplementedException(); diff --git a/src/ILToNative/src/ILToNative.csproj b/src/ILToNative/src/ILToNative.csproj index 387279863e8..3d7b29c7ad9 100644 --- a/src/ILToNative/src/ILToNative.csproj +++ b/src/ILToNative/src/ILToNative.csproj @@ -39,11 +39,14 @@ + + + @@ -163,6 +166,9 @@ IL\MethodIL.cs + + IL\ILImporter.cs + IL\Stubs\ArrayMethodILEmitter.cs @@ -187,6 +193,9 @@ JitInterface\CorInfoTypes.cs + + + diff --git a/src/TypeSystem/src/IL/ILProvider.cs b/src/TypeSystem/src/IL/ILProvider.cs index daa3bc82c4b..a6ca9ff1c87 100644 --- a/src/TypeSystem/src/IL/ILProvider.cs +++ b/src/TypeSystem/src/IL/ILProvider.cs @@ -29,7 +29,10 @@ public MethodIL GetMethodIL(MethodDesc method) else if (method is MethodForInstantiatedType) { - return new InstantiatedMethodIL(GetMethodIL(method.GetTypicalMethodDefinition()), method.OwningType.Instantiation, new Instantiation()); + var methodDefinitionIL = GetMethodIL(method.GetTypicalMethodDefinition()); + if (methodDefinitionIL == null) + return null; + return new InstantiatedMethodIL(methodDefinitionIL, method.OwningType.Instantiation, new Instantiation()); } else if (method is InstantiatedMethod) diff --git a/src/TypeSystem/src/IL/Stubs/DelegateThunks.cs b/src/TypeSystem/src/IL/Stubs/DelegateThunks.cs index a0e682409ba..e2c8f2523fa 100644 --- a/src/TypeSystem/src/IL/Stubs/DelegateThunks.cs +++ b/src/TypeSystem/src/IL/Stubs/DelegateThunks.cs @@ -57,10 +57,12 @@ public override MethodIL EmitIL() ILEmitter emitter = new ILEmitter(); var codeStream = emitter.NewCodeStream(); - for (int i = 0; i < _signature.Length; i++) + + for (int i = 0; i < Signature.Length; i++) { codeStream.EmitLdArg(i + 1); } + codeStream.Emit(ILOpcode.call, emitter.NewToken(_target)); codeStream.Emit(ILOpcode.ret);