Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
81 commits
Select commit Hold shift + click to select a range
67ed7cb
builtins: expose type signatures and fix range iterator len
youknowone Aug 17, 2026
8bb3291
builtins: expose iterator method signatures
youknowone Aug 17, 2026
36a78bf
builtins: collect terminal integer strings safely
youknowone Aug 17, 2026
91f073d
jit: install blackhole opcode metadata for every driver
youknowone Aug 17, 2026
c822a4b
gc: hide scalar builtins from tracked-object APIs
youknowone Aug 17, 2026
214d5bf
code: realize constants when PyCode is created
youknowone Aug 17, 2026
34dcef6
gc: complete tracked-object generation queries
youknowone Aug 17, 2026
4c08e5b
gc: expose CPython generation statistics and callbacks
youknowone Aug 17, 2026
4aa2b10
gc: complete CPython referent inspection
youknowone Aug 17, 2026
82aadbd
test: restore tracing-GC weakref collection points
youknowone Aug 17, 2026
4ebc60b
builtins: align async generator awaitables with 3.14
youknowone Aug 17, 2026
8dcd670
test: adapt frame teardown checks for tracing GC
youknowone Aug 17, 2026
83b5d58
types: preserve SimpleNamespace insertion order
youknowone Aug 17, 2026
59df56a
code: retain weakref lifelines on objects
youknowone Aug 17, 2026
69b7688
code: warn when reading co_lnotab
youknowone Aug 17, 2026
e070bae
code: decode location tables for line iterators
youknowone Aug 17, 2026
f202792
compiler: honor no_debug_ranges configuration
youknowone Aug 18, 2026
04a27d6
types: expose descriptor get signatures
youknowone Aug 18, 2026
75f4f7b
exceptions: enrich attribute lookup context
youknowone Aug 18, 2026
c065b2e
typing: complete TypeAliasType runtime semantics
youknowone Aug 18, 2026
039d32a
typing: preserve type parameter immutability
youknowone Aug 18, 2026
4eb8dcb
generators: finalize references at delete boundaries
youknowone Aug 18, 2026
1843a14
code: defer unknown opcode errors to dispatch
youknowone Aug 18, 2026
2a07341
marshal: preserve invalid code bytes through loads
youknowone Aug 18, 2026
40226e6
objspace: dispatch packed calls through Arguments
youknowone Aug 18, 2026
1f2df22
address review: root objects across warning dispatch, restore ParamSp…
youknowone Aug 18, 2026
1b7a881
address review: defer awaitable finalization under gc.disable, keep R…
youknowone Aug 18, 2026
f1047bd
address review: drop the eager DELETE collection, guard nested gc.col…
youknowone Aug 19, 2026
5fd756d
wasm: emit a fixed-arity label-parameter entry beside the narrow one
youknowone Aug 19, 2026
5373475
pycode: pin the opposite varint byte orders of the two code tables
youknowone Aug 19, 2026
fba6052
gc: return the frontend to the PyPy collector's contract
youknowone Aug 19, 2026
e88f1f7
pycode: apply the owner write barrier when publishing code slots
youknowone Aug 19, 2026
e9c95a1
address review: bound the varint shift, fix the shim's frame gate and…
youknowone Aug 19, 2026
a949a73
address review: reserve the wide trace slot, order the code-root regi…
youknowone Aug 19, 2026
4b55739
builtins: publish module __doc__ and the remaining 3.14 type signatures
youknowone Aug 19, 2026
3fbea5c
sys: record the case that requires the SimpleNamespace devolution
youknowone Aug 19, 2026
b88887c
jit: recover the post-blackhole frame from the rooted virtualizable
youknowone Aug 19, 2026
707db63
address review: reset the loop-region scan across ranges, reject narr…
youknowone Aug 19, 2026
12a6d56
bench: re-record inline_freevar_after_mayforce for the recognized cat…
youknowone Aug 20, 2026
9a5f87b
jit: fold isinstance's exact-type quick test in the walker
youknowone Aug 20, 2026
9f6d5ab
jit: extend the isinstance walker fold to tuple classinfo
youknowone Aug 20, 2026
dd4ebcd
jit: fold the isinstance miss and issubclass subtype tests in the walker
youknowone Aug 20, 2026
2e06a84
bench: restore inline_freevar_after_mayforce to six compiled loops
youknowone Aug 20, 2026
0ddb6a9
_typing: record the boundaries of the immutability guards
youknowone Aug 20, 2026
0b4511f
types: publish the HAVE_GC flag
youknowone Aug 20, 2026
4b6429a
Revert "bench: restore inline_freevar_after_mayforce to six compiled …
youknowone Aug 20, 2026
d1c06c6
types: publish the disallow-instantiation flag
youknowone Aug 20, 2026
118390c
deps: update the RustPython pin
youknowone Aug 20, 2026
84cb8bd
types: publish the base-type flag
youknowone Aug 20, 2026
b3a337a
deps: advance the RustPython pin
youknowone Aug 20, 2026
16a8ca4
types: publish the fast-subclass family flags
youknowone Aug 20, 2026
1a797b7
types: publish ready and match-self flags
youknowone Aug 20, 2026
dc257e1
types: publish managed dict and inline value flags
youknowone Aug 20, 2026
ae2c645
types: publish the managed weakref flag
youknowone Aug 20, 2026
14a114a
types: separate CPython builtin ownership flags
youknowone Aug 20, 2026
b77dd00
_ctypes: give the native type family a common metaclass owner and CPy…
youknowone Aug 20, 2026
7d6ba21
bench: compare pypy_type_surface against the bits get_flags publishes
youknowone Aug 20, 2026
8b99f8f
check.py: widen the appended panic body to reach the site field
youknowone Aug 20, 2026
c821b27
contextvars: project Context as a static builtin type
youknowone Aug 21, 2026
28a863a
_types: publish PyCapsule disallow-instantiation flag
youknowone Aug 21, 2026
f93b8c4
gc: filter public object census to tracked types
youknowone Aug 21, 2026
4f75905
gc: answer collect() with an int again
youknowone Aug 21, 2026
6492d5e
check.py: report the exception line of a crashing fixture
youknowone Aug 21, 2026
13c7830
bench: drop the string rows from pypy_type_surface, and pin the pattern
youknowone Aug 21, 2026
0d9b376
bench: reach the string results through the collector's edge walk
youknowone Aug 21, 2026
8a00051
bench: record inline_freevar_after_mayforce at six loops again
youknowone Aug 21, 2026
29ebc25
docs: make module ownership follow PyPy
youknowone Aug 21, 2026
8c33305
objspace: narrow __class__ assignment, read the namespace dict direct…
youknowone Aug 21, 2026
353ab16
builtins: expose PyPy weakref descriptors
youknowone Aug 21, 2026
bee98fe
docs: scope builtin ports to PyPy modules
youknowone Aug 21, 2026
3a9283a
io: name the rejected exporter type in readinto's TypeError
youknowone Aug 21, 2026
1f39f8a
bench: follow the two jitstats fixtures to what CI observes
youknowone Aug 21, 2026
bfdb263
address review: root getattr's operands, close three observable gaps
youknowone Aug 21, 2026
2fdbb92
bench: follow the wasm baseline, and band the counter that splits per…
youknowone Aug 21, 2026
ae327ed
builtins: stop publishing __weakref__ on type and memoryview
youknowone Aug 21, 2026
7720413
jit: fold getattr() and hasattr() through the LOAD_ATTR specializer
youknowone Aug 21, 2026
3003b9d
jit: accept an unboxed slot in the hasattr fold
youknowone Aug 22, 2026
406f892
jit: read a walk-boxed bool's truth instead of unboxing it again
youknowone Aug 22, 2026
45383b9
bench: re-record pickle_terminal_raise_resume guard_failures
youknowone Aug 22, 2026
b1a34e4
jit: fold hasattr to a constant False on a proven miss
youknowone Aug 22, 2026
3c5c768
bench: re-record inline_freevar_after_mayforce for the recognized cat…
youknowone Aug 22, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,30 @@ The `t` is the **free-threaded** build: "CPython does X" is an answer only once
holds without the GIL. Correct-because-a-global-lock-serialises-it is not
on-spec.

