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

Non-PGO calli/delegate call transformation #109679

Closed
wants to merge 16 commits into from

Conversation

MichalPetryka
Copy link
Contributor

@MichalPetryka MichalPetryka commented Nov 10, 2024

I've decided to split my earlier attempt from #85197 into first adding just the transformation and only then making it find more cases with substitution.

TODO before merge:

TODO after merge:

  • Add some importer forward substitution to handle calli with args and more cases.
  • Do [API Proposal]: Introduce an intrinsic for more efficient lambda generation #85014 to handle lambdas.
  • Handle explicitly allocated delegates (for example capturing lambdas, might be done as a part of the substitution)
  • Make the VM not mark all DynamicMethods as DONTINLINE.
  • Handle methods closed over null in some way.
  • Avoid loads for frozen targets.
  • Reuse the handling for later phases where we can't inline but can devirt more after forwardsub and other passes.

@dotnet-issue-labeler dotnet-issue-labeler bot added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Nov 10, 2024
@dotnet-policy-service dotnet-policy-service bot added the community-contribution Indicates that the PR has been added by a community member label Nov 10, 2024
@MichalPetryka
Copy link
Contributor Author

@MihuBot -dependsOn 108579

@MichalPetryka
Copy link
Contributor Author

@MihuBot -dependsOn 108579

@MichalPetryka
Copy link
Contributor Author

@MihuBot -dependsOn 108579

@MichalPetryka
Copy link
Contributor Author

@jkotas It seems to me like the CONTRACT_ASSERT has some bug where it crashes with some non null terminated string instead of properly asserting, should I open an issue for it?

(1724.ab4): Access violation - code c0000005 (first/second chance not available)
For analysis of this file, run !analyze -v
*** WARNING: Unable to verify checksum for coreclr.dll
coreclr!common_strnlen_simd<0,1,unsigned char>+0x17d:
00007ff8`4c1593dd c5fe6f00        vmovdqu ymm0,ymmword ptr [rax] ds:00007ff8`00000000=??
0:000> cdb: Reading initial command '$<C:\h\w\A222091B\t\tmpbv5o3k.tmp'
0:000> .load C:\Users\runner\.dotnet\sos\sos.dll
0:000> ~*k

.  0  Id: 1724.ab4 Suspend: 0 Teb: 000000c3`5c72a000 Unfrozen
Child-SP          RetAddr           Call Site
000000c3`5c972960 00007ff8`4c158ad6 coreclr!common_strnlen_simd<0,1,unsigned char>+0x17d
000000c3`5c972af0 00007ff8`4c159efd coreclr!common_strnlen<0,unsigned char>+0x26
000000c3`5c972b20 00007ff8`4c13fb18 coreclr!strnlen+0x1d
000000c3`5c972b50 00007ff8`4c13f742 coreclr!__crt_stdio_output::output_processor<char,__crt_stdio_output::string_output_adapter<char>,__crt_stdio_output::format_validation_base<char,__crt_stdio_output::string_output_adapter<char> > >::type_case_s_compute_narrow_string_length+0x28
000000c3`5c972b80 00007ff8`4c13a762 coreclr!__crt_stdio_output::output_processor<char,__crt_stdio_output::string_output_adapter<char>,__crt_stdio_output::format_validation_base<char,__crt_stdio_output::string_output_adapter<char> > >::type_case_s+0x102
000000c3`5c972bc0 00007ff8`4c136a7f coreclr!__crt_stdio_output::output_processor<char,__crt_stdio_output::string_output_adapter<char>,__crt_stdio_output::format_validation_base<char,__crt_stdio_output::string_output_adapter<char> > >::state_case_type+0x82
000000c3`5c972c30 00007ff8`4c12a295 coreclr!__crt_stdio_output::output_processor<char,__crt_stdio_output::string_output_adapter<char>,__crt_stdio_output::format_validation_base<char,__crt_stdio_output::string_output_adapter<char> > >::process+0x34f
000000c3`5c972ca0 00007ff8`4c12b011 coreclr!common_vsprintf<__crt_stdio_output::format_validation_base,char>+0x2a5
000000c3`5c9731d0 00007ff8`4c142ff9 coreclr!common_vsprintf_s<char>+0x201
000000c3`5c973270 00007ff8`4b803554 coreclr!__stdio_common_vsprintf_s+0x69
(Inline Function) --------`-------- coreclr!_vsprintf_s_l+0x24
000000c3`5c973300 00007ff8`4b7d1067 coreclr!sprintf_s+0x44
000000c3`5c973360 00007ff8`4bb7fb8e coreclr!CONTRACT_ASSERT+0x237
000000c3`5c976a30 00007ff8`4b9c2445 coreclr!EEContract::DoChecks+0x2ce
000000c3`5c976ab0 00007ff8`4b99022a coreclr!Entry2MethodDesc+0x2c5

@jkotas
Copy link
Member

jkotas commented Nov 10, 2024

Yes, it looks like a bug somewhere. Do you have a link to the crashdump or are you able to tell where the non-terminated string comes from?

@MichalPetryka
Copy link
Contributor Author

Yes, it looks like a bug somewhere. Do you have a link to the crashdump or are you able to tell where the non-terminated string comes from?

The crash is from the Build Libraries Test Run checked coreclr windows x64 Release System.Linq.Parallel.Tests on this PR, not sure how to extract the dump from there.

@jkotas
Copy link
Member

jkotas commented Nov 11, 2024

The crash is from the Build Libraries Test Run checked coreclr windows x64 Release System.Linq.Parallel.Tests on this PR

Multiple things went wrong:

  • The changes in your PR are introducing contract violation
  • The per-thread ContractStackRecord that is used to report the contract violation is corrupted that leads to the crash inside sprintf

The non-null terminated string is a random pointer that came from the corrupted ContractStackRecord linked list. I am not able to tell whether the ContractStackRecord linked list corruption is related to the changes in your PR.

I have tried to introduce an artificial contract violation locally and it was reported fine (no ContractStackRecord linked list corruption).

not sure how to extract the dump from there.

runfo get-helix-payload -j 3836380a-b687-43fa-9d1b-6f438a90cd05 -w System.Linq.Parallel.Tests -o c:\helix_payload\System.Linq.Parallel.Tests

This command is mentioned in the how-to-debug-dump.md doc that is part of the test artifacts: https://dev.azure.com/dnceng-public/public/_build/results?buildId=865877&view=ms.vss-test-web.build-test-results-tab&runId=22530538&paneView=dotnet-dnceng.dnceng-build-release-tasks.helix-test-information-tab&resultId=214160

@MichalPetryka
Copy link
Contributor Author

  • The changes in your PR are introducing contract violation

