between a block and an object file. When a block is created also
store a pointer to the object file for later use. */
struct objfile *objfile;
- /* Keep track of all blocks with a doubly-linked list. Needed for
- block invalidation if the source object file has been freed. */
- block_object *prev;
- block_object *next;
};
struct block_syms_iterator_object {
} \
} while (0)
-/* This is called when an objfile is about to be freed.
- Invalidate the block as further actions on the block would result
- in bad data. All access to obj->symbol should be gated by
- BLPY_REQUIRE_VALID which will raise an exception on invalid
- blocks. */
-struct blpy_deleter
-{
- void operator() (block_object *obj)
- {
- while (obj)
- {
- block_object *next = obj->next;
-
- obj->block = NULL;
- obj->objfile = NULL;
- obj->next = NULL;
- obj->prev = NULL;
-
- obj = next;
- }
- }
-};
-
extern PyTypeObject block_syms_iterator_object_type
CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("block_syms_iterator_object");
-static const registry<objfile>::key<block_object, blpy_deleter>
+static const registry<objfile>::key<htab, htab_deleter>
blpy_objfile_data_key;
static PyObject *
return nullptr;
}
+/* Deleter function for the hash table. */
+
static void
-blpy_dealloc (PyObject *obj)
+block_object_del (void *obj)
{
block_object *block = (block_object *) obj;
+ block->block = nullptr;
+ block->objfile = nullptr;
+}
- if (block->prev)
- block->prev->next = block->next;
- else if (block->objfile)
- blpy_objfile_data_key.set (block->objfile, block->next);
- if (block->next)
- block->next->prev = block->prev;
- block->block = NULL;
- Py_TYPE (obj)->tp_free (obj);
+/* Hash function for the hash table. */
+
+static hashval_t
+block_object_hash (const void *obj)
+{
+ const block_object *block = (const block_object *) obj;
+ return htab_hash_pointer (block->block);
+}
+
+/* Equality function for the hash table. Note that searches must be
+ done with a plain block. */
+
+static int
+block_object_eq (const void *a, const void *b)
+{
+ const block_object *blocka = (const block_object *) a;
+ const block *blockb = (const block *) b;
+ return blocka->block == blockb;
}
-/* Given a block, and a block_object that has previously been
- allocated and initialized, populate the block_object with the
- struct block data. Also, register the block_object life-cycle
- with the life-cycle of the object file associated with this
- block, if needed. */
+/* Called when a gdb.Block is destroyed. This removes it from the
+ hash. */
+
static void
-set_block (block_object *obj, const struct block *block,
- struct objfile *objfile)
+blpy_dealloc (PyObject *obj)
{
- obj->block = block;
- obj->prev = NULL;
- if (objfile)
+ block_object *block = (block_object *) obj;
+
+ if (block->objfile != nullptr)
{
- obj->objfile = objfile;
- obj->next = blpy_objfile_data_key.get (objfile);
- if (obj->next)
- obj->next->prev = obj;
- blpy_objfile_data_key.set (objfile, obj);
+ htab_t table = blpy_objfile_data_key.get (block->objfile);
+ hashval_t hash = block_object_hash (block);
+ /* This will clear the contents of the block as a side
+ effect. */
+ htab_remove_elt_with_hash (table, block->block, hash);
}
- else
- obj->next = NULL;
+
+ Py_TYPE (obj)->tp_free (obj);
}
/* Create a new block object (gdb.Block) that encapsulates the struct
PyObject *
block_to_block_object (const struct block *block, struct objfile *objfile)
{
- block_object *block_obj;
+ htab_t table = blpy_objfile_data_key.get (objfile);
+ if (table == nullptr)
+ {
+ table = htab_create_alloc (10, block_object_hash, block_object_eq,
+ block_object_del, xcalloc, xfree);
+ blpy_objfile_data_key.set (objfile, table);
+ }
+
+ hashval_t hash = htab_hash_pointer (block);
+ block_object *result = (block_object *) htab_find_with_hash (table, block,
+ hash);
+ if (result != nullptr)
+ {
+ PyObject *py_result = (PyObject *) result;
+ Py_INCREF (py_result);
+ return py_result;
+ }
+
+ result = PyObject_New (block_object, &block_object_type);
+ result->block = block;
+ result->objfile = objfile;
- block_obj = PyObject_New (block_object, &block_object_type);
- if (block_obj)
- set_block (block_obj, block, objfile);
+ void **slot = htab_find_slot_with_hash (table, block, hash, INSERT);
+ *slot = result;
- return (PyObject *) block_obj;
+ return (PyObject *) result;
}
/* Return struct block reference that is wrapped by this object. */
name, str.c_str ());
}
+/* Hash function for block objects. */
+
+static Py_hash_t
+blpy_hash (PyObject *self)
+{
+ /* Python doesn't really expose its pointer hash function, so we use
+ our own. */
+ Py_hash_t result = (Py_hash_t) htab_hash_pointer (self);
+ /* -1 has a special meaning for Python. */
+ if (result == -1)
+ result = -2;
+ return result;
+}
+
/* Implements the equality comparison for Block objects. All other
comparison operators will throw NotImplemented, as they aren't
valid for blocks. */
return Py_NotImplemented;
}
- block_object *self_block = (block_object *) self;
- block_object *other_block = (block_object *) other;
-
- bool expected = self_block->block == other_block->block;
+ bool expected = self == other;
bool equal = op == Py_EQ;
return PyBool_FromLong (equal == expected);
}
0, /*tp_as_number*/
0, /*tp_as_sequence*/
&block_object_as_mapping, /*tp_as_mapping*/
- 0, /*tp_hash */
+ blpy_hash, /*tp_hash */
0, /*tp_call*/
0, /*tp_str*/
0, /*tp_getattro*/