### Module presence follows PyPy

**Do not implement a module that PyPy does not have merely to unskip a CPython
test.** Whether a module exists, and which layer owns it, is part of the PyPy
implementation shape. Before adding any builtin, extension, compatibility, or
test-support module, verify that the real `pypy3` oracle imports it and locate
its owner in `pypy/`, `rpython/`, or `lib_pypy/`. If neither exists, the module
is not a pyre porting target unless the user explicitly expands the scope.
This applies to builtin-type and CPython-test-suite sweeps too: exclude an
absent module from the backlog instead of treating its skipped tests as missing
implementation work. The goal is to complete PyPy's module/type surface in the
PyPy way, not to reproduce CPython's private extension-module inventory.

In particular, CPython-only test helpers such as `_testlimitedcapi` are not
product modules. PyPy also has no `_datetime` extension module: it provides
`datetime` through its pure-Python implementation, so pyre must preserve the
working pure-Python path rather than invent an `_datetime` stub or accelerator.
A CPython test that directly imports one of these absent private modules may
skip or remain blocked; that is not by itself an implementation gap. If the
public stdlib feature is broken, port PyPy's actual owner/fallback and fix that
root cause. Never add an empty or partial module just to make the import
succeed, because that suppresses the intended fallback and turns a clean skip
into misleading failures.

