-
Notifications
You must be signed in to change notification settings - Fork 4.9k
Conversation
@@ -41,6 +41,8 @@ public static partial class PlatformDetection | |||
|
|||
public static bool IsDomainJoinedMachine => !Environment.MachineName.Equals(Environment.UserDomainName, StringComparison.OrdinalIgnoreCase); | |||
|
|||
public static bool IsNotGCForVeryLargeObjects => true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the definition of the capability that this is controlling?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It should be something like https://docs.microsoft.com/en-us/dotnet/framework/configure-apps/file-schema/runtime/gcallowverylargeobjects-element on netcore
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On .NET Framework, these tests will pass both with gcAllowVeryLargeObjects=false
and gcAllowVeryLargeObjects=true
. So it must be something else...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wrote like I don't know what blocks coreclr to allocate collections with more than int.MaxValue items, happy to tweak the name to fit that
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
.NET Framework/Core have documented limits on maximum array sizes. From https://docs.microsoft.com/en-us/dotnet/framework/configure-apps/file-schema/runtime/gcallowverylargeobjects-element :
The maximum index in any single dimension is 2,147,483,591 (0x7FFFFFC7) for byte arrays and arrays of single-byte structures, and 2,146,435,071 (0X7FEFFFFF) for other types.
These limits are less than Int32.MaxValue for defense-in-depth security (to reduce changes of integer overflows causing security bugs), and to allow certain types of bounds-check elimination optimizations and loop unrolling (the JIT can assume that array.Length + small_constant
won't overflow).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, renamed the property. I didn't know coreclr throws OutOfMemory when indexing into an already allocated array.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't know coreclr throws OutOfMemory when indexing into an already allocated array.
OutOfMemory exception is thrown by new
when the array is allocated , not when you index into it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jkotas I have to say this is getting more confusing as the documentation seems to be .NET Framework specific.
var a = new byte[(uint)int.MaxValue + 1]; // This throws System.OverflowException Array dimensions exceeded supported range
var b = new byte[int.MaxValue - 100];
Array.Resize (ref b, int.MaxValue); // This throws OutOfMemoryException
Shouldn't the first one just work, coreclr has LargeObjects enabled by default since dotnet/coreclr#8853 and you said
OutOfMemory exception is thrown by new when the array is allocated , not when you index into it.
The second one is why the tests have OOM expectation but should that throw the exception with Array dimensions exceeded supported range
instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The behavior of new T[len]
is:
0 <= len && len <= MAX_LENGTH
- Succeeds, assuming there is enough memoryMAX_LENGTH < len && len <= Int32.MaxValue
- throw OutOfMemoryException.len < 0 || len > Int32.MaxValue
- throw OverflowException
On .NET Core, and on .NET Framework with gcAllowVeryLargeObjects=true, MAX_LENGTH
is sizeof(T) > 1 ? 0X7FEFFFFF : 0x7FFFFFC7
On .NET Framework with gcAllowVeryLargeObjects=false, MAX_LENGTH
is approximately 0x7FFFFFC7 / sizeof(T)
.
@@ -73,6 +73,8 @@ private static bool GetIsWindowsSubsystemForLinux() | |||
return false; | |||
} | |||
|
|||
public static bool IsIntMaxValueArrayIndexNotSupported => true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is better to use positive names (XXXSupported instead of XXXNotSupported) for readability.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree but xunit conditionals don't support negating syntax (you have Not everywhere)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit, but I believe when we do this we consistently begin with IsNot...
@@ -73,6 +73,8 @@ private static bool GetIsWindowsSubsystemForLinux() | |||
return false; | |||
} | |||
|
|||
public static bool IsIntMaxValueArrayIndexNotSupported => true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be nice to auto-detect the right value for this, similar to how IsNonZeroLowerBoundArraySupported is auto-detected.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I could add that but what's the coreclr way of checking that for this behaviour? Based on my comment above I could catch System.OverflowException but that seems quite odd to me.
01a1491
to
73dba83
Compare
@dotnet-bot test NETFX x86 Release Build please |
@@ -73,6 +73,20 @@ private static bool GetIsWindowsSubsystemForLinux() | |||
return false; | |||
} | |||
|
|||
static Lazy<bool> s_largeArrayIsNotSupported = new Lazy<bool>(() => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: I think the corefx convention would be to put {
on a new line.
static Lazy<bool> s_largeArrayIsNotSupported = new Lazy<bool>(() => { | ||
try | ||
{ | ||
var tmp = new byte[int.MaxValue]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some codegens may optimize this allocation out. I may be useful to consume the value in a way that is unlikely to be optimized out. E.g. call ToString()
on it.
LGTM otherwise |
try | ||
{ | ||
var tmp = new byte[int.MaxValue]; | ||
return tmp == null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should to be a black box operation that the optimizations are not able to eliminate. tmp == null
can be optimized out easily.
FWIW, RyuJIT does some of these optimizations today already. For example, if you have:
class Test
{
static public bool Method()
{
Test t = new Test();
return (t != null);
}
}
It will get optimized to just return true
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would [MethodImpl(MethodImplOptions.NoOptimization)]
help?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, NoOptimization
is probably the most appropriate solution.
ea55cf0
to
b630e9f
Compare
} | ||
} | ||
|
||
public static bool IsNotIntMaxValueArrayIndexSupported => s_largeArrayIsNotSupported.Value; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What you have is fine, but does it need to use lazy? I'm wondering if it can just be:
public static bool IsNotIntMaxValueArrayIndexSupported { get; } = IsLargeArrayIsNotSupported();
or if there's a reason doing that in the static cctor is a bad idea?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It could be but allocating 2GB of memory when any of other values are read from the type does not seem to me like a good idea
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, this is in the PlatformDetection class; in that case, I agree. I was thinking it was on the test class itself, in which case such a benefit wouldn't exist.
@@ -73,6 +74,24 @@ private static bool GetIsWindowsSubsystemForLinux() | |||
return false; | |||
} | |||
|
|||
static Lazy<bool> s_largeArrayIsNotSupported = new Lazy<bool>(IsLargeArrayIsNotSupported); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: private
static Lazy<bool> s_largeArrayIsNotSupported = new Lazy<bool>(IsLargeArrayIsNotSupported); | ||
|
||
[MethodImpl(MethodImplOptions.NoOptimization)] | ||
static bool IsLargeArrayIsNotSupported() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: private
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Other than my few remaining nits, LGTM.
* Factors out few GC specific tests * Tweaks to address the review Commit migrated from dotnet/corefx@ae9c360
No description provided.