Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
57fe91c
Move DependentHandle to System.Runtime
Sergio0694 Jun 15, 2021
b1f54b5
Update DependentHandle APIs to follow review
Sergio0694 Jun 15, 2021
b331b8f
Make DependentHandle type public
Sergio0694 Jun 15, 2021
a96fa3f
Update DependentHandle on Mono runtime
Sergio0694 Jun 15, 2021
16fdf0e
Add allocation checks to DependentHandle APIs
Sergio0694 Jun 15, 2021
748d88e
Add more unit tests for new public DependentHandle APIs
Sergio0694 Jun 16, 2021
247fa5a
Add faster, unsafe internal APIs versions to DependentHandle
Sergio0694 Jun 16, 2021
66d2ac5
Naming improvements to Ephemeron type
Sergio0694 Jun 16, 2021
4067ac3
Code style tweaks, improved nullability annotations
Sergio0694 Jun 16, 2021
1670339
Remove incorrect DependentHandle comment on Mono
Sergio0694 Jun 16, 2021
96cfc91
Add default Dispose test for DependentHandle
Sergio0694 Jun 16, 2021
6a8db56
Fix race condition in DependentHandle on Mono
Sergio0694 Jun 16, 2021
1601d88
Optimize DependentHandle.nGetPrimary on CoreCLR
Sergio0694 Jun 16, 2021
359938b
Small IL codegen improvement in DependentHandle.nGetPrimary
Sergio0694 Jun 16, 2021
312851a
Simplify comments, add #ifdef for using directive
Sergio0694 Jun 16, 2021
0145a76
Minor code style tweaks
Sergio0694 Jun 16, 2021
4925877
Change nGetPrimaryAndSecondary to nGetSecondary
Sergio0694 Jun 16, 2021
1664a95
Minor code refactoring to DependentHandle on Mono
Sergio0694 Jun 16, 2021
ca515b6
Rename DependentHandle FCalls
Sergio0694 Jun 16, 2021
08df598
Remove DependentHandle.UnsafeGetTargetAndDependent
Sergio0694 Jun 16, 2021
4e2b624
Remove DependentHandle.GetTargetAndDependent
Sergio0694 Jun 16, 2021
4e03297
Fix FCall path for internal DependentHandle APIs
Sergio0694 Jun 16, 2021
25b34c2
Add more DependentHandle unit tests
Sergio0694 Jun 17, 2021
01f32a3
Reintroduce DependentHandle.GetTargetAndDependent()
Sergio0694 Jun 17, 2021
b3963f2
Minor IL tweaks to produce smaller IR in the JIT
Sergio0694 Jun 18, 2021
34e1bcb
Add DependentHandle.StopTracking() API
Sergio0694 Jun 21, 2021
9fd1da4
Rename InternalSetTarget to StopTracking, remove redundant param
Sergio0694 Jun 21, 2021
d7146e0
Remove FCUnique from InternalStopTracking
Sergio0694 Jun 21, 2021
c9c6325
Update API surface to match approved specs from API review
Sergio0694 Jun 22, 2021
c463d54
Update DependentHandle XML docs
Sergio0694 Jun 23, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Remove DependentHandle.GetTargetAndDependent
  • Loading branch information
Sergio0694 committed Jun 18, 2021
commit 4e2b624c52023bf5f5e4e1a4479be37e75ad2f84
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ namespace System.Runtime
/// that object having a field or property (or some other strong reference) to a dependent object instance B.
/// </para>
/// </summary>
Copy link
Member

Choose a reason for hiding this comment

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

