Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Refresh System.Runtime ref from System.Private.CoreLib in Coreclr#26264

Merged
weshaggard merged 5 commits into
dotnet:masterfrom
weshaggard:UpdateSystemRuntimeFromCoreCLR
Jan 12, 2018
Merged

Refresh System.Runtime ref from System.Private.CoreLib in Coreclr#26264
weshaggard merged 5 commits into
dotnet:masterfrom
weshaggard:UpdateSystemRuntimeFromCoreCLR

Conversation

@weshaggard
Copy link
Copy Markdown
Member

This also includes an update to the genapi tool that includes the
necessary private fields in structs to enable the compiler to
do correctness checks.

See https://github.com/dotnet/corefx/issues/6185.

The ref was generated with the updated changes in dotnet/buildtools#1859.

PTAL @jkotas @VSadov @jaredpar @gafter

Note that some of the updates are just a refresh from what is in the System.Private.CoreLib and not about the fields in structs.

This also includes an update to the genapi tool that includes the
necessary private fields in structs to enable the compiler to
do correctness checks.

See https://github.com/dotnet/corefx/issues/6185.
[System.Runtime.CompilerServices.AsyncMethodBuilderAttribute(typeof(System.Runtime.CompilerServices.AsyncValueTaskMethodBuilder<>))]
public readonly partial struct ValueTask<TResult> : System.IEquatable<System.Threading.Tasks.ValueTask<TResult>>
{
internal readonly TResult _result;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should all the fields be private?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I noticed a couple of these as well, I don't know why they showed up as internal but I will investigate.

Copy link
Copy Markdown
Member Author

@weshaggard weshaggard Jan 11, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reason this and a couple others are internal instead of private is because for any non-public fields that are generic I just blindly include those unchanged. For now I will keep them like this so they correctly show the usage of generic parameters. If you feel there is a reason to switch them I can.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same in Nullable<T> - internal T value . I think that is ok.


In reply to: 161028771 [](ancestors = 161028771)

public virtual bool IsAsync { get { throw null; } }
public override long Length { get { throw null; } }
public string Name { get { throw null; } }
public virtual string Name { get { throw null; } }
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a bunch of unrelated changes like this one. Are they all intentional?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes these are intentional. They are essentially refreshing based on what is in System.Private.CoreLib implementation. A number of changes to the API never made it to the ref.

public static System.ReadOnlySpan<T> DangerousCreate(object obj, ref T objectData, int length) { throw null; }
[System.ComponentModel.EditorBrowsableAttribute((System.ComponentModel.EditorBrowsableState)(1))]
[System.ObsoleteAttribute("Equals() on ReadOnlySpan will always throw an exception. Use == instead.")]
[System.ObsoleteAttribute("Equals() on Span will always throw an exception. Use == instead.")]
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The original message looks right. This looks like a bug in the implementation.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This just updated to what is in the implementation. We could definitely update both to be consistent with ReadOnlySpan.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

}
public partial struct GCHandle
{
private object _dummy;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should be int. GCHandle does not have instance object fields.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this might be a side-effect of me not filtering out statics while doing the contains reference check. I will regenerate once I update the tool.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jkotas the GCHandle holds a IntPtr which in turn holds a void* so based on our logic I would expect this to have an object dummy field. Is there something I'm missing?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

void* should be treated as int, not as object.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK with that change we get a bunch of updates. Can you have a look over 9288c49 to ensure they look as expected?

}
public partial struct Boolean : System.IComparable, System.IComparable<bool>, System.IConvertible, System.IEquatable<bool>
{
private object _dummy;
Copy link
Copy Markdown
Member

@VSadov VSadov Jan 11, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why Boolean contains an object field?
The real one only contains a bool. #Closed

Copy link
Copy Markdown
Member Author

@weshaggard weshaggard Jan 11, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just pushed a change that fixes this. #Closed

}
public partial struct Char : System.IComparable, System.IComparable<char>, System.IConvertible, System.IEquatable<char>
{
private object _dummy;
Copy link
Copy Markdown
Member

@VSadov VSadov Jan 11, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as Boolean - why object? #Closed

Copy link
Copy Markdown
Member Author

@weshaggard weshaggard Jan 11, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was an issue in detecting a reference type, just fixed. #Closed

}
public partial struct IntPtr : System.IEquatable<System.IntPtr>, System.Runtime.Serialization.ISerializable
{
private object _dummy;
Copy link
Copy Markdown
Member

@VSadov VSadov Jan 11, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be int or IntPtr. #Closed

[System.CLSCompliantAttribute(false)]
public partial struct UIntPtr : System.IEquatable<System.UIntPtr>, System.Runtime.Serialization.ISerializable
{
private object _dummy;
Copy link
Copy Markdown
Member

@VSadov VSadov Jan 11, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be int or UIntPtr #Closed

public override bool Equals(object obj) { throw null; }
public bool Equals(System.RuntimeTypeHandle handle) { throw null; }
public override int GetHashCode() { throw null; }
[System.CLSCompliantAttribute(false)]
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can delete this unnecessary CLSCompliantAttribute attribute. I have deleted it in the implementation already.

{
public readonly partial struct CancellationToken
{
private readonly object _dummy;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 This one was causing particularly annoying bug reports.

@VSadov
Copy link
Copy Markdown
Member

VSadov commented Jan 11, 2018

    public static System.Span<T> DangerousCreate(object obj, ref T objectData, int length) { throw null; }

Just wondering - what happened to the DangerousGetPinnableReference ? #Closed


Refers to: src/System.Runtime/ref/System.Runtime.cs:2170 in 925866d. [](commit_id = 925866d, deletion_comment = False)

@weshaggard
Copy link
Copy Markdown
Member Author

Just wondering - what happened to the DangerousGetPinnableReference ?

dotnet/coreclr@4d0e363

…f Span

Remove unnecessary CLSCompliant(false) on GetModuleHandle
@weshaggard weshaggard force-pushed the UpdateSystemRuntimeFromCoreCLR branch from 925866d to c58e40f Compare January 11, 2018 18:47
}
public readonly ref partial struct Span<T>
{
private readonly int _dummy;
Copy link
Copy Markdown
Member

@VSadov VSadov Jan 11, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think .NET implementation contains an object. And even the fast implementation technically may contain an object reference.

We do not consider any generic struct as unmanaged right now, regardless of fields, but might in the future.

I think Span/ReadOnlySpan should be considered object-containing

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think Span/ReadOnlySpan should be considered object-containing

I agree. It is not something that the tool can figure out from CoreLib metadata because of Span is treated as intrinsic by the runtime. Types like these will need exceptions.

BTW: It is a bit odd that the primitive types like Int64 has 32-bit fields now. I won't be surprised if we find that it broke something somewhere and we need similar exceptions for them.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On the other hand - even if we see all the fields we would consider fast span unmanaged. (since we do not see or understand the hidden byref)
And other ones - like TypedReference were always considered unmanaged.

I guess the object inside the slow spans would be the only reason to make the spans managed. - Just to conservatively match the implementations.


In reply to: 161045136 [](ancestors = 161045136)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah - I had that concern about primitives as well. Maybe it would be safer if they are self-containing, like all their implementations?


In reply to: 161048209 [](ancestors = 161048209)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I.E. - intcontains an int dummy, bool contains a bool, and so on ...


In reply to: 161049185 [](ancestors = 161049185,161048209)

Copy link
Copy Markdown
Member

@jkotas jkotas Jan 11, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And other ones - like TypedReference were always considered unmanaged.

While it actually contains managed references because of it is treated as intrinsic by the runtime...

This highlights that this has number of false positives and false negatives.

Would it make sense to relax C# to let you take pointer of anything, and demote the current error for taking pointer of "managed type" to just a warning?

Copy link
Copy Markdown
Member

@VSadov VSadov Jan 11, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Possibly. I do not know the exact rationale for not allowing pointers to managed structs. It was the case since v1.0

Perhaps to reduce chances of heap corruption when one dereferences garbage...


In reply to: 161052501 [](ancestors = 161052501)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Latest update fixes primitive types to have matching field types and manually marks Span and ReadOnlySpan as having an object type.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are there any other special types we need to manually fix?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is all that is needed.
The old-style ref-likes like TypedReference should stay as they are. At least for compat reasons.


In reply to: 161073853 [](ancestors = 161073853)

@jkotas
Copy link
Copy Markdown
Member

jkotas commented Jan 11, 2018

Just wondering - what happened to the DangerousGetPinnableReference ?

It was replaced by System.Runtime.InteropServices.MemoryMarshal.GetReference, and removed from the public surface. The DangerousCreate method will be moved to MemoryMarshal as well before we ship - there is an issue about that.

Once the pattern-based fixed statement in C# is figured out, we will add it back in the right form:
dotnet/csharplang#1100 (comment)

@VSadov
Copy link
Copy Markdown
Member

VSadov commented Jan 11, 2018

Re: DangerousGetPinnableReference - makes sense. Thanks!

Copy link
Copy Markdown
Member

@VSadov VSadov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

public bool TryCopyTo(System.Span<T> destination) { throw null; }
public ref partial struct Enumerator
{
private int _dummy;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Enumerator struct contains Span field. It should be treated same way as Span and have object field.

This applies to all structs with Span fields.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I should probably update the tool to special case Span and ReadOnlySpan.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps it is easier to hack the tool so that it thinks Span/ReadonlySpan actually contain an extra private object _dummy ?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm going to teach the tool to recognize "ByReference" as hold a reference.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That could add an object into TypedReference.
It is technically breaking. TypedReference* It is a very corner case and maybe fragile/broken anyways, so I am not sure how much we care.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The rule dotnet/buildtools@4b80362 produced the expected output
6ef9545.

TypedReference didn't change because it only contains an IntPtr not a ByReference.

public bool TryCopyTo(System.Span<T> destination) { throw null; }
public ref partial struct Enumerator
{
private int _dummy;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here

@weshaggard
Copy link
Copy Markdown
Member Author

test Linux x64 Release Build
test UWP CoreCLR x64 Debug Build

}
public readonly ref partial struct ReadOnlySpan<T>
{
private readonly object _dummy; //Manually set to object because tools don't know it is special
Copy link
Copy Markdown
Member Author

@weshaggard weshaggard Jan 12, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jkotas @VSadov should this (and Span) be of type object or type T?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

object , there are no fields of type T in Span.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is similar to the ImmutableArray<T> - T is the element type, but the struct is just an indirection to some other storage, it does not contain any instances directly.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have the changed for ImmutableArray locally and my tool generates internal T[] array; for it as it is generic underneath.

Copy link
Copy Markdown
Member

@VSadov VSadov Jan 12, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Either T[] or object would work since T[] is not T and is not a struct that contains instance field of type T .

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Basically arrays are just reference types for this purpose.

This make Span and ReadOnlySpan have a reference and thus generates
a private object field for the compiler to do the correct checks.
@weshaggard weshaggard force-pushed the UpdateSystemRuntimeFromCoreCLR branch from ece948d to 6ef9545 Compare January 12, 2018 00:31
@weshaggard weshaggard merged commit c84ed43 into dotnet:master Jan 12, 2018
@karelz karelz added this to the 2.1.0 milestone Jan 20, 2018
@weshaggard weshaggard deleted the UpdateSystemRuntimeFromCoreCLR branch February 9, 2018 17:54
picenka21 pushed a commit to picenka21/runtime that referenced this pull request Feb 18, 2022
…ntimeFromCoreCLR

Refresh System.Runtime ref from System.Private.CoreLib in Coreclr

Commit migrated from dotnet/corefx@c84ed43
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants