mirror of
https://github.com/ghostty-org/ghostty.git
synced 2026-07-31 04:39:01 +00:00
mitchell's touchups
- benchmark: avoid buffers to avoid a memcpy - build: keep frame pointers on macOS. There was some debug changes from Zig 0.15 and this helps. Also, Apple actually requires/expects x29 to always be a frame pointer. - build/macos: force libSystem symbols instead of compiler-rt - global: add InitOpts.tool so that ghostty-gen/bench can parse their own actions in `+action` - quirks: provide our own vectorized memset. see the comment for more details why. - synthetic: fix UB by accessing global.io before it was initialized - terminal/hash_map: force inline for unique repr types. Zig 0.15 inlined and 0.16 doesn't, measured a huge slowdown in hyperlink benchmarks. - terminal: add explicit `@Vector` usage for storing a run of identical cells as well as for scanning printable cells. This auto-vectorized in Zig 0.15 but not in Zig 0.16. This produces the same assembly. - unicode: properties and LUT need power-of-two backing integer to avoid bad LLVM codegen
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -14,7 +14,7 @@ zig-pkg/
|
||||
build-cmake/
|
||||
CMakeCache.txt
|
||||
CMakeFiles/
|
||||
/build.zig.zon.bak
|
||||
build.zig.zon.bak
|
||||
/result*
|
||||
/.nixos-test-history
|
||||
example/*.wasm
|
||||
|
||||
@@ -11,62 +11,62 @@
|
||||
// Aro/translate-c itself.
|
||||
.translate_c = .{
|
||||
.lazy = true,
|
||||
.url = "https://codeberg.org/vancluever/translate-c/archive/a916baf225a3cfc93a982225462db612604ae290.tar.gz",
|
||||
.url = "https://deps.files.ghostty.org/translate_c-a916baf225a3cfc93a982225462db612604ae290.tar.gz",
|
||||
.hash = "translate_c-0.0.0-Q_BUWj8_BwCr4na219OimiKKj4IVSq0aKtMXCQmIk4AB",
|
||||
},
|
||||
|
||||
// Zig libs
|
||||
.libxev = .{
|
||||
// mitchellh/libxev
|
||||
.url = "https://github.com/mitchellh/libxev/archive/9ce8e8e6ff89e583258a7f8e7adeeeaeae8611bf.tar.gz",
|
||||
.url = "https://deps.files.ghostty.org/libxev-9ce8e8e6ff89e583258a7f8e7adeeeaeae8611bf.tar.gz",
|
||||
.hash = "libxev-0.0.0-86vtcwIRFADbH4hk-EjROXxlrKIRPQdA41XiTSytYO-F",
|
||||
.lazy = true,
|
||||
},
|
||||
.vaxis = .{
|
||||
// rockorager/libvaxis
|
||||
.url = "https://github.com/rockorager/libvaxis/archive/1dbbe575dff4586fe51e3217aa5c3fecdcbb6089.tar.gz",
|
||||
.url = "https://deps.files.ghostty.org/vaxis-1dbbe575dff4586fe51e3217aa5c3fecdcbb6089.tar.gz",
|
||||
.hash = "vaxis-0.6.0-BWNV_CrbCQCscGpzsAlR402rYQ_tV3aAl081c2iRRkka",
|
||||
.lazy = true,
|
||||
},
|
||||
.z2d = .{
|
||||
// vancluever/z2d
|
||||
.url = "https://github.com/vancluever/z2d/archive/refs/tags/v0.11.0.tar.gz",
|
||||
.url = "https://deps.files.ghostty.org/z2d-0.11.0-j5P_HtLzDwBGyQt49DrT0v4BuVqI_SRs6CXsuj7eBVhR.tar.gz",
|
||||
.hash = "z2d-0.11.0-j5P_HtLzDwBGyQt49DrT0v4BuVqI_SRs6CXsuj7eBVhR",
|
||||
.lazy = true,
|
||||
},
|
||||
.zig_objc = .{
|
||||
// mitchellh/zig-objc
|
||||
.url = "https://github.com/mitchellh/zig-objc/archive/c8de82ff80281215ad92900866dab7103a8efa8b.tar.gz",
|
||||
.url = "https://deps.files.ghostty.org/zig_objc-c8de82ff80281215ad92900866dab7103a8efa8b.tar.gz",
|
||||
.hash = "zig_objc-0.0.0-Ir_Sp9gsAQCPAJc0oF5xoWePHWP6Y6tCphDeyNUThJoi",
|
||||
.lazy = true,
|
||||
},
|
||||
.zig_js = .{
|
||||
// mitchellh/zig-js
|
||||
.url = "https://github.com/mitchellh/zig-js/archive/3c23860e47fdcdc5af805efb7fd0bdac5fd3e9bc.tar.gz",
|
||||
.url = "https://deps.files.ghostty.org/zig_js-3c23860e47fdcdc5af805efb7fd0bdac5fd3e9bc.tar.gz",
|
||||
.hash = "zig_js-0.0.0-rjCAV7-GAADvMTBL7lPMuvDk7xgS9PCMIZWiOUXLZSlj",
|
||||
.lazy = true,
|
||||
},
|
||||
.uucode = .{
|
||||
// jacobsandlund/uucode
|
||||
.url = "https://github.com/jacobsandlund/uucode/archive/2826a37a4562284fdacd8fa029d49509cc9bffcd.tar.gz",
|
||||
.url = "https://deps.files.ghostty.org/uucode-2826a37a4562284fdacd8fa029d49509cc9bffcd.tar.gz",
|
||||
.hash = "uucode-0.2.0-ZZjBPlK5VADj7fdoq7G8LIHzD5o6FSkcBXXrRWr4jnrA",
|
||||
},
|
||||
.zig_wayland = .{
|
||||
// codeberg ifreund/zig-wayland
|
||||
.url = "https://codeberg.org/ifreund/zig-wayland/archive/v0.6.0.tar.gz",
|
||||
.url = "https://deps.files.ghostty.org/wayland-0.6.0-lQa1kqz8AQADQmdNJsNhLoNHcnEGEUjrOaPV-dtEnEmX.tar.gz",
|
||||
.hash = "wayland-0.6.0-lQa1kqz8AQADQmdNJsNhLoNHcnEGEUjrOaPV-dtEnEmX",
|
||||
.lazy = true,
|
||||
},
|
||||
.zf = .{
|
||||
// natecraddock/zf
|
||||
.url = "https://github.com/natecraddock/zf/archive/c35c421f84895193246db06c40683c1a30e616ef.tar.gz",
|
||||
.url = "https://deps.files.ghostty.org/zf-c35c421f84895193246db06c40683c1a30e616ef.tar.gz",
|
||||
.hash = "zf-0.11.0-OIRy8X-RAAAwaRXHMYpj2uvBnuGTZWEE_3V7acqHQNtW",
|
||||
.lazy = true,
|
||||
},
|
||||
.gobject = .{
|
||||
// https://github.com/ghostty-org/zig-gobject based on zig_gobject
|
||||
// Temporary until we generate them at build time automatically.
|
||||
.url = "https://github.com/ghostty-org/zig-gobject/releases/download/0.8.0-2026-04-23-26-1/ghostty-gobject-0.8.0-2026-04-23-26-1.tar.zst",
|
||||
.url = "https://deps.files.ghostty.org/gobject-2026-04-23-26-1.tar.zst",
|
||||
.hash = "gobject-0.3.1-Skun7E1KnwBGMX5nslHYG1yWHaSevywxQO8oM7tTOgIp",
|
||||
.lazy = true,
|
||||
},
|
||||
@@ -99,7 +99,7 @@
|
||||
.lazy = true,
|
||||
},
|
||||
.wayland_protocols = .{
|
||||
.url = "https://gitlab.freedesktop.org/wayland/wayland-protocols/-/archive/1.47/wayland-protocols-1.47.tar.gz",
|
||||
.url = "https://deps.files.ghostty.org/N-V-__8AAFdWDwA0ktbNUi9pFBHCRN4weXIgIfCrVjfGxqgA.tar.gz",
|
||||
.hash = "N-V-__8AAFdWDwA0ktbNUi9pFBHCRN4weXIgIfCrVjfGxqgA",
|
||||
.lazy = true,
|
||||
},
|
||||
|
||||
32
build.zig.zon.json
generated
32
build.zig.zon.json
generated
@@ -36,7 +36,7 @@
|
||||
},
|
||||
"gobject-0.3.1-Skun7E1KnwBGMX5nslHYG1yWHaSevywxQO8oM7tTOgIp": {
|
||||
"name": "gobject",
|
||||
"url": "https://github.com/ghostty-org/zig-gobject/releases/download/0.8.0-2026-04-23-26-1/ghostty-gobject-0.8.0-2026-04-23-26-1.tar.zst",
|
||||
"url": "https://deps.files.ghostty.org/gobject-2026-04-23-26-1.tar.zst",
|
||||
"hash": "sha256-cZGf9a1+sDeORKWYIdzQ/5KLT7l/9pgPc2cIbqfBc4o="
|
||||
},
|
||||
"N-V-__8AALiNBAA-_0gprYr92CjrMj1I5bqNu0TSJOnjFNSr": {
|
||||
@@ -56,7 +56,7 @@
|
||||
},
|
||||
"N-V-__8AAEbOfQBnvcFcCX2W5z7tDaN8vaNZGamEQtNOe0UI": {
|
||||
"name": "imgui",
|
||||
"url": "https://github.com/ocornut/imgui/archive/refs/tags/v1.92.5-docking.tar.gz",
|
||||
"url": "https://deps.files.ghostty.org/N-V-__8AAEbOfQBnvcFcCX2W5z7tDaN8vaNZGamEQtNOe0UI.tar.gz",
|
||||
"hash": "sha256-yBbCDox18+Fa6Gc1DnmSVQLRpqhZOLsac7iSfl8x+cs="
|
||||
},
|
||||
"N-V-__8AALZGBAAS5NLVH-c8eC-6VtCdcH-9nUvVfUSkWS__": {
|
||||
@@ -76,7 +76,7 @@
|
||||
},
|
||||
"libxev-0.0.0-86vtcwIRFADbH4hk-EjROXxlrKIRPQdA41XiTSytYO-F": {
|
||||
"name": "libxev",
|
||||
"url": "https://github.com/mitchellh/libxev/archive/9ce8e8e6ff89e583258a7f8e7adeeeaeae8611bf.tar.gz",
|
||||
"url": "https://deps.files.ghostty.org/libxev-9ce8e8e6ff89e583258a7f8e7adeeeaeae8611bf.tar.gz",
|
||||
"hash": "sha256-fOU1oxIxfoEgoLuWz7fVX6M+zmqpo7gqZObWiH/aDE0="
|
||||
},
|
||||
"N-V-__8AAG3RoQEyRC2Vw7Qoro5SYBf62IHn3HjqtNVY6aWK": {
|
||||
@@ -116,12 +116,12 @@
|
||||
},
|
||||
"translate_c-0.0.0-Q_BUWj8_BwCr4na219OimiKKj4IVSq0aKtMXCQmIk4AB": {
|
||||
"name": "translate_c",
|
||||
"url": "https://codeberg.org/vancluever/translate-c/archive/a916baf225a3cfc93a982225462db612604ae290.tar.gz",
|
||||
"url": "https://deps.files.ghostty.org/translate_c-a916baf225a3cfc93a982225462db612604ae290.tar.gz",
|
||||
"hash": "sha256-i7TSSiLU9YGtLtEjgVqy2jSnKLDTeKHX+EFuXEMXJ+U="
|
||||
},
|
||||
"uucode-0.2.0-ZZjBPlK5VADj7fdoq7G8LIHzD5o6FSkcBXXrRWr4jnrA": {
|
||||
"name": "uucode",
|
||||
"url": "https://github.com/jacobsandlund/uucode/archive/2826a37a4562284fdacd8fa029d49509cc9bffcd.tar.gz",
|
||||
"url": "https://deps.files.ghostty.org/uucode-2826a37a4562284fdacd8fa029d49509cc9bffcd.tar.gz",
|
||||
"hash": "sha256-R5RXW5tWIaDq5JOF2+oWd5YOYOyns6WH7f687WE+b20="
|
||||
},
|
||||
"vaxis-0.6.0-BWNV_MjFCQCs9UDHiRkrgw_ayeiPkzOe4xVbaAqXkUWW": {
|
||||
@@ -131,7 +131,7 @@
|
||||
},
|
||||
"vaxis-0.6.0-BWNV_CrbCQCscGpzsAlR402rYQ_tV3aAl081c2iRRkka": {
|
||||
"name": "vaxis",
|
||||
"url": "https://github.com/rockorager/libvaxis/archive/1dbbe575dff4586fe51e3217aa5c3fecdcbb6089.tar.gz",
|
||||
"url": "https://deps.files.ghostty.org/vaxis-1dbbe575dff4586fe51e3217aa5c3fecdcbb6089.tar.gz",
|
||||
"hash": "sha256-z3J3w+oYapfAZZR+MvWXwg+th1hePDA1TptnKFO4r+M="
|
||||
},
|
||||
"N-V-__8AAKrHGAAs2shYq8UkE6bGcR1QJtLTyOE_lcosMn6t": {
|
||||
@@ -139,16 +139,16 @@
|
||||
"url": "https://deps.files.ghostty.org/wayland-9cb3d7aa9dc995ffafdbdef7ab86a949d0fb0e7d.tar.gz",
|
||||
"hash": "sha256-6kGR1o5DdnflHzqs3ieCmBAUTpMdOXoyfcYDXiw5xQ0="
|
||||
},
|
||||
"N-V-__8AAFdWDwA0ktbNUi9pFBHCRN4weXIgIfCrVjfGxqgA": {
|
||||
"name": "wayland_protocols",
|
||||
"url": "https://deps.files.ghostty.org/N-V-__8AAFdWDwA0ktbNUi9pFBHCRN4weXIgIfCrVjfGxqgA.tar.gz",
|
||||
"hash": "sha256-3S3xSrX0EDgleq7cxLX7msDuAY8/D5SvkJcCjmDTMiM="
|
||||
},
|
||||
"N-V-__8AAKw-DAAaV8bOAAGqA0-oD7o-HNIlPFYKRXSPT03S": {
|
||||
"name": "wayland_protocols",
|
||||
"url": "https://deps.files.ghostty.org/wayland-protocols-258d8f88f2c8c25a830c6316f87d23ce1a0f12d9.tar.gz",
|
||||
"hash": "sha256-XO3K3egbdeYPI+XoO13SuOtO+5+Peb16NH0UiusFMPg="
|
||||
},
|
||||
"N-V-__8AAFdWDwA0ktbNUi9pFBHCRN4weXIgIfCrVjfGxqgA": {
|
||||
"name": "wayland_protocols",
|
||||
"url": "https://gitlab.freedesktop.org/wayland/wayland-protocols/-/archive/1.47/wayland-protocols-1.47.tar.gz",
|
||||
"hash": "sha256-3S3xSrX0EDgleq7cxLX7msDuAY8/D5SvkJcCjmDTMiM="
|
||||
},
|
||||
"N-V-__8AAAzZywE3s51XfsLbP9eyEw57ae9swYB9aGB6fCMs": {
|
||||
"name": "wuffs",
|
||||
"url": "https://deps.files.ghostty.org/wuffs-122037b39d577ec2db3fd7b2130e7b69ef6cc1807d68607a7c232c958315d381b5cd.tar.gz",
|
||||
@@ -156,27 +156,27 @@
|
||||
},
|
||||
"z2d-0.11.0-j5P_HtLzDwBGyQt49DrT0v4BuVqI_SRs6CXsuj7eBVhR": {
|
||||
"name": "z2d",
|
||||
"url": "https://github.com/vancluever/z2d/archive/refs/tags/v0.11.0.tar.gz",
|
||||
"url": "https://deps.files.ghostty.org/z2d-0.11.0-j5P_HtLzDwBGyQt49DrT0v4BuVqI_SRs6CXsuj7eBVhR.tar.gz",
|
||||
"hash": "sha256-/Yje2P+ro7IrPodQ26YKk7RsPSYj1Cqx6bdrmykXEKA="
|
||||
},
|
||||
"zf-0.11.0-OIRy8X-RAAAwaRXHMYpj2uvBnuGTZWEE_3V7acqHQNtW": {
|
||||
"name": "zf",
|
||||
"url": "https://github.com/natecraddock/zf/archive/c35c421f84895193246db06c40683c1a30e616ef.tar.gz",
|
||||
"url": "https://deps.files.ghostty.org/zf-c35c421f84895193246db06c40683c1a30e616ef.tar.gz",
|
||||
"hash": "sha256-LHurWwqK8jhP8AZd/CXrMJNeVsKftRCTN31/EgEgKaA="
|
||||
},
|
||||
"zig_js-0.0.0-rjCAV7-GAADvMTBL7lPMuvDk7xgS9PCMIZWiOUXLZSlj": {
|
||||
"name": "zig_js",
|
||||
"url": "https://github.com/mitchellh/zig-js/archive/3c23860e47fdcdc5af805efb7fd0bdac5fd3e9bc.tar.gz",
|
||||
"url": "https://deps.files.ghostty.org/zig_js-3c23860e47fdcdc5af805efb7fd0bdac5fd3e9bc.tar.gz",
|
||||
"hash": "sha256-Q1643wb/MCX0QkPa9QEY9xeQbqpC2IOrjER0ZyL3mH0="
|
||||
},
|
||||
"zig_objc-0.0.0-Ir_Sp9gsAQCPAJc0oF5xoWePHWP6Y6tCphDeyNUThJoi": {
|
||||
"name": "zig_objc",
|
||||
"url": "https://github.com/mitchellh/zig-objc/archive/c8de82ff80281215ad92900866dab7103a8efa8b.tar.gz",
|
||||
"url": "https://deps.files.ghostty.org/zig_objc-c8de82ff80281215ad92900866dab7103a8efa8b.tar.gz",
|
||||
"hash": "sha256-t8cTTJm0crcoGAyOqXO0wB2w7Yit80J2Orwr6prd/G0="
|
||||
},
|
||||
"wayland-0.6.0-lQa1kqz8AQADQmdNJsNhLoNHcnEGEUjrOaPV-dtEnEmX": {
|
||||
"name": "zig_wayland",
|
||||
"url": "https://codeberg.org/ifreund/zig-wayland/archive/v0.6.0.tar.gz",
|
||||
"url": "https://deps.files.ghostty.org/wayland-0.6.0-lQa1kqz8AQADQmdNJsNhLoNHcnEGEUjrOaPV-dtEnEmX.tar.gz",
|
||||
"hash": "sha256-3m/ITNhZUJ/5uD/Tqm+0uZSktGoYgWF5oldOqOCUkIE="
|
||||
},
|
||||
"zigimg-0.1.0-8_eo2oyaFwBZwJpmqPkCfVXWBrHcqbYwmrp1I6bTD3lI": {
|
||||
|
||||
40
build.zig.zon.nix
generated
40
build.zig.zon.nix
generated
@@ -164,7 +164,7 @@ in
|
||||
name = "gobject-0.3.1-Skun7E1KnwBGMX5nslHYG1yWHaSevywxQO8oM7tTOgIp";
|
||||
path = fetchZigArtifact {
|
||||
name = "gobject";
|
||||
url = "https://github.com/ghostty-org/zig-gobject/releases/download/0.8.0-2026-04-23-26-1/ghostty-gobject-0.8.0-2026-04-23-26-1.tar.zst";
|
||||
url = "https://deps.files.ghostty.org/gobject-2026-04-23-26-1.tar.zst";
|
||||
hash = "sha256-cZGf9a1+sDeORKWYIdzQ/5KLT7l/9pgPc2cIbqfBc4o=";
|
||||
unpack = true;
|
||||
};
|
||||
@@ -200,7 +200,7 @@ in
|
||||
name = "N-V-__8AAEbOfQBnvcFcCX2W5z7tDaN8vaNZGamEQtNOe0UI";
|
||||
path = fetchZigArtifact {
|
||||
name = "imgui";
|
||||
url = "https://github.com/ocornut/imgui/archive/refs/tags/v1.92.5-docking.tar.gz";
|
||||
url = "https://deps.files.ghostty.org/N-V-__8AAEbOfQBnvcFcCX2W5z7tDaN8vaNZGamEQtNOe0UI.tar.gz";
|
||||
hash = "sha256-yBbCDox18+Fa6Gc1DnmSVQLRpqhZOLsac7iSfl8x+cs=";
|
||||
unpack = false;
|
||||
};
|
||||
@@ -236,7 +236,7 @@ in
|
||||
name = "libxev-0.0.0-86vtcwIRFADbH4hk-EjROXxlrKIRPQdA41XiTSytYO-F";
|
||||
path = fetchZigArtifact {
|
||||
name = "libxev";
|
||||
url = "https://github.com/mitchellh/libxev/archive/9ce8e8e6ff89e583258a7f8e7adeeeaeae8611bf.tar.gz";
|
||||
url = "https://deps.files.ghostty.org/libxev-9ce8e8e6ff89e583258a7f8e7adeeeaeae8611bf.tar.gz";
|
||||
hash = "sha256-fOU1oxIxfoEgoLuWz7fVX6M+zmqpo7gqZObWiH/aDE0=";
|
||||
unpack = true;
|
||||
};
|
||||
@@ -308,7 +308,7 @@ in
|
||||
name = "translate_c-0.0.0-Q_BUWj8_BwCr4na219OimiKKj4IVSq0aKtMXCQmIk4AB";
|
||||
path = fetchZigArtifact {
|
||||
name = "translate_c";
|
||||
url = "https://codeberg.org/vancluever/translate-c/archive/a916baf225a3cfc93a982225462db612604ae290.tar.gz";
|
||||
url = "https://deps.files.ghostty.org/translate_c-a916baf225a3cfc93a982225462db612604ae290.tar.gz";
|
||||
hash = "sha256-i7TSSiLU9YGtLtEjgVqy2jSnKLDTeKHX+EFuXEMXJ+U=";
|
||||
unpack = true;
|
||||
};
|
||||
@@ -317,7 +317,7 @@ in
|
||||
name = "uucode-0.2.0-ZZjBPlK5VADj7fdoq7G8LIHzD5o6FSkcBXXrRWr4jnrA";
|
||||
path = fetchZigArtifact {
|
||||
name = "uucode";
|
||||
url = "https://github.com/jacobsandlund/uucode/archive/2826a37a4562284fdacd8fa029d49509cc9bffcd.tar.gz";
|
||||
url = "https://deps.files.ghostty.org/uucode-2826a37a4562284fdacd8fa029d49509cc9bffcd.tar.gz";
|
||||
hash = "sha256-R5RXW5tWIaDq5JOF2+oWd5YOYOyns6WH7f687WE+b20=";
|
||||
unpack = true;
|
||||
};
|
||||
@@ -335,7 +335,7 @@ in
|
||||
name = "vaxis-0.6.0-BWNV_CrbCQCscGpzsAlR402rYQ_tV3aAl081c2iRRkka";
|
||||
path = fetchZigArtifact {
|
||||
name = "vaxis";
|
||||
url = "https://github.com/rockorager/libvaxis/archive/1dbbe575dff4586fe51e3217aa5c3fecdcbb6089.tar.gz";
|
||||
url = "https://deps.files.ghostty.org/vaxis-1dbbe575dff4586fe51e3217aa5c3fecdcbb6089.tar.gz";
|
||||
hash = "sha256-z3J3w+oYapfAZZR+MvWXwg+th1hePDA1TptnKFO4r+M=";
|
||||
unpack = true;
|
||||
};
|
||||
@@ -349,6 +349,15 @@ in
|
||||
unpack = false;
|
||||
};
|
||||
}
|
||||
{
|
||||
name = "N-V-__8AAFdWDwA0ktbNUi9pFBHCRN4weXIgIfCrVjfGxqgA";
|
||||
path = fetchZigArtifact {
|
||||
name = "wayland_protocols";
|
||||
url = "https://deps.files.ghostty.org/N-V-__8AAFdWDwA0ktbNUi9pFBHCRN4weXIgIfCrVjfGxqgA.tar.gz";
|
||||
hash = "sha256-3S3xSrX0EDgleq7cxLX7msDuAY8/D5SvkJcCjmDTMiM=";
|
||||
unpack = false;
|
||||
};
|
||||
}
|
||||
{
|
||||
name = "N-V-__8AAKw-DAAaV8bOAAGqA0-oD7o-HNIlPFYKRXSPT03S";
|
||||
path = fetchZigArtifact {
|
||||
@@ -358,15 +367,6 @@ in
|
||||
unpack = false;
|
||||
};
|
||||
}
|
||||
{
|
||||
name = "N-V-__8AAFdWDwA0ktbNUi9pFBHCRN4weXIgIfCrVjfGxqgA";
|
||||
path = fetchZigArtifact {
|
||||
name = "wayland_protocols";
|
||||
url = "https://gitlab.freedesktop.org/wayland/wayland-protocols/-/archive/1.47/wayland-protocols-1.47.tar.gz";
|
||||
hash = "sha256-3S3xSrX0EDgleq7cxLX7msDuAY8/D5SvkJcCjmDTMiM=";
|
||||
unpack = false;
|
||||
};
|
||||
}
|
||||
{
|
||||
name = "N-V-__8AAAzZywE3s51XfsLbP9eyEw57ae9swYB9aGB6fCMs";
|
||||
path = fetchZigArtifact {
|
||||
@@ -380,7 +380,7 @@ in
|
||||
name = "z2d-0.11.0-j5P_HtLzDwBGyQt49DrT0v4BuVqI_SRs6CXsuj7eBVhR";
|
||||
path = fetchZigArtifact {
|
||||
name = "z2d";
|
||||
url = "https://github.com/vancluever/z2d/archive/refs/tags/v0.11.0.tar.gz";
|
||||
url = "https://deps.files.ghostty.org/z2d-0.11.0-j5P_HtLzDwBGyQt49DrT0v4BuVqI_SRs6CXsuj7eBVhR.tar.gz";
|
||||
hash = "sha256-/Yje2P+ro7IrPodQ26YKk7RsPSYj1Cqx6bdrmykXEKA=";
|
||||
unpack = true;
|
||||
};
|
||||
@@ -389,7 +389,7 @@ in
|
||||
name = "zf-0.11.0-OIRy8X-RAAAwaRXHMYpj2uvBnuGTZWEE_3V7acqHQNtW";
|
||||
path = fetchZigArtifact {
|
||||
name = "zf";
|
||||
url = "https://github.com/natecraddock/zf/archive/c35c421f84895193246db06c40683c1a30e616ef.tar.gz";
|
||||
url = "https://deps.files.ghostty.org/zf-c35c421f84895193246db06c40683c1a30e616ef.tar.gz";
|
||||
hash = "sha256-LHurWwqK8jhP8AZd/CXrMJNeVsKftRCTN31/EgEgKaA=";
|
||||
unpack = true;
|
||||
};
|
||||
@@ -398,7 +398,7 @@ in
|
||||
name = "zig_js-0.0.0-rjCAV7-GAADvMTBL7lPMuvDk7xgS9PCMIZWiOUXLZSlj";
|
||||
path = fetchZigArtifact {
|
||||
name = "zig_js";
|
||||
url = "https://github.com/mitchellh/zig-js/archive/3c23860e47fdcdc5af805efb7fd0bdac5fd3e9bc.tar.gz";
|
||||
url = "https://deps.files.ghostty.org/zig_js-3c23860e47fdcdc5af805efb7fd0bdac5fd3e9bc.tar.gz";
|
||||
hash = "sha256-Q1643wb/MCX0QkPa9QEY9xeQbqpC2IOrjER0ZyL3mH0=";
|
||||
unpack = true;
|
||||
};
|
||||
@@ -407,7 +407,7 @@ in
|
||||
name = "zig_objc-0.0.0-Ir_Sp9gsAQCPAJc0oF5xoWePHWP6Y6tCphDeyNUThJoi";
|
||||
path = fetchZigArtifact {
|
||||
name = "zig_objc";
|
||||
url = "https://github.com/mitchellh/zig-objc/archive/c8de82ff80281215ad92900866dab7103a8efa8b.tar.gz";
|
||||
url = "https://deps.files.ghostty.org/zig_objc-c8de82ff80281215ad92900866dab7103a8efa8b.tar.gz";
|
||||
hash = "sha256-t8cTTJm0crcoGAyOqXO0wB2w7Yit80J2Orwr6prd/G0=";
|
||||
unpack = true;
|
||||
};
|
||||
@@ -416,7 +416,7 @@ in
|
||||
name = "wayland-0.6.0-lQa1kqz8AQADQmdNJsNhLoNHcnEGEUjrOaPV-dtEnEmX";
|
||||
path = fetchZigArtifact {
|
||||
name = "zig_wayland";
|
||||
url = "https://codeberg.org/ifreund/zig-wayland/archive/v0.6.0.tar.gz";
|
||||
url = "https://deps.files.ghostty.org/wayland-0.6.0-lQa1kqz8AQADQmdNJsNhLoNHcnEGEUjrOaPV-dtEnEmX.tar.gz";
|
||||
hash = "sha256-3m/ITNhZUJ/5uD/Tqm+0uZSktGoYgWF5oldOqOCUkIE=";
|
||||
unpack = true;
|
||||
};
|
||||
|
||||
24
build.zig.zon.txt
generated
24
build.zig.zon.txt
generated
@@ -1,9 +1,9 @@
|
||||
git+https://github.com/rockorager/libvaxis.git#c1e1f23be38951c425cdf31af455ba23ef178940
|
||||
git+https://github.com/zigimg/zigimg#d695acd97c02e57bb151e8f659d1280f5cd6ca70
|
||||
https://codeberg.org/ifreund/zig-wayland/archive/v0.6.0.tar.gz
|
||||
https://codeberg.org/vancluever/translate-c/archive/a916baf225a3cfc93a982225462db612604ae290.tar.gz
|
||||
https://deps.files.ghostty.org/DearBindings_v0.17_ImGui_v1.92.5-docking.tar.gz
|
||||
https://deps.files.ghostty.org/JetBrainsMono-2.304.tar.gz
|
||||
https://deps.files.ghostty.org/N-V-__8AAEbOfQBnvcFcCX2W5z7tDaN8vaNZGamEQtNOe0UI.tar.gz
|
||||
https://deps.files.ghostty.org/N-V-__8AAFdWDwA0ktbNUi9pFBHCRN4weXIgIfCrVjfGxqgA.tar.gz
|
||||
https://deps.files.ghostty.org/NerdFontsSymbolsOnly-3.4.0.tar.gz
|
||||
https://deps.files.ghostty.org/breakpad-b99f444ba5f6b98cac261cbb391d8766b34a5918.tar.gz
|
||||
https://deps.files.ghostty.org/fontconfig-2.14.2.tar.gz
|
||||
@@ -11,28 +11,28 @@ https://deps.files.ghostty.org/freetype-1220b81f6ecfb3fd222f76cf9106fecfa6554ab0
|
||||
https://deps.files.ghostty.org/gettext-0.24.tar.gz
|
||||
https://deps.files.ghostty.org/ghostty-themes-release-20260713-155359-c3968b3.tgz
|
||||
https://deps.files.ghostty.org/glslang-12201278a1a05c0ce0b6eb6026c65cd3e9247aa041b1c260324bf29cee559dd23ba1.tar.gz
|
||||
https://deps.files.ghostty.org/gobject-2026-04-23-26-1.tar.zst
|
||||
https://deps.files.ghostty.org/gtk4-layer-shell-1.1.0.tar.gz
|
||||
https://deps.files.ghostty.org/harfbuzz-11.0.0.tar.xz
|
||||
https://deps.files.ghostty.org/highway-66486a10623fa0d72fe91260f96c892e41aceb06.tar.gz
|
||||
https://deps.files.ghostty.org/libpng-1220aa013f0c83da3fb64ea6d327f9173fa008d10e28bc9349eac3463457723b1c66.tar.gz
|
||||
https://deps.files.ghostty.org/libxev-9ce8e8e6ff89e583258a7f8e7adeeeaeae8611bf.tar.gz
|
||||
https://deps.files.ghostty.org/libxml2-2.11.5.tar.gz
|
||||
https://deps.files.ghostty.org/oniguruma-1220c15e72eadd0d9085a8af134904d9a0f5dfcbed5f606ad60edc60ebeccd9706bb.tar.gz
|
||||
https://deps.files.ghostty.org/pixels-12207ff340169c7d40c570b4b6a97db614fe47e0d83b5801a932dcd44917424c8806.tar.gz
|
||||
https://deps.files.ghostty.org/plasma_wayland_protocols-12207e0851c12acdeee0991e893e0132fc87bb763969a585dc16ecca33e88334c566.tar.gz
|
||||
https://deps.files.ghostty.org/sentry-1220446be831adcca918167647c06c7b825849fa3fba5f22da394667974537a9c77e.tar.gz
|
||||
https://deps.files.ghostty.org/spirv_cross-1220fb3b5586e8be67bc3feb34cbe749cf42a60d628d2953632c2f8141302748c8da.tar.gz
|
||||
https://deps.files.ghostty.org/translate_c-a916baf225a3cfc93a982225462db612604ae290.tar.gz
|
||||
https://deps.files.ghostty.org/uucode-2826a37a4562284fdacd8fa029d49509cc9bffcd.tar.gz
|
||||
https://deps.files.ghostty.org/vaxis-1dbbe575dff4586fe51e3217aa5c3fecdcbb6089.tar.gz
|
||||
https://deps.files.ghostty.org/wayland-0.6.0-lQa1kqz8AQADQmdNJsNhLoNHcnEGEUjrOaPV-dtEnEmX.tar.gz
|
||||
https://deps.files.ghostty.org/wayland-9cb3d7aa9dc995ffafdbdef7ab86a949d0fb0e7d.tar.gz
|
||||
https://deps.files.ghostty.org/wayland-protocols-258d8f88f2c8c25a830c6316f87d23ce1a0f12d9.tar.gz
|
||||
https://deps.files.ghostty.org/wuffs-122037b39d577ec2db3fd7b2130e7b69ef6cc1807d68607a7c232c958315d381b5cd.tar.gz
|
||||
https://deps.files.ghostty.org/z2d-0.11.0-j5P_HtLzDwBGyQt49DrT0v4BuVqI_SRs6CXsuj7eBVhR.tar.gz
|
||||
https://deps.files.ghostty.org/zf-c35c421f84895193246db06c40683c1a30e616ef.tar.gz
|
||||
https://deps.files.ghostty.org/zig_js-3c23860e47fdcdc5af805efb7fd0bdac5fd3e9bc.tar.gz
|
||||
https://deps.files.ghostty.org/zig_objc-c8de82ff80281215ad92900866dab7103a8efa8b.tar.gz
|
||||
https://deps.files.ghostty.org/zlib-1220fed0c74e1019b3ee29edae2051788b080cd96e90d56836eea857b0b966742efb.tar.gz
|
||||
https://github.com/ghostty-org/zig-gobject/releases/download/0.8.0-2026-04-23-26-1/ghostty-gobject-0.8.0-2026-04-23-26-1.tar.zst
|
||||
https://github.com/jacobsandlund/uucode/archive/2826a37a4562284fdacd8fa029d49509cc9bffcd.tar.gz
|
||||
https://github.com/mitchellh/libxev/archive/9ce8e8e6ff89e583258a7f8e7adeeeaeae8611bf.tar.gz
|
||||
https://github.com/mitchellh/zig-js/archive/3c23860e47fdcdc5af805efb7fd0bdac5fd3e9bc.tar.gz
|
||||
https://github.com/mitchellh/zig-objc/archive/c8de82ff80281215ad92900866dab7103a8efa8b.tar.gz
|
||||
https://github.com/natecraddock/zf/archive/c35c421f84895193246db06c40683c1a30e616ef.tar.gz
|
||||
https://github.com/ocornut/imgui/archive/refs/tags/v1.92.5-docking.tar.gz
|
||||
https://github.com/rockorager/libvaxis/archive/1dbbe575dff4586fe51e3217aa5c3fecdcbb6089.tar.gz
|
||||
https://github.com/vancluever/arocc/archive/ecbc5c799574e0da2758a961b12efa586007f03c.tar.gz
|
||||
https://github.com/vancluever/z2d/archive/refs/tags/v0.11.0.tar.gz
|
||||
https://gitlab.freedesktop.org/wayland/wayland-protocols/-/archive/1.47/wayland-protocols-1.47.tar.gz
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
},
|
||||
{
|
||||
"type": "archive",
|
||||
"url": "https://github.com/ghostty-org/zig-gobject/releases/download/0.8.0-2026-04-23-26-1/ghostty-gobject-0.8.0-2026-04-23-26-1.tar.zst",
|
||||
"url": "https://deps.files.ghostty.org/gobject-2026-04-23-26-1.tar.zst",
|
||||
"dest": "vendor/p/gobject-0.3.1-Skun7E1KnwBGMX5nslHYG1yWHaSevywxQO8oM7tTOgIp",
|
||||
"sha256": "642e324b3644c00464a2161e4af497f73cbbe8ce02a4c0edb92aacb365748047"
|
||||
},
|
||||
@@ -67,7 +67,7 @@
|
||||
},
|
||||
{
|
||||
"type": "archive",
|
||||
"url": "https://github.com/ocornut/imgui/archive/refs/tags/v1.92.5-docking.tar.gz",
|
||||
"url": "https://deps.files.ghostty.org/N-V-__8AAEbOfQBnvcFcCX2W5z7tDaN8vaNZGamEQtNOe0UI.tar.gz",
|
||||
"dest": "vendor/p/N-V-__8AAEbOfQBnvcFcCX2W5z7tDaN8vaNZGamEQtNOe0UI",
|
||||
"sha256": "c816c20e8c75f3e15ae867350e79925502d1a6a85938bb1a73b8927e5f31f9cb"
|
||||
},
|
||||
@@ -91,7 +91,7 @@
|
||||
},
|
||||
{
|
||||
"type": "archive",
|
||||
"url": "https://github.com/mitchellh/libxev/archive/9ce8e8e6ff89e583258a7f8e7adeeeaeae8611bf.tar.gz",
|
||||
"url": "https://deps.files.ghostty.org/libxev-9ce8e8e6ff89e583258a7f8e7adeeeaeae8611bf.tar.gz",
|
||||
"dest": "vendor/p/libxev-0.0.0-86vtcwIRFADbH4hk-EjROXxlrKIRPQdA41XiTSytYO-F",
|
||||
"sha256": "e2b9b224cd78101156abb8f46479a51f6cce66c4815c632856e20a1440dd02b7"
|
||||
},
|
||||
@@ -139,13 +139,13 @@
|
||||
},
|
||||
{
|
||||
"type": "archive",
|
||||
"url": "https://codeberg.org/vancluever/translate-c/archive/a916baf225a3cfc93a982225462db612604ae290.tar.gz",
|
||||
"url": "https://deps.files.ghostty.org/translate_c-a916baf225a3cfc93a982225462db612604ae290.tar.gz",
|
||||
"dest": "vendor/p/translate_c-0.0.0-Q_BUWj8_BwCr4na219OimiKKj4IVSq0aKtMXCQmIk4AB",
|
||||
"sha256": "4fd2a2b21dbc49c22bea6854a59a7568dc77183760531ace3cf8da1267696afd"
|
||||
},
|
||||
{
|
||||
"type": "archive",
|
||||
"url": "https://github.com/jacobsandlund/uucode/archive/2826a37a4562284fdacd8fa029d49509cc9bffcd.tar.gz",
|
||||
"url": "https://deps.files.ghostty.org/uucode-2826a37a4562284fdacd8fa029d49509cc9bffcd.tar.gz",
|
||||
"dest": "vendor/p/uucode-0.2.0-ZZjBPlK5VADj7fdoq7G8LIHzD5o6FSkcBXXrRWr4jnrA",
|
||||
"sha256": "7e76fc7fab1e7ac728c52b35bbb3e5b8c639841abfc7fe1a4bcb13050594bc9e"
|
||||
},
|
||||
@@ -157,7 +157,7 @@
|
||||
},
|
||||
{
|
||||
"type": "archive",
|
||||
"url": "https://github.com/rockorager/libvaxis/archive/1dbbe575dff4586fe51e3217aa5c3fecdcbb6089.tar.gz",
|
||||
"url": "https://deps.files.ghostty.org/vaxis-1dbbe575dff4586fe51e3217aa5c3fecdcbb6089.tar.gz",
|
||||
"dest": "vendor/p/vaxis-0.6.0-BWNV_CrbCQCscGpzsAlR402rYQ_tV3aAl081c2iRRkka",
|
||||
"sha256": "3ea050e905887c46bca1a2c18e41d6edf574c1aa6ebfbc5cf3c52846275e4fa8"
|
||||
},
|
||||
@@ -169,15 +169,15 @@
|
||||
},
|
||||
{
|
||||
"type": "archive",
|
||||
"url": "https://deps.files.ghostty.org/wayland-protocols-258d8f88f2c8c25a830c6316f87d23ce1a0f12d9.tar.gz",
|
||||
"dest": "vendor/p/N-V-__8AAKw-DAAaV8bOAAGqA0-oD7o-HNIlPFYKRXSPT03S",
|
||||
"sha256": "5cedcadde81b75e60f23e5e83b5dd2b8eb4efb9f8f79bd7a347d148aeb0530f8"
|
||||
"url": "https://deps.files.ghostty.org/N-V-__8AAFdWDwA0ktbNUi9pFBHCRN4weXIgIfCrVjfGxqgA.tar.gz",
|
||||
"dest": "vendor/p/N-V-__8AAFdWDwA0ktbNUi9pFBHCRN4weXIgIfCrVjfGxqgA",
|
||||
"sha256": "dd2df14ab5f41038257aaedcc4b5fb9ac0ee018f3f0f94af9097028e60d33223"
|
||||
},
|
||||
{
|
||||
"type": "archive",
|
||||
"url": "https://gitlab.freedesktop.org/wayland/wayland-protocols/-/archive/1.47/wayland-protocols-1.47.tar.gz",
|
||||
"dest": "vendor/p/N-V-__8AAFdWDwA0ktbNUi9pFBHCRN4weXIgIfCrVjfGxqgA",
|
||||
"sha256": "dd2df14ab5f41038257aaedcc4b5fb9ac0ee018f3f0f94af9097028e60d33223"
|
||||
"url": "https://deps.files.ghostty.org/wayland-protocols-258d8f88f2c8c25a830c6316f87d23ce1a0f12d9.tar.gz",
|
||||
"dest": "vendor/p/N-V-__8AAKw-DAAaV8bOAAGqA0-oD7o-HNIlPFYKRXSPT03S",
|
||||
"sha256": "5cedcadde81b75e60f23e5e83b5dd2b8eb4efb9f8f79bd7a347d148aeb0530f8"
|
||||
},
|
||||
{
|
||||
"type": "archive",
|
||||
@@ -187,31 +187,31 @@
|
||||
},
|
||||
{
|
||||
"type": "archive",
|
||||
"url": "https://github.com/vancluever/z2d/archive/refs/tags/v0.11.0.tar.gz",
|
||||
"url": "https://deps.files.ghostty.org/z2d-0.11.0-j5P_HtLzDwBGyQt49DrT0v4BuVqI_SRs6CXsuj7eBVhR.tar.gz",
|
||||
"dest": "vendor/p/z2d-0.11.0-j5P_HtLzDwBGyQt49DrT0v4BuVqI_SRs6CXsuj7eBVhR",
|
||||
"sha256": "d48b117307f767ca379bf31bd171880e66dcafb89eca4a8f923222619992fcb4"
|
||||
},
|
||||
{
|
||||
"type": "archive",
|
||||
"url": "https://github.com/natecraddock/zf/archive/c35c421f84895193246db06c40683c1a30e616ef.tar.gz",
|
||||
"url": "https://deps.files.ghostty.org/zf-c35c421f84895193246db06c40683c1a30e616ef.tar.gz",
|
||||
"dest": "vendor/p/zf-0.11.0-OIRy8X-RAAAwaRXHMYpj2uvBnuGTZWEE_3V7acqHQNtW",
|
||||
"sha256": "ca4bc109fd9d97cedae2f5bdb879cc78c346d43c14a34e3a2abd2ee9208c8547"
|
||||
},
|
||||
{
|
||||
"type": "archive",
|
||||
"url": "https://github.com/mitchellh/zig-js/archive/3c23860e47fdcdc5af805efb7fd0bdac5fd3e9bc.tar.gz",
|
||||
"url": "https://deps.files.ghostty.org/zig_js-3c23860e47fdcdc5af805efb7fd0bdac5fd3e9bc.tar.gz",
|
||||
"dest": "vendor/p/zig_js-0.0.0-rjCAV7-GAADvMTBL7lPMuvDk7xgS9PCMIZWiOUXLZSlj",
|
||||
"sha256": "a2ff488a244301f4e59469a5232aad6869b01acc50f7d7ed2647c029a57d4b3b"
|
||||
},
|
||||
{
|
||||
"type": "archive",
|
||||
"url": "https://github.com/mitchellh/zig-objc/archive/c8de82ff80281215ad92900866dab7103a8efa8b.tar.gz",
|
||||
"url": "https://deps.files.ghostty.org/zig_objc-c8de82ff80281215ad92900866dab7103a8efa8b.tar.gz",
|
||||
"dest": "vendor/p/zig_objc-0.0.0-Ir_Sp9gsAQCPAJc0oF5xoWePHWP6Y6tCphDeyNUThJoi",
|
||||
"sha256": "831eaec554bb23ef20229f1e705d8f53e8a29c829840bb8d0f5edb05c76d6df0"
|
||||
},
|
||||
{
|
||||
"type": "archive",
|
||||
"url": "https://codeberg.org/ifreund/zig-wayland/archive/v0.6.0.tar.gz",
|
||||
"url": "https://deps.files.ghostty.org/wayland-0.6.0-lQa1kqz8AQADQmdNJsNhLoNHcnEGEUjrOaPV-dtEnEmX.tar.gz",
|
||||
"dest": "vendor/p/wayland-0.6.0-lQa1kqz8AQADQmdNJsNhLoNHcnEGEUjrOaPV-dtEnEmX",
|
||||
"sha256": "759a632e36a948e0e412d2d74a43a69d2f34e65d40289a16af7aa3725852ef25"
|
||||
},
|
||||
|
||||
@@ -2,23 +2,34 @@
|
||||
|
||||
# This script downloads external dependencies from build.zig.zon.json that
|
||||
# are not already mirrored at deps.files.ghostty.org, saves them to a local
|
||||
# directory, and updates build.zig.zon to point to the new mirror URLs.
|
||||
# directory, and updates the build.zig.zon files (the root one as well as
|
||||
# every pkg/*/build.zig.zon) to point to the new mirror URLs.
|
||||
#
|
||||
# The downloaded files are unmodified so their checksums and content hashes
|
||||
# will match the originals.
|
||||
#
|
||||
# After running this script, the files in the output directory can be uploaded
|
||||
# to blob storage, and build.zig.zon will already be updated with the new URLs.
|
||||
# to blob storage, and the build.zig.zon files will already be updated with
|
||||
# the new URLs.
|
||||
def main [
|
||||
--output: string = "tmp-mirror", # Output directory for the mirrored files
|
||||
--prefix: string = "https://deps.files.ghostty.org/", # Final URL prefix to ignore
|
||||
--dry-run, # Print what would be downloaded without downloading
|
||||
] {
|
||||
let script_dir = ($env.CURRENT_FILE | path dirname)
|
||||
let input_file = ($script_dir | path join ".." ".." "build.zig.zon.json")
|
||||
let zon_file = ($script_dir | path join ".." ".." "build.zig.zon")
|
||||
let root_dir = ($script_dir | path join ".." ".." | path expand)
|
||||
let input_file = ($root_dir | path join "build.zig.zon.json")
|
||||
let output_dir = $output
|
||||
|
||||
# All build.zig.zon files that may reference external URLs: the root
|
||||
# one plus every package under pkg/. build.zig.zon.json is generated
|
||||
# from the full dependency tree so it covers all of these.
|
||||
let zon_files = (
|
||||
[($root_dir | path join "build.zig.zon")]
|
||||
| append (glob ($root_dir | path join "pkg" "*" "build.zig.zon"))
|
||||
| sort
|
||||
)
|
||||
|
||||
# Ensure the output directory exists
|
||||
mkdir $output_dir
|
||||
|
||||
@@ -75,22 +86,34 @@ def main [
|
||||
|
||||
if $dry_run {
|
||||
print "Dry run complete - no files were downloaded\n"
|
||||
print $"Would update ($url_replacements | length) URLs in build.zig.zon"
|
||||
} else {
|
||||
print "All dependencies downloaded successfully\n"
|
||||
print $"Updating ($zon_file)..."
|
||||
|
||||
# Backup the old file
|
||||
let backup_file = $"($zon_file).bak"
|
||||
cp $zon_file $backup_file
|
||||
print $"Backed up to ($backup_file)"
|
||||
|
||||
mut zon_content = (open $zon_file)
|
||||
for replacement in $url_replacements {
|
||||
$zon_content = ($zon_content | str replace $replacement.old $replacement.new)
|
||||
}
|
||||
$zon_content | save -f $zon_file
|
||||
}
|
||||
|
||||
print $"Updated ($url_replacements | length) URLs in build.zig.zon"
|
||||
# Apply the URL replacements to every build.zig.zon that references them.
|
||||
for zon_file in $zon_files {
|
||||
mut zon_content = (open --raw $zon_file)
|
||||
mut count = 0
|
||||
for replacement in $url_replacements {
|
||||
if ($zon_content | str contains $replacement.old) {
|
||||
$zon_content = ($zon_content | str replace --all $replacement.old $replacement.new)
|
||||
$count = $count + 1
|
||||
}
|
||||
}
|
||||
|
||||
if $count == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
let relative_path = ($zon_file | path relative-to $root_dir)
|
||||
if $dry_run {
|
||||
print $"Would update ($count) URLs in ($relative_path)"
|
||||
} else {
|
||||
# Backup the old file
|
||||
let backup_file = $"($zon_file).bak"
|
||||
cp $zon_file $backup_file
|
||||
$zon_content | save -f $zon_file
|
||||
print $"Updated ($count) URLs in ($relative_path), backup at ($relative_path).bak"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
.imgui = .{
|
||||
// https://github.com/ocornut/imgui
|
||||
.url = "https://github.com/ocornut/imgui/archive/refs/tags/v1.92.5-docking.tar.gz",
|
||||
.url = "https://deps.files.ghostty.org/N-V-__8AAEbOfQBnvcFcCX2W5z7tDaN8vaNZGamEQtNOe0UI.tar.gz",
|
||||
.hash = "N-V-__8AAEbOfQBnvcFcCX2W5z7tDaN8vaNZGamEQtNOe0UI",
|
||||
.lazy = true,
|
||||
},
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
.lazy = true,
|
||||
},
|
||||
.translate_c = .{
|
||||
.url = "https://codeberg.org/vancluever/translate-c/archive/a916baf225a3cfc93a982225462db612604ae290.tar.gz",
|
||||
.url = "https://deps.files.ghostty.org/translate_c-a916baf225a3cfc93a982225462db612604ae290.tar.gz",
|
||||
.hash = "translate_c-0.0.0-Q_BUWj8_BwCr4na219OimiKKj4IVSq0aKtMXCQmIk4AB",
|
||||
.lazy = true,
|
||||
},
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
.paths = .{""},
|
||||
.dependencies = .{
|
||||
.translate_c = .{
|
||||
.url = "https://codeberg.org/vancluever/translate-c/archive/a916baf225a3cfc93a982225462db612604ae290.tar.gz",
|
||||
.url = "https://deps.files.ghostty.org/translate_c-a916baf225a3cfc93a982225462db612604ae290.tar.gz",
|
||||
.hash = "translate_c-0.0.0-Q_BUWj8_BwCr4na219OimiKKj4IVSq0aKtMXCQmIk4AB",
|
||||
.lazy = true,
|
||||
},
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
.dependencies = .{
|
||||
.apple_sdk = .{ .path = "../apple-sdk" },
|
||||
.translate_c = .{
|
||||
.url = "https://codeberg.org/vancluever/translate-c/archive/a916baf225a3cfc93a982225462db612604ae290.tar.gz",
|
||||
.url = "https://deps.files.ghostty.org/translate_c-a916baf225a3cfc93a982225462db612604ae290.tar.gz",
|
||||
.hash = "translate_c-0.0.0-Q_BUWj8_BwCr4na219OimiKKj4IVSq0aKtMXCQmIk4AB",
|
||||
.lazy = true,
|
||||
},
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
.dependencies = .{
|
||||
.translate_c = .{
|
||||
.lazy = true,
|
||||
.url = "https://codeberg.org/vancluever/translate-c/archive/a916baf225a3cfc93a982225462db612604ae290.tar.gz",
|
||||
.url = "https://deps.files.ghostty.org/translate_c-a916baf225a3cfc93a982225462db612604ae290.tar.gz",
|
||||
.hash = "translate_c-0.0.0-Q_BUWj8_BwCr4na219OimiKKj4IVSq0aKtMXCQmIk4AB",
|
||||
},
|
||||
|
||||
|
||||
@@ -113,8 +113,10 @@ fn step(ptr: *anyopaque) Benchmark.Error!void {
|
||||
// aren't currently IO bound.
|
||||
const f = self.data_f orelse return;
|
||||
|
||||
var read_buf: [64 * 1024]u8 align(std.atomic.cache_line) = undefined;
|
||||
var f_reader = f.reader(global.io(), &read_buf);
|
||||
// Unbuffered: readSliceShort below reads directly into `buf`,
|
||||
// avoiding a per-chunk memcpy through an intermediate reader
|
||||
// buffer that would pollute the measurement.
|
||||
var f_reader = f.reader(global.io(), &.{});
|
||||
const r = &f_reader.interface;
|
||||
|
||||
// This buffer size matches the read buffer size used by the
|
||||
|
||||
@@ -46,7 +46,7 @@ pub const Action = enum {
|
||||
|
||||
/// An entrypoint for the benchmark CLI.
|
||||
pub fn main(init: std.process.Init) !void {
|
||||
try global.init(.{ .main = init });
|
||||
try global.init(.{ .tool = init });
|
||||
const alloc = std.heap.c_allocator;
|
||||
const action_ = try cli.action.detectArgs(Action, alloc, init.minimal.args);
|
||||
const action = action_ orelse return error.NoAction;
|
||||
|
||||
@@ -669,6 +669,17 @@ pub fn fromOptions() Config {
|
||||
};
|
||||
}
|
||||
|
||||
/// Whether release artifacts should omit frame pointers.
|
||||
///
|
||||
/// Stripped release builds omit them in general, but we always keep frame
|
||||
/// pointers on Apple platforms: the Apple arm64 ABI expects x29 to
|
||||
/// be a valid frame pointer and Apple's profiling and crash reporting
|
||||
/// tools rely on it for backtraces.
|
||||
pub fn omitFramePointer(self: *const Config) bool {
|
||||
if (self.target.result.os.tag.isDarwin()) return false;
|
||||
return self.strip;
|
||||
}
|
||||
|
||||
/// Returns the minimum OS version for the given OS tag. This shouldn't
|
||||
/// be used generally, it should only be used for Darwin-based OS currently.
|
||||
pub fn osVersionMin(tag: std.Target.Os.Tag) ?std.Target.Query.OsVersion {
|
||||
|
||||
@@ -18,7 +18,7 @@ pub fn init(b: *std.Build, cfg: *const Config, deps: *const SharedDeps) !Ghostty
|
||||
.target = cfg.target,
|
||||
.optimize = cfg.optimize,
|
||||
.strip = cfg.strip,
|
||||
.omit_frame_pointer = cfg.strip,
|
||||
.omit_frame_pointer = cfg.omitFramePointer(),
|
||||
.unwind_tables = if (cfg.strip) .none else .sync,
|
||||
}),
|
||||
// Crashes on x86_64 self-hosted on 0.15.1
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
const GhosttyLib = @This();
|
||||
|
||||
const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
const RunStep = std.Build.Step.Run;
|
||||
const CombineArchivesStep = @import("CombineArchivesStep.zig");
|
||||
const Config = @import("Config.zig");
|
||||
const LibsystemOverrideStep = @import("LibsystemOverrideStep.zig");
|
||||
const SharedDeps = @import("SharedDeps.zig");
|
||||
const LipoStep = @import("LipoStep.zig");
|
||||
|
||||
@@ -27,7 +29,7 @@ pub fn initStatic(
|
||||
.target = deps.config.target,
|
||||
.optimize = deps.config.optimize,
|
||||
.strip = deps.config.strip,
|
||||
.omit_frame_pointer = deps.config.strip,
|
||||
.omit_frame_pointer = deps.config.omitFramePointer(),
|
||||
.unwind_tables = if (deps.config.strip) .none else .sync,
|
||||
.link_libc = true,
|
||||
}),
|
||||
@@ -57,9 +59,19 @@ pub fn initStatic(
|
||||
const combined = CombineArchivesStep.create(b, deps.config.target, "ghostty-internal", lib_list.items);
|
||||
combined.step.dependOn(&lib.step);
|
||||
|
||||
// On Darwin, prefer libSystem's libc/libm over the bundled
|
||||
// compiler-rt for consumers of this archive. See
|
||||
// libsystem_override.sh for details. This is a no-op elsewhere.
|
||||
const override = LibsystemOverrideStep.create(
|
||||
b,
|
||||
deps.config.target,
|
||||
combined.output,
|
||||
"libghostty-internal.a",
|
||||
);
|
||||
|
||||
return .{
|
||||
.step = combined.step,
|
||||
.output = combined.output,
|
||||
.step = override.step orelse combined.step,
|
||||
.output = override.output,
|
||||
|
||||
// Static libraries cannot have dSYMs because they aren't linked.
|
||||
.dsym = null,
|
||||
@@ -88,7 +100,7 @@ pub fn initShared(
|
||||
.target = deps.config.target,
|
||||
.optimize = deps.config.optimize,
|
||||
.strip = deps.config.strip,
|
||||
.omit_frame_pointer = deps.config.strip,
|
||||
.omit_frame_pointer = deps.config.omitFramePointer(),
|
||||
.unwind_tables = if (deps.config.strip) .none else .sync,
|
||||
}),
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ const builtin = @import("builtin");
|
||||
const assert = std.debug.assert;
|
||||
const RunStep = std.Build.Step.Run;
|
||||
const CombineArchivesStep = @import("CombineArchivesStep.zig");
|
||||
const LibsystemOverrideStep = @import("LibsystemOverrideStep.zig");
|
||||
const Config = @import("Config.zig");
|
||||
const GhosttyZig = @import("GhosttyZig.zig");
|
||||
const LipoStep = @import("LipoStep.zig");
|
||||
@@ -295,22 +296,44 @@ fn initLib(
|
||||
const combined = CombineArchivesStep.create(b, target, "ghostty-vt", sources.items);
|
||||
combined.step.dependOn(&lib.step);
|
||||
|
||||
// On Darwin, prefer libSystem's libc/libm over the bundled
|
||||
// compiler-rt for consumers of this archive. See GhosttyLib
|
||||
// and libsystem_override.sh for details.
|
||||
const override = LibsystemOverrideStep.create(
|
||||
b,
|
||||
target,
|
||||
combined.output,
|
||||
"libghostty-vt-fat.a",
|
||||
);
|
||||
|
||||
return .{
|
||||
.step = combined.step,
|
||||
.step = override.step orelse combined.step,
|
||||
.artifact = &b.addInstallArtifact(lib, .{}).step,
|
||||
.kind = kind,
|
||||
.output = combined.output,
|
||||
.output = override.output,
|
||||
.dsym = dsymutil,
|
||||
.pkg_config = if (pcs) |v| v.shared else null,
|
||||
.pkg_config_static = if (pcs) |v| v.static else null,
|
||||
};
|
||||
}
|
||||
|
||||
// Same libSystem preference for the plain (no vendored SIMD)
|
||||
// static archive; a no-op off Darwin.
|
||||
const override: LibsystemOverrideStep.Result = if (kind == .static) LibsystemOverrideStep.create(
|
||||
b,
|
||||
target,
|
||||
lib.getEmittedBin(),
|
||||
"libghostty-vt-static.a",
|
||||
) else .{
|
||||
.step = null,
|
||||
.output = lib.getEmittedBin(),
|
||||
};
|
||||
|
||||
return .{
|
||||
.step = &lib.step,
|
||||
.step = override.step orelse &lib.step,
|
||||
.artifact = &b.addInstallArtifact(lib, .{}).step,
|
||||
.kind = kind,
|
||||
.output = lib.getEmittedBin(),
|
||||
.output = override.output,
|
||||
.dsym = dsymutil,
|
||||
.pkg_config = if (pcs) |v| v.shared else null,
|
||||
.pkg_config_static = if (pcs) |v| v.static else null,
|
||||
|
||||
51
src/build/LibsystemOverrideStep.zig
Normal file
51
src/build/LibsystemOverrideStep.zig
Normal file
@@ -0,0 +1,51 @@
|
||||
//! Wraps a Darwin static archive with the libsystem_override.sh
|
||||
//! post-processing step so that consumers linking the archive bind
|
||||
//! well-known libc/libm symbols (memcpy, memmove, memset, cos, sin,
|
||||
//! ...) to Apple's libSystem instead of the bundled Zig compiler-rt.
|
||||
//! See src/build/libsystem_override.sh for the full rationale.
|
||||
//!
|
||||
//! This applies to every static archive we produce, public
|
||||
//! (e.g. libghostty-vt) and app-internal alike: the compiler-rt
|
||||
//! bundle must stay because the few symbols libSystem does not
|
||||
//! provide (f128 conversions, *q math, sincos*, ___zig_probe_stack)
|
||||
//! have live references, e.g. from the bundled ubsan runtime and
|
||||
//! x86_64 stack probing in Debug builds.
|
||||
//!
|
||||
//! Note shared libraries can't use either approach: Zig 0.16 links
|
||||
//! compiler-rt as an eagerly-included object, so its definitions are
|
||||
//! already bound into the dylib at link time and cannot be repaired
|
||||
//! post-hoc. That needs an upstream Zig fix.
|
||||
const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
|
||||
pub const Result = struct {
|
||||
/// The step performing the override, or null if the override
|
||||
/// doesn't apply to this target/host (in which case `output` is
|
||||
/// the unmodified input).
|
||||
step: ?*std.Build.Step,
|
||||
output: std.Build.LazyPath,
|
||||
};
|
||||
|
||||
/// Post-process the given static archive on Darwin. Requires a Darwin
|
||||
/// host for the Apple toolchain (nmedit); in all other configurations
|
||||
/// this is a no-op and the input is returned unmodified, which is
|
||||
/// functional (the bundled compiler-rt symbols are used), just slower.
|
||||
pub fn create(
|
||||
b: *std.Build,
|
||||
target: std.Build.ResolvedTarget,
|
||||
input: std.Build.LazyPath,
|
||||
out_name: []const u8,
|
||||
) Result {
|
||||
if (!target.result.os.tag.isDarwin() or
|
||||
comptime !builtin.os.tag.isDarwin())
|
||||
{
|
||||
return .{ .step = null, .output = input };
|
||||
}
|
||||
|
||||
const run = b.addSystemCommand(&.{"/bin/sh"});
|
||||
run.setName("libsystem override");
|
||||
run.addFileArg(b.path("src/build/libsystem_override.sh"));
|
||||
run.addFileArg(input);
|
||||
const output = run.addOutputFileArg(out_name);
|
||||
return .{ .step = &run.step, .output = output };
|
||||
}
|
||||
123
src/build/libsystem_override.sh
Executable file
123
src/build/libsystem_override.sh
Executable file
@@ -0,0 +1,123 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Darwin-only: rewrite a static archive so that consumers linking it bind
|
||||
# libc/libm symbols to Apple's libSystem instead of the bundled Zig
|
||||
# compiler-rt. This uses the Apple toolchain (xcrun, nmedit) and libSystem
|
||||
# semantics, so it must run on a Darwin host for a Darwin target.
|
||||
#
|
||||
# Background: our static library bundles Zig's compiler-rt, which defines
|
||||
# strong global implementations of libc/libm functions (memcpy, memmove,
|
||||
# memset, cos, sin, ...). When a consumer (e.g. the macOS app via the
|
||||
# XCFramework) links this archive, ld64 resolves those symbols from the
|
||||
# archive instead of libSystem, silently replacing Apple's highly
|
||||
# optimized implementations (_platform_memmove and friends, vectorized
|
||||
# libm) with compiler-rt's generic ones. We measured Zig 0.16 (LLVM 21)
|
||||
# compiler-rt memmove costing several percent of PTY throughput on
|
||||
# scroll-region workloads versus libSystem's.
|
||||
#
|
||||
# The mechanism is to localize (make non-external) the libSystem-provided
|
||||
# symbols defined by the compiler_rt.o archive member. This keeps
|
||||
# compiler_rt.o functional for the intrinsics that libSystem does NOT
|
||||
# provide (e.g. the f128 conversions ___extenddftf2/___extendxftf2, *q
|
||||
# math, sincos*) while letting every other archive member bind the
|
||||
# well-known libc/libm symbols to libSystem at final link.
|
||||
#
|
||||
# usage: libsystem_override.sh <input.a> <output.a>
|
||||
set -eu
|
||||
|
||||
in="$1"
|
||||
out="$2"
|
||||
|
||||
tmp="$(mktemp -d)"
|
||||
trap 'rm -rf "$tmp"' EXIT
|
||||
|
||||
cp -f "$in" "$out"
|
||||
chmod u+w "$out"
|
||||
|
||||
# The symbols to prefer from libSystem. Everything listed here is a
|
||||
# stable macOS export (verified against libSystem's link surface).
|
||||
# Notably NOT listed (not exported by libSystem): the *q (f128)
|
||||
# variants, sincos/sincosf/sincosl, and all ___-prefixed compiler
|
||||
# intrinsics except the fortify _chk wrappers below.
|
||||
cat >"$tmp/localize.txt" <<'EOF'
|
||||
_bcmp
|
||||
_memcmp
|
||||
_memcpy
|
||||
_memmove
|
||||
_memset
|
||||
_strlen
|
||||
___memcpy_chk
|
||||
___memmove_chk
|
||||
___memset_chk
|
||||
___strcat_chk
|
||||
___strcpy_chk
|
||||
_ceil
|
||||
_ceilf
|
||||
_ceill
|
||||
_cos
|
||||
_cosf
|
||||
_cosl
|
||||
_exp
|
||||
_exp2
|
||||
_exp2f
|
||||
_exp2l
|
||||
_expf
|
||||
_expl
|
||||
_fabs
|
||||
_fabsf
|
||||
_fabsl
|
||||
_floor
|
||||
_floorf
|
||||
_floorl
|
||||
_fma
|
||||
_fmaf
|
||||
_fmal
|
||||
_fmax
|
||||
_fmaxf
|
||||
_fmaxl
|
||||
_fmin
|
||||
_fminf
|
||||
_fminl
|
||||
_fmod
|
||||
_fmodf
|
||||
_fmodl
|
||||
_log
|
||||
_log10
|
||||
_log10f
|
||||
_log10l
|
||||
_log2
|
||||
_log2f
|
||||
_log2l
|
||||
_logf
|
||||
_logl
|
||||
_round
|
||||
_roundf
|
||||
_roundl
|
||||
_sin
|
||||
_sinf
|
||||
_sinl
|
||||
_sqrt
|
||||
_sqrtf
|
||||
_sqrtl
|
||||
_tan
|
||||
_tanf
|
||||
_tanl
|
||||
_trunc
|
||||
_truncf
|
||||
_truncl
|
||||
EOF
|
||||
|
||||
cd "$tmp"
|
||||
|
||||
xcrun ar x "$out" compiler_rt.o
|
||||
chmod 644 compiler_rt.o
|
||||
|
||||
# nmedit takes a keep-list (-s): all current global definitions except
|
||||
# the ones we want to localize.
|
||||
xcrun nm -g compiler_rt.o | awk '$2 ~ /^[A-TV-Z]$/ {print $3}' | sort -u >all.txt
|
||||
sort -u localize.txt >loc.txt
|
||||
comm -23 all.txt loc.txt >keep.txt
|
||||
xcrun nmedit -s keep.txt compiler_rt.o
|
||||
|
||||
xcrun ar r "$out" compiler_rt.o
|
||||
xcrun ranlib "$out" 2>/dev/null || true
|
||||
@@ -204,7 +204,7 @@ pub const Path = union(enum) {
|
||||
defer dir.close(global.io());
|
||||
|
||||
const abs = abs: {
|
||||
const dir_len = dir.realPathFile(global.io(), ".", &buf) catch |err| {
|
||||
const abs_len = dir.realPathFile(global.io(), path, &buf) catch |err| {
|
||||
if (err == error.FileNotFound) {
|
||||
// The file doesn't exist. Try to resolve the relative path
|
||||
// another way.
|
||||
@@ -229,7 +229,7 @@ pub const Path = union(enum) {
|
||||
return;
|
||||
};
|
||||
|
||||
break :abs buf[0..dir_len];
|
||||
break :abs buf[0..abs_len];
|
||||
};
|
||||
|
||||
log.debug(
|
||||
|
||||
@@ -35,6 +35,14 @@ var state: ?GlobalState = undefined;
|
||||
|
||||
pub const InitOpts = union(enum) {
|
||||
main: std.process.Init,
|
||||
|
||||
/// Same as `main` but for auxiliary tool binaries (e.g. ghostty-bench
|
||||
/// and ghostty-gen) that have their own CLI action namespace. This
|
||||
/// skips detection of ghostty app CLI actions, since tool actions
|
||||
/// (e.g. `+terminal-stream`) are not valid app actions and would
|
||||
/// otherwise cause init to fail with InvalidAction.
|
||||
tool: std.process.Init,
|
||||
|
||||
c: struct {
|
||||
argc: usize,
|
||||
argv: [*][*:0]u8,
|
||||
@@ -52,11 +60,11 @@ pub fn init(opts: InitOpts) !void {
|
||||
.gpa = null,
|
||||
.alloc = undefined,
|
||||
.environ = switch (opts) {
|
||||
.main => |m| m.minimal.environ,
|
||||
.main, .tool => |m| m.minimal.environ,
|
||||
.c => |c| c.environ,
|
||||
},
|
||||
.args = switch (opts) {
|
||||
.main => |m| m.minimal.args,
|
||||
.main, .tool => |m| m.minimal.args,
|
||||
// TODO: Using the C API from Windows is unsupported at this time.
|
||||
//
|
||||
// When do we plan on supporting Windows, it's recommended to
|
||||
@@ -116,11 +124,16 @@ pub fn init(opts: InitOpts) !void {
|
||||
errdefer freeTmpDir(self.alloc, self.tmp_dir_path.?);
|
||||
|
||||
// We first try to parse any action that we may be executing.
|
||||
self.action = try cli.action.detectArgs(
|
||||
cli.ghostty.Action,
|
||||
self.alloc,
|
||||
self.args,
|
||||
);
|
||||
// Tool binaries (ghostty-bench, ghostty-gen) have their own action
|
||||
// namespace and detect their own actions, so we skip detection here.
|
||||
self.action = switch (opts) {
|
||||
.main, .c => try cli.action.detectArgs(
|
||||
cli.ghostty.Action,
|
||||
self.alloc,
|
||||
self.args,
|
||||
),
|
||||
.tool => null,
|
||||
};
|
||||
|
||||
// If we have an action executing, we disable logging by default
|
||||
// since we write to stderr we don't want logs messing up our
|
||||
|
||||
@@ -145,6 +145,12 @@ comptime {
|
||||
// If we're building the C library (vs. the Zig module) then
|
||||
// we want to reference the C API so that it gets exported.
|
||||
if (@import("root") == lib) {
|
||||
// Force-reference our memset override so its export is
|
||||
// emitted. This must stay inside the root guard so that
|
||||
// downstream Zig module consumers don't get the override
|
||||
// injected into their binaries. See quirks_memset.zig.
|
||||
_ = @import("quirks_memset.zig");
|
||||
|
||||
const c = terminal.c_api;
|
||||
@export(&c.key_event_new, .{ .name = "ghostty_key_event_new" });
|
||||
@export(&c.key_event_free, .{ .name = "ghostty_key_event_free" });
|
||||
|
||||
@@ -21,6 +21,12 @@ pub const std_options: std.Options = if (@hasDecl(entrypoint, "std_options"))
|
||||
else
|
||||
.{};
|
||||
|
||||
comptime {
|
||||
// Force-reference our memset override so its export is emitted.
|
||||
// See quirks_memset.zig for details on why this exists.
|
||||
_ = @import("quirks_memset.zig");
|
||||
}
|
||||
|
||||
test {
|
||||
// Zig 0.16.0 has made test logging more strict. Now, *anything* that gets
|
||||
// printed to stderr results in a "failed command" message, even if the
|
||||
@@ -28,4 +34,5 @@ test {
|
||||
// log spam in general), we bump the default testing log level to error.
|
||||
std.testing.log_level = std.log.Level.err;
|
||||
_ = entrypoint;
|
||||
_ = @import("quirks_memset.zig");
|
||||
}
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
const benchmark = @import("benchmark/main.zig");
|
||||
|
||||
comptime {
|
||||
// Force-reference our memset override so its export is emitted.
|
||||
// See quirks_memset.zig for details on why this exists.
|
||||
_ = @import("quirks_memset.zig");
|
||||
}
|
||||
|
||||
pub const main = benchmark.cli.main;
|
||||
|
||||
@@ -44,6 +44,10 @@ comptime {
|
||||
// Our benchmark API. We probably want to gate this on a build
|
||||
// config in the future but for now we always just export it.
|
||||
_ = @import("benchmark/main.zig").CApi;
|
||||
|
||||
// Force-reference our memset override so its export is emitted.
|
||||
// See quirks_memset.zig for details on why this exists.
|
||||
_ = @import("quirks_memset.zig");
|
||||
}
|
||||
|
||||
/// ghostty_info_s
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
const synthetic = @import("synthetic/main.zig");
|
||||
|
||||
comptime {
|
||||
// Force-reference our memset override so its export is emitted.
|
||||
// See quirks_memset.zig for details on why this exists.
|
||||
_ = @import("quirks_memset.zig");
|
||||
}
|
||||
|
||||
pub const main = synthetic.cli.main;
|
||||
|
||||
322
src/quirks_memset.zig
Normal file
322
src/quirks_memset.zig
Normal file
@@ -0,0 +1,322 @@
|
||||
//! Provides a fast `memset` symbol that overrides the slow scalar
|
||||
//! implementation provided by Zig 0.16's compiler_rt.
|
||||
//!
|
||||
//! Consider deleting when upstream ships an optimized compiler_rt
|
||||
//! memset (tracked by ziglang/zig#32091, maybe fixed at
|
||||
//! ziglang/zig#35754). To verify it is safe to delete, check that
|
||||
//! the disassembly of `memset` in a ReleaseFast binary is vectorized
|
||||
//! (or at least not a byte-at-a-time loop).
|
||||
//!
|
||||
//! ## Background
|
||||
//!
|
||||
//! Zig 0.16.0 globally disabled LLVM loop auto-vectorization to work
|
||||
//! around an LLVM 21 miscompilation (llvm/llvm-project#186922, see
|
||||
//! the 0.16.0 release notes). compiler_rt's memset is a naive
|
||||
//! byte-at-a-time loop that relied entirely on auto-vectorization,
|
||||
//! so it now compiles to a scalar loop roughly 24x slower than what
|
||||
//! Zig 0.15 produced.
|
||||
//!
|
||||
//! In benchmarks this made `ghostty-bench +terminal-stream` 2.8x slower on
|
||||
//! ASCII input (memset was 63% of all executed instructions!).
|
||||
//!
|
||||
//! Because compiler_rt's symbol is weak, exporting a strong `memset`
|
||||
//! from our own code transparently overrides it everywhere. The
|
||||
//! implementation below is manually vectorized with `@Vector`, which
|
||||
//! does not depend on the disabled loop vectorizer.
|
||||
//!
|
||||
//! Other mem functions deliberately not overridden:
|
||||
//!
|
||||
//! - memcpy/memmove: compiler_rt's implementations are manually
|
||||
//! vectorized upstream ("memcpyFast") and remain fast.
|
||||
//! - memcmp/bcmp/strlen: also scalar in 0.16, but they never showed
|
||||
//! up in our profiles.
|
||||
//!
|
||||
//! This file has no effect unless it is referenced from an artifact
|
||||
//! root (e.g. `comptime { _ = @import("quirks_memset.zig"); }`).
|
||||
//! It must NOT be imported from shared code, otherwise downstream
|
||||
//! consumers of our Zig modules would get this export injected into
|
||||
//! their binaries.
|
||||
//!
|
||||
//! ## References
|
||||
//!
|
||||
//! I referenced the musl asm + c memset implementation (MIT licensed).
|
||||
//! The primary thing I took away from that is the dc zva trick for
|
||||
//! aarch64. The remainder is fairly obvious memset work.
|
||||
|
||||
const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
|
||||
comptime {
|
||||
// Strong linkage when we control the final link (executables,
|
||||
// shared libraries), weak otherwise.
|
||||
const linkage: std.builtin.GlobalLinkage = switch (builtin.output_mode) {
|
||||
.Exe => .strong,
|
||||
.Lib => switch (builtin.link_mode) {
|
||||
.dynamic => .strong,
|
||||
.static => .weak,
|
||||
},
|
||||
.Obj => .weak,
|
||||
};
|
||||
|
||||
// Whether the override is emitted:
|
||||
//
|
||||
// 1. On targets without SIMD we disable, since compiler_rt's
|
||||
// scalar operations are going to be just as good.
|
||||
// 2. The C object format target uses strong linkage which
|
||||
// conflits with ours and errors.
|
||||
// 3. Weak COFF builds fatally error because MSVC's linker
|
||||
// errors when two identical linked symbols exist. MSVC has
|
||||
// CRT which links so we don't need this there anyways.
|
||||
const enabled =
|
||||
std.simd.suggestVectorLength(u8) != null and
|
||||
builtin.object_format != .c and
|
||||
!(linkage == .weak and builtin.object_format == .coff);
|
||||
|
||||
if (enabled) @export(&memset, .{
|
||||
.name = "memset",
|
||||
.linkage = linkage,
|
||||
|
||||
// Hidden so that shared library builds (libghostty,
|
||||
// libghostty-vt) resolve this internally without exporting
|
||||
// it to their host applications.
|
||||
.visibility = .hidden,
|
||||
});
|
||||
}
|
||||
|
||||
/// Bytes stored per loop iteration. Twice the native vector size so
|
||||
/// each iteration issues two vector stores (e.g. `stp q0, q0` on
|
||||
/// aarch64). Capped at 128 both because the small path below relies
|
||||
/// on len < 128 once the loop is skipped, and because wider single
|
||||
/// iterations stop paying off anyway (e.g. on scalable-vector
|
||||
/// targets that suggest very large lengths).
|
||||
const vec_bytes = @min(128, 2 * (std.simd.suggestVectorLength(u8) orelse 8));
|
||||
|
||||
/// Whether the `dc zva` fast path for large zero fills is available.
|
||||
/// `dc zva` zeroes a whole cacheline per instruction without moving data
|
||||
/// through the store pipeline. Based on musl.
|
||||
const zva_enabled = builtin.cpu.arch == .aarch64 and
|
||||
builtin.os.tag != .freestanding;
|
||||
|
||||
/// Only use `dc zva` at or above this many bytes. Below this our
|
||||
/// plain vector loop measures faster. Empirically mesaured.
|
||||
const zva_threshold = 16384;
|
||||
|
||||
/// Matches compiler_rt's memset signature (lib/compiler_rt.zig).
|
||||
fn memset(dest: ?[*]u8, c: u8, len: usize) callconv(.c) ?[*]u8 {
|
||||
@setRuntimeSafety(false);
|
||||
|
||||
if (len == 0) return dest;
|
||||
const d = dest.?;
|
||||
|
||||
// Large path: full-width vector stores.
|
||||
if (len >= vec_bytes) {
|
||||
// Very large zero fills: zero whole cachelines with `dc zva`
|
||||
// instead. Only implemented for the (universal in practice)
|
||||
// 64-byte block size; anything else falls through to the
|
||||
// vector loop.
|
||||
if (comptime zva_enabled) {
|
||||
if (len >= zva_threshold and c == 0) zva: {
|
||||
if (zvaSize() != 64) break :zva;
|
||||
const splat64: @Vector(64, u8) = @splat(0);
|
||||
|
||||
// Head: one unaligned store covering every byte up
|
||||
// to the first 64-aligned address (and usually a bit
|
||||
// beyond it; the overlap is fine).
|
||||
const addr = @intFromPtr(d);
|
||||
const aligned = std.mem.alignForward(usize, addr, 64);
|
||||
d[0..64].* = splat64;
|
||||
|
||||
// Zero whole aligned cachelines while at least one
|
||||
// full line remains in range. `dc zva` requires the
|
||||
// WHOLE line to be inside the buffer: it always
|
||||
// zeroes all 64 bytes.
|
||||
var p: [*]u8 = @ptrFromInt(aligned);
|
||||
const end_addr = addr + len;
|
||||
while (@intFromPtr(p) + 64 <= end_addr) : (p += 64) {
|
||||
asm volatile ("dc zva, %[ptr]"
|
||||
:
|
||||
: [ptr] "r" (p),
|
||||
: .{ .memory = true });
|
||||
}
|
||||
|
||||
// Tail: overlapping unaligned store anchored to the
|
||||
// end of the buffer, covering whatever the line loop
|
||||
// could not. len >= zva_threshold >= 64 so this
|
||||
// cannot underflow.
|
||||
d[len - 64 ..][0..64].* = splat64;
|
||||
return dest;
|
||||
}
|
||||
}
|
||||
|
||||
const splat: @Vector(vec_bytes, u8) = @splat(c);
|
||||
|
||||
// Fill [0, N) where N is len rounded down to a multiple of
|
||||
// vec_bytes.
|
||||
var i: usize = 0;
|
||||
while (i + vec_bytes <= len) : (i += vec_bytes) {
|
||||
d[i..][0..vec_bytes].* = splat;
|
||||
|
||||
// This empty asm statement prevents LLVM's
|
||||
// LoopIdiomRecognize pass from replacing this loop with
|
||||
// a call to memset, which would be infinite recursion
|
||||
// since we ARE memset. compiler_rt is protected from
|
||||
// this by being built with -fno-builtin; Ghostty is not.
|
||||
asm volatile ("" ::: .{ .memory = true });
|
||||
}
|
||||
|
||||
// Fill the remaining [N, len) tail, if any, with one more
|
||||
// full-width store anchored to the END of the buffer. It
|
||||
// overlaps up to vec_bytes-1 bytes that the loop already
|
||||
// wrote, which is fine (same value), and cannot underflow
|
||||
// because len >= vec_bytes in this path.
|
||||
if (i != len) d[len - vec_bytes ..][0..vec_bytes].* = splat;
|
||||
return dest;
|
||||
}
|
||||
|
||||
// Small path (len < vec_bytes): pairs of narrower stores, one
|
||||
// anchored to the start of the buffer and one to the end.
|
||||
//
|
||||
// The invariant for each branch below: a store of width w at
|
||||
// [0..w] plus a store at [len-w..len] covers every byte exactly
|
||||
// when w <= len <= 2*w. Smaller lens are handled by a later
|
||||
// branch; larger lens by an earlier one.
|
||||
|
||||
comptime std.debug.assert(vec_bytes <= 128);
|
||||
if (comptime vec_bytes > 64) {
|
||||
if (len >= 64) {
|
||||
// 64 <= len < vec_bytes <= 128 (asserted above): one
|
||||
// pair of 64-byte stores covers len <= 128. Only emitted
|
||||
// when vec_bytes > 64 (e.g. AVX-512), otherwise the
|
||||
// vector loop above already handled these lengths.
|
||||
const splat64: @Vector(64, u8) = @splat(c);
|
||||
d[0..64].* = splat64;
|
||||
d[len - 64 ..][0..64].* = splat64;
|
||||
return dest;
|
||||
}
|
||||
}
|
||||
if (len >= 16) {
|
||||
// 16 <= len < @min(vec_bytes, 64), so at most 63. One pair
|
||||
// of 16-byte stores covers len <= 32. For 32 < len < 64, a
|
||||
// second pair extends the covered prefix to [0..32] and the
|
||||
// covered suffix to [len-32..len], which meet or overlap in
|
||||
// the middle.
|
||||
const splat16: @Vector(16, u8) = @splat(c);
|
||||
d[0..16].* = splat16;
|
||||
d[len - 16 ..][0..16].* = splat16;
|
||||
if (len > 32) {
|
||||
d[16..32].* = splat16;
|
||||
d[len - 32 ..][0..16].* = splat16;
|
||||
}
|
||||
return dest;
|
||||
}
|
||||
if (len >= 8) {
|
||||
// 8 <= len <= 15: one 8-byte pair (covers len <= 16).
|
||||
const splat8: @Vector(8, u8) = @splat(c);
|
||||
d[0..8].* = splat8;
|
||||
d[len - 8 ..][0..8].* = splat8;
|
||||
return dest;
|
||||
}
|
||||
if (len >= 4) {
|
||||
// 4 <= len <= 7: one 4-byte pair (covers len <= 8).
|
||||
const splat4: @Vector(4, u8) = @splat(c);
|
||||
d[0..4].* = splat4;
|
||||
d[len - 4 ..][0..4].* = splat4;
|
||||
return dest;
|
||||
}
|
||||
|
||||
// 1 <= len <= 3: too short for the pair trick; write bytes one
|
||||
// at a time. The asm statement again keeps LoopIdiomRecognize
|
||||
// from turning this into a recursive memset call; LLVM will do
|
||||
// that even for a loop this short because the trip count is not
|
||||
// statically known.
|
||||
var i: usize = 0;
|
||||
while (i < len) : (i += 1) {
|
||||
d[i] = c;
|
||||
asm volatile ("" ::: .{ .memory = true });
|
||||
}
|
||||
return dest;
|
||||
}
|
||||
|
||||
/// Cached `dc zva` block size: 0 = not yet queried, 1 = unavailable
|
||||
/// or prohibited, otherwise the block size in bytes. Racing threads
|
||||
/// store the same value so the memory ordering is irrelevant.
|
||||
var zva_size: std.atomic.Value(usize) = .init(0);
|
||||
|
||||
fn zvaSize() usize {
|
||||
const cached = zva_size.load(.monotonic);
|
||||
if (cached != 0) return cached;
|
||||
const dczid = asm ("mrs %[out], dczid_el0"
|
||||
: [out] "=r" (-> u64),
|
||||
);
|
||||
// Bit 4 (DZP) prohibits DC ZVA; bits 0-3 are log2 of the block
|
||||
// size in 4-byte words.
|
||||
const size: usize = if (dczid & 0x10 != 0)
|
||||
1
|
||||
else
|
||||
@as(usize, 4) << @intCast(dczid & 0xF);
|
||||
zva_size.store(size, .monotonic);
|
||||
return size;
|
||||
}
|
||||
|
||||
test memset {
|
||||
const testing = std.testing;
|
||||
|
||||
// A buffer larger than anything the small/vector paths special
|
||||
// case, with room for offset (alignment) variations. Guard bytes
|
||||
// around the fill region must remain untouched.
|
||||
var buf: [4 * vec_bytes + 33]u8 = undefined;
|
||||
for (0..vec_bytes + 1) |offset| {
|
||||
for (0..buf.len - offset) |len| {
|
||||
for ([_]u8{ 0x00, 0x5C, 0xFF }) |c| {
|
||||
@memset(&buf, 0xAA);
|
||||
const region = buf[offset..][0..len];
|
||||
const ret = memset(region.ptr, c, len);
|
||||
try testing.expectEqual(region.ptr, ret.?);
|
||||
for (buf[0..offset]) |b| try testing.expectEqual(0xAA, b);
|
||||
for (region) |b| try testing.expectEqual(c, b);
|
||||
for (buf[offset + len ..]) |b| try testing.expectEqual(0xAA, b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Zero length must not touch memory and must tolerate null.
|
||||
try testing.expectEqual(null, memset(null, 0x11, 0));
|
||||
var one: [1]u8 = .{0xAA};
|
||||
_ = memset(&one, 0x11, 0);
|
||||
try testing.expectEqual(0xAA, one[0]);
|
||||
}
|
||||
|
||||
test "memset large zero fills (dc zva path)" {
|
||||
const testing = std.testing;
|
||||
const alloc = testing.allocator;
|
||||
|
||||
// Sizes at and around the ZVA threshold, with a guard byte on
|
||||
// each side and every offset within a cacheline so the head and
|
||||
// tail alignment handling is fully exercised.
|
||||
const buf = try alloc.alloc(u8, 2 * zva_threshold + 66);
|
||||
defer alloc.free(buf);
|
||||
|
||||
for ([_]usize{
|
||||
zva_threshold - 1,
|
||||
zva_threshold,
|
||||
zva_threshold + 63,
|
||||
2 * zva_threshold,
|
||||
}) |len| {
|
||||
for (0..65) |offset| {
|
||||
@memset(buf, 0xAA);
|
||||
const region = buf[1 + offset ..][0..len];
|
||||
_ = memset(region.ptr, 0x00, len);
|
||||
for (buf[0 .. 1 + offset]) |b| try testing.expectEqual(0xAA, b);
|
||||
for (region) |b| try testing.expectEqual(0x00, b);
|
||||
for (buf[1 + offset + len ..]) |b| try testing.expectEqual(0xAA, b);
|
||||
}
|
||||
}
|
||||
|
||||
// Nonzero fills of ZVA-eligible sizes must not take the ZVA path
|
||||
// (it can only write zeroes).
|
||||
@memset(buf, 0xAA);
|
||||
_ = memset(buf.ptr + 1, 0x5C, zva_threshold);
|
||||
try testing.expectEqual(0xAA, buf[0]);
|
||||
for (buf[1 .. 1 + zva_threshold]) |b| try testing.expectEqual(0x5C, b);
|
||||
try testing.expectEqual(0xAA, buf[1 + zva_threshold]);
|
||||
}
|
||||
@@ -9,6 +9,18 @@ pub const index_of = @import("index_of.zig");
|
||||
pub const vt = @import("vt.zig");
|
||||
pub const codepointWidth = codepoint_width.codepointWidth;
|
||||
|
||||
/// The number of vector lanes to use for manually vectorized hot
|
||||
/// loops operating on elements of type T, or null if the target has
|
||||
/// no usable SIMD support and a plain scalar loop should be used
|
||||
/// instead (e.g. wasm32 without simd128).
|
||||
///
|
||||
/// This is twice the native vector width so that each iteration works
|
||||
/// two vector registers, giving better instruction-level parallelism.
|
||||
pub fn lanes(comptime T: type) ?comptime_int {
|
||||
const native = std.simd.suggestVectorLength(T) orelse return null;
|
||||
return native * 2;
|
||||
}
|
||||
|
||||
test {
|
||||
@import("std").testing.refAllDecls(@This());
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
const std = @import("std");
|
||||
const Allocator = std.mem.Allocator;
|
||||
const cli = @import("../cli.zig");
|
||||
const global = @import("../global.zig");
|
||||
|
||||
/// The available actions for the CLI. This is the list of available
|
||||
/// synthetic generators. View docs for each individual one in the
|
||||
@@ -93,7 +92,7 @@ fn mainActionImpl(
|
||||
|
||||
// Our output always goes to stdout.
|
||||
var buffer: [2048]u8 = undefined;
|
||||
var stdout_writer = std.Io.File.stdout().writer(global.io(), &buffer);
|
||||
var stdout_writer = std.Io.File.stdout().writer(io, &buffer);
|
||||
const writer = &stdout_writer.interface;
|
||||
|
||||
// Create our implementation
|
||||
|
||||
@@ -10,6 +10,7 @@ const assert = @import("../quirks.zig").inlineAssert;
|
||||
const tripwire = @import("../tripwire.zig");
|
||||
const testing = std.testing;
|
||||
const Allocator = std.mem.Allocator;
|
||||
const simd = @import("../simd/main.zig");
|
||||
const unicode = @import("../unicode/main.zig");
|
||||
const uucode = @import("uucode");
|
||||
|
||||
@@ -630,6 +631,85 @@ inline fn printSliceEligible(cp: u32, comptime width: PrintSliceWidth) bool {
|
||||
});
|
||||
}
|
||||
|
||||
/// Store a run of narrow codepoint cells built from a bit template:
|
||||
/// for each `idx` in `[from, to)`, `cells[idx]` is assigned the bits
|
||||
/// `template_bits | (cps[idx] << cp_shift)`.
|
||||
///
|
||||
/// The template is a complete Cell (content tag, style, wide state,
|
||||
/// etc. already baked in by the caller) whose codepoint content bits
|
||||
/// are zero. Since Cell is a packed struct(u64), OR-ing a codepoint
|
||||
/// into the content field's bit position yields a finished cell as a
|
||||
/// single integer, keeping the loop pure data movement: no per-cell
|
||||
/// field assignments and no branches.
|
||||
///
|
||||
/// This loop is manually vectorized: Zig 0.16 (LLVM 21) no longer
|
||||
/// auto-vectorizes the scalar form the way Zig 0.15 (LLVM 20) did.
|
||||
inline fn printSliceStoreRun(
|
||||
cells: [*]Cell,
|
||||
cps: [*]const u32,
|
||||
from: usize,
|
||||
to: usize,
|
||||
template_bits: u64,
|
||||
) void {
|
||||
// The bit position of the `content` field within the packed
|
||||
// Cell. A codepoint occupies the low bits of `content`, so
|
||||
// shifting a codepoint left by this amount places it exactly
|
||||
// where `.content = .{ .codepoint = .{ .data = cp } }` would.
|
||||
const cp_shift = @bitOffsetOf(Cell, "content");
|
||||
|
||||
// Since codepoints are OR'd into the content field rather than
|
||||
// assigned, any nonzero content bits in the template would
|
||||
// corrupt the stored codepoints.
|
||||
const content_mask: u64 = comptime mask: {
|
||||
const bits = @bitSizeOf(@FieldType(Cell, "content"));
|
||||
break :mask ((1 << bits) - 1) << cp_shift;
|
||||
};
|
||||
assert(template_bits & content_mask == 0);
|
||||
|
||||
var idx = from;
|
||||
|
||||
// Vectorized bulk of the run.
|
||||
if (simd.lanes(u64)) |lanes| {
|
||||
// u64 due to backing integer of Cell
|
||||
const V = @Vector(lanes, u64);
|
||||
|
||||
// The template and shift amount are loop-invariant, so
|
||||
// broadcast them to every lane once up front.
|
||||
const template: V = @splat(template_bits);
|
||||
const shift: @Vector(
|
||||
lanes,
|
||||
std.math.Log2Int(u64),
|
||||
) = @splat(cp_shift);
|
||||
|
||||
while (idx + lanes <= to) : (idx += lanes) {
|
||||
// Load `lanes` decoded codepoints...
|
||||
const narrow: @Vector(lanes, u32) = cps[idx..][0..lanes].*;
|
||||
|
||||
// ...widen each u32 lane to the u64 cell size...
|
||||
const wide: V = @intCast(narrow);
|
||||
|
||||
// ...shift each codepoint into the content field's bit
|
||||
// position and merge with the template, producing
|
||||
// `lanes` finished cells (coerced from vector to array
|
||||
// so they can be bitcast for the store below)...
|
||||
const bits: [lanes]u64 = template | (wide << shift);
|
||||
|
||||
// ...and store them contiguously. Cell is a packed
|
||||
// struct(u64) so an array of u64 bit patterns has
|
||||
// identical layout to an array of cells.
|
||||
cells[idx..][0..lanes].* = @bitCast(bits);
|
||||
}
|
||||
}
|
||||
|
||||
// Scalar tail: the final `< lanes` cells of the run, or the
|
||||
// entire run on targets without SIMD. Note `idx` carries over
|
||||
// from the vector loop above. This is the same computation as
|
||||
// the vector body, one cell at a time.
|
||||
while (idx < to) : (idx += 1) {
|
||||
cells[idx] = @bitCast(template_bits | (@as(u64, cps[idx]) << cp_shift));
|
||||
}
|
||||
}
|
||||
|
||||
/// The row-filling portion of the printSlice fast path, specialized by
|
||||
/// width class. The first codepoint must already be validated by the
|
||||
/// caller (printSliceFast).
|
||||
@@ -671,19 +751,20 @@ fn printSliceFill(
|
||||
// Anything else (including eligible unicode) proceeds via
|
||||
// the scalar loop below.
|
||||
if (comptime width == .narrow) {
|
||||
const lanes = 8;
|
||||
const V = @Vector(lanes, u32);
|
||||
const lo: V = @splat(0x10);
|
||||
const hi: V = @splat(0xFF);
|
||||
while (idx + lanes <= cps.len) {
|
||||
const v: V = cps[idx..][0..lanes].*;
|
||||
const in_range = (v >= lo) & (v <= hi);
|
||||
if (!@reduce(.And, in_range)) {
|
||||
const bits: std.meta.Int(.unsigned, lanes) = @bitCast(in_range);
|
||||
idx += @ctz(~bits);
|
||||
break;
|
||||
if (simd.lanes(u32)) |lanes| {
|
||||
const V = @Vector(lanes, u32);
|
||||
const lo: V = @splat(0x10);
|
||||
const hi: V = @splat(0xFF);
|
||||
while (idx + lanes <= cps.len) {
|
||||
const v: V = cps[idx..][0..lanes].*;
|
||||
const in_range = (v >= lo) & (v <= hi);
|
||||
if (!@reduce(.And, in_range)) {
|
||||
const bits: std.meta.Int(.unsigned, lanes) = @bitCast(in_range);
|
||||
idx += @ctz(~bits);
|
||||
break;
|
||||
}
|
||||
idx += lanes;
|
||||
}
|
||||
idx += lanes;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -817,12 +898,38 @@ fn printSliceFill(
|
||||
// We can only write whole (wide, spacer) pairs.
|
||||
const pair_end = k + (simple - k) / 2 * 2;
|
||||
var idx = k;
|
||||
|
||||
// Manually vectorized for the same reason as
|
||||
// printSliceStoreRun: build a vector of wide cells,
|
||||
// interleave with spacer tails, and store (wide,
|
||||
// spacer) pairs several at a time.
|
||||
if (simd.lanes(u64)) |lanes| {
|
||||
const pair_lanes = lanes / 2;
|
||||
const Vp = @Vector(pair_lanes, u64);
|
||||
const wide_v: Vp = @splat(wide_bits);
|
||||
const spacer_v: Vp = @splat(spacer_bits);
|
||||
const shift_v: @Vector(
|
||||
pair_lanes,
|
||||
std.math.Log2Int(u64),
|
||||
) = @splat(cp_shift);
|
||||
while (idx + 2 * pair_lanes <= pair_end) : (idx += 2 * pair_lanes) {
|
||||
const narrow: @Vector(pair_lanes, u32) =
|
||||
cps[printed + idx / 2 ..][0..pair_lanes].*;
|
||||
const wides: Vp = wide_v | (@as(Vp, @intCast(narrow)) << shift_v);
|
||||
const inter: [2 * pair_lanes]u64 = std.simd.interlace(.{
|
||||
wides,
|
||||
spacer_v,
|
||||
});
|
||||
cells[idx..][0 .. 2 * pair_lanes].* = @bitCast(inter);
|
||||
}
|
||||
}
|
||||
while (idx < pair_end) : (idx += 2) {
|
||||
cells[idx] = @bitCast(
|
||||
wide_bits | (@as(u64, cps[printed + idx / 2]) << cp_shift),
|
||||
);
|
||||
cells[idx + 1] = @bitCast(spacer_bits);
|
||||
}
|
||||
|
||||
// If the simple run ended mid-pair we stop at the pair
|
||||
// boundary and handle the offending cell below.
|
||||
k = pair_end;
|
||||
@@ -832,11 +939,13 @@ fn printSliceFill(
|
||||
simple = pair_end;
|
||||
}
|
||||
} else {
|
||||
for (k..simple) |idx| {
|
||||
cells[idx] = @bitCast(
|
||||
template_bits | (@as(u64, cps[printed + idx]) << cp_shift),
|
||||
);
|
||||
}
|
||||
printSliceStoreRun(
|
||||
cells,
|
||||
cps.ptr + printed,
|
||||
k,
|
||||
simple,
|
||||
template_bits,
|
||||
);
|
||||
k = simple;
|
||||
}
|
||||
if (k >= cell_count) break;
|
||||
@@ -888,11 +997,13 @@ fn printSliceFill(
|
||||
page.styles.useMultiple(page.memory, style_id, @intCast(n));
|
||||
}
|
||||
|
||||
for (k..m) |idx| {
|
||||
cells[idx] = @bitCast(
|
||||
template_bits | (@as(u64, cps[printed + idx]) << cp_shift),
|
||||
);
|
||||
}
|
||||
printSliceStoreRun(
|
||||
cells,
|
||||
cps.ptr + printed,
|
||||
k,
|
||||
m,
|
||||
template_bits,
|
||||
);
|
||||
k = m;
|
||||
continue :fill;
|
||||
}
|
||||
|
||||
@@ -70,8 +70,24 @@ fn AutoHashMapUnmanaged(
|
||||
|
||||
fn AutoContext(comptime K: type) type {
|
||||
return struct {
|
||||
pub const hash = std.hash_map.getAutoHashFn(K, @This());
|
||||
pub const eql = std.hash_map.getAutoEqlFn(K, @This());
|
||||
|
||||
pub fn hash(_: @This(), key: K) u64 {
|
||||
if (comptime std.meta.hasUniqueRepresentation(K)) {
|
||||
// LLVM 21 (Zig 0.16) failed to inline this which resulted
|
||||
// in a measurable almost 2x slowdown on our hyperlink map
|
||||
// benchmark. So, force it.
|
||||
return @call(
|
||||
.always_inline,
|
||||
std.hash.Wyhash.hash,
|
||||
.{ 0, std.mem.asBytes(&key) },
|
||||
);
|
||||
}
|
||||
|
||||
var hasher = std.hash.Wyhash.init(0);
|
||||
std.hash.autoHash(&hasher, key);
|
||||
return hasher.final();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -579,8 +579,30 @@ pub fn Stream(comptime H: type) type {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Find the end of the printable run. This is an
|
||||
// early-exit search loop that LLVM won't
|
||||
// auto-vectorize, and printable runs dominate real
|
||||
// input, so scan several codepoints at a time
|
||||
// manually (same idiom as the printSliceFill run
|
||||
// scan).
|
||||
var end = i + 1;
|
||||
while (end < cps.len and cps[end] > 0xF) end += 1;
|
||||
scan: {
|
||||
if (simd.lanes(u32)) |lanes| {
|
||||
const V = @Vector(lanes, u32);
|
||||
const threshold: V = @splat(0xF);
|
||||
while (end + lanes <= cps.len) {
|
||||
const v: V = cps[end..][0..lanes].*;
|
||||
const gt = v > threshold;
|
||||
if (!@reduce(.And, gt)) {
|
||||
const bits: std.meta.Int(.unsigned, lanes) = @bitCast(gt);
|
||||
end += @ctz(~bits);
|
||||
break :scan;
|
||||
}
|
||||
end += lanes;
|
||||
}
|
||||
}
|
||||
while (end < cps.len and cps[end] > 0xF) end += 1;
|
||||
}
|
||||
self.handler.vt(.print_slice, .{ .cps = cps[i..end] });
|
||||
i = end;
|
||||
}
|
||||
|
||||
@@ -141,8 +141,8 @@ inline fn invalidCodepoint(cp: anytype) bool {
|
||||
|
||||
/// This is all the structures and data for the precomputed lookup table
|
||||
/// for all possible permutations of state and grapheme break properties.
|
||||
/// Precomputation requires 2^13 keys of 4 bit values so the whole table is
|
||||
/// 8KB.
|
||||
/// Precomputation requires 2^13 keys of byte-sized values so the whole
|
||||
/// table is 8KB.
|
||||
const Precompute = struct {
|
||||
const Key = packed struct(u13) {
|
||||
state: uucode.grapheme.BreakState,
|
||||
@@ -154,9 +154,15 @@ const Precompute = struct {
|
||||
}
|
||||
};
|
||||
|
||||
const Value = packed struct(u4) {
|
||||
const Value = packed struct(u8) {
|
||||
result: bool,
|
||||
state: uucode.grapheme.BreakState,
|
||||
|
||||
/// Explicit padding to give the struct a power-of-two backing
|
||||
/// integer, for the same reason as `Properties._padding` (avoids
|
||||
/// exotic-width LLVM integer accesses that defeat register
|
||||
/// promotion). @sizeOf was already 1, so the table stays 8KB.
|
||||
_padding: u4 = 0,
|
||||
};
|
||||
|
||||
const data = precompute: {
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
const std = @import("std");
|
||||
const uucode = @import("uucode");
|
||||
|
||||
pub const Properties = packed struct {
|
||||
pub const Properties = packed struct(u16) {
|
||||
/// Codepoint width. We clamp to [0, 2] since Ghostty handles control
|
||||
/// characters and we max out at 2 for wide characters (i.e. 3-em dash
|
||||
/// becomes a 2-em dash).
|
||||
@@ -23,6 +23,16 @@ pub const Properties = packed struct {
|
||||
/// Emoji VS compatibility
|
||||
emoji_vs_base: bool = false,
|
||||
|
||||
/// Explicit padding to give the struct a power-of-two backing integer.
|
||||
/// This is a performance workaround: with a non-power-of-two backing
|
||||
/// integer (u9), Zig 0.16 lowers loads/stores of this struct through
|
||||
/// mismatched exotic-width LLVM integer types (store i9 / load i16),
|
||||
/// which blocks LLVM from promoting temporaries to registers and forces
|
||||
/// stack round-trips in hot paths like `graphemeBreak`. See
|
||||
/// https://github.com/ziglang/zig/issues/21891 for the upstream issue.
|
||||
/// The size of the lookup table is unchanged (@sizeOf was already 2).
|
||||
_padding: u7 = 0,
|
||||
|
||||
// Needed for lut.Generator
|
||||
pub fn eql(a: Properties, b: Properties) bool {
|
||||
return a.width == b.width and
|
||||
|
||||
Reference in New Issue
Block a user