Esempio n. 1
0
/*
 * Static methods use the lsr_method closure which is generated at class initialization time
 * Instance methods are bound to a generated lsr_method closure the first time the method is referenced (at runtime)
 * lsr_method is a thin wrapper which handles catching native calls for profiling, default arguments, etc
 */
int lsr_method(lua_State *L)
{
    int nargs = lua_gettop(L);

    MethodBase *method = (MethodBase *)lua_topointer(L, lua_upvalueindex(1));

    bool staticCall = method->isStatic();

    if (staticCall)
    {
        lua_pushvalue(L, lua_upvalueindex(2));
        lua_insert(L, 1); // method
    }
    else
    {
        lua_pushvalue(L, lua_upvalueindex(2));
        lua_insert(L, 1); // this (can be a loomscript table or luabridge userdata

        lua_pushvalue(L, lua_upvalueindex(3));
        lua_insert(L, 1); // method
    }


    int dargs = nargs;

    int fidx            = method->getFirstDefaultParm();
    int varArgIdx       = method->getVarArgIndex();
    int varArgVectorIdx = lua_gettop(L);

    // don't consider the varargs in when
    // checking whether we need to insert default arguments
    if ((fidx != -1) && (varArgIdx != -1))
    {
        dargs--;
    }

    if (dargs < method->getNumParameters())
    {
        // TODO: Report line numbers LOOM-603
        // if we have var args and not enough parameters, VM will insert null for ...args value
        // otherwise, we have a compiler error
        if (varArgIdx < 0)
        {
            lmAssert(fidx >= 0, "Method '%s::%s' called with too few arguments.", method->getDeclaringType()->getFullName().c_str(), method->getStringSignature().c_str());
        }

        bool inserted = false;
        for (int i = dargs; i < method->getNumParameters(); i++)
        {
            if (i == varArgIdx)
            {
                break;
            }

            lua_pushvalue(L, lua_upvalueindex(i - fidx + (staticCall ? 3 : 4)));
            inserted = true;
            nargs++;
        }

        // if we inserted *and* have var args, we
        // need to shift the var args to the end
        if (inserted && (varArgIdx != -1))
        {
            lua_pushvalue(L, varArgVectorIdx);
            lua_remove(L, varArgVectorIdx);
        }
    }

    LSLuaState *ls = LSLuaState::getLuaState(L);

    // error handling
    lua_getglobal(L, "__ls_traceback");
    lua_insert(L, 1);

    if (lua_pcall(L, nargs + (staticCall ? 0 : 1), LUA_MULTRET, 1))
    {
        ls->triggerRuntimeError("Error calling %s:%s", method->getDeclaringType()->getFullName().c_str(), method->getName());
    }

    // get rid of the traceback
    lua_remove(L, 1);

    int nreturn = lua_gettop(L);

    if (nreturn == 1)
    {
        if (method->isNative() && method->isMethod() && lua_isuserdata(L, -1))
        {
            lualoom_pushnative_userdata(L, ((MethodInfo *)method)->getReturnType(), -1);
        }
    }

    return nreturn;
}
Esempio n. 2
0
    static int _call(lua_State *L)
    {
        // position 1 is the function
        // position 2 is the thisObject
        // position 3 is the varargs

        // look in global method lookup for methodbase
        lua_rawgeti(L, LUA_GLOBALSINDEX, LSINDEXMETHODLOOKUP);
        lua_pushvalue(L, 1);
        lua_rawget(L, -2);

        MethodBase *methodBase = NULL;
        int varArgs = -1;

        if (!lua_isnil(L, -1))
        {
            methodBase = (MethodBase *)lua_topointer(L, -1);
            varArgs = methodBase->getVarArgIndex();
            lua_pop(L, 2);
        }
        else
        {            
            //  we better be a local function with an upvalue at index 1 describing the parameter index of varargs
            const char *upvalue = lua_getupvalue(L, 1, 1);


            lmAssert(upvalue, "Internal Error: funcinfo not at upvalue 1");

    #ifdef LOOM_DEBUG
            lmAssert(!strncmp(upvalue, "__ls_funcinfo_arginfo", 21), "Internal Error: funcinfo not __ls_funcinfo_arginfo");
    #endif

            lmAssert(lua_isnumber(L, -1), "Internal Error: __ls_funcinfo_arginfo not a number");

            // vararg count is packed into lower 16 bits, with 0xFFFF stored for no-varargs
            unsigned int mask = ((( unsigned int) lua_tonumber(L, -1)) & 0x0000FFFF);
            varArgs =  mask == 0xFFFF ? -1 : mask;

            lua_pop(L, 3);

        }

        // check for static call
        if (lua_isnil(L, 2))
        {
            // remove the this object (which should be null for static call/apply)
            lua_remove(L, 2);
        }
        else
        {
            // otherwise, we better be an instance method

            int top = lua_gettop(L);

            if (!methodBase)
            {
                lua_pushstring(L, "MethodBase is missing from function table in Function.call(this, ...)");
                lua_error(L);
            }

            lua_pushnumber(L, methodBase->getOrdinal());
            lua_gettable(L, 2);

            if (lua_isnil(L, -1))
            {
                char error[512];
                snprintf(error, 512, "Unable to resolve instance method %s for Function.call(this, ...)", methodBase->getStringSignature().c_str());
                lua_pushstring(L, error);
                lua_error(L);
            }

            lua_replace(L, 1);
            lua_settop(L, top);
            lua_remove(L, 2);
        }

        int nargs = 0;

        if (!lua_isnil(L, 2))
        {
            // we have a varargs array of values

            // get the length
            int vlength = lsr_vector_get_length(L, 2);

            // retrieve the interval vector store
            lua_rawgeti(L, 2, LSINDEXVECTOR);
            int vindex = lua_gettop(L);

            // loop through the values and unwind
            for (int i = 0; i < vlength; i++)
            {
                // if we hit the varArgs index, the rest wants to be a vector
                if (i == varArgs)
                {
                    // we're at the var args argument and have some left
                    if (i)
                    {
                        // shift and store new length
                        for (int j  = 0; j < vlength - i; j++)
                        {
                            lua_rawgeti(L, vindex, j + varArgs);
                            lua_rawseti(L, vindex, j);
                        }

                        lsr_vector_set_length(L, 2, vlength - varArgs);
                    }
                    // reuse the varargs vector in the call, as an arg
                    lua_pushvalue(L, 2);
                    nargs++;

                    // outta here
                    break;
                }
                else
                {
                    // unwind and keep going
                    lua_rawgeti(L, vindex, i);
                    nargs++;
                }

            }

            // remove vector table
            lua_remove(L, vindex);

            // ... and varargs
            lua_remove(L, 2);

        }
        else
        {
            // no args, so remove the null
            lua_remove(L, 2);
        }

        // and call
        lua_call(L, nargs, 1);

        return 1;
    }