Skip to content

Commit a1d491d

Browse files
committed
Always pass parallel checker cache around
1 parent 4162d23 commit a1d491d

File tree

3 files changed

+65
-70
lines changed

3 files changed

+65
-70
lines changed

lib/elixir/lib/kernel/parallel_compiler.ex

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,11 @@ defmodule Kernel.ParallelCompiler do
3131
dest = :erlang.get(:elixir_compiler_dest)
3232

3333
{:error_handler, error_handler} = :erlang.process_info(self(), :error_handler)
34-
{_parent, checker} = Module.ParallelChecker.get()
34+
{_parent, cache} = Module.ParallelChecker.get()
3535

3636
task =
3737
Task.async(fn ->
38-
Module.ParallelChecker.put(compiler_pid, checker)
38+
Module.ParallelChecker.put(compiler_pid, cache)
3939
:erlang.put(:elixir_compiler_info, {compiler_pid, file_pid})
4040
:erlang.put(:elixir_compiler_file, file)
4141
dest != :undefined and :erlang.put(:elixir_compiler_dest, dest)
@@ -253,11 +253,11 @@ defmodule Kernel.ParallelCompiler do
253253
max(:erlang.system_info(:schedulers_online), 2)
254254
end)
255255

256-
{:ok, checker} = Module.ParallelChecker.start_link(schedulers)
256+
{:ok, cache} = Module.ParallelChecker.start_link(schedulers)
257257

258258
{status, modules_or_errors, info} =
259259
try do
260-
outcome = spawn_workers(schedulers, checker, files, output, options)
260+
outcome = spawn_workers(schedulers, cache, files, output, options)
261261
{outcome, Keyword.get(options, :warnings_as_errors, false)}
262262
else
263263
{{:ok, _, %{runtime_warnings: r_warnings, compile_warnings: c_warnings} = info}, true}
@@ -281,7 +281,7 @@ defmodule Kernel.ParallelCompiler do
281281
{{:error, errors, info}, _} ->
282282
{:error, errors, info}
283283
after
284-
Module.ParallelChecker.stop(checker)
284+
Module.ParallelChecker.stop(cache)
285285
end
286286

287287
# TODO: Require this to be set from Elixir v1.19
@@ -428,13 +428,13 @@ defmodule Kernel.ParallelCompiler do
428428
end
429429

430430
defp spawn_workers([file | queue], spawned, waiting, files, result, warnings, errors, state) do
431-
%{output: output, dest: dest, checker: checker} = state
431+
%{output: output, dest: dest, checker: cache} = state
432432
parent = self()
433433
file = Path.expand(file)
434434

435435
{pid, ref} =
436436
:erlang.spawn_monitor(fn ->
437-
Module.ParallelChecker.put(parent, checker)
437+
Module.ParallelChecker.put(parent, cache)
438438
:erlang.put(:elixir_compiler_info, {parent, self()})
439439
:erlang.put(:elixir_compiler_file, file)
440440

lib/elixir/lib/module/parallel_checker.ex

Lines changed: 49 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,13 @@ defmodule Module.ParallelChecker do
1111
Initializes the parallel checker process.
1212
"""
1313
def start_link(schedulers \\ nil) do
14-
:gen_server.start_link(__MODULE__, schedulers, [])
14+
:proc_lib.start_link(__MODULE__, :init, [schedulers])
1515
end
1616

1717
@doc """
1818
Stops the parallel checker process.
1919
"""
20-
def stop(checker) do
20+
def stop({checker, _table}) do
2121
send(checker, {__MODULE__, :stop})
2222
:ok
2323
end
@@ -28,39 +28,38 @@ defmodule Module.ParallelChecker do
2828
def get do
2929
case :erlang.get(:elixir_checker_info) do
3030
{parent, nil} ->
31-
{:ok, checker} = start_link()
32-
put(parent, checker)
33-
{parent, checker}
31+
{:ok, checker_table} = start_link()
32+
put(parent, checker_table)
33+
{parent, checker_table}
3434

35-
{parent, checker} ->
36-
{parent, checker}
35+
{parent, checker_table} ->
36+
{parent, checker_table}
3737
end
3838
end
3939

4040
@doc """
4141
Stores the parallel checker information.
4242
"""
43-
def put(pid, checker) when is_pid(pid) and is_pid(checker) do
44-
:erlang.put(:elixir_checker_info, {pid, checker})
43+
def put(pid, {checker, table}) when is_pid(pid) do
44+
:erlang.put(:elixir_checker_info, {pid, {checker, table}})
4545
end
4646

4747
@doc """
4848
Spawns a process that runs the parallel checker.
4949
"""
50-
def spawn({pid, checker}, module, module_map, log?) do
51-
ets = :gen_server.call(checker, :ets, :infinity)
52-
inner_spawn(pid, checker, module, cache_from_module_map(ets, module_map), log?)
50+
def spawn({pid, {checker, table}}, module, module_map, log?) do
51+
inner_spawn(pid, checker, table, module, cache_from_module_map(table, module_map), log?)
5352
end
5453

55-
defp inner_spawn(pid, checker, module, info, log?) do
54+
defp inner_spawn(pid, checker, table, module, info, log?) do
5655
ref = make_ref()
5756

5857
spawned =
5958
spawn(fn ->
6059
mon_ref = Process.monitor(pid)
6160

6261
receive do
63-
{^ref, :cache, ets} ->
62+
{^ref, :cache} ->
6463
Process.link(pid)
6564

6665
module_tuple =
@@ -73,7 +72,7 @@ defmodule Module.ParallelChecker do
7372
{:ok, {_, [debug_info: chunk]}} <- :beam_lib.chunks(binary, [:debug_info]),
7473
{:debug_info_v1, backend, data} = chunk,
7574
{:ok, module_map} <- backend.debug_info(:elixir_v1, module, data, []) do
76-
cache_from_module_map(ets, module_map)
75+
cache_from_module_map(table, module_map)
7776
else
7877
_ -> nil
7978
end
@@ -88,7 +87,7 @@ defmodule Module.ParallelChecker do
8887

8988
warnings =
9089
if module_tuple do
91-
check_module(module_tuple, {checker, ets}, log?)
90+
check_module(module_tuple, {checker, table}, log?)
9291
else
9392
[]
9493
end
@@ -122,20 +121,20 @@ defmodule Module.ParallelChecker do
122121

123122
case :erlang.get(:elixir_checker_info) do
124123
{_, nil} -> :ok
125-
{_, checker} -> verify(checker, [])
124+
{_, cache} -> verify(cache, [])
126125
end
127126

128127
result
129128
after
130-
{_, checker} = :erlang.get(:elixir_checker_info)
129+
{_, cache} = :erlang.get(:elixir_checker_info)
131130

132131
if previous != :undefined do
133132
:erlang.put(:elixir_checker_info, previous)
134133
else
135134
:erlang.erase(:elixir_checker_info)
136135
end
137136

138-
checker && stop(checker)
137+
cache && stop(cache)
139138
end
140139

141140
_ ->
@@ -150,13 +149,13 @@ defmodule Module.ParallelChecker do
150149
the modules and adds the ExCk chunk to the binaries. Returns the updated
151150
list of warnings from the verification.
152151
"""
153-
@spec verify(pid(), [{module(), Path.t()}]) :: [warning()]
154-
def verify(checker, runtime_files) do
152+
@spec verify(cache(), [{module(), Path.t()}]) :: [warning()]
153+
def verify({checker, table}, runtime_files) do
155154
value = :erlang.get(:elixir_code_diagnostics)
156155
log? = not match?({_, false}, value)
157156

158157
for {module, file} <- runtime_files do
159-
inner_spawn(self(), checker, module, file, log?)
158+
inner_spawn(self(), checker, table, module, file, log?)
160159
end
161160

162161
count = :gen_server.call(checker, :start, :infinity)
@@ -190,8 +189,8 @@ defmodule Module.ParallelChecker do
190189
Test cache.
191190
"""
192191
def test_cache do
193-
{:ok, checker} = start_link()
194-
{checker, :gen_server.call(checker, :ets, :infinity)}
192+
{:ok, checker_table} = start_link()
193+
checker_table
195194
end
196195

197196
@doc """
@@ -202,17 +201,17 @@ defmodule Module.ParallelChecker do
202201
@spec fetch_export(cache(), module(), atom(), arity()) ::
203202
{:ok, mode(), binary() | nil, {:infer, [term()]} | :none}
204203
| {:error, :function | :module}
205-
def fetch_export({server, ets}, module, fun, arity) do
206-
case :ets.lookup(ets, module) do
204+
def fetch_export({checker, table}, module, fun, arity) do
205+
case :ets.lookup(table, module) do
207206
[] ->
208-
cache_module({server, ets}, module)
209-
fetch_export({server, ets}, module, fun, arity)
207+
cache_module({checker, table}, module)
208+
fetch_export({checker, table}, module, fun, arity)
210209

211210
[{_key, false}] ->
212211
{:error, :module}
213212

214213
[{_key, mode}] ->
215-
case :ets.lookup(ets, {module, {fun, arity}}) do
214+
case :ets.lookup(table, {module, {fun, arity}}) do
216215
[{_key, reason, signature}] -> {:ok, mode, reason, signature}
217216
[] -> {:error, :function}
218217
end
@@ -371,37 +370,37 @@ defmodule Module.ParallelChecker do
371370

372371
## Cache
373372

374-
defp cache_module({server, ets}, module) do
375-
if lock(server, module) do
373+
defp cache_module({checker, table}, module) do
374+
if lock(checker, module) do
376375
object_code = :code.get_object_code(module)
377376

378377
# The chunk has more information, so that's our preference
379378
with {^module, binary, _filename} <- object_code,
380379
{:ok, {^module, [{~c"ExCk", chunk}]}} <- :beam_lib.chunks(binary, [~c"ExCk"]),
381380
{:elixir_checker_v1, contents} <- :erlang.binary_to_term(chunk) do
382-
cache_chunk(ets, module, contents.exports)
381+
cache_chunk(table, module, contents.exports)
383382
else
384383
_ ->
385384
# Otherwise, if the module is loaded, use its info
386385
case :erlang.module_loaded(module) do
387386
true ->
388387
{mode, exports} = info_exports(module)
389388
deprecated = info_deprecated(module)
390-
cache_info(ets, module, exports, deprecated, %{}, mode)
389+
cache_info(table, module, exports, deprecated, %{}, mode)
391390

392391
false ->
393392
# Or load exports from chunk
394393
with {^module, binary, _filename} <- object_code,
395394
{:ok, {^module, [exports: exports]}} <- :beam_lib.chunks(binary, [:exports]) do
396-
cache_info(ets, module, exports, %{}, %{}, :erlang)
395+
cache_info(table, module, exports, %{}, %{}, :erlang)
397396
else
398397
_ ->
399-
:ets.insert(ets, {module, false})
398+
:ets.insert(table, {module, false})
400399
end
401400
end
402401
end
403402

404-
unlock(server, module)
403+
unlock(checker, module)
405404
end
406405
end
407406

@@ -417,36 +416,36 @@ defmodule Module.ParallelChecker do
417416
_ -> %{}
418417
end
419418

420-
defp cache_from_module_map(ets, map) do
419+
defp cache_from_module_map(table, map) do
421420
exports =
422421
[{:__info__, 1}] ++
423422
behaviour_exports(map) ++
424423
for({function, :def, _meta, _clauses} <- map.definitions, do: function)
425424

426-
cache_info(ets, map.module, exports, Map.new(map.deprecated), map.signatures, :elixir)
425+
cache_info(table, map.module, exports, Map.new(map.deprecated), map.signatures, :elixir)
427426
module_map_to_module_tuple(map)
428427
end
429428

430-
defp cache_info(ets, module, exports, deprecated, sigs, mode) do
429+
defp cache_info(table, module, exports, deprecated, sigs, mode) do
431430
Enum.each(exports, fn fa ->
432431
reason = Map.get(deprecated, fa)
433-
:ets.insert(ets, {{module, fa}, reason, Map.get(sigs, fa, :none)})
432+
:ets.insert(table, {{module, fa}, reason, Map.get(sigs, fa, :none)})
434433
end)
435434

436-
:ets.insert(ets, {module, mode})
435+
:ets.insert(table, {module, mode})
437436
end
438437

439-
defp cache_chunk(ets, module, exports) do
438+
defp cache_chunk(table, module, exports) do
440439
Enum.each(exports, fn {{fun, arity}, info} ->
441440
# TODO: Match on signature directly in Elixir v1.22+
442441
:ets.insert(
443-
ets,
442+
table,
444443
{{module, {fun, arity}}, Map.get(info, :deprecated), Map.get(info, :sig, :none)}
445444
)
446445
end)
447446

448-
:ets.insert(ets, {{module, {:__info__, 1}}, nil, :none})
449-
:ets.insert(ets, {module, :elixir})
447+
:ets.insert(table, {{module, {:__info__, 1}}, nil, :none})
448+
:ets.insert(table, {module, :elixir})
450449
end
451450

452451
defp behaviour_exports(%{defines_behaviour: true}), do: [{:behaviour_info, 1}]
@@ -475,22 +474,22 @@ defmodule Module.ParallelChecker do
475474
## Server callbacks
476475

477476
def init(schedulers) do
478-
ets = :ets.new(__MODULE__, [:set, :public, {:read_concurrency, true}])
477+
table = :ets.new(__MODULE__, [:set, :public, {:read_concurrency, true}])
478+
:proc_lib.init_ack({:ok, {self(), table}})
479479

480480
state = %{
481-
ets: ets,
482481
waiting: %{},
483482
modules: [],
484483
spawned: 0,
485484
schedulers: schedulers || max(:erlang.system_info(:schedulers_online), 2)
486485
}
487486

488-
{:ok, state}
487+
:gen_server.enter_loop(__MODULE__, [], state)
489488
end
490489

491-
def handle_call(:start, _from, %{ets: ets, modules: modules} = state) do
490+
def handle_call(:start, _from, %{modules: modules} = state) do
492491
for {pid, ref} <- modules do
493-
send(pid, {ref, :cache, ets})
492+
send(pid, {ref, :cache})
494493
end
495494

496495
for {_pid, ref} <- modules do
@@ -502,10 +501,6 @@ defmodule Module.ParallelChecker do
502501
{:reply, length(modules), run_checkers(state)}
503502
end
504503

505-
def handle_call(:ets, _from, state) do
506-
{:reply, state.ets, state}
507-
end
508-
509504
def handle_call({:lock, module}, from, %{waiting: waiting} = state) do
510505
case waiting do
511506
%{^module => froms} ->

lib/elixir/test/elixir/kernel/raise_test.exs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -434,15 +434,15 @@ defmodule Kernel.RaiseTest do
434434

435435
:code.purge(BadFunction.Missing)
436436

437-
result =
438-
try do
439-
fun.()
440-
rescue
441-
x in [BadFunctionError] -> Exception.message(x)
442-
end
443-
444-
assert result =~
445-
~r/function #Function<[0-9]\.[0-9]*\/0[^>]*> is invalid, likely because it points to an old version of the code/
437+
try do
438+
fun.()
439+
rescue
440+
x in [BadFunctionError] ->
441+
assert Exception.message(x) =~
442+
~r/function #Function<[0-9]\.[0-9]*\/0[^>]*> is invalid, likely because it points to an old version of the code/
443+
else
444+
_ -> flunk("this should not be invoked")
445+
end
446446
end
447447

448448
test "badmatch error" do

0 commit comments

Comments
 (0)