The Elixir compiler spawns a separate process per file.
When a file has to wait on another module, Elixir tracks
in the compiler that the file is waiting.
However, every time a module is defined, the Elixir compiler
spawns a separate process to compile to .beam, and this
process may expand structs in the typespec. Since this
new process is no longer the original file process, Elixir
was not able to track its waiting time.
This PR address this issue by passing the original file_pid
to the .beam compiler process. Note though that, if we
change typespecs to be compiled in the original file process,
this change is no longer required, but at the moment there are
no plans to make such change.
Closes#11036.
Prior to this commit, compilation would copy the module map
(which is the map with the module definitions, attriubutes,
etc) multiple times. In particular, the module execution
process would pass it to the compiler. Then the module
execution process would send it to the parallel compiler
coordinator, which would pass it to the parallel checker
coordinator and then to each individual parallel checker.
That's four copies, which can be quite expensive since it
has the whole Elixir AST.
This commit makes it so it is copied only once. The map
is assembled inside the compiler process and then copied
to the checker process.
This has yielded good improvements in Elixir's test suite.
Before:
Finished in 27.3 seconds (14.4s on load, 7.0s async, 5.8s sync)
After:
Finished in 22.0 seconds (9.4s on load, 6.7s async, 5.8s sync)
This speeds up the Elixir compiler from 5-10% as we no
longer do duplicate work on erl_lint and expand_records.
We also avoid the copying of messages by controlling
exactly when the compiler spawns new processes.
Refers to #5800
Performs the erl_lint check "underspecified_opaque, {TypeName, Arity}}" in Elixir.
After reading the Erlang/OTP codebase, it seems an "underspecified opaque" is an opaque type of arity 0 with a spec of "term" or "any".
Optimizes :maps.put/3 to a VM operation instead of a remote call, including nested calls to it.
It does the same for :maps.merge/2 with a simple map on the right side.
Closes#7353
This guarantees decompiling Elixir code to Erlang results
in runnable code and improves Elixir's interoperability
with tools such as the Erlang debugger.