~jelmer/meliae/hurd

« back to all changes in this revision

Viewing changes to meliae/_scanner_core.c

  • Committer: John Arbash Meinel
  • Date: 2010-08-10 16:21:52 UTC
  • mfrom: (183.1.6 special_cases)
  • Revision ID: john@arbash-meinel.com-20100810162152-kwinrlv78flsdox5
We now support custom sizeof methods registered at runtime.

Show diffs side-by-side

added added

removed removed

Lines of Context:
60
60
#else
61
61
static void _write_to_ref_info(struct ref_info *info, const char *fmt_string, ...);
62
62
#endif
 
63
static PyObject * _get_specials();
63
64
 
64
65
/* The address of the last thing we dumped. Stuff like dumping the string
65
66
 * interned dictionary will dump the same string 2x in a row. This helps
66
67
 * prevent that.
67
68
 */
68
69
static PyObject *_last_dumped = NULL;
 
70
static PyObject *_special_case_dict = NULL;
69
71
 
70
72
void
71
73
_clear_last_dumped()
73
75
    _last_dumped = NULL;
74
76
}
75
77
 
76
 
Py_ssize_t
 
78
static Py_ssize_t
77
79
_basic_object_size(PyObject *c_obj)
78
80
{
79
81
    Py_ssize_t size;
85
87
}
86
88
 
87
89
 
88
 
Py_ssize_t
 
90
static Py_ssize_t
89
91
_var_object_size(PyVarObject *c_obj)
90
92
{
91
93
    Py_ssize_t num_entries;
99
101
            + num_entries * c_obj->ob_type->tp_itemsize;
100
102
}
101
103
 
102
 
Py_ssize_t
 
104
static Py_ssize_t
 
105
_object_to_size_with_gc(PyObject *size_obj, PyObject *c_obj)
 
106
{
 
107
    Py_ssize_t size = -1;
 
108
 
 
109
    size = PyInt_AsSsize_t(size_obj);
 
110
    if (size == -1) {
 
111
        // Probably an error occurred, we don't know for sure, but we might as
 
112
        // well just claim that we don't know the size. We *could* check
 
113
        // PyErr_Occurred(), but if we are just clearing it anyway...
 
114
        PyErr_Clear();
 
115
        return -1;
 
116
    }
 
117
    // There is one trick left. Namely, __sizeof__ doesn't include the
 
118
    // GC overhead, so let's add that back in
 
119
    if (PyType_HasFeature(Py_TYPE(c_obj), Py_TPFLAGS_HAVE_GC)) {
 
120
        size += sizeof(PyGC_Head);
 
121
    }
 
122
    return size;
 
123
}
 
124
 
 
125
static Py_ssize_t
103
126
_size_of_from__sizeof__(PyObject *c_obj)
104
127
{
105
128
    PyObject *size_obj = NULL;
117
140
        PyErr_Clear();
118
141
        return -1;
119
142
    }
120
 
    size = PyInt_AsSsize_t(size_obj);
121
 
    if (size == -1) {
122
 
        // Probably an error occurred, we don't know for sure, but we might as
123
 
        // well just claim that we don't know the size. We *could* check
124
 
        // PyErr_Occurred(), but if we are just clearing it anyway...
125
 
        PyErr_Clear();
126
 
        return -1;
127
 
    }
128
 
    // There is one trick left. Namely, __sizeof__ doesn't seem to include the
129
 
    // GC overhead, so let's add that back in
130
 
    if (PyType_HasFeature(c_obj->ob_type, Py_TPFLAGS_HAVE_GC)) {
131
 
        size += sizeof(PyGC_Head);
132
 
    }
 
143
    size = _object_to_size_with_gc(size_obj, c_obj);
 
144
    Py_DECREF(size_obj);
133
145
    return size;
134
146
}
135
147
 
136
148
 
137
 
Py_ssize_t
 
149
static Py_ssize_t
138
150
_size_of_list(PyListObject *c_obj)
139
151
{
140
152
    Py_ssize_t size;
144
156
}
145
157
 
146
158
 
147
 
Py_ssize_t
 
159
static Py_ssize_t
148
160
_size_of_set(PySetObject *c_obj)
149
161
{
150
162
    Py_ssize_t size;
156
168
}
157
169
 
158
170
 
159
 
Py_ssize_t
 
171
static Py_ssize_t
160
172
_size_of_dict(PyDictObject *c_obj)
161
173
{
162
174
    Py_ssize_t size;
168
180
}
169
181
 
170
182
 
171
 
Py_ssize_t
 
183
static Py_ssize_t
172
184
_size_of_unicode(PyUnicodeObject *c_obj)
173
185
{
174
186
    Py_ssize_t size;
177
189
    return size;
178
190
}
179
191
 
 
192
static Py_ssize_t
 
193
_size_of_from_specials(PyObject *c_obj)
 
194
{
 
195
    PyObject *special_dict;
 
196
    PyObject *special_size_of;
 
197
    PyObject *val;
 
198
    Py_ssize_t size;
 
199
 
 
200
    special_dict = _get_specials();
 
201
    if (special_dict == NULL) {
 
202
        PyErr_Clear(); // Not sure what happened, but don't propogate it
 
203
        return -1;
 
204
    }
 
205
    special_size_of = PyDict_GetItemString(special_dict,
 
206
                                           Py_TYPE(c_obj)->tp_name);
 
207
    if (special_size_of == NULL) {
 
208
        // if special_size_of is NULL, an exception is *not* set
 
209
        return -1;
 
210
    } 
 
211
    // special_size_of is a *borrowed referenced*
 
212
    val = PyObject_CallFunction(special_size_of, "O", c_obj);
 
213
    if (val == NULL) {
 
214
        return -1;
 
215
    }
 
216
    size = _object_to_size_with_gc(val, c_obj);
 
217
    Py_DECREF(val);
 
218
    return size;
 
219
}
 
220
 
 
221
static Py_ssize_t
 
222
_size_of_from_var_or_basic_size(PyObject *c_obj)
 
223
{
 
224
    /* There are a bunch of types that we know we can check directly, without
 
225
     * having to go through the __sizeof__ abstraction. This allows us to avoid
 
226
     * the extra intermediate allocations. It is also our final fallback
 
227
     * method.
 
228
     */
 
229
 
 
230
    if (c_obj->ob_type->tp_itemsize != 0) {
 
231
        // Variable length object with inline storage
 
232
        // total size is tp_itemsize * ob_size
 
233
        return _var_object_size((PyVarObject *)c_obj);
 
234
    }
 
235
    return _basic_object_size(c_obj);
 
236
}
180
237
 
181
238
Py_ssize_t
182
239
_size_of(PyObject *c_obj)
191
248
        return _size_of_dict((PyDictObject *)c_obj);
192
249
    } else if PyUnicode_Check(c_obj) {
193
250
        return _size_of_unicode((PyUnicodeObject *)c_obj);
 
251
    } else if (PyTuple_CheckExact(c_obj)
 
252
            || PyString_CheckExact(c_obj)
 
253
            || PyInt_CheckExact(c_obj)
 
254
            || PyBool_Check(c_obj)
 
255
            || c_obj == Py_None
 
256
            || PyModule_CheckExact(c_obj))
 
257
    {
 
258
        // All of these implement __sizeof__, but we don't need to use it
 
259
        return _size_of_from_var_or_basic_size(c_obj);
194
260
    }
195
261
 
 
262
    // object implements __sizeof__ so we have to specials first
 
263
    size = _size_of_from_specials(c_obj);
 
264
    if (size != -1) {
 
265
        return size;
 
266
    }
196
267
    size = _size_of_from__sizeof__(c_obj);
197
268
    if (size != -1) {
198
269
        return size;
199
270
    }
200
 
 
201
 
    if (c_obj->ob_type->tp_itemsize != 0) {
202
 
        // Variable length object with inline storage
203
 
        // total size is tp_itemsize * ob_size
204
 
        return _var_object_size((PyVarObject *)c_obj);
205
 
    }
206
 
    return _basic_object_size(c_obj);
 
271
    return _size_of_from_var_or_basic_size(c_obj);
207
272
}
208
273
 
209
274
 
527
592
/**
528
593
 * Return a PyList of all objects referenced via tp_traverse.
529
594
 */
530
 
PyObject *_get_referents(PyObject *c_obj)
 
595
PyObject *
 
596
_get_referents(PyObject *c_obj)
531
597
{
532
598
    PyObject *lst;
533
599
 
543
609
    }
544
610
    return lst;
545
611
}
 
612
 
 
613
static PyObject *
 
614
_get_specials()
 
615
{
 
616
    if (_special_case_dict == NULL) {
 
617
        _special_case_dict = PyDict_New();
 
618
    }
 
619
    return _special_case_dict;
 
620
}
 
621
 
 
622
PyObject *
 
623
_get_special_case_dict()
 
624
{
 
625
    PyObject *ret;
 
626
 
 
627
    ret = _get_specials();
 
628
    Py_XINCREF(ret);
 
629
    return ret;
 
630
}