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; }
void Type::cache() { if (baseType) { baseType->cache(); } if (cached) { return; } cached = true; MemberTypes types; types.constructor = true; types.field = true; types.method = true; types.property = true; utArray<MemberInfo *> allMembers; findMembers(types, allMembers, true, true); maxMemberOrdinal = 0; for (UTsize i = 0; i < allMembers.size(); i++) { MemberInfo *mi = allMembers.at(i); if (mi->ordinal > maxMemberOrdinal) { maxMemberOrdinal = mi->ordinal; } } maxMemberOrdinal++; memberInfoOrdinalLookup = (MemberInfo **)lmAlloc(NULL, sizeof(MemberInfo *) * maxMemberOrdinal); memset(memberInfoOrdinalLookup, 0, sizeof(MemberInfo *) * maxMemberOrdinal); for (int i = (int)(allMembers.size() - 1); i >= 0; i--) { MemberInfo *mi = allMembers.at(i); memberCache.insert(mi->getName(), mi); memberInfoOrdinalLookup[mi->getOrdinal()] = mi; } }
void Type::assignOrdinals() { if (baseType) { baseType->assignOrdinals(); } // already assigned? if (members.size() && members.at(0)->ordinal) { return; } MemberTypes types; types.constructor = true; types.field = true; types.method = true; types.property = true; utArray<MemberInfo *> allMembers; findMembers(types, allMembers, true, true); int maxOrdinal = 0; for (UTsize i = 0; i < allMembers.size(); i++) { MemberInfo *mi = allMembers.at(i); if (mi->getOrdinal() > maxOrdinal) { maxOrdinal = mi->getOrdinal(); } } // and assign int start = maxOrdinal + 1; for (UTsize i = 0; i < allMembers.size(); i++) { MemberInfo *mi = allMembers.at(i); if (!mi->ordinal) { lmAssert(mi->getDeclaringType() == this, "ordinal being assigned to non-declared member"); UTsize j; for (j = 0; j < allMembers.size(); j++) { MemberInfo *other = allMembers.at(j); if (other->getDeclaringType() == this) { continue; } if (strcmp(other->getName(), mi->getName())) { continue; } break; } if (j == allMembers.size()) { mi->setOrdinal(start++); } else { mi->setOrdinal(allMembers.at(j)->getOrdinal()); } } } }
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; }