Skip to content

Conversation

koszeggy
Copy link

@koszeggy koszeggy commented Sep 4, 2024

Fixes #107265

I see that you already set the milestone to v10 but hoping that some contribution may help to add this to .NET 9 I prepared a possible solution. Of course, I understand if it's too late.

Feel free to adjust it.

@ghost ghost added the area-System.IO label Sep 4, 2024
@dotnet-policy-service dotnet-policy-service bot added the community-contribution Indicates that the PR has been added by a community member label Sep 4, 2024
OutStream = Stream.Null;
_encoding = Encoding.UTF8;
_useFastUtf8 = true;
_isDerivedWriter = GetType() != typeof(BinaryWriter);
Copy link
Member

Choose a reason for hiding this comment

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

Note: You do not need to save the result into a field. GetType() != typeof(X) compiles into a single instruction.

Copy link
Author

Choose a reason for hiding this comment

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

Ah, alright. As I mentioned, feel free to adjust it. Or let me know if you want me to change it.

@huoyaoyuan
Copy link
Member

The original issue was marked as "needs further triage" and we haven't decided what's the expected behavior. Since it's not a recent change happened from 9.0, it's not likely to change for 9.0.

@koszeggy
Copy link
Author

koszeggy commented Sep 5, 2024

Since it's not a recent change happened from 9.0, it's not likely to change for 9.0.

Understood. Actually I can live with the (far from optimized) workaround I applied as it's just a unit test helper class:

public override void Write(string value)
{
#if !NET6_0_OR_GREATER // https://github.com/dotnet/runtime/issues/107265
    base.Write(value);
#else
    var bytes = Encoding.UTF8.GetBytes(value);
    Write7BitEncodedInt(bytes.Length);
    OutStream.Write(bytes, 0, bytes.Length);
#endif
    // [...] actual logging, stack trace dump
}

@kasperk81
Copy link
Contributor

add a unit test in src/libraries/System.Runtime/tests/System.IO.Tests/BinaryWriter/BinaryWriter.WriteTests.cs

@koszeggy
Copy link
Author

add a unit test in src/libraries/System.Runtime/tests/System.IO.Tests/BinaryWriter/BinaryWriter.WriteTests.cs

In the end I did not add a new test case but modified the WriteTest<T> method, executing the passed delegates on derived and non-derived BinaryWriter/BinaryReader instances, with UTF8 and non-UTF8 encodings.

Now the already existing BinaryWriter_WriteStringTest fails on .NET 9.0 but succeeds on .NET 5.0

Copy link
Member

@adamsitnik adamsitnik left a comment

Choose a reason for hiding this comment

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

@koszeggy First of all please excuse me for such a delay in the code review process. For some reason I've missed the GH notification.

The fix LGTM, but I need to ensure that it's not going to regress the performance before merging it.

// If this is a non-derived BinaryWriter, then we can bypass the Write7BitEncodedInt call.
// But when this is a derived instance, call must not bypass it for compatibility reasons
// as it calls the virtual Write(int) overload.
if (GetType() == typeof(BinaryWriter) && value.Length <= 127 / 3)
Copy link
Member

Choose a reason for hiding this comment

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

@EgorBo How is runtime optimizing the logic that uses GetType() == typeof(BinaryWriter) pattern as of today? Will this be always replaced with a constant for each derived type? If not, should we cache the result of the check? Or at least change the order (perform the cheap length check first)

Copy link
Member

Choose a reason for hiding this comment

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

It's a single pointer check (*object == TypeTableOf(BinaryWriter)) and equivalent to accessing a field. This pattern is used a lot currently.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-System.IO community-contribution Indicates that the PR has been added by a community member
Projects
None yet
Development

Successfully merging this pull request may close these issues.

BinaryWriter breaking change
5 participants