WebKit Bugzilla
New
Browse
Search+
Log In
×
Sign in with GitHub
or
Remember my login
Create Account
·
Forgot Password
Forgotten password account recovery
RESOLVED INVALID
324968
iOS 27: JS and Wasm run without JIT on non-secure-context (http://) pages
https://bugs.webkit.org/show_bug.cgi?id=324968
Summary
iOS 27: JS and Wasm run without JIT on non-secure-context (http://) pages
alexey.pelykh
Reported
2026-09-23 05:24:29 PDT
Created
attachment 481528
[details]
Minimal self-contained reproduction (2.3 KB, no network). Runs a 30M-iteration float loop three times in JavaScript and once as a 128-byte hand-assembled WebAssembly module (bit-identical result), and <!-- bugs.webkit.org — suggested fields --> <!-- Product: WebKit · Component: JavaScriptCore · Version: Safari 27 (or "Other") · Hardware: iPhone / iPad · OS: iOS 27 · Severity: Normal --> <!-- Attachment: secure-context-jit.html (2.3 KB, self-contained, no external resources) --> # iOS 27: JS and Wasm run without JIT on non-secure-context (http://) pages ## Summary On iOS 27.0, a page that is **not a secure context** — plain `http://` served from a machine on the local network, whether addressed by IP literal or by a `.local` mDNS hostname — executes JavaScript **and** WebAssembly at interpreter speed: roughly 4–5× slower on a scalar loop and 20–60× slower on compute-heavy library code, with no tier-up over 45 s of hot execution. The **same page** served over an `https://` origin, on the **same device**, minutes later, runs at full JIT speed. The behaviour is identical in Safari and in Chrome for iOS (WKWebView), so it appears to be WebKit-wide rather than Safari-specific. The same device on iOS 26.6 five weeks earlier ran the same library code at full speed over the same kind of plain-HTTP LAN origin. I could not find this documented anywhere (Safari 27.0 release notes, iOS 27 security notes, WebKit blog). If it is an intentional hardening step, the practical problem is that it silently invalidates every on-device measurement made through the ordinary local-development workflow (`python3 -m http.server`, `npm run dev` on a LAN IP), with no console warning and no observable difference except the numbers. ## Environment | Detail | Value | |--------|-------| | Device | iPhone [model — please fill in], iOS 27.0 | | Safari | UA `Version/27.0 Mobile/15E148 Safari/604.1` (reports `iPhone OS 18_7` in the UA; the device is on 27.0) | | Chrome for iOS (WKWebView) | `CriOS/154.0.8037.41` — same result as Safari | | Serving (slow case) | `python3 -m http.server` (Python 3.14) on a Mac on the same Wi-Fi; page opened as `http://<lan-ip>:<port>/…` and as `http://<host>.local:<port>/…` — `window.isSecureContext === false` | | Serving (fast case) | the same directory exposed through an HTTPS tunnel (ngrok); page opened as `https://…` — `window.isSecureContext === true` | | Control, desktop | macOS 26.6.2 (25G83), Safari 26.6.2, same plain-HTTP LAN origin: **full JIT speed** — the macOS engine does not show this | | Control, engines | node v26.8.2 (V8) normal, and `node --jitless` as a known-interpreter reference | | Lockdown Mode | off (`WebAssembly` is present on the page; Lockdown Mode removes it) | | Low Power Mode | off. Rebooting the device changes nothing | ## Steps to reproduce 1. Save the attached `secure-context-jit.html` (self-contained: a 30M-iteration float loop in JavaScript, the identical loop as a 128-byte hand-assembled WebAssembly module, and a readout of `location.origin`, `isSecureContext` and the UA). It loads nothing from the network. 2. On a Mac on the same Wi-Fi: `python3 -m http.server 8000` in that directory. 3. On the iPhone (iOS 27.0), in Safari, open `http://<mac-lan-ip>:8000/secure-context-jit.html` and tap **Run**. Note the three JS timings and the wasm timing. 4. Serve the same directory over HTTPS (any tunnel, or a locally trusted certificate) and open the `https://` URL on the same phone. Tap **Run**. 5. Optional: repeat step 3 with `http://<mac-hostname>.local:8000/…`, and in Chrome for iOS. ## Expected behaviour The same page yields the same timings on the same device regardless of whether the origin is a secure context. If JIT policy depends on the origin, that policy is documented, and local-development origins (private-network IPs, `.local`) have a supported way to opt in. ## Actual behaviour Over `http://` (either IP or `.local`), all three consecutive JS runs take ~430–550 ms and the wasm loop ~520–570 ms; no run is faster than the previous one. Over `https://` the JS loop takes ~98 ms and the wasm loop ~66 ms. ## Measurements All on the same iPhone, same page, the same afternoon. ms. | Probe | `http://` LAN, IP literal | `http://` LAN, `.local` hostname | **`https://`** | macOS 26.6.2 Safari, same http:// LAN origin | node V8 | node `--jitless` | |---|---:|---:|---:|---:|---:|---:| | JS loop, 30M iterations | 409–550 (5 runs) | 444 | **98** | 75 | 118 | 599 | | Same loop, WebAssembly | 517–568 | 568 | **66** | — | 177 | — | | 200,000 × h3-js `latLngToCell` (emscripten asm.js-style) | 5,236–5,948 | 5,451 | **204** | — | 231 | 5,471 | | Real workload: h3-js `polygonToCells` + per-cell filtering, 150 km disk | 3,845–4,417 (Safari and Chrome) | 4,190 | **116** | 147 | 78 | 3,549 | | Same workload, 500 km disk | 43,008–46,112 | — | **793** | 991 | 950 | 40,214 | Two further observations: - **No tier-up.** Per-cell cost of the workload over `http://` is constant across radii (0.237 ms/cell at 150 km, 0.227 at 300, 0.226 at 500) — i.e. across 45 s of the same hot function nothing gets faster. Over `https://` the phone is 1.2× *faster* than the laptop's V8, as it was on iOS 26.6. - **The device JITs fine otherwise.** JetStream 3 (browserbench.org, an `https://` origin) scores **257** on this phone in the same session. The `http://` column matches `node --jitless` within ~10% on every row, which is why I read it as interpreter-only execution rather than a slow JIT. ## Regression window Same device, same library, same plain-HTTP LAN workflow: on **iOS 26.6 (2026-08-19)** `latLngToCell` ran at ~0.68 µs/call (79 ms per 117k). On **iOS 27.0 (2026-09-23)** it runs at ~26 µs/call over `http://` and ~1 µs/call over `https://`. ## What this breaks in practice Any on-device performance measurement made through the normal local workflow (`python3 -m http.server`, a dev server on a LAN IP, `.local` names) now reports interpreter numbers with nothing to indicate why. In our case a build that costs 116 ms in production was measured at 4.0 s, and a 500 km variant that costs 0.8 s was measured at 45 s, before the origin was suspected. ## Ask 1. If this is intentional: document the policy (which origins are affected, and whether WKWebView hosts can override it), and provide a developer affordance — e.g. a Feature Flag, or treating private-network / `.local` origins as *potentially trustworthy* for JIT purposes the way `localhost` already is. 2. If it is not intentional: this looks like JSC running LLInt-only (and wasm without its compiled tiers) for non-secure-context pages on iOS 27.0. Happy to run any further probe on the device.
Attachments
Minimal self-contained reproduction (2.3 KB, no network). Runs a 30M-iteration float loop three times in JavaScript and once as a 128-byte hand-assembled WebAssembly module (bit-identical result), and
(2.29 KB, text/html)
2026-09-23 05:24 PDT
,
alexey.pelykh
no flags
Details
View All
Add attachment
proposed patch, testcase, etc.
Alexey Proskuryakov
Comment 1
2026-09-23 23:27:35 PDT
Have you tried if the "Enable EnhancedSecurity Heuristic" feature flag changes this behavior? As far as I know, this is intentional, and details are subject to change, so documenting those may not be realistic. CC'ed some folks who may speak more authoritatively. Would you be willing to elaborate on the use case? I understand it as a hypothetical, but in practice I'd expect that a plain http server is rarely of use to Web developers, because so many APIs are disabled in insecure contexts. So even before performance testing, one can't use it for correctness validation.
> treating private-network / `.local` origins as *potentially trustworthy* for JIT purposes the way `localhost` already is.
This is an interesting idea, although an active network attacker on one's corporate network could once again inject malicious content attacking JIT if this was allowed.
Radar WebKit Bug Importer
Comment 2
2026-09-30 05:25:14 PDT
<
rdar://problem/188805621
>
ronan_turner
Comment 3
2026-09-30 08:31:42 PDT
I can confirm this is intended behaviour - this is part of a feature named Enhanced Security which applies certain hardening policies when navigations occur that we wish to protect further. Requests relating to plaintext HTTP are one such scenario. As noted above, disabling the "Enable EnhancedSecurity Heuristics" flag should prevent this behaviour from occurring if necessary for testing and benchmarking purposes.
Note
You need to
log in
before you can comment on or make changes to this bug.
Top of Page
Format For Printing
XML
Clone This Bug