Commit graph

179 commits

Author SHA1 Message Date
Mark Shannon
b420f6be53
GH-139109: Support switch/case dispatch with the tracing interpreter. (GH-141703) 2025-11-18 13:31:48 +00:00
Ken Jin
4fa80ce74c
gh-139109: A new tracing JIT compiler frontend for CPython (GH-140310)
This PR changes the current JIT model from trace projection to trace recording. Benchmarking: better pyperformance (about 1.7% overall) geomean versus current https://raw.githubusercontent.com/facebookexperimental/free-threading-benchmarking/refs/heads/main/results/bm-20251108-3.15.0a1%2B-7e2bc1d-JIT/bm-20251108-vultr-x86_64-Fidget%252dSpinner-tracing_jit-3.15.0a1%2B-7e2bc1d-vs-base.svg, 100% faster Richards on the most improved benchmark versus the current JIT. Slowdown of about 10-15% on the worst benchmark versus the current JIT. **Note: the fastest version isn't the one merged, as it relies on fixing bugs in the specializing interpreter, which is left to another PR**. The speedup in the merged version is about 1.1%. https://raw.githubusercontent.com/facebookexperimental/free-threading-benchmarking/refs/heads/main/results/bm-20251112-3.15.0a1%2B-f8a764a-JIT/bm-20251112-vultr-x86_64-Fidget%252dSpinner-tracing_jit-3.15.0a1%2B-f8a764a-vs-base.svg

Stats: 50% more uops executed, 30% more traces entered the last time we ran them. It also suggests our trace lengths for a real trace recording JIT are too short, as a lot of trace too long aborts https://github.com/facebookexperimental/free-threading-benchmarking/blob/main/results/bm-20251023-3.15.0a1%2B-eb73378-CLANG%2CJIT/bm-20251023-vultr-x86_64-Fidget%252dSpinner-tracing_jit-3.15.0a1%2B-eb73378-pystats-vs-base.md .

This new JIT frontend is already able to record/execute significantly more instructions than the previous JIT frontend. In this PR, we are now able to record through custom dunders, simple object creation, generators, etc. None of these were done by the old JIT frontend. Some custom dunders uops were discovered to be broken as part of this work gh-140277

The optimizer stack space check is disabled, as it's no longer valid to deal with underflow.

Pros:
* Ignoring the generated tracer code as it's automatically created, this is only additional 1k lines of code. The maintenance burden is handled by the DSL and code generator.
* `optimizer.c` is now significantly simpler, as we don't have to do strange things to recover the bytecode from a trace.
* The new JIT frontend is able to handle a lot more control-flow than the old one.
* Tracing is very low overhead. We use the tail calling interpreter/computed goto interpreter to switch between tracing mode and non-tracing mode. I call this mechanism dual dispatch, as we have two dispatch tables dispatching to each other. Specialization is still enabled while tracing.
* Better handling of polymorphism. We leverage the specializing interpreter for this.

