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);