diff options
author | Raimo Niskanen <[email protected]> | 2019-01-17 12:17:30 +0100 |
---|---|---|
committer | Raimo Niskanen <[email protected]> | 2019-01-17 16:04:58 +0100 |
commit | 7c0df9ac2879e5d5bcdf511fc81b1465105c4b61 (patch) | |
tree | 3c191c353937a438a9cad0126f4e9eb791a46bd2 /lib/stdlib | |
parent | dfb91c491f1bd21b8c05ed38e5addedd6ddf7292 (diff) | |
download | otp-7c0df9ac2879e5d5bcdf511fc81b1465105c4b61.tar.gz otp-7c0df9ac2879e5d5bcdf511fc81b1465105c4b61.tar.bz2 otp-7c0df9ac2879e5d5bcdf511fc81b1465105c4b61.zip |
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.
Diffstat (limited to 'lib/stdlib')
-rw-r--r-- | lib/stdlib/src/gen_statem.erl | 48 |
1 files changed, 40 insertions, 8 deletions
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} = |