Skip to content

Commit f45f964

Browse files
castholmandrewrk
authored andcommitted
Lower @returnAddress to a constant 0 in Emscripten release builds
Emscripten currently implements `emscripten_return_address()` by calling out into JavaScript and parsing a stack trace, which introduces significant overhead that we would prefer to avoid in release builds. This is especially problematic for allocators because the generic parts of `std.mem.Allocator` make frequent use of `@returnAddress`, even though very few allocator implementations even observe the return address, which makes allocators nigh unusable for performance-critical applications like games if the compiler is unable to devirtualize the allocator calls.
1 parent 9f235a1 commit f45f964

File tree

3 files changed

+11
-4
lines changed

3 files changed

+11
-4
lines changed

lib/std/debug.zig

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,9 +183,11 @@ pub const sys_can_stack_trace = switch (builtin.cpu.arch) {
183183

184184
// `@returnAddress()` in LLVM 10 gives
185185
// "Non-Emscripten WebAssembly hasn't implemented __builtin_return_address".
186+
// On Emscripten, Zig only supports `@returnAddress()` in debug builds
187+
// because Emscripten's implementation is very slow.
186188
.wasm32,
187189
.wasm64,
188-
=> native_os == .emscripten,
190+
=> native_os == .emscripten and builtin.mode == .Debug,
189191

190192
// `@returnAddress()` is unsupported in LLVM 13.
191193
.bpfel,

src/codegen/llvm.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9525,7 +9525,7 @@ pub const FuncGen = struct {
95259525
_ = inst;
95269526
const o = self.ng.object;
95279527
const llvm_usize = try o.lowerType(Type.usize);
9528-
if (!target_util.supportsReturnAddress(o.pt.zcu.getTarget())) {
9528+
if (!target_util.supportsReturnAddress(o.pt.zcu.getTarget(), self.ng.ownerModule().optimize_mode)) {
95299529
// https://github.com/ziglang/zig/issues/11946
95309530
return o.builder.intValue(llvm_usize, 0);
95319531
}

src/target.zig

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -248,9 +248,14 @@ pub fn libcProvidesStackProtector(target: std.Target) bool {
248248
return !target.isMinGW() and target.os.tag != .wasi and !target.cpu.arch.isSpirV();
249249
}
250250

251-
pub fn supportsReturnAddress(target: std.Target) bool {
251+
/// Returns true if `@returnAddress()` is supported by the target and has a
252+
/// reasonably performant implementation for the requested optimization mode.
253+
pub fn supportsReturnAddress(target: std.Target, optimize: std.builtin.OptimizeMode) bool {
252254
return switch (target.cpu.arch) {
253-
.wasm32, .wasm64 => target.os.tag == .emscripten,
255+
// Emscripten currently implements `emscripten_return_address()` by calling
256+
// out into JavaScript and parsing a stack trace, which introduces significant
257+
// overhead that we would prefer to avoid in release builds.
258+
.wasm32, .wasm64 => target.os.tag == .emscripten and optimize == .Debug,
254259
.bpfel, .bpfeb => false,
255260
.spirv, .spirv32, .spirv64 => false,
256261
else => true,

0 commit comments

Comments
 (0)