aboutsummaryrefslogtreecommitdiffstats
path: root/lib/compiler/src
diff options
context:
space:
mode:
authorBjörn Gustavsson <[email protected]>2015-11-09 16:14:16 +0100
committerBjörn Gustavsson <[email protected]>2015-11-10 13:04:56 +0100
commitf51512fadee8f9ef817bfc0af8ba92a532f8def2 (patch)
tree5db16e00c0365bcc8832a100acfa7261790f69c1 /lib/compiler/src
parente28fdaaad1c367bd073116fa0468ae22303189c2 (diff)
downloadotp-f51512fadee8f9ef817bfc0af8ba92a532f8def2.tar.gz
otp-f51512fadee8f9ef817bfc0af8ba92a532f8def2.tar.bz2
otp-f51512fadee8f9ef817bfc0af8ba92a532f8def2.zip
sys_pre_expand: Clean up data structures
The handling of non-remote calls is messy, with several lookups to determine whether the call is local or to some imported module. We can simplify the code if we keep a map that immediately gives us the answer. Here is an example of what the map entries look like: {f,1} => local {foldl,3} => {imported,lists} That is, there should be a local call to f/1 and a remote call to lists:foldl/3. Note that there is no longer any need to keep the set of all defined functions in the state record.
Diffstat (limited to 'lib/compiler/src')
-rw-r--r--lib/compiler/src/sys_pre_expand.erl115
1 files changed, 48 insertions, 67 deletions
diff --git a/lib/compiler/src/sys_pre_expand.erl b/lib/compiler/src/sys_pre_expand.erl
index e0c35d63e4..21961bc020 100644
--- a/lib/compiler/src/sys_pre_expand.erl
+++ b/lib/compiler/src/sys_pre_expand.erl
@@ -35,21 +35,20 @@
-record(expand, {module=[], %Module name
exports=[], %Exports
- imports=[], %Imports
attributes=[], %Attributes
callbacks=[], %Callbacks
optional_callbacks=[] :: [fa()], %Optional callbacks
- defined, %Defined functions (gb_set)
vcount=0, %Variable counter
func=[], %Current function
arity=[], %Arity for current function
- fcount=0 %Local fun count
+ fcount=0, %Local fun count
+ ctype %Call type map
}).
%% module(Forms, CompileOptions)
%% {ModuleName,Exports,TransformedForms,CompileOptions'}
-%% Expand the forms in one module. N.B.: the lists of predefined
-%% exports and imports are really ordsets!
+%% Expand the forms in one module.
+%%
%% CompileOptions is augmented with options from -compile attributes.
module(Fs0, Opts0) ->
@@ -62,19 +61,28 @@ module(Fs0, Opts0) ->
%% Set pre-defined exported functions.
PreExp = [{module_info,0},{module_info,1}],
+ %% Build the set of defined functions and the initial call
+ %% type map.
+ Defined = defined_functions(Fs, PreExp),
+ Ctype = maps:from_list([{K,local} || K <- Defined]),
+
%% Build initial expand record.
St0 = #expand{exports=PreExp,
- defined=PreExp
+ ctype=Ctype
},
+
%% Expand the functions.
- {Tfs,St1} = forms(Fs, define_functions(Fs, St0)),
+ {Tfs,St1} = forms(Fs, St0),
+
%% Get the correct list of exported functions.
Exports = case member(export_all, Opts) of
- true -> gb_sets:to_list(St1#expand.defined);
+ true -> Defined;
false -> St1#expand.exports
end,
+ St2 = St1#expand{exports=Exports,ctype=undefined},
+
%% Generate all functions from stored info.
- {Ats,St3} = module_attrs(St1#expand{exports = Exports}),
+ {Ats,St3} = module_attrs(St2),
{Mfs,St4} = module_predef_funcs(St3),
{St4#expand.module, St4#expand.exports, Ats ++ Tfs ++ Mfs,
Opts}.
@@ -82,14 +90,14 @@ module(Fs0, Opts0) ->
compiler_options(Forms) ->
lists:flatten([C || {attribute,_,compile,C} <- Forms]).
-%% define_function(Form, State) -> State.
+%% defined_function(Forms, Predef) -> Functions.
%% Add function to defined if form is a function.
-define_functions(Forms, #expand{defined=Predef}=St) ->
+defined_functions(Forms, Predef) ->
Fs = foldl(fun({function,_,N,A,_Cs}, Acc) -> [{N,A}|Acc];
(_, Acc) -> Acc
end, Predef, Forms),
- St#expand{defined=gb_sets:from_list(Fs)}.
+ ordsets:from_list(Fs).
module_attrs(#expand{attributes=Attributes}=St) ->
Attrs = [{attribute,Line,Name,Val} || {Name,Line,Val} <- Attributes],
@@ -110,23 +118,21 @@ is_fa_list([{FuncName, Arity}|L])
is_fa_list([]) -> true;
is_fa_list(_) -> false.
-module_predef_funcs(St) ->
- {Mpf1,St1}=module_predef_func_beh_info(St),
- {Mpf2,St2}=module_predef_funcs_mod_info(St1),
+module_predef_funcs(St0) ->
+ {Mpf1,St1} = module_predef_func_beh_info(St0),
+ Mpf2 = module_predef_funcs_mod_info(St1),
Mpf = [erl_parse:new_anno(F) || F <- Mpf1++Mpf2],
- {Mpf,St2}.
+ {Mpf,St1}.
module_predef_func_beh_info(#expand{callbacks=[]}=St) ->
{[], St};
module_predef_func_beh_info(#expand{callbacks=Callbacks,
optional_callbacks=OptionalCallbacks,
- defined=Defined,
exports=Exports}=St) ->
- PreDef=[{behaviour_info,1}],
- PreExp=PreDef,
+ PreDef0 = [{behaviour_info,1}],
+ PreDef = ordsets:from_list(PreDef0),
{[gen_beh_info(Callbacks, OptionalCallbacks)],
- St#expand{defined=gb_sets:union(gb_sets:from_list(PreDef), Defined),
- exports=ordsets:union(ordsets:from_list(PreExp), Exports)}}.
+ St#expand{exports=ordsets:union(PreDef, Exports)}}.
gen_beh_info(Callbacks, OptionalCallbacks) ->
List = make_list(Callbacks),
@@ -153,21 +159,16 @@ make_optional_list([{Name,Arity}|Rest]) ->
{integer,0,Arity}]},
make_optional_list(Rest)}.
-module_predef_funcs_mod_info(St) ->
- PreDef = [{module_info,0},{module_info,1}],
- PreExp = PreDef,
- {[{function,0,module_info,0,
- [{clause,0,[],[],
+module_predef_funcs_mod_info(#expand{module=Mod}) ->
+ ModAtom = {atom,0,Mod},
+ [{function,0,module_info,0,
+ [{clause,0,[],[],
[{call,0,{remote,0,{atom,0,erlang},{atom,0,get_module_info}},
- [{atom,0,St#expand.module}]}]}]},
- {function,0,module_info,1,
- [{clause,0,[{var,0,'X'}],[],
+ [ModAtom]}]}]},
+ {function,0,module_info,1,
+ [{clause,0,[{var,0,'X'}],[],
[{call,0,{remote,0,{atom,0,erlang},{atom,0,get_module_info}},
- [{atom,0,St#expand.module},{var,0,'X'}]}]}]}],
- St#expand{defined=gb_sets:union(gb_sets:from_list(PreDef),
- St#expand.defined),
- exports=ordsets:union(ordsets:from_list(PreExp),
- St#expand.exports)}}.
+ [ModAtom,{var,0,'X'}]}]}]}].
%% forms(Forms, State) ->
%% {TransformedForms,State'}
@@ -403,21 +404,15 @@ expr({named_fun,Line,Name,Cs}, St) ->
expr({call,Line,{atom,La,N}=Atom,As0}, St0) ->
{As,St1} = expr_list(As0, St0),
Ar = length(As),
- case defined(N,Ar,St1) of
- true ->
+ Key = {N,Ar},
+ case St1#expand.ctype of
+ #{Key:=local} ->
{{call,Line,Atom,As},St1};
+ #{Key:={imported,Mod}} ->
+ {{call,Line,{remote,La,{atom,La,Mod},Atom},As},St1};
_ ->
- case imported(N, Ar, St1) of
- {yes,Mod} ->
- {{call,Line,{remote,La,{atom,La,Mod},Atom},As},St1};
- no ->
- case erl_internal:bif(N, Ar) of
- true ->
- {{call,Line,{remote,La,{atom,La,erlang},Atom},As},St1};
- false -> %% This should have been handled by erl_lint
- {{call,Line,Atom,As},St1}
- end
- end
+ true = erl_internal:bif(N, Ar),
+ {{call,Line,{remote,La,{atom,La,erlang},Atom},As},St1}
end;
expr({call,Line,{remote,Lr,M0,F},As0}, St0) ->
{[M1,F1|As1],St1} = expr_list([M0,F|As0], St0),
@@ -613,25 +608,11 @@ string_to_conses(Line, Cs, Tail) ->
%% import(Line, Imports, State) ->
%% State'
-%% imported(Name, Arity, State) ->
-%% {yes,Module} | no
-%% Handle import declarations and test for imported functions. No need to
-%% check when building imports as code is correct.
+%% Handle import declarations.
-import({Mod,Fs}, St) ->
+import({Mod,Fs}, #expand{ctype=Ctype0}=St) ->
true = is_atom(Mod),
- Mfs = ordsets:from_list(Fs),
- St#expand{imports=add_imports(Mod, Mfs, St#expand.imports)}.
-
-add_imports(Mod, [F|Fs], Is) ->
- add_imports(Mod, Fs, orddict:store(F, Mod, Is));
-add_imports(_, [], Is) -> Is.
-
-imported(F, A, St) ->
- case orddict:find({F,A}, St#expand.imports) of
- {ok,Mod} -> {yes,Mod};
- error -> no
- end.
-
-defined(F, A, St) ->
- gb_sets:is_element({F,A}, St#expand.defined).
+ Ctype = foldl(fun(F, A) ->
+ A#{F=>{imported,Mod}}
+ end, Ctype0, Fs),
+ St#expand{ctype=Ctype}.