Merge branch 'master' into r2r

This commit is contained in:
Simon Nattress 2018-09-05 11:57:39 -07:00
Родитель 05abf70454 4af59530ed
Коммит 8ca402c5a3
196 изменённых файлов: 4652 добавлений и 1881 удалений

Просмотреть файл

@ -37,6 +37,7 @@ This is Windows only for now.
# Useful tips #
* To manually make ILC compile to WebAssembly, add ```--wasm``` to the command line.
* To debug C# source, add ```-g4``` to the emcc command line and change ```-s WASM=1``` to ```-s WASM=0```. This will generate a JavaScript source map that browser debuggers and Visual Studio Code can work with. Using Visual Studio Code's Chrome debugger works particularly well.
* Add ```-g3``` to the emcc command line to generate more debuggable output and a .wast file with the text form of the WebAssembly.
* Omit ```-s WASM=1``` from the emcc command line to generate asm.js. Browser debuggers currently work better with asm.js and it's often a bit more readable than wast.
* Change ```-s WASM=1``` to ```-s WASM=0``` in the emcc command line to generate asm.js. Browser debuggers currently work better with asm.js and it's often a bit more readable than wast.
* Add ```-O2 --llvm-lto 2``` to the emcc command line to enable optimizations. This makes the generated WebAssembly as much as 75% smaller as well as more efficient.

Просмотреть файл

@ -44,7 +44,7 @@ Choose the set of tests you want to run. Currently the options are:
* Top200
* Small set of the suite selected to provide broad coverage quickly (Under 10 minutes). These run as part of the CI when submitting a pull request.
* KnownGood
* Subset of the suite previously validated to all pass on CoreRT. If these all pass you can be pretty sure you haven't regressed the compiler.
* Subset of the suite previously validated to all pass on CoreRT. If these all pass you can be pretty sure you haven't regressed the compiler. We currently only have a KnownGood list on Windows.
* All
* The entire suite. Many of the tests will fail since CoreRT is still pre-release and some tests don't play well with an ahead-of-time compiler.

Просмотреть файл

@ -1,10 +1,10 @@
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<RyuJITVersion>3.0.0-preview1-26802-02</RyuJITVersion>
<RyuJITVersion>3.0.0-preview1-26831-01</RyuJITVersion>
<ObjectWriterVersion>1.0.0-alpha-26412-0</ObjectWriterVersion>
<CoreFxVersion>4.6.0-preview1-26625-01</CoreFxVersion>
<CoreFxUapVersion>4.7.0-preview1-26625-01</CoreFxUapVersion>
<MicrosoftNETCoreNativeVersion>3.0.0-preview1-26702-01</MicrosoftNETCoreNativeVersion>
<CoreFxVersion>4.6.0-preview1-26831-01</CoreFxVersion>
<CoreFxUapVersion>4.7.0-preview1-26831-01</CoreFxUapVersion>
<MicrosoftNETCoreNativeVersion>3.0.0-preview1-26831-01</MicrosoftNETCoreNativeVersion>
<MicrosoftNETCoreAppPackageVersion>2.1.0</MicrosoftNETCoreAppPackageVersion>
<XunitNetcoreExtensionsVersion>1.0.1-prerelease-02104-02</XunitNetcoreExtensionsVersion>
</PropertyGroup>

Просмотреть файл

@ -85,8 +85,8 @@
<ItemGroup>
<PackageReference Include="Microsoft.DotNet.ILCompiler" Version="1.0.0-alpha-*" />
<PackageReference Include="MonoGame.Content.Builder" Version="3.7.0.1" />
<PackageReference Include="MonoGame.Framework.DesktopGL.Core" Version="3.7.0.3" />
<PackageReference Include="MonoGame.Content.Builder" Version="3.7.0.9" />
<PackageReference Include="MonoGame.Framework.DesktopGL.Core" Version="3.7.0.7" />
</ItemGroup>
</Project>

Просмотреть файл

@ -64,8 +64,8 @@
<ItemGroup>
<PackageReference Include="Microsoft.DotNet.ILCompiler" Version="1.0.0-alpha-*" />
<PackageReference Include="MonoGame.Content.Builder" Version="3.7.0.1" />
<PackageReference Include="MonoGame.Framework.DesktopGL.Core" Version="3.7.0.3" />
<PackageReference Include="MonoGame.Content.Builder" Version="3.7.0.9" />
<PackageReference Include="MonoGame.Framework.DesktopGL.Core" Version="3.7.0.7" />
</ItemGroup>
</Project>

Просмотреть файл

@ -81,6 +81,7 @@ See the LICENSE file in the project root for more information.
<LinkerArg Include="@(NativeLibrary)" />
<LinkerArg Include="-g" />
<LinkerArg Include="-Wl,-rpath,'$ORIGIN'" />
<LinkerArg Include="-Wl,--as-needed" Condition="'$(TargetOS)' != 'OSX'" />
<LinkerArg Include="-pthread" />
<LinkerArg Include="-lstdc++" />
<LinkerArg Include="-ldl" />

Просмотреть файл

@ -84,11 +84,21 @@ See the LICENSE file in the project root for more information.
<ItemGroup>
<AutoInitializedAssemblies Include="System.Private.CoreLib" />
<AutoInitializedAssemblies Include="System.Private.DeveloperExperience.Console" />
<AutoInitializedAssemblies Include="System.Private.StackTraceMetadata" />
</ItemGroup>
<ItemGroup Condition="'$(ExperimentalInterpreterSupport)' != 'true'">
<AutoInitializedAssemblies Include="System.Private.TypeLoader" />
<AutoInitializedAssemblies Include="System.Private.Reflection.Execution" />
<AutoInitializedAssemblies Include="System.Private.DeveloperExperience.Console" />
<AutoInitializedAssemblies Include="System.Private.Interop" />
<AutoInitializedAssemblies Include="System.Private.StackTraceMetadata" />
</ItemGroup>
<ItemGroup Condition="'$(ExperimentalInterpreterSupport)' == 'true'">
<AutoInitializedAssemblies Include="System.Private.Interpreter" />
<AutoInitializedAssemblies Include="System.Private.TypeLoader.Experimental" />
<AutoInitializedAssemblies Include="System.Private.Reflection.Execution.Experimental" />
<AutoInitializedAssemblies Include="System.Private.Interop.Experimental" />
</ItemGroup>
<ItemGroup>
@ -174,6 +184,7 @@ See the LICENSE file in the project root for more information.
<IlcArg Condition="$(OutputType) == 'Library' and $(NativeLib) != ''" Include="--nativelib" />
<IlcArg Condition="$(ExportsFile) != ''" Include="--exportsfile:$(ExportsFile)" />
<ILcArg Condition="'$(Platform)' == 'wasm'" Include="--wasm" />
<ILcArg Condition="'$(ExperimentalInterpreterSupport)' == 'true'" Include="--nometadatablocking" />
<IlcArg Include="@(AutoInitializedAssemblies->'--initassembly:%(Identity)')" />
<IlcArg Include="@(AppContextSwitchOverrides->'--appcontextswitch:%(Identity)')" />
<IlcArg Condition="$(ServerGarbageCollection) != ''" Include="--runtimeopt:RH_UseServerGC=1" />

Просмотреть файл

@ -644,7 +644,7 @@ class SchemaDef
new MemberDef("Flags", "GenericParameterAttributes"),
new MemberDef("Kind", "GenericParameterKind"),
new MemberDef("Name", "ConstantStringValue", MemberDefFlags.RecordRef | MemberDefFlags.Child),
new MemberDef("Constraints", TypeDefOrRefOrSpec, MemberDefFlags.List | MemberDefFlags.RecordRef | MemberDefFlags.EnumerateForHashCode),
new MemberDef("Constraints", TypeDefOrRefOrSpecOrMod, MemberDefFlags.List | MemberDefFlags.RecordRef | MemberDefFlags.EnumerateForHashCode),
new MemberDef("CustomAttributes", "CustomAttribute", MemberDefFlags.List | MemberDefFlags.RecordRef | MemberDefFlags.Child),
}
),

Просмотреть файл

@ -4314,7 +4314,7 @@ namespace Internal.Metadata.NativeFormat
} // Name
internal ConstantStringValueHandle _name;
/// One of: TypeDefinition, TypeReference, TypeSpecification
/// One of: TypeDefinition, TypeReference, TypeSpecification, ModifiedType
public HandleCollection Constraints
{

Просмотреть файл

@ -0,0 +1,15 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Runtime.InteropServices;
internal static partial class Interop
{
internal unsafe partial class Sys
{
[DllImport(Interop.Libraries.CoreLibNative, EntryPoint = "CoreLibNative_GetEnviron")]
internal static extern unsafe IntPtr GetEnviron();
}
}

Просмотреть файл

@ -0,0 +1,161 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
/*============================================================
**
**
** Private version of Stack<T> for internal System.Private.CoreLib use. This
** permits sharing more source between BCL and System.Private.CoreLib (as well as the
** fact that Stack<T> is just a useful class in general.)
**
** This does not strive to implement the full api surface area
** (but any portion it does implement should match the real Stack<T>'s
** behavior.)
**
===========================================================*/
namespace System.Collections.Generic
{
// Implements a variable-size Stack that uses an array of objects to store the
// elements. A Stack has a capacity, which is the allocated length
// of the internal array. As elements are added to a Stack, the capacity
// of the Stack is automatically increased as required by reallocating the
// internal array.
//
/// <summary>
/// LowLevelStack with no interface implementation to minimize both code and data size
/// Data size is smaller because there will be minimal virtual function table.
/// Code size is smaller because only functions called will be in the binary.
/// </summary>
internal class LowLevelStack<T>
{
protected T[] _items;
protected int _size;
protected int _version;
private static readonly T[] s_emptyArray = new T[0];
public LowLevelStack()
{
_items = s_emptyArray;
}
public LowLevelStack(int capacity)
{
if (capacity < 0)
throw new ArgumentOutOfRangeException(nameof(capacity));
if (capacity == 0)
_items = s_emptyArray;
else
{
_size = capacity;
_items = new T[capacity];
}
}
public LowLevelStack(IEnumerable<T> collection)
{
if (collection == null)
throw new ArgumentNullException(nameof(collection));
ICollection<T> c = collection as ICollection<T>;
if (c != null)
{
int count = c.Count;
if (count == 0)
{
_items = s_emptyArray;
}
else
{
_items = new T[count];
c.CopyTo(_items, 0);
_size = count;
}
}
else
{
_size = 0;
_items = s_emptyArray;
using (IEnumerator<T> en = collection.GetEnumerator())
{
while (en.MoveNext())
{
Push(en.Current);
}
}
}
}
public int Count
{
get
{
return _items.Length;
}
}
public void Push(T item)
{
_size = _size + 1;
Array.Resize(ref _items, _size);
_items[_size - 1] = item;
_version++;
}
public T Pop()
{
ThrowIfEmptyStack();
_size = _size - 1;
T item = _items[_size];
Array.Resize(ref _items, _size);
_version++;
return item;
}
public bool TryPop(out T result)
{
if (_size == 0)
{
result = default;
return false;
}
_size = _size - 1;
result = _items[_size];
Array.Resize(ref _items, _size);
_version++;
return true;
}
public T Peek()
{
ThrowIfEmptyStack();
return _items[_size - 1];
}
public bool TryPeek(out T result)
{
if (_size == 0)
{
result = default;
return false;
}
result = _items[_size - 1];
_version++;
return true;
}
private void ThrowIfEmptyStack()
{
if (_size == 0)
throw new InvalidOperationException();
}
}
}

Просмотреть файл

@ -55,7 +55,8 @@ namespace Internal.TypeSystem
{
public StaticsBlock NonGcStatics;
public StaticsBlock GcStatics;
public StaticsBlock ThreadStatics;
public StaticsBlock ThreadNonGcStatics;
public StaticsBlock ThreadGcStatics;
}
ThreadSafeFlags _fieldLayoutFlags;
@ -217,10 +218,10 @@ namespace Internal.TypeSystem
}
/// <summary>
/// How many bytes must be allocated to represent the (potentially GC visible) thread static
/// fields of this type.
/// How many bytes must be allocated to represent the non GC visible thread static fields
/// of this type.
/// </summary>
public LayoutInt ThreadStaticFieldSize
public LayoutInt ThreadNonGcStaticFieldSize
{
get
{
@ -228,7 +229,39 @@ namespace Internal.TypeSystem
{
ComputeStaticFieldLayout(StaticLayoutKind.StaticRegionSizes);
}
return _staticBlockInfo == null ? LayoutInt.Zero : _staticBlockInfo.ThreadStatics.Size;
return _staticBlockInfo == null ? LayoutInt.Zero : _staticBlockInfo.ThreadNonGcStatics.Size;
}
}
/// <summary>
/// What is the alignment required for allocating the non GC visible thread static fields
/// of this type.
/// </summary>
public LayoutInt ThreadNonGcStaticFieldAlignment
{
get
{
if (!_fieldLayoutFlags.HasFlags(FieldLayoutFlags.ComputedStaticRegionLayout))
{
ComputeStaticFieldLayout(StaticLayoutKind.StaticRegionSizes);
}
return _staticBlockInfo == null ? LayoutInt.Zero : _staticBlockInfo.ThreadNonGcStatics.LargestAlignment;
}
}
/// <summary>
/// How many bytes must be allocated to represent the (potentially GC visible) thread static
/// fields of this type.
/// </summary>
public LayoutInt ThreadGcStaticFieldSize
{
get
{
if (!_fieldLayoutFlags.HasFlags(FieldLayoutFlags.ComputedStaticRegionLayout))
{
ComputeStaticFieldLayout(StaticLayoutKind.StaticRegionSizes);
}
return _staticBlockInfo == null ? LayoutInt.Zero : _staticBlockInfo.ThreadGcStatics.Size;
}
}
@ -236,7 +269,7 @@ namespace Internal.TypeSystem
/// What is the alignment required for allocating the (potentially GC visible) thread static
/// fields of this type.
/// </summary>
public LayoutInt ThreadStaticFieldAlignment
public LayoutInt ThreadGcStaticFieldAlignment
{
get
{
@ -244,7 +277,7 @@ namespace Internal.TypeSystem
{
ComputeStaticFieldLayout(StaticLayoutKind.StaticRegionSizes);
}
return _staticBlockInfo == null ? LayoutInt.Zero : _staticBlockInfo.ThreadStatics.LargestAlignment;
return _staticBlockInfo == null ? LayoutInt.Zero : _staticBlockInfo.ThreadGcStatics.LargestAlignment;
}
}
@ -328,13 +361,15 @@ namespace Internal.TypeSystem
if ((computedStaticLayout.NonGcStatics.Size != LayoutInt.Zero) ||
(computedStaticLayout.GcStatics.Size != LayoutInt.Zero) ||
(computedStaticLayout.ThreadStatics.Size != LayoutInt.Zero))
(computedStaticLayout.ThreadNonGcStatics.Size != LayoutInt.Zero) ||
(computedStaticLayout.ThreadGcStatics.Size != LayoutInt.Zero))
{
var staticBlockInfo = new StaticBlockInfo
{
NonGcStatics = computedStaticLayout.NonGcStatics,
GcStatics = computedStaticLayout.GcStatics,
ThreadStatics = computedStaticLayout.ThreadStatics
ThreadNonGcStatics = computedStaticLayout.ThreadNonGcStatics,
ThreadGcStatics = computedStaticLayout.ThreadGcStatics
};
_staticBlockInfo = staticBlockInfo;
}

Просмотреть файл

@ -33,16 +33,13 @@ namespace Internal.TypeSystem
}
/// <summary>
/// For static fields, represents whether or not the field is held in the GC or non GC statics region
/// Does not apply to thread static fields.
/// For static fields, represents whether or not the field is held in the GC or non GC statics region.
/// </summary>
public bool HasGCStaticBase
{
get
{
// If this assert fires then make sure the caller checks the IsThreadStatic attribute
// of FieldDesc before checking its HasGCStaticBase property.
Debug.Assert(IsStatic && !IsThreadStatic);
Debug.Assert(IsStatic);
return Context.ComputeHasGCStaticBase(this);
}
}

Просмотреть файл

@ -101,7 +101,8 @@ namespace Internal.TypeSystem
{
public StaticsBlock NonGcStatics;
public StaticsBlock GcStatics;
public StaticsBlock ThreadStatics;
public StaticsBlock ThreadNonGcStatics;
public StaticsBlock ThreadGcStatics;
/// <summary>
/// If Offsets is non-null, then all field based layout is complete.

Просмотреть файл

@ -185,7 +185,8 @@ namespace Internal.TypeSystem
ComputedStaticFieldLayout result;
result.GcStatics = new StaticsBlock();
result.NonGcStatics = new StaticsBlock();
result.ThreadStatics = new StaticsBlock();
result.ThreadGcStatics = new StaticsBlock();
result.ThreadNonGcStatics = new StaticsBlock();
if (numStaticFields == 0)
{
@ -231,7 +232,12 @@ namespace Internal.TypeSystem
private ref StaticsBlock GetStaticsBlockForField(ref ComputedStaticFieldLayout layout, FieldDesc field)
{
if (field.IsThreadStatic)
return ref layout.ThreadStatics;
{
if (field.HasGCStaticBase)
return ref layout.ThreadGcStatics;
else
return ref layout.ThreadNonGcStatics;
}
else if (field.HasGCStaticBase)
return ref layout.GcStatics;
else

Просмотреть файл

@ -133,7 +133,32 @@ namespace Internal.TypeSystem
return TypeHashingAlgorithms.ComputeMethodSignatureHashCode(_returnType.GetHashCode(), _parameters);
}
public SignatureEnumerator GetEnumerator()
{
return new SignatureEnumerator(this);
}
public override TypeSystemContext Context => _returnType.Context;
public struct SignatureEnumerator
{
private int _index;
private MethodSignature _signature;
public SignatureEnumerator(MethodSignature signature)
{
_signature = signature;
_index = -1;
}
public TypeDesc Current => _signature[_index];
public bool MoveNext()
{
_index++;
return _index < _signature.Length;
}
}
}
/// <summary>

Просмотреть файл

@ -45,7 +45,8 @@ namespace Internal.TypeSystem
{
NonGcStatics = new StaticsBlock() { Size = LayoutInt.Zero, LargestAlignment = LayoutInt.Zero },
GcStatics = new StaticsBlock() { Size = LayoutInt.Zero, LargestAlignment = LayoutInt.Zero },
ThreadStatics = new StaticsBlock() { Size = LayoutInt.Zero, LargestAlignment = LayoutInt.Zero },
ThreadNonGcStatics = new StaticsBlock() { Size = LayoutInt.Zero, LargestAlignment = LayoutInt.Zero },
ThreadGcStatics = new StaticsBlock() { Size = LayoutInt.Zero, LargestAlignment = LayoutInt.Zero },
Offsets = Array.Empty<FieldAndOffset>()
};
}

Просмотреть файл

@ -61,11 +61,11 @@ namespace Internal.TypeSystem
/// </summary>
public static GCPointerMap FromThreadStaticLayout(DefType type)
{
GCPointerMapBuilder builder = new GCPointerMapBuilder(type.ThreadStaticFieldSize.AsInt, type.Context.Target.PointerSize);
GCPointerMapBuilder builder = new GCPointerMapBuilder(type.ThreadGcStaticFieldSize.AsInt, type.Context.Target.PointerSize);
foreach (FieldDesc field in type.GetFields())
{
if (!field.IsStatic || field.HasRva || field.IsLiteral || !field.IsThreadStatic)
if (!field.IsStatic || field.HasRva || field.IsLiteral || !field.IsThreadStatic || !field.HasGCStaticBase)
continue;
TypeDesc fieldType = field.FieldType;
@ -85,7 +85,7 @@ namespace Internal.TypeSystem
}
}
Debug.Assert(builder.ToGCMap().Size * type.Context.Target.PointerSize >= type.ThreadStaticFieldSize.AsInt);
Debug.Assert(builder.ToGCMap().Size * type.Context.Target.PointerSize >= type.ThreadGcStaticFieldSize.AsInt);
return builder.ToGCMap();
}

Просмотреть файл

@ -212,7 +212,7 @@ namespace Internal.IL
TypeSystemContext context = elementType.Context;
MetadataType helperType = context.SystemModule.GetKnownType("Internal.IntrinsicSupport", "EqualityComparerHelpers");
MethodDesc methodToCall = null;
MethodDesc methodToCall;
if (elementType.IsEnum)
{
methodToCall = helperType.GetKnownMethod("EnumOnlyEquals", null).MakeInstantiatedMethod(elementType);
@ -225,9 +225,11 @@ namespace Internal.IL
{
methodToCall = helperType.GetKnownMethod("StructOnlyEqualsIEquatable", null).MakeInstantiatedMethod(elementType);
}
if (methodToCall != null)
else
{
methodToCall = helperType.GetKnownMethod("StructOnlyNormalEquals", null).MakeInstantiatedMethod(elementType);
}
return new ILStubMethodIL(method, new byte[]
{
(byte)ILOpcode.ldarg_0,
@ -239,7 +241,6 @@ namespace Internal.IL
}
}
}
}
break;
}