I think the current version should be fine now, could you check if all looks good with the new JIT-EE call?

@@ -5066,7 +5101,7 @@ void CEEInfo::getCallInfo(
}
else
{
if (!exactType.IsTypeDesc() && !pTargetMD->IsArray())
if (!exactType.IsTypeDesc() && !pTargetMD->IsArray() && !pTargetMD->IsDynamicMethod())
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@jkotas CoreCLR is asserting here on DynamicMethod without adding a check here, is this the right solution? With it we can emit direct calls to them but they're still not inlined cause VM says they're DONTINLINE.

Copy link
Member

Choose a reason for hiding this comment

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

What's the assert?

Dynamic methods can call each other today. This code is able to handle that. How is the case that you are introducing different?

Copy link
Contributor Author

@MichalPetryka MichalPetryka Nov 11, 2024

Choose a reason for hiding this comment

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

What's the assert?

It's the null return assert inside of this if.

How is the case that you are introducing different?

The MethodTable* from the DynamicMethod is different from the one this method obtains from the JIT which in turn gets it from getMethodClass(replacementMethod). It seems like getMethodClass causes the pointer to be normalized to the real one while the VM here has a special DynamicMethodTable* which causes GetExactDeclaringType to fail.

Copy link
Member

Choose a reason for hiding this comment

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

I am not following. DynamicMethodTable and MethodTable are unrelated types. DynamicMethodTable should never show up in the JIT/EE interface calls.

Copy link
Contributor Author

@MichalPetryka MichalPetryka Nov 12, 2024

Choose a reason for hiding this comment

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

I am not following. DynamicMethodTable and MethodTable are unrelated types. DynamicMethodTable should never show up in the JIT/EE interface calls.

I mean, the JIT is passing the proper class handle (the class the DynamicMethod is being attached to, which it gets from getMethodClass), but the method table stored in the dynamic MethodDesc is a custom one with the debug name for it being dynamicClass, which makes GetExactDeclaringType fail cause that seems to have no relation to the parent type.

Copy link
Member

Choose a reason for hiding this comment

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

Ok, so the problem is that getMethodClass returns the owning class handle for dynamic methods, but CORINFO_RESOLVED_TOKEN is expected to have the actual class handle for dynamic methods.

I think it would be best to fix it in the place that fills in CORINFO_RESOLVED_TOKEN to have the actual class handle. It will make the dynamic methods path introduced by this PR work the same way as the existing paths taken by the dynamic methods.

Copy link
Contributor Author

@MichalPetryka MichalPetryka Nov 13, 2024

Choose a reason for hiding this comment

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

Ok, so the problem is that getMethodClass returns the owning class handle for dynamic methods, but CORINFO_RESOLVED_TOKEN is expected to have the actual class handle for dynamic methods.

I think it would be best to fix it in the place that fills in CORINFO_RESOLVED_TOKEN to have the actual class handle. It will make the dynamic methods path introduced by this PR work the same way as the existing paths taken by the dynamic methods.

How would I grab that from the JIT? This is where I grab that currently with getMethodClass.

EDIT: Would you suggest to add it to the getMethodFromDelegate JIT-EE api?

Copy link
Contributor Author

@MichalPetryka MichalPetryka Nov 13, 2024

Choose a reason for hiding this comment

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

Also to be honest, this seems to me a bit like CoreCLR is leaking implementation details of itself to the JIT, for me it'd make more sense if it always returned the handle of the owner class to the JIT and then mapped back to its dynamic one on its end reliably. Otherwise we're polluting the JIT with behaviours specific to one VM.

Copy link
Member

Choose a reason for hiding this comment

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

I agree that CoreCLR is leaking the implementation details here, but I have different opinion about what the correct behavior should be.

The dynamic method type owner is optional and it is only meant to be used for visibility checks. All visibility checks should be done on the EE side. I am not sure why the JIT ever needs to see the type owner. I think it would make more sense for the JIT to always see the special MethodTable that the dynamic methods are attached to.

Would you suggest to add it to the getMethodFromDelegate JIT-EE api?

I would think so. It may also help you with communicating precise type to the JIT. I think MethodDesc* may not always have the precise type in case of shared generic code - notice that Delegate.GetMethodImpl does extra work to figure out the precise type for generic types https://github.com/dotnet/runtime/blob/main/src/coreclr/System.Private.CoreLib/src/System/Delegate.CoreCLR.cs#L169-L170.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I would think so. It may also help you with communicating precise type to the JIT. I think MethodDesc* may not always have the precise type in case of shared generic code - notice that Delegate.GetMethodImpl does extra work to figure out the precise type for generic types https://github.com/dotnet/runtime/blob/main/src/coreclr/System.Private.CoreLib/src/System/Delegate.CoreCLR.cs#L169-L170.

I can't find a case where this is an issue, the JIT seems to always have the proper generic context to resolve stuff so I wonder if this is just a reflection only issue?

If not, could you assist me with handling this cause I couldn't figure out how to replicate this logic in VMs?

@@ -106,7 +106,6 @@ public TypeDesc Type
public DelegateInfo(TypeDesc delegateType, DelegateFeature features)
{
Debug.Assert(delegateType.IsDelegate);
Debug.Assert(delegateType.IsTypeDefinition);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm not sure if this is safe but NativeAOT otherwise asserts here.

Copy link
Member

Choose a reason for hiding this comment

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

It isn't, the implementation is non-sensical for instantiated types.

Is this only used to get signature of the delegate? If so, replace this:

                DelegateInfo delegateInfo = _compilation.TypeSystemContext.GetDelegateInfo(calledType);
                int paramCountDelegateClosed = delegateInfo.Signature.Length + 1;

with this:

                int paramCountDelegateClosed = calledType.GetMethod("Invoke", null).Signature.Length + 1;

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I made it check _firstParameter instead since AFAIR I can just do that on NativeAOT since it seems to not support closed static delegates or instance ones closed over null.

@AndyAyersMS
Copy link
Member

Copying and slightly editing part of my note from #108579 (comment)

I think we should approach this differently. Instead of trying to pull all this off during importation and inlining, where it is difficult for us to reason about dataflow, I would like to see us focus on refactoring the inliner so it can be invoked as a utility in later phases and then rely on normal forward propagation of facts to enable new inlining in cases like these.

That would be a more robust and more general solution, but also a fair amount more work, and not something I think we're prepared to do or oversee during .NET 10.

Thinking about it a bit more, you might also be able to re-express this as a special case of GDV, where the analysis you do here creates a guarded delegate invoke, and then later JIT optimizations prove it's the only possibility and remove the guard test and alternative paths. @jakobbotsch might have been hinting at something like this recently.

@MichalPetryka
Copy link
Contributor Author

Copying and slightly editing part of my note from #108579 (comment)

I think we should approach this differently. Instead of trying to pull all this off during importation and inlining, where it is difficult for us to reason about dataflow, I would like to see us focus on refactoring the inliner so it can be invoked as a utility in later phases and then rely on normal forward propagation of facts to enable new inlining in cases like these.
That would be a more robust and more general solution, but also a fair amount more work, and not something I think we're prepared to do or oversee during .NET 10.

Thinking about it a bit more, you might also be able to re-express this as a special case of GDV, where the analysis you do here creates a guarded delegate invoke, and then later JIT optimizations prove it's the only possibility and remove the guard test and alternative paths. @jakobbotsch might have been hinting at something like this recently.

Sorry for the delay, I had a cold for the past few days so I didn't really feel like going back to this but now I will.
I'll start with the previous comment:

I disagree with the idea that doing the transformation early is a bad idea. While doing it early on misses some cases, doing it early lets us apply all optimizations possible, while doing it later on would miss for example all optimizations done by forward-sub and earlier phases. Additionally, doing it early is still possible for a considerable about of cases including single-def locals.
Seeing how your idea of adding late inlining requires significant work, I feel like a saying we have here - "better is the enemy of good" - describes my opinion on this. While this solution is not perfect, it's at the same idea not an useless addition, it still provides improvements to the generated codegen and especially helps AOT catch up with the gaps created by PGO.

Additionally, doing early expansion does not block adding late expansion in any way. In fact, I'd say that having both an early expansion here for the easy cases and then a second part later on that would at first just transform the call and later on fully inline it when your proposed changes would be implemented would be the best end solution for this as it'd handle both the easy cases optimally and harder to find ones would still be handled although not as good.

The main issue with my approach here is not being able to see through calls to stuff returned from methods, but AFAIR that should only be a noticeable issue with properties and such and those could be handled by something like #96325.

As for compelling data on improvements, I assume that doing #85014 first would be required for obtaining such. For now, I'm afraid that static readonly delegates and function pointers are not common enough to be extremely noticeable other than a few cases. It'd be easy to use microbenchmarks here, but I rarely see delegates stored as such outside of some perf optimized places like the BCL.

One thing worth to note here is that this'd help with hiding the current limitations of PGO like the profile data not being collected per callsite, being able to remove known callsites here from the data would help with keeping it clean for other places too.

Thinking about it a bit more, you might also be able to re-express this as a special case of GDV, where the analysis you do here creates a guarded delegate invoke, and then later JIT optimizations prove it's the only possibility and remove the guard test and alternative paths.

Today I've realised that'd only really be useful for handling multi-def locals.
For single def locals we'll only see one assignment which we can just save but we then have the issue you mentioned with users writing unusual IL that accesses the variable before the assignment.
I was thinking we needed to exactly check the dataflow for assignment or create a branching check that's GDV style, but today I realised that case is way simpler to handle - such variables will always either have the value that we saw assigned or will either be null from localsinit/being a gc ref or will be undefined with skiplocalsinit.
As such, it's enough to just spawn a single GT_NULLCHECK before the call in the case we know the local is zeroed and in the undefined case we could technically exploit that and just make the JIT behave as if the local pointer to the single value from the start since AFAIR the JIT is free to optimize out crashes from stuff like AV (this would technically introduce as Einstein dubbed it "spooky action at a distance" behaviour to the JIT so I'm not sure how comfortable of a solution would this be).
Additionally, for nullchecking ftn pointers we'd need to have a guarantee from the VM that valid function pointers are always on a readable page, but AFAIR the VM doesn't ever use execute-only pages today (cc @jkotas).

@MichalPetryka
Copy link
Contributor Author

MichalPetryka commented Nov 29, 2024

The failed test here is a GC hole with GC info according to the crash dump from the pipeline but I don't see anything immediately wrong with the JIT-EE API, it appears to be using COOP and GC_PROTECT properly as far as I realise. Could it possibly come from merging main since it only appeared now? Or if not, can anybody spot what's wrong here cause I'm not exactly sure how to debug such case other than running with GCSTRESS and hoping for it to crash.

@jkotas
Copy link
Member

jkotas commented Nov 29, 2024

I'm not exactly sure how to debug such case

The best first step is to find as much as possible from the crash dump collected by the CI. What did you find from the crash dump about the crash?

@MichalPetryka
Copy link
Contributor Author

MichalPetryka commented Nov 29, 2024

I'm not exactly sure how to debug such case

The best first step is to find as much as possible from the crash dump collected by the CI. What did you find from the crash dump about the crash?

WinDBG gives this as the stacktrace:
image

However SOS refuses to work with the dump and gives messages like:
No CLR runtime found. This means that a .NET runtime module or the DAC for the runtime can not be found or downloaded.
Failed to load data access module, 0x80004002
even after I loaded a local windows build of the DAC.

@MichalPetryka
Copy link
Contributor Author

MichalPetryka commented Nov 30, 2024

@jkotas I've realised a fundamental issue with devirtualizing delegates without runtime checks: delegates can be fully legally mutated by explicitly calling the delegate .ctor on an already constructed instance, which is legal in the ECMA. As such, one can change what method a delegate points to this way. I'm not sure how well would the VM handle doing so, but does this mean we always need to do a check if we wanted to merge this? Or would you prefer to maybe make it illegal with an ECMA addendum?

cc @AndyAyersMS does PGO have any unguarded cases for delegates that would break with this?

EDIT: After some more looking around, I noticed the ECMA having this: The objects and methods to which it delegates are chosen when the delegate instance is created. which I think could make unguarded devirt fine if I interpret it correctly? Since the issue is only about changing it with the .ctor after it's created.

@jkotas
Copy link
Member

jkotas commented Nov 30, 2024

delegates can be fully legally mutated by explicitly calling the delegate .ctor on an already constructed instance, which is legal in the ECMA

Why do think that it is legal? It does not sound legal to me. If it was legal to call constructors multiple times (on the types provided by the runtime in particular), things would get very interesting.

@jkotas
Copy link
Member

jkotas commented Nov 30, 2024

I loaded a local windows build of the DAC.

Was it Linux-targeting Windows-hosted CrossDAC? You typically have to download this DAC manually from the special build leg that builds it (or just build it locally).

Alternatively, you can debug natively on Linux using LLBD. The CrossDAC is not needed for that.

@MichalPetryka
Copy link
Contributor Author

MichalPetryka commented Nov 30, 2024

delegates can be fully legally mutated by explicitly calling the delegate .ctor on an already constructed instance, which is legal in the ECMA

Why do think that it is legal? It does not sound legal to me. If it was legal to call constructors multiple times (on the types provided by the runtime in particular), things would get very interesting.

Calling constructors multiple time is legal in the ECMA, it's only said to be not CLS compliant there. Even calling .cctors multiple times is legal.

@jkotas
Copy link
Member

jkotas commented Nov 30, 2024

Calling constructors multiple time is legal in the ECMA,

Does it explicitly say that it is legal somewhere?

Calling constructors (via call instruction) has been verifiable only when calling object base class constructor or to initialize value type location. It is mentioned in the verification rules for the call instruction in ECMA and ILVerify checks it here. It prohibits re-initialization of an initialized instance by calling a constructor in verifiable code. ECMA does not cover the distinction between legal unverifiable code and invalid code.

I agree that ECMA wording could have been more precise. We can fix via the augments doc if needed

@EgorBo
Copy link
Member

EgorBo commented Nov 30, 2024

/azp run runtime-coreclr gcstress-extra, runtime-coreclr gcstress0x3-gcstress0xc

Copy link

Azure Pipelines successfully started running 2 pipeline(s).

@MichalPetryka
Copy link
Contributor Author

I loaded a local windows build of the DAC.

Was it Linux-targeting Windows-hosted CrossDAC? You typically have to download this DAC manually from the special build leg that builds it (or just build it locally).

Alternatively, you can debug natively on Linux using LLBD. The CrossDAC is not needed for that.

Ah missed the fact I was not using a CrossDAC.
With it SOS says:

0:018> !sos.verifyheap
688?172 objects verified, 0 errors.
No heap corruption detected.
0:018> !sos.clrstack
OS Thread Id: 0x12b00 (18)
        Child SP               IP Call Site
0000709D965FB5D8 000070dec8aea42f [HelperMethodFrame: 0000709d965fb5d8] 
0000709D965FB760 000070de5af4b63a Microsoft.CodeAnalysis.SmallDictionary`2[[System.__Canon, System.Private.CoreLib],[Microsoft.CodeAnalysis.CSharp.Symbols.TypeWithAnnotations, Microsoft.CodeAnalysis.CSharp]].Insert(Int32, System.__Canon, Microsoft.CodeAnalysis.CSharp.Symbols.TypeWithAnnotations, Boolean)
0000709D965FB8A0 000070de5af46e62 Microsoft.CodeAnalysis.SmallDictionary`2[[System.__Canon, System.Private.CoreLib],[Microsoft.CodeAnalysis.CSharp.Symbols.TypeWithAnnotations, Microsoft.CodeAnalysis.CSharp]].Add(System.__Canon, Microsoft.CodeAnalysis.CSharp.Symbols.TypeWithAnnotations)
0000709D965FB8E0 000070de5af4dfac Microsoft.CodeAnalysis.CSharp.Symbols.TypeMap..ctor(Microsoft.CodeAnalysis.CSharp.Symbols.NamedTypeSymbol, System.Collections.Immutable.ImmutableArray`1<Microsoft.CodeAnalysis.CSharp.Symbols.TypeParameterSymbol>, System.Collections.Immutable.ImmutableArray`1<Microsoft.CodeAnalysis.CSharp.Symbols.TypeWithAnnotations>)
0000709D965FB990 000070de5af4de16 Microsoft.CodeAnalysis.CSharp.Symbols.ConstructedNamedTypeSymbol..ctor(Microsoft.CodeAnalysis.CSharp.Symbols.NamedTypeSymbol, System.Collections.Immutable.ImmutableArray`1<Microsoft.CodeAnalysis.CSharp.Symbols.TypeWithAnnotations>, Boolean, TupleExtraData)
0000709D965FBA20 000070de5af4dcc9 Microsoft.CodeAnalysis.CSharp.Symbols.NamedTypeSymbol.ConstructCore(System.Collections.Immutable.ImmutableArray`1<Microsoft.CodeAnalysis.CSharp.Symbols.TypeWithAnnotations>, Boolean)
0000709D965FBA50 000070de5af4d922 Microsoft.CodeAnalysis.CSharp.Symbols.NamedTypeSymbol.Construct(System.Collections.Immutable.ImmutableArray`1<Microsoft.CodeAnalysis.CSharp.Symbols.TypeWithAnnotations>, Boolean)
0000709D965FBB10 000070de5af4d5a8 Microsoft.CodeAnalysis.CSharp.Symbols.SymbolExtensions.ConstructIfGeneric(Microsoft.CodeAnalysis.CSharp.Symbols.NamedTypeSymbol, System.Collections.Immutable.ImmutableArray`1<Microsoft.CodeAnalysis.CSharp.Symbols.TypeWithAnnotations>)
0000709D965FBB40 000070de5af4b0c2 Microsoft.CodeAnalysis.CSharp.Symbols.AbstractTypeMap.SubstituteNamedType(Microsoft.CodeAnalysis.CSharp.Symbols.NamedTypeSymbol)
0000709D965FBC70 000070de5af49aa6 Microsoft.CodeAnalysis.CSharp.Symbols.Metadata.PE.SymbolFactory.SubstituteTypeParameters(Microsoft.CodeAnalysis.CSharp.Symbols.Metadata.PE.PEModuleSymbol, Microsoft.CodeAnalysis.CSharp.Symbols.TypeSymbol, System.Collections.Immutable.ImmutableArray`1<System.Collections.Generic.KeyValuePair`2<Microsoft.CodeAnalysis.CSharp.Symbols.TypeSymbol,System.Collections.Immutable.ImmutableArray`1<Microsoft.CodeAnalysis.ModifierInfo`1<Microsoft.CodeAnalysis.CSharp.Symbols.TypeSymbol>>>>, System.Collections.Immutable.ImmutableArray`1)
0000709D965FBE20 000070de5af49300 Microsoft.CodeAnalysis.TypeNameDecoder`2[[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib]].SubstituteTypeParameters(System.__Canon, System.Collections.Immutable.ImmutableArray`1<System.Collections.Generic.KeyValuePair`2<System.__Canon,System.Collections.Immutable.ImmutableArray`1<Microsoft.CodeAnalysis.ModifierInfo`1<System.__Canon>>>>, System.Collections.Immutable.ImmutableArray`1)
0000709D965FBE60 000070de5af47fa9 Microsoft.CodeAnalysis.MetadataDecoder`5[[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib]].DecodeGenericTypeInstanceOrThrow(System.Reflection.Metadata.BlobReader ByRef, Boolean ByRef)
0000709D965FBFA0 000070de5c3422ce Microsoft.CodeAnalysis.MetadataDecoder`5[[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib]].DecodeTypeOrThrow(System.Reflection.Metadata.BlobReader ByRef, System.Reflection.Metadata.SignatureTypeCode, Boolean ByRef)
0000709D965FC040 000070de5af47c6d Microsoft.CodeAnalysis.MetadataDecoder`5[[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib]].DecodeTypeOrThrow(System.Reflection.Metadata.BlobReader ByRef, Boolean ByRef)
0000709D965FC070 000070de5af47883 Microsoft.CodeAnalysis.MetadataDecoder`5[[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib]].GetTypeOfTypeSpec(System.Reflection.Metadata.TypeSpecificationHandle)
0000709D965FC0E0 000070de5c33f0ae Microsoft.CodeAnalysis.MetadataDecoder`5[[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib]].GetTypeOfToken(System.Reflection.Metadata.EntityHandle, Boolean ByRef)
0000709D965FC110 000070de5c33f651 Microsoft.CodeAnalysis.MetadataDecoder`5[[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib]].GetTypeOfToken(System.Reflection.Metadata.EntityHandle)
0000709D965FC120 000070de5af5c2ca Microsoft.CodeAnalysis.MetadataDecoder`5[[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib]].EnqueueTypeToken(System.Collections.Generic.Queue`1<System.Reflection.Metadata.TypeDefinitionHandle>, System.Collections.Generic.Queue`1<System.__Canon>, System.Reflection.Metadata.EntityHandle)
0000709D965FC170 000070de5af5c125 Microsoft.CodeAnalysis.MetadataDecoder`5[[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib]].EnqueueTypeDefInterfacesAndBaseTypeOrThrow(System.Collections.Generic.Queue`1<System.Reflection.Metadata.TypeDefinitionHandle>, System.Collections.Generic.Queue`1<System.__Canon>, System.Reflection.Metadata.TypeDefinitionHandle)
0000709D965FC260 000070de5af5cb98 Microsoft.CodeAnalysis.MetadataDecoder`5[[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib]].FindMethodSymbolInSuperType(System.Reflection.Metadata.TypeDefinitionHandle, System.Reflection.Metadata.MethodDefinitionHandle)
0000709D965FC3F0 000070de5af59720 Microsoft.CodeAnalysis.MetadataDecoder`5[[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib]].GetExplicitlyOverriddenMethods(System.Reflection.Metadata.TypeDefinitionHandle, System.Reflection.Metadata.MethodDefinitionHandle, System.__Canon)
0000709D965FC510 000070de5af58eba Microsoft.CodeAnalysis.CSharp.Symbols.Metadata.PE.PEMethodSymbol.get_ExplicitInterfaceImplementations()
0000709D965FC670 000070de5c378591 Microsoft.CodeAnalysis.CSharp.Symbols.Metadata.PE.PEMethodSymbol.ComputeMethodKind()
0000709D965FC6C0 000070de5c363bf7 Microsoft.CodeAnalysis.CSharp.Symbols.Metadata.PE.PENamedTypeSymbol.LoadMembers()
0000709D965FC7E0 000070de5af5e6c2 Microsoft.CodeAnalysis.CSharp.Symbols.Metadata.PE.PENamedTypeSymbol.GetSimpleNonTypeMembers(System.String)
0000709D965FC810 000070de5c879f6c Microsoft.CodeAnalysis.CSharp.Symbols.NamedTypeSymbol.GetOperators(System.String)
0000709D965FC860 000070de5af5e00a Microsoft.CodeAnalysis.CSharp.ConversionsBase.g__addCandidatesFromType|159_0(Microsoft.CodeAnalysis.CSharp.Symbols.TypeParameterSymbol, Microsoft.CodeAnalysis.CSharp.Symbols.NamedTypeSymbol, Microsoft.CodeAnalysis.CSharp.BoundExpression, Microsoft.CodeAnalysis.CSharp.Symbols.TypeSymbol, Microsoft.CodeAnalysis.CSharp.Symbols.TypeSymbol, Microsoft.CodeAnalysis.PooledObjects.ArrayBuilder`1<Microsoft.CodeAnalysis.CSharp.UserDefinedConversionAnalysis>, Microsoft.CodeAnalysis.CompoundUseSiteInfo`1<Microsoft.CodeAnalysis.CSharp.Symbols.AssemblySymbol> ByRef, Boolean)
0000709D965FCA50 000070de5afbbd40 Microsoft.CodeAnalysis.CSharp.ConversionsBase.ComputeApplicableUserDefinedImplicitConversionSet(Microsoft.CodeAnalysis.CSharp.BoundExpression, Microsoft.CodeAnalysis.CSharp.Symbols.TypeSymbol, Microsoft.CodeAnalysis.CSharp.Symbols.TypeSymbol, Microsoft.CodeAnalysis.PooledObjects.ArrayBuilder`1<System.ValueTuple`2<Microsoft.CodeAnalysis.CSharp.Symbols.NamedTypeSymbol,Microsoft.CodeAnalysis.CSharp.Symbols.TypeParameterSymbol>>, Microsoft.CodeAnalysis.PooledObjects.ArrayBuilder`1<Microsoft.CodeAnalysis.CSharp.UserDefinedConversionAnalysis>, Microsoft.CodeAnalysis.CompoundUseSiteInfo`1<Microsoft.CodeAnalysis.CSharp.Symbols.AssemblySymbol> ByRef, Boolean)
0000709D965FCB60 000070de5afbb8d8 Microsoft.CodeAnalysis.CSharp.ConversionsBase.AnalyzeImplicitUserDefinedConversions(Microsoft.CodeAnalysis.CSharp.BoundExpression, Microsoft.CodeAnalysis.CSharp.Symbols.TypeSymbol, Microsoft.CodeAnalysis.CSharp.Symbols.TypeSymbol, Microsoft.CodeAnalysis.CompoundUseSiteInfo`1<Microsoft.CodeAnalysis.CSharp.Symbols.AssemblySymbol> ByRef)
0000709D965FCC50 000070de5afbb7cc Microsoft.CodeAnalysis.CSharp.ConversionsBase.GetImplicitUserDefinedConversion(Microsoft.CodeAnalysis.CSharp.BoundExpression, Microsoft.CodeAnalysis.CSharp.Symbols.TypeSymbol, Microsoft.CodeAnalysis.CSharp.Symbols.TypeSymbol, Microsoft.CodeAnalysis.CompoundUseSiteInfo`1<Microsoft.CodeAnalysis.CSharp.Symbols.AssemblySymbol> ByRef)
0000709D965FCCB0 000070de5af33ccf Microsoft.CodeAnalysis.CSharp.ConversionsBase.ClassifyImplicitConversionFromExpression(Microsoft.CodeAnalysis.CSharp.BoundExpression, Microsoft.CodeAnalysis.CSharp.Symbols.TypeSymbol, Microsoft.CodeAnalysis.CompoundUseSiteInfo`1<Microsoft.CodeAnalysis.CSharp.Symbols.AssemblySymbol> ByRef)
0000709D965FCDA0 000070de5afa8014 Microsoft.CodeAnalysis.CSharp.ConversionsBase.ClassifyConversionFromExpression(Microsoft.CodeAnalysis.CSharp.BoundExpression, Microsoft.CodeAnalysis.CSharp.Symbols.TypeSymbol, Boolean, Microsoft.CodeAnalysis.CompoundUseSiteInfo`1<Microsoft.CodeAnalysis.CSharp.Symbols.AssemblySymbol> ByRef, Boolean)
0000709D965FCE40 000070de5bf5b996 Microsoft.CodeAnalysis.CSharp.OverloadResolution.CandidateOperators(Boolean, Microsoft.CodeAnalysis.PooledObjects.ArrayBuilder`1<Microsoft.CodeAnalysis.CSharp.BinaryOperatorSignature>, Microsoft.CodeAnalysis.CSharp.BoundExpression, Microsoft.CodeAnalysis.CSharp.BoundExpression, Microsoft.CodeAnalysis.PooledObjects.ArrayBuilder`1<Microsoft.CodeAnalysis.CSharp.BinaryOperatorAnalysisResult>, Microsoft.CodeAnalysis.CompoundUseSiteInfo`1<Microsoft.CodeAnalysis.CSharp.Symbols.AssemblySymbol> ByRef)
0000709D965FD080 000070de5bf57325 Microsoft.CodeAnalysis.CSharp.OverloadResolution.GetAllBuiltInOperators(Microsoft.CodeAnalysis.CSharp.BinaryOperatorKind, Boolean, Microsoft.CodeAnalysis.CSharp.BoundExpression, Microsoft.CodeAnalysis.CSharp.BoundExpression, Microsoft.CodeAnalysis.PooledObjects.ArrayBuilder`1<Microsoft.CodeAnalysis.CSharp.BinaryOperatorAnalysisResult>, Microsoft.CodeAnalysis.CompoundUseSiteInfo`1<Microsoft.CodeAnalysis.CSharp.Symbols.AssemblySymbol> ByRef)
0000709D965FD290 000070de5bf54fb9 Microsoft.CodeAnalysis.CSharp.OverloadResolution.BinaryOperatorOverloadResolution_NoEasyOut(Microsoft.CodeAnalysis.CSharp.BinaryOperatorKind, Boolean, Microsoft.CodeAnalysis.CSharp.BoundExpression, Microsoft.CodeAnalysis.CSharp.BoundExpression, Microsoft.CodeAnalysis.CSharp.BinaryOperatorOverloadResolutionResult, Microsoft.CodeAnalysis.CompoundUseSiteInfo`1<Microsoft.CodeAnalysis.CSharp.Symbols.AssemblySymbol> ByRef)
0000709D965FD390 000070de5beeccd9 Microsoft.CodeAnalysis.CSharp.OverloadResolution.BinaryOperatorOverloadResolution(Microsoft.CodeAnalysis.CSharp.BinaryOperatorKind, Boolean, Microsoft.CodeAnalysis.CSharp.BoundExpression, Microsoft.CodeAnalysis.CSharp.BoundExpression, Microsoft.CodeAnalysis.CSharp.BinaryOperatorOverloadResolutionResult, Microsoft.CodeAnalysis.CompoundUseSiteInfo`1<Microsoft.CodeAnalysis.CSharp.Symbols.AssemblySymbol> ByRef)
0000709D965FD3D0 000070de5beec556 Microsoft.CodeAnalysis.CSharp.Binder.BinaryOperatorOverloadResolution(Microsoft.CodeAnalysis.CSharp.BinaryOperatorKind, Boolean, Microsoft.CodeAnalysis.CSharp.BoundExpression, Microsoft.CodeAnalysis.CSharp.BoundExpression, Microsoft.CodeAnalysis.CSharp.CSharpSyntaxNode, Microsoft.CodeAnalysis.CSharp.BindingDiagnosticBag, Microsoft.CodeAnalysis.CSharp.LookupResultKind ByRef, System.Collections.Immutable.ImmutableArray`1<Microsoft.CodeAnalysis.CSharp.Symbols.MethodSymbol> ByRef)
0000709D965FD600 000070de5beebfd4 Microsoft.CodeAnalysis.CSharp.Binder.BindSimpleBinaryOperatorParts(Microsoft.CodeAnalysis.CSharp.Syntax.BinaryExpressionSyntax, Microsoft.CodeAnalysis.CSharp.BindingDiagnosticBag, Microsoft.CodeAnalysis.CSharp.BoundExpression, Microsoft.CodeAnalysis.CSharp.BoundExpression, Microsoft.CodeAnalysis.CSharp.BinaryOperatorKind, Microsoft.CodeAnalysis.CSharp.LookupResultKind ByRef, System.Collections.Immutable.ImmutableArray`1<Microsoft.CodeAnalysis.CSharp.Symbols.MethodSymbol> ByRef, Microsoft.CodeAnalysis.CSharp.BinaryOperatorSignature ByRef, Microsoft.CodeAnalysis.CSharp.BinaryOperatorAnalysisResult ByRef)
0000709D965FD780 000070de5beeadf7 Microsoft.CodeAnalysis.CSharp.Binder.BindSimpleBinaryOperator(Microsoft.CodeAnalysis.CSharp.Syntax.BinaryExpressionSyntax, Microsoft.CodeAnalysis.CSharp.BindingDiagnosticBag, Microsoft.CodeAnalysis.CSharp.BoundExpression, Microsoft.CodeAnalysis.CSharp.BoundExpression, Boolean)
0000709D965FDAC0 000070de5bee965b Microsoft.CodeAnalysis.CSharp.Binder.BindSimpleBinaryOperator(Microsoft.CodeAnalysis.CSharp.Syntax.BinaryExpressionSyntax, Microsoft.CodeAnalysis.CSharp.BindingDiagnosticBag)
0000709D965FDBB0 000070de5af8ab4c Microsoft.CodeAnalysis.CSharp.Binder.g__bindExpressionInternal|343_0(Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax, Microsoft.CodeAnalysis.CSharp.BindingDiagnosticBag, Boolean, Boolean)
0000709D965FDE60 000070de5af8a300 Microsoft.CodeAnalysis.CSharp.Binder.BindExpressionInternal(Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax, Microsoft.CodeAnalysis.CSharp.BindingDiagnosticBag, Boolean, Boolean)
0000709D965FDEB0 000070de5af8a1d2 Microsoft.CodeAnalysis.CSharp.Binder.BindExpression(Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax, Microsoft.CodeAnalysis.CSharp.BindingDiagnosticBag, Boolean, Boolean)
0000709D965FDEF0 000070de5af8a156 Microsoft.CodeAnalysis.CSharp.Binder.BindValue(Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax, Microsoft.CodeAnalysis.CSharp.BindingDiagnosticBag, BindValueKind)
0000709D965FDF30 000070de5bf53ac6 Microsoft.CodeAnalysis.CSharp.Binder.BindBooleanExpression(Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax, Microsoft.CodeAnalysis.CSharp.BindingDiagnosticBag)
0000709D965FE0E0 000070de5bf543f7 Microsoft.CodeAnalysis.CSharp.Binder.BindValueConditionalOperator(Microsoft.CodeAnalysis.CSharp.Syntax.ConditionalExpressionSyntax, Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax, Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax, Microsoft.CodeAnalysis.CSharp.BindingDiagnosticBag)
0000709D965FE230 000070de5bf5431a Microsoft.CodeAnalysis.CSharp.Binder.BindConditionalOperator(Microsoft.CodeAnalysis.CSharp.Syntax.ConditionalExpressionSyntax, Microsoft.CodeAnalysis.CSharp.BindingDiagnosticBag)
0000709D965FE2C0 000070de5af8b06c Microsoft.CodeAnalysis.CSharp.Binder.g__bindExpressionInternal|343_0(Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax, Microsoft.CodeAnalysis.CSharp.BindingDiagnosticBag, Boolean, Boolean)
0000709D965FE570 000070de5af8a300 Microsoft.CodeAnalysis.CSharp.Binder.BindExpressionInternal(Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax, Microsoft.CodeAnalysis.CSharp.BindingDiagnosticBag, Boolean, Boolean)
0000709D965FE5C0 000070de5af8a1d2 Microsoft.CodeAnalysis.CSharp.Binder.BindExpression(Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax, Microsoft.CodeAnalysis.CSharp.BindingDiagnosticBag, Boolean, Boolean)
0000709D965FE600 000070de5af8a156 Microsoft.CodeAnalysis.CSharp.Binder.BindValue(Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax, Microsoft.CodeAnalysis.CSharp.BindingDiagnosticBag, BindValueKind)
0000709D965FE640 000070de5bea1152 Microsoft.CodeAnalysis.CSharp.Binder.g__bindExpressionBodyAsBlockInternal|1000_0(Microsoft.CodeAnalysis.CSharp.Syntax.ArrowExpressionClauseSyntax, Microsoft.CodeAnalysis.CSharp.Binder, Microsoft.CodeAnalysis.CSharp.BindingDiagnosticBag)
0000709D965FE6B0 000070de5bea0f50 Microsoft.CodeAnalysis.CSharp.Binder.BindExpressionBodyAsBlock(Microsoft.CodeAnalysis.CSharp.Syntax.ArrowExpressionClauseSyntax, Microsoft.CodeAnalysis.CSharp.BindingDiagnosticBag)
0000709D965FE790 000070de5af752d7 Microsoft.CodeAnalysis.CSharp.Binder.BindMethodBody(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxNode, Microsoft.CodeAnalysis.CSharp.BindingDiagnosticBag)
0000709D965FE860 000070de5af74f88 Microsoft.CodeAnalysis.CSharp.MethodCompiler+c.b__42_1(Microsoft.CodeAnalysis.CSharp.Binder, Microsoft.CodeAnalysis.CSharp.CSharpSyntaxNode, System.Object, Microsoft.CodeAnalysis.CSharp.BindingDiagnosticBag)
0000709D965FE8B0 000070de5af74c8f Microsoft.CodeAnalysis.CSharp.Binder.BindWithLambdaBindingCountDiagnostics[[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib]](System.__Canon, System.__Canon, Microsoft.CodeAnalysis.CSharp.BindingDiagnosticBag, System.Func`5<Microsoft.CodeAnalysis.CSharp.Binder,System.__Canon,System.__Canon,Microsoft.CodeAnalysis.CSharp.BindingDiagnosticBag,System.__Canon>)
0000709D965FE9C0 000070de5963fc14 Microsoft.CodeAnalysis.CSharp.MethodCompiler.BindMethodBody(Microsoft.CodeAnalysis.CSharp.Symbols.MethodSymbol, Microsoft.CodeAnalysis.CSharp.TypeCompilationState, Microsoft.CodeAnalysis.CSharp.BindingDiagnosticBag, Boolean, Microsoft.CodeAnalysis.CSharp.BoundNode, Boolean, Microsoft.CodeAnalysis.CSharp.ImportChain ByRef, Boolean ByRef, Boolean ByRef, InitialState ByRef)
0000709D965FED80 000070de5963d82f Microsoft.CodeAnalysis.CSharp.MethodCompiler.CompileMethod(Microsoft.CodeAnalysis.CSharp.Symbols.MethodSymbol, Int32, ProcessedFieldInitializers ByRef, Microsoft.CodeAnalysis.CSharp.SynthesizedSubmissionFields, Microsoft.CodeAnalysis.CSharp.TypeCompilationState)
0000709D965FF430 000070de596135d7 Microsoft.CodeAnalysis.CSharp.MethodCompiler.CompileNamedType(Microsoft.CodeAnalysis.CSharp.Symbols.NamedTypeSymbol)
0000709D965FF7A0 000070de59612da1 Microsoft.CodeAnalysis.CSharp.MethodCompiler+c__DisplayClass25_0.b__0()
0000709D965FF800 000070de5960f87f Roslyn.Utilities.UICultureUtilities+c__DisplayClass5_0.b__0()
0000709D965FF840 000070de595e423f System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(System.Threading.Thread, System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object) [/_/src/libraries/System.Private.CoreLib/src/System/Threading/ExecutionContext.cs @ 264]
0000709D965FF890 000070de58e0cd98 System.Threading.Tasks.Task.ExecuteWithThreadLocal(System.Threading.Tasks.Task ByRef, System.Threading.Thread) [/_/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs @ 2347]
0000709D965FF910 000070de59542f2b System.Threading.ThreadPoolWorkQueue.Dispatch() [/_/src/libraries/System.Private.CoreLib/src/System/Threading/ThreadPoolWorkQueue.cs @ 1118]
0000709D965FF9A0 000070de550573a1 System.Threading.PortableThreadPool+WorkerThread.WorkerThreadStart() [/_/src/libraries/System.Private.CoreLib/src/System/Threading/PortableThreadPool.WorkerThread.cs @ 126]
0000709D965FFA40 000070de530da844 System.Threading.Thread+StartHelper.RunWorker() [/_/src/libraries/System.Private.CoreLib/src/System/Threading/Thread.cs @ 77]
0000709D965FFC00 000070dec84a0200 [DebuggerU2MCatchHandlerFrame: 0000709d965ffc00] 
0:018> !sos.gcinfo 000070de5af4b63a
entry point 000070DE5AF4B2D0
Normal JIT generated code
GC info 000070DE5B6B1C48
Pointer table:
Prolog size: 68
Security object: <none>
GS cookie: <none>
PSPSym: <none>
Generics inst context: caller.sp-40
PSP slot: <none>
GenericInst slot: caller.sp-40 (GENERIC_PARAM_CONTEXT_THIS)
Varargs: 0
Frame pointer: rbp
Wants Report Only Leaf: 0
Size of parameter area: 18
Return Kind: Scalar
Code size: 675
Untracked: +rbp+18 +rbp+10 +rbp-30 +rbp-38 +rbp-48 +rbp-58 +rbp-60 +rbp-68 +rbp-70 +rbp-78 +rbp-80 +rbp-90 +rbp-a0 +rbp-a8 +rbp-b0 +rbp-b8 +rbp-c8 +rbp-d0
00000044 interruptible
00000048 +rax
00000074 -rax
00000078 +rax
0000007b -rax
000000de +rax
000000f0 +rcx
000000f4 +sp+0
00000104 +sp+8
00000115 +rdi
0000011c +rdx
00000122 -sp+8 -sp+0 -rdi -rdx -rcx -rax
00000126 +rax
0000012a +rdi(interior)
00000131 +rsi
00000136 -rsi -rax -rdi(interior)
0000013d +rax
0000014f -rax
0000017b +rax
0000017e -rax
00000188 +rax
0000018d -rax
000001a4 +rax
000001b0 -rax
000001c3 +rax
000001d5 -rax
00000238 +rax
0000024a +rcx
0000024e +sp+0
0000025e +sp+8
0000026f +rdi
00000276 +rdx
0000027c -sp+8 -sp+0 -rdi -rdx -rcx -rax
00000280 +rax
0000029d +rdi(interior)
000002a1 +rsi
000002a6 -rsi -rax -rdi(interior)
000002be +rax
000002d3 -rax
000002e6 +rax
00000300 -rax
00000304 +rax
00000307 -rax
0000036a +rax
0000037c +rcx
00000380 +sp+0
00000390 +sp+8
000003a1 +rdi
000003a8 +rdx
000003ae -sp+8 -sp+0 -rdi -rdx -rcx -rax
000003b2 +rax
000003cf +rdi(interior)
000003d3 +rsi
000003d8 -rsi -rax -rdi(interior)
000003f0 +rax
00000405 -rax
0000041f +rcx
00000423 +sp+0
00000433 +sp+8
00000448 +rdi
0000044c +rsi
00000450 +rdx
0000045a -sp+8 -sp+0 -rdi -rsi -rdx -rcx
00000463 +rax
00000467 -rax
00000493 +rax
00000496 -rax
0000049f +rax
000004b0 -rax
000004c3 +rax
000004d2 -rax
000004d6 +rax
000004e5 -rax
000004f8 +rax
00000501 -rax
00000509 +rax
00000510 +rsi
00000516 -rsi
0000051f -rax
00000546 +rax
0000054d +rsi
00000553 -rsi
0000055a -rax
00000561 +rax
0000056a -rax
00000577 +rax
00000580 -rax
00000588 +rax
0000058f +rsi
00000595 -rsi
0000059e -rax
000005b1 +rax
000005b8 +rsi
000005be -rsi
000005c5 -rax
000005db +rax
000005e1 -rax
0000060c +rax
00000610 +rdi(interior)
00000614 +rsi
00000619 -rsi -rax -rdi(interior)
0000061f +rax
00000638 -rax
0000063c +rax
00000640 +rdi(interior)
00000644 +rsi
00000649 -rsi -rax -rdi(interior)
0000065e +rax
00000662 +rdi(interior)
00000666 +rsi
0000066b -rsi -rax -rdi(interior)
00000673 not interruptible

What other commands would be useful here?

@MichalPetryka
Copy link
Contributor Author

MichalPetryka commented Nov 30, 2024

Calling constructors multiple time is legal in the ECMA,

Does it explicitly say that it is legal somewhere?

Calling constructors (via call instruction) has been verifiable only when calling object base class constructor or to initialize value type location. It is mentioned in the verification rules for the call instruction in ECMA and ILVerify checks it here. It prohibits re-initialization of an initialized instance by calling a constructor in verifiable code. ECMA does not cover the distinction between legal unverifiable code and invalid code.

I agree that ECMA wording could have been more precise. We can fix via the augments doc if needed

For instance constructors, as far as I can see the ECMA only says that they're instance methods that are used for newobj and doesn't otherwise forbid calling them in any way. However it says this regarding CLS compliance:

CLS Rule 21: An object constructor shall call some instance constructor of its base class before
any access occurs to inherited instance data. (This does not apply to value types, which need not
have constructors.)
CLS Rule 22: An object constructor shall not be called except as part of the creation of an
object, and an object shall not be initialized twice.
[Note:
CLS (consumer): Shall provide syntax for choosing the constructor to be called when an object
is created.
CLS (extender): Shall provide syntax for defining constructor methods with different
signatures. It can issue a compiler error if the constructor does not obey these rules.
CLS (framework): Can assume that object creation includes a call to one of the constructors,
and that no object is initialized twice. System.Object.MemberwiseClone (see Partition IV
Library) and deserialization (including object remoting) shall not run constructors. end note] 

Which says that it's non CLS compliant so one could assume it's only invalid for that and legal otherwise.

For type initializers the ECMA says doesn't forbid it anywhere but says this:

3. A type initializer shall be executed exactly once for any given type, unless explicitly
called by user code. 

which seems to directly suggest that calling them 2nd time explicitly from user code is legal. Since this is already broken with the static readonly optimization, it should definitely be made illegal in an addendum.

@jkotas
Copy link
Member

jkotas commented Dec 1, 2024

What other commands would be useful here?

The unmanaged callstack that you have shared earlier shows that the crash occurs during enumerating of GC root of some thread. You need to find the thread and method that the GC roots are enumerated for, and than switch to that thread in the debugger. I expect that you will find a method with bad GC info that was introduced by your change.

MichalPetryka added a commit to MichalPetryka/runtime that referenced this pull request Dec 3, 2024
Multiple initializations of instances and types might violate runtime invariants, we should forbid it then as discussed in dotnet#109679.

Users are not expected to have been relying on the behaviour being legal, especially since multiple type initializations are already resulting in invalid behaviour due to JIT optimizations.
Copy link
Contributor

Draft Pull Request was automatically closed for 30 days of inactivity. Please let us know if you'd like to reopen it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI 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.

5 participants