Beispiel #1
0
void Assembly::bootstrap()
{
    utArray<Type *> types;
    getTypes(types);

    Type *btype = vm->getType("system.Bootstrap");

    for (UTsize i = 0; i < types.size(); i++)
    {
        Type *type = types[i];

        if (type->getFullName() == "system.Null")
        {
            continue;
        }

        if (type->castToType(btype))
        {
            MemberInfo *mi = type->findMember("initialize");
            assert(mi);
            assert(mi->isMethod());

            MethodInfo *method = (MethodInfo *)mi;

            method->invoke(NULL, 0);
        }
    }
}
Beispiel #2
0
bool Type::isNativeMemberPure(bool ignoreStaticMembers)
{
    //if (!attr.isNative)
    //	return false;

    for (UTsize i = 0; i < members.size(); i++)
    {
        MemberInfo *memberInfo = members.at(i);

        if (ignoreStaticMembers && memberInfo->isStatic())
        {
            continue;
        }

        if (memberInfo->isConstructor())
        {
            ConstructorInfo *cinfo = (ConstructorInfo *)memberInfo;
            if (cinfo->defaultConstructor)
            {
                continue;
            }
        }

        if (memberInfo->isConstructor() || memberInfo->isMethod())
        {
            if (!((MethodBase *)memberInfo)->isNative())
            {
                return false;
            }
        }

        if (memberInfo->isProperty())
        {
            PropertyInfo *pinfo = (PropertyInfo *)memberInfo;
            if (pinfo->getGetMethod() && !pinfo->getGetMethod()->isNative())
            {
                return false;
            }
            if (pinfo->getSetMethod() && !pinfo->getSetMethod()->isNative())
            {
                return false;
            }
        }

        if (memberInfo->isField())
        {
            if (!memberInfo->getOrdinal())
            {
                return false;
            }
        }
    }

    if (baseType)
    {
        return baseType->isNativeMemberPure();
    }

    return true;
}
Beispiel #3
0
MethodInfo *Type::getMethodInfo(const utString& name)
{
    MemberInfo *minfo = findMember(name.c_str());

    if (minfo && minfo->isMethod())
    {
        return (MethodInfo *)minfo;
    }

    return NULL;
}
Beispiel #4
0
void Type::findMembers(const MemberTypes& memberTypes,
                       utArray<MemberInfo *>& membersOut, bool includeBases, bool includePropertyGetterSetters)
{
    if (!includeBases)
    {
        membersOut.clear();
    }

    for (size_t i = 0; i < members.size(); i++)
    {
        MemberInfo *m = members.at((int)i);

        if (m->isConstructor() && memberTypes.constructor)
        {
            membersOut.push_back(m);
        }

        if (m->isMethod() && memberTypes.method)
        {
            membersOut.push_back(m);
        }

        if (m->isField() && memberTypes.field)
        {
            membersOut.push_back(m);
        }

        if (m->isProperty() && memberTypes.property)
        {
            membersOut.push_back(m);

            if (includePropertyGetterSetters)
            {
                PropertyInfo *p = (PropertyInfo *)m;

                if (p->getter && (p->getter->getDeclaringType() == p->getDeclaringType()))
                {
                    membersOut.push_back(p->getter);
                }

                if (p->setter && (p->setter->getDeclaringType() == p->getDeclaringType()))
                {
                    membersOut.push_back(p->setter);
                }
            }
        }
    }

    if (baseType && includeBases)
    {
        baseType->findMembers(memberTypes, membersOut, true, includePropertyGetterSetters);
    }
}
Beispiel #5
0
MethodInfo *Type::findOperatorMethod(const utString& methodName)
{
    MemberInfo *mi = findMember(methodName.c_str());

    if (!mi)
    {
        return NULL;
    }
    if (!mi->isMethod())
    {
        return NULL;
    }
    if (!((MethodInfo *)mi)->isOperator())
    {
        return NULL;
    }

    return (MethodInfo *)mi;
}
Beispiel #6
0
void LSLuaState::invokeStaticMethod(const utString& typePath,
                                    const char *methodName, int numParameters)
{
    Type *type = getType(typePath.c_str());

    lmAssert(type, "LSLuaState::invokeStaticMethod unknown type: %s", typePath.c_str());

    MemberInfo *member = type->findMember(methodName);
    lmAssert(member, "LSLuaState::invokeStaticMethod unknown member: %s:%s", typePath.c_str(), methodName);
    if (!member->isMethod())
    {
        lmAssert(0, "LSLuaState::invokeStaticMethod member: %s:%s is not a method", typePath.c_str(), methodName);
    }

    MethodInfo *method = (MethodInfo *)member;

    lmAssert(method->isStatic(), "LSLuaState::invokeStaticMethod member: %s:%s is not a static method", typePath.c_str(), methodName);

    method->invoke(NULL, numParameters);
}
Beispiel #7
0
static int lsr_instanceindex(lua_State *L)
{
    // we hit the instance index metamethod when we can't find a value
    // in the instance's table, this is a native or a bound method

    lua_rawgeti(L, 1, LSINDEXTYPE);
    Type *type = (Type *)lua_topointer(L, -1);
    lua_pop(L, 1);

    lmAssert(type, "Missing type on instance index");

    if (lua_isnumber(L, 2))
    {
        int ordinal = (int)lua_tonumber(L, 2);

        MemberInfo *mi = type->getMemberInfoByOrdinal(ordinal);

        lmAssert(mi, "Unable to find ordinal %s %i", type->getFullName().c_str(), ordinal);

        if (mi->isStatic())
        {
            lua_rawgeti(L, 1, LSINDEXCLASS);
            lua_replace(L, 1);
            lua_gettable(L, 1);
            return 1;
        }

        // we need to look in the class, the result will be cached to instance

        MethodBase *method = NULL;

        if (mi->isMethod())
        {
            method = (MethodBase *)mi;
        }

        if (method)
        {
            lua_rawgeti(L, 1, LSINDEXCLASS);
            assert(!lua_isnil(L, -1));

            int clsIdx = lua_gettop(L);

            if (!method->isStatic())
            {
                if (method->isFastCall())
                {
                    // get the fast call structure pointer
                    lua_pushlightuserdata(L, method->getFastCall());

                    // get the the "this"
                    if (lua_type(L, 1) == LUA_TTABLE)
                    {
                        lua_rawgeti(L, 1, LSINDEXNATIVE);
                    }
                    else
                    {
                        lua_pushvalue(L, 1);
                    }

                    // unwrap this
                    Detail::UserdataPtr *p1 = (Detail::UserdataPtr *)lua_topointer(L, -1);
                    lua_pushlightuserdata(L, p1->getPointer());
                    lua_replace(L, -2);

                    lua_pushnumber(L, ordinal);
                    lua_gettable(L, clsIdx);
                }
                else
                {
                    lua_pushlightuserdata(L, method);
                    lua_pushvalue(L, 1);
                    lua_pushnumber(L, ordinal);
                    lua_gettable(L, clsIdx);
                }

                assert(!lua_isnil(L, -1));

                int nup = 3;

                int fd = method->getFirstDefaultParm();
                if (fd != -1)
                {
                    utString dname;
                    if (method->isConstructor())
                    {
                        dname = "__ls_constructor";
                    }
                    else
                    {
                        dname = method->getName();
                    }

                    dname += "__default_args";

                    lua_getfield(L, clsIdx, dname.c_str());

                    int dargs = lua_gettop(L);

                    for (int i = fd; i < method->getNumParameters(); i++)
                    {
                        lua_pushnumber(L, i);
                        lua_gettable(L, dargs);
                        nup++;
                    }

                    lua_remove(L, dargs);
                }

                // check for fast path
                if (method->isFastCall())
                {
                    if (method->getNumParameters())
                    {
                        // setter
                        lua_pushcclosure(L, lsr_method_fastcall_set, nup);
                    }
                    else
                    {
                        // getter
                        lua_pushcclosure(L, lsr_method_fastcall_get, nup);
                    }
                }
                else
                {
                    // bind the instance method
                    lua_pushcclosure(L, lsr_method, nup);
                }

                // store to method lookup, this is worth it
                // as only happens once per instance method bind
                // and can now lookup MethodBase on any function
                // in one table lookup
                lua_rawgeti(L, LUA_GLOBALSINDEX, LSINDEXMETHODLOOKUP);
                lua_pushvalue(L, -2);
                lua_pushlightuserdata(L, method);
                lua_rawset(L, -3);
                lua_pop(L, 1);

                // cache to instance
                lua_pushvalue(L, -1);
                lua_rawseti(L, 1, ordinal);


                return 1;
            }
            else
            {
                assert(0);
            }
        }

        FieldInfo *field = NULL;

        if (mi->isField())
        {
            field = (FieldInfo *)mi;
        }

        if (field && field->isNative())
        {
            // for primitive fields, we could generate
            // a direct lookup in the LSINDEXNATIVE table
            // in bytecode gen, however this only saves for
            // native vars and not properties
            // (which should be using fast path anyway and complicates bytecode)

            // get the native userdata
            lua_rawgeti(L, 1, LSINDEXNATIVE);
            lua_pushnumber(L, field->getOrdinal());
            lua_gettable(L, -2);

            // if we are native we need to wrap
            if (lua_isuserdata(L, -1))
            {
                lualoom_pushnative_userdata(L, field->getType(), -1);
            }

            return 1;
        }

        // if we get here the value actually is null
        lua_pushnil(L);
        return 1;
    }

    // if we hit here, this should be an interface access where we have to
    // look up by string (and cache as these are only ever instance methods)

    const char *name  = lua_tostring(L, 2);
    const char *pname = name;
    MemberInfo *mi    = NULL;

    if (!strncmp(name, "__pget_", 7))
    {
        pname = &name[7];
        mi    = type->findMember(pname, true);
        lmAssert(mi && mi->isProperty(), "Could not find property getter for '%s' on type '%s'", pname, type->getFullName().c_str());
        mi = ((PropertyInfo *)mi)->getGetMethod();
        lmAssert(mi, "Found NULL property getter for '%s' on type '%s'", pname, type->getFullName().c_str());
    }
    else if (!strncmp(name, "__pset_", 7))
    {
        pname = &name[7];
        mi    = type->findMember(pname, true);
        lmAssert(mi && mi->isProperty(), "Could not find property setter for '%s' on type '%s'", pname, type->getFullName().c_str());
        mi = ((PropertyInfo *)mi)->getSetMethod();
        lmAssert(mi, "Found NULL property setter for '%s' on type '%s'", pname, type->getFullName().c_str());
    }
    else
    {
        mi = type->findMember(name, true);
        lmAssert(mi, "Unable to find member '%s' via string on instance of type %s", name, type->getFullName().c_str());
        assert(mi);
        assert(mi->isMethod());
        assert(mi->getOrdinal());
    }

    lua_pushnumber(L, mi->getOrdinal());
    lua_gettable(L, 1);
    lua_pushstring(L, name);
    lua_pushvalue(L, -2);
    lua_rawset(L, 1);

    return 1;
}
Beispiel #8
0
Expression *TypeCompiler::visit(SuperExpression *expression)
{
    lmAssert(currentMethod, "super outside of method");

    Type *type     = currentMethod->getDeclaringType();
    Type *baseType = type->getBaseType();

    //FIXME:  issue a warning
    if (!baseType)
    {
        return expression;
    }

    FuncState *fs = cs->fs;

    if (currentMethod->isConstructor())
    {
        ConstructorInfo *base = baseType->getConstructor();

        //FIXME: warn if no base constructor
        if (!base)
        {
            return expression;
        }

        // load up base class
        ExpDesc eclass;
        BC::singleVar(cs, &eclass, baseType->getFullName().c_str());

        // index with the __ls_constructor
        BC::expToNextReg(fs, &eclass);

        ExpDesc fname;
        BC::expString(cs, &fname, "__ls_constructor");

        BC::expToNextReg(fs, &fname);
        BC::expToVal(fs, &fname);
        BC::indexed(fs, &eclass, &fname);

        // call the LSMethod
        generateCall(&eclass, &expression->arguments);
    }
    else
    {
        utString name = currentMethod->getName();

        if (expression->method)
        {
            name = expression->method->string;
        }

        MemberInfo *mi = baseType->findMember(name.c_str());
        //FIXME: warn
        if (!mi)
        {
            return expression;
        }

        lmAssert(mi->isMethod(), "Non-method in super call");

        MethodInfo *methodInfo = (MethodInfo *)mi;

        // load up declaring class
        ExpDesc eclass;
        BC::singleVar(cs, &eclass,
                      methodInfo->getDeclaringType()->getFullName().c_str());

        BC::expToNextReg(fs, &eclass);

        ExpDesc fname;
        BC::expString(cs, &fname, name.c_str());

        BC::expToNextReg(fs, &fname);
        BC::expToVal(fs, &fname);
        BC::indexed(fs, &eclass, &fname);

        // call the LSMethod
        generateCall(&eclass, &expression->arguments);

        expression->e = eclass;
    }

    return expression;
}
Beispiel #9
0
// TODO: Unify this with the JIT bc generator binary expressions
// https://theengineco.atlassian.net/browse/LOOM-640
// https://theengineco.atlassian.net/browse/LOOM-641
Expression *TypeCompiler::visit(BinaryOperatorExpression *expression)
{
    Tokens *tok = Tokens::getSingletonPtr();

    Expression *eleft  = expression->leftExpression;
    Expression *eright = expression->rightExpression;

    // operator overloads
    lmAssert(eleft->type && eright->type, "Untyped binary expression");

    const char *opmethod = tok->getOperatorMethodName(expression->op);
    if (opmethod)
    {
        MemberInfo *mi = eleft->type->findMember(opmethod);
        if (mi)
        {
            lmAssert(mi->isMethod(), "Non-method operator");
            MethodInfo *method = (MethodInfo *)mi;
            lmAssert(method->isOperator(), "Non-operator method");

            utArray<Expression *> args;
            args.push_back(eleft);
            args.push_back(eright);

            ExpDesc opcall;
            ExpDesc emethod;

            BC::singleVar(cs, &opcall, eleft->type->getName());
            BC::expString(cs, &emethod, method->getName());

            BC::expToNextReg(cs->fs, &opcall);
            BC::expToNextReg(cs->fs, &emethod);
            BC::expToVal(cs->fs, &emethod);
            BC::indexed(cs->fs, &opcall, &emethod);

            generateCall(&opcall, &args, method);

            expression->e = opcall;
            return expression;
        }
    }

    // dynamic cast
    if ((expression->op == &tok->KEYWORD_IS) ||
        (expression->op == &tok->KEYWORD_INSTANCEOF) ||
        (expression->op == &tok->KEYWORD_AS))
    {
        lmAssert(eleft->type && eright->type, "Untype expression");

        FuncState *fs = cs->fs;

        ExpDesc object;
        BC::singleVar(cs, &object, "Object");

        ExpDesc method;

        if (expression->op == &tok->KEYWORD_IS)
        {
            BC::expString(cs, &method, "_is");
        }
        else if (expression->op == &tok->KEYWORD_AS)
        {
            BC::expString(cs, &method, "_as");
        }
        else
        {
            BC::expString(cs, &method, "_instanceof");
        }

        BC::expToNextReg(fs, &object);
        BC::expToNextReg(fs, &method);
        BC::expToVal(fs, &method);
        BC::indexed(fs, &object, &method);

        utArray<Expression *> args;
        args.push_back(eleft);
        args.push_back(new StringLiteral(eright->type->getAssembly()->getName().c_str()));
        args.push_back(new NumberLiteral(eright->type->getTypeID()));

        generateCall(&object, &args);

        expression->e = object;

        return expression;
    }

    BinOpr op = getbinopr(expression->op);

    if (op == OPR_LOOM_ADD)
    {
        lmAssert(eleft->type && eright->type, "Untyped add operaton %i",
                 lineNumber);

        int ncheck = 0;
        if (eleft->type->isEnum() || (eleft->type->getFullName() == "system.Number"))
        {
            ncheck++;
        }

        if (eright->type->isEnum() || (eright->type->getFullName() == "system.Number"))
        {
            ncheck++;
        }

        if (ncheck != 2)
        {
            op = OPR_CONCAT;
        }
    }


    // If we're concat'ing arbitrary types with a string, we need to coerce them
    // to strings with Object._toString otherwise the Lua VM will error when
    // it can't concat (which has strict rules, for instance cannot concat nil)
    if ((op == OPR_CONCAT) && ((eleft->type->getFullName() == "system.String") || (eright->type->getFullName() == "system.String")))
    {
        // coerce left to string, must be done even for string types as they may be null
        coerceToString(eleft);

        BC::infix(cs->fs, op, &eleft->e);

        // coerce right to string, must be done even for string types as they may be null
        coerceToString(eright);

        // and the binary op
        BC::posFix(cs->fs, op, &eleft->e, &eright->e);
        // save off expression and return
        expression->e = eleft->e;

        return expression;
    }

    eleft->visitExpression(this);

    BC::infix(cs->fs, op, &eleft->e);

    eright->visitExpression(this);

    BC::posFix(cs->fs, op, &eleft->e, &eright->e);

    expression->e = eleft->e;

    // promote to register
    BC::expToNextReg(cs->fs, &expression->e);

    return expression;
}
Beispiel #10
0
Expression *TypeCompiler::visit(AssignmentOperatorExpression *expression)
{
    Tokens *tok = Tokens::getSingletonPtr();
    BinOpr op   = getassignmentopr(expression->type);

    lmAssert(op != OPR_NOBINOPR, "Unknown bin op on AssignentOperatorExpression");

    Expression *eleft  = expression->leftExpression;
    Expression *eright = expression->rightExpression;

    lmAssert(eleft->type, "Untyped error on left expression");

    const char *opmethod = tok->getOperatorMethodName(expression->type);
    if (opmethod)
    {
        MemberInfo *mi = eleft->type->findMember(opmethod);
        if (mi)
        {
            lmAssert(mi->isMethod(), "Non-method operator");

            MethodInfo *method = (MethodInfo *)mi;

            lmAssert(method->isOperator(), "Non-operator method");

            utArray<Expression *> args;
            args.push_back(eright);

            ExpDesc opcall;
            ExpDesc emethod;

            eleft->visitExpression(this);
            opcall = eleft->e;

            BC::initExpDesc(&emethod, VKNUM, 0);
            emethod.u.nval = method->getOrdinal();
            BC::expToNextReg(cs->fs, &opcall);
            BC::expToNextReg(cs->fs, &emethod);
            BC::expToVal(cs->fs, &emethod);
            BC::indexed(cs->fs, &opcall, &emethod);

            generateCall(&opcall, &args, method);

            expression->e = opcall;
            return expression;
        }
    }

    eleft->assignment = false;
    eleft->visitExpression(this);

    BC::infix(cs->fs, op, &eleft->e);

    eright->visitExpression(this);
    BC::expToNextReg(cs->fs, &eright->e);

    BC::posFix(cs->fs, op, &eleft->e, &eright->e);

    ExpDesc right = eleft->e;

    BC::expToNextReg(cs->fs, &right);

    memset(&eleft->e, 0, sizeof(ExpDesc));
    eleft->assignment = true;
    eleft->visitExpression(this);
    ExpDesc left = eleft->e;

    if (eleft->memberInfo && eleft->memberInfo->isProperty())
    {
        eright->e = right;
        generatePropertySet(&eleft->e, eright, false);
    }
    else
    {
        BC::storeVar(cs->fs, &left, &right);
    }

    return expression;
}