/lib/hipe/icode/hipe_icode_coordinator.erl

http://erlang.googlecode.com/ · Erlang · 255 lines · 214 code · 28 blank · 13 comment · 2 complexity · a679ef1a105c8970e8bc7ea1e9aec86d MD5 · raw file

  1. %% -*- erlang-indent-level: 2 -*-
  2. %%--------------------------------------------------------------------
  3. %% File : hipe_icode_coordinator.erl
  4. %% Author : Per Gustafsson <pergu@it.uu.se>
  5. %% Description : This module coordinates an Icode pass.
  6. %% Created : 20 Feb 2007 by Per Gustafsson <pergu@it.uu.se>
  7. %%---------------------------------------------------------------------
  8. -module(hipe_icode_coordinator).
  9. -export([coordinate/4]).
  10. -include("hipe_icode.hrl").
  11. -include("../util/hipe_digraph.hrl").
  12. %%---------------------------------------------------------------------
  13. -define(MAX_CONCURRENT, erlang:system_info(schedulers)).
  14. %%---------------------------------------------------------------------
  15. -spec coordinate(#hipe_digraph{}, [{mfa(),bool()}], [mfa()], atom()) -> no_return().
  16. coordinate(CG, Escaping, NonEscaping, Mod) ->
  17. ServerPid = initialize_server(Escaping, Mod),
  18. Clean = [MFA || {MFA, _} <- Escaping],
  19. All = NonEscaping ++ Clean,
  20. Restart =
  21. fun(MFALists, PM) -> restart_funs(MFALists, PM, All, ServerPid) end,
  22. LastAction =
  23. fun(PM) -> last_action(PM, ServerPid, Mod, All) end,
  24. coordinate({Clean,All}, CG, gb_trees:empty(), Restart, LastAction, ServerPid).
  25. coordinate(MFALists, CG, PM, Restart, LastAction, ServerPid) ->
  26. case MFALists of
  27. {[], []} ->
  28. LastAction(PM),
  29. ServerPid ! stop,
  30. receive
  31. {stop, Ans2Pid} ->
  32. Ans2Pid ! {done, self()},
  33. exit(normal)
  34. end;
  35. _ -> ok
  36. end,
  37. receive
  38. {stop, AnsPid} ->
  39. ServerPid ! stop,
  40. AnsPid ! {done, self()},
  41. exit(normal);
  42. Message ->
  43. {NewPM, NewMFALists} =
  44. case Message of
  45. {restart_call, MFA} ->
  46. {PM,handle_restart_call(MFA, MFALists)};
  47. {ready, {MFA, Pid}} ->
  48. handle_ready(MFA, Pid, MFALists, PM);
  49. {restart_done, MFA} ->
  50. {PM, handle_restart_done(MFA, MFALists, CG)};
  51. {no_change_done, MFA} ->
  52. {PM, handle_no_change_done(MFA, MFALists)}
  53. end,
  54. coordinate(Restart(NewMFALists, NewPM), CG, NewPM, Restart,
  55. LastAction, ServerPid)
  56. end.
  57. handle_restart_call(MFA, {Queue, Busy}) ->
  58. case lists:member(MFA, Queue) of
  59. true ->
  60. {Queue, Busy};
  61. false ->
  62. {[MFA|Queue], Busy}
  63. end.
  64. handle_ready(MFA, Pid, {Queue, Busy}, PM) ->
  65. {gb_trees:insert(MFA, Pid, PM), {Queue, Busy -- [MFA]}}.
  66. handle_restart_done(MFA, {Queue, Busy}, CG) ->
  67. Restarts = hipe_digraph:get_parents(MFA, CG),
  68. {ordsets:from_list(Restarts ++ Queue), Busy -- [MFA]}.
  69. handle_no_change_done(MFA, {Queue, Busy}) ->
  70. {Queue, Busy -- [MFA]}.
  71. last_action(PM, ServerPid, Mod, All) ->
  72. lists:foreach(fun(MFA) -> gb_trees:get(MFA, PM) ! {done, final_funs(ServerPid, Mod)},
  73. receive
  74. {done_rewrite, MFA} -> ok
  75. end
  76. end, All),
  77. ok.
  78. restart_funs({Queue, Busy}, PM, All, ServerPid) ->
  79. case ?MAX_CONCURRENT - length(Busy) of
  80. X when is_integer(X), X > 0 ->
  81. Possible = [Pos || Pos <- Queue, (not lists:member(Pos, Busy))],
  82. Restarts = lists:sublist(Possible, X),
  83. lists:foreach(fun(MFA) ->
  84. restart_fun(MFA, PM, All, ServerPid)
  85. end, Restarts),
  86. {Queue -- Restarts, Busy ++ Restarts};
  87. X when is_integer(X) ->
  88. {Queue, Busy}
  89. end.
  90. initialize_server(Escaping, Mod) ->
  91. Pid = spawn_link(fun () -> info_server(Mod) end),
  92. lists:foreach(fun ({MFA, _}) ->
  93. Pid ! {set_escaping, MFA}
  94. end, Escaping),
  95. Pid.
  96. safe_get_args(MFA, Cfg, Pid, Mod) ->
  97. Mod:replace_nones(get_args(MFA, Cfg, Pid)).
  98. get_args(MFA, Cfg, Pid) ->
  99. Ref = make_ref(),
  100. Pid ! {get_call, MFA, Cfg, self(), Ref},
  101. receive
  102. {Ref, Types} ->
  103. Types
  104. end.
  105. safe_get_res(MFA, Pid, Mod) ->
  106. Mod:replace_nones(get_res(MFA, Pid)).
  107. get_res(MFA, Pid) ->
  108. Ref = make_ref(),
  109. Pid ! {get_return, MFA, self(), Ref},
  110. receive
  111. {Ref, Types} ->
  112. Types
  113. end.
  114. update_return_type(MFA, NewType, Pid) ->
  115. Ref = make_ref(),
  116. Pid ! {update_return, MFA, NewType, self(), Ref},
  117. receive
  118. {Ref, Ans} ->
  119. Ans
  120. end.
  121. update_call_type(MFA, NewTypes, Pid) ->
  122. Ref = make_ref(),
  123. Pid ! {update_call, MFA, NewTypes, self(), Ref},
  124. receive
  125. {Ref, Ans} ->
  126. Ans
  127. end.
  128. restart_fun(MFA, PM, All, ServerPid) ->
  129. gb_trees:get(MFA, PM) ! {analyse, analysis_funs(All, ServerPid)},
  130. ok.
  131. analysis_funs(All, Pid) ->
  132. Self = self(),
  133. ArgsFun = fun (MFA, Cfg) -> get_args(MFA, Cfg, Pid) end,
  134. GetResFun = fun (MFA, Args) ->
  135. case lists:member(MFA, All) of
  136. true ->
  137. case update_call_type(MFA, Args, Pid) of
  138. do_restart ->
  139. Self ! {restart_call, MFA},
  140. ok;
  141. no_change ->
  142. ok
  143. end;
  144. false ->
  145. ok
  146. end,
  147. [Ans] = get_res(MFA, Pid),
  148. Ans
  149. end,
  150. FinalFun = fun (MFA, RetTypes) ->
  151. case update_return_type(MFA, RetTypes, Pid) of
  152. do_restart ->
  153. Self ! {restart_done, MFA},
  154. ok;
  155. no_change ->
  156. Self ! {no_change_done, MFA},
  157. ok
  158. end
  159. end,
  160. {ArgsFun, GetResFun, FinalFun}.
  161. final_funs(Pid,Mod) ->
  162. ArgsFun = fun (MFA, Cfg) -> safe_get_args(MFA, Cfg, Pid, Mod) end,
  163. GetResFun = fun (MFA, _) ->
  164. [Ans] = safe_get_res(MFA, Pid, Mod),
  165. Ans
  166. end,
  167. FinalFun = fun(_,_) -> ok end,
  168. {ArgsFun, GetResFun, FinalFun}.
  169. info_server(Mod) ->
  170. info_server_loop(gb_trees:empty(), gb_trees:empty(), Mod).
  171. info_server_loop(CallInfo, ReturnInfo, Mod) ->
  172. receive
  173. {update_return, MFA, NewInfo, Pid, Ref} ->
  174. NewReturnInfo = handle_update(MFA, ReturnInfo, NewInfo, Pid, Ref, Mod),
  175. info_server_loop(CallInfo, NewReturnInfo, Mod);
  176. {update_call, MFA, NewInfo, Pid, Ref} ->
  177. NewCallInfo = handle_update(MFA, CallInfo, NewInfo, Pid, Ref, Mod),
  178. info_server_loop(NewCallInfo, ReturnInfo, Mod);
  179. {get_return, MFA, Pid, Ref} ->
  180. Ans =
  181. case gb_trees:lookup(MFA,ReturnInfo) of
  182. none ->
  183. Mod:return_none();
  184. {value, TypesComp} ->
  185. Mod:return__info((TypesComp))
  186. end,
  187. Pid ! {Ref, Ans},
  188. info_server_loop(CallInfo, ReturnInfo, Mod);
  189. {get_call, MFA, Cfg, Pid, Ref} ->
  190. Ans =
  191. case gb_trees:lookup(MFA, CallInfo) of
  192. none ->
  193. Mod:return_none_args(Cfg, MFA);
  194. {value, escaping} ->
  195. Mod:return_any_args(Cfg, MFA);
  196. {value, TypesComp} ->
  197. Mod:return__info((TypesComp))
  198. end,
  199. Pid ! {Ref, Ans},
  200. info_server_loop(CallInfo, ReturnInfo, Mod);
  201. {set_escaping, MFA} ->
  202. info_server_loop(gb_trees:enter(MFA,escaping,CallInfo),ReturnInfo,Mod);
  203. stop ->
  204. ok
  205. end.
  206. handle_update(MFA, Tree, NewInfo, Pid, Ref, Mod) ->
  207. case gb_trees:lookup(MFA,Tree) of
  208. none ->
  209. %% io:format("First Type: ~w ~w~n", [NewType, MFA]),
  210. Pid ! {Ref, do_restart},
  211. ResType = Mod:new__info(NewInfo);
  212. {value, escaping} ->
  213. Pid ! {Ref, no_change},
  214. ResType = escaping;
  215. {value, OldInfoComp} ->
  216. OldInfo = (OldInfoComp),
  217. %% io:format("New Type: ~w ~w~n", [NewType,MFA]),
  218. %% io:format("Old Type: ~w ~w~n", [OldType,MFA]),
  219. case Mod:update__info(NewInfo, OldInfo) of
  220. {true, ResType} ->
  221. Pid ! {Ref, no_change};
  222. {false, ResType} ->
  223. Pid ! {Ref, do_restart}
  224. end
  225. end,
  226. %% ResType = binary_to_term(term_to_binary(ResType)),
  227. gb_trees:enter(MFA, ResType, Tree).