cocos2dx LuaJavaBridge解析


#include "CCLuaJavaBridge.h"
#include "platform/android/jni/JniHelper.h"
#include <android/log.h>
#include "base/ccUTF8.h"

#define  LOG_TAG    "luajc"
#define  LOGD(...)  __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__)

extern "C" {
#include "tolua_fix.h"
}

LuaJavaBridge::CallInfo::~CallInfo(void)
{
	if (m_returnType == TypeString && m_ret.stringValue)
	{
		delete m_ret.stringValue;
	}
}

bool LuaJavaBridge::CallInfo::execute(void)
{
	switch (m_returnType)
    {
        case TypeVoid:
            m_env->CallStaticVoidMethod(m_classID, m_methodID);
            break;

        case TypeInteger:
            m_ret.intValue = m_env->CallStaticIntMethod(m_classID, m_methodID);
            break;

        case TypeFloat:
            m_ret.floatValue = m_env->CallStaticFloatMethod(m_classID, m_methodID);
            break;

        case TypeBoolean:
            m_ret.boolValue = m_env->CallStaticBooleanMethod(m_classID, m_methodID);
            break;

        case TypeString:
            m_retjs = (jstring)m_env->CallStaticObjectMethod(m_classID, m_methodID);
            std::string strValue = cocos2d::StringUtils::getStringUTFCharsJNI(m_env, m_retjs);
            m_ret.stringValue = new string(strValue);
           break;
    }

	if (m_env->ExceptionCheck() == JNI_TRUE)
	{
		m_env->ExceptionDescribe();
		m_env->ExceptionClear();
		m_error = LUAJ_ERR_EXCEPTION_OCCURRED;
		return false;
	}

	return true;
}


bool LuaJavaBridge::CallInfo::executeWithArgs(jvalue *args)
{
    switch (m_returnType)
     {
         case TypeVoid:
             m_env->CallStaticVoidMethodA(m_classID, m_methodID, args);
             break;

         case TypeInteger:
             m_ret.intValue = m_env->CallStaticIntMethodA(m_classID, m_methodID, args);
             break;

         case TypeFloat:
             m_ret.floatValue = m_env->CallStaticFloatMethodA(m_classID, m_methodID, args);
             break;

         case TypeBoolean:
             m_ret.boolValue = m_env->CallStaticBooleanMethodA(m_classID, m_methodID, args);
             break;

         case TypeString:
        	 m_retjs = (jstring)m_env->CallStaticObjectMethodA(m_classID, m_methodID, args);
            std::string strValue = cocos2d::StringUtils::getStringUTFCharsJNI(m_env, m_retjs);
            m_ret.stringValue = new string(strValue);
            break;
     }

	if (m_env->ExceptionCheck() == JNI_TRUE)
	{
		m_env->ExceptionDescribe();
		m_env->ExceptionClear();
		m_error = LUAJ_ERR_EXCEPTION_OCCURRED;
		return false;
	}

	return true;
}

int LuaJavaBridge::CallInfo::pushReturnValue(lua_State *L)
{
	if (m_error != LUAJ_ERR_OK)
	{
		lua_pushinteger(L, m_error);
		return 1;
	}

	switch (m_returnType)
	{
		case TypeInteger:
			lua_pushinteger(L, m_ret.intValue);
			return 1;
		case TypeFloat:
			lua_pushnumber(L, m_ret.floatValue);
			return 1;
		case TypeBoolean:
			lua_pushboolean(L, m_ret.boolValue);
			return 1;
		case TypeString:
			lua_pushstring(L, m_ret.stringValue->c_str());
			return 1;
	}

	return 0;
}

