Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Soundness feedback requested: Increasing cache success in S.L.Expressions #24325

Closed
JonHanna opened this issue Dec 3, 2017 · 7 comments
Closed

Comments

@JonHanna
Copy link
Contributor

JonHanna commented Dec 3, 2017

Expressions contains a CanCache(Type) method that reports on the safety of caching a delegate or information about a method based on whether the type is a mscrolib type that (if generic) has only mscorlib type parameters.

The netfx version allows not just mscorlib types to be considered safe, but also those in System.Core where the cache lives. While there aren't as many types in corefx's S.L.Expressions as there are in netfx's S.Core, this basic principle seems sound to me.

It also seems worth doing, tracking hits and misses (of the outer calls only, ignoring its recursive calls on generic parameters except as they affect the final result) has the tests for Microsoft.CSharp go from 0.05% hits to 54.40% and the tests for System.Dynamic.Runtime go from 0.27% to 41.87%. (S.L.Expressions itself goes from 49.59% to 54.34%, and if anything I was expecting it to be an unfair comparison in explicitly using Expressions types more than other tests would, but it it also does a lot of permutations on the primitive types that would have a high hit rate). That would seem to be enough to suggest that dynamic is attempting to cache with so low a success rate as to maybe not be worth trying, but with the change to include Expressions' types it becomes much more useful.

And it seems safe to me, as surely if the types in Expressions were collectible then collecting would also make the static cache collected.

Question 1: Am I wrong in this? Could a type in Expressions be collectible without the TypeUtils type becoming collectible (unreachable at least, even if not yet collected) and making the static cache collectible? Because if I am wrong, then this idea isn't safe.

Question 2: If I'm correct in this, and caching uses of these types would be safe, would it also be safe to consider types in assemblies referenced by Expressions (transitively) safe to cache?

Question 3: Iff the answer to the first question is "safe" and to the second is "not safe", would the assemblies of types that are base types or implemented interfaces of safe types, also be safe (probably too much of a burden to check that to pay off anyway, but figuring out an efficient way to check on this is a separate investigation).

@jkotas
Copy link
Member

jkotas commented Dec 3, 2017

Would it be better to introduce a IsCollectible property on a Type instead, and use it here?

@JonHanna
Copy link
Contributor Author

JonHanna commented Dec 3, 2017

@jkotas I don't know how feasible the implementation of that would be, though it could likely bring many real-world uses of dynamic from near-zero up to 100%, and be useful in many other places, +1.

I'd still be interested in attempting the above in the meantime, since if my reasoning is correct then it would still be safe for S.L.Expressions to cache types from itself even if it had been loaded in a way that made its types collectible (can this even happen right now without dotnet/coreclr#8677? anyway caution suggests assuming that makes it possible) because if the assembly was unloaded again then the TypeUtils type and its cache would itself become collectible.

@JonHanna
Copy link
Contributor Author

JonHanna commented Dec 3, 2017