Просмотреть файл

@ -30,12 +30,9 @@ namespace Internal.IL.Stubs
if (result != 0)
return result;
if (thisReturnType == DynamicInvokeMethodParameterKind.Pointer)
{
result = _targetSignature.GetNumerOfReturnTypePointerIndirections() - otherMethod._targetSignature.GetNumerOfReturnTypePointerIndirections();
if (result != 0)
return result;
}
for (int i = 0; i < _targetSignature.Length; i++)
{
@ -44,13 +41,10 @@ namespace Internal.IL.Stubs
if (result != 0)
return result;
if (thisParamType == DynamicInvokeMethodParameterKind.Pointer)
{
result = _targetSignature.GetNumberOfParameterPointerIndirections(i) - otherMethod._targetSignature.GetNumberOfParameterPointerIndirections(i);
if (result != 0)
return result;
}
}
Debug.Assert(this == otherMethod);
return 0;

Просмотреть файл

@ -37,41 +37,37 @@ namespace Internal.IL.Stubs
return context.SystemModule.GetType("System", "InvokeUtils", false) != null;
}
private static TypeDesc UnwrapByRef(TypeDesc type)
{
if (type.IsByRef)
return ((ByRefType)type).ParameterType;
return type;
}
public static bool SupportsSignature(MethodSignature signature)
{
for (int i = 0; i < signature.Length; i++)
if (signature[i].IsByRef && ((ByRefType)signature[i]).ParameterType.IsPointer)
return false;
// ----------------------------------------------------------------
// TODO: function pointer types are odd: https://github.com/dotnet/corert/issues/1929
// ----------------------------------------------------------------
if (signature.ReturnType.IsFunctionPointer)
if (UnwrapByRef(signature.ReturnType).IsFunctionPointer)
return false;
for (int i = 0; i < signature.Length; i++)
if (signature[i].IsFunctionPointer)
return false;
// ----------------------------------------------------------------
// Methods with ByRef returns can't be reflection invoked
// ----------------------------------------------------------------
if (signature.ReturnType.IsByRef)
if (UnwrapByRef(signature[i]).IsFunctionPointer)
return false;
// ----------------------------------------------------------------
// Methods that return ByRef-like types or take them by reference can't be reflection invoked
// ----------------------------------------------------------------
if (!signature.ReturnType.IsSignatureVariable && signature.ReturnType.IsByRefLike)
if (!signature.ReturnType.IsSignatureVariable && UnwrapByRef(signature.ReturnType).IsByRefLike)
return false;
for (int i = 0; i < signature.Length; i++)
{
ByRefType paramType = signature[i] as ByRefType;
if (paramType != null && !paramType.ParameterType.IsSignatureVariable && paramType.ParameterType.IsByRefLike)
if (paramType != null && !paramType.ParameterType.IsSignatureVariable && UnwrapByRef(paramType.ParameterType).IsByRefLike)
return false;
}
@ -93,7 +89,10 @@ namespace Internal.IL.Stubs
// strip ByRefType off the parameter (the method already has ByRef in the signature)
parameterType = ((ByRefType)parameterType).ParameterType;
Debug.Assert(!parameterType.IsPointer); // TODO: support for methods returning pointer types - https://github.com/dotnet/corert/issues/2113
// Strip off all the pointers. Pointers are not valid instantiation arguments and the thunk compensates for that
// by being specialized for the specific pointer depth.
while (parameterType.IsPointer)
parameterType = ((PointerType)parameterType).ParameterType;
}
else if (parameterType.IsPointer)
{
@ -131,7 +130,10 @@ namespace Internal.IL.Stubs
if (!sig.ReturnType.IsVoid)
{
TypeDesc returnType = sig.ReturnType;
Debug.Assert(!returnType.IsByRef);
// strip ByRefType off the return type (the method already has ByRef in the signature)
if (returnType.IsByRef)
returnType = ((ByRefType)returnType).ParameterType;
// If the invoke method return an object reference, we don't need to specialize on the
// exact type of the object reference, as the behavior is not different.
@ -250,10 +252,13 @@ namespace Internal.IL.Stubs
break;
case DynamicInvokeMethodParameterKind.Pointer:
sb.Append('P');
for (int i = 0; i < _targetSignature.GetNumerOfReturnTypePointerIndirections() - 1; i++)
sb.Append('p');
break;
case DynamicInvokeMethodParameterKind.Reference:
sb.Append("R");
for (int i = 0; i < _targetSignature.GetNumerOfReturnTypePointerIndirections(); i++)
sb.Append('p');
break;
case DynamicInvokeMethodParameterKind.Value:
sb.Append('O');
@ -276,6 +281,9 @@ namespace Internal.IL.Stubs
break;
case DynamicInvokeMethodParameterKind.Reference:
sb.Append("R");
for (int j = 0; j < _targetSignature.GetNumberOfParameterPointerIndirections(i); j++)
sb.Append('p');
break;
case DynamicInvokeMethodParameterKind.Value:
sb.Append("I");
@ -296,6 +304,7 @@ namespace Internal.IL.Stubs
ILCodeStream argSetupStream = emitter.NewCodeStream();
ILCodeStream thisCallSiteSetupStream = emitter.NewCodeStream();
ILCodeStream staticCallSiteSetupStream = emitter.NewCodeStream();
ILCodeStream returnCodeStream = emitter.NewCodeStream();
// This function will look like
//
@ -328,13 +337,7 @@ namespace Internal.IL.Stubs
// ldloc localX
// ldarg.1
// calli ReturnType thiscall(TypeOfParameter1, ...)
// !if ((ReturnType == void)
// ldnull
// !elif (ReturnType is pointer)
// System.Reflection.Pointer.Box(ReturnType)
// !else
// box ReturnType
// ret
// br Process_return
// *** Static call instruction stream starts here ***
@ -347,6 +350,14 @@ namespace Internal.IL.Stubs
// ldloc localX
// ldarg.1
// calli ReturnType (TypeOfParameter1, ...)
// *** Return code stream starts here ***
// Process_return:
// !if (ReturnType is Byref)
// dup
// brfalse ByRefNull
// ldobj ReturnType
// !if ((ReturnType == void)
// ldnull
// !elif (ReturnType is pointer)
@ -354,8 +365,15 @@ namespace Internal.IL.Stubs
// !else
// box ReturnType
// ret
//
// !if (ReturnType is ByRef)
// ByRefNull:
// pop
// call InvokeUtils.get_NullByRefValueSentinel
// ret
ILCodeLabel lStaticCall = emitter.NewCodeLabel();
ILCodeLabel lProcessReturn = emitter.NewCodeLabel();
thisCallSiteSetupStream.EmitLdArg(3); // targetIsThisCall
thisCallSiteSetupStream.Emit(ILOpcode.brfalse, lStaticCall);
staticCallSiteSetupStream.EmitLabel(lStaticCall);
@ -374,7 +392,6 @@ namespace Internal.IL.Stubs
TypeDesc paramType = Context.GetSignatureVariable(paramIndex, true);
DynamicInvokeMethodParameterKind paramKind = _targetSignature[paramIndex];
if (paramKind == DynamicInvokeMethodParameterKind.Pointer)
for (int i = 0; i < _targetSignature.GetNumberOfParameterPointerIndirections(paramIndex); i++)
paramType = paramType.MakePointerType();
@ -415,45 +432,69 @@ namespace Internal.IL.Stubs
Context.GetSignatureVariable(_targetSignature.Length, true) :
Context.GetWellKnownType(WellKnownType.Void);
if (returnKind == DynamicInvokeMethodParameterKind.Pointer)
for (int i = 0; i < _targetSignature.GetNumerOfReturnTypePointerIndirections(); i++)
returnType = returnType.MakePointerType();
if (returnKind == DynamicInvokeMethodParameterKind.Reference)
returnType = returnType.MakeByRefType();
MethodSignature thisCallMethodSig = new MethodSignature(0, 0, returnType, targetMethodSignature);
thisCallSiteSetupStream.Emit(ILOpcode.calli, emitter.NewToken(thisCallMethodSig));
thisCallSiteSetupStream.Emit(ILOpcode.br, lProcessReturn);
MethodSignature staticCallMethodSig = new MethodSignature(MethodSignatureFlags.Static, 0, returnType, targetMethodSignature);
staticCallSiteSetupStream.Emit(ILOpcode.calli, emitter.NewToken(staticCallMethodSig));
returnCodeStream.EmitLabel(lProcessReturn);
ILCodeLabel lByRefReturnNull = null;
if (returnKind == DynamicInvokeMethodParameterKind.None)
{
thisCallSiteSetupStream.Emit(ILOpcode.ldnull);
staticCallSiteSetupStream.Emit(ILOpcode.ldnull);
}
else if (returnKind == DynamicInvokeMethodParameterKind.Pointer)
{
thisCallSiteSetupStream.Emit(ILOpcode.ldtoken, emitter.NewToken(returnType));
staticCallSiteSetupStream.Emit(ILOpcode.ldtoken, emitter.NewToken(returnType));
MethodDesc getTypeFromHandleMethod =
Context.SystemModule.GetKnownType("System", "Type").GetKnownMethod("GetTypeFromHandle", null);
thisCallSiteSetupStream.Emit(ILOpcode.call, emitter.NewToken(getTypeFromHandleMethod));
staticCallSiteSetupStream.Emit(ILOpcode.call, emitter.NewToken(getTypeFromHandleMethod));
MethodDesc pointerBoxMethod =
Context.SystemModule.GetKnownType("System.Reflection", "Pointer").GetKnownMethod("Box", null);
thisCallSiteSetupStream.Emit(ILOpcode.call, emitter.NewToken(pointerBoxMethod));
staticCallSiteSetupStream.Emit(ILOpcode.call, emitter.NewToken(pointerBoxMethod));
returnCodeStream.Emit(ILOpcode.ldnull);
}
else
{
Debug.Assert(returnKind == DynamicInvokeMethodParameterKind.Value);
ILToken tokReturnType = emitter.NewToken(returnType);
thisCallSiteSetupStream.Emit(ILOpcode.box, tokReturnType);
staticCallSiteSetupStream.Emit(ILOpcode.box, tokReturnType);
TypeDesc returnTypeForBoxing = returnType;
if (returnType.IsByRef)
{
// If this is a byref return, we need to dereference first
returnTypeForBoxing = ((ByRefType)returnType).ParameterType;
lByRefReturnNull = emitter.NewCodeLabel();
returnCodeStream.Emit(ILOpcode.dup);
returnCodeStream.Emit(ILOpcode.brfalse, lByRefReturnNull);
returnCodeStream.Emit(ILOpcode.ldobj, emitter.NewToken(returnTypeForBoxing));
}
thisCallSiteSetupStream.Emit(ILOpcode.ret);
staticCallSiteSetupStream.Emit(ILOpcode.ret);
if (returnTypeForBoxing.IsPointer)
{
// Pointers box differently
returnCodeStream.Emit(ILOpcode.ldtoken, emitter.NewToken(returnTypeForBoxing));
MethodDesc getTypeFromHandleMethod =
Context.SystemModule.GetKnownType("System", "Type").GetKnownMethod("GetTypeFromHandle", null);
returnCodeStream.Emit(ILOpcode.call, emitter.NewToken(getTypeFromHandleMethod));
MethodDesc pointerBoxMethod =
Context.SystemModule.GetKnownType("System.Reflection", "Pointer").GetKnownMethod("Box", null);
returnCodeStream.Emit(ILOpcode.call, emitter.NewToken(pointerBoxMethod));
}
else
{
ILToken tokReturnType = emitter.NewToken(returnTypeForBoxing);
returnCodeStream.Emit(ILOpcode.box, tokReturnType);
}
}
returnCodeStream.Emit(ILOpcode.ret);
if (lByRefReturnNull != null)
{
returnCodeStream.EmitLabel(lByRefReturnNull);
returnCodeStream.Emit(ILOpcode.pop);
returnCodeStream.Emit(ILOpcode.call, emitter.NewToken(InvokeUtilsType.GetKnownMethod("get_NullByRefValueSentinel", null)));
returnCodeStream.Emit(ILOpcode.ret);
}
return emitter.Link(this);
}
@ -541,6 +582,10 @@ namespace Internal.IL.Stubs
public static int GetNumberOfIndirections(TypeDesc type)
{
// Strip byrefness off. This is to support "ref void**"-style signatures.
if (type.IsByRef)
type = ((ByRefType)type).ParameterType;
int result = 0;
while (type.IsPointer)
{
@ -565,13 +610,13 @@ namespace Internal.IL.Stubs
{
get
{
Debug.Assert(!_signature.ReturnType.IsByRef);
TypeDesc type = _signature.ReturnType;
if (type.IsPointer)
return DynamicInvokeMethodParameterKind.Pointer;
else if (type.IsVoid)
return DynamicInvokeMethodParameterKind.None;
else if (type.IsByRef)
return DynamicInvokeMethodParameterKind.Reference;
else
return DynamicInvokeMethodParameterKind.Value;
}
@ -607,8 +652,7 @@ namespace Internal.IL.Stubs
if (thisReturnKind != other.ReturnType)
return false;
if (thisReturnKind == DynamicInvokeMethodParameterKind.Pointer &&
GetNumerOfReturnTypePointerIndirections() != other.GetNumerOfReturnTypePointerIndirections())
if (GetNumerOfReturnTypePointerIndirections() != other.GetNumerOfReturnTypePointerIndirections())
return false;
if (Length != other.Length)
@ -620,8 +664,7 @@ namespace Internal.IL.Stubs
if (thisParamKind != other[i])
return false;
if (thisParamKind == DynamicInvokeMethodParameterKind.Pointer &&
GetNumberOfParameterPointerIndirections(i) != other.GetNumberOfParameterPointerIndirections(i))
if (GetNumberOfParameterPointerIndirections(i) != other.GetNumberOfParameterPointerIndirections(i))
return false;
}

Просмотреть файл

@ -253,6 +253,8 @@ namespace Internal.IL.Stubs
break;
case TypeFlags.ValueType:
case TypeFlags.Nullable:
case TypeFlags.SignatureMethodVariable:
case TypeFlags.SignatureTypeVariable:
Emit(ILOpcode.ldobj, _emitter.NewToken(type));
break;
default:

Просмотреть файл

@ -502,7 +502,7 @@ namespace Internal.TypeSystem.NativeFormat
AssemblyBindResult bindResult;
RuntimeAssemblyName assemblyName = AssemblyNameParser.Parse(assemblyNameString);
Exception failureException;
if (!AssemblyBinderImplementation.Instance.Bind(assemblyName, out bindResult, out failureException))
if (!AssemblyBinderImplementation.Instance.Bind(assemblyName, cacheMissedLookups: true, out bindResult, out failureException))
{
throw failureException;
}

Просмотреть файл

@ -46,6 +46,11 @@
<FileToExclude Include="System.Data.Common" />
<FileToExclude Include="System.Diagnostics.StackTrace" />
<!-- TODO: WinRT -->
<FileToExclude Include="System.Runtime.InteropServices.WindowsRuntime" />
<FileToExclude Include="System.Runtime.WindowsRuntime" />
<FileToExclude Include="System.Runtime.WindowsRuntime.UI.Xaml" />
<!-- TODO: https://github.com/dotnet/corert/issues/5496 -->
<!-- <FileToExclude Include="clrcompression" /> -->
</ItemGroup>

Просмотреть файл

@ -30,11 +30,12 @@ namespace ILCompiler
ManifestResourceBlockingPolicy resourceBlockingPolicy,
string logFile,
StackTraceEmissionPolicy stackTracePolicy,
DynamicInvokeThunkGenerationPolicy invokeThunkGenerationPolicy,
IEnumerable<ModuleDesc> modulesWithMetadata,
IEnumerable<ReflectableEntity<TypeDesc>> reflectableTypes,
IEnumerable<ReflectableEntity<MethodDesc>> reflectableMethods,
IEnumerable<ReflectableEntity<FieldDesc>> reflectableFields)
: base(typeSystemContext, blockingPolicy, resourceBlockingPolicy, logFile, stackTracePolicy)
: base(typeSystemContext, blockingPolicy, resourceBlockingPolicy, logFile, stackTracePolicy, invokeThunkGenerationPolicy)
{
_modulesWithMetadata = new List<ModuleDesc>(modulesWithMetadata);

Просмотреть файл

@ -372,7 +372,7 @@ namespace ILCompiler
Debug.Assert(!type.IsGenericDefinition);
MetadataType metadataType = type as MetadataType;
if (metadataType != null && metadataType.ThreadStaticFieldSize.AsInt > 0)
if (metadataType != null && metadataType.ThreadGcStaticFieldSize.AsInt > 0)
{
_graph.AddRoot(_factory.TypeThreadStaticIndex(metadataType), reason);

Просмотреть файл

@ -7,6 +7,8 @@ using System.Collections.Generic;
using Internal.TypeSystem;
using Debug = System.Diagnostics.Debug;
namespace ILCompiler
{
internal class CompilerMetadataFieldLayoutAlgorithm : MetadataFieldLayoutAlgorithm
@ -15,7 +17,7 @@ namespace ILCompiler
{
// GC statics start with a pointer to the "EEType" that signals the size and GCDesc to the GC
layout.GcStatics.Size = context.Target.LayoutPointerSize;
layout.ThreadStatics.Size = context.Target.LayoutPointerSize;
layout.ThreadGcStatics.Size = context.Target.LayoutPointerSize;
}
protected override void FinalizeRuntimeSpecificStaticFieldLayout(TypeSystemContext context, ref ComputedStaticFieldLayout layout)
@ -26,10 +28,14 @@ namespace ILCompiler
{
layout.GcStatics.Size = LayoutInt.Zero;
}
if (layout.ThreadStatics.Size == context.Target.LayoutPointerSize)
if (layout.ThreadGcStatics.Size == context.Target.LayoutPointerSize)
{
layout.ThreadStatics.Size = LayoutInt.Zero;
layout.ThreadGcStatics.Size = LayoutInt.Zero;
}
// CoreRT makes no distinction between Gc / non-Gc thread statics. All are placed into ThreadGcStatics since thread statics
// are typically rare.
Debug.Assert(layout.ThreadNonGcStatics.Size == LayoutInt.Zero);
}
}
}

Просмотреть файл

@ -47,5 +47,24 @@ namespace ILCompiler
}
}
}
partial class UnboxingThunk : IPrefixMangledMethod
{
MethodDesc IPrefixMangledMethod.BaseMethod
{
get
{
return _targetMethod;
}
}
string IPrefixMangledMethod.Prefix
{
get
{
return "unbox";
}
}
}
}
}

Просмотреть файл

@ -424,6 +424,9 @@ namespace ILCompiler
{
Debug.Assert(field.IsStatic);
if (field.IsThreadStatic)
return true;
TypeDesc fieldType = field.FieldType;
if (fieldType.IsValueType)
return ((DefType)fieldType).ContainsGCPointers;
@ -499,6 +502,10 @@ namespace ILCompiler
// method table.
public long UniversalCanonReflectionMethodRootHeuristic_InstantiationCount { get; }
// To avoid infinite generic recursion issues during debug type record generation, attempt to
// use canonical form for types with high generic complexity.
public long MaxGenericDepthOfDebugRecord { get; }
public SharedGenericsConfiguration()
{
UniversalCanonGVMReflectionRootHeuristic_InstantiationCount = 4;
@ -510,6 +517,8 @@ namespace ILCompiler
// expansion is allowed. Numbers are chosen to allow a fairly large
// amount of generic expansion before trimming.
UniversalCanonReflectionMethodRootHeuristic_InstantiationCount = 1024;
MaxGenericDepthOfDebugRecord = 15;
}
};
}

Просмотреть файл

@ -15,7 +15,7 @@ namespace ILCompiler.DependencyAnalysis
protected override string GetName(NodeFactory factory) => this.GetMangledName(factory.NameMangler) + " cloned";
public override ObjectNode NodeForLinkage(NodeFactory factory) => this;
public override ISymbolNode NodeForLinkage(NodeFactory factory) => this;
//
// A cloned type must be named differently than the type it is a clone of so the linker

Просмотреть файл

