summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Meadows-Jönsson <eric.meadows.jonsson@gmail.com>2019-12-06 20:53:32 +0100
committerEric Meadows-Jönsson <eric.meadows.jonsson@gmail.com>2019-12-07 13:32:29 +0100
commitcdcda87282f8e22fa768152fd20ab74dbc186965 (patch)
tree18bc01845ab02cad2674cce9130e08f114b53c96
parentfb2a991fcaf2449ab6dd90632efdc806f4dd86b5 (diff)
downloadelixir-emj/remove-chunk-signatures.tar.gz
Build checker chunk before group passemj/remove-chunk-signatures
-rw-r--r--lib/elixir/lib/code.ex4
-rw-r--r--lib/elixir/lib/kernel/parallel_compiler.ex30
-rw-r--r--lib/elixir/lib/module/checker.ex28
-rw-r--r--lib/elixir/lib/module/parallel_checker.ex60
-rw-r--r--lib/elixir/src/elixir_erl.erl30
-rw-r--r--lib/elixir/test/elixir/module/checker_test.exs2
6 files changed, 72 insertions, 82 deletions
diff --git a/lib/elixir/lib/code.ex b/lib/elixir/lib/code.ex
index 8fb96c83b..37d78ad44 100644
--- a/lib/elixir/lib/code.ex
+++ b/lib/elixir/lib/code.ex
@@ -1376,7 +1376,7 @@ defmodule Code do
defp verify_loaded(loaded) do
maps_binaries = Enum.map(loaded, fn {_module, map, binary} -> {map, binary} end)
- {loaded, _warnings} = Module.ParallelChecker.verify(maps_binaries, [])
- loaded
+ Module.ParallelChecker.verify(maps_binaries, [])
+ Enum.map(loaded, fn {module, map, _binary} -> {module, map} end)
end
end
diff --git a/lib/elixir/lib/kernel/parallel_compiler.ex b/lib/elixir/lib/kernel/parallel_compiler.ex
index 722d11065..7994560a0 100644
--- a/lib/elixir/lib/kernel/parallel_compiler.ex
+++ b/lib/elixir/lib/kernel/parallel_compiler.ex
@@ -355,32 +355,34 @@ defmodule Kernel.ParallelCompiler do
defp each_cycle_return(other), do: other
defp write_and_verify_modules(result, warnings, dependent_modules, state) do
- %{output: output, beam_timestamp: beam_timestamp} = state
-
- {binaries, checker_warnings} = maybe_check_modules(result, dependent_modules, state)
- write_module_binaries(output, beam_timestamp, binaries)
+ modules = write_module_binaries(result, state)
+ checker_warnings = maybe_check_modules(result, dependent_modules, state)
warnings = Enum.reverse(warnings, checker_warnings)
- {:ok, Enum.map(binaries, &elem(&1, 0)), warnings}
+ {:ok, modules, warnings}
end
- defp write_module_binaries({:compile, path}, timestamp, result) do
- Enum.each(result, fn {module, binary} ->
- full_path = Path.join(path, Atom.to_string(module) <> ".beam")
- File.write!(full_path, binary)
- if timestamp, do: File.touch!(full_path, timestamp)
+ defp write_module_binaries(result, %{output: {:compile, path}, beam_timestamp: timestamp}) do
+ Enum.flat_map(result, fn
+ {{:module, module}, {binary, _map}} ->
+ full_path = Path.join(path, Atom.to_string(module) <> ".beam")
+ File.write!(full_path, binary)
+ if timestamp, do: File.touch!(full_path, timestamp)
+ [module]
+
+ _ ->
+ []
end)
end
- defp write_module_binaries(_output, _timestamp, _result) do
- :ok
+ defp write_module_binaries(result, _state) do
+ for {{:module, module}, _} <- result, do: module
end
defp maybe_check_modules(result, runtime_modules, state) do
%{schedulers: schedulers, profile: profile} = state
if :elixir_config.get(:bootstrap) do
- binaries = for {{:module, module}, {binary, _map}} <- result, do: {module, binary}
- {binaries, []}
+ []
else
compiled_modules = checker_compiled_modules(result)
runtime_modules = checker_runtime_modules(runtime_modules)
diff --git a/lib/elixir/lib/module/checker.ex b/lib/elixir/lib/module/checker.ex
index 38ef5671f..452f6cd15 100644
--- a/lib/elixir/lib/module/checker.ex
+++ b/lib/elixir/lib/module/checker.ex
@@ -9,10 +9,10 @@ defmodule Module.Checker do
undefined_and_deprecation_warnings = undefined_and_deprecation_warnings(map, cache)
infer_warnings = infer_definitions(map)
warnings = infer_warnings ++ undefined_and_deprecation_warnings
- {build_chunk(map), emit_warnings(warnings)}
+ emit_warnings(warnings)
:error ->
- {nil, []}
+ []
end
end
@@ -21,9 +21,9 @@ defmodule Module.Checker do
%{
module: module,
file: module_map.file,
- no_warn_undefined: no_warn_undefined(module_map.compile_opts),
definitions: module_map.definitions,
- deprecated: module_map.deprecated
+ deprecated: module_map.deprecated,
+ no_warn_undefined: no_warn_undefined(module_map.compile_opts)
}}
end
@@ -33,8 +33,8 @@ defmodule Module.Checker do
{:ok,
%{
module: module,
- definitions: debug_info.definitions,
file: debug_info.file,
+ definitions: debug_info.definitions,
deprecated: checker_info.deprecated,
no_warn_undefined: checker_info.no_warn_undefined
}}
@@ -69,24 +69,6 @@ defmodule Module.Checker do
end
end
- defp build_chunk(map) do
- exports = ParallelChecker.definitions_to_exports(map.definitions)
- deprecated = Map.new(map.deprecated)
-
- exports =
- Enum.map(exports, fn {function, kind} ->
- deprecated_reason = Map.get(deprecated, function)
- {function, %{kind: kind, deprecated_reason: deprecated_reason}}
- end)
-
- contents = %{
- exports: Enum.sort(exports),
- no_warn_undefined: map.no_warn_undefined
- }
-
- {'ExCk', :erlang.term_to_binary({:elixir_checker_v1, contents})}
- end
-
defp infer_definitions(map) do
results = Module.Types.infer_definitions(map.file, map.module, map.definitions)
Enum.flat_map(results, fn {_function, reasons} -> reasons end)
diff --git a/lib/elixir/lib/module/parallel_checker.ex b/lib/elixir/lib/module/parallel_checker.ex
index ca737457f..a16bf106a 100644
--- a/lib/elixir/lib/module/parallel_checker.ex
+++ b/lib/elixir/lib/module/parallel_checker.ex
@@ -10,8 +10,7 @@ defmodule Module.ParallelChecker do
the modules and adds the ExCk chunk to the binaries. Returns the updated
binaries and a list of warnings from the verification.
"""
- @spec verify([{%{}, binary()}], [{module(), binary()}], pos_integer()) ::
- {[{module(), binary()}], [warning()]}
+ @spec verify([{map(), binary()}], [{module(), binary()}], pos_integer()) :: [warning()]
def verify(compiled_modules, runtime_binaries, schedulers \\ nil) do
compiled_maps = Enum.map(compiled_modules, fn {map, _binary} -> {map.module, map} end)
check_modules = compiled_maps ++ runtime_binaries
@@ -21,36 +20,20 @@ defmodule Module.ParallelChecker do
preload_cache(get_ets(server), check_modules)
start(server)
- compiled_binaries = Enum.map(compiled_modules, fn {map, binary} -> {map.module, binary} end)
- old_binaries = Map.new(compiled_binaries ++ runtime_binaries)
- collect_results(old_binaries, [], [])
+ collect_results(length(check_modules), [])
end
- defp collect_results(old_binaries, binaries, warnings) when map_size(old_binaries) == 0 do
- {binaries, warnings}
+ defp collect_results(0, warnings) do
+ warnings
end
- defp collect_results(old_binaries, binaries, warnings) do
+ defp collect_results(count, warnings) do
receive do
- {__MODULE__, module, chunk, new_warnings} ->
- {binary, old_binaries} = Map.pop(old_binaries, module)
- binaries = [{module, add_chunk(chunk, binary)} | binaries]
-
- warnings = new_warnings ++ warnings
- collect_results(old_binaries, binaries, warnings)
+ {__MODULE__, _module, new_warnings} ->
+ collect_results(count - 1, new_warnings ++ warnings)
end
end
- defp add_chunk(nil, binary) do
- binary
- end
-
- defp add_chunk(chunk, binary) do
- {:ok, _module, chunks} = :beam_lib.all_chunks(binary)
- {:ok, binary} = :beam_lib.build_module([chunk | :lists.keydelete('ExCk', 1, chunks)])
- binary
- end
-
@doc """
Preloads a module into the cache. Call this function before any other
cache lookups for the module.
@@ -98,21 +81,6 @@ defmodule Module.ParallelChecker do
|> Enum.sort()
end
- @doc """
- Collects all exported functions and macros from the module definition ASTs.
- """
- @spec definitions_to_exports([{atom(), arity(), term(), term()}]) ::
- [{{atom(), arity()}, kind()}]
- def definitions_to_exports(definitions) do
- Enum.flat_map(definitions, fn {function, kind, _meta, _clauses} ->
- if kind in [:def, :defmacro] do
- [{function, kind}]
- else
- []
- end
- end)
- end
-
def init([modules, send_results, schedulers]) do
ets = :ets.new(:checker_cache, [:set, :public, {:read_concurrency, true}])
@@ -208,8 +176,8 @@ defmodule Module.ParallelChecker do
send_results_pid = state.send_results
spawn_link(fn ->
- {chunk, warnings} = Module.Checker.verify(verify, {parent, ets})
- send(send_results_pid, {__MODULE__, module, chunk, warnings})
+ warnings = Module.Checker.verify(verify, {parent, ets})
+ send(send_results_pid, {__MODULE__, module, warnings})
send(parent, {__MODULE__, :done})
end)
@@ -299,4 +267,14 @@ defmodule Module.ParallelChecker do
:ets.insert(ets, {{:all_exports, module}, exports})
:ets.insert(ets, {{:cached, module}, true})
end
+
+ defp definitions_to_exports(definitions) do
+ Enum.flat_map(definitions, fn {function, kind, _meta, _clauses} ->
+ if kind in [:def, :defmacro] do
+ [{function, kind}]
+ else
+ []
+ end
+ end)
+ end
end
diff --git a/lib/elixir/src/elixir_erl.erl b/lib/elixir/src/elixir_erl.erl
index 8eb87e2e3..954d6b05a 100644
--- a/lib/elixir/src/elixir_erl.erl
+++ b/lib/elixir/src/elixir_erl.erl
@@ -146,8 +146,9 @@ spawned_compile(Map, Set, _Bag, TranslatedTypespecs) ->
#{module := Module, line := Line} = Map,
DocsChunk = docs_chunk(Set, Module, Line, Def, Defmacro, Types, Callbacks),
+ CheckerChunk = checker_chunk(Map),
- load_form(Map, Prefix, Forms, TypeSpecs, DocsChunk).
+ load_form(Map, Prefix, Forms, TypeSpecs, DocsChunk ++ CheckerChunk).
dynamic_form(#{module := Module, line := Line, relative_file := RelativeFile,
attributes := Attributes, definitions := Definitions, unreachable := Unreachable,
@@ -548,6 +549,33 @@ signature_to_binary(Module, '__struct__', []) ->
signature_to_binary(_, Name, Signature) ->
'Elixir.Macro':to_string({Name, [], Signature}).
+checker_chunk(#{definitions := Definitions, deprecated := Deprecated, compile_opts := CompileOpts}) ->
+ DeprecatedMap = maps:from_list(Deprecated),
+
+ Exports =
+ lists:foldl(fun({Function, Kind, _Meta, _Clauses}, Acc) ->
+ case Kind of
+ _ when Kind == def orelse Kind == defmacro ->
+ Reason = maps:get(Function, DeprecatedMap, nil),
+ [{Function, #{kind => Kind, deprecated_reason => Reason}} | Acc];
+ _ ->
+ Acc
+ end
+ end, [], Definitions),
+
+ Contents = #{
+ exports => lists:sort(Exports),
+ no_warn_undefined => no_warn_undefined(CompileOpts)
+ },
+
+ [{<<"ExCk">>, erlang:term_to_binary({elixir_checker_v1, Contents})}].
+
+no_warn_undefined(CompileOpts) ->
+ [Value || {no_warn_undefined, Values} <- CompileOpts, Value <- list_wrap(Values)].
+
+list_wrap(List) when is_list(List) -> List;
+list_wrap(Other) -> [Other].
+
%% Errors
form_error(#{line := Line, file := File}, Error) ->
diff --git a/lib/elixir/test/elixir/module/checker_test.exs b/lib/elixir/test/elixir/module/checker_test.exs
index 543d7f300..07efb2120 100644
--- a/lib/elixir/test/elixir/module/checker_test.exs
+++ b/lib/elixir/test/elixir/module/checker_test.exs
@@ -156,7 +156,7 @@ defmodule Module.CheckerTest do
assert_warnings(files, warning)
end
- test " reports missing functions respecting arity" do
+ test "reports missing functions respecting arity" do
files = %{
"a.ex" => """
defmodule A do