diff --git a/src/ILToNative/reproNative/main.cpp b/src/ILToNative/reproNative/main.cpp index b7c2750f6f5..c1567c9ea1c 100644 --- a/src/ILToNative/reproNative/main.cpp +++ b/src/ILToNative/reproNative/main.cpp @@ -88,28 +88,38 @@ void __register_module(SimpleModuleHeader* pModule) #endif // USE_MRT } -namespace System { class Object { -public: - EEType * get_EEType() { return *(EEType **)this; } -}; }; +namespace mscorlib { namespace System { + + class Object { + public: + EEType * get_EEType() { return *(EEType **)this; } + }; + + class Array : public Object { + public: + int32_t GetArrayLength() { + return *(int32_t *)((void **)this + 1); + } + void * GetArrayData() { + return (void **)this + 2; + } + }; + + class String : public Object { public: + static MethodTable * __getMethodTable(); + }; + + class String__Array : public Object { public: + static MethodTable * __getMethodTable(); + }; + + class EETypePtr { public: + intptr_t m_value; + }; -namespace System { class Array : public System::Object { -public: - int32_t GetArrayLength() { - return *(int32_t *)((void **)this + 1); - } - void * GetArrayData() { - return (void **)this + 2; - } }; }; -namespace System { class String : public System::Object { public: -static MethodTable * __getMethodTable(); -}; }; - -namespace System { class EETypePtr { public: - intptr_t m_value; -}; } +using namespace mscorlib; // // The fast paths for object allocation and write barriers is performance critical. They are often @@ -147,6 +157,8 @@ extern "C" Object * __allocate_object(MethodTable * pMT) Object * __allocate_string(int32_t len) { +#ifdef CPPCODEGEN + #if !USE_MRT alloc_context * acontext = GetThread()->GetAllocContext(); Object * pObject; @@ -178,6 +190,10 @@ Object * __allocate_string(int32_t len) #else return RhNewArray(System::String::__getMethodTable(), len); #endif + +#else + throw 42; +#endif } extern "C" Object * __allocate_array(MethodTable * pMT, size_t elements) @@ -291,11 +307,7 @@ void __range_check(void * a, size_t elem) ThrowRangeOverflowException(); } -namespace System { class String__Array : public System::Object { public: -static MethodTable * __getMethodTable(); -}; }; - - +#ifdef CPPCODEGEN Object * __get_commandline_args(int argc, char * argv[]) { System::Array * p = (System::Array *)__allocate_array(System::String__Array::__getMethodTable(), argc); @@ -308,6 +320,7 @@ Object * __get_commandline_args(int argc, char * argv[]) return (Object *)p; } +#endif // FCalls @@ -523,17 +536,17 @@ extern "C" intptr_t RhGetModuleFromEEType(System::EETypePtr) throw 42; } -#if 0 +#ifndef CPPCODEGEN SimpleModuleHeader __module = { NULL, NULL /* &__gcStatics, &__gcStaticsDescs */ }; -extern "C" int Program__Main(); +extern "C" int repro_Program__Main(); int main(int argc, char * argv[]) { if (__initialize_runtime() != 0) return -1; __register_module(&__module); ReversePInvokeFrame frame; __reverse_pinvoke(&frame); - Program::Main((System::String__Array*)__get_commandline_args(argc - 1, argv + 1)); + repro_Program__Main(); __reverse_pinvoke_return(&frame); __shutdown_runtime(); diff --git a/src/ILToNative/reproNative/reproNativeCpp.vcxproj b/src/ILToNative/reproNative/reproNativeCpp.vcxproj index eb037a78fd9..537b8ccec2a 100644 --- a/src/ILToNative/reproNative/reproNativeCpp.vcxproj +++ b/src/ILToNative/reproNative/reproNativeCpp.vcxproj @@ -53,7 +53,7 @@ Use Level3 Disabled - WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) + CPPCODEGEN;WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) true common.h ..\..\Native\gc;..\..\Native\gc\env @@ -71,7 +71,7 @@ MaxSpeed true true - WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) + CPPCODEGEN;WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) true common.h ..\gc;..\..\Native\gc\env diff --git a/src/ILToNative/reproNative/stubs.cpp b/src/ILToNative/reproNative/stubs.cpp index 2c1f8caa835..8a405d74468 100644 --- a/src/ILToNative/reproNative/stubs.cpp +++ b/src/ILToNative/reproNative/stubs.cpp @@ -1,6 +1,8 @@ // Copyright (c) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. +using namespace mscorlib; + // // BoundsChecking // diff --git a/src/ILToNative/src/Compiler/AsmWriter.cs b/src/ILToNative/src/Compiler/AsmWriter.cs index 7205837de24..a00f01f9cdd 100644 --- a/src/ILToNative/src/Compiler/AsmWriter.cs +++ b/src/ILToNative/src/Compiler/AsmWriter.cs @@ -16,12 +16,13 @@ void OutputCode() foreach (var t in _registeredTypes.Values) { - RegisteredMethod m = t.Methods; - while (m != null) + if (t.Methods != null) { - if (m.MethodCode != null) - OutputMethodCode(m); - m = m.Next; + foreach (var m in t.Methods) + { + if (m.MethodCode != null) + OutputMethodCode(m); + } } } diff --git a/src/ILToNative/src/Compiler/Compilation.cs b/src/ILToNative/src/Compiler/Compilation.cs index e74a8dad24c..98747715c05 100644 --- a/src/ILToNative/src/Compiler/Compilation.cs +++ b/src/ILToNative/src/Compiler/Compilation.cs @@ -290,20 +290,23 @@ public void AddMethod(MethodDesc method) return; reg.IncludedInCompilation = true; + RegisteredType regType = GetRegisteredType(method.OwningType); + if (regType.Methods == null) + regType.Methods = new List(); + regType.Methods.Add(reg); + if (_methodsThatNeedsCompilation == null) _methodsThatNeedsCompilation = new List(); _methodsThatNeedsCompilation.Add(method); - NameMangler.GetMangledMethodName(method); - if (_options.IsCppCodeGen) { // Precreate name to ensure that all types referenced by signatures are present - NameMangler.GetMangledTypeName(method.OwningType); + GetRegisteredType(method.OwningType); var signature = method.Signature; - NameMangler.GetMangledTypeName(signature.ReturnType); + GetRegisteredType(signature.ReturnType); for (int i = 0; i < signature.Length; i++) - NameMangler.GetMangledTypeName(signature[i]); + GetRegisteredType(signature[i]); } } @@ -352,8 +355,8 @@ public void AddField(FieldDesc field) if (_options.IsCppCodeGen) { // Precreate name to ensure that all types referenced by signatures are present - NameMangler.GetMangledTypeName(field.OwningType); - NameMangler.GetMangledTypeName(field.FieldType); + GetRegisteredType(field.OwningType); + GetRegisteredType(field.FieldType); } } diff --git a/src/ILToNative/src/Compiler/NameMangler.cs b/src/ILToNative/src/Compiler/NameMangler.cs index 03e5aa4d2aa..e7e36094371 100644 --- a/src/ILToNative/src/Compiler/NameMangler.cs +++ b/src/ILToNative/src/Compiler/NameMangler.cs @@ -2,7 +2,11 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; +using System.Diagnostics; +using System.Globalization; using System.Collections.Generic; +using System.Collections.Immutable; +using System.Text; using Internal.TypeSystem; using Internal.TypeSystem.Ecma; @@ -10,7 +14,9 @@ namespace ILToNative { // - // NameMangler is reponsible for giving extern C/C++ names to types, methods and fields + // NameMangler is reponsible for giving extern C/C++ names to managed types, methods and fields + // + // The key invariant is that the mangled names are independent on the compilation order. // public class NameMangler { @@ -21,28 +27,119 @@ public NameMangler(Compilation compilation) _compilation = compilation; } - // Turn a name into a valid identifier - private static string SanitizeName(string s) + // + // Turn a name into a valid C/C++ identifier + // + private string SanitizeName(string s, bool typeName = false) { - // TODO: Handle Unicode, etc. - s = s.Replace("`", "_"); - s = s.Replace("<", "_"); - s = s.Replace(">", "_"); - s = s.Replace("$", "_"); - return s; + StringBuilder sb = null; + for (int i = 0; i < s.Length; i++) + { + char c = s[i]; + + if (((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z'))) + { + if (sb != null) + sb.Append(c); + continue; + } + + if ((c >= '0') && (c <= '9')) + { + // C identifiers cannot start with a digit. Prepend underscores. + if (i == 0) + { + if (sb == null) + sb = new StringBuilder(s.Length + 2); + sb.Append("_"); + } + if (sb != null) + sb.Append(c); + continue; + } + + if (sb == null) + sb = new StringBuilder(s, 0, i, s.Length); + + // For CppCodeGen, replace "." (C# namespace separator) with "::" (C++ namespace separator) + if (typeName && c == '.' && _compilation.IsCppCodeGen) + { + sb.Append("::"); + continue; + } + + // Everything else is replaced by underscore. + // TODO: We assume that there won't be collisions with our own or C++ built-in identifiers. + sb.Append("_"); + } + return (sb != null) ? sb.ToString() : s; } - int _unique = 1; - HashSet _deduplicator = new HashSet(); + ImmutableDictionary _mangledTypeNames = ImmutableDictionary.Empty; - internal string GetMangledTypeName(TypeDesc type) + public string GetMangledTypeName(TypeDesc type) { - var reg = _compilation.GetRegisteredType(type); - - string mangledName = reg.MangledName; - if (mangledName != null) + string mangledName; + if (_mangledTypeNames.TryGetValue(type, out mangledName)) return mangledName; + return ComputeMangledTypeName(type); + } + + private string ComputeMangledTypeName(TypeDesc type) + { + if (type is EcmaType) + { + string prependAssemblyName = SanitizeName(((EcmaType)type).Module.GetName().Name); + + var deduplicator = new HashSet(); + + // Add consistent names for all types in the module, independent on the order in which + // they are compiled + lock (this) + { + foreach (var t in ((EcmaType)type).Module.GetAllTypes()) + { + string name = t.Name; + + // Include encapsulating type + TypeDesc containingType = ((EcmaType)t).ContainingType; + while (containingType != null) + { + name = containingType.Name + "_" + name; + containingType = ((EcmaType)containingType).ContainingType; + } + + name = SanitizeName(name, true); + + if (deduplicator.Contains(name)) + { + string nameWithIndex; + for (int index = 1; ; index++) + { + nameWithIndex = name + "_" + index.ToString(CultureInfo.InvariantCulture); + if (!deduplicator.Contains(nameWithIndex)) + break; + } + name = nameWithIndex; + } + deduplicator.Add(name); + + if (_compilation.IsCppCodeGen) + name = prependAssemblyName + "::" + name; + else + name = prependAssemblyName + "_" + name; + + _mangledTypeNames = _mangledTypeNames.Add(t, name); + } + } + + return _mangledTypeNames[type]; + } + + + string mangledName; + switch (type.Category) { case TypeFlags.Array: @@ -57,73 +154,118 @@ internal string GetMangledTypeName(TypeDesc type) case TypeFlags.Pointer: mangledName = GetMangledTypeName(((PointerType)type).ParameterType) + "__Pointer"; break; - default: - mangledName = type.Name; - - // Include encapsulating type - TypeDesc def = type.GetTypeDefinition(); - TypeDesc containingType = (def is EcmaType) ? ((EcmaType)def).ContainingType : null; - while (containingType != null) + var typeDefinition = type.GetTypeDefinition(); + if (typeDefinition != type) { - mangledName = containingType.Name + "__" + mangledName; + mangledName = GetMangledTypeName(typeDefinition); - containingType = ((EcmaType)containingType).ContainingType; + var inst = type.Instantiation; + for (int i = 0; i < inst.Length; i++) + { + string instArgName = GetMangledTypeName(inst[i]); + if (_compilation.IsCppCodeGen) + instArgName = instArgName.Replace("::", "_"); + mangledName += "__" + instArgName; + } + } + else + { + mangledName = type.Name; } + break; + } - mangledName = SanitizeName(mangledName); + lock (this) + { + _mangledTypeNames = _mangledTypeNames.Add(type, mangledName); + } - mangledName = mangledName.Replace(".", _compilation.IsCppCodeGen ? "::" : "_"); + return 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); + ImmutableDictionary _mangledMethodNames = ImmutableDictionary.Empty; - break; - } + public string GetMangledMethodName(MethodDesc method) + { + string mangledName; + if (_mangledMethodNames.TryGetValue(method, out mangledName)) + return mangledName; - reg.MangledName = mangledName; - return mangledName; + return ComputeMangledMethodName(method); } - internal string GetMangledMethodName(MethodDesc method) + private string ComputeMangledMethodName(MethodDesc method) { - var reg = _compilation.GetRegisteredMethod(method); + string prependTypeName = null; + if (!_compilation.IsCppCodeGen) + prependTypeName = GetMangledTypeName(method.OwningType); - string mangledName = reg.MangledName; - if (mangledName != null) - return mangledName; + if (method is EcmaMethod) + { + var deduplicator = new HashSet(); - RegisteredType regType = _compilation.GetRegisteredType(method.OwningType); + // Add consistent names for all methods of the type, independent on the order in which + // they are compiled + lock (this) + { + foreach (var m in method.OwningType.GetMethods()) + { + string name = SanitizeName(m.Name); - mangledName = SanitizeName(method.Name); + if (deduplicator.Contains(name)) + { + string nameWithIndex; + for (int index = 1; ; index++) + { + nameWithIndex = name + "_" + index.ToString(CultureInfo.InvariantCulture); + if (!deduplicator.Contains(nameWithIndex)) + break; + } + name = nameWithIndex; + } + deduplicator.Add(name); - mangledName = mangledName.Replace(".", "_"); // To handle names like .ctor + if (prependTypeName != null) + name = prependTypeName + "__" + name; + + _mangledMethodNames = _mangledMethodNames.Add(m, name); + } + } + + return _mangledMethodNames[method]; + } - if (!_compilation.IsCppCodeGen) - mangledName = GetMangledTypeName(method.OwningType) + "__" + mangledName; - RegisteredMethod rm = regType.Methods; - bool dedup = false; - while (rm != null) + string mangledName; + + var methodDefinition = method.GetTypicalMethodDefinition(); + if (methodDefinition != method) { - if (rm.MangledName != null && rm.MangledName == mangledName) + mangledName = GetMangledMethodName(methodDefinition.GetMethodDefinition()); + + var inst = method.Instantiation; + for (int i = 0; i < inst.Length; i++) { - dedup = true; - break; + string instArgName = GetMangledTypeName(inst[i]); + if (_compilation.IsCppCodeGen) + instArgName = instArgName.Replace("::", "_"); + mangledName += "__" + instArgName; } - - rm = rm.Next; } - if (dedup) - mangledName = mangledName + "_" + regType.UniqueMethod++; + else + { + // Assume that Name is unique for all other methods + mangledName = method.Name; + } - reg.MangledName = mangledName; + if (prependTypeName != null) + mangledName = prependTypeName + "__" + mangledName; - reg.Next = regType.Methods; - regType.Methods = reg; + lock (this) + { + _mangledMethodNames = _mangledMethodNames.Add(method, mangledName); + } return mangledName; } diff --git a/src/ILToNative/src/Compiler/RegisteredMethod.cs b/src/ILToNative/src/Compiler/RegisteredMethod.cs index 41af6bc74ea..cd722d12aa6 100644 --- a/src/ILToNative/src/Compiler/RegisteredMethod.cs +++ b/src/ILToNative/src/Compiler/RegisteredMethod.cs @@ -13,10 +13,6 @@ class RegisteredMethod public bool IncludedInCompilation; - public string MangledName; - public Object MethodCode; - - public RegisteredMethod Next; } } diff --git a/src/ILToNative/src/Compiler/RegisteredType.cs b/src/ILToNative/src/Compiler/RegisteredType.cs index 8d121e9851a..13b590b92c5 100644 --- a/src/ILToNative/src/Compiler/RegisteredType.cs +++ b/src/ILToNative/src/Compiler/RegisteredType.cs @@ -15,12 +15,9 @@ class RegisteredType public bool IncludedInCompilation; public bool Constructed; - public int UniqueMethod; - - public string MangledName; public string MangledSignatureName; // CppCodeGen specific - public RegisteredMethod Methods; + public List Methods; public List VirtualSlots; } diff --git a/src/ILToNative/src/CppCodeGen/CppWriter.cs b/src/ILToNative/src/CppCodeGen/CppWriter.cs index 9d1bbe2bb8a..6ae5f65b595 100644 --- a/src/ILToNative/src/CppCodeGen/CppWriter.cs +++ b/src/ILToNative/src/CppCodeGen/CppWriter.cs @@ -613,12 +613,13 @@ void OutputType(RegisteredType t, bool full) _statics.AppendLine("bool __cctor_" + GetCppTypeName(t.Type).Replace("::", "__") + ";"); } - RegisteredMethod m = t.Methods; - while (m != null) + if (t.Methods != null) { - if (m.IncludedInCompilation) - OutputMethod(m); - m = m.Next; + foreach (var m in t.Methods) + { + if (m.IncludedInCompilation) + OutputMethod(m); + } } Out.Write("};"); } @@ -860,12 +861,14 @@ public void OutputCode() { Out.WriteLine(GetCodeForType(t.Type)); } - RegisteredMethod m = t.Methods; - while (m != null) + + if (t.Methods != null) { - if (m.MethodCode != null) - Out.WriteLine(m.MethodCode); - m = m.Next; + foreach (var m in t.Methods) + { + if (m.MethodCode != null) + Out.WriteLine(m.MethodCode); + } } } diff --git a/src/ILToNative/src/CppCodeGen/ILToCppImporter.cs b/src/ILToNative/src/CppCodeGen/ILToCppImporter.cs index 8ea842939c6..e9b433d476f 100644 --- a/src/ILToNative/src/CppCodeGen/ILToCppImporter.cs +++ b/src/ILToNative/src/CppCodeGen/ILToCppImporter.cs @@ -824,7 +824,7 @@ void ImportCall(ILOpcode opcode, int token) if (delegateInvoke) { _stack[_stackTop - (methodSignature.Length + 1)].Value.Name = - "((System::Delegate *)" + + "((" + _writer.GetCppSignatureTypeName(GetWellKnownType(WellKnownType.MulticastDelegate)) + ")" + _stack[_stackTop - (methodSignature.Length + 1)].Value.Name + ")->m_firstParameter"; } } diff --git a/src/TypeSystem/src/Common/InstantiatedMethod.cs b/src/TypeSystem/src/Common/InstantiatedMethod.cs index 03d1940d5b8..d96f3fb9bd7 100644 --- a/src/TypeSystem/src/Common/InstantiatedMethod.cs +++ b/src/TypeSystem/src/Common/InstantiatedMethod.cs @@ -3,6 +3,7 @@ using System; using System.Diagnostics; +using System.Text; namespace Internal.TypeSystem { @@ -91,8 +92,12 @@ public override string Name public override string ToString() { - // TODO: Append instantiation - return _methodDef.ToString(); + var sb = new StringBuilder(_methodDef.ToString()); + sb.Append('<'); + for (int i = 0; i < _instantiation.Length; i++) + sb.Append(_instantiation[i].ToString()); + sb.Append('>'); + return sb.ToString(); } } } diff --git a/src/TypeSystem/src/Common/InstantiatedType.cs b/src/TypeSystem/src/Common/InstantiatedType.cs index 557cb95e0ce..6a5eb88460e 100644 --- a/src/TypeSystem/src/Common/InstantiatedType.cs +++ b/src/TypeSystem/src/Common/InstantiatedType.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; +using System.Text; using System.Collections.Generic; using System.Diagnostics; @@ -203,5 +204,15 @@ public override TypeDesc GetTypeDefinition() { return _typeDef; } + + public override string ToString() + { + var sb = new StringBuilder(_typeDef.ToString()); + sb.Append('<'); + for (int i = 0; i < _instantiation.Length; i++) + sb.Append(_instantiation[i].ToString()); + sb.Append('>'); + return sb.ToString(); + } } }