aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHans Bolinder <[email protected]>2016-12-28 19:22:42 +0100
committerHans Bolinder <[email protected]>2017-01-11 09:34:59 +0100
commit5d9e51a4271833855519df37df8f964216a0e594 (patch)
tree7e1f58c7daa7cd0483b6378694df495e5b2da136
parent66d387c039156989a6ea834033888ac50f1efc1e (diff)
downloadotp-5d9e51a4271833855519df37df8f964216a0e594.tar.gz
otp-5d9e51a4271833855519df37df8f964216a0e594.tar.bz2
otp-5d9e51a4271833855519df37df8f964216a0e594.zip
dialyzer: Use less memory when translating contracts
-rw-r--r--lib/dialyzer/src/dialyzer_codeserver.erl83
-rw-r--r--lib/dialyzer/src/dialyzer_contracts.erl28
2 files changed, 58 insertions, 53 deletions
diff --git a/lib/dialyzer/src/dialyzer_codeserver.erl b/lib/dialyzer/src/dialyzer_codeserver.erl
index c05a7a075b..ba278b627a 100644
--- a/lib/dialyzer/src/dialyzer_codeserver.erl
+++ b/lib/dialyzer/src/dialyzer_codeserver.erl
@@ -29,7 +29,8 @@
-module(dialyzer_codeserver).
-export([delete/1,
- finalize_contracts/3,
+ store_temp_contracts/4,
+ finalize_contracts/1,
finalize_exported_types/2,
finalize_records/2,
get_contracts/1,
@@ -38,7 +39,9 @@
get_exports/1,
get_records/1,
get_next_core_label/1,
- get_temp_contracts/1,
+ get_temp_contracts/2,
+ contracts_modules/1,
+ store_contracts/4,
get_temp_exported_types/1,
get_temp_records/1,
insert/3,
@@ -56,8 +59,7 @@
new/0,
set_next_core_label/2,
set_temp_records/2,
- store_temp_records/3,
- store_temp_contracts/4]).
+ store_temp_records/3]).
-export_type([codeserver/0, fun_meta_info/0, contracts/0]).
@@ -85,8 +87,8 @@
code :: dict_ets(),
exported_types :: set_ets() | 'undefined', % set(mfa())
records :: map_ets() | 'undefined',
- contracts :: map_ets() | 'undefined',
- callbacks :: map_ets() | 'undefined',
+ contracts :: map_ets(),
+ callbacks :: map_ets(),
fun_meta_info :: dict_ets(), % {mfa(), meta_info()}
exports :: 'clean' | set_ets(), % set(mfa())
temp_exported_types :: 'clean' | set_ets(), % set(mfa())
@@ -141,6 +143,8 @@ new() ->
CodeOptions = [compressed, public, {read_concurrency, true}],
Code = ets:new(dialyzer_codeserver_code, CodeOptions),
TempOptions = [public, {write_concurrency, true}],
+ Contracts = ets_read_concurrent_table(dialyzer_codeserver_contracts),
+ Callbacks = ets_read_concurrent_table(dialyzer_codeserver_callbacks),
[Exports, FunMetaInfo, TempExportedTypes, TempRecords, TempContracts,
TempCallbacks] =
[ets:new(Name, TempOptions) ||
@@ -152,6 +156,8 @@ new() ->
#codeserver{code = Code,
exports = Exports,
fun_meta_info = FunMetaInfo,
+ contracts = Contracts,
+ callbacks = Callbacks,
temp_exported_types = TempExportedTypes,
temp_records = TempRecords,
temp_contracts = TempContracts,
@@ -341,44 +347,43 @@ store_temp_contracts(Mod, SpecMap, CallbackMap,
#codeserver{temp_contracts = Cn,
temp_callbacks = Cb} = CS)
when is_atom(Mod) ->
- CS1 =
- case maps:size(SpecMap) =:= 0 of
- true -> CS;
- false ->
- CS#codeserver{temp_contracts = ets_map_store(Mod, SpecMap, Cn)}
- end,
- case maps:size(CallbackMap) =:= 0 of
- true -> CS1;
- false ->
- CS1#codeserver{temp_callbacks = ets_map_store(Mod, CallbackMap, Cb)}
- end.
+ CS1 = CS#codeserver{temp_contracts = ets_map_store(Mod, SpecMap, Cn)},
+ CS1#codeserver{temp_callbacks = ets_map_store(Mod, CallbackMap, Cb)}.
--spec get_temp_contracts(codeserver()) -> {mod_contracts(), mod_contracts()}.
+-spec contracts_modules(codeserver()) -> [module()].
-get_temp_contracts(#codeserver{temp_contracts = TempContDict,
- temp_callbacks = TempCallDict}) ->
- {ets_dict_to_dict(TempContDict), ets_dict_to_dict(TempCallDict)}.
+contracts_modules(#codeserver{temp_contracts = TempContTable}) ->
+ ets:select(TempContTable, [{{'$1', '$2'}, [], ['$1']}]).
--spec finalize_contracts(mod_contracts(), mod_contracts(), codeserver()) ->
- codeserver().
+-spec store_contracts(module(), contracts(), contracts(), codeserver()) ->
+ codeserver().
-finalize_contracts(SpecDict, CallbackDict, CS) ->
- Contracts = ets_read_concurrent_table(dialyzer_codeserver_contracts),
- Callbacks = ets_read_concurrent_table(dialyzer_codeserver_callbacks),
- Contracts = dict:fold(fun decompose_spec_dict/3, Contracts, SpecDict),
- Callbacks = dict:fold(fun decompose_cb_dict/3, Callbacks, CallbackDict),
- CS#codeserver{contracts = Contracts, callbacks = Callbacks,
- temp_contracts = clean, temp_callbacks = clean}.
-
-decompose_spec_dict(Mod, Map, Table) ->
- Keys = maps:keys(Map),
- true = ets:insert(Table, maps:to_list(Map)),
- true = ets:insert(Table, {Mod, Keys}),
- Table.
+store_contracts(Mod, SpecMap, CallbackMap, CS) ->
+ #codeserver{contracts = SpecDict, callbacks = CallbackDict} = CS,
+ Keys = maps:keys(SpecMap),
+ true = ets:insert(SpecDict, maps:to_list(SpecMap)),
+ true = ets:insert(SpecDict, {Mod, Keys}),
+ true = ets:insert(CallbackDict, maps:to_list(CallbackMap)),
+ CS.
-decompose_cb_dict(_Mod, Map, Table) ->
- true = ets:insert(Table, maps:to_list(Map)),
- Table.
+-spec get_temp_contracts(module(), codeserver()) ->
+ {contracts(), contracts()}.
+
+get_temp_contracts(Mod, #codeserver{temp_contracts = TempContDict,
+ temp_callbacks = TempCallDict}) ->
+ [{Mod, Contracts}] = ets:lookup(TempContDict, Mod),
+ true = ets:delete(TempContDict, Mod),
+ [{Mod, Callbacks}] = ets:lookup(TempCallDict, Mod),
+ true = ets:delete(TempCallDict, Mod),
+ {Contracts, Callbacks}.
+
+-spec finalize_contracts(codeserver()) -> codeserver().
+
+finalize_contracts(#codeserver{temp_contracts = TempContDict,
+ temp_callbacks = TempCallDict} = CS) ->
+ true = ets:delete(TempContDict),
+ true = ets:delete(TempCallDict),
+ CS#codeserver{temp_contracts = clean, temp_callbacks = clean}.
table__lookup(TablePid, M) when is_atom(M) ->
{Name, Exports, Attrs, Keys, As} = ets:lookup_element(TablePid, M, 2),
diff --git a/lib/dialyzer/src/dialyzer_contracts.erl b/lib/dialyzer/src/dialyzer_contracts.erl
index d3ed4435ad..c0a4c6892c 100644
--- a/lib/dialyzer/src/dialyzer_contracts.erl
+++ b/lib/dialyzer/src/dialyzer_contracts.erl
@@ -150,8 +150,7 @@ sequence([H|T], Delimiter) -> H ++ Delimiter ++ sequence(T, Delimiter).
dialyzer_codeserver:codeserver().
process_contract_remote_types(CodeServer) ->
- {TmpContractDict, TmpCallbackDict} =
- dialyzer_codeserver:get_temp_contracts(CodeServer),
+ Mods = dialyzer_codeserver:contracts_modules(CodeServer),
ExpTypes = dialyzer_codeserver:get_exported_types(CodeServer),
RecordDict = dialyzer_codeserver:get_records(CodeServer),
ContractFun =
@@ -165,21 +164,22 @@ process_contract_remote_types(CodeServer) ->
{{MFA, {File, Contract, Xtra}}, C2}
end,
ModuleFun =
- fun({ModuleName, ContractMap}) ->
+ fun(ModuleName) ->
Cache = erl_types:cache__new(),
- {NewContractList, _NewCache} =
+ {ContractMap, CallbackMap} =
+ dialyzer_codeserver:get_temp_contracts(ModuleName, CodeServer),
+ {NewContractList, Cache1} =
lists:mapfoldl(ContractFun, Cache, maps:to_list(ContractMap)),
- {ModuleName, maps:from_list(NewContractList)}
+ {NewCallbackList, _NewCache} =
+ lists:mapfoldl(ContractFun, Cache1, maps:to_list(CallbackMap)),
+ dialyzer_codeserver:store_contracts(ModuleName,
+ maps:from_list(NewContractList),
+ maps:from_list(NewCallbackList),
+ CodeServer)
end,
- erlang:garbage_collect(),
- NewContractList = lists:map(ModuleFun, dict:to_list(TmpContractDict)),
- NewCallbackList = lists:map(ModuleFun, dict:to_list(TmpCallbackDict)),
- NewContractDict = dict:from_list(NewContractList),
- NewCallbackDict = dict:from_list(NewCallbackList),
- %% Make sure temporary data and the (huge) cache are garbage collected:
- erlang:garbage_collect(),
- dialyzer_codeserver:finalize_contracts(NewContractDict, NewCallbackDict,
- CodeServer).
+ lists:foreach(ModuleFun, Mods),
+ %% erlang:garbage_collect(),
+ dialyzer_codeserver:finalize_contracts(CodeServer).
-type opaques_fun() :: fun((module()) -> [erl_types:erl_type()]).