Skip to content

builtins: layout-checked object.__new__, buffer request kinds, and six argument-handling sites - #1063

Merged
youknowone merged 21 commits into
mainfrom
buitlins
Aug 7, 2026
Merged

builtins: layout-checked object.__new__, buffer request kinds, and six argument-handling sites#1063
youknowone merged 21 commits into
mainfrom
buitlins

Conversation

@youknowone

@youknowone youknowone commented Aug 5, 2026

Copy link
Copy Markdown
Owner

An audit of the builtin types against CPython 3.14.2 and PyPy 7.3.20, fixing the places where pyre agreed with neither.

object.__new__ and the layout check

object.__new__ never ran check_user_subclass, so object.__new__(int), object.__new__(list) and user subclasses of them all allocated a bare instance missing the fields their own methods then read. The check itself already existed; only the call was absent.

type was a second, independent hole: check_user_subclass decides safety purely by layout.typedef pointer identity, and type was built with layout_pytype = &INSTANCE_TYPE, so it reused object's Layout. That made the identity hold for type and every metaclass, since heap types inherit base_layout.typedef. type now gets &TYPE_TYPE, matching W_TypeObject.typedef upstream.

object.__new__(type) did not fail at the allocation — it returned a live non-type, and the first repr() of it reported descriptor '__repr__' requires a 'type' object but received a 'type'.

Buffer request kinds were inverted

Upstream spells C-contiguity in the request flag, not the operation:

request strided source used by
BUF_SIMPLE BufferError replace, strip, join, translate, find, startswith, fill char
BUF_FULL_RO copied out bytes() / bytearray() constructors

pyre had these exactly backwards, so bytes(memoryview(b'abcd')[::2]) raised where both references return b'ac', while b'abcd'.replace(mv[::2], b'z') succeeded where both raise. simple_buffer_bytes / full_ro_buffer_bytes now share one buffer_bytes(obj, require_contiguous), and require_contiguous_buffer is the gate for the operand side.

Argument handling

  • bytes.startswith / endswith convert the operand before the start > len(value) early-out, so b'abc'.startswith('a', 10) raises instead of answering False.
  • A supplied None is a value, not an omitted argument: bytes.center/ljust/rjust fill char, bytes.decode encoding and errors, bytearray.pop index, memoryview.cast shape. WrappedDefault / if w_shape: apply to the slot, not to app-level None. builtin_str spells the utf-8 default out where it previously passed None through, so str(b'abc', errors='strict') keeps working.
  • Surplus positional arguments are rejected by str.replace, bytes.center/ljust/rjust, bytearray.remove, memoryview.cast.
  • bytearray.pop reads its index before taking the storage borrow — that read can run user code.

Messages

  • An unset __slots__ read reports %T, the bare type name, through raiseattrerror — the same miss taken through the descriptor's own __get__ already did. It was printing '__main__.S'.
  • type(1, (), {}) names argument 1 instead of reporting an arity error, and argument 1's text says string like its two siblings.
  • SyntaxError.__str__ splits its filename with ntpath rules on windows (\ and the drive prefix), fixing source_encoding_syntax_error.py there.

Verification

  • 37/37 targeted cases match both references, including 15 guard cases that must not change (object.__new__ on __slots__ and multiple-base classes, every accepted arity).
  • cargo test --all 101 test binaries, 0 failures.
  • pyre/extra_tests/parity_tests 178 scripts: the only red is type_members_python314.py under the cpython runner (BaseExceptionGroup tp_basicsize 88 vs 96), unrelated and pre-existing.
  • pyre/check.py --backend dynasm --synthetic-only 362/362.

Known remaining

bytearray's six comparison dunders still accept only bytes/bytearray, so bytearray(b'ab') == array.array('B', [97, 98]) is False where both references say True. Upstream _comparison_helper accepts any BUF_SIMPLE exporter. bytes is correct as-is and must not be widened. Left for a follow-up.

authored by Claude

Summary by CodeRabbit

  • New Features

    • Improved JIT support for eligible functions using surplus positional (*args) arguments.
    • Added support for strided read-only buffers in applicable operations.
    • Expanded byte and bytearray comparisons to support more buffer-exporting objects.
  • Bug Fixes

    • Improved compatibility with Python’s argument-count validation and error messages.
    • Corrected memoryview, type, exception, string, and str.replace behavior.
    • Improved Windows filename handling in syntax errors and descriptor naming.
    • Refined raise ... from ... validation and object construction checks.

@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

Too many files!

This PR contains 1009 files, which is 909 over the limit of 100.

To get a review, reduce the PR to 100 files or fewer by splitting it into smaller PRs or changing its base branch.

Upgrade to a paid plan to raise the limit.

Usage-priced reviews support at most 300 files.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: c73b4e8e-8979-4aa8-8f50-28c4b72390ba

📥 Commits

Reviewing files that changed from the base of the PR and between 1391a96 and f3cf797.

