ffi #jni_main: Alias.new(args) constructor dispatch via JNI NewObject

Adds the constructor-invocation arm of the foreign-class DSL:
`SurfaceView.new(ctx)` (where `SurfaceView` is a `#foreign #jni_class`
with `static new :: (ctx: *Context) -> *Self;`) lowers to
`FindClass(env, "android/view/SurfaceView") + GetMethodID(env, cls,
"<init>", "(args)V") + NewObject(env, cls, mid, args...)`. Returns
the fresh jobject.

  - inst.zig: `JniMsgSend.is_constructor` flag + `parent_class_path`
    re-purposed to carry the class being constructed (alongside its
    existing nonvirtual-super-class use). Mutually exclusive with
    `is_static` / `is_nonvirtual`.
  - lower.zig: `lowerCall.field_access` arm now recognises
    `Alias.method(args)` where `Alias` resolves in `foreign_class_map`
    and the matching member is `static`. `new` routes to a new
    `lowerForeignStaticCall` that derives a `(args)V` JNI descriptor
    and emits a `JniMsgSend` with `is_constructor=true`. Non-`new`
    static calls report a clear "use #jni_static_call" diagnostic
    until that sugar lands.
  - emit_llvm.zig: new `NewObject` vtable slot (28) + `emitJniConstructor`
    helper expanding the FindClass+GetMethodID+NewObject chain. The
    jni_msg_send arm short-circuits to it when `is_constructor` is set.

Smoke `ffi-jni-main-03-ctor.sx` exercises both this slice and the
previous super-dispatch slice in a single `onCreate` body: calls
`super.onCreate(b)` then constructs a `SurfaceView` with the Activity
as Context. IR shows the expected six-stage chain (FindClass+GetMethodID+
CallNonvirtual + FindClass+GetMethodID+NewObject); APK builds clean.

Naming caveat: the Java type `android.content.Context` clashes with
sx stdlib's `Context :: struct {...}` (heap-context). The smoke aliases
it `JContext` — future work could add a path-prefix or `as` rename
form on `#jni_class` to avoid the manual rename.

133 host / 6 cross / zig build test all green.
This commit is contained in:
agra
2026-05-20 17:14:51 +03:00
parent 36f40057f7
commit c02b6b3b1b
7 changed files with 202 additions and 3 deletions

View File

@@ -0,0 +1,30 @@
// `Alias.new(args)` constructor dispatch on a `#foreign #jni_class`
// (chess-on-Pixel migration, R.6). The sx-side `static new :: (...) ->
// *Self;` member lowers to JNI `FindClass + GetMethodID("<init>", sig)
// + NewObject(env, clazz, mid, args...)`.
//
// This smoke instantiates a `SurfaceView` from inside the Activity's
// `onCreate` body — chess's render surface starts the same way.
#import "modules/std.sx";
#import "modules/compiler.sx";
Bundle :: #foreign #jni_class("android/os/Bundle") { }
JContext :: #foreign #jni_class("android/content/Context") { }
SurfaceView :: #foreign #jni_class("android/view/SurfaceView") {
static new :: (ctx: *JContext) -> *Self;
}
g_held_view : *void = null;
SxApp :: #jni_main #jni_class("co/swipelab/sxjnictor/SxApp") {
onCreate :: (self: *Self, b: *Bundle) {
super.onCreate(b);
ctx : *JContext = xx self; // Activity IS a JContext (extends JContext).
view := SurfaceView.new(ctx);
g_held_view = xx view; // keep alive so LLVM doesn't DCE the construction.
}
}
main :: () -> s32 { 0; }