@@ -3444,6 +3444,34 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
3444
3444
}
3445
3445
}
3446
3446
3447
+ TARGET (LOAD_FAST__LOAD_ATTR_INSTANCE_VALUE ) {
3448
+ assert (cframe .use_tracing == 0 );
3449
+ PyObject * owner = GETLOCAL (oparg ); // borrowed
3450
+ if (owner == NULL ) {
3451
+ goto unbound_local_error ;
3452
+ }
3453
+ // GET_CACHE(), but for the following opcode
3454
+ assert (_Py_OPCODE (* next_instr ) == LOAD_ATTR_INSTANCE_VALUE );
3455
+ SpecializedCacheEntry * caches = _GetSpecializedCacheEntryForInstruction (
3456
+ first_instr , INSTR_OFFSET () + 1 , _Py_OPARG (* next_instr ));
3457
+ _PyAdaptiveEntry * cache0 = & caches [0 ].adaptive ;
3458
+ assert (cache0 -> version != 0 );
3459
+ PyTypeObject * tp = Py_TYPE (owner );
3460
+ // These DEOPT_IF miss branches do PUSH(Py_NewRef(owner)).
3461
+ DEOPT_IF (tp -> tp_version_tag != cache0 -> version ,
3462
+ LOAD_FAST__LOAD_ATTR_INSTANCE_VALUE );
3463
+ assert (tp -> tp_dictoffset < 0 );
3464
+ assert (tp -> tp_flags & Py_TPFLAGS_MANAGED_DICT );
3465
+ PyDictValues * values = * _PyObject_ValuesPointer (owner );
3466
+ DEOPT_IF (values == NULL , LOAD_FAST__LOAD_ATTR_INSTANCE_VALUE );
3467
+ PyObject * res = values -> values [cache0 -> index ];
3468
+ DEOPT_IF (res == NULL , LOAD_FAST__LOAD_ATTR_INSTANCE_VALUE );
3469
+ STAT_INC (LOAD_ATTR , hit );
3470
+ PUSH (Py_NewRef (res ));
3471
+ next_instr ++ ;
3472
+ NOTRACE_DISPATCH ();
3473
+ }
3474
+
3447
3475
TARGET (LOAD_ATTR_INSTANCE_VALUE ) {
3448
3476
assert (cframe .use_tracing == 0 );
3449
3477
PyObject * owner = TOP ();
@@ -3452,13 +3480,13 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
3452
3480
SpecializedCacheEntry * caches = GET_CACHE ();
3453
3481
_PyAdaptiveEntry * cache0 = & caches [0 ].adaptive ;
3454
3482
assert (cache0 -> version != 0 );
3455
- DEOPT_IF (tp -> tp_version_tag != cache0 -> version , LOAD_ATTR );
3483
+ DEOPT_IF (tp -> tp_version_tag != cache0 -> version , LOAD_ATTR_INSTANCE_VALUE );
3456
3484
assert (tp -> tp_dictoffset < 0 );
3457
3485
assert (tp -> tp_flags & Py_TPFLAGS_MANAGED_DICT );
3458
3486
PyDictValues * values = * _PyObject_ValuesPointer (owner );
3459
- DEOPT_IF (values == NULL , LOAD_ATTR );
3487
+ DEOPT_IF (values == NULL , LOAD_ATTR_INSTANCE_VALUE );
3460
3488
res = values -> values [cache0 -> index ];
3461
- DEOPT_IF (res == NULL , LOAD_ATTR );
3489
+ DEOPT_IF (res == NULL , LOAD_ATTR_INSTANCE_VALUE );
3462
3490
STAT_INC (LOAD_ATTR , hit );
3463
3491
Py_INCREF (res );
3464
3492
SET_TOP (res );
@@ -5515,6 +5543,52 @@ MISS_WITH_CACHE(BINARY_SUBSCR)
5515
5543
MISS_WITH_CACHE (UNPACK_SEQUENCE )
5516
5544
MISS_WITH_OPARG_COUNTER (STORE_SUBSCR )
5517
5545
5546
+ LOAD_ATTR_INSTANCE_VALUE_miss :
5547
+ {
5548
+ // Special-cased so that if LOAD_ATTR_INSTANCE_VALUE
5549
+ // gets replaced, then any preceeding
5550
+ // LOAD_FAST__LOAD_ATTR_INSTANCE_VALUE gets replaced as well
5551
+ STAT_INC (LOAD_ATTR_INSTANCE_VALUE , miss );
5552
+ STAT_INC (LOAD_ATTR , miss );
5553
+ _PyAdaptiveEntry * cache = & GET_CACHE ()-> adaptive ;
5554
+ cache -> counter -- ;
5555
+ if (cache -> counter == 0 ) {
5556
+ next_instr [-1 ] = _Py_MAKECODEUNIT (LOAD_ATTR_ADAPTIVE , _Py_OPARG (next_instr [-1 ]));
5557
+ if (_Py_OPCODE (next_instr [-2 ]) == LOAD_FAST__LOAD_ATTR_INSTANCE_VALUE ) {
5558
+ next_instr [-2 ] = _Py_MAKECODEUNIT (LOAD_FAST , _Py_OPARG (next_instr [-2 ]));
5559
+ if (_Py_OPCODE (next_instr [-3 ]) == LOAD_FAST ) {
5560
+ next_instr [-3 ] = _Py_MAKECODEUNIT (LOAD_FAST__LOAD_FAST , _Py_OPARG (next_instr [-3 ]));
5561
+ }
5562
+ }
5563
+ STAT_INC (LOAD_ATTR , deopt );
5564
+ cache_backoff (cache );
5565
+ }
5566
+ oparg = cache -> original_oparg ;
5567
+ JUMP_TO_INSTRUCTION (LOAD_ATTR );
5568
+ }
5569
+
5570
+ LOAD_FAST__LOAD_ATTR_INSTANCE_VALUE_miss :
5571
+ {
5572
+ // This is special-cased because we have a superinstruction
5573
+ // that includes a specialized instruction.
5574
+ // If the specialized portion misses, carry out
5575
+ // the first instruction, then perform a miss
5576
+ // for the second instruction as usual.
5577
+
5578
+ // Do LOAD_FAST
5579
+ {
5580
+ PyObject * value = GETLOCAL (oparg );
5581
+ assert (value != NULL ); // Already checked if unbound
5582
+ Py_INCREF (value );
5583
+ PUSH (value );
5584
+ NEXTOPARG ();
5585
+ next_instr ++ ;
5586
+ }
5587
+
5588
+ // Now we are in the correct state for LOAD_ATTR
5589
+ goto LOAD_ATTR_INSTANCE_VALUE_miss ;
5590
+ }
5591
+
5518
5592
binary_subscr_dict_error :
5519
5593
{
5520
5594
PyObject * sub = POP ();
0 commit comments