📒 Files selected for processing (1009)
  • lib-python/3/test/test_descr.py
  • pyre/bench/synth/abstractmethods_metaclass_getattr.cranelift.jitstats
  • pyre/bench/synth/abstractmethods_metaclass_getattr.dynasm.jitstats
  • pyre/bench/synth/abstractmethods_metaclass_getattr.wasm.jitstats
  • pyre/bench/synth/abstractmethods_nonstring_name.cranelift.jitstats
  • pyre/bench/synth/abstractmethods_nonstring_name.dynasm.jitstats
  • pyre/bench/synth/abstractmethods_nonstring_name.wasm.jitstats
  • pyre/bench/synth/aiter_anext.cranelift.jitstats
  • pyre/bench/synth/aiter_anext.dynasm.jitstats
  • pyre/bench/synth/aiter_anext.wasm.jitstats
  • pyre/bench/synth/arith_int_bool.cranelift.jitstats
  • pyre/bench/synth/arith_int_bool.dynasm.jitstats
  • pyre/bench/synth/array_deopt_resume.cranelift.jitstats
  • pyre/bench/synth/array_deopt_resume.dynasm.jitstats
  • pyre/bench/synth/array_deopt_resume.wasm.jitstats
  • pyre/bench/synth/assert_in_loop.cranelift.jitstats
  • pyre/bench/synth/assert_in_loop.dynasm.jitstats
  • pyre/bench/synth/assert_in_loop.wasm.jitstats
  • pyre/bench/synth/ast_compile_roundtrip.cranelift.jitstats
  • pyre/bench/synth/ast_compile_roundtrip.dynasm.jitstats
  • pyre/bench/synth/ast_compile_roundtrip.wasm.jitstats
  • pyre/bench/synth/attr_cache_invalidation.cranelift.jitstats
  • pyre/bench/synth/attr_cache_invalidation.dynasm.jitstats
  • pyre/bench/synth/attr_cache_invalidation.wasm.jitstats
  • pyre/bench/synth/attr_delete.cranelift.jitstats
  • pyre/bench/synth/attr_delete.dynasm.jitstats
  • pyre/bench/synth/attr_delete.wasm.jitstats
  • pyre/bench/synth/attr_instance_shadows_class.cranelift.jitstats
  • pyre/bench/synth/attr_instance_shadows_class.dynasm.jitstats
  • pyre/bench/synth/attr_instance_shadows_class.wasm.jitstats
  • pyre/bench/synth/attr_store_add_transition.cranelift.jitstats
  • pyre/bench/synth/attr_store_add_transition.dynasm.jitstats
  • pyre/bench/synth/attr_store_add_transition.py
  • pyre/bench/synth/attr_store_add_transition.wasm.jitstats
  • pyre/bench/synth/attr_store_cache.cranelift.jitstats
  • pyre/bench/synth/attr_store_cache.dynasm.jitstats
  • pyre/bench/synth/attr_store_cache.wasm.jitstats
  • pyre/bench/synth/bases_reassign_cache.cranelift.jitstats
  • pyre/bench/synth/bases_reassign_cache.dynasm.jitstats
  • pyre/bench/synth/bases_reassign_cache.wasm.jitstats
  • pyre/bench/synth/binary_int_overflow_local_resume.cranelift.jitstats
  • pyre/bench/synth/binary_int_overflow_local_resume.dynasm.jitstats
  • pyre/bench/synth/binary_int_overflow_local_resume.wasm.jitstats
  • pyre/bench/synth/binary_slice_index.cranelift.jitstats
  • pyre/bench/synth/binary_slice_index.dynasm.jitstats
  • pyre/bench/synth/bool_dunder_error_no_leak.cranelift.jitstats
  • pyre/bench/synth/bool_dunder_error_no_leak.dynasm.jitstats
  • pyre/bench/synth/bound_method_builtin_fold.cranelift.jitstats
  • pyre/bench/synth/bound_method_builtin_fold.dynasm.jitstats
  • pyre/bench/synth/bound_method_builtin_fold.wasm.jitstats
  • pyre/bench/synth/break_except_live_local.cranelift.jitstats
  • pyre/bench/synth/break_except_live_local.dynasm.jitstats
  • pyre/bench/synth/break_except_live_local.wasm.jitstats
  • pyre/bench/synth/bridge_branchy_callee.cranelift.jitstats
  • pyre/bench/synth/bridge_branchy_callee.dynasm.jitstats
  • pyre/bench/synth/bridge_branchy_callee.py
  • pyre/bench/synth/bridge_branchy_callee.wasm.jitstats
  • pyre/bench/synth/bridge_global_fold_invalidate_hot.cranelift.jitstats
  • pyre/bench/synth/bridge_global_fold_invalidate_hot.dynasm.jitstats
  • pyre/bench/synth/bridge_global_fold_invalidate_hot.wasm.jitstats
  • pyre/bench/synth/bridge_recursion_overflow.cranelift.jitstats
  • pyre/bench/synth/bridge_recursion_overflow.dynasm.jitstats
  • pyre/bench/synth/bridge_recursion_overflow.wasm.jitstats
  • pyre/bench/synth/build_class_surrogate_namespace.cranelift.jitstats
  • pyre/bench/synth/build_class_surrogate_namespace.dynasm.jitstats
  • pyre/bench/synth/build_class_surrogate_namespace.wasm.jitstats
  • pyre/bench/synth/build_container_return_resume.cranelift.jitstats
  • pyre/bench/synth/build_container_return_resume.dynasm.jitstats
  • pyre/bench/synth/build_container_return_resume.py
  • pyre/bench/synth/build_container_return_resume.wasm.jitstats
  • pyre/bench/synth/build_list_resume.cranelift.jitstats
  • pyre/bench/synth/build_list_resume.dynasm.jitstats
  • pyre/bench/synth/build_list_resume.py
  • pyre/bench/synth/build_list_resume.wasm.jitstats
  • pyre/bench/synth/build_set_hashability.cranelift.jitstats
  • pyre/bench/synth/build_set_hashability.dynasm.jitstats
  • pyre/bench/synth/builtin_type_surface.cranelift.jitstats
  • pyre/bench/synth/builtin_type_surface.dynasm.jitstats
  • pyre/bench/synth/builtin_type_surface.wasm.jitstats
  • pyre/bench/synth/bytes_split_whitespace_maxsplit.cranelift.jitstats
  • pyre/bench/synth/bytes_split_whitespace_maxsplit.dynasm.jitstats
  • pyre/bench/synth/bytes_split_whitespace_maxsplit.wasm.jitstats
  • pyre/bench/synth/call_ex_kwargs_mapping.cranelift.jitstats
  • pyre/bench/synth/call_ex_kwargs_mapping.dynasm.jitstats
  • pyre/bench/synth/call_ex_kwargs_mapping.wasm.jitstats
  • pyre/bench/synth/call_kw_hot_loop.cranelift.jitstats
  • pyre/bench/synth/call_kw_hot_loop.dynasm.jitstats
  • pyre/bench/synth/call_kw_hot_loop.wasm.jitstats
  • pyre/bench/synth/call_loop_local_function.cranelift.jitstats
  • pyre/bench/synth/call_loop_local_function.dynasm.jitstats
  • pyre/bench/synth/call_loop_local_function.py
  • pyre/bench/synth/call_loop_local_function.wasm.jitstats
  • pyre/bench/synth/call_slot_descriptor_protocol.cranelift.jitstats
  • pyre/bench/synth/call_slot_descriptor_protocol.dynasm.jitstats
  • pyre/bench/synth/call_slot_descriptor_protocol.wasm.jitstats
  • pyre/bench/synth/call_star_forms_inlined_callee.cranelift.jitstats
  • pyre/bench/synth/call_star_forms_inlined_callee.dynasm.jitstats
  • pyre/bench/synth/call_star_forms_inlined_callee.wasm.jitstats
  • pyre/bench/synth/callable_iterator_type.cranelift.jitstats
  • pyre/bench/synth/callable_iterator_type.dynasm.jitstats
  • pyre/bench/synth/callable_iterator_type.wasm.jitstats
  • pyre/bench/synth/callee_return_side_effect.cranelift.jitstats
  • pyre/bench/synth/callee_return_side_effect.dynasm.jitstats
  • pyre/bench/synth/callee_return_side_effect.wasm.jitstats
  • pyre/bench/synth/callee_store_global_read_after_call.cranelift.jitstats
  • pyre/bench/synth/callee_store_global_read_after_call.dynasm.jitstats
  • pyre/bench/synth/callee_store_global_read_after_call.wasm.jitstats
  • pyre/bench/synth/calls_closures.cranelift.jitstats
  • pyre/bench/synth/calls_closures.dynasm.jitstats
  • pyre/bench/synth/calls_closures.wasm.jitstats
  • pyre/bench/synth/chained_comparison.cranelift.jitstats
  • pyre/bench/synth/chained_comparison.dynasm.jitstats
  • pyre/bench/synth/chained_comparison.wasm.jitstats
  • pyre/bench/synth/check_exc_match_invalid_class.cranelift.jitstats
  • pyre/bench/synth/check_exc_match_invalid_class.dynasm.jitstats
  • pyre/bench/synth/check_exc_match_invalid_class.wasm.jitstats
  • pyre/bench/synth/class_attrs_methods.cranelift.jitstats
  • pyre/bench/synth/class_attrs_methods.dynasm.jitstats
  • pyre/bench/synth/class_attrs_methods.wasm.jitstats
  • pyre/bench/synth/class_reassign_hot.cranelift.jitstats
  • pyre/bench/synth/class_reassign_hot.dynasm.jitstats
  • pyre/bench/synth/class_reassign_hot.wasm.jitstats
  • pyre/bench/synth/classmethod_type_dispatch_hot.cranelift.jitstats
  • pyre/bench/synth/classmethod_type_dispatch_hot.dynasm.jitstats
  • pyre/bench/synth/classmethod_type_dispatch_hot.wasm.jitstats
  • pyre/bench/synth/closure_freevar_branch_resume.cranelift.jitstats
  • pyre/bench/synth/closure_freevar_branch_resume.dynasm.jitstats
  • pyre/bench/synth/closure_freevar_branch_resume.wasm.jitstats
  • pyre/bench/synth/closure_per_call.cranelift.jitstats
  • pyre/bench/synth/closure_per_call.dynasm.jitstats
  • pyre/bench/synth/complex_from_index.cranelift.jitstats
  • pyre/bench/synth/complex_from_index.dynasm.jitstats
  • pyre/bench/synth/complex_from_index.wasm.jitstats
  • pyre/bench/synth/complex_real_imag.cranelift.jitstats
  • pyre/bench/synth/complex_real_imag.dynasm.jitstats
  • pyre/bench/synth/complex_real_imag.wasm.jitstats
  • pyre/bench/synth/comprehension_accumulators.cranelift.jitstats
  • pyre/bench/synth/comprehension_accumulators.dynasm.jitstats
  • pyre/bench/synth/comprehension_accumulators.wasm.jitstats
  • pyre/bench/synth/comprehension_module_scope.cranelift.jitstats
  • pyre/bench/synth/comprehension_module_scope.dynasm.jitstats
  • pyre/bench/synth/comprehension_module_scope.wasm.jitstats
  • pyre/bench/synth/comprehension_object_append_hot.cranelift.jitstats
  • pyre/bench/synth/comprehension_object_append_hot.dynasm.jitstats
  • pyre/bench/synth/comprehension_object_append_hot.wasm.jitstats
  • pyre/bench/synth/comprehension_param_range_call_flush.cranelift.jitstats
  • pyre/bench/synth/comprehension_param_range_call_flush.dynasm.jitstats
  • pyre/bench/synth/comprehension_param_range_call_flush.wasm.jitstats
  • pyre/bench/synth/condexpr_heap_const_merge.cranelift.jitstats
  • pyre/bench/synth/condexpr_heap_const_merge.dynasm.jitstats
  • pyre/bench/synth/condexpr_heap_const_merge.wasm.jitstats
  • pyre/bench/synth/const_arg_call_resume.cranelift.jitstats
  • pyre/bench/synth/const_arg_call_resume.dynasm.jitstats
  • pyre/bench/synth/const_arg_call_resume.wasm.jitstats
  • pyre/bench/synth/context_manager.cranelift.jitstats
  • pyre/bench/synth/context_manager.dynasm.jitstats
  • pyre/bench/synth/context_manager.wasm.jitstats
  • pyre/bench/synth/defaults_reassigned_midloop.cranelift.jitstats
  • pyre/bench/synth/defaults_reassigned_midloop.dynasm.jitstats
  • pyre/bench/synth/defaults_reassigned_midloop.wasm.jitstats
  • pyre/bench/synth/del_cellvar_walk_commit.cranelift.jitstats
  • pyre/bench/synth/del_cellvar_walk_commit.dynasm.jitstats
  • pyre/bench/synth/del_cellvar_walk_commit.wasm.jitstats
  • pyre/bench/synth/delete_negative_open_slice_hot.cranelift.jitstats
  • pyre/bench/synth/delete_negative_open_slice_hot.dynasm.jitstats
  • pyre/bench/synth/delete_negative_open_slice_hot.wasm.jitstats
  • pyre/bench/synth/dict_ctor_consume.cranelift.jitstats
  • pyre/bench/synth/dict_ctor_consume.dynasm.jitstats
  • pyre/bench/synth/dict_ctor_consume.wasm.jitstats
  • pyre/bench/synth/dict_hash_protocol.cranelift.jitstats
  • pyre/bench/synth/dict_hash_protocol.dynasm.jitstats
  • pyre/bench/synth/dict_hash_protocol.wasm.jitstats
  • pyre/bench/synth/dict_set.cranelift.jitstats
  • pyre/bench/synth/dict_set.dynasm.jitstats
  • pyre/bench/synth/dict_set_key_eq_operand_order.cranelift.jitstats
  • pyre/bench/synth/dict_set_key_eq_operand_order.dynasm.jitstats
  • pyre/bench/synth/dict_set_key_eq_operand_order.wasm.jitstats
  • pyre/bench/synth/dict_update_hot.cranelift.jitstats
  • pyre/bench/synth/dict_update_hot.dynasm.jitstats
  • pyre/bench/synth/dict_update_hot.wasm.jitstats
  • pyre/bench/synth/dict_update_source_mutation.cranelift.jitstats
  • pyre/bench/synth/dict_update_source_mutation.dynasm.jitstats
  • pyre/bench/synth/dict_update_source_mutation.wasm.jitstats
  • pyre/bench/synth/dict_view_set_ops.cranelift.jitstats
  • pyre/bench/synth/dict_view_set_ops.dynasm.jitstats
  • pyre/bench/synth/dict_view_set_ops.wasm.jitstats
  • pyre/bench/synth/dir_custom.cranelift.jitstats
  • pyre/bench/synth/dir_custom.dynasm.jitstats
  • pyre/bench/synth/dir_custom.wasm.jitstats
  • pyre/bench/synth/dir_dict_class_attrs.cranelift.jitstats
  • pyre/bench/synth/dir_dict_class_attrs.dynasm.jitstats
  • pyre/bench/synth/dir_dict_class_attrs.wasm.jitstats
  • pyre/bench/synth/dir_full_mro.cranelift.jitstats
  • pyre/bench/synth/dir_full_mro.dynasm.jitstats
  • pyre/bench/synth/dir_full_mro.wasm.jitstats
  • pyre/bench/synth/divmod_long_int_pair.cranelift.jitstats
  • pyre/bench/synth/divmod_long_int_pair.dynasm.jitstats
  • pyre/bench/synth/dunder_repr_str_errors.cranelift.jitstats
  • pyre/bench/synth/dunder_repr_str_errors.dynasm.jitstats
  • pyre/bench/synth/dunder_repr_str_errors.wasm.jitstats
  • pyre/bench/synth/enumerate_bignum_start.cranelift.jitstats
  • pyre/bench/synth/enumerate_bignum_start.dynasm.jitstats
  • pyre/bench/synth/enumerate_bignum_start.wasm.jitstats
  • pyre/bench/synth/exc_bridge_entry_guard_not_removed.cranelift.jitstats
  • pyre/bench/synth/exc_bridge_entry_guard_not_removed.dynasm.jitstats
  • pyre/bench/synth/exc_bridge_entry_guard_not_removed.wasm.jitstats
  • pyre/bench/synth/exc_caught_in_callee_return_loop.cranelift.jitstats
  • pyre/bench/synth/exc_caught_in_callee_return_loop.dynasm.jitstats
  • pyre/bench/synth/exc_in_loop_divzero_continue.cranelift.jitstats
  • pyre/bench/synth/exc_in_loop_divzero_continue.dynasm.jitstats
  • pyre/bench/synth/exc_in_loop_divzero_continue.py
  • pyre/bench/synth/exc_in_loop_divzero_continue.wasm.jitstats
  • pyre/bench/synth/exc_info_module_loop_hot.cranelift.jitstats
  • pyre/bench/synth/exc_info_module_loop_hot.dynasm.jitstats
  • pyre/bench/synth/exc_info_module_loop_hot.wasm.jitstats
  • pyre/bench/synth/exc_mixed_classes_bridge_flavor.cranelift.jitstats
  • pyre/bench/synth/exc_mixed_classes_bridge_flavor.dynasm.jitstats
  • pyre/bench/synth/exc_mixed_classes_bridge_flavor.wasm.jitstats
  • pyre/bench/synth/except_star.cranelift.jitstats
  • pyre/bench/synth/except_star.dynasm.jitstats
  • pyre/bench/synth/except_star.wasm.jitstats
  • pyre/bench/synth/except_tuple_clause_hot.cranelift.jitstats
  • pyre/bench/synth/except_tuple_clause_hot.dynasm.jitstats
  • pyre/bench/synth/except_tuple_clause_hot.wasm.jitstats
  • pyre/bench/synth/exception_args_virtual.cranelift.jitstats
  • pyre/bench/synth/exception_args_virtual.dynasm.jitstats
  • pyre/bench/synth/exception_args_virtual.wasm.jitstats
  • pyre/bench/synth/exception_as_cell_cleanup.cranelift.jitstats
  • pyre/bench/synth/exception_as_cell_cleanup.dynasm.jitstats
  • pyre/bench/synth/exception_as_cell_cleanup.wasm.jitstats
  • pyre/bench/synth/exception_bare_reraise_nested_outer.cranelift.jitstats
  • pyre/bench/synth/exception_bare_reraise_nested_outer.dynasm.jitstats
  • pyre/bench/synth/exception_bare_reraise_nested_outer.wasm.jitstats
  • pyre/bench/synth/exception_bare_reraise_restore.cranelift.jitstats
  • pyre/bench/synth/exception_bare_reraise_restore.dynasm.jitstats
  • pyre/bench/synth/exception_bare_reraise_restore.wasm.jitstats
  • pyre/bench/synth/exception_bridge_traceback_head.cranelift.jitstats
  • pyre/bench/synth/exception_bridge_traceback_head.dynasm.jitstats
  • pyre/bench/synth/exception_bridge_traceback_head.wasm.jitstats
  • pyre/bench/synth/exception_catching_frame_tb_node.cranelift.jitstats
  • pyre/bench/synth/exception_catching_frame_tb_node.dynasm.jitstats
  • pyre/bench/synth/exception_catching_frame_tb_node.wasm.jitstats
  • pyre/bench/synth/exception_const_operand_resume.cranelift.jitstats
  • pyre/bench/synth/exception_const_operand_resume.dynasm.jitstats
  • pyre/bench/synth/exception_const_operand_resume.wasm.jitstats
  • pyre/bench/synth/exception_context_chain_inhandler.cranelift.jitstats
  • pyre/bench/synth/exception_context_chain_inhandler.dynasm.jitstats
  • pyre/bench/synth/exception_context_chain_inhandler.wasm.jitstats
  • pyre/bench/synth/exception_dict_slot_reject.cranelift.jitstats
  • pyre/bench/synth/exception_dict_slot_reject.dynasm.jitstats
  • pyre/bench/synth/exception_dict_slot_reject.wasm.jitstats
  • pyre/bench/synth/exception_escape_caller_frame_tb_node.cranelift.jitstats
  • pyre/bench/synth/exception_escape_caller_frame_tb_node.dynasm.jitstats
  • pyre/bench/synth/exception_escape_caller_frame_tb_node.wasm.jitstats
  • pyre/bench/synth/exception_escape_hot_callee_tb_node_once.cranelift.jitstats
  • pyre/bench/synth/exception_escape_hot_callee_tb_node_once.dynasm.jitstats
  • pyre/bench/synth/exception_escape_inlined_midframe_tb_node.cranelift.jitstats
  • pyre/bench/synth/exception_escape_inlined_midframe_tb_node.dynasm.jitstats
  • pyre/bench/synth/exception_escape_inlined_midframe_tb_node.wasm.jitstats
  • pyre/bench/synth/exception_group_type.cranelift.jitstats
  • pyre/bench/synth/exception_group_type.dynasm.jitstats
  • pyre/bench/synth/exception_group_type.wasm.jitstats
  • pyre/bench/synth/exception_inline_callee_tb_frame_locals.cranelift.jitstats
  • pyre/bench/synth/exception_inline_callee_tb_frame_locals.dynasm.jitstats
  • pyre/bench/synth/exception_inline_callee_tb_frame_locals.wasm.jitstats
  • pyre/bench/synth/exception_inline_callee_tb_frames.cranelift.jitstats
  • pyre/bench/synth/exception_inline_callee_tb_frames.dynasm.jitstats
  • pyre/bench/synth/exception_inlined_callee_caught.cranelift.jitstats
  • pyre/bench/synth/exception_inlined_callee_caught.dynasm.jitstats
  • pyre/bench/synth/exception_loop_warmup.cranelift.jitstats
  • pyre/bench/synth/exception_loop_warmup.dynasm.jitstats
  • pyre/bench/synth/exception_loop_warmup.wasm.jitstats
  • pyre/bench/synth/exception_metadata_hot.cranelift.jitstats
  • pyre/bench/synth/exception_metadata_hot.dynasm.jitstats
  • pyre/bench/synth/exception_metadata_hot.wasm.jitstats
  • pyre/bench/synth/exception_metadata_jitstress.cranelift.jitstats
  • pyre/bench/synth/exception_metadata_jitstress.dynasm.jitstats
  • pyre/bench/synth/exception_metadata_jitstress.wasm.jitstats
  • pyre/bench/synth/exception_multi_handler_warmup.cranelift.jitstats
  • pyre/bench/synth/exception_multi_handler_warmup.dynasm.jitstats
  • pyre/bench/synth/exception_multi_handler_warmup.wasm.jitstats
  • pyre/bench/synth/exception_nested_exc_info_restore.cranelift.jitstats
  • pyre/bench/synth/exception_nested_exc_info_restore.dynasm.jitstats
  • pyre/bench/synth/exception_nested_exc_info_restore.wasm.jitstats
  • pyre/bench/synth/exception_oserror_fields.cranelift.jitstats
  • pyre/bench/synth/exception_oserror_fields.dynasm.jitstats
  • pyre/bench/synth/exception_raise_caught_same_frame_tb.cranelift.jitstats
  • pyre/bench/synth/exception_raise_caught_same_frame_tb.dynasm.jitstats
  • pyre/bench/synth/exception_raise_caught_same_frame_tb.wasm.jitstats
  • pyre/bench/synth/exception_reduce.cranelift.jitstats
  • pyre/bench/synth/exception_reduce.dynasm.jitstats
  • pyre/bench/synth/exception_reduce.wasm.jitstats
  • pyre/bench/synth/exception_reentry_guard_finally_residual.cranelift.jitstats
  • pyre/bench/synth/exception_reentry_guard_finally_residual.dynasm.jitstats
  • pyre/bench/synth/exception_reentry_guard_finally_residual.wasm.jitstats
  • pyre/bench/synth/exception_reraise_tb_depth_hot.cranelift.jitstats
  • pyre/bench/synth/exception_reraise_tb_depth_hot.dynasm.jitstats
  • pyre/bench/synth/exception_reraise_tb_depth_hot.wasm.jitstats
  • pyre/bench/synth/exception_reraise_tb_depth_jitstress.cranelift.jitstats
  • pyre/bench/synth/exception_reraise_tb_depth_jitstress.dynasm.jitstats
  • pyre/bench/synth/exception_reraise_tb_depth_jitstress.wasm.jitstats
  • pyre/bench/synth/exception_residual_raise_caught_in_frame.cranelift.jitstats
  • pyre/bench/synth/exception_residual_raise_caught_in_frame.dynasm.jitstats
  • pyre/bench/synth/exception_residual_raise_caught_in_frame.wasm.jitstats
  • pyre/bench/synth/exception_reused_object_tb_not_doubled.cranelift.jitstats
  • pyre/bench/synth/exception_reused_object_tb_not_doubled.dynasm.jitstats
  • pyre/bench/synth/exception_reused_object_tb_not_doubled.wasm.jitstats
  • pyre/bench/synth/exception_subclass_attrs.cranelift.jitstats
  • pyre/bench/synth/exception_subclass_attrs.dynasm.jitstats
  • pyre/bench/synth/exception_traceback_frame_lineno.cranelift.jitstats
  • pyre/bench/synth/exception_traceback_frame_lineno.dynasm.jitstats
  • pyre/bench/synth/exception_traceback_lineno_chain.cranelift.jitstats
  • pyre/bench/synth/exception_traceback_lineno_chain.dynasm.jitstats
  • pyre/bench/synth/exception_traceback_lineno_chain.wasm.jitstats
  • pyre/bench/synth/exception_traceback_loop_forms.cranelift.jitstats
  • pyre/bench/synth/exception_traceback_loop_forms.dynasm.jitstats
  • pyre/bench/synth/exception_try_call_inlined_callee_raise.cranelift.jitstats
  • pyre/bench/synth/exception_try_call_inlined_callee_raise.dynasm.jitstats
  • pyre/bench/synth/exception_try_call_inlined_callee_raise.wasm.jitstats
  • pyre/bench/synth/exception_vable_frame_virtual_local.cranelift.jitstats
  • pyre/bench/synth/exception_vable_frame_virtual_local.dynasm.jitstats
  • pyre/bench/synth/exception_vable_frame_virtual_local.wasm.jitstats
  • pyre/bench/synth/exception_value_op_caught.cranelift.jitstats
  • pyre/bench/synth/exception_value_op_caught.dynasm.jitstats
  • pyre/bench/synth/exceptions.cranelift.jitstats
  • pyre/bench/synth/exceptions.dynasm.jitstats
  • pyre/bench/synth/exceptions.wasm.jitstats
  • pyre/bench/synth/exec_defined_global_read.cranelift.jitstats
  • pyre/bench/synth/exec_defined_global_read.dynasm.jitstats
  • pyre/bench/synth/exec_defined_global_read.wasm.jitstats
  • pyre/bench/synth/exec_fresh_globals_delete_name.cranelift.jitstats
  • pyre/bench/synth/exec_fresh_globals_delete_name.dynasm.jitstats
  • pyre/bench/synth/exec_fresh_globals_delete_name.wasm.jitstats
  • pyre/bench/synth/fast_local_swap.cranelift.jitstats
  • pyre/bench/synth/fast_local_swap.dynasm.jitstats
  • pyre/bench/synth/fast_local_swap.wasm.jitstats
  • pyre/bench/synth/finally_bare_raise.cranelift.jitstats
  • pyre/bench/synth/finally_bare_raise.dynasm.jitstats
  • pyre/bench/synth/finally_bare_raise.py
  • pyre/bench/synth/finally_bare_raise.wasm.jitstats
  • pyre/bench/synth/float_builtin_hot.cranelift.jitstats
  • pyre/bench/synth/float_builtin_hot.dynasm.jitstats
  • pyre/bench/synth/float_builtin_hot.wasm.jitstats
  • pyre/bench/synth/float_div_zero_caught_loop.cranelift.jitstats
  • pyre/bench/synth/float_div_zero_caught_loop.dynasm.jitstats
  • pyre/bench/synth/float_pow_overflow_exp.cranelift.jitstats
  • pyre/bench/synth/float_pow_overflow_exp.dynasm.jitstats
  • pyre/bench/synth/float_pow_overflow_exp.wasm.jitstats
  • pyre/bench/synth/float_subclass_binop_dispatch.cranelift.jitstats
  • pyre/bench/synth/float_subclass_binop_dispatch.dynasm.jitstats
  • pyre/bench/synth/float_subclass_binop_dispatch.wasm.jitstats
  • pyre/bench/synth/for_iter_conditional_store_bridge.cranelift.jitstats
  • pyre/bench/synth/for_iter_conditional_store_bridge.dynasm.jitstats
  • pyre/bench/synth/for_iter_conditional_store_bridge.wasm.jitstats
  • pyre/bench/synth/for_iter_select_receiver_swap.cranelift.jitstats
  • pyre/bench/synth/for_iter_select_receiver_swap.dynasm.jitstats
  • pyre/bench/synth/for_iter_select_receiver_swap.wasm.jitstats
  • pyre/bench/synth/foriter_body_return.cranelift.jitstats
  • pyre/bench/synth/foriter_body_return.dynasm.jitstats
  • pyre/bench/synth/foriter_call_body.cranelift.jitstats
  • pyre/bench/synth/foriter_call_body.dynasm.jitstats
  • pyre/bench/synth/foriter_call_body.wasm.jitstats
  • pyre/bench/synth/foriter_call_resume_drops_iteration.cranelift.jitstats
  • pyre/bench/synth/foriter_call_resume_drops_iteration.dynasm.jitstats
  • pyre/bench/synth/foriter_call_resume_drops_iteration.wasm.jitstats
  • pyre/bench/synth/foriter_exempt_nested_foriter.cranelift.jitstats
  • pyre/bench/synth/foriter_exempt_nested_foriter.dynasm.jitstats
  • pyre/bench/synth/foriter_exempt_shared_generator.cranelift.jitstats
  • pyre/bench/synth/foriter_exempt_shared_generator.dynasm.jitstats
  • pyre/bench/synth/foriter_in_while.cranelift.jitstats
  • pyre/bench/synth/foriter_in_while.dynasm.jitstats
  • pyre/bench/synth/foriter_in_while.wasm.jitstats
  • pyre/bench/synth/foriter_inplace_immutable.dynasm.jitstats
  • pyre/bench/synth/foriter_inplace_immutable.wasm.jitstats
  • pyre/bench/synth/foriter_loadglobal_body.cranelift.jitstats
  • pyre/bench/synth/foriter_loadglobal_body.dynasm.jitstats
  • pyre/bench/synth/foriter_loadglobal_body.wasm.jitstats
  • pyre/bench/synth/foriter_user_iter_kept_stack.cranelift.jitstats
  • pyre/bench/synth/foriter_user_iter_kept_stack.dynasm.jitstats
  • pyre/bench/synth/foriter_user_iter_kept_stack.wasm.jitstats
  • pyre/bench/synth/format_z_negative_zero.cranelift.jitstats
  • pyre/bench/synth/format_z_negative_zero.dynasm.jitstats
  • pyre/bench/synth/format_z_negative_zero.wasm.jitstats
  • pyre/bench/synth/gc_bug_bridge_flavor_traceback_names.cranelift.jitstats
  • pyre/bench/synth/gc_bug_bridge_flavor_traceback_names.dynasm.jitstats
  • pyre/bench/synth/gc_deque_backing_list.cranelift.jitstats
  • pyre/bench/synth/gc_deque_backing_list.dynasm.jitstats
  • pyre/bench/synth/gc_iterator_source_drop.cranelift.jitstats
  • pyre/bench/synth/gc_iterator_source_drop.dynasm.jitstats
  • pyre/bench/synth/generator_pep479.cranelift.jitstats
  • pyre/bench/synth/generator_pep479.dynasm.jitstats
  • pyre/bench/synth/generator_pep479.wasm.jitstats
  • pyre/bench/synth/generator_tree_recursion.cranelift.jitstats
  • pyre/bench/synth/generator_tree_recursion.dynasm.jitstats
  • pyre/bench/synth/generator_tree_recursion.wasm.jitstats
  • pyre/bench/synth/getattr_attribute_fallbacks.cranelift.jitstats
  • pyre/bench/synth/getattr_attribute_fallbacks.dynasm.jitstats
  • pyre/bench/synth/getattr_attribute_fallbacks.wasm.jitstats
  • pyre/bench/synth/getattr_hook_binding.cranelift.jitstats
  • pyre/bench/synth/getattr_hook_binding.dynasm.jitstats
  • pyre/bench/synth/getattr_hook_binding.wasm.jitstats
  • pyre/bench/synth/getattr_surrogate_hook.cranelift.jitstats
  • pyre/bench/synth/getattr_surrogate_hook.dynasm.jitstats
  • pyre/bench/synth/getattr_surrogate_hook.wasm.jitstats
  • pyre/bench/synth/getattribute_intercepts_dunder.cranelift.jitstats
  • pyre/bench/synth/getattribute_intercepts_dunder.dynasm.jitstats
  • pyre/bench/synth/getattribute_intercepts_dunder.wasm.jitstats
  • pyre/bench/synth/getattribute_override_no_bind.cranelift.jitstats
  • pyre/bench/synth/getattribute_override_no_bind.dynasm.jitstats
  • pyre/bench/synth/getattribute_override_no_bind.wasm.jitstats
  • pyre/bench/synth/global_cell_shortpreamble_hot.cranelift.jitstats
  • pyre/bench/synth/global_cell_shortpreamble_hot.dynasm.jitstats
  • pyre/bench/synth/global_quasiimmut_invalidation.cranelift.jitstats
  • pyre/bench/synth/global_quasiimmut_invalidation.dynasm.jitstats
  • pyre/bench/synth/global_quasiimmut_invalidation.py
  • pyre/bench/synth/global_quasiimmut_invalidation.wasm.jitstats
  • pyre/bench/synth/global_reassign.cranelift.jitstats
  • pyre/bench/synth/global_reassign.dynasm.jitstats
  • pyre/bench/synth/global_reassign.wasm.jitstats
  • pyre/bench/synth/global_reassign_invalidation.cranelift.jitstats
  • pyre/bench/synth/global_reassign_invalidation.dynasm.jitstats
  • pyre/bench/synth/global_reassign_invalidation.wasm.jitstats
  • pyre/bench/synth/global_store_plain_dict_globals.cranelift.jitstats
  • pyre/bench/synth/global_store_plain_dict_globals.dynasm.jitstats
  • pyre/bench/synth/global_store_plain_dict_globals.wasm.jitstats
  • pyre/bench/synth/goto_if_not_same_box.cranelift.jitstats
  • pyre/bench/synth/goto_if_not_same_box.dynasm.jitstats
  • pyre/bench/synth/goto_if_not_same_box.py
  • pyre/bench/synth/goto_if_not_same_box.wasm.jitstats
  • pyre/bench/synth/handler_reraise_second_exc.cranelift.jitstats
  • pyre/bench/synth/handler_reraise_second_exc.dynasm.jitstats
  • pyre/bench/synth/handler_reraise_second_exc.wasm.jitstats
  • pyre/bench/synth/hash_subclass_disabled.cranelift.jitstats
  • pyre/bench/synth/hash_subclass_disabled.dynasm.jitstats
  • pyre/bench/synth/hash_subclass_disabled.wasm.jitstats
  • pyre/bench/synth/hot_loop_exit_then_class_stmt.cranelift.jitstats
  • pyre/bench/synth/hot_loop_exit_then_class_stmt.dynasm.jitstats
  • pyre/bench/synth/hot_loop_exit_then_class_stmt.wasm.jitstats
  • pyre/bench/synth/if_else_jump_forward.cranelift.jitstats
  • pyre/bench/synth/if_else_jump_forward.dynasm.jitstats
  • pyre/bench/synth/if_else_jump_forward.wasm.jitstats
  • pyre/bench/synth/imp_lock_rlock_semantics.cranelift.jitstats
  • pyre/bench/synth/imp_lock_rlock_semantics.dynasm.jitstats
  • pyre/bench/synth/imp_lock_rlock_semantics.wasm.jitstats
  • pyre/bench/synth/import_from_hot.cranelift.jitstats
  • pyre/bench/synth/import_from_hot.dynasm.jitstats
  • pyre/bench/synth/import_from_hot.wasm.jitstats
  • pyre/bench/synth/import_from_name_path.cranelift.jitstats
  • pyre/bench/synth/import_from_name_path.dynasm.jitstats
  • pyre/bench/synth/import_from_name_path.wasm.jitstats
  • pyre/bench/synth/import_math.cranelift.jitstats
  • pyre/bench/synth/import_math.dynasm.jitstats
  • pyre/bench/synth/import_math.wasm.jitstats
  • pyre/bench/synth/import_name.cranelift.jitstats
  • pyre/bench/synth/import_name.dynasm.jitstats
  • pyre/bench/synth/import_name.wasm.jitstats
  • pyre/bench/synth/import_none_sentinel.cranelift.jitstats
  • pyre/bench/synth/import_none_sentinel.dynasm.jitstats
  • pyre/bench/synth/import_none_sentinel.wasm.jitstats
  • pyre/bench/synth/inheritance_dispatch.cranelift.jitstats
  • pyre/bench/synth/inheritance_dispatch.dynasm.jitstats
  • pyre/bench/synth/inheritance_dispatch.wasm.jitstats
  • pyre/bench/synth/inline_bignum_bridge_twoclamp.cranelift.jitstats
  • pyre/bench/synth/inline_bignum_bridge_twoclamp.dynasm.jitstats
  • pyre/bench/synth/inline_bignum_bridge_twoclamp.wasm.jitstats
  • pyre/bench/synth/inline_callee_constructs_object.dynasm.jitstats
  • pyre/bench/synth/inline_callee_constructs_object.wasm.jitstats
  • pyre/bench/synth/inline_chain_depth_typeflip.cranelift.jitstats
  • pyre/bench/synth/inline_chain_depth_typeflip.dynasm.jitstats
  • pyre/bench/synth/inline_chain_depth_typeflip.py
  • pyre/bench/synth/inline_chain_depth_typeflip.wasm.jitstats
  • pyre/bench/synth/inline_freevar_after_mayforce.cranelift.jitstats
  • pyre/bench/synth/inline_freevar_after_mayforce.dynasm.jitstats
  • pyre/bench/synth/inline_freevar_after_mayforce.wasm.jitstats
  • pyre/bench/synth/inline_gate_operand_provenance.cranelift.jitstats
  • pyre/bench/synth/inline_gate_operand_provenance.dynasm.jitstats
  • pyre/bench/synth/inline_multiframe_branchy_carrier.cranelift.jitstats
  • pyre/bench/synth/inline_multiframe_branchy_carrier.dynasm.jitstats
  • pyre/bench/synth/inline_multiframe_branchy_carrier.wasm.jitstats
  • pyre/bench/synth/inline_subwalk_mutating_residual.cranelift.jitstats
  • pyre/bench/synth/inline_subwalk_mutating_residual.dynasm.jitstats
  • pyre/bench/synth/inline_subwalk_property_mutates.cranelift.jitstats
  • pyre/bench/synth/inline_subwalk_property_mutates.dynasm.jitstats
  • pyre/bench/synth/inline_subwalk_radd_consumed.cranelift.jitstats
  • pyre/bench/synth/inline_subwalk_radd_consumed.dynasm.jitstats
  • pyre/bench/synth/inline_subwalk_radd_consumed.wasm.jitstats
  • pyre/bench/synth/inline_subwalk_user_iterator.cranelift.jitstats
  • pyre/bench/synth/inline_subwalk_user_iterator.dynasm.jitstats
  • pyre/bench/synth/inlined_callee_extended_arg_handler.cranelift.jitstats
  • pyre/bench/synth/inlined_callee_extended_arg_handler.dynasm.jitstats
  • pyre/bench/synth/inlined_callee_extended_arg_handler.wasm.jitstats
  • pyre/bench/synth/inlined_helper_arith_hot.cranelift.jitstats
  • pyre/bench/synth/inlined_helper_arith_hot.dynasm.jitstats
  • pyre/bench/synth/inlined_helper_arith_hot.py
  • pyre/bench/synth/inlined_helper_arith_hot.wasm.jitstats
  • pyre/bench/synth/inlined_helper_mutation.cranelift.jitstats
  • pyre/bench/synth/inlined_helper_mutation.dynasm.jitstats
  • pyre/bench/synth/inlined_helper_mutation.wasm.jitstats
  • pyre/bench/synth/instance_dict_reassign.cranelift.jitstats
  • pyre/bench/synth/instance_dict_reassign.dynasm.jitstats
  • pyre/bench/synth/instance_dict_reassign.wasm.jitstats
  • pyre/bench/synth/instance_surrogate_attrs.cranelift.jitstats
  • pyre/bench/synth/instance_surrogate_attrs.dynasm.jitstats
  • pyre/bench/synth/instance_surrogate_attrs.wasm.jitstats
  • pyre/bench/synth/int_base0_error_literal.cranelift.jitstats
  • pyre/bench/synth/int_base0_error_literal.dynasm.jitstats
  • pyre/bench/synth/int_base0_error_literal.wasm.jitstats
  • pyre/bench/synth/int_from_bad_dunder.cranelift.jitstats
  • pyre/bench/synth/int_from_bad_dunder.dynasm.jitstats
  • pyre/bench/synth/int_from_bad_dunder.wasm.jitstats
  • pyre/bench/synth/int_lshift_memoryerror.cranelift.jitstats
  • pyre/bench/synth/int_lshift_memoryerror.dynasm.jitstats
  • pyre/bench/synth/int_lshift_memoryerror.wasm.jitstats
  • pyre/bench/synth/int_max_str_digits.cranelift.jitstats
  • pyre/bench/synth/int_max_str_digits.dynasm.jitstats
  • pyre/bench/synth/int_max_str_digits.wasm.jitstats
  • pyre/bench/synth/int_mul_ovf_bignum_promote.cranelift.jitstats
  • pyre/bench/synth/int_mul_ovf_bignum_promote.dynasm.jitstats
  • pyre/bench/synth/int_mul_ovf_bignum_promote.py
  • pyre/bench/synth/int_mul_ovf_bignum_promote.wasm.jitstats
  • pyre/bench/synth/is_op_identity.cranelift.jitstats
  • pyre/bench/synth/is_op_identity.dynasm.jitstats
  • pyre/bench/synth/is_op_identity.wasm.jitstats
  • pyre/bench/synth/iter_sentinel_stopiteration.cranelift.jitstats
  • pyre/bench/synth/iter_sentinel_stopiteration.dynasm.jitstats
  • pyre/bench/synth/iter_sentinel_stopiteration.wasm.jitstats
  • pyre/bench/synth/iteration_protocol.cranelift.jitstats
  • pyre/bench/synth/iteration_protocol.dynasm.jitstats
  • pyre/bench/synth/iteration_protocol.wasm.jitstats
  • pyre/bench/synth/itertools_cycle.cranelift.jitstats
  • pyre/bench/synth/itertools_cycle.dynasm.jitstats
  • pyre/bench/synth/itertools_cycle.wasm.jitstats
  • pyre/bench/synth/jit_callee_raised_exc_value.cranelift.jitstats
  • pyre/bench/synth/jit_callee_raised_exc_value.dynasm.jitstats
  • pyre/bench/synth/jit_callee_raised_exc_value.wasm.jitstats
  • pyre/bench/synth/jit_reg_const_pool_256_slot_decline.cranelift.jitstats
  • pyre/bench/synth/jit_reg_const_pool_256_slot_decline.dynasm.jitstats
  • pyre/bench/synth/jit_reg_const_pool_256_slot_decline.wasm.jitstats
  • pyre/bench/synth/kept_stack_aliased_swap_boxed.cranelift.jitstats
  • pyre/bench/synth/kept_stack_aliased_swap_boxed.dynasm.jitstats
  • pyre/bench/synth/kept_stack_aliased_swap_boxed.wasm.jitstats
  • pyre/bench/synth/kept_stack_boxed_in_handler.cranelift.jitstats
  • pyre/bench/synth/kept_stack_boxed_in_handler.dynasm.jitstats
  • pyre/bench/synth/kept_stack_boxed_in_handler.wasm.jitstats
  • pyre/bench/synth/kept_stack_branch_depths.cranelift.jitstats
  • pyre/bench/synth/kept_stack_branch_depths.dynasm.jitstats
  • pyre/bench/synth/kept_stack_branch_depths.wasm.jitstats
  • pyre/bench/synth/kept_stack_deep_var_condexpr.cranelift.jitstats
  • pyre/bench/synth/kept_stack_deep_var_condexpr.dynasm.jitstats
  • pyre/bench/synth/kept_stack_deep_var_condexpr.wasm.jitstats
  • pyre/bench/synth/kept_stack_deep_var_nested_call.cranelift.jitstats
  • pyre/bench/synth/kept_stack_deep_var_nested_call.dynasm.jitstats
  • pyre/bench/synth/kept_stack_deep_var_nested_call.wasm.jitstats
  • pyre/bench/synth/kept_stack_deep_var_shortcircuit.cranelift.jitstats
  • pyre/bench/synth/kept_stack_deep_var_shortcircuit.dynasm.jitstats
  • pyre/bench/synth/kept_stack_depth_gt1.cranelift.jitstats
  • pyre/bench/synth/kept_stack_depth_gt1.dynasm.jitstats
  • pyre/bench/synth/kept_stack_depth_gt1.wasm.jitstats
  • pyre/bench/synth/kept_stack_depth_gt1_heap.cranelift.jitstats
  • pyre/bench/synth/kept_stack_depth_gt1_heap.dynasm.jitstats
  • pyre/bench/synth/kept_stack_depth_gt1_heap.wasm.jitstats
  • pyre/bench/synth/key_eq_resize_restart.cranelift.jitstats
  • pyre/bench/synth/key_eq_resize_restart.dynasm.jitstats
  • pyre/bench/synth/key_eq_resize_restart.wasm.jitstats
  • pyre/bench/synth/key_eq_restart_forgets.cranelift.jitstats
  • pyre/bench/synth/key_eq_restart_forgets.dynasm.jitstats
  • pyre/bench/synth/key_eq_restart_forgets.wasm.jitstats
  • pyre/bench/synth/kwargs_positional_only.cranelift.jitstats
  • pyre/bench/synth/kwargs_positional_only.dynasm.jitstats
  • pyre/bench/synth/kwargs_positional_only.wasm.jitstats
  • pyre/bench/synth/len_dunder_validation.cranelift.jitstats
  • pyre/bench/synth/len_dunder_validation.dynasm.jitstats
  • pyre/bench/synth/len_dunder_validation.wasm.jitstats
  • pyre/bench/synth/list_append_funcentry_helper.cranelift.jitstats
  • pyre/bench/synth/list_append_funcentry_helper.dynasm.jitstats
  • pyre/bench/synth/list_append_funcentry_helper.wasm.jitstats
  • pyre/bench/synth/list_append_virtual_payload.cranelift.jitstats
  • pyre/bench/synth/list_append_virtual_payload.dynasm.jitstats
  • pyre/bench/synth/list_append_virtual_payload.wasm.jitstats
  • pyre/bench/synth/list_append_write_barrier_gc.cranelift.jitstats
  • pyre/bench/synth/list_append_write_barrier_gc.dynasm.jitstats
  • pyre/bench/synth/list_append_write_barrier_gc.wasm.jitstats
  • pyre/bench/synth/list_bound_method_mutation.cranelift.jitstats
  • pyre/bench/synth/list_bound_method_mutation.dynasm.jitstats
  • pyre/bench/synth/list_bound_method_mutation.wasm.jitstats
  • pyre/bench/synth/list_error_parity.cranelift.jitstats
  • pyre/bench/synth/list_error_parity.dynasm.jitstats
  • pyre/bench/synth/list_error_parity.wasm.jitstats
  • pyre/bench/synth/list_inplace_mul_parity.cranelift.jitstats
  • pyre/bench/synth/list_inplace_mul_parity.dynasm.jitstats
  • pyre/bench/synth/list_inplace_mul_parity.wasm.jitstats
  • pyre/bench/synth/list_insert.cranelift.jitstats
  • pyre/bench/synth/list_insert.dynasm.jitstats
  • pyre/bench/synth/list_insert.wasm.jitstats
  • pyre/bench/synth/list_insert_pop_index.cranelift.jitstats
  • pyre/bench/synth/list_insert_pop_index.dynasm.jitstats
  • pyre/bench/synth/list_insert_pop_index.wasm.jitstats
  • pyre/bench/synth/list_length_hint_validate.cranelift.jitstats
  • pyre/bench/synth/list_length_hint_validate.dynasm.jitstats
  • pyre/bench/synth/list_length_hint_validate.wasm.jitstats
  • pyre/bench/synth/list_nan_identity.cranelift.jitstats
  • pyre/bench/synth/list_nan_identity.dynasm.jitstats
  • pyre/bench/synth/list_nan_identity.wasm.jitstats
  • pyre/bench/synth/list_ops.cranelift.jitstats
  • pyre/bench/synth/list_ops.dynasm.jitstats
  • pyre/bench/synth/list_pop_append.cranelift.jitstats
  • pyre/bench/synth/list_pop_append.dynasm.jitstats
  • pyre/bench/synth/list_pop_append.wasm.jitstats
  • pyre/bench/synth/list_reverse.cranelift.jitstats
  • pyre/bench/synth/list_reverse.dynasm.jitstats
  • pyre/bench/synth/list_reverse.wasm.jitstats
  • pyre/bench/synth/list_setslice.cranelift.jitstats
  • pyre/bench/synth/list_setslice.dynasm.jitstats
  • pyre/bench/synth/list_setslice.wasm.jitstats
  • pyre/bench/synth/list_subscript_index.cranelift.jitstats
  • pyre/bench/synth/list_subscript_index.dynasm.jitstats
  • pyre/bench/synth/list_subscript_index.wasm.jitstats
  • pyre/bench/synth/list_to_tuple_star.cranelift.jitstats
  • pyre/bench/synth/list_to_tuple_star.dynasm.jitstats
  • pyre/bench/synth/list_to_tuple_star.wasm.jitstats
  • pyre/bench/synth/listcomp_hot.cranelift.jitstats
  • pyre/bench/synth/listcomp_hot.dynasm.jitstats
  • pyre/bench/synth/listcomp_hot.wasm.jitstats
  • pyre/bench/synth/load_attr_blackhole_resume.cranelift.jitstats
  • pyre/bench/synth/load_attr_blackhole_resume.dynasm.jitstats
  • pyre/bench/synth/load_attr_blackhole_resume.wasm.jitstats
  • pyre/bench/synth/load_fast_check.cranelift.jitstats
  • pyre/bench/synth/load_fast_check.dynasm.jitstats
  • pyre/bench/synth/load_fast_check.wasm.jitstats
  • pyre/bench/synth/load_super_attr.cranelift.jitstats
  • pyre/bench/synth/load_super_attr.dynasm.jitstats
  • pyre/bench/synth/load_super_attr.wasm.jitstats
  • pyre/bench/synth/loop_callee_return.cranelift.jitstats
  • pyre/bench/synth/loop_callee_return.dynasm.jitstats
  • pyre/bench/synth/loop_callee_return.wasm.jitstats
  • pyre/bench/synth/loop_callee_shared_mutation.cranelift.jitstats
  • pyre/bench/synth/loop_callee_shared_mutation.dynasm.jitstats
  • pyre/bench/synth/loop_callee_shared_mutation.wasm.jitstats
  • pyre/bench/synth/loop_exit_empty_dict_local_clobber.cranelift.jitstats
  • pyre/bench/synth/loop_exit_empty_dict_local_clobber.dynasm.jitstats
  • pyre/bench/synth/loop_exit_empty_dict_local_clobber.wasm.jitstats
  • pyre/bench/synth/loop_in_try_raise_into_handler.cranelift.jitstats
  • pyre/bench/synth/loop_in_try_raise_into_handler.dynasm.jitstats
  • pyre/bench/synth/loop_in_try_raise_into_handler.wasm.jitstats
  • pyre/bench/synth/loop_in_try_tail_raise_and_second_loop.cranelift.jitstats
  • pyre/bench/synth/loop_in_try_tail_raise_and_second_loop.dynasm.jitstats
  • pyre/bench/synth/loop_in_try_tail_raise_and_second_loop.wasm.jitstats
  • pyre/bench/synth/loop_in_try_tail_unbound_check.cranelift.jitstats
  • pyre/bench/synth/loop_in_try_tail_unbound_check.dynasm.jitstats
  • pyre/bench/synth/loop_in_try_tail_unbound_check.wasm.jitstats
  • pyre/bench/synth/loops_comprehension.cranelift.jitstats
  • pyre/bench/synth/loops_comprehension.dynasm.jitstats
  • pyre/bench/synth/make_function_inline.cranelift.jitstats
  • pyre/bench/synth/make_function_inline.dynasm.jitstats
  • pyre/bench/synth/make_function_inline.wasm.jitstats
  • pyre/bench/synth/mapdict_polymorphic_map_attr.cranelift.jitstats
  • pyre/bench/synth/mapdict_polymorphic_map_attr.dynasm.jitstats
  • pyre/bench/synth/mapdict_polymorphic_map_attr.wasm.jitstats
  • pyre/bench/synth/mapdict_unboxed_type_change_attr.cranelift.jitstats
  • pyre/bench/synth/mapdict_unboxed_type_change_attr.dynasm.jitstats
  • pyre/bench/synth/mapdict_unboxed_type_change_attr.wasm.jitstats
  • pyre/bench/synth/match_sequence_of_class_patterns.cranelift.jitstats
  • pyre/bench/synth/match_sequence_of_class_patterns.dynasm.jitstats
  • pyre/bench/synth/math_isqrt_compare_bridge_resume.cranelift.jitstats
  • pyre/bench/synth/math_isqrt_compare_bridge_resume.dynasm.jitstats
  • pyre/bench/synth/math_log_trig_hot.cranelift.jitstats
  • pyre/bench/synth/math_log_trig_hot.dynasm.jitstats
  • pyre/bench/synth/math_log_trig_hot.wasm.jitstats
  • pyre/bench/synth/math_sqrt_hot.cranelift.jitstats
  • pyre/bench/synth/math_sqrt_hot.dynasm.jitstats
  • pyre/bench/synth/math_sqrt_hot.wasm.jitstats
  • pyre/bench/synth/metaclass_conflict.cranelift.jitstats
  • pyre/bench/synth/metaclass_conflict.dynasm.jitstats
  • pyre/bench/synth/metaclass_conflict.wasm.jitstats
  • pyre/bench/synth/metaclass_getattr.cranelift.jitstats
  • pyre/bench/synth/metaclass_getattr.dynasm.jitstats
  • pyre/bench/synth/metaclass_getattr.wasm.jitstats
  • pyre/bench/synth/metaclass_getattribute_delattr.cranelift.jitstats
  • pyre/bench/synth/metaclass_getattribute_delattr.dynasm.jitstats
  • pyre/bench/synth/metaclass_getattribute_delattr.wasm.jitstats
  • pyre/bench/synth/metatype_property_dunder.cranelift.jitstats
  • pyre/bench/synth/metatype_property_dunder.dynasm.jitstats
  • pyre/bench/synth/metatype_property_dunder.wasm.jitstats
  • pyre/bench/synth/method_reassign_after_warmup.cranelift.jitstats
  • pyre/bench/synth/method_reassign_after_warmup.dynasm.jitstats
  • pyre/bench/synth/method_reassign_after_warmup.wasm.jitstats
  • pyre/bench/synth/minmax_key_rooting.cranelift.jitstats
  • pyre/bench/synth/minmax_key_rooting.dynasm.jitstats
  • pyre/bench/synth/minmax_key_rooting.wasm.jitstats
  • pyre/bench/synth/module_attr_message.cranelift.jitstats
  • pyre/bench/synth/module_attr_message.dynasm.jitstats
  • pyre/bench/synth/module_attr_message.wasm.jitstats
  • pyre/bench/synth/module_body_truncated_jitcode_replay.cranelift.jitstats
  • pyre/bench/synth/module_body_truncated_jitcode_replay.dynasm.jitstats
  • pyre/bench/synth/module_body_truncated_jitcode_replay.wasm.jitstats
  • pyre/bench/synth/module_dir_dunder.cranelift.jitstats
  • pyre/bench/synth/module_dir_dunder.dynasm.jitstats
  • pyre/bench/synth/module_dir_dunder.wasm.jitstats
  • pyre/bench/synth/module_function_not_descriptor.cranelift.jitstats
  • pyre/bench/synth/module_function_not_descriptor.dynasm.jitstats
  • pyre/bench/synth/module_function_not_descriptor.wasm.jitstats
  • pyre/bench/synth/module_getattr.cranelift.jitstats
  • pyre/bench/synth/module_getattr.dynasm.jitstats
  • pyre/bench/synth/module_getattr.wasm.jitstats
  • pyre/bench/synth/module_getattr_descr_error.cranelift.jitstats
  • pyre/bench/synth/module_getattr_descr_error.dynasm.jitstats
  • pyre/bench/synth/module_getattr_descr_error.wasm.jitstats
  • pyre/bench/synth/module_getattr_surrogate_cls.cranelift.jitstats
  • pyre/bench/synth/module_getattr_surrogate_cls.dynasm.jitstats
  • pyre/bench/synth/module_getattr_surrogate_cls.wasm.jitstats
  • pyre/bench/synth/mutate_then_raise_caught.cranelift.jitstats
  • pyre/bench/synth/mutate_then_raise_caught.dynasm.jitstats
  • pyre/bench/synth/mutate_uncaught_raise_delivery.cranelift.jitstats
  • pyre/bench/synth/mutate_uncaught_raise_delivery.dynasm.jitstats
  • pyre/bench/synth/mutate_uncaught_raise_delivery.wasm.jitstats
  • pyre/bench/synth/named_reraise_sibling_hot.cranelift.jitstats
  • pyre/bench/synth/named_reraise_sibling_hot.dynasm.jitstats
  • pyre/bench/synth/named_reraise_sibling_hot.wasm.jitstats
  • pyre/bench/synth/nested_break_not_hot.cranelift.jitstats
  • pyre/bench/synth/nested_break_not_hot.dynasm.jitstats
  • pyre/bench/synth/nested_break_not_hot.wasm.jitstats
  • pyre/bench/synth/nested_callee_chain_mutation_abort.cranelift.jitstats
  • pyre/bench/synth/nested_callee_chain_mutation_abort.dynasm.jitstats
  • pyre/bench/synth/nested_callee_chain_mutation_abort.wasm.jitstats
  • pyre/bench/synth/nested_for_int_scratch_bridge.cranelift.jitstats
  • pyre/bench/synth/nested_for_int_scratch_bridge.dynasm.jitstats
  • pyre/bench/synth/nested_for_int_scratch_bridge.wasm.jitstats
  • pyre/bench/synth/nested_for_outer_local_postread.cranelift.jitstats
  • pyre/bench/synth/nested_for_outer_local_postread.dynasm.jitstats
  • pyre/bench/synth/nested_for_outer_local_postread.wasm.jitstats
  • pyre/bench/synth/nested_for_varying_trip.cranelift.jitstats
  • pyre/bench/synth/nested_for_varying_trip.dynasm.jitstats
  • pyre/bench/synth/nested_for_varying_trip.wasm.jitstats
  • pyre/bench/synth/nested_foriter_poly.cranelift.jitstats
  • pyre/bench/synth/nested_foriter_poly.dynasm.jitstats
  • pyre/bench/synth/nested_foriter_poly.wasm.jitstats
  • pyre/bench/synth/nested_list_comprehension_hot.cranelift.jitstats
  • pyre/bench/synth/nested_list_comprehension_hot.dynasm.jitstats
  • pyre/bench/synth/nested_list_comprehension_hot.wasm.jitstats
  • pyre/bench/synth/nested_loop_correctness.cranelift.jitstats
  • pyre/bench/synth/nested_loop_correctness.dynasm.jitstats
  • pyre/bench/synth/nested_loop_correctness.wasm.jitstats
  • pyre/bench/synth/nested_loop_gate_switch.cranelift.jitstats
  • pyre/bench/synth/nested_loop_gate_switch.dynasm.jitstats
  • pyre/bench/synth/nested_loop_gate_switch.wasm.jitstats
  • pyre/bench/synth/newslice_step_hot.cranelift.jitstats
  • pyre/bench/synth/newslice_step_hot.dynasm.jitstats
  • pyre/bench/synth/object_getattribute_no_hook.cranelift.jitstats
  • pyre/bench/synth/object_getattribute_no_hook.dynasm.jitstats
  • pyre/bench/synth/object_getattribute_no_hook.wasm.jitstats
  • pyre/bench/synth/operator_error_typename.cranelift.jitstats
  • pyre/bench/synth/operator_error_typename.dynasm.jitstats
  • pyre/bench/synth/operator_error_typename.wasm.jitstats
  • pyre/bench/synth/operator_set_inplace_ops.cranelift.jitstats
  • pyre/bench/synth/operator_set_inplace_ops.dynasm.jitstats
  • pyre/bench/synth/operator_set_inplace_ops.wasm.jitstats
  • pyre/bench/synth/or_chain_fresh_alloc_arg.cranelift.jitstats
  • pyre/bench/synth/or_chain_fresh_alloc_arg.dynasm.jitstats
  • pyre/bench/synth/or_chain_fresh_alloc_arg.wasm.jitstats
  • pyre/bench/synth/p2_local_result_bridge.cranelift.jitstats
  • pyre/bench/synth/p2_local_result_bridge.dynasm.jitstats
  • pyre/bench/synth/p2_local_result_bridge.wasm.jitstats
  • pyre/bench/synth/polymorphic_slot_retype.cranelift.jitstats
  • pyre/bench/synth/polymorphic_slot_retype.dynasm.jitstats
  • pyre/bench/synth/polymorphic_slot_retype.wasm.jitstats
  • pyre/bench/synth/pow3_arg_types.cranelift.jitstats
  • pyre/bench/synth/pow3_arg_types.dynasm.jitstats
  • pyre/bench/synth/pow3_arg_types.wasm.jitstats
  • pyre/bench/synth/print_stdout_redirect.cranelift.jitstats
  • pyre/bench/synth/print_stdout_redirect.dynasm.jitstats
  • pyre/bench/synth/print_stdout_redirect.wasm.jitstats
  • pyre/bench/synth/property_custom_hook_decline.cranelift.jitstats
  • pyre/bench/synth/property_custom_hook_decline.dynasm.jitstats
  • pyre/bench/synth/property_custom_hook_decline.wasm.jitstats
  • pyre/bench/synth/property_getattr_exceptions.cranelift.jitstats
  • pyre/bench/synth/property_getattr_exceptions.dynasm.jitstats
  • pyre/bench/synth/property_getattr_exceptions.wasm.jitstats
  • pyre/bench/synth/property_protocol_hot.cranelift.jitstats
  • pyre/bench/synth/property_protocol_hot.dynasm.jitstats
  • pyre/bench/synth/property_protocol_hot.wasm.jitstats
  • pyre/bench/synth/pure_listload_raw.cranelift.jitstats
  • pyre/bench/synth/pure_listload_raw.dynasm.jitstats
  • pyre/bench/synth/pure_listload_raw.wasm.jitstats
  • pyre/bench/synth/pure_tupleload.cranelift.jitstats
  • pyre/bench/synth/pure_tupleload.dynasm.jitstats
  • pyre/bench/synth/pure_tupleload.wasm.jitstats
  • pyre/bench/synth/pypy_dict_primitives_nonbinding.cranelift.jitstats
  • pyre/bench/synth/pypy_dict_primitives_nonbinding.dynasm.jitstats
  • pyre/bench/synth/pypy_dict_primitives_nonbinding.wasm.jitstats
  • pyre/bench/synth/raise_reg_unbound_jitstress.cranelift.jitstats
  • pyre/bench/synth/raise_reg_unbound_jitstress.dynasm.jitstats
  • pyre/bench/synth/raise_reg_unbound_jitstress.wasm.jitstats
  • pyre/bench/synth/range_ctor_in_loop.cranelift.jitstats
  • pyre/bench/synth/range_ctor_in_loop.dynasm.jitstats
  • pyre/bench/synth/range_ctor_in_loop.wasm.jitstats
  • pyre/bench/synth/recursion_memo_branch.cranelift.jitstats
  • pyre/bench/synth/recursion_memo_branch.dynasm.jitstats
  • pyre/bench/synth/recursive_call_frame_relocation.cranelift.jitstats
  • pyre/bench/synth/recursive_call_frame_relocation.dynasm.jitstats
  • pyre/bench/synth/reentrant_key_eq_mutation.cranelift.jitstats
  • pyre/bench/synth/reentrant_key_eq_mutation.dynasm.jitstats
  • pyre/bench/synth/reentrant_key_eq_mutation.wasm.jitstats
  • pyre/bench/synth/residual_raise_except_resume.cranelift.jitstats
  • pyre/bench/synth/residual_raise_except_resume.dynasm.jitstats
  • pyre/bench/synth/residual_raise_except_resume.py
  • pyre/bench/synth/residual_raise_except_resume.wasm.jitstats
  • pyre/bench/synth/retrace_accumulator_type_flip.cranelift.jitstats
  • pyre/bench/synth/retrace_accumulator_type_flip.dynasm.jitstats
  • pyre/bench/synth/retrace_accumulator_type_flip.wasm.jitstats
  • pyre/bench/synth/reversed_disabled.cranelift.jitstats
  • pyre/bench/synth/reversed_disabled.dynasm.jitstats
  • pyre/bench/synth/reversed_disabled.wasm.jitstats
  • pyre/bench/synth/selfrec_tail_exception_unwind.cranelift.jitstats
  • pyre/bench/synth/selfrec_tail_exception_unwind.dynasm.jitstats
  • pyre/bench/synth/selfrec_tail_exception_unwind.wasm.jitstats
  • pyre/bench/synth/seq_repeat_overflow.cranelift.jitstats
  • pyre/bench/synth/seq_repeat_overflow.dynasm.jitstats
  • pyre/bench/synth/seq_repeat_overflow.wasm.jitstats
  • pyre/bench/synth/seqiter_getitem_lazy.cranelift.jitstats
  • pyre/bench/synth/seqiter_getitem_lazy.dynasm.jitstats
  • pyre/bench/synth/seqiter_getitem_lazy.wasm.jitstats
  • pyre/bench/synth/seqiter_pickle_parity.cranelift.jitstats
  • pyre/bench/synth/seqiter_pickle_parity.dynasm.jitstats
  • pyre/bench/synth/seqiter_pickle_parity.wasm.jitstats
  • pyre/bench/synth/seqiter_tuple_error_parity.cranelift.jitstats
  • pyre/bench/synth/seqiter_tuple_error_parity.dynasm.jitstats
  • pyre/bench/synth/seqiter_tuple_error_parity.wasm.jitstats
  • pyre/bench/synth/sequence_repeat_index.cranelift.jitstats
  • pyre/bench/synth/sequence_repeat_index.dynasm.jitstats
  • pyre/bench/synth/sequence_repeat_index.wasm.jitstats
  • pyre/bench/synth/set_contains_frozenset.cranelift.jitstats
  • pyre/bench/synth/set_contains_frozenset.dynasm.jitstats
  • pyre/bench/synth/set_contains_frozenset.wasm.jitstats
  • pyre/bench/synth/set_intersection_operand.cranelift.jitstats
  • pyre/bench/synth/set_intersection_operand.dynasm.jitstats
  • pyre/bench/synth/set_intersection_operand.wasm.jitstats
  • pyre/bench/synth/set_key_protocol.cranelift.jitstats
  • pyre/bench/synth/set_key_protocol.dynasm.jitstats
  • pyre/bench/synth/set_key_protocol.wasm.jitstats
  • pyre/bench/synth/set_method_arity.cranelift.jitstats
  • pyre/bench/synth/set_method_arity.dynasm.jitstats
  • pyre/bench/synth/set_method_arity.wasm.jitstats
  • pyre/bench/synth/set_name_filtered_dict.cranelift.jitstats
  • pyre/bench/synth/set_name_filtered_dict.dynasm.jitstats
  • pyre/bench/synth/set_name_filtered_dict.wasm.jitstats
  • pyre/bench/synth/set_reentrant_eq_mutation.cranelift.jitstats
  • pyre/bench/synth/set_reentrant_eq_mutation.dynasm.jitstats
  • pyre/bench/synth/set_reentrant_eq_mutation.wasm.jitstats
  • pyre/bench/synth/set_remove_ord_errors.cranelift.jitstats
  • pyre/bench/synth/set_remove_ord_errors.dynasm.jitstats
  • pyre/bench/synth/set_remove_ord_errors.wasm.jitstats
  • pyre/bench/synth/set_update_hash_other.cranelift.jitstats
  • pyre/bench/synth/set_update_hash_other.dynasm.jitstats
  • pyre/bench/synth/set_update_hash_other.wasm.jitstats
  • pyre/bench/synth/set_update_hot.cranelift.jitstats
  • pyre/bench/synth/set_update_hot.dynasm.jitstats
  • pyre/bench/synth/set_update_hot.wasm.jitstats
  • pyre/bench/synth/set_update_materialize_rhs.cranelift.jitstats
  • pyre/bench/synth/set_update_materialize_rhs.dynasm.jitstats
  • pyre/bench/synth/set_update_materialize_rhs.wasm.jitstats
  • pyre/bench/synth/short_circuit_boxed_int_cross_fn.cranelift.jitstats
  • pyre/bench/synth/short_circuit_boxed_int_cross_fn.dynasm.jitstats
  • pyre/bench/synth/short_circuit_boxed_int_cross_fn.wasm.jitstats
  • pyre/bench/synth/short_circuit_falsy_func_entry_resume.cranelift.jitstats
  • pyre/bench/synth/short_circuit_falsy_func_entry_resume.dynasm.jitstats
  • pyre/bench/synth/short_circuit_falsy_func_entry_resume.wasm.jitstats
  • pyre/bench/synth/short_circuit_side_effects.cranelift.jitstats
  • pyre/bench/synth/short_circuit_side_effects.dynasm.jitstats
  • pyre/bench/synth/short_circuit_side_effects.wasm.jitstats
  • pyre/bench/synth/short_circuit_value_kept_stack.cranelift.jitstats
  • pyre/bench/synth/short_circuit_value_kept_stack.dynasm.jitstats
  • pyre/bench/synth/short_circuit_value_kept_stack.wasm.jitstats
  • pyre/bench/synth/short_circuit_value_local_kept.cranelift.jitstats
  • pyre/bench/synth/short_circuit_value_local_kept.dynasm.jitstats
  • pyre/bench/synth/short_circuit_value_local_kept.wasm.jitstats
  • pyre/bench/synth/simple_namespace_type.cranelift.jitstats
  • pyre/bench/synth/simple_namespace_type.dynasm.jitstats
  • pyre/bench/synth/simple_namespace_type.wasm.jitstats
  • pyre/bench/synth/slots_class_var_conflict.cranelift.jitstats
  • pyre/bench/synth/slots_class_var_conflict.dynasm.jitstats
  • pyre/bench/synth/slots_class_var_conflict.wasm.jitstats
  • pyre/bench/synth/store_global_hot.cranelift.jitstats
  • pyre/bench/synth/store_global_hot.dynasm.jitstats
  • pyre/bench/synth/store_global_hot.wasm.jitstats
  • pyre/bench/synth/store_slice_hot.cranelift.jitstats
  • pyre/bench/synth/store_slice_hot.dynasm.jitstats
  • pyre/bench/synth/store_slice_hot.wasm.jitstats
  • pyre/bench/synth/str_encode_text_codec.cranelift.jitstats
  • pyre/bench/synth/str_encode_text_codec.dynasm.jitstats
  • pyre/bench/synth/str_encode_text_codec.wasm.jitstats
  • pyre/bench/synth/str_fstring.cranelift.jitstats
  • pyre/bench/synth/str_fstring.dynasm.jitstats
  • pyre/bench/synth/str_getitem_len_hot.cranelift.jitstats
  • pyre/bench/synth/str_getitem_len_hot.dynasm.jitstats
  • pyre/bench/synth/str_getitem_len_hot.wasm.jitstats
  • pyre/bench/synth/str_index_bytes_iter_surface.cranelift.jitstats
  • pyre/bench/synth/str_index_bytes_iter_surface.dynasm.jitstats
  • pyre/bench/synth/str_index_bytes_iter_surface.wasm.jitstats
  • pyre/bench/synth/str_search_index_bounds.cranelift.jitstats
  • pyre/bench/synth/str_search_index_bounds.dynasm.jitstats
  • pyre/bench/synth/str_search_index_bounds.wasm.jitstats
  • pyre/bench/synth/str_startswith_bounds.cranelift.jitstats
  • pyre/bench/synth/str_startswith_bounds.dynasm.jitstats
  • pyre/bench/synth/str_startswith_bounds.wasm.jitstats
  • pyre/bench/synth/struct_pack_unpack.cranelift.jitstats
  • pyre/bench/synth/struct_pack_unpack.dynasm.jitstats
  • pyre/bench/synth/struct_pack_unpack.wasm.jitstats
  • pyre/bench/synth/subscr_negative_index_deopt.cranelift.jitstats
  • pyre/bench/synth/subscr_negative_index_deopt.dynasm.jitstats
  • pyre/bench/synth/subscr_negative_index_deopt.wasm.jitstats
  • pyre/bench/synth/subscr_user_getitem_inline.cranelift.jitstats
  • pyre/bench/synth/subscr_user_getitem_inline.dynasm.jitstats
  • pyre/bench/synth/subscr_user_getitem_inline.wasm.jitstats
  • pyre/bench/synth/surrogate_class_kwargs.cranelift.jitstats
  • pyre/bench/synth/surrogate_class_kwargs.dynasm.jitstats
  • pyre/bench/synth/surrogate_class_kwargs.wasm.jitstats
  • pyre/bench/synth/surrogate_dir.cranelift.jitstats
  • pyre/bench/synth/surrogate_dir.dynasm.jitstats
  • pyre/bench/synth/surrogate_dir.wasm.jitstats
  • pyre/bench/synth/surrogate_kwargs.cranelift.jitstats
  • pyre/bench/synth/surrogate_kwargs.dynasm.jitstats
  • pyre/bench/synth/surrogate_kwargs.wasm.jitstats
  • pyre/bench/synth/surrogate_metaclass_kwargs.cranelift.jitstats
  • pyre/bench/synth/surrogate_metaclass_kwargs.dynasm.jitstats
  • pyre/bench/synth/surrogate_metaclass_kwargs.wasm.jitstats
  • pyre/bench/synth/swap_except_return_resume.cranelift.jitstats
  • pyre/bench/synth/swap_except_return_resume.dynasm.jitstats
  • pyre/bench/synth/swap_except_return_resume.wasm.jitstats
  • pyre/bench/synth/syntaxerror_location.cranelift.jitstats
  • pyre/bench/synth/syntaxerror_location.dynasm.jitstats
  • pyre/bench/synth/syntaxerror_location.wasm.jitstats
  • pyre/bench/synth/syntaxerror_str.cranelift.jitstats
  • pyre/bench/synth/syntaxerror_str.dynasm.jitstats
  • pyre/bench/synth/syntaxerror_str.wasm.jitstats
  • pyre/bench/synth/tuple_contains_eq_raises.cranelift.jitstats
  • pyre/bench/synth/tuple_contains_eq_raises.dynasm.jitstats
  • pyre/bench/synth/tuple_contains_eq_raises.wasm.jitstats
  • pyre/bench/synth/tuple_str_bytes_subscript_index.cranelift.jitstats
  • pyre/bench/synth/tuple_str_bytes_subscript_index.dynasm.jitstats
  • pyre/bench/synth/tuple_str_bytes_subscript_index.wasm.jitstats
  • pyre/bench/synth/tuple_unpack_array_backed_hot.cranelift.jitstats
  • pyre/bench/synth/tuple_unpack_array_backed_hot.dynasm.jitstats
  • pyre/bench/synth/tuple_unpack_array_backed_hot.wasm.jitstats
  • pyre/bench/synth/type_call_inline_init_branch_deopt.cranelift.jitstats
  • pyre/bench/synth/type_call_inline_init_branch_deopt.dynasm.jitstats
  • pyre/bench/synth/type_call_inline_init_branch_deopt.wasm.jitstats
  • pyre/bench/synth/type_descr_get_metaclass_getattr.cranelift.jitstats
  • pyre/bench/synth/type_descr_get_metaclass_getattr.dynasm.jitstats
  • pyre/bench/synth/type_descr_get_metaclass_getattr.wasm.jitstats
  • pyre/bench/synth/type_dict_surrogate.cranelift.jitstats
  • pyre/bench/synth/type_dict_surrogate.dynasm.jitstats
  • pyre/bench/synth/type_dict_surrogate.wasm.jitstats
  • pyre/bench/synth/type_dotted_name.cranelift.jitstats
  • pyre/bench/synth/type_dotted_name.dynasm.jitstats
  • pyre/bench/synth/type_dotted_name.wasm.jitstats
  • pyre/bench/synth/type_error_message_parity.cranelift.jitstats
  • pyre/bench/synth/type_error_message_parity.dynasm.jitstats
  • pyre/bench/synth/type_error_message_parity.wasm.jitstats
  • pyre/bench/synth/type_immutable_reject.cranelift.jitstats
  • pyre/bench/synth/type_immutable_reject.dynasm.jitstats
  • pyre/bench/synth/type_immutable_reject.wasm.jitstats
  • pyre/bench/synth/type_metatype_data_descr.cranelift.jitstats
  • pyre/bench/synth/type_metatype_data_descr.dynasm.jitstats
  • pyre/bench/synth/type_metatype_data_descr.wasm.jitstats
  • pyre/bench/synth/type_name_setter.cranelift.jitstats
  • pyre/bench/synth/type_name_setter.dynasm.jitstats
  • pyre/bench/synth/type_name_surrogate_reject.cranelift.jitstats
  • pyre/bench/synth/type_name_surrogate_reject.dynasm.jitstats
  • pyre/bench/synth/unary_int_loop_carried.cranelift.jitstats
  • pyre/bench/synth/unary_int_loop_carried.dynasm.jitstats
  • pyre/bench/synth/unary_int_loop_carried.wasm.jitstats
  • pyre/bench/synth/unary_negative.cranelift.jitstats
  • pyre/bench/synth/unary_negative.dynasm.jitstats
  • pyre/bench/synth/unary_positive_resume.cranelift.jitstats
  • pyre/bench/synth/unary_positive_resume.dynasm.jitstats
  • pyre/bench/synth/unpack_drain_star_raise.cranelift.jitstats
  • pyre/bench/synth/unpack_drain_star_raise.dynasm.jitstats
  • pyre/bench/synth/unpack_drain_star_raise.wasm.jitstats
  • pyre/bench/synth/unpack_ex_hot.cranelift.jitstats
  • pyre/bench/synth/unpack_ex_hot.dynasm.jitstats
  • pyre/bench/synth/unpack_wrong_arity_caught.cranelift.jitstats
  • pyre/bench/synth/unpack_wrong_arity_caught.dynasm.jitstats
  • pyre/bench/synth/unpack_wrong_arity_caught.wasm.jitstats
  • pyre/bench/synth/wasm_ca_trampoline_decline.cranelift.jitstats
  • pyre/bench/synth/wasm_ca_trampoline_decline.dynasm.jitstats
  • pyre/bench/synth/while_is_none.cranelift.jitstats
  • pyre/bench/synth/while_is_none.dynasm.jitstats
  • pyre/bench/synth/while_is_none.wasm.jitstats
  • pyre/bench/synth/wide_callkw_resume.cranelift.jitstats
  • pyre/bench/synth/wide_callkw_resume.dynasm.jitstats
  • pyre/bench/synth/wide_callkw_resume.wasm.jitstats
  • pyre/bench/synth/with_except_start_function_resume.cranelift.jitstats
  • pyre/bench/synth/with_except_start_function_resume.dynasm.jitstats
  • pyre/bench/synth/with_except_start_function_resume.wasm.jitstats
  • pyre/extra_tests/parity_tests/memoryview_python314.py
  • pyre/extra_tests/parity_tests/specialised_pair_consumers.py
  • pyre/extra_tests/parity_tests/type_new_metatype_guard.py
  • pyre/extra_tests/parity_tests/vararg_callee_inline_shapes.py
  • pyre/pyre-interpreter/src/baseobjspace.rs
  • pyre/pyre-interpreter/src/builtins.rs
  • pyre/pyre-interpreter/src/eval.rs
  • pyre/pyre-interpreter/src/gateway.rs
  • pyre/pyre-interpreter/src/module/__pypy__/interp_buffer.rs
  • pyre/pyre-interpreter/src/objspace/descroperation.rs
  • pyre/pyre-interpreter/src/type_methods.rs
  • pyre/pyre-interpreter/src/typedef.rs
  • pyre/pyre-jit-trace/src/jitcode_dispatch/inline_call.rs
  • pyre/pyre-jit-trace/src/jitcode_dispatch/residual_call.rs
  • pyre/pyre-jit-trace/src/jitcode_dispatch/specialize.rs

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

