_PyBloomFilter dependencies;
} _PyJitTracerPreviousState;
+typedef struct _PyJitTracerTranslatorState {
+ int jump_backward_seen;
+} _PyJitTracerTranslatorState;
+
typedef struct _PyJitTracerState {
_PyUOpInstruction *code_buffer;
_PyJitTracerInitialState initial_state;
_PyJitTracerPreviousState prev_state;
+ _PyJitTracerTranslatorState translator_state;
} _PyJitTracerState;
#endif
self.assertIsNotNone(ex)
self.assertIn("_FOR_ITER_TIER_TWO", get_opnames(ex))
- @unittest.skip("Tracing into generators currently isn't supported.")
- def test_for_iter_gen(self):
- def gen(n):
- for i in range(n):
- yield i
- def testfunc(n):
- g = gen(n)
- s = 0
- for i in g:
- s += i
- return s
- res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD)
- self.assertEqual(res, sum(range(TIER2_THRESHOLD)))
- self.assertIsNotNone(ex)
- self.assertIn("_FOR_ITER_GEN_FRAME", get_opnames(ex))
-
def test_modified_local_is_seen_by_optimized_code(self):
l = sys._getframe().f_locals
a = 1
self.assertIn("_POP_TOP_NOP", uops)
self.assertLessEqual(count_ops(ex, "_POP_TOP"), 2)
+ def test_for_iter_gen_frame(self):
+ def f(n):
+ for i in range(n):
+ # Should be optimized to POP_TOP_NOP
+ yield i + i
+ def testfunc(n):
+ for _ in f(n):
+ pass
+
+ res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD*2)
+ self.assertIsNotNone(ex)
+ uops = get_opnames(ex)
+
+ self.assertIn("_FOR_ITER_GEN_FRAME", uops)
+ # _POP_TOP_NOP is a sign the optimizer ran and didn't hit bottom.
+ self.assertGreaterEqual(count_ops(ex, "_POP_TOP_NOP"), 1)
+
+ def test_send_gen_frame(self):
+
+ def gen(n):
+ for i in range(n):
+ yield i + i
+ def send_gen(n):
+ yield from gen(n)
+ def testfunc(n):
+ for _ in send_gen(n):
+ pass
+
+ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
+ # Ensure SEND is specialized to SEND_GEN
+ send_gen(10)
+
+ res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD*2)
+ self.assertIsNotNone(ex)
+ uops = get_opnames(ex)
+
+ self.assertIn("_FOR_ITER_GEN_FRAME", uops)
+ self.assertIn("_SEND_GEN_FRAME", uops)
+ # _POP_TOP_NOP is a sign the optimizer ran and didn't hit bottom.
+ self.assertGreaterEqual(count_ops(ex, "_POP_TOP_NOP"), 1)
+
def test_143026(self):
# https://github.com/python/cpython/issues/143026
--- /dev/null
+The JIT optimizer now understands more generator instructions.
}
op(_FOR_ITER_GEN_FRAME, (unused, unused -- unused, unused, gen_frame)) {
- gen_frame = PyJitRef_NULL;
- /* We are about to hit the end of the trace */
- ctx->done = true;
+ assert((this_instr + 1)->opcode == _PUSH_FRAME);
+ PyCodeObject *co = get_code_with_logging((this_instr + 1));
+ if (co == NULL) {
+ ctx->done = true;
+ break;
+ }
+ _Py_UOpsAbstractFrame *new_frame = frame_new(ctx, co, 1, NULL, 0);
+ if (new_frame == NULL) {
+ ctx->done = true;
+ break;
+ }
+ new_frame->stack[0] = sym_new_const(ctx, Py_None);
+ gen_frame = PyJitRef_Wrap((JitOptSymbol *)new_frame);
}
- op(_SEND_GEN_FRAME, (unused, unused -- unused, gen_frame)) {
- gen_frame = PyJitRef_NULL;
- // We are about to hit the end of the trace:
- ctx->done = true;
+ op(_SEND_GEN_FRAME, (unused, v -- unused, gen_frame)) {
+ assert((this_instr + 1)->opcode == _PUSH_FRAME);
+ PyCodeObject *co = get_code_with_logging((this_instr + 1));
+ if (co == NULL) {
+ ctx->done = true;
+ break;
+ }
+ _Py_UOpsAbstractFrame *new_frame = frame_new(ctx, co, 1, NULL, 0);
+ if (new_frame == NULL) {
+ ctx->done = true;
+ break;
+ }
+ new_frame->stack[0] = PyJitRef_StripReferenceInfo(v);
+ gen_frame = PyJitRef_Wrap((JitOptSymbol *)new_frame);
}
op(_CHECK_STACK_SPACE, (unused, unused, unused[oparg] -- unused, unused, unused[oparg])) {
/* _SEND is not a viable micro-op for tier 2 */
case _SEND_GEN_FRAME: {
+ JitOptRef v;
JitOptRef gen_frame;
- gen_frame = PyJitRef_NULL;
- ctx->done = true;
+ v = stack_pointer[-1];
+ assert((this_instr + 1)->opcode == _PUSH_FRAME);
+ PyCodeObject *co = get_code_with_logging((this_instr + 1));
+ if (co == NULL) {
+ ctx->done = true;
+ break;
+ }
+ _Py_UOpsAbstractFrame *new_frame = frame_new(ctx, co, 1, NULL, 0);
+ if (new_frame == NULL) {
+ ctx->done = true;
+ break;
+ }
+ new_frame->stack[0] = PyJitRef_StripReferenceInfo(v);
+ gen_frame = PyJitRef_Wrap((JitOptSymbol *)new_frame);
stack_pointer[-1] = gen_frame;
break;
}
case _FOR_ITER_GEN_FRAME: {
JitOptRef gen_frame;
- gen_frame = PyJitRef_NULL;
- ctx->done = true;
+ assert((this_instr + 1)->opcode == _PUSH_FRAME);
+ PyCodeObject *co = get_code_with_logging((this_instr + 1));
+ if (co == NULL) {
+ ctx->done = true;
+ break;
+ }
+ _Py_UOpsAbstractFrame *new_frame = frame_new(ctx, co, 1, NULL, 0);
+ if (new_frame == NULL) {
+ ctx->done = true;
+ break;
+ }
+ new_frame->stack[0] = sym_new_const(ctx, Py_None);
+ gen_frame = PyJitRef_Wrap((JitOptSymbol *)new_frame);
CHECK_STACK_BOUNDS(1);
stack_pointer[0] = gen_frame;
stack_pointer += 1;