@ -56,7 +56,7 @@ namespace ILCompiler.DependencyAnalysis
/// |
/// [Pointer Size] | Pointer to the generic argument and variance info (optional)
/// </summary>
public partial class EETypeNode : ObjectNode, IExportableSymbolNode, IEETypeNode, ISymbolDefinitionNode
public partial class EETypeNode : ObjectNode, IExportableSymbolNode, IEETypeNode, ISymbolDefinitionNode, ISymbolNodeWithLinkage
{
protected TypeDesc _type;
internal EETypeOptionalFieldsBuilder _optionalFieldsBuilder = new EETypeOptionalFieldsBuilder();
@ -90,9 +90,9 @@ namespace ILCompiler.DependencyAnalysis
return false;
}
public override ObjectNode NodeForLinkage(NodeFactory factory)
public virtual ISymbolNode NodeForLinkage(NodeFactory factory)
{
return (ObjectNode)factory.NecessaryTypeSymbol(_type);
return factory.NecessaryTypeSymbol(_type);
}
public ExportForm GetExportForm(NodeFactory factory) => factory.CompilationModuleGroup.GetExportTypeForm(Type);

Просмотреть файл

@ -32,6 +32,16 @@ namespace ILCompiler.DependencyAnalysis
bool RepresentsIndirectionCell { get; }
}
/// <summary>
/// Represents a symbol backed by a different symbol for object emission purposes.
/// </summary>
public interface ISymbolNodeWithLinkage : ISymbolNode
{
/// <summary>
/// Return a node that is used for linkage
/// </summary>
ISymbolNode NodeForLinkage(NodeFactory factory);
}
public interface ISortableSymbolNode : ISymbolNode, ISortableNode
{

Просмотреть файл

@ -982,7 +982,7 @@ namespace ILCompiler.DependencyAnalysis
yield return new DependencyListEntry(GetStaticsNode(context, out ignored), "type gc static info");
}
if (_type.GetClosestDefType().ThreadStaticFieldSize.AsInt > 0)
if (_type.GetClosestDefType().ThreadGcStaticFieldSize.AsInt > 0)
{
BagElementKind ignored;
yield return new DependencyListEntry(GetThreadStaticsNode(context, out ignored), "type thread static info");
@ -1201,9 +1201,9 @@ namespace ILCompiler.DependencyAnalysis
layoutInfo.AppendUnsigned(staticDescBagType, gcStaticsSymbolIndex);
}
if (closestDefType.ThreadStaticFieldSize.AsInt != 0)
if (closestDefType.ThreadGcStaticFieldSize.AsInt != 0)
{
layoutInfo.AppendUnsigned(BagElementKind.ThreadStaticDataSize, checked((uint)closestDefType.ThreadStaticFieldSize.AsInt));
layoutInfo.AppendUnsigned(BagElementKind.ThreadStaticDataSize, checked((uint)closestDefType.ThreadGcStaticFieldSize.AsInt));
BagElementKind threadStaticDescBagType;
ISymbolNode threadStaticsDescSymbol = GetThreadStaticsNode(factory, out threadStaticDescBagType);
uint threadStaticsSymbolIndex = factory.MetadataManager.NativeLayoutInfo.StaticsReferences.GetIndex(threadStaticsDescSymbol);

Просмотреть файл

@ -51,16 +51,6 @@ namespace ILCompiler.DependencyAnalysis
return false;
}
/// <summary>
/// Return a node that is used for linkage
/// </summary>
/// <param name="factory"></param>
/// <returns></returns>
public virtual ObjectNode NodeForLinkage(NodeFactory factory)
{
return this;
}
public override bool HasConditionalStaticDependencies => false;
public override bool HasDynamicDependencies => false;
public override bool InterestingForDynamicDependencyAnalysis => false;

Просмотреть файл

@ -732,16 +732,25 @@ namespace ILCompiler.DependencyAnalysis
// Emit individual cfi blob for the given offset
List<byte[]> cfis;
if (_offsetToCfis.TryGetValue(offset, out cfis))
{
if (forArm)
{
// Unwind insts are generated in the object file in the reversed order on arm,
// so we should reverse the cfi list
for (int index = cfis.Count - 1; index >= 0; index--)
{
EmitARMExIdxCode(offset, cfis[index]);
}
}
else
{
foreach (byte[] cfi in cfis)
{
if (forArm)
EmitARMExIdxCode(offset, cfi);
else
EmitCFICode(offset, cfi);
}
}
}
}
public void EmitDebugLocInfo(int offset)
{

Просмотреть файл

@ -20,7 +20,7 @@ namespace ILCompiler.DependencyAnalysis
/// method body, as if it was generated. The node acts as a symbol for the canonical
/// method for convenience.
/// </summary>
public class ShadowConcreteMethodNode : DependencyNodeCore<NodeFactory>, IMethodNode
public class ShadowConcreteMethodNode : DependencyNodeCore<NodeFactory>, IMethodNode, ISymbolNodeWithLinkage
{
/// <summary>
/// Gets the canonical method body that defines the dependencies of this node.
@ -53,6 +53,11 @@ namespace ILCompiler.DependencyAnalysis
CanonicalMethodNode = canonicalMethod;
}
public ISymbolNode NodeForLinkage(NodeFactory factory)
{
return CanonicalMethodNode;
}
public override IEnumerable<DependencyListEntry> GetStaticDependencies(NodeFactory factory)
{
DependencyList dependencies = new DependencyList();

Просмотреть файл

@ -70,7 +70,7 @@ namespace ILCompiler.DependencyAnalysis
dependencies.Add(factory.Indirection(factory.TypeNonGCStaticsSymbol(metadataType)), "Non-GC statics indirection for StaticsInfoHashtable");
}
if (metadataType.ThreadStaticFieldSize.AsInt > 0)
if (metadataType.ThreadGcStaticFieldSize.AsInt > 0)
{
if (factory.Target.Abi == TargetAbi.ProjectN)
{
@ -116,7 +116,7 @@ namespace ILCompiler.DependencyAnalysis
ISymbolNode nonGCStaticIndirection = factory.Indirection(factory.TypeNonGCStaticsSymbol(metadataType));
bag.AppendUnsigned(BagElementKind.NonGcStaticData, _nativeStaticsReferences.GetIndex(nonGCStaticIndirection));
}
if (metadataType.ThreadStaticFieldSize.AsInt > 0)
if (metadataType.ThreadGcStaticFieldSize.AsInt > 0)
{
if (factory.Target.Abi == TargetAbi.ProjectN)
{

Просмотреть файл

@ -59,7 +59,7 @@ namespace ILCompiler
return null;
}
private static MetadataManager PickMetadataManager(CompilerTypeSystemContext context, CompilationModuleGroup compilationModuleGroup, IEnumerable<ModuleDesc> inputModules, IEnumerable<ModuleDesc> inputMetadataOnlyAssemblies, string metadataFile)
private static MetadataManager PickMetadataManager(CompilerTypeSystemContext context, CompilationModuleGroup compilationModuleGroup, IEnumerable<ModuleDesc> inputModules, IEnumerable<ModuleDesc> inputMetadataOnlyAssemblies, string metadataFile, bool emitStackTraceMetadata, bool disableExceptionMessages, bool disableInvokeThunks)
{
if (metadataFile == null)
{
@ -67,7 +67,28 @@ namespace ILCompiler
}
else
{
return new PrecomputedMetadataManager(compilationModuleGroup, context, FindMetadataDescribingModuleInInputSet(inputModules), inputModules, inputMetadataOnlyAssemblies, ReadBytesFromFile(metadataFile), new UtcStackTraceEmissionPolicy(), new NoManifestResourceBlockingPolicy());
// Set Policies according to passed arguments
StackTraceEmissionPolicy stackTraceEmissionPolicy;
if (emitStackTraceMetadata)
{
stackTraceEmissionPolicy = new UtcStackTraceEmissionPolicy();
}
else
{
stackTraceEmissionPolicy = new NoStackTraceEmissionPolicy();
}
ManifestResourceBlockingPolicy resourceBlockingPolicy;
if (disableExceptionMessages)
{
resourceBlockingPolicy = new FrameworkStringResourceBlockingPolicy();
}
else
{
resourceBlockingPolicy = new NoManifestResourceBlockingPolicy();
}
return new PrecomputedMetadataManager(compilationModuleGroup, context, FindMetadataDescribingModuleInInputSet(inputModules), inputModules, inputMetadataOnlyAssemblies, ReadBytesFromFile(metadataFile), stackTraceEmissionPolicy , resourceBlockingPolicy, disableInvokeThunks);
}
}
@ -86,11 +107,14 @@ namespace ILCompiler
string outputFile,
UTCNameMangler nameMangler,
bool buildMRT,
bool emitStackTraceMetadata,
bool disableExceptionMessages,
bool allowInvokeThunks,
DictionaryLayoutProvider dictionaryLayoutProvider,
ImportedNodeProvider importedNodeProvider)
: base(context,
compilationModuleGroup,
PickMetadataManager(context, compilationModuleGroup, inputModules, inputMetadataOnlyAssemblies, metadataFile),
PickMetadataManager(context, compilationModuleGroup, inputModules, inputMetadataOnlyAssemblies, metadataFile, emitStackTraceMetadata, disableExceptionMessages, allowInvokeThunks),
NewEmptyInteropStubManager(context, compilationModuleGroup),
nameMangler,
new AttributeDrivenLazyGenericsPolicy(),

Просмотреть файл

@ -58,7 +58,7 @@ namespace ILCompiler.DependencyAnalysis
{
ObjectDataBuilder builder = new ObjectDataBuilder(factory, relocsOnly);
builder.RequireInitialPointerAlignment();
builder.EmitZeros(_type.ThreadStaticFieldSize.AsInt);
builder.EmitZeros(_type.ThreadGcStaticFieldSize.AsInt);
builder.AddSymbol(this);
return builder.ToObjectData();
}

Просмотреть файл

@ -0,0 +1,48 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Internal.TypeSystem;
namespace ILCompiler
{
/// <summary>
/// Controls the way calling convention conversion is performed in
/// <see cref="System.Reflection.MethodBase.Invoke(object, object[])"/>
/// scenarios.
/// </summary>
public abstract class DynamicInvokeThunkGenerationPolicy
{
/// <summary>
/// Gets a value indicating whether reflection-invokable method '<paramref name="targetMethod"/>'
/// should get a static calling convention conversion thunk. Static calling convention
/// conversion thunks speed up reflection invoke of the method at the cost of extra code generation.
/// </summary>
public abstract bool HasStaticInvokeThunk(MethodDesc targetMethod);
}
/// <summary>
/// A thunk generation policy that generates no static invocation thunks.
/// </summary>
public sealed class NoDynamicInvokeThunkGenerationPolicy : DynamicInvokeThunkGenerationPolicy
{
public override bool HasStaticInvokeThunk(MethodDesc targetMethod) => false;
}
/// <summary>
/// A thunk generation policy that uses static invocation thunks whenever possible.
/// </summary>
public sealed class DefaultDynamicInvokeThunkGenerationPolicy : DynamicInvokeThunkGenerationPolicy
{
public override bool HasStaticInvokeThunk(MethodDesc targetMethod)
{
// Place an upper limit on how many parameters a method can have to still get a static stub.
// From the past experience, methods taking 8000+ parameters get a stub that can hit various limitations
// in the codegen. On Project N, we were limited to 256 parameters because of MDIL limitations.
// We don't have such limitations here, but it's a nice round number.
// Reflection invoke will still work, but will go through the calling convention converter.
return targetMethod.Signature.Length <= 256;
}
}
}

Просмотреть файл

@ -17,7 +17,7 @@ namespace ILCompiler
public override bool SupportsReflection => false;
public EmptyMetadataManager(CompilerTypeSystemContext typeSystemContext)
: base(typeSystemContext, new FullyBlockedMetadataPolicy(), new FullyBlockedManifestResourcePolicy())
: base(typeSystemContext, new FullyBlockedMetadataPolicy(), new FullyBlockedManifestResourcePolicy(), new NoDynamicInvokeThunkGenerationPolicy())
{
}
@ -61,15 +61,6 @@ namespace ILCompiler
stackTraceMapping = new List<MetadataMapping<MethodDesc>>();
}
/// <summary>
/// Is there a reflection invoke stub for a method that is invokable?
/// </summary>
public override bool HasReflectionInvokeStubForInvokableMethod(MethodDesc method)
{
Debug.Assert(IsReflectionInvokable(method));
return false;
}
/// <summary>
/// Gets a stub that can be used to reflection-invoke a method with a given signature.
/// </summary>

Просмотреть файл

@ -14,8 +14,6 @@ using Internal.Metadata.NativeFormat.Writer;
using ILCompiler.Metadata;
using ILCompiler.DependencyAnalysis;
using Debug = System.Diagnostics.Debug;
namespace ILCompiler
{
/// <summary>
@ -27,8 +25,10 @@ namespace ILCompiler
protected readonly StackTraceEmissionPolicy _stackTraceEmissionPolicy;
private readonly ModuleDesc _generatedAssembly;
public GeneratingMetadataManager(CompilerTypeSystemContext typeSystemContext, MetadataBlockingPolicy blockingPolicy, ManifestResourceBlockingPolicy resourceBlockingPolicy, string logFile, StackTraceEmissionPolicy stackTracePolicy)
: base(typeSystemContext, blockingPolicy, resourceBlockingPolicy)
public GeneratingMetadataManager(CompilerTypeSystemContext typeSystemContext, MetadataBlockingPolicy blockingPolicy,
ManifestResourceBlockingPolicy resourceBlockingPolicy, string logFile, StackTraceEmissionPolicy stackTracePolicy,
DynamicInvokeThunkGenerationPolicy invokeThunkGenerationPolicy)
: base(typeSystemContext, blockingPolicy, resourceBlockingPolicy, invokeThunkGenerationPolicy)
{
_metadataLogFile = logFile;
_stackTraceEmissionPolicy = stackTracePolicy;
@ -168,22 +168,6 @@ namespace ILCompiler
/// <returns></returns>
protected abstract IEnumerable<FieldDesc> GetFieldsWithRuntimeMapping();
/// <summary>
/// Is there a reflection invoke stub for a method that is invokable?
/// </summary>
public sealed override bool HasReflectionInvokeStubForInvokableMethod(MethodDesc method)
{
Debug.Assert(IsReflectionInvokable(method));
// Place an upper limit on how many parameters a method can have to still get a static stub.
// From the past experience, methods taking 8000+ parameters get a stub that can hit various limitations
// in the codegen. On Project N, we were limited to 256 parameters because of MDIL limitations.
// We don't have such limitations here, but it's a nice round number.
// Reflection invoke will still work, but will go through the calling convention converter.
return method.Signature.Length <= 256;
}
/// <summary>
/// Gets a stub that can be used to reflection-invoke a method with a given signature.
/// </summary>

Просмотреть файл

@ -43,6 +43,7 @@ namespace ILCompiler
protected readonly CompilerTypeSystemContext _typeSystemContext;
protected readonly MetadataBlockingPolicy _blockingPolicy;
protected readonly ManifestResourceBlockingPolicy _resourceBlockingPolicy;
protected readonly DynamicInvokeThunkGenerationPolicy _dynamicInvokeThunkGenerationPolicy;
private List<NonGCStaticsNode> _cctorContextsGenerated = new List<NonGCStaticsNode>();
private readonly HashSet<TypeDesc> _typesWithEETypesGenerated = new HashSet<TypeDesc>();
@ -56,11 +57,13 @@ namespace ILCompiler
internal DynamicInvokeTemplateDataNode DynamicInvokeTemplateData { get; private set; }
public virtual bool SupportsReflection => true;
public MetadataManager(CompilerTypeSystemContext typeSystemContext, MetadataBlockingPolicy blockingPolicy, ManifestResourceBlockingPolicy resourceBlockingPolicy)
public MetadataManager(CompilerTypeSystemContext typeSystemContext, MetadataBlockingPolicy blockingPolicy,
ManifestResourceBlockingPolicy resourceBlockingPolicy, DynamicInvokeThunkGenerationPolicy dynamicInvokeThunkGenerationPolicy)
{
_typeSystemContext = typeSystemContext;
_blockingPolicy = blockingPolicy;
_resourceBlockingPolicy = resourceBlockingPolicy;
_dynamicInvokeThunkGenerationPolicy = dynamicInvokeThunkGenerationPolicy;
}
public void AttachToDependencyGraph(DependencyAnalyzerBase<NodeFactory> graph)
@ -375,7 +378,11 @@ namespace ILCompiler
/// <summary>
/// Given that a method is invokable, does there exist a reflection invoke stub?
/// </summary>
public abstract bool HasReflectionInvokeStubForInvokableMethod(MethodDesc method);
public bool HasReflectionInvokeStubForInvokableMethod(MethodDesc method)
{
Debug.Assert(IsReflectionInvokable(method));
return _dynamicInvokeThunkGenerationPolicy.HasStaticInvokeThunk(method);
}
/// <summary>
/// Given that a method is invokable, if it is inserted into the reflection invoke table

Просмотреть файл

@ -64,9 +64,14 @@ namespace ILCompiler
IEnumerable<ModuleDesc> inputMetadataOnlyAssemblies,
byte[] metadataBlob,
StackTraceEmissionPolicy stackTraceEmissionPolicy,
ManifestResourceBlockingPolicy resourceBlockingPolicy)
: base(typeSystemContext, new AttributeSpecifiedBlockingPolicy(), resourceBlockingPolicy)
ManifestResourceBlockingPolicy resourceBlockingPolicy,
bool disableInvokeThunks)
: base(typeSystemContext, new AttributeSpecifiedBlockingPolicy(), resourceBlockingPolicy,
disableInvokeThunks ? (DynamicInvokeThunkGenerationPolicy)new NoDynamicInvokeThunkGenerationPolicy() : new PrecomputedDynamicInvokeThunkGenerationPolicy())
{
// Need to do this dance because C# won't let us access `this` in the `base()` expression above. Sigh.
(_dynamicInvokeThunkGenerationPolicy as PrecomputedDynamicInvokeThunkGenerationPolicy)?.SetParentWorkaround(this);
_compilationModuleGroup = group;
_metadataDescribingModule = metadataDescribingModule;
_compilationModules = new HashSet<ModuleDesc>(compilationModules);
@ -540,7 +545,7 @@ namespace ILCompiler
}
}
if (metadataType.ThreadStaticFieldSize.AsInt > 0)
if (metadataType.ThreadGcStaticFieldSize.AsInt > 0)
{
dependencies.Add(((UtcNodeFactory)factory).TypeThreadStaticsOffsetSymbol(metadataType), "Thread statics for ReflectionFieldMap entry");
}
@ -903,38 +908,6 @@ namespace ILCompiler
return dynamicInvokeMapTable;
}
/// <summary>
/// Is there a reflection invoke stub for a method that is invokable?
/// </summary>
public override bool HasReflectionInvokeStubForInvokableMethod(MethodDesc method)
{
Debug.Assert(IsReflectionInvokable(method));
if (!ProjectNDependencyBehavior.EnableFullAnalysis)
{
if (method.IsCanonicalMethod(CanonicalFormKind.Any))
return false;
}
else
{
if (method.IsCanonicalMethod(CanonicalFormKind.Universal))
return false;
}
MethodDesc reflectionInvokeStub = GetCanonicalReflectionInvokeStub(method);
if (reflectionInvokeStub == null)
return false;
// TODO: Generate DynamicInvokeTemplateMap dependencies correctly. For now, force all canonical stubs to go through the
// calling convention converter interpreter path.
if (reflectionInvokeStub.IsSharedByGenericInstantiations)
return false;
return true;
}
/// <summary>
/// Gets a stub that can be used to reflection-invoke a method with a given signature.
/// </summary>
@ -1050,5 +1023,45 @@ namespace ILCompiler
public bool IsBlocked(MethodDesc methodDef) => false;
public ModuleDesc GetModuleOfType(MetadataType typeDef) => typeDef.Module;
}
private sealed class PrecomputedDynamicInvokeThunkGenerationPolicy : DynamicInvokeThunkGenerationPolicy
{
private PrecomputedMetadataManager _parent;
public PrecomputedDynamicInvokeThunkGenerationPolicy()
{
}
public void SetParentWorkaround(PrecomputedMetadataManager parent)
{
_parent = parent;
}
public override bool HasStaticInvokeThunk(MethodDesc method)
{
if (!ProjectNDependencyBehavior.EnableFullAnalysis)
{
if (method.IsCanonicalMethod(CanonicalFormKind.Any))
return false;
}
else
{
if (method.IsCanonicalMethod(CanonicalFormKind.Universal))
return false;
}
MethodDesc reflectionInvokeStub = _parent.GetCanonicalReflectionInvokeStub(method);
if (reflectionInvokeStub == null)
return false;
// TODO: Generate DynamicInvokeTemplateMap dependencies correctly. For now, force all canonical stubs to go through the
// calling convention converter interpreter path.
if (reflectionInvokeStub.IsSharedByGenericInstantiations)
return false;
return true;
}
}
}
}