The PR updates interpreter compatibility behavior, buffer and argument validation, byte comparisons, JIT vararg inlining, tuple virtualization, parity tests, and benchmark statistics.

Changes

Interpreter compatibility and validation

Layer / File(s) Summary
Interpreter behavior and diagnostics
pyre/pyre-interpreter/src/{baseobjspace,builtins,display,eval,gateway,type_methods}.rs
Updates buffer acquisition, builtin arity checks, exception messages, Windows path handling, descriptor naming, and type-name diagnostics.
Bytes, bytearray, and type operations
pyre/pyre-interpreter/src/{objspace/descroperation,typedef}.rs
Adds shared ordering and buffer validation, supports strided read-only buffers where permitted, refines bytes-like argument handling, and updates type construction and bytearray comparisons.

JIT tuple and vararg handling

Layer / File(s) Summary
Vararg inline-call reconstruction
pyre/pyre-jit-trace/src/jitcode_dispatch/inline_call.rs
Supports eligible *args callees by collecting surplus positional arguments and initializing the callee vararg local, registers, frame boxes, and shadows.
Tuple virtualization fallback order
pyre/pyre-jit-trace/src/jitcode_dispatch/{residual_call,specialize}.rs
Uses canonical array-backed tuple virtualization for supported arities and retains the arity-2 specialized tuple path as a fallback.