/*
确认方法的参数,解析参数中类型
将其转换为java认可的类型存入m_argumentsType和m_returnType中
*/
bool LuaJavaBridge::CallInfo::validateMethodSig(void)
{
    //获取方法参数的长度
    //最小的方法是"()V",如果不满足则认为传参错误
    size_t len = m_methodSig.length();
    if (len < 3 || m_methodSig[0] != '(') // min sig is "()V"
    {
    	m_error = LUAJ_ERR_INVALID_SIGNATURES;
    	return false;
	}

    size_t pos = 1;//访问字符串的位置
    //下面这个循环是解析lua往java方向传入的参数类型
    while (pos < len && m_methodSig[pos] != ')')
    {
    	LuaJavaBridge::ValueType type = checkType(m_methodSig, &pos);
    	if (type == TypeInvalid) return false;

		m_argumentsCount++;
        //将兑换以后的类型存起来
		m_argumentsType.push_back(type);
        pos++;
    }

    if (pos >= len || m_methodSig[pos] != ')')
	{
    	m_error = LUAJ_ERR_INVALID_SIGNATURES;
    	return false;
	}

    pos++;
    //获取java向lua端的参数类型
    m_returnType = checkType(m_methodSig, &pos);
    return true;
}

/*
检查类型
我们在lua端往java端传值的类型如下:
I:--------------------》TypeInteger
F:--------------------》TypeFloat
Z:--------------------》TypeBoolean
V:--------------------》TypeVoid
Ljava/lang/String;----》TypeString
Ljava/util/Vector;----》TypeVector
本函数从lua函数以后会按照上面提到的类型进行兑换
*/
LuaJavaBridge::ValueType LuaJavaBridge::CallInfo::checkType(const string& sig, size_t *pos)
{
    switch (sig[*pos])
    {
        case 'I':
            return TypeInteger;//整形
        case 'F':
            return TypeFloat;//浮点型
        case 'Z':
            return TypeBoolean;//bool值
        case 'V':
        	return TypeVoid;//空值
        case 'L':
            size_t pos2 = sig.find_first_of(';', *pos + 1);
            if (pos2 == string::npos)
            {
                m_error = LUAJ_ERR_INVALID_SIGNATURES;
                return TypeInvalid;
            }

            const string t = sig.substr(*pos, pos2 - *pos + 1);
            if (t.compare("Ljava/lang/String;") == 0)
            {
            	*pos = pos2;
                return TypeString;
            }
            else if (t.compare("Ljava/util/Vector;") == 0)
            {
            	*pos = pos2;
                return TypeVector;
            }
            else
            {
            	m_error = LUAJ_ERR_TYPE_NOT_SUPPORT;
                return TypeInvalid;
            }
    }

    m_error = LUAJ_ERR_TYPE_NOT_SUPPORT;
    return TypeInvalid;
}

/*
获取方法的信息
m_classID :
m_methodID :
m_env :
*/
bool LuaJavaBridge::CallInfo::getMethodInfo(void)
{
    m_methodID = 0;
    m_env = 0;

    JavaVM* jvm = cocos2d::JniHelper::getJavaVM();
    jint ret = jvm->GetEnv((void**)&m_env, JNI_VERSION_1_4);
    switch (ret) {
        case JNI_OK:
            break;

        case JNI_EDETACHED :
            if (jvm->AttachCurrentThread(&m_env, NULL) < 0)
            {
                LOGD("%s", "Failed to get the environment using AttachCurrentThread()");
                m_error = LUAJ_ERR_VM_THREAD_DETACHED;
                return false;
            }
            break;

        case JNI_EVERSION :
        default :
            LOGD("%s", "Failed to get the environment using GetEnv()");
            m_error = LUAJ_ERR_VM_FAILURE;
            return false;
    }
    jstring _jstrClassName = m_env->NewStringUTF(m_className.c_str());
    m_classID = (jclass) m_env->CallObjectMethod(cocos2d::JniHelper::classloader,
                                                   cocos2d::JniHelper::loadclassMethod_methodID,
                                                   _jstrClassName);

    if (NULL == m_classID) {
        LOGD("Classloader failed to find class of %s", m_className.c_str());
    }

    m_env->DeleteLocalRef(_jstrClassName);
    m_methodID = m_env->GetStaticMethodID(m_classID, m_methodName.c_str(), m_methodSig.c_str());
    if (!m_methodID)
    {
        m_env->ExceptionClear();
        LOGD("Failed to find method id of %s.%s %s",
                m_className.c_str(),
                m_methodName.c_str(),
                m_methodSig.c_str());
        m_error = LUAJ_ERR_METHOD_NOT_FOUND;
        return false;
    }

    return true;
}