Просмотреть файл

@ -39,8 +39,9 @@ namespace ILCompiler
ManifestResourceBlockingPolicy resourceBlockingPolicy,
string logFile,
StackTraceEmissionPolicy stackTracePolicy,
DynamicInvokeThunkGenerationPolicy invokeThunkGenerationPolicy,
UsageBasedMetadataGenerationOptions generationOptions)
: base(typeSystemContext, blockingPolicy, resourceBlockingPolicy, logFile, stackTracePolicy)
: base(typeSystemContext, blockingPolicy, resourceBlockingPolicy, logFile, stackTracePolicy, invokeThunkGenerationPolicy)
{
// We use this to mark places that would behave differently if we tracked exact fields used.
_hasPreciseFieldUsageInformation = false;
@ -359,7 +360,7 @@ namespace ILCompiler
}
return new AnalysisBasedMetadataManager(
_typeSystemContext, _blockingPolicy, _resourceBlockingPolicy, _metadataLogFile, _stackTraceEmissionPolicy,
_typeSystemContext, _blockingPolicy, _resourceBlockingPolicy, _metadataLogFile, _stackTraceEmissionPolicy, _dynamicInvokeThunkGenerationPolicy,
_modulesWithMetadata, reflectableTypes.ToEnumerable(), reflectableMethods.ToEnumerable(),
reflectableFields.ToEnumerable());
}

Просмотреть файл

@ -387,27 +387,57 @@ namespace ILCompiler
return 0;
}
TypeDesc GetFieldDebugType(FieldDesc field)
bool ShouldUseCanonicalTypeRecord(TypeDesc type)
{
TypeDesc type = field.FieldType;
// TODO: check the type's generic complexity
if (NodeFactory.LazyGenericsPolicy.UsesLazyGenerics(type))
return type.GetGenericDepth() > NodeFactory.TypeSystemContext.GenericsConfig.MaxGenericDepthOfDebugRecord;
}
TypeDesc GetDebugType(TypeDesc type)
{
TypeDesc typeGenericComplexityInfo = type;
// Strip off pointer, array, and byref details.
while (typeGenericComplexityInfo is ParameterizedType paramType) {
typeGenericComplexityInfo = paramType.ParameterType;
}
// Types that have some canonical subtypes types should always be represented in normalized canonical form to the binder.
// Also, to avoid infinite generic recursion issues, attempt to use canonical form for fields with high generic complexity.
if (type.IsCanonicalSubtype(CanonicalFormKind.Specific) || (typeGenericComplexityInfo is DefType defType) && ShouldUseCanonicalTypeRecord(defType))
{
type = type.ConvertToCanonForm(CanonicalFormKind.Specific);
// Re-check if the canonical subtype has acceptable generic complexity
typeGenericComplexityInfo = type;
while (typeGenericComplexityInfo is ParameterizedType paramType) {
typeGenericComplexityInfo = paramType.ParameterType;
}
if ((typeGenericComplexityInfo is DefType canonDefType) && ShouldUseCanonicalTypeRecord(canonDefType))
{
type = type.ConvertToCanonForm(CanonicalFormKind.Universal);
}
}
return type;
}
TypeDesc GetFieldDebugType(FieldDesc field)
{
return GetDebugType(field.FieldType);
}
private uint GetClassTypeIndex(TypeDesc type, bool needsCompleteType)
{
DefType defType = type as DefType;
TypeDesc debugType = GetDebugType(type);
DefType defType = debugType as DefType;
System.Diagnostics.Debug.Assert(defType != null, "GetClassTypeIndex was called with non def type");
ClassTypeDescriptor classTypeDescriptor = new ClassTypeDescriptor
{
IsStruct = type.IsValueType ? 1 : 0,
Name = _objectWriter.GetMangledName(type),
Name = _objectWriter.GetMangledName(defType),
BaseClassId = 0,
InstanceSize = 0
};

Просмотреть файл

@ -124,6 +124,7 @@
<Compile Include="Compiler\DependencyAnalysis\LoopHijackFlagNode.cs" />
<Compile Include="Compiler\DevirtualizationManager.cs" />
<Compile Include="Compiler\DictionaryLayoutProvider.cs" />
<Compile Include="Compiler\DynamicInvokeThunkGenerationPolicy.cs" />
<Compile Include="Compiler\EmptyInteropStubManager.cs" />
<Compile Include="Compiler\DependencyAnalysis\ISortableNode.cs" />
<Compile Include="Compiler\DependencyAnalysis\SortableDependencyNode.cs" />

Просмотреть файл

@ -2807,7 +2807,8 @@ namespace Internal.Metadata.NativeFormat.Writer
Debug.Assert(Constraints.TrueForAll(handle => handle == null ||
handle.HandleType == HandleType.TypeDefinition ||
handle.HandleType == HandleType.TypeReference ||
handle.HandleType == HandleType.TypeSpecification));
handle.HandleType == HandleType.TypeSpecification ||
handle.HandleType == HandleType.ModifiedType));
writer.Write(Constraints);
writer.Write(CustomAttributes);
} // Save

Просмотреть файл

@ -15,7 +15,7 @@ namespace TypeSystemTests
{
// GC statics start with a pointer to the "EEType" that signals the size and GCDesc to the GC
layout.GcStatics.Size = context.Target.LayoutPointerSize;
layout.ThreadStatics.Size = context.Target.LayoutPointerSize;
layout.ThreadGcStatics.Size = context.Target.LayoutPointerSize;
}
protected override void FinalizeRuntimeSpecificStaticFieldLayout(TypeSystemContext context, ref ComputedStaticFieldLayout layout)
@ -26,9 +26,9 @@ namespace TypeSystemTests
{
layout.GcStatics.Size = LayoutInt.Zero;
}
if (layout.ThreadStatics.Size == context.Target.LayoutPointerSize)
if (layout.ThreadGcStatics.Size == context.Target.LayoutPointerSize)
{
layout.ThreadStatics.Size = LayoutInt.Zero;
layout.ThreadGcStatics.Size = LayoutInt.Zero;
}
}
}

Просмотреть файл

@ -110,6 +110,9 @@ namespace TypeSystemTests
{
Debug.Assert(field.IsStatic);
if (field.IsThreadStatic)
return true;
TypeDesc fieldType = field.FieldType;
if (fieldType.IsValueType)
return ((DefType)fieldType).ContainsGCPointers;

Просмотреть файл

@ -200,8 +200,8 @@ namespace TypeSystemTests
Assert.Equal(LayoutInt.Zero, context.UniversalCanonType.GCStaticFieldSize);
Assert.Equal(LayoutInt.Zero, context.UniversalCanonType.NonGCStaticFieldAlignment);
Assert.Equal(LayoutInt.Zero, context.UniversalCanonType.NonGCStaticFieldSize);
Assert.Equal(LayoutInt.Zero, context.UniversalCanonType.ThreadStaticFieldAlignment);
Assert.Equal(LayoutInt.Zero, context.UniversalCanonType.ThreadStaticFieldSize);
Assert.Equal(LayoutInt.Zero, context.UniversalCanonType.ThreadGcStaticFieldAlignment);
Assert.Equal(LayoutInt.Zero, context.UniversalCanonType.ThreadGcStaticFieldSize);
}
[Fact]
public void TestLayoutOfUniversalCanonType()

Просмотреть файл

@ -0,0 +1,23 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Text;
using LLVMSharp;
namespace ILCompiler.WebAssembly
{
class DebugMetadata
{
public DebugMetadata(LLVMMetadataRef file, LLVMMetadataRef compileUnit)
{
File = file;
CompileUnit = compileUnit;
}
public LLVMMetadataRef CompileUnit { get; }
public LLVMMetadataRef File { get; }
}
}

Просмотреть файл

