ffi 2.16c xfail: omitted env in #jni_call from cross-function helper
A `#jni_call(void)(target, "name", "sig")` inside a helper fn that
isn't lexically inside a `#jni_env` block should fall back to a
thread-local env read populated by the enclosing `#jni_env(env) {
helper(target); }` scope at runtime. Today the lower-side
"jni_env_stack empty" diagnostic gets queued but compilation
continues to emit_llvm, which fails LLVM verification because env
lowers to `Ref.none` (`i64 undef`).
The make-green follow-up:
- Synthesizes a thread-local `@sx_jni_env_tl` global in emit_llvm.
- `#jni_env(env) { body }` emits a `(load TL → saved, store env → TL,
defer store saved → TL)` sequence so the TL tracks the
innermost-scope env and restores correctly on nesting.
- `lowerJniCall`'s omitted-env path falls back to a TL load when
`jni_env_stack` is empty, instead of erroring.
The lexical-direct optimisation from 2.16b stays the fast path —
helpers in the same fn never touch TL. Only cross-fn callees pay
the (cheap) TL load.
This commit is contained in:
37
examples/ffi-jni-env-03-tl-fallback.sx
Normal file
37
examples/ffi-jni-env-03-tl-fallback.sx
Normal file
@@ -0,0 +1,37 @@
|
||||
// Phase 2 step 2.16c (PLAN-FFI.md): xfail then green for the
|
||||
// thread-local env fallback in `#jni_call`. When a `#jni_call` site
|
||||
// has its env arg omitted AND no `#jni_env` block exists in the same
|
||||
// function (e.g., we're in a helper called FROM such a block), the
|
||||
// compiler emits a TL load instead of a sema error.
|
||||
//
|
||||
// The TL is pushed/popped by the `#jni_env(env) { ... }` enclosing
|
||||
// scope at runtime; helpers that don't see the lexical scope still
|
||||
// pick up the env transparently. Cross-function callers no longer
|
||||
// need to thread env as an explicit parameter.
|
||||
//
|
||||
// Today (2.16b only): lowerJniCall errors when env is omitted and
|
||||
// jni_env_stack is empty, because TL emission isn't wired yet.
|
||||
|
||||
#import "modules/std.sx";
|
||||
|
||||
g_should_call : bool = false;
|
||||
|
||||
// Helper fn — no `#jni_env` block in scope. Without TL fallback this
|
||||
// errors because the omitted env can't be resolved.
|
||||
helper :: (target: *void) {
|
||||
#jni_call(void)(target, "noop", "()V");
|
||||
}
|
||||
|
||||
unused :: (env: *void, target: *void) {
|
||||
#jni_env(env) {
|
||||
helper(target);
|
||||
}
|
||||
}
|
||||
|
||||
main :: () -> s32 {
|
||||
if g_should_call {
|
||||
unused(null, null);
|
||||
}
|
||||
print("ok\n");
|
||||
0;
|
||||
}
|
||||
Reference in New Issue
Block a user