/* ---------------------------------------- */

lua_State *LuaJavaBridge::s_luaState = NULL;
int LuaJavaBridge::s_newFunctionId = 0;

void LuaJavaBridge::luaopen_luaj(lua_State *L)
{
	s_luaState = L;
    lua_newtable(L);
    lua_pushstring(L, "callStaticMethod");
    lua_pushcfunction(L, LuaJavaBridge::callJavaStaticMethod);
    lua_rawset(L, -3);
    lua_setglobal(L, "LuaJavaBridge");
}

/*
args:
    const char *className
    const char *methodName
    LUA_TABLE   args
    const char *sig
*/
int LuaJavaBridge::callJavaStaticMethod(lua_State *L)
{
    if (!lua_isstring(L, -4) || !lua_isstring(L, -3)  || !lua_istable(L, -2) || !lua_isstring(L, -1))
    {
    	lua_pushboolean(L, 0);
    	lua_pushinteger(L, LUAJ_ERR_INVALID_SIGNATURES);
    	return 2;
    }

    LOGD("%s", "LuaJavaBridge::callJavaStaticMethod(lua_State *L)");
    /*
        虚拟机在执行下面这句话的时候,会依次向栈中push参数(函数首地址,className,javaMethodName,args,sigs)
        luaj.callStaticMethod(className,javaMethodName,args,sigs)
        此时栈中的元素分布如下
        L->top  -----> null
        L->top-1-----> methodSig
        L->top-2-----> args
        L->top-3-----> methodName
        L->top-4-----> className
        L->base -----> callJavaStaticMethod(函数的首地址)
    */

    const char *className  = lua_tostring(L, -4);
    const char *methodName = lua_tostring(L, -3);
    const char *methodSig  = lua_tostring(L, -1);
    
    //生成一个call对象
    //CallInfo这个类被包含在LuaJavaBridge中用于处理数据
    //除此之外LuaJavaBridge包含的方法全是静态方法
    CallInfo call(className, methodName, methodSig);

    // check args 弹出栈顶元素methodSig
    // 弹出以后 栈顶元素指向了args
    lua_pop(L, 1);
    

    /*
       下面这个函数其实就是取出args中的参数,并且将他们全部入栈
       最后返回table元素的个数
    */													/* L: args */
    int count = fetchArrayElements(L, -1);                      	/* L: args e1 e2 e3 e4 ... */

    jvalue *args = NULL;
    if (count > 0)
    {
	    args = new jvalue[count];
        //遍历所有args的参数
	    for (int i = 0; i < count; ++i)
	    {
            //参数是正着入栈的
            //取得时候反着来,这样和之前传参的时候一一对应
	        int index = -count + i;
            /*
               call.argumentTypeAtIndex(i)
               这个方法是去获取参数的类型
            */
	        switch (call.argumentTypeAtIndex(i))
	        {
	            case TypeInteger:
	            	if (lua_isfunction(L, index))
	            	{
	                    args[i].i = retainLuaFunction(L, index, NULL);
	            	}
	            	else
	            	{
	            		args[i].i = (int)lua_tonumber(L, index);
	            	}
	                break;

	            case TypeFloat:
	                args[i].f = lua_tonumber(L, index);
	                break;

	            case TypeBoolean:
	                args[i].z = lua_toboolean(L, index) != 0 ? JNI_TRUE : JNI_FALSE;
	                break;

	            case TypeString:
	            default:
	                args[i].l = call.getEnv()->NewStringUTF(lua_tostring(L, index));
	                break;
	        }
	    }
        //从栈中弹出所有的参数
	    lua_pop(L, count);                               			/* L: args */
    }

    bool success = args ? call.executeWithArgs(args) : call.execute();
    if (args) delete []args;

    if (!success)
    {
    	LOGD("LuaJavaBridge::callJavaStaticMethod(\"%s\", \"%s\", args, \"%s\") EXECUTE FAILURE, ERROR CODE: %d",
    			className, methodName, methodSig, call.getErrorCode());

    	lua_pushboolean(L, 0);
    	lua_pushinteger(L, call.getErrorCode());
    	return 2;
    }

	LOGD("LuaJavaBridge::callJavaStaticMethod(\"%s\", \"%s\", args, \"%s\") SUCCESS",
			className, methodName, methodSig);

	lua_pushboolean(L, 1);
	return 1 + call.pushReturnValue(L);
}