Cons:
* (For now) requires tail calling interpreter or computed gotos. This means no Windows JIT for now :(. Not to fret, tail calling is coming soon to Windows though https://github.com/python/cpython/pull/139962

Design:
* After each instruction, the `record_previous_inst` function/label is executed. This does as the name suggests.
* The tracing interpreter lowers bytecode to uops directly so that it can obtain "fresh" values at the point of lowering.
* The tracing version behaves nearly identical to the normal interpreter, in fact it even has specialization! This allows it to run without much of a slowdown when tracing. The actual cost of tracing is only a function call and writes to memory.
* The tracing interpreter uses the specializing interpreter's deopt to naturally form the side exit chains. This allows it to side exit chain effectively, without repeating much code. We force a re-specializing when tracing a deopt.
* The tracing interpreter can even handle goto errors/exceptions, but I chose to disable them for now as it's not tested.
* Because we do not share interpreter dispatch, there is should be no significant slowdown to the original specializing interpreter on tailcall and computed got with JIT disabled. With JIT enabled, there might be a slowdown in the form of the JIT trying to trace.
* Things that could have dynamic instruction pointer effects are guarded on. The guard deopts to a new instruction --- `_DYNAMIC_EXIT`.
2025-11-13 18:08:32 +00:00
Peter Bierma
b07a267953
gh-137883: Check the recursion limit for specialized keyword argument calls (GH-137887) 2025-08-19 09:53:38 +01:00
Mark Shannon
af15e1d13e
GH-132532: Add new DSL macros to better declare semantics of exits at ends of instructions/uops. (GH-137098) 2025-08-09 15:41:28 +01:00
Mark Shannon
801cf3fcdd
GH-137276: Don't mark uop as escaping if the escaping call is on an exit branch (GH-137277) 2025-08-02 16:49:34 +01:00
Mark Shannon
9731dd2c8d
GH-135379: Specialize int operations for compact ints only (GH-135668) 2025-06-19 11:10:29 +01:00
Ken Jin
7b15873ed0
gh-135474: Specialize arithmetic only on compact ints (GH-135479)
Specialize arithmetic only on compact ints. This also makes int operations non-escaping in the JIT and in tier 1.
2025-06-14 17:13:32 +08:00
Mark Shannon
f6f4e8a662
GH-132554: "Virtual" iterators (GH-132555)
* FOR_ITER now pushes either the iterator and NULL or leaves the iterable and pushes tagged zero

* NEXT_ITER uses the tagged int as the index into the sequence or, if TOS is NULL, iterates as before.
2025-05-27 15:59:45 +01:00
Mark Shannon
fbe7b87c06
GH-131688: Mark instructions and uops with DECREF_INPUTS as escaping. (GH-133501) 2025-05-22 09:54:35 +01:00
Mark Shannon
6dcb0fdfe0
GH-134282: Always borrow references LOAD_CONST (GH-134284) 2025-05-20 11:24:11 -04:00
Diego Russo
42d03f3933
GH-131798: Split CALL_LIST_APPEND into several uops (GH-134240) 2025-05-19 15:48:55 -04:00
Dino Viehland
3fa30d9e9c
gh-128045: Syncs w/ latest opcode metadata (#134231)
Fix opcode metadata
2025-05-19 11:08:50 -04:00
Dino Viehland
cc9add695d
gh-128045: Mark unknown opcodes as deopting to themselves (#128044)
* Mark unknown opcodes as deopting to themselves
2025-05-19 10:15:16 -04:00
Tomas R.
c492ac7252
GH-131798: Split up and optimize CALL_ISINSTANCE (GH-133339) 2025-05-08 14:26:30 -07:00
Irit Katriel
296cd128bf
Revert "gh-133395: add option for extension modules to specialize BINARY_OP/SUBSCR, apply to arrays (#133396)" (#133498) 2025-05-06 13:12:26 +03:00
Diego Russo
9cc77aaf9d
GH-131798: Split CALL_LEN into several uops (GH-133180) 2025-05-05 14:31:48 -07:00
Irit Katriel
082dbf7788
gh-133395: add option for extension modules to specialize BINARY_OP/SUBSCR, apply to arrays (#133396) 2025-05-05 17:46:56 +01:00
Mark Shannon
ac7d5ba96e
GH-133231: Changes to executor management to support proposed sys._jit module (GH-133287)
* Track the current executor, not the previous one, on the thread-state. 

* Batch executors for deallocation to avoid having to constantly incref executors; this is an ad-hoc form of deferred reference counting.
2025-05-04 10:05:35 +01:00
Ken Jin
ddac7ac59a
gh-132744: Check recursion limit in CALL_PY_GENERAL (GH-132746) 2025-05-02 17:36:29 +01:00
Irit Katriel
a4be3bc34f
gh-133258: Fix crash in test_index (GH-133262) 2025-05-01 19:15:53 +02:00
Irit Katriel
5529213d4e
gh-100239: specialize BINARY_OP/SUBSCR for list-slice (#132626) 2025-05-01 10:28:52 +00:00
Lysandros Nikolaou
60202609a2
gh-132661: Implement PEP 750 (#132662)
Co-authored-by: Lysandros Nikolaou <lisandrosnik@gmail.com>
Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com>
Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com>
Co-authored-by: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com>
Co-authored-by: Wingy <git@wingysam.xyz>
Co-authored-by: Koudai Aono <koxudaxi@gmail.com>
Co-authored-by: Dave Peck <davepeck@gmail.com>
Co-authored-by: Terry Jan Reedy <tjreedy@udel.edu>
Co-authored-by: Paul Everitt <pauleveritt@me.com>
Co-authored-by: sobolevn <mail@sobolevn.me>
2025-04-30 11:46:41 +02:00
Jelle Zijlstra
922049b613
gh-130907: Treat all module-level annotations as conditional (#131550) 2025-04-28 06:10:28 -07:00
Tomas R.
08e3389e8c
GH-131798: Split up and optimize CALL_TUPLE_1 in the JIT (GH-132851) 2025-04-24 15:55:03 -07:00
Tomas R.
0a387b311e
GH-131798: Split up and optimize CALL_STR_1 in the JIT (GH-132849) 2025-04-24 12:54:46 -07:00
Tomas R.
a6a3dbb7db
GH-131798: JIT: Split CALL_TYPE_1 into several uops (GH-132419) 2025-04-22 09:30:38 -07:00
Sam Gross
da53660f35
gh-131586: Avoid refcount contention in context managers (gh-131851)
This avoid reference count contention in the free threading build
when calling special methods like `__enter__` and `__exit__`.
2025-04-21 15:54:25 -04:00
Brandt Bucher
20926c73b5
GH-131798: Remove JIT guards for dict, frozenset, list, set, and tuple (GH-132289) 2025-04-09 14:32:21 -07:00
Mark Shannon
7099c75550
GH-131498: Cases generator: manage stacks automatically (GH-132074) 2025-04-04 17:59:36 +01:00
Brandt Bucher
1a9d4a1fb3
GH-131798: Allow the JIT to remove more int/float/str guards (GH-131800) 2025-04-01 15:10:15 -07:00
mpage
053c285f6b
gh-130704: Strength reduce LOAD_FAST{_LOAD_FAST} (#130708)
Optimize `LOAD_FAST` opcodes into faster versions that load borrowed references onto the operand stack when we can prove that the lifetime of the local outlives the lifetime of the temporary that is loaded onto the stack.
2025-04-01 10:18:42 -07:00
Amit Lavon
685fd74f81
GH-131798: Remove type checks for _TO_BOOL_STR (GH-131816) 2025-03-30 16:07:25 -07:00
Sam Gross
3d4ac1a2c2
gh-123358: Use _PyStackRef in LOAD_DEREF (gh-130064)
Concurrent accesses from multiple threads to the same `cell` object did not
scale well in the free-threaded build. Use `_PyStackRef` and optimistically
avoid locking to improve scaling.

With the locks around cell reads gone, some of the free threading tests were
prone to starvation: the readers were able to run in a tight loop and the
writer threads weren't scheduled frequently enough to make timely progress.
Adjust the tests to avoid this.

Co-authored-by: Donghee Na <donghee.na@python.org>
2025-03-26 12:08:20 -04:00
Mark Shannon
83d54fa876
GH-130296: Remove _PyOpcode_max_stack_effect as it is no longer used (GH-131493) 2025-03-20 11:42:54 +00:00
T. Wouters
de2f7da77d
gh-115999: Add free-threaded specialization for FOR_ITER (#128798)
Add free-threaded versions of existing specialization for FOR_ITER (list, tuples, fast range iterators and generators), without significantly affecting their thread-safety. (Iterating over shared lists/tuples/ranges should be fine like before. Reusing iterators between threads is not fine, like before. Sharing generators between threads is a recipe for significant crashes, like before.)
2025-03-12 16:21:46 +01:00
Mark Shannon
2bef8ea8ea
GH-127705: Use _PyStackRefs in the default build. (GH-127875) 2025-03-10 14:06:56 +00:00
Mark Shannon
89df62c120
GH-128534: Fix behavior of branch monitoring for async for (GH-130847)
* Both branches in a pair now have a common source and are included in co_branches
2025-03-07 14:30:31 +00:00
Tomasz Pytel
aeb2327386
gh-130574: renumber RESUME opcode from 149 to 128 (GH-130685) 2025-03-06 08:59:36 +00:00
mpage
d7bb7c7817
gh-118331: Fix a couple of issues when list allocation fails (#130811)
* Fix use after free in list objects

Set the items pointer in the list object to NULL after the items array
is freed during list deallocation. Otherwise, we can end up with a list
object added to the free list that contains a pointer to an already-freed
items array.

* Mark `_PyList_FromStackRefStealOnSuccess` as escaping

I think technically it's not escaping, because the only object that
can be decrefed if allocation fails is an exact list, which cannot
execute arbitrary code when it is destroyed. However, this seems less
intrusive than trying to special cases objects in the assert in `_Py_Dealloc`
that checks for non-null stackpointers and shouldn't matter for performance.
2025-03-05 10:42:09 -08:00
Mark Shannon
54965f3fb2
GH-130296: Avoid stack transients in four instructions. (GH-130310)
* Combine _GUARD_GLOBALS_VERSION_PUSH_KEYS and _LOAD_GLOBAL_MODULE_FROM_KEYS into _LOAD_GLOBAL_MODULE

* Combine _GUARD_BUILTINS_VERSION_PUSH_KEYS and _LOAD_GLOBAL_BUILTINS_FROM_KEYS into _LOAD_GLOBAL_BUILTINS

* Combine _CHECK_ATTR_MODULE_PUSH_KEYS and _LOAD_ATTR_MODULE_FROM_KEYS into _LOAD_ATTR_MODULE

* Remove stack transient in LOAD_ATTR_WITH_HINT
2025-02-28 18:00:38 +00:00
Mark Shannon
2a18e80695
GH-128534: Instrument branches for async for loops. (GH-130569) 2025-02-27 09:36:41 +00:00
Mark Shannon
72f56654d0
GH-128682: Account for escapes in DECREF_INPUTS (GH-129953)
* Handle escapes in DECREF_INPUTS

* Mark a few more functions as escaping

* Replace DECREF_INPUTS with PyStackRef_CLOSE where possible
2025-02-12 17:44:59 +00:00
Irit Katriel
a1417b211f
gh-100239: replace BINARY_SUBSCR & family by BINARY_OP with oparg NB_SUBSCR (#129700) 2025-02-07 22:39:54 +00:00
Mark Shannon
75b628adeb
GH-128563: Generate opcode = ... in instructions that need opcode (GH-129608)
* Remove support for GO_TO_INSTRUCTION
2025-02-03 15:09:21 +00:00
Mark Shannon
808071b994
GH-128682: Make PyStackRef_CLOSE escaping. (GH-129404) 2025-02-03 12:41:32 +00:00
Irit Katriel
4815131910
gh-100239: specialize bitwise logical binary ops on ints (#128927) 2025-01-29 09:28:21 +00:00
Brandt Bucher
828b27680f
GH-126599: Remove the PyOptimizer API (GH-129194) 2025-01-28 16:10:51 -08:00
Mark Shannon
75b4962157
GH-128914: Remove all but one conditional stack effects (GH-129226)
* Remove all 'if (0)' and 'if (1)' conditional stack effects

* Use array instead of conditional for BUILD_SLICE args

* Refactor LOAD_GLOBAL to use a common conditional uop

* Remove conditional stack effects from LOAD_ATTR specializations

* Replace conditional stack effects in LOAD_ATTR with a 0 or 1 sized array.

* Remove conditional stack effects from CALL_FUNCTION_EX
2025-01-27 16:24:48 +00:00
Sam Gross
a10f99375e
Revert "GH-128914: Remove conditional stack effects from bytecodes.c and the code generators (GH-128918)" (GH-129202)
The commit introduced a ~2.5-3% regression in the free threading build.

This reverts commit ab61d3f430.
2025-01-23 09:26:25 +00:00
Mark Shannon
470a0a68eb
GH-128682: Change a couple of functions to only steal references on success. (GH-129132)
Change PyTuple_FromStackRefSteal and PyList_FromStackRefSteal to only steal on success to avoid escaping
2025-01-22 10:51:37 +00:00