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

Unable to use custom metatable to pushed JavaObject #216

Open
dayo05 opened this issue Oct 13, 2024 · 2 comments
Open

Unable to use custom metatable to pushed JavaObject #216

dayo05 opened this issue Oct 13, 2024 · 2 comments

Comments

@dayo05
Copy link
Contributor

dayo05 commented Oct 13, 2024

I am trying to make custom metatable for pushed java object for faster function invoke(compared using reflection) and making some method lua-side private.

I have resolved this using following (kotlin) code:

// initialize
lua.pushJavaObject(Any())
lua.getMetatable(-1)
lua.setGlobal("aris__obj_mt")

// if(lua.getMetaField(-1, "__gc") == 0) throw NoSuchElementException("Cannot retrieve __gc metafield")
// lua.setGlobal("aris__gc_internal")
lua.push { lua ->
    // lua.pushTable(...)
    lua.getGlobal("aris__obj_mt")
    lua.setMetatable(-2)
    lua.getGlobal("aris__obj_mt")
    lua.getField(-2, "__gc")
    lua.pushValue(1)
    println("Before GC Called")
    lua.pCall(1, 0)
    println("After GC Called")
    lua.pop(1)
    0
}
lua.setGlobal("aris__gc")
if(lua.getMetaField(-1, "__newindex") == 0) throw NoSuchElementException("Cannot retrieve __newindex metafield")
lua.setGlobal("aris__newindex")
if(lua.getMetaField(-1, "__eq") == 0) throw NoSuchElementException("Cannot retrieve __eq metafield")
lua.setGlobal("aris__eq")
lua.pop(1)

// create metatable using existing fields of metatables
// ...
// pusing to lua
lua.pushJavaObject(this)
lua.getGlobal("my_metatable")
lua.setMetatable(-2)

There are two major issues on this purpose.
First, It cannot uses .toJavaObject() because it choses whether jclass or jobject using metatable.

I resolved this by temporally replacing the metatable on unpacking like this:

lua.getGlobal("aris__obj_mt")
lua.push(arg[0])
lua.getMetatable(-1)
lua.pushValue(-3)
lua.setMetatable(-3)
val rt = listOf((arg[0].toJavaObject() as /* my class */).method())
lua.setMetatable(-2)
lua.pop(1)
lua.pop(1)

This is a bit dirty but works fine.

The main problem is __gc metamethod throws error. The reason was from this code:

jobject * data = (jobject *) luaL_checkudata(L, 1, R);

It throws error in __gc metamethod (RUNTIME: party.iroiro.luajava.LuaException: no matching method found) in lua5.2 and no error message but coroutine.resume failes on luajit(maybe stackoverflow?).

@dayo05
Copy link
Contributor Author

dayo05 commented Oct 13, 2024

So, I suggest to add lua.unsafeToJavaObject() and lua.unsafeCollectJavaObject() function on JNI side.

Those function will works same with normal function but does not check is it valid.

Or is there any other solution for this?

Thanks

@dayo05
Copy link
Contributor Author

dayo05 commented Oct 16, 2024

I found some issue on my code:

lua.push { lua ->
    // lua.pushTable(...)
    lua.getGlobal("aris__obj_mt")
    lua.setMetatable(-2)
    lua.getGlobal("aris__obj_mt")
    lua.getField(-2, "__gc")
    lua.pushValue(1)
    println("Before GC Called")
    lua.pCall(1, 0)
    println("After GC Called")
    lua.pop(1)
    0
}

in here, I must mention -1 instead of -2 on lua.getField(-2, "__gc"). This fix my major issue but still code looks dirty...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant