Remove Python type tables from interrogatedb

This commit is contained in:
rdb 2018-11-05 21:48:50 +01:00
parent da05ef1f5c
commit e6f870ece6
12 changed files with 216 additions and 163 deletions

View File

@ -153,6 +153,19 @@ deallocate_array(void *ptr) {
PANDA_FREE_ARRAY(ptr);
}
/**
* Returns the internal void pointer that is stored for interrogate's benefit.
*/
PyObject *TypeHandle::
get_python_type() const {
TypeRegistryNode *rnode = TypeRegistry::ptr()->look_up(*this, nullptr);
if (rnode != nullptr) {
return rnode->get_python_type();
} else {
return nullptr;
}
}
/**
* Return the Index of the BEst fit Classs from a set
*/

View File

@ -138,6 +138,8 @@ PUBLISHED:
MAKE_SEQ_PROPERTY(child_classes, get_num_child_classes, get_child_class);
public:
PyObject *get_python_type() const;
void *allocate_array(size_t size) RETURNS_ALIGNED(MEMORY_HOOK_ALIGNMENT);
void *reallocate_array(void *ptr, size_t size) RETURNS_ALIGNED(MEMORY_HOOK_ALIGNMENT);
void deallocate_array(void *ptr);

View File

@ -207,6 +207,22 @@ record_alternate_name(TypeHandle type, const string &name) {
_lock->unlock();
}
/**
* Records the given Python type pointer in the type registry for the benefit
* of interrogate.
*/
void TypeRegistry::
record_python_type(TypeHandle type, PyObject *python_type) {
_lock->lock();
TypeRegistryNode *rnode = look_up(type, nullptr);
if (rnode != nullptr) {
rnode->_python_type = python_type;
}
_lock->unlock();
}
/**
* Looks for a previously-registered type of the given name. Returns its
* TypeHandle if it exists, or TypeHandle::none() if there is no such type.

View File

@ -45,6 +45,7 @@ PUBLISHED:
void record_derivation(TypeHandle child, TypeHandle parent);
void record_alternate_name(TypeHandle type, const std::string &name);
void record_python_type(TypeHandle type, PyObject *python_type);
TypeHandle find_type(const std::string &name) const;
TypeHandle find_type_by_id(int id) const;

View File

@ -11,6 +11,19 @@
* @date 2001-08-06
*/
/**
* Returns the Python type object associated with this node.
*/
INLINE PyObject *TypeRegistryNode::
get_python_type() const {
if (_python_type != nullptr || _parent_classes.empty()) {
return _python_type;
} else {
// Recurse through parent classes.
return r_get_python_type();
}
}
/**
*
*/

View File

@ -308,6 +308,29 @@ r_build_subtrees(TypeRegistryNode *top, int bit_count,
}
}
/**
* Recurses through the parent nodes to find the best Python type object to
* represent objects of this type.
*/
PyObject *TypeRegistryNode::
r_get_python_type() const {
Classes::const_iterator ni;
for (ni = _parent_classes.begin(); ni != _parent_classes.end(); ++ni) {
const TypeRegistryNode *parent = *ni;
if (parent->_python_type != nullptr) {
return parent->_python_type;
} else if (!parent->_parent_classes.empty()) {
PyObject *py_type = parent->r_get_python_type();
if (py_type != nullptr) {
return py_type;
}
}
}
return nullptr;
}
/**
* A recursive function to double-check the result of is_derived_from(). This
* is the slow, examine-the-whole-graph approach, as opposed to the clever and

View File

@ -37,6 +37,8 @@ public:
static TypeHandle get_parent_towards(const TypeRegistryNode *child,
const TypeRegistryNode *base);
INLINE PyObject *get_python_type() const;
void clear_subtree();
void define_subtree();
@ -46,6 +48,7 @@ public:
typedef std::vector<TypeRegistryNode *> Classes;
Classes _parent_classes;
Classes _child_classes;
PyObject *_python_type = nullptr;
AtomicAdjust::Integer _memory_usage[TypeHandle::MC_limit];
@ -77,6 +80,8 @@ private:
void r_build_subtrees(TypeRegistryNode *top,
int bit_count, SubtreeMaskType bits);
PyObject *r_get_python_type() const;
static bool check_derived_from(const TypeRegistryNode *child,
const TypeRegistryNode *base);

View File

@ -821,10 +821,54 @@ write_prototypes(ostream &out_code, ostream *out_h) {
}
}
out_code << "/**\n";
out_code << " * Declarations for exported classes\n";
out_code << " */\n";
out_code << "static const Dtool_TypeDef exports[] = {\n";
for (oi = _objects.begin(); oi != _objects.end(); ++oi) {
Object *object = (*oi).second;
if (object->_itype.is_class() || object->_itype.is_struct()) {
CPPType *type = object->_itype._cpptype;
if (isExportThisRun(type) && is_cpp_type_legal(type)) {
string class_name = type->get_local_name(&parser);
string safe_name = make_safe_name(class_name);
out_code << " {\"" << class_name << "\", &Dtool_" << safe_name << "},\n";
}
}
}
out_code << " {nullptr, nullptr},\n";
out_code << "};\n\n";
out_code << "/**\n";
out_code << " * Extern declarations for imported classes\n";
out_code << " */\n";
// Write out a table of the externally imported types that will be filled in
// upon module initialization.
if (!_external_imports.empty()) {
out_code << "#ifndef LINK_ALL_STATIC\n";
out_code << "static Dtool_TypeDef imports[] = {\n";
int idx = 0;
for (CPPType *type : _external_imports) {
string class_name = type->get_local_name(&parser);
string safe_name = make_safe_name(class_name);
out_code << " {\"" << class_name << "\", nullptr},\n";
out_code << "#define Dtool_Ptr_" << safe_name << " (imports[" << idx << "].type)\n";
++idx;
}
out_code << " {nullptr, nullptr},\n";
out_code << "};\n";
out_code << "#endif\n\n";
}
for (CPPType *type : _external_imports) {
string class_name = type->get_local_name(&parser);
string safe_name = make_safe_name(class_name);
@ -834,7 +878,9 @@ write_prototypes(ostream &out_code, ostream *out_h) {
out_code << "#ifndef LINK_ALL_STATIC\n";
// out_code << "IMPORT_THIS struct Dtool_PyTypedObject Dtool_" <<
// safe_name << ";\n";
out_code << "static struct Dtool_PyTypedObject *Dtool_Ptr_" << safe_name << ";\n";
//if (has_get_class_type_function(type)) {
// out_code << "static struct Dtool_PyTypedObject *Dtool_Ptr_" << safe_name << ";\n";
//}
// out_code << "#define Dtool_Ptr_" << safe_name << " &Dtool_" <<
// safe_name << "\n"; out_code << "IMPORT_THIS void
// Dtool_PyModuleClassInit_" << safe_name << "(PyObject *module);\n";
@ -1258,36 +1304,36 @@ write_module_support(ostream &out, ostream *out_h, InterrogateModuleDef *def) {
Objects::iterator oi;
out << "void Dtool_" << def->library_name << "_RegisterTypes() {\n";
out << "void Dtool_" << def->library_name << "_RegisterTypes() {\n"
" TypeRegistry *registry = TypeRegistry::ptr();\n"
" nassertv(registry != nullptr);\n";
for (oi = _objects.begin(); oi != _objects.end(); ++oi) {
Object *object = (*oi).second;
if (object->_itype.is_class() ||
object->_itype.is_struct()) {
if (is_cpp_type_legal(object->_itype._cpptype) &&
isExportThisRun(object->_itype._cpptype)) {
string class_name = make_safe_name(object->_itype.get_scoped_name());
bool is_typed = has_get_class_type_function(object->_itype._cpptype);
if (object->_itype.is_class() || object->_itype.is_struct()) {
CPPType *type = object->_itype._cpptype;
if (is_cpp_type_legal(type) && isExportThisRun(type)) {
string class_name = object->_itype.get_scoped_name();
string safe_name = make_safe_name(class_name);
bool is_typed = has_get_class_type_function(type);
if (is_typed) {
if (has_init_type_function(object->_itype._cpptype)) {
out << " {\n";
if (has_init_type_function(type)) {
// Call the init_type function. This isn't necessary for all
// types as many of them are automatically initialized at static
// init type, but for some extension classes it's useful.
out << " " << object->_itype._cpptype->get_local_name(&parser)
out << " " << type->get_local_name(&parser)
<< "::init_type();\n";
}
out << " Dtool_" << class_name << "._type = "
<< object->_itype._cpptype->get_local_name(&parser)
<< "::get_class_type();\n"
<< " RegisterRuntimeTypedClass(Dtool_" << class_name << ");\n";
out << " TypeHandle handle = " << type->get_local_name(&parser)
<< "::get_class_type();\n";
out << " Dtool_" << safe_name << "._type = handle;\n";
out << " registry->record_python_type(handle, "
"(PyObject *)&Dtool_" << safe_name << ");\n";
out << " }\n";
} else {
out << "#ifndef LINK_ALL_STATIC\n"
<< " RegisterNamedClass(\"" << object->_itype.get_scoped_name()
<< "\", Dtool_" << class_name << ");\n"
<< "#endif\n";
if (IsPandaTypedObject(object->_itype._cpptype->as_struct_type())) {
if (IsPandaTypedObject(type->as_struct_type())) {
nout << object->_itype.get_scoped_name() << " derives from TypedObject, "
<< "but does not define a get_class_type() function.\n";
}
@ -1297,23 +1343,6 @@ write_module_support(ostream &out, ostream *out_h, InterrogateModuleDef *def) {
}
out << "}\n\n";
out << "void Dtool_" << def->library_name << "_ResolveExternals() {\n";
out << "#ifndef LINK_ALL_STATIC\n";
out << " // Resolve externally imported types.\n";
for (CPPType *type : _external_imports) {
string class_name = type->get_local_name(&parser);
string safe_name = make_safe_name(class_name);
if (has_get_class_type_function(type)) {
out << " Dtool_Ptr_" << safe_name << " = LookupRuntimeTypedClass(" << class_name << "::get_class_type());\n";
} else {
out << " Dtool_Ptr_" << safe_name << " = LookupNamedClass(\"" << class_name << "\");\n";
}
}
out << "#endif\n";
out << "}\n\n";
out << "void Dtool_" << def->library_name << "_BuildInstants(PyObject *module) {\n";
out << " (void) module;\n";
@ -1466,9 +1495,14 @@ write_module_support(ostream &out, ostream *out_h, InterrogateModuleDef *def) {
out << " {nullptr, nullptr, 0, nullptr}\n" << "};\n\n";
out << "struct LibraryDef " << def->library_name << "_moddef = {python_simple_funcs};\n";
out << "extern const struct LibraryDef " << def->library_name << "_moddef = {python_simple_funcs, exports, ";
if (_external_imports.empty()) {
out << "nullptr};\n";
} else {
out << "imports};\n";
}
if (out_h != nullptr) {
*out_h << "extern struct LibraryDef " << def->library_name << "_moddef;\n";
*out_h << "extern const struct LibraryDef " << def->library_name << "_moddef;\n";
}
}

View File

@ -286,9 +286,8 @@ int write_python_table_native(std::ostream &out) {
vector_string::const_iterator ii;
for (ii = libraries.begin(); ii != libraries.end(); ++ii) {
printf("Referencing Library %s\n", (*ii).c_str());
out << "extern LibraryDef " << *ii << "_moddef;\n";
out << "extern const struct LibraryDef " << *ii << "_moddef;\n";
out << "extern void Dtool_" << *ii << "_RegisterTypes();\n";
out << "extern void Dtool_" << *ii << "_ResolveExternals();\n";
out << "extern void Dtool_" << *ii << "_BuildInstants(PyObject *module);\n";
}
@ -339,12 +338,9 @@ int write_python_table_native(std::ostream &out) {
for (ii = libraries.begin(); ii != libraries.end(); ii++) {
out << " Dtool_" << *ii << "_RegisterTypes();\n";
}
for (ii = libraries.begin(); ii != libraries.end(); ii++) {
out << " Dtool_" << *ii << "_ResolveExternals();\n";
}
out << "\n";
out << " LibraryDef *defs[] = {";
out << " const LibraryDef *defs[] = {";
for(ii = libraries.begin(); ii != libraries.end(); ii++) {
out << "&" << *ii << "_moddef, ";
}
@ -386,12 +382,9 @@ int write_python_table_native(std::ostream &out) {
for (ii = libraries.begin(); ii != libraries.end(); ii++) {
out << " Dtool_" << *ii << "_RegisterTypes();\n";
}
for (ii = libraries.begin(); ii != libraries.end(); ii++) {
out << " Dtool_" << *ii << "_ResolveExternals();\n";
}
out << "\n";
out << " LibraryDef *defs[] = {";
out << " const LibraryDef *defs[] = {";
for(ii = libraries.begin(); ii != libraries.end(); ii++) {
out << "&" << *ii << "_moddef, ";
}

View File

@ -26,7 +26,7 @@
template<class T> INLINE bool
DtoolInstance_GetPointer(PyObject *self, T *&into) {
if (DtoolInstance_Check(self)) {
Dtool_PyTypedObject *target_class = Dtool_RuntimeTypeDtoolType(get_type_handle(T).get_index());
Dtool_PyTypedObject *target_class = (Dtool_PyTypedObject *)get_type_handle(T).get_python_type();
if (target_class != nullptr) {
if (_IS_FINAL(T)) {
if (DtoolInstance_TYPE(self) == target_class) {
@ -116,28 +116,28 @@ INLINE long Dtool_EnumValue_AsLong(PyObject *value) {
*/
template<class T> INLINE PyObject *
DTool_CreatePyInstance(const T *obj, bool memory_rules) {
Dtool_PyTypedObject *known_class = Dtool_RuntimeTypeDtoolType(get_type_handle(T).get_index());
Dtool_PyTypedObject *known_class = (Dtool_PyTypedObject *)get_type_handle(T).get_python_type();
nassertr(known_class != nullptr, nullptr);
return DTool_CreatePyInstance((void*) obj, *known_class, memory_rules, true);
}
template<class T> INLINE PyObject *
DTool_CreatePyInstance(T *obj, bool memory_rules) {
Dtool_PyTypedObject *known_class = Dtool_RuntimeTypeDtoolType(get_type_handle(T).get_index());
Dtool_PyTypedObject *known_class = (Dtool_PyTypedObject *)get_type_handle(T).get_python_type();
nassertr(known_class != nullptr, nullptr);
return DTool_CreatePyInstance((void*) obj, *known_class, memory_rules, false);
}
template<class T> INLINE PyObject *
DTool_CreatePyInstanceTyped(const T *obj, bool memory_rules) {
Dtool_PyTypedObject *known_class = Dtool_RuntimeTypeDtoolType(get_type_handle(T).get_index());
Dtool_PyTypedObject *known_class = (Dtool_PyTypedObject *)get_type_handle(T).get_python_type();
nassertr(known_class != nullptr, nullptr);
return DTool_CreatePyInstanceTyped((void*) obj, *known_class, memory_rules, true, obj->get_type().get_index());
}
template<class T> INLINE PyObject *
DTool_CreatePyInstanceTyped(T *obj, bool memory_rules) {
Dtool_PyTypedObject *known_class = Dtool_RuntimeTypeDtoolType(get_type_handle(T).get_index());
Dtool_PyTypedObject *known_class = (Dtool_PyTypedObject *)get_type_handle(T).get_python_type();
nassertr(known_class != nullptr, nullptr);
return DTool_CreatePyInstanceTyped((void*) obj, *known_class, memory_rules, false, obj->get_type().get_index());
}

View File

@ -29,10 +29,6 @@ PyMemberDef standard_type_members[] = {
{nullptr} /* Sentinel */
};
static RuntimeTypeMap runtime_type_map;
static RuntimeTypeSet runtime_type_set;
static NamedTypeMap named_type_map;
/**
*/
@ -431,7 +427,7 @@ PyObject *DTool_CreatePyInstanceTyped(void *local_this_in, Dtool_PyTypedObject &
// IF the class is possibly a run time typed object
if (type_index > 0) {
// get best fit class...
Dtool_PyTypedObject *target_class = Dtool_RuntimeTypeDtoolType(type_index);
Dtool_PyTypedObject *target_class = (Dtool_PyTypedObject *)TypeHandle::from_index(type_index).get_python_type();
if (target_class != nullptr) {
// cast to the type...
void *new_local_this = target_class->_Dtool_DowncastInterface(local_this_in, &known_class_type);
@ -507,109 +503,30 @@ void Dtool_Accum_MethDefs(PyMethodDef in[], MethodDefmap &themap) {
}
}
// ** HACK ** alert.. Need to keep a runtime type dictionary ... that is
// forward declared of typed object. We rely on the fact that typed objects
// are uniquly defined by an integer.
void
RegisterNamedClass(const string &name, Dtool_PyTypedObject &otype) {
std::pair<NamedTypeMap::iterator, bool> result =
named_type_map.insert(NamedTypeMap::value_type(name, &otype));
if (!result.second) {
// There was already a class with this name in the dictionary.
interrogatedb_cat.warning()
<< "Double definition for class " << name << "\n";
}
}
void
RegisterRuntimeTypedClass(Dtool_PyTypedObject &otype) {
int type_index = otype._type.get_index();
if (type_index == 0) {
interrogatedb_cat.warning()
<< "Class " << otype._PyType.tp_name
<< " has a zero TypeHandle value; check that init_type() is called.\n";
} else if (type_index < 0 || type_index >= TypeRegistry::ptr()->get_num_typehandles()) {
interrogatedb_cat.warning()
<< "Class " << otype._PyType.tp_name
<< " has an illegal TypeHandle value; check that init_type() is called.\n";
/**
* Returns a borrowed reference to the global type dictionary.
*/
Dtool_TypeMap *Dtool_GetGlobalTypeMap() {
PyObject *capsule = PySys_GetObject("_interrogate_types");
if (capsule != nullptr) {
return (Dtool_TypeMap *)PyCapsule_GetPointer(capsule, nullptr);
} else {
std::pair<RuntimeTypeMap::iterator, bool> result =
runtime_type_map.insert(RuntimeTypeMap::value_type(type_index, &otype));
if (!result.second) {
// There was already an entry in the dictionary for type_index.
Dtool_PyTypedObject *other_type = (*result.first).second;
interrogatedb_cat.warning()
<< "Classes " << otype._PyType.tp_name
<< " and " << other_type->_PyType.tp_name
<< " share the same TypeHandle value (" << type_index
<< "); check class definitions.\n";
} else {
runtime_type_set.insert(type_index);
}
}
}
Dtool_PyTypedObject *
LookupNamedClass(const string &name) {
NamedTypeMap::const_iterator it;
it = named_type_map.find(name);
if (it == named_type_map.end()) {
// Find a type named like this in the type registry.
TypeHandle handle = TypeRegistry::ptr()->find_type(name);
if (handle.get_index() > 0) {
RuntimeTypeMap::const_iterator it2;
it2 = runtime_type_map.find(handle.get_index());
if (it2 != runtime_type_map.end()) {
return it2->second;
}
}
interrogatedb_cat.error()
<< "Attempt to use type " << name << " which has not yet been defined!\n";
return nullptr;
} else {
return it->second;
}
}
Dtool_PyTypedObject *
LookupRuntimeTypedClass(TypeHandle handle) {
RuntimeTypeMap::const_iterator it;
it = runtime_type_map.find(handle.get_index());
if (it == runtime_type_map.end()) {
interrogatedb_cat.error()
<< "Attempt to use type " << handle << " which has not yet been defined!\n";
return nullptr;
} else {
return it->second;
Dtool_TypeMap *type_map = new Dtool_TypeMap;
capsule = PyCapsule_New((void *)type_map, nullptr, nullptr);
PySys_SetObject("_interrogate_types", capsule);
Py_DECREF(capsule);
return type_map;
}
}
Dtool_PyTypedObject *Dtool_RuntimeTypeDtoolType(int type) {
RuntimeTypeMap::iterator di = runtime_type_map.find(type);
if (di != runtime_type_map.end()) {
return di->second;
} else {
int type2 = get_best_parent_from_Set(type, runtime_type_set);
di = runtime_type_map.find(type2);
if (di != runtime_type_map.end()) {
return di->second;
}
}
return nullptr;
return (Dtool_PyTypedObject *)TypeHandle::from_index(type).get_python_type();
}
#if PY_MAJOR_VERSION >= 3
PyObject *Dtool_PyModuleInitHelper(LibraryDef *defs[], PyModuleDef *module_def) {
PyObject *Dtool_PyModuleInitHelper(const LibraryDef *defs[], PyModuleDef *module_def) {
#else
PyObject *Dtool_PyModuleInitHelper(LibraryDef *defs[], const char *modulename) {
PyObject *Dtool_PyModuleInitHelper(const LibraryDef *defs[], const char *modulename) {
#endif
// Check the version so we can print a helpful error if it doesn't match.
string version = Py_GetVersion();
@ -672,10 +589,40 @@ PyObject *Dtool_PyModuleInitHelper(LibraryDef *defs[], const char *modulename) {
Dtool_PyModuleClassInit_DTOOL_SUPER_BASE(nullptr);
}
Dtool_TypeMap *type_map = Dtool_GetGlobalTypeMap();
// the module level function inits....
MethodDefmap functions;
for (int xx = 0; defs[xx] != nullptr; xx++) {
Dtool_Accum_MethDefs(defs[xx]->_methods, functions);
for (size_t i = 0; defs[i] != nullptr; i++) {
const LibraryDef &def = *defs[i];
Dtool_Accum_MethDefs(def._methods, functions);
// Define exported types.
const Dtool_TypeDef *types = def._types;
if (types != nullptr) {
while (types->name != nullptr) {
(*type_map)[std::string(types->name)] = types->type;
++types;
}
}
}
// Resolve external types, in a second pass.
for (size_t i = 0; defs[i] != nullptr; i++) {
const LibraryDef &def = *defs[i];
Dtool_TypeDef *types = def._external_types;
if (types != nullptr) {
while (types->name != nullptr) {
auto it = type_map->find(std::string(types->name));
if (it != type_map->end()) {
types->type = it->second;
} else {
return PyErr_Format(PyExc_NameError, "name '%s' is not defined", types->name);
}
++types;
}
}
}
PyMethodDef *newdef = new PyMethodDef[functions.size() + 1];

View File

@ -190,11 +190,9 @@ static void Dtool_FreeInstance_##CLASS_NAME(PyObject *self) {\
// forward declared of typed object. We rely on the fact that typed objects
// are uniquly defined by an integer.
EXPCL_INTERROGATEDB void RegisterNamedClass(const std::string &name, Dtool_PyTypedObject &otype);
EXPCL_INTERROGATEDB void RegisterRuntimeTypedClass(Dtool_PyTypedObject &otype);
typedef std::map<std::string, Dtool_PyTypedObject *> Dtool_TypeMap;
EXPCL_INTERROGATEDB Dtool_PyTypedObject *LookupNamedClass(const std::string &name);
EXPCL_INTERROGATEDB Dtool_PyTypedObject *LookupRuntimeTypedClass(TypeHandle handle);
EXPCL_INTERROGATEDB Dtool_TypeMap *Dtool_GetGlobalTypeMap();
EXPCL_INTERROGATEDB Dtool_PyTypedObject *Dtool_RuntimeTypeDtoolType(int type);
@ -326,14 +324,22 @@ EXPCL_INTERROGATEDB void Dtool_Accum_MethDefs(PyMethodDef in[], MethodDefmap &th
// We need a way to runtime merge compile units into a python "Module" .. this
// is done with the fallowing structors and code.. along with the support of
// interigate_module
struct Dtool_TypeDef {
const char *const name;
Dtool_PyTypedObject *type;
};
struct LibraryDef {
PyMethodDef *_methods;
PyMethodDef *const _methods;
const Dtool_TypeDef *const _types;
Dtool_TypeDef *const _external_types;
};
#if PY_MAJOR_VERSION >= 3
EXPCL_INTERROGATEDB PyObject *Dtool_PyModuleInitHelper(LibraryDef *defs[], PyModuleDef *module_def);
EXPCL_INTERROGATEDB PyObject *Dtool_PyModuleInitHelper(const LibraryDef *defs[], PyModuleDef *module_def);
#else
EXPCL_INTERROGATEDB PyObject *Dtool_PyModuleInitHelper(LibraryDef *defs[], const char *modulename);
EXPCL_INTERROGATEDB PyObject *Dtool_PyModuleInitHelper(const LibraryDef *defs[], const char *modulename);
#endif
// HACK.... Be carefull Dtool_BorrowThisReference This function can be used to