The details are nice, but this is way too long for a summary, which should be at most one sentence (it's what pops up in IntelliSense for a method). Can you move everything but the first sentence to remarks, editing it appropriately? Thanks!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed this in c463d54, as well as all the other review comments below 🙂

/// <remarks>
/// The <see cref="DependentHandle"/> type is not thread-safe, and consumers are responsible for ensuring that
/// <see cref="Dispose"/> is not called concurrently with other APIs. Not doing so results in undefined behavior.
/// <para>The <see cref="Target"/> and <see cref="Dependent"/> properties are instead thread-safe.</para>
/// </remarks>
public struct DependentHandle : IDisposable
Copy link
Member

Choose a reason for hiding this comment

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

Should we add a [DebuggerDisplay(...)] attribute? And/or a [DebuggerTypeProxy(...)]?

Copy link
Contributor Author

@Sergio0694 Sergio0694 Jun 16, 2021

Choose a reason for hiding this comment

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

Not sure how to structure them exactly, as in, what info did you have in mind for them to expose that wouldn't already be displayed by the built-in debugger view? I guess I can see how eg. [DebuggerDisplay] could add more info, but wouldn't a [DebuggerTypeProxy] with the same IsAllocated, Target and Dependent properties offer the same info as what VS would already do on its own? Or is that to avoid throwing InvalidOperationExceptions in the debugger if the handle is not allocated, or something else? Thanks! 🙂

EDIT: Tanner pointed me towards this comment from Jan that seems to suggest that it might not be worth it in this case to add either of those two debugging types, given that the debugger interfering with the GC is by design? 🤔

Copy link
Member

@stephentoub stephentoub Jun 17, 2021

Choose a reason for hiding this comment

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

I was actually thinking more about, for example, the Target and Dependent properties showing as null instead of showing as a thrown exception if the instance isn't allocated. But, not a big deal.

{
// =========================================================================================
Expand Down Expand Up @@ -68,6 +73,7 @@ public DependentHandle(object? target, object? dependent)
/// Gets or sets the target object instance for the current handle.
/// </summary>
/// <exception cref="InvalidOperationException">Thrown if <see cref="IsAllocated"/> is <see langword="false"/>.</exception>
/// <remarks>This property is thread-safe.</remarks>
Copy link
Member

Choose a reason for hiding this comment

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

IsAllocated is missing a similar thread-safety remark.

public object? Target
{
get
Expand Down Expand Up @@ -98,11 +104,13 @@ public object? Target
/// Gets or sets the dependent object instance for the current handle.
/// </summary>
/// <remarks>
/// If it is necessary to retrieve both <see cref="Target"/> and <see cref="Dependent"/>, it is
/// recommended to use <see cref="GetTargetAndDependent"/> instead. This will result in better
/// performance and it will reduce the chance of unexpected behavior in some cases.
/// If it is needed to retrieve both <see cref="Target"/> and <see cref="Dependent"/>, it is necessary
/// to ensure that the returned instance from <see cref="Target"/> will be kept alive until <see cref="Dependent"/>
/// is retrieved as well, or it might be collected and result in unexpected behavior. This can be done by storing the
/// target in a local and calling <see cref="GC.KeepAlive(object)"/> on it after <see cref="Dependent"/> is accessed.
/// </remarks>
/// <exception cref="InvalidOperationException">Thrown if <see cref="IsAllocated"/> is <see langword="false"/>.</exception>
/// <remarks>This property is thread-safe.</remarks>
public object? Dependent
{
get
Expand All @@ -129,26 +137,6 @@ public object? Dependent
}
}

/// <summary>
/// Retrieves the values of both <see cref="Target"/> and <see cref="Dependent"/>, if available.
/// </summary>
/// <returns>The values of <see cref="Target"/> and <see cref="Dependent"/>.</returns>
/// <exception cref="InvalidOperationException">Thrown if <see cref="IsAllocated"/> is <see langword="false"/>.</exception>
public (object? Target, object? Dependent) GetTargetAndDependent()
{
IntPtr handle = _handle;

if (handle == IntPtr.Zero)
{
ThrowHelper.ThrowInvalidOperationException();
}

object? target = InternalGetTarget(handle);
object? secondary = InternalGetDependent(handle);

return (target, secondary);
}

/// <summary>
/// Gets the target object instance for the current handle.
/// </summary>
Expand Down Expand Up @@ -188,6 +176,7 @@ internal void UnsafeSetDependent(object? dependent)
}

/// <inheritdoc cref="IDisposable.Dispose"/>
/// <remarks>This method is not thread-safe.</remarks>
public void Dispose()
{
// Forces dependentHandle back to non-allocated state (if not already there)
Expand Down
1 change: 0 additions & 1 deletion src/libraries/System.Runtime/ref/System.Runtime.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9602,7 +9602,6 @@ public partial struct DependentHandle : System.IDisposable
public bool IsAllocated { get { throw null; } }
public object? Target { get { throw null; } set { } }
public void Dispose() { }
public (object? Target, object? Dependent) GetTargetAndDependent() { throw null; }
}
public enum GCLargeObjectHeapCompactionMode
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,6 @@ public void SetDependent_ThrowsInvalidOperationException()
});
}

[Fact]
public void GetTargetAndDependent_ThrowsInvalidOperationException()
{
Assert.Throws<InvalidOperationException>(() => default(DependentHandle).GetTargetAndDependent());
}

[Fact]
public void Dispose_RepeatedCallsAreFine()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,22 +38,6 @@ public object? Dependent
set => UnsafeSetDependent(value);
}

public (object? Target, object? Dependent) GetTargetAndDependent()
{
Ephemeron[]? data = _data;

if (data is null)
{
ThrowHelper.ThrowInvalidOperationException();

return default;
}

Ephemeron e = data[0];

return e.Key != GC.EPHEMERON_TOMBSTONE ? (e.Key, e.Value) : default;
}

internal object? UnsafeGetTarget()
{
Ephemeron[]? data = _data;
Expand Down