Open lambdageek opened 1 month ago
Tagging subscribers to this area: @steveisok, @lambdageek See info in area-owners.md if you want to be subscribed.
FYI @BrzVlad
Not sure if we need to fix this right away or not. Since C# function pointers are unsafe
, it seems like these kinds of mixed mode scenarios might be rare. Also it seems like "llvmonly" mixed mode wouldn't have a problem.
If we can't think of a way to fix the problem without sacrificing efficiency in AOT code, it would be nice to at least detect that something has gone wrong and throw an ExecutionEngineException
rather than having a native crash.
For targets that can JIT (Android, browser WASM), we could manufacture real ftn ptrs (trampolines?) on demand for interp code and use ftn ptrs everywhere, I think. I don't know what we'd do on iOS and WASI.
use ftn ptrs everywhere
the problem is that we'd then repeatedly enter/exit the interpreter (growing/shrinking the native stack). Currently the interpreter tries to be non-recursive and just manipulates InterpFrames
in a loop.
use ftn ptrs everywhere
the problem is that we'd then repeatedly enter/exit the interpreter (growing/shrinking the native stack). Currently the interpreter tries to be non-recursive and just manipulates
InterpFrames
in a loop.
we would probably want to attach information to the trampoline that points to the interpmethod... good point though, that's messy.
The IL opcodes
ldftn
/calli
(for methods without an[UnmanagedCallersOnly]
attribute) are compiled differently in mono in some scenarios:ldftn
returns a pointer to native code andcalli
is just an indirect call. (In generic sharing there is a trampoline involved to pass an additional runtime generic context that isn't part of the normal platform calling convention)ldftn
returns aMonoFtnDesc*
structure (used to pair up the code pointer and the rgctx arg and theMonoMethod*
)andcalli
consumes such a thing and invokes the underlying method together with the extra arg).ldftn
returns a (sometimes tagged)InterpMethod*
pointer thatcalli
uses to adjust the interpreter state and enter into the method.MonoFtnDesc*
for interpreted methods too, by also storing anInterpMethod*
in theMonoFtnDesc*
and making a decision about whether the method is AOT or interpreted.The problem is that in a mixed AOT+interp non-"llvmonly" environment, we might use a combination of (1) and (3): for example we might AOT part of the app that includes an API like:
and we might call it from interpreted use code:
The problem is that when we interpret
Program
we will pass anInterpMethod*
toFrameworkMethod
whereas it expects a pointer to executable machine code, resulting in a hard to diagnose crash.The reverse is also possible - we might be doing the
ldftn
in AOTed code (and get back a native code pointer), while thecalli
might be in interpreted code - which will expect anInterpMethod*
.In both cases the result is a crash