Age | Commit message (Collapse) | Author |
|
Maps have certain invariants that must be preserved:
(1) A map as a pattern must be represented as #c_map{} record,
never as a literal. The reason is that the pattern '#{}' will
match any map, not just the empty map. The literal '#{}' will
only match the empty map.
(2) In a map pattern, the key must be a literal, a variable, or
data (list or tuple). Keys that are binaries or maps *must* be
represented as literals.
(3) Maps in expressions should be represented as literals if possible.
Nothing is broken if this invariant is broken, but the generated
code will be less efficient.
To preserve invariant (1), cerl:update_c_map/3 must never collapse
a map to a literal. To preserve invariant (3), cerl:update_c_map/3
must collapse a map to a literal if possible.
To preserve both invariants, we need a way for cerl:update_c_map/3 to
know whether the map is used as a pattern or as an expression. The
simplest way is to have an 'is_pat' boolean in the #c_map{} record
which is set when a #c_map{} record is initially created.
We also need to update core_parse.yrl to establish the invariants
in the same way as v3_core, to ensure that compiling from a
.core file will work even if all optimizations on Core Erlang are
disabled.
|
|
|
|
We used to evaluate the body of a 'letrec' in value context, even
if the 'letrec' was being evaluated in effect context. In most
cases, the context does not matter because the body is usually
just an 'apply' which will never be optimized away.
However, in the case of incorrect code described in the previous
commit, it does matter. We can find such bad code by evaluating
the body in effect context. For example, if we have the following
incorrect code:
letrec
f/1 = fun(A) -> ... <use of Var> ...
in let Var = <<2:301>>
in apply(Arg)
If the letrec is evaluated in effect context, the code will be
reduced to:
letrec
f/1 = fun(A) -> ... <use of Var> ...
in seq Var = <<2:301>> do apply(Arg)
Now Var will be unbound and a later compiler pass will crash to
ensure that the bad Core Erlang code is noticed.
Also add a test case to ensure that the compiler crashes if the
bug fixed in the previous commit re-surfaces.
|
|
The translation of list comprehension with a map pattern
with a big literal binary as key such as:
lc(L) ->
[V || #{<<2:301>> := V} <- L].
would generate Core Erlang code where an unbound variable
were referenced:
'lc'/1 =
fun (L) ->
letrec
'lc$^0'/1 = fun (_cor4) ->
case _cor4 of
<[~{~<_cor1,V>}~|_cor3]> when 'true' ->
let <_cor5> = apply 'lc$^0'/1(_cor3)
in [V|_cor5]
<[_cor2|_cor3]> when 'true' ->
apply 'lc$^0'/1(_cor3)
<[]> when 'true' ->
[]
end
in let <_cor1> = #{#<2>(301,1,'integer',['unsigned'|['big']])}#
in apply 'lc$^0'/1(L)
In the map pattern in the 'case' in the 'letrec', the key is the
variable '_cor1' which should be bound in the enclosing environment.
It is not.
There is binding of '_cor1', but in the wrong place (at the end of
the function). Because of the way v3_kernel translates letrecs,
the code *happens* to work.
The code will break if Core Erlang optimizations were strengthened
to more aggressively eliminate variable bindings that are not used,
or if the translation from Core Erlang to Kernel Erlang were changed.
Correct the translation so that '_cor1' is bound in the environment
enclosing the 'letrec':
'lc'/1 =
fun (L) ->
let <_cor1> = #{#<2>(301,1,'integer',['unsigned'|['big']])}#
in letrec
'lc$^0'/1 = fun (_cor4) ->
case _cor4 of
<[~{~<_cor1,V>}~|_cor3]> when 'true' ->
let <_cor5> = apply 'lc$^0'/1(_cor3)
in [V|_cor5]
<[_cor2|_cor3]> when 'true' ->
apply 'lc$^0'/1(_cor3)
<[]> when 'true' ->
[]
end
in apply 'lc$^0'/1(L)
Unfortunately I was not able to come up with a test case that
demonstrates the bug.
|
|
|
|
* s1n4/httpc_invalid_set_cookies/OTP-12430:
httpc: Avoid parsing invalid 'Set-Cookie' headers
|
|
is_var_used/2 did not notice that variable keys in map patterns
were used, which could cause sys_core_fold to do unsafe
optimizations.
|
|
|
|
|
|
Remove ?line macros. Run test cases in parallel.
|
|
|
|
* sverk/port_get_data-race-r16b03/OTP-12208:
erts: Fix port data memory allocation bug
erts: Mend port_set_data with non-immed data for halfword VM
erts: Add test case for port_set_data and port_get_data
erts: Fix race between port_set_data, port_get_data and port termination
erts: Fix erlang:port_set_data/2 for non immediate data
|
|
* marcus/16/fix-rebuild:
Sort keys before generating
|
|
|
|
* ia/ssh/sftp-v3-flags:
ssh: Add some more flags
ssh: Correct Sftp flag handling
ssh: Add handling of sftp v3 flags
|
|
|
|
* ia/ssl/poddle/OTP-12390:
ssl: Remove default support for RC4 ciphers
ssl: Reenable padding check for TLS-1.0 and provide backwards compatible disable option
ssl: Remove sslv3 from the default supported protocol versions
|
|
* ia/ssl/maint/poddle/OTP-12420:
ssl: Reenable padding check for TLS-1.0 and provide backwards compatible disable option
|
|
|
|
* egil/fix-maps-compiler-coverage/OTP-12425:
compiler: Rename util function to adhere to name policy
compiler: Remove get_map_elements label check in blocks
compiler: Remove unnecassary guard for get_map_elements
compiler: Remove dead code in beam_flatten
compiler: Increase Maps code coverage
|
|
|
|
* egil/fix-lcnt/OTP-12364:
tools: Fix lcnt printout of histograms
tools: Fix lcnt sort of inspected locks
|
|
|
|
|
|
|
|
Closes all open socket before writing crashdump to file.
|
|
|
|
* nox/standard_error/OTP-12424:
Test standard_error
Properly handle broken input in standard_error
Fix io:getopts(standard_error)
|
|
|
|
* marcus/rabbe-doc-typos2/OTP-12399:
fix spelling
|
|
|
|
disable option
|
|
|
|
disable option
Conflicts:
lib/ssl/src/ssl_cipher.erl
lib/ssl/src/ssl_record.erl
lib/ssl/src/tls_record.erl
lib/ssl/test/ssl_cipher_SUITE.erl
|
|
|
|
Function name was somewhat confusing and when trying to find a better
name for it we realised it did not work as intended.
|
|
|
|
for non-immediate port data >= sizeof(Eterm)*2 words.
|
|
|
|
|
|
Always update prt->data with atomic xchg-op.
Check for NULL data to detect racing port terminator.
Use NULL, as THE_NON_VALUE can be a valid pointer on debug VM.
|
|
hsize field was not set leading to VM crash
|
|
|
|
* bjorn/compiler/coverage:
map_SUITE: Ensure recompilation when running cover
Add beam_utils_SUITE to cover more lines in beam_utils
beam_utils: Remove unreachable clauses in live_opt/4
receive_SUITE: Cover handling of recv_mark & recv_set in beam_utils
beam_validator_SUITE: Mend the compiler_bug/1 test case
beam_clean: Remove handling of forgotten instructions
compile_SUITE: Test the 'dialyzer' option
|
|
* maint:
Update primary bootstrap
core_lib: Handle patterns in map values
|
|
|
|
* bjorn/compiler/map-pattern/OTP-12414:
core_lib: Handle patterns in map values
|
|
|
|
|
|
beam_utils:live_opt() is only invoked on code that has been
blockified by beam_block. Therefore the allocate/3 and
allocate_heap/4 instructions only occur in their transformed
form inside a block.
While we are it, correct a comment. 'asm' has been replaced
by 'from_asm'.
|