Merge branch 'master' into r2r
This commit is contained in:
Коммит
8ca402c5a3
|
@ -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
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче