@@ -3174,9 +3174,10 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
3174
3174
la = & co_opcache -> u .la ;
3175
3175
if (la -> type == type && la -> tp_version_tag == type -> tp_version_tag )
3176
3176
{
3177
- // Hint >= 0 is a dict index; hint < 0 is an inverted slot index.
3178
- if (la -> hint < 0 ) {
3179
- /* Even faster path -- slot hint */
3177
+ // Hint >= 0 is a dict index; hint == -1 is a dict miss.
3178
+ // Hint < -1 is an inverted slot offset (offsets are never 0).
3179
+ if (la -> hint < -1 ) {
3180
+ // Even faster path -- slot hint.
3180
3181
Py_ssize_t offset = ~la -> hint ;
3181
3182
// fprintf(stderr, "Using hint for offset %zd\n", offset);
3182
3183
char * addr = (char * )owner + offset ;
@@ -3190,7 +3191,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
3190
3191
// Else slot is NULL. Fall through to slow path to raise AttributeError(name).
3191
3192
// Don't DEOPT, since the slot is still there.
3192
3193
} else {
3193
- // Fast path for dict
3194
+ // Fast path for dict.
3194
3195
assert (type -> tp_dict != NULL );
3195
3196
assert (type -> tp_dictoffset > 0 );
3196
3197
@@ -3204,11 +3205,11 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
3204
3205
3205
3206
if (res != NULL ) {
3206
3207
if (la -> hint == hint && hint >= 0 ) {
3207
- /* Our hint has helped -- cache hit. */
3208
+ // Our hint has helped -- cache hit.
3208
3209
OPCACHE_STAT_ATTR_HIT ();
3209
3210
} else {
3210
- /* The hint we provided didn't work.
3211
- Maybe next time? */
3211
+ // The hint we provided didn't work.
3212
+ // Maybe next time?
3212
3213
OPCACHE_MAYBE_DEOPT_LOAD_ATTR ();
3213
3214
}
3214
3215
@@ -3218,13 +3219,13 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
3218
3219
Py_DECREF (dict );
3219
3220
DISPATCH ();
3220
3221
} else {
3221
- // This attribute can be missing sometimes -- we
3222
- // don't want to optimize this lookup.
3222
+ // This attribute can be missing sometimes;
3223
+ // we don't want to optimize this lookup.
3223
3224
OPCACHE_DEOPT_LOAD_ATTR ();
3224
3225
Py_DECREF (dict );
3225
3226
}
3226
3227
} else {
3227
- // There is no dict, or __dict__ doesn't satisfy PyDict_CheckExact
3228
+ // There is no dict, or __dict__ doesn't satisfy PyDict_CheckExact.
3228
3229
OPCACHE_DEOPT_LOAD_ATTR ();
3229
3230
}
3230
3231
}
@@ -3236,7 +3237,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
3236
3237
OPCACHE_STAT_ATTR_MISS ();
3237
3238
}
3238
3239
3239
- if (co_opcache != NULL && /* co_opcache can be NULL after a DEOPT() call. */
3240
+ if (co_opcache != NULL && // co_opcache can be NULL after a DEOPT() call.
3240
3241
type -> tp_getattro == PyObject_GenericGetAttr )
3241
3242
{
3242
3243
if (type -> tp_dict == NULL ) {
@@ -3255,6 +3256,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
3255
3256
struct PyMemberDef * dmem = member -> d_member ;
3256
3257
if (dmem -> type == T_OBJECT_EX ) {
3257
3258
Py_ssize_t offset = dmem -> offset ;
3259
+ assert (offset > 0 ); // 0 would be confused with dict hint == -1 (miss).
3258
3260
3259
3261
if (co_opcache -> optimized == 0 ) {
3260
3262
// First time we optimize this opcode.
@@ -3291,7 +3293,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
3291
3293
if (dict != NULL && PyDict_CheckExact (dict )) {
3292
3294
Py_INCREF (dict );
3293
3295
res = NULL ;
3294
- Py_ssize_t ret = _PyDict_GetItemHint ((PyDictObject * )dict , name , -1 , & res );
3296
+ Py_ssize_t hint = _PyDict_GetItemHint ((PyDictObject * )dict , name , -1 , & res );
3295
3297
if (res != NULL ) {
3296
3298
Py_INCREF (res );
3297
3299
Py_DECREF (dict );
@@ -3307,25 +3309,25 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
3307
3309
la = & co_opcache -> u .la ;
3308
3310
la -> type = type ;
3309
3311
la -> tp_version_tag = type -> tp_version_tag ;
3310
- la -> hint = ret ;
3312
+ la -> hint = hint ;
3311
3313
3312
3314
DISPATCH ();
3313
3315
}
3314
3316
Py_DECREF (dict );
3315
3317
} else {
3316
- // There is no dict, or __dict__ doesn't satisfy PyDict_CheckExact
3318
+ // There is no dict, or __dict__ doesn't satisfy PyDict_CheckExact.
3317
3319
OPCACHE_DEOPT_LOAD_ATTR ();
3318
3320
}
3319
3321
} else {
3320
- // The object's class does not have a tp_dictoffset we can use
3322
+ // The object's class does not have a tp_dictoffset we can use.
3321
3323
OPCACHE_DEOPT_LOAD_ATTR ();
3322
3324
}
3323
3325
} else if (type -> tp_getattro != PyObject_GenericGetAttr ) {
3324
3326
OPCACHE_DEOPT_LOAD_ATTR ();
3325
3327
}
3326
3328
}
3327
3329
3328
- /* slow path */
3330
+ // Slow path.
3329
3331
res = PyObject_GetAttr (owner , name );
3330
3332
Py_DECREF (owner );
3331
3333
SET_TOP (res );
0 commit comments