(Also, if we could have IsCollectible and if typeof(NonCollectibleGeneric<CollectibleTypeArgument).IsCollectible was false, it would make the code easier. It's existence might also lead to it being discovered by people who would realise they should have used it to remove a memory leak they aren't aware they have. (Related: I'm not entirely easy with the way Microsoft.CSharp caches types it sees, though I can't think of a good way around it that wouldn't slow a lot of things up).

@JonHanna
Copy link
Contributor Author

JonHanna commented Dec 4, 2017

Looking at the history of the implementation, it had been in src/Common which would make the way netfx identified the assembly by looking for that of typeof(Expression) no longer valid, and I think that may be why it was dropped. I'm going to go ahead and make a PR, though I'll keep this open for a while in case anyone does see a danger.

@JonHanna
Copy link
Contributor Author

JonHanna commented Dec 4, 2017

Scratch that. I looked into how one would implement such an IsCollectible and I can see how to get to it through reflection today. Thanks @jkotas

@JonHanna JonHanna closed this as completed Dec 4, 2017
@jkotas
Copy link
Member

jkotas commented Dec 4, 2017

Note that System.Linq.Expressions has direct access to CoreLib. It means that you can use CoreLib APIs that are not exposed in public contracts (yet). It is preferable to do it that way instead of private reflection.

@JonHanna
Copy link
Contributor Author

JonHanna commented Dec 4, 2017

@jkotas but RuntimeType is still internal, so

public static bool CanCache(this Type t) => t is RuntimeType rt && rt.IsCollectible();

Gives the error I'd expect. Are you saying there's a way around that?

JonHanna referenced this issue in JonHanna/coreclr Dec 4, 2017
dotnet/corefx#25671 asks for this as a public API, but this just seeks
to make it available to corefx.

Motivation discussed at dotnet/corefx#25663 and dotnet/corefx#25670

Mirror PR to corert will need and overload making runtime types return
false there.
jkotas referenced this issue in dotnet/coreclr Dec 5, 2017
dotnet/corefx#25671 asks for this as a public API, but this just seeks
to make it available to corefx.

Motivation discussed at dotnet/corefx#25663 and dotnet/corefx#25670

Mirror PR to corert will need and overload making runtime types return
false there.
dotnet-bot referenced this issue in dotnet/corert Dec 5, 2017
dotnet/corefx#25671 asks for this as a public API, but this just seeks
to make it available to corefx.

Motivation discussed at dotnet/corefx#25663 and dotnet/corefx#25670

Mirror PR to corert will need and overload making runtime types return
false there.

Signed-off-by: dotnet-bot <dotnet-bot@microsoft.com>
jkotas referenced this issue in dotnet/corert Dec 5, 2017
dotnet/corefx#25671 asks for this as a public API, but this just seeks
to make it available to corefx.

Motivation discussed at dotnet/corefx#25663 and dotnet/corefx#25670

Mirror PR to corert will need and overload making runtime types return
false there.

Signed-off-by: dotnet-bot <dotnet-bot@microsoft.com>
jashook referenced this issue in jashook/coreclr Dec 12, 2017
dotnet/corefx#25671 asks for this as a public API, but this just seeks
to make it available to corefx.

Motivation discussed at dotnet/corefx#25663 and dotnet/corefx#25670

Mirror PR to corert will need and overload making runtime types return
false there.
dotnet-bot referenced this issue in dotnet/corefx Jan 13, 2018
dotnet/corefx#25671 asks for this as a public API, but this just seeks
to make it available to corefx.

Motivation discussed at dotnet/corefx#25663 and #25670

Mirror PR to corert will need and overload making runtime types return
false there.

Signed-off-by: dotnet-bot-corefx-mirror <dotnet-bot@microsoft.com>
dotnet-bot referenced this issue in dotnet/corefx Jan 13, 2018
dotnet/corefx#25671 asks for this as a public API, but this just seeks
to make it available to corefx.

Motivation discussed at dotnet/corefx#25663 and #25670

Mirror PR to corert will need and overload making runtime types return
false there.

Signed-off-by: dotnet-bot-corefx-mirror <dotnet-bot@microsoft.com>
safern referenced this issue in dotnet/corefx Jan 16, 2018
dotnet/corefx#25671 asks for this as a public API, but this just seeks
to make it available to corefx.

Motivation discussed at dotnet/corefx#25663 and #25670

Mirror PR to corert will need and overload making runtime types return
false there.

Signed-off-by: dotnet-bot-corefx-mirror <dotnet-bot@microsoft.com>
safern referenced this issue in dotnet/corefx Jan 16, 2018
dotnet/corefx#25671 asks for this as a public API, but this just seeks
to make it available to corefx.

Motivation discussed at dotnet/corefx#25663 and #25670

Mirror PR to corert will need and overload making runtime types return
false there.

Signed-off-by: dotnet-bot-corefx-mirror <dotnet-bot@microsoft.com>
@msftgits msftgits transferred this issue from dotnet/corefx Jan 31, 2020
@msftgits msftgits added this to the 2.1.0 milestone Jan 31, 2020
@dotnet dotnet locked as resolved and limited conversation to collaborators Dec 19, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

3 participants