**The spec governs only what a caller can observe** — return value, exception
type/message/attributes, identity, encoding-and-errors contract, accepted
argument shapes. Everything else follows PyPy **unconditionally**: names, module
Expand Down
18 changes: 9 additions & 9 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

25 changes: 14 additions & 11 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -64,19 +64,22 @@ pyre-jit-trace = { version = "0.0.2", path = "pyre/pyre-jit-trace" }
pyre-wasm = { version = "0.0.2", path = "pyre/pyre-wasm" }
pyrex = { version = "0.0.2", path = "pyre/pyrex" }

# Pinned to upstream main after the `Constants` mutable-access impls from
# #8557 merged; `fix_code_filenames` needs `IndexMut` to edit nested code
# constants in place.
rustpython-common = { git = "https://github.com/RustPython/RustPython.git", rev = "91a725fe833dbc06912a2619e0c39fffa0c61232" }
rustpython-literal = { git = "https://github.com/RustPython/RustPython.git", rev = "91a725fe833dbc06912a2619e0c39fffa0c61232" }
rustpython-compiler = { git = "https://github.com/RustPython/RustPython.git", rev = "91a725fe833dbc06912a2619e0c39fffa0c61232" }
rustpython-compiler-core = { git = "https://github.com/RustPython/RustPython.git", rev = "91a725fe833dbc06912a2619e0c39fffa0c61232" }
# Pinned to upstream main after the pyre compatibility fixes from #8390 and
# #8506, the memoryview fixes from #8553, the runtime marshal code-byte hook
# from #8552, the `Constants` mutable-access impls from #8557, and the compiler
# parity fixes from #8550 were merged. `fix_code_filenames` needs `IndexMut`
# to edit nested code constants in place, and `loads` relies on the #8552 hook
# to preserve invalid code bytes, so this pin must not move below either.
rustpython-common = { git = "https://github.com/RustPython/RustPython.git", rev = "dd2cc4d77a625661e5ca189f1cf9be199ecaa434" }
rustpython-literal = { git = "https://github.com/RustPython/RustPython.git", rev = "dd2cc4d77a625661e5ca189f1cf9be199ecaa434" }
rustpython-compiler = { git = "https://github.com/RustPython/RustPython.git", rev = "dd2cc4d77a625661e5ca189f1cf9be199ecaa434" }
rustpython-compiler-core = { git = "https://github.com/RustPython/RustPython.git", rev = "dd2cc4d77a625661e5ca189f1cf9be199ecaa434" }
ruff-text-size = { package = "rustpython-ruff_text_size", git = "https://github.com/RustPython/ruff.git", tag = "0.15.19-rustpython" }
num-complex = "0.4"
rustpython-host_env = { git = "https://github.com/RustPython/RustPython.git", rev = "91a725fe833dbc06912a2619e0c39fffa0c61232" }
rustpython-wtf8 = { git = "https://github.com/RustPython/RustPython.git", rev = "91a725fe833dbc06912a2619e0c39fffa0c61232" }
rustpython-unicode = { git = "https://github.com/RustPython/RustPython.git", rev = "91a725fe833dbc06912a2619e0c39fffa0c61232" }
sre-engine = { package = "rustpython-sre_engine", git = "https://github.com/RustPython/RustPython.git", rev = "91a725fe833dbc06912a2619e0c39fffa0c61232" }
rustpython-host_env = { git = "https://github.com/RustPython/RustPython.git", rev = "dd2cc4d77a625661e5ca189f1cf9be199ecaa434" }
rustpython-wtf8 = { git = "https://github.com/RustPython/RustPython.git", rev = "dd2cc4d77a625661e5ca189f1cf9be199ecaa434" }
rustpython-unicode = { git = "https://github.com/RustPython/RustPython.git", rev = "dd2cc4d77a625661e5ca189f1cf9be199ecaa434" }
sre-engine = { package = "rustpython-sre_engine", git = "https://github.com/RustPython/RustPython.git", rev = "dd2cc4d77a625661e5ca189f1cf9be199ecaa434" }