Validation and benchmark baselines

Layer / File(s) Summary
Parity coverage
pyre/extra_tests/parity_tests/vararg_callee_inline_shapes.py, lib-python/3/test/test_descr.py
Adds extensive vararg call-shape coverage and makes test_bad_new implementation-specific.
JIT statistics
pyre/bench/**/*.jitstats
Adds zero-valued field-position counters and updates recorded bridge, loop, and guard-failure values across benchmark backends.

Estimated code review effort: 5 (Critical) | ~120 minutes

Possibly related issues

  • youknowone/pyre#205 — The JIT inline-call changes relate to its JIT trace-correctness scope.
  • youknowone/pyre#204 — The tuple virtualization changes relate to planned JIT constant and tuple specialization work.

Possibly related PRs

Poem

A rabbit watched the varargs hop,
While tuples formed in every slot.
Buffers stretched, errors grew clear,
New JIT counters appeared here.
“Parity blooms!” the rabbit sings,
And bounds through freshly tested things.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch buitlins

@github-actions

github-actions Bot commented Aug 5, 2026

Copy link
Copy Markdown

🤖 Codex parity review

Static analysis of this diff vs the local RPython/PyPy sources (commit f3cf797).
Updated: 2026-08-07T00:59:11.455Z

Files in the reviewed diff
lib-python/3/test/test_descr.py
pyre/bench/synth/attr_store_add_transition.py
pyre/bench/synth/bridge_branchy_callee.py
pyre/bench/synth/build_container_return_resume.py
pyre/bench/synth/build_list_resume.py
pyre/bench/synth/call_loop_local_function.py
pyre/bench/synth/exc_in_loop_divzero_continue.py
pyre/bench/synth/finally_bare_raise.py
pyre/bench/synth/global_quasiimmut_invalidation.py
pyre/bench/synth/goto_if_not_same_box.py
pyre/bench/synth/inline_chain_depth_typeflip.py
pyre/bench/synth/inlined_helper_arith_hot.py
pyre/bench/synth/int_mul_ovf_bignum_promote.py
pyre/bench/synth/residual_raise_except_resume.py
pyre/extra_tests/parity_tests/memoryview_python314.py
pyre/extra_tests/parity_tests/specialised_pair_consumers.py
pyre/extra_tests/parity_tests/type_new_metatype_guard.py
pyre/extra_tests/parity_tests/vararg_callee_inline_shapes.py
pyre/pyre-interpreter/src/baseobjspace.rs
pyre/pyre-interpreter/src/builtins.rs
pyre/pyre-interpreter/src/eval.rs
pyre/pyre-interpreter/src/gateway.rs
pyre/pyre-interpreter/src/module/__pypy__/interp_buffer.rs
pyre/pyre-interpreter/src/objspace/descroperation.rs
pyre/pyre-interpreter/src/type_methods.rs
pyre/pyre-interpreter/src/typedef.rs
pyre/pyre-jit-trace/src/jitcode_dispatch/inline_call.rs
pyre/pyre-jit-trace/src/jitcode_dispatch/residual_call.rs
pyre/pyre-jit-trace/src/jitcode_dispatch/specialize.rs

