-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Description
Type of issue
Missing information
Description
In the documentation of constrained opcode, it says for constrained.thisType callvirt.method:
- The following should have been pushed onto the evaluation stack, in order:
ptr, managed pointer tothisType; thenarg1toargNof the arguments tomethod. - If
thisTypeis reference type, thenptris dereferenced and passed asthistomethod. - If
thisTypeis value type and implementsmethod, thenptris passed asthistomethod. - If
thisTypeis value type and does not implementmethod(fromObject,ValueType,Enum, or aninterfacewith default implementation), thenptris dereferenced, boxed, and passed asthistomethod.
From the text, it is unclear when ptr is dereferenced (and the referent potentially boxed):
- Is it dereferenced when it is pushed onto the evaluation stack?
- Note that this choice is easily possible, thanks to conservative verification rules and generics sharing rules --- pushing of
ptrandconstrained. callvirt.must appear in the method body of a single method and generics are not shared for different value types, which allows JIT to know whetherptris eventually dereferenced when compiling each (shared) instantiation of a method.
- Note that this choice is easily possible, thanks to conservative verification rules and generics sharing rules --- pushing of
- Is it dereferenced at the point of
constrained. callvirt.?
The two options are not equivalent, because the referent of ptr could be changed after ptr has been pushed before reaching constrained. callvirt..
- If
thisTypeis reference type, this could change thethisinsidemethod. - If
thisTypeis value type and implementsmethod, there is no difference. - If
thisTypeis value type and does not implementmethod, this could change what value is being boxed before enteringmethod.
After some simple testing, I found on Windows 11 version 25H2, x64, .NET 10.0:
- If
thisTypeis reference type, thenptris dereferenced when it's pushed, which could be long beforeconstrained. callvirt.. - If
thisTypeis value type and does not implementmethod, thenptris dereferenced and boxed atconstrained. callvirt., which could be long after it's pushed.
Note that the timings of dereference are different for value types (not implementing method) and reference types.
The most typical use of constrained. callvirt. is C# generics, so naturally this behavior should easily enable C# spec 12.6.6.1 semantics. (Which, unfortunately, is also unclear on the timing of reading from a variable...)
Page URL
Content source URL
https://github.com/dotnet/dotnet-api-docs/blob/main/xml/System.Reflection.Emit/OpCodes.xml
Document Version Independent Id
9831712a-63bd-b93d-be05-0535facb360a
Platform Id
530be95c-469c-3b4c-3a24-431f3aa53d66