# majit JIT framework
majit = { version = "0.0.2", path = "majit/majit" }
Expand Down
2 changes: 2 additions & 0 deletions lib-python/3/test/test_frame.py
Original file line number Diff line number Diff line change
Expand Up @@ -677,6 +677,7 @@ def test_eq(self):
pass


@support.cpython_only
class TestFrameCApi(unittest.TestCase):
def test_basic(self):
x = 1
Expand Down Expand Up @@ -792,6 +793,7 @@ def f():
# Call from C, so there is a shim frame directly above f:
weak = operator.call(f) # BOOM!
# Cool, we didn't crash. Check that the callback actually happened:
support.gc_collect() # For PyPy or other GCs.
self.assertIs(catcher.unraisable.exc_type, TypeError)
self.assertIsNone(weak())

Expand Down
2 changes: 2 additions & 0 deletions lib-python/3/test/test_weakref.py
Original file line number Diff line number Diff line change
Expand Up @@ -1781,6 +1781,7 @@ def test_weak_valued_union_operators(self):
self.assertIs(type(tmp4), weakref.WeakValueDictionary)

del a
gc_collect() # For PyPy or other GCs.
self.assertNotIn(2, tmp1)
self.assertNotIn(2, tmp2)
self.assertNotIn(1, tmp3)
Expand Down Expand Up @@ -1833,6 +1834,7 @@ def test_weak_keyed_union_operators(self):
self.assertIs(type(tmp4), weakref.WeakKeyDictionary)

del o1
gc_collect() # For PyPy or other GCs.
self.assertNotIn(4, tmp1.values())
self.assertNotIn(4, tmp2.values())
self.assertNotIn(1, tmp3.values())
Expand Down
58 changes: 48 additions & 10 deletions majit/majit-backend-wasm/js/jit_glue.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@ function jitCallTrampoline(framePtr, callAreaOfs = CALL_RESULT_OFS) {
}

export function jit_compile_wasm(bytesPtr, bytesLen) {
const trace = instantiateTrace(bytesPtr, bytesLen);
return registerTrace(trace);
const entries = instantiateTrace(bytesPtr, bytesLen);
return registerTrace(entries);
}

