Skip to content

Commit

Permalink
Merge branch 'bjorn/asn1/optimizations/OTP-11573'
Browse files Browse the repository at this point in the history
* bjorn/asn1/optimizations/OTP-11573:
  Optimize code surrounding calls to complete/1
  asn1ct_imm: Add the intermediate instruction {list,List,Dst}
  Generate intermediate code that is easier to optimize
  asn1ct_imm: Add the {set,{var,Src},{var,Dst}} instruction
  Keep type information in the apply intermediate instruction
  asn1ct_imm: Add a field for intermediate code for call_gen
  Introduce asn1ct_gen:open_output_file/1
  Factor out printing of verbose messages
  Improve optimization of alignment for encoding
  Improve construction of {cons,H,T} instructions
  Teach asn1ct_func:call_gen/4 to quote the generated function name
  Test open types that may need more than 128 bytes
  • Loading branch information
bjorng committed Jan 22, 2014
2 parents d203887 + 7699312 commit 990b655
Show file tree
Hide file tree
Showing 9 changed files with 759 additions and 245 deletions.
11 changes: 7 additions & 4 deletions lib/asn1/src/asn1ct.erl
Original file line number Diff line number Diff line change
Expand Up @@ -333,8 +333,7 @@ print_structured_errors([_|_]=Errors) ->
print_structured_errors(_) -> ok.

compile1(File, #st{opts=Opts}=St0) ->
verbose("Erlang ASN.1 version ~p, compiling ~p~n", [?vsn,File], Opts),
verbose("Compiler Options: ~p~n", [Opts], Opts),
compiler_verbose(File, Opts),
Passes = single_passes(),
Base = filename:rootname(filename:basename(File)),
OutFile = outfile(Base, "", Opts),
Expand All @@ -349,8 +348,7 @@ compile1(File, #st{opts=Opts}=St0) ->
%% compile_set/3 merges and compiles a number of asn1 modules
%% specified in a .set.asn file to one .erl file.
compile_set(SetBase, Files, #st{opts=Opts}=St0) ->
verbose("Erlang ASN.1 version ~p compiling ~p ~n", [?vsn,Files], Opts),
verbose("Compiler Options: ~p~n",[Opts], Opts),
compiler_verbose(Files, Opts),
OutFile = outfile(SetBase, "", Opts),
DbFile = outfile(SetBase, "asn1db", Opts),
InputModules = [begin
Expand All @@ -363,6 +361,11 @@ compile_set(SetBase, Files, #st{opts=Opts}=St0) ->
Passes = set_passes(),
run_passes(Passes, St).

compiler_verbose(What, Opts) ->
verbose("Erlang ASN.1 compiler ~s\n", [?vsn], Opts),
verbose("Compiling: ~p\n", [What], Opts),
verbose("Options: ~p\n", [Opts], Opts).

%% merge_modules/2 -> returns a module record where the typeorval lists are merged,
%% the exports lists are merged, the imports lists are merged when the
%% elements come from other modules than the merge set, the tagdefault
Expand Down
114 changes: 61 additions & 53 deletions lib/asn1/src/asn1ct_constructed_per.erl
Original file line number Diff line number Diff line change
Expand Up @@ -79,15 +79,15 @@ gen_encode_constructed_imm(Erule, Typename, #type{}=D) ->
[]
end,
Aligned = is_aligned(Erule),
Value0 = asn1ct_gen:mk_var(asn1ct_name:curr(val)),
Value0 = make_var(val),
Optionals = optionals(to_textual_order(CompList)),
ImmOptionals = [asn1ct_imm:per_enc_optional(Value0, Opt, Aligned) ||
Opt <- Optionals],
Ext = extensible_enc(CompList),
ExtImm = case Ext of
{ext,ExtPos,NumExt} when NumExt > 0 ->
gen_encode_extaddgroup(CompList),
Value = asn1ct_gen:mk_var(asn1ct_name:curr(val)),
Value = make_var(val),
asn1ct_imm:per_enc_extensions(Value, ExtPos,
NumExt, Aligned);
_ ->
Expand All @@ -106,19 +106,17 @@ gen_encode_constructed_imm(Erule, Typename, #type{}=D) ->
c_index=N,
usedclassfield=UniqueFieldName,
uniqueclassfield=UniqueFieldName,
valueindex=ValueIndex
valueindex=ValueIndex0
} -> %% N is index of attribute that determines constraint
{Module,ObjSetName} = ObjectSet,
#typedef{typespec=#'ObjectSet'{gen=Gen}} =
asn1_db:dbget(Module, ObjSetName),
case Gen of
true ->
ObjectEncode =
asn1ct_gen:un_hyphen_var(lists:concat(['Obj',AttrN])),
El = make_element(N+1, asn1ct_gen:mk_var(asn1ct_name:curr(val))),
ValueMatch = value_match(ValueIndex, El),
ObjSetImm0 = [{assign,{var,ObjectEncode},ValueMatch}],
{{AttrN,ObjectEncode},ObjSetImm0};
ValueIndex = ValueIndex0 ++ [{N+1,top}],
Val = make_var(val),
{ObjSetImm0,Dst} = enc_dig_out_value(ValueIndex, Val),
{{AttrN,Dst},ObjSetImm0};
false ->
{false,[]}
end;
Expand All @@ -128,15 +126,15 @@ gen_encode_constructed_imm(Erule, Typename, #type{}=D) ->
%% when the simpletableattributes was at an outer
%% level and the objfun has been passed through the
%% function call
{{"got objfun through args","ObjFun"},[]};
{{"got objfun through args",{var,"ObjFun"}},[]};
_ ->
{false,[]}
end
end,
ImmSetExt =
case Ext of
{ext,_Pos,NumExt2} when NumExt2 > 0 ->
asn1ct_imm:per_enc_extension_bit('Extensions', Aligned);
asn1ct_imm:per_enc_extension_bit({var,"Extensions"}, Aligned);
{ext,_Pos,_} ->
asn1ct_imm:per_enc_extension_bit([], Aligned);
_ ->
Expand Down Expand Up @@ -540,7 +538,7 @@ gen_encode_choice_imm(Erule, TopType, #type{def={'CHOICE',CompList}}) ->
Aligned = is_aligned(Erule),
Cs = gen_enc_choice(Erule, TopType, CompList, Ext),
[{assign,{expr,"{ChoiceTag,ChoiceVal}"},"Val"}|
asn1ct_imm:per_enc_choice('ChoiceTag', Cs, Aligned)].
asn1ct_imm:per_enc_choice({var,"ChoiceTag"}, Cs, Aligned)].

gen_decode_choice(Erules,Typename,D) when is_record(D,type) ->
asn1ct_name:start(),
Expand All @@ -562,32 +560,34 @@ gen_encode_sof(Erule, Typename, SeqOrSetOf, D) ->
gen_encode_sof_imm(Erule, Typename, SeqOrSetOf, #type{}=D) ->
{_SeqOrSetOf,ComponentType} = D#type.def,
Aligned = is_aligned(Erule),
Constructed_Suffix =
asn1ct_gen:constructed_suffix(SeqOrSetOf,
ComponentType#type.def),
Conttype = asn1ct_gen:get_inner(ComponentType#type.def),
CompType = ComponentType#type.def,
Constructed_Suffix = asn1ct_gen:constructed_suffix(SeqOrSetOf, CompType),
Conttype = asn1ct_gen:get_inner(CompType),
Currmod = get(currmod),
Imm0 = case asn1ct_gen:type(Conttype) of
{primitive,bif} ->
asn1ct_gen_per:gen_encode_prim_imm('Comp', ComponentType, Aligned);
asn1ct_gen_per:gen_encode_prim_imm({var,"Comp"},
ComponentType, Aligned);
{constructed,bif} ->
TypeName = [Constructed_Suffix|Typename],
Enc = enc_func(asn1ct_gen:list2name(TypeName)),
ObjArg = case D#type.tablecinf of
[{objfun,_}|_] -> [{var,"ObjFun"}];
_ -> []
end,
[{apply,Enc,[{var,"Comp"}|ObjArg]}];
[{apply,{local,Enc,CompType},
[{var,"Comp"}|ObjArg]}];
#'Externaltypereference'{module=Currmod,type=Ename} ->
[{apply,enc_func(Ename),[{var,"Comp"}]}];
[{apply,{local,enc_func(Ename),CompType},[{var,"Comp"}]}];
#'Externaltypereference'{module=EMod,type=Ename} ->
[{apply,{EMod,enc_func(Ename)},[{var,"Comp"}]}];
[{apply,{EMod,enc_func(Ename),CompType},[{var,"Comp"}]}];
'ASN1_OPEN_TYPE' ->
asn1ct_gen_per:gen_encode_prim_imm('Comp',
asn1ct_gen_per:gen_encode_prim_imm({var,"Comp"},
#type{def='ASN1_OPEN_TYPE'},
Aligned)
end,
asn1ct_imm:per_enc_sof('Val', D#type.constraint, 'Comp', Imm0, Aligned).
asn1ct_imm:per_enc_sof({var,"Val"}, D#type.constraint, 'Comp',
Imm0, Aligned).

gen_decode_sof(Erules, Typename, SeqOrSetOf, #type{}=D) ->
asn1ct_name:start(),
Expand Down Expand Up @@ -871,8 +871,8 @@ gen_enc_components_call1(Erule,TopType,
CanonicalNum ->
CanonicalNum
end,
Element0 = make_element(TermNo+1, asn1ct_gen:mk_var(asn1ct_name:curr(val))),
{Imm0,Element} = asn1ct_imm:enc_bind_var(Element0),
Val = make_var(val),
{Imm0,Element} = asn1ct_imm:enc_element(TermNo+1, Val),
Imm1 = gen_enc_line_imm(Erule, TopType, Cname, Type, Element, DynamicEnc, Ext),
Category = case {Prop,Ext} of
{'OPTIONAL',_} ->
Expand Down Expand Up @@ -967,9 +967,9 @@ gen_enc_line_imm_1(Erule, TopType, Cname, Type, Element, DynamicEnc) ->
CurrMod = get(currmod),
case asn1ct_gen:type(Atype) of
#'Externaltypereference'{module=CurrMod,type=EType} ->
[{apply,enc_func(EType),[{expr,Element}]}];
[{apply,{local,enc_func(EType),Atype},[Element]}];
#'Externaltypereference'{module=Mod,type=EType} ->
[{apply,{Mod,enc_func(EType)},[{expr,Element}]}];
[{apply,{Mod,enc_func(EType),Atype},[Element]}];
{primitive,bif} ->
asn1ct_gen_per:gen_encode_prim_imm(Element, Type, Aligned);
'ASN1_OPEN_TYPE' ->
Expand All @@ -988,9 +988,9 @@ gen_enc_line_imm_1(Erule, TopType, Cname, Type, Element, DynamicEnc) ->
Enc = enc_func(asn1ct_gen:list2name(NewTypename)),
case {Type#type.tablecinf,DynamicEnc} of
{[{objfun,_}|_R],{_,EncFun}} ->
[{apply,Enc,[{expr,Element},{var,EncFun}]}];
[{apply,{local,Enc,Type},[Element,EncFun]}];
_ ->
[{apply,Enc,[{expr,Element}]}]
[{apply,{local,Enc,Type},[Element]}]
end
end
end.
Expand All @@ -1014,13 +1014,16 @@ enc_var_type_call(Erule, Name, RestFieldNames,
{_,Key,Code} <- ObjSet1],
ObjSet = lists:sort([P || {_,B}=P <- ObjSet2, B =/= none]),
Key = erlang:md5(term_to_binary({encode,ObjSet,RestFieldNames,Extensible})),
Imm = enc_objset_imm(Erule, Name, ObjSet, RestFieldNames, Extensible),
Lambda = {lambda,[{var,"Val"},{var,"Id"}],Imm},
Gen = fun(_Fd, N) ->
enc_objset(Erule, Name, N, ObjSet,
RestFieldNames, Extensible)
Aligned = is_aligned(Erule),
emit([{asis,N},"(Val, Id) ->",nl]),
asn1ct_imm:enc_cg(Imm, Aligned),
emit([".",nl])
end,
Prefix = lists:concat(["enc_os_",Name]),
F = asn1ct_func:call_gen(Prefix, Key, Gen),
[{apply,F,[{var,atom_to_list(Val)},{var,Fun}]}].
[{call_gen,Prefix,Key,Gen,Lambda,[Val,Fun]}].

fix_object_code(Name, [{Name,B}|_], _ClassFields) ->
B;
Expand All @@ -1042,9 +1045,7 @@ fix_object_code(Name, [], ClassFields) ->
end
end.


enc_objset(Erule, Component, Name, ObjSet, RestFieldNames, Extensible) ->
asn1ct_name:start(),
enc_objset_imm(Erule, Component, ObjSet, RestFieldNames, Extensible) ->
Aligned = is_aligned(Erule),
E = {error,
fun() ->
Expand All @@ -1053,22 +1054,19 @@ enc_objset(Erule, Component, Name, ObjSet, RestFieldNames, Extensible) ->
"{value,Val},"
"{unique_name_and_value,'_'}})",nl])
end},
Imm = [{'cond',
[[{eq,{var,"Id"},Key}|
enc_obj(Erule, Obj, RestFieldNames, Aligned)] ||
{Key,Obj} <- ObjSet] ++
[['_',case Extensible of
false -> E;
true -> {put_bits,{var,"Val"},binary,[1]}
end]]}],
emit([{asis,Name},"(Val, Id) ->",nl]),
asn1ct_imm:enc_cg(Imm, Aligned),
emit([".",nl]).
[{'cond',
[[{eq,{var,"Id"},Key}|
enc_obj(Erule, Obj, RestFieldNames, Aligned)] ||
{Key,Obj} <- ObjSet] ++
[['_',case Extensible of
false -> E;
true -> {put_bits,{var,"Val"},binary,[1]}
end]]}].

enc_obj(Erule, Obj, RestFieldNames0, Aligned) ->
case Obj of
#typedef{name={primitive,bif},typespec=Def} ->
asn1ct_gen_per:gen_encode_prim_imm('Val', Def, Aligned);
asn1ct_gen_per:gen_encode_prim_imm({var,"Val"}, Def, Aligned);
#typedef{name={constructed,bif},typespec=Def} ->
InnerType = asn1ct_gen:get_inner(Def#type.def),
case InnerType of
Expand All @@ -1084,7 +1082,7 @@ enc_obj(Erule, Obj, RestFieldNames0, Aligned) ->
gen_encode_sof_imm(Erule, name, InnerType, Def)
end;
#typedef{name=Type} ->
[{apply,enc_func(Type),[{var,"Val"}]}];
[{apply,{local,enc_func(Type),Type},[{var,"Val"}]}];
#'Externalvaluereference'{module=Mod,value=Value} ->
case asn1_db:dbget(Mod, Value) of
#typedef{typespec=#'Object'{def=Def}} ->
Expand All @@ -1097,9 +1095,9 @@ enc_obj(Erule, Obj, RestFieldNames0, Aligned) ->
Func = enc_func(Type),
case get(currmod) of
Mod ->
[{apply,Func,[{var,"Val"}]}];
[{apply,{local,Func,Obj},[{var,"Val"}]}];
_ ->
[{apply,{Mod,Func},[{var,"Val"}]}]
[{apply,{Mod,Func,Obj},[{var,"Val"}]}]
end
end.

Expand Down Expand Up @@ -1540,12 +1538,12 @@ gen_enc_choices([H|T], Erule, TopType, Pos, Constr, Ext) ->
no ->
case Type#type.tablecinf of
[{objfun,_}|_] ->
{"got objfun through args","ObjFun"};
{"got objfun through args",{var,"ObjFun"}};
_ ->
false
end;
_ ->
{no_attr,"ObjFun"}
{no_attr,{var,"ObjFun"}}
end,
DoExt = case Constr of
ext -> Ext;
Expand All @@ -1561,7 +1559,7 @@ gen_enc_choices([H|T], Erule, TopType, Pos, Constr, Ext) ->
[{put_bits,0,1,[1]}|
asn1ct_imm:per_enc_integer(Pos, Constr, Aligned)]
end,
Body = gen_enc_line_imm(Erule, TopType, Cname, Type, 'ChoiceVal',
Body = gen_enc_line_imm(Erule, TopType, Cname, Type, {var,"ChoiceVal"},
EncObj, DoExt),
Imm = Tag ++ Body,
[{Cname,Imm}|gen_enc_choices(T, Erule, TopType, Pos+1, Constr, Ext)];
Expand Down Expand Up @@ -1778,3 +1776,13 @@ value_match1(Value,[],Acc,Depth) ->
Acc ++ Value ++ lists:concat(lists:duplicate(Depth,")"));
value_match1(Value,[{VI,_}|VIs],Acc,Depth) ->
value_match1(Value,VIs,Acc++lists:concat(["element(",VI,","]),Depth+1).

enc_dig_out_value([], Value) ->
{[],Value};
enc_dig_out_value([{N,_}|T], Value) ->
{Imm0,Dst0} = enc_dig_out_value(T, Value),
{Imm,Dst} = asn1ct_imm:enc_element(N, Dst0),
{Imm0++Imm,Dst}.

make_var(Base) ->
{var,atom_to_list(asn1ct_gen:mk_var(asn1ct_name:curr(Base)))}.
2 changes: 1 addition & 1 deletion lib/asn1/src/asn1ct_func.erl
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ need(MFA) ->

call_gen(Prefix, Key, Gen, Args) when is_function(Gen, 2) ->
F = req({gen_func,Prefix,Key,Gen}),
asn1ct_gen:emit([F,"(",call_args(Args, ""),")"]).
asn1ct_gen:emit([{asis,F},"(",call_args(Args, ""),")"]).

call_gen(Prefix, Key, Gen) when is_function(Gen, 2) ->
req({gen_func,Prefix,Key,Gen}).
Expand Down
24 changes: 13 additions & 11 deletions lib/asn1/src/asn1ct_gen.erl
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

-export([demit/1,
emit/1,
open_output_file/1,close_output_file/0,
get_inner/1,type/1,def_to_tag/1,prim_bif/1,
list2name/1,
list2rname/1,
Expand Down Expand Up @@ -70,8 +71,7 @@ pgen_module(OutFile,Erules,Module,
HrlGenerated = pgen_hrl(Erules,Module,TypeOrVal,Options,Indent),
asn1ct_name:start(),
ErlFile = lists:concat([OutFile,".erl"]),
Fid = fopen(ErlFile),
put(gen_file_out,Fid),
open_output_file(ErlFile),
asn1ct_func:start_link(),
gen_head(Erules,Module,HrlGenerated),
pgen_exports(Erules,Module,TypeOrVal),
Expand All @@ -85,9 +85,9 @@ pgen_module(OutFile,Erules,Module,
"%%%",nl,
"%%% Run-time functions.",nl,
"%%%",nl]),
asn1ct_func:generate(Fid),
file:close(Fid),
_ = erase(gen_file_out),
Fd = get(gen_file_out),
asn1ct_func:generate(Fd),
close_output_file(),
_ = erase(outfile),
asn1ct:verbose("--~p--~n",[{generated,ErlFile}],Options).

Expand Down Expand Up @@ -1121,8 +1121,7 @@ pgen_info() ->

open_hrl(OutFile,Module) ->
File = lists:concat([OutFile,".hrl"]),
Fid = fopen(File),
put(gen_file_out,Fid),
open_output_file(File),
gen_hrlhead(Module).

%% EMIT functions ************************
Expand Down Expand Up @@ -1195,15 +1194,19 @@ call_args([A|As], Sep) ->
[Sep,do_emit(A)|call_args(As, ", ")];
call_args([], _) -> [].

fopen(F) ->
open_output_file(F) ->
case file:open(F, [write,raw,delayed_write]) of
{ok, Fd} ->
{ok,Fd} ->
put(gen_file_out, Fd),
Fd;
{error, Reason} ->
io:format("** Can't open file ~p ~n", [F]),
exit({error,Reason})
end.

close_output_file() ->
ok = file:close(erase(gen_file_out)).

pgen_hrl(Erules,Module,TypeOrVal,Options,_Indent) ->
put(currmod,Module),
{Types,Values,Ptypes,_,_,_} = TypeOrVal,
Expand All @@ -1226,8 +1229,7 @@ pgen_hrl(Erules,Module,TypeOrVal,Options,_Indent) ->
0 ->
0;
Y ->
Fid = get(gen_file_out),
file:close(Fid),
close_output_file(),
asn1ct:verbose("--~p--~n",
[{generated,lists:concat([get(outfile),".hrl"])}],
Options),
Expand Down
Loading

0 comments on commit 990b655

Please sign in to comment.