// increase lua function reference counter, return counter
int LuaJavaBridge::retainLuaFunctionById(int functionId)
{
    lua_State *L = s_luaState;

    lua_pushstring(L, LUAJ_REGISTRY_RETAIN);                    /* L: key */
    lua_rawget(L, LUA_REGISTRYINDEX);                           /* L: id_r */
    if (!lua_istable(L, -1))
    {
        lua_pop(L, 1);
        return 0;
    }

    // get counter
    lua_pushinteger(L, functionId);                             /* L: id_r id */
    lua_rawget(L, -2);                                          /* L: id_r r */
    if (lua_type(L, -1) != LUA_TNUMBER)
    {
        lua_pop(L, 2);
        return 0;
    }

    // increase counter
    int retainCount = lua_tonumber(L, -1);
    retainCount++;
    lua_pop(L, 1);                                              /* L: id_r */
    lua_pushinteger(L, functionId);                             /* L: id_r id */
    lua_pushinteger(L, retainCount);                            /* L: id_r id r */
    lua_rawset(L, -3);                            /* id_r[id] = r, L: id_r */
    lua_pop(L, 1);

    LOGD("luajretainLuaFunctionById(%d) - retain count = %d", functionId, retainCount);

    return retainCount;
}

// decrease lua function reference counter, return counter
int LuaJavaBridge::releaseLuaFunctionById(int functionId)
{
    lua_State *L = s_luaState;
                                                                /* L: */
    lua_pushstring(L, LUAJ_REGISTRY_FUNCTION);                  /* L: key */
    lua_rawget(L, LUA_REGISTRYINDEX);                           /* L: f_id */
    if (!lua_istable(L, -1))
    {
        lua_pop(L, 1);
        LOGD("%s", "luajreleaseLuaFunctionById() - LUAJ_REGISTRY_FUNCTION not exists");
        return 0;
    }

    lua_pushstring(L, LUAJ_REGISTRY_RETAIN);                    /* L: f_id key */
    lua_rawget(L, LUA_REGISTRYINDEX);                           /* L: f_id id_r */
    if (!lua_istable(L, -1))
    {
        lua_pop(L, 2);
        LOGD("%s", "luajreleaseLuaFunctionById() - LUAJ_REGISTRY_RETAIN not exists");
        return 0;
    }

    lua_pushinteger(L, functionId);                             /* L: f_id id_r id */
    lua_rawget(L, -2);                                          /* L: f_id id_r r */
    if (lua_type(L, -1) != LUA_TNUMBER)
    {
        lua_pop(L, 3);
        LOGD("luajreleaseLuaFunctionById() - function id %d not found", functionId);
        return 0;
    }

    int retainCount = lua_tonumber(L, -1);
    retainCount--;

    if (retainCount > 0)
    {
        // update counter
        lua_pop(L, 1);                                          /* L: f_id id_r */
        lua_pushinteger(L, functionId);                         /* L: f_id id_r id */
        lua_pushinteger(L, retainCount);                        /* L: f_id id_r id r */
        lua_rawset(L, -3);                        /* id_r[id] = r, L: f_id id_r */
        lua_pop(L, 2);
        LOGD("luajreleaseLuaFunctionById() - function id %d retain count = %d", functionId, retainCount);
        return retainCount;
    }

    // remove lua function reference
    lua_pop(L, 1);                                              /* L: f_id id_r */
    lua_pushinteger(L, functionId);                             /* L: f_id id_r id */
    lua_pushnil(L);                                             /* L: f_id id_r id nil */
    lua_rawset(L, -3);                          /* id_r[id] = nil, L: f_id id_r */

    lua_pop(L, 1);                                              /* L: f_id */
    lua_pushnil(L);                                             /* L: f_id nil */
    while (lua_next(L, -2) != 0)                                /* L: f_id f id */
    {
        int value = lua_tonumber(L, -1);
        lua_pop(L, 1);                                          /* L: f_id f */
        if (value == functionId)
        {
            lua_pushnil(L);                                     /* L: f_id f nil */
            lua_rawset(L, -3);                   /* f_id[f] = nil, L: f_id */
            break;
        }
    }                                                           /* L: f_id */

    lua_pop(L, 1);
    LOGD("luajreleaseLuaFunctionById() - function id %d released", functionId);
    return 0;
}