function instantiateTrace(bytesPtr, bytesLen) {
Expand All @@ -74,16 +74,24 @@ function instantiateTrace(bytesPtr, bytesLen) {
const instance = new WebAssembly.Instance(module, {
env: { memory: mainMemory, jit_call: jitCallTrampoline, jit_call_compact: jitCallTrampoline, __indirect_function_table: mainTable }
});
return instance.exports.trace;
return traceEntries(instance);
} catch (e) {
// Retry without jit_call (for traces without CALL ops)
const instance = new WebAssembly.Instance(module, {
env: { memory: mainMemory }
});
return instance.exports.trace;
return traceEntries(instance);
}
}

// A resumable peeled loop exports a fixed-arity `trace_wide` beside the narrow
// `trace` shim, and the backend publishes its table slot as `handle + 1`. Both
// hosts must therefore install the pair adjacently or that published slot names
// an unrelated trace.
function traceEntries(instance) {
return { trace: instance.exports.trace, wide: instance.exports.trace_wide };
}

// Compile and instantiate a trace, then overwrite an existing shared-table
// slot. A caller already running the old function retains that invocation;
// later indirect calls use the replacement.
Expand All @@ -92,11 +100,29 @@ export function jit_replace_wasm(funcId, bytesPtr, bytesLen) {
if (!funcTable[funcId]) {
return 0;
}
const trace = instantiateTrace(bytesPtr, bytesLen);
const { trace, wide } = instantiateTrace(bytesPtr, bytesLen);
// Modules emitted while this slot was wide carry `call_indirect funcId + 1`
// baked in. A narrow replacement cannot retract those, so accepting one
// would leave the pair straddling two compiles: `funcId` on the new trace
// and `funcId + 1` still on the old. `funcTable` records the wide entry
// only when one existed, so it is the discriminator the shared table
// cannot be — its spare slot holds the narrow function either way. Reject
// the shape change before touching either table; narrow-to-wide stays
// allowed, mirroring the wasmtime host.
if (!wide && funcTable[funcId + 1] !== undefined) {
console.error('[jit_replace_wasm] refused: id', funcId, 'has a published wide entry the replacement does not');
return 0;
}
if (mainTable) {
mainTable.set(funcId, trace);
if (wide) {
mainTable.set(funcId + 1, wide);
}
}
funcTable[funcId] = trace;
if (wide) {
funcTable[funcId + 1] = wide;
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
return funcId;
} catch (e) {
console.error('[jit_replace_wasm] failed:', e);
Expand All @@ -108,15 +134,27 @@ export function jit_replace_wasm(funcId, bytesPtr, bytesLen) {
// table slot as the id, mirroring the wasmtime host. The slot is both the
// jit_execute_wasm handle and the index an in-module call_indirect targets.
// Falls back to a private counter when no table is available.
function registerTrace(traceFn) {
function registerTrace(entries) {
const { trace, wide } = entries;
let id;
// The pair is appended even for a narrow module, mirroring the wasmtime
// host. An emitted module names its wide entry `id + 1`, and a later
// `jit_replace_wasm` may install one where this compile had none; without
// the reservation that write would land on the next trace's own entry.
if (mainTable) {
id = mainTable.grow(1);
mainTable.set(id, traceFn);
id = mainTable.grow(2, trace);
mainTable.set(id, trace);
if (wide) {
mainTable.set(id + 1, wide);
}
} else {
id = nextFuncId++;
id = nextFuncId;
nextFuncId += 2;
}
funcTable[id] = trace;
if (wide) {
funcTable[id + 1] = wide;
Comment on lines +154 to +156

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Clear the browser host's wide slot when freeing a trace

When a browser/WebAssembly trace exports trace_wide, this stores it at funcId + 1, but jit_free_wasm still deletes only funcTable[funcId] and clears neither the wide private entry nor the corresponding mainTable slot. Reclaiming a resumable peeled loop therefore leaves its wide function rooted and executable by later inter-trace call_indirect operations after the trace was supposedly freed; remove both entries together as the Wasmtime host now does.

AGENTS.md reference: AGENTS.md:L66-L77

Useful? React with 👍 / 👎.

}
funcTable[id] = traceFn;
return id;
}

Expand Down
Loading
Loading