From 7c0df9ac2879e5d5bcdf511fc81b1465105c4b61 Mon Sep 17 00:00:00 2001 From: Raimo Niskanen Date: Thu, 17 Jan 2019 12:17:30 +0100 Subject: Work around a compiler mis-optimization The common subexpression optimization accidentally caused unnecessary spilling of live registers. A rather ugly workaround can be found in loop_timeouts_cancel. --- lib/stdlib/src/gen_statem.erl | 48 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 40 insertions(+), 8 deletions(-) (limited to 'lib/stdlib/src/gen_statem.erl') diff --git a/lib/stdlib/src/gen_statem.erl b/lib/stdlib/src/gen_statem.erl index 819efa57b8..beb37e43e0 100644 --- a/lib/stdlib/src/gen_statem.erl +++ b/lib/stdlib/src/gen_statem.erl @@ -1838,7 +1838,7 @@ loop_timeouts( P, Debug, S, Events, NextState_NewData, NextEventsR, Hibernate, TimeoutsR, Postponed, - Timers, Seen, TimeoutEvents, + {TimerRefs,TimeoutTypes} = Timers, Seen, TimeoutEvents, TimeoutType, Time, TimeoutMsg, TimeoutOpts) -> %% case Time of @@ -1854,13 +1854,32 @@ loop_timeouts( %% Relative timeout zero %% - cancel any running timer %% handle timeout zero events later - Timers_1 = cancel_timer_by_type(TimeoutType, Timers), - loop_timeouts( - P, Debug, S, - Events, NextState_NewData, - NextEventsR, Hibernate, TimeoutsR, Postponed, - Timers_1, Seen#{TimeoutType => true}, - [{TimeoutType,TimeoutMsg}|TimeoutEvents]); + %% + %% Instead of using cancel_timer_by_type/2 here, duplicate + %% the code, so we can make the function exit differ, + %% so the common subexpression optimization does not + %% kick in and accidentally force spilling all live + %% registers for the no TimeoutType match path + case TimeoutTypes of + #{TimeoutType := TimerRef} -> + Timers_1 = + cancel_timer_by_ref_and_type( + TimerRef, TimeoutType, TimerRefs, TimeoutTypes), + loop_timeouts( + P, Debug, S, + Events, NextState_NewData, + NextEventsR, Hibernate, TimeoutsR, Postponed, + Timers_1, Seen, + [{TimeoutType,TimeoutMsg}|TimeoutEvents], + TimeoutType); + #{} -> + loop_timeouts( + P, Debug, S, + Events, NextState_NewData, + NextEventsR, Hibernate, TimeoutsR, Postponed, + Timers, Seen#{TimeoutType => true}, + [{TimeoutType,TimeoutMsg}|TimeoutEvents]) + end; _ -> %% (Re)start the timer TimerRef = @@ -1895,6 +1914,19 @@ loop_timeouts( Timers_1, Seen#{TimeoutType => true}, TimeoutEvents) end end. +%% +loop_timeouts( + P, Debug, S, + Events, NextState_NewData, + NextEventsR, Hibernate, TimeoutsR, Postponed, + Timers, Seen, TimeoutEvents, + TimeoutType) -> + %% + loop_timeouts( + P, Debug, S, + Events, NextState_NewData, + NextEventsR, Hibernate, TimeoutsR, Postponed, + Timers, Seen#{TimeoutType => true}, TimeoutEvents). loop_prepend_timeout_events(P, Debug, S, TimeoutEvents, EventsR) -> {Debug_1,Events_1R} = -- cgit v1.2.3