KStarbound/lua_glue.c

111 lines
3.5 KiB
C

#include "build/generated/sources/headers/java/main/ru_dbotthepony_kstarbound_lua_LuaJNI.h"
#include "lua-5.3.6/src/lapi.h"
#include "lua-5.3.6/src/lua.h"
#include "lua-5.3.6/src/lauxlib.h"
#include <stdio.h>
static int lua_jniFunc(lua_State *state) {
JNIEnv *env = (JNIEnv *) lua_touserdata(state, lua_upvalueindex(1));
jmethodID callback = (jmethodID) lua_touserdata(state, lua_upvalueindex(2));
jobject* lua_JCClosure = (jobject*) lua_touserdata(state, lua_upvalueindex(3));
jint result = (*env)->CallIntMethod(env, *lua_JCClosure, callback, (long long) state);
if (result <= -1) {
const char* errMsg = lua_tostring(state, -1);
if (errMsg == NULL)
return luaL_error(state, "Internal JVM Error");
return luaL_error(state, "%s", errMsg);
}
return result;
}
static int remove_gc_root(lua_State *state) {
JNIEnv *env = (JNIEnv *) lua_touserdata(state, lua_upvalueindex(1));
jobject* obj = (jobject*) lua_touserdata(state, 1);
if (obj == NULL) {
printf("Lua Glue: remove_gc_root: obj is NULL! This is VERY LIKELY is going to result into a memory leak!\n");
return 0;
}
(*env)->DeleteGlobalRef(env, *obj);
return 0;
}
static JNIEXPORT void JNICALL Java_ru_dbotthepony_kstarbound_lua_LuaJNI_lua_1pushcclosure(JNIEnv *env, jclass interface, jlong luaState, jobject lua_JCClosure) {
lua_State* LluaState = (lua_State*) luaState;
jclass clazz = (*env)->GetObjectClass(env, lua_JCClosure);
if (clazz == NULL)
return;
jmethodID callback = (*env)->GetMethodID(env, clazz, "invoke", "(J)I");
if (callback == NULL)
return;
lua_pushlightuserdata(LluaState, env);
lua_pushlightuserdata(LluaState, callback);
void *umemory = lua_newuserdata(LluaState, sizeof(jobject));
jobject* rawBlock = (jobject*) umemory;
*rawBlock = (*env)->NewGlobalRef(env, lua_JCClosure);
int userdataIndex = lua_gettop(LluaState);
// local table = {}
lua_createtable(LluaState, 0, 1);
int tableIndex = lua_gettop(LluaState);
// function()
lua_pushlightuserdata(LluaState, env);
lua_pushcclosure(LluaState, remove_gc_root, 1);
// table.__gc = fn
lua_setfield(LluaState, tableIndex, "__gc");
// setmetatable(userdata, table)
lua_setmetatable(LluaState, userdataIndex);
lua_pushcclosure(LluaState, lua_jniFunc, 3);
}
// pushes Java object to Lua state, creating new GC root
// Created reference is full userdata, hence it can have metatables attached to it
// IT IS EXPECTED that before pushing object, at top of stack there is a table which is to be attached as metatable to newly created object
// After this function returns, freshly created userdata will replace metatable
static JNIEXPORT void JNICALL Java_ru_dbotthepony_kstarbound_lua_LuaJNI_lua_1pushjobject(JNIEnv *env, jclass interface, jlong luaState, jobject obj) {
lua_State* LluaState = (lua_State*) luaState;
jobject *umemory = (jobject *) lua_newuserdata(LluaState, sizeof(jobject));
*umemory = (*env)->NewGlobalRef(env, obj);
lua_pushlightuserdata(LluaState, env);
lua_pushcclosure(LluaState, remove_gc_root, 1);
lua_setfield(LluaState, -3, "__gc");
lua_pushnil(LluaState);
lua_copy(LluaState, -3, -1);
lua_setmetatable(LluaState, -2);
lua_copy(LluaState, -1, -2);
lua_settop(LluaState, -2);
}
// returns NULL if index is invalid or doesn't contain userdata
static JNIEXPORT jobject JNICALL Java_ru_dbotthepony_kstarbound_lua_LuaJNI_lua_1tojobject(JNIEnv *env, jclass interface, jlong luaState, jint stackIndex) {
lua_State* LluaState = (lua_State*) luaState;
jobject *data = lua_touserdata(LluaState, stackIndex);
if (data == NULL)
return NULL;
return *data;
}