From df851c894ad6d764d9a3514ecb3a127786819fdf Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 29 Aug 2026 20:09:22 +0200 Subject: [PATCH] Use architecture-dependent download URL in Firefox again When Git for Windows started to distribute ARM64 binaries along the x86 and x64 ones, the logic to choose the appropriate download URL on Git for Windows' home page was adjusted in 607efe1 (Drop 32-bit and add ARM64 architecture check, 2025-04-26) to detect when running on Windows/ARM64. Sadly, this new logic does not work on Firefox, and while the commit message of above-mentioned commit omits mentioning it, this was immediately spotted as a problem and there was an extensive discussion revolving around it, with the sad outcome that the download button does not link directly to the installer in Firefox, see https://github.com/git-for-windows/git-for-windows.github.io/pull/61. In the meantime, I stumbled across a neat trick to determine the CPU architecture that is used in the WebAssembly version of TensorFlow, which I traced all the way back to this commit: https://github.com/google/XNNPACK/commit/466b52379d (Use GEMM/IGEMM micro-kernels with Swizzle on WAsm SIMD, 2019-10-09). Technically, it does not allow us to determine whether the CPU architecture is ARM64 (but only if it is not x86). For our purposes, this is enough for now: At present, Windows only supports Intel-compatible CPU architectures and ARM64. Let's use this trick as a fallback on Firefox (and really, any browser that isn't (based on) Chrome). Signed-off-by: Johannes Schindelin --- layouts/_default/baseof.html | 41 +++++++++++++++++++++++++++++------- 1 file changed, 33 insertions(+), 8 deletions(-) diff --git a/layouts/_default/baseof.html b/layouts/_default/baseof.html index fee5ec4..135b79b 100644 --- a/layouts/_default/baseof.html +++ b/layouts/_default/baseof.html @@ -37,17 +37,42 @@ var a = document.querySelector('.version > a') var href = a?.href.match(/^(.*\/)tag(\/.*)$/); var version = a?.title.match(/^Version ([0-9.]*)(\(([0-9]*)?\))?/); - if (!href || !version || !navigator.userAgentData) - throw 0; + if (!href || !version) throw 0; - navigator.userAgentData.getHighEntropyValues(["architecture", "platform", "bitness"]) - .then(function(browser) { - if (browser.platform != "Windows" || browser.bitness != "64") return; - - var architecture = browser.architecture == "arm" ? "arm64" : "64-bit"; + const setDownloadURL = (architecture) => { var url = href[1] + 'download' + href[2] + '/Git-' + version[1] + '-' + architecture + '.exe'; document.getElementById("download").href = url; - }) + }; + if (!navigator.userAgentData) { + if (!navigator.userAgent?.includes('Windows')) throw 0; + /* + * Infinity - Infinity is an invalid floating-point operation. On x86, + * that operation conventionally produces the “real indefinite” negative + * NaN, whose float32 representation is 0xffc00000. ARM64 normally + * produces positive canonical NaN, 0x7fc00000. + * + * This trick was found by Marat Dukhan, as per + * https://github.com/google/XNNPACK/commit/466b52379d (Use GEMM/IGEMM + * micro-kernels with Swizzle on WAsm SIMD, 2019-10-09). + */ + const architecture = { + "ffc00000": "64-bit", + "7fc00000": "arm64", + }[ + (new Uint32Array((new Float32Array([Infinity - Infinity])).buffer))[0] + .toString(16) + .padStart(8, "0") + ]; + if (!architecture) throw 0; + setDownloadURL(architecture); + } else { + navigator.userAgentData.getHighEntropyValues(["architecture", "platform", "bitness"]) + .then(function(browser) { + if (browser.platform != "Windows" || browser.bitness != "64") return; + + setDownloadURL(browser.architecture == "arm" ? "arm64" : "64-bit"); + }) + } } catch(e) {} {{ end -}} });