/lib/dialyzer/src/dialyzer_codeserver.erl

http://erlang.googlecode.com/ · Erlang · 183 lines · 134 code · 24 blank · 25 comment · 3 complexity · 5e3c447d6cb4f0e2007b098ce5980917 MD5 · raw file

  1. %% -*- erlang-indent-level: 2 -*-
  2. %%-----------------------------------------------------------------------
  3. %% ``The contents of this file are subject to the Erlang Public License,
  4. %% Version 1.1, (the "License"); you may not use this file except in
  5. %% compliance with the License. You should have received a copy of the
  6. %% Erlang Public License along with this software. If not, it can be
  7. %% retrieved via the world wide web at http://www.erlang.org/.
  8. %%
  9. %% Software distributed under the License is distributed on an "AS IS"
  10. %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
  11. %% the License for the specific language governing rights and limitations
  12. %% under the License.
  13. %%
  14. %% Copyright 2006-2008, Tobias Lindahl and Kostis Sagonas
  15. %%
  16. %% $Id$
  17. %%
  18. %%%-------------------------------------------------------------------
  19. %%% File : dialyzer_codeserver.erl
  20. %%% Author : Tobias Lindahl <tobiasl@it.uu.se>
  21. %%% Description :
  22. %%%
  23. %%% Created : 4 Apr 2005 by Tobias Lindahl <tobiasl@it.uu.se>
  24. %%%-------------------------------------------------------------------
  25. -module(dialyzer_codeserver).
  26. -export([all_exports/1,
  27. delete/1,
  28. insert/2,
  29. insert_exports/2,
  30. is_exported/2,
  31. lookup/2,
  32. lookup_records/2,
  33. lookup_contracts/2,
  34. lookup_contract/2,
  35. new/0,
  36. next_core_label/1,
  37. store_records/3,
  38. store_contracts/3,
  39. update_next_core_label/2]).
  40. -include("dialyzer.hrl").
  41. %%--------------------------------------------------------------------
  42. -spec new() -> #dialyzer_codeserver{}.
  43. new() ->
  44. Table = table__new(),
  45. Exports = sets:new(),
  46. #dialyzer_codeserver{table=Table, exports=Exports, next_core_label=0,
  47. records=dict:new(), contracts=dict:new()}.
  48. -spec delete(#dialyzer_codeserver{}) -> 'ok'.
  49. delete(#dialyzer_codeserver{table=Table}) ->
  50. table__delete(Table).
  51. -spec insert([_], #dialyzer_codeserver{}) -> #dialyzer_codeserver{}.
  52. insert(List, CS) ->
  53. NewTable = table__insert(CS#dialyzer_codeserver.table, List),
  54. CS#dialyzer_codeserver{table=NewTable}.
  55. -spec insert_exports([mfa()], #dialyzer_codeserver{}) -> #dialyzer_codeserver{}.
  56. insert_exports(List, CS = #dialyzer_codeserver{exports=Exports}) ->
  57. Set = sets:from_list(List),
  58. NewExports = sets:union(Exports, Set),
  59. CS#dialyzer_codeserver{exports=NewExports}.
  60. -spec is_exported(mfa(), #dialyzer_codeserver{}) -> bool().
  61. is_exported(MFA, #dialyzer_codeserver{exports=Exports}) ->
  62. sets:is_element(MFA, Exports).
  63. -spec all_exports(#dialyzer_codeserver{}) -> set().
  64. all_exports(#dialyzer_codeserver{exports=Exports}) ->
  65. Exports.
  66. -spec lookup(_, #dialyzer_codeserver{}) -> any().
  67. lookup(Id, CS) ->
  68. table__lookup(CS#dialyzer_codeserver.table, Id).
  69. -spec next_core_label(#dialyzer_codeserver{}) -> non_neg_integer().
  70. next_core_label(#dialyzer_codeserver{next_core_label=NCL}) ->
  71. NCL.
  72. -spec update_next_core_label(non_neg_integer(), #dialyzer_codeserver{}) -> #dialyzer_codeserver{}.
  73. update_next_core_label(NCL, CS = #dialyzer_codeserver{}) ->
  74. CS#dialyzer_codeserver{next_core_label=NCL}.
  75. -spec store_records(atom(), dict(), #dialyzer_codeserver{}) -> #dialyzer_codeserver{}.
  76. store_records(Module, Dict,
  77. CS=#dialyzer_codeserver{records=RecDict}) when is_atom(Module) ->
  78. case dict:size(Dict) =:= 0 of
  79. true -> CS;
  80. false ->
  81. CS#dialyzer_codeserver{records=dict:store(Module, Dict, RecDict)}
  82. end.
  83. -spec lookup_records(atom(), #dialyzer_codeserver{}) -> dict().
  84. lookup_records(Module,
  85. #dialyzer_codeserver{records=RecDict}) when is_atom(Module) ->
  86. case dict:find(Module, RecDict) of
  87. error -> dict:new();
  88. {ok, Dict} -> Dict
  89. end.
  90. -spec store_contracts(atom(), dict(), #dialyzer_codeserver{}) -> #dialyzer_codeserver{}.
  91. store_contracts(Module, Dict,
  92. CS=#dialyzer_codeserver{contracts=C}) when is_atom(Module) ->
  93. case dict:size(Dict) =:= 0 of
  94. true -> CS;
  95. false -> CS#dialyzer_codeserver{contracts=dict:store(Module, Dict, C)}
  96. end.
  97. -spec lookup_contracts(atom(), #dialyzer_codeserver{}) -> dict().
  98. lookup_contracts(Mod,
  99. #dialyzer_codeserver{contracts=ContDict}) when is_atom(Mod) ->
  100. case dict:find(Mod, ContDict) of
  101. error -> dict:new();
  102. {ok, Dict} -> Dict
  103. end.
  104. -spec lookup_contract(mfa(), #dialyzer_codeserver{}) -> 'error' | {'ok',_}.
  105. lookup_contract(MFA={M,_F,_A}, #dialyzer_codeserver{contracts=ContDict}) ->
  106. case dict:find(M, ContDict) of
  107. error -> error;
  108. {ok, Dict} -> dict:find(MFA, Dict)
  109. end.
  110. table__new() ->
  111. spawn_link(fun() -> table__loop(none, dict:new()) end).
  112. table__delete(TablePid) ->
  113. TablePid ! stop,
  114. ok.
  115. table__lookup(TablePid, Key) ->
  116. TablePid ! {self(), lookup, Key},
  117. receive
  118. {TablePid, Key, Ans} -> Ans
  119. end.
  120. table__insert(Table, List) ->
  121. List1 = [{Key, term_to_binary(Val, [compressed])} || {Key, Val} <- List],
  122. Table ! {insert, List1},
  123. Table.
  124. table__loop(Cached, Map) ->
  125. receive
  126. stop -> ok;
  127. {Pid, lookup, Key = {M, F, A}} ->
  128. {NewCached, Ans} =
  129. case Cached of
  130. {M, Tree} ->
  131. [Val] = [{Var, Fun} || {Var, Fun} <- cerl:module_defs(Tree),
  132. cerl:fname_id(Var) =:= F,
  133. cerl:fname_arity(Var) =:= A],
  134. {Cached, Val};
  135. _ ->
  136. Tree = fetch_and_expand(M, Map),
  137. [Val] = [{Var, Fun} || {Var, Fun} <- cerl:module_defs(Tree),
  138. cerl:fname_id(Var) =:= F,
  139. cerl:fname_arity(Var) =:= A],
  140. {{M, Tree}, Val}
  141. end,
  142. Pid ! {self(), Key, {ok, Ans}},
  143. table__loop(NewCached, Map);
  144. {Pid, lookup, Key} ->
  145. Ans = case Cached of
  146. {Key, Tree} -> Tree;
  147. _ -> fetch_and_expand(Key, Map)
  148. end,
  149. Pid ! {self(), Key, {ok, Ans}},
  150. table__loop({Key, Ans}, Map);
  151. {insert, List} ->
  152. NewMap = lists:foldl(fun({Key, Val}, AccMap) ->
  153. dict:store(Key, Val, AccMap)
  154. end, Map, List),
  155. table__loop(Cached, NewMap)
  156. end.
  157. fetch_and_expand(Key, Map) ->
  158. Bin = dict:fetch(Key, Map),
  159. binary_to_term(Bin).