Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/corert.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMichal Strehovský <MichalStrehovsky@users.noreply.github.com>2018-08-11 17:26:36 +0300
committerGitHub <noreply@github.com>2018-08-11 17:26:36 +0300
commitb55fbd3fde12e56a5be81979ebed31ae780c5666 (patch)
tree15adbe8665459d8c1e13050f7edd01c80a18e49c /src
parent6048b4d2e6bcb6c3195876bc2c74f883d23e4a36 (diff)
parent0fd0ca289196d2e5d5308bbb3e8e51a4a9cef31a (diff)
Merge pull request #6213 from dotnet/master
Merge master to nmirror
Diffstat (limited to 'src')
-rw-r--r--src/BuildIntegration/Microsoft.NETCore.Native.Unix.props3
-rw-r--r--src/Common/src/TypeSystem/Common/MethodDesc.cs25
-rw-r--r--src/Framework/Framework.depproj5
-rw-r--r--src/ILCompiler.Compiler/src/Compiler/CompilerTypeSystemContext.Mangling.cs19
-rw-r--r--src/ILCompiler.WebAssembly/src/CodeGen/ILToWebAssemblyImporter.cs332
-rw-r--r--src/ILCompiler.WebAssembly/src/CodeGen/WebAssemblyObjectWriter.cs18
-rw-r--r--src/ILCompiler/repro/repro.csproj6
-rw-r--r--src/JitInterface/src/ThunkGenerator/corinfo.h3
-rw-r--r--src/JitInterface/src/ThunkGenerator/corjithost.h26
-rw-r--r--src/Native/ObjWriter/objwriter.cpp4
-rw-r--r--src/Native/jitinterface/jithost.cpp15
-rw-r--r--src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems6
-rw-r--r--src/System.Private.CoreLib/shared/System/Collections/Generic/NonRandomizedStringEqualityComparer.cs2
-rw-r--r--src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/EventSource.cs5
-rw-r--r--src/System.Private.CoreLib/shared/System/IO/DisableMediaInsertionPrompt.cs6
-rw-r--r--src/System.Private.CoreLib/shared/System/IO/Path.Windows.cs39
-rw-r--r--src/System.Private.CoreLib/shared/System/IO/Path.cs46
-rw-r--r--src/System.Private.CoreLib/shared/System/IO/PathHelper.Windows.cs2
-rw-r--r--src/System.Private.CoreLib/shared/System/IO/PathInternal.Windows.cs2
-rw-r--r--src/System.Private.CoreLib/shared/System/IO/PathInternal.cs8
-rw-r--r--src/System.Private.CoreLib/shared/System/IO/StreamWriter.cs117
-rw-r--r--src/System.Private.CoreLib/shared/System/Reflection/ExceptionHandlingClause.cs (renamed from src/System.Private.CoreLib/src/System/Reflection/ExceptionHandlingClause.cs)17
-rw-r--r--src/System.Private.CoreLib/shared/System/Reflection/LocalVariableInfo.cs26
-rw-r--r--src/System.Private.CoreLib/shared/System/Reflection/MethodBody.cs (renamed from src/System.Private.CoreLib/src/System/Reflection/MethodBody.cs)8
-rw-r--r--src/System.Private.CoreLib/shared/System/Runtime/InteropServices/NativeCallableAttribute.cs (renamed from src/System.Private.CoreLib/src/System/Runtime/InteropServices/NativeCallableAttribute.cs)25
-rw-r--r--src/System.Private.CoreLib/shared/System/Runtime/Intrinsics/Vector128.cs6
-rw-r--r--src/System.Private.CoreLib/shared/System/Runtime/Intrinsics/Vector128DebugView.cs4
-rw-r--r--src/System.Private.CoreLib/shared/System/Runtime/Intrinsics/Vector256.cs10
-rw-r--r--src/System.Private.CoreLib/shared/System/Runtime/Intrinsics/Vector256DebugView.cs4
-rw-r--r--src/System.Private.CoreLib/shared/System/Runtime/Intrinsics/Vector64.cs4
-rw-r--r--src/System.Private.CoreLib/shared/System/Runtime/Intrinsics/Vector64DebugView.cs4
-rw-r--r--src/System.Private.CoreLib/shared/System/String.Comparison.cs69
-rw-r--r--src/System.Private.CoreLib/shared/System/Text/ValueStringBuilder.cs2
-rw-r--r--src/System.Private.CoreLib/shared/System/Threading/SpinLock.cs (renamed from src/System.Private.CoreLib/src/System/Threading/SpinLock.cs)206
-rw-r--r--src/System.Private.CoreLib/shared/System/Threading/ThreadLocal.cs (renamed from src/System.Private.CoreLib/src/System/Threading/ThreadLocal.cs)251
-rw-r--r--src/System.Private.CoreLib/src/Resources/Strings.resx3
-rw-r--r--src/System.Private.CoreLib/src/System.Private.CoreLib.csproj8
-rw-r--r--src/System.Private.CoreLib/src/System/Reflection/AssemblyName.cs214
-rw-r--r--src/System.Private.CoreLib/src/System/Reflection/LocalVariableInfo.cs54
-rw-r--r--src/System.Private.CoreLib/src/System/Runtime/CompilerServices/ClassConstructorRunner.NonPortable.cs5
-rw-r--r--src/System.Private.CoreLib/src/System/Runtime/CompilerServices/ClassConstructorRunner.cs2
41 files changed, 974 insertions, 637 deletions
diff --git a/src/BuildIntegration/Microsoft.NETCore.Native.Unix.props b/src/BuildIntegration/Microsoft.NETCore.Native.Unix.props
index c5b397b3f..a8c8bafdb 100644
--- a/src/BuildIntegration/Microsoft.NETCore.Native.Unix.props
+++ b/src/BuildIntegration/Microsoft.NETCore.Native.Unix.props
@@ -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" />
@@ -94,7 +95,7 @@ See the LICENSE file in the project root for more information.
<LinkerArg Include="-shared" Condition="'$(TargetOS)' != 'OSX' and '$(NativeLib)' == 'Shared'" />
<LinkerArg Include="@(NativeFramework->'-framework %(Identity)')" Condition="'$(TargetOS)' == 'OSX'" />
</ItemGroup>
-
+
<Exec Command="command -v $(CppLinker)" IgnoreExitCode="true">
<Output TaskParameter="ExitCode" PropertyName="_WhereLinker"/>
</Exec>
diff --git a/src/Common/src/TypeSystem/Common/MethodDesc.cs b/src/Common/src/TypeSystem/Common/MethodDesc.cs
index 74c48d8eb..7103433b0 100644
--- a/src/Common/src/TypeSystem/Common/MethodDesc.cs
+++ b/src/Common/src/TypeSystem/Common/MethodDesc.cs
@@ -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>
diff --git a/src/Framework/Framework.depproj b/src/Framework/Framework.depproj
index 395b213e6..d72b2e1a0 100644
--- a/src/Framework/Framework.depproj
+++ b/src/Framework/Framework.depproj
@@ -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>
diff --git a/src/ILCompiler.Compiler/src/Compiler/CompilerTypeSystemContext.Mangling.cs b/src/ILCompiler.Compiler/src/Compiler/CompilerTypeSystemContext.Mangling.cs
index 720f06114..ace374f04 100644
--- a/src/ILCompiler.Compiler/src/Compiler/CompilerTypeSystemContext.Mangling.cs
+++ b/src/ILCompiler.Compiler/src/Compiler/CompilerTypeSystemContext.Mangling.cs
@@ -47,5 +47,24 @@ namespace ILCompiler
}
}
}
+
+ partial class UnboxingThunk : IPrefixMangledMethod
+ {
+ MethodDesc IPrefixMangledMethod.BaseMethod
+ {
+ get
+ {
+ return _targetMethod;
+ }
+ }
+
+ string IPrefixMangledMethod.Prefix
+ {
+ get
+ {
+ return "unbox";
+ }
+ }
+ }
}
}
diff --git a/src/ILCompiler.WebAssembly/src/CodeGen/ILToWebAssemblyImporter.cs b/src/ILCompiler.WebAssembly/src/CodeGen/ILToWebAssemblyImporter.cs
index a4567950c..19960e6a9 100644
--- a/src/ILCompiler.WebAssembly/src/CodeGen/ILToWebAssemblyImporter.cs
+++ b/src/ILCompiler.WebAssembly/src/CodeGen/ILToWebAssemblyImporter.cs
@@ -45,6 +45,7 @@ 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;
@@ -53,9 +54,7 @@ namespace Internal.IL
/// 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 +93,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,7 +103,7 @@ 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;
}
@@ -158,9 +158,36 @@ 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++;
+ }
+
+ for (int i = 0; i < _signature.Length; i++)
+ {
+ if (CanStoreTypeOnStack(_signature[i]))
+ {
+ LLVMValueRef argStackSlot = LLVM.BuildAlloca(_builder, GetLLVMTypeForTypeDesc(_signature[i]), $"arg{i + thisOffset}_");
+ LLVM.BuildStore(_builder, LLVM.GetParam(_llvmFunction, (uint)signatureIndex), argStackSlot);
+ _argSlots[i] = argStackSlot;
+ signatureIndex++;
+ }
+ }
+
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}_");
_localSlots[i] = localStackSlot;
@@ -172,7 +199,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 +263,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;
}
@@ -484,7 +511,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 +526,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 +819,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,38 +827,56 @@ namespace Internal.IL
return offset.AlignUp(_pointerSize);
}
+ 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)
+ {
+ 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 bool CanStoreTypeOnStack(TypeDesc localType)
+ private static bool CanStoreTypeOnStack(TypeDesc type)
{
- // Keep all locals on the shadow stack if there is exception
- // handling so funclets can access them
- if (_exceptionRegions.Length == 0)
+ if (type is DefType defType)
{
- if (localType is DefType)
- {
- if (!((DefType)localType).ContainsGCPointers)
- {
- return true;
- }
- }
- else if (localType is PointerType)
+ if (!defType.IsGCPointer && !defType.ContainsGCPointers)
{
return true;
}
}
+ 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++)
{
- offset = PadNextOffset(_signature[i], offset);
+ if (!CanStoreTypeOnStack(_signature[i]))
+ {
+ offset = PadNextOffset(_signature[i], offset);
+ }
}
if (!_signature.IsStatic)
{
@@ -842,8 +894,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,12 +917,29 @@ namespace Internal.IL
var argType = _signature[index];
size = argType.GetElementSize().AsInt;
+ int potentialRealArgIndex = 0;
+
offset = thisSize;
for (int i = 0; i < index; i++)
{
- offset = PadNextOffset(_signature[i], offset);
+ // 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);
}
- offset = PadOffset(argType, offset);
}
private void GetLocalSizeAndOffsetAtIndex(int index, out int size, out int offset)
@@ -876,7 +947,7 @@ namespace Internal.IL
LocalVariableDefinition local = _locals[index];
size = local.Type.GetElementSize().AsInt;
- if (CanStoreTypeOnStack(local.Type))
+ if (CanStoreLocalOnStack(local.Type))
{
offset = -1;
}
@@ -885,7 +956,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,14 +1063,25 @@ 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;
}
- LLVM.BuildRetVoid(_builder);
+ 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)
@@ -1022,7 +1104,28 @@ namespace Internal.IL
if (opcode == ILOpcode.newobj)
{
TypeDesc newType = callee.OwningType;
- if (newType.IsString)
+ if (newType.IsArray)
+ {
+ var paramCnt = callee.Signature.Length;
+ var eeTypeDesc = _compilation.TypeSystemContext.SystemModule.GetKnownType("Internal.Runtime", "EEType").MakePointerType();
+ LLVMValueRef dimensions = LLVM.BuildArrayAlloca(_builder, LLVMTypeRef.Int32Type(), BuildConstInt32(paramCnt), "newobj_array_pdims_" + _currentOffset);
+ for (int i = paramCnt - 1; i >= 0; --i)
+ {
+ LLVM.BuildStore(_builder, _stack.Pop().ValueAsInt32(_builder, true),
+ LLVM.BuildGEP(_builder, dimensions, new LLVMValueRef[] { BuildConstInt32(i) }, "pdims_ptr"));
+ }
+ var arguments = new StackEntry[]
+ {
+ new LoadExpressionEntry(StackValueKind.ValueType, "eeType", GetEETypePointerForTypeDesc(newType, true), eeTypeDesc),
+ new Int32ConstantEntry(paramCnt),
+ new AddressExpressionEntry(StackValueKind.ValueType, "newobj_array_pdims", dimensions)
+ };
+ MetadataType helperType = _compilation.TypeSystemContext.SystemModule.GetKnownType("Internal.Runtime.CompilerHelpers", "ArrayHelpers");
+ MethodDesc helperMethod = helperType.GetKnownMethod("NewObjArray", null);
+ PushNonNull(HandleCall(helperMethod, helperMethod.Signature, arguments, forcedReturnType: newType));
+ return;
+ }
+ else if (newType.IsString)
{
// String constructors actually look like regular method calls
IMethodNode node = _compilation.NodeFactory.StringAllocator(callee);
@@ -1074,7 +1177,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));
}
}
@@ -1084,6 +1187,14 @@ namespace Internal.IL
private LLVMValueRef LLVMFunctionForMethod(MethodDesc callee, StackEntry thisPointer, bool isCallVirt)
{
string calleeName = _compilation.NameMangler.GetMangledMethodName(callee).ToString();
+
+ // Sealed methods must not be called virtually due to sealed vTables, so call them directly
+ if(callee.IsFinal || callee.OwningType.IsSealed())
+ {
+ AddMethodReference(callee);
+ return GetOrCreateLLVMFunction(calleeName, callee.Signature);
+ }
+
if (thisPointer != null && callee.IsVirtual && isCallVirt)
{
// TODO: Full resolution of virtual methods
@@ -1126,7 +1237,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);
@@ -1134,7 +1245,7 @@ namespace Internal.IL
}
else
{
- return GetOrCreateLLVMFunction(calleeName);
+ return GetOrCreateLLVMFunction(calleeName, callee.Signature);
}
}
@@ -1151,7 +1262,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)
{
@@ -1159,11 +1270,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__");
@@ -1172,6 +1283,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;
@@ -1342,10 +1489,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);
@@ -1353,11 +1502,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),
@@ -1365,16 +1509,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)
@@ -1387,14 +1540,24 @@ namespace Internal.IL
argType = signature[index - instanceAdjustment];
}
- // The previous argument might have left this type unaligned, so pad if necessary
- argOffset = PadOffset(argType, argOffset);
-
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);
- ImportStoreHelper(toStore.ValueAsType(valueType, _builder), valueType, castShadowStack, (uint)argOffset);
+ ImportStoreHelper(argValue, valueType, castShadowStack, (uint)argOffset);
- argOffset += argType.GetElementSize().AsInt;
+ argOffset += argType.GetElementSize().AsInt;
+ }
}
LLVMValueRef fn;
@@ -1407,14 +1570,18 @@ 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)
{
- return returnSlot;
+ if (needsReturnSlot)
+ {
+ return returnSlot;
+ }
+ else
+ {
+ return new ExpressionEntry(GetStackValueKind(returnType), callee?.Name + "_return", llvmReturn, returnType);
+ }
}
else
{
@@ -1612,15 +1779,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++)
{
- 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}_"));
- curOffset = PadNextOffset(method.Signature[i], curOffset);
+ 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, 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)
{
@@ -1628,9 +1815,16 @@ namespace Internal.IL
LLVM.BuildCall(builder, RhpReversePInvokeReturn2, new LLVMValueRef[] { reversePInvokeFrame }, "");
}
- if (method.Signature.ReturnType != compilation.TypeSystemContext.GetWellKnownType(WellKnownType.Void))
+ if (!method.Signature.ReturnType.IsVoid)
{
- LLVM.BuildRet(builder, LLVM.BuildLoad(builder, CastIfNecessary(builder, shadowStack, LLVM.PointerType(GetLLVMTypeForTypeDesc(method.Signature.ReturnType), 0)), "returnValue"));
+ 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
{
@@ -1641,7 +1835,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)
@@ -1664,7 +1858,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);
diff --git a/src/ILCompiler.WebAssembly/src/CodeGen/WebAssemblyObjectWriter.cs b/src/ILCompiler.WebAssembly/src/CodeGen/WebAssemblyObjectWriter.cs
index cec8c0563..5b819d8a6 100644
--- a/src/ILCompiler.WebAssembly/src/CodeGen/WebAssemblyObjectWriter.cs
+++ b/src/ILCompiler.WebAssembly/src/CodeGen/WebAssemblyObjectWriter.cs
@@ -270,22 +270,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);
}
diff --git a/src/ILCompiler/repro/repro.csproj b/src/ILCompiler/repro/repro.csproj
index 4a81549b0..e8ec9a042 100644
--- a/src/ILCompiler/repro/repro.csproj
+++ b/src/ILCompiler/repro/repro.csproj
@@ -8,11 +8,17 @@
<SkipSigning>true</SkipSigning>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<CopyNuGetImplementations>false</CopyNuGetImplementations>
+
+ <!-- Supress warnings that often happen in repro code -->
+ <NoWarn>169;414</NoWarn>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NETCore.App">
<Version>$(MicrosoftNETCoreAppPackageVersion)</Version>
</PackageReference>
+ <PackageReference Include="System.Runtime.CompilerServices.Unsafe">
+ <Version>4.5.1</Version>
+ </PackageReference>
</ItemGroup>
<ItemGroup>
<Compile Include="Program.cs" />
diff --git a/src/JitInterface/src/ThunkGenerator/corinfo.h b/src/JitInterface/src/ThunkGenerator/corinfo.h
index 2270d328d..89cd95f75 100644
--- a/src/JitInterface/src/ThunkGenerator/corinfo.h
+++ b/src/JitInterface/src/ThunkGenerator/corinfo.h
@@ -1963,9 +1963,6 @@ struct DelegateCtorArgs
// use offsetof to get the offset of the fields above
#include <stddef.h> // offsetof
-#ifndef offsetof
-#define offsetof(s,m) ((size_t)&(((s *)0)->m))
-#endif
// Guard-stack cookie for preventing against stack buffer overruns
typedef SIZE_T GSCookie;
diff --git a/src/JitInterface/src/ThunkGenerator/corjithost.h b/src/JitInterface/src/ThunkGenerator/corjithost.h
index 8242fab2b..b2ab80646 100644
--- a/src/JitInterface/src/ThunkGenerator/corjithost.h
+++ b/src/JitInterface/src/ThunkGenerator/corjithost.h
@@ -15,15 +15,11 @@
class ICorJitHost
{
public:
- // Allocate memory of the given size in bytes. All bytes of the returned block
- // must be initialized to zero. If `usePageAllocator` is true, the implementation
- // should use an allocator that deals in OS pages if one exists.
- virtual void* allocateMemory(size_t size, bool usePageAllocator = false) = 0;
+ // Allocate memory of the given size in bytes.
+ virtual void* allocateMemory(size_t size) = 0;
- // Frees memory previous obtained by a call to `ICorJitHost::allocateMemory`. The
- // value of the `usePageAllocator` parameter must match the value that was
- // provided to the call to used to allocate the memory.
- virtual void freeMemory(void* block, bool usePageAllocator = false) = 0;
+ // Frees memory previous obtained by a call to `ICorJitHost::allocateMemory`.
+ virtual void freeMemory(void* block) = 0;
// Return an integer config value for the given key, if any exists.
virtual int getIntConfigValue(
@@ -43,6 +39,20 @@ public:
virtual void freeStringConfigValue(
const wchar_t* value
) = 0;
+
+ // Allocate memory slab of the given size in bytes. The host is expected to pool
+ // these for a good performance.
+ virtual void* allocateSlab(size_t size, size_t* pActualSize)
+ {
+ *pActualSize = size;
+ return allocateMemory(size);
+ }
+
+ // Free memory slab of the given size in bytes.
+ virtual void freeSlab(void* slab, size_t actualSize)
+ {
+ freeMemory(slab);
+ }
};
#endif
diff --git a/src/Native/ObjWriter/objwriter.cpp b/src/Native/ObjWriter/objwriter.cpp
index 4470f04be..bdf1016dc 100644
--- a/src/Native/ObjWriter/objwriter.cpp
+++ b/src/Native/ObjWriter/objwriter.cpp
@@ -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");
diff --git a/src/Native/jitinterface/jithost.cpp b/src/Native/jitinterface/jithost.cpp
index 2e2f17bfb..f433cf5b1 100644
--- a/src/Native/jitinterface/jithost.cpp
+++ b/src/Native/jitinterface/jithost.cpp
@@ -36,12 +36,12 @@ public:
JitHost(JitConfigProvider* pConfigProvider)
: pConfigProvider(pConfigProvider) { }
- virtual void* allocateMemory(size_t size, bool usePageAllocator = false)
+ virtual void* allocateMemory(size_t size)
{
return malloc(size);
}
- virtual void freeMemory(void* block, bool usePageAllocator = false)
+ virtual void freeMemory(void* block)
{
free(block);
}
@@ -76,6 +76,17 @@ public:
{
free(value);
}
+
+ virtual void* allocateSlab(size_t size, size_t* pActualSize)
+ {
+ *pActualSize = size;
+ return allocateMemory(size);
+ }
+
+ virtual void freeSlab(void* slab, size_t actualSize)
+ {
+ freeMemory(slab);
+ }
};
DLL_EXPORT void* GetJitHost(JitConfigProvider* pConfigProvider)
diff --git a/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems b/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems
index 743a70361..1133ce595 100644
--- a/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems
+++ b/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems
@@ -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" />
@@ -349,12 +350,14 @@
<Compile Include="$(MSBuildThisFileDirectory)System\Reflection\InvalidFilterCriteriaException.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Reflection\IReflect.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Reflection\IReflectableType.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)System\Reflection\LocalVariableInfo.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Reflection\ManifestResourceInfo.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Reflection\MemberFilter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Reflection\MemberInfo.cs" />
<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" />
@@ -484,6 +487,7 @@
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\MarshalDirectiveException.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\MemoryMarshal.Fast.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\MemoryMarshal.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\NativeCallableAttribute.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\OptionalAttribute.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\OutAttribute.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\PreserveSigAttribute.cs" />
@@ -603,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" />
diff --git a/src/System.Private.CoreLib/shared/System/Collections/Generic/NonRandomizedStringEqualityComparer.cs b/src/System.Private.CoreLib/shared/System/Collections/Generic/NonRandomizedStringEqualityComparer.cs
index e7efa22b2..91b782061 100644
--- a/src/System.Private.CoreLib/shared/System/Collections/Generic/NonRandomizedStringEqualityComparer.cs
+++ b/src/System.Private.CoreLib/shared/System/Collections/Generic/NonRandomizedStringEqualityComparer.cs
@@ -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)
{
diff --git a/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/EventSource.cs b/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/EventSource.cs
index ce43ed093..5c05bf831 100644
--- a/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/EventSource.cs
+++ b/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/EventSource.cs
@@ -181,6 +181,7 @@ using System.Security.Permissions;
using System.Text;
using System.Threading;
using Microsoft.Win32;
+using Internal.Runtime.Augments;
#if ES_BUILD_STANDALONE
using EventDescriptor = Microsoft.Diagnostics.Tracing.EventDescriptor;
@@ -196,10 +197,6 @@ using Contract = System.Diagnostics.Contracts.Contract;
using Contract = Microsoft.Diagnostics.Contracts.Internal.Contract;
#endif
-#if CORECLR || ES_BUILD_PN
-using Internal.Runtime.Augments;
-#endif
-
#if ES_BUILD_STANDALONE
namespace Microsoft.Diagnostics.Tracing
#else
diff --git a/src/System.Private.CoreLib/shared/System/IO/DisableMediaInsertionPrompt.cs b/src/System.Private.CoreLib/shared/System/IO/DisableMediaInsertionPrompt.cs
index aa10e8d88..a3a2d2983 100644
--- a/src/System.Private.CoreLib/shared/System/IO/DisableMediaInsertionPrompt.cs
+++ b/src/System.Private.CoreLib/shared/System/IO/DisableMediaInsertionPrompt.cs
@@ -2,7 +2,13 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+#if MS_IO_REDIST
+using System;
+
+namespace Microsoft.IO
+#else
namespace System.IO
+#endif
{
/// <summary>
/// Simple wrapper to safely disable the normal media insertion prompt for
diff --git a/src/System.Private.CoreLib/shared/System/IO/Path.Windows.cs b/src/System.Private.CoreLib/shared/System/IO/Path.Windows.cs
index f22a9913e..1c27e0cf1 100644
--- a/src/System.Private.CoreLib/shared/System/IO/Path.Windows.cs
+++ b/src/System.Private.CoreLib/shared/System/IO/Path.Windows.cs
@@ -5,7 +5,14 @@
using System.Diagnostics;
using System.Text;
+#if MS_IO_REDIST
+using System;
+using System.IO;
+
+namespace Microsoft.IO
+#else
namespace System.IO
+#endif
{
public static partial class Path
{
@@ -34,7 +41,7 @@ namespace System.IO
throw new ArgumentNullException(nameof(path));
// If the path would normalize to string empty, we'll consider it empty
- if (PathInternal.IsEffectivelyEmpty(path))
+ if (PathInternal.IsEffectivelyEmpty(path.AsSpan()))
throw new ArgumentException(SR.Arg_PathEmpty, nameof(path));
// Embedded null characters are the only invalid character case we trully care about.
@@ -43,7 +50,7 @@ namespace System.IO
if (path.IndexOf('\0') != -1)
throw new ArgumentException(SR.Argument_InvalidPathChars, nameof(path));
- if (PathInternal.IsExtended(path))
+ if (PathInternal.IsExtended(path.AsSpan()))
{
// \\?\ paths are considered normalized by definition. Windows doesn't normalize \\?\
// paths and neither should we. Even if we wanted to GetFullPathName does not work
@@ -72,7 +79,7 @@ namespace System.IO
if (IsPathFullyQualified(path))
return GetFullPath(path);
- if (PathInternal.IsEffectivelyEmpty(path))
+ if (PathInternal.IsEffectivelyEmpty(path.AsSpan()))
return basePath;
int length = path.Length;
@@ -90,23 +97,23 @@ namespace System.IO
// Drive relative paths
Debug.Assert(length == 2 || !PathInternal.IsDirectorySeparator(path[2]));
- if (GetVolumeName(path).EqualsOrdinal(GetVolumeName(basePath)))
+ if (GetVolumeName(path.AsSpan()).EqualsOrdinal(GetVolumeName(basePath.AsSpan())))
{
// Matching root
// "C:Foo" and "C:\Bar" => "C:\Bar\Foo"
// "C:Foo" and "\\?\C:\Bar" => "\\?\C:\Bar\Foo"
- combinedPath = Join(basePath, path.AsSpan(2));
+ combinedPath = Join(basePath.AsSpan(), path.AsSpan(2));
}
else
{
// No matching root, root to specified drive
// "D:Foo" and "C:\Bar" => "D:Foo"
// "D:Foo" and "\\?\C:\Bar" => "\\?\D:\Foo"
- combinedPath = !PathInternal.IsDevice(basePath)
+ combinedPath = !PathInternal.IsDevice(basePath.AsSpan())
? path.Insert(2, @"\")
: length == 2
- ? JoinInternal(basePath.AsSpan(0, 4), path, @"\")
- : JoinInternal(basePath.AsSpan(0, 4), path.AsSpan(0, 2), @"\", path.AsSpan(2));
+ ? JoinInternal(basePath.AsSpan(0, 4), path.AsSpan(), @"\".AsSpan())
+ : JoinInternal(basePath.AsSpan(0, 4), path.AsSpan(0, 2), @"\".AsSpan(), path.AsSpan(2));
}
}
else
@@ -114,15 +121,15 @@ namespace System.IO
// "Simple" relative path
// "Foo" and "C:\Bar" => "C:\Bar\Foo"
// "Foo" and "\\?\C:\Bar" => "\\?\C:\Bar\Foo"
- combinedPath = JoinInternal(basePath, path);
+ combinedPath = JoinInternal(basePath.AsSpan(), path.AsSpan());
}
// Device paths are normalized by definition, so passing something of this format (i.e. \\?\C:\.\tmp, \\.\C:\foo)
// to Windows APIs won't do anything by design. Additionally, GetFullPathName() in Windows doesn't root
// them properly. As such we need to manually remove segments and not use GetFullPath().
- return PathInternal.IsDevice(combinedPath)
- ? PathInternal.RemoveRelativeSegments(combinedPath, PathInternal.GetRootLength(combinedPath))
+ return PathInternal.IsDevice(combinedPath.AsSpan())
+ ? PathInternal.RemoveRelativeSegments(combinedPath, PathInternal.GetRootLength(combinedPath.AsSpan()))
: GetFullPath(combinedPath);
}
@@ -205,14 +212,14 @@ namespace System.IO
// only contains whitespace characters an ArgumentException gets thrown.
public static string GetPathRoot(string path)
{
- if (PathInternal.IsEffectivelyEmpty(path))
+ if (PathInternal.IsEffectivelyEmpty(path.AsSpan()))
return null;
ReadOnlySpan<char> result = GetPathRoot(path.AsSpan());
if (path.Length == result.Length)
return PathInternal.NormalizeDirectorySeparators(path);
- return PathInternal.NormalizeDirectorySeparators(new string(result));
+ return PathInternal.NormalizeDirectorySeparators(result.ToString());
}
/// <remarks>
@@ -273,11 +280,11 @@ namespace System.IO
{
bool isDevice = PathInternal.IsDevice(path);
- if (!isDevice && path.Slice(0, 2).EqualsOrdinal(@"\\") )
+ if (!isDevice && path.Slice(0, 2).EqualsOrdinal(@"\\".AsSpan()) )
return 2;
else if (isDevice && path.Length >= 8
- && (path.Slice(0, 8).EqualsOrdinal(PathInternal.UncExtendedPathPrefix)
- || path.Slice(5, 4).EqualsOrdinal(@"UNC\")))
+ && (path.Slice(0, 8).EqualsOrdinal(PathInternal.UncExtendedPathPrefix.AsSpan())
+ || path.Slice(5, 4).EqualsOrdinal(@"UNC\".AsSpan())))
return 8;
return -1;
diff --git a/src/System.Private.CoreLib/shared/System/IO/Path.cs b/src/System.Private.CoreLib/shared/System/IO/Path.cs
index e619ecd8c..7b4565a13 100644
--- a/src/System.Private.CoreLib/shared/System/IO/Path.cs
+++ b/src/System.Private.CoreLib/shared/System/IO/Path.cs
@@ -6,7 +6,14 @@ using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Text;
+#if MS_IO_REDIST
+using System;
+using System.IO;
+
+namespace Microsoft.IO
+#else
namespace System.IO
+#endif
{
// Provides methods for processing file system strings in a cross-platform manner.
// Most of the methods don't do a complete parsing (such as examining a UNC hostname),
@@ -79,10 +86,10 @@ namespace System.IO
/// </remarks>
public static string GetDirectoryName(string path)
{
- if (path == null || PathInternal.IsEffectivelyEmpty(path))
+ if (path == null || PathInternal.IsEffectivelyEmpty(path.AsSpan()))
return null;
- int end = GetDirectoryNameOffset(path);
+ int end = GetDirectoryNameOffset(path.AsSpan());
return end >= 0 ? PathInternal.NormalizeDirectorySeparators(path.Substring(0, end)) : null;
}
@@ -130,7 +137,7 @@ namespace System.IO
if (path == null)
return null;
- return new string(GetExtension(path.AsSpan()));
+ return GetExtension(path.AsSpan()).ToString();
}
/// <summary>
@@ -173,7 +180,7 @@ namespace System.IO
if (path.Length == result.Length)
return path;
- return new string(result);
+ return result.ToString();
}
/// <summary>
@@ -204,7 +211,7 @@ namespace System.IO
if (path.Length == result.Length)
return path;
- return new string(result);
+ return result.ToString();
}
/// <summary>
@@ -388,9 +395,9 @@ namespace System.IO
public static string Join(ReadOnlySpan<char> path1, ReadOnlySpan<char> path2)
{
if (path1.Length == 0)
- return new string(path2);
+ return path2.ToString();
if (path2.Length == 0)
- return new string(path1);
+ return path1.ToString();
return JoinInternal(path1, path2);
}
@@ -498,7 +505,7 @@ namespace System.IO
if (IsPathRooted(second.AsSpan()))
return second;
- return JoinInternal(first, second);
+ return JoinInternal(first.AsSpan(), second.AsSpan());
}
private static string CombineInternal(string first, string second, string third)
@@ -515,7 +522,7 @@ namespace System.IO
if (IsPathRooted(second.AsSpan()))
return CombineInternal(second, third);
- return JoinInternal(first, second, third);
+ return JoinInternal(first.AsSpan(), second.AsSpan(), third.AsSpan());
}
private static string CombineInternal(string first, string second, string third, string fourth)
@@ -536,7 +543,7 @@ namespace System.IO
if (IsPathRooted(second.AsSpan()))
return CombineInternal(second, third, fourth);
- return JoinInternal(first, second, third, fourth);
+ return JoinInternal(first.AsSpan(), second.AsSpan(), third.AsSpan(), fourth.AsSpan());
}
private static unsafe string JoinInternal(ReadOnlySpan<char> first, ReadOnlySpan<char> second)
@@ -548,7 +555,11 @@ namespace System.IO
fixed (char* f = &MemoryMarshal.GetReference(first), s = &MemoryMarshal.GetReference(second))
{
+#if MS_IO_REDIST
+ return StringExtensions.Create(
+#else
return string.Create(
+#endif
first.Length + second.Length + (hasSeparator ? 0 : 1),
(First: (IntPtr)f, FirstLength: first.Length, Second: (IntPtr)s, SecondLength: second.Length, HasSeparator: hasSeparator),
(destination, state) =>
@@ -572,7 +583,11 @@ namespace System.IO
fixed (char* f = &MemoryMarshal.GetReference(first), s = &MemoryMarshal.GetReference(second), t = &MemoryMarshal.GetReference(third))
{
+#if MS_IO_REDIST
+ return StringExtensions.Create(
+#else
return string.Create(
+#endif
first.Length + second.Length + third.Length + (firstHasSeparator ? 0 : 1) + (thirdHasSeparator ? 0 : 1),
(First: (IntPtr)f, FirstLength: first.Length, Second: (IntPtr)s, SecondLength: second.Length,
Third: (IntPtr)t, ThirdLength: third.Length, FirstHasSeparator: firstHasSeparator, ThirdHasSeparator: thirdHasSeparator),
@@ -602,7 +617,12 @@ namespace System.IO
fixed (char* f = &MemoryMarshal.GetReference(first), s = &MemoryMarshal.GetReference(second), t = &MemoryMarshal.GetReference(third), u = &MemoryMarshal.GetReference(fourth))
{
+
+#if MS_IO_REDIST
+ return StringExtensions.Create(
+#else
return string.Create(
+#endif
first.Length + second.Length + third.Length + fourth.Length + (firstHasSeparator ? 0 : 1) + (thirdHasSeparator ? 0 : 1) + (fourthHasSeparator ? 0 : 1),
(First: (IntPtr)f, FirstLength: first.Length, Second: (IntPtr)s, SecondLength: second.Length,
Third: (IntPtr)t, ThirdLength: third.Length, Fourth: (IntPtr)u, FourthLength:fourth.Length,
@@ -697,7 +717,7 @@ namespace System.IO
private static string GetRelativePath(string relativeTo, string path, StringComparison comparisonType)
{
if (string.IsNullOrEmpty(relativeTo)) throw new ArgumentNullException(nameof(relativeTo));
- if (PathInternal.IsEffectivelyEmpty(path)) throw new ArgumentNullException(nameof(path));
+ if (PathInternal.IsEffectivelyEmpty(path.AsSpan())) throw new ArgumentNullException(nameof(path));
Debug.Assert(comparisonType == StringComparison.Ordinal || comparisonType == StringComparison.OrdinalIgnoreCase);
relativeTo = GetFullPath(relativeTo);
@@ -715,10 +735,10 @@ namespace System.IO
// Trailing separators aren't significant for comparison
int relativeToLength = relativeTo.Length;
- if (PathInternal.EndsInDirectorySeparator(relativeTo))
+ if (PathInternal.EndsInDirectorySeparator(relativeTo.AsSpan()))
relativeToLength--;
- bool pathEndsInSeparator = PathInternal.EndsInDirectorySeparator(path);
+ bool pathEndsInSeparator = PathInternal.EndsInDirectorySeparator(path.AsSpan());
int pathLength = path.Length;
if (pathEndsInSeparator)
pathLength--;
diff --git a/src/System.Private.CoreLib/shared/System/IO/PathHelper.Windows.cs b/src/System.Private.CoreLib/shared/System/IO/PathHelper.Windows.cs
index ed49422c1..bada2f5cd 100644
--- a/src/System.Private.CoreLib/shared/System/IO/PathHelper.Windows.cs
+++ b/src/System.Private.CoreLib/shared/System/IO/PathHelper.Windows.cs
@@ -243,7 +243,7 @@ namespace System.IO
ReadOnlySpan<char> output = builderToUse.AsSpan(rootDifference);
string returnValue = ((originalPath != null) && output.Equals(originalPath.AsSpan(), StringComparison.Ordinal))
- ? originalPath : new string(output);
+ ? originalPath : output.ToString();
inputBuilder.Dispose();
return returnValue;
diff --git a/src/System.Private.CoreLib/shared/System/IO/PathInternal.Windows.cs b/src/System.Private.CoreLib/shared/System/IO/PathInternal.Windows.cs
index b01482abd..5f9ee0e02 100644
--- a/src/System.Private.CoreLib/shared/System/IO/PathInternal.Windows.cs
+++ b/src/System.Private.CoreLib/shared/System/IO/PathInternal.Windows.cs
@@ -130,7 +130,7 @@ namespace System.IO
// In any case, all internal usages should be hitting normalize path (Path.GetFullPath) before they hit this
// shimming method. (Or making a change that doesn't impact normalization, such as adding a filename to a
// normalized base path.)
- if (IsPartiallyQualified(path) || IsDevice(path))
+ if (IsPartiallyQualified(path.AsSpan()) || IsDevice(path.AsSpan()))
return path;
// Given \\server\share in longpath becomes \\?\UNC\server\share
diff --git a/src/System.Private.CoreLib/shared/System/IO/PathInternal.cs b/src/System.Private.CoreLib/shared/System/IO/PathInternal.cs
index c9defac1f..1b08a2612 100644
--- a/src/System.Private.CoreLib/shared/System/IO/PathInternal.cs
+++ b/src/System.Private.CoreLib/shared/System/IO/PathInternal.cs
@@ -22,10 +22,10 @@ namespace System.IO
internal static bool StartsWithDirectorySeparator(ReadOnlySpan<char> path) => path.Length > 0 && IsDirectorySeparator(path[0]);
internal static string EnsureTrailingSeparator(string path)
- => EndsInDirectorySeparator(path) ? path : path + DirectorySeparatorCharAsString;
+ => EndsInDirectorySeparator(path.AsSpan()) ? path : path + DirectorySeparatorCharAsString;
internal static string TrimEndingDirectorySeparator(string path) =>
- EndsInDirectorySeparator(path) && !IsRoot(path) ?
+ EndsInDirectorySeparator(path.AsSpan()) && !IsRoot(path.AsSpan()) ?
path.Substring(0, path.Length - 1) :
path;
@@ -97,8 +97,8 @@ namespace System.IO
/// </summary>
internal static bool AreRootsEqual(string first, string second, StringComparison comparisonType)
{
- int firstRootLength = GetRootLength(first);
- int secondRootLength = GetRootLength(second);
+ int firstRootLength = GetRootLength(first.AsSpan());
+ int secondRootLength = GetRootLength(second.AsSpan());
return firstRootLength == secondRootLength
&& string.Compare(
diff --git a/src/System.Private.CoreLib/shared/System/IO/StreamWriter.cs b/src/System.Private.CoreLib/shared/System/IO/StreamWriter.cs
index b510b6b28..8d94ac60b 100644
--- a/src/System.Private.CoreLib/shared/System/IO/StreamWriter.cs
+++ b/src/System.Private.CoreLib/shared/System/IO/StreamWriter.cs
@@ -476,6 +476,123 @@ namespace System.IO
}
}
+ private void WriteFormatHelper(string format, ParamsArray args, bool appendNewLine)
+ {
+ StringBuilder sb =
+ StringBuilderCache.Acquire(format.Length + args.Length * 8)
+ .AppendFormatHelper(null, format, args);
+
+ StringBuilder.ChunkEnumerator chunks = sb.GetChunks();
+
+ bool more = chunks.MoveNext();
+ while (more)
+ {
+ ReadOnlySpan<char> current = chunks.Current.Span;
+ more = chunks.MoveNext();
+
+ // If final chunk, include the newline if needed
+ WriteSpan(current, appendNewLine: more ? false : appendNewLine);
+ }
+
+ StringBuilderCache.Release(sb);
+ }
+
+ public override void Write(string format, object arg0)
+ {
+ if (GetType() == typeof(StreamWriter))
+ {
+ WriteFormatHelper(format, new ParamsArray(arg0), appendNewLine: false);
+ }
+ else
+ {
+ base.Write(format, arg0);
+ }
+ }
+
+ public override void Write(string format, object arg0, object arg1)
+ {
+ if (GetType() == typeof(StreamWriter))
+ {
+ WriteFormatHelper(format, new ParamsArray(arg0, arg1), appendNewLine: false);
+ }
+ else
+ {
+ base.Write(format, arg0, arg1);
+ }
+ }
+
+ public override void Write(string format, object arg0, object arg1, object arg2)
+ {
+ if (GetType() == typeof(StreamWriter))
+ {
+ WriteFormatHelper(format, new ParamsArray(arg0, arg1, arg2), appendNewLine: false);
+ }
+ else
+ {
+ base.Write(format, arg0, arg1, arg2);
+ }
+ }
+
+ public override void Write(string format, params object[] arg)
+ {
+ if (GetType() == typeof(StreamWriter))
+ {
+ WriteFormatHelper(format, new ParamsArray(arg), appendNewLine: false);
+ }
+ else
+ {
+ base.Write(format, arg);
+ }
+ }
+
+ public override void WriteLine(string format, object arg0)
+ {
+ if (GetType() == typeof(StreamWriter))
+ {
+ WriteFormatHelper(format, new ParamsArray(arg0), appendNewLine: true);
+ }
+ else
+ {
+ base.WriteLine(format, arg0);
+ }
+ }
+
+ public override void WriteLine(string format, object arg0, object arg1)
+ {
+ if (GetType() == typeof(StreamWriter))
+ {
+ WriteFormatHelper(format, new ParamsArray(arg0, arg1), appendNewLine: true);
+ }
+ else
+ {
+ base.WriteLine(format, arg0, arg1);
+ }
+ }
+
+ public override void WriteLine(string format, object arg0, object arg1, object arg2)
+ {
+ if (GetType() == typeof(StreamWriter))
+ {
+ WriteFormatHelper(format, new ParamsArray(arg0, arg1, arg2), appendNewLine: true);
+ }
+ else
+ {
+ base.WriteLine(format, arg0, arg1, arg2);
+ }
+ }
+
+ public override void WriteLine(string format, params object[] arg)
+ {
+ if (GetType() == typeof(StreamWriter))
+ {
+ WriteFormatHelper(format, new ParamsArray(arg), appendNewLine: true);
+ }
+ else
+ {
+ base.WriteLine(format, arg);
+ }
+ }
+
#region Task based Async APIs
public override Task WriteAsync(char value)
{
diff --git a/src/System.Private.CoreLib/src/System/Reflection/ExceptionHandlingClause.cs b/src/System.Private.CoreLib/shared/System/Reflection/ExceptionHandlingClause.cs
index 8598256b3..15780f11c 100644
--- a/src/System.Private.CoreLib/src/System/Reflection/ExceptionHandlingClause.cs
+++ b/src/System.Private.CoreLib/shared/System/Reflection/ExceptionHandlingClause.cs
@@ -9,17 +9,13 @@ namespace System.Reflection
public class ExceptionHandlingClause
{
protected ExceptionHandlingClause() { }
-
- // Desktop compat: These default implementations behave strangely because this class was originally
- // creatable only from the native runtime, not through subclass inheritance.
-
- public virtual Type CatchType => null;
- public virtual int FilterOffset { get { throw new InvalidOperationException(); } }
- public virtual ExceptionHandlingClauseOptions Flags => default(ExceptionHandlingClauseOptions);
- public virtual int HandlerLength => 0;
- public virtual int HandlerOffset => 0;
- public virtual int TryLength => 0;
+ public virtual ExceptionHandlingClauseOptions Flags => default;
public virtual int TryOffset => 0;
+ public virtual int TryLength => 0;
+ public virtual int HandlerOffset => 0;
+ public virtual int HandlerLength => 0;
+ public virtual int FilterOffset => throw new InvalidOperationException(SR.Arg_EHClauseNotFilter);
+ public virtual Type CatchType => null;
public override string ToString()
{
@@ -29,3 +25,4 @@ namespace System.Reflection
}
}
}
+
diff --git a/src/System.Private.CoreLib/shared/System/Reflection/LocalVariableInfo.cs b/src/System.Private.CoreLib/shared/System/Reflection/LocalVariableInfo.cs
new file mode 100644
index 000000000..1540bde53
--- /dev/null
+++ b/src/System.Private.CoreLib/shared/System/Reflection/LocalVariableInfo.cs
@@ -0,0 +1,26 @@
+// 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.Diagnostics;
+
+namespace System.Reflection
+{
+ public class LocalVariableInfo
+ {
+ public virtual Type LocalType { get { Debug.Fail("type must be set!"); return null; } }
+ public virtual int LocalIndex => 0;
+ public virtual bool IsPinned => false;
+ protected LocalVariableInfo() { }
+ public override string ToString()
+ {
+ string toString = LocalType.ToString() + " (" + LocalIndex + ")";
+
+ if (IsPinned)
+ toString += " (pinned)";
+
+ return toString;
+ }
+ }
+}
+
diff --git a/src/System.Private.CoreLib/src/System/Reflection/MethodBody.cs b/src/System.Private.CoreLib/shared/System/Reflection/MethodBody.cs
index b87558573..bdf53ad12 100644
--- a/src/System.Private.CoreLib/src/System/Reflection/MethodBody.cs
+++ b/src/System.Private.CoreLib/shared/System/Reflection/MethodBody.cs
@@ -9,14 +9,12 @@ namespace System.Reflection
public class MethodBody
{
protected MethodBody() { }
-
- // Desktop compat: These default implementations behave strangely because this class was originally
- // creatable only from the native runtime, not through subclass inheritance.
public virtual int LocalSignatureMetadataToken => 0;
- public virtual IList<LocalVariableInfo> LocalVariables { get { throw new ArgumentNullException("array"); } }
+ public virtual IList<LocalVariableInfo> LocalVariables => throw new ArgumentNullException("array");
public virtual int MaxStackSize => 0;
public virtual bool InitLocals => false;
public virtual byte[] GetILAsByteArray() => null;
- public virtual IList<ExceptionHandlingClause> ExceptionHandlingClauses { get { throw new ArgumentNullException("array"); } }
+ public virtual IList<ExceptionHandlingClause> ExceptionHandlingClauses => throw new ArgumentNullException("array");
}
}
+
diff --git a/src/System.Private.CoreLib/src/System/Runtime/InteropServices/NativeCallableAttribute.cs b/src/System.Private.CoreLib/shared/System/Runtime/InteropServices/NativeCallableAttribute.cs
index 32fc29593..bad4d7f6a 100644
--- a/src/System.Private.CoreLib/src/System/Runtime/InteropServices/NativeCallableAttribute.cs
+++ b/src/System.Private.CoreLib/shared/System/Runtime/InteropServices/NativeCallableAttribute.cs
@@ -2,23 +2,28 @@
// 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.CompilerServices;
-
namespace System.Runtime.InteropServices
{
- //BARTOK expects
+ /// <summary>
+ /// Any method marked with NativeCallableAttribute can be directly called from
+ /// native code. The function token can be loaded to a local variable using LDFTN
+ /// and passed as a callback to native method.
+ /// </summary>
[AttributeUsage(AttributeTargets.Method)]
public sealed class NativeCallableAttribute : Attribute
{
- // Optional. If omitted, then the method is native callable, but no EAT is emitted.
- public string EntryPoint;
-
- // Optional. If omitted a default will be chosen by the compiler.
- public CallingConvention CallingConvention;
-
public NativeCallableAttribute()
{
}
+
+ /// <summary>
+ /// Optional. If omitted, compiler will choose one for you.
+ /// </summary>
+ public CallingConvention CallingConvention;
+
+ /// <summary>
+ /// Optional. If omitted, then the method is native callable, but no EAT is emitted.
+ /// </summary>
+ public string EntryPoint;
}
}
diff --git a/src/System.Private.CoreLib/shared/System/Runtime/Intrinsics/Vector128.cs b/src/System.Private.CoreLib/shared/System/Runtime/Intrinsics/Vector128.cs
index f61310e4e..b2e72ddf8 100644
--- a/src/System.Private.CoreLib/shared/System/Runtime/Intrinsics/Vector128.cs
+++ b/src/System.Private.CoreLib/shared/System/Runtime/Intrinsics/Vector128.cs
@@ -13,12 +13,12 @@ namespace System.Runtime.Intrinsics
[DebuggerDisplay("{DisplayString,nq}")]
[DebuggerTypeProxy(typeof(Vector128DebugView<>))]
[StructLayout(LayoutKind.Sequential, Size = 16)]
- public struct Vector128<T> where T : struct
+ public readonly struct Vector128<T> where T : struct
{
// These fields exist to ensure the alignment is 8, rather than 1.
// This also allows the debug view to work https://github.com/dotnet/coreclr/issues/15694)
- private ulong _00;
- private ulong _01;
+ private readonly ulong _00;
+ private readonly ulong _01;
private unsafe string DisplayString
{
diff --git a/src/System.Private.CoreLib/shared/System/Runtime/Intrinsics/Vector128DebugView.cs b/src/System.Private.CoreLib/shared/System/Runtime/Intrinsics/Vector128DebugView.cs
index 7119757b7..ccdc65594 100644
--- a/src/System.Private.CoreLib/shared/System/Runtime/Intrinsics/Vector128DebugView.cs
+++ b/src/System.Private.CoreLib/shared/System/Runtime/Intrinsics/Vector128DebugView.cs
@@ -6,9 +6,9 @@ using Internal.Runtime.CompilerServices;
namespace System.Runtime.Intrinsics
{
- internal struct Vector128DebugView<T> where T : struct
+ internal readonly struct Vector128DebugView<T> where T : struct
{
- private Vector128<T> _value;
+ private readonly Vector128<T> _value;
public Vector128DebugView(Vector128<T> value)
{
diff --git a/src/System.Private.CoreLib/shared/System/Runtime/Intrinsics/Vector256.cs b/src/System.Private.CoreLib/shared/System/Runtime/Intrinsics/Vector256.cs
index 88fd9973e..48744bb5e 100644
--- a/src/System.Private.CoreLib/shared/System/Runtime/Intrinsics/Vector256.cs
+++ b/src/System.Private.CoreLib/shared/System/Runtime/Intrinsics/Vector256.cs
@@ -13,14 +13,14 @@ namespace System.Runtime.Intrinsics
[DebuggerDisplay("{DisplayString,nq}")]
[DebuggerTypeProxy(typeof(Vector256DebugView<>))]
[StructLayout(LayoutKind.Sequential, Size = 32)]
- public struct Vector256<T> where T : struct
+ public readonly struct Vector256<T> where T : struct
{
// These fields exist to ensure the alignment is 8, rather than 1.
// This also allows the debug view to work https://github.com/dotnet/coreclr/issues/15694)
- private ulong _00;
- private ulong _01;
- private ulong _02;
- private ulong _03;
+ private readonly ulong _00;
+ private readonly ulong _01;
+ private readonly ulong _02;
+ private readonly ulong _03;
private unsafe string DisplayString
{
diff --git a/src/System.Private.CoreLib/shared/System/Runtime/Intrinsics/Vector256DebugView.cs b/src/System.Private.CoreLib/shared/System/Runtime/Intrinsics/Vector256DebugView.cs
index f07277604..5131341ad 100644
--- a/src/System.Private.CoreLib/shared/System/Runtime/Intrinsics/Vector256DebugView.cs
+++ b/src/System.Private.CoreLib/shared/System/Runtime/Intrinsics/Vector256DebugView.cs
@@ -6,9 +6,9 @@ using Internal.Runtime.CompilerServices;
namespace System.Runtime.Intrinsics
{
- internal struct Vector256DebugView<T> where T : struct
+ internal readonly struct Vector256DebugView<T> where T : struct
{
- private Vector256<T> _value;
+ private readonly Vector256<T> _value;
public Vector256DebugView(Vector256<T> value)
{
diff --git a/src/System.Private.CoreLib/shared/System/Runtime/Intrinsics/Vector64.cs b/src/System.Private.CoreLib/shared/System/Runtime/Intrinsics/Vector64.cs
index 776fe2017..8ce90b9d0 100644
--- a/src/System.Private.CoreLib/shared/System/Runtime/Intrinsics/Vector64.cs
+++ b/src/System.Private.CoreLib/shared/System/Runtime/Intrinsics/Vector64.cs
@@ -13,11 +13,11 @@ namespace System.Runtime.Intrinsics
[DebuggerDisplay("{DisplayString,nq}")]
[DebuggerTypeProxy(typeof(Vector64DebugView<>))]
[StructLayout(LayoutKind.Sequential, Size = 8)]
- public struct Vector64<T> where T : struct
+ public readonly struct Vector64<T> where T : struct
{
// These fields exist to ensure the alignment is 8, rather than 1.
// This also allows the debug view to work https://github.com/dotnet/coreclr/issues/15694)
- private ulong _00;
+ private readonly ulong _00;
private unsafe string DisplayString
{
diff --git a/src/System.Private.CoreLib/shared/System/Runtime/Intrinsics/Vector64DebugView.cs b/src/System.Private.CoreLib/shared/System/Runtime/Intrinsics/Vector64DebugView.cs
index 129832a3c..878e29949 100644
--- a/src/System.Private.CoreLib/shared/System/Runtime/Intrinsics/Vector64DebugView.cs
+++ b/src/System.Private.CoreLib/shared/System/Runtime/Intrinsics/Vector64DebugView.cs
@@ -6,9 +6,9 @@ using Internal.Runtime.CompilerServices;
namespace System.Runtime.Intrinsics
{
- internal struct Vector64DebugView<T> where T : struct
+ internal readonly struct Vector64DebugView<T> where T : struct
{
- private Vector64<T> _value;
+ private readonly Vector64<T> _value;
public Vector64DebugView(Vector64<T> value)
{
diff --git a/src/System.Private.CoreLib/shared/System/String.Comparison.cs b/src/System.Private.CoreLib/shared/System/String.Comparison.cs
index 3ddc90a50..8ac31796b 100644
--- a/src/System.Private.CoreLib/shared/System/String.Comparison.cs
+++ b/src/System.Private.CoreLib/shared/System/String.Comparison.cs
@@ -753,54 +753,37 @@ namespace System
// that string.Equals(A, B, C), then they will return the same hash code with this comparison C.
public int GetHashCode(StringComparison comparisonType) => StringComparer.FromComparison(comparisonType).GetHashCode(this);
- // Use this if and only if you need the hashcode to not change across app domains (e.g. you have an app domain agile
- // hash table).
- internal int GetLegacyNonRandomizedHashCode()
+ // Use this if and only if 'Denial of Service' attacks are not a concern (i.e. never used for free-form user input),
+ // or are otherwise mitigated
+ internal unsafe int GetNonRandomizedHashCode()
{
- unsafe
+ fixed (char* src = &_firstChar)
{
- fixed (char* src = &_firstChar)
- {
- Debug.Assert(src[this.Length] == '\0', "src[this.Length] == '\\0'");
- Debug.Assert(((int)src) % 4 == 0, "Managed string should start at 4 bytes boundary");
-#if BIT64
- int hash1 = 5381;
-#else // !BIT64 (32)
- int hash1 = (5381<<16) + 5381;
-#endif
- int hash2 = hash1;
+ Debug.Assert(src[this.Length] == '\0', "src[this.Length] == '\\0'");
+ Debug.Assert(((int)src) % 4 == 0, "Managed string should start at 4 bytes boundary");
-#if BIT64
- int c;
- char* s = src;
- while ((c = s[0]) != 0)
- {
- hash1 = ((hash1 << 5) + hash1) ^ c;
- c = s[1];
- if (c == 0)
- break;
- hash2 = ((hash2 << 5) + hash2) ^ c;
- s += 2;
- }
-#else // !BIT64 (32)
- // 32 bit machines.
- int* pint = (int *)src;
- int len = this.Length;
- while (len > 2)
- {
- hash1 = ((hash1 << 5) + hash1 + (hash1 >> 27)) ^ pint[0];
- hash2 = ((hash2 << 5) + hash2 + (hash2 >> 27)) ^ pint[1];
- pint += 2;
- len -= 4;
- }
+ uint hash1 = (5381 << 16) + 5381;
+ uint hash2 = hash1;
- if (len > 0)
- {
- hash1 = ((hash1 << 5) + hash1 + (hash1 >> 27)) ^ pint[0];
- }
-#endif
- return hash1 + (hash2 * 1566083941);
+ uint* ptr = (uint*)src;
+ int length = this.Length;
+
+ while (length > 2)
+ {
+ length -= 4;
+ // Where length is 4n-1 (e.g. 3,7,11,15,19) this additionally consumes the null terminator
+ hash1 = (((hash1 << 5) | (hash1 >> 27)) + hash1) ^ ptr[0];
+ hash2 = (((hash2 << 5) | (hash2 >> 27)) + hash2) ^ ptr[1];
+ ptr += 2;
}
+
+ if (length > 0)
+ {
+ // Where length is 4n-3 (e.g. 1,5,9,13,17) this additionally consumes the null terminator
+ hash2 = (((hash2 << 5) | (hash2 >> 27)) + hash2) ^ ptr[0];
+ }
+
+ return (int)(hash1 + (hash2 * 1566083941));
}
}
diff --git a/src/System.Private.CoreLib/shared/System/Text/ValueStringBuilder.cs b/src/System.Private.CoreLib/shared/System/Text/ValueStringBuilder.cs
index 045a40b65..21cc3dc01 100644
--- a/src/System.Private.CoreLib/shared/System/Text/ValueStringBuilder.cs
+++ b/src/System.Private.CoreLib/shared/System/Text/ValueStringBuilder.cs
@@ -73,7 +73,7 @@ namespace System.Text
public override string ToString()
{
- var s = new string(_chars.Slice(0, _pos));
+ var s = _chars.Slice(0, _pos).ToString();
Dispose();
return s;
}
diff --git a/src/System.Private.CoreLib/src/System/Threading/SpinLock.cs b/src/System.Private.CoreLib/shared/System/Threading/SpinLock.cs
index 7f3cb120b..2b0610539 100644
--- a/src/System.Private.CoreLib/src/System/Threading/SpinLock.cs
+++ b/src/System.Private.CoreLib/shared/System/Threading/SpinLock.cs
@@ -12,12 +12,8 @@
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
using System.Diagnostics;
-using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
-using Internal.Runtime.Augments;
-using Internal.Threading.Tracing;
-
namespace System.Threading
{
/// <summary>
@@ -66,35 +62,28 @@ namespace System.Threading
//
// There are several masks and constants below for convenience.
- private volatile int m_owner;
-
- // The multiplier factor for the each spinning iteration
- // This number has been chosen after trying different numbers on different CPUs (4, 8 and 16 ) and this provided the best results
- private const int SPINNING_FACTOR = 100;
+ private volatile int _owner;
// After how many yields, call Sleep(1)
private const int SLEEP_ONE_FREQUENCY = 40;
- // After how many yields, call Sleep(0)
- private const int SLEEP_ZERO_FREQUENCY = 10;
-
// After how many yields, check the timeout
private const int TIMEOUT_CHECK_FREQUENCY = 10;
// Thr thread tracking disabled mask
- private const int LOCK_ID_DISABLE_MASK = unchecked((int)0x80000000); //1000 0000 0000 0000 0000 0000 0000 0000
+ private const int LOCK_ID_DISABLE_MASK = unchecked((int)0x80000000); // 1000 0000 0000 0000 0000 0000 0000 0000
//the lock is held by some thread, but we don't know which
- private const int LOCK_ANONYMOUS_OWNED = 0x1; //0000 0000 0000 0000 0000 0000 0000 0001
+ private const int LOCK_ANONYMOUS_OWNED = 0x1; // 0000 0000 0000 0000 0000 0000 0000 0001
// Waiters mask if the thread tracking is disabled
- private const int WAITERS_MASK = ~(LOCK_ID_DISABLE_MASK | 1); //0111 1111 1111 1111 1111 1111 1111 1110
+ private const int WAITERS_MASK = ~(LOCK_ID_DISABLE_MASK | 1); // 0111 1111 1111 1111 1111 1111 1111 1110
// The Thread tacking is disabled and the lock bit is set, used in Enter fast path to make sure the id is disabled and lock is available
- private const int ID_DISABLED_AND_ANONYMOUS_OWNED = unchecked((int)0x80000001); //1000 0000 0000 0000 0000 0000 0000 0001
+ private const int ID_DISABLED_AND_ANONYMOUS_OWNED = unchecked((int)0x80000001); // 1000 0000 0000 0000 0000 0000 0000 0001
// If the thread is unowned if:
- // m_owner zero and the threa tracking is enabled
+ // m_owner zero and the thread tracking is enabled
// m_owner & LOCK_ANONYMOUS_OWNED = zero and the thread tracking is disabled
private const int LOCK_UNOWNED = 0;
@@ -104,7 +93,7 @@ namespace System.Threading
private static int MAXIMUM_WAITERS = WAITERS_MASK;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private int CompareExchange(ref int location, int value, int comparand, ref bool success)
+ private static int CompareExchange(ref int location, int value, int comparand, ref bool success)
{
int result = Interlocked.CompareExchange(ref location, value, comparand);
success = (result == comparand);
@@ -122,10 +111,10 @@ namespace System.Threading
/// purposes.</param>
public SpinLock(bool enableThreadOwnerTracking)
{
- m_owner = LOCK_UNOWNED;
+ _owner = LOCK_UNOWNED;
if (!enableThreadOwnerTracking)
{
- m_owner |= LOCK_ID_DISABLE_MASK;
+ _owner |= LOCK_ID_DISABLE_MASK;
Debug.Assert(!IsThreadOwnerTrackingEnabled, "property should be false by now");
}
}
@@ -159,11 +148,11 @@ namespace System.Threading
/// </exception>
public void Enter(ref bool lockTaken)
{
- //Try to keep the code and branching in this method as small as possible in order to inline the method
- int observedOwner = m_owner;
- if (lockTaken || //invalid parameter
- (observedOwner & ID_DISABLED_AND_ANONYMOUS_OWNED) != LOCK_ID_DISABLE_MASK || //thread tracking is enabled or the lock is already acquired
- CompareExchange(ref m_owner, observedOwner | LOCK_ANONYMOUS_OWNED, observedOwner, ref lockTaken) != observedOwner) //acquiring the lock failed
+ // Try to keep the code and branching in this method as small as possible in order to inline the method
+ int observedOwner = _owner;
+ if (lockTaken || // invalid parameter
+ (observedOwner & ID_DISABLED_AND_ANONYMOUS_OWNED) != LOCK_ID_DISABLE_MASK || // thread tracking is enabled or the lock is already acquired
+ CompareExchange(ref _owner, observedOwner | LOCK_ANONYMOUS_OWNED, observedOwner, ref lockTaken) != observedOwner) //acquiring the lock failed
ContinueTryEnter(Timeout.Infinite, ref lockTaken); // Then try the slow path if any of the above conditions is met
}
@@ -187,7 +176,7 @@ namespace System.Threading
/// </exception>
public void TryEnter(ref bool lockTaken)
{
- int observedOwner = m_owner;
+ int observedOwner = _owner;
if (((observedOwner & LOCK_ID_DISABLE_MASK) == 0) | lockTaken)
{
// Thread tracking enabled or invalid arg. Take slow path.
@@ -201,7 +190,7 @@ namespace System.Threading
else
{
// Lock wasn't held; try to acquire it.
- CompareExchange(ref m_owner, observedOwner | LOCK_ANONYMOUS_OWNED, observedOwner, ref lockTaken);
+ CompareExchange(ref _owner, observedOwner | LOCK_ANONYMOUS_OWNED, observedOwner, ref lockTaken);
}
}
@@ -269,18 +258,18 @@ namespace System.Threading
/// a negative number other than -1, which represents an infinite time-out.</exception>
public void TryEnter(int millisecondsTimeout, ref bool lockTaken)
{
- int observedOwner = m_owner;
+ int observedOwner = _owner;
if (millisecondsTimeout < -1 || //invalid parameter
lockTaken || //invalid parameter
(observedOwner & ID_DISABLED_AND_ANONYMOUS_OWNED) != LOCK_ID_DISABLE_MASK || //thread tracking is enabled or the lock is already acquired
- CompareExchange(ref m_owner, observedOwner | LOCK_ANONYMOUS_OWNED, observedOwner, ref lockTaken) != observedOwner) // acquiring the lock failed
+ CompareExchange(ref _owner, observedOwner | LOCK_ANONYMOUS_OWNED, observedOwner, ref lockTaken) != observedOwner) // acquiring the lock failed
ContinueTryEnter(millisecondsTimeout, ref lockTaken); // The call the slow pth
}
/// <summary>
/// Try acquire the lock with long path, this is usually called after the first path in Enter and
/// TryEnter failed The reason for short path is to make it inline in the run time which improves the
- /// performance. This method assumed that the parameter are validated in Enter ir TryENter method
+ /// performance. This method assumed that the parameter are validated in Enter or TryEnter method.
/// </summary>
/// <param name="millisecondsTimeout">The timeout milliseconds</param>
/// <param name="lockTaken">The lockTaken param</param>
@@ -290,7 +279,7 @@ namespace System.Threading
if (lockTaken)
{
lockTaken = false;
- throw new System.ArgumentException(SR.SpinLock_TryReliableEnter_ArgumentException);
+ throw new ArgumentException(SR.SpinLock_TryReliableEnter_ArgumentException);
}
if (millisecondsTimeout < -1)
@@ -305,11 +294,6 @@ namespace System.Threading
startTime = TimeoutHelper.GetTime();
}
- if (SpinLockTrace.Enabled)
- {
- SpinLockTrace.SpinLock_FastPathFailed(m_owner);
- }
-
if (IsThreadOwnerTrackingEnabled)
{
// Slow path for enabled thread tracking mode
@@ -332,10 +316,10 @@ namespace System.Threading
//***Step 1, take the lock or update the waiters
// try to acquire the lock directly if possible or update the waiters count
- observedOwner = m_owner;
+ observedOwner = _owner;
if ((observedOwner & LOCK_ANONYMOUS_OWNED) == LOCK_UNOWNED)
{
- if (CompareExchange(ref m_owner, observedOwner | 1, observedOwner, ref lockTaken) == observedOwner)
+ if (CompareExchange(ref _owner, observedOwner | 1, observedOwner, ref lockTaken) == observedOwner)
{
// Acquired lock
return;
@@ -352,89 +336,50 @@ namespace System.Threading
// Did not acquire lock as owned and timeout is 0 so fail fast
return;
}
- else //failed to acquire the lock,then try to update the waiters. If the waiters count reached the maximum, jsut break the loop to avoid overflow
+ else //failed to acquire the lock, then try to update the waiters. If the waiters count reached the maximum, just break the loop to avoid overflow
{
if ((observedOwner & WAITERS_MASK) != MAXIMUM_WAITERS)
- turn = (Interlocked.Add(ref m_owner, 2) & WAITERS_MASK) >> 1;
- }
-
- //***Step 2. Spinning
- //lock acquired failed and waiters updated
- int processorCount = PlatformHelper.ProcessorCount;
- if (turn < processorCount)
- {
- int processFactor = 1;
- for (int i = 1; i <= turn * SPINNING_FACTOR; i++)
- {
- RuntimeThread.SpinWait((turn + i) * SPINNING_FACTOR * processFactor);
- if (processFactor < processorCount)
- processFactor++;
- observedOwner = m_owner;
- if ((observedOwner & LOCK_ANONYMOUS_OWNED) == LOCK_UNOWNED)
- {
- int newOwner = (observedOwner & WAITERS_MASK) == 0 ? // Gets the number of waiters, if zero
- observedOwner | 1 // don't decrement it. just set the lock bit, it is zzero because a previous call of Exit(false) ehich corrupted the waiters
- : (observedOwner - 2) | 1; // otherwise decrement the waiters and set the lock bit
- Debug.Assert((newOwner & WAITERS_MASK) >= 0);
-
- if (CompareExchange(ref m_owner, newOwner, observedOwner, ref lockTaken) == observedOwner)
- {
- return;
- }
- }
- }
-
- // Check the timeout.
- if (millisecondsTimeout != Timeout.Infinite && TimeoutHelper.UpdateTimeOut(startTime, millisecondsTimeout) <= 0)
{
- DecrementWaiters();
- return;
+ // This can still overflow, but maybe there will never be that many waiters
+ turn = (Interlocked.Add(ref _owner, 2) & WAITERS_MASK) >> 1;
}
}
- //*** Step 3, Yielding
- //Sleep(1) every 50 yields
- int yieldsoFar = 0;
+ // lock acquired failed and waiters updated
+
+ //*** Step 2, Spinning and Yielding
+ var spinner = new SpinWait();
+ if (turn > PlatformHelper.ProcessorCount)
+ {
+ spinner.Count = SpinWait.YieldThreshold;
+ }
while (true)
{
- observedOwner = m_owner;
+ spinner.SpinOnce(SLEEP_ONE_FREQUENCY);
+
+ observedOwner = _owner;
if ((observedOwner & LOCK_ANONYMOUS_OWNED) == LOCK_UNOWNED)
{
int newOwner = (observedOwner & WAITERS_MASK) == 0 ? // Gets the number of waiters, if zero
- observedOwner | 1 // don't decrement it. just set the lock bit, it is zzero because a previous call of Exit(false) ehich corrupted the waiters
+ observedOwner | 1 // don't decrement it. just set the lock bit, it is zero because a previous call of Exit(false) which corrupted the waiters
: (observedOwner - 2) | 1; // otherwise decrement the waiters and set the lock bit
Debug.Assert((newOwner & WAITERS_MASK) >= 0);
- if (CompareExchange(ref m_owner, newOwner, observedOwner, ref lockTaken) == observedOwner)
+ if (CompareExchange(ref _owner, newOwner, observedOwner, ref lockTaken) == observedOwner)
{
return;
}
}
- if (yieldsoFar % SLEEP_ONE_FREQUENCY == 0)
- {
- RuntimeThread.Sleep(1);
- }
- else if (yieldsoFar % SLEEP_ZERO_FREQUENCY == 0)
- {
- RuntimeThread.Sleep(0);
- }
- else
- {
- RuntimeThread.Yield();
- }
-
- if (yieldsoFar % TIMEOUT_CHECK_FREQUENCY == 0)
+ if (spinner.Count % TIMEOUT_CHECK_FREQUENCY == 0)
{
- //Check the timeout.
+ // Check the timeout.
if (millisecondsTimeout != Timeout.Infinite && TimeoutHelper.UpdateTimeOut(startTime, millisecondsTimeout) <= 0)
{
DecrementWaiters();
return;
}
}
-
- yieldsoFar++;
}
}
@@ -446,9 +391,9 @@ namespace System.Threading
SpinWait spinner = new SpinWait();
while (true)
{
- int observedOwner = m_owner;
+ int observedOwner = _owner;
if ((observedOwner & WAITERS_MASK) == 0) return; // don't decrement the waiters if it's corrupted by previous call of Exit(false)
- if (Interlocked.CompareExchange(ref m_owner, observedOwner - 2, observedOwner) == observedOwner)
+ if (Interlocked.CompareExchange(ref _owner, observedOwner - 2, observedOwner) == observedOwner)
{
Debug.Assert(!IsThreadOwnerTrackingEnabled); // Make sure the waiters never be negative which will cause the thread tracking bit to be flipped
break;
@@ -467,8 +412,8 @@ namespace System.Threading
int lockUnowned = 0;
// We are using thread IDs to mark ownership. Snap the thread ID and check for recursion.
// We also must or the ID enablement bit, to ensure we propagate when we CAS it in.
- int m_newOwner = Environment.CurrentManagedThreadId;
- if (m_owner == m_newOwner)
+ int newOwner = Environment.CurrentManagedThreadId;
+ if (_owner == newOwner)
{
// We don't allow lock recursion.
throw new LockRecursionException(SR.SpinLock_TryEnter_LockRecursionException);
@@ -486,9 +431,9 @@ namespace System.Threading
// Test before trying to CAS, to avoid acquiring the line exclusively unnecessarily.
- if (m_owner == lockUnowned)
+ if (_owner == lockUnowned)
{
- if (CompareExchange(ref m_owner, m_newOwner, lockUnowned, ref lockTaken) == lockUnowned)
+ if (CompareExchange(ref _owner, newOwner, lockUnowned, ref lockTaken) == lockUnowned)
{
return;
}
@@ -516,10 +461,10 @@ namespace System.Threading
public void Exit()
{
//This is the fast path for the thread tracking is disabled, otherwise go to the slow path
- if ((m_owner & LOCK_ID_DISABLE_MASK) == 0)
+ if ((_owner & LOCK_ID_DISABLE_MASK) == 0)
ExitSlowPath(true);
else
- Interlocked.Decrement(ref m_owner);
+ Interlocked.Decrement(ref _owner);
}
/// <summary>
@@ -540,16 +485,18 @@ namespace System.Threading
/// </exception>
public void Exit(bool useMemoryBarrier)
{
- // This is the fast path for the thread tracking is diabled and not to use memory barrier, otherwise go to the slow path
+ // This is the fast path for the thread tracking is disabled and not to use memory barrier, otherwise go to the slow path
// The reason not to add else statement if the usememorybarrier is that it will add more branching in the code and will prevent
// method inlining, so this is optimized for useMemoryBarrier=false and Exit() overload optimized for useMemoryBarrier=true.
- int tmpOwner = m_owner;
+ int tmpOwner = _owner;
if ((tmpOwner & LOCK_ID_DISABLE_MASK) != 0 & !useMemoryBarrier)
{
- m_owner = tmpOwner & (~LOCK_ANONYMOUS_OWNED);
+ _owner = tmpOwner & (~LOCK_ANONYMOUS_OWNED);
}
else
+ {
ExitSlowPath(useMemoryBarrier);
+ }
}
/// <summary>
@@ -561,28 +508,33 @@ namespace System.Threading
/// </param>
private void ExitSlowPath(bool useMemoryBarrier)
{
- bool threadTrackingEnabled = (m_owner & LOCK_ID_DISABLE_MASK) == 0;
+ bool threadTrackingEnabled = (_owner & LOCK_ID_DISABLE_MASK) == 0;
if (threadTrackingEnabled && !IsHeldByCurrentThread)
{
- throw new System.Threading.SynchronizationLockException(
- SR.SpinLock_Exit_SynchronizationLockException);
+ throw new SynchronizationLockException(SR.SpinLock_Exit_SynchronizationLockException);
}
if (useMemoryBarrier)
{
if (threadTrackingEnabled)
- Interlocked.Exchange(ref m_owner, LOCK_UNOWNED);
+ {
+ Interlocked.Exchange(ref _owner, LOCK_UNOWNED);
+ }
else
- Interlocked.Decrement(ref m_owner);
+ {
+ Interlocked.Decrement(ref _owner);
+ }
}
else
{
if (threadTrackingEnabled)
- m_owner = LOCK_UNOWNED;
+ {
+ _owner = LOCK_UNOWNED;
+ }
else
{
- int tmpOwner = m_owner;
- m_owner = tmpOwner & (~LOCK_ANONYMOUS_OWNED);
+ int tmpOwner = _owner;
+ _owner = tmpOwner & (~LOCK_ANONYMOUS_OWNED);
}
}
}
@@ -595,9 +547,9 @@ namespace System.Threading
get
{
if (IsThreadOwnerTrackingEnabled)
- return m_owner != LOCK_UNOWNED;
+ return _owner != LOCK_UNOWNED;
- return (m_owner & LOCK_ANONYMOUS_OWNED) != LOCK_UNOWNED;
+ return (_owner & LOCK_ANONYMOUS_OWNED) != LOCK_UNOWNED;
}
}
@@ -623,15 +575,12 @@ namespace System.Threading
{
throw new InvalidOperationException(SR.SpinLock_IsHeldByCurrentThread);
}
- return ((m_owner & (~LOCK_ID_DISABLE_MASK)) == Environment.CurrentManagedThreadId);
+ return ((_owner & (~LOCK_ID_DISABLE_MASK)) == Environment.CurrentManagedThreadId);
}
}
/// <summary>Gets whether thread ownership tracking is enabled for this instance.</summary>
- public bool IsThreadOwnerTrackingEnabled
- {
- get { return (m_owner & LOCK_ID_DISABLE_MASK) == 0; }
- }
+ public bool IsThreadOwnerTrackingEnabled => (_owner & LOCK_ID_DISABLE_MASK) == 0;
#region Debugger proxy class
/// <summary>
@@ -640,7 +589,7 @@ namespace System.Threading
internal class SystemThreading_SpinLockDebugView
{
// SpinLock object
- private SpinLock m_spinLock;
+ private SpinLock _spinLock;
/// <summary>
/// SystemThreading_SpinLockDebugView constructor
@@ -649,7 +598,7 @@ namespace System.Threading
public SystemThreading_SpinLockDebugView(SpinLock spinLock)
{
// Note that this makes a copy of the SpinLock (struct). It doesn't hold a reference to it.
- m_spinLock = spinLock;
+ _spinLock = spinLock;
}
/// <summary>
@@ -661,7 +610,7 @@ namespace System.Threading
{
try
{
- return m_spinLock.IsHeldByCurrentThread;
+ return _spinLock.IsHeldByCurrentThread;
}
catch (InvalidOperationException)
{
@@ -677,9 +626,9 @@ namespace System.Threading
{
get
{
- if (m_spinLock.IsThreadOwnerTrackingEnabled)
+ if (_spinLock.IsThreadOwnerTrackingEnabled)
{
- return m_spinLock.m_owner;
+ return _spinLock._owner;
}
else
{
@@ -692,10 +641,7 @@ namespace System.Threading
/// <summary>
/// Gets whether the lock is currently held by any thread or not.
/// </summary>
- public bool IsHeld
- {
- get { return m_spinLock.IsHeld; }
- }
+ public bool IsHeld => _spinLock.IsHeld;
}
#endregion
diff --git a/src/System.Private.CoreLib/src/System/Threading/ThreadLocal.cs b/src/System.Private.CoreLib/shared/System/Threading/ThreadLocal.cs
index ad6da89a9..9f4beae9c 100644
--- a/src/System.Private.CoreLib/src/System/Threading/ThreadLocal.cs
+++ b/src/System.Private.CoreLib/shared/System/Threading/ThreadLocal.cs
@@ -1,23 +1,13 @@
// 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.
-#pragma warning disable 0420
-// =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
-//
-//
+using System.Collections.Generic;
+using System.Diagnostics;
-//
// A class that provides a simple, lightweight implementation of thread-local lazy-initialization, where a value is initialized once per accessing
// thread; this provides an alternative to using a ThreadStatic static variable and having
// to check the variable prior to every access to see if it's been initialized.
-//
-//
-//
-// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
-
-using System.Diagnostics;
-using System.Collections.Generic;
namespace System.Threading
{
@@ -37,15 +27,13 @@ namespace System.Threading
public class ThreadLocal<T> : IDisposable
{
// a delegate that returns the created value, if null the created value will be default(T)
- private Func<T> m_valueFactory;
+ private Func<T> _valueFactory;
- //
// ts_slotArray is a table of thread-local values for all ThreadLocal<T> instances
//
// So, when a thread reads ts_slotArray, it gets back an array of *all* ThreadLocal<T> values for this thread and this T.
- // The slot relevant to this particular ThreadLocal<T> instance is determined by the m_idComplement instance field stored in
+ // The slot relevant to this particular ThreadLocal<T> instance is determined by the _idComplement instance field stored in
// the ThreadLocal<T> instance.
- //
[ThreadStatic]
private static LinkedSlotVolatile[] ts_slotArray;
@@ -55,22 +43,22 @@ namespace System.Threading
// Slot ID of this ThreadLocal<> instance. We store a bitwise complement of the ID (that is ~ID), which allows us to distinguish
// between the case when ID is 0 and an incompletely initialized object, either due to a thread abort in the constructor, or
// possibly due to a memory model issue in user code.
- private int m_idComplement;
+ private int _idComplement;
// This field is set to true when the constructor completes. That is helpful for recognizing whether a constructor
// threw an exception - either due to invalid argument or due to a thread abort. Finally, the field is set to false
// when the instance is disposed.
- private volatile bool m_initialized;
+ private volatile bool _initialized;
// IdManager assigns and reuses slot IDs. Additionally, the object is also used as a global lock.
private static IdManager s_idManager = new IdManager();
// A linked list of all values associated with this ThreadLocal<T> instance.
// We create a dummy head node. That allows us to remove any (non-dummy) node without having to locate the m_linkedSlot field.
- private LinkedSlot m_linkedSlot = new LinkedSlot(null);
+ private LinkedSlot _linkedSlot = new LinkedSlot(null);
// Whether the Values property is supported
- private bool m_trackAllValues;
+ private bool _trackAllValues;
/// <summary>
/// Initializes the <see cref="System.Threading.ThreadLocal{T}"/> instance.
@@ -131,19 +119,19 @@ namespace System.Threading
private void Initialize(Func<T> valueFactory, bool trackAllValues)
{
- m_valueFactory = valueFactory;
- m_trackAllValues = trackAllValues;
+ _valueFactory = valueFactory;
+ _trackAllValues = trackAllValues;
- // Assign the ID and mark the instance as initialized. To avoid leaking IDs, we assign the ID and set m_initialized
+ // Assign the ID and mark the instance as initialized. To avoid leaking IDs, we assign the ID and set _initialized
// in a finally block, to avoid a thread abort in between the two statements.
try { }
finally
{
- m_idComplement = ~s_idManager.GetId();
+ _idComplement = ~s_idManager.GetId();
- // As the last step, mark the instance as fully initialized. (Otherwise, if m_initialized=false, we know that an exception
+ // As the last step, mark the instance as fully initialized. (Otherwise, if _initialized=false, we know that an exception
// occurred in the constructor.)
- m_initialized = true;
+ _initialized = true;
}
}
@@ -183,23 +171,23 @@ namespace System.Threading
{
int id;
- using (LockHolder.Hold(s_idManager.m_lock))
+ lock (s_idManager)
{
- id = ~m_idComplement;
- m_idComplement = 0;
+ id = ~_idComplement;
+ _idComplement = 0;
- if (id < 0 || !m_initialized)
+ if (id < 0 || !_initialized)
{
- Debug.Assert(id >= 0 || !m_initialized, "expected id >= 0 if initialized");
+ Debug.Assert(id >= 0 || !_initialized, "expected id >= 0 if initialized");
// Handle double Dispose calls or disposal of an instance whose constructor threw an exception.
return;
}
- m_initialized = false;
+ _initialized = false;
- for (LinkedSlot linkedSlot = m_linkedSlot.Next; linkedSlot != null; linkedSlot = linkedSlot.Next)
+ for (LinkedSlot linkedSlot = _linkedSlot._next; linkedSlot != null; linkedSlot = linkedSlot._next)
{
- LinkedSlotVolatile[] slotArray = linkedSlot.SlotArray;
+ LinkedSlotVolatile[] slotArray = linkedSlot._slotArray;
if (slotArray == null)
{
@@ -208,15 +196,15 @@ namespace System.Threading
}
// Remove the reference from the LinkedSlot to the slot table.
- linkedSlot.SlotArray = null;
+ linkedSlot._slotArray = null;
// And clear the references from the slot table to the linked slot and the value so that
// both can get garbage collected.
- slotArray[id].Value.Value = default(T);
+ slotArray[id].Value._value = default;
slotArray[id].Value = null;
}
}
- m_linkedSlot = null;
+ _linkedSlot = null;
s_idManager.ReturnId(id);
}
@@ -265,7 +253,7 @@ namespace System.Threading
{
LinkedSlotVolatile[] slotArray = ts_slotArray;
LinkedSlot slot;
- int id = ~m_idComplement;
+ int id = ~_idComplement;
//
// Attempt to get the value using the fast path
@@ -274,7 +262,7 @@ namespace System.Threading
&& id >= 0 // Is the ID non-negative (i.e., instance is not disposed)?
&& id < slotArray.Length // Is the table large enough?
&& (slot = slotArray[id].Value) != null // Has a LinkedSlot object has been allocated for this ID?
- && m_initialized // Has the instance *still* not been disposed (important for races with Dispose)?
+ && _initialized // Has the instance *still* not been disposed (important for a race condition with Dispose)?
)
{
// We verified that the instance has not been disposed *after* we got a reference to the slot.
@@ -282,7 +270,7 @@ namespace System.Threading
//
// Volatile read of the LinkedSlotVolatile.Value property ensures that the m_initialized read
// will not be reordered before the read of slotArray[id].
- return slot.Value;
+ return slot._value;
}
return GetValueSlow();
@@ -291,16 +279,14 @@ namespace System.Threading
{
LinkedSlotVolatile[] slotArray = ts_slotArray;
LinkedSlot slot;
- int id = ~m_idComplement;
+ int id = ~_idComplement;
- //
// Attempt to set the value using the fast path
- //
if (slotArray != null // Has the slot array been initialized?
&& id >= 0 // Is the ID non-negative (i.e., instance is not disposed)?
&& id < slotArray.Length // Is the table large enough?
&& (slot = slotArray[id].Value) != null // Has a LinkedSlot object has been allocated for this ID?
- && m_initialized // Has the instance *still* not been disposed (important for races with Dispose)?
+ && _initialized // Has the instance *still* not been disposed (important for a race condition with Dispose)?
)
{
// We verified that the instance has not been disposed *after* we got a reference to the slot.
@@ -308,7 +294,7 @@ namespace System.Threading
//
// Volatile read of the LinkedSlotVolatile.Value property ensures that the m_initialized read
// will not be reordered before the read of slotArray[id].
- slot.Value = value;
+ slot._value = value;
}
else
{
@@ -320,23 +306,23 @@ namespace System.Threading
private T GetValueSlow()
{
// If the object has been disposed, the id will be -1.
- int id = ~m_idComplement;
+ int id = ~_idComplement;
if (id < 0)
{
throw new ObjectDisposedException(SR.ThreadLocal_Disposed);
}
- //Debugger.NotifyOfCrossThreadDependency();
+ Debugger.NotifyOfCrossThreadDependency();
// Determine the initial value
T value;
- if (m_valueFactory == null)
+ if (_valueFactory == null)
{
- value = default(T);
+ value = default;
}
else
{
- value = m_valueFactory();
+ value = _valueFactory();
if (IsValueCreated)
{
@@ -351,7 +337,7 @@ namespace System.Threading
private void SetValueSlow(T value, LinkedSlotVolatile[] slotArray)
{
- int id = ~m_idComplement;
+ int id = ~_idComplement;
// If the object has been disposed, id will be -1.
if (id < 0)
@@ -363,7 +349,7 @@ namespace System.Threading
if (slotArray == null)
{
slotArray = new LinkedSlotVolatile[GetNewTableSize(id + 1)];
- ts_finalizationHelper = new FinalizationHelper(slotArray, m_trackAllValues);
+ ts_finalizationHelper = new FinalizationHelper(slotArray, _trackAllValues);
ts_slotArray = slotArray;
}
@@ -392,12 +378,12 @@ namespace System.Threading
// if this ThreadLocal instance was disposed on another thread and another ThreadLocal instance was
// created, we definitely won't assign the value into the wrong instance.
- if (!m_initialized)
+ if (!_initialized)
{
throw new ObjectDisposedException(SR.ThreadLocal_Disposed);
}
- slot.Value = value;
+ slot._value = value;
}
}
@@ -410,32 +396,30 @@ namespace System.Threading
var linkedSlot = new LinkedSlot(slotArray);
// Insert the LinkedSlot into the linked list maintained by this ThreadLocal<> instance and into the slot array
- using (LockHolder.Hold(s_idManager.m_lock))
+ lock (s_idManager)
{
// Check that the instance has not been disposed. It is important to check this under a lock, since
// Dispose also executes under a lock.
- if (!m_initialized)
+ if (!_initialized)
{
throw new ObjectDisposedException(SR.ThreadLocal_Disposed);
}
- LinkedSlot firstRealNode = m_linkedSlot.Next;
+ LinkedSlot firstRealNode = _linkedSlot._next;
- //
// Insert linkedSlot between nodes m_linkedSlot and firstRealNode.
- // (m_linkedSlot is the dummy head node that should always be in the front.)
- //
- linkedSlot.Next = firstRealNode;
- linkedSlot.Previous = m_linkedSlot;
- linkedSlot.Value = value;
+ // (_linkedSlot is the dummy head node that should always be in the front.)
+ linkedSlot._next = firstRealNode;
+ linkedSlot._previous = _linkedSlot;
+ linkedSlot._value = value;
if (firstRealNode != null)
{
- firstRealNode.Previous = linkedSlot;
+ firstRealNode._previous = linkedSlot;
}
- m_linkedSlot.Next = linkedSlot;
+ _linkedSlot._next = linkedSlot;
- // Assigning the slot under a lock prevents a race with Dispose (dispose also acquires the lock).
+ // Assigning the slot under a lock prevents a race condition with Dispose (dispose also acquires the lock).
// Otherwise, it would be possible that the ThreadLocal instance is disposed, another one gets created
// with the same ID, and the write would go to the wrong instance.
slotArray[id].Value = linkedSlot;
@@ -452,7 +436,7 @@ namespace System.Threading
{
get
{
- if (!m_trackAllValues)
+ if (!_trackAllValues)
{
throw new InvalidOperationException(SR.ThreadLocal_ValuesNotAvailable);
}
@@ -464,21 +448,21 @@ namespace System.Threading
}
/// <summary>Gets all of the threads' values in a list.</summary>
- private LowLevelListWithIList<T> GetValuesAsList()
+ private List<T> GetValuesAsList()
{
- LowLevelListWithIList<T> valueList = new LowLevelListWithIList<T>();
- int id = ~m_idComplement;
+ List<T> valueList = new List<T>();
+ int id = ~_idComplement;
if (id == -1)
{
return null;
}
// Walk over the linked list of slots and gather the values associated with this ThreadLocal instance.
- for (LinkedSlot linkedSlot = m_linkedSlot.Next; linkedSlot != null; linkedSlot = linkedSlot.Next)
+ for (LinkedSlot linkedSlot = _linkedSlot._next; linkedSlot != null; linkedSlot = linkedSlot._next)
{
// We can safely read linkedSlot.Value. Even if this ThreadLocal has been disposed in the meantime, the LinkedSlot
// objects will never be assigned to another ThreadLocal instance.
- valueList.Add(linkedSlot.Value);
+ valueList.Add(linkedSlot._value);
}
return valueList;
@@ -490,7 +474,7 @@ namespace System.Threading
get
{
int count = 0;
- for (LinkedSlot linkedSlot = m_linkedSlot.Next; linkedSlot != null; linkedSlot = linkedSlot.Next)
+ for (LinkedSlot linkedSlot = _linkedSlot._next; linkedSlot != null; linkedSlot = linkedSlot._next)
{
count++;
}
@@ -508,7 +492,7 @@ namespace System.Threading
{
get
{
- int id = ~m_idComplement;
+ int id = ~_idComplement;
if (id < 0)
{
throw new ObjectDisposedException(SR.ThreadLocal_Disposed);
@@ -527,17 +511,17 @@ namespace System.Threading
get
{
LinkedSlotVolatile[] slotArray = ts_slotArray;
- int id = ~m_idComplement;
+ int id = ~_idComplement;
LinkedSlot slot;
- if (slotArray == null || id >= slotArray.Length || (slot = slotArray[id].Value) == null || !m_initialized)
- return default(T);
- return slot.Value;
+ if (slotArray == null || id >= slotArray.Length || (slot = slotArray[id].Value) == null || !_initialized)
+ return default;
+ return slot._value;
}
}
/// <summary>Gets the values of all threads that accessed the ThreadLocal&lt;T&gt;.</summary>
- internal IList<T> ValuesForDebugDisplay // same as Values property, but doesn't throw if disposed
+ internal List<T> ValuesForDebugDisplay // same as Values property, but doesn't throw if disposed
{
get { return GetValuesAsList(); }
}
@@ -559,14 +543,14 @@ namespace System.Threading
// Dispose could use a stale SlotArray reference and clear out a slot in the old array only, while
// the value continues to be referenced from the new (larger) array.
//
- using (LockHolder.Hold(s_idManager.m_lock))
+ lock (s_idManager)
{
for (int i = 0; i < table.Length; i++)
{
LinkedSlot linkedSlot = table[i].Value;
- if (linkedSlot != null && linkedSlot.SlotArray != null)
+ if (linkedSlot != null && linkedSlot._slotArray != null)
{
- linkedSlot.SlotArray = newTable;
+ linkedSlot._slotArray = newTable;
newTable[i] = table[i];
}
}
@@ -575,14 +559,12 @@ namespace System.Threading
table = newTable;
}
- private const int MaxArrayLength = int.MaxValue;
-
/// <summary>
/// Chooses the next larger table size
/// </summary>
private static int GetNewTableSize(int minSize)
{
- if ((uint)minSize > MaxArrayLength)
+ if ((uint)minSize > Array.MaxArrayLength)
{
// Intentionally return a value that will result in an OutOfMemoryException
return int.MaxValue;
@@ -593,13 +575,13 @@ namespace System.Threading
// Round up the size to the next power of 2
//
// The algorithm takes three steps:
- // input -> subtract one -> propagate 1-bits to the right -> add one
+ // input -> subtract one -> propagate 1-bits to the right -> add one
//
// Let's take a look at the 3 steps in both interesting cases: where the input
// is (Example 1) and isn't (Example 2) a power of 2.
//
- // Example 1: 100000 -> 011111 -> 011111 -> 100000
- // Example 2: 011010 -> 011001 -> 011111 -> 100000
+ // Example 1: 100000 -> 011111 -> 011111 -> 100000
+ // Example 2: 011010 -> 011001 -> 011111 -> 100000
//
int newSize = minSize;
@@ -617,9 +599,9 @@ namespace System.Threading
newSize++;
// Don't set newSize to more than Array.MaxArrayLength
- if ((uint)newSize > MaxArrayLength)
+ if ((uint)newSize > Array.MaxArrayLength)
{
- newSize = MaxArrayLength;
+ newSize = Array.MaxArrayLength;
}
return newSize;
@@ -629,7 +611,7 @@ namespace System.Threading
/// A wrapper struct used as LinkedSlotVolatile[] - an array of LinkedSlot instances, but with volatile semantics
/// on array accesses.
/// </summary>
- internal struct LinkedSlotVolatile
+ private struct LinkedSlotVolatile
{
internal volatile LinkedSlot Value;
}
@@ -642,24 +624,24 @@ namespace System.Threading
/// 1. If SlotArray is not null, the value is in SlotArray.Table[id]
/// 2. If SlotArray is null, the value is in FinalValue.
/// </summary>
- internal sealed class LinkedSlot
+ private sealed class LinkedSlot
{
internal LinkedSlot(LinkedSlotVolatile[] slotArray)
{
- SlotArray = slotArray;
+ _slotArray = slotArray;
}
// The next LinkedSlot for this ThreadLocal<> instance
- internal volatile LinkedSlot Next;
+ internal volatile LinkedSlot _next;
// The previous LinkedSlot for this ThreadLocal<> instance
- internal volatile LinkedSlot Previous;
+ internal volatile LinkedSlot _previous;
// The SlotArray that stores this LinkedSlot at SlotArray.Table[id].
- internal volatile LinkedSlotVolatile[] SlotArray;
+ internal volatile LinkedSlotVolatile[] _slotArray;
// The value for this slot.
- internal T Value;
+ internal T _value;
}
/// <summary>
@@ -668,34 +650,32 @@ namespace System.Threading
private class IdManager
{
// The next ID to try
- private int m_nextIdToTry = 0;
+ private int _nextIdToTry = 0;
// Stores whether each ID is free or not. Additionally, the object is also used as a lock for the IdManager.
- private LowLevelList<bool> m_freeIds = new LowLevelList<bool>();
-
- internal Lock m_lock = new Lock();
+ private List<bool> _freeIds = new List<bool>();
internal int GetId()
{
- using (LockHolder.Hold(m_lock))
+ lock (_freeIds)
{
- int availableId = m_nextIdToTry;
- while (availableId < m_freeIds.Count)
+ int availableId = _nextIdToTry;
+ while (availableId < _freeIds.Count)
{
- if (m_freeIds[availableId]) { break; }
+ if (_freeIds[availableId]) { break; }
availableId++;
}
- if (availableId == m_freeIds.Count)
+ if (availableId == _freeIds.Count)
{
- m_freeIds.Add(false);
+ _freeIds.Add(false);
}
else
{
- m_freeIds[availableId] = false;
+ _freeIds[availableId] = false;
}
- m_nextIdToTry = availableId + 1;
+ _nextIdToTry = availableId + 1;
return availableId;
}
@@ -704,10 +684,10 @@ namespace System.Threading
// Return an ID to the pool
internal void ReturnId(int id)
{
- using (LockHolder.Hold(m_lock))
+ lock (_freeIds)
{
- m_freeIds[id] = true;
- if (id < m_nextIdToTry) m_nextIdToTry = id;
+ _freeIds[id] = true;
+ if (id < _nextIdToTry) _nextIdToTry = id;
}
}
}
@@ -716,7 +696,7 @@ namespace System.Threading
/// A class that facilitates ThreadLocal cleanup after a thread exits.
///
/// After a thread with an associated thread-local table has exited, the FinalizationHelper
- /// is reponsible for removing back-references to the table. Since an instance of FinalizationHelper
+ /// is responsible for removing back-references to the table. Since an instance of FinalizationHelper
/// is only referenced from a single thread-local slot, the FinalizationHelper will be GC'd once
/// the thread has exited.
///
@@ -724,15 +704,15 @@ namespace System.Threading
/// (all those LinkedSlot instances can be found by following references from the table slots) and
/// releases the table so that it can get GC'd.
/// </summary>
- internal class FinalizationHelper
+ private class FinalizationHelper
{
internal LinkedSlotVolatile[] SlotArray;
- private bool m_trackAllValues;
+ private bool _trackAllValues;
internal FinalizationHelper(LinkedSlotVolatile[] slotArray, bool trackAllValues)
{
SlotArray = slotArray;
- m_trackAllValues = trackAllValues;
+ _trackAllValues = trackAllValues;
}
~FinalizationHelper()
@@ -749,25 +729,25 @@ namespace System.Threading
continue;
}
- if (m_trackAllValues)
+ if (_trackAllValues)
{
// Set the SlotArray field to null to release the slot array.
- linkedSlot.SlotArray = null;
+ linkedSlot._slotArray = null;
}
else
{
// Remove the LinkedSlot from the linked list. Once the FinalizationHelper is done, all back-references to
// the table will be have been removed, and so the table can get GC'd.
- using (LockHolder.Hold(s_idManager.m_lock))
+ lock (s_idManager)
{
- if (linkedSlot.Next != null)
+ if (linkedSlot._next != null)
{
- linkedSlot.Next.Previous = linkedSlot.Previous;
+ linkedSlot._next._previous = linkedSlot._previous;
}
// Since the list uses a dummy head node, the Previous reference should never be null.
- Debug.Assert(linkedSlot.Previous != null);
- linkedSlot.Previous.Next = linkedSlot.Next;
+ Debug.Assert(linkedSlot._previous != null);
+ linkedSlot._previous._next = linkedSlot._next;
}
}
}
@@ -780,37 +760,22 @@ namespace System.Threading
internal sealed class SystemThreading_ThreadLocalDebugView<T>
{
//The ThreadLocal object being viewed.
- private readonly ThreadLocal<T> m_tlocal;
+ private readonly ThreadLocal<T> _tlocal;
/// <summary>Constructs a new debugger view object for the provided ThreadLocal object.</summary>
/// <param name="tlocal">A ThreadLocal object to browse in the debugger.</param>
public SystemThreading_ThreadLocalDebugView(ThreadLocal<T> tlocal)
{
- m_tlocal = tlocal;
+ _tlocal = tlocal;
}
/// <summary>Returns whether the ThreadLocal object is initialized or not.</summary>
- public bool IsValueCreated
- {
- get { return m_tlocal.IsValueCreated; }
- }
+ public bool IsValueCreated => _tlocal.IsValueCreated;
/// <summary>Returns the value of the ThreadLocal object.</summary>
- public T Value
- {
- get
- {
- return m_tlocal.ValueForDebugDisplay;
- }
- }
+ public T Value => _tlocal.ValueForDebugDisplay;
/// <summary>Return all values for all threads that have accessed this instance.</summary>
- public IList<T> Values
- {
- get
- {
- return m_tlocal.ValuesForDebugDisplay;
- }
- }
+ public List<T> Values => _tlocal.ValuesForDebugDisplay;
}
}
diff --git a/src/System.Private.CoreLib/src/Resources/Strings.resx b/src/System.Private.CoreLib/src/Resources/Strings.resx
index 0fb811bca..52d9e03c5 100644
--- a/src/System.Private.CoreLib/src/Resources/Strings.resx
+++ b/src/System.Private.CoreLib/src/Resources/Strings.resx
@@ -192,6 +192,9 @@
<data name="Arg_DuplicateWaitObjectException" xml:space="preserve">
<value>Duplicate objects in argument.</value>
</data>
+ <data name="Arg_EHClauseNotFilter" xml:space="preserve">
+ <value>This ExceptionHandlingClause is not a filter.</value>
+ </data>
<data name="Arg_EnumAndObjectMustBeSameType" xml:space="preserve">
<value>Object must be the same type as the enum. The type passed in was '{0}'; the enum type was '{1}'.</value>
</data>
diff --git a/src/System.Private.CoreLib/src/System.Private.CoreLib.csproj b/src/System.Private.CoreLib/src/System.Private.CoreLib.csproj
index ee7b79f3b..f898a11a2 100644
--- a/src/System.Private.CoreLib/src/System.Private.CoreLib.csproj
+++ b/src/System.Private.CoreLib/src/System.Private.CoreLib.csproj
@@ -179,12 +179,9 @@
<Compile Include="System\Reflection\Emit\ReflectionEmitThrower.cs" />
<Compile Include="System\Reflection\Emit\SignatureHelper.cs" />
<Compile Include="System\Reflection\Emit\TypeBuilder.cs" />
- <Compile Include="System\Reflection\ExceptionHandlingClause.cs" />
<Compile Include="System\Reflection\FieldInfo.CoreRT.cs" />
<Compile Include="System\Reflection\LegacyCustomAttributeApis.cs" />
- <Compile Include="System\Reflection\LocalVariableInfo.cs" />
<Compile Include="System\Reflection\MethodBase.CoreRT.cs" />
- <Compile Include="System\Reflection\MethodBody.cs" />
<Compile Include="System\Reflection\Runtime\CustomAttributes\RuntimeImplementedCustomAttributeData.cs" />
<Compile Include="System\Resources\FileBasedResourceGroveler.cs" />
<Compile Include="System\Resources\IResourceGroveler.cs" />
@@ -265,7 +262,6 @@
<Compile Include="System\Runtime\InteropServices\GCHandle.cs" />
<Compile Include="System\Runtime\InteropServices\GCHandleType.cs" />
<Compile Include="System\Runtime\InteropServices\InteropExtensions.cs" />
- <Compile Include="System\Runtime\InteropServices\NativeCallableAttribute.cs" />
<Compile Include="System\Runtime\InteropServices\NativeFunctionPointerWrapper.cs" />
<Compile Include="System\Runtime\InteropServices\PInvokeMarshal.cs" />
<Compile Include="System\Runtime\InteropServices\Marshal.cs" />
@@ -306,7 +302,6 @@
<Compile Include="System\Threading\Monitor.cs" />
<Compile Include="System\Threading\ObjectHeader.cs" Condition="'$(UseSyncTable)' == 'true'" />
<Compile Include="System\Threading\Overlapped.cs" />
- <Compile Include="System\Threading\SpinLock.cs" />
<Compile Include="System\Threading\SynchronizationContext.cs" />
<Compile Include="System\Threading\SynchronizationContext.WinRT.cs" Condition="'$(EnableWinRT)' == 'true'" />
<Compile Include="System\Threading\SynchronizationContext.Dummy.cs" Condition="'$(EnableWinRT)' != 'true'" />
@@ -323,7 +318,6 @@
<Compile Include="System\Threading\Tasks\TaskFactory.cs" />
<Compile Include="System\Threading\Tasks\TaskScheduler.cs" />
<Compile Include="System\Threading\Tasks\ThreadPoolTaskScheduler.cs" />
- <Compile Include="System\Threading\ThreadLocal.cs" />
<Compile Include="System\Threading\ThreadPool.cs" />
<Compile Include="System\Threading\ThreadPoolCallbackWrapper.cs" />
<Compile Include="System\Threading\Timer.cs" />
@@ -748,4 +742,4 @@
</ItemGroup>
<Import Project="..\shared\System.Private.CoreLib.Shared.projitems" Label="Shared" />
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
-</Project> \ No newline at end of file
+</Project>
diff --git a/src/System.Private.CoreLib/src/System/Reflection/AssemblyName.cs b/src/System.Private.CoreLib/src/System/Reflection/AssemblyName.cs
index 3dadda396..34b2fbcc3 100644
--- a/src/System.Private.CoreLib/src/System/Reflection/AssemblyName.cs
+++ b/src/System.Private.CoreLib/src/System/Reflection/AssemblyName.cs
@@ -6,16 +6,27 @@ using System.Globalization;
using System.Runtime.Serialization;
using System.Configuration.Assemblies;
-using Internal.Reflection.Augments;
-
namespace System.Reflection
{
public sealed class AssemblyName : ICloneable, IDeserializationCallback, ISerializable
{
+ private string _name;
+ private byte[] _publicKey;
+ private byte[] _publicKeyToken;
+ private CultureInfo _cultureInfo;
+ private string _codeBase;
+ private Version _version;
+
+ private StrongNameKeyPair _strongNameKeyPair;
+ private AssemblyHashAlgorithm _hashAlgorithm;
+
+ private AssemblyVersionCompatibility _versionCompatibility;
+ private AssemblyNameFlags _flags;
+
public AssemblyName()
{
- HashAlgorithm = AssemblyHashAlgorithm.None;
- VersionCompatibility = AssemblyVersionCompatibility.SameMachine;
+ _hashAlgorithm = AssemblyHashAlgorithm.None;
+ _versionCompatibility = AssemblyVersionCompatibility.SameMachine;
_flags = AssemblyNameFlags.None;
}
@@ -28,19 +39,55 @@ namespace System.Reflection
runtimeAssemblyName.CopyToAssemblyName(this);
}
- public object Clone()
+ // Set and get the name of the assembly. If this is a weak Name
+ // then it optionally contains a site. For strong assembly names,
+ // the name partitions up the strong name's namespace
+ public string Name
{
- AssemblyName n = new AssemblyName();
- n.Name = Name;
- n._publicKey = (byte[])_publicKey?.Clone();
- n._publicKeyToken = (byte[])_publicKeyToken?.Clone();
- n.CultureInfo = CultureInfo;
- n.Version = (Version)Version?.Clone();
- n._flags = _flags;
- n.CodeBase = CodeBase;
- n.HashAlgorithm = HashAlgorithm;
- n.VersionCompatibility = VersionCompatibility;
- return n;
+ get { return _name; }
+ set { _name = value; }
+ }
+
+ public Version Version
+ {
+ get { return _version; }
+ set { _version = value; }
+ }
+
+ // Locales, internally the LCID is used for the match.
+ public CultureInfo CultureInfo
+ {
+ get { return _cultureInfo; }
+ set { _cultureInfo = value; }
+ }
+
+ public string CultureName
+ {
+ get
+ {
+ return (_cultureInfo == null) ? null : _cultureInfo.Name;
+ }
+ set
+ {
+ _cultureInfo = (value == null) ? null : new CultureInfo(value);
+ }
+ }
+
+ public string CodeBase
+ {
+ get { return _codeBase; }
+ set { _codeBase = value; }
+ }
+
+ public string EscapedCodeBase
+ {
+ get
+ {
+ if (_codeBase == null)
+ return null;
+ else
+ return EscapeCodeBase(_codeBase);
+ }
}
public ProcessorArchitecture ProcessorArchitecture
@@ -83,85 +130,105 @@ namespace System.Reflection
}
}
- public string CultureName
+ // Make a copy of this assembly name.
+ public object Clone()
{
- get
- {
- return CultureInfo?.Name;
- }
- set
- {
- CultureInfo = (value == null) ? null : new CultureInfo(value);
- }
+ AssemblyName name = new AssemblyName();
+ name._name = _name;
+ name._publicKey = (byte[])_publicKey?.Clone();
+ name._publicKeyToken = (byte[])_publicKeyToken?.Clone();
+ name._cultureInfo = _cultureInfo;
+ name._version = (Version)_version?.Clone();
+ name._flags = _flags;
+ name._codeBase = _codeBase;
+ name._hashAlgorithm = _hashAlgorithm;
+ name._versionCompatibility = _versionCompatibility;
+ return name;
}
- public CultureInfo CultureInfo { get; set; }
+ public static AssemblyName GetAssemblyName(string assemblyFile)
+ {
+ throw new PlatformNotSupportedException(SR.Arg_PlatformNotSupported_AssemblyName_GetAssemblyName);
+ }
- public AssemblyNameFlags Flags
+ // The public key that is used to verify an assemblies
+ // inclusion into the namespace. If the public key associated
+ // with the namespace cannot verify the assembly the assembly
+ // will fail to load.
+ public byte[] GetPublicKey()
{
- get { return (AssemblyNameFlags)((uint)_flags & 0xFFFFF10F); }
- set
- {
- _flags &= unchecked((AssemblyNameFlags)0x00000EF0);
- _flags |= (value & unchecked((AssemblyNameFlags)0xFFFFF10F));
- }
+ return _publicKey;
}
- public string FullName
+ public void SetPublicKey(byte[] publicKey)
{
- get
- {
- if (this.Name == null)
- return string.Empty;
- // Do not call GetPublicKeyToken() here - that latches the result into AssemblyName which isn't a side effect we want.
- byte[] pkt = _publicKeyToken ?? AssemblyNameHelpers.ComputePublicKeyToken(_publicKey);
- return AssemblyNameFormatter.ComputeDisplayName(Name, Version, CultureName, pkt, Flags, ContentType);
- }
+ _publicKey = publicKey;
+
+ if (publicKey == null)
+ _flags &= ~AssemblyNameFlags.PublicKey;
+ else
+ _flags |= AssemblyNameFlags.PublicKey;
}
- public string Name { get; set; }
- public Version Version { get; set; }
- public string CodeBase { get; set; }
- public AssemblyHashAlgorithm HashAlgorithm { get; set; }
- public AssemblyVersionCompatibility VersionCompatibility { get; set; }
- public StrongNameKeyPair KeyPair { get; set; }
+ // The compressed version of the public key formed from a truncated hash.
+ // Will throw a SecurityException if _PublicKey is invalid
+ public byte[] GetPublicKeyToken()
+ {
+ if (_publicKeyToken == null)
+ _publicKeyToken = AssemblyNameHelpers.ComputePublicKeyToken(_publicKey);
+ return _publicKeyToken;
+ }
- public string EscapedCodeBase
+ public void SetPublicKeyToken(byte[] publicKeyToken)
{
- get
+ _publicKeyToken = publicKeyToken;
+ }
+
+ // Flags modifying the name. So far the only flag is PublicKey, which
+ // indicates that a full public key and not the compressed version is
+ // present.
+ // Processor Architecture flags are set only through ProcessorArchitecture
+ // property and can't be set or retrieved directly
+ // Content Type flags are set only through ContentType property and can't be
+ // set or retrieved directly
+ public AssemblyNameFlags Flags
+ {
+ get { return (AssemblyNameFlags)((uint)_flags & 0xFFFFF10F); }
+ set
{
- if (CodeBase == null)
- return null;
- else
- return EscapeCodeBase(CodeBase);
+ _flags &= unchecked((AssemblyNameFlags)0x00000EF0);
+ _flags |= (value & unchecked((AssemblyNameFlags)0xFFFFF10F));
}
}
- public byte[] GetPublicKey()
+ public AssemblyHashAlgorithm HashAlgorithm
{
- return _publicKey;
+ get { return _hashAlgorithm; }
+ set { _hashAlgorithm = value; }
}
- public byte[] GetPublicKeyToken()
+ public AssemblyVersionCompatibility VersionCompatibility
{
- if (_publicKeyToken == null)
- _publicKeyToken = AssemblyNameHelpers.ComputePublicKeyToken(_publicKey);
- return _publicKeyToken;
+ get { return _versionCompatibility; }
+ set { _versionCompatibility = value; }
}
- public void SetPublicKey(byte[] publicKey)
+ public StrongNameKeyPair KeyPair
{
- _publicKey = publicKey;
-
- if (publicKey == null)
- _flags &= ~AssemblyNameFlags.PublicKey;
- else
- _flags |= AssemblyNameFlags.PublicKey;
+ get { return _strongNameKeyPair; }
+ set { _strongNameKeyPair = value; }
}
- public void SetPublicKeyToken(byte[] publicKeyToken)
+ public string FullName
{
- _publicKeyToken = publicKeyToken;
+ get
+ {
+ if (this.Name == null)
+ return string.Empty;
+ // Do not call GetPublicKeyToken() here - that latches the result into AssemblyName which isn't a side effect we want.
+ byte[] pkt = _publicKeyToken ?? AssemblyNameHelpers.ComputePublicKeyToken(_publicKey);
+ return AssemblyNameFormatter.ComputeDisplayName(Name, Version, CultureName, pkt, Flags, ContentType);
+ }
}
public override string ToString()
@@ -183,11 +250,6 @@ namespace System.Reflection
throw new PlatformNotSupportedException();
}
- public static AssemblyName GetAssemblyName(string assemblyFile)
- {
- throw new PlatformNotSupportedException(SR.Arg_PlatformNotSupported_AssemblyName_GetAssemblyName);
- }
-
/// <summary>
/// Compares the simple names disregarding Version, Culture and PKT. While this clearly does not
/// match the intent of this api, this api has been broken this way since its debut and we cannot
@@ -210,10 +272,6 @@ namespace System.Reflection
}
internal static string EscapeCodeBase(string codebase) { throw new PlatformNotSupportedException(); }
-
- private AssemblyNameFlags _flags;
- private byte[] _publicKey;
- private byte[] _publicKeyToken;
}
}
diff --git a/src/System.Private.CoreLib/src/System/Reflection/LocalVariableInfo.cs b/src/System.Private.CoreLib/src/System/Reflection/LocalVariableInfo.cs
deleted file mode 100644
index 31e58caeb..000000000
--- a/src/System.Private.CoreLib/src/System/Reflection/LocalVariableInfo.cs
+++ /dev/null
@@ -1,54 +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.
-
-using System.Diagnostics;
-
-namespace System.Reflection
-{
- public class LocalVariableInfo
- {
- protected LocalVariableInfo()
- {
- }
-
- public virtual bool IsPinned
- {
- get
- {
- return false;
- }
- }
-
- public virtual int LocalIndex
- {
- get
- {
- return 0;
- }
- }
-
- public virtual Type LocalType
- {
- get
- {
- // Don't laugh - this is really how the desktop behaves if you don't override.
- Debug.Fail("type must be set!");
- return null;
- }
- }
-
- public override string ToString()
- {
- // Don't laugh - this is really how the desktop behaves if you don't override, including the NullReference when
- // it calls ToString() on LocalType's null return.
- string toString = LocalType.ToString() + " (" + LocalIndex + ")";
-
- if (IsPinned)
- toString += " (pinned)";
-
- return toString;
- }
- }
-}
-
diff --git a/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/ClassConstructorRunner.NonPortable.cs b/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/ClassConstructorRunner.NonPortable.cs
index 4c309ca34..5374478e7 100644
--- a/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/ClassConstructorRunner.NonPortable.cs
+++ b/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/ClassConstructorRunner.NonPortable.cs
@@ -19,10 +19,9 @@ namespace System.Runtime.CompilerServices
{
//=========================================================================================================
// Intrinsic to call the cctor given a pointer to the code (this method's body is ignored and replaced
- // with a calli during compilation). The transform doesn't handle non-generic versions yet (i.e.
- // functions that are void).
+ // with a calli during compilation).
//=========================================================================================================
- private static T Call<T>(System.IntPtr pfn)
+ private static void Call(System.IntPtr pfn)
{
throw NotImplemented.ByDesign;
}
diff --git a/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/ClassConstructorRunner.cs b/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/ClassConstructorRunner.cs
index d8a418e15..a82e434b8 100644
--- a/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/ClassConstructorRunner.cs
+++ b/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/ClassConstructorRunner.cs
@@ -94,7 +94,7 @@ namespace System.Runtime.CompilerServices
{
NoisyLog("Calling cctor, cctor={0}, thread={1}", pfnCctor, currentManagedThreadId);
- Call<int>(pfnCctor);
+ Call(pfnCctor);
// Insert a memory barrier here to order any writes executed as part of static class
// construction above with respect to the initialized flag update we're about to make