From 0b799135b5085aef81da59f435acccf3ec971f9d Mon Sep 17 00:00:00 2001 From: dotnet-bot Date: Tue, 29 Sep 2015 21:11:34 -0700 Subject: [PATCH] Add ILToNative source files All files have been copied from TFS at changeset 1531496. --- src/ILToNative/src/Compiler/AsmWriter.cs | 258 +++++ src/ILToNative/src/Compiler/Compilation.cs | 437 +++++++++ .../src/Compiler/CompilerTypeSystemContext.cs | 141 +++ src/ILToNative/src/Compiler/MemoryHelper.cs | 20 + src/ILToNative/src/Compiler/MethodCode.cs | 29 + src/ILToNative/src/Compiler/Program.cs | 152 +++ .../src/Compiler/ReadyToRunHelper.cs | 51 + .../src/Compiler/RegisteredField.cs | 16 + .../src/Compiler/RegisteredMethod.cs | 22 + src/ILToNative/src/Compiler/RegisteredType.cs | 26 + src/TypeSystem/src/IL/EcmaMethodIL.cs | 113 +++ src/TypeSystem/src/IL/ILImporter.cs | 916 ++++++++++++++++++ src/TypeSystem/src/IL/ILOpcode.cs | 234 +++++ src/TypeSystem/src/IL/ILProvider.cs | 55 ++ src/TypeSystem/src/IL/InstantiatedMethodIL.cs | 92 ++ src/TypeSystem/src/IL/MethodIL.cs | 97 ++ .../src/IL/Stubs/ArrayMethodILEmitter.cs | 164 ++++ src/TypeSystem/src/IL/Stubs/DelegateThunks.cs | 86 ++ src/TypeSystem/src/IL/Stubs/ILEmitter.cs | 224 +++++ 19 files changed, 3133 insertions(+) create mode 100644 src/ILToNative/src/Compiler/AsmWriter.cs create mode 100644 src/ILToNative/src/Compiler/Compilation.cs create mode 100644 src/ILToNative/src/Compiler/CompilerTypeSystemContext.cs create mode 100644 src/ILToNative/src/Compiler/MemoryHelper.cs create mode 100644 src/ILToNative/src/Compiler/MethodCode.cs create mode 100644 src/ILToNative/src/Compiler/Program.cs create mode 100644 src/ILToNative/src/Compiler/ReadyToRunHelper.cs create mode 100644 src/ILToNative/src/Compiler/RegisteredField.cs create mode 100644 src/ILToNative/src/Compiler/RegisteredMethod.cs create mode 100644 src/ILToNative/src/Compiler/RegisteredType.cs create mode 100644 src/TypeSystem/src/IL/EcmaMethodIL.cs create mode 100644 src/TypeSystem/src/IL/ILImporter.cs create mode 100644 src/TypeSystem/src/IL/ILOpcode.cs create mode 100644 src/TypeSystem/src/IL/ILProvider.cs create mode 100644 src/TypeSystem/src/IL/InstantiatedMethodIL.cs create mode 100644 src/TypeSystem/src/IL/MethodIL.cs create mode 100644 src/TypeSystem/src/IL/Stubs/ArrayMethodILEmitter.cs create mode 100644 src/TypeSystem/src/IL/Stubs/DelegateThunks.cs create mode 100644 src/TypeSystem/src/IL/Stubs/ILEmitter.cs diff --git a/src/ILToNative/src/Compiler/AsmWriter.cs b/src/ILToNative/src/Compiler/AsmWriter.cs new file mode 100644 index 00000000000..7c61891926f --- /dev/null +++ b/src/ILToNative/src/Compiler/AsmWriter.cs @@ -0,0 +1,258 @@ +// 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 System.Diagnostics; + +using Internal.TypeSystem; + +namespace ILToNative +{ + public partial class Compilation + { + void OutputCode() + { + Out.WriteLine(".text"); + + foreach (var t in _registeredTypes.Values) + { + RegisteredMethod m = t.Methods; + while (m != null) + { + if (m.MethodCode != null) + OutputMethodCode(m); + m = m.Next; + } + } + + Out.WriteLine("//" + new string('-', 80)); + Out.WriteLine(); + + OutputReadyToHelpers(); + + OutputEETypes(); + + Out.Dispose(); + } + + void OutputMethodCode(RegisteredMethod m) + { + string mangledName = GetMangledMethodName(m.Method); + + Out.Write(".global "); + Out.WriteLine(mangledName); + + Out.Write(mangledName); + Out.WriteLine(":"); + + var methodCode = m.MethodCode; + + Relocation[] relocs = methodCode.Relocs; + int currentRelocIndex = 0; + int nextRelocOffset = -1; + + byte[] code = methodCode.Code; + + if (relocs != null) + { + nextRelocOffset = relocs[currentRelocIndex].Offset; + if (relocs[currentRelocIndex].RelocType == 0x10) // IMAGE_REL_BASED_REL32 + nextRelocOffset--; + } + + int lineLength = 0; + for (int i = 0; i < code.Length; i++) + { + if (i == nextRelocOffset) + { + if (lineLength > 0) + { + Out.WriteLine(); + lineLength = 0; + } + + Relocation reloc = relocs[currentRelocIndex]; + + Object target = reloc.Target; + string targetName; + if (target is MethodDesc) + { + targetName = GetMangledMethodName((MethodDesc)target); + } + else + if (target is ReadyToRunHelper) + { + targetName = ((ReadyToRunHelper)target).MangledName; + } + else + { + // TODO: + throw new NotImplementedException(); + } + + switch (reloc.RelocType) + { + case 0x0A: // IMAGE_REL_BASED_DIR64 + Out.Write(".quad "); + Out.WriteLine(targetName); + i += 7; + break; + case 0x10: + if (code[i] != 0xE8) // call + throw new NotImplementedException(); + Out.Write("call "); + Out.WriteLine(targetName); + i += 4; + break; + default: + throw new NotImplementedException(); + } + + currentRelocIndex++; + nextRelocOffset = -1; + if (currentRelocIndex < relocs.Length) + { + nextRelocOffset = relocs[currentRelocIndex].Offset; + if (relocs[currentRelocIndex].RelocType == 0x10) // IMAGE_REL_BASED_REL32 + nextRelocOffset--; + } + + continue; + } + + if (lineLength == 0) + { + Out.Write(".byte "); + } + else + { + Out.Write(","); + } + + Out.Write(code[i]); + + if (lineLength++ > 15) + { + Out.WriteLine(); + lineLength = 0; + } + } + + // TODO: ColdCode + if (methodCode.ColdCode != null) + throw new NotImplementedException(); + + // TODO: ROData + if (methodCode.ROData != null) + throw new NotImplementedException(); + + if (lineLength > 0) + Out.WriteLine(); + Out.WriteLine(); + } + + void OutputReadyToHelpers() + { + foreach (var helper in _readyToRunHelpers.Values) + { + Out.Write(helper.MangledName); + Out.WriteLine(":"); + + switch (helper.Id) + { + case ReadyToRunHelperId.NewHelper: + Out.Write("leaq __EEType_"); + Out.Write(GetMangledTypeName((TypeDesc)helper.Target)); + Out.WriteLine("(%rip), %rcx"); + + Out.WriteLine("jmp __allocate_object"); + break; + + case ReadyToRunHelperId.VirtualCall: + Out.WriteLine("movq (%rcx), %rax"); + Out.Write("jmp *"); + + // TODO: More efficient lookup of the slot + { + MethodDesc method = (MethodDesc)helper.Target; + TypeDesc owningType = method.OwningType; + + int baseSlots = 0; + var baseType = owningType.BaseType; + + while (baseType != null) + { + var baseReg = GetRegisteredType(baseType); + if (baseReg.VirtualSlots != null) + baseSlots += baseReg.VirtualSlots.Count; + baseType = baseType.BaseType; + } + + var t = GetRegisteredType(owningType); + int methodSlot = -1; + for (int slot = 0; slot < t.VirtualSlots.Count; slot++) + { + if (t.VirtualSlots[slot] == method) + { + methodSlot = slot; + break; + } + } + + Debug.Assert(methodSlot != -1); + Out.Write(8 /* sizeof(EEType */ + (baseSlots + methodSlot) * _typeSystemContext.Target.PointerSize); + } + + Out.WriteLine("(%rax)"); + break; + + default: + throw new NotImplementedException(); + } + Out.WriteLine(); + } + } + + void OutputEETypes() + { + foreach (var t in _registeredTypes.Values) + { + if (!t.IncludedInCompilation) + continue; + + Out.WriteLine(".align 16"); + Out.Write("__EEType_"); + Out.Write(GetMangledTypeName(t.Type)); + Out.WriteLine(":"); + + Out.WriteLine(".int 0, 24"); + + if (t.Constructed) + OutputVirtualSlots(t.Type, t.Type); + + Out.WriteLine(); + } + } + + void OutputVirtualSlots(TypeDesc implType, TypeDesc declType) + { + var baseType = declType.BaseType; + if (baseType != null) + OutputVirtualSlots(implType, baseType); + + var reg = GetRegisteredType(declType); + if (reg.VirtualSlots != null) + { + for (int i = 0; i < reg.VirtualSlots.Count; i++) + { + MethodDesc declMethod = reg.VirtualSlots[i]; + + MethodDesc implMethod = ResolveVirtualMethod(implType, declMethod); + + Out.Write(".quad "); + Out.WriteLine(GetMangledMethodName(implMethod)); + } + } + } + } +} \ No newline at end of file diff --git a/src/ILToNative/src/Compiler/Compilation.cs b/src/ILToNative/src/Compiler/Compilation.cs new file mode 100644 index 00000000000..34ec7ced62d --- /dev/null +++ b/src/ILToNative/src/Compiler/Compilation.cs @@ -0,0 +1,437 @@ +// 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 System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Text; + +using Internal.TypeSystem; +using Internal.TypeSystem.Ecma; + +using Internal.IL; + +using Internal.JitInterface; + +namespace ILToNative +{ + public partial class Compilation + { + TypeSystemContext _typeSystemContext; + + Dictionary _registeredTypes = new Dictionary(); + Dictionary _registeredMethods = new Dictionary(); + Dictionary _registeredFields = new Dictionary(); + List _methodsThatNeedsCompilation = null; + + public Compilation(TypeSystemContext typeSystemContext) + { + _typeSystemContext = typeSystemContext; + } + + public TextWriter Log + { + get; + set; + } + + public TextWriter Out + { + get; + set; + } + + MethodDesc _mainMethod; + + + RegisteredType GetRegisteredType(TypeDesc type) + { + RegisteredType existingRegistration; + if (_registeredTypes.TryGetValue(type, out existingRegistration)) + return existingRegistration; + + RegisteredType registration = new RegisteredType() { Type = type }; + _registeredTypes.Add(type, registration); + + // Register all base types too + var baseType = type.BaseType; + if (baseType != null) + GetRegisteredType(baseType); + + return registration; + } + + RegisteredMethod GetRegisteredMethod(MethodDesc method) + { + RegisteredMethod existingRegistration; + if (_registeredMethods.TryGetValue(method, out existingRegistration)) + return existingRegistration; + + RegisteredMethod registration = new RegisteredMethod() { Method = method }; + _registeredMethods.Add(method, registration); + + GetRegisteredType(method.OwningType); + + return registration; + } + + RegisteredField GetRegisteredField(FieldDesc field) + { + RegisteredField existingRegistration; + if (_registeredFields.TryGetValue(field, out existingRegistration)) + return existingRegistration; + + RegisteredField registration = new RegisteredField() { Field = field }; + _registeredFields.Add(field, registration); + + GetRegisteredType(field.OwningType); + + return registration; + } + + enum SpecialMethodKind + { + Unknown, + PInvoke, + RuntimeImport, + Intrinsic, + BoundsChecking, + }; + + SpecialMethodKind DetectSpecialMethodKind(MethodDesc method) + { + if (method is EcmaMethod) + { + if (((EcmaMethod)method).IsPInvoke()) + { + return SpecialMethodKind.PInvoke; + } + else if (((EcmaMethod)method).HasCustomAttribute("System.Runtime.RuntimeImportAttribute")) + { + Log.WriteLine("RuntimeImport: " + method.ToString()); + return SpecialMethodKind.RuntimeImport; + } + else if (((EcmaMethod)method).HasCustomAttribute("System.Runtime.CompilerServices.IntrinsicAttribute")) + { + 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()); + // TODO: add reverse pinvoke callout + throw new NotImplementedException(); + } + } + return SpecialMethodKind.Unknown; + } + + ILProvider _ilProvider = new ILProvider(); + + public MethodIL GetMethodIL(MethodDesc method) + { + return _ilProvider.GetMethodIL(method); + } + + void CompileMethod(MethodDesc method) + { + string methodName = method.ToString(); + Log.WriteLine("Compiling " + methodName); + + SpecialMethodKind kind = DetectSpecialMethodKind(method); + + if (kind == SpecialMethodKind.Unknown || kind == SpecialMethodKind.Intrinsic) + { + var methodIL = _ilProvider.GetMethodIL(method); + if (methodIL == null) + return; + + var methodCode = _corInfo.CompileMethod(method); + + GetRegisteredMethod(method).MethodCode = methodCode; + } + } + + void CompileMethods() + { + var pendingMethods = _methodsThatNeedsCompilation; + _methodsThatNeedsCompilation = null; + + foreach (MethodDesc method in pendingMethods) + { + try + { + CompileMethod(method); + } + catch (Exception e) + { + Log.WriteLine(e.Message + " (" + method + ")"); + + throw new NotImplementedException(); + } + } + } + + void ExpandVirtualMethods() + { + // Take a snapshot of _registeredTypes - new registered types can be added during the expansion + foreach (var reg in _registeredTypes.Values.ToArray()) + { + if (!reg.Constructed) + continue; + + TypeDesc declType = reg.Type; + while (declType != null) + { + var declReg = GetRegisteredType(declType); + if (declReg.VirtualSlots != null) + { + for (int i = 0; i < declReg.VirtualSlots.Count; i++) + { + MethodDesc declMethod = declReg.VirtualSlots[i]; + + AddMethod(ResolveVirtualMethod(reg.Type, declMethod)); + } + } + + declType = declType.BaseType; + } + } + } + + CorInfoImpl _corInfo; + + public void CompileSingleFile(MethodDesc mainMethod) + { + _corInfo = new CorInfoImpl(this); + + _mainMethod = mainMethod; + AddMethod(mainMethod); + + while (_methodsThatNeedsCompilation != null) + { + CompileMethods(); + + ExpandVirtualMethods(); + } + + OutputCode(); + } + + public void AddMethod(MethodDesc method) + { + RegisteredMethod reg = GetRegisteredMethod(method); + if (reg.IncludedInCompilation) + 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); + } + + public void AddVirtualSlot(MethodDesc method) + { + RegisteredType reg = GetRegisteredType(method.OwningType); + + if (reg.VirtualSlots == null) + reg.VirtualSlots = new List(); + + for (int i = 0; i < reg.VirtualSlots.Count; i++) + { + if (reg.VirtualSlots[i] == method) + return; + } + + reg.VirtualSlots.Add(method); + } + + public void MarkAsConstructed(TypeDesc type) + { + GetRegisteredType(type).Constructed = true; + } + + public void AddType(TypeDesc type) + { + RegisteredType reg = GetRegisteredType(type); + if (reg.IncludedInCompilation) + return; + reg.IncludedInCompilation = true; + + TypeDesc baseType = type.BaseType; + if (baseType != null) + AddType(baseType); + if (type.IsArray) + AddType(((ArrayType)type).ElementType); + } + + public void AddField(FieldDesc field) + { + RegisteredField reg = GetRegisteredField(field); + if (reg.IncludedInCompilation) + return; + reg.IncludedInCompilation = true; + } + + MethodDesc ResolveVirtualMethod(TypeDesc implType, MethodDesc declMethod) + { + // TODO: Proper virtual method resolution + string name = declMethod.Name; + MethodSignature sig = declMethod.Signature; + + MethodDesc implMethod; + TypeDesc t = implType; + for (;;) + { + implMethod = t.GetMethod(name, sig); + if (implMethod != null) + return implMethod; + t = t.BaseType; + } + } + + internal TypeDesc GetWellKnownType(WellKnownType wellKnownType) + { + return _typeSystemContext.GetWellKnownType(wellKnownType); + } + + // Turn a name into a valid identifier + private static string SanitizeName(string s) + { + // TODO: Handle Unicode, etc. + s = s.Replace("`", "_"); + s = s.Replace("<", "_"); + s = s.Replace(">", "_"); + s = s.Replace("$", "_"); + return s; + } + + int _unique = 1; + HashSet _deduplicator = new HashSet(); + + internal string GetMangledTypeName(TypeDesc type) + { + var reg = GetRegisteredType(type); + + string mangledName = reg.MangledName; + if (mangledName != null) + return mangledName; + + switch (type.Category) + { + case TypeFlags.Array: + mangledName = GetMangledTypeName(((ArrayType)type).ElementType) + "__Array"; + break; + case TypeFlags.ByRef: + mangledName = GetMangledTypeName(((ByRefType)type).ParameterType) + "__ByRef"; + break; + case TypeFlags.Pointer: + mangledName = GetMangledTypeName(((PointerType)type).ParameterType) + "__Pointer"; + break; + default: + // TODO: Include encapsulating type + mangledName = SanitizeName(type.Name); + + mangledName = mangledName.Replace(".", "_"); + + if (type.HasInstantiation || _deduplicator.Contains(mangledName)) + mangledName = mangledName + "_" + _unique++; + _deduplicator.Add(mangledName); + + break; + } + + reg.MangledName = mangledName; + return mangledName; + } + + internal string GetMangledMethodName(MethodDesc method) + { + var reg = GetRegisteredMethod(method); + + string mangledName = reg.MangledName; + if (mangledName != null) + return mangledName; + + RegisteredType owner = GetRegisteredType(method.OwningType); + + mangledName = SanitizeName(method.Name); + + mangledName = mangledName.Replace(".", "_"); // To handle names like .ctor + + mangledName = GetMangledTypeName(method.OwningType) + "__" + mangledName; + + RegisteredMethod rm = owner.Methods; + bool dedup = false; + while (rm != null) + { + if (rm.MangledName != null && rm.MangledName == mangledName) + { + dedup = true; + break; + } + + rm = rm.Next; + } + if (dedup) + mangledName = mangledName + "_" + owner.UniqueMethod++; + + reg.MangledName = mangledName; + return mangledName; + } + + struct ReadyToRunHelperKey : IEquatable + { + ReadyToRunHelperId _id; + Object _obj; + + public ReadyToRunHelperKey(ReadyToRunHelperId id, Object obj) + { + _id = id; + _obj = obj; + } + + public bool Equals(ReadyToRunHelperKey other) + { + return (_id == other._id) && ReferenceEquals(_obj, other._obj); + } + + public override int GetHashCode() + { + return _id.GetHashCode() ^ _obj.GetHashCode(); + } + + public override bool Equals(object obj) + { + if (!(obj is ReadyToRunHelperKey)) + return false; + + return Equals((ReadyToRunHelperKey)obj); + } + } + + Dictionary _readyToRunHelpers = new Dictionary(); + + public Object GetReadyToRunHelper(ReadyToRunHelperId id, Object target) + { + ReadyToRunHelper helper; + + ReadyToRunHelperKey key = new ReadyToRunHelperKey(id, target); + if (!_readyToRunHelpers.TryGetValue(key, out helper)) + _readyToRunHelpers.Add(key, helper = new ReadyToRunHelper(this, id, target)); + + return helper; + } + } +} diff --git a/src/ILToNative/src/Compiler/CompilerTypeSystemContext.cs b/src/ILToNative/src/Compiler/CompilerTypeSystemContext.cs new file mode 100644 index 00000000000..05ae530a99a --- /dev/null +++ b/src/ILToNative/src/Compiler/CompilerTypeSystemContext.cs @@ -0,0 +1,141 @@ +// 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 System.IO; +using System.Diagnostics; +using System.Collections.Generic; +using System.Reflection.Metadata; +using System.Reflection.PortableExecutable; + +using Internal.TypeSystem; +using Internal.TypeSystem.Ecma; + +using Internal.CommandLine; + +namespace ILToNative +{ + class CompilerTypeSystemContext : TypeSystemContext + { + static readonly string[] s_wellKnownTypeNames = new string[] { + "Void", + "Boolean", + "Char", + "SByte", + "Byte", + "Int16", + "UInt16", + "Int32", + "UInt32", + "Int64", + "UInt64", + "IntPtr", + "UIntPtr", + "Single", + "Double", + + "ValueType", + "Enum", + "Nullable`1", + + "Object", + "String", + "Array", + "MulticastDelegate", + + "RuntimeTypeHandle", + "RuntimeMethodHandle", + "RuntimeFieldHandle", + }; + + MetadataType[] _wellKnownTypes = new MetadataType[s_wellKnownTypeNames.Length]; + + EcmaModule _systemModule; + + Dictionary _modules = new Dictionary(StringComparer.InvariantCultureIgnoreCase); + + class ModuleData + { + public string Path; + // public ISymbolReader SymbolReader; + + } + Dictionary _moduleData = new Dictionary(); + + public CompilerTypeSystemContext(TargetDetails details) + : base(details) + { + } + + public IDictionary InputFilePaths + { + get; + set; + } + + public IDictionary ReferenceFilePaths + { + get; + set; + } + + public void SetSystemModule(EcmaModule systemModule) + { + _systemModule = systemModule; + + // Sanity check the name table + Debug.Assert(s_wellKnownTypeNames[(int)WellKnownType.MulticastDelegate - 1] == "MulticastDelegate"); + + // Initialize all well known types - it will save us from checking the name for each loaded type + for (int typeIndex = 0; typeIndex < _wellKnownTypes.Length; typeIndex++) + { + MetadataType type = _systemModule.GetType("System", s_wellKnownTypeNames[typeIndex]); + type.SetWellKnownType((WellKnownType)(typeIndex + 1)); + _wellKnownTypes[typeIndex] = type; + } + } + + public override MetadataType GetWellKnownType(WellKnownType wellKnownType) + { + return _wellKnownTypes[(int)wellKnownType - 1]; + } + + public override object ResolveAssembly(System.Reflection.AssemblyName name) + { + return GetModuleForSimpleName(name.Name); + } + + public EcmaModule GetModuleForSimpleName(string simpleName) + { + EcmaModule existingModule; + if (_modules.TryGetValue(simpleName, out existingModule)) + return existingModule; + + return CreateModuleForSimpleName(simpleName); + } + + private EcmaModule CreateModuleForSimpleName(string simpleName) + { + string filePath; + if (!InputFilePaths.TryGetValue(simpleName, out filePath)) + { + if (!ReferenceFilePaths.TryGetValue(simpleName, out filePath)) + throw new CommandLineException("Assembly not found: " + simpleName); + } + + EcmaModule module = new EcmaModule(this, new PEReader(File.OpenRead(filePath))); + + MetadataReader metadataReader = module.MetadataReader; + string actualSimpleName = metadataReader.GetString(metadataReader.GetAssemblyDefinition().Name); + if (!actualSimpleName.Equals(simpleName, StringComparison.InvariantCultureIgnoreCase)) + throw new CommandLineException("Assembly name does not match filename " + filePath); + + _modules.Add(simpleName, module); + + ModuleData moduleData = new ModuleData() { Path = filePath }; + _moduleData.Add(module, moduleData); + + return module; + } + } +} diff --git a/src/ILToNative/src/Compiler/MemoryHelper.cs b/src/ILToNative/src/Compiler/MemoryHelper.cs new file mode 100644 index 00000000000..5b07f497920 --- /dev/null +++ b/src/ILToNative/src/Compiler/MemoryHelper.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ILToNative +{ + static unsafe class MemoryHelper + { + public static void FillMemory(byte* dest, byte fill, int count) + { + for (; count > 0; count--) + { + *dest = fill; + dest++; + } + } + } +} diff --git a/src/ILToNative/src/Compiler/MethodCode.cs b/src/ILToNative/src/Compiler/MethodCode.cs new file mode 100644 index 00000000000..d39fede3212 --- /dev/null +++ b/src/ILToNative/src/Compiler/MethodCode.cs @@ -0,0 +1,29 @@ +// 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 System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ILToNative +{ + class MethodCode + { + public byte[] Code; + public byte[] ColdCode; + public byte[] ROData; + + public Relocation[] Relocs; + } + + struct Relocation + { + public ushort RelocType; + public sbyte Block; // Code = 0, ColdCode = 1, ROData = 2 + public int Offset; + public Object Target; + public int Delta; + } +} diff --git a/src/ILToNative/src/Compiler/Program.cs b/src/ILToNative/src/Compiler/Program.cs new file mode 100644 index 00000000000..f4c566e312f --- /dev/null +++ b/src/ILToNative/src/Compiler/Program.cs @@ -0,0 +1,152 @@ +// 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 System.Linq; +using System.IO; +using System.Collections.Generic; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; +using System.Reflection.PortableExecutable; + +using Internal.TypeSystem; +using Internal.TypeSystem.Ecma; + +using Internal.CommandLine; + +namespace ILToNative +{ + class Program + { + bool _help; + + string _outputPath; + + Dictionary _inputFilePaths = new Dictionary(StringComparer.InvariantCultureIgnoreCase); + Dictionary _referenceFilePaths = new Dictionary(StringComparer.InvariantCultureIgnoreCase); + + CompilerTypeSystemContext _compilerTypeSystemContext; + + Program() + { + } + + void Help() + { + Console.WriteLine("ILToNative compiler version " + typeof(Program).Assembly.GetName().Version.ToString()); + Console.WriteLine(); + Console.WriteLine("-help Display this usage message (Short form: -?)"); + Console.WriteLine("-out Specify output file name"); + Console.WriteLine("-reference Reference metadata from the specified assembly (Short form: -r)"); + } + + void ParseCommandLine(string[] args) + { + var parser = new CommandLineParser(args); + + string option; + while ((option = parser.GetOption()) != null) + { + switch (option.ToLowerInvariant()) + { + case "?": + case "help": + _help = true; + break; + + case "": + case "in": + parser.AppendExpandedPaths(_inputFilePaths, true); + break; + + case "o": + case "out": + _outputPath = parser.GetStringValue(); + break; + + case "r": + case "reference": + parser.AppendExpandedPaths(_referenceFilePaths, false); + break; + + default: + throw new CommandLineException("Unrecognized option: " + parser.GetCurrentOption()); + } + } + } + + EcmaModule GetEntryPointModule() + { + EcmaModule mainModule = null; + foreach (var inputFile in _inputFilePaths) + { + EcmaModule module = _compilerTypeSystemContext.GetModuleForSimpleName(inputFile.Key); + if (module.PEReader.PEHeaders.IsExe) + { + if (mainModule != null) + throw new CommandLineException("Multiple entrypoint modules"); + mainModule = module; + } + } + return mainModule; + } + + void SingleFileCompilation() + { + EcmaModule entryPointModule = GetEntryPointModule(); + if (entryPointModule == null) + throw new CommandLineException("No entrypoint module"); + + int entryPointToken = entryPointModule.PEReader.PEHeaders.CorHeader.EntryPointTokenOrRelativeVirtualAddress; + MethodDesc entryPointMethod = entryPointModule.GetMethod(MetadataTokens.EntityHandle(entryPointToken)); + + Compilation compilation = new Compilation(_compilerTypeSystemContext); + compilation.Log = Console.Out; + compilation.Out = new StreamWriter(File.Create(_outputPath)); + + compilation.CompileSingleFile(entryPointMethod); + } + + int Run(string[] args) + { + ParseCommandLine(args); + + if (_help) + { + Help(); + return 1; + } + + if (_inputFilePaths.Count == 0) + throw new CommandLineException("No input files specified"); + + if (_outputPath == null) + throw new CommandLineException("Output filename must be specified (/out )"); + + _compilerTypeSystemContext = new CompilerTypeSystemContext(new TargetDetails(TargetArchitecture.X64)); + _compilerTypeSystemContext.InputFilePaths = _inputFilePaths; + _compilerTypeSystemContext.ReferenceFilePaths = _referenceFilePaths; + + _compilerTypeSystemContext.SetSystemModule(_compilerTypeSystemContext.GetModuleForSimpleName("mscorlib")); + + // For now, we can do single file compilation only + // TODO: Multifile + SingleFileCompilation(); + + return 0; + } + + static int Main(string[] args) + { + try + { + return new Program().Run(args); + } + catch (Exception e) + { + Console.Error.WriteLine("Error: " + e.Message); + return 1; + } + } + } +} diff --git a/src/ILToNative/src/Compiler/ReadyToRunHelper.cs b/src/ILToNative/src/Compiler/ReadyToRunHelper.cs new file mode 100644 index 00000000000..494cffaaf91 --- /dev/null +++ b/src/ILToNative/src/Compiler/ReadyToRunHelper.cs @@ -0,0 +1,51 @@ +// 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 System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +using Internal.TypeSystem; + +namespace ILToNative +{ + public enum ReadyToRunHelperId + { + NewHelper, + VirtualCall + } + + class ReadyToRunHelper + { + Compilation _compilation; + + public ReadyToRunHelper(Compilation compilation, ReadyToRunHelperId id, Object target) + { + _compilation = compilation; + + this.Id = id; + this.Target = target; + } + + public ReadyToRunHelperId Id { get; private set; } + public Object Target { get; private set; } + + public string MangledName + { + get + { + switch (this.Id) + { + case ReadyToRunHelperId.NewHelper: + return "__NewHelper_" + _compilation.GetMangledTypeName((TypeDesc)this.Target); + case ReadyToRunHelperId.VirtualCall: + return "__VirtualCall_" + _compilation.GetMangledMethodName((MethodDesc)this.Target); + default: + throw new NotImplementedException(); + } + } + } + } +} diff --git a/src/ILToNative/src/Compiler/RegisteredField.cs b/src/ILToNative/src/Compiler/RegisteredField.cs new file mode 100644 index 00000000000..8d1b8b952d2 --- /dev/null +++ b/src/ILToNative/src/Compiler/RegisteredField.cs @@ -0,0 +1,16 @@ +// 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; + +namespace ILToNative +{ + class RegisteredField + { + public FieldDesc Field; + + public bool IncludedInCompilation; + } +} diff --git a/src/ILToNative/src/Compiler/RegisteredMethod.cs b/src/ILToNative/src/Compiler/RegisteredMethod.cs new file mode 100644 index 00000000000..f5de81b4b24 --- /dev/null +++ b/src/ILToNative/src/Compiler/RegisteredMethod.cs @@ -0,0 +1,22 @@ +// 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; + +namespace ILToNative +{ + class RegisteredMethod + { + public MethodDesc Method; + + public bool IncludedInCompilation; + + public string MangledName; + + public MethodCode MethodCode; + + public RegisteredMethod Next; + } +} diff --git a/src/ILToNative/src/Compiler/RegisteredType.cs b/src/ILToNative/src/Compiler/RegisteredType.cs new file mode 100644 index 00000000000..8acc4e577f2 --- /dev/null +++ b/src/ILToNative/src/Compiler/RegisteredType.cs @@ -0,0 +1,26 @@ +// 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 System.Collections.Generic; + +using Internal.TypeSystem; + +namespace ILToNative +{ + class RegisteredType + { + public TypeDesc Type; + + public bool IncludedInCompilation; + public bool Constructed; + + public int UniqueMethod; + + public string MangledName; + + public RegisteredMethod Methods; + + public List VirtualSlots; + } +} diff --git a/src/TypeSystem/src/IL/EcmaMethodIL.cs b/src/TypeSystem/src/IL/EcmaMethodIL.cs new file mode 100644 index 00000000000..8af8e733b97 --- /dev/null +++ b/src/TypeSystem/src/IL/EcmaMethodIL.cs @@ -0,0 +1,113 @@ +// 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 System.Runtime.InteropServices; +using System.Collections.Immutable; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; + +using Internal.TypeSystem; +using Internal.TypeSystem.Ecma; + +namespace Internal.IL +{ + public class EcmaMethodIL : MethodIL + { + EcmaModule _module; + MethodBodyBlock _methodBody; + + static public EcmaMethodIL Create(EcmaMethod method) + { + var rva = method.MethodDefinition.RelativeVirtualAddress; + if (rva == 0) + return null; + return new EcmaMethodIL(method.Module, method.Module.PEReader.GetMethodBody(rva)); + } + + public EcmaMethodIL(EcmaModule module, MethodBodyBlock methodBody) + { + _module = module; + _methodBody = methodBody; + } + + // Avoid unnecessary copy + static byte[] DangerousGetUnderlyingArray(ImmutableArray array) + { + var union = new ByteArrayUnion(); + union.ImmutableArray = array; + return union.UnderlyingArray; + } + + [StructLayout(LayoutKind.Explicit)] + struct ByteArrayUnion + { + [FieldOffset(0)] + internal byte[] UnderlyingArray; + + [FieldOffset(0)] + internal ImmutableArray ImmutableArray; + } + + public override byte[] GetILBytes() + { + return DangerousGetUnderlyingArray(_methodBody.GetILContent()); + } + + public override bool GetInitLocals() + { + return _methodBody.LocalVariablesInitialized; + } + + public override int GetMaxStack() + { + return _methodBody.MaxStack; + } + + public override TypeDesc[] GetLocals() + { + var metadataReader = _module.MetadataReader; + var localSignature = _methodBody.LocalSignature; + if (localSignature.IsNil) + return TypeDesc.EmptyTypes; + BlobReader signatureReader = metadataReader.GetBlobReader(metadataReader.GetStandaloneSignature(localSignature).Signature); + + EcmaSignatureParser parser = new EcmaSignatureParser(_module, signatureReader); + return parser.ParseLocalsSignature(); + } + + public override ILExceptionRegion[] GetExceptionRegions() + { + ImmutableArray exceptionRegions = _methodBody.ExceptionRegions; + + int length = exceptionRegions.Length; + if (exceptionRegions.Length == 0) + return new ILExceptionRegion[0]; // TODO: Array.Empty() + + ILExceptionRegion[] ilExceptionRegions = new ILExceptionRegion[length]; + for (int i = 0; i < length; i++) + { + var exceptionRegion = exceptionRegions[i]; + + ilExceptionRegions[i] = new ILExceptionRegion( + (ILExceptionRegionKind)exceptionRegion.Kind, // assumes that ILExceptionRegionKind and ExceptionRegionKind enums are in sync + exceptionRegion.TryOffset, + exceptionRegion.TryLength, + exceptionRegion.HandlerOffset, + exceptionRegion.HandlerLength, + MetadataTokens.GetToken(exceptionRegion.CatchType), + exceptionRegion.FilterOffset); + } + return ilExceptionRegions; + } + + public override object GetObject(int token) + { + // UserStrings cannot be wrapped in EntityHandle + if ((token & 0xFF000000) == 0x70000000) + return _module.GetUserString(MetadataTokens.UserStringHandle(token)); + + return _module.GetObject(MetadataTokens.EntityHandle(token)); + } + } +} diff --git a/src/TypeSystem/src/IL/ILImporter.cs b/src/TypeSystem/src/IL/ILImporter.cs new file mode 100644 index 00000000000..540a422d258 --- /dev/null +++ b/src/TypeSystem/src/IL/ILImporter.cs @@ -0,0 +1,916 @@ +// 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.IL; + +namespace Internal.IL +{ + // + // Corresponds to "I.12.3.2.1 The evaluation stack" in ECMA spec + // + enum StackValueKind + { + Unknown, + Int32, + Int64, + NativeInt, + Float, + ByRef, + ObjRef, + ValueType + } + + partial class ILImporter + { + static readonly StackValue[] s_emptyStack = new StackValue[0]; + StackValue[] _stack = s_emptyStack; + int _stackTop = 0; + + BasicBlock[] _basicBlocks; // Maps IL offset to basic block + + BasicBlock _currentBasicBlock; + int _currentOffset; + + BasicBlock _pendingBasicBlocks; + + // + // IL stream reading + // + + private byte ReadILByte() + { + return _ilBytes[_currentOffset++]; + } + + private UInt16 ReadILUInt16() + { + UInt16 val = (UInt16)(_ilBytes[_currentOffset] + (_ilBytes[_currentOffset + 1] << 8)); + _currentOffset += 2; + return val; + } + + private UInt32 ReadILUInt32() + { + UInt32 val = (UInt32)(_ilBytes[_currentOffset] + (_ilBytes[_currentOffset + 1] << 8) + (_ilBytes[_currentOffset + 2] << 16) + (_ilBytes[_currentOffset + 3] << 24)); + _currentOffset += 4; + return val; + } + + private int ReadILToken() + { + return (int)ReadILUInt32(); + } + + private ulong ReadILUInt64() + { + ulong value = ReadILUInt32(); + value |= (((ulong)ReadILUInt32()) << 32); + return value; + } + + private unsafe float ReadILFloat() + { + uint value = ReadILUInt32(); + return *(float*)(&value); + } + + private unsafe double ReadILDouble() + { + ulong value = ReadILUInt64(); + return *(double*)(&value); + } + + private void SkipIL(int bytes) + { + _currentOffset += bytes; + } + + // + // Basic block identification + // + + void FindBasicBlocks() + { + _basicBlocks = new BasicBlock[_ilBytes.Length]; + + CreateBasicBlock(0); + + FindJumpTargets(); + + FindEHTargets(); + } + + BasicBlock CreateBasicBlock(int offset) + { + BasicBlock basicBlock = _basicBlocks[offset]; + if (basicBlock == null) + { + basicBlock = new BasicBlock() { StartOffset = offset }; + _basicBlocks[offset] = basicBlock; + } + return basicBlock; + } + + void FindJumpTargets() + { + _currentOffset = 0; + + while (_currentOffset < _ilBytes.Length) + { + MarkInstructionBoundary(); + + ILOpcode opCode = (ILOpcode)ReadILByte(); + + again: + switch (opCode) + { + case ILOpcode.ldarg_s: + case ILOpcode.ldarga_s: + case ILOpcode.starg_s: + case ILOpcode.ldloc_s: + case ILOpcode.ldloca_s: + case ILOpcode.stloc_s: + case ILOpcode.ldc_i4_s: + case ILOpcode.unaligned: + SkipIL(1); + break; + case ILOpcode.ldarg: + case ILOpcode.ldarga: + case ILOpcode.starg: + case ILOpcode.ldloc: + case ILOpcode.ldloca: + case ILOpcode.stloc: + SkipIL(2); + break; + case ILOpcode.ldc_i4: + case ILOpcode.ldc_r4: + SkipIL(4); + break; + case ILOpcode.ldc_i8: + case ILOpcode.ldc_r8: + SkipIL(8); + break; + case ILOpcode.jmp: + case ILOpcode.call: + case ILOpcode.calli: + case ILOpcode.callvirt: + case ILOpcode.cpobj: + case ILOpcode.ldobj: + case ILOpcode.ldstr: + case ILOpcode.newobj: + case ILOpcode.castclass: + case ILOpcode.isinst: + case ILOpcode.unbox: + case ILOpcode.ldfld: + case ILOpcode.ldflda: + case ILOpcode.stfld: + case ILOpcode.ldsfld: + case ILOpcode.ldsflda: + case ILOpcode.stsfld: + case ILOpcode.stobj: + case ILOpcode.box: + case ILOpcode.newarr: + case ILOpcode.ldelema: + case ILOpcode.ldelem: + case ILOpcode.stelem: + case ILOpcode.unbox_any: + case ILOpcode.refanyval: + case ILOpcode.mkrefany: + case ILOpcode.ldtoken: + case ILOpcode.ldftn: + case ILOpcode.ldvirtftn: + case ILOpcode.initobj: + case ILOpcode.constrained: + case ILOpcode.sizeof_: + SkipIL(4); + break; + case ILOpcode.prefix1: + opCode = (ILOpcode)(0x100 + ReadILByte()); + goto again; + case ILOpcode.br_s: + case ILOpcode.leave_s: + { + int delta = (sbyte)ReadILByte(); + CreateBasicBlock(_currentOffset + delta); + } + break; + case ILOpcode.brfalse_s: + case ILOpcode.brtrue_s: + case ILOpcode.beq_s: + case ILOpcode.bge_s: + case ILOpcode.bgt_s: + case ILOpcode.ble_s: + case ILOpcode.blt_s: + case ILOpcode.bne_un_s: + case ILOpcode.bge_un_s: + case ILOpcode.bgt_un_s: + case ILOpcode.ble_un_s: + case ILOpcode.blt_un_s: + { + int delta = (sbyte)ReadILByte(); + CreateBasicBlock(_currentOffset + delta); + CreateBasicBlock(_currentOffset); + } + break; + case ILOpcode.br: + case ILOpcode.leave: + { + int delta = (int)ReadILUInt32(); + CreateBasicBlock(_currentOffset + delta); + } + break; + case ILOpcode.brfalse: + case ILOpcode.brtrue: + case ILOpcode.beq: + case ILOpcode.bge: + case ILOpcode.bgt: + case ILOpcode.ble: + case ILOpcode.blt: + case ILOpcode.bne_un: + case ILOpcode.bge_un: + case ILOpcode.bgt_un: + case ILOpcode.ble_un: + case ILOpcode.blt_un: + { + int delta = (int)ReadILUInt32(); + CreateBasicBlock(_currentOffset + delta); + CreateBasicBlock(_currentOffset); + } + break; + case ILOpcode.switch_: + { + uint count = ReadILUInt32(); + int jmpBase = _currentOffset + (int)(4 * count); + for (uint i = 0; i < count; i++) + { + int delta = (int)ReadILUInt32(); + CreateBasicBlock(jmpBase + delta); + } + CreateBasicBlock(_currentOffset); + } + break; + default: + continue; + } + } + } + + void FindEHTargets() + { + for (int i = 0; i < _exceptionRegions.Length; i++) + { + var r = _exceptionRegions[i]; + + CreateBasicBlock(r.ILRegion.TryOffset).TryStart = true; + if (r.ILRegion.Kind == ILExceptionRegionKind.Filter) + CreateBasicBlock(r.ILRegion.FilterOffset).FilterStart = true; + CreateBasicBlock(r.ILRegion.HandlerOffset).HandlerStart = true; + } + } + + // + // Basic block importing + // + + void ImportBasicBlocks() + { + _pendingBasicBlocks = _basicBlocks[0]; + while (_pendingBasicBlocks != null) + { + BasicBlock basicBlock = _pendingBasicBlocks; + _pendingBasicBlocks = basicBlock.Next; + + StartImportingBasicBlock(basicBlock); + ImportBasicBlock(basicBlock); + EndImportingBasicBlock(basicBlock); + } + } + + void MarkBasicBlock(BasicBlock basicBlock) + { + if (basicBlock.EndOffset == 0) + { + // Link + basicBlock.Next = _pendingBasicBlocks; + _pendingBasicBlocks = basicBlock; + + basicBlock.EndOffset = -1; + } + } + + void ImportBasicBlock(BasicBlock basicBlock) + { + _stackTop = 0; + + StackValue[] entryStack = basicBlock.EntryStack; + if (entryStack != null) + { + for (int i = 0; i < entryStack.Length; i++) + Push(entryStack[i]); + } + + _currentBasicBlock = basicBlock; + _currentOffset = basicBlock.StartOffset; + + for (;;) + { + StartImportingInstruction(); + + ILOpcode opCode = (ILOpcode)ReadILByte(); + + again: + switch (opCode) + { + case ILOpcode.nop: + ImportNop(); + break; + case ILOpcode.break_: + ImportBreak(); + break; + case ILOpcode.ldarg_0: + case ILOpcode.ldarg_1: + case ILOpcode.ldarg_2: + case ILOpcode.ldarg_3: + ImportLoadVar(opCode - ILOpcode.ldarg_0, true); + break; + case ILOpcode.ldloc_0: + case ILOpcode.ldloc_1: + case ILOpcode.ldloc_2: + case ILOpcode.ldloc_3: + ImportLoadVar(opCode - ILOpcode.ldloc_0, false); + break; + case ILOpcode.stloc_0: + case ILOpcode.stloc_1: + case ILOpcode.stloc_2: + case ILOpcode.stloc_3: + ImportStoreVar(opCode - ILOpcode.stloc_0, false); + break; + case ILOpcode.ldarg_s: + ImportLoadVar(ReadILByte(), true); + break; + case ILOpcode.ldarga_s: + ImportAddressOfVar(ReadILByte(), true); + break; + case ILOpcode.starg_s: + ImportStoreVar(ReadILByte(), true); + break; + case ILOpcode.ldloc_s: + ImportLoadVar(ReadILByte(), false); + break; + case ILOpcode.ldloca_s: + ImportAddressOfVar(ReadILByte(), false); + break; + case ILOpcode.stloc_s: + ImportStoreVar(ReadILByte(), false); + break; + case ILOpcode.ldnull: + ImportLoadNull(); + break; + case ILOpcode.ldc_i4_m1: + ImportLoadInt(-1, StackValueKind.Int32); + break; + case ILOpcode.ldc_i4_0: + case ILOpcode.ldc_i4_1: + case ILOpcode.ldc_i4_2: + case ILOpcode.ldc_i4_3: + case ILOpcode.ldc_i4_4: + case ILOpcode.ldc_i4_5: + case ILOpcode.ldc_i4_6: + case ILOpcode.ldc_i4_7: + case ILOpcode.ldc_i4_8: + ImportLoadInt(opCode - ILOpcode.ldc_i4_0, StackValueKind.Int32); + break; + case ILOpcode.ldc_i4_s: + ImportLoadInt((sbyte)ReadILByte(), StackValueKind.Int32); + break; + case ILOpcode.ldc_i4: + ImportLoadInt((int)ReadILUInt32(), StackValueKind.Int32); + break; + case ILOpcode.ldc_i8: + ImportLoadInt((long)ReadILUInt64(), StackValueKind.Int64); + break; + case ILOpcode.ldc_r4: + ImportLoadFloat(ReadILFloat()); + break; + case ILOpcode.ldc_r8: + ImportLoadFloat(ReadILDouble()); + break; + case ILOpcode.dup: + ImportDup(); + break; + case ILOpcode.pop: + ImportPop(); + break; + case ILOpcode.jmp: + ImportJmp(ReadILToken()); + break; + case ILOpcode.call: + ImportCall(opCode, ReadILToken()); + break; + case ILOpcode.calli: + ImportCall(opCode, ReadILToken()); + break; + case ILOpcode.ret: + ImportReturn(); + return; + case ILOpcode.br_s: + case ILOpcode.brfalse_s: + case ILOpcode.brtrue_s: + case ILOpcode.beq_s: + case ILOpcode.bge_s: + case ILOpcode.bgt_s: + case ILOpcode.ble_s: + case ILOpcode.blt_s: + case ILOpcode.bne_un_s: + case ILOpcode.bge_un_s: + case ILOpcode.bgt_un_s: + case ILOpcode.ble_un_s: + case ILOpcode.blt_un_s: + { + int delta = (sbyte)ReadILByte(); + ImportBranch(opCode + (ILOpcode.br - ILOpcode.br_s), + _basicBlocks[_currentOffset + delta], (opCode != ILOpcode.br_s) ? _basicBlocks[_currentOffset] : null); + } + return; + case ILOpcode.br: + case ILOpcode.brfalse: + case ILOpcode.brtrue: + case ILOpcode.beq: + case ILOpcode.bge: + case ILOpcode.bgt: + case ILOpcode.ble: + case ILOpcode.blt: + case ILOpcode.bne_un: + case ILOpcode.bge_un: + case ILOpcode.bgt_un: + case ILOpcode.ble_un: + case ILOpcode.blt_un: + { + int delta = (int)ReadILUInt32(); + ImportBranch(opCode, + _basicBlocks[_currentOffset + delta], (opCode != ILOpcode.br) ? _basicBlocks[_currentOffset] : null); + } + return; + case ILOpcode.switch_: + { + uint count = ReadILUInt32(); + int jmpBase = _currentOffset + (int)(4 * count); + int[] jmpDelta = new int[count]; + for (uint i = 0; i < count; i++) + jmpDelta[i] = (int)ReadILUInt32(); + + ImportSwitchJump(jmpBase, jmpDelta, _basicBlocks[_currentOffset]); + } + return; + case ILOpcode.ldind_i1: + ImportLoadIndirect(WellKnownType.SByte); + break; + case ILOpcode.ldind_u1: + ImportLoadIndirect(WellKnownType.Byte); + break; + case ILOpcode.ldind_i2: + ImportLoadIndirect(WellKnownType.Int16); + break; + case ILOpcode.ldind_u2: + ImportLoadIndirect(WellKnownType.UInt16); + break; + case ILOpcode.ldind_i4: + ImportLoadIndirect(WellKnownType.Int32); + break; + case ILOpcode.ldind_u4: + ImportLoadIndirect(WellKnownType.UInt32); + break; + case ILOpcode.ldind_i8: + ImportLoadIndirect(WellKnownType.Int64); + break; + case ILOpcode.ldind_i: + ImportLoadIndirect(WellKnownType.IntPtr); + break; + case ILOpcode.ldind_r4: + ImportLoadIndirect(WellKnownType.Single); + break; + case ILOpcode.ldind_r8: + ImportLoadIndirect(WellKnownType.Double); + break; + case ILOpcode.ldind_ref: + ImportLoadIndirect(null); + break; + case ILOpcode.stind_ref: + ImportStoreIndirect(null); + break; + case ILOpcode.stind_i1: + ImportStoreIndirect(WellKnownType.SByte); + break; + case ILOpcode.stind_i2: + ImportStoreIndirect(WellKnownType.Int16); + break; + case ILOpcode.stind_i4: + ImportStoreIndirect(WellKnownType.Int32); + break; + case ILOpcode.stind_i8: + ImportStoreIndirect(WellKnownType.Int64); + break; + case ILOpcode.stind_r4: + ImportStoreIndirect(WellKnownType.Single); + break; + case ILOpcode.stind_r8: + ImportStoreIndirect(WellKnownType.Double); + break; + case ILOpcode.add: + case ILOpcode.sub: + case ILOpcode.mul: + case ILOpcode.div: + case ILOpcode.div_un: + case ILOpcode.rem: + case ILOpcode.rem_un: + case ILOpcode.and: + case ILOpcode.or: + case ILOpcode.xor: + ImportBinaryOperation(opCode); + break; + case ILOpcode.shl: + case ILOpcode.shr: + case ILOpcode.shr_un: + ImportShiftOperation(opCode); + break; + case ILOpcode.neg: + case ILOpcode.not: + ImportUnaryOperation(opCode); + break; + case ILOpcode.conv_i1: + ImportConvert(WellKnownType.Byte, false, false); + break; + case ILOpcode.conv_i2: + ImportConvert(WellKnownType.Int16, false, false); + break; + case ILOpcode.conv_i4: + ImportConvert(WellKnownType.Int32, false, false); + break; + case ILOpcode.conv_i8: + ImportConvert(WellKnownType.Int64, false, false); + break; + case ILOpcode.conv_r4: + ImportConvert(WellKnownType.Single, false, false); + break; + case ILOpcode.conv_r8: + ImportConvert(WellKnownType.Double, false, false); + break; + case ILOpcode.conv_u4: + ImportConvert(WellKnownType.UInt32, false, false); + break; + case ILOpcode.conv_u8: + ImportConvert(WellKnownType.UInt64, false, false); + break; + case ILOpcode.callvirt: + ImportCall(opCode, ReadILToken()); + break; + case ILOpcode.cpobj: + ImportCpOpj(ReadILToken()); + break; + case ILOpcode.ldobj: + ImportLoadIndirect(ReadILToken()); + break; + case ILOpcode.ldstr: + ImportLoadString(ReadILToken()); + break; + case ILOpcode.newobj: + ImportCall(opCode, ReadILToken()); + break; + case ILOpcode.castclass: + case ILOpcode.isinst: + ImportCasting(opCode, ReadILToken()); + break; + case ILOpcode.conv_r_un: + ImportConvert(WellKnownType.Double, false, true); + break; + case ILOpcode.unbox: + ImportUnbox(ReadILToken(), opCode); + break; + case ILOpcode.throw_: + ImportThrow(); + return; + case ILOpcode.ldfld: + ImportLoadField(ReadILToken(), false); + break; + case ILOpcode.ldflda: + ImportAddressOfField(ReadILToken(), false); + break; + case ILOpcode.stfld: + ImportStoreField(ReadILToken(), false); + break; + case ILOpcode.ldsfld: + ImportLoadField(ReadILToken(), true); + break; + case ILOpcode.ldsflda: + ImportAddressOfField(ReadILToken(), true); + break; + case ILOpcode.stsfld: + ImportStoreField(ReadILToken(), true); + break; + case ILOpcode.stobj: + ImportStoreIndirect(ReadILToken()); + break; + case ILOpcode.conv_ovf_i1_un: + ImportConvert(WellKnownType.SByte, true, true); + break; + case ILOpcode.conv_ovf_i2_un: + ImportConvert(WellKnownType.Int16, true, true); + break; + case ILOpcode.conv_ovf_i4_un: + ImportConvert(WellKnownType.Int32, true, true); + break; + case ILOpcode.conv_ovf_i8_un: + ImportConvert(WellKnownType.Int64, true, true); + break; + case ILOpcode.conv_ovf_u1_un: + ImportConvert(WellKnownType.Byte, true, true); + break; + case ILOpcode.conv_ovf_u2_un: + ImportConvert(WellKnownType.UInt16, true, true); + break; + case ILOpcode.conv_ovf_u4_un: + ImportConvert(WellKnownType.UInt32, true, true); + break; + case ILOpcode.conv_ovf_u8_un: + ImportConvert(WellKnownType.UInt64, true, true); + break; + case ILOpcode.conv_ovf_i_un: + ImportConvert(WellKnownType.IntPtr, true, true); + break; + case ILOpcode.conv_ovf_u_un: + ImportConvert(WellKnownType.UIntPtr, true, true); + break; + case ILOpcode.box: + ImportBox(ReadILToken()); + break; + case ILOpcode.newarr: + ImportNewArray(ReadILToken()); + break; + case ILOpcode.ldlen: + ImportLoadLength(); + break; + case ILOpcode.ldelema: + ImportAddressOfElement(ReadILToken()); + break; + case ILOpcode.ldelem_i1: + ImportLoadElement(WellKnownType.SByte); + break; + case ILOpcode.ldelem_u1: + ImportLoadElement(WellKnownType.Byte); + break; + case ILOpcode.ldelem_i2: + ImportLoadElement(WellKnownType.Int16); + break; + case ILOpcode.ldelem_u2: + ImportLoadElement(WellKnownType.UInt16); + break; + case ILOpcode.ldelem_i4: + ImportLoadElement(WellKnownType.Int32); + break; + case ILOpcode.ldelem_u4: + ImportLoadElement(WellKnownType.UInt32); + break; + case ILOpcode.ldelem_i8: + ImportLoadElement(WellKnownType.Int64); + break; + case ILOpcode.ldelem_i: + ImportLoadElement(WellKnownType.IntPtr); + break; + case ILOpcode.ldelem_r4: + ImportLoadElement(WellKnownType.Single); + break; + case ILOpcode.ldelem_r8: + ImportLoadElement(WellKnownType.Double); + break; + case ILOpcode.ldelem_ref: + ImportLoadElement(null); + break; + case ILOpcode.stelem_i: + ImportStoreElement(WellKnownType.IntPtr); + break; + case ILOpcode.stelem_i1: + ImportStoreElement(WellKnownType.SByte); + break; + case ILOpcode.stelem_i2: + ImportStoreElement(WellKnownType.Int16); + break; + case ILOpcode.stelem_i4: + ImportStoreElement(WellKnownType.Int32); + break; + case ILOpcode.stelem_i8: + ImportStoreElement(WellKnownType.Int32); + break; + case ILOpcode.stelem_r4: + ImportStoreElement(WellKnownType.Single); + break; + case ILOpcode.stelem_r8: + ImportStoreElement(WellKnownType.Double); + break; + case ILOpcode.stelem_ref: + ImportStoreElement(null); + break; + case ILOpcode.ldelem: + ImportLoadElement(ReadILToken()); + break; + case ILOpcode.stelem: + ImportStoreElement(ReadILToken()); + break; + case ILOpcode.unbox_any: + ImportUnbox(ReadILToken(), opCode); + break; + case ILOpcode.conv_ovf_i1: + ImportConvert(WellKnownType.SByte, true, false); + break; + case ILOpcode.conv_ovf_u1: + ImportConvert(WellKnownType.Byte, true, false); + break; + case ILOpcode.conv_ovf_i2: + ImportConvert(WellKnownType.Int16, true, false); + break; + case ILOpcode.conv_ovf_u2: + ImportConvert(WellKnownType.UInt16, true, false); + break; + case ILOpcode.conv_ovf_i4: + ImportConvert(WellKnownType.Int32, true, false); + break; + case ILOpcode.conv_ovf_u4: + ImportConvert(WellKnownType.UInt32, true, false); + break; + case ILOpcode.conv_ovf_i8: + ImportConvert(WellKnownType.Int64, true, false); + break; + case ILOpcode.conv_ovf_u8: + ImportConvert(WellKnownType.UInt64, true, false); + break; + case ILOpcode.refanyval: + ImportRefAnyVal(ReadILToken()); + break; + case ILOpcode.ckfinite: + ImportCkFinite(); + break; + case ILOpcode.mkrefany: + ImportMkRefAny(ReadILToken()); + break; + case ILOpcode.ldtoken: + ImportLdToken(ReadILToken()); + break; + case ILOpcode.conv_u2: + ImportConvert(WellKnownType.UInt16, false, false); + break; + case ILOpcode.conv_u1: + ImportConvert(WellKnownType.Byte, false, false); + break; + case ILOpcode.conv_i: + ImportConvert(WellKnownType.IntPtr, false, false); + break; + case ILOpcode.conv_ovf_i: + ImportConvert(WellKnownType.IntPtr, true, false); + break; + case ILOpcode.conv_ovf_u: + ImportConvert(WellKnownType.UIntPtr, true, false); + break; + case ILOpcode.add_ovf: + case ILOpcode.add_ovf_un: + case ILOpcode.mul_ovf: + case ILOpcode.mul_ovf_un: + case ILOpcode.sub_ovf: + case ILOpcode.sub_ovf_un: + ImportBinaryOperation(opCode); + break; + case ILOpcode.endfinally: + ImportEndFinally(); + break; + case ILOpcode.leave: + { + int delta = (int)ReadILUInt32(); + ImportLeave(_basicBlocks[_currentOffset + delta]); + } + return; + case ILOpcode.leave_s: + { + int delta = (sbyte)ReadILByte(); + ImportLeave(_basicBlocks[_currentOffset + delta]); + } + return; + case ILOpcode.stind_i: + ImportStoreIndirect(WellKnownType.IntPtr); + break; + case ILOpcode.conv_u: + ImportConvert(WellKnownType.UIntPtr, false, false); + break; + case ILOpcode.prefix1: + opCode = (ILOpcode)(0x100 + ReadILByte()); + goto again; + case ILOpcode.arglist: + ImportArgList(); + break; + case ILOpcode.ceq: + case ILOpcode.cgt: + case ILOpcode.cgt_un: + case ILOpcode.clt: + case ILOpcode.clt_un: + ImportCompareOperation(opCode); + break; + case ILOpcode.ldftn: + case ILOpcode.ldvirtftn: + ImportLdFtn(ReadILToken(), opCode); + break; + case ILOpcode.ldarg: + ImportLoadVar(ReadILUInt16(), true); + break; + case ILOpcode.ldarga: + ImportAddressOfVar(ReadILUInt16(), true); + break; + case ILOpcode.starg: + ImportStoreVar(ReadILUInt16(), true); + break; + case ILOpcode.ldloc: + ImportLoadVar(ReadILUInt16(), false); + break; + case ILOpcode.ldloca: + ImportAddressOfVar(ReadILUInt16(), false); + break; + case ILOpcode.stloc: + ImportStoreVar(ReadILUInt16(), false); + break; + case ILOpcode.localloc: + ImportLocalAlloc(); + break; + case ILOpcode.endfilter: + ImportEndFilter(); + break; + case ILOpcode.unaligned: + ImportUnalignedPrefix(ReadILByte()); + continue; + case ILOpcode.volatile_: + ImportVolatilePrefix(); + continue; + case ILOpcode.tail: + ImportTailPrefix(); + continue; + case ILOpcode.initobj: + ImportInitObj(ReadILToken()); + break; + case ILOpcode.constrained: + ImportConstrainedPrefix(ReadILToken()); + continue; + case ILOpcode.cpblk: + ImportCpBlk(); + break; + case ILOpcode.initblk: + ImportInitBlk(); + break; + case ILOpcode.no: + ImportNoPrefix(ReadILByte()); + continue; + case ILOpcode.rethrow: + ImportRethrow(); + break; + case ILOpcode.sizeof_: + ImportSizeOf(ReadILToken()); + break; + case ILOpcode.refanytype: + ImportRefAnyType(); + break; + case ILOpcode.readonly_: + ImportReadOnlyPrefix(); + continue; + default: + throw new BadImageFormatException("Invalid opcode"); + } + + BasicBlock nextBasicBlock = _basicBlocks[_currentOffset]; + if (nextBasicBlock != null) + { + ImportFallthrough(nextBasicBlock); + return; + } + + EndImportingInstruction(); + } + } + + void ImportLoadIndirect(WellKnownType wellKnownType) + { + ImportLoadIndirect(GetWellKnownType(wellKnownType)); + } + + void ImportStoreIndirect(WellKnownType wellKnownType) + { + ImportStoreIndirect(GetWellKnownType(wellKnownType)); + } + + void ImportLoadElement(WellKnownType wellKnownType) + { + ImportLoadElement(GetWellKnownType(wellKnownType)); + } + + void ImportStoreElement(WellKnownType wellKnownType) + { + ImportStoreElement(GetWellKnownType(wellKnownType)); + } + } +} diff --git a/src/TypeSystem/src/IL/ILOpcode.cs b/src/TypeSystem/src/IL/ILOpcode.cs new file mode 100644 index 00000000000..4df27a3181c --- /dev/null +++ b/src/TypeSystem/src/IL/ILOpcode.cs @@ -0,0 +1,234 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Internal.IL +{ + /// + /// An enumeration of all of the operation codes that are used in the CLI Common Intermediate Language. + /// + public enum ILOpcode + { + nop=0x00, + break_=0x01, + ldarg_0=0x02, + ldarg_1=0x03, + ldarg_2=0x04, + ldarg_3=0x05, + ldloc_0=0x06, + ldloc_1=0x07, + ldloc_2=0x08, + ldloc_3=0x09, + stloc_0=0x0a, + stloc_1=0x0b, + stloc_2=0x0c, + stloc_3=0x0d, + ldarg_s=0x0e, + ldarga_s=0x0f, + starg_s=0x10, + ldloc_s=0x11, + ldloca_s=0x12, + stloc_s=0x13, + ldnull=0x14, + ldc_i4_m1=0x15, + ldc_i4_0=0x16, + ldc_i4_1=0x17, + ldc_i4_2=0x18, + ldc_i4_3=0x19, + ldc_i4_4=0x1a, + ldc_i4_5=0x1b, + ldc_i4_6=0x1c, + ldc_i4_7=0x1d, + ldc_i4_8=0x1e, + ldc_i4_s=0x1f, + ldc_i4=0x20, + ldc_i8=0x21, + ldc_r4=0x22, + ldc_r8=0x23, + dup=0x25, + pop=0x26, + jmp=0x27, + call=0x28, + calli=0x29, + ret=0x2a, + br_s=0x2b, + brfalse_s=0x2c, + brtrue_s=0x2d, + beq_s=0x2e, + bge_s=0x2f, + bgt_s=0x30, + ble_s=0x31, + blt_s=0x32, + bne_un_s=0x33, + bge_un_s=0x34, + bgt_un_s=0x35, + ble_un_s=0x36, + blt_un_s=0x37, + br=0x38, + brfalse=0x39, + brtrue=0x3a, + beq=0x3b, + bge=0x3c, + bgt=0x3d, + ble=0x3e, + blt=0x3f, + bne_un=0x40, + bge_un=0x41, + bgt_un=0x42, + ble_un=0x43, + blt_un=0x44, + switch_=0x45, + ldind_i1=0x46, + ldind_u1=0x47, + ldind_i2=0x48, + ldind_u2=0x49, + ldind_i4=0x4a, + ldind_u4=0x4b, + ldind_i8=0x4c, + ldind_i=0x4d, + ldind_r4=0x4e, + ldind_r8=0x4f, + ldind_ref=0x50, + stind_ref=0x51, + stind_i1=0x52, + stind_i2=0x53, + stind_i4=0x54, + stind_i8=0x55, + stind_r4=0x56, + stind_r8=0x57, + add=0x58, + sub=0x59, + mul=0x5a, + div=0x5b, + div_un=0x5c, + rem=0x5d, + rem_un=0x5e, + and=0x5f, + or=0x60, + xor=0x61, + shl=0x62, + shr=0x63, + shr_un=0x64, + neg=0x65, + not=0x66, + conv_i1=0x67, + conv_i2=0x68, + conv_i4=0x69, + conv_i8=0x6a, + conv_r4=0x6b, + conv_r8=0x6c, + conv_u4=0x6d, + conv_u8=0x6e, + callvirt=0x6f, + cpobj=0x70, + ldobj=0x71, + ldstr=0x72, + newobj=0x73, + castclass=0x74, + isinst=0x75, + conv_r_un=0x76, + unbox=0x79, + throw_=0x7a, + ldfld=0x7b, + ldflda=0x7c, + stfld=0x7d, + ldsfld=0x7e, + ldsflda=0x7f, + stsfld=0x80, + stobj=0x81, + conv_ovf_i1_un=0x82, + conv_ovf_i2_un=0x83, + conv_ovf_i4_un=0x84, + conv_ovf_i8_un=0x85, + conv_ovf_u1_un=0x86, + conv_ovf_u2_un=0x87, + conv_ovf_u4_un=0x88, + conv_ovf_u8_un=0x89, + conv_ovf_i_un=0x8a, + conv_ovf_u_un=0x8b, + box=0x8c, + newarr=0x8d, + ldlen=0x8e, + ldelema=0x8f, + ldelem_i1=0x90, + ldelem_u1=0x91, + ldelem_i2=0x92, + ldelem_u2=0x93, + ldelem_i4=0x94, + ldelem_u4=0x95, + ldelem_i8=0x96, + ldelem_i=0x97, + ldelem_r4=0x98, + ldelem_r8=0x99, + ldelem_ref=0x9a, + stelem_i=0x9b, + stelem_i1=0x9c, + stelem_i2=0x9d, + stelem_i4=0x9e, + stelem_i8=0x9f, + stelem_r4=0xa0, + stelem_r8=0xa1, + stelem_ref=0xa2, + ldelem=0xa3, + stelem=0xa4, + unbox_any=0xa5, + conv_ovf_i1=0xb3, + conv_ovf_u1=0xb4, + conv_ovf_i2=0xb5, + conv_ovf_u2=0xb6, + conv_ovf_i4=0xb7, + conv_ovf_u4=0xb8, + conv_ovf_i8=0xb9, + conv_ovf_u8=0xba, + refanyval=0xc2, + ckfinite=0xc3, + mkrefany=0xc6, + ldtoken=0xd0, + conv_u2=0xd1, + conv_u1=0xd2, + conv_i=0xd3, + conv_ovf_i=0xd4, + conv_ovf_u=0xd5, + add_ovf=0xd6, + add_ovf_un=0xd7, + mul_ovf=0xd8, + mul_ovf_un=0xd9, + sub_ovf=0xda, + sub_ovf_un=0xdb, + endfinally=0xdc, + leave=0xdd, + leave_s=0xde, + stind_i=0xdf, + conv_u=0xe0, + prefix1=0xfe, + arglist=0x100, + ceq=0x101, + cgt=0x102, + cgt_un=0x103, + clt=0x104, + clt_un=0x105, + ldftn=0x106, + ldvirtftn=0x107, + ldarg=0x109, + ldarga=0x10a, + starg=0x10b, + ldloc=0x10c, + ldloca=0x10d, + stloc=0x10e, + localloc=0x10f, + endfilter=0x111, + unaligned=0x112, + volatile_=0x113, + tail=0x114, + initobj=0x115, + constrained=0x116, + cpblk=0x117, + initblk=0x118, + no=0x119, + rethrow=0x11a, + sizeof_=0x11c, + refanytype=0x11d, + readonly_=0x11e, + } +} diff --git a/src/TypeSystem/src/IL/ILProvider.cs b/src/TypeSystem/src/IL/ILProvider.cs new file mode 100644 index 00000000000..daa3bc82c4b --- /dev/null +++ b/src/TypeSystem/src/IL/ILProvider.cs @@ -0,0 +1,55 @@ +// 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 System.Collections.Immutable; +using System.Runtime.InteropServices; + +using Internal.TypeSystem; +using Internal.TypeSystem.Ecma; + +using Internal.IL.Stubs; + +namespace Internal.IL +{ + class ILProvider + { + // TODO: Caching + + public ILProvider() + { + } + + public MethodIL GetMethodIL(MethodDesc method) + { + if (method is EcmaMethod) + { + return EcmaMethodIL.Create((EcmaMethod)method); + } + else + if (method is MethodForInstantiatedType) + { + return new InstantiatedMethodIL(GetMethodIL(method.GetTypicalMethodDefinition()), method.OwningType.Instantiation, new Instantiation()); + } + else + if (method is InstantiatedMethod) + { + return new InstantiatedMethodIL(GetMethodIL(method.GetMethodDefinition()), new Instantiation(), method.Instantiation); + } + else + if (method is ILStubMethod) + { + return ((ILStubMethod)method).EmitIL(); + } + else + if (method is ArrayMethod) + { + return new ArrayMethodILEmitter((ArrayMethod)method).EmitIL(); + } + else + { + return null; + } + } + } +} diff --git a/src/TypeSystem/src/IL/InstantiatedMethodIL.cs b/src/TypeSystem/src/IL/InstantiatedMethodIL.cs new file mode 100644 index 00000000000..5d81661acb4 --- /dev/null +++ b/src/TypeSystem/src/IL/InstantiatedMethodIL.cs @@ -0,0 +1,92 @@ +// 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; + +namespace Internal.IL +{ + public sealed class InstantiatedMethodIL : MethodIL + { + MethodIL _methodIL; + Instantiation _typeInstantiation; + Instantiation _methodInstantiation; + + public InstantiatedMethodIL(MethodIL methodIL, Instantiation typeInstantiation, Instantiation methodInstantiation) + { + _methodIL = methodIL; + + _typeInstantiation = typeInstantiation; + _methodInstantiation = methodInstantiation; + } + + public override byte[] GetILBytes() + { + return _methodIL.GetILBytes(); + } + + public override int GetMaxStack() + { + return _methodIL.GetMaxStack(); + } + + public override ILExceptionRegion[] GetExceptionRegions() + { + return _methodIL.GetExceptionRegions(); + } + + public override bool GetInitLocals() + { + return _methodIL.GetInitLocals(); + } + + public override TypeDesc[] GetLocals() + { + TypeDesc[] locals = _methodIL.GetLocals(); + TypeDesc[] clone = null; + + for (int i = 0; i < locals.Length; i++) + { + TypeDesc uninst = locals[i]; + TypeDesc inst = uninst.InstantiateSignature(_typeInstantiation, _methodInstantiation); + if (uninst != inst) + { + if (clone == null) + { + clone = new TypeDesc[locals.Length]; + for (int j = 0; j < clone.Length; j++) + { + clone[j] = locals[j]; + } + } + clone[i] = inst; + } + } + + return (clone == null) ? locals : clone; + } + + public override Object GetObject(int token) + { + Object o = _methodIL.GetObject(token); + + if (o is MethodDesc) + { + o = ((MethodDesc)o).InstantiateSignature(_typeInstantiation, _methodInstantiation); + } + else + if (o is TypeDesc) + { + o = ((TypeDesc)o).InstantiateSignature(_typeInstantiation, _methodInstantiation); + } + else + if (o is FieldDesc) + { + o = ((FieldDesc)o).InstantiateSignature(_typeInstantiation, _methodInstantiation); + } + + return o; + } + } +} diff --git a/src/TypeSystem/src/IL/MethodIL.cs b/src/TypeSystem/src/IL/MethodIL.cs new file mode 100644 index 00000000000..b3e3df771e0 --- /dev/null +++ b/src/TypeSystem/src/IL/MethodIL.cs @@ -0,0 +1,97 @@ +// 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 System.Collections.Immutable; + +using Internal.TypeSystem; + +namespace Internal.IL +{ + // + // This duplicates types from System.Reflection.Metadata to avoid layering issues, and + // because of the System.Reflection.Metadata constructors are not public anyway. + // + + public enum ILExceptionRegionKind + { + Catch = 0, + Filter = 1, + Finally = 2, + Fault = 4, + } + + public struct ILExceptionRegion + { + private readonly ILExceptionRegionKind _kind; + private readonly int _tryOffset; + private readonly int _tryLength; + private readonly int _handlerOffset; + private readonly int _handlerLength; + private readonly int _classToken; + private readonly int _filterOffset; + + public ILExceptionRegion( + ILExceptionRegionKind kind, + int tryOffset, + int tryLength, + int handlerOffset, + int handlerLength, + int classToken, + int filterOffset) + { + _kind = kind; + _tryOffset = tryOffset; + _tryLength = tryLength; + _handlerOffset = handlerOffset; + _handlerLength = handlerLength; + _classToken = classToken; + _filterOffset = filterOffset; + } + + public ILExceptionRegionKind Kind + { + get { return _kind; } + } + + public int TryOffset + { + get { return _tryOffset; } + } + + public int TryLength + { + get { return _tryLength; } + } + + public int HandlerOffset + { + get { return _handlerOffset; } + } + + public int HandlerLength + { + get { return _handlerLength; } + } + + public int ClassToken + { + get { return _classToken; } + } + + public int FilterOffset + { + get { return _filterOffset; } + } + } + + public abstract class MethodIL + { + public abstract byte[] GetILBytes(); + public abstract int GetMaxStack(); + public abstract bool GetInitLocals(); + public abstract TypeDesc[] GetLocals(); + public abstract Object GetObject(int token); + public abstract ILExceptionRegion[] GetExceptionRegions(); + } +} diff --git a/src/TypeSystem/src/IL/Stubs/ArrayMethodILEmitter.cs b/src/TypeSystem/src/IL/Stubs/ArrayMethodILEmitter.cs new file mode 100644 index 00000000000..25c312fcfd4 --- /dev/null +++ b/src/TypeSystem/src/IL/Stubs/ArrayMethodILEmitter.cs @@ -0,0 +1,164 @@ +// 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; + +using Internal.IL; + +namespace Internal.IL.Stubs +{ + internal class ArrayMethodILEmitter : ILEmitter + { + ArrayMethod _method; + TypeDesc _elementType; + TypeDesc _backingType; + int _rank; + + public ArrayMethodILEmitter(ArrayMethod method) + { + _method = method; + + ArrayType arrayType = (ArrayType)method.OwningType; + _rank = arrayType.Rank; + _elementType = arrayType.ElementType; + + var systemModule = ((EcmaType)method.Context.GetWellKnownType(WellKnownType.Object)).Module; + + _backingType = systemModule.GetType("System", "MDArrayRank" + _rank.ToString() + "`1").MakeInstantiatedType( + new Instantiation(new TypeDesc[] { _elementType }) + ); + } + + public MethodIL EmitIL() + { + switch (_method.Kind) + { + case ArrayMethodKind.Get: + EmitILForGet(); + break; + case ArrayMethodKind.Set: + EmitILForSet(); + break; + case ArrayMethodKind.Address: + EmitILForAddress(); + break; + default: + EmitILForCtor(); + break; + } + + return Link(); + } + + void EmitComputeIndex(ILCodeStream codeStream) + { + // Compute index into the backing array + for (int i = 1; i < _rank; i++) + { + FieldDesc upperBoundField = _backingType.GetField("m_upperBound" + _rank); + codeStream.EmitLdArg(0); + codeStream.Emit(ILOpcode.ldfld, NewToken(upperBoundField)); + for (int j = _rank - 1; j > i; j--) + { + upperBoundField = _backingType.GetField("m_upperBound" + j); + codeStream.EmitLdArg(0); + codeStream.Emit(ILOpcode.ldfld, NewToken(upperBoundField)); + codeStream.Emit(ILOpcode.mul); + } + + codeStream.EmitLdArg(i); + codeStream.Emit(ILOpcode.mul); + + if (i != 1) + { + codeStream.Emit(ILOpcode.add); + } + } + + codeStream.EmitLdArg(_rank); + codeStream.Emit(ILOpcode.add); + } + + void EmitILForCtor() + { + var codeStream = NewCodeStream(); + + // TODO: generate IL to check for negative bounds and throw OverflowException + + codeStream.EmitLdArg(0); + + // Compute size of the backing array + codeStream.EmitLdArg(1); + for (int i = 2; i <= _rank; i++) + { + codeStream.EmitLdArg(i); + codeStream.Emit(ILOpcode.mul_ovf); + } + + // Allocate backing array and store it in the private field + codeStream.Emit(ILOpcode.newarr, NewToken(_elementType)); + FieldDesc backingArrayField = _backingType.GetField("m_array"); + codeStream.Emit(ILOpcode.stfld, NewToken(backingArrayField)); + + // Store bounds + for (int i = 1; i <= _rank; i++) + { + FieldDesc upperBoundField = _backingType.GetField("m_upperBound" + i); + + codeStream.EmitLdArg(0); + codeStream.EmitLdArg(i); + codeStream.Emit(ILOpcode.stfld, NewToken(upperBoundField)); + } + + codeStream.Emit(ILOpcode.ret); + } + + MethodIL EmitILForSet() + { + var codeStream = NewCodeStream(); + + // TODO: generate IL to check bounds + + codeStream.EmitLdArg(0); + FieldDesc backingArrayField = _backingType.GetField("m_array"); + codeStream.Emit(ILOpcode.ldfld, NewToken(backingArrayField)); + + EmitComputeIndex(codeStream); + + // Store value at index + codeStream.EmitLdArg(_rank + 1); + codeStream.Emit(ILOpcode.stelem, NewToken(_elementType)); + + codeStream.Emit(ILOpcode.ret); + + return Link(); + } + + void EmitILForGet() + { + var codeStream = NewCodeStream(); + + // TODO: generate IL to check bounds + + codeStream.EmitLdArg(0); + FieldDesc backingArrayField = _backingType.GetField("m_array"); + codeStream.Emit(ILOpcode.ldfld, NewToken(backingArrayField)); + + EmitComputeIndex(codeStream); + + // Load value at index + codeStream.Emit(ILOpcode.ldelem, NewToken(_elementType)); + + codeStream.Emit(ILOpcode.ret); + } + + void EmitILForAddress() + { + // TODO + throw new NotImplementedException(); + } + } +} diff --git a/src/TypeSystem/src/IL/Stubs/DelegateThunks.cs b/src/TypeSystem/src/IL/Stubs/DelegateThunks.cs new file mode 100644 index 00000000000..a0e682409ba --- /dev/null +++ b/src/TypeSystem/src/IL/Stubs/DelegateThunks.cs @@ -0,0 +1,86 @@ +// 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.IL; + +namespace Internal.IL.Stubs +{ + public sealed class DelegateShuffleThunk : ILStubMethod + { + MethodDesc _target; + MethodSignature _signature; + + internal DelegateShuffleThunk(MethodDesc target) + { + _target = target; + } + + public override TypeSystemContext Context + { + get + { + return _target.Context; + } + } + + public override TypeDesc OwningType + { + get + { + return _target.OwningType; + } + } + + public override MethodSignature Signature + { + get + { + if (_signature == null) + { + MethodSignature template = _target.Signature; + MethodSignatureBuilder builder = new MethodSignatureBuilder(template); + + builder.Flags = 0; + + _signature = builder.ToSignature(); + } + + return _signature; + } + } + + public override MethodIL EmitIL() + { + ILEmitter emitter = new ILEmitter(); + + var codeStream = emitter.NewCodeStream(); + for (int i = 0; i < _signature.Length; i++) + { + codeStream.EmitLdArg(i + 1); + } + codeStream.Emit(ILOpcode.call, emitter.NewToken(_target)); + codeStream.Emit(ILOpcode.ret); + + return emitter.Link(); + } + + public override Instantiation Instantiation + { + get + { + return _target.Instantiation; + } + } + + public override string Name + { + get + { + return "__DelegateShuffleThunk__" + _target.Name; + } + } + } +} diff --git a/src/TypeSystem/src/IL/Stubs/ILEmitter.cs b/src/TypeSystem/src/IL/Stubs/ILEmitter.cs new file mode 100644 index 00000000000..31aba99e6f9 --- /dev/null +++ b/src/TypeSystem/src/IL/Stubs/ILEmitter.cs @@ -0,0 +1,224 @@ +// 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 System.Collections.Generic; + +using Internal.IL; +using Internal.TypeSystem; + +namespace Internal.IL.Stubs +{ + public class ILCodeStream + { + static readonly byte[] s_empty = new byte[0]; + + internal byte[] _instructions; + internal int _length; + + internal ILCodeStream() + { + _instructions = s_empty; + } + + private void EmitByte(byte b) + { + if (_instructions.Length == _length) + Array.Resize(ref _instructions, 2 * _instructions.Length + 10); + _instructions[_length++] = b; + } + + private void EmitUInt16(ushort value) + { + EmitByte((byte)value); + EmitByte((byte)(value >> 8)); + } + + private void EmitUInt32(int value) + { + EmitByte((byte)value); + EmitByte((byte)(value >> 8)); + EmitByte((byte)(value >> 16)); + EmitByte((byte)(value >> 24)); + } + + public void Emit(ILOpcode opcode) + { + if ((int)opcode > 0x100) + EmitByte((byte)ILOpcode.prefix1); + EmitByte((byte)opcode); + } + + public void Emit(ILOpcode opcode, int token) + { + Emit(opcode); + EmitUInt32(token); + } + + public void EmitLdArg(int index) + { + if (index < 4) + { + Emit((ILOpcode)(ILOpcode.ldarg_0 + index)); + } + else + { + Emit(ILOpcode.ldarg); + EmitUInt16((ushort)index); + } + } + } + + class ILStubMethodIL : MethodIL + { + byte[] _ilBytes; + TypeDesc[] _locals; + Object[] _tokens; + + public ILStubMethodIL(byte[] ilBytes, TypeDesc[] locals, Object[] tokens) + { + _ilBytes = ilBytes; + _locals = locals; + _tokens = tokens; + } + public override byte[] GetILBytes() + { + return _ilBytes; + } + public override int GetMaxStack() + { + // Conservative estimate... + return _ilBytes.Length; + } + public override ILExceptionRegion[] GetExceptionRegions() + { + return new ILExceptionRegion[0]; // TODO: Array.Empty() + } + public override bool GetInitLocals() + { + return true; + } + public override TypeDesc[] GetLocals() + { + return _locals; + } + public override Object GetObject(int token) + { + return _tokens[(token & 0xFFFFFF) - 1]; + } + } + + struct ListBuilder // struct to avoid unnecessary allocations + { + static readonly T[] s_empty = new T[0]; + + T[] _items; + int _count; + + internal void Initialize() // TODO: Change to default constructor once it is available + { + _items = s_empty; // TODO: Change to Array.GetEmpty() once it is available + _count = 0; + } + + internal T[] ToArray() + { + if (_count != _items.Length) + Array.Resize(ref _items, _count); + return _items; + } + + public void Add(T item) + { + if (_count == _items.Length) + Array.Resize(ref _items, 2 * _count + 1); + _items[_count++] = item; + } + + public int Count + { + get + { + return _count; + } + } + + public T this[int index] + { + get + { + return _items[index]; + } + } + } + + public class ILEmitter + { + ListBuilder _codeStreams; + ListBuilder _locals; + ListBuilder _tokens; + + public ILEmitter() + { + _codeStreams.Initialize(); + _locals.Initialize(); + _tokens.Initialize(); + } + + public ILCodeStream NewCodeStream() + { + ILCodeStream stream = new ILCodeStream(); + _codeStreams.Add(stream); + return stream; + } + + private int NewToken(Object value, int tokenType) + { + _tokens.Add(value); + return _tokens.Count | tokenType; + } + + public int NewToken(TypeDesc value) + { + return NewToken(value, 0x01000000); + } + + public int NewToken(MethodDesc value) + { + return NewToken(value, 0x0a000000); + } + + public int NewToken(FieldDesc value) + { + return NewToken(value, 0x0a000000); + } + + public int NewToken(string value) + { + return NewToken(value, 0x70000000); + } + + public MethodIL Link() + { + int totalLength = 0; + for (int i = 0; i < _codeStreams.Count; i++) + totalLength += _codeStreams[i]._length; + + byte[] ilInstructions = new byte[totalLength]; + int copiedLength = 0; + for (int i = 0; i < _codeStreams.Count; i++) + { + ILCodeStream ilCodeStream = _codeStreams[i]; + Array.Copy(ilCodeStream._instructions, 0, ilInstructions, copiedLength, ilCodeStream._length); + copiedLength += ilCodeStream._length; + } + + return new ILStubMethodIL(ilInstructions, _locals.ToArray(), _tokens.ToArray()); + } + } + + public abstract class ILStubMethod : MethodDesc + { + public abstract MethodIL EmitIL(); + } +}