hipe.erl

来自「OTP是开放电信平台的简称」· ERL 代码 · 共 1,594 行 · 第 1/4 页

ERL
1,594
字号
%%       Reason = term()%%%% @doc Direct compiler interface, for advanced use. This just compiles%% the named function or module, reading BEAM code from the%% corresponding "Module<code>.beam</code>" file in the system path.%% Returns <code>{ok, Binary}</code> if successful, or <code>{error,%% Reason}</code> otherwise. By default, it does <em>not</em> load the%% binary to memory (the <code>load</code> option can be used to%% activate automatic loading). <code>File</code> can be either a file%% name or a binary containing the BEAM code for the module.%%%% @see c/2%% @see compile/1%% @see compile/3%% @see file/2%% @see load/2compile(Name, Options) ->  compile(Name, beam_file(Name), Options).beam_file({M,F,A}) when is_atom(M), is_atom(F), is_integer(A), A >= 0 ->  beam_file(M);beam_file(Module) when is_atom(Module) ->  case code:which(Module) of    non_existing ->      ?error_msg("Cannot find ~w.beam file.",[Module]),      ?EXIT({cant_find_beam_file,Module});    File ->      File  end.%% @spec compile(Name, File, options()) -> {ok, Binary} | {error, Reason}%%       Name = mod() | mfa()%%       File = filename() | binary()%%       Binary = binary()%%       Reason = term()%% %% @doc Like <code>compile/2</code>, but reads BEAM code from the%% specified <code>File</code>.%%%% @see compile/2compile(Name, File, Opts0) ->  Opts1 = expand_kt2(Opts0),  Opts =     case Name of      {_Mod, _Fun, _Arity} ->	[no_concurrent_comp|Opts1];      _ ->	Opts1    end,  case proplists:get_value(core, Opts) of    true when is_binary(File) ->      ?error_msg("Cannot get Core Erlang code from BEAM binary.",[]),      ?EXIT({cant_compile_core_from_binary});    true ->      case filename:find_src(filename:rootname(File, ".beam")) of	{error, _} ->	  ?error_msg("Cannot find source code for ~p.",[File]),	  ?EXIT({cant_find_source_code});	{Source, CompOpts} ->	  CoreOpts = [X || X = {core_transform, _} <- Opts],	  %%io:format("Using: ~w\n", [CoreOpts]),	  case compile:file(Source, CoreOpts ++ [to_core, binary|CompOpts]) of	    {ok, _, Core} ->	      compile_core(Name, Core, File, Opts);	    Error ->	      ?error_msg("Error compiling ~p:\n~p.",[File, Error]),	      ?EXIT({cant_compile_source_code})	  end      end;    {src_file, Source} ->      CoreOpts1 = [X || X = {core_transform, _} <-Opts],      CoreOpts2 = [report_errors, to_core, binary, {i,"../include"}|CoreOpts1],      %% io:format("Using: ~w\n", [CoreOpts2]),      case compile:file(Source, CoreOpts2) of	{ok, _, Core} ->	  compile_core(Name, Core, File, Opts);	Error ->	  ?error_msg("Error compiling ~p:\n~p\n",[Source, Error]),	  ?EXIT({cant_compile_source_code, Error})      end;    Other when Other =:= false; Other =:= undefined ->      NewOpts =	case proplists:get_value(use_callgraph, Opts) of	  No when No =:= false; No =:= undefined -> Opts;	  _ ->	    case Name of	      {_M,_F,_A} ->		%% There is no point in using the callgraph when		%% analyzing just one function. or to use concurrent comp		[no_use_callgraph,no_concurrent_comp|Opts];	      _ -> Opts	    end	end,      DisasmFun = fun (_) -> disasm(File) end,      IcodeFun = fun (Code, Opts_) ->		     get_beam_icode(Name, Code, File, Opts_)		 end,      run_compiler(Name, DisasmFun, IcodeFun, NewOpts)  end.compile_core(Name, Core0, File, Opts) ->  Core = cerl:from_records(Core0),  Core1 = case (erlang:system_info(heap_type) =:= hybrid)	    andalso proplists:get_bool(hybrid, Opts) of	    true -> cerl_hybrid_transform:transform(Core, Opts);	    false -> Core	  end,  compile(Name, Core1, File, Opts).%% @spec compile(Name, Core, File, options()) ->%%           {ok, Binary} | {error, Reason}%%       Name = mod()%%       Core = coreErlang() | []%%       File = filename() | binary()%%       Binary = binary()%%       Reason = term()%% %% @doc Like <code>compile/3</code>, but unless <code>Core</code> is%% <code>[]</code>, low-level code is generated from the given Core%% Erlang code instead of from the BEAM code.%%%% <p>Note that only whole modules can be compiled with this%% function.</p>%%%% @see compile/3compile(Name, [], File, Opts) ->  compile(Name, File, Opts);compile({M,F,A}, _Core, _File, _Opts) ->  ?WARNING_MSG("Cannot compile single functions from source code. (~p}.\n",[{M,F,A}]),  {ok, <<>>};  % dummy%  compile(M, Core, File, Opts);compile(Name, Core, File, Opts) when is_atom(Name) ->  DisasmFun = fun (_) -> {false, []} end,  IcodeFun = fun (_, Opts) ->		 get_core_icode(Name, Core, File, Opts)	     end,  run_compiler(Name, DisasmFun, IcodeFun, Opts).%% @spec file(File) -> {ok, Name, Binary} | {error, Reason}%%       File = filename() | binary()%%       Name = mod() | mfa()%%       Binary = binary()%%       Reason = term()%% %% @equiv file(File, [])file(File) ->  file(File, []).%% @spec file(File, options()) -> {ok, Name, Binary} | {error, Reason}%%       File = filename() | binary()%%       Name = mod() | mfa()%%       Binary = binary()%%       Reason = term()%% %% @doc Like <code>compile/2</code>, but takes the module name from the%% specified <code>File</code>. Returns both the name and the final%% binary if successful.%%%% @see file/1%% @see compile/2file(File, Options) when is_atom(File) ->  case beam_lib:info(File) of    L when is_list(L) ->      {value,{module,Mod}} = lists:keysearch(module,1,L),      case compile(Mod, File, Options) of	{ok, Bin} ->	  {ok, Mod, Bin};	Other ->	  Other      end;    Error ->      Error  end.%%-----------------------------------------------------------------------%% The rest are internal functions:%%-----------------------------------------------------------------------%% @doc%% Get BEAM code from `.beam' files or direct from binaries.%%   File is either a file name or a binary containing the BEAM code.disasm(File) ->  case beam_disasm:file(File) of    {beam_file,DisasmBeam} ->      {value,{code,BeamCode}} = lists:keysearch(code,1,DisasmBeam),      {value,{exports,BeamExports}} = lists:keysearch(exports,1,DisasmBeam),      {value,{comp_info,CompInfo}} = lists:keysearch(comp_info,1,DisasmBeam),      {value,{options,CompOpts}} = lists:keysearch(options,1,CompInfo),      HCompOpts = case lists:keysearch(hipe,1,CompOpts) of		    {value,{hipe,L}} when is_list(L) -> L;		    {value,{hipe,X}} -> [X];		    _ -> []		  end,      Exports = fix_beam_exports(BeamExports),      {{BeamCode, Exports}, HCompOpts};    Error ->      io:format("~s\n", [beam_lib:format_error(Error)]),      ?EXIT(no_beam_code)  end.fix_beam_exports(BeamExports) ->  fix_beam_exports(BeamExports, []).fix_beam_exports([{F,A,_}|BeamExports], Exports) ->  fix_beam_exports(BeamExports, [{F,A} | Exports]);fix_beam_exports([], Exports) ->  Exports.get_beam_icode({M,_F,_A} = MFA, {BeamCode, Exports}, _File, Options) ->  ?option_time({ok,Icode} = 	       (catch {ok, hipe_beam_to_icode:mfa(BeamCode, MFA, Options)}),	       "BEAM-to-Icode", Options),  {{M, Exports, Icode}, false};get_beam_icode(Mod, {BeamCode, Exports}, File, Options) ->  ?option_time({ok, Icode} =	       (catch {ok, hipe_beam_to_icode:module(BeamCode, Options)}),	       "BEAM-to-Icode", Options),  BeamBin = get_beam_code(File),  {{Mod, Exports, Icode}, BeamBin}.get_core_icode(Mod, Core, File, Options) ->  ?option_time({ok, Icode} =	       (catch {ok, cerl_to_icode:module(Core, Options)}),	       "BEAM-to-Icode", Options),  NeedBeamCode =     not proplists:get_bool(load, Options),  BeamBin =     case NeedBeamCode of      true -> [];      false -> get_beam_code(File)    end,  Exports = [cerl:var_name(V) || V <- cerl:module_exports(Core)],  {{Mod, Exports, Icode}, BeamBin}.get_beam_code(Bin) when is_binary(Bin) -> Bin;get_beam_code(FileName) ->  case erl_prim_loader:get_file(FileName) of    {ok,Bin,_} ->      Bin;    error ->      ?EXIT(no_beam_file)  end.%% ---------------------------------------------------------------------%% All compilations go through this function. Note that it receives only%% "basic" options. Name is just used for verbosity. The DisasmFun and%% IcodeFun only collect the Icode; most of the real work is done in the%% 'finalize' function.run_compiler(Name, DisasmFun, IcodeFun, Opts0) ->  Opts = expand_basic_options(Opts0 ++ ?COMPILE_DEFAULTS),  ?when_option(verbose, Opts, ?debug_msg("Compiling: ~p\n",[Name])),  ?option_start_time("Compile", Opts),  Res = run_compiler_1(DisasmFun, IcodeFun, Opts),  ?option_stop_time("Compile", Opts),  Res.run_compiler_1(DisasmFun, IcodeFun, Options) ->  Parent = self(),  {trap_exit,TrapExit} = process_info(Parent, trap_exit),  %% Spawn a compilation process CompProc. In case this process gets  %% killed, the trap_exit flag is restored to that of the Parent process.  process_flag(trap_exit, true),  CompProc = spawn_link(fun () ->			    %% Compiler process			    set_architecture(Options),			    pre_init(Options),			    %% The full option expansion is not done			    %% until the DisasmFun returns.			    {Code, CompOpts} = DisasmFun(Options),			    Opts = expand_options(Options ++ CompOpts),			    check_options(Opts),			    ?when_option(verbose, Options,					 ?debug_msg("Options: ~p.\n",[Opts])),			    init(Opts),			    {Icode, WholeModule} = IcodeFun(Code, Opts),			    CompRes = compile_finish(Icode, WholeModule, Opts),			    compiler_return(CompRes, Parent)			end),  Timeout = case proplists:get_value(timeout, Options) of	      N when is_integer(N), N >= 0 -> N;	      undefined -> ?DEFAULT_TIMEOUT;	      infinity -> infinity;	      Other ->		?WARNING_MSG("Bad timeout value: ~P\n"			     "Using default timeout limit.\n",				     [Other, 5]),		?DEFAULT_TIMEOUT	    end,  receive    {'EXIT', CompProc, normal} -> ok;    {'EXIT', CompProc, Reason} -> exit(Reason)  after Timeout ->      %% Kill the compilation process      exit(CompProc, kill),      receive {'EXIT', CompProc, _} -> ok end,      flush(),      ?error_msg("ERROR: Compilation timed out.\n",[]),      exit(timed_out)  end,  Result = receive {CompProc, Res} -> Res end,  process_flag(trap_exit, TrapExit),  Result.flush() ->  receive    _ -> flush()  after 0 ->      ok  end.compiler_return(Res, Client) ->  Client ! {self(), Res}.compile_finish({Mod, Exports, Icode}, WholeModule, Options) ->  Res = finalize(Icode, Mod, Exports, WholeModule, Options),  post(Res, Icode, Options).%% ---------------------------------------------------------------------%% finalize/4 compiles, assembles, and optionally loads a list of `{MFA,%% Icode}' pairs, and returns `{ok, Binary}' or `{error, Reason}'.%% TODO: make the Exports info accessible to the compilation passes.finalize(OrigList, Mod, Exports, WholeModule, Opts0) ->  Opts = [{exports, Exports} |Opts0],  List = icode_multret(OrigList, Mod, Opts, Exports),  {T1Compile,_} = erlang:statistics(runtime),  CompiledCode =    case proplists:get_value(use_callgraph, Opts) of      true -> 	%% Compiling the functions bottom-up by using a call graph	CallGraph = hipe_icode_callgraph:construct(List),	OrdList = hipe_icode_callgraph:to_list(CallGraph),	finalize_fun(OrdList, Opts);      _ -> 	%% Compiling the functions bottom-up by reversing the list	OrdList = lists:reverse(List),	finalize_fun(OrdList, Opts)    end,  {T2Compile,_} = erlang:statistics(runtime),  ?when_option(verbose, Opts,	       ?debug_msg("Compiled ~p in ~.2f s\n",			  [Mod,(T2Compile-T1Compile)/1000])),  case (proplists:get_bool(to_rtl, Opts) orelse 	proplists:get_bool(dialyzer, Opts)) of    true ->      {ok, CompiledCode};    false ->      Closures = 	[MFA || {MFA, Icode} <- List,		hipe_icode:icode_is_closure(Icode)],      {T1,_} = erlang:statistics(runtime),      ?when_option(verbose, Opts, ?debug_msg("Assembling ~w",[Mod])),      case catch assemble(CompiledCode, Closures, Exports, Opts) of	{'EXIT',Error} -> {error,Error};	Bin ->	  {T2,_} = erlang:statistics(runtime),	  ?when_option(verbose, Opts,		       ?debug_untagged_msg(" in ~.2f s\n",					   [(T2-T1)/1000])),	  maybe_load(Mod, Bin, WholeModule, Opts),	  TargetArch = get(hipe_target_arch),	  {ok, {TargetArch,Bin}}      end  end.finalize_fun(MfaIcodeList, Opts) ->  case proplists:get_value(concurrent_comp, Opts) of    FalseVal when (FalseVal =:= undefined) or (FalseVal =:= false) ->      [finalize_fun_sequential({MFA, Icode}, Opts) || {MFA, Icode} <- MfaIcodeList];    TrueVal when (TrueVal =:= true) or (TrueVal =:= debug) ->      finalize_fun_concurrent(MfaIcodeList, Opts)  end.finalize_fun_concurrent(MfaIcodeList, Opts) ->  Self = self(),  case MfaIcodeList of    [{{M,_,_},_}|_] ->      Exports = proplists:get_value(exports,Opts),      CallGraph = hipe_icode_callgraph:construct_callgraph(MfaIcodeList),      Closures = [{MFA,true} || {MFA, Icode} <- MfaIcodeList,				hipe_icode:icode_is_closure(Icode)],      Exported = [{{M,F,A},false} || {F,A} <- Exports, not ((F =:= module_info) 							    and ((A =:= 1) or (A =:= 0)))],      NonEscaping = [{M,F,A} || {{M,F,A}, Icode} <- MfaIcodeList, 				not lists:member({F,A},Exports),				not hipe_icode:icode_is_closure(Icode)],      Escaping = Closures++Exported,       TypeServerFun = 

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?