1. Regressions to PyPy parity introduced by this patch

None.

2. Other mismatches introduced by this patch

None.

3. Pre-existing mismatches (already present before this patch)

  • pyre/pyre-interpreter/src/builtins.rs:4917 ↔ pypy/objspace/std/typeobject.py:899: the pre-existing “find the first str” dispatch loses a non-type metatype in type.__new__(42, "C", (), {}), passes a null metatype onward, and can create/validate the class instead of _precheck_for_new rejecting 42.

  • pyre/pyre-interpreter/src/typedef.rs:10802 ↔ pypy/objspace/std/typeobject.py:1083: type.mro computes an MRO for its receiver without upstream’s _check(..., "expected type"); a non-type receiver should raise TypeError, not be treated as a type layout.

  • pyre/pyre-interpreter/src/type_methods.rs:5197 ↔ pypy/objspace/std/unicodeobject.py:175-184: str.ljust/str.rjust still reject bytearray, memoryview, and other buffer exporters as fill characters, while PyPy routes non-bytes operands through decode_object and accepts decodable buffers.

4. Structural adaptations

  • pyre/pyre-interpreter/src/gateway.rs:921 ↔ pypy/objspace/std/callmethod.py:66-73: Rust exposes one builtin callable representation, so diagnostics use the declaring owner (list.append) even after binding to a subclass instance; PyPy preserves distinct method-descriptor and bound-method paths.

  • pyre/pyre-interpreter/src/typedef.rs:294 ↔ pypy/objspace/std/typeobject.py:568: Rust gives type its own static layout pointer to preserve PyPy’s layout.typedef identity check. This is a representation adaptation, not a semantic divergence.

  • pyre/pyre-interpreter/src/baseobjspace.rs:8605 ↔ pypy/objspace/std/bytesobject.py:827-836: the BUF_FULL_RO dispatcher additionally supports CPython 3.14’s __buffer__ protocol and flags; PyPy’s corresponding path is space.buffer_w(..., BUF_FULL_RO).

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 74b51f8ffb

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