int LuaJavaBridge::callLuaFunctionById(int functionId, const char *arg)
{
    lua_State *L = s_luaState;
    int top = lua_gettop(L);
                                                                /* L: */
    lua_pushstring(L, LUAJ_REGISTRY_FUNCTION);                  /* L: key */
    lua_rawget(L, LUA_REGISTRYINDEX);                           /* L: f_id */
    if (!lua_istable(L, -1))
    {
        lua_pop(L, 1);
        return -1;
    }

    lua_pushnil(L); 
    /*
    L->top    null
    L->top-1  nil
    L->top-2  G(L)->l_registry[LUAJ_REGISTRY_FUNCTION]
    ...
    */ 
    //寻找G(L)->l_registry[LUAJ_REGISTRY_FUNCTION]它的所有(key value)
                                                 /* L: f_id nil */
    while (lua_next(L, -2) != 0)                                /* L: f_id f id */
    {
         /*
        L->top    null
        L->top-1  value
        L->top-2  下一次寻找的key
        L->top-3  G(L)->l_registry[LUAJ_REGISTRY_FUNCTION]
        ...
        */ 
        int value = lua_tonumber(L, -1);
        lua_pop(L, 1);                                          /* L: f_id f */
         /*
        L->top    null
        L->top-1  下一次寻找的key
        L->top-2  G(L)->l_registry[LUAJ_REGISTRY_FUNCTION]
        ...
        */ 
        if (value == functionId)
        {
            lua_pushstring(L, arg);                             /* L: f_id f arg */
            int ok = lua_pcall(L, 1, 1, 0);                     /* L: f_id ret|err */
            int ret;
            if (ok == 0)
            {
                ret = lua_tonumber(L, -1);
            }
            else
            {
                ret = -ok;
            }

            lua_settop(L, top);
            return ret;
        }
    }                                                           /* L: f_id */

    lua_settop(L, top);
    return -1;
}

// call lua global function
int LuaJavaBridge::callLuaGlobalFunction(const char *functionName, const char *arg)
{
    lua_State *L = s_luaState;

    int ret = -1;
    int top = lua_gettop(L);

    lua_getglobal(L, functionName);
    if (lua_isfunction(L, -1))
    {
        lua_pushstring(L, arg);
        int ok = lua_pcall(L, 1, 1, 0);
        if (ok == 0)
        {
            ret = lua_tonumber(L, -1);
        }
        else
        {
            ret = -ok;
        }
    }

    lua_settop(L, top);
    return ret;
}

// ----------------------------------------

