From 15deb7a118dc3bb21f494b36126b271b3d2fdaed Mon Sep 17 00:00:00 2001 From: Krzysztof Furman Date: Sat, 13 Jun 2026 09:53:43 +0100 Subject: [PATCH] Commented the workaround with links to issues, and put it behind a build flag. --- src/build_settings.cpp | 2 ++ src/main.cpp | 10 ++++++++++ src/name_canonicalization.cpp | 13 +++++++++++-- 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/src/build_settings.cpp b/src/build_settings.cpp index f31830598..509d4bf57 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -539,6 +539,8 @@ struct BuildContext { bool disallow_do; bool show_import_graph; + bool webkit_switch_workaround; + IntegerDivisionByZeroKind integer_division_by_zero_behaviour; LinkerChoice linker_choice; diff --git a/src/main.cpp b/src/main.cpp index a63cee5e0..6589efb54 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -312,6 +312,7 @@ enum BuildFlagKind { BuildFlag_Debug, BuildFlag_DisableAssert, BuildFlag_NoBoundsCheck, + BuildFlag_WebkitSwitchWorkaround, BuildFlag_NoTypeAssert, BuildFlag_NoDynamicLiterals, BuildFlag_DynamicLiterals, @@ -545,6 +546,7 @@ gb_internal bool parse_build_flags(Array args) { add_flag(&build_flags, BuildFlag_Debug, str_lit("debug"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_DisableAssert, str_lit("disable-assert"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_NoBoundsCheck, str_lit("no-bounds-check"), BuildFlagParam_None, Command__does_check); + add_flag(&build_flags, BuildFlag_WebkitSwitchWorkaround, str_lit("webkit-switch-workaround"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_NoTypeAssert, str_lit("no-type-assert"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_NoThreadLocal, str_lit("no-thread-local"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_NoDynamicLiterals, str_lit("no-dynamic-literals"), BuildFlagParam_None, Command__does_check); @@ -1235,6 +1237,9 @@ gb_internal bool parse_build_flags(Array args) { case BuildFlag_NoBoundsCheck: build_context.no_bounds_check = true; break; + case BuildFlag_WebkitSwitchWorkaround: + build_context.webkit_switch_workaround = true; + break; case BuildFlag_NoTypeAssert: build_context.no_type_assert = true; break; @@ -2891,6 +2896,11 @@ gb_internal int print_show_help(String const arg0, String command, String option print_usage_line(2, "Disables bounds checking program wide."); } + if (print_flag("-webkit-switch-workaround")) { + print_usage_line(2, "Constrains 'typeid' values to 63 bits to avoid an OMG JIT crash in WebKit when running WASM builds."); + print_usage_line(2, "Only needed for 'js_wasm32'/'js_wasm64p32' targets run in Safari/WebKit. See: https://github.com/odin-lang/Odin/issues/6810"); + } + if (print_flag("-no-crt")) { print_usage_line(2, "Disables automatic linking with the C Run Time."); } diff --git a/src/name_canonicalization.cpp b/src/name_canonicalization.cpp index ccd65e610..67ca9e278 100644 --- a/src/name_canonicalization.cpp +++ b/src/name_canonicalization.cpp @@ -520,8 +520,17 @@ gb_internal u64 type_hash_canonical_type(Type *type) { type_writer_make_hasher(&w, &w.hash_ctx); write_type_to_canonical_string(&w, type); u64 hash = typeid_hash_context_fini(&w.hash_ctx); - hash &= 0x7fffffffffffffffull; - hash = hash ? hash : 1; + if (build_context.webkit_switch_workaround) { + // Clear the top bit so every `typeid` is in [1, 2^63). A `switch` over a + // typeid (e.g. a type switch over `any` in core:fmt) then has a case-value + // span < 2^63. WebKit's B3/OMG wasm JIT computes a switch's value range as + // a signed i64 (max - min); a span >= 2^63 overflows and makes it build a + // pathologically-sized jump table, OOM-crashing the tab. + // WebKit bug: https://bugs.webkit.org/show_bug.cgi?id=317022 + // Odin issue/PR: https://github.com/odin-lang/Odin/issues/6810 + hash &= 0x7fffffffffffffffull; + hash = hash ? hash : 1; + } type->canonical_hash.store(hash, std::memory_order_relaxed);