aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorRaimo Niskanen <[email protected]>2019-01-17 12:17:30 +0100
committerRaimo Niskanen <[email protected]>2019-01-17 16:04:58 +0100
commit7c0df9ac2879e5d5bcdf511fc81b1465105c4b61 (patch)
tree3c191c353937a438a9cad0126f4e9eb791a46bd2 /lib
parentdfb91c491f1bd21b8c05ed38e5addedd6ddf7292 (diff)
downloadotp-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')
-rw-r--r--lib/stdlib/src/gen_statem.erl48
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} =