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; }
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; }