// increase lua function reference counter, return functionId
/*
下面的函数的意思就是要把luaFunc注册到G(L)->l_registry[LUAJ_REGISTRY_FUNCTION]中
并且对于同样一个函数记录它注册的次数
G(L)->l_registry[LUAJ_REGISTRY_FUNCTION][luaFunc] = functionId
G(L)->l_registry[LUAJ_REGISTRY_RETAIN][functionId] = retainCount
*/
int LuaJavaBridge::retainLuaFunction(lua_State *L, int functionIndex, int *retainCountReturn)
{
    /*
    压如一个字符串LUAJ_REGISTRY_FUNCTION  栈的高度加1
    *1                                                            /* L: f ... */
    lua_pushstring(L, LUAJ_REGISTRY_FUNCTION);                  /* L: f ... key */
    /*
    将G(L)->l_registry[LUAJ_REGISTRY_FUNCTION]放到栈顶 栈的大小不变
    */
    lua_rawget(L, LUA_REGISTRYINDEX);                           /* L: f ... f_id */
    if (!lua_istable(L, -1))
    {
        /*
        如果栈顶不是table 则弹出栈顶元素 
        */
        lua_pop(L, 1);
        //压入一个table
        lua_newtable(L);
        //压入一个字符串
        lua_pushstring(L, LUAJ_REGISTRY_FUNCTION);
        //将table放到栈顶
        lua_pushvalue(L, -2);
        /*
        此时栈中情况如下
        L->top    null
        L->top-1  table
        L->top-2  LUAJ_REGISTRY_FUNCTION
        L->top-3  table
        ...
        */
        //下面这句话
        // G(L)->l_registry[LUAJ_REGISTRY_FUNCTION] = table
        lua_rawset(L, LUA_REGISTRYINDEX);
        /*
            此时栈中的情况是
            L->top 
            L->top-1 G(L)->l_registry[LUAJ_REGISTRY_FUNCTION]
        */
    }

    lua_pushstring(L, LUAJ_REGISTRY_RETAIN);                    /* L: f ... f_id key */
    lua_rawget(L, LUA_REGISTRYINDEX);                           /* L: f ... f_id id_r */
    if (!lua_istable(L, -1))
    {
        lua_pop(L, 1);
        lua_newtable(L);
        lua_pushstring(L, LUAJ_REGISTRY_RETAIN);
        lua_pushvalue(L, -2);
        //G(L)->l_registry[LUAJ_REGISTRY_RETAIN] = table
        lua_rawset(L, LUA_REGISTRYINDEX);
    }



    // get function id
    //经过上面两个操作以后栈的高度加了2
    /*
       L->top null
       L->top-1 G(L)->l_registry[LUAJ_REGISTRY_RETAIN]
       L->top-2 G(L)->l_registry[LUAJ_REGISTRY_FUNCTION]
       下面栈的内容就和刚进来的时候一样了
       所以此处获取函数的时候,将之前的索引-2
       将目标函数放到栈顶(L->top-1)位置,栈高度加一
    */
    lua_pushvalue(L, functionIndex - 2);                        /* L: f ... f_id id_r f */
    /*
    此时栈中的内容
    L->top null
    L->top-1 luaFunc  每一个函数的地址都是唯一的
    L->top-2 G(L)->l_registry[LUAJ_REGISTRY_RETAIN]
    L->top-3 G(L)->l_registry[LUAJ_REGISTRY_FUNCTION]
    下面栈的内容就和刚进来的时候一样了
    */
    lua_rawget(L, -3);                                          /* L: f ... f_id id_r id */
    /*
    此时栈中内容
    L->top null
    L->top-1 G(L)->l_registry[LUAJ_REGISTRY_FUNCTION][luaFunc]
    L->top-2 G(L)->l_registry[LUAJ_REGISTRY_RETAIN]
    L->top-3 G(L)->l_registry[LUAJ_REGISTRY_FUNCTION]
    下面栈的内容就和刚进来的时候一样了
    */

    int functionId;
    if (lua_type(L, -1) != LUA_TNUMBER)
    {
        // first retain, create new id
        lua_pop(L, 1);                                          /* L: f ... f_id id_r */

        s_newFunctionId++;
        functionId = s_newFunctionId;
        /*
           L->top null
           L->top-1 G(L)->l_registry[LUAJ_REGISTRY_RETAIN]
           L->top-2 G(L)->l_registry[LUAJ_REGISTRY_FUNCTION]
           下面栈的内容就和刚进来的时候一样了
           所以此处获取函数的时候,将之前的索引-2
           将目标函数放到栈顶(L->top-1)位置,栈高度加一
       */
        lua_pushvalue(L, functionIndex - 2);                    /* L: f ... f_id id_r f */
        lua_pushinteger(L, functionId);                         /* L: f ... f_id id_r f id */
        /*
           L->top null
           L->top-1 functionId
           L->top-2 luaFunc
           L->top-3 G(L)->l_registry[LUAJ_REGISTRY_RETAIN]
           L->top-4 G(L)->l_registry[LUAJ_REGISTRY_FUNCTION]
           下面栈的内容就和刚进来的时候一样了
        */
        //G(L)->l_registry[LUAJ_REGISTRY_FUNCTION][luaFunc] = functionId
        //栈的高度-2
        lua_rawset(L, -4);                        /* f_id[f] = id, L: f ... f_id id_r */
        /*
           L->top null
           L->top-1 G(L)->l_registry[LUAJ_REGISTRY_RETAIN]
           L->top-2 G(L)->l_registry[LUAJ_REGISTRY_FUNCTION]
           下面栈的内容就和刚进来的时候一样了
       */
        lua_pushinteger(L, functionId);                         /* L: f ... f_id id_r id */
        /*
           L->top null
           L->top-1 functionId
           L->top-2 G(L)->l_registry[LUAJ_REGISTRY_RETAIN]
           L->top-3 G(L)->l_registry[LUAJ_REGISTRY_FUNCTION]
           下面栈的内容就和刚进来的时候一样了
       */
    }
    else
    {
        functionId = lua_tonumber(L, -1);
        /*
           L->top null
           L->top-1 functionId
           L->top-2 G(L)->l_registry[LUAJ_REGISTRY_RETAIN]
           L->top-3 G(L)->l_registry[LUAJ_REGISTRY_FUNCTION]
           下面栈的内容就和刚进来的时候一样了
       */
    }

    // get function retain
    lua_pushvalue(L, -1);                                       /* L: f ... f_id id_r id id */
    /*
       L->top null
       L->top-1 functionId
       L->top-2 functionId
       L->top-3 G(L)->l_registry[LUAJ_REGISTRY_RETAIN]
       L->top-4 G(L)->l_registry[LUAJ_REGISTRY_FUNCTION]
       下面栈的内容就和刚进来的时候一样了
    */
    lua_rawget(L, -3);                                          /* L: f ... f_id id_r id r */
    /*
       L->top null
       L->top-1 G(L)->l_registry[LUAJ_REGISTRY_RETAIN][functionId]
       L->top-2 functionId
       L->top-3 G(L)->l_registry[LUAJ_REGISTRY_RETAIN]
       L->top-4 G(L)->l_registry[LUAJ_REGISTRY_FUNCTION]
       下面栈的内容就和刚进来的时候一样了
    */
    int retainCount = 1;
    if (lua_type(L, -1) != LUA_TNUMBER)
    {
        // first retain, set retain count = 1
        lua_pop(L, 1);
        lua_pushinteger(L, retainCount);
        /*
           L->top null
           L->top-1 retainCount
           L->top-2 functionId
           L->top-3 G(L)->l_registry[LUAJ_REGISTRY_RETAIN]
           L->top-4 G(L)->l_registry[LUAJ_REGISTRY_FUNCTION]
           下面栈的内容就和刚进来的时候一样了
       */
    }
    else
    {
        // add retain count
        retainCount = lua_tonumber(L, -1);
        retainCount++;
        lua_pop(L, 1);
        lua_pushinteger(L, retainCount);
    }
    //G(L)->l_registry[LUAJ_REGISTRY_RETAIN][functionId] = retainCount
    lua_rawset(L, -3);                            /* id_r[id] = r, L: f ... f_id id_r */
    /*
       L->top null
       L->top-1 G(L)->l_registry[LUAJ_REGISTRY_RETAIN]
       L->top-2 G(L)->l_registry[LUAJ_REGISTRY_FUNCTION]
       下面栈的内容就和刚进来的时候一样了
    */

    lua_pop(L, 2);                                              /* L: f ... */

    /*
       最终栈的内容和刚进来一样
       L->top null
       下面栈的内容就和刚进来的时候一样了
    */


    if (retainCountReturn) *retainCountReturn = retainCount;
    return functionId;
}

//取出数组元素
//取出栈中指定索引index的table,并且把这个table的所有value值全部入栈
int LuaJavaBridge::fetchArrayElements(lua_State *L, int index)
{
    int count = 0;
    do
    {
        /*
          取出栈中指定位置的table,并且把它的table指定位置的value入栈
          所以栈的大小会不断加大,要想获取最原始的table,需要调整索引(index - count)
          而table的值则是默认自增取(1,2,3...n)
        */
        lua_rawgeti(L, index - count, count + 1);
        if (lua_isnil(L, -1))
        {
            //如果判断栈顶元素为空,说明取完了啊,弹出这个空值
            lua_pop(L, 1);
            break;
        }
        ++count;
    } while (1);
    return count;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值