)]}'
{
  "commit": "6576fb46db1ac2c1280c852df637a66c3e5aada7",
  "tree": "6b80475be669e22b58b54896c1667927152d5713",
  "parents": [
    "597ae8fdc4cbd5e73c82d9df2a31fc8f836b79c4"
  ],
  "author": {
    "name": "Cody Maloney",
    "email": "cmaloney@users.noreply.github.com",
    "time": "Mon Oct 19 20:39:11 2026"
  },
  "committer": {
    "name": "GitHub",
    "email": "noreply@github.com",
    "time": "Mon Oct 19 20:39:11 2026"
  },
  "message": "gh-87613: Use AC vectorcall for bytes and bytearray (#158891)\n\n* gh-87613: Use AC vectorcall for bytes and bytearray\n\nSpeeds up common construction of both objects. Enables optimizing\nconstruction off uniquely referenced temporary objects.\n\nPreviously the argument tuples / dictionaries required by the call\nprotocol resulted in arguments never being unique temporaries. With\nvectorcall they can be. Avoid copying by adopting the existing\nallocation when possible.\n\nBenchmark\nRun on my linux dev machine: PGO+LTO, clang 23, --with-tail-call-interp\n\n(note: AI Written, but I think sufficiently representative)\n```python\n\"\"\"bytes() and bytearray() construction.\n\ntemp/ passes a unique temporary (adopted, no copy); named/ binds the same\nsource to a name first so it is always copied.\n\"\"\"\nimport pyperf\n\nrunner \u003d pyperf.Runner()\n\nrunner.timeit(\u0027call/bytes()\u0027, \u0027bytes()\u0027)\nrunner.timeit(\u0027call/bytes(int)\u0027, \u0027bytes(16)\u0027)\nrunner.timeit(\u0027call/bytes(bytes)\u0027, \"bytes(b\u0027abcdefghabcdefgh\u0027)\")\nrunner.timeit(\"call/bytes(str, \u0027ascii\u0027)\", \"bytes(\u0027abcdefgh\u0027, \u0027ascii\u0027)\")\nrunner.timeit(\u0027call/bytearray()\u0027, \u0027bytearray()\u0027)\nrunner.timeit(\u0027call/bytearray(int)\u0027, \u0027bytearray(16)\u0027)\nrunner.timeit(\u0027call/bytearray(bytes)\u0027, \"bytearray(b\u0027abcdefghabcdefgh\u0027)\")\nrunner.timeit(\"call/bytearray(str, \u0027ascii\u0027)\",\n              \"bytearray(\u0027abcdefgh\u0027, \u0027ascii\u0027)\")\n\nfor size_name, size in ((\u002716B\u0027, 16), (\u00274KiB\u0027, 4096), (\u00271MiB\u0027, 1 \u003c\u003c 20)):\n    # Slicing in the statement makes a fresh unique temporary.\n    setup \u003d f\"b \u003d b\u0027x\u0027 * {size}; ba \u003d bytearray(b)\"\n    runner.timeit(f\u0027temp/bytes(bytearray) {size_name}\u0027,\n                  \u0027bytes(ba[1:])\u0027, setup)\n    runner.timeit(f\u0027named/bytes(bytearray) {size_name}\u0027,\n                  \u0027x \u003d ba[1:]; bytes(x); del x\u0027, setup)\n    runner.timeit(f\u0027temp/bytearray(bytes) {size_name}\u0027,\n                  \u0027bytearray(b[1:])\u0027, setup)\n    runner.timeit(f\u0027named/bytearray(bytes) {size_name}\u0027,\n                  \u0027x \u003d b[1:]; bytearray(x); del x\u0027, setup)\n    runner.timeit(f\u0027temp/bytearray(bytearray) {size_name}\u0027,\n                  \u0027bytearray(ba[1:])\u0027, setup)\n    runner.timeit(f\u0027named/bytearray(bytearray) {size_name}\u0027,\n                  \u0027x \u003d ba[1:]; bytearray(x); del x\u0027, setup)\n```\n\n| Benchmark                       | main    | patch                  |\n|---------------------------------|:-------:|:----------------------:|\n| temp/bytearray(bytearray) 1MiB  | 515 us  | 14.9 us: 34.53x faster |\n| temp/bytearray(bytes) 1MiB      | 508 us  | 14.8 us: 34.27x faster |\n| temp/bytes(bytearray) 1MiB      | 507 us  | 14.9 us: 34.05x faster |\n| temp/bytearray(bytes) 4KiB      | 144 ns  | 79.5 ns: 1.81x faster  |\n| temp/bytearray(bytearray) 4KiB  | 155 ns  | 94.7 ns: 1.63x faster  |\n| temp/bytearray(bytes) 16B       | 56.4 ns | 36.1 ns: 1.56x faster  |\n| temp/bytes(bytearray) 4KiB      | 150 ns  | 96.4 ns: 1.55x faster  |\n| temp/bytearray(bytearray) 16B   | 64.1 ns | 47.3 ns: 1.35x faster  |\n| call/bytes()                    | 14.7 ns | 11.1 ns: 1.32x faster  |\n| call/bytes(int)                 | 31.5 ns | 24.3 ns: 1.29x faster  |\n| call/bytes(str, \u0027ascii\u0027)        | 36.9 ns | 28.7 ns: 1.28x faster  |\n| call/bytes(bytes)               | 34.3 ns | 27.3 ns: 1.26x faster  |\n| temp/bytes(bytearray) 16B       | 59.4 ns | 49.5 ns: 1.20x faster  |\n| call/bytearray(str, \u0027ascii\u0027)    | 45.6 ns | 39.1 ns: 1.17x faster  |\n| call/bytearray(bytes)           | 44.3 ns | 38.9 ns: 1.14x faster  |\n| call/bytearray(int)             | 41.7 ns | 37.3 ns: 1.12x faster  |\n| named/bytearray(bytes) 16B      | 59.6 ns | 54.4 ns: 1.10x faster  |\n| named/bytes(bytearray) 16B      | 61.3 ns | 56.2 ns: 1.09x faster  |\n| named/bytearray(bytearray) 16B  | 65.3 ns | 60.9 ns: 1.07x faster  |\n| named/bytes(bytearray) 4KiB     | 154 ns  | 148 ns: 1.04x faster   |\n| call/bytearray()                | 22.1 ns | 21.4 ns: 1.03x faster  |\n| named/bytearray(bytearray) 4KiB | 156 ns  | 151 ns: 1.03x faster   |\n| named/bytearray(bytes) 4KiB     | 146 ns  | 143 ns: 1.02x faster   |\n| Geometric mean                  | (ref)   | 1.77x faster           |\n\nBenchmark hidden because not significant (3): named/bytes(bytearray) 1MiB,\nnamed/bytearray(bytes) 1MiB, named/bytearray(bytearray) 1MiB\n\n* Remove unique temporary adoption optimizations\n\nPyUnstable_Object_IsUniqueReferencedTemporary() can\u0027t tell when a C\ncaller still holds a borrowed reference to the argument (for example\nbisect.insort(lst, bytearray(b\u0027abc\u0027)[1:], key\u003dbytes)), so adopting the\nbuffer empties an object still in use. Leave the optimization for a\nfollow-up and keep this PR to the vectorcall change.\n\nCo-Authored-By: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e\n\n---------\n\nCo-authored-by: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e",
  "tree_diff": [
    {
      "type": "add",
      "old_id": "0000000000000000000000000000000000000000",
      "old_mode": 0,
      "old_path": "/dev/null",
      "new_id": "830e8ef1dc23b28451fad4d119e030970899064a",
      "new_mode": 33188,
      "new_path": "Misc/NEWS.d/next/Core_and_Builtins/2026-10-05-13-19-49.gh-issue-87613.JLTGBy.rst"
    },
    {
      "type": "modify",
      "old_id": "496d04a1704d46d032ce98986d01e0d8f07c8b49",
      "old_mode": 33188,
      "old_path": "Objects/bytearrayobject.c",
      "new_id": "429b8d993867f0c566d9bfbf96fb634a680c7f4d",
      "new_mode": 33188,
      "new_path": "Objects/bytearrayobject.c"
    },
    {
      "type": "modify",
      "old_id": "bfd54176e5f662c0c09c9ed9eb9d9852815bb101",
      "old_mode": 33188,
      "old_path": "Objects/bytesobject.c",
      "new_id": "a5c369757d452f377cef9168ede9dff26021c634",
      "new_mode": 33188,
      "new_path": "Objects/bytesobject.c"
    },
    {
      "type": "modify",
      "old_id": "b074851f1fbf78fef253867f5bd8af5586aaf664",
      "old_mode": 33188,
      "old_path": "Objects/clinic/bytearrayobject.c.h",
      "new_id": "9c8ba841200f30653275fa880da4764ea4953fc8",
      "new_mode": 33188,
      "new_path": "Objects/clinic/bytearrayobject.c.h"
    },
    {
      "type": "modify",
      "old_id": "56e8d089334a7a7a5a60911dea555bf70164c11a",
      "old_mode": 33188,
      "old_path": "Objects/clinic/bytesobject.c.h",
      "new_id": "2b2850b5933cf9bada02c71b836324e24176186c",
      "new_mode": 33188,
      "new_path": "Objects/clinic/bytesobject.c.h"
    }
  ]
}