@ -5,6 +5,8 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using Internal.TypeSystem;
using ILCompiler;
@ -12,8 +14,8 @@ using LLVMSharp;
using ILCompiler.CodeGen;
using ILCompiler.DependencyAnalysis;
using ILCompiler.DependencyAnalysisFramework;
using ILCompiler.WebAssembly;
using Internal.TypeSystem.Ecma;
using System.Linq;
namespace Internal.IL
{
@ -35,6 +37,7 @@ namespace Internal.IL
}
public LLVMModuleRef Module { get; }
public LLVMContextRef Context { get; }
private readonly MethodDesc _method;
private readonly MethodIL _methodIL;
private readonly MethodSignature _signature;
@ -45,17 +48,18 @@ namespace Internal.IL
private LLVMBuilderRef _builder;
private readonly LocalVariableDefinition[] _locals;
private readonly LLVMValueRef[] _localSlots;
private readonly LLVMValueRef[] _argSlots;
private List<SpilledExpressionEntry> _spilledExpressions = new List<SpilledExpressionEntry>();
private int _pointerSize;
private readonly byte[] _ilBytes;
private MethodDebugInformation _debugInformation;
private LLVMMetadataRef _debugFunction;
/// <summary>
/// Stack of values pushed onto the IL stack: locals, arguments, values, function pointer, ...
/// </summary>
private EvaluationStack<StackEntry> _stack = new EvaluationStack<StackEntry>(0);
LLVMTypeRef _universalSignature = LLVM.FunctionType(LLVM.VoidType(), new LLVMTypeRef[] { LLVM.PointerType(LLVM.Int8Type(), 0), LLVM.PointerType(LLVM.Int8Type(), 0) }, false);
private class BasicBlock
{
// Common fields
@ -94,6 +98,7 @@ namespace Internal.IL
_ilBytes = methodIL.GetILBytes();
_locals = methodIL.GetLocals();
_localSlots = new LLVMValueRef[_locals.Length];
_argSlots = new LLVMValueRef[method.Signature.Length];
_signature = method.Signature;
_thisType = method.OwningType;
@ -103,9 +108,13 @@ namespace Internal.IL
{
_exceptionRegions[i] = new ExceptionRegion() { ILRegion = ilExceptionRegions[i] };
}
_llvmFunction = GetOrCreateLLVMFunction(mangledName);
_llvmFunction = GetOrCreateLLVMFunction(mangledName, method.Signature);
_builder = LLVM.CreateBuilder();
_pointerSize = compilation.NodeFactory.Target.PointerSize;
_debugInformation = _compilation.GetDebugInfo(_methodIL);
Context = LLVM.GetModuleContext(Module);
}
public void Import()
@ -158,11 +167,73 @@ namespace Internal.IL
LLVMBasicBlockRef prologBlock = LLVM.AppendBasicBlock(_llvmFunction, "Prolog");
LLVM.PositionBuilderAtEnd(_builder, prologBlock);
// Copy arguments onto the stack to allow
// them to be referenced by address
int thisOffset = 0;
if (!_signature.IsStatic)
{
thisOffset = 1;
}
// Keep track of where we are in the llvm signature, starting after the
// shadow stack pointer and return adress
int signatureIndex = 1;
if (NeedsReturnStackSlot(_signature))
{
signatureIndex++;
}
string[] argNames = null;
if (_debugInformation != null)
{
argNames = _debugInformation.GetParameterNames()?.ToArray();
}
for (int i = 0; i < _signature.Length; i++)
{
if (CanStoreTypeOnStack(_signature[i]))
{
string argName = String.Empty;
if (argNames != null && argNames[i] != null)
{
argName = argNames[i] + "_";
}
argName += $"arg{i + thisOffset}_";
LLVMValueRef argStackSlot = LLVM.BuildAlloca(_builder, GetLLVMTypeForTypeDesc(_signature[i]), argName);
LLVM.BuildStore(_builder, LLVM.GetParam(_llvmFunction, (uint)signatureIndex), argStackSlot);
_argSlots[i] = argStackSlot;
signatureIndex++;
}
}
string[] localNames = new string[_locals.Length];
if (_debugInformation != null)
{
foreach (ILLocalVariable localDebugInfo in _debugInformation.GetLocalVariables() ?? Enumerable.Empty<ILLocalVariable>())
{
// Check whether the slot still exists as the compiler may remove it for intrinsics
int slot = localDebugInfo.Slot;
if (slot < localNames.Length)
{
localNames[localDebugInfo.Slot] = localDebugInfo.Name;
}
}
}
for (int i = 0; i < _locals.Length; i++)
{
if (CanStoreTypeOnStack(_locals[i].Type))
if (CanStoreLocalOnStack(_locals[i].Type))
{
LLVMValueRef localStackSlot = LLVM.BuildAlloca(_builder, GetLLVMTypeForTypeDesc(_locals[i].Type), $"local{i}_");
string localName = String.Empty;
if (localNames[i] != null)
{
localName = localNames[i] + "_";
}
localName += $"local{i}_";
LLVMValueRef localStackSlot = LLVM.BuildAlloca(_builder, GetLLVMTypeForTypeDesc(_locals[i].Type), localName);
_localSlots[i] = localStackSlot;
}
}
@ -172,7 +243,7 @@ namespace Internal.IL
for(int i = 0; i < _locals.Length; i++)
{
LLVMValueRef localAddr = LoadVarAddress(i, LocalVarKind.Local, out TypeDesc localType);
if(CanStoreTypeOnStack(localType))
if(CanStoreLocalOnStack(localType))
{
LLVMTypeRef llvmType = GetLLVMTypeForTypeDesc(localType);
LLVMTypeKind typeKind = LLVM.GetTypeKind(llvmType);
@ -236,18 +307,18 @@ namespace Internal.IL
LLVM.BuildBr(_builder, block0);
}
private LLVMValueRef CreateLLVMFunction(string mangledName)
private LLVMValueRef CreateLLVMFunction(string mangledName, MethodSignature signature)
{
return LLVM.AddFunction(Module, mangledName , _universalSignature);
return LLVM.AddFunction(Module, mangledName, GetLLVMSignatureForMethod(signature));
}
private LLVMValueRef GetOrCreateLLVMFunction(string mangledName)
private LLVMValueRef GetOrCreateLLVMFunction(string mangledName, MethodSignature signature)
{
LLVMValueRef llvmFunction = LLVM.GetNamedFunction(Module, mangledName);
if(llvmFunction.Pointer == IntPtr.Zero)
{
return CreateLLVMFunction(mangledName);
return CreateLLVMFunction(mangledName, signature);
}
return llvmFunction;
}
@ -371,10 +442,69 @@ namespace Internal.IL
private void StartImportingInstruction()
{
if (_debugInformation != null)
{
bool foundSequencePoint = false;
ILSequencePoint curSequencePoint = default;
foreach (var sequencePoint in _debugInformation.GetSequencePoints() ?? Enumerable.Empty<ILSequencePoint>())
{
if (sequencePoint.Offset == _currentOffset)
{
curSequencePoint = sequencePoint;
foundSequencePoint = true;
break;
}
else if (sequencePoint.Offset < _currentOffset)
{
curSequencePoint = sequencePoint;
foundSequencePoint = true;
}
}
if (!foundSequencePoint)
{
return;
}
// LLVM can't process empty string file names
if (String.IsNullOrWhiteSpace(curSequencePoint.Document))
{
return;
}
DebugMetadata debugMetadata;
if (!_compilation.DebugMetadataMap.TryGetValue(curSequencePoint.Document, out debugMetadata))
{
string fullPath = curSequencePoint.Document;
string fileName = Path.GetFileName(fullPath);
string directory = Path.GetDirectoryName(fullPath) ?? String.Empty;
LLVMMetadataRef fileMetadata = LLVMPInvokes.LLVMDIBuilderCreateFile(_compilation.DIBuilder, fullPath, fullPath.Length,
directory, directory.Length);
// todo: get the right value for isOptimized
LLVMMetadataRef compileUnitMetadata = LLVMPInvokes.LLVMDIBuilderCreateCompileUnit(_compilation.DIBuilder, LLVMDWARFSourceLanguage.LLVMDWARFSourceLanguageC,
fileMetadata, "ILC", 3, isOptimized: false, String.Empty, 0, 1, String.Empty, 0, LLVMDWARFEmissionKind.LLVMDWARFEmissionFull, 0, false, false);
LLVM.AddNamedMetadataOperand(Module, "llvm.dbg.cu", LLVM.MetadataAsValue(Context, compileUnitMetadata));
debugMetadata = new DebugMetadata(fileMetadata, compileUnitMetadata);
_compilation.DebugMetadataMap[fullPath] = debugMetadata;
}
if (_debugFunction.Pointer == IntPtr.Zero)
{
_debugFunction = LLVM.DIBuilderCreateFunction(_compilation.DIBuilder, debugMetadata.CompileUnit, _method.Name, String.Empty, debugMetadata.File,
(uint)_debugInformation.GetSequencePoints().FirstOrDefault().LineNumber, default(LLVMMetadataRef), 1, 1, 1, 0, IsOptimized: 0, _llvmFunction);
}
LLVMMetadataRef currentLine = LLVMPInvokes.LLVMDIBuilderCreateDebugLocation(Context, (uint)curSequencePoint.LineNumber, 0, _debugFunction, default(LLVMMetadataRef));
LLVM.SetCurrentDebugLocation(_builder, LLVM.MetadataAsValue(Context, currentLine));
}
}
private void EndImportingInstruction()
{
// Reset the debug position so it doesn't end up applying to the wrong instructions
LLVM.SetCurrentDebugLocation(_builder, default(LLVMValueRef));
}
private void ImportNop()
@ -484,7 +614,7 @@ namespace Internal.IL
varCountBase = 1;
}
GetArgSizeAndOffsetAtIndex(index, out int argSize, out varOffset);
GetArgSizeAndOffsetAtIndex(index, out int argSize, out varOffset, out int realArgIndex);
if (!_signature.IsStatic && index == 0)
{
@ -499,6 +629,13 @@ namespace Internal.IL
type = _signature[index - varCountBase];
}
valueType = GetLLVMTypeForTypeDesc(type);
// If the argument can be passed as a real argument rather than on the shadow stack,
// get its address here
if(realArgIndex != -1)
{
return _argSlots[realArgIndex];
}
}
else if (kind == LocalVarKind.Local)
{
@ -785,7 +922,7 @@ namespace Internal.IL
for (int i = 0; i < _locals.Length; i++)
{
TypeDesc localType = _locals[i].Type;
if (!CanStoreTypeOnStack(localType))
if (!CanStoreLocalOnStack(localType))
{
offset = PadNextOffset(localType, offset);
}
@ -793,39 +930,57 @@ namespace Internal.IL
return offset.AlignUp(_pointerSize);
}
/// <summary>
/// Returns true if the type can be stored on the local stack
/// instead of the shadow stack in this method.
/// </summary>
private bool CanStoreTypeOnStack(TypeDesc localType)
private bool CanStoreLocalOnStack(TypeDesc localType)
{
// Keep all locals on the shadow stack if there is exception
// handling so funclets can access them
if (_exceptionRegions.Length == 0)
{
if (localType is DefType)
return CanStoreTypeOnStack(localType);
}
return false;
}
/// <summary>
/// Returns true if the type can be stored on the local stack
/// instead of the shadow stack in this method.
/// </summary>
private static bool CanStoreTypeOnStack(TypeDesc type)
{
if (!((DefType)localType).ContainsGCPointers)
if (type is DefType defType)
{
if (!defType.IsGCPointer && !defType.ContainsGCPointers)
{
return true;
}
}
else if (localType is PointerType)
else if (type is PointerType)
{
return true;
}
}
return false;
}
/// <summary>
/// Returns true if the method returns a type that must be kept
/// on the shadow stack
/// </summary>
private static bool NeedsReturnStackSlot(MethodSignature signature)
{
return !signature.ReturnType.IsVoid && !CanStoreTypeOnStack(signature.ReturnType);
}
private int GetTotalParameterOffset()
{
int offset = 0;
for (int i = 0; i < _signature.Length; i++)
{
if (!CanStoreTypeOnStack(_signature[i]))
{
offset = PadNextOffset(_signature[i], offset);
}
}
if (!_signature.IsStatic)
{
// If this is a struct, then it's a pointer on the stack
@ -842,8 +997,10 @@ namespace Internal.IL
return offset.AlignUp(_pointerSize);
}
private void GetArgSizeAndOffsetAtIndex(int index, out int size, out int offset)
private void GetArgSizeAndOffsetAtIndex(int index, out int size, out int offset, out int realArgIndex)
{
realArgIndex = -1;
int thisSize = 0;
if (!_signature.IsStatic)
{
@ -863,20 +1020,37 @@ namespace Internal.IL
var argType = _signature[index];
size = argType.GetElementSize().AsInt;
int potentialRealArgIndex = 0;
offset = thisSize;
for (int i = 0; i < index; i++)
{
// We could compact the set of argSlots to only those that we'd keep on the stack, but currently don't
potentialRealArgIndex++;
if (!CanStoreTypeOnStack(_signature[i]))
{
offset = PadNextOffset(_signature[i], offset);
}
}
if (CanStoreTypeOnStack(argType))
{
realArgIndex = potentialRealArgIndex;
offset = -1;
}
else
{
offset = PadOffset(argType, offset);
}
}
private void GetLocalSizeAndOffsetAtIndex(int index, out int size, out int offset)
{
LocalVariableDefinition local = _locals[index];
size = local.Type.GetElementSize().AsInt;
if (CanStoreTypeOnStack(local.Type))
if (CanStoreLocalOnStack(local.Type))
{
offset = -1;
}
@ -885,7 +1059,7 @@ namespace Internal.IL
offset = 0;
for (int i = 0; i < index; i++)
{
if (!CanStoreTypeOnStack(_locals[i].Type))
if (!CanStoreLocalOnStack(_locals[i].Type))
{
offset = PadNextOffset(_locals[i].Type, offset);
}
@ -992,15 +1166,26 @@ namespace Internal.IL
private void ImportReturn()
{
if (_signature.ReturnType != GetWellKnownType(WellKnownType.Void))
if (_signature.ReturnType.IsVoid)
{
StackEntry retVal = _stack.Pop();
LLVMTypeRef valueType = GetLLVMTypeForTypeDesc(_signature.ReturnType);
ImportStoreHelper(retVal.ValueAsType(valueType, _builder), valueType, LLVM.GetNextParam(LLVM.GetFirstParam(_llvmFunction)), 0);
LLVM.BuildRetVoid(_builder);
return;
}
StackEntry retVal = _stack.Pop();
LLVMTypeRef valueType = GetLLVMTypeForTypeDesc(_signature.ReturnType);
LLVMValueRef castValue = retVal.ValueAsType(valueType, _builder);
if (NeedsReturnStackSlot(_signature))
{
ImportStoreHelper(castValue, valueType, LLVM.GetNextParam(LLVM.GetFirstParam(_llvmFunction)), 0);
LLVM.BuildRetVoid(_builder);
}
else
{
LLVM.BuildRet(_builder, castValue);
}
}
private void ImportCall(ILOpcode opcode, int token)
{
@ -1095,7 +1280,7 @@ namespace Internal.IL
callee = delegateInfo.Constructor.Method;
if (callee.Signature.Length == 3)
{
PushExpression(StackValueKind.NativeInt, "thunk", GetOrCreateLLVMFunction(_compilation.NodeFactory.NameMangler.GetMangledMethodName(delegateInfo.Thunk.Method).ToString()));
PushExpression(StackValueKind.NativeInt, "thunk", GetOrCreateLLVMFunction(_compilation.NodeFactory.NameMangler.GetMangledMethodName(delegateInfo.Thunk.Method).ToString(), delegateInfo.Thunk.Method.Signature));
}
}
@ -1110,7 +1295,7 @@ namespace Internal.IL
if(callee.IsFinal || callee.OwningType.IsSealed())
{
AddMethodReference(callee);
return GetOrCreateLLVMFunction(calleeName);
return GetOrCreateLLVMFunction(calleeName, callee.Signature);
}
if (thisPointer != null && callee.IsVirtual && isCallVirt)
@ -1155,7 +1340,7 @@ namespace Internal.IL
if (targetMethod != null)
{
AddMethodReference(targetMethod);
return GetOrCreateLLVMFunction(_compilation.NameMangler.GetMangledMethodName(targetMethod).ToString());
return GetOrCreateLLVMFunction(_compilation.NameMangler.GetMangledMethodName(targetMethod).ToString(), callee.Signature);
}
return GetCallableVirtualMethod(thisPointer, callee);
@ -1163,7 +1348,7 @@ namespace Internal.IL
}
else
{
return GetOrCreateLLVMFunction(calleeName);
return GetOrCreateLLVMFunction(calleeName, callee.Signature);
}
}
@ -1180,7 +1365,7 @@ namespace Internal.IL
Debug.Assert(method.IsVirtual);
LLVMValueRef slot = GetOrCreateMethodSlot(method);
var pointerSize = method.Context.Target.PointerSize;
LLVMTypeRef universalSignature = LLVM.FunctionType(LLVM.VoidType(), new LLVMTypeRef[] { LLVM.PointerType(LLVM.Int8Type(), 0), LLVM.PointerType(LLVM.Int8Type(), 0) }, false);
LLVMTypeRef llvmSignature = GetLLVMSignatureForMethod(method.Signature);
LLVMValueRef functionPtr;
if (method.OwningType.IsInterface)
{
@ -1188,11 +1373,11 @@ namespace Internal.IL
var interfaceEEType = new LoadExpressionEntry(StackValueKind.ValueType, "interfaceEEType", GetEETypePointerForTypeDesc(method.OwningType, true), eeTypeDesc);
var eeTypeExpression = new LoadExpressionEntry(StackValueKind.ValueType, "eeType", objectPtr.ValueAsType(LLVM.PointerType(LLVM.Int8Type(), 0), _builder), eeTypeDesc);
var targetEntry = CallRuntime(_compilation.TypeSystemContext, DispatchResolve, "FindInterfaceMethodImplementationTarget", new StackEntry[] { eeTypeExpression, interfaceEEType, new ExpressionEntry(StackValueKind.Int32, "slot", slot, GetWellKnownType(WellKnownType.UInt16)) });
functionPtr = targetEntry.ValueAsType(LLVM.PointerType(universalSignature, 0), _builder);
functionPtr = targetEntry.ValueAsType(LLVM.PointerType(llvmSignature, 0), _builder);
}
else
{
var rawObjectPtr = CastIfNecessary(objectPtr.ValueAsType(LLVM.PointerType(LLVM.Int8Type(), 0), _builder), LLVM.PointerType(LLVM.PointerType(LLVM.PointerType(universalSignature, 0), 0), 0), objectPtr.Name());
var rawObjectPtr = CastIfNecessary(objectPtr.ValueAsType(LLVM.PointerType(LLVM.Int8Type(), 0), _builder), LLVM.PointerType(LLVM.PointerType(LLVM.PointerType(llvmSignature, 0), 0), 0), objectPtr.Name());
var eeType = LLVM.BuildLoad(_builder, rawObjectPtr, "ldEEType");
var slotPtr = LLVM.BuildGEP(_builder, eeType, new LLVMValueRef[] { slot }, "__getslot__");
functionPtr = LLVM.BuildLoad(_builder, slotPtr, "ld__getslot__");
@ -1201,6 +1386,42 @@ namespace Internal.IL
return functionPtr;
}
private LLVMTypeRef GetLLVMSignatureForMethod(MethodSignature signature)
{
TypeDesc returnType = signature.ReturnType;
LLVMTypeRef llvmReturnType;
bool returnOnStack = false;
if (!NeedsReturnStackSlot(signature))
{
returnOnStack = true;
llvmReturnType = GetLLVMTypeForTypeDesc(returnType);
}
else
{
llvmReturnType = LLVM.VoidType();
}
List<LLVMTypeRef> signatureTypes = new List<LLVMTypeRef>();
signatureTypes.Add(LLVM.PointerType(LLVM.Int8Type(), 0)); // Shadow stack pointer
if (!returnOnStack && returnType != GetWellKnownType(WellKnownType.Void))
{
signatureTypes.Add(LLVM.PointerType(LLVM.Int8Type(), 0));
}
// Intentionally skipping the 'this' pointer since it could always be a GC reference
// and thus must be on the shadow stack
foreach (TypeDesc type in signature)
{
if (CanStoreTypeOnStack(type))
{
signatureTypes.Add(GetLLVMTypeForTypeDesc(type));
}
}
return LLVM.FunctionType(llvmReturnType, signatureTypes.ToArray(), false);
}
private ExpressionEntry AllocateObject(TypeDesc type)
{
MetadataType metadataType = (MetadataType)type;
@ -1341,6 +1562,23 @@ namespace Internal.IL
return true;
}
break;
case ".ctor":
if (metadataType.IsByReferenceOfT)
{
StackEntry byRefValueParamHolder = _stack.Pop();
// Allocate a slot on the shadow stack for the ByReference type
int spillIndex = _spilledExpressions.Count;
SpilledExpressionEntry spillEntry = new SpilledExpressionEntry(StackValueKind.ByRef, "byref" + _currentOffset, metadataType, spillIndex, this);
_spilledExpressions.Add(spillEntry);
LLVMValueRef addrOfValueType = LoadVarAddress(spillIndex, LocalVarKind.Temp, out TypeDesc unused);
var typedAddress = CastIfNecessary(_builder, addrOfValueType, LLVM.PointerType(LLVM.Int32Type(), 0));
LLVM.BuildStore(_builder, byRefValueParamHolder.ValueForStackKind(StackValueKind.ByRef, _builder, false), typedAddress);
_stack.Push(spillEntry);
return true;
}
break;
}
return false;
@ -1371,10 +1609,12 @@ namespace Internal.IL
var pointerSize = _compilation.NodeFactory.Target.PointerSize;
LLVMValueRef returnAddress;
LLVMValueRef castReturnAddress;
LLVMValueRef castReturnAddress = default;
TypeDesc returnType = signature.ReturnType;
bool needsReturnSlot = NeedsReturnStackSlot(signature);
SpilledExpressionEntry returnSlot = null;
if (!returnType.IsVoid)
if (needsReturnSlot)
{
int returnIndex = _spilledExpressions.Count;
returnSlot = new SpilledExpressionEntry(GetStackValueKind(returnType), callee?.Name + "_return", returnType, returnIndex, this);
@ -1382,11 +1622,6 @@ namespace Internal.IL
returnAddress = LoadVarAddress(returnIndex, LocalVarKind.Temp, out TypeDesc unused);
castReturnAddress = LLVM.BuildPointerCast(_builder, returnAddress, LLVM.PointerType(LLVM.Int8Type(), 0), callee?.Name + "_castreturn");
}
else
{
returnAddress = LLVM.ConstNull(LLVM.PointerType(LLVM.Int8Type(), 0));
castReturnAddress = returnAddress;
}
int offset = GetTotalParameterOffset() + GetTotalLocalOffset();
LLVMValueRef shadowStack = LLVM.BuildGEP(_builder, LLVM.GetFirstParam(_llvmFunction),
@ -1394,16 +1629,25 @@ namespace Internal.IL
String.Empty);
var castShadowStack = LLVM.BuildPointerCast(_builder, shadowStack, LLVM.PointerType(LLVM.Int8Type(), 0), "castshadowstack");
// argument offset
List<LLVMValueRef> llvmArgs = new List<LLVMValueRef>();
llvmArgs.Add(castShadowStack);
if (needsReturnSlot)
{
llvmArgs.Add(castReturnAddress);
}
// argument offset on the shadow stack
int argOffset = 0;
var instanceAdjustment = signature.IsStatic ? 0 : 1;
for (int index = 0; index < argumentValues.Length; index++)
{
StackEntry toStore = argumentValues[index];
bool isThisParameter = false;
TypeDesc argType;
if (index == 0 && !signature.IsStatic)
{
isThisParameter = true;
if (opcode == ILOpcode.calli)
argType = toStore.Type;
else if (callee.OwningType.IsValueType)
@ -1416,15 +1660,25 @@ namespace Internal.IL
argType = signature[index - instanceAdjustment];
}
LLVMTypeRef valueType = GetLLVMTypeForTypeDesc(argType);
LLVMValueRef argValue = toStore.ValueAsType(valueType, _builder);
// Pass arguments as parameters if possible
if (!isThisParameter && CanStoreTypeOnStack(argType))
{
llvmArgs.Add(argValue);
}
// Otherwise store them on the shadow stack
else
{
// The previous argument might have left this type unaligned, so pad if necessary
argOffset = PadOffset(argType, argOffset);
LLVMTypeRef valueType = GetLLVMTypeForTypeDesc(argType);
ImportStoreHelper(toStore.ValueAsType(valueType, _builder), valueType, castShadowStack, (uint)argOffset);
ImportStoreHelper(argValue, valueType, castShadowStack, (uint)argOffset);
argOffset += argType.GetElementSize().AsInt;
}
}
LLVMValueRef fn;
if (opcode == ILOpcode.calli)
@ -1436,16 +1690,20 @@ namespace Internal.IL
fn = LLVMFunctionForMethod(callee, signature.IsStatic ? null : argumentValues[0], opcode == ILOpcode.callvirt);
}
LLVM.BuildCall(_builder, fn, new LLVMValueRef[] {
castShadowStack,
castReturnAddress}, string.Empty);
LLVMValueRef llvmReturn = LLVM.BuildCall(_builder, fn, llvmArgs.ToArray(), string.Empty);
if (!returnType.IsVoid)
{
if (needsReturnSlot)
{
return returnSlot;
}
else
{
return new ExpressionEntry(GetStackValueKind(returnType), callee?.Name + "_return", llvmReturn, returnType);
}
}
else
{
return null;
}
@ -1641,15 +1899,35 @@ namespace Internal.IL
curOffset = PadNextOffset(method.Signature.ReturnType, curOffset);
LLVMValueRef calleeFrame = LLVM.BuildGEP(builder, shadowStack, new LLVMValueRef[] { BuildConstInt32(curOffset) }, "calleeFrame");
List<LLVMValueRef> llvmArgs = new List<LLVMValueRef>();
llvmArgs.Add(calleeFrame);
bool needsReturnSlot = NeedsReturnStackSlot(method.Signature);
if (needsReturnSlot)
{
// Slot for return value if necessary
llvmArgs.Add(shadowStack);
}
for (int i = 0; i < llvmParams.Length; i++)
{
LLVMValueRef argValue = LLVM.GetParam(thunkFunc, (uint)i);
if (CanStoreTypeOnStack(method.Signature[i]))
{
llvmArgs.Add(argValue);
}
else
{
curOffset = PadOffset(method.Signature[i], curOffset);
LLVMValueRef argAddr = LLVM.BuildGEP(builder, shadowStack, new LLVMValueRef[] { LLVM.ConstInt(LLVM.Int32Type(), (ulong)curOffset, LLVMMisc.False) }, "arg" + i);
LLVM.BuildStore(builder, LLVM.GetParam(thunkFunc, (uint)i), CastIfNecessary(builder, argAddr, LLVM.PointerType(llvmParams[i], 0), $"parameter{i}_"));
LLVM.BuildStore(builder, argValue, CastIfNecessary(builder, argAddr, LLVM.PointerType(llvmParams[i], 0), $"parameter{i}_"));
curOffset = PadNextOffset(method.Signature[i], curOffset);
}
}
LLVM.BuildCall(builder, managedFunction, new LLVMValueRef[] { calleeFrame, shadowStack }, "");
LLVMValueRef llvmReturnValue = LLVM.BuildCall(builder, managedFunction, llvmArgs.ToArray(), "");
if (method.IsNativeCallable)
{
@ -1657,11 +1935,18 @@ namespace Internal.IL
LLVM.BuildCall(builder, RhpReversePInvokeReturn2, new LLVMValueRef[] { reversePInvokeFrame }, "");
}
if (method.Signature.ReturnType != compilation.TypeSystemContext.GetWellKnownType(WellKnownType.Void))
if (!method.Signature.ReturnType.IsVoid)
{
if (needsReturnSlot)
{
LLVM.BuildRet(builder, LLVM.BuildLoad(builder, CastIfNecessary(builder, shadowStack, LLVM.PointerType(GetLLVMTypeForTypeDesc(method.Signature.ReturnType), 0)), "returnValue"));
}
else
{
LLVM.BuildRet(builder, llvmReturnValue);
}
}
else
{
LLVM.BuildRetVoid(builder);
}
@ -1670,7 +1955,7 @@ namespace Internal.IL
private void ImportCalli(int token)
{
MethodSignature methodSignature = (MethodSignature)_methodIL.GetObject(token);
HandleCall(null, methodSignature, ILOpcode.calli, ((ExpressionEntry)_stack.Pop()).ValueAsType(LLVM.PointerType(_universalSignature, 0), _builder));
HandleCall(null, methodSignature, ILOpcode.calli, ((ExpressionEntry)_stack.Pop()).ValueAsType(LLVM.PointerType(GetLLVMSignatureForMethod(methodSignature), 0), _builder));
}
private void ImportLdFtn(int token, ILOpcode opCode)
@ -1693,7 +1978,7 @@ namespace Internal.IL
if (targetLLVMFunction.Pointer.Equals(IntPtr.Zero))
{
targetLLVMFunction = GetOrCreateLLVMFunction(_compilation.NameMangler.GetMangledMethodName(method).ToString());
targetLLVMFunction = GetOrCreateLLVMFunction(_compilation.NameMangler.GetMangledMethodName(method).ToString(), method.Signature);
}
var entry = new FunctionPointerEntry("ldftn", method, targetLLVMFunction, GetWellKnownType(WellKnownType.IntPtr), opCode == ILOpcode.ldvirtftn);

Просмотреть файл

@ -0,0 +1,78 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Runtime.InteropServices;
using LLVMSharp;
namespace ILCompiler.WebAssembly
{
// LLVM P/Invokes copied from LLVMSharp that match the current LLVM surface area.
// If we get a new version of LLVMSharp containing these, this file should be removed.
internal class LLVMPInvokes
{
const string libraryPath = "libLLVM";
[DllImport(libraryPath, CallingConvention = CallingConvention.Cdecl)]
public static extern LLVMDIBuilderRef LLVMCreateDIBuilder(LLVMModuleRef M);
[DllImport(libraryPath, EntryPoint = "LLVMDIBuilderCreateCompileUnit", CallingConvention = CallingConvention.Cdecl)]
public static extern LLVMMetadataRef LLVMDIBuilderCreateCompileUnit(LLVMDIBuilderRef @Builder, LLVMDWARFSourceLanguage @Lang, LLVMMetadataRef @FileRef, [MarshalAs(UnmanagedType.LPStr)] string @Producer, size_t @ProducerLen, LLVMBool @isOptimized, [MarshalAs(UnmanagedType.LPStr)] string @Flags, size_t @FlagsLen, uint @RuntimeVer, [MarshalAs(UnmanagedType.LPStr)] string @SplitName, size_t @SplitNameLen, LLVMDWARFEmissionKind @Kind, uint @DWOId, LLVMBool @SplitDebugInlining, LLVMBool @DebugInfoForProfiling);
[DllImport(libraryPath, EntryPoint = "LLVMDIBuilderCreateFile", CallingConvention = CallingConvention.Cdecl)]
public static extern LLVMMetadataRef LLVMDIBuilderCreateFile(LLVMDIBuilderRef @Builder, [MarshalAs(UnmanagedType.LPStr)] string @Filename, size_t @FilenameLen, [MarshalAs(UnmanagedType.LPStr)] string @Directory, size_t @DirectoryLen);
[DllImport(libraryPath, EntryPoint = "LLVMDIBuilderCreateDebugLocation", CallingConvention = CallingConvention.Cdecl)]
public static extern LLVMMetadataRef LLVMDIBuilderCreateDebugLocation(LLVMContextRef @Ctx, uint @Line, uint @Column, LLVMMetadataRef @Scope, LLVMMetadataRef @InlinedAt);
}
internal enum LLVMDWARFSourceLanguage : int
{
@LLVMDWARFSourceLanguageC89 = 0,
@LLVMDWARFSourceLanguageC = 1,
@LLVMDWARFSourceLanguageAda83 = 2,
@LLVMDWARFSourceLanguageC_plus_plus = 3,
@LLVMDWARFSourceLanguageCobol74 = 4,
@LLVMDWARFSourceLanguageCobol85 = 5,
@LLVMDWARFSourceLanguageFortran77 = 6,
@LLVMDWARFSourceLanguageFortran90 = 7,
@LLVMDWARFSourceLanguagePascal83 = 8,
@LLVMDWARFSourceLanguageModula2 = 9,
@LLVMDWARFSourceLanguageJava = 10,
@LLVMDWARFSourceLanguageC99 = 11,
@LLVMDWARFSourceLanguageAda95 = 12,
@LLVMDWARFSourceLanguageFortran95 = 13,
@LLVMDWARFSourceLanguagePLI = 14,
@LLVMDWARFSourceLanguageObjC = 15,
@LLVMDWARFSourceLanguageObjC_plus_plus = 16,
@LLVMDWARFSourceLanguageUPC = 17,
@LLVMDWARFSourceLanguageD = 18,
@LLVMDWARFSourceLanguagePython = 19,
@LLVMDWARFSourceLanguageOpenCL = 20,
@LLVMDWARFSourceLanguageGo = 21,
@LLVMDWARFSourceLanguageModula3 = 22,
@LLVMDWARFSourceLanguageHaskell = 23,
@LLVMDWARFSourceLanguageC_plus_plus_03 = 24,
@LLVMDWARFSourceLanguageC_plus_plus_11 = 25,
@LLVMDWARFSourceLanguageOCaml = 26,
@LLVMDWARFSourceLanguageRust = 27,
@LLVMDWARFSourceLanguageC11 = 28,
@LLVMDWARFSourceLanguageSwift = 29,
@LLVMDWARFSourceLanguageJulia = 30,
@LLVMDWARFSourceLanguageDylan = 31,
@LLVMDWARFSourceLanguageC_plus_plus_14 = 32,
@LLVMDWARFSourceLanguageFortran03 = 33,
@LLVMDWARFSourceLanguageFortran08 = 34,
@LLVMDWARFSourceLanguageRenderScript = 35,
@LLVMDWARFSourceLanguageBLISS = 36,
@LLVMDWARFSourceLanguageMips_Assembler = 37,
@LLVMDWARFSourceLanguageGOOGLE_RenderScript = 38,
@LLVMDWARFSourceLanguageBORLAND_Delphi = 39,
}
internal enum LLVMDWARFEmissionKind : int
{
@LLVMDWARFEmissionNone = 0,
@LLVMDWARFEmissionFull = 1,
@LLVMDWARFEmissionLineTablesOnly = 2,
}
}

Просмотреть файл

@ -143,6 +143,8 @@ namespace ILCompiler.DependencyAnalysis
// this is the llvm instance.
public LLVMModuleRef Module { get; }
public LLVMDIBuilderRef DIBuilder { get; }
// This is used to build mangled names
private Utf8StringBuilder _sb = new Utf8StringBuilder();
@ -180,6 +182,9 @@ namespace ILCompiler.DependencyAnalysis
}
EmitNativeMain();
EmitDebugMetadata();
LLVM.WriteBitcodeToFile(Module, _objectFilePath);
#if DEBUG
LLVM.PrintModuleToFile(Module, Path.ChangeExtension(_objectFilePath, ".txt"), out string unused2);
@ -189,6 +194,25 @@ namespace ILCompiler.DependencyAnalysis
//throw new NotImplementedException(); // This function isn't complete
}
private void EmitDebugMetadata()
{
var dwarfVersion = LLVM.MDNode(new[]
{
LLVM.ConstInt(LLVM.Int32Type(), 2, false),
LLVM.MDString("Dwarf Version", 13),
LLVM.ConstInt(LLVM.Int32Type(), 4, false)
});
var dwarfSchemaVersion = LLVM.MDNode(new[]
{
LLVM.ConstInt(LLVM.Int32Type(), 2, false),
LLVM.MDString("Debug Info Version", 18),
LLVM.ConstInt(LLVM.Int32Type(), 3, false)
});
LLVM.AddNamedMetadataOperand(Module, "llvm.module.flags", dwarfVersion);
LLVM.AddNamedMetadataOperand(Module, "llvm.module.flags", dwarfSchemaVersion);
LLVM.DIBuilderFinalize(DIBuilder);
}
public static LLVMValueRef GetConstZeroArray(int length)
{
var int8Type = LLVM.Int8Type();
@ -269,22 +293,18 @@ namespace ILCompiler.DependencyAnalysis
LLVM.BuildStore(builder, castShadowStack, shadowStackTop);
// Pass on main arguments
var argcSlot = LLVM.BuildPointerCast(builder, shadowStack, LLVM.PointerType(LLVM.Int32Type(), 0), "argcSlot");
LLVM.BuildStore(builder, LLVM.GetParam(mainFunc, 0), argcSlot);
var argvSlot = LLVM.BuildGEP(builder, castShadowStack, new LLVMValueRef[] { LLVM.ConstInt(LLVM.Int32Type(), 4, LLVMMisc.False) }, "argvSlot");
LLVM.BuildStore(builder, LLVM.GetParam(mainFunc, 1), LLVM.BuildPointerCast(builder, argvSlot, LLVM.PointerType(LLVM.PointerType(LLVM.Int8Type(), 0), 0), ""));
LLVMValueRef argc = LLVM.GetParam(mainFunc, 0);
LLVMValueRef argv = LLVM.GetParam(mainFunc, 1);
// StartupCodeMain will always return a value whether the user's main does or not
LLVMValueRef returnValueSlot = LLVM.BuildAlloca(builder, LLVM.Int32Type(), "returnValue");
LLVM.BuildCall(builder, managedMain, new LLVMValueRef[]
LLVMValueRef mainReturn = LLVM.BuildCall(builder, managedMain, new LLVMValueRef[]
{
castShadowStack,
LLVM.BuildPointerCast(builder, returnValueSlot, LLVM.PointerType(LLVM.Int8Type(), 0), String.Empty)
argc,
argv,
},
String.Empty);
"returnValue");
LLVM.BuildRet(builder, LLVM.BuildLoad(builder, returnValueSlot, String.Empty));
LLVM.BuildRet(builder, mainReturn);
LLVM.SetLinkage(mainFunc, LLVMLinkage.LLVMExternalLinkage);
}
@ -648,6 +668,7 @@ namespace ILCompiler.DependencyAnalysis
_nodeFactory = factory;
_objectFilePath = objectFilePath;
Module = compilation.Module;
DIBuilder = compilation.DIBuilder;
}
public void Dispose()

Просмотреть файл

@ -9,6 +9,7 @@ using Internal.TypeSystem;
using ILCompiler.DependencyAnalysis;
using ILCompiler.DependencyAnalysisFramework;
using LLVMSharp;
using ILCompiler.WebAssembly;
namespace ILCompiler
{
@ -17,18 +18,23 @@ namespace ILCompiler
internal WebAssemblyCodegenConfigProvider Options { get; }
internal LLVMModuleRef Module { get; }
public new WebAssemblyCodegenNodeFactory NodeFactory { get; }
internal LLVMDIBuilderRef DIBuilder { get; }
internal Dictionary<string, DebugMetadata> DebugMetadataMap { get; }
internal WebAssemblyCodegenCompilation(
DependencyAnalyzerBase<NodeFactory> dependencyGraph,
WebAssemblyCodegenNodeFactory nodeFactory,
IEnumerable<ICompilationRootProvider> roots,
DebugInformationProvider debugInformationProvider,
Logger logger,
WebAssemblyCodegenConfigProvider options)
: base(dependencyGraph, nodeFactory, GetCompilationRoots(roots, nodeFactory), null, null, logger)
: base(dependencyGraph, nodeFactory, GetCompilationRoots(roots, nodeFactory), debugInformationProvider, null, logger)
{
NodeFactory = nodeFactory;
Module = LLVM.ModuleCreateWithName("netscripten");
LLVM.SetTarget(Module, "asmjs-unknown-emscripten");
Options = options;
DIBuilder = LLVMPInvokes.LLVMCreateDIBuilder(Module);
DebugMetadataMap = new Dictionary<string, DebugMetadata>();
}
private static IEnumerable<ICompilationRootProvider> GetCompilationRoots(IEnumerable<ICompilationRootProvider> existingRoots, NodeFactory factory)

Просмотреть файл

@ -34,8 +34,7 @@ namespace ILCompiler
var interopStubManager = new CompilerGeneratedInteropStubManager(_compilationGroup, _context, new InteropStateManager(_context.GeneratedAssembly));
WebAssemblyCodegenNodeFactory factory = new WebAssemblyCodegenNodeFactory(_context, _compilationGroup, _metadataManager, interopStubManager, _nameMangler, _vtableSliceProvider, _dictionaryLayoutProvider);
DependencyAnalyzerBase<NodeFactory> graph = CreateDependencyGraph(factory, new ObjectNode.ObjectNodeComparer(new CompilerComparer()));
return new WebAssemblyCodegenCompilation(graph, factory, _compilationRoots, _logger, _config);
return new WebAssemblyCodegenCompilation(graph, factory, _compilationRoots, _debugInformationProvider, _logger, _config);
}
}

Просмотреть файл

@ -37,8 +37,10 @@
<Compile Include="..\..\Common\src\TypeSystem\IL\HelperExtensions.cs">
<Link>IL\HelperExtensions.cs</Link>
</Compile>
<Compile Include="CodeGen\DebugMetadata.cs" />
<Compile Include="CodeGen\ILToWebAssemblyImporter_Statics.cs" />
<Compile Include="CodeGen\LLVMMisc.cs" />
<Compile Include="CodeGen\LLVMPInvokes.cs" />
<Compile Include="CodeGen\WebAssemblyObjectWriter.cs" />
<Compile Include="Compiler\DependencyAnalysis\RawMainMethodRootProvider.cs" />
<Compile Include="Compiler\DependencyAnalysis\WebAssemblyCodegenNodeFactory.cs" />
@ -56,13 +58,13 @@
<Content Include="..\..\..\packages\llvmsharp\5.0.0\lib\netstandard1.1\LLVMSharp.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="..\..\..\packages\libllvm\4.0.0\runtimes\osx\native\libLLVM.dylib" Condition="'$(NuPkgRid)' == 'osx-x64'">
<Content Include="..\..\..\packages\libllvm\6.0.0-beta1\runtimes\osx\native\libLLVM.dylib" Condition="'$(NuPkgRid)' == 'osx-x64'">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="..\..\..\packages\libllvm\4.0.0\runtimes\linux-x64\native\libLLVM.so" Condition="'$(NuPkgRid)' == 'linux-x64'">
<Content Include="..\..\..\packages\libllvm\6.0.0-beta1\runtimes\linux-x64\native\libLLVM.so" Condition="'$(NuPkgRid)' == 'linux-x64'">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="..\..\..\packages\libllvm\4.0.0\runtimes\win-x64\native\libLLVM.dll" Condition="'$(NuPkgRid)' == 'win-x64' or '$(NuPkgRid)' == ''">
<Content Include="..\..\..\packages\libllvm\6.0.0-beta1\runtimes\win-x64\native\libLLVM.dll" Condition="'$(NuPkgRid)' == 'win-x64' or '$(NuPkgRid)' == ''">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>

Просмотреть файл

@ -13,7 +13,7 @@
<ItemGroup>
<PackageReference Include="libLLVM">
<Version>4.0.0</Version>
<Version>6.0.0-beta1</Version>
</PackageReference>
</ItemGroup>

Просмотреть файл

@ -463,6 +463,8 @@ namespace ILCompiler
if (_completeTypesMetadata)
metadataGenerationOptions |= UsageBasedMetadataGenerationOptions.CompleteTypesOnly;
DynamicInvokeThunkGenerationPolicy invokeThunkGenerationPolicy = new DefaultDynamicInvokeThunkGenerationPolicy();
UsageBasedMetadataManager metadataManager = new UsageBasedMetadataManager(
compilationGroup,
typeSystemContext,
@ -470,6 +472,7 @@ namespace ILCompiler
resBlockingPolicy,
_metadataLogFileName,
stackTracePolicy,
invokeThunkGenerationPolicy,
metadataGenerationOptions
);

Просмотреть файл

@ -921,13 +921,13 @@ void ObjectWriter::EmitARMExIdxCode(int Offset, const char *Blob)
ATS.emitPad(CfiCode->Offset);
break;
case CFI_REL_OFFSET:
RegList.push_back(CfiCode->DwarfReg);
RegList.push_back(CfiCode->DwarfReg + 14); // See ARMRegEncodingTable in ARMGenRegisterInfo.inc by getEncodingValue
ATS.emitRegSave(RegList, false);
break;
case CFI_DEF_CFA_REGISTER:
assert(CfiCode->Offset == 0 &&
"Unexpected Offset Value for OpDefCfaRegister");
ATS.emitMovSP(CfiCode->DwarfReg, 0);
ATS.emitMovSP(CfiCode->DwarfReg + 14, 0); // See ARMRegEncodingTable in ARMGenRegisterInfo.inc by getEncodingValue
break;
default:
assert(false && "Unrecognized CFI");

Просмотреть файл

@ -1327,7 +1327,6 @@ bool EECodeManager::GetEpilogOffset(
// ARM64 epilogs have a window between loading the hijackable return address into LR and the RET instruction.
// We cannot hijack or unhijack a thread while it is suspended in that window unless we implement hijacking
// via LR register modification.
#ifndef _ARM64_
void ** EECodeManager::GetReturnAddressLocationFromEpilog(GCInfoHeader * pInfoHeader, REGDISPLAY * pContext,
UInt32 epilogOffset, UInt32 epilogSize)
{
@ -1740,7 +1739,6 @@ void ** EECodeManager::GetReturnAddressLocationFromEpilog(GCInfoHeader * pInfoHe
#endif
}
#endif // _ARM64_
#ifdef _DEBUG

Просмотреть файл

@ -207,6 +207,7 @@ NESTED_ENTRY RhpRethrow, _TEXT, NoHandler
mov [rsi + OFFSETOF__ExInfo__m_exception], rdx // init the exception object to null
mov byte ptr [rsi + OFFSETOF__ExInfo__m_passNumber], 1 // init to the first pass
mov dword ptr [rsi + OFFSETOF__ExInfo__m_idxCurClause], 0xFFFFFFFF
mov byte ptr [rsi + OFFSETOF__ExInfo__m_kind], 0 // init to a deterministic value (ExKind.None)
// link the ExInfo into the thread's ExInfo chain

Просмотреть файл

@ -254,6 +254,7 @@ NESTED_ENTRY RhpRethrow, _TEXT
mov [rdx + OFFSETOF__ExInfo__m_exception], r8 ;; init the exception object to null
mov byte ptr [rdx + OFFSETOF__ExInfo__m_passNumber], 1 ;; init to the first pass
mov dword ptr [rdx + OFFSETOF__ExInfo__m_idxCurClause], 0FFFFFFFFh
mov byte ptr [rdx + OFFSETOF__ExInfo__m_kind], 0 ;; init to a deterministic value (ExKind.None)
;; link the ExInfo into the thread's ExInfo chain

Просмотреть файл

@ -206,6 +206,7 @@ NESTED_ENTRY RhpRethrow, _TEXT, NoHandler
mov r3, #0
str r3, [r1, #OFFSETOF__ExInfo__m_exception] // init the exception object to null
strb r3, [r1, #OFFSETOF__ExInfo__m_kind] // init to a deterministic value (ExKind.None)
mov r3, #0xFFFFFFFF
str r3, [r1, #OFFSETOF__ExInfo__m_idxCurClause]

Просмотреть файл

@ -211,6 +211,7 @@ NotHijacked
add r1, sp, #rsp_offsetof_ExInfo ;; r1 <- ExInfo*
mov r3, #0
str r3, [r1, #OFFSETOF__ExInfo__m_exception] ;; pExInfo->m_exception = null
strb r3, [r1, #OFFSETOF__ExInfo__m_kind] ;; init to a deterministic value (ExKind.None)
mov r3, #1
strb r3, [r1, #OFFSETOF__ExInfo__m_passNumber] ;; pExInfo->m_passNumber = 1
mov r3, #0xFFFFFFFF

Просмотреть файл

@ -360,6 +360,7 @@ NotHijacked
add x1, sp, #rsp_offsetof_ExInfo ;; x1 <- ExInfo*
str xzr, [x1, #OFFSETOF__ExInfo__m_exception] ;; pExInfo->m_exception = null
strb wzr, [x1, #OFFSETOF__ExInfo__m_kind] ;; init to a deterministic value (ExKind.None)
mov w3, #1
strb w3, [x1, #OFFSETOF__ExInfo__m_passNumber] ;; pExInfo->m_passNumber = 1
mov w3, #0xFFFFFFFF

Просмотреть файл

@ -207,6 +207,7 @@ FASTCALL_FUNC RhpRethrow, 0
mov [edx + OFFSETOF__ExInfo__m_exception], esi ;; init the exception object to null
mov byte ptr [edx + OFFSETOF__ExInfo__m_passNumber], 1 ;; init to the first pass
mov dword ptr [edx + OFFSETOF__ExInfo__m_idxCurClause], 0FFFFFFFFh
mov byte ptr [edx + OFFSETOF__ExInfo__m_kind], 0 ;; init to a deterministic value (ExKind.None)
;; link the ExInfo into the thread's ExInfo chain
mov ecx, [eax + OFFSETOF__Thread__m_pExInfoStackHead] ;; ecx <- currently active ExInfo

Просмотреть файл

@ -46,7 +46,9 @@ struct ExInfo;
typedef DPTR(ExInfo) PTR_ExInfo;
// also defined in ExceptionHandling.cs, layouts must match
// Also defined in ExceptionHandling.cs, layouts must match.
// When adding new fields to this struct, ensure they get properly initialized in the exception handling
// assembly stubs
struct ExInfo
{

Просмотреть файл

@ -232,11 +232,11 @@ int unw_get_save_loc(unw_cursor_t*, int, unw_save_loc_t*)
static void RegDisplayToUnwindCursor(REGDISPLAY* regDisplay, unw_cursor_t *cursor)
{
#define ASSIGN_REG(regName1, regName2) \
unw_set_reg(cursor, regName1, regDisplay->regName2);
unw_set_reg(cursor, regName1, regDisplay->regName2, 0);
#define ASSIGN_REG_PTR(regName1, regName2) \
if (regDisplay->p##regName2 != NULL) \
unw_set_reg(cursor, regName1, *(regDisplay->p##regName2));
unw_set_reg(cursor, regName1, *(regDisplay->p##regName2), 0);
#if defined(_AMD64_)
ASSIGN_REG(UNW_REG_SP, SP)

Просмотреть файл

@ -292,13 +292,152 @@ struct Registers_REGDISPLAY : REGDISPLAY
};
#endif // _TARGET_AMD64_
#if defined(_TARGET_ARM_)
class Registers_arm_rt: public libunwind::Registers_arm {
public:
Registers_arm_rt() { abort(); };
Registers_arm_rt(void *registers) { regs = (REGDISPLAY *)registers; };
uint32_t getRegister(int num);
void setRegister(int num, uint32_t value, uint32_t location);
uint32_t getRegisterLocation(int regNum) const { abort();}
unw_fpreg_t getFloatRegister(int num) { abort();}
void setFloatRegister(int num, unw_fpreg_t value) {abort();}
bool validVectorRegister(int num) const { abort();}
uint32_t getVectorRegister(int num) const {abort();};
void setVectorRegister(int num, uint32_t value) {abort();};
void jumpto() { abort();};
uint32_t getSP() const { return regs->SP;}
void setSP(uint32_t value, uint32_t location) { regs->SP = value;}
uint32_t getIP() const { return regs->IP;}
void setIP(uint32_t value, uint32_t location)
{ regs->IP = value; regs->pIP = (PTR_UIntNative)location; }
void saveVFPAsX() {abort();};
private:
REGDISPLAY *regs;
};
inline uint32_t Registers_arm_rt::getRegister(int regNum) {
if (regNum == UNW_REG_SP || regNum == UNW_ARM_SP)
return regs->SP;
if (regNum == UNW_ARM_LR)
return *regs->pLR;
if (regNum == UNW_REG_IP || regNum == UNW_ARM_IP)
return regs->IP;
switch (regNum)
{
case (UNW_ARM_R0):
return *regs->pR0;
case (UNW_ARM_R1):
return *regs->pR1;
case (UNW_ARM_R2):
return *regs->pR2;
case (UNW_ARM_R3):
return *regs->pR3;
case (UNW_ARM_R4):
return *regs->pR4;
case (UNW_ARM_R5):
return *regs->pR5;
case (UNW_ARM_R6):
return *regs->pR6;
case (UNW_ARM_R7):
return *regs->pR7;
case (UNW_ARM_R8):
return *regs->pR8;
case (UNW_ARM_R9):
return *regs->pR9;
case (UNW_ARM_R10):
return *regs->pR10;
case (UNW_ARM_R11):
return *regs->pR11;
case (UNW_ARM_R12):
return *regs->pR12;
}
PORTABILITY_ASSERT("unsupported arm register");
}
void Registers_arm_rt::setRegister(int num, uint32_t value, uint32_t location)
{
if (num == UNW_REG_SP || num == UNW_ARM_SP) {
regs->SP = (UIntNative )value;
return;
}
if (num == UNW_ARM_LR) {
regs->pLR = (PTR_UIntNative)location;
return;
}
if (num == UNW_REG_IP || num == UNW_ARM_IP) {
regs->IP = value;
/* the location could be NULL, we could try to recover
pointer to value in stack from pLR */
if ((!location) && (regs->pLR) && (*regs->pLR == value))
regs->pIP = regs->pLR;
else
regs->pIP = (PTR_UIntNative)location;
return;
}
switch (num)
{
case (UNW_ARM_R0):
regs->pR0 = (PTR_UIntNative)location;
break;
case (UNW_ARM_R1):
regs->pR1 = (PTR_UIntNative)location;
break;
case (UNW_ARM_R2):
regs->pR2 = (PTR_UIntNative)location;
break;
case (UNW_ARM_R3):
regs->pR3 = (PTR_UIntNative)location;
break;
case (UNW_ARM_R4):
regs->pR4 = (PTR_UIntNative)location;
break;
case (UNW_ARM_R5):
regs->pR5 = (PTR_UIntNative)location;
break;
case (UNW_ARM_R6):
regs->pR6 = (PTR_UIntNative)location;
break;
case (UNW_ARM_R7):
regs->pR7 = (PTR_UIntNative)location;
break;
case (UNW_ARM_R8):
regs->pR8 = (PTR_UIntNative)location;
break;
case (UNW_ARM_R9):
regs->pR9 = (PTR_UIntNative)location;
break;
case (UNW_ARM_R10):
regs->pR10 = (PTR_UIntNative)location;
break;
case (UNW_ARM_R11):
regs->pR11 = (PTR_UIntNative)location;
break;
case (UNW_ARM_R12):
regs->pR12 = (PTR_UIntNative)location;
break;
default:
PORTABILITY_ASSERT("unsupported arm register");
}
}
#endif // _TARGET_ARM_
bool DoTheStep(uintptr_t pc, UnwindInfoSections uwInfoSections, REGDISPLAY *regs)
{
#if defined(_TARGET_AMD64_)
libunwind::UnwindCursor<LocalAddressSpace, Registers_x86_64> uc(_addressSpace);
#elif defined(_TARGET_ARM_)
libunwind::UnwindCursor<LocalAddressSpace, Registers_arm> uc(_addressSpace);
libunwind::UnwindCursor<LocalAddressSpace, Registers_arm_rt> uc(_addressSpace, regs);
#else
#error "Unwinding is not implemented for this architecture yet."
#endif
@ -322,8 +461,13 @@ bool DoTheStep(uintptr_t pc, UnwindInfoSections uwInfoSections, REGDISPLAY *regs
}
regs->pIP = PTR_PCODE(regs->SP - sizeof(TADDR));
#else
PORTABILITY_ASSERT("DoTheStep");
#elif defined(_LIBUNWIND_ARM_EHABI)
uc.setInfoBasedOnIPRegister(true);
int stepRet = uc.step();
if ((stepRet != UNW_STEP_SUCCESS) && (stepRet != UNW_STEP_END))
{
return false;
}
#endif
return true;
@ -365,18 +509,20 @@ UnwindInfoSections LocateUnwindSections(uintptr_t pc)
bool UnwindHelpers::StepFrame(REGDISPLAY *regs)
{
uintptr_t pc = regs->GetIP();
UnwindInfoSections uwInfoSections = LocateUnwindSections(pc);
#if _LIBUNWIND_SUPPORT_DWARF_UNWIND
uintptr_t pc = regs->GetIP();
UnwindInfoSections uwInfoSections = LocateUnwindSections(pc);
if (uwInfoSections.dwarf_section == NULL)
{
return false;
}
return DoTheStep(pc, uwInfoSections, regs);
#elif defined(_LIBUNWIND_ARM_EHABI)
// unwind section is located later for ARM
// pc will be taked from regs parameter
UnwindInfoSections uwInfoSections;
return DoTheStep(0, uwInfoSections, regs);
#else
PORTABILITY_ASSERT("StepFrame");
#endif
return DoTheStep(pc, uwInfoSections, regs);
}

Просмотреть файл

@ -6,3 +6,4 @@
#cmakedefine01 HAVE_MACH_ABSOLUTE_TIME
#cmakedefine01 HAVE_SCHED_GETCPU
#cmakedefine01 HAVE_GNU_LIBNAMES_H
#cmakedefine01 HAVE__NSGETENVIRON

Просмотреть файл

@ -1,6 +1,7 @@
include(CheckCXXSourceCompiles)
include(CheckCXXSourceRuns)
include(CheckLibraryExists)
include(CheckFunctionExists)
check_library_exists(pthread pthread_condattr_setclock "" HAVE_PTHREAD_CONDATTR_SETCLOCK)
@ -62,6 +63,8 @@ set(CMAKE_REQUIRED_LIBRARIES)
check_include_files(gnu/lib-names.h HAVE_GNU_LIBNAMES_H)
check_function_exists(_NSGetEnviron HAVE__NSGETENVIRON)
configure_file(
${CMAKE_CURRENT_SOURCE_DIR}/config.h.in
${CMAKE_CURRENT_BINARY_DIR}/config.h)

Просмотреть файл

@ -10,6 +10,9 @@
#if HAVE_SCHED_GETCPU
#include <sched.h>
#endif
#if HAVE__NSGETENVIRON
#include <crt_externs.h>
#endif
extern "C" char* CoreLibNative_GetEnv(const char* variable)
@ -30,3 +33,17 @@ extern "C" void CoreLibNative_Exit(int32_t exitCode)
{
exit(exitCode);
}
extern "C" char** CoreLibNative_GetEnviron()
{
char** sysEnviron;
#if HAVE__NSGETENVIRON
sysEnviron = *(_NSGetEnviron());
#else // HAVE__NSGETENVIRON
extern char **environ;
sysEnviron = environ;
#endif // HAVE__NSGETENVIRON
return sysEnviron;
}

Просмотреть файл

@ -124,7 +124,7 @@ extern int unw_init_local(unw_cursor_t *, unw_context_t *) LIBUNWIND_AVAIL;
extern int unw_step(unw_cursor_t *) LIBUNWIND_AVAIL;
extern int unw_get_reg(unw_cursor_t *, unw_regnum_t, unw_word_t *) LIBUNWIND_AVAIL;
extern int unw_get_fpreg(unw_cursor_t *, unw_regnum_t, unw_fpreg_t *) LIBUNWIND_AVAIL;
extern int unw_set_reg(unw_cursor_t *, unw_regnum_t, unw_word_t) LIBUNWIND_AVAIL;
extern int unw_set_reg(unw_cursor_t *, unw_regnum_t, unw_word_t, unw_word_t *) LIBUNWIND_AVAIL;
extern int unw_set_fpreg(unw_cursor_t *, unw_regnum_t, unw_fpreg_t) LIBUNWIND_AVAIL;
extern int unw_resume(unw_cursor_t *) LIBUNWIND_AVAIL;

Просмотреть файл

@ -200,7 +200,7 @@ _Unwind_VRS_Get(_Unwind_Context *context, _Unwind_VRS_RegClass regclass,
extern _Unwind_VRS_Result
_Unwind_VRS_Set(_Unwind_Context *context, _Unwind_VRS_RegClass regclass,
uint32_t regno, _Unwind_VRS_DataRepresentation representation,
void *valuep);
void *valuep, uint32_t *pos);
extern _Unwind_VRS_Result
_Unwind_VRS_Pop(_Unwind_Context *context, _Unwind_VRS_RegClass regclass,
@ -212,7 +212,7 @@ _Unwind_VRS_Pop(_Unwind_Context *context, _Unwind_VRS_RegClass regclass,
extern uintptr_t _Unwind_GetGR(struct _Unwind_Context *context, int index);
extern void _Unwind_SetGR(struct _Unwind_Context *context, int index,
uintptr_t new_value);
uintptr_t new_value, uintptr_t *pos);
extern uintptr_t _Unwind_GetIP(struct _Unwind_Context *context);
extern void _Unwind_SetIP(struct _Unwind_Context *, uintptr_t new_value);
@ -240,8 +240,8 @@ uintptr_t _Unwind_GetGR(struct _Unwind_Context *context, int index) {
_LIBUNWIND_EXPORT_UNWIND_LEVEL1
void _Unwind_SetGR(struct _Unwind_Context *context, int index,
uintptr_t value) {
_Unwind_VRS_Set(context, _UVRSC_CORE, (uint32_t)index, _UVRSD_UINT32, &value);
uintptr_t value,uintptr_t *pos) {
_Unwind_VRS_Set(context, _UVRSC_CORE, (uint32_t)index, _UVRSD_UINT32, &value, pos);
}
_LIBUNWIND_EXPORT_UNWIND_LEVEL1
@ -253,7 +253,7 @@ uintptr_t _Unwind_GetIP(struct _Unwind_Context *context) {
_LIBUNWIND_EXPORT_UNWIND_LEVEL1
void _Unwind_SetIP(struct _Unwind_Context *context, uintptr_t value) {
uintptr_t thumb_bit = _Unwind_GetGR(context, 15) & ((uintptr_t)0x1);
_Unwind_SetGR(context, 15, value | thumb_bit);
_Unwind_SetGR(context, 15, value | thumb_bit, NULL);
}
#endif // _LIBUNWIND_ARM_EHABI

Просмотреть файл

@ -259,7 +259,7 @@ _Unwind_VRS_Interpret(_Unwind_Context *context, const uint32_t *data,
sp -= (((uint32_t)byte & 0x3f) << 2) + 4;
else
sp += ((uint32_t)byte << 2) + 4;
_Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_SP, _UVRSD_UINT32, &sp);
_Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_SP, _UVRSD_UINT32, &sp, NULL);
} else {
switch (byte & 0xf0) {
case 0x80: {
@ -283,7 +283,7 @@ _Unwind_VRS_Interpret(_Unwind_Context *context, const uint32_t *data,
_Unwind_VRS_Get(context, _UVRSC_CORE, UNW_ARM_R0 + reg,
_UVRSD_UINT32, &sp);
_Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_SP, _UVRSD_UINT32,
&sp);
&sp, NULL);
break;
}
case 0xa0: {
@ -325,7 +325,7 @@ _Unwind_VRS_Interpret(_Unwind_Context *context, const uint32_t *data,
&sp);
sp += 0x204 + (addend << 2);
_Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_SP, _UVRSD_UINT32,
&sp);
&sp, NULL);
break;
}
case 0xb3: {
@ -411,7 +411,7 @@ _Unwind_VRS_Interpret(_Unwind_Context *context, const uint32_t *data,
if (!wrotePC) {
uint32_t lr;
_Unwind_VRS_Get(context, _UVRSC_CORE, UNW_ARM_LR, _UVRSD_UINT32, &lr);
_Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_IP, _UVRSD_UINT32, &lr);
_Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_IP, _UVRSD_UINT32, &lr, NULL);
}
return _URC_CONTINUE_UNWIND;
}
@ -559,7 +559,7 @@ static _Unwind_Reason_Code unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor
//
// See #7.4.6 for details.
unw_set_reg(cursor, UNW_REG_IP,
exception_object->unwinder_cache.reserved2);
exception_object->unwinder_cache.reserved2, NULL);
resume = false;
}
@ -753,7 +753,7 @@ static uint64_t ValueAsBitPattern(_Unwind_VRS_DataRepresentation representation,
_LIBUNWIND_EXPORT _Unwind_VRS_Result
_Unwind_VRS_Set(_Unwind_Context *context, _Unwind_VRS_RegClass regclass,
uint32_t regno, _Unwind_VRS_DataRepresentation representation,
void *valuep) {
void *valuep, unw_word_t *pos) {
_LIBUNWIND_TRACE_API("_Unwind_VRS_Set(context=%p, regclass=%d, reg=%d, "
"rep=%d, value=0x%llX)",
static_cast<void *>(context), regclass, regno,
@ -765,7 +765,7 @@ _Unwind_VRS_Set(_Unwind_Context *context, _Unwind_VRS_RegClass regclass,
if (representation != _UVRSD_UINT32 || regno > 15)
return _UVRSR_FAILED;
return unw_set_reg(cursor, (unw_regnum_t)(UNW_ARM_R0 + regno),
*(unw_word_t *)valuep) == UNW_ESUCCESS
*(unw_word_t *)valuep,(unw_word_t *)pos) == UNW_ESUCCESS
? _UVRSR_OK
: _UVRSR_FAILED;
case _UVRSC_VFP:
@ -897,6 +897,7 @@ _Unwind_VRS_Pop(_Unwind_Context *context, _Unwind_VRS_RegClass regclass,
// computed new stack location. See EHABI #7.5.4 table 3.
bool poppedSP = false;
uint32_t* sp;
uint32_t* pos;
if (_Unwind_VRS_Get(context, _UVRSC_CORE, UNW_ARM_SP,
_UVRSD_UINT32, &sp) != _UVRSR_OK) {
return _UVRSR_FAILED;
@ -904,17 +905,18 @@ _Unwind_VRS_Pop(_Unwind_Context *context, _Unwind_VRS_RegClass regclass,
for (uint32_t i = 0; i < 16; ++i) {
if (!(discriminator & static_cast<uint32_t>(1 << i)))
continue;
pos = sp;
uint32_t value = *sp++;
if (regclass == _UVRSC_CORE && i == 13)
poppedSP = true;
if (_Unwind_VRS_Set(context, regclass, i,
_UVRSD_UINT32, &value) != _UVRSR_OK) {
_UVRSD_UINT32, &value, pos) != _UVRSR_OK) {
return _UVRSR_FAILED;
}
}
if (!poppedSP) {
return _Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_SP,
_UVRSD_UINT32, &sp);
_UVRSD_UINT32, &sp, NULL);
}
return _UVRSR_OK;
}
@ -939,14 +941,14 @@ _Unwind_VRS_Pop(_Unwind_Context *context, _Unwind_VRS_RegClass regclass,
// SP is only 32-bit aligned so don't copy 64-bit at a time.
uint64_t value = *sp++;
value |= ((uint64_t)(*sp++)) << 32;
if (_Unwind_VRS_Set(context, regclass, i, representation, &value) !=
if (_Unwind_VRS_Set(context, regclass, i, representation, &value, NULL) !=
_UVRSR_OK)
return _UVRSR_FAILED;
}
if (representation == _UVRSD_VFPX)
++sp;
return _Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_SP, _UVRSD_UINT32,
&sp);
&sp, NULL);
}
}
_LIBUNWIND_ABORT("unsupported register class");

Просмотреть файл

@ -628,9 +628,11 @@ UnwindCursor<A, R>::UnwindCursor(unw_context_t *context, A &as)
}
template <typename A, typename R>
UnwindCursor<A, R>::UnwindCursor(A &as, void *)
: _addressSpace(as), _unwindInfoMissing(false), _isSignalFrame(false) {
UnwindCursor<A, R>::UnwindCursor(A &as, void *arg)
: _addressSpace(as),_registers(arg), _unwindInfoMissing(false),
_isSignalFrame(false) {
memset(&_info, 0, sizeof(_info));
// FIXME
// fill in _registers from thread arg
}

Просмотреть файл

@ -42,13 +42,8 @@
#endif
#else
#if defined(__ARM_DWARF_EH__) || !defined(__arm__)
#define _LIBUNWIND_SUPPORT_COMPACT_UNWIND 0
#define _LIBUNWIND_SUPPORT_DWARF_UNWIND 1
#define _LIBUNWIND_SUPPORT_DWARF_INDEX 1
#else
#define _LIBUNWIND_SUPPORT_COMPACT_UNWIND 0
#define _LIBUNWIND_SUPPORT_DWARF_UNWIND 0
#define _LIBUNWIND_SUPPORT_DWARF_INDEX 0
#endif
#endif

Просмотреть файл

@ -171,13 +171,13 @@ _LIBUNWIND_EXPORT int unw_get_reg(unw_cursor_t *cursor, unw_regnum_t regNum,
/// Set value of specified register at cursor position in stack frame.
_LIBUNWIND_EXPORT int unw_set_reg(unw_cursor_t *cursor, unw_regnum_t regNum,
unw_word_t value) {
unw_word_t value, unw_word_t *pos) {
_LIBUNWIND_TRACE_API("unw_set_reg(cursor=%p, regNum=%d, value=0x%llX)",
static_cast<void *>(cursor), regNum, (long long)value);
typedef LocalAddressSpace::pint_t pint_t;
AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
if (co->validReg(regNum)) {
co->setReg(regNum, (pint_t)value, 0);
co->setReg(regNum, (pint_t)value, (pint_t)pos);
// special case altering IP to re-find info (being called by personality
// function)
if (regNum == UNW_REG_IP)

Просмотреть файл

@ -2,15 +2,14 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Microsoft.Win32.SafeHandles;
using System;
using System.Runtime.InteropServices;
internal partial class Interop
{
internal partial class mincore
internal partial class Advapi32
{
[DllImport(Libraries.Registry_L1)]
internal extern static int RegCloseKey(IntPtr hKey);
[DllImport(Libraries.Advapi32)]
internal static extern int RegCloseKey(IntPtr hKey);
}
}

Просмотреть файл

@ -0,0 +1,65 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
internal partial class Interop
{
internal partial class Advapi32
{
internal static class RegistryOptions
{
internal const int REG_OPTION_NON_VOLATILE = 0x0000; // (default) keys are persisted beyond reboot/unload
internal const int REG_OPTION_VOLATILE = 0x0001; // All keys created by the function are volatile
internal const int REG_OPTION_CREATE_LINK = 0x0002; // They key is a symbolic link
internal const int REG_OPTION_BACKUP_RESTORE = 0x0004; // Use SE_BACKUP_NAME process special privileges
}
internal static class RegistryView
{
internal const int KEY_WOW64_64KEY = 0x0100;
internal const int KEY_WOW64_32KEY = 0x0200;
}
internal static class RegistryOperations
{
internal const int KEY_QUERY_VALUE = 0x0001;
internal const int KEY_SET_VALUE = 0x0002;
internal const int KEY_CREATE_SUB_KEY = 0x0004;
internal const int KEY_ENUMERATE_SUB_KEYS = 0x0008;
internal const int KEY_NOTIFY = 0x0010;
internal const int KEY_CREATE_LINK = 0x0020;
internal const int KEY_READ = ((STANDARD_RIGHTS_READ |
KEY_QUERY_VALUE |
KEY_ENUMERATE_SUB_KEYS |
KEY_NOTIFY)
&
(~SYNCHRONIZE));
internal const int KEY_WRITE = ((STANDARD_RIGHTS_WRITE |
KEY_SET_VALUE |
KEY_CREATE_SUB_KEY)
&
(~SYNCHRONIZE));
internal const int SYNCHRONIZE = 0x00100000;
internal const int READ_CONTROL = 0x00020000;
internal const int STANDARD_RIGHTS_READ = READ_CONTROL;
internal const int STANDARD_RIGHTS_WRITE = READ_CONTROL;
}
internal static class RegistryValues
{
internal const int REG_NONE = 0; // No value type
internal const int REG_SZ = 1; // Unicode nul terminated string
internal const int REG_EXPAND_SZ = 2; // Unicode nul terminated string
// (with environment variable references)
internal const int REG_BINARY = 3; // Free form binary
internal const int REG_DWORD = 4; // 32-bit number
internal const int REG_DWORD_LITTLE_ENDIAN = 4; // 32-bit number (same as REG_DWORD)
internal const int REG_DWORD_BIG_ENDIAN = 5; // 32-bit number
internal const int REG_LINK = 6; // Symbolic Link (Unicode)
internal const int REG_MULTI_SZ = 7; // Multiple Unicode strings
internal const int REG_QWORD = 11; // 64-bit number
}
}
}

Просмотреть файл

@ -14,6 +14,7 @@ internal partial class Interop
STATUS_NOT_FOUND = 0xc0000225,
STATUS_INVALID_PARAMETER = 0xc000000d,
STATUS_NO_MEMORY = 0xc0000017,
STATUS_AUTH_TAG_MISMATCH = 0xc000a002,
}
}
}

Просмотреть файл

@ -6,11 +6,13 @@ internal static partial class Interop
{
internal static partial class Libraries
{
internal const string Advapi32 = "advapi32.dll";
internal const string BCrypt = "BCrypt.dll";
internal const string Crypt32 = "crypt32.dll";
internal const string Kernel32 = "kernel32.dll";
internal const string Ole32 = "ole32.dll";
internal const string OleAut32 = "oleaut32.dll";
internal const string User32 = "user32.dll";
internal const string NtDll = "ntdll.dll";
}
}

Просмотреть файл

@ -1,24 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
internal partial class Interop
{
internal partial class Kernel32
{
internal partial class RegistryValues
{
internal const int REG_NONE = 0; // No value type
internal const int REG_SZ = 1; // Unicode nul terminated string
internal const int REG_EXPAND_SZ = 2; // Unicode nul terminated string
// (with environment variable references)
internal const int REG_BINARY = 3; // Free form binary
internal const int REG_DWORD = 4; // 32-bit number
internal const int REG_DWORD_LITTLE_ENDIAN = 4; // 32-bit number (same as REG_DWORD)
internal const int REG_DWORD_BIG_ENDIAN = 5; // 32-bit number
internal const int REG_LINK = 6; // Symbolic Link (Unicode)
internal const int REG_MULTI_SZ = 7; // Multiple Unicode strings
internal const int REG_QWORD = 11; // 64-bit number
}
}
}

Просмотреть файл

@ -0,0 +1,46 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Microsoft.Win32.SafeHandles;
using System;
using System.Runtime.InteropServices;
internal partial class Interop
{
internal partial class NtDll
{
[DllImport(Libraries.NtDll, ExactSpelling = true)]
unsafe internal static extern int NtQueryInformationFile(
SafeFileHandle FileHandle,
out IO_STATUS_BLOCK IoStatusBlock,
void* FileInformation,
uint Length,
uint FileInformationClass);
[StructLayout(LayoutKind.Sequential)]
internal struct IO_STATUS_BLOCK
{
IO_STATUS Status;
IntPtr Information;
}
// This isn't an actual Windows type, we have to separate it out as the size of IntPtr varies by architecture
// and we can't specify the size at compile time to offset the Information pointer in the status block.
[StructLayout(LayoutKind.Explicit)]
internal struct IO_STATUS
{
[FieldOffset(0)]
int Status;
[FieldOffset(0)]
IntPtr Pointer;
}
internal const uint FileModeInformation = 16;
internal const uint FILE_SYNCHRONOUS_IO_ALERT = 0x00000010;
internal const uint FILE_SYNCHRONOUS_IO_NONALERT = 0x00000020;
internal const int STATUS_INVALID_HANDLE = unchecked((int)0xC0000008);
}
}

Просмотреть файл

@ -0,0 +1,104 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Diagnostics;
namespace Microsoft.Win32
{
/// <summary>Registry encapsulation. Contains members representing all top level system keys.</summary>
#if REGISTRY_ASSEMBLY
public
#else
internal
#endif
static class Registry
{
/// <summary>Current User Key. This key should be used as the root for all user specific settings.</summary>
public static readonly RegistryKey CurrentUser = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Default);
/// <summary>Local Machine key. This key should be used as the root for all machine specific settings.</summary>
public static readonly RegistryKey LocalMachine = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Default);
/// <summary>Classes Root Key. This is the root key of class information.</summary>
public static readonly RegistryKey ClassesRoot = RegistryKey.OpenBaseKey(RegistryHive.ClassesRoot, RegistryView.Default);
/// <summary>Users Root Key. This is the root of users.</summary>
public static readonly RegistryKey Users = RegistryKey.OpenBaseKey(RegistryHive.Users, RegistryView.Default);
/// <summary>Performance Root Key. This is where dynamic performance data is stored on NT.</summary>
public static readonly RegistryKey PerformanceData = RegistryKey.OpenBaseKey(RegistryHive.PerformanceData, RegistryView.Default);
/// <summary>Current Config Root Key. This is where current configuration information is stored.</summary>
public static readonly RegistryKey CurrentConfig = RegistryKey.OpenBaseKey(RegistryHive.CurrentConfig, RegistryView.Default);
/// <summary>
/// Parse a keyName and returns the basekey for it.
/// It will also store the subkey name in the out parameter.
/// If the keyName is not valid, we will throw ArgumentException.
/// The return value shouldn't be null.
/// </summary>
private static RegistryKey GetBaseKeyFromKeyName(string keyName, out string subKeyName)
{
if (keyName == null)
{
throw new ArgumentNullException(nameof(keyName));
}
int i = keyName.IndexOf('\\');
int length = i != -1 ? i : keyName.Length;
// Determine the potential base key from the length.
RegistryKey baseKey = null;
switch (length)
{
case 10: baseKey = Users; break; // HKEY_USERS
case 17: baseKey = char.ToUpperInvariant(keyName[6]) == 'L' ? ClassesRoot : CurrentUser; break; // HKEY_C[L]ASSES_ROOT, otherwise HKEY_CURRENT_USER
case 18: baseKey = LocalMachine; break; // HKEY_LOCAL_MACHINE
case 19: baseKey = CurrentConfig; break; // HKEY_CURRENT_CONFIG
case 21: baseKey = PerformanceData; break; // HKEY_PERFORMANCE_DATA
}
// If a potential base key was found, see if keyName actually starts with the potential base key's name.
if (baseKey != null && keyName.StartsWith(baseKey.Name, StringComparison.OrdinalIgnoreCase))
{
subKeyName = (i == -1 || i == keyName.Length) ?
string.Empty :
keyName.Substring(i + 1, keyName.Length - i - 1);
return baseKey;
}
throw new ArgumentException(SR.Format(SR.Arg_RegInvalidKeyName, nameof(keyName)), nameof(keyName));
}
public static object GetValue(string keyName, string valueName, object defaultValue)
{
string subKeyName;
RegistryKey basekey = GetBaseKeyFromKeyName(keyName, out subKeyName);
using (RegistryKey key = basekey.OpenSubKey(subKeyName))
{
return key?.GetValue(valueName, defaultValue);
}
}
public static void SetValue(string keyName, string valueName, object value)
{
SetValue(keyName, valueName, value, RegistryValueKind.Unknown);
}
public static void SetValue(string keyName, string valueName, object value, RegistryValueKind valueKind)
{
string subKeyName;
RegistryKey basekey = GetBaseKeyFromKeyName(keyName, out subKeyName);
using (RegistryKey key = basekey.CreateSubKey(subKeyName))
{
Debug.Assert(key != null, "An exception should be thrown if failed!");
key.SetValue(valueName, value, valueKind);
}
}
}
}

Просмотреть файл

@ -11,12 +11,12 @@ namespace Microsoft.Win32
#endif
enum RegistryValueKind
{
String = Interop.Kernel32.RegistryValues.REG_SZ,
ExpandString = Interop.Kernel32.RegistryValues.REG_EXPAND_SZ,
Binary = Interop.Kernel32.RegistryValues.REG_BINARY,
DWord = Interop.Kernel32.RegistryValues.REG_DWORD,
MultiString = Interop.Kernel32.RegistryValues.REG_MULTI_SZ,
QWord = Interop.Kernel32.RegistryValues.REG_QWORD,
String = Interop.Advapi32.RegistryValues.REG_SZ,
ExpandString = Interop.Advapi32.RegistryValues.REG_EXPAND_SZ,
Binary = Interop.Advapi32.RegistryValues.REG_BINARY,
DWord = Interop.Advapi32.RegistryValues.REG_DWORD,
MultiString = Interop.Advapi32.RegistryValues.REG_MULTI_SZ,
QWord = Interop.Advapi32.RegistryValues.REG_QWORD,
Unknown = 0, // REG_NONE is defined as zero but BCL
None = unchecked((int)0xFFFFFFFF), // mistakenly overrode this value.
} // Now instead of using Interop.Kernel32.RegistryValues.REG_NONE we use "-1".

Просмотреть файл

@ -11,9 +11,9 @@ namespace Microsoft.Win32.SafeHandles
#else
internal
#endif
sealed partial class SafeRegistryHandle : SafeHandle
sealed partial class SafeRegistryHandle : SafeHandleZeroOrMinusOneIsInvalid
{
protected override bool ReleaseHandle() =>
Interop.mincore.RegCloseKey(handle) == Interop.Errors.ERROR_SUCCESS;
Interop.Advapi32.RegCloseKey(handle) == Interop.Errors.ERROR_SUCCESS;
}
}

Просмотреть файл

@ -3,20 +3,21 @@
// See the LICENSE file in the project root for more information.
using System;
using System.Runtime.InteropServices;
namespace Microsoft.Win32.SafeHandles
{
#if REGISTRY_ASSEMBLY
public
#else
internal
sealed partial class SafeRegistryHandle : SafeHandle
#endif
sealed partial class SafeRegistryHandle : SafeHandleZeroOrMinusOneIsInvalid
{
internal SafeRegistryHandle() : base(IntPtr.Zero, true) { }
internal SafeRegistryHandle() : base(true) { }
public SafeRegistryHandle(IntPtr preexistingHandle, bool ownsHandle) : base(IntPtr.Zero, ownsHandle)
public SafeRegistryHandle(IntPtr preexistingHandle, bool ownsHandle) : base(ownsHandle)
{
SetHandle(preexistingHandle);
}
public override bool IsInvalid => handle == IntPtr.Zero || handle == new IntPtr(-1);
}
}

Просмотреть файл

@ -338,6 +338,7 @@
<Compile Include="$(MSBuildThisFileDirectory)System\Reflection\Emit\StackBehaviour.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Reflection\EventAttributes.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Reflection\EventInfo.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Reflection\ExceptionHandlingClause.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Reflection\ExceptionHandlingClauseOptions.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Reflection\FieldAttributes.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Reflection\FieldInfo.cs" />
@ -356,6 +357,7 @@
<Compile Include="$(MSBuildThisFileDirectory)System\Reflection\MemberTypes.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Reflection\MethodAttributes.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Reflection\MethodBase.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Reflection\MethodBody.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Reflection\MethodImplAttributes.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Reflection\MethodInfo.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Reflection\MethodInfo.Internal.cs" />
@ -605,8 +607,10 @@
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\SemaphoreFullException.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\SemaphoreSlim.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\SendOrPostCallback.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\SpinLock.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\SpinWait.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\SynchronizationLockException.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\ThreadLocal.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\Tasks\ConcurrentExclusiveSchedulerPair.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\Tasks\TaskCanceledException.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\Tasks\TaskCompletionSource.cs" />
@ -757,8 +761,6 @@
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.OutputDebugString.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.ReadFile_SafeHandle_IntPtr.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.ReadFile_SafeHandle_NativeOverlapped.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.RegistryValues.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.RegistryView.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.SECURITY_ATTRIBUTES.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.SecurityOptions.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.SetEndOfFile.cs" />
@ -778,8 +780,6 @@
<Compile Include="$(MSBuildThisFileDirectory)Internal\IO\File.Windows.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Microsoft\Win32\SafeHandles\SafeFileHandle.Windows.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Microsoft\Win32\SafeHandles\SafeFindHandle.Windows.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Microsoft\Win32\RegistryValueKind.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Microsoft\Win32\RegistryView.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CalendarData.Windows.cs" Condition="'$(EnableDummyGlobalizationImplementation)' != 'true'" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CompareInfo.Windows.cs" Condition="'$(EnableDummyGlobalizationImplementation)' != 'true'" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CultureData.Windows.cs" Condition="'$(EnableDummyGlobalizationImplementation)' != 'true'" />
@ -801,9 +801,19 @@
<Compile Include="$(MSBuildThisFileDirectory)System\Security\SecureString.Windows.cs" />
</ItemGroup>
<ItemGroup Condition="$(TargetsWindows) and '$(EnableWinRT)' != 'true'">
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\NtDll\NtQueryInformationFile.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Advapi32\Interop.RegistryConstants.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.RegistryView.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\FileStream.Win32.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\TimeZoneInfo.Win32.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Microsoft\Win32\Registry.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Microsoft\Win32\RegistryHive.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Microsoft\Win32\RegistryValueKind.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Microsoft\Win32\RegistryView.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Microsoft\Win32\SafeHandles\SafeLibraryHandle.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Microsoft\Win32\SafeHandles\SafeRegistryHandle.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Microsoft\Win32\SafeHandles\SafeRegistryHandle.Windows.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Advapi32\Interop.RegCloseKey.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.LoadLibraryEx.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.FreeLibrary.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.CreateFile.cs" />

Просмотреть файл

@ -174,27 +174,27 @@ namespace System
public override string ToString()
{
return Number.FormatInt32(m_value, null, null);
return Number.FormatUInt32(m_value, null, null);
}
public string ToString(string format)
{
return Number.FormatInt32(m_value, format, null);
return Number.FormatUInt32(m_value, format, null);
}
public string ToString(IFormatProvider provider)
{
return Number.FormatInt32(m_value, null, provider);
return Number.FormatUInt32(m_value, null, provider);
}
public string ToString(string format, IFormatProvider provider)
{
return Number.FormatInt32(m_value, format, provider);
return Number.FormatUInt32(m_value, format, provider);
}
public bool TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format = default, IFormatProvider provider = null)
{
return Number.TryFormatInt32(m_value, format, provider, destination, out charsWritten);
return Number.TryFormatUInt32(m_value, format, provider, destination, out charsWritten);
}
//

Просмотреть файл

@ -1157,11 +1157,11 @@ namespace System.Collections.Generic
public struct Enumerator : IEnumerator<KeyValuePair<TKey, TValue>>,
IDictionaryEnumerator
{
private Dictionary<TKey, TValue> _dictionary;
private int _version;
private readonly Dictionary<TKey, TValue> _dictionary;
private readonly int _version;
private int _index;
private KeyValuePair<TKey, TValue> _current;
private int _getEnumeratorRetType; // What should Enumerator.Current return?
private readonly int _getEnumeratorRetType; // What should Enumerator.Current return?
internal const int DictEntry = 1;
internal const int KeyValuePair = 2;
@ -1392,9 +1392,9 @@ namespace System.Collections.Generic
public struct Enumerator : IEnumerator<TKey>, IEnumerator
{
private Dictionary<TKey, TValue> _dictionary;
private readonly Dictionary<TKey, TValue> _dictionary;
private int _index;
private int _version;
private readonly int _version;
private TKey _currentKey;
internal Enumerator(Dictionary<TKey, TValue> dictionary)
@ -1575,9 +1575,9 @@ namespace System.Collections.Generic
public struct Enumerator : IEnumerator<TValue>, IEnumerator
{
private Dictionary<TKey, TValue> _dictionary;
private readonly Dictionary<TKey, TValue> _dictionary;
private int _index;
private int _version;
private readonly int _version;
private TValue _currentValue;
internal Enumerator(Dictionary<TKey, TValue> dictionary)

Просмотреть файл

@ -941,7 +941,6 @@ namespace System.Collections.Generic
if (count > 0)
{
int i = _size;
_size -= count;
if (index < _size)
{
@ -1117,9 +1116,9 @@ namespace System.Collections.Generic
public struct Enumerator : IEnumerator<T>, IEnumerator
{
private List<T> _list;
private readonly List<T> _list;
private int _index;
private int _version;
private readonly int _version;
private T _current;
internal Enumerator(List<T> list)

Просмотреть файл

@ -23,7 +23,7 @@ namespace System.Collections.Generic
public sealed override bool Equals(string x, string y) => string.Equals(x, y);
public sealed override int GetHashCode(string obj) => obj?.GetLegacyNonRandomizedHashCode() ?? 0;
public sealed override int GetHashCode(string obj) => obj?.GetNonRandomizedHashCode() ?? 0;
public void GetObjectData(SerializationInfo info, StreamingContext context)
{

Просмотреть файл

@ -2,11 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.Runtime.InteropServices;
using System.Threading;
namespace System.ComponentModel
{
@ -23,6 +20,9 @@ namespace System.ComponentModel
/// </devdoc>
private object _value;
// Delegate ad hoc created 'TypeDescriptor.ConvertFromInvariantString' reflection object cache
static object s_convertFromInvariantString;
/// <devdoc>
/// <para>Initializes a new instance of the <see cref='System.ComponentModel.DefaultValueAttribute'/> class, converting the
/// specified value to the
@ -36,7 +36,11 @@ namespace System.ComponentModel
// load an otherwise normal class.
try
{
if (type.IsSubclassOf(typeof(Enum)))
if (TryConvertFromInvariantString(type, value, out object convertedValue))
{
_value = convertedValue;
}
else if (type.IsSubclassOf(typeof(Enum)))
{
_value = Enum.Parse(type, value, true);
}
@ -48,6 +52,28 @@ namespace System.ComponentModel
{
_value = Convert.ChangeType(value, type, CultureInfo.InvariantCulture);
}
return;
// Looking for ad hoc created TypeDescriptor.ConvertFromInvariantString(Type, string)
bool TryConvertFromInvariantString(Type typeToConvert, string stringValue, out object conversionResult)
{
conversionResult = null;
// lazy init reflection objects
if (s_convertFromInvariantString == null)
{
Type typeDescriptorType = Type.GetType("System.ComponentModel.TypeDescriptor, System.ComponentModel.TypeConverter", throwOnError: false);
Volatile.Write(ref s_convertFromInvariantString, typeDescriptorType == null ? new object() : Delegate.CreateDelegate(typeof(Func<Type, string, object>), typeDescriptorType, "ConvertFromInvariantString", ignoreCase: false));
}
if (!(s_convertFromInvariantString is Func<Type, string, object> convertFromInvariantString))
return false;
conversionResult = convertFromInvariantString(typeToConvert, stringValue);
return true;
}
}
catch
{

Просмотреть файл

@ -31,7 +31,7 @@ namespace System
[StructLayout(LayoutKind.Auto)]
[Serializable]
[System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public struct DateTimeOffset : IComparable, IFormattable, IComparable<DateTimeOffset>, IEquatable<DateTimeOffset>, ISerializable, IDeserializationCallback, ISpanFormattable
public readonly struct DateTimeOffset : IComparable, IFormattable, IComparable<DateTimeOffset>, IEquatable<DateTimeOffset>, ISerializable, IDeserializationCallback, ISpanFormattable
{
// Constants
internal const long MaxOffset = TimeSpan.TicksPerHour * 14;
@ -49,8 +49,8 @@ namespace System
public static readonly DateTimeOffset UnixEpoch = new DateTimeOffset(DateTime.UnixEpochTicks, TimeSpan.Zero);
// Instance Fields
private DateTime _dateTime;
private short _offsetMinutes;
private readonly DateTime _dateTime;
private readonly short _offsetMinutes;
// Constructors
@ -553,8 +553,8 @@ namespace System
{
try
{
_offsetMinutes = ValidateOffset(Offset);
_dateTime = ValidateDate(ClockDateTime, Offset);
ValidateOffset(Offset);
ValidateDate(ClockDateTime, Offset);
}
catch (ArgumentException e)
{

Просмотреть файл

@ -36,16 +36,6 @@ namespace System
return DecCalc.DecDivMod1E9(ref AsMutable(ref value));
}
internal static void DecAddInt32(ref decimal value, uint i)
{
DecCalc.DecAddInt32(ref AsMutable(ref value), i);
}
internal static void DecMul10(ref decimal value)
{
DecCalc.DecMul10(ref AsMutable(ref value));
}
#endregion
/// <summary>
@ -2471,8 +2461,6 @@ done:
return;
}
#region Number Formatting helpers
internal static uint DecDivMod1E9(ref DecCalc value)
{
ulong high64 = ((ulong)value.uhi << 32) + value.umid;
@ -2486,57 +2474,6 @@ done:
return (uint)num - div * TenToPowerNine;
}
internal static void DecAddInt32(ref DecCalc value, uint i)
{
if (D32AddCarry(ref value.ulo, i))
{
if (D32AddCarry(ref value.umid, 1))
D32AddCarry(ref value.uhi, 1);
}
}
private static bool D32AddCarry(ref uint value, uint i)
{
uint v = value;
uint sum = v + i;
value = sum;
return (sum < v) || (sum < i);
}
internal static void DecMul10(ref DecCalc value)
{
DecCalc d = value;
DecShiftLeft(ref value);
DecShiftLeft(ref value);
DecAdd(ref value, d);
DecShiftLeft(ref value);
}
private static void DecShiftLeft(ref DecCalc value)
{
uint c0 = (value.Low & 0x80000000) != 0 ? 1u : 0u;
uint c1 = (value.Mid & 0x80000000) != 0 ? 1u : 0u;
value.Low = value.Low << 1;
value.Mid = (value.Mid << 1) | c0;
value.High = (value.High << 1) | c1;
}
private static void DecAdd(ref DecCalc value, DecCalc d)
{
if (D32AddCarry(ref value.ulo, d.Low))
{
if (D32AddCarry(ref value.umid, 1))
D32AddCarry(ref value.uhi, 1);
}
if (D32AddCarry(ref value.umid, d.Mid))
D32AddCarry(ref value.uhi, 1);
D32AddCarry(ref value.uhi, d.High);
}
#endregion
struct PowerOvfl
{
public readonly uint Hi;

Просмотреть файл

@ -882,26 +882,19 @@ namespace System.Diagnostics.Tracing
else
{
if (data is System.Enum)
{
try
{
Type underlyingType = Enum.GetUnderlyingType(data.GetType());
if (underlyingType == typeof(int))
{
#if !ES_BUILD_PCL
data = ((IConvertible)data).ToInt32(null);
#else
data = (int)data;
#endif
goto Again;
}
if (underlyingType == typeof(ulong))
data = (ulong)data;
else if (underlyingType == typeof(long))
{
#if !ES_BUILD_PCL
data = ((IConvertible)data).ToInt64(null);
#else
data = (long)data;
#endif
else
data = (int)Convert.ToInt64(data); // This handles all int/uint or below (we treat them like 32 bit ints)
goto Again;
}
catch { } // On wierd cases (e.g. enums of type double), give up and for compat simply tostring.
}
// To our eyes, everything else is a just a string

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше