| Commit message (Collapse) | Author | Age | Files | Lines |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Rather than allowing modules to be writable all the time, either
through RWX pages or a dual-mapped RW page, support making them
writable only in the brief window that they are actually being
modified.
To avoid introducing subtle bugs this late in the release cycle,
we'll settle for adding assertions that modifications are only
made while a module is marked writable. We won't change any page
permissions just yet.
The one exception to this are the per-thread permissions on MacOS,
where a thread can temporarily trade permission to execute MAP_JIT
pages for being able to write to them. This permission is added
when making a module writable and removed when we're done. This
fixes the long-standing issue GH-4911 on Apple Silicon (Intel macs
are still affected since we don't want to give up W^X).
|
| |
|
|\
| |
| |
| |
| |
| |
| |
| | |
* maint:
Eliminate compiler crash in binary construction
non-JIT BEAM: Avoid redundant GC in binary syntax
BEAM disassembler: Correct printout of W operands
GC: Support heap needs of more than 2 GiB
|
| | |
|
|/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Because funs are tied to their canonical module rather than a
specific instance of a module, they are "moved over" to the newest
instance whenever we reload _the exact same module_ over itself.
This quirk, together with how fun entries are updated when a module
is loaded, caused a small window where it was possible for a holder
of an "old" fun to call the new instance before it was fully loaded.
This commit fixes that by versioning funs in roughly the same way
we do exports. It also fixes a related bug where fun purging could
be messed up if a new module instance was loaded in the middle of
purging, solving the issue by disallowing code loading while
purging a module with funs.
|
|\
| |
| |
| |
| | |
* maint:
Update copyright year
|
| | |
|
| | |
|
|\ \
| | |
| | | |
Implement extended error information for binary construction
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | | |
Implement the bs_create_bin instruction for the JITs and the emulator.
Consider this example module:
-module(foo).
-export([bin/2, int/2, float/2, var_int/2]).
bin(A, B) -> <<A/binary, B/binary>>.
int(A, B) -> <<A/integer, B/integer>>.
float(A, B) -> <<A/float, B/float>>.
var_int(A, Size) -> <<A:Size>>.
With the extended error information introduced in this commit, failures to build
binaries will be reported like this:
1> c(foo).
{ok,foo}
2> foo:bin(2, <<>>).
** exception error: construction of binary failed
in function foo:bin/2 (foo.erl, line 4)
*** segment 1 of type 'binary': expected a binary but got: 2
3> foo:bin(<<>>, 42).
** exception error: construction of binary failed
in function foo:bin/2 (foo.erl, line 4)
*** segment 2 of type 'binary': expected a binary but got: 42
4> foo:bin(<<>>, <<1:1>>).
** exception error: construction of binary failed
in function foo:bin/2 (foo.erl, line 4)
*** segment 2 of type 'binary': the size of the value <<1:1>> is not a multiple of the unit for the segment
5> foo:int(a, 42).
** exception error: construction of binary failed
in function foo:int/2 (foo.erl, line 5)
*** segment 1 of type 'integer': expected an integer but got: a
6> foo:float(<<>>, <<>>).
** exception error: construction of binary failed
in function foo:float/2 (foo.erl, line 6)
*** segment 1 of type 'float': expected a float or an integer but got: <<>>
7> foo:var_int(42, -1).
** exception error: construction of binary failed
in function foo:var_int/2 (foo.erl, line 7)
*** segment 1 of type 'integer': expected a non-negative integer as size but got: -1
8> foo:var_int(42, a).
** exception error: construction of binary failed
in function foo:var_int/2 (foo.erl, line 7)
*** segment 1 of type 'integer': expected a non-negative integer as size but got: a
9> foo:var_int(42, 1 bsl 64).
** exception error: construction of binary failed
in function foo:var_int/2 (foo.erl, line 7)
*** segment 1 of type 'integer': the size 18446744073709551616 is too large
Closes #4971.
|
|\ \ \
| | | |
| | | | |
erts: Optimize fun calls
|
| |/ /
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | | |
By making local and external funs share the same structure, we can
remove a substantial amount of code from the `call_fun` family of
instructions.
As a result fun calls are now about 15% faster with the interpreter
on my machine, 10% faster with the x64 JIT on that same machine,
and 15% faster with the AArch64 JIT on my M1 Mac. The improvement
is a bit less pronounced for funs with free variables, and a bit
more for those without (including external funs).
|
|\ \ \
| |/ /
|/| /
| |/ |
|
| |
| |
| |
| | |
with CopyLiterals boolean argument.
|
|\ \
| |/ |
|
| | |
|
|/ |
|
| |
|
|
|
|
|
| |
Using `BeamInstr*` means that all code must be word-aligned even
when we're not pointing at BEAM opcodes, which is rather wasteful.
|
| |
|
|
|
|
|
|
|
|
| |
This allows the JIT to be used on systems that enforce a W^X
policy.
To help catch related errors at compile time, all code pointers
have been marked `const`.
|
| |
|
|
|
|
|
| |
We will slightly reduce the size of process_main() for the
interpreter.
|
|
|
|
|
|
| |
Co-authored-by: Lukas Larsson <lukas@erlang.org>
Co-authored-by: Björn Gustavsson <bjorn@erlang.org>
Co-authored-by: Dan Gudmundsson <dgud@erlang.org>
|
|
|
|
|
|
| |
Co-authored-by: John Högberg <john@erlang.org>
Co-authored-by: Dan Gudmundsson <dgud@erlang.org>
Co-authored-by: Björn Gustavsson <bjorn@erlang.org>
|
|
|
|
|
|
|
| |
This is done in preperation from BeamAsm
Co-authored-by: John Högberg <john@erlang.org>
Co-authored-by: Dan Gudmundsson <dgud@erlang.org>
|
|
|
|
|
|
|
|
| |
This is needed as BeamAsm needs the export entries to
be executable, which means that we need to allocate them.
Co-authored-by: John Högberg <john@erlang.org>
Co-authored-by: Dan Gudmundsson <dgud@erlang.org>
|
| |
|
| |
|
| |
|
|\
| |
| |
| |
| | |
* maint:
Update copyright year
|
| | |
|
| | |
|
| |
| |
| |
| |
| | |
This hides traps when BIFs are traced, making them appear as a
single call + return pair.
|
|/ |
|
|
|
|
|
| |
Add erts_debug:interpreter_size/0 for retrieving the approximate
size of the BEAM interpreter (process_main()).
|
| |
|
|
|
|
|
| |
That will avoid showing garbage instructions that will never be
executed.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Summary: This commit simplifies the implementation of the "GC BIFs" so
that they no longer need to do a garbage collection, removing duplicate
code for all GC BIFs in the runtime system, as well as potentially
reducing the size of the loaded BEAM code by using shorter
instructions calling those BIFs.
A GC BIF is a guard BIF that will do a garbage
collection if it needs to build anything on the heap.
For example, `abs/1` is a GC BIF because it might need to
allocate space on the heap (if the result is a floating point
number or the resulting integer is a bignum).
Before R12, a guard BIF (such as `abs/1`) that need to allocate
heap space would allocate outside of process's main heap, in
a heap fragment.
GC BIFs were introduced in R12B to support literals. During garbage
collection it become necessary to quickly test whether a term was
a literal. To make the check simple, guards BIFs were no longer
allowed to create heap fragments. Instead GC BIFs were introduced.
In OTP 19, the implementation of literals was changed to support
storing messages in heap fragments outside of the main heap for a
process. That change again made it allowed for guard BIFs to create
heap fragments when they need to build terms on the heap.
It would even be possible for the guard BIFs to build directly
on the main heap if there is room there, because the compiler
assumes that a new `test_heap/2` instruction must be emitted
when building anything after calling a GC BIF. (We don't do that
in this commit; see below.)
This commit simplifies the implementation of the GC BIFs in
the runtime system.
Each GC BIF had a dual implementation: one that was used when the GC
BIF was called directly and one used when it was called via
`apply/3`. For example, `abs/1` was implemented in `abs_1()` and
`erts_gc_abs_1()`. This commit removes the GC version of each BIF. The
other version that allocates heap space using `HAlloc()` is updated to
use the new `HeapFragOnlyAlloc()` macro that will allocate heap
space in a heap fragment outside of the main heap.
Because the BIFs will allocate outside of the main heap, the same
`bif` instructions used by nonbuilding BIFs can be used for the
(former) GC BIFs. Those instructions don't use the macros that save
and restore the heap and stack pointers (SWAPOUT/SWAPIN). If the
former GC BIFs would build on the main heap, either new instructions
would be needed, or SWAPOUT/SWAPIN instructions would need to be added
to the `bif` instructions.
Instructions that call the former GC BIFs don't need the operand
that specifies the number of live X registers. Therefore, the
instructions that call the BIFs are usually one word shorter.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Sometimes when building a tuple, there is no way to avoid an
extra `move` instruction. Consider this code:
make_tuple(A) -> {ok,A}.
The corresponding BEAM code looks like this:
{test_heap,3,1}.
{put_tuple,2,{x,1}}.
{put,{atom,ok}}.
{put,{x,0}}.
{move,{x,1},{x,0}}.
return.
To avoid overwriting the source register `{x,0}`, a `move`
instruction is necessary.
The problem doesn't exist when building a list:
%% build_list(A) -> [A].
{test_heap,2,1}.
{put_list,{x,0},nil,{x,0}}.
return.
Introduce a new `put_tuple2` instruction that builds a tuple in a
single instruction, so that the `move` instruction can be eliminated:
%% make_tuple(A) -> {ok,A}.
{test_heap,3,1}.
{put_tuple2,{x,0},{list,[{atom,ok},{x,0}]}}.
return.
Note that the BEAM loader already combines `put_tuple` and `put`
instructions into an internal instruction similar to `put_tuple2`.
Therefore the introduction of the new instruction will not speed up
execution of tuple building itself, but it will be less work for
the loader to load the new instruction.
|
|
|
|
|
|
|
|
|
|
| |
A lot of erts internal messages used behind APIs to create
non-blocking calls, e.g. port_command, would cause the seq_trace
token to be cleared from the caller when it should not.
This commit fixes that and adds asserts that makes sure
that all messages sent have to correct token set.
Fixes: ERL-602
|
| |
|
| |
|
|
|
|
|
| |
If no message/signal is sent (to same destination)
then monitor signal is flushed when process is scheduled out.
|
| |
|
| |
|
| |
|
| |
|
| |
|