/// `bytes()` / `bytearray()` source this way, which is why
/// `bytes(memoryview(b'abcd')[::2])` is a copy and not a `BufferError`.
pub(crate) fn full_ro_buffer_bytes(obj: PyObjectRef) -> Result<Option<SimpleBufferBytes>, PyError> {
buffer_bytes(obj, false)

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 Pass BUF_FULL_RO to Python buffer exporters

When the source implements PEP 688 __buffer__, this new constructor path still falls through to w_memoryview_new_with_flags(r_obj, 0), so bytes(x) and bytearray(x) pass PyBUF_SIMPLE to the exporter instead of the BUF_FULL_RO request this wrapper documents. An exporter that branches on the requested flags will observe the wrong contract even though PyPy's _convert_from_buffer_or_iterable calls space.buffer_w(..., space.BUF_FULL_RO); thread the full request flag through buffer_bytes rather than only disabling the contiguity check.

AGENTS.md reference: AGENTS.md:L231-L232

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Fixed on this branch after the review, in the commit
"baseobjspace: hand the buffer request kind's flags to a __buffer__ exporter":
buffer_bytes now takes the request kind and threads its flags into
w_memoryview_new_with_flags, so bytes(x) / bytearray(x) reach a PEP 688
exporter with BUF_FULL_RO (0x011c) rather than PyBUF_SIMPLE, matching
_convert_from_buffer_or_iterable (bytesobject.py:830).

commented by Claude

Comment on lines +20353 to +20355
if pyre_object::memoryview::is_w_memoryview(obj) {
crate::builtins::memoryview_check_released(obj)?;
if !crate::builtins::memoryview_contiguity(obj).0 {

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 Recurse before checking PickleBuffer contiguity

For a PickleBuffer wrapping a strided memoryview, this helper returns Ok(()) because the wrapper itself is not a memoryview; the caller then reaches buffer_as_bytes_like, which unwraps the forwarded exporter and gathers the strided bytes. That leaves BUF_SIMPLE operand paths such as strip, translate, and join accepting non-C-contiguous PickleBuffers instead of raising BufferError; recurse through forwarded_exporter here the way simple_buffer_bytes already does.

AGENTS.md reference: AGENTS.md:L231-L232

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

The shape is real; the predicted BufferError is not.

W_PickleBuffer.buffer_w forwards to self.buf.w_obj (interp_buffer.py:169-174),
and for a sliced memoryview that is the contiguous base object, so no
contiguity failure arises to report. check_buf_flags tests writability only
(baseobjspace.py:1646-1648). A BUF_SIMPLE operand path therefore does not raise
here upstream either.

commented by Claude

@youknowone

Copy link
Copy Markdown
Owner Author

Follow-up pushed (e347cf9): the known-remaining item from the description is fixed.

bytearray's six comparison dunders were built from the shared cmp_dunder_set! macro behind cmp_guard_bytearray, which admitted only bytes and bytearray. descr_eq / descr_ne / _comparison_helper (bytearrayobject.py) instead hand a non-bytes-like operand to space.acquire_py_buffer(w_other, space.BUF_SIMPLE), and turn only the TypeError that raises into NotImplemented.

before now both references
bytearray(b'ab') == array.array('B',[97,98]) False True True
bytearray(b'ab') < memoryview(b'b') TypeError True True
bytearray(b'ab').__eq__(memoryview(b'ab')) NotImplemented True True

The first was a silent wrong answer. The middle one was only visible through ordering — == against a memoryview already read True because memoryview's reflected __eq__ answered it.

Two cases where the references disagree land on PyPy, which is what a BUF_SIMPLE request gives: a strided view is a BufferError (CPython linearises) and a released view is a ValueError (CPython answers False). Neither error is a TypeError, so neither becomes NotImplemented.

bytes is untouched and must stay that way — b'ab' == array.array('B',[97,98]) is False in both references because its comparisons never acquire a buffer.

Also folded in: ordering_satisfies replaces the two spellings of the _memcmp-result mapping in descroperation.

Verification (re-run in full on the new base)

  • targeted suites: 37/37 and 12/12 against both references; the bytearray comparison suite is 30/30; 66/68 on the broad suite.
  • cargo test --all 101 test binaries, 0 failures.
  • pyre/extra_tests/parity_tests 179 scripts — only red is type_members_python314.py under the cpython runner (BaseExceptionGroup tp_basicsize 88 vs 96), pre-existing and unrelated.
  • pyre/check.py --backend dynasm --synthetic-only 365/365, after re-extracting LLBC on this base.
  • cargo fmt --check and the sandbox clippy fence clean.

Deliberately not changed

str.center / ljust / rjust refuse a non-str fill char with <method>() argument 2 must be a single character, where CPython says The fill character must be a unicode character, not X. Upstream splits here — descr_center converts with space.utf8_w but descr_ljust / descr_rjust use convert_arg_to_w_unicode, which decodes a buffer operand into a fill char ('ab'.ljust(6, memoryview(b'-')) succeeds under PyPy, and CPython refuses it for all three). pyre follows CPython on the acceptance, so matching PyPy's text would have meant either importing that quirk or giving three sibling methods three different messages for the same rejection. The reasoning is recorded on pad_fillchar.

b'x'.decode(None) reports not NoneType where CPython writes not None — CPython's argument clinic spells only None that way, and pyre matches it exactly for every other type.

commented by Claude

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d8fc362e94

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread pyre/pyre-interpreter/src/builtins.rs Outdated
// first arg is `self`; the count reported excludes it.
return Err(crate::PyError::type_error(format!(
"function takes exactly 4 arguments ({} given)",
args.len() - 1

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 Avoid underflowing Unicode error init arity

These __init__ methods are installed with make_builtin_function, so unbound calls such as UnicodeTranslateError.__init__() can reach this branch with args.len() == 0; the new args.len() - 1 subtraction then underflows (panics with overflow checks, or formats a huge count in release) instead of returning the normal TypeError. The same changed pattern is repeated in the UnicodeDecodeError and UnicodeEncodeError initializers below, so use a saturating count before formatting it.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Fixed on this branch after the review — all three initializers use
args.len().saturating_sub(1) for the reported count.

commented by Claude

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

https://github.com/youknowone/pyre/blob/ada9c264b8e04bc3a7c12362b545e66476905707/pyre-jit-trace/src/jitcode_dispatch/specialize.rs#L3745-L3748
P1 Badge Restore the specialized representation for arity-two tuples

For every traced two-element BUILD_TUPLE whose backing-array length is cached, the reordered residual dispatch now reaches this arm first and constructs a canonical W_TupleObject, while the interpreter and upstream makespecialisedtuple2 construct Cls_ii/Cls_ff/Cls_oo. This intentionally replaces the upstream representation to reuse existing canonical-only consumer folds rather than porting those folds for specialized tuples, violating the repository's required line-by-line structural parity; retain the specialized shape and extend its consumer optimizations instead.

AGENTS.md reference: AGENTS.md:L231-L233

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e3d151e924

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +4870 to +4871
if !unsafe { std::ptr::eq(pos[0], crate::typedef::w_type()) } {
return Err(crate::PyError::type_error(new_arity_message(pos[0])));

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Validate the metatype before reading its name

For an invalid direct call such as type.__new__(42, 1), this branch passes the non-type first argument to new_arity_message, which unconditionally calls w_type_get_name and casts it to W_TypeObject. An integer or other ordinary object is therefore read using the wrong layout, potentially crashing the interpreter instead of raising the expected TypeError; reject or safely name a non-type metatype before formatting the arity error.

AGENTS.md reference: AGENTS.md:L231-L232

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Fixed on this branch after the review, in the commit
"builtins: check the metatype is a type before naming it in type.new":
new_arity_message no longer reads w_type_get_name off an unvalidated first
argument. Upstream decides arity first and names the metatype through the %N
operand, then runs _precheck_for_new (typeobject.py:886-911).

commented by Claude

Comment on lines +3745 to +3747
/// Arity 2 is `makespecialisedtuple2` territory at runtime (`Cls_ii` /
/// `Cls_ff` / `Cls_oo`, `specialisedtupleobject.py`), and this arm builds the
/// canonical shape there instead. Representation is not observable — the

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Keep arity-two BUILD_TUPLE on the specialized shape

The specialized representation is observable for an exact-int pair: w_tuple_new normally creates Cls_ii, stores the integers unboxed, and w_tuple_getitem boxes them again, whereas this canonical tuple retains the original object references. Consequently hot code such as x = int('1000'); (x, x)[0] is x can change from false in the interpreter to true after tracing; leave length-two tuples on makespecialisedtuple2 or reproduce its exact representation and readers.

AGENTS.md reference: AGENTS.md:L16-L19

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

The mechanism is right but the consequence does not occur, on pypy or here.

W_AbstractIntObject.is_w is bigint value equality and immutable_unique_id
is derived from the value (intobject.py:44-59); floats compare by bit pattern
(floatobject.py:196-204). So an int or float pair's representation is not
identity-observable — only bool is, and it keeps pointer identity.

Ran the suggested witness hot, 200000 iterations, collecting the set of results
so an interpreter/traced split would show as [False, True]:

                 pypy3      pyre-dynasm   pyre PYRE_NO_JIT=1
tuple_pair_is    [True]     [True]        [True]
float_pair_is    [True]     [True]        [True]
bool_pair_is     [True]     [True]        [True]

No divergence between the interpreter and the compiled trace, and none from
pypy.

commented by Claude

}
// A new allocation with no heap mutation, safe during the walk, and the
// same constructor `emit_object_tuple_inline` reproduces.
let concrete = pyre_object::w_tuple_new_array_backed(surplus_concretes);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Preserve specialized tuples when packing varargs

When a newly inlined *args callee receives exactly two exact integers, _match_signature would create the tuple through the ordinary space.newtuple path and therefore use Cls_ii, but this code always constructs an array-backed tuple containing the original boxes. A callee that observes identity, for example def f(a, *args): return args[0] is a called hot as f(x, x, x), can therefore return a different result once inlined; either emit the normal specialized pair shape or decline this case.

AGENTS.md reference: AGENTS.md:L16-L19

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Same answer as the BUILD_TUPLE comment: the premise about the representation is
accurate, the observable consequence is not.

def f(a, *args): return args[0] is a, called hot as f(x, x, x) with
x = int('1000'), 200000 iterations, results collected as a set:

              pypy3    pyre-dynasm   pyre PYRE_NO_JIT=1
vararg_is     [True]   [True]        [True]

is on ints is value equality upstream (intobject.py:44-59), so the packed
tuple's element representation is not reachable through identity.

commented by Claude

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@pyre/pyre-interpreter/src/builtins.rs`:
- Around line 6671-6678: Update the argument-count formatting in
exc_unicode_translate_error_init, exc_unicode_decode_error_init, and
exc_unicode_encode_error_init to use args.len().saturating_sub(1) instead of
args.len() - 1, preventing underflow when these initializers receive no
arguments.

In `@pyre/pyre-jit-trace/src/jitcode_dispatch/inline_call.rs`:
- Line 3887: Update the concrete argument construction near param_boxes so the
callee frame receives code.varnames.len() elements rather than limiting the
input to nparams. Ensure the seeded vararg slot is populated consistently with
PyFrame::new_for_call_with_closure_and_globals_obj, while preserving the
existing argument ordering and behavior for non-vararg calls.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 92253de9-0722-48cb-82ea-c04d41e18b3f

📥 Commits

Reviewing files that changed from the base of the PR and between fcf997d and e3d151e.

📒 Files selected for processing (100)
  • lib-python/3/test/test_descr.py
  • pyre/bench/fannkuch.cranelift.jitstats
  • pyre/bench/fannkuch.dynasm.jitstats
  • pyre/bench/fannkuch.wasm.jitstats
  • pyre/bench/fib_loop.cranelift.jitstats
  • pyre/bench/fib_loop.dynasm.jitstats
  • pyre/bench/fib_loop.wasm.jitstats
  • pyre/bench/fib_recursive.cranelift.jitstats
  • pyre/bench/fib_recursive.dynasm.jitstats
  • pyre/bench/fib_recursive.wasm.jitstats
  • pyre/bench/float_loop.cranelift.jitstats
  • pyre/bench/float_loop.dynasm.jitstats
  • pyre/bench/float_loop.wasm.jitstats
  • pyre/bench/inline_helper.cranelift.jitstats
  • pyre/bench/inline_helper.dynasm.jitstats
  • pyre/bench/inline_helper.wasm.jitstats
  • pyre/bench/int_loop.cranelift.jitstats
  • pyre/bench/int_loop.dynasm.jitstats
  • pyre/bench/int_loop.wasm.jitstats
  • pyre/bench/nbody.cranelift.jitstats
  • pyre/bench/nbody.dynasm.jitstats
  • pyre/bench/nbody.wasm.jitstats
  • pyre/bench/nested_loop.cranelift.jitstats
  • pyre/bench/nested_loop.dynasm.jitstats
  • pyre/bench/nested_loop.wasm.jitstats
  • pyre/bench/raise_catch_loop.cranelift.jitstats
  • pyre/bench/raise_catch_loop.dynasm.jitstats
  • pyre/bench/raise_catch_loop.wasm.jitstats
  • pyre/bench/spectral_norm.cranelift.jitstats
  • pyre/bench/spectral_norm.dynasm.jitstats
  • pyre/bench/spectral_norm.wasm.jitstats
  • pyre/bench/synth/binary_int_overflow_local_resume.cranelift.jitstats
  • pyre/bench/synth/binary_int_overflow_local_resume.dynasm.jitstats
  • pyre/bench/synth/binary_int_overflow_local_resume.wasm.jitstats
  • pyre/bench/synth/comprehension_object_append_hot.cranelift.jitstats
  • pyre/bench/synth/comprehension_object_append_hot.dynasm.jitstats
  • pyre/bench/synth/comprehension_object_append_hot.wasm.jitstats
  • pyre/bench/synth/const_arg_call_resume.cranelift.jitstats
  • pyre/bench/synth/const_arg_call_resume.dynasm.jitstats
  • pyre/bench/synth/const_arg_call_resume.wasm.jitstats
  • pyre/bench/synth/exc_bridge_entry_guard_not_removed.cranelift.jitstats
  • pyre/bench/synth/exc_bridge_entry_guard_not_removed.dynasm.jitstats
  • pyre/bench/synth/exc_bridge_entry_guard_not_removed.wasm.jitstats
  • pyre/bench/synth/exception_catching_frame_tb_node.cranelift.jitstats
  • pyre/bench/synth/exception_catching_frame_tb_node.dynasm.jitstats
  • pyre/bench/synth/exception_catching_frame_tb_node.wasm.jitstats
  • pyre/bench/synth/exception_inline_callee_tb_frames.cranelift.jitstats
  • pyre/bench/synth/exception_inline_callee_tb_frames.dynasm.jitstats
  • pyre/bench/synth/exception_inline_callee_tb_frames.wasm.jitstats
  • pyre/bench/synth/exception_reentry_guard_finally_residual.cranelift.jitstats
  • pyre/bench/synth/exception_reentry_guard_finally_residual.dynasm.jitstats
  • pyre/bench/synth/exception_reentry_guard_finally_residual.wasm.jitstats
  • pyre/bench/synth/exception_traceback_frame_lineno.cranelift.jitstats
  • pyre/bench/synth/exception_traceback_frame_lineno.dynasm.jitstats
  • pyre/bench/synth/exception_traceback_frame_lineno.wasm.jitstats
  • pyre/bench/synth/exception_traceback_lineno_chain.cranelift.jitstats
  • pyre/bench/synth/exception_traceback_lineno_chain.dynasm.jitstats
  • pyre/bench/synth/exception_traceback_lineno_chain.wasm.jitstats
  • pyre/bench/synth/gc_bug_bridge_flavor_traceback_names.cranelift.jitstats
  • pyre/bench/synth/gc_bug_bridge_flavor_traceback_names.dynasm.jitstats
  • pyre/bench/synth/gc_bug_bridge_flavor_traceback_names.wasm.jitstats
  • pyre/bench/synth/getattribute_override_no_bind.cranelift.jitstats
  • pyre/bench/synth/getattribute_override_no_bind.dynasm.jitstats
  • pyre/bench/synth/getattribute_override_no_bind.wasm.jitstats
  • pyre/bench/synth/list_append_write_barrier_gc.cranelift.jitstats
  • pyre/bench/synth/list_append_write_barrier_gc.dynasm.jitstats
  • pyre/bench/synth/list_append_write_barrier_gc.wasm.jitstats
  • pyre/bench/synth/minmax_key_rooting.cranelift.jitstats
  • pyre/bench/synth/minmax_key_rooting.dynasm.jitstats
  • pyre/bench/synth/minmax_key_rooting.wasm.jitstats
  • pyre/bench/synth/nested_list_comprehension_hot.cranelift.jitstats
  • pyre/bench/synth/nested_list_comprehension_hot.dynasm.jitstats
  • pyre/bench/synth/nested_list_comprehension_hot.wasm.jitstats
  • pyre/bench/synth/pickle_terminal_raise_resume.cranelift.jitstats
  • pyre/bench/synth/pickle_terminal_raise_resume.dynasm.jitstats
  • pyre/bench/synth/pickle_terminal_raise_resume.wasm.jitstats
  • pyre/bench/synth/sre_pattern_methods.cranelift.jitstats
  • pyre/bench/synth/sre_pattern_methods.dynasm.jitstats
  • pyre/bench/synth/sre_pattern_methods.wasm.jitstats
  • pyre/bench/synth/sre_wasm_min.cranelift.jitstats
  • pyre/bench/synth/sre_wasm_min.dynasm.jitstats
  • pyre/bench/synth/sre_wasm_min.wasm.jitstats
  • pyre/bench/synth/sre_wasm_min1.cranelift.jitstats
  • pyre/bench/synth/sre_wasm_min1.dynasm.jitstats
  • pyre/bench/synth/sre_wasm_min1.wasm.jitstats
  • pyre/bench/synth/str_index_bytes_iter_surface.cranelift.jitstats
  • pyre/bench/synth/str_index_bytes_iter_surface.dynasm.jitstats
  • pyre/bench/synth/str_index_bytes_iter_surface.wasm.jitstats
  • pyre/extra_tests/parity_tests/vararg_callee_inline_shapes.py
  • pyre/pyre-interpreter/src/baseobjspace.rs
  • pyre/pyre-interpreter/src/builtins.rs
  • pyre/pyre-interpreter/src/display.rs
  • pyre/pyre-interpreter/src/eval.rs
  • pyre/pyre-interpreter/src/gateway.rs
  • pyre/pyre-interpreter/src/objspace/descroperation.rs
  • pyre/pyre-interpreter/src/type_methods.rs
  • pyre/pyre-interpreter/src/typedef.rs
  • pyre/pyre-jit-trace/src/jitcode_dispatch/inline_call.rs
  • pyre/pyre-jit-trace/src/jitcode_dispatch/residual_call.rs
  • pyre/pyre-jit-trace/src/jitcode_dispatch/specialize.rs

Comment thread pyre/pyre-interpreter/src/builtins.rs
Comment thread pyre/pyre-jit-trace/src/jitcode_dispatch/inline_call.rs

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 82d10778c5

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +16635 to +16637
// `getdata()` is read after the acquisition: a `__buffer__` slot is
// app-level code and may have resized the receiver.
let data = unsafe { pyre_object::bytesobject::bytes_like_data(a) }.to_vec();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Snapshot ordering receiver before buffer acquisition

For ordering comparisons against a Python __buffer__ exporter, the exporter can mutate the left-hand bytearray before this post-acquisition copy is taken. PyPy's _comparison_helper snapshots self.getdata() before acquire_py_buffer (pypy/objspace/std/bytearrayobject.py:355-379), so an exporter that clears or replaces the receiver compares against its original contents; this implementation compares against the mutated contents and can reverse </> results. Keep the equality ordering as-is, but snapshot before acquisition for the four ordering operations.

AGENTS.md reference: AGENTS.md:L231-L232

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Real, and deliberately not fixed here — the faithful repair is larger than this
PR and the literal one is a regression.

Copying bytes_like_data(a) before acquisition, as suggested, regresses six
oracle rows: the length that decides the comparison must come from the
receiver's state after acquisition, not from a pre-acquisition copy. The
faithful edit reproduces RPython's list identity instead, which needs
bytearray_method_clear and bytearray_descr_init to install a fresh Vec in
W_BytearrayObject.data rather than clearing in place (mirroring
self._data = ... at bytearrayobject.py:251 and :557). Without that rebind the
captured pointer equals the current one and the capture is inert; with it, a
raw *mut Vec<u8> acquires a second owner, and a leak or a use-after-free is
the failure mode.

Trigger is an app-level __buffer__ that clears the left operand mid-comparison.
Filing it rather than attempting it inside a PR whose subject is the buffer
request kind.

commented by Claude

Comment on lines 5177 to 5181
if !unsafe { pyre_object::is_str(args[2]) } {
let type_name = arg_type_name(args[2]);
return Err(crate::PyError::type_error(format!(
"{method}() argument 2 must be a single character"
"The fill character must be a unicode character, not {type_name}"
)));

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Preserve the upstream per-method fill conversion

This shared rejection deliberately replaces two different upstream paths: center uses space.utf8_w, while ljust and rjust use convert_arg_to_w_unicode (pypy/objspace/std/unicodeobject.py:1098-1104,1351-1376). Consequently center(3, None) now reports the CPython-style fill-character error instead of the upstream typed-unwrapping error, and ljust/rjust still reject buffer operands that upstream decodes. Split these methods and port their respective conversion paths rather than normalizing them to one shortcut.

AGENTS.md reference: AGENTS.md:L231-L232

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Confirmed for the wording, fixed in c390a3a and 567ea0d. Measured first
— pyre matched CPython on all seven refusals and pypy on none of them:

case pypy3 pyre, before
"ab".center(6, 1) expected str, got int object The fill character must be a unicode character, not int
"ab".ljust(6, 1) decoding to str: a bytes-like object is required, not 'int' same shared string
"ab".ljust(6, b"x") Can't convert 'bytes' object to str implicitly same shared string

The three arms now follow the two converters: space.utf8_w for center
(unicodeobject.py:1101), and for ljust/rjust the bytes refusal at
unicodeobject.py:179-180 plus decode_object's "decoding to str: %S" wrapper
(unicodeobject.py:1727-1739), with None rendered unquoted where a type name is
quoted. All eight cases checked, plus the eight type names %T renders, now
print what pypy prints byte for byte.

The conversion half is deliberately not taken here. decode_object turns a
bytearray/memoryview/array fill into a fill char — "ab".ljust(6, bytearray(b"x"))
is 'abxxxx' on pypy — and pyre refuses it. That refusal is on main and
predates this PR, which only touched the message; importing the decode changes
three previously-failing inputs into successes and belongs in its own change.
The doc comment now states that as the remaining difference instead of
presenting it as a reason for a shared message.

commented by Claude

@youknowone

Copy link
Copy Markdown
Owner Author

Worked through all six review findings. Two were real and are fixed, one is
hardened, three are declined with reasoning below.

Fixed

P1 builtins.rs — validate the metatype before reading its name. Correct,
and worse than reported: it is a segfault, not just a wrong-layout read.

$ ./target/release/pyre-dynasm -c "type.__new__(42, 1)"
[rc=-11]

type_descr_new reached new_arity_message(pos[0]) with pos[0] = 42 and
w_type_get_name read an int through the W_TypeObject layout. type.__new__('s', 1)
did not crash but reported s.__new__() takes exactly 3 arguments (1 given)
the same wrong-layout read, landing on the str's own bytes.

The fix follows descr__new__ (typeobject.py:886-911) rather than patching the
formatter: _precheck_for_new (typeobject.py:1001-1003) now runs where upstream
runs it, and the arity message uses the %N operand spelling —
W_Root.getname (baseobjspace.py:90-94), which reports __name__ or ?.

before now pypy
type.__new__(42, 1) SIGSEGV X is not a type object (int) same
type.__new__('s', 1) s.__new__() takes exactly 3 arguments (1 given) X is not a type object (str) same
type.__new__(None, 1) X is not a type object (NoneType) same
type.__new__(42) <class 'int'> ?.__new__() takes exactly 3 arguments (1 given) same
type.__new__(int, 1) int.__new__() takes exactly 3 arguments (1 given) unchanged same
type.__new__(type, 1) <class 'int'> unchanged same

P2 baseobjspace.rs — pass BUF_FULL_RO to Python __buffer__ exporters.
Correct and observable. buffer_bytes handed a literal 0 to
w_memoryview_new_with_flags on every path, so a PEP 688 exporter saw
PyBUF_SIMPLE even when the request was BUF_FULL_RO:

class Picky:
    def __buffer__(self, flags):
        if not (flags & 0x004): raise BufferError("format not requested")
        return memoryview(b'wxyz')
    def __release_buffer__(self, view): pass

bytes(Picky())   # cpython: b'wxyz' (flags 0x11c) / pyre before: BufferError (flags 0x0)

buffer_bytes's require_contiguous: bool is now a BufferRequest naming the
two upstream requests, and both the contiguity rule and the exporter flags are
derived from it. Covered in memoryview_python314.py.

Hardened, but the reported path does not exist

P2 builtins.rsargs.len() - 1 underflow in the three unicode-error
initialisers.
The subtraction is now saturating_sub, but the premise does not
hold: these are installed through make_exc_type_with_init, which produces a
wrapper_descriptor, so both UnicodeTranslateError.__init__() and
UnicodeTranslateError.__dict__['__init__']() are rejected by the descriptor
with descriptor '__init__' of 'UnicodeTranslateError' object needs an argument
before the body runs — identical to CPython. args.len() == 0 is unreachable
today; the change is a guard on the usize, not a bug fix.

Declined

P1 ×2 — arity-2 BUILD_TUPLE / vararg packing must keep the specialised
shape.
The premise is that Cls_ii stores unboxed ints and getitem boxes
them again, so (x, x)[0] is x is False interpreted and True traced. That
re-boxing is real, but it is not observable, because is and id on a plain
int or float are value-based upstream: W_IntObject.is_w
(intobject.py:44-52) and W_FloatObject.is_w (floatobject.py:196) compare
values and only fall back to real identity when user_overridden_class is set —
and makespecialisedtuple2 builds Cls_ii / Cls_ff for exactly W_IntObject
/ W_FloatObject, never a subclass. Cls_oo stores the references verbatim, so
it re-boxes nothing.

Measured, with values built at runtime far outside any cache:

                     cpython   pypy   pyre
a = int('1000000'); b = int('1000000'); t = (a, b)
t[0] is a              True    True   True
t[0] is t[1]           False   True   True     # <- pypy's value-based `is`

t[0] is t[1] is the discriminator: two distinct objects of equal value. PyPy
answers True and so does pyre; CPython answers False. So the boxing distinction
the finding depends on cannot be seen from app level in a PyPy-faithful
implementation, and the same holds for def f(a, *args): return args[0] is a.
No change made. A concrete failing case would of course change this.

P2 typedef.rs — recurse before checking PickleBuffer contiguity. Correct
about the mechanism and correct that pyre accepts a strided PickleBuffer where
CPython raises BufferError — but that is PyPy's behaviour, which pyre is
matching:

cpython pypy pyre
b'xabcx'.strip(pb_strided) BufferError b'xabcx' b'xabcx'
b','.join([pb_strided]) TypeError b'ace' b'ace'
b'abc'.translate(None, pb_strided) BufferError b'b' b'b'
b'ab' + pb_strided TypeError b'abace' b'abace'
b'xabcx'.strip(strided_memoryview) BufferError BufferError BufferError

(pb_strided = PickleBuffer(memoryview(b'abcdef')[::2]).) pyre tracks PyPy on
every row, so applying this would move it off upstream. One genuine
inconsistency did surface while checking: b'abcdef'.count(pb_strided) raises
BufferError in pyre where PyPy returns 0. That is pre-existing, unrelated to
this PR, and left for its own change.

commented by Claude

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 87fd52b910

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

} else {
None
};
let seeded_locals = nparams + usize::from(vararg_slot.is_some());

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Seed the vararg tuple into the concrete callee frame

When an admitted *args callee executes a residual operation that publishes or forces its concrete frame (for example sys._getframe() or traceback inspection), seeded_locals includes the packed tuple, but the concrete-frame builder at lines 3913-3918 still roots and passes only nparams entries. The frame therefore leaves the vararg local as PY_NULL, so frame readers during tracing can observe missing locals and bake a result that differs from the interpreted call; build concrete_args from all seeded_locals as well.

AGENTS.md reference: AGENTS.md:L32-L41

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Confirmed and fixed in 92df982.

Reproduced against the oracle before touching anything — the symbolic frame is
built from param_boxes, which spans seeded_locals, while the concrete frame
beside it took the first nparams entries only:

def g(a, *args):
    L = sys._getframe().f_locals
    return ('args' in L, L.get('args'), 'a' in L, L.get('a'))

driven by a hot while loop, 200000 iterations:

wrong iterations
pyre-dynasm, before 5 — e.g. (1040, (False, None, True, 1040))
pypy3 0
pyre-dynasm, after 0

a was present and correct throughout; only args was missing, which is
exactly the nparams vs seeded_locals split. _match_signature writes the
vararg tuple into scope_w like any other local (argument.py:222-234), so both
halves must carry the same set. callee_arg_concretes already holds the tuple
at index nparams and the call is declined unless its length is
seeded_locals, so both bounds stay in range.

commented by Claude

Comment thread pyre/pyre-interpreter/src/builtins.rs Outdated
// (stringmethods.py:200-201). This positional shape cannot skip the
// slot when `errors` follows it, so spell the default out: `decode`
// refuses a literal `None` there like any other non-str.
let mut decode_args = vec![src, w_encoding.unwrap_or_else(|| w_str_new("utf-8"))];

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 Avoid allocating an immortal default encoding per call

For calls such as str(data, errors="ignore") where encoding is omitted, this now invokes w_str_new("utf-8") on every call. That constructor is explicitly the immortal/off-GC string path (pyre-object/src/unicodeobject.rs:130-165), so a hot loop permanently leaks one string header and backing buffer per iteration; preserve the omitted encoding through the decode path or use a shared rooted default instead of materializing a new immortal object.

AGENTS.md reference: AGENTS.md:L231-L232

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Confirmed and fixed in 82d6aef, using the cell that already exists for this
shape rather than a new one: warn::PrebuiltText documents exactly this
reasoning (w_str_new is immortal, so the box is never swept, never relocated
and needs no root). bytes_method_decode only reads the encoding through
str_utf8_w, so sharing one object is not observable.

commented by Claude

Comment on lines 921 to +925
let ty = match receiver {
Some(r) if unsafe { pyre_object::typeobject::is_type(r) } => {
unsafe { pyre_object::w_type_get_name(r) }.to_string()
}
Some(r) => crate::baseobjspace::object_functionstr_type_name(r),
None => owner.type_name.to_string(),
Some(r) if unsafe { pyre_object::typeobject::is_type(r) } => unsafe {
pyre_object::w_type_get_name(r)
},
_ => owner.type_name,

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 Preserve the receiver name for bound builtin errors

When a builtin method is first bound from a subclass and then called with the wrong arity, this fallback now always uses the declaring owner. For example, checked on CPython 3.14, f = MyList().append; f() reports MyList.append(), consistent with the callable's __qualname__, whereas this branch reports list.append(); the preceding comment explicitly acknowledges the mismatch and normalizes both callable forms to the descriptor behavior instead of preserving their distinct semantics.

AGENTS.md reference: AGENTS.md:L231-L232

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

This is what pypy prints, so there is nothing to preserve.

BuiltinCode.funcrun_obj passes func.qualname — the declaring type's name —
as the name source for the arity/keyword error, and the receiver w_obj is
never consulted for it (gateway.py:875). Ran the comment's own example on
pypy3 and the output matches this branch verbatim.

commented by Claude

@youknowone

Copy link
Copy Markdown
Owner Author

The CPython suite (gate) red on 87fd52b9109 was a real regression from this
branch, not base drift: test.test_datetime went PASS -> FAIL. Fixed in
8c026e37c07.

What broke. 17c9c4a6677 added a BINARY_SUBSCR fold for the arity-2
specialised tuple layouts. Its object-slot (_oo) arm reads
W_SpecialisedTupleObject_oo.value0 / value1 with a getfield_gc_r, and that
read is wrong code. datetimetester.py holds
self.lt = (array('q', ut), array('q', ut)) and reads self.lt[dt.fold]; with
the fold in place the next call in that frame comes out one positional argument
short:

  File ".../datetimetester.py", line 6525, in _find_ti
    idx = bisect.bisect_right(lt, timestamp)
TypeError: bisect_right() missing 1 required positional argument: 'x'

Attribution and narrowing, all on the full module (550 tests):

arm result
PYRE_NO_JIT=1 550 OK — JIT-only
main at this branch's base CPython gate green — branch regression
specialize.rs reverted to 17c9c4a6677^ 550 OK
whole subscript fold disabled, len() fold kept 550 OK
only the _oo kind declined 550 OK
MAJIT_NO_BRIDGE=1 still FAILS — main trace, not a bridge
_oo executes the residual + records its concrete still FAILS
replace_box dropped still FAILS
index guard via walker_emit_guard_with_snapshot still FAILS

So the _ii / _ff arms are sound and the object-slot read is not. What makes
it wrong is still open; the fix declines that one kind rather than guessing.

Cost. The _ii / _ff folds and the len() fold are untouched — over an
empty loop II[0] stays at 0.1 ns and II[i & 1] at 0.7 ns, against 169.3 ns
and 175.5 ns with the whole fold declined. OO[0] returns to the residual,
193.1 ns from 35.9 ns. That moves divmod_long_int_pair's wasm
guard_failures 7 → 9 (its pair is two longs, so _oo); the baseline is
re-recorded.

Verification on the new head. CPython gate 46/46 no regressions;
check.py --synthetic-only dynasm 371/371, cranelift 371/371, wasm 370/370,
SNAPDIFF 0; cargo test --all 7489 passed / 0 failed; cargo fmt --check
clean; parity 191 scripts down to the pre-existing
type_members_python314.py cpython=FAIL.

One note on the cranelift run: wasm_ca_trampoline_decline failed its ratio
gate once at 63.1x (gate 57x) with pypy clamped to the execution floor, and
passed on an immediate re-run. Clamped denominators are unstable run-to-run;
the fixture has no tuple pair in it.

The pyre/check.py (ubuntu-24.04 / windows-latest) reds are unchanged and
still base-inherited — pickle_ctor_args, type_dict_surrogate,
type_immutable_reject, unary_positive_resume all fail the same way on
main at 5eefca2d43e, and every one of those ceilings was set by #1033.

commented by Claude

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

https://github.com/youknowone/pyre/blob/481d73eabfece0b0772cb46cfc81f7f8fa04c806/pyre-interpreter/src/eval.rs#L1532-L1534
P2 Badge Preserve the rejected cause type in raise-from errors

When an invalid cause is used, such as raise ValueError() from 1, PyPy's OperationError._exception_getclass reports exception causes must derive from BaseException, not int (pypy/interpreter/error.py:255-260), but this replacement drops the , not <type> suffix and the updated test locks in that divergence. Include the rejected cause's class name when constructing this error to preserve the upstream behavior.

AGENTS.md reference: AGENTS.md:L231-L232

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

https://github.com/youknowone/pyre/blob/acadf40daeb450ffbe5ee948a6148879ff6ba6e8/pyre-interpreter/src/builtins.rs#L4951-L4955
P2 Badge Validate the metatype in the four-argument path

For type.__new__(42, 1, (), {}), this new arm leaves w_metaclass null and validates only the trailing (name, bases, dict), producing type() argument 1 must be string instead of rejecting 42 as the metatype. PyPy's descr__new__ runs _precheck_for_new before _check_new_args, so validate pos[0] before dispatching this shape. The newly added four-positional branch is fresh evidence distinct from the earlier two-positional metatype report.

AGENTS.md reference: AGENTS.md:L231-L232

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8653735c58

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

} {
return crate::objspace::descroperation::compare_slot(a, b, op);
}
let buffer = match crate::baseobjspace::simple_buffer_bytes(b) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Root the bytearray across exporter execution

When b implements Python-level __buffer__, simple_buffer_bytes(b) can execute arbitrary allocating code and trigger the moving GC, but a remains only an unrooted raw pointer and is dereferenced afterward at line 16638. An exporter that induces collection can therefore make the equality path read a stale receiver address, causing memory corruption or a crash; pin a before acquisition and reload it from the shadow stack for the required post-acquisition snapshot.

AGENTS.md reference: AGENTS.md:L231-L232

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

The code path is as described, but the ordering is upstream's own.

W_BytearrayObject.descr_eq acquires first and reads the receiver second —
view = space.acquire_py_buffer(w_other, space.BUF_SIMPLE) at
bytearrayobject.py:317, then value = self.getdata() at :318. bytearray_compare
reproduces that, which is why the receiver read sits after the acquisition.
Reordering it would diverge from upstream, not converge on it.

The related hazard for the ordering comparisons is tracked in the
Snapshot ordering receiver thread, where the faithful repair is described.

commented by Claude

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 567ea0d24e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +4951 to +4955
if pos.len() == 4 {
if unsafe { pyre_object::is_type(pos[0]) } {
w_metaclass = pos[0];
}
return type_descr_new_with_metaclass(&pos[1..], w_metaclass, kwargs);

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 Precheck the metatype on the four-argument path

For a direct call such as type.__new__(42, 1, (), {}), this newly added fallback leaves w_metaclass null and validates 1 as the class name, producing the argument-1 diagnostic instead of rejecting 42 as a non-type metatype. PyPy's descr__new__ runs _precheck_for_new after confirming the three public arguments are present but before _check_new_args, so call precheck_for_new(pos[0]) before dispatching this shape. Fresh evidence beyond the previously reported two-argument case is this new four-position branch, which bypasses that branch's precheck.

AGENTS.md reference: AGENTS.md:L231-L233

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Confirmed and fixed in f6e0e2fprecheck_for_new(pos[0])? now runs before the branch dispatches.

type.__new__(42, 1, (), {})
  pypy3   TypeError: X is not a type object (int)
  before  TypeError: type() argument 1 must be string, not int
  after   TypeError: X is not a type object (int)

Checked the blast radius against pypy3 on an 18-case matrix: the five-argument super() shape and every call whose name argument is a str are taken by the scan above and never reach this branch, so M(1, (), {}), type.__new__(M, 1, (), {}) and type.__new__(M, 'A', (), {}) are unchanged and still match.

Worth recording separately: the same matrix shows five rows that diverge and are not from this branch — origin/main has a byte-identical scan loop, and this PR added no branch that reaches them.

pypy3 here
type.__new__(42, 'A', (), {}) X is not a type object (int) creates the class
type.__new__(None, 'A', (), {}) X is not a type object (NoneType) creates the class
type.__new__('s', 'A', (), {}) X is not a type object (str) type() takes 1 or 3 arguments
type.__new__(int, 'A', (), {}) type.__new__(int): int is not a subtype of type metaclass conflict: ...
type.__new__(42, 'A', ()) ?.__new__() takes exactly 3 arguments (1 given) type() takes 1 or 3 arguments

The first two are wrong answers rather than wrong wording. The cause is structural: descr__new__ is a plain switch on len(__args__.arguments_w) with _precheck_for_new after it (typeobject.py:886-911), whereas type_descr_new locates the triple by scanning for the first str, so the metatype is never validated on that path. Bolting a precheck onto the scan is not safe on its own, because the scan is also what absorbs the five-argument super() binding shape [self, metatype, name, bases, dict], where pos[0] is not the metatype. Porting the arity switch means changing how the receiver reaches this function, which is out of scope here.

Verified on this head: dynasm 391/391, cranelift 391/391, wasm 387/387, parity all pass, CPython gate 46 PASS / 0 FAIL / no regressions, cargo test --all 7495 passed 0 failed, cargo fmt --check clean, 0 LLBC STALE.

commented by Claude

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 78b45f07f2

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

/// missing decode still shows.
///
/// A str of the wrong length is a separate refusal, and the one upstream
/// words per method.
fn pad_fillchar(args: &[PyObjectRef], method: &str) -> Result<CodePoint, crate::PyError> {
if args.len() <= 2 {
return Ok(CodePoint::from_char(' '));
}
if !unsafe { pyre_object::is_str(args[2]) } {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Port the fill conversion for ljust and rjust

When the fill operand is a one-byte bytearray, memoryview, or array, this non-str branch raises TypeError, while PyPy's descr_ljust and descr_rjust pass it through convert_arg_to_w_unicode/decode_object and use the decoded character. Fresh evidence beyond the earlier review is the final follow-up's own comment immediately above this branch explicitly stating that the decode is still not imported; changing only the error wording therefore leaves the behavioral divergence intact. Split center from ljust/rjust and port their respective conversion paths.

AGENTS.md reference: AGENTS.md:L231-L233

Useful? React with 👍 / 👎.

Comment on lines +3915 to +3917
/// Arity 2 is `makespecialisedtuple2` territory at runtime (`Cls_ii` /
/// `Cls_ff` / `Cls_oo`, `specialisedtupleobject.py`), and this arm builds the
/// canonical shape there instead. Representation is not observable — the

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 Preserve the runtime representation for arity-two tuples

When one BUILD_TUPLE site alternates between traced and residual execution, this canonical object conflicts with the Cls_ii/Cls_ff/Cls_oo object the interpreter constructs, creating mixed-representation side exits. Fresh evidence beyond the earlier identity-based review is in the committed baselines: binary_int_overflow_local_resume rises from 647 to 686 guard failures and exc_bridge_entry_guard_not_removed from 809 to 1009, each gaining a bridge on all three backends, and the follow-up commit attributes these deltas to this representation mismatch. Keep arity two on the specialized shape and port its consumers instead of deliberately diverging from the interpreter.

AGENTS.md reference: AGENTS.md:L231-L233

Useful? React with 👍 / 👎.

…x argument-handling sites

`object.__new__` now runs `check_user_subclass`, and `type` gets its own
Layout typedef (`TYPE_TYPE`) instead of sharing `object`'s — that identity is
what the check reads, so `object.__new__(int)` and `object.__new__(<metaclass>)`
are refused.

Buffer requests are split by kind: `bytes()` / `bytearray()` read their source
with `BUF_FULL_RO` (a strided memoryview is copied out, not refused), while
bytes-method operands — `replace`, `strip`, `join`, `translate`, the fill char —
require the C-contiguity `BUF_SIMPLE` carries.

`bytes.startswith` / `endswith` convert the operand before the
`start > len(value)` early-out, so an empty window no longer hides a prefix of
the wrong type.

A supplied `None` is a value, not an omitted argument, for `bytes.center` /
`ljust` / `rjust`'s fill char, `bytes.decode`'s encoding and errors,
`bytearray.pop`'s index, and `memoryview.cast`'s shape.  `builtin_str` spells
the utf-8 default out where it previously passed `None` through.

Surplus positional arguments are rejected by `str.replace`, `bytes.center` /
`ljust` / `rjust`, `bytearray.remove` and `memoryview.cast`.

An unset `__slots__` read reports `%T` — the bare type name — through
`raiseattrerror`, matching the same miss taken through the descriptor's
`__get__`.  `type(1, (), {})` names argument 1 instead of reporting an arity
error, and argument 1's message says `string` like its two siblings.

`SyntaxError.__str__` splits its filename with `ntpath` rules on windows.

Assisted-by: Claude
`cmp_guard_bytearray` admitted only bytes and bytearray, so
`bytearray(b'ab') == array.array('B', [97, 98])` answered `False` and
`bytearray(b'ab') < memoryview(b'b')` raised.  `descr_eq` / `descr_ne` /
`_comparison_helper` (bytearrayobject.py) hand a non-bytes-like operand to
`space.acquire_py_buffer(w_other, space.BUF_SIMPLE)` and turn only the
TypeError that raises into `NotImplemented`; a released view's ValueError and
a strided view's BufferError propagate.

The six dunders are now built from `bytearray_compare`, which keeps the
by-layout `compare_slot` for the bytes-like arms and for any receiver the slot
was not meant for, and reads the receiver's data after the acquisition since a
`__buffer__` slot is app-level code.

`bytes` keeps the narrow guard: its comparisons never acquire a buffer, which
is what makes `b'ab' == array.array('B', [97, 98])` `False`.

`ordering_satisfies` replaces the two spellings of the `_memcmp`-result
mapping in `descroperation`.

`pad_fillchar`'s doc records why `str.ljust` / `rjust` keep refusing a buffer
fill char: `convert_arg_to_w_unicode` decodes one, but CPython refuses it for
all three methods and pyre follows CPython there.

Assisted-by: Claude
…Error

`descr_member_get`'s miss reported `getfulltypename` before d8fc362
narrowed it to the bare `%T` name; `test.test_descr.test_slots` pins the
`module.__qualname__` form and the cpython_tests runner drives that module
through its dotted-identity driver, so the narrowing turned the gate red.
The unit test's name and expectation go back with it.

`test_bad_new` regains the `@support.impl_detail(cpython=False)` marker the
3.14.6 stdlib import replaced with CPython's `@unittest.expectedFailure`:
the layout check added in fdcce06 makes the test pass here, and an
unexpected success fails the module.

Assisted-by: Claude
…rarg local

`try_walker_specialize_newtuple_object` no longer declines arity 2. The
canonical array-backed `W_TupleObject` is the shape `subscr_tuple`,
`builtin_len`, `get_iter` and the array-backed arm of `unpack` already read,
whereas a `makespecialisedtuple2` pair has an UNPACK fold and nothing else,
so every other read of one forced it out of virtual state. The `spec_ii`
arm stays as the fallback for a pair whose backing-array length never
reached the heap-cache as a constant. Measured over an empty loop:
`(i, i + 1)[1]` 258.6ns -> 0.1ns, `f()[1]` for a pair-returning `f`
1247.7ns -> 34.4ns, `d[(a, b)]` 1207.6ns -> 313.1ns.

`try_walker_inline_resolved_user_call` accepts a `*args` callee and writes
`newtuple(starargs_w)` into `scope_w[co_argcount]`
(`argument.py:222-234 _match_signature`) instead of leaving the call
residual. `**kwargs` and keyword-only callees stay residual, as does a
zero-surplus call (the empty tuple is a singleton) and a bound method whose
callee has no positional parameter to hold the receiver — its
`callee_args[0]` is still the placeholder the resolved half replaces with
`GetfieldGcR(Method.w_self)`. 300k calls: `f(*args)` 0.480s -> 0.000s,
`c.m(*args)` 0.514s -> 0.000s, `f(a=i)` into `**kw` 0.254s -> 0.142s.

jit-stats: the trace-built pair and a runtime-built specialised one meeting
at one code location costs a side exit, so three fixtures gain a bridge
(`binary_int_overflow_local_resume`, `exc_bridge_entry_guard_not_removed`,
`list_append_write_barrier_gc`); `getattribute_override_no_bind` compiles
one loop instead of two now that its `*args` callee inlines, and
`pickle_ctor_args` sheds half its cranelift guard failures. The wasm
baseline missing for `exception_escape_hot_callee_tb_node_once` is recorded.

Assisted-by: Claude
15 synthetic fixtures move on all three backends: the arity-2 BUILD_TUPLE
virtualization composes with the walker setfield_gc store and the FOR_ITER
RETURN_VALUE admission from #1068 and the loop-perf folds from #1061, so the
sre, exception-traceback and comprehension traces take fewer side exits —
`nested_list_comprehension_hot` drops from 6 bridges / 1202 guard failures to
2 / 401, `sre_wasm_min` from 8 / 1849 to 5 / 1161.

The 30 macro baselines only gain `field_pos_attached_misplaced` and
`field_pos_spec_misplaced` at 0, the counters #1053 added to the binary
without recording them here.

Assisted-by: Claude
Each carries `# pyre-check: skip-cpython` followed by the measured cpython and
pyre times, the way the directive requires. The directive itself is on the
base; this only names the fixtures that claim it.

Assisted-by: Claude
`specialised_pair_consumers.py` reads the `_ii` / `_ff` / `_oo` pair layouts
through `len()`, subscription and unpacking, at a constant index, at an
alternating index and off a nested pair, with accumulators that do not cancel
a swapped or mis-represented slot.

The specialisation folds themselves are already on the base.

Assisted-by: Claude
`compare_slot`'s tuple arm walked both operands with `w_tuple_getitem`, which
for a `W_SpecialisedTupleObject_ii` / `_ff` builds a fresh box per element
because the payload is an inline machine word.

`specialised_tuple_same_class_eq` reproduces `specialisedtupleobject.py:113-127
descr_eq`: when both operands are the same specialised class the value slots
compare raw, with the float arm falling back to the bit pattern so the same NaN
in both slots stays equal (`float2longlong` upstream) while `+0.0` / `-0.0` are
caught by the value compare. `_oo` slots still go through `eq_w`. Eq/Ne only —
ordering keeps the generic walk, as upstream does. A mixed pair (one
specialised, one array-backed) falls through to the existing element walk.

Measured `(1, 2) == (1, 2)` on two loop-invariant pairs: 252.9ns -> 151.1ns.
The remainder is not the boxing: `_ff` barely moves and an arity-3 array-backed
comparison is 29ns, so ~120ns of arity-2 comparison is upstream of this arm.

Assisted-by: Claude
The baselines committed in e3d151e were recorded against a stale
`build/llbc`: a `pyre-jit-trace` / `pyre-interpreter` edit invalidates the
extraction fingerprint, and the JIT reads the function bodies it inlines out
of those artefacts, so trace shape — not just field offsets — depends on them.
The recorded counters therefore did not reproduce on CI, which extracts its
own. `pyre/check.py (ubuntu-24.04)` failed with 49 jit-stats regressions
across 19 benches on all three backends with identical numbers.

Re-extracted `pyre-object pyre-interpreter pyre-jit`, rebuilt dynasm,
cranelift and wasm with no `LLBC STALE` warning, and re-recorded. A local run
now reproduces the CI numbers exactly, e.g. `nested_list_comprehension_hot`
bridges 2 -> 6 and guard_failures 401 -> 1202.

84 counter values change across 21 benches (51 guard_failures, 33
bridges_compiled). 19 are the arity-2 tuple fold's mixed-representation side
exits, which the ca7351f message under-reported for the same stale-artefact
reason. Two are improvements from the specialised-pair subscript fold:
`divmod_long_int_pair` guard_failures 9 -> 7 (its pair result now folds) and
`exception_oserror_fields` 202 -> 201.

The remaining 2218 added lines are `field_pos_attached_misplaced` /
`field_pos_spec_misplaced`, counters #1053 added to the binary without
recording them.

check.py --synthetic-only: dynasm 371/371, cranelift 371/371, wasm 370/370.

Assisted-by: Claude
`type_descr_new` reached `new_arity_message` with an unvalidated first
argument, and that read it through the `W_TypeObject` layout:
`type.__new__(42, 1)` segfaulted and `type.__new__('s', 1)` reported
`s.__new__() takes exactly 3 arguments (1 given)`, naming the str's own
bytes.

`descr__new__` (typeobject.py:886-911) decides the arity first and then
runs `_precheck_for_new` (typeobject.py:1001-1003), so the one-name form
now refuses a non-type with `X is not a type object (%T)` and the
no-name form names it through the `%N` operand spelling — `W_Root.getname`
(baseobjspace.py:90-94), which answers `?` when `__name__` is absent.
`type.__new__(42)` answered `<class 'int'>` and now raises.

Also folds the two `pos.len() == 1` arms, which had become the same
branch, and saturates the reported argument count in the three unicode
error initialisers; those are installed as `wrapper_descriptor`s that
reject a zero-argument call before the body runs, so the subtraction was
not reachable.

Assisted-by: Claude
…exporter

`buffer_bytes` passed a literal `0` to `w_memoryview_new_with_flags` on
every path, so a Python `__buffer__` saw `PyBUF_SIMPLE` even when the
caller was `full_ro_buffer_bytes`, whose request is `BUF_FULL_RO`. An
exporter that branches on the request observed the wrong one:
`bytes(x)` on a `__buffer__` that requires `PyBUF_FORMAT` raised
`BufferError` where cpython returns the bytes.

`require_contiguous: bool` becomes a `BufferRequest` naming the two
requests, and both the contiguity rule and the exporter flags are derived
from it. `BUF_FULL_RO` moves next to it from `interp_buffer`, which
already spelled the same constant.

Assisted-by: Claude
`try_walker_specialize_subscr_specialised_pair` reaches
`W_SpecialisedTupleObject_oo.value0` / `value1` through
`walker_emit_specialised_pair_item`, which reads them with a `getfield_gc_r`.
That read is wrong code on this path. `test.test_datetime` holds
`self.lt = (array('q', ut), array('q', ut))` and reads `self.lt[dt.fold]`; with
the fold in place the next call in that frame comes out one positional argument
short, so `bisect.bisect_right(lt, timestamp)` raises `TypeError: bisect_right()
missing 1 required positional argument: 'x'` and the module goes `PASS -> FAIL`
on the CPython gate.

Measured on the full module, 550 tests: `PYRE_NO_JIT=1` passes while the JIT
fails one. Declining only the `Object` kind passes. `MAJIT_NO_BRIDGE=1` still
fails, so the exit is the main trace's and not a compiled bridge; executing the
residual for the object arm and recording its concrete result, dropping the
`replace_box`, and emitting the index guard through
`walker_emit_guard_with_snapshot` each leave it failing. What makes the
object-slot read itself wrong is not yet known.

The decline sits in the subscript entry point rather than in
`walker_emit_specialised_pair_item`, because UNPACK reaches the same slots
through that helper with no index operand and is sound. The `ii` and `ff` arms
share the class guard and the pinned index and keep their fold — over an empty
loop, `II[0]` 0.1ns and `II[i & 1]` 0.7ns against 169.3ns and 175.5ns with the
whole fold declined. `len()` on a pair is untouched. `OO[0]` returns to the
residual at 193.1ns from 35.9ns.

Assisted-by: Claude
…e measures

The rebase carried this branch's earlier recording through without raising a
conflict: bridges_compiled=4 and guard_failures=803. All three backends read 3
and 603 against the rebased tree, which is what main records.

Assisted-by: Claude
The rebase resolved this file to main's side, which reads loops_compiled=2 and
guard_failures=2. The tree measures 1 and 1 on wasm, matching the dynasm and
cranelift baselines for the same fixture. The re-record also picks up the five
counters added to the snapshot field set.

Assisted-by: Claude
The symbolic frame is built from `param_boxes`, which spans `seeded_locals`
and so carries the packed `*args` tuple; the concrete frame beside it was
built from the first `nparams` entries only. That frame is published on the
interpreter frame chain for the whole sub-walk, so a residual running inside
an admitted `*args` callee read the vararg name as unbound:

    def g(a, *args):
        return 'args' in sys._getframe().f_locals

called in a hot `while` loop answered False on 5 of 200000 iterations, where
pypy answers True on all of them. `_match_signature` writes the vararg tuple
into `scope_w` like any other local (argument.py:222-234).

`callee_arg_concretes` already holds the tuple at index `nparams` and is
declined unless its length is `seeded_locals`, so both bounds stay in range.

Assisted-by: Claude
`center` converts with `space.utf8_w` and `ljust`/`rjust` with
`convert_arg_to_w_unicode` (unicodeobject.py:1101, 175-184), and the two
refuse in different words. Both arms carried one shared string that matched
neither:

    "ab".center(6, 1)   pypy: expected str, got int object
    "ab".ljust(6, b"x") pypy: Can't convert 'bytes' object to str implicitly
    pyre, both:         The fill character must be a unicode character, not X

`arg_type_name` renders the same names `%T` does for all eight types checked.
`decode_object`, which turns a buffer operand into a fill char for
`ljust`/`rjust`, is still not imported; the doc comment now states that as the
remaining difference instead of as the reason for a shared message.

Assisted-by: Claude
`builtin_str` wrapped a fresh "utf-8" for every `str(b, errors=...)` call that
omits the encoding. `w_str_new` is immortal, so each one stays allocated for
the life of the process. `warn::PrebuiltText` is the existing cell for this
shape; `bytes_method_decode` only reads the encoding through `str_utf8_w`.

Assisted-by: Claude
`convert_arg_to_w_unicode` declines only `bytes` itself; every other non-str
operand reaches `decode_object`, which reports a failed conversion as
"decoding to str: %S" over the buffer error (unicodeobject.py:175-184,
1727-1739). The `ljust`/`rjust` arm now says that, with `None` rendered
unquoted where a type name is quoted:

    "ab".ljust(6, 1)     decoding to str: a bytes-like object is required, not 'int'
    "ab".ljust(6, None)  decoding to str: a bytes-like object is required, not None
    "ab".ljust(6, b"x")  Can't convert 'bytes' object to str implicitly

All eight cases checked now print what pypy prints, byte for byte.

Assisted-by: Claude
`type_descr_new` finds `(name, bases, dict)` by scanning for a str, so a
four-position call whose name is not a str falls past the scan.  That branch
took `pos[0]` as the metatype only when it already was a type and otherwise
left it null, which sent `type.__new__(42, 1, (), {})` on to report argument
1.  `descr__new__` runs `_precheck_for_new` once the count is settled and
before `_check_new_args` (typeobject.py:899), so the branch calls
`precheck_for_new` first:

    type.__new__(42, 1, (), {})
      before  TypeError: type() argument 1 must be string, not int
      after   TypeError: X is not a type object (int)

The five-argument `super()` shape and every call whose name is a str are
taken by the scan above and do not reach this branch.

Assisted-by: Claude
`try_walker_specialize_newtuple_object` emitted a canonical `W_TupleObject`
virtual at every arity, including 2.  At that arity the interpreter calls
`makespecialisedtuple2` (specialisedtupleobject.py:169-179) instead, so the
virtual is the one shape the runtime never builds: `Cls_ii` / `Cls_ff` /
`Cls_oo` hold `value0` / `value1` inline and carry no `wrappeditems` block.

The trace is self-consistent on its own, but a side exit puts a real pair in
front of a consumer the trace chose for the canonical layout, and
`try_walker_specialize_subscr_specialised_pair` reads a field that is not
there.  A pair built inside the loop and subscripted at an alternating
non-negative index reaches it:

    t = (i, BIG)
    item = t[i & 1]

which segfaults, or returns whatever the stale pointer lands on — one run
answered `TypeError: unsupported operand type(s) for &: 'type' and 'int'`.
`extra_tests/parity_tests/subscr_specialised_pair_shapes.py` fails both ways.
Building the pair outside the loop, or indexing it only at a negative index,
does not reach it.

Arity 2 now falls to `try_walker_specialize_newtuple`, which builds the
specialised shape the runtime builds.  Arity 1 and 3 up are unchanged.

Assisted-by: Claude

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f3cf79760d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

}
// A new allocation with no heap mutation, safe during the walk, and the
// same constructor `emit_object_tuple_inline` reproduces.
let concrete = pyre_object::w_tuple_new_array_backed(surplus_concretes);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Root the concrete vararg tuple immediately

When tracing an eligible call with surplus *args, this GC-managed tuple is kept only as a raw pointer in callee_arg_concretes until it is stamped onto tuple_op roughly 900 lines later. The intervening admission and guard-emission code can allocate or encounter a concurrent collection; raw concrete shadows are not GC roots, so the tuple may be swept or its address may become stale before it is used to seed the callee frame. Pin the tuple across this interval or create and stamp its frontend op immediately.

Useful? React with 👍 / 👎.

@youknowone
youknowone merged commit 9d2fff9 into main Aug 7, 2026
13 of 17 checks passed
@youknowone
youknowone deleted the buitlins branch August 7, 2026 01:50
youknowone added a commit that referenced this pull request Aug 7, 2026
…elines

`9d2fff92649` (#1063) re-recorded 993 jit-stats baselines. All but four gained
only the two new `field_pos_*_misplaced=0` keys; three changed a value:

    binary_int_overflow_local_resume    bridges 5 -> 6  guards  647 -> 686
    exc_bridge_entry_guard_not_removed  bridges 4 -> 5  guards  809 -> 1009
    list_append_write_barrier_gc        bridges 5 -> 6  guards 1345 -> 1562

Five runs report the pre-#1063 values and none reports the recorded ones:
dynasm, cranelift and wasm here, and `main`'s own CI on ubuntu-24.04 and
macos-latest at 9d2fff9 -- run 31139317566, jobs 92747505633 and
92748753166, on a tree carrying no commit from this branch. The three benches
fail identically on all three backends in each of them.

Only those two keys are restored; #1063's two added keys stay. The fourth bench
it revalued, getattribute_override_no_bind, is left as recorded: it passes here
and in that CI run, so its new values do reproduce.

Assisted-by: Claude
youknowone added a commit that referenced this pull request Aug 7, 2026
… on a non-measurement (#1095)

* jit: stamp the qmut abort's own subwalk coordinate, and re-seed a live-NULL operand slot

A walk that executed residual side effects and then fails to commit its end
state falls back to the legacy replay from the traced region's entry, which runs
those residuals a second time.  Two shapes reached that fallback; both show up
under `PYRE_FBW_CENSUS=1` as `committed=false effects>0`.

`WalkSession::abort_in_subwalk` is sticky — `claim_abort_coordinate` only ever
sets it — so an inline sub-walk abort the walk recovered from left it true for
every later abort in the same trace attempt, and `flush_qmut_abort_state`'s gate
then read a root-frame abort as a callee coordinate.  The `ForceQuasiImmutable`
raise in `dispatch_residual_call_iRd_kind` now stamps it from
`fbw_mode.inline_subwalk` at the raise point, as the two kept-stack branch-guard
raises already do.

`reseed_vstack_from_shadow` rejected a NULL const-ptr shadow slot outright,
because a NULL there can also mean a slot the portal never wrote.  It now
accepts one carrying the `virtualizable_live_null_slots` marker, which records
that the last executed store into that slot wrote a NULL.  PUSH_NULL's
`self_or_null` sentinel is such a slot and stays live across the whole
callable/args/kwargs build ahead of a CALL; the reorder region re-seeds the
mirror in the middle of that build, and the rejected slot made
`capture_vstack_mirror_image` refuse the image, leaving an escape inside the
call with no blackhole resume.

`capture_vstack_mirror_image`'s decline line gains the Python pc and the mirror
boxes.  The LoadName cell-fold gate comment is rewritten to the measured state:
with the gate lifted the `bench/synth` corpus is output-correct, and what fails
is `exception_reraise_tb_depth_jitstress` at 13.0x against its 4x pypy gate plus
four benches' jit-stats.

Measured with the gate lifted, in-place arms: `iter57/real_exception` 100003 ->
100000, `exception_reentry_guard_finally_residual` `leaked 4 reentry 2` ->
`leaked 0 reentry 0`.

Assisted-by: Claude

* jit: record why reseed_vstack_from_callee_shadow keeps its NULL const-ptr rejection

The callee-shadow reseed is the structural twin of `reseed_vstack_from_shadow`
and rejects a NULL const-ptr the same way, but its source is a sparse
`HashMap`, where a present key is already the write-witness the dense
virtualizable array needed a per-slot side table to supply. So the clause
discards a proven write whose value happens to be PUSH_NULL's `self_or_null`.

Measured before writing this: dropping the clause leaves `check.py --backend
dynasm` at 386/386 with no jit-stats movement and no baseline change, so the
corpus does not distinguish the two behaviours. Behaviour unchanged; the
comment records the asymmetry and the measurement.

Assisted-by: Claude

* rework.md: refresh the audit against the current tree

The findings were measured on `pc-map` on 2026-07-05. Re-measured on
`ec-wiring` at base 58fcd37, thirteen of the fifteen issues the document
tracks are closed and the priority order has inverted.

F1: gh#366/367/368/369 closed; `metadata.pc_map` and `resume_jitcode_pc_for`
have zero hits and `resume::SnapshotFrame.pc` is the JitCode byte offset. The
surviving `pc_map` matches are the compile-time exit-recovery `Vec<usize>` in
jit/codewriter.rs and jit/flatten.rs, a different thing. Residue recorded:
recorder.rs's SnapshotFrame doc still describes the deleted translation, py_pc
is stored rather than derived, and build_state_field_snapshot stamps the
JitCode offset into py_pc (unproven, needs a repro).

F2: verified done — `is_full_body_walk`, `PYRE_FULL_BODY_WALK` and
`OpcodeHandler for MIFrame` have zero hits each.

F3: regressed to 15 registrations against MAX_EXTRA_ROOT_WALKERS = 16; the
16th caller hits `panic!("capacity exceeded")` at startup.

F4: gh#346 and gh#373 closed, coverage still landing (#1065); abort_permanent
unchanged in scale, but the exit criterion is the census, not a match count.

F5: gate-triage.md now exists but the population grew from 119 matches to 245
distinct PYRE_* identifiers.

Sequencing amended to WS3 > WS2 > WS1-residue > WS4.

Assisted-by: Claude

* rework.md: correct the F5 gate count to a reproducible measurement

The refresh recorded 245 distinct `PYRE_*` identifiers against the audit's
original 119. That figure does not reproduce: tracked `*.rs` holds 131 distinct
identifiers, all tracked files 174, and 548 raw matches.

The quantity comparable to the original "distinct `PYRE_*` env gates" is the
set of names actually read from the environment, which is 126. The command is
now stated in the document so the number can be re-derived, along with the three
other counts it is easy to confuse it with.

Assisted-by: Claude

* check.py: do not fail a ratio gate whose baseline is clamped to the floor

`_exec_time` clamps a startup-subtracted time to `EXEC_TIME_FLOOR_S` so
ratios cannot divide by ~0. When the pypy baseline lands there, the ratio
is `pyre_exec / EXEC_TIME_FLOOR_S` and the ceiling it is compared against
is an absolute wall-clock budget of `ceiling * EXEC_TIME_FLOOR_S` seconds,
fitted on whichever host wrote the header. The comparison table already
marks those ratios `~` and prints "ratio is not a measurement"; the gate
failed the run on them anyway.

`failed_bound` now returns None whenever the baseline is clamped, instead
of requiring the backend to be at the floor as well. Only the ceiling
changes behaviour: the floor arms at `exec_baseline >=
FLOOR_GATE_MIN_BASELINE_S`, which a clamped baseline is always under. The
gate can therefore only pass more than before, never fail more.

The `[... clamped to floor; ratio not a measurement]` suffix in
`_gate_fail_detail` is unreachable once a clamped baseline returns no
bound, and is removed; the `~` legend states the consequence instead.

Three consecutive `main` runs failed this way on three different fixtures
across two runners: global_cell_shortpreamble_hot 24.1x > 19x and
class_reassign_hot 49.2x > 47x on ubuntu-24.04, reentrant_key_eq_mutation
10.3x > 5x on macos-latest (runs 31079972573, 31080288895).

Discriminator, cranelift, `class_reassign_hot` with its ceiling
temporarily set to 1: the previous check.py reports SLOWER "exec 0.13s >
pypy 0.01s ratio 27.0x > gate 1x [pypy exec clamped to floor; ratio not a
measurement]", this one reports PASS. With the same ceiling of 1 on
seqiter_tuple_error_parity, whose pypy exec is a measurement, this
check.py still reports SLOWER at 18.3x — the ceiling is untouched
wherever the baseline is real. The three fixtures above pass with their
own ceilings restored.

Assisted-by: Claude

* posix: correct which stat rejection precedes the platform's dir_fd check

`stat_entry` consults `HAVE_FSTATAT` while unwrapping `dir_fd`, above the
descriptor branch, so the descriptor+`dir_fd` conflict is unreachable where
`fstatat` does not exist. The comment claimed both fd-conflict rejections
come first. #1081 corrected the same claim in
`extra_tests/parity_tests/os_stat_file_descriptor.py` and cites
`_DirFD_Unavailable` (`interp_posix.py:285-292`) for it; this is the
statement of it that sits next to the code.

Assisted-by: Claude

* bench: re-record the wasm jit-stats for exception_reused_object_tb_not_doubled

`fbw_blackhole_adopted_single_frame` reads 3 where the baseline had no entry
for it. `loops_compiled=4` and `bridges_compiled=3` are unchanged, so the
trace shape is the same and what moved is that the walk now adopts the
blackhole resume image instead of falling back to the replay from the traced
region's entry.

Attributed by measuring both arms with the same command, `check.py --backend
wasm --synthetic-only --synthetic-pattern exception_reused_object_tb_not_doubled`:
with `ff503b5d746` reverse-applied in place the bench reports ALL PASSED
against the existing baseline, and with it restored it reports the 0 -> 3
change. The control arm took 2m32s against the treatment arm's 4s, which is
the wasm module being relinked rather than reused.

The counter arrived with #1064 and this bench's baselines were last recorded
at `da5e6fb38c7` (#1059), so absence from the baseline did not by itself say
which of the two it was. No CI job runs `--backend wasm`, so the wasm
baselines are not gated there either.

The other four keys the re-record adds -- fbw_blackhole_adopted_multi_frame,
fbw_store_journal_rollback_failed, field_pos_attached_misplaced,
field_pos_spec_misplaced -- are counters that did not exist at #1059 and are
pinned at 0 here for the first time. The dynasm and cranelift baselines are
not re-recorded: both backends still report ALL PASSED for this bench.

Assisted-by: Claude

* bench: restore bridges_compiled and guard_failures on three synth baselines

`9d2fff92649` (#1063) re-recorded 993 jit-stats baselines. All but four gained
only the two new `field_pos_*_misplaced=0` keys; three changed a value:

    binary_int_overflow_local_resume    bridges 5 -> 6  guards  647 -> 686
    exc_bridge_entry_guard_not_removed  bridges 4 -> 5  guards  809 -> 1009
    list_append_write_barrier_gc        bridges 5 -> 6  guards 1345 -> 1562

Five runs report the pre-#1063 values and none reports the recorded ones:
dynasm, cranelift and wasm here, and `main`'s own CI on ubuntu-24.04 and
macos-latest at 9d2fff9 -- run 31139317566, jobs 92747505633 and
92748753166, on a tree carrying no commit from this branch. The three benches
fail identically on all three backends in each of them.

Only those two keys are restored; #1063's two added keys stay. The fourth bench
it revalued, getattribute_override_no_bind, is left as recorded: it passes here
and in that CI run, so its new values do reproduce.

Assisted-by: Claude
youknowone added a commit that referenced this pull request Aug 7, 2026
…es no host

produces

`pyre/check.py` has been red on main for binary_int_overflow_local_resume,
exc_bridge_entry_guard_not_removed and list_append_write_barrier_gc since
9d2fff9, on ubuntu-24.04, macos-latest AND windows-latest (run
31140634730), and locally on macOS across all three backends.

Every one of those hosts observes bridges_compiled/guard_failures 5/647, 4/809
and 5/1345. Those are exactly the values that stood on main before 9d2fff9
(last written by #947 and #1059); 9d2fff9 recorded 6/686, 5/1009 and 6/1562,
which reproduce nowhere. The re-record was taken against a base whose behaviour
these fixtures no longer had, and the merge replayed it.

Re-recorded on dynasm, cranelift and wasm. The counters land back on the
pre-9d2fff92649 values; the `field_pos_*` fields 9d2fff9 added are kept.

Assisted-by: Claude
youknowone added a commit that referenced this pull request Aug 7, 2026
…es that have main red on every OS (#1099)

* jit: keep find_biggest_function's closed-frame result when the recorder is gone

pyjitpl.py:3562 reads `self.history.get_trace_position()` unconditionally, so
the `max_key` the closed-frame loop above produced always survives to the
return. pyre's recorder is an `Option` and the port spelled that read as
`self.tracing.as_ref()?`, which returns `None` for the whole function whenever
tracing has ended with an unmatched open entry still in
`portal_trace_positions`. Only the open frame is unmeasurable without a
recorder, so only its measurement is skipped now.

Not reachable from `blackhole_trace_too_long_slow`, which holds `self.tracing`
as `Some`; `find_biggest_function` is `pub`.

`find_biggest_function_keeps_a_closed_frame_when_the_recorder_is_gone` covers
it and fails with the `?` put back.

Also corrects blackhole_inlined_callee_local_after_escape_declined.py's second
description block, which still called `sys._getframe()` the residual after the
file's own header states it folds and the added `.f_locals` read is the force.

Assisted-by: Claude

* jit: emit sys._getframe's mark_as_escaped as a setfield, and carry the sized
frame's jitdriver out of find_biggest_function

vm.py:54 `f.mark_as_escaped()` is traced as an ordinary `setfield_gc` on the
flag. The constant-depth fold emitted it as a void CallN into a Rust helper
instead, which hides the update from the optimizer and its heap cache. Replaced
with the read/or/store the `tb_frame` fold in the same file already uses
(specialize.rs:2299-2313): getfield_gc_i(flags) + int_or(FLAG_ESCAPED) +
setfield_gc + heapcache_setfield_cached. `jit_frame_mark_as_escaped` is deleted.

pyjitpl.py:3575 returns `max_jdsd, max_key`, and pyjitpl.py:2821-2824 uses both
-- the disable goes through the OWNING driver's warmstate and that driver is
what `aborted_tracing_jitdriver` stores. The port dropped the jd_no its own log
entries already carry and hardcoded driver 0. It now returns
`Option<(usize, u64)>` and the caller stores the index it was given. pyre keeps
one WarmEnterState on the MetaInterp rather than one per JitDriverStaticData, so
`disable_noninlinable_function` still lands on that single state; the comment
names it.

No recorded counter moves on dynasm, cranelift or wasm.

Assisted-by: Claude

* bench: restore the three jit-stats baselines #1063 replaced with values no host
produces

`pyre/check.py` has been red on main for binary_int_overflow_local_resume,
exc_bridge_entry_guard_not_removed and list_append_write_barrier_gc since
9d2fff9, on ubuntu-24.04, macos-latest AND windows-latest (run
31140634730), and locally on macOS across all three backends.

Every one of those hosts observes bridges_compiled/guard_failures 5/647, 4/809
and 5/1345. Those are exactly the values that stood on main before 9d2fff9
(last written by #947 and #1059); 9d2fff9 recorded 6/686, 5/1009 and 6/1562,
which reproduce nowhere. The re-record was taken against a base whose behaviour
these fixtures no longer had, and the merge replayed it.

Re-recorded on dynasm, cranelift and wasm. The counters land back on the
pre-9d2fff92649 values; the `field_pos_*` fields 9d2fff9 added are kept.

Assisted-by: Claude

* jit: arm the deferred escape-flush undo when only the locals region flushed

`flush_active_frame_escape`'s force arm has three outcomes. A committed full
flush publishes a resume pc into `COMMITTED_FRAME_ESCAPE_PC`; an all-or-nothing
decline discards the undo capture; the third -- the full flush declines and
`flush_locals_region_to_frame` writes slots `0..nlocals` on their own -- did
neither.

That leg claims no resume pc, so `take_committed_frame_escape_pc` yields
nothing and the walk-end block gated on it is skipped in its entirety,
including the `restore_escape_flush_undo()` in its `else`. The capture stays
armed, `LiveLastInstrGuard::drop` reads an armed capture as a flush owning the
frame and declines to put `last_instr` back, and the legacy replay re-enters
one opcode past the call on an operand stack no flush wrote: `value-stack
underflow: depth=N base=N`, a JIT-only panic with no program output.

`mark_escape_flush_undo_pending()` routes the leg to the walk-end deferred
restore, which is already conditioned on no continuation having claimed the
flushed frame -- so where the walk goes on to adopt a blackhole image the
request is consumed without restoring and the adoption keeps the frame it
claimed.

Restoring earlier is not equivalent: making `LiveLastInstrGuard::drop` test the
commit instead removes the crash and returns a stale caller line, because the
walk goes on after the residual and nothing else advances `last_instr`.

`bench/synth/handler_tb_frame_locals_after_declined_flush.py` reaches the leg:
`'i' in tb.tb_frame.f_locals` forces the frame mid-expression, with the
`seen.add` receiver and its bound method live below the value being computed.

A/B on the cranelift binary that reproduced it: 10/10 panics without the
change, 0/10 with it, output `[True]` matching `PYRE_NO_JIT=1`.

Assisted-by: Claude

* bench: survey a caller's f_lineno and f_lasti from two call sites

A callee reading its caller's frame through `sys._getframe(1)` had no coverage
of the resume coordinate: `bench/synth` holds ten `_getframe(1)` fixtures, one
`f_lineno` fixture (a traceback frame) and no `f_lasti` fixture at all. Both
fields resolve off `last_instr`, which compiled code does not store per opcode,
so the value only reaches the frame if the force publishes it.

Two call sites are what make that observable. One holds the caller's coordinate
constant by construction, so a frozen read is indistinguishable from a live
one. Surveying every iteration into a set rather than sampling the last one is
the other half: the pre-compile iterations are correct, so a miss appears as a
changed row count.

`f_lasti` is a bytecode offset and so is not comparable against the pypy
oracle; only its discrimination is printed. `f_lineno` is compared directly,
relative to `co_firstlineno`.

Measured by putting a defect back in: with the `flushed` test dropped from
`LiveLastInstrGuard::drop`, so the guard restores at the residual's return
instead of at walk end, the fixture reports

    ([(0, 3), (0, 8), (1, 3), (1, 6)], [0, 0, 1, 1], 3)

against its

    ([(0, 8), (1, 6)], [0, 1], 2)

-- the pre-call coordinate appears alongside the call-site one on both legs.
cpython, pypy, `PYRE_NO_JIT=1`, dynasm, cranelift and wasm all print the
latter.

The walk-end epilogue gains the negative result measured while looking for a
counter to gate the same defect: every walk reaching that point on this fixture
reports `armed=false fb=true`, so a leak counter conditioned on the three
adoption flags being false reads 0 whether or not the force arm arms its
deferred restore.

Assisted-by: Claude

* check.py: fail the build on a stale LLBC instead of measuring through it

`pyre-jit-trace/build.rs` compares each `build/llbc/*.ullbc` against what its
crate's sources hash to now and reports a mismatch as `cargo::warning`, which
cargo replays only when it re-runs the build script -- so a run whose crates
were cached prints nothing at all. Every number check.py produces is read out
of a binary whose field offsets come from those artefacts.

Measured on this tree: four measurement runs -- a three-backend gate, two A/B
arms and a base control -- carried the mismatch, and the string `LLBC STALE`
appears in none of their logs, while `cargo check -p pyrex` on the same tree
printed it for all three crates. check.py only ever tested for the artefacts
being missing.

It now exports `PYRE_LLBC_STRICT=1` before every backend build, the promotion
build.rs documents for callers that want a gate, and names staleness in the
build-failure diagnostics beside the missing-artefact branch. The cost is that
a rebase which moves the LLBC crates stops the next check.py until a
re-extraction; `PYRE_LLBC_SKIP_FINGERPRINT_CHECK=1` still opts out for an A/B
whose only changed crate contributes no field offsets.

First use found one: the wasm jit-stats fall on
`exception_reused_object_tb_not_doubled` that four arms reproduced was an
artefact of the stale artefacts, and the bench passes on all three backends
after a re-extraction with nothing re-recorded.

Assisted-by: Claude
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant