aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile.in2
-rw-r--r--OTP_VERSION2
-rw-r--r--bootstrap/bin/no_dot_erlang.bootbin6541 -> 6544 bytes
-rw-r--r--bootstrap/bin/start.bootbin6541 -> 6544 bytes
-rw-r--r--bootstrap/bin/start_clean.bootbin6541 -> 6544 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_asm.beambin10996 -> 10988 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_dict.beambin4660 -> 4644 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_except.beambin4228 -> 4204 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_flatten.beambin1940 -> 1928 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_jump.beambin9988 -> 10012 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_kernel_to_ssa.beambin28880 -> 28692 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_peep.beambin3604 -> 3588 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_ssa.beambin12176 -> 12168 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_ssa_bsm.beambin17952 -> 17888 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_ssa_codegen.beambin37708 -> 37604 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_ssa_dead.beambin11876 -> 12072 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_ssa_funs.beambin2572 -> 2556 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_ssa_opt.beambin38664 -> 39916 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_ssa_pre_codegen.beambin45400 -> 45300 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_ssa_recv.beambin3912 -> 3884 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_ssa_type.beambin28456 -> 28324 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_validator.beambin44140 -> 46224 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_z.beambin3620 -> 3604 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/cerl.beambin28252 -> 28236 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/cerl_inline.beambin34840 -> 34712 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/cerl_sets.beambin2840 -> 2728 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/cerl_trees.beambin20416 -> 20408 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/compile.beambin41276 -> 41208 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/rec_env.beambin4492 -> 4468 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/sys_core_alias.beambin5588 -> 5548 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/sys_core_fold.beambin45584 -> 45480 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/sys_core_inline.beambin3912 -> 3908 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/v3_core.beambin50704 -> 50672 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/v3_kernel.beambin50348 -> 50576 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/v3_kernel_pp.beambin12060 -> 12052 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/application.beambin3732 -> 3684 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/application_controller.beambin29864 -> 29612 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/application_starter.beambin1188 -> 1180 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/auth.beambin6164 -> 6148 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/code.beambin12740 -> 12688 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/code_server.beambin22624 -> 22552 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/disk_log.beambin29652 -> 29556 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/disk_log_1.beambin22496 -> 22392 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/disk_log_server.beambin6160 -> 6136 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/dist_ac.beambin23492 -> 23356 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/dist_util.beambin12312 -> 12312 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/erl_boot_server.beambin5588 -> 5580 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/erl_ddll.beambin2752 -> 2744 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/erl_epmd.beambin7060 -> 7036 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/error_logger.beambin6128 -> 6112 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/erts_debug.beambin9184 -> 9176 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/file.beambin13384 -> 13356 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/file_io_server.beambin15324 -> 15292 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/file_server.beambin4920 -> 4912 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/global.beambin29228 -> 29188 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/global_group.beambin15812 -> 15708 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/group.beambin14240 -> 14200 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/group_history.beambin5536 -> 5496 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/heart.beambin5172 -> 5140 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/inet.beambin23256 -> 23232 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/inet_config.beambin7252 -> 7236 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/inet_db.beambin25288 -> 25300 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/inet_dns.beambin18604 -> 18564 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/inet_gethost_native.beambin9732 -> 9708 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/inet_parse.beambin13404 -> 13396 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/inet_res.beambin13200 -> 13192 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/inet_tcp_dist.beambin7492 -> 7476 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/kernel.app3
-rw-r--r--bootstrap/lib/kernel/ebin/kernel.beambin3572 -> 3532 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/kernel_config.beambin2644 -> 2604 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/logger.beambin15100 -> 15012 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/logger_backend.beambin2552 -> 2544 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/logger_disk_log_h.beambin3356 -> 3348 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/logger_formatter.beambin8568 -> 8552 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/logger_h_common.beambin7668 -> 7644 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/logger_handler_watcher.beambin1352 -> 1344 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/logger_olp.beambin8316 -> 8308 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/logger_server.beambin11376 -> 11352 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/logger_simple_h.beambin4244 -> 4236 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/logger_std_h.beambin5184 -> 5168 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/net_kernel.beambin24244 -> 24164 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/os.beambin5128 -> 5112 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/raw_file_io.beambin1668 -> 1660 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/raw_file_io_deflate.beambin2600 -> 2592 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/raw_file_io_delayed.beambin5208 -> 5200 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/raw_file_io_inflate.beambin4188 -> 4140 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/user.beambin11020 -> 10980 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/user_drv.beambin10908 -> 10844 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/wrap_log_reader.beambin2936 -> 2940 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/beam_lib.beambin18708 -> 18660 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/c.beambin17000 -> 16968 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/dets.beambin45236 -> 45128 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/dets_server.beambin6468 -> 6444 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/dets_utils.beambin25788 -> 25712 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/dets_v9.beambin45256 -> 45228 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/digraph.beambin7508 -> 7500 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/edlin.beambin10504 -> 10472 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/edlin_expand.beambin3756 -> 3748 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/epp.beambin28276 -> 28268 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/erl_bits.beambin2356 -> 2348 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/erl_compile.beambin6684 -> 6676 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/erl_error.beambin8280 -> 8256 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/erl_eval.beambin35192 -> 35048 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/erl_expand_records.beambin19396 -> 19356 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/erl_lint.beambin85148 -> 84964 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/erl_pp.beambin25568 -> 25552 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/erl_scan.beambin25720 -> 25696 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/erl_tar.beambin31016 -> 30896 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/error_logger_file_h.beambin3956 -> 3944 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/error_logger_tty_h.beambin4788 -> 4776 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/escript.beambin15676 -> 15636 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/ets.beambin21536 -> 21460 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/eval_bits.beambin7684 -> 7660 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/file_sorter.beambin27324 -> 27276 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/filelib.beambin10216 -> 10188 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/filename.beambin14796 -> 14788 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/gen.beambin4912 -> 4896 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/gen_event.beambin13020 -> 13012 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/gen_fsm.beambin12432 -> 12424 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/gen_server.beambin15344 -> 15328 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/gen_statem.beambin20448 -> 20408 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/io.beambin5796 -> 5792 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/io_lib_pretty.beambin21068 -> 20996 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/lists.beambin29280 -> 29272 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/log_mf_h.beambin2360 -> 2352 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/ms_transform.beambin18460 -> 18452 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/otp_internal.beambin10208 -> 10396 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/proc_lib.beambin12628 -> 12624 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/qlc.beambin65192 -> 65060 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/qlc_pt.beambin70568 -> 70536 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/re.beambin12344 -> 12312 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/shell.beambin28484 -> 28396 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/slave.beambin4756 -> 4740 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/sofs.beambin35276 -> 35276 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/supervisor.beambin21700 -> 21588 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/supervisor_bridge.beambin2340 -> 2332 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/sys.beambin9100 -> 9084 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/timer.beambin5280 -> 5272 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/unicode.beambin14140 -> 14076 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/unicode_util.beambin198716 -> 198636 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/zip.beambin24236 -> 24188 bytes
-rw-r--r--erts/doc/src/erl.xml2
-rw-r--r--erts/emulator/beam/beam_load.c31
-rw-r--r--erts/emulator/beam/instrs.tab54
-rw-r--r--erts/emulator/beam/ops.tab136
-rw-r--r--erts/emulator/beam/utils.c2
-rw-r--r--erts/emulator/internal_doc/CountingInstructions.md53
-rw-r--r--erts/emulator/nifs/common/net_nif.c37
-rw-r--r--erts/emulator/sys/common/erl_mmap.h2
-rw-r--r--erts/emulator/test/Makefile9
-rw-r--r--erts/emulator/test/esock_misc/socket_client.erl (renamed from erts/emulator/test/socket_client.erl)0
-rw-r--r--erts/emulator/test/esock_misc/socket_lib.erl (renamed from erts/emulator/test/socket_lib.erl)0
-rw-r--r--erts/emulator/test/esock_misc/socket_server.erl (renamed from erts/emulator/test/socket_server.erl)0
-rw-r--r--erts/emulator/test/net_SUITE.erl481
-rw-r--r--erts/emulator/test/socket_SUITE.erl996
-rw-r--r--erts/emulator/test/socket_test_logger.erl27
-rw-r--r--erts/etc/unix/to_erl.c1
-rw-r--r--erts/lib_src/common/erl_printf.c5
-rw-r--r--erts/preloaded/ebin/erl_prim_loader.beambin53300 -> 52636 bytes
-rw-r--r--erts/preloaded/ebin/init.beambin50364 -> 50304 bytes
-rw-r--r--erts/preloaded/ebin/prim_file.beambin28072 -> 28084 bytes
-rw-r--r--erts/preloaded/src/erl_prim_loader.erl7
-rw-r--r--erts/preloaded/src/init.erl7
-rw-r--r--erts/preloaded/src/prim_eval.S4
-rw-r--r--erts/preloaded/src/prim_file.erl7
-rw-r--r--lib/common_test/doc/src/basics_chapter.xml2
-rw-r--r--lib/common_test/test_server/ts_install.erl2
-rw-r--r--lib/compiler/src/beam_jump.erl8
-rw-r--r--lib/compiler/src/beam_kernel_to_ssa.erl10
-rw-r--r--lib/compiler/src/beam_ssa_dead.erl364
-rw-r--r--lib/compiler/src/beam_ssa_opt.erl92
-rw-r--r--lib/compiler/src/beam_ssa_type.erl3
-rw-r--r--lib/compiler/src/beam_validator.erl1540
-rw-r--r--lib/compiler/src/cerl_sets.erl2
-rw-r--r--lib/compiler/src/v3_kernel.erl85
-rw-r--r--lib/compiler/test/beam_jump_SUITE.erl47
-rw-r--r--lib/compiler/test/beam_validator_SUITE.erl19
-rw-r--r--lib/compiler/test/receive_SUITE.erl30
-rw-r--r--lib/crypto/c_src/pkey.c76
-rw-r--r--lib/crypto/test/Makefile1
-rw-r--r--lib/crypto/test/blowfish_SUITE.erl300
-rw-r--r--lib/crypto/test/crypto_SUITE.erl34
-rw-r--r--lib/edoc/src/edoc.erl17
-rw-r--r--lib/erl_docgen/priv/css/otp_doc.css10
-rw-r--r--lib/erl_docgen/priv/xsl/db_html.xsl76
-rw-r--r--lib/erl_interface/src/prog/erl_start.c2
-rw-r--r--lib/inets/examples/httpd_load_test/hdlt_slave.erl11
-rw-r--r--lib/kernel/doc/src/application.xml35
-rw-r--r--lib/kernel/doc/src/logger.xml24
-rw-r--r--lib/kernel/src/application.erl22
-rw-r--r--lib/kernel/src/application_controller.erl104
-rw-r--r--lib/kernel/src/code_server.erl10
-rw-r--r--lib/kernel/src/inet_db.erl7
-rw-r--r--lib/kernel/src/logger.erl10
-rw-r--r--lib/kernel/src/logger_h_common.erl2
-rw-r--r--lib/kernel/src/logger_simple_h.erl4
-rw-r--r--lib/kernel/test/application_SUITE.erl97
-rw-r--r--lib/kernel/test/inet_SUITE.erl31
-rw-r--r--lib/kernel/test/logger_SUITE.erl4
-rw-r--r--lib/kernel/test/logger_formatter_SUITE.erl2
-rw-r--r--lib/mnesia/examples/bench/README2
-rw-r--r--lib/ssl/doc/src/ssl.xml21
-rw-r--r--lib/ssl/src/dtls_packet_demux.erl3
-rw-r--r--lib/ssl/src/dtls_socket.erl49
-rw-r--r--lib/ssl/src/ssl.erl2
-rw-r--r--lib/ssl/src/ssl_connection.erl49
-rw-r--r--lib/ssl/src/tls_socket.erl56
-rw-r--r--lib/ssl/test/ssl_basic_SUITE.erl176
-rw-r--r--lib/stdlib/doc/src/slave.xml19
-rw-r--r--lib/stdlib/src/calendar.erl55
-rw-r--r--lib/stdlib/src/slave.erl17
-rw-r--r--lib/stdlib/test/binary_module_SUITE.erl5
-rw-r--r--lib/stdlib/test/calendar_SUITE.erl2
-rw-r--r--lib/stdlib/test/qlc_SUITE.erl10
214 files changed, 3681 insertions, 1736 deletions
diff --git a/Makefile.in b/Makefile.in
index 240450cdd4..88b3670999 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -767,7 +767,7 @@ tertiary_bootstrap_copy:
true; \
done
# copy erl_interface includes
- $(V_at)for x in lib/erl_interface/include/*; do \
+ $(V_at)for x in lib/erl_interface/include/* lib/erl_interface/include/$(TARGET)/*; do \
BN=`basename $$x`; \
TF=$(BOOTSTRAP_ROOT)/bootstrap/lib/erl_interface/include/$$BN; \
test -f $$TF && \
diff --git a/OTP_VERSION b/OTP_VERSION
index a12e109d04..da0a41680b 100644
--- a/OTP_VERSION
+++ b/OTP_VERSION
@@ -1 +1 @@
-22.0-rc0
+22.0-rc1
diff --git a/bootstrap/bin/no_dot_erlang.boot b/bootstrap/bin/no_dot_erlang.boot
index 496654fcea..b48d22fe41 100644
--- a/bootstrap/bin/no_dot_erlang.boot
+++ b/bootstrap/bin/no_dot_erlang.boot
Binary files differ
diff --git a/bootstrap/bin/start.boot b/bootstrap/bin/start.boot
index 496654fcea..b48d22fe41 100644
--- a/bootstrap/bin/start.boot
+++ b/bootstrap/bin/start.boot
Binary files differ
diff --git a/bootstrap/bin/start_clean.boot b/bootstrap/bin/start_clean.boot
index 496654fcea..b48d22fe41 100644
--- a/bootstrap/bin/start_clean.boot
+++ b/bootstrap/bin/start_clean.boot
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_asm.beam b/bootstrap/lib/compiler/ebin/beam_asm.beam
index 232cc74188..5c91f09b30 100644
--- a/bootstrap/lib/compiler/ebin/beam_asm.beam
+++ b/bootstrap/lib/compiler/ebin/beam_asm.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_dict.beam b/bootstrap/lib/compiler/ebin/beam_dict.beam
index 19a05c1276..b9317a55ee 100644
--- a/bootstrap/lib/compiler/ebin/beam_dict.beam
+++ b/bootstrap/lib/compiler/ebin/beam_dict.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_except.beam b/bootstrap/lib/compiler/ebin/beam_except.beam
index c76d41c58a..0fb15b1422 100644
--- a/bootstrap/lib/compiler/ebin/beam_except.beam
+++ b/bootstrap/lib/compiler/ebin/beam_except.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_flatten.beam b/bootstrap/lib/compiler/ebin/beam_flatten.beam
index cc245af68a..d7780861c2 100644
--- a/bootstrap/lib/compiler/ebin/beam_flatten.beam
+++ b/bootstrap/lib/compiler/ebin/beam_flatten.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_jump.beam b/bootstrap/lib/compiler/ebin/beam_jump.beam
index e23ff4e906..289c08630a 100644
--- a/bootstrap/lib/compiler/ebin/beam_jump.beam
+++ b/bootstrap/lib/compiler/ebin/beam_jump.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_kernel_to_ssa.beam b/bootstrap/lib/compiler/ebin/beam_kernel_to_ssa.beam
index b02630aed9..a6b54314f6 100644
--- a/bootstrap/lib/compiler/ebin/beam_kernel_to_ssa.beam
+++ b/bootstrap/lib/compiler/ebin/beam_kernel_to_ssa.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_peep.beam b/bootstrap/lib/compiler/ebin/beam_peep.beam
index 29016312bc..9246bd1c27 100644
--- a/bootstrap/lib/compiler/ebin/beam_peep.beam
+++ b/bootstrap/lib/compiler/ebin/beam_peep.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_ssa.beam b/bootstrap/lib/compiler/ebin/beam_ssa.beam
index 4f44f50dff..9ba124a92d 100644
--- a/bootstrap/lib/compiler/ebin/beam_ssa.beam
+++ b/bootstrap/lib/compiler/ebin/beam_ssa.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_ssa_bsm.beam b/bootstrap/lib/compiler/ebin/beam_ssa_bsm.beam
index cdbc969b92..50412bc8de 100644
--- a/bootstrap/lib/compiler/ebin/beam_ssa_bsm.beam
+++ b/bootstrap/lib/compiler/ebin/beam_ssa_bsm.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_ssa_codegen.beam b/bootstrap/lib/compiler/ebin/beam_ssa_codegen.beam
index 7a09803699..50737c66b1 100644
--- a/bootstrap/lib/compiler/ebin/beam_ssa_codegen.beam
+++ b/bootstrap/lib/compiler/ebin/beam_ssa_codegen.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_ssa_dead.beam b/bootstrap/lib/compiler/ebin/beam_ssa_dead.beam
index edc5cc5679..f3dbfc42ff 100644
--- a/bootstrap/lib/compiler/ebin/beam_ssa_dead.beam
+++ b/bootstrap/lib/compiler/ebin/beam_ssa_dead.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_ssa_funs.beam b/bootstrap/lib/compiler/ebin/beam_ssa_funs.beam
index d28c4c6b81..6370e1eb78 100644
--- a/bootstrap/lib/compiler/ebin/beam_ssa_funs.beam
+++ b/bootstrap/lib/compiler/ebin/beam_ssa_funs.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_ssa_opt.beam b/bootstrap/lib/compiler/ebin/beam_ssa_opt.beam
index d889add00d..7b34cc5906 100644
--- a/bootstrap/lib/compiler/ebin/beam_ssa_opt.beam
+++ b/bootstrap/lib/compiler/ebin/beam_ssa_opt.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_ssa_pre_codegen.beam b/bootstrap/lib/compiler/ebin/beam_ssa_pre_codegen.beam
index 6e8f7ac648..8481429a30 100644
--- a/bootstrap/lib/compiler/ebin/beam_ssa_pre_codegen.beam
+++ b/bootstrap/lib/compiler/ebin/beam_ssa_pre_codegen.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_ssa_recv.beam b/bootstrap/lib/compiler/ebin/beam_ssa_recv.beam
index e86fa1831a..578e8db0eb 100644
--- a/bootstrap/lib/compiler/ebin/beam_ssa_recv.beam
+++ b/bootstrap/lib/compiler/ebin/beam_ssa_recv.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_ssa_type.beam b/bootstrap/lib/compiler/ebin/beam_ssa_type.beam
index de9929bc92..52bdbf6937 100644
--- a/bootstrap/lib/compiler/ebin/beam_ssa_type.beam
+++ b/bootstrap/lib/compiler/ebin/beam_ssa_type.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_validator.beam b/bootstrap/lib/compiler/ebin/beam_validator.beam
index 74590b52d7..a5db96bdaf 100644
--- a/bootstrap/lib/compiler/ebin/beam_validator.beam
+++ b/bootstrap/lib/compiler/ebin/beam_validator.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_z.beam b/bootstrap/lib/compiler/ebin/beam_z.beam
index 9a8ca5e718..21ca7bcf46 100644
--- a/bootstrap/lib/compiler/ebin/beam_z.beam
+++ b/bootstrap/lib/compiler/ebin/beam_z.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/cerl.beam b/bootstrap/lib/compiler/ebin/cerl.beam
index 254f94fd36..948c4759b0 100644
--- a/bootstrap/lib/compiler/ebin/cerl.beam
+++ b/bootstrap/lib/compiler/ebin/cerl.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/cerl_inline.beam b/bootstrap/lib/compiler/ebin/cerl_inline.beam
index c20b40541c..7bf92a0dd7 100644
--- a/bootstrap/lib/compiler/ebin/cerl_inline.beam
+++ b/bootstrap/lib/compiler/ebin/cerl_inline.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/cerl_sets.beam b/bootstrap/lib/compiler/ebin/cerl_sets.beam
index 4ab7584977..bda70130a6 100644
--- a/bootstrap/lib/compiler/ebin/cerl_sets.beam
+++ b/bootstrap/lib/compiler/ebin/cerl_sets.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/cerl_trees.beam b/bootstrap/lib/compiler/ebin/cerl_trees.beam
index 63532015b0..831eddc405 100644
--- a/bootstrap/lib/compiler/ebin/cerl_trees.beam
+++ b/bootstrap/lib/compiler/ebin/cerl_trees.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/compile.beam b/bootstrap/lib/compiler/ebin/compile.beam
index fda55d4035..5829ab4867 100644
--- a/bootstrap/lib/compiler/ebin/compile.beam
+++ b/bootstrap/lib/compiler/ebin/compile.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/rec_env.beam b/bootstrap/lib/compiler/ebin/rec_env.beam
index 329100e682..6d0c5baa04 100644
--- a/bootstrap/lib/compiler/ebin/rec_env.beam
+++ b/bootstrap/lib/compiler/ebin/rec_env.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/sys_core_alias.beam b/bootstrap/lib/compiler/ebin/sys_core_alias.beam
index 953776ebaa..622221a8b0 100644
--- a/bootstrap/lib/compiler/ebin/sys_core_alias.beam
+++ b/bootstrap/lib/compiler/ebin/sys_core_alias.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/sys_core_fold.beam b/bootstrap/lib/compiler/ebin/sys_core_fold.beam
index 98d24fc57a..dd2874bbe0 100644
--- a/bootstrap/lib/compiler/ebin/sys_core_fold.beam
+++ b/bootstrap/lib/compiler/ebin/sys_core_fold.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/sys_core_inline.beam b/bootstrap/lib/compiler/ebin/sys_core_inline.beam
index d06f8d4823..5647c8fcb5 100644
--- a/bootstrap/lib/compiler/ebin/sys_core_inline.beam
+++ b/bootstrap/lib/compiler/ebin/sys_core_inline.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/v3_core.beam b/bootstrap/lib/compiler/ebin/v3_core.beam
index a4da69abdf..06a5b9973a 100644
--- a/bootstrap/lib/compiler/ebin/v3_core.beam
+++ b/bootstrap/lib/compiler/ebin/v3_core.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/v3_kernel.beam b/bootstrap/lib/compiler/ebin/v3_kernel.beam
index 8fc867e66b..54b2f1f0ad 100644
--- a/bootstrap/lib/compiler/ebin/v3_kernel.beam
+++ b/bootstrap/lib/compiler/ebin/v3_kernel.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/v3_kernel_pp.beam b/bootstrap/lib/compiler/ebin/v3_kernel_pp.beam
index e60bd7c722..5177b65198 100644
--- a/bootstrap/lib/compiler/ebin/v3_kernel_pp.beam
+++ b/bootstrap/lib/compiler/ebin/v3_kernel_pp.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/application.beam b/bootstrap/lib/kernel/ebin/application.beam
index faf620850e..9db02f55fd 100644
--- a/bootstrap/lib/kernel/ebin/application.beam
+++ b/bootstrap/lib/kernel/ebin/application.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/application_controller.beam b/bootstrap/lib/kernel/ebin/application_controller.beam
index e0c3790efe..32612f1bf6 100644
--- a/bootstrap/lib/kernel/ebin/application_controller.beam
+++ b/bootstrap/lib/kernel/ebin/application_controller.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/application_starter.beam b/bootstrap/lib/kernel/ebin/application_starter.beam
index d17ed145cb..0daab463ab 100644
--- a/bootstrap/lib/kernel/ebin/application_starter.beam
+++ b/bootstrap/lib/kernel/ebin/application_starter.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/auth.beam b/bootstrap/lib/kernel/ebin/auth.beam
index a470129eff..c77178bf7c 100644
--- a/bootstrap/lib/kernel/ebin/auth.beam
+++ b/bootstrap/lib/kernel/ebin/auth.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/code.beam b/bootstrap/lib/kernel/ebin/code.beam
index 0a35cf9036..41e4bd4ab2 100644
--- a/bootstrap/lib/kernel/ebin/code.beam
+++ b/bootstrap/lib/kernel/ebin/code.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/code_server.beam b/bootstrap/lib/kernel/ebin/code_server.beam
index cb1b8374e0..6add687cf2 100644
--- a/bootstrap/lib/kernel/ebin/code_server.beam
+++ b/bootstrap/lib/kernel/ebin/code_server.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/disk_log.beam b/bootstrap/lib/kernel/ebin/disk_log.beam
index 35d41e0604..25142ee575 100644
--- a/bootstrap/lib/kernel/ebin/disk_log.beam
+++ b/bootstrap/lib/kernel/ebin/disk_log.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/disk_log_1.beam b/bootstrap/lib/kernel/ebin/disk_log_1.beam
index 3884d05e0f..350b66d1fb 100644
--- a/bootstrap/lib/kernel/ebin/disk_log_1.beam
+++ b/bootstrap/lib/kernel/ebin/disk_log_1.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/disk_log_server.beam b/bootstrap/lib/kernel/ebin/disk_log_server.beam
index bd40c824a6..3b961dcefa 100644
--- a/bootstrap/lib/kernel/ebin/disk_log_server.beam
+++ b/bootstrap/lib/kernel/ebin/disk_log_server.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/dist_ac.beam b/bootstrap/lib/kernel/ebin/dist_ac.beam
index 99f5c66998..e82fc7dc75 100644
--- a/bootstrap/lib/kernel/ebin/dist_ac.beam
+++ b/bootstrap/lib/kernel/ebin/dist_ac.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/dist_util.beam b/bootstrap/lib/kernel/ebin/dist_util.beam
index aec35239f6..fd21dd47f5 100644
--- a/bootstrap/lib/kernel/ebin/dist_util.beam
+++ b/bootstrap/lib/kernel/ebin/dist_util.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/erl_boot_server.beam b/bootstrap/lib/kernel/ebin/erl_boot_server.beam
index 00e4aba64d..81f6779c20 100644
--- a/bootstrap/lib/kernel/ebin/erl_boot_server.beam
+++ b/bootstrap/lib/kernel/ebin/erl_boot_server.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/erl_ddll.beam b/bootstrap/lib/kernel/ebin/erl_ddll.beam
index 9708d146f7..c04bc43872 100644
--- a/bootstrap/lib/kernel/ebin/erl_ddll.beam
+++ b/bootstrap/lib/kernel/ebin/erl_ddll.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/erl_epmd.beam b/bootstrap/lib/kernel/ebin/erl_epmd.beam
index 5e43e48577..6ed9862a0e 100644
--- a/bootstrap/lib/kernel/ebin/erl_epmd.beam
+++ b/bootstrap/lib/kernel/ebin/erl_epmd.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/error_logger.beam b/bootstrap/lib/kernel/ebin/error_logger.beam
index f9b1dd2ed9..10b13c35b6 100644
--- a/bootstrap/lib/kernel/ebin/error_logger.beam
+++ b/bootstrap/lib/kernel/ebin/error_logger.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/erts_debug.beam b/bootstrap/lib/kernel/ebin/erts_debug.beam
index eff26cf7a2..5336f4ae6c 100644
--- a/bootstrap/lib/kernel/ebin/erts_debug.beam
+++ b/bootstrap/lib/kernel/ebin/erts_debug.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/file.beam b/bootstrap/lib/kernel/ebin/file.beam
index 3bf1cbeeaf..9c2759adc9 100644
--- a/bootstrap/lib/kernel/ebin/file.beam
+++ b/bootstrap/lib/kernel/ebin/file.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/file_io_server.beam b/bootstrap/lib/kernel/ebin/file_io_server.beam
index 354fce8576..b8f1272be4 100644
--- a/bootstrap/lib/kernel/ebin/file_io_server.beam
+++ b/bootstrap/lib/kernel/ebin/file_io_server.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/file_server.beam b/bootstrap/lib/kernel/ebin/file_server.beam
index bfbef9341d..cc2face79c 100644
--- a/bootstrap/lib/kernel/ebin/file_server.beam
+++ b/bootstrap/lib/kernel/ebin/file_server.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/global.beam b/bootstrap/lib/kernel/ebin/global.beam
index 4a9a6cd229..f57cf03afd 100644
--- a/bootstrap/lib/kernel/ebin/global.beam
+++ b/bootstrap/lib/kernel/ebin/global.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/global_group.beam b/bootstrap/lib/kernel/ebin/global_group.beam
index 6252b1b3c2..83885cdeb5 100644
--- a/bootstrap/lib/kernel/ebin/global_group.beam
+++ b/bootstrap/lib/kernel/ebin/global_group.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/group.beam b/bootstrap/lib/kernel/ebin/group.beam
index 8fe196f806..396f1166f1 100644
--- a/bootstrap/lib/kernel/ebin/group.beam
+++ b/bootstrap/lib/kernel/ebin/group.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/group_history.beam b/bootstrap/lib/kernel/ebin/group_history.beam
index 5cfc7183f9..b9df7cfc14 100644
--- a/bootstrap/lib/kernel/ebin/group_history.beam
+++ b/bootstrap/lib/kernel/ebin/group_history.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/heart.beam b/bootstrap/lib/kernel/ebin/heart.beam
index d826f4f99d..1b63142893 100644
--- a/bootstrap/lib/kernel/ebin/heart.beam
+++ b/bootstrap/lib/kernel/ebin/heart.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/inet.beam b/bootstrap/lib/kernel/ebin/inet.beam
index 29225eb473..b0c67afe90 100644
--- a/bootstrap/lib/kernel/ebin/inet.beam
+++ b/bootstrap/lib/kernel/ebin/inet.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/inet_config.beam b/bootstrap/lib/kernel/ebin/inet_config.beam
index f06a0d5c68..c44b389b75 100644
--- a/bootstrap/lib/kernel/ebin/inet_config.beam
+++ b/bootstrap/lib/kernel/ebin/inet_config.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/inet_db.beam b/bootstrap/lib/kernel/ebin/inet_db.beam
index dfc94974b9..76d7ac2adb 100644
--- a/bootstrap/lib/kernel/ebin/inet_db.beam
+++ b/bootstrap/lib/kernel/ebin/inet_db.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/inet_dns.beam b/bootstrap/lib/kernel/ebin/inet_dns.beam
index 1af10a472f..d88fa2185d 100644
--- a/bootstrap/lib/kernel/ebin/inet_dns.beam
+++ b/bootstrap/lib/kernel/ebin/inet_dns.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/inet_gethost_native.beam b/bootstrap/lib/kernel/ebin/inet_gethost_native.beam
index 70af600524..afc4999c42 100644
--- a/bootstrap/lib/kernel/ebin/inet_gethost_native.beam
+++ b/bootstrap/lib/kernel/ebin/inet_gethost_native.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/inet_parse.beam b/bootstrap/lib/kernel/ebin/inet_parse.beam
index 818c26d776..84c0169d4b 100644
--- a/bootstrap/lib/kernel/ebin/inet_parse.beam
+++ b/bootstrap/lib/kernel/ebin/inet_parse.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/inet_res.beam b/bootstrap/lib/kernel/ebin/inet_res.beam
index 2a54ed84e8..c964152d79 100644
--- a/bootstrap/lib/kernel/ebin/inet_res.beam
+++ b/bootstrap/lib/kernel/ebin/inet_res.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/inet_tcp_dist.beam b/bootstrap/lib/kernel/ebin/inet_tcp_dist.beam
index e2122ff2a3..d09aa250c8 100644
--- a/bootstrap/lib/kernel/ebin/inet_tcp_dist.beam
+++ b/bootstrap/lib/kernel/ebin/inet_tcp_dist.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/kernel.app b/bootstrap/lib/kernel/ebin/kernel.app
index 1b4665a31c..ab106113c2 100644
--- a/bootstrap/lib/kernel/ebin/kernel.app
+++ b/bootstrap/lib/kernel/ebin/kernel.app
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -74,7 +74,6 @@
logger_simple_h,
logger_std_h,
logger_sup,
- net,
net_adm,
net_kernel,
os,
diff --git a/bootstrap/lib/kernel/ebin/kernel.beam b/bootstrap/lib/kernel/ebin/kernel.beam
index 75ff192576..8f75029c0f 100644
--- a/bootstrap/lib/kernel/ebin/kernel.beam
+++ b/bootstrap/lib/kernel/ebin/kernel.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/kernel_config.beam b/bootstrap/lib/kernel/ebin/kernel_config.beam
index bcadaab5f1..e749cc6c96 100644
--- a/bootstrap/lib/kernel/ebin/kernel_config.beam
+++ b/bootstrap/lib/kernel/ebin/kernel_config.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/logger.beam b/bootstrap/lib/kernel/ebin/logger.beam
index 3865db9d89..bd17885e22 100644
--- a/bootstrap/lib/kernel/ebin/logger.beam
+++ b/bootstrap/lib/kernel/ebin/logger.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/logger_backend.beam b/bootstrap/lib/kernel/ebin/logger_backend.beam
index efc5d37a12..40a3c4d80a 100644
--- a/bootstrap/lib/kernel/ebin/logger_backend.beam
+++ b/bootstrap/lib/kernel/ebin/logger_backend.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/logger_disk_log_h.beam b/bootstrap/lib/kernel/ebin/logger_disk_log_h.beam
index 2b64b2ca84..dd0ca5f204 100644
--- a/bootstrap/lib/kernel/ebin/logger_disk_log_h.beam
+++ b/bootstrap/lib/kernel/ebin/logger_disk_log_h.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/logger_formatter.beam b/bootstrap/lib/kernel/ebin/logger_formatter.beam
index c790d87569..83df11e66f 100644
--- a/bootstrap/lib/kernel/ebin/logger_formatter.beam
+++ b/bootstrap/lib/kernel/ebin/logger_formatter.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/logger_h_common.beam b/bootstrap/lib/kernel/ebin/logger_h_common.beam
index 7361625f7c..5e14216b5d 100644
--- a/bootstrap/lib/kernel/ebin/logger_h_common.beam
+++ b/bootstrap/lib/kernel/ebin/logger_h_common.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/logger_handler_watcher.beam b/bootstrap/lib/kernel/ebin/logger_handler_watcher.beam
index 2ebf3799ee..fb20fd1818 100644
--- a/bootstrap/lib/kernel/ebin/logger_handler_watcher.beam
+++ b/bootstrap/lib/kernel/ebin/logger_handler_watcher.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/logger_olp.beam b/bootstrap/lib/kernel/ebin/logger_olp.beam
index ea04f7bde8..ed06b6ae5e 100644
--- a/bootstrap/lib/kernel/ebin/logger_olp.beam
+++ b/bootstrap/lib/kernel/ebin/logger_olp.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/logger_server.beam b/bootstrap/lib/kernel/ebin/logger_server.beam
index daa22aee33..dcff9beac7 100644
--- a/bootstrap/lib/kernel/ebin/logger_server.beam
+++ b/bootstrap/lib/kernel/ebin/logger_server.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/logger_simple_h.beam b/bootstrap/lib/kernel/ebin/logger_simple_h.beam
index a6d0c9e17c..954bbdc071 100644
--- a/bootstrap/lib/kernel/ebin/logger_simple_h.beam
+++ b/bootstrap/lib/kernel/ebin/logger_simple_h.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/logger_std_h.beam b/bootstrap/lib/kernel/ebin/logger_std_h.beam
index 921e853f73..3b5d3cd9f8 100644
--- a/bootstrap/lib/kernel/ebin/logger_std_h.beam
+++ b/bootstrap/lib/kernel/ebin/logger_std_h.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/net_kernel.beam b/bootstrap/lib/kernel/ebin/net_kernel.beam
index 7f57ea3d77..4c57f5f6c8 100644
--- a/bootstrap/lib/kernel/ebin/net_kernel.beam
+++ b/bootstrap/lib/kernel/ebin/net_kernel.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/os.beam b/bootstrap/lib/kernel/ebin/os.beam
index 80e3f7b1e2..f05007041b 100644
--- a/bootstrap/lib/kernel/ebin/os.beam
+++ b/bootstrap/lib/kernel/ebin/os.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/raw_file_io.beam b/bootstrap/lib/kernel/ebin/raw_file_io.beam
index 7d3cc2e3c3..16dc314ba5 100644
--- a/bootstrap/lib/kernel/ebin/raw_file_io.beam
+++ b/bootstrap/lib/kernel/ebin/raw_file_io.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/raw_file_io_deflate.beam b/bootstrap/lib/kernel/ebin/raw_file_io_deflate.beam
index 7185506bc5..11b8f4a6db 100644
--- a/bootstrap/lib/kernel/ebin/raw_file_io_deflate.beam
+++ b/bootstrap/lib/kernel/ebin/raw_file_io_deflate.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/raw_file_io_delayed.beam b/bootstrap/lib/kernel/ebin/raw_file_io_delayed.beam
index 0ae74c7045..b3381cc397 100644
--- a/bootstrap/lib/kernel/ebin/raw_file_io_delayed.beam
+++ b/bootstrap/lib/kernel/ebin/raw_file_io_delayed.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/raw_file_io_inflate.beam b/bootstrap/lib/kernel/ebin/raw_file_io_inflate.beam
index 194f5fb507..bd0064ebf2 100644
--- a/bootstrap/lib/kernel/ebin/raw_file_io_inflate.beam
+++ b/bootstrap/lib/kernel/ebin/raw_file_io_inflate.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/user.beam b/bootstrap/lib/kernel/ebin/user.beam
index 3e7be39f5f..f3573d95af 100644
--- a/bootstrap/lib/kernel/ebin/user.beam
+++ b/bootstrap/lib/kernel/ebin/user.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/user_drv.beam b/bootstrap/lib/kernel/ebin/user_drv.beam
index 9232703812..ce4d4328de 100644
--- a/bootstrap/lib/kernel/ebin/user_drv.beam
+++ b/bootstrap/lib/kernel/ebin/user_drv.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/wrap_log_reader.beam b/bootstrap/lib/kernel/ebin/wrap_log_reader.beam
index 6cfafbd750..ceb8dd9a78 100644
--- a/bootstrap/lib/kernel/ebin/wrap_log_reader.beam
+++ b/bootstrap/lib/kernel/ebin/wrap_log_reader.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/beam_lib.beam b/bootstrap/lib/stdlib/ebin/beam_lib.beam
index 4782583fd6..c13a82a074 100644
--- a/bootstrap/lib/stdlib/ebin/beam_lib.beam
+++ b/bootstrap/lib/stdlib/ebin/beam_lib.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/c.beam b/bootstrap/lib/stdlib/ebin/c.beam
index 9d9bf170a2..c61132b2de 100644
--- a/bootstrap/lib/stdlib/ebin/c.beam
+++ b/bootstrap/lib/stdlib/ebin/c.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/dets.beam b/bootstrap/lib/stdlib/ebin/dets.beam
index 37f31e1945..a92506125d 100644
--- a/bootstrap/lib/stdlib/ebin/dets.beam
+++ b/bootstrap/lib/stdlib/ebin/dets.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/dets_server.beam b/bootstrap/lib/stdlib/ebin/dets_server.beam
index c5fabc5e98..8cd247e3be 100644
--- a/bootstrap/lib/stdlib/ebin/dets_server.beam
+++ b/bootstrap/lib/stdlib/ebin/dets_server.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/dets_utils.beam b/bootstrap/lib/stdlib/ebin/dets_utils.beam
index b25999333b..16c6f1aba5 100644
--- a/bootstrap/lib/stdlib/ebin/dets_utils.beam
+++ b/bootstrap/lib/stdlib/ebin/dets_utils.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/dets_v9.beam b/bootstrap/lib/stdlib/ebin/dets_v9.beam
index 1e12c7a8b8..2f82423bac 100644
--- a/bootstrap/lib/stdlib/ebin/dets_v9.beam
+++ b/bootstrap/lib/stdlib/ebin/dets_v9.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/digraph.beam b/bootstrap/lib/stdlib/ebin/digraph.beam
index 999a3c5b7d..60abe020fd 100644
--- a/bootstrap/lib/stdlib/ebin/digraph.beam
+++ b/bootstrap/lib/stdlib/ebin/digraph.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/edlin.beam b/bootstrap/lib/stdlib/ebin/edlin.beam
index 9b6ea06df2..b6a7ecc9a5 100644
--- a/bootstrap/lib/stdlib/ebin/edlin.beam
+++ b/bootstrap/lib/stdlib/ebin/edlin.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/edlin_expand.beam b/bootstrap/lib/stdlib/ebin/edlin_expand.beam
index 81d57e38d9..865066c3ac 100644
--- a/bootstrap/lib/stdlib/ebin/edlin_expand.beam
+++ b/bootstrap/lib/stdlib/ebin/edlin_expand.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/epp.beam b/bootstrap/lib/stdlib/ebin/epp.beam
index 9611419792..2618efb7d2 100644
--- a/bootstrap/lib/stdlib/ebin/epp.beam
+++ b/bootstrap/lib/stdlib/ebin/epp.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/erl_bits.beam b/bootstrap/lib/stdlib/ebin/erl_bits.beam
index 508da7ba8a..1beb0d5ebb 100644
--- a/bootstrap/lib/stdlib/ebin/erl_bits.beam
+++ b/bootstrap/lib/stdlib/ebin/erl_bits.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/erl_compile.beam b/bootstrap/lib/stdlib/ebin/erl_compile.beam
index 07a8f1c9ac..fa223657bf 100644
--- a/bootstrap/lib/stdlib/ebin/erl_compile.beam
+++ b/bootstrap/lib/stdlib/ebin/erl_compile.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/erl_error.beam b/bootstrap/lib/stdlib/ebin/erl_error.beam
index f47b2b2e14..db9d45a0d2 100644
--- a/bootstrap/lib/stdlib/ebin/erl_error.beam
+++ b/bootstrap/lib/stdlib/ebin/erl_error.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/erl_eval.beam b/bootstrap/lib/stdlib/ebin/erl_eval.beam
index ee6df8efcb..90b3858207 100644
--- a/bootstrap/lib/stdlib/ebin/erl_eval.beam
+++ b/bootstrap/lib/stdlib/ebin/erl_eval.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/erl_expand_records.beam b/bootstrap/lib/stdlib/ebin/erl_expand_records.beam
index 331a946757..3a631e24bc 100644
--- a/bootstrap/lib/stdlib/ebin/erl_expand_records.beam
+++ b/bootstrap/lib/stdlib/ebin/erl_expand_records.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/erl_lint.beam b/bootstrap/lib/stdlib/ebin/erl_lint.beam
index e50e44fc4b..35e02b9595 100644
--- a/bootstrap/lib/stdlib/ebin/erl_lint.beam
+++ b/bootstrap/lib/stdlib/ebin/erl_lint.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/erl_pp.beam b/bootstrap/lib/stdlib/ebin/erl_pp.beam
index 64b26f2510..64e558e272 100644
--- a/bootstrap/lib/stdlib/ebin/erl_pp.beam
+++ b/bootstrap/lib/stdlib/ebin/erl_pp.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/erl_scan.beam b/bootstrap/lib/stdlib/ebin/erl_scan.beam
index 8347f97ec1..3b30d3e8c7 100644
--- a/bootstrap/lib/stdlib/ebin/erl_scan.beam
+++ b/bootstrap/lib/stdlib/ebin/erl_scan.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/erl_tar.beam b/bootstrap/lib/stdlib/ebin/erl_tar.beam
index 79cddbdab2..97ddc7d703 100644
--- a/bootstrap/lib/stdlib/ebin/erl_tar.beam
+++ b/bootstrap/lib/stdlib/ebin/erl_tar.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/error_logger_file_h.beam b/bootstrap/lib/stdlib/ebin/error_logger_file_h.beam
index 7f3c843426..64de26f7a4 100644
--- a/bootstrap/lib/stdlib/ebin/error_logger_file_h.beam
+++ b/bootstrap/lib/stdlib/ebin/error_logger_file_h.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/error_logger_tty_h.beam b/bootstrap/lib/stdlib/ebin/error_logger_tty_h.beam
index bdb80ce1e4..e7ee41cc2e 100644
--- a/bootstrap/lib/stdlib/ebin/error_logger_tty_h.beam
+++ b/bootstrap/lib/stdlib/ebin/error_logger_tty_h.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/escript.beam b/bootstrap/lib/stdlib/ebin/escript.beam
index 880fc090b2..7685b4a49a 100644
--- a/bootstrap/lib/stdlib/ebin/escript.beam
+++ b/bootstrap/lib/stdlib/ebin/escript.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/ets.beam b/bootstrap/lib/stdlib/ebin/ets.beam
index 8d3538e7a7..cb7c957719 100644
--- a/bootstrap/lib/stdlib/ebin/ets.beam
+++ b/bootstrap/lib/stdlib/ebin/ets.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/eval_bits.beam b/bootstrap/lib/stdlib/ebin/eval_bits.beam
index 2f36309102..08f86f86ff 100644
--- a/bootstrap/lib/stdlib/ebin/eval_bits.beam
+++ b/bootstrap/lib/stdlib/ebin/eval_bits.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/file_sorter.beam b/bootstrap/lib/stdlib/ebin/file_sorter.beam
index 65dcc78f23..f24f6cfbe8 100644
--- a/bootstrap/lib/stdlib/ebin/file_sorter.beam
+++ b/bootstrap/lib/stdlib/ebin/file_sorter.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/filelib.beam b/bootstrap/lib/stdlib/ebin/filelib.beam
index 6efc5e219a..62b8c3588e 100644
--- a/bootstrap/lib/stdlib/ebin/filelib.beam
+++ b/bootstrap/lib/stdlib/ebin/filelib.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/filename.beam b/bootstrap/lib/stdlib/ebin/filename.beam
index b882b287c2..9981a33a4e 100644
--- a/bootstrap/lib/stdlib/ebin/filename.beam
+++ b/bootstrap/lib/stdlib/ebin/filename.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/gen.beam b/bootstrap/lib/stdlib/ebin/gen.beam
index 3179f098c9..85a9c25618 100644
--- a/bootstrap/lib/stdlib/ebin/gen.beam
+++ b/bootstrap/lib/stdlib/ebin/gen.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/gen_event.beam b/bootstrap/lib/stdlib/ebin/gen_event.beam
index 4727efff99..f3376d2ee2 100644
--- a/bootstrap/lib/stdlib/ebin/gen_event.beam
+++ b/bootstrap/lib/stdlib/ebin/gen_event.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/gen_fsm.beam b/bootstrap/lib/stdlib/ebin/gen_fsm.beam
index be5213e76d..5c4a0aa3d5 100644
--- a/bootstrap/lib/stdlib/ebin/gen_fsm.beam
+++ b/bootstrap/lib/stdlib/ebin/gen_fsm.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/gen_server.beam b/bootstrap/lib/stdlib/ebin/gen_server.beam
index b84877582b..06c3d6de19 100644
--- a/bootstrap/lib/stdlib/ebin/gen_server.beam
+++ b/bootstrap/lib/stdlib/ebin/gen_server.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/gen_statem.beam b/bootstrap/lib/stdlib/ebin/gen_statem.beam
index f5185696eb..0aab776d07 100644
--- a/bootstrap/lib/stdlib/ebin/gen_statem.beam
+++ b/bootstrap/lib/stdlib/ebin/gen_statem.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/io.beam b/bootstrap/lib/stdlib/ebin/io.beam
index bce83b5a3a..631863b587 100644
--- a/bootstrap/lib/stdlib/ebin/io.beam
+++ b/bootstrap/lib/stdlib/ebin/io.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/io_lib_pretty.beam b/bootstrap/lib/stdlib/ebin/io_lib_pretty.beam
index 09e9be48f8..7ffe569c60 100644
--- a/bootstrap/lib/stdlib/ebin/io_lib_pretty.beam
+++ b/bootstrap/lib/stdlib/ebin/io_lib_pretty.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/lists.beam b/bootstrap/lib/stdlib/ebin/lists.beam
index 6178717067..5a330bece0 100644
--- a/bootstrap/lib/stdlib/ebin/lists.beam
+++ b/bootstrap/lib/stdlib/ebin/lists.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/log_mf_h.beam b/bootstrap/lib/stdlib/ebin/log_mf_h.beam
index bc1b5c7552..b812621c0a 100644
--- a/bootstrap/lib/stdlib/ebin/log_mf_h.beam
+++ b/bootstrap/lib/stdlib/ebin/log_mf_h.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/ms_transform.beam b/bootstrap/lib/stdlib/ebin/ms_transform.beam
index aa9d279a9e..bb98ae56b3 100644
--- a/bootstrap/lib/stdlib/ebin/ms_transform.beam
+++ b/bootstrap/lib/stdlib/ebin/ms_transform.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/otp_internal.beam b/bootstrap/lib/stdlib/ebin/otp_internal.beam
index 4dbdabbb7d..a975a43c00 100644
--- a/bootstrap/lib/stdlib/ebin/otp_internal.beam
+++ b/bootstrap/lib/stdlib/ebin/otp_internal.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/proc_lib.beam b/bootstrap/lib/stdlib/ebin/proc_lib.beam
index c49c165b13..b51898901d 100644
--- a/bootstrap/lib/stdlib/ebin/proc_lib.beam
+++ b/bootstrap/lib/stdlib/ebin/proc_lib.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/qlc.beam b/bootstrap/lib/stdlib/ebin/qlc.beam
index de61165aae..4b7a3b5278 100644
--- a/bootstrap/lib/stdlib/ebin/qlc.beam
+++ b/bootstrap/lib/stdlib/ebin/qlc.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/qlc_pt.beam b/bootstrap/lib/stdlib/ebin/qlc_pt.beam
index 653fa3e808..22c0e2ef95 100644
--- a/bootstrap/lib/stdlib/ebin/qlc_pt.beam
+++ b/bootstrap/lib/stdlib/ebin/qlc_pt.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/re.beam b/bootstrap/lib/stdlib/ebin/re.beam
index 7a010dbdd5..d6920d54ce 100644
--- a/bootstrap/lib/stdlib/ebin/re.beam
+++ b/bootstrap/lib/stdlib/ebin/re.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/shell.beam b/bootstrap/lib/stdlib/ebin/shell.beam
index 6bd3978bb4..319bb9aebf 100644
--- a/bootstrap/lib/stdlib/ebin/shell.beam
+++ b/bootstrap/lib/stdlib/ebin/shell.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/slave.beam b/bootstrap/lib/stdlib/ebin/slave.beam
index ad8763725e..259d300155 100644
--- a/bootstrap/lib/stdlib/ebin/slave.beam
+++ b/bootstrap/lib/stdlib/ebin/slave.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/sofs.beam b/bootstrap/lib/stdlib/ebin/sofs.beam
index 3efc50d4a8..f64faafa52 100644
--- a/bootstrap/lib/stdlib/ebin/sofs.beam
+++ b/bootstrap/lib/stdlib/ebin/sofs.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/supervisor.beam b/bootstrap/lib/stdlib/ebin/supervisor.beam
index 243a67008b..1816fe6c41 100644
--- a/bootstrap/lib/stdlib/ebin/supervisor.beam
+++ b/bootstrap/lib/stdlib/ebin/supervisor.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/supervisor_bridge.beam b/bootstrap/lib/stdlib/ebin/supervisor_bridge.beam
index 63cfa4ab2e..761907b40c 100644
--- a/bootstrap/lib/stdlib/ebin/supervisor_bridge.beam
+++ b/bootstrap/lib/stdlib/ebin/supervisor_bridge.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/sys.beam b/bootstrap/lib/stdlib/ebin/sys.beam
index fb1d52268c..2b4906508a 100644
--- a/bootstrap/lib/stdlib/ebin/sys.beam
+++ b/bootstrap/lib/stdlib/ebin/sys.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/timer.beam b/bootstrap/lib/stdlib/ebin/timer.beam
index d54c6de720..2953299e8b 100644
--- a/bootstrap/lib/stdlib/ebin/timer.beam
+++ b/bootstrap/lib/stdlib/ebin/timer.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/unicode.beam b/bootstrap/lib/stdlib/ebin/unicode.beam
index 8534ddbe22..d61ed589aa 100644
--- a/bootstrap/lib/stdlib/ebin/unicode.beam
+++ b/bootstrap/lib/stdlib/ebin/unicode.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/unicode_util.beam b/bootstrap/lib/stdlib/ebin/unicode_util.beam
index 7da23997df..8ddf73ca26 100644
--- a/bootstrap/lib/stdlib/ebin/unicode_util.beam
+++ b/bootstrap/lib/stdlib/ebin/unicode_util.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/zip.beam b/bootstrap/lib/stdlib/ebin/zip.beam
index 84807f7e39..cd6274efe5 100644
--- a/bootstrap/lib/stdlib/ebin/zip.beam
+++ b/bootstrap/lib/stdlib/ebin/zip.beam
Binary files differ
diff --git a/erts/doc/src/erl.xml b/erts/doc/src/erl.xml
index 05a9895687..88ddb03e97 100644
--- a/erts/doc/src/erl.xml
+++ b/erts/doc/src/erl.xml
@@ -464,7 +464,7 @@
</item>
<tag><c><![CDATA[-rsh Program]]></c></tag>
<item>
- <p>Specifies an alternative to <c><![CDATA[rsh]]></c> for starting a
+ <p>Specifies an alternative to <c><![CDATA[ssh]]></c> for starting a
slave node on a remote host; see
<seealso marker="stdlib:slave"><c>slave(3)</c></seealso>.</p>
</item>
diff --git a/erts/emulator/beam/beam_load.c b/erts/emulator/beam/beam_load.c
index e9e294cd59..f4eeb54a1b 100644
--- a/erts/emulator/beam/beam_load.c
+++ b/erts/emulator/beam/beam_load.c
@@ -2970,6 +2970,8 @@ load_code(LoaderState* stp)
#define succ(St, X, Y) ((X).type == (Y).type && (X).val + 1 == (Y).val)
#define succ2(St, X, Y) ((X).type == (Y).type && (X).val + 2 == (Y).val)
#define succ3(St, X, Y) ((X).type == (Y).type && (X).val + 3 == (Y).val)
+#define succ4(St, X, Y) ((X).type == (Y).type && (X).val + 4 == (Y).val)
+
#ifdef NO_FPE_SIGNALS
#define no_fpe_signals(St) 1
@@ -2986,6 +2988,35 @@ compiled_with_otp_20_or_higher(LoaderState* stp)
}
/*
+ * Predicate that tests whether the following two moves are independent:
+ *
+ * move Src1 Dst1
+ * move Src2 Dst2
+ *
+ */
+static int
+independent_moves(LoaderState* stp, GenOpArg Src1, GenOpArg Dst1,
+ GenOpArg Src2, GenOpArg Dst2)
+{
+ return (Src1.type != Dst2.type || Src1.val != Dst2.val) &&
+ (Src2.type != Dst1.type || Src2.val != Dst1.val) &&
+ (Dst1.type != Dst2.type ||Dst1.val != Dst2.val);
+}
+
+/*
+ * Predicate that tests that two registers are distinct.
+ *
+ * move Src1 Dst1
+ * move Src2 Dst2
+ *
+ */
+static int
+distinct(LoaderState* stp, GenOpArg Reg1, GenOpArg Reg2)
+{
+ return Reg1.type != Reg2.type || Reg1.val != Reg2.val;
+}
+
+/*
* Predicate that tests whether a jump table can be used.
*/
diff --git a/erts/emulator/beam/instrs.tab b/erts/emulator/beam/instrs.tab
index e55c4a112d..fc88cab22f 100644
--- a/erts/emulator/beam/instrs.tab
+++ b/erts/emulator/beam/instrs.tab
@@ -359,7 +359,7 @@ i_get_tuple_element2(Src, Element, Dst) {
dst[1] = E2;
}
-i_get_tuple_element2y(Src, Element, D1, D2) {
+i_get_tuple_element2_dst(Src, Element, D1, D2) {
Eterm* src;
Eterm E1, E2;
src = ADD_BYTE_OFFSET(tuple_val($Src), $Element);
@@ -436,6 +436,30 @@ init(Y) {
make_blank($Y);
}
+init_seq3(Y1) {
+ Eterm* dst = &$Y1;
+ make_blank(dst[0]);
+ make_blank(dst[1]);
+ make_blank(dst[2]);
+}
+
+init_seq4(Y1) {
+ Eterm* dst = &$Y1;
+ make_blank(dst[0]);
+ make_blank(dst[1]);
+ make_blank(dst[2]);
+ make_blank(dst[3]);
+}
+
+init_seq5(Y1) {
+ Eterm* dst = &$Y1;
+ make_blank(dst[0]);
+ make_blank(dst[1]);
+ make_blank(dst[2]);
+ make_blank(dst[3]);
+ make_blank(dst[4]);
+}
+
init2(Y1, Y2) {
make_blank($Y1);
make_blank($Y2);
@@ -642,12 +666,6 @@ is_nonempty_list(Fail, Src) {
}
}
-is_nonempty_list_test_heap(Fail, Need, Live) {
- //| -no_prefetch
- $is_nonempty_list($Fail, x(0));
- $test_heap($Need, $Live);
-}
-
is_nonempty_list_allocate(Fail, Src, Need, Live) {
//| -no_prefetch
$is_nonempty_list($Fail, $Src);
@@ -660,6 +678,18 @@ is_nonempty_list_get_list(Fail, Src, Hd, Tl) {
$get_list($Src, $Hd, $Tl);
}
+is_nonempty_list_get_hd(Fail, Src, Hd) {
+ //| -no_prefetch
+ $is_nonempty_list($Fail, $Src);
+ $get_hd($Src, $Hd);
+}
+
+is_nonempty_list_get_tl(Fail, Src, Tl) {
+ //| -no_prefetch
+ $is_nonempty_list($Fail, $Src);
+ $get_tl($Src, $Tl);
+}
+
jump(Fail) {
$JUMP($Fail);
}
@@ -797,6 +827,16 @@ test_arity(Fail, Pointer, Arity) {
}
}
+test_arity_get_tuple_element(Fail, Pointer, Arity, Pos, Dst) {
+ Eterm* ptr = tuple_val($Pointer);
+ Eterm* src;
+ if (*ptr != $Arity) {
+ $FAIL($Fail);
+ }
+ src = ADD_BYTE_OFFSET(ptr, $Pos);
+ $Dst = *src;
+}
+
i_is_eq_exact_immed(Fail, X, Y) {
if ($X != $Y) {
$FAIL($Fail);
diff --git a/erts/emulator/beam/ops.tab b/erts/emulator/beam/ops.tab
index 8e730e42d6..3cfc685336 100644
--- a/erts/emulator/beam/ops.tab
+++ b/erts/emulator/beam/ops.tab
@@ -118,11 +118,21 @@ test_heap I t?
allocate_heap S u==0 R => allocate S R
allocate_heap_zero S u==0 R => allocate_zero S R
-init2 y y
-init3 y y y
+init Y1 | init Y2 | init Y3 | succ(Y1,Y2) | succ(Y2,Y3) => init_seq3 Y1
+init_seq3 Y1 | init Y4 | succ3(Y1,Y4) => init_seq4 Y1
+init_seq4 Y1 | init Y5 | succ4(Y1,Y5) => init_seq5 Y1
+
+init_seq3 y
+init_seq4 y
+init_seq5 y
+
init Y1 | init Y2 | init Y3 => init3 Y1 Y2 Y3
init Y1 | init Y2 => init2 Y1 Y2
+init2 y y
+init3 y y y
+
+
# Selecting values
select_val S=aiq Fail=f Size=u Rest=* => const_select_val(S, Fail, Size, Rest)
@@ -212,7 +222,8 @@ i_get_tuple_element xy P y
%hot
i_get_tuple_element2 x P x
-i_get_tuple_element2y x P y y
+i_get_tuple_element2_dst x P x x
+i_get_tuple_element2_dst x P y y
i_get_tuple_element3 x P x
@@ -288,7 +299,7 @@ move_window4 x x x x y
move_window5 x x x x x y
# Swap registers.
-move R1=x Tmp=x | move R2=xy R1 | move Tmp R2 => swap_temp R1 R2 Tmp
+move R1=x Tmp=x | move R2=x R1 | move Tmp R2 => swap_temp R1 R2 Tmp
swap_temp R1 R2 Tmp | line Loc | apply Live | is_killed_apply(Tmp, Live) => \
swap R1 R2 | line Loc | apply Live
@@ -307,73 +318,84 @@ swap_temp R1 R2 Tmp | line Loc | call_ext_only Live Addr | \
swap_temp R1 R2 Tmp | line Loc | call_ext_last Live Addr D | \
is_killed(Tmp, Live) => swap R1 R2 | line Loc | call_ext_last Live Addr D
-swap_temp x xy x
+swap_temp x x x
+
+swap x x
-swap x xy
+# move_dup
move Src=x D1=x | move Src=x D2=x => move_dup Src D1 D2
-move Src=x SD=x | move SD=x D=x => move_dup Src SD D
-move Src=x D1=x | move Src=x D2=y => move_dup Src D1 D2
-move Src=y SD=x | move SD=x D=y => move_dup Src SD D
-move Src=x SD=x | move SD=x D=y => move_dup Src SD D
-move Src=y SD=x | move SD=x D=x => move_dup Src SD D
-
-move SD=x D=x | move Src=xy SD=x => move_shift Src SD D
-move SD=y D=x | move Src=x SD=y => move_shift Src SD D
-move SD=x D=y | move Src=x SD=x => move_shift Src SD D
-
-# The transformations above guarantee that the source for
-# the second move is not the same as the destination for
-# the first move. That means that we can do the moves in
-# parallel (fetch both values, then store them) which could
-# be faster.
+move Src=x SD=x | move SD=x D=x => move_dup Src SD D
-move X1=x Y1=y | move X2=x Y2=y => move2_par X1 Y1 X2 Y2
-move Y1=y X1=x | move Y2=y X2=x => move2_par Y1 X1 Y2 X2
+move_dup x x x
-move X1=x X2=x | move X3=x X4=x => move2_par X1 X2 X3 X4
+# move_shift
-move X1=x X2=x | move X3=x Y1=y => move2_par X1 X2 X3 Y1
+move SD=x D=x | move Src=xy SD=x | distinct(D, Src) => move_shift Src SD D
+move SD=y D=x | move Src=x SD=y | distinct(D, Src) => move_shift Src SD D
+move SD=x D=y | move Src=x SD=x | distinct(D, Src) => move_shift Src SD D
-move S1=x S2=x | move X1=x Y1=y => move2_par S1 S2 X1 Y1
+move_shift x x x
+move_shift y x x
+move_shift x y x
+move_shift x x y
-move S1=y S2=x | move X1=x Y1=y => move2_par S1 S2 X1 Y1
+# move2_par x x x x
-move Y1=y X1=x | move S1=x D1=x => move2_par Y1 X1 S1 D1
-move S1=x D1=x | move Y1=y X1=x => move2_par S1 D1 Y1 X1
+move X1=x X2=x | move X3=x X4=x | independent_moves(X1, X2, X3, X4) => \
+ move2_par X1 X2 X3 X4
+move2_par x x x x
-move2_par X1=x Y1=y X2=x Y2=y | move X3=x Y3=y => move3 X1 Y1 X2 Y2 X3 Y3
-move2_par Y1=y X1=x Y2=y X2=x | move Y3=y X3=x => move3 Y1 X1 Y2 X2 Y3 X3
-move2_par X1=x X2=x X3=x X4=x | move X5=x X6=x => move3 X1 X2 X3 X4 X5 X6
+# move2_par x y x y
-move C=aiq X=x==1 => move_x1 C
-move C=aiq X=x==2 => move_x2 C
+move X1=x Y1=y | move X2=x Y2=y => move2_par X1 Y1 X2 Y2
+move2_par x y x y
-move_x1 c
-move_x2 c
+# move2_par x x x y
-move_shift x x x
-move_shift y x x
-move_shift x y x
-move_shift x x y
+move X1=x X2=x | move X3=x Y1=y | independent_moves(X1, X2, X3, Y1) => \
+ move2_par X1 X2 X3 Y1
+move X3=x Y1=y | move X1=x X2=x | independent_moves(X3, Y1, X1, X2) => \
+ move2_par X1 X2 X3 Y1
+move2_par x x x y
-move_dup xy x xy
+# move2_par y x y x
-move2_par x y x y
+move Y1=y X1=x | move Y2=y X2=x => move2_par Y1 X1 Y2 X2
move2_par y x y x
-move2_par x x x x
-move2_par x x x y
+# move2_par y x x y
+move S1=y S2=x | move X1=x Y1=y | independent_moves(S1, S2, X1, Y1) => \
+ move2_par S1 S2 X1 Y1
+move X1=x Y1=y | move S1=y S2=x | independent_moves(S1, S2, X1, Y1) => \
+ move2_par S1 S2 X1 Y1
move2_par y x x y
-move2_par x x y x
+# move2_par y x x x
+
+move Y1=y X1=x | move S1=x D1=x | independent_moves(Y1, X1, S1, D1) => \
+ move2_par Y1 X1 S1 D1
+move S1=x D1=x | move Y1=y X1=x | independent_moves(Y1, X1, S1, D1) => \
+ move2_par Y1 X1 S1 D1
move2_par y x x x
-move3 x y x y x y
+# move3
+
+move2_par Y1=y X1=x Y2=y X2=x | move Y3=y X3=x => move3 Y1 X1 Y2 X2 Y3 X3
+move2_par X1=x X2=x X3=x X4=x | move X5=x X6=x => move3 X1 X2 X3 X4 X5 X6
+
move3 y x y x y x
move3 x x x x x x
+# move_x1, move_x2
+
+move C=aiq X=x==1 => move_x1 C
+move C=aiq X=x==2 => move_x2 C
+
+move_x1 c
+move_x2 c
+
# The compiler almost never generates a "move Literal y(Y)" instruction,
# so let's cheat if we encounter one.
move S=n D=y => init D
@@ -611,9 +633,13 @@ is_tuple f? rxy
test_arity Fail Literal=q Arity => move Literal x | test_arity Fail x Arity
test_arity Fail=f c Arity => jump Fail
+test_arity Fail Tuple=x Arity | get_tuple_element Tuple Pos Dst=x => \
+ test_arity_get_tuple_element Fail Tuple Arity Pos Dst
test_arity f? xy A
+test_arity_get_tuple_element f? x A P x
+
get_tuple_element Reg=x P1 D1=x | get_tuple_element Reg=x P2 D2=x | \
get_tuple_element Reg=x P3 D3=x | \
succ(P1, P2) | succ(P2, P3) | \
@@ -622,8 +648,11 @@ get_tuple_element Reg=x P1 D1=x | get_tuple_element Reg=x P2 D2=x | \
get_tuple_element Reg=x P1 D1=x | get_tuple_element Reg=x P2 D2=x | \
succ(P1, P2) | succ(D1, D2) => i_get_tuple_element2 Reg P1 D1
+get_tuple_element Reg=x P1 D1=x | get_tuple_element Reg=x P2 D2=x | \
+ succ(P1, P2) | distinct(D1, Reg) => i_get_tuple_element2_dst Reg P1 D1 D2
+
get_tuple_element Reg=x P1 D1=y | get_tuple_element Reg=x P2 D2=y | \
- succ(P1, P2) => i_get_tuple_element2y Reg P1 D1 D2
+ succ(P1, P2) => i_get_tuple_element2_dst Reg P1 D1 D2
get_tuple_element Reg P Dst => i_get_tuple_element Reg P Dst
@@ -647,14 +676,21 @@ is_list f? y
is_nonempty_list Fail=f S=x | allocate Need Rs => is_nonempty_list_allocate Fail S Need Rs
-is_nonempty_list F=f x==0 | test_heap I1 I2 => is_nonempty_list_test_heap F I1 I2
-
is_nonempty_list Fail=f S=x | get_list S D1=x D2=x => \
is_nonempty_list_get_list Fail S D1 D2
+is_nonempty_list Fail=f S=x | get_hd S Dst=x => \
+ is_nonempty_list_get_hd Fail S Dst
+
+is_nonempty_list Fail=f S=x | get_tl S Dst=x => \
+ is_nonempty_list_get_tl Fail S Dst
+
is_nonempty_list_allocate f? rx t t
-is_nonempty_list_test_heap f? I t
+
is_nonempty_list_get_list f? rx x x
+is_nonempty_list_get_hd f? x x
+is_nonempty_list_get_tl f? x x
+
is_nonempty_list f? xy
is_atom f? x
diff --git a/erts/emulator/beam/utils.c b/erts/emulator/beam/utils.c
index 36a492f00d..36cfe0548e 100644
--- a/erts/emulator/beam/utils.c
+++ b/erts/emulator/beam/utils.c
@@ -1946,7 +1946,7 @@ do_allocate_logger_message(Eterm gleader, ErtsMonotonicTime *ts, Eterm *pid,
else
sz += MAP4_SZ /* metadata map w gl w pid*/;
- *ts = ERTS_MONOTONIC_TO_USEC(erts_get_monotonic_time(NULL) + erts_get_time_offset());
+ *ts = ERTS_MONOTONIC_TO_USEC(erts_os_system_time());
erts_bld_sint64(NULL, &sz, *ts);
*bp = new_message_buffer(sz);
diff --git a/erts/emulator/internal_doc/CountingInstructions.md b/erts/emulator/internal_doc/CountingInstructions.md
new file mode 100644
index 0000000000..d4b1213d00
--- /dev/null
+++ b/erts/emulator/internal_doc/CountingInstructions.md
@@ -0,0 +1,53 @@
+Counting Instructions
+=====================
+
+Here is an example that shows how to count how many times each
+instruction is executed:
+
+ $ (cd erts/emulator && make icount)
+ MAKE icount
+ make[1]: Entering directory `/home/uabbgus/otp/erts/emulator'
+ .
+ .
+ .
+ make[1]: Leaving directory `/home/uabbgus/otp/erts/emulator'
+ $ cat t.erl
+ -module(t).
+ -compile([export_all,nowarn_export_all]).
+
+ count() ->
+ erts_debug:ic(fun benchmark/0).
+
+ benchmark() ->
+ %% Run dialyzer.
+ Root = code:root_dir(),
+ Wc1 = filename:join(Root, "lib/{kernel,stdlib}/ebin/*.beam"),
+ Wc2 = filename:join(Root, "erts/preloaded/ebin/*.beam"),
+ Files = filelib:wildcard(Wc1) ++ filelib:wildcard(Wc2),
+ Opts = [{analysis_type,plt_build},{files,Files},{get_warnings,true}],
+ dialyzer:run(Opts).
+ $ $ERL_TOP/bin/cerl -icount
+ Erlang/OTP 22 [RELEASE CANDIDATE 1] [erts-10.2.4] [source-ac0d451] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:1] [hipe] [instruction-counting]
+
+ Eshell V10.2.4 (abort with ^G)
+ 1> c(t).
+ {ok,t}
+ 2> t:count().
+ 0 badarg_j
+ 0 badmatch_x
+ 0 bs_add_jsstx
+ 0 bs_context_to_binary_x
+ .
+ .
+ .
+ 536461394 move_call_last_yfQ
+ 552405176 allocate_tt
+ 619920327 i_is_eq_exact_immed_frc
+ 636419163 is_nonempty_list_allocate_frtt
+ 641859278 i_get_tuple_element_xPx
+ 678196718 move_return_c
+ 786289914 is_tagged_tuple_frAa
+ 865826424 i_call_f
+ Total: 20728870321
+ []
+ 3>
diff --git a/erts/emulator/nifs/common/net_nif.c b/erts/emulator/nifs/common/net_nif.c
index fba9ee54fc..9a18ed3b15 100644
--- a/erts/emulator/nifs/common/net_nif.c
+++ b/erts/emulator/nifs/common/net_nif.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2018-2018. All Rights Reserved.
+ * Copyright Ericsson AB 2018-2019. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -392,6 +392,7 @@ static char str_esystem[] = "esystem";
static ERL_NIF_TERM atom_address_info;
static ERL_NIF_TERM atom_debug;
+static ERL_NIF_TERM atom_host;
static ERL_NIF_TERM atom_idn;
static ERL_NIF_TERM atom_idna_allow_unassigned;
static ERL_NIF_TERM atom_idna_use_std3_ascii_rules;
@@ -400,6 +401,7 @@ static ERL_NIF_TERM atom_name_info;
static ERL_NIF_TERM atom_nofqdn;
static ERL_NIF_TERM atom_numerichost;
static ERL_NIF_TERM atom_numericserv;
+static ERL_NIF_TERM atom_service;
static ERL_NIF_TERM atom_eaddrfamily;
@@ -652,6 +654,7 @@ ERL_NIF_TERM nif_getnameinfo(ErlNifEnv* env,
int flags = 0; // Just in case...
SocketAddress sa;
SOCKLEN_T saLen = 0; // Just in case...
+ char* xres;
NDBG( ("NET", "nif_getnameinfo -> entry (%d)\r\n", argc) );
@@ -666,8 +669,12 @@ ERL_NIF_TERM nif_getnameinfo(ErlNifEnv* env,
"\r\n Flags: %T"
"\r\n", eSockAddr, eFlags) );
- if (!esock_decode_sockaddr(env, eSockAddr, &sa, &saLen))
- return enif_make_badarg(env);
+ if ((xres = esock_decode_sockaddr(env, eSockAddr, &sa, &saLen)) != NULL) {
+ NDBG( ("NET", "nif_getnameinfo -> failed decode sockaddr: %s\r\n", xres) );
+ return esock_make_error_str(env, xres);
+ }
+
+ NDBG( ("NET", "nif_getnameinfo -> (try) decode flags\r\n") );
if (!decode_nameinfo_flags(env, eFlags, &flags))
return enif_make_badarg(env);
@@ -684,7 +691,7 @@ ERL_NIF_TERM nif_getnameinfo(ErlNifEnv* env,
-/* Given the provided sock(et) address (and honts), retreive the host and
+/* Given the provided sock(et) address (and flags), retreive the host and
* service info.
*/
#if !defined(__WIN32__)
@@ -710,10 +717,17 @@ ERL_NIF_TERM ngetnameinfo(ErlNifEnv* env,
switch (res) {
case 0:
{
- ERL_NIF_TERM info = MKT3(env,
- atom_name_info,
- MKS(env, host),
- MKS(env, serv));
+ ERL_NIF_TERM keys[] = {atom_host, atom_service};
+ ERL_NIF_TERM vals[] = {MKS(env, host), MKS(env, serv)};
+ ERL_NIF_TERM info;
+ unsigned int numKeys = sizeof(keys) / sizeof(ERL_NIF_TERM);
+ unsigned int numVals = sizeof(vals) / sizeof(ERL_NIF_TERM);
+
+ ESOCK_ASSERT( (numKeys == numVals) );
+
+ if (!MKMA(env, keys, vals, numKeys, &info))
+ return enif_make_badarg(env);
+
result = esock_make_ok2(env, info);
}
break;
@@ -1229,6 +1243,7 @@ BOOLEAN_T decode_nameinfo_flags(ErlNifEnv* env,
BOOLEAN_T result;
if (IS_ATOM(env, eflags)) {
+ NDBG( ("NET", "decode_nameinfo_flags -> is atom (%T)\r\n", eflags) );
if (COMPARE(eflags, esock_atom_undefined) == 0) {
*flags = 0;
result = TRUE;
@@ -1236,12 +1251,14 @@ BOOLEAN_T decode_nameinfo_flags(ErlNifEnv* env,
result = FALSE;
}
} else if (IS_LIST(env, eflags)) {
- NDBG( ("NET", "decode_nameinfo_flags -> is atom\r\n") );
+ NDBG( ("NET", "decode_nameinfo_flags -> is list\r\n") );
result = decode_nameinfo_flags_list(env, eflags, flags);
} else {
result = FALSE;
}
+ NDBG( ("NET", "decode_nameinfo_flags -> result: %s\r\n", B2S(result)) );
+
return result;
}
@@ -1637,6 +1654,7 @@ int on_load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)
/* +++ Misc atoms +++ */
atom_address_info = MKA(env, str_address_info);
atom_debug = MKA(env, str_debug);
+ atom_host = MKA(env, "host");
atom_idn = MKA(env, str_idn);
atom_idna_allow_unassigned = MKA(env, str_idna_allow_unassigned);
atom_idna_use_std3_ascii_rules = MKA(env, str_idna_use_std3_ascii_rules);
@@ -1645,6 +1663,7 @@ int on_load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)
atom_nofqdn = MKA(env, str_nofqdn);
atom_numerichost = MKA(env, str_numerichost);
atom_numericserv = MKA(env, str_numericserv);
+ atom_service = MKA(env, "service");
/* Error codes */
atom_eaddrfamily = MKA(env, str_eaddrfamily);
diff --git a/erts/emulator/sys/common/erl_mmap.h b/erts/emulator/sys/common/erl_mmap.h
index e1ff0fe80a..3085bf7e19 100644
--- a/erts/emulator/sys/common/erl_mmap.h
+++ b/erts/emulator/sys/common/erl_mmap.h
@@ -203,7 +203,7 @@ ERTS_GLB_INLINE void erts_mem_discard(void *p, UWord size);
data[i] = pattern[i % sizeof(pattern)];
}
}
-#elif defined(HAVE_SYS_MMAN_H)
+#elif defined(HAVE_SYS_MMAN_H) && !(defined(__sun) || defined(__sun__))
#include <sys/mman.h>
ERTS_GLB_INLINE void erts_mem_discard(void *ptr, UWord size) {
diff --git a/erts/emulator/test/Makefile b/erts/emulator/test/Makefile
index c2a01b9e71..8c2054cb51 100644
--- a/erts/emulator/test/Makefile
+++ b/erts/emulator/test/Makefile
@@ -29,9 +29,6 @@ EBIN = .
# ----------------------------------------------------
SOCKET_MODULES = \
- socket_lib \
- socket_server \
- socket_client \
socket_test_lib \
socket_test_logger \
socket_test_evaluator \
@@ -46,6 +43,9 @@ SOCKET_MODULES = \
socket_test_ttest_tcp_server_socket \
socket_SUITE
+NET_MODULES = \
+ net_SUITE
+
MODULES= \
a_SUITE \
after_SUITE \
@@ -102,6 +102,7 @@ MODULES= \
monitor_SUITE \
multi_load_SUITE \
nested_SUITE \
+ $(NET_MODULES) \
nif_SUITE \
node_container_SUITE \
nofrag_SUITE \
@@ -178,6 +179,7 @@ HRL_FILES= \
socket_test_ttest_client.hrl
TARGET_FILES = $(MODULES:%=$(EBIN)/%.$(EMULATOR))
+NET_TARGETS = $(NET_MODULES:%=$(EBIN)/%.$(EMULATOR))
SOCKET_TARGETS = $(SOCKET_MODULES:%=$(EBIN)/%.$(EMULATOR))
EMAKEFILE=Emakefile
@@ -227,6 +229,7 @@ docs:
targets: $(TARGET_FILES)
socket_targets: $(SOCKET_TARGETS)
+net_targets: $(NET_TARGETS)
# ----------------------------------------------------
# Special targets
diff --git a/erts/emulator/test/socket_client.erl b/erts/emulator/test/esock_misc/socket_client.erl
index 1c07e799b8..1c07e799b8 100644
--- a/erts/emulator/test/socket_client.erl
+++ b/erts/emulator/test/esock_misc/socket_client.erl
diff --git a/erts/emulator/test/socket_lib.erl b/erts/emulator/test/esock_misc/socket_lib.erl
index 9d6524d467..9d6524d467 100644
--- a/erts/emulator/test/socket_lib.erl
+++ b/erts/emulator/test/esock_misc/socket_lib.erl
diff --git a/erts/emulator/test/socket_server.erl b/erts/emulator/test/esock_misc/socket_server.erl
index 45adffc5e6..45adffc5e6 100644
--- a/erts/emulator/test/socket_server.erl
+++ b/erts/emulator/test/esock_misc/socket_server.erl
diff --git a/erts/emulator/test/net_SUITE.erl b/erts/emulator/test/net_SUITE.erl
new file mode 100644
index 0000000000..1a973cacb2
--- /dev/null
+++ b/erts/emulator/test/net_SUITE.erl
@@ -0,0 +1,481 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2019-2019. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%% This test suite is basically a "placeholder" for a proper test suite...
+%%
+
+%% Run the entire test suite:
+%% ts:run(emulator, net_SUITE, [batch]).
+%%
+%% Run a specific group:
+%% ts:run(emulator, net_SUITE, {group, foo}, [batch]).
+%%
+%% Run a specific test case:
+%% ts:run(emulator, net_SUITE, foo, [batch]).
+
+-module(net_SUITE).
+
+-include_lib("common_test/include/ct.hrl").
+-include_lib("common_test/include/ct_event.hrl").
+
+%% Suite exports
+-export([suite/0, all/0, groups/0]).
+-export([init_per_suite/1, end_per_suite/1,
+ init_per_group/2, end_per_group/2,
+ init_per_testcase/2, end_per_testcase/2]).
+
+%% Test cases
+-export([
+ %% *** API Basic ***
+ api_b_gethostname/1,
+ api_b_name_and_addr_info/1,
+
+ api_b_name_and_index/1
+
+ %% Tickets
+ ]).
+
+
+%% -include("socket_test_evaluator.hrl").
+
+%% Internal exports
+%% -export([]).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+-define(SLEEP(T), receive after T -> ok end).
+
+-define(FAIL(R), exit(R)).
+
+-define(MINS(M), timer:minutes(M)).
+-define(SECS(S), timer:seconds(S)).
+
+-define(TT(T), ct:timetrap(T)).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+suite() ->
+ [{ct_hooks,[ts_install_cth]},
+ {timetrap,{minutes,1}}].
+
+all() ->
+ Groups = [{api, "ENET_TEST_API", include}],
+ [use_group(Group, Env, Default) || {Group, Env, Default} <- Groups].
+
+use_group(Group, Env, Default) ->
+ case os:getenv(Env) of
+ false when (Default =:= include) ->
+ [{group, Group}];
+ false ->
+ [];
+ Val ->
+ case list_to_atom(string:to_lower(Val)) of
+ Use when (Use =:= include) orelse
+ (Use =:= enable) orelse
+ (Use =:= true) ->
+ [{group, Group}];
+ _ ->
+ []
+ end
+ end.
+
+
+groups() ->
+ [{api, [], api_cases()},
+ {api_basic, [], api_basic_cases()}
+
+ %% {tickets, [], ticket_cases()}
+ ].
+
+api_cases() ->
+ [
+ {group, api_basic}
+ ].
+
+api_basic_cases() ->
+ [
+ api_b_gethostname,
+ api_b_name_and_addr_info,
+ api_b_name_and_index
+ ].
+
+%% ticket_cases() ->
+%% [].
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+init_per_suite(Config) ->
+ case os:type() of
+ {win32, _} ->
+ not_yet_implemented();
+ _ ->
+ %% ?LOGGER:start(),
+ Config
+ end.
+
+end_per_suite(_) ->
+ %% ?LOGGER:stop(),
+ ok.
+
+init_per_group(_Group, Config) ->
+ Config.
+
+end_per_group(_Group, Config) ->
+ Config.
+
+
+init_per_testcase(_TC, Config) ->
+ Config.
+
+end_per_testcase(_TC, Config) ->
+ Config.
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% %%
+%% API BASIC %%
+%% %%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Get the hostname of the host.
+api_b_gethostname(suite) ->
+ [];
+api_b_gethostname(doc) ->
+ [];
+api_b_gethostname(_Config) when is_list(_Config) ->
+ ?TT(?SECS(5)),
+ tc_try(api_b_gethostname,
+ fun() ->
+ ok = api_b_gethostname()
+ end).
+
+
+api_b_gethostname() ->
+ case net:gethostname() of
+ {ok, Hostname} ->
+ i("hostname: ~s", [Hostname]),
+ ok;
+ {error, Reason} ->
+ ?FAIL(Reason)
+ end.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Get name and address info.
+api_b_name_and_addr_info(suite) ->
+ [];
+api_b_name_and_addr_info(doc) ->
+ [];
+api_b_name_and_addr_info(_Config) when is_list(_Config) ->
+ ?TT(?SECS(5)),
+ tc_try(api_b_name_and_addr_info,
+ fun() ->
+ ok = api_b_name_and_addr_info()
+ end).
+
+
+api_b_name_and_addr_info() ->
+ Domain = inet,
+ Addr = which_local_addr(Domain),
+ SA = #{family => Domain, addr => Addr},
+ Hostname =
+ case net:getnameinfo(SA) of
+ {ok, #{host := Name, service := Service} = NameInfo}
+ when is_list(Name) andalso is_list(Service) ->
+ i("getnameinfo: "
+ "~n ~p", [NameInfo]),
+ Name;
+ {ok, BadNameInfo} ->
+ ?FAIL({getnameinfo, SA, BadNameInfo});
+ {error, Reason1} ->
+ ?FAIL({getnameinfo, SA, Reason1})
+ end,
+ case net:getaddrinfo(Hostname) of
+ {ok, AddrInfos} when is_list(AddrInfos) ->
+ i("getaddrinfo: "
+ "~n ~p", [AddrInfos]),
+ verify_addr_info(AddrInfos, Domain);
+ {ok, BadAddrInfo} ->
+ ?FAIL({getaddrinfo, Hostname, BadAddrInfo});
+ {error, Reason2} ->
+ ?FAIL({getaddrinfo, Hostname, Reason2})
+ end.
+
+
+verify_addr_info(AddrInfos, Domain) when (AddrInfos =/= []) ->
+ verify_addr_info2(AddrInfos, Domain).
+
+verify_addr_info2([], _Domain) ->
+ ok;
+verify_addr_info2([#{addr := #{addr := Addr,
+ family := Domain,
+ port := Port},
+ family := Domain,
+ type := _Type,
+ protocol := _Proto}|T], Domain)
+ when is_integer(Port) andalso
+ (((Domain =:= inet) andalso is_tuple(Addr) andalso (size(Addr) =:= 4)) orelse
+ ((Domain =:= inet6) andalso is_tuple(Addr) andalso (size(Addr) =:= 8))) ->
+ verify_addr_info2(T, Domain);
+verify_addr_info2([#{family := DomainA}|T], DomainB)
+ when (DomainA =/= DomainB) ->
+ %% Ignore entries for other domains
+ verify_addr_info2(T, DomainB);
+verify_addr_info2([BadAddrInfo|_], Domain) ->
+ ?FAIL({bad_address_info, BadAddrInfo, Domain}).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Verify (interface) name and index functions.
+%% if_names/0,
+%% if_name2index/1
+%% if_index2name/1
+api_b_name_and_index(suite) ->
+ [];
+api_b_name_and_index(doc) ->
+ [];
+api_b_name_and_index(_Config) when is_list(_Config) ->
+ ?TT(?SECS(5)),
+ tc_try(api_b_name_and_index,
+ fun() ->
+ ok = api_b_name_and_index()
+ end).
+
+
+api_b_name_and_index() ->
+ Names =
+ case net:if_names() of
+ {ok, N} when is_list(N) andalso (N =/= []) ->
+ N;
+ {error, Reason} ->
+ ?FAIL({if_names, Reason})
+ end,
+ verify_if_names(Names).
+
+verify_if_names([]) ->
+ ok;
+verify_if_names([{Index, Name}|T]) ->
+ case net:if_name2index(Name) of
+ {ok, Index} ->
+ ok;
+ {ok, BadIndex} ->
+ ?FAIL({name2index, Name, Index, BadIndex});
+ {error, ReasonN2I} ->
+ ?FAIL({name2index, Name, ReasonN2I})
+ end,
+ case net:if_index2name(Index) of
+ {ok, Name} ->
+ ok;
+ {ok, BadName} ->
+ ?FAIL({index2name, Index, Name, BadName});
+ {error, ReasonI2N} ->
+ ?FAIL({index2name, Index, ReasonI2N})
+ end,
+ verify_if_names(T).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% local_host() ->
+%% try net_adm:localhost() of
+%% Host when is_list(Host) ->
+%% %% Convert to shortname if long
+%% case string:tokens(Host, [$.]) of
+%% [H|_] ->
+%% list_to_atom(H)
+%% end
+%% catch
+%% C:E:S ->
+%% erlang:raise(C, E, S)
+%% end.
+
+
+%% This gets the local address (not 127.0...)
+%% We should really implement this using the (new) net module,
+%% but until that gets the necessary functionality...
+which_local_addr(Domain) ->
+ case inet:getifaddrs() of
+ {ok, IFL} ->
+ which_addr(Domain, IFL);
+ {error, Reason} ->
+ ?FAIL({inet, getifaddrs, Reason})
+ end.
+
+which_addr(_Domain, []) ->
+ skip(no_address);
+which_addr(Domain, [{"lo" ++ _, _}|IFL]) ->
+ which_addr(Domain, IFL);
+which_addr(Domain, [{_Name, IFO}|IFL]) ->
+ case which_addr2(Domain, IFO) of
+ {ok, Addr} ->
+ Addr;
+ {error, no_address} ->
+ which_addr(Domain, IFL)
+ end;
+which_addr(Domain, [_|IFL]) ->
+ which_addr(Domain, IFL).
+
+which_addr2(_Domain, []) ->
+ {error, no_address};
+which_addr2(inet = _Domain, [{addr, Addr}|_IFO]) when (size(Addr) =:= 4) ->
+ {ok, Addr};
+which_addr2(inet6 = _Domain, [{addr, Addr}|_IFO]) when (size(Addr) =:= 8) ->
+ {ok, Addr};
+which_addr2(Domain, [_|IFO]) ->
+ which_addr2(Domain, IFO).
+
+
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+not_yet_implemented() ->
+ skip("not yet implemented").
+
+skip(Reason) ->
+ throw({skip, Reason}).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% t() ->
+%% os:timestamp().
+
+
+%% tdiff({A1, B1, C1} = _T1x, {A2, B2, C2} = _T2x) ->
+%% T1 = A1*1000000000+B1*1000+(C1 div 1000),
+%% T2 = A2*1000000000+B2*1000+(C2 div 1000),
+%% T2 - T1.
+
+
+formated_timestamp() ->
+ format_timestamp(os:timestamp()).
+
+format_timestamp({_N1, _N2, _N3} = TS) ->
+ {_Date, Time} = calendar:now_to_local_time(TS),
+ %% {YYYY,MM,DD} = Date,
+ {Hour,Min,Sec} = Time,
+ %% FormatTS =
+ %% io_lib:format("~.4w-~.2.0w-~.2.0w ~.2.0w:~.2.0w:~.2.0w.~w",
+ %% [YYYY, MM, DD, Hour, Min, Sec, N3]),
+ FormatTS = io_lib:format("~.2.0w:~.2.0w:~.2.0w", [Hour, Min, Sec]),
+ lists:flatten(FormatTS).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+set_tc_name(N) when is_atom(N) ->
+ set_tc_name(atom_to_list(N));
+set_tc_name(N) when is_list(N) ->
+ put(tc_name, N).
+
+%% get_tc_name() ->
+%% get(tc_name).
+
+tc_begin(TC) ->
+ set_tc_name(TC),
+ tc_print("begin ***",
+ "~n----------------------------------------------------~n", "").
+
+tc_end(Result) when is_list(Result) ->
+ tc_print("done: ~s", [Result],
+ "", "----------------------------------------------------~n~n"),
+ ok.
+
+
+tc_try(Case, Fun) when is_atom(Case) andalso is_function(Fun, 0) ->
+ tc_begin(Case),
+ try
+ begin
+ Fun(),
+ ?SLEEP(?SECS(1)),
+ tc_end("ok")
+ end
+ catch
+ throw:{skip, _} = SKIP ->
+ tc_end("skipping"),
+ SKIP;
+ Class:Error:Stack ->
+ tc_end("failed"),
+ erlang:raise(Class, Error, Stack)
+ end.
+
+
+tc_print(F, Before, After) ->
+ tc_print(F, [], Before, After).
+
+tc_print(F, A, Before, After) ->
+ Name = tc_which_name(),
+ FStr = f("*** [~s][~s][~p] " ++ F ++ "~n",
+ [formated_timestamp(),Name,self()|A]),
+ io:format(user, Before ++ FStr ++ After, []).
+
+tc_which_name() ->
+ case get(tc_name) of
+ undefined ->
+ case get(sname) of
+ undefined ->
+ "";
+ SName when is_list(SName) ->
+ SName
+ end;
+ Name when is_list(Name) ->
+ Name
+ end.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% l2a(S) when is_list(S) ->
+%% list_to_atom(S).
+
+%% l2b(L) when is_list(L) ->
+%% list_to_binary(L).
+
+%% b2l(B) when is_binary(B) ->
+%% binary_to_list(B).
+
+f(F, A) ->
+ lists:flatten(io_lib:format(F, A)).
+
+
+%% i(F) ->
+%% i(F, []).
+
+i(F, A) ->
+ FStr = f("[~s] " ++ F, [formated_timestamp()|A]),
+ io:format(user, FStr ++ "~n", []),
+ io:format(FStr, []).
+
diff --git a/erts/emulator/test/socket_SUITE.erl b/erts/emulator/test/socket_SUITE.erl
index f799186675..52d002c9b8 100644
--- a/erts/emulator/test/socket_SUITE.erl
+++ b/erts/emulator/test/socket_SUITE.erl
@@ -18,6 +18,29 @@
%% %CopyrightEnd%
%%
+%% There are some environment variables that can be used to "manipulate"
+%% the test suite:
+%%
+%% Variable that controls which 'groups' are to run (with default values)
+%%
+%% ESOCK_TEST_API: include
+%% ESOCK_TEST_SOCK_CLOSE: include
+%% ESOCK_TEST_TRAFFIC: include
+%% ESOCK_TEST_TTEST: exclude
+%%
+%% Defines the runtime of the ttest cases
+%% (This is the time during which "measurement" is performed.
+%% the actual time it takes for the test case to complete
+%% will be longer)
+%%
+%% ESOCK_TEST_TTEST_RUNTIME: 10 seconds
+%% Format of values: <integer>[<unit>]
+%% Where unit is: ms | s | m
+%% ms - milli seconds
+%% s - seconds (default)
+%% m - minutes
+%%
+
%% Run the entire test suite:
%% ts:run(emulator, socket_SUITE, [batch]).
%%
@@ -35,6 +58,7 @@
%% Suite exports
-export([suite/0, all/0, groups/0]).
-export([init_per_suite/1, end_per_suite/1,
+ init_per_group/2, end_per_group/2,
init_per_testcase/2, end_per_testcase/2]).
%% Test cases
@@ -1361,16 +1385,53 @@ init_per_suite(Config) ->
{win32, _} ->
not_yet_implemented();
_ ->
- ?LOGGER:start(),
- Config
+ case quiet_mode(Config) of
+ default ->
+ ?LOGGER:start(),
+ Config;
+ Quiet ->
+ ?LOGGER:start(Quiet),
+ [{esock_test_quiet, Quiet}|Config]
+ end
end.
end_per_suite(_) ->
?LOGGER:stop(),
ok.
+
+init_per_group(ttest = _GroupName, Config) ->
+ io:format("init_per_group(~w) -> entry with"
+ "~n Config: ~p"
+ "~n", [_GroupName, Config]),
+ case lists:keysearch(esock_test_ttest_runtime, 1, Config) of
+ {value, _} ->
+ Config;
+ false ->
+ [{esock_test_ttest_runtime, which_ttest_runtime_env()}|Config]
+ end;
+init_per_group(_GroupName, Config) ->
+ Config.
+
+end_per_group(ttest = _GroupName, Config) ->
+ io:format("init_per_group(~w) -> entry with"
+ "~n Config: ~p"
+ "~n", [_GroupName, Config]),
+ lists:keydelete(esock_test_ttest_runtime, 1, Config);
+end_per_group(_GroupName, Config) ->
+ Config.
+
+
init_per_testcase(_TC, Config) ->
- ?LOGGER:start(),
+ io:format("init_per_testcase(~w) -> entry with"
+ "~n Config: ~p"
+ "~n", [_TC, Config]),
+ case quiet_mode(Config) of
+ default ->
+ ?LOGGER:start();
+ Quiet ->
+ ?LOGGER:start(Quiet)
+ end,
Config.
end_per_testcase(_TC, Config) ->
@@ -1378,7 +1439,20 @@ end_per_testcase(_TC, Config) ->
Config.
+quiet_mode(Config) ->
+ case lists:keysearch(esock_test_quiet, 1, Config) of
+ {value, {esock_test_quiet, Quiet}} ->
+ Quiet;
+ false ->
+ case os:getenv("ESOCK_TEST_QUIET") of
+ "true" -> true;
+ "false" -> false;
+ _ -> default
+ end
+ end.
+
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% %%
@@ -11884,8 +11958,10 @@ ttest_sgenf_cgenf_small_tcp4(suite) ->
[];
ttest_sgenf_cgenf_small_tcp4(doc) ->
[];
-ttest_sgenf_cgenf_small_tcp4(_Config) when is_list(_Config) ->
+ttest_sgenf_cgenf_small_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgenf_cgenf_small_tcp4,
+ Runtime,
inet,
gen, false,
gen, false,
@@ -11906,8 +11982,10 @@ ttest_sgenf_cgenf_small_tcp6(suite) ->
[];
ttest_sgenf_cgenf_small_tcp6(doc) ->
[];
-ttest_sgenf_cgenf_small_tcp6(_Config) when is_list(_Config) ->
+ttest_sgenf_cgenf_small_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgenf_cgenf_small_tcp6,
+ Runtime,
inet6,
gen, false,
gen, false,
@@ -11928,8 +12006,10 @@ ttest_sgenf_cgenf_medium_tcp4(suite) ->
[];
ttest_sgenf_cgenf_medium_tcp4(doc) ->
[];
-ttest_sgenf_cgenf_medium_tcp4(_Config) when is_list(_Config) ->
+ttest_sgenf_cgenf_medium_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgenf_cgenf_medium_tcp4,
+ Runtime,
inet,
gen, false,
gen, false,
@@ -11950,8 +12030,10 @@ ttest_sgenf_cgenf_medium_tcp6(suite) ->
[];
ttest_sgenf_cgenf_medium_tcp6(doc) ->
[];
-ttest_sgenf_cgenf_medium_tcp6(_Config) when is_list(_Config) ->
+ttest_sgenf_cgenf_medium_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgenf_cgenf_medium_tcp6,
+ Runtime,
inet6,
gen, false,
gen, false,
@@ -11972,8 +12054,10 @@ ttest_sgenf_cgenf_large_tcp4(suite) ->
[];
ttest_sgenf_cgenf_large_tcp4(doc) ->
[];
-ttest_sgenf_cgenf_large_tcp4(_Config) when is_list(_Config) ->
+ttest_sgenf_cgenf_large_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgenf_cgenf_large_tcp4,
+ Runtime,
inet,
gen, false,
gen, false,
@@ -11994,8 +12078,10 @@ ttest_sgenf_cgenf_large_tcp6(suite) ->
[];
ttest_sgenf_cgenf_large_tcp6(doc) ->
[];
-ttest_sgenf_cgenf_large_tcp6(_Config) when is_list(_Config) ->
+ttest_sgenf_cgenf_large_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgenf_cgenf_large_tcp6,
+ Runtime,
inet6,
gen, false,
gen, false,
@@ -12016,8 +12102,10 @@ ttest_sgenf_cgeno_small_tcp4(suite) ->
[];
ttest_sgenf_cgeno_small_tcp4(doc) ->
[];
-ttest_sgenf_cgeno_small_tcp4(_Config) when is_list(_Config) ->
+ttest_sgenf_cgeno_small_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgenf_cgeno_small_tcp4,
+ Runtime,
inet,
gen, false,
gen, once,
@@ -12038,8 +12126,10 @@ ttest_sgenf_cgeno_small_tcp6(suite) ->
[];
ttest_sgenf_cgeno_small_tcp6(doc) ->
[];
-ttest_sgenf_cgeno_small_tcp6(_Config) when is_list(_Config) ->
+ttest_sgenf_cgeno_small_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgenf_cgeno_small_tcp6,
+ Runtime,
inet6,
gen, false,
gen, once,
@@ -12060,8 +12150,10 @@ ttest_sgenf_cgeno_medium_tcp4(suite) ->
[];
ttest_sgenf_cgeno_medium_tcp4(doc) ->
[];
-ttest_sgenf_cgeno_medium_tcp4(_Config) when is_list(_Config) ->
+ttest_sgenf_cgeno_medium_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgenf_cgeno_medium_tcp4,
+ Runtime,
inet,
gen, false,
gen, once,
@@ -12082,8 +12174,10 @@ ttest_sgenf_cgeno_medium_tcp6(suite) ->
[];
ttest_sgenf_cgeno_medium_tcp6(doc) ->
[];
-ttest_sgenf_cgeno_medium_tcp6(_Config) when is_list(_Config) ->
+ttest_sgenf_cgeno_medium_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgenf_cgeno_medium_tcp6,
+ Runtime,
inet6,
gen, false,
gen, once,
@@ -12104,8 +12198,10 @@ ttest_sgenf_cgeno_large_tcp4(suite) ->
[];
ttest_sgenf_cgeno_large_tcp4(doc) ->
[];
-ttest_sgenf_cgeno_large_tcp4(_Config) when is_list(_Config) ->
+ttest_sgenf_cgeno_large_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgenf_cgeno_large_tcp4,
+ Runtime,
inet,
gen, false,
gen, once,
@@ -12126,8 +12222,10 @@ ttest_sgenf_cgeno_large_tcp6(suite) ->
[];
ttest_sgenf_cgeno_large_tcp6(doc) ->
[];
-ttest_sgenf_cgeno_large_tcp6(_Config) when is_list(_Config) ->
+ttest_sgenf_cgeno_large_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgenf_cgeno_large_tcp6,
+ Runtime,
inet6,
gen, false,
gen, once,
@@ -12148,8 +12246,10 @@ ttest_sgenf_cgent_small_tcp4(suite) ->
[];
ttest_sgenf_cgent_small_tcp4(doc) ->
[];
-ttest_sgenf_cgent_small_tcp4(_Config) when is_list(_Config) ->
+ttest_sgenf_cgent_small_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgenf_cgent_small_tcp4,
+ Runtime,
inet,
gen, false,
gen, true,
@@ -12170,8 +12270,10 @@ ttest_sgenf_cgent_small_tcp6(suite) ->
[];
ttest_sgenf_cgent_small_tcp6(doc) ->
[];
-ttest_sgenf_cgent_small_tcp6(_Config) when is_list(_Config) ->
+ttest_sgenf_cgent_small_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgenf_cgeno_small_tcp6,
+ Runtime,
inet6,
gen, false,
gen, true,
@@ -12192,8 +12294,10 @@ ttest_sgenf_cgent_medium_tcp4(suite) ->
[];
ttest_sgenf_cgent_medium_tcp4(doc) ->
[];
-ttest_sgenf_cgent_medium_tcp4(_Config) when is_list(_Config) ->
+ttest_sgenf_cgent_medium_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgenf_cgent_medium_tcp4,
+ Runtime,
inet,
gen, false,
gen, true,
@@ -12214,8 +12318,10 @@ ttest_sgenf_cgent_medium_tcp6(suite) ->
[];
ttest_sgenf_cgent_medium_tcp6(doc) ->
[];
-ttest_sgenf_cgent_medium_tcp6(_Config) when is_list(_Config) ->
+ttest_sgenf_cgent_medium_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgenf_cgent_medium_tcp6,
+ Runtime,
inet6,
gen, false,
gen, true,
@@ -12236,8 +12342,10 @@ ttest_sgenf_cgent_large_tcp4(suite) ->
[];
ttest_sgenf_cgent_large_tcp4(doc) ->
[];
-ttest_sgenf_cgent_large_tcp4(_Config) when is_list(_Config) ->
+ttest_sgenf_cgent_large_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgenf_cgent_large_tcp4,
+ Runtime,
inet,
gen, false,
gen, true,
@@ -12258,8 +12366,10 @@ ttest_sgenf_cgent_large_tcp6(suite) ->
[];
ttest_sgenf_cgent_large_tcp6(doc) ->
[];
-ttest_sgenf_cgent_large_tcp6(_Config) when is_list(_Config) ->
+ttest_sgenf_cgent_large_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgenf_cgent_large_tcp6,
+ Runtime,
inet6,
gen, false,
gen, true,
@@ -12280,8 +12390,10 @@ ttest_sgenf_csockf_small_tcp4(suite) ->
[];
ttest_sgenf_csockf_small_tcp4(doc) ->
[];
-ttest_sgenf_csockf_small_tcp4(_Config) when is_list(_Config) ->
+ttest_sgenf_csockf_small_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgenf_csockf_small_tcp4,
+ Runtime,
inet,
gen, false,
sock, false,
@@ -12302,8 +12414,10 @@ ttest_sgenf_csockf_small_tcp6(suite) ->
[];
ttest_sgenf_csockf_small_tcp6(doc) ->
[];
-ttest_sgenf_csockf_small_tcp6(_Config) when is_list(_Config) ->
+ttest_sgenf_csockf_small_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgenf_csockf_small_tcp6,
+ Runtime,
inet6,
gen, false,
sock, false,
@@ -12324,8 +12438,10 @@ ttest_sgenf_csockf_medium_tcp4(suite) ->
[];
ttest_sgenf_csockf_medium_tcp4(doc) ->
[];
-ttest_sgenf_csockf_medium_tcp4(_Config) when is_list(_Config) ->
+ttest_sgenf_csockf_medium_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgenf_csockf_medium_tcp4,
+ Runtime,
inet,
gen, false,
sock, false,
@@ -12346,8 +12462,10 @@ ttest_sgenf_csockf_medium_tcp6(suite) ->
[];
ttest_sgenf_csockf_medium_tcp6(doc) ->
[];
-ttest_sgenf_csockf_medium_tcp6(_Config) when is_list(_Config) ->
+ttest_sgenf_csockf_medium_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgenf_csockf_medium_tcp6,
+ Runtime,
inet6,
gen, false,
sock, false,
@@ -12368,8 +12486,10 @@ ttest_sgenf_csockf_large_tcp4(suite) ->
[];
ttest_sgenf_csockf_large_tcp4(doc) ->
[];
-ttest_sgenf_csockf_large_tcp4(_Config) when is_list(_Config) ->
+ttest_sgenf_csockf_large_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgenf_csockf_large_tcp4,
+ Runtime,
inet,
gen, false,
sock, false,
@@ -12390,8 +12510,10 @@ ttest_sgenf_csockf_large_tcp6(suite) ->
[];
ttest_sgenf_csockf_large_tcp6(doc) ->
[];
-ttest_sgenf_csockf_large_tcp6(_Config) when is_list(_Config) ->
+ttest_sgenf_csockf_large_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgenf_csockf_large_tcp6,
+ Runtime,
inet6,
gen, false,
sock, false,
@@ -12412,8 +12534,10 @@ ttest_sgenf_csocko_small_tcp4(suite) ->
[];
ttest_sgenf_csocko_small_tcp4(doc) ->
[];
-ttest_sgenf_csocko_small_tcp4(_Config) when is_list(_Config) ->
+ttest_sgenf_csocko_small_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgenf_csocko_small_tcp4,
+ Runtime,
inet,
gen, false,
sock, once,
@@ -12434,8 +12558,10 @@ ttest_sgenf_csocko_small_tcp6(suite) ->
[];
ttest_sgenf_csocko_small_tcp6(doc) ->
[];
-ttest_sgenf_csocko_small_tcp6(_Config) when is_list(_Config) ->
+ttest_sgenf_csocko_small_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgenf_csocko_small_tcp6,
+ Runtime,
inet6,
gen, false,
sock, once,
@@ -12456,8 +12582,10 @@ ttest_sgenf_csocko_medium_tcp4(suite) ->
[];
ttest_sgenf_csocko_medium_tcp4(doc) ->
[];
-ttest_sgenf_csocko_medium_tcp4(_Config) when is_list(_Config) ->
+ttest_sgenf_csocko_medium_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgenf_csocko_medium_tcp4,
+ Runtime,
inet,
gen, false,
sock, once,
@@ -12478,8 +12606,10 @@ ttest_sgenf_csocko_medium_tcp6(suite) ->
[];
ttest_sgenf_csocko_medium_tcp6(doc) ->
[];
-ttest_sgenf_csocko_medium_tcp6(_Config) when is_list(_Config) ->
+ttest_sgenf_csocko_medium_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgenf_csocko_medium_tcp6,
+ Runtime,
inet6,
gen, false,
sock, once,
@@ -12500,8 +12630,10 @@ ttest_sgenf_csocko_large_tcp4(suite) ->
[];
ttest_sgenf_csocko_large_tcp4(doc) ->
[];
-ttest_sgenf_csocko_large_tcp4(_Config) when is_list(_Config) ->
+ttest_sgenf_csocko_large_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgenf_csocko_large_tcp4,
+ Runtime,
inet,
gen, false,
sock, once,
@@ -12522,8 +12654,10 @@ ttest_sgenf_csocko_large_tcp6(suite) ->
[];
ttest_sgenf_csocko_large_tcp6(doc) ->
[];
-ttest_sgenf_csocko_large_tcp6(_Config) when is_list(_Config) ->
+ttest_sgenf_csocko_large_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgenf_csocko_large_tcp6,
+ Runtime,
inet6,
gen, false,
sock, once,
@@ -12544,8 +12678,10 @@ ttest_sgenf_csockt_small_tcp4(suite) ->
[];
ttest_sgenf_csockt_small_tcp4(doc) ->
[];
-ttest_sgenf_csockt_small_tcp4(_Config) when is_list(_Config) ->
+ttest_sgenf_csockt_small_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgenf_csockt_small_tcp4,
+ Runtime,
inet,
gen, false,
sock, true,
@@ -12566,8 +12702,10 @@ ttest_sgenf_csockt_small_tcp6(suite) ->
[];
ttest_sgenf_csockt_small_tcp6(doc) ->
[];
-ttest_sgenf_csockt_small_tcp6(_Config) when is_list(_Config) ->
+ttest_sgenf_csockt_small_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgenf_csocko_small_tcp6,
+ Runtime,
inet6,
gen, false,
sock, true,
@@ -12588,8 +12726,10 @@ ttest_sgenf_csockt_medium_tcp4(suite) ->
[];
ttest_sgenf_csockt_medium_tcp4(doc) ->
[];
-ttest_sgenf_csockt_medium_tcp4(_Config) when is_list(_Config) ->
+ttest_sgenf_csockt_medium_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgenf_csockt_medium_tcp4,
+ Runtime,
inet,
gen, false,
sock, true,
@@ -12610,8 +12750,10 @@ ttest_sgenf_csockt_medium_tcp6(suite) ->
[];
ttest_sgenf_csockt_medium_tcp6(doc) ->
[];
-ttest_sgenf_csockt_medium_tcp6(_Config) when is_list(_Config) ->
+ttest_sgenf_csockt_medium_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgenf_csockt_medium_tcp6,
+ Runtime,
inet6,
gen, false,
sock, true,
@@ -12632,8 +12774,10 @@ ttest_sgenf_csockt_large_tcp4(suite) ->
[];
ttest_sgenf_csockt_large_tcp4(doc) ->
[];
-ttest_sgenf_csockt_large_tcp4(_Config) when is_list(_Config) ->
+ttest_sgenf_csockt_large_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgenf_csockt_large_tcp4,
+ Runtime,
inet,
gen, false,
sock, true,
@@ -12654,8 +12798,10 @@ ttest_sgenf_csockt_large_tcp6(suite) ->
[];
ttest_sgenf_csockt_large_tcp6(doc) ->
[];
-ttest_sgenf_csockt_large_tcp6(_Config) when is_list(_Config) ->
+ttest_sgenf_csockt_large_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgenf_csockt_large_tcp6,
+ Runtime,
inet6,
gen, false,
sock, true,
@@ -12676,8 +12822,10 @@ ttest_sgeno_cgenf_small_tcp4(suite) ->
[];
ttest_sgeno_cgenf_small_tcp4(doc) ->
[];
-ttest_sgeno_cgenf_small_tcp4(_Config) when is_list(_Config) ->
+ttest_sgeno_cgenf_small_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgeno_cgenf_small_tcp4,
+ Runtime,
inet,
gen, once,
gen, false,
@@ -12698,8 +12846,10 @@ ttest_sgeno_cgenf_small_tcp6(suite) ->
[];
ttest_sgeno_cgenf_small_tcp6(doc) ->
[];
-ttest_sgeno_cgenf_small_tcp6(_Config) when is_list(_Config) ->
+ttest_sgeno_cgenf_small_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgeno_cgenf_small_tcp6,
+ Runtime,
inet6,
gen, once,
gen, false,
@@ -12720,8 +12870,10 @@ ttest_sgeno_cgenf_medium_tcp4(suite) ->
[];
ttest_sgeno_cgenf_medium_tcp4(doc) ->
[];
-ttest_sgeno_cgenf_medium_tcp4(_Config) when is_list(_Config) ->
+ttest_sgeno_cgenf_medium_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgeno_cgenf_medium_tcp4,
+ Runtime,
inet,
gen, once,
gen, false,
@@ -12742,8 +12894,10 @@ ttest_sgeno_cgenf_medium_tcp6(suite) ->
[];
ttest_sgeno_cgenf_medium_tcp6(doc) ->
[];
-ttest_sgeno_cgenf_medium_tcp6(_Config) when is_list(_Config) ->
+ttest_sgeno_cgenf_medium_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgeno_cgenf_medium_tcp6,
+ Runtime,
inet6,
gen, once,
gen, false,
@@ -12764,8 +12918,10 @@ ttest_sgeno_cgenf_large_tcp4(suite) ->
[];
ttest_sgeno_cgenf_large_tcp4(doc) ->
[];
-ttest_sgeno_cgenf_large_tcp4(_Config) when is_list(_Config) ->
+ttest_sgeno_cgenf_large_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgeno_cgenf_large_tcp4,
+ Runtime,
inet,
gen, once,
gen, false,
@@ -12786,8 +12942,10 @@ ttest_sgeno_cgenf_large_tcp6(suite) ->
[];
ttest_sgeno_cgenf_large_tcp6(doc) ->
[];
-ttest_sgeno_cgenf_large_tcp6(_Config) when is_list(_Config) ->
+ttest_sgeno_cgenf_large_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgeno_cgenf_large_tcp6,
+ Runtime,
inet6,
gen, once,
gen, false,
@@ -12808,8 +12966,10 @@ ttest_sgeno_cgeno_small_tcp4(suite) ->
[];
ttest_sgeno_cgeno_small_tcp4(doc) ->
[];
-ttest_sgeno_cgeno_small_tcp4(_Config) when is_list(_Config) ->
+ttest_sgeno_cgeno_small_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgeno_cgeno_small_tcp4,
+ Runtime,
inet,
gen, once,
gen, once,
@@ -12830,8 +12990,10 @@ ttest_sgeno_cgeno_small_tcp6(suite) ->
[];
ttest_sgeno_cgeno_small_tcp6(doc) ->
[];
-ttest_sgeno_cgeno_small_tcp6(_Config) when is_list(_Config) ->
+ttest_sgeno_cgeno_small_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgeno_cgeno_small_tcp6,
+ Runtime,
inet6,
gen, once,
gen, once,
@@ -12852,8 +13014,10 @@ ttest_sgeno_cgeno_medium_tcp4(suite) ->
[];
ttest_sgeno_cgeno_medium_tcp4(doc) ->
[];
-ttest_sgeno_cgeno_medium_tcp4(_Config) when is_list(_Config) ->
+ttest_sgeno_cgeno_medium_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgeno_cgeno_medium_tcp4,
+ Runtime,
inet,
gen, once,
gen, once,
@@ -12874,8 +13038,10 @@ ttest_sgeno_cgeno_medium_tcp6(suite) ->
[];
ttest_sgeno_cgeno_medium_tcp6(doc) ->
[];
-ttest_sgeno_cgeno_medium_tcp6(_Config) when is_list(_Config) ->
+ttest_sgeno_cgeno_medium_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgeno_cgeno_medium_tcp6,
+ Runtime,
inet6,
gen, once,
gen, once,
@@ -12896,8 +13062,10 @@ ttest_sgeno_cgeno_large_tcp4(suite) ->
[];
ttest_sgeno_cgeno_large_tcp4(doc) ->
[];
-ttest_sgeno_cgeno_large_tcp4(_Config) when is_list(_Config) ->
+ttest_sgeno_cgeno_large_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgeno_cgeno_large_tcp4,
+ Runtime,
inet,
gen, once,
gen, once,
@@ -12918,8 +13086,10 @@ ttest_sgeno_cgeno_large_tcp6(suite) ->
[];
ttest_sgeno_cgeno_large_tcp6(doc) ->
[];
-ttest_sgeno_cgeno_large_tcp6(_Config) when is_list(_Config) ->
+ttest_sgeno_cgeno_large_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgeno_cgeno_large_tcp6,
+ Runtime,
inet6,
gen, once,
gen, once,
@@ -12940,8 +13110,10 @@ ttest_sgeno_cgent_small_tcp4(suite) ->
[];
ttest_sgeno_cgent_small_tcp4(doc) ->
[];
-ttest_sgeno_cgent_small_tcp4(_Config) when is_list(_Config) ->
+ttest_sgeno_cgent_small_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgeno_cgent_small_tcp4,
+ Runtime,
inet,
gen, once,
gen, true,
@@ -12962,8 +13134,10 @@ ttest_sgeno_cgent_small_tcp6(suite) ->
[];
ttest_sgeno_cgent_small_tcp6(doc) ->
[];
-ttest_sgeno_cgent_small_tcp6(_Config) when is_list(_Config) ->
+ttest_sgeno_cgent_small_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgeno_cgeno_small_tcp6,
+ Runtime,
inet6,
gen, once,
gen, true,
@@ -12984,8 +13158,10 @@ ttest_sgeno_cgent_medium_tcp4(suite) ->
[];
ttest_sgeno_cgent_medium_tcp4(doc) ->
[];
-ttest_sgeno_cgent_medium_tcp4(_Config) when is_list(_Config) ->
+ttest_sgeno_cgent_medium_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgeno_cgent_medium_tcp4,
+ Runtime,
inet,
gen, once,
gen, true,
@@ -13006,8 +13182,10 @@ ttest_sgeno_cgent_medium_tcp6(suite) ->
[];
ttest_sgeno_cgent_medium_tcp6(doc) ->
[];
-ttest_sgeno_cgent_medium_tcp6(_Config) when is_list(_Config) ->
+ttest_sgeno_cgent_medium_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgeno_cgent_medium_tcp6,
+ Runtime,
inet6,
gen, once,
gen, true,
@@ -13028,8 +13206,10 @@ ttest_sgeno_cgent_large_tcp4(suite) ->
[];
ttest_sgeno_cgent_large_tcp4(doc) ->
[];
-ttest_sgeno_cgent_large_tcp4(_Config) when is_list(_Config) ->
+ttest_sgeno_cgent_large_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgeno_cgent_large_tcp4,
+ Runtime,
inet,
gen, once,
gen, true,
@@ -13050,8 +13230,10 @@ ttest_sgeno_cgent_large_tcp6(suite) ->
[];
ttest_sgeno_cgent_large_tcp6(doc) ->
[];
-ttest_sgeno_cgent_large_tcp6(_Config) when is_list(_Config) ->
+ttest_sgeno_cgent_large_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgeno_cgent_large_tcp6,
+ Runtime,
inet6,
gen, once,
gen, true,
@@ -13072,8 +13254,10 @@ ttest_sgeno_csockf_small_tcp4(suite) ->
[];
ttest_sgeno_csockf_small_tcp4(doc) ->
[];
-ttest_sgeno_csockf_small_tcp4(_Config) when is_list(_Config) ->
+ttest_sgeno_csockf_small_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgeno_csockf_small_tcp4,
+ Runtime,
inet,
gen, once,
sock, false,
@@ -13094,8 +13278,10 @@ ttest_sgeno_csockf_small_tcp6(suite) ->
[];
ttest_sgeno_csockf_small_tcp6(doc) ->
[];
-ttest_sgeno_csockf_small_tcp6(_Config) when is_list(_Config) ->
+ttest_sgeno_csockf_small_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgeno_csockf_small_tcp6,
+ Runtime,
inet6,
gen, once,
sock, false,
@@ -13116,8 +13302,10 @@ ttest_sgeno_csockf_medium_tcp4(suite) ->
[];
ttest_sgeno_csockf_medium_tcp4(doc) ->
[];
-ttest_sgeno_csockf_medium_tcp4(_Config) when is_list(_Config) ->
+ttest_sgeno_csockf_medium_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgeno_csockf_medium_tcp4,
+ Runtime,
inet,
gen, once,
sock, false,
@@ -13138,8 +13326,10 @@ ttest_sgeno_csockf_medium_tcp6(suite) ->
[];
ttest_sgeno_csockf_medium_tcp6(doc) ->
[];
-ttest_sgeno_csockf_medium_tcp6(_Config) when is_list(_Config) ->
+ttest_sgeno_csockf_medium_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgeno_csockf_medium_tcp6,
+ Runtime,
inet6,
gen, once,
sock, false,
@@ -13160,8 +13350,10 @@ ttest_sgeno_csockf_large_tcp4(suite) ->
[];
ttest_sgeno_csockf_large_tcp4(doc) ->
[];
-ttest_sgeno_csockf_large_tcp4(_Config) when is_list(_Config) ->
+ttest_sgeno_csockf_large_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgeno_csockf_large_tcp4,
+ Runtime,
inet,
gen, once,
sock, false,
@@ -13182,8 +13374,10 @@ ttest_sgeno_csockf_large_tcp6(suite) ->
[];
ttest_sgeno_csockf_large_tcp6(doc) ->
[];
-ttest_sgeno_csockf_large_tcp6(_Config) when is_list(_Config) ->
+ttest_sgeno_csockf_large_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgeno_csockf_large_tcp6,
+ Runtime,
inet6,
gen, once,
sock, false,
@@ -13204,8 +13398,10 @@ ttest_sgeno_csocko_small_tcp4(suite) ->
[];
ttest_sgeno_csocko_small_tcp4(doc) ->
[];
-ttest_sgeno_csocko_small_tcp4(_Config) when is_list(_Config) ->
+ttest_sgeno_csocko_small_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgeno_csocko_small_tcp4,
+ Runtime,
inet,
gen, once,
sock, once,
@@ -13226,8 +13422,10 @@ ttest_sgeno_csocko_small_tcp6(suite) ->
[];
ttest_sgeno_csocko_small_tcp6(doc) ->
[];
-ttest_sgeno_csocko_small_tcp6(_Config) when is_list(_Config) ->
+ttest_sgeno_csocko_small_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgeno_csocko_small_tcp6,
+ Runtime,
inet6,
gen, once,
sock, once,
@@ -13248,8 +13446,10 @@ ttest_sgeno_csocko_medium_tcp4(suite) ->
[];
ttest_sgeno_csocko_medium_tcp4(doc) ->
[];
-ttest_sgeno_csocko_medium_tcp4(_Config) when is_list(_Config) ->
+ttest_sgeno_csocko_medium_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgeno_csocko_medium_tcp4,
+ Runtime,
inet,
gen, once,
sock, once,
@@ -13270,8 +13470,10 @@ ttest_sgeno_csocko_medium_tcp6(suite) ->
[];
ttest_sgeno_csocko_medium_tcp6(doc) ->
[];
-ttest_sgeno_csocko_medium_tcp6(_Config) when is_list(_Config) ->
+ttest_sgeno_csocko_medium_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgeno_csocko_medium_tcp6,
+ Runtime,
inet6,
gen, once,
sock, once,
@@ -13292,8 +13494,10 @@ ttest_sgeno_csocko_large_tcp4(suite) ->
[];
ttest_sgeno_csocko_large_tcp4(doc) ->
[];
-ttest_sgeno_csocko_large_tcp4(_Config) when is_list(_Config) ->
+ttest_sgeno_csocko_large_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgeno_csocko_large_tcp4,
+ Runtime,
inet,
gen, once,
sock, once,
@@ -13314,8 +13518,10 @@ ttest_sgeno_csocko_large_tcp6(suite) ->
[];
ttest_sgeno_csocko_large_tcp6(doc) ->
[];
-ttest_sgeno_csocko_large_tcp6(_Config) when is_list(_Config) ->
+ttest_sgeno_csocko_large_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgeno_csocko_large_tcp6,
+ Runtime,
inet6,
gen, once,
sock, once,
@@ -13336,8 +13542,10 @@ ttest_sgeno_csockt_small_tcp4(suite) ->
[];
ttest_sgeno_csockt_small_tcp4(doc) ->
[];
-ttest_sgeno_csockt_small_tcp4(_Config) when is_list(_Config) ->
+ttest_sgeno_csockt_small_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgeno_csockt_small_tcp4,
+ Runtime,
inet,
gen, once,
sock, true,
@@ -13358,8 +13566,10 @@ ttest_sgeno_csockt_small_tcp6(suite) ->
[];
ttest_sgeno_csockt_small_tcp6(doc) ->
[];
-ttest_sgeno_csockt_small_tcp6(_Config) when is_list(_Config) ->
+ttest_sgeno_csockt_small_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgeno_csocko_small_tcp6,
+ Runtime,
inet6,
gen, once,
sock, true,
@@ -13380,8 +13590,10 @@ ttest_sgeno_csockt_medium_tcp4(suite) ->
[];
ttest_sgeno_csockt_medium_tcp4(doc) ->
[];
-ttest_sgeno_csockt_medium_tcp4(_Config) when is_list(_Config) ->
+ttest_sgeno_csockt_medium_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgeno_csockt_medium_tcp4,
+ Runtime,
inet,
gen, once,
sock, true,
@@ -13402,8 +13614,10 @@ ttest_sgeno_csockt_medium_tcp6(suite) ->
[];
ttest_sgeno_csockt_medium_tcp6(doc) ->
[];
-ttest_sgeno_csockt_medium_tcp6(_Config) when is_list(_Config) ->
+ttest_sgeno_csockt_medium_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgeno_csockt_medium_tcp6,
+ Runtime,
inet6,
gen, once,
sock, true,
@@ -13424,8 +13638,10 @@ ttest_sgeno_csockt_large_tcp4(suite) ->
[];
ttest_sgeno_csockt_large_tcp4(doc) ->
[];
-ttest_sgeno_csockt_large_tcp4(_Config) when is_list(_Config) ->
+ttest_sgeno_csockt_large_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgeno_csockt_large_tcp4,
+ Runtime,
inet,
gen, once,
sock, true,
@@ -13446,8 +13662,10 @@ ttest_sgeno_csockt_large_tcp6(suite) ->
[];
ttest_sgeno_csockt_large_tcp6(doc) ->
[];
-ttest_sgeno_csockt_large_tcp6(_Config) when is_list(_Config) ->
+ttest_sgeno_csockt_large_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgeno_csockt_large_tcp6,
+ Runtime,
inet6,
gen, once,
sock, true,
@@ -13468,8 +13686,10 @@ ttest_sgent_cgenf_small_tcp4(suite) ->
[];
ttest_sgent_cgenf_small_tcp4(doc) ->
[];
-ttest_sgent_cgenf_small_tcp4(_Config) when is_list(_Config) ->
+ttest_sgent_cgenf_small_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgent_cgenf_small_tcp4,
+ Runtime,
inet,
gen, true,
gen, false,
@@ -13490,8 +13710,10 @@ ttest_sgent_cgenf_small_tcp6(suite) ->
[];
ttest_sgent_cgenf_small_tcp6(doc) ->
[];
-ttest_sgent_cgenf_small_tcp6(_Config) when is_list(_Config) ->
+ttest_sgent_cgenf_small_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgent_cgenf_small_tcp6,
+ Runtime,
inet6,
gen, true,
gen, false,
@@ -13512,8 +13734,10 @@ ttest_sgent_cgenf_medium_tcp4(suite) ->
[];
ttest_sgent_cgenf_medium_tcp4(doc) ->
[];
-ttest_sgent_cgenf_medium_tcp4(_Config) when is_list(_Config) ->
+ttest_sgent_cgenf_medium_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgent_cgenf_medium_tcp4,
+ Runtime,
inet,
gen, true,
gen, false,
@@ -13534,8 +13758,10 @@ ttest_sgent_cgenf_medium_tcp6(suite) ->
[];
ttest_sgent_cgenf_medium_tcp6(doc) ->
[];
-ttest_sgent_cgenf_medium_tcp6(_Config) when is_list(_Config) ->
+ttest_sgent_cgenf_medium_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgent_cgenf_medium_tcp6,
+ Runtime,
inet6,
gen, true,
gen, false,
@@ -13556,8 +13782,10 @@ ttest_sgent_cgenf_large_tcp4(suite) ->
[];
ttest_sgent_cgenf_large_tcp4(doc) ->
[];
-ttest_sgent_cgenf_large_tcp4(_Config) when is_list(_Config) ->
+ttest_sgent_cgenf_large_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgent_cgenf_large_tcp4,
+ Runtime,
inet,
gen, true,
gen, false,
@@ -13578,8 +13806,10 @@ ttest_sgent_cgenf_large_tcp6(suite) ->
[];
ttest_sgent_cgenf_large_tcp6(doc) ->
[];
-ttest_sgent_cgenf_large_tcp6(_Config) when is_list(_Config) ->
+ttest_sgent_cgenf_large_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgent_cgenf_large_tcp6,
+ Runtime,
inet6,
gen, true,
gen, false,
@@ -13600,8 +13830,10 @@ ttest_sgent_cgeno_small_tcp4(suite) ->
[];
ttest_sgent_cgeno_small_tcp4(doc) ->
[];
-ttest_sgent_cgeno_small_tcp4(_Config) when is_list(_Config) ->
+ttest_sgent_cgeno_small_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgent_cgeno_small_tcp4,
+ Runtime,
inet,
gen, true,
gen, once,
@@ -13622,8 +13854,10 @@ ttest_sgent_cgeno_small_tcp6(suite) ->
[];
ttest_sgent_cgeno_small_tcp6(doc) ->
[];
-ttest_sgent_cgeno_small_tcp6(_Config) when is_list(_Config) ->
+ttest_sgent_cgeno_small_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgent_cgeno_small_tcp6,
+ Runtime,
inet6,
gen, true,
gen, once,
@@ -13644,8 +13878,10 @@ ttest_sgent_cgeno_medium_tcp4(suite) ->
[];
ttest_sgent_cgeno_medium_tcp4(doc) ->
[];
-ttest_sgent_cgeno_medium_tcp4(_Config) when is_list(_Config) ->
+ttest_sgent_cgeno_medium_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgent_cgeno_medium_tcp4,
+ Runtime,
inet,
gen, true,
gen, once,
@@ -13666,8 +13902,10 @@ ttest_sgent_cgeno_medium_tcp6(suite) ->
[];
ttest_sgent_cgeno_medium_tcp6(doc) ->
[];
-ttest_sgent_cgeno_medium_tcp6(_Config) when is_list(_Config) ->
+ttest_sgent_cgeno_medium_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgent_cgeno_medium_tcp6,
+ Runtime,
inet6,
gen, true,
gen, once,
@@ -13688,8 +13926,10 @@ ttest_sgent_cgeno_large_tcp4(suite) ->
[];
ttest_sgent_cgeno_large_tcp4(doc) ->
[];
-ttest_sgent_cgeno_large_tcp4(_Config) when is_list(_Config) ->
+ttest_sgent_cgeno_large_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgent_cgeno_large_tcp4,
+ Runtime,
inet,
gen, true,
gen, once,
@@ -13710,8 +13950,10 @@ ttest_sgent_cgeno_large_tcp6(suite) ->
[];
ttest_sgent_cgeno_large_tcp6(doc) ->
[];
-ttest_sgent_cgeno_large_tcp6(_Config) when is_list(_Config) ->
+ttest_sgent_cgeno_large_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgent_cgeno_large_tcp6,
+ Runtime,
inet6,
gen, true,
gen, once,
@@ -13732,8 +13974,10 @@ ttest_sgent_cgent_small_tcp4(suite) ->
[];
ttest_sgent_cgent_small_tcp4(doc) ->
[];
-ttest_sgent_cgent_small_tcp4(_Config) when is_list(_Config) ->
+ttest_sgent_cgent_small_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgent_cgent_small_tcp4,
+ Runtime,
inet,
gen, true,
gen, true,
@@ -13754,8 +13998,10 @@ ttest_sgent_cgent_small_tcp6(suite) ->
[];
ttest_sgent_cgent_small_tcp6(doc) ->
[];
-ttest_sgent_cgent_small_tcp6(_Config) when is_list(_Config) ->
+ttest_sgent_cgent_small_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgent_cgeno_small_tcp6,
+ Runtime,
inet6,
gen, true,
gen, true,
@@ -13776,8 +14022,10 @@ ttest_sgent_cgent_medium_tcp4(suite) ->
[];
ttest_sgent_cgent_medium_tcp4(doc) ->
["Server(gen,true), Client(gen,true), Domain=inet, msg=medium"];
-ttest_sgent_cgent_medium_tcp4(_Config) when is_list(_Config) ->
+ttest_sgent_cgent_medium_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgent_cgent_medium_tcp4,
+ Runtime,
inet,
gen, true,
gen, true,
@@ -13798,8 +14046,10 @@ ttest_sgent_cgent_medium_tcp6(suite) ->
[];
ttest_sgent_cgent_medium_tcp6(doc) ->
["Server(gen,true), Client(gen,true), Domain=inet6, msg=medium"];
-ttest_sgent_cgent_medium_tcp6(_Config) when is_list(_Config) ->
+ttest_sgent_cgent_medium_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgent_cgent_medium_tcp6,
+ Runtime,
inet6,
gen, true,
gen, true,
@@ -13820,8 +14070,10 @@ ttest_sgent_cgent_large_tcp4(suite) ->
[];
ttest_sgent_cgent_large_tcp4(doc) ->
["Server(gen,true), Client(gen,true), Domain=inet, msg=large"];
-ttest_sgent_cgent_large_tcp4(_Config) when is_list(_Config) ->
+ttest_sgent_cgent_large_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgent_cgent_large_tcp4,
+ Runtime,
inet,
gen, true,
gen, true,
@@ -13842,8 +14094,10 @@ ttest_sgent_cgent_large_tcp6(suite) ->
[];
ttest_sgent_cgent_large_tcp6(doc) ->
["Server(gen,true), Client(gen,true), Domain=inet6, msg=large"];
-ttest_sgent_cgent_large_tcp6(_Config) when is_list(_Config) ->
+ttest_sgent_cgent_large_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgent_cgent_large_tcp6,
+ Runtime,
inet6,
gen, true,
gen, true,
@@ -13864,8 +14118,10 @@ ttest_sgent_csockf_small_tcp4(suite) ->
[];
ttest_sgent_csockf_small_tcp4(doc) ->
[];
-ttest_sgent_csockf_small_tcp4(_Config) when is_list(_Config) ->
+ttest_sgent_csockf_small_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgent_csockf_small_tcp4,
+ Runtime,
inet,
gen, true,
sock, false,
@@ -13886,8 +14142,10 @@ ttest_sgent_csockf_small_tcp6(suite) ->
[];
ttest_sgent_csockf_small_tcp6(doc) ->
[];
-ttest_sgent_csockf_small_tcp6(_Config) when is_list(_Config) ->
+ttest_sgent_csockf_small_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgent_csockf_small_tcp6,
+ Runtime,
inet6,
gen, true,
sock, false,
@@ -13908,8 +14166,10 @@ ttest_sgent_csockf_medium_tcp4(suite) ->
[];
ttest_sgent_csockf_medium_tcp4(doc) ->
[];
-ttest_sgent_csockf_medium_tcp4(_Config) when is_list(_Config) ->
+ttest_sgent_csockf_medium_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgent_csockf_medium_tcp4,
+ Runtime,
inet,
gen, true,
sock, false,
@@ -13930,8 +14190,10 @@ ttest_sgent_csockf_medium_tcp6(suite) ->
[];
ttest_sgent_csockf_medium_tcp6(doc) ->
[];
-ttest_sgent_csockf_medium_tcp6(_Config) when is_list(_Config) ->
+ttest_sgent_csockf_medium_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgent_csockf_medium_tcp6,
+ Runtime,
inet6,
gen, true,
sock, false,
@@ -13952,8 +14214,10 @@ ttest_sgent_csockf_large_tcp4(suite) ->
[];
ttest_sgent_csockf_large_tcp4(doc) ->
[];
-ttest_sgent_csockf_large_tcp4(_Config) when is_list(_Config) ->
+ttest_sgent_csockf_large_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgent_csockf_large_tcp4,
+ Runtime,
inet,
gen, true,
sock, false,
@@ -13974,8 +14238,10 @@ ttest_sgent_csockf_large_tcp6(suite) ->
[];
ttest_sgent_csockf_large_tcp6(doc) ->
[];
-ttest_sgent_csockf_large_tcp6(_Config) when is_list(_Config) ->
+ttest_sgent_csockf_large_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgent_csockf_large_tcp6,
+ Runtime,
inet6,
gen, true,
sock, false,
@@ -13996,8 +14262,10 @@ ttest_sgent_csocko_small_tcp4(suite) ->
[];
ttest_sgent_csocko_small_tcp4(doc) ->
[];
-ttest_sgent_csocko_small_tcp4(_Config) when is_list(_Config) ->
+ttest_sgent_csocko_small_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgent_csocko_small_tcp4,
+ Runtime,
inet,
gen, true,
sock, once,
@@ -14018,8 +14286,10 @@ ttest_sgent_csocko_small_tcp6(suite) ->
[];
ttest_sgent_csocko_small_tcp6(doc) ->
[];
-ttest_sgent_csocko_small_tcp6(_Config) when is_list(_Config) ->
+ttest_sgent_csocko_small_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgent_csocko_small_tcp6,
+ Runtime,
inet6,
gen, true,
sock, once,
@@ -14040,8 +14310,10 @@ ttest_sgent_csocko_medium_tcp4(suite) ->
[];
ttest_sgent_csocko_medium_tcp4(doc) ->
[];
-ttest_sgent_csocko_medium_tcp4(_Config) when is_list(_Config) ->
+ttest_sgent_csocko_medium_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgent_csocko_medium_tcp4,
+ Runtime,
inet,
gen, true,
sock, once,
@@ -14062,8 +14334,10 @@ ttest_sgent_csocko_medium_tcp6(suite) ->
[];
ttest_sgent_csocko_medium_tcp6(doc) ->
[];
-ttest_sgent_csocko_medium_tcp6(_Config) when is_list(_Config) ->
+ttest_sgent_csocko_medium_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgent_csocko_medium_tcp6,
+ Runtime,
inet6,
gen, true,
sock, once,
@@ -14084,8 +14358,10 @@ ttest_sgent_csocko_large_tcp4(suite) ->
[];
ttest_sgent_csocko_large_tcp4(doc) ->
[];
-ttest_sgent_csocko_large_tcp4(_Config) when is_list(_Config) ->
+ttest_sgent_csocko_large_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgent_csocko_large_tcp4,
+ Runtime,
inet,
gen, true,
sock, once,
@@ -14106,8 +14382,10 @@ ttest_sgent_csocko_large_tcp6(suite) ->
[];
ttest_sgent_csocko_large_tcp6(doc) ->
[];
-ttest_sgent_csocko_large_tcp6(_Config) when is_list(_Config) ->
+ttest_sgent_csocko_large_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgent_csocko_large_tcp6,
+ Runtime,
inet6,
gen, true,
sock, once,
@@ -14128,8 +14406,10 @@ ttest_sgent_csockt_small_tcp4(suite) ->
[];
ttest_sgent_csockt_small_tcp4(doc) ->
[];
-ttest_sgent_csockt_small_tcp4(_Config) when is_list(_Config) ->
+ttest_sgent_csockt_small_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgent_csockt_small_tcp4,
+ Runtime,
inet,
gen, true,
sock, true,
@@ -14150,8 +14430,10 @@ ttest_sgent_csockt_small_tcp6(suite) ->
[];
ttest_sgent_csockt_small_tcp6(doc) ->
[];
-ttest_sgent_csockt_small_tcp6(_Config) when is_list(_Config) ->
+ttest_sgent_csockt_small_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgent_csocko_small_tcp6,
+ Runtime,
inet6,
gen, true,
sock, true,
@@ -14172,8 +14454,10 @@ ttest_sgent_csockt_medium_tcp4(suite) ->
[];
ttest_sgent_csockt_medium_tcp4(doc) ->
[];
-ttest_sgent_csockt_medium_tcp4(_Config) when is_list(_Config) ->
+ttest_sgent_csockt_medium_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgent_csockt_medium_tcp4,
+ Runtime,
inet,
gen, true,
sock, true,
@@ -14194,8 +14478,10 @@ ttest_sgent_csockt_medium_tcp6(suite) ->
[];
ttest_sgent_csockt_medium_tcp6(doc) ->
[];
-ttest_sgent_csockt_medium_tcp6(_Config) when is_list(_Config) ->
+ttest_sgent_csockt_medium_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgent_csockt_medium_tcp6,
+ Runtime,
inet6,
gen, true,
sock, true,
@@ -14216,8 +14502,10 @@ ttest_sgent_csockt_large_tcp4(suite) ->
[];
ttest_sgent_csockt_large_tcp4(doc) ->
[];
-ttest_sgent_csockt_large_tcp4(_Config) when is_list(_Config) ->
+ttest_sgent_csockt_large_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgent_csockt_large_tcp4,
+ Runtime,
inet,
gen, true,
sock, true,
@@ -14238,8 +14526,10 @@ ttest_sgent_csockt_large_tcp6(suite) ->
[];
ttest_sgent_csockt_large_tcp6(doc) ->
[];
-ttest_sgent_csockt_large_tcp6(_Config) when is_list(_Config) ->
+ttest_sgent_csockt_large_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_sgent_csockt_large_tcp6,
+ Runtime,
inet6,
gen, true,
sock, true,
@@ -14260,8 +14550,10 @@ ttest_ssockf_cgenf_small_tcp4(suite) ->
[];
ttest_ssockf_cgenf_small_tcp4(doc) ->
[];
-ttest_ssockf_cgenf_small_tcp4(_Config) when is_list(_Config) ->
+ttest_ssockf_cgenf_small_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssockf_cgenf_small_tcp4,
+ Runtime,
inet,
sock, false,
gen, false,
@@ -14282,8 +14574,10 @@ ttest_ssockf_cgenf_small_tcp6(suite) ->
[];
ttest_ssockf_cgenf_small_tcp6(doc) ->
[];
-ttest_ssockf_cgenf_small_tcp6(_Config) when is_list(_Config) ->
+ttest_ssockf_cgenf_small_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssockf_cgenf_small_tcp6,
+ Runtime,
inet6,
sock, false,
gen, false,
@@ -14304,8 +14598,10 @@ ttest_ssockf_cgenf_medium_tcp4(suite) ->
[];
ttest_ssockf_cgenf_medium_tcp4(doc) ->
[];
-ttest_ssockf_cgenf_medium_tcp4(_Config) when is_list(_Config) ->
+ttest_ssockf_cgenf_medium_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssockf_cgenf_medium_tcp4,
+ Runtime,
inet,
sock, false,
gen, false,
@@ -14326,8 +14622,10 @@ ttest_ssockf_cgenf_medium_tcp6(suite) ->
[];
ttest_ssockf_cgenf_medium_tcp6(doc) ->
[];
-ttest_ssockf_cgenf_medium_tcp6(_Config) when is_list(_Config) ->
+ttest_ssockf_cgenf_medium_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssockf_cgenf_medium_tcp6,
+ Runtime,
inet6,
sock, false,
gen, false,
@@ -14348,8 +14646,10 @@ ttest_ssockf_cgenf_large_tcp4(suite) ->
[];
ttest_ssockf_cgenf_large_tcp4(doc) ->
[];
-ttest_ssockf_cgenf_large_tcp4(_Config) when is_list(_Config) ->
+ttest_ssockf_cgenf_large_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssockf_cgenf_large_tcp4,
+ Runtime,
inet,
sock, false,
gen, false,
@@ -14370,8 +14670,10 @@ ttest_ssockf_cgenf_large_tcp6(suite) ->
[];
ttest_ssockf_cgenf_large_tcp6(doc) ->
[];
-ttest_ssockf_cgenf_large_tcp6(_Config) when is_list(_Config) ->
+ttest_ssockf_cgenf_large_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssockf_cgenf_large_tcp6,
+ Runtime,
inet6,
sock, false,
gen, false,
@@ -14392,8 +14694,10 @@ ttest_ssockf_cgeno_small_tcp4(suite) ->
[];
ttest_ssockf_cgeno_small_tcp4(doc) ->
[];
-ttest_ssockf_cgeno_small_tcp4(_Config) when is_list(_Config) ->
+ttest_ssockf_cgeno_small_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssockf_cgeno_small_tcp4,
+ Runtime,
inet,
sock, false,
gen, once,
@@ -14414,8 +14718,10 @@ ttest_ssockf_cgeno_small_tcp6(suite) ->
[];
ttest_ssockf_cgeno_small_tcp6(doc) ->
[];
-ttest_ssockf_cgeno_small_tcp6(_Config) when is_list(_Config) ->
+ttest_ssockf_cgeno_small_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssockf_cgeno_small_tcp6,
+ Runtime,
inet6,
sock, false,
gen, once,
@@ -14436,8 +14742,10 @@ ttest_ssockf_cgeno_medium_tcp4(suite) ->
[];
ttest_ssockf_cgeno_medium_tcp4(doc) ->
[];
-ttest_ssockf_cgeno_medium_tcp4(_Config) when is_list(_Config) ->
+ttest_ssockf_cgeno_medium_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssockf_cgeno_medium_tcp4,
+ Runtime,
inet,
sock, false,
gen, once,
@@ -14458,8 +14766,10 @@ ttest_ssockf_cgeno_medium_tcp6(suite) ->
[];
ttest_ssockf_cgeno_medium_tcp6(doc) ->
[];
-ttest_ssockf_cgeno_medium_tcp6(_Config) when is_list(_Config) ->
+ttest_ssockf_cgeno_medium_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssockf_cgeno_medium_tcp6,
+ Runtime,
inet6,
sock, false,
gen, once,
@@ -14480,8 +14790,10 @@ ttest_ssockf_cgeno_large_tcp4(suite) ->
[];
ttest_ssockf_cgeno_large_tcp4(doc) ->
[];
-ttest_ssockf_cgeno_large_tcp4(_Config) when is_list(_Config) ->
+ttest_ssockf_cgeno_large_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssockf_cgeno_large_tcp4,
+ Runtime,
inet,
sock, false,
gen, once,
@@ -14502,8 +14814,10 @@ ttest_ssockf_cgeno_large_tcp6(suite) ->
[];
ttest_ssockf_cgeno_large_tcp6(doc) ->
[];
-ttest_ssockf_cgeno_large_tcp6(_Config) when is_list(_Config) ->
+ttest_ssockf_cgeno_large_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssockf_cgeno_large_tcp6,
+ Runtime,
inet6,
sock, false,
gen, once,
@@ -14524,8 +14838,10 @@ ttest_ssockf_cgent_small_tcp4(suite) ->
[];
ttest_ssockf_cgent_small_tcp4(doc) ->
[];
-ttest_ssockf_cgent_small_tcp4(_Config) when is_list(_Config) ->
+ttest_ssockf_cgent_small_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssockf_cgent_small_tcp4,
+ Runtime,
inet,
sock, false,
gen, true,
@@ -14546,8 +14862,10 @@ ttest_ssockf_cgent_small_tcp6(suite) ->
[];
ttest_ssockf_cgent_small_tcp6(doc) ->
[];
-ttest_ssockf_cgent_small_tcp6(_Config) when is_list(_Config) ->
+ttest_ssockf_cgent_small_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssockf_cgeno_small_tcp6,
+ Runtime,
inet6,
sock, false,
gen, true,
@@ -14568,8 +14886,10 @@ ttest_ssockf_cgent_medium_tcp4(suite) ->
[];
ttest_ssockf_cgent_medium_tcp4(doc) ->
[];
-ttest_ssockf_cgent_medium_tcp4(_Config) when is_list(_Config) ->
+ttest_ssockf_cgent_medium_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssockf_cgent_medium_tcp4,
+ Runtime,
inet,
sock, false,
gen, true,
@@ -14590,8 +14910,10 @@ ttest_ssockf_cgent_medium_tcp6(suite) ->
[];
ttest_ssockf_cgent_medium_tcp6(doc) ->
[];
-ttest_ssockf_cgent_medium_tcp6(_Config) when is_list(_Config) ->
+ttest_ssockf_cgent_medium_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssockf_cgent_medium_tcp6,
+ Runtime,
inet6,
sock, false,
gen, true,
@@ -14612,8 +14934,10 @@ ttest_ssockf_cgent_large_tcp4(suite) ->
[];
ttest_ssockf_cgent_large_tcp4(doc) ->
[];
-ttest_ssockf_cgent_large_tcp4(_Config) when is_list(_Config) ->
+ttest_ssockf_cgent_large_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssockf_cgent_large_tcp4,
+ Runtime,
inet,
sock, false,
gen, true,
@@ -14634,8 +14958,10 @@ ttest_ssockf_cgent_large_tcp6(suite) ->
[];
ttest_ssockf_cgent_large_tcp6(doc) ->
[];
-ttest_ssockf_cgent_large_tcp6(_Config) when is_list(_Config) ->
+ttest_ssockf_cgent_large_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssockf_cgent_large_tcp6,
+ Runtime,
inet6,
sock, false,
gen, true,
@@ -14656,8 +14982,10 @@ ttest_ssockf_csockf_small_tcp4(suite) ->
[];
ttest_ssockf_csockf_small_tcp4(doc) ->
[];
-ttest_ssockf_csockf_small_tcp4(_Config) when is_list(_Config) ->
+ttest_ssockf_csockf_small_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssockf_csockf_small_tcp4,
+ Runtime,
inet,
sock, false,
sock, false,
@@ -14678,8 +15006,10 @@ ttest_ssockf_csockf_small_tcp6(suite) ->
[];
ttest_ssockf_csockf_small_tcp6(doc) ->
[];
-ttest_ssockf_csockf_small_tcp6(_Config) when is_list(_Config) ->
+ttest_ssockf_csockf_small_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssockf_csockf_small_tcp6,
+ Runtime,
inet6,
sock, false,
sock, false,
@@ -14700,8 +15030,10 @@ ttest_ssockf_csockf_medium_tcp4(suite) ->
[];
ttest_ssockf_csockf_medium_tcp4(doc) ->
[];
-ttest_ssockf_csockf_medium_tcp4(_Config) when is_list(_Config) ->
+ttest_ssockf_csockf_medium_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssockf_csockf_medium_tcp4,
+ Runtime,
inet,
sock, false,
sock, false,
@@ -14722,8 +15054,10 @@ ttest_ssockf_csockf_medium_tcp6(suite) ->
[];
ttest_ssockf_csockf_medium_tcp6(doc) ->
[];
-ttest_ssockf_csockf_medium_tcp6(_Config) when is_list(_Config) ->
+ttest_ssockf_csockf_medium_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssockf_csockf_medium_tcp6,
+ Runtime,
inet6,
sock, false,
sock, false,
@@ -14744,8 +15078,10 @@ ttest_ssockf_csockf_large_tcp4(suite) ->
[];
ttest_ssockf_csockf_large_tcp4(doc) ->
[];
-ttest_ssockf_csockf_large_tcp4(_Config) when is_list(_Config) ->
+ttest_ssockf_csockf_large_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssockf_csockf_large_tcp4,
+ Runtime,
inet,
sock, false,
sock, false,
@@ -14766,8 +15102,10 @@ ttest_ssockf_csockf_large_tcp6(suite) ->
[];
ttest_ssockf_csockf_large_tcp6(doc) ->
[];
-ttest_ssockf_csockf_large_tcp6(_Config) when is_list(_Config) ->
+ttest_ssockf_csockf_large_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssockf_csockf_large_tcp6,
+ Runtime,
inet6,
sock, false,
sock, false,
@@ -14788,8 +15126,10 @@ ttest_ssockf_csocko_small_tcp4(suite) ->
[];
ttest_ssockf_csocko_small_tcp4(doc) ->
[];
-ttest_ssockf_csocko_small_tcp4(_Config) when is_list(_Config) ->
+ttest_ssockf_csocko_small_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssockf_csocko_small_tcp4,
+ Runtime,
inet,
sock, false,
sock, once,
@@ -14810,8 +15150,10 @@ ttest_ssockf_csocko_small_tcp6(suite) ->
[];
ttest_ssockf_csocko_small_tcp6(doc) ->
[];
-ttest_ssockf_csocko_small_tcp6(_Config) when is_list(_Config) ->
+ttest_ssockf_csocko_small_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssockf_csocko_small_tcp6,
+ Runtime,
inet6,
sock, false,
sock, once,
@@ -14832,8 +15174,10 @@ ttest_ssockf_csocko_medium_tcp4(suite) ->
[];
ttest_ssockf_csocko_medium_tcp4(doc) ->
[];
-ttest_ssockf_csocko_medium_tcp4(_Config) when is_list(_Config) ->
+ttest_ssockf_csocko_medium_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssockf_csocko_medium_tcp4,
+ Runtime,
inet,
sock, false,
sock, once,
@@ -14854,8 +15198,10 @@ ttest_ssockf_csocko_medium_tcp6(suite) ->
[];
ttest_ssockf_csocko_medium_tcp6(doc) ->
[];
-ttest_ssockf_csocko_medium_tcp6(_Config) when is_list(_Config) ->
+ttest_ssockf_csocko_medium_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssockf_csocko_medium_tcp6,
+ Runtime,
inet6,
sock, false,
sock, once,
@@ -14876,8 +15222,10 @@ ttest_ssockf_csocko_large_tcp4(suite) ->
[];
ttest_ssockf_csocko_large_tcp4(doc) ->
[];
-ttest_ssockf_csocko_large_tcp4(_Config) when is_list(_Config) ->
+ttest_ssockf_csocko_large_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssockf_csocko_large_tcp4,
+ Runtime,
inet,
sock, false,
sock, once,
@@ -14898,8 +15246,10 @@ ttest_ssockf_csocko_large_tcp6(suite) ->
[];
ttest_ssockf_csocko_large_tcp6(doc) ->
[];
-ttest_ssockf_csocko_large_tcp6(_Config) when is_list(_Config) ->
+ttest_ssockf_csocko_large_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssockf_csocko_large_tcp6,
+ Runtime,
inet6,
sock, false,
sock, once,
@@ -14920,8 +15270,10 @@ ttest_ssockf_csockt_small_tcp4(suite) ->
[];
ttest_ssockf_csockt_small_tcp4(doc) ->
[];
-ttest_ssockf_csockt_small_tcp4(_Config) when is_list(_Config) ->
+ttest_ssockf_csockt_small_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssockf_csockt_small_tcp4,
+ Runtime,
inet,
sock, false,
sock, true,
@@ -14942,8 +15294,10 @@ ttest_ssockf_csockt_small_tcp6(suite) ->
[];
ttest_ssockf_csockt_small_tcp6(doc) ->
[];
-ttest_ssockf_csockt_small_tcp6(_Config) when is_list(_Config) ->
+ttest_ssockf_csockt_small_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssockf_csocko_small_tcp6,
+ Runtime,
inet6,
sock, false,
sock, true,
@@ -14964,8 +15318,10 @@ ttest_ssockf_csockt_medium_tcp4(suite) ->
[];
ttest_ssockf_csockt_medium_tcp4(doc) ->
[];
-ttest_ssockf_csockt_medium_tcp4(_Config) when is_list(_Config) ->
+ttest_ssockf_csockt_medium_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssockf_csockt_medium_tcp4,
+ Runtime,
inet,
sock, false,
sock, true,
@@ -14986,8 +15342,10 @@ ttest_ssockf_csockt_medium_tcp6(suite) ->
[];
ttest_ssockf_csockt_medium_tcp6(doc) ->
[];
-ttest_ssockf_csockt_medium_tcp6(_Config) when is_list(_Config) ->
+ttest_ssockf_csockt_medium_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssockf_csockt_medium_tcp6,
+ Runtime,
inet6,
sock, false,
sock, true,
@@ -15008,8 +15366,10 @@ ttest_ssockf_csockt_large_tcp4(suite) ->
[];
ttest_ssockf_csockt_large_tcp4(doc) ->
[];
-ttest_ssockf_csockt_large_tcp4(_Config) when is_list(_Config) ->
+ttest_ssockf_csockt_large_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssockf_csockt_large_tcp4,
+ Runtime,
inet,
sock, false,
sock, true,
@@ -15030,8 +15390,10 @@ ttest_ssockf_csockt_large_tcp6(suite) ->
[];
ttest_ssockf_csockt_large_tcp6(doc) ->
[];
-ttest_ssockf_csockt_large_tcp6(_Config) when is_list(_Config) ->
+ttest_ssockf_csockt_large_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssockf_csockt_large_tcp6,
+ Runtime,
inet6,
sock, false,
sock, true,
@@ -15052,8 +15414,10 @@ ttest_ssocko_cgenf_small_tcp4(suite) ->
[];
ttest_ssocko_cgenf_small_tcp4(doc) ->
[];
-ttest_ssocko_cgenf_small_tcp4(_Config) when is_list(_Config) ->
+ttest_ssocko_cgenf_small_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssocko_cgenf_small_tcp4,
+ Runtime,
inet,
sock, once,
gen, false,
@@ -15074,8 +15438,10 @@ ttest_ssocko_cgenf_small_tcp6(suite) ->
[];
ttest_ssocko_cgenf_small_tcp6(doc) ->
[];
-ttest_ssocko_cgenf_small_tcp6(_Config) when is_list(_Config) ->
+ttest_ssocko_cgenf_small_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssocko_cgenf_small_tcp6,
+ Runtime,
inet6,
sock, once,
gen, false,
@@ -15096,8 +15462,10 @@ ttest_ssocko_cgenf_medium_tcp4(suite) ->
[];
ttest_ssocko_cgenf_medium_tcp4(doc) ->
[];
-ttest_ssocko_cgenf_medium_tcp4(_Config) when is_list(_Config) ->
+ttest_ssocko_cgenf_medium_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssocko_cgenf_medium_tcp4,
+ Runtime,
inet,
sock, once,
gen, false,
@@ -15118,8 +15486,10 @@ ttest_ssocko_cgenf_medium_tcp6(suite) ->
[];
ttest_ssocko_cgenf_medium_tcp6(doc) ->
[];
-ttest_ssocko_cgenf_medium_tcp6(_Config) when is_list(_Config) ->
+ttest_ssocko_cgenf_medium_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssocko_cgenf_medium_tcp6,
+ Runtime,
inet6,
sock, once,
gen, false,
@@ -15140,8 +15510,10 @@ ttest_ssocko_cgenf_large_tcp4(suite) ->
[];
ttest_ssocko_cgenf_large_tcp4(doc) ->
[];
-ttest_ssocko_cgenf_large_tcp4(_Config) when is_list(_Config) ->
+ttest_ssocko_cgenf_large_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssocko_cgenf_large_tcp4,
+ Runtime,
inet,
sock, once,
gen, false,
@@ -15162,8 +15534,10 @@ ttest_ssocko_cgenf_large_tcp6(suite) ->
[];
ttest_ssocko_cgenf_large_tcp6(doc) ->
[];
-ttest_ssocko_cgenf_large_tcp6(_Config) when is_list(_Config) ->
+ttest_ssocko_cgenf_large_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssocko_cgenf_large_tcp6,
+ Runtime,
inet6,
sock, once,
gen, false,
@@ -15184,8 +15558,10 @@ ttest_ssocko_cgeno_small_tcp4(suite) ->
[];
ttest_ssocko_cgeno_small_tcp4(doc) ->
[];
-ttest_ssocko_cgeno_small_tcp4(_Config) when is_list(_Config) ->
+ttest_ssocko_cgeno_small_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssocko_cgeno_small_tcp4,
+ Runtime,
inet,
sock, once,
gen, once,
@@ -15206,8 +15582,10 @@ ttest_ssocko_cgeno_small_tcp6(suite) ->
[];
ttest_ssocko_cgeno_small_tcp6(doc) ->
[];
-ttest_ssocko_cgeno_small_tcp6(_Config) when is_list(_Config) ->
+ttest_ssocko_cgeno_small_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssocko_cgeno_small_tcp6,
+ Runtime,
inet6,
sock, once,
gen, once,
@@ -15228,8 +15606,10 @@ ttest_ssocko_cgeno_medium_tcp4(suite) ->
[];
ttest_ssocko_cgeno_medium_tcp4(doc) ->
[];
-ttest_ssocko_cgeno_medium_tcp4(_Config) when is_list(_Config) ->
+ttest_ssocko_cgeno_medium_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssocko_cgeno_medium_tcp4,
+ Runtime,
inet,
sock, once,
gen, once,
@@ -15250,8 +15630,10 @@ ttest_ssocko_cgeno_medium_tcp6(suite) ->
[];
ttest_ssocko_cgeno_medium_tcp6(doc) ->
[];
-ttest_ssocko_cgeno_medium_tcp6(_Config) when is_list(_Config) ->
+ttest_ssocko_cgeno_medium_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssocko_cgeno_medium_tcp6,
+ Runtime,
inet6,
sock, once,
gen, once,
@@ -15272,8 +15654,10 @@ ttest_ssocko_cgeno_large_tcp4(suite) ->
[];
ttest_ssocko_cgeno_large_tcp4(doc) ->
[];
-ttest_ssocko_cgeno_large_tcp4(_Config) when is_list(_Config) ->
+ttest_ssocko_cgeno_large_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssocko_cgeno_large_tcp4,
+ Runtime,
inet,
sock, once,
gen, once,
@@ -15294,8 +15678,10 @@ ttest_ssocko_cgeno_large_tcp6(suite) ->
[];
ttest_ssocko_cgeno_large_tcp6(doc) ->
[];
-ttest_ssocko_cgeno_large_tcp6(_Config) when is_list(_Config) ->
+ttest_ssocko_cgeno_large_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssocko_cgeno_large_tcp6,
+ Runtime,
inet6,
sock, once,
gen, once,
@@ -15316,8 +15702,10 @@ ttest_ssocko_cgent_small_tcp4(suite) ->
[];
ttest_ssocko_cgent_small_tcp4(doc) ->
[];
-ttest_ssocko_cgent_small_tcp4(_Config) when is_list(_Config) ->
+ttest_ssocko_cgent_small_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssocko_cgent_small_tcp4,
+ Runtime,
inet,
sock, once,
gen, true,
@@ -15338,8 +15726,10 @@ ttest_ssocko_cgent_small_tcp6(suite) ->
[];
ttest_ssocko_cgent_small_tcp6(doc) ->
[];
-ttest_ssocko_cgent_small_tcp6(_Config) when is_list(_Config) ->
+ttest_ssocko_cgent_small_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssocko_cgent_small_tcp6,
+ Runtime,
inet6,
sock, once,
gen, true,
@@ -15360,8 +15750,10 @@ ttest_ssocko_cgent_medium_tcp4(suite) ->
[];
ttest_ssocko_cgent_medium_tcp4(doc) ->
[];
-ttest_ssocko_cgent_medium_tcp4(_Config) when is_list(_Config) ->
+ttest_ssocko_cgent_medium_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssocko_cgent_medium_tcp4,
+ Runtime,
inet,
sock, once,
gen, true,
@@ -15382,8 +15774,10 @@ ttest_ssocko_cgent_medium_tcp6(suite) ->
[];
ttest_ssocko_cgent_medium_tcp6(doc) ->
[];
-ttest_ssocko_cgent_medium_tcp6(_Config) when is_list(_Config) ->
+ttest_ssocko_cgent_medium_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssocko_cgent_medium_tcp6,
+ Runtime,
inet6,
sock, once,
gen, true,
@@ -15404,8 +15798,10 @@ ttest_ssocko_cgent_large_tcp4(suite) ->
[];
ttest_ssocko_cgent_large_tcp4(doc) ->
[];
-ttest_ssocko_cgent_large_tcp4(_Config) when is_list(_Config) ->
+ttest_ssocko_cgent_large_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssocko_cgent_large_tcp4,
+ Runtime,
inet,
sock, once,
gen, true,
@@ -15426,8 +15822,10 @@ ttest_ssocko_cgent_large_tcp6(suite) ->
[];
ttest_ssocko_cgent_large_tcp6(doc) ->
[];
-ttest_ssocko_cgent_large_tcp6(_Config) when is_list(_Config) ->
+ttest_ssocko_cgent_large_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssocko_cgent_large_tcp6,
+ Runtime,
inet6,
sock, once,
gen, true,
@@ -15448,8 +15846,10 @@ ttest_ssocko_csockf_small_tcp4(suite) ->
[];
ttest_ssocko_csockf_small_tcp4(doc) ->
[];
-ttest_ssocko_csockf_small_tcp4(_Config) when is_list(_Config) ->
+ttest_ssocko_csockf_small_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssocko_csockf_small_tcp4,
+ Runtime,
inet,
sock, once,
sock, false,
@@ -15470,8 +15870,10 @@ ttest_ssocko_csockf_small_tcp6(suite) ->
[];
ttest_ssocko_csockf_small_tcp6(doc) ->
[];
-ttest_ssocko_csockf_small_tcp6(_Config) when is_list(_Config) ->
+ttest_ssocko_csockf_small_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssocko_csockf_small_tcp6,
+ Runtime,
inet6,
sock, once,
sock, false,
@@ -15492,8 +15894,10 @@ ttest_ssocko_csockf_medium_tcp4(suite) ->
[];
ttest_ssocko_csockf_medium_tcp4(doc) ->
[];
-ttest_ssocko_csockf_medium_tcp4(_Config) when is_list(_Config) ->
+ttest_ssocko_csockf_medium_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssocko_csockf_medium_tcp4,
+ Runtime,
inet,
sock, once,
sock, false,
@@ -15514,8 +15918,10 @@ ttest_ssocko_csockf_medium_tcp6(suite) ->
[];
ttest_ssocko_csockf_medium_tcp6(doc) ->
[];
-ttest_ssocko_csockf_medium_tcp6(_Config) when is_list(_Config) ->
+ttest_ssocko_csockf_medium_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssocko_csockf_medium_tcp6,
+ Runtime,
inet6,
sock, once,
sock, false,
@@ -15536,8 +15942,10 @@ ttest_ssocko_csockf_large_tcp4(suite) ->
[];
ttest_ssocko_csockf_large_tcp4(doc) ->
[];
-ttest_ssocko_csockf_large_tcp4(_Config) when is_list(_Config) ->
+ttest_ssocko_csockf_large_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssocko_csockf_large_tcp4,
+ Runtime,
inet,
sock, once,
sock, false,
@@ -15558,8 +15966,10 @@ ttest_ssocko_csockf_large_tcp6(suite) ->
[];
ttest_ssocko_csockf_large_tcp6(doc) ->
[];
-ttest_ssocko_csockf_large_tcp6(_Config) when is_list(_Config) ->
+ttest_ssocko_csockf_large_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssocko_csockf_large_tcp6,
+ Runtime,
inet6,
sock, once,
sock, false,
@@ -15580,8 +15990,10 @@ ttest_ssocko_csocko_small_tcp4(suite) ->
[];
ttest_ssocko_csocko_small_tcp4(doc) ->
[];
-ttest_ssocko_csocko_small_tcp4(_Config) when is_list(_Config) ->
+ttest_ssocko_csocko_small_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssocko_csocko_small_tcp4,
+ Runtime,
inet,
sock, once,
sock, once,
@@ -15602,8 +16014,10 @@ ttest_ssocko_csocko_small_tcp6(suite) ->
[];
ttest_ssocko_csocko_small_tcp6(doc) ->
[];
-ttest_ssocko_csocko_small_tcp6(_Config) when is_list(_Config) ->
+ttest_ssocko_csocko_small_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssocko_csocko_small_tcp6,
+ Runtime,
inet6,
sock, once,
sock, once,
@@ -15624,8 +16038,10 @@ ttest_ssocko_csocko_medium_tcp4(suite) ->
[];
ttest_ssocko_csocko_medium_tcp4(doc) ->
[];
-ttest_ssocko_csocko_medium_tcp4(_Config) when is_list(_Config) ->
+ttest_ssocko_csocko_medium_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssocko_csocko_medium_tcp4,
+ Runtime,
inet,
sock, once,
sock, once,
@@ -15646,8 +16062,10 @@ ttest_ssocko_csocko_medium_tcp6(suite) ->
[];
ttest_ssocko_csocko_medium_tcp6(doc) ->
[];
-ttest_ssocko_csocko_medium_tcp6(_Config) when is_list(_Config) ->
+ttest_ssocko_csocko_medium_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssocko_csocko_medium_tcp6,
+ Runtime,
inet6,
sock, once,
sock, once,
@@ -15668,8 +16086,10 @@ ttest_ssocko_csocko_large_tcp4(suite) ->
[];
ttest_ssocko_csocko_large_tcp4(doc) ->
[];
-ttest_ssocko_csocko_large_tcp4(_Config) when is_list(_Config) ->
+ttest_ssocko_csocko_large_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssocko_csocko_large_tcp4,
+ Runtime,
inet,
sock, once,
sock, once,
@@ -15690,8 +16110,10 @@ ttest_ssocko_csocko_large_tcp6(suite) ->
[];
ttest_ssocko_csocko_large_tcp6(doc) ->
[];
-ttest_ssocko_csocko_large_tcp6(_Config) when is_list(_Config) ->
+ttest_ssocko_csocko_large_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssocko_csocko_large_tcp6,
+ Runtime,
inet6,
sock, once,
sock, once,
@@ -15712,8 +16134,10 @@ ttest_ssocko_csockt_small_tcp4(suite) ->
[];
ttest_ssocko_csockt_small_tcp4(doc) ->
[];
-ttest_ssocko_csockt_small_tcp4(_Config) when is_list(_Config) ->
+ttest_ssocko_csockt_small_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssocko_csockt_small_tcp4,
+ Runtime,
inet,
sock, once,
sock, true,
@@ -15734,8 +16158,10 @@ ttest_ssocko_csockt_small_tcp6(suite) ->
[];
ttest_ssocko_csockt_small_tcp6(doc) ->
[];
-ttest_ssocko_csockt_small_tcp6(_Config) when is_list(_Config) ->
+ttest_ssocko_csockt_small_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssocko_csocko_small_tcp6,
+ Runtime,
inet6,
sock, once,
sock, true,
@@ -15756,8 +16182,10 @@ ttest_ssocko_csockt_medium_tcp4(suite) ->
[];
ttest_ssocko_csockt_medium_tcp4(doc) ->
[];
-ttest_ssocko_csockt_medium_tcp4(_Config) when is_list(_Config) ->
+ttest_ssocko_csockt_medium_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssocko_csockt_medium_tcp4,
+ Runtime,
inet,
sock, once,
sock, true,
@@ -15778,8 +16206,10 @@ ttest_ssocko_csockt_medium_tcp6(suite) ->
[];
ttest_ssocko_csockt_medium_tcp6(doc) ->
[];
-ttest_ssocko_csockt_medium_tcp6(_Config) when is_list(_Config) ->
+ttest_ssocko_csockt_medium_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssocko_csockt_medium_tcp6,
+ Runtime,
inet6,
sock, once,
sock, true,
@@ -15800,8 +16230,10 @@ ttest_ssocko_csockt_large_tcp4(suite) ->
[];
ttest_ssocko_csockt_large_tcp4(doc) ->
[];
-ttest_ssocko_csockt_large_tcp4(_Config) when is_list(_Config) ->
+ttest_ssocko_csockt_large_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssocko_csockt_large_tcp4,
+ Runtime,
inet,
sock, once,
sock, true,
@@ -15822,8 +16254,10 @@ ttest_ssocko_csockt_large_tcp6(suite) ->
[];
ttest_ssocko_csockt_large_tcp6(doc) ->
[];
-ttest_ssocko_csockt_large_tcp6(_Config) when is_list(_Config) ->
+ttest_ssocko_csockt_large_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssocko_csockt_large_tcp6,
+ Runtime,
inet6,
sock, once,
sock, true,
@@ -15844,8 +16278,10 @@ ttest_ssockt_cgenf_small_tcp4(suite) ->
[];
ttest_ssockt_cgenf_small_tcp4(doc) ->
[];
-ttest_ssockt_cgenf_small_tcp4(_Config) when is_list(_Config) ->
+ttest_ssockt_cgenf_small_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssockt_cgenf_small_tcp4,
+ Runtime,
inet,
sock, true,
gen, false,
@@ -15866,8 +16302,10 @@ ttest_ssockt_cgenf_small_tcp6(suite) ->
[];
ttest_ssockt_cgenf_small_tcp6(doc) ->
[];
-ttest_ssockt_cgenf_small_tcp6(_Config) when is_list(_Config) ->
+ttest_ssockt_cgenf_small_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssockt_cgenf_small_tcp6,
+ Runtime,
inet6,
sock, true,
gen, false,
@@ -15888,8 +16326,10 @@ ttest_ssockt_cgenf_medium_tcp4(suite) ->
[];
ttest_ssockt_cgenf_medium_tcp4(doc) ->
[];
-ttest_ssockt_cgenf_medium_tcp4(_Config) when is_list(_Config) ->
+ttest_ssockt_cgenf_medium_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssockt_cgenf_medium_tcp4,
+ Runtime,
inet,
sock, true,
gen, false,
@@ -15910,8 +16350,10 @@ ttest_ssockt_cgenf_medium_tcp6(suite) ->
[];
ttest_ssockt_cgenf_medium_tcp6(doc) ->
[];
-ttest_ssockt_cgenf_medium_tcp6(_Config) when is_list(_Config) ->
+ttest_ssockt_cgenf_medium_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssockt_cgenf_medium_tcp6,
+ Runtime,
inet6,
sock, true,
gen, false,
@@ -15932,8 +16374,10 @@ ttest_ssockt_cgenf_large_tcp4(suite) ->
[];
ttest_ssockt_cgenf_large_tcp4(doc) ->
[];
-ttest_ssockt_cgenf_large_tcp4(_Config) when is_list(_Config) ->
+ttest_ssockt_cgenf_large_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssockt_cgenf_large_tcp4,
+ Runtime,
inet,
sock, true,
gen, false,
@@ -15954,8 +16398,10 @@ ttest_ssockt_cgenf_large_tcp6(suite) ->
[];
ttest_ssockt_cgenf_large_tcp6(doc) ->
[];
-ttest_ssockt_cgenf_large_tcp6(_Config) when is_list(_Config) ->
+ttest_ssockt_cgenf_large_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssockt_cgenf_large_tcp6,
+ Runtime,
inet6,
sock, true,
gen, false,
@@ -15976,8 +16422,10 @@ ttest_ssockt_cgeno_small_tcp4(suite) ->
[];
ttest_ssockt_cgeno_small_tcp4(doc) ->
[];
-ttest_ssockt_cgeno_small_tcp4(_Config) when is_list(_Config) ->
+ttest_ssockt_cgeno_small_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssockt_cgeno_small_tcp4,
+ Runtime,
inet,
sock, true,
gen, once,
@@ -15998,8 +16446,10 @@ ttest_ssockt_cgeno_small_tcp6(suite) ->
[];
ttest_ssockt_cgeno_small_tcp6(doc) ->
[];
-ttest_ssockt_cgeno_small_tcp6(_Config) when is_list(_Config) ->
+ttest_ssockt_cgeno_small_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssockt_cgeno_small_tcp6,
+ Runtime,
inet6,
sock, true,
gen, once,
@@ -16020,8 +16470,10 @@ ttest_ssockt_cgeno_medium_tcp4(suite) ->
[];
ttest_ssockt_cgeno_medium_tcp4(doc) ->
[];
-ttest_ssockt_cgeno_medium_tcp4(_Config) when is_list(_Config) ->
+ttest_ssockt_cgeno_medium_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssockt_cgeno_medium_tcp4,
+ Runtime,
inet,
sock, true,
gen, once,
@@ -16042,8 +16494,10 @@ ttest_ssockt_cgeno_medium_tcp6(suite) ->
[];
ttest_ssockt_cgeno_medium_tcp6(doc) ->
[];
-ttest_ssockt_cgeno_medium_tcp6(_Config) when is_list(_Config) ->
+ttest_ssockt_cgeno_medium_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssockt_cgeno_medium_tcp6,
+ Runtime,
inet6,
sock, true,
gen, once,
@@ -16064,8 +16518,10 @@ ttest_ssockt_cgeno_large_tcp4(suite) ->
[];
ttest_ssockt_cgeno_large_tcp4(doc) ->
[];
-ttest_ssockt_cgeno_large_tcp4(_Config) when is_list(_Config) ->
+ttest_ssockt_cgeno_large_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssockt_cgeno_large_tcp4,
+ Runtime,
inet,
sock, true,
gen, once,
@@ -16086,8 +16542,10 @@ ttest_ssockt_cgeno_large_tcp6(suite) ->
[];
ttest_ssockt_cgeno_large_tcp6(doc) ->
[];
-ttest_ssockt_cgeno_large_tcp6(_Config) when is_list(_Config) ->
+ttest_ssockt_cgeno_large_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssockt_cgeno_large_tcp6,
+ Runtime,
inet6,
sock, true,
gen, once,
@@ -16108,8 +16566,10 @@ ttest_ssockt_cgent_small_tcp4(suite) ->
[];
ttest_ssockt_cgent_small_tcp4(doc) ->
[];
-ttest_ssockt_cgent_small_tcp4(_Config) when is_list(_Config) ->
+ttest_ssockt_cgent_small_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssockt_cgent_small_tcp4,
+ Runtime,
inet,
sock, true,
gen, true,
@@ -16130,8 +16590,10 @@ ttest_ssockt_cgent_small_tcp6(suite) ->
[];
ttest_ssockt_cgent_small_tcp6(doc) ->
[];
-ttest_ssockt_cgent_small_tcp6(_Config) when is_list(_Config) ->
+ttest_ssockt_cgent_small_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssockt_cgent_small_tcp6,
+ Runtime,
inet6,
sock, true,
gen, true,
@@ -16152,8 +16614,10 @@ ttest_ssockt_cgent_medium_tcp4(suite) ->
[];
ttest_ssockt_cgent_medium_tcp4(doc) ->
[];
-ttest_ssockt_cgent_medium_tcp4(_Config) when is_list(_Config) ->
+ttest_ssockt_cgent_medium_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssockt_cgent_medium_tcp4,
+ Runtime,
inet,
sock, true,
gen, true,
@@ -16174,8 +16638,10 @@ ttest_ssockt_cgent_medium_tcp6(suite) ->
[];
ttest_ssockt_cgent_medium_tcp6(doc) ->
[];
-ttest_ssockt_cgent_medium_tcp6(_Config) when is_list(_Config) ->
+ttest_ssockt_cgent_medium_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssockt_cgent_medium_tcp6,
+ Runtime,
inet6,
sock, true,
gen, true,
@@ -16196,8 +16662,10 @@ ttest_ssockt_cgent_large_tcp4(suite) ->
[];
ttest_ssockt_cgent_large_tcp4(doc) ->
[];
-ttest_ssockt_cgent_large_tcp4(_Config) when is_list(_Config) ->
+ttest_ssockt_cgent_large_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssockt_cgent_large_tcp4,
+ Runtime,
inet,
sock, true,
gen, true,
@@ -16218,8 +16686,10 @@ ttest_ssockt_cgent_large_tcp6(suite) ->
[];
ttest_ssockt_cgent_large_tcp6(doc) ->
[];
-ttest_ssockt_cgent_large_tcp6(_Config) when is_list(_Config) ->
+ttest_ssockt_cgent_large_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssockt_cgent_large_tcp6,
+ Runtime,
inet6,
sock, true,
gen, true,
@@ -16240,8 +16710,10 @@ ttest_ssockt_csockf_small_tcp4(suite) ->
[];
ttest_ssockt_csockf_small_tcp4(doc) ->
[];
-ttest_ssockt_csockf_small_tcp4(_Config) when is_list(_Config) ->
+ttest_ssockt_csockf_small_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssockt_csockf_small_tcp4,
+ Runtime,
inet,
sock, true,
sock, false,
@@ -16262,8 +16734,10 @@ ttest_ssockt_csockf_small_tcp6(suite) ->
[];
ttest_ssockt_csockf_small_tcp6(doc) ->
[];
-ttest_ssockt_csockf_small_tcp6(_Config) when is_list(_Config) ->
+ttest_ssockt_csockf_small_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssockt_csockf_small_tcp6,
+ Runtime,
inet6,
sock, true,
sock, false,
@@ -16284,8 +16758,10 @@ ttest_ssockt_csockf_medium_tcp4(suite) ->
[];
ttest_ssockt_csockf_medium_tcp4(doc) ->
[];
-ttest_ssockt_csockf_medium_tcp4(_Config) when is_list(_Config) ->
+ttest_ssockt_csockf_medium_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssockt_csockf_medium_tcp4,
+ Runtime,
inet,
sock, true,
sock, false,
@@ -16306,8 +16782,10 @@ ttest_ssockt_csockf_medium_tcp6(suite) ->
[];
ttest_ssockt_csockf_medium_tcp6(doc) ->
[];
-ttest_ssockt_csockf_medium_tcp6(_Config) when is_list(_Config) ->
+ttest_ssockt_csockf_medium_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssockt_csockf_medium_tcp6,
+ Runtime,
inet6,
sock, true,
sock, false,
@@ -16328,8 +16806,10 @@ ttest_ssockt_csockf_large_tcp4(suite) ->
[];
ttest_ssockt_csockf_large_tcp4(doc) ->
[];
-ttest_ssockt_csockf_large_tcp4(_Config) when is_list(_Config) ->
+ttest_ssockt_csockf_large_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssockt_csockf_large_tcp4,
+ Runtime,
inet,
sock, true,
sock, false,
@@ -16350,8 +16830,10 @@ ttest_ssockt_csockf_large_tcp6(suite) ->
[];
ttest_ssockt_csockf_large_tcp6(doc) ->
[];
-ttest_ssockt_csockf_large_tcp6(_Config) when is_list(_Config) ->
+ttest_ssockt_csockf_large_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssockt_csockf_large_tcp6,
+ Runtime,
inet6,
sock, true,
sock, false,
@@ -16372,8 +16854,10 @@ ttest_ssockt_csocko_small_tcp4(suite) ->
[];
ttest_ssockt_csocko_small_tcp4(doc) ->
[];
-ttest_ssockt_csocko_small_tcp4(_Config) when is_list(_Config) ->
+ttest_ssockt_csocko_small_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssockt_csocko_small_tcp4,
+ Runtime,
inet,
sock, true,
sock, once,
@@ -16394,8 +16878,10 @@ ttest_ssockt_csocko_small_tcp6(suite) ->
[];
ttest_ssockt_csocko_small_tcp6(doc) ->
[];
-ttest_ssockt_csocko_small_tcp6(_Config) when is_list(_Config) ->
+ttest_ssockt_csocko_small_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssockt_csocko_small_tcp6,
+ Runtime,
inet6,
sock, true,
sock, once,
@@ -16416,8 +16902,10 @@ ttest_ssockt_csocko_medium_tcp4(suite) ->
[];
ttest_ssockt_csocko_medium_tcp4(doc) ->
[];
-ttest_ssockt_csocko_medium_tcp4(_Config) when is_list(_Config) ->
+ttest_ssockt_csocko_medium_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssockt_csocko_medium_tcp4,
+ Runtime,
inet,
sock, true,
sock, once,
@@ -16438,8 +16926,10 @@ ttest_ssockt_csocko_medium_tcp6(suite) ->
[];
ttest_ssockt_csocko_medium_tcp6(doc) ->
[];
-ttest_ssockt_csocko_medium_tcp6(_Config) when is_list(_Config) ->
+ttest_ssockt_csocko_medium_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssockt_csocko_medium_tcp6,
+ Runtime,
inet6,
sock, true,
sock, once,
@@ -16460,8 +16950,10 @@ ttest_ssockt_csocko_large_tcp4(suite) ->
[];
ttest_ssockt_csocko_large_tcp4(doc) ->
[];
-ttest_ssockt_csocko_large_tcp4(_Config) when is_list(_Config) ->
+ttest_ssockt_csocko_large_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssockt_csocko_large_tcp4,
+ Runtime,
inet,
sock, true,
sock, once,
@@ -16482,8 +16974,10 @@ ttest_ssockt_csocko_large_tcp6(suite) ->
[];
ttest_ssockt_csocko_large_tcp6(doc) ->
[];
-ttest_ssockt_csocko_large_tcp6(_Config) when is_list(_Config) ->
+ttest_ssockt_csocko_large_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssockt_csocko_large_tcp6,
+ Runtime,
inet6,
sock, true,
sock, once,
@@ -16504,8 +16998,10 @@ ttest_ssockt_csockt_small_tcp4(suite) ->
[];
ttest_ssockt_csockt_small_tcp4(doc) ->
[];
-ttest_ssockt_csockt_small_tcp4(_Config) when is_list(_Config) ->
+ttest_ssockt_csockt_small_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssockt_csockt_small_tcp4,
+ Runtime,
inet,
sock, true,
sock, true,
@@ -16526,8 +17022,10 @@ ttest_ssockt_csockt_small_tcp6(suite) ->
[];
ttest_ssockt_csockt_small_tcp6(doc) ->
[];
-ttest_ssockt_csockt_small_tcp6(_Config) when is_list(_Config) ->
+ttest_ssockt_csockt_small_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssockt_csocko_small_tcp6,
+ Runtime,
inet6,
sock, true,
sock, true,
@@ -16548,8 +17046,10 @@ ttest_ssockt_csockt_medium_tcp4(suite) ->
[];
ttest_ssockt_csockt_medium_tcp4(doc) ->
[];
-ttest_ssockt_csockt_medium_tcp4(_Config) when is_list(_Config) ->
+ttest_ssockt_csockt_medium_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssockt_csockt_medium_tcp4,
+ Runtime,
inet,
sock, true,
sock, true,
@@ -16570,8 +17070,10 @@ ttest_ssockt_csockt_medium_tcp6(suite) ->
[];
ttest_ssockt_csockt_medium_tcp6(doc) ->
[];
-ttest_ssockt_csockt_medium_tcp6(_Config) when is_list(_Config) ->
+ttest_ssockt_csockt_medium_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssockt_csockt_medium_tcp6,
+ Runtime,
inet6,
sock, true,
sock, true,
@@ -16592,8 +17094,10 @@ ttest_ssockt_csockt_large_tcp4(suite) ->
[];
ttest_ssockt_csockt_large_tcp4(doc) ->
[];
-ttest_ssockt_csockt_large_tcp4(_Config) when is_list(_Config) ->
+ttest_ssockt_csockt_large_tcp4(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssockt_csockt_large_tcp4,
+ Runtime,
inet,
sock, true,
sock, true,
@@ -16614,8 +17118,10 @@ ttest_ssockt_csockt_large_tcp6(suite) ->
[];
ttest_ssockt_csockt_large_tcp6(doc) ->
[];
-ttest_ssockt_csockt_large_tcp6(_Config) when is_list(_Config) ->
+ttest_ssockt_csockt_large_tcp6(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
ttest_tcp(ttest_ssockt_csockt_large_tcp6,
+ Runtime,
inet6,
sock, true,
sock, true,
@@ -16625,12 +17131,62 @@ ttest_ssockt_csockt_large_tcp6(_Config) when is_list(_Config) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+which_ttest_runtime(Config) when is_list(Config) ->
+ case lists:keysearch(esock_test_ttest_runtime, 1, Config) of
+ {value, {esock_test_ttest_runtime, Runtime}} ->
+ Runtime;
+ false ->
+ which_ttest_runtime_env()
+ end.
+
+which_ttest_runtime_env() ->
+ which_ttest_runtime_env(os:getenv("ESOCK_TEST_TTEST_RUNTIME")).
+
+which_ttest_runtime_env(TStr) when is_list(TStr) ->
+ which_ttest_runtime_env2(lists:reverse(TStr));
+which_ttest_runtime_env(false) ->
+ ?TTEST_RUNTIME.
+
+
+%% The format is: <int>[unit]
+%% where the optional unit can be:
+%% ms: milliseconds
+%% s: seconds (default)
+%% m: minutes
+which_ttest_runtime_env2([$m, $s | MS]) when (length(MS) > 0) ->
+ convert_time(MS, fun(X) -> X end);
+which_ttest_runtime_env2([$m | M]) when (length(M) > 0) ->
+ convert_time(M, fun(X) -> ?MINS(X) end);
+which_ttest_runtime_env2([$s | S]) when (length(S) > 0) ->
+ convert_time(S, fun(X) -> ?SECS(X) end);
+which_ttest_runtime_env2(S) ->
+ convert_time(S, fun(X) -> ?SECS(X) end).
+
+convert_time(TStrRev, Convert) ->
+ try list_to_integer(lists:reverse(TStrRev)) of
+ I -> Convert(I)
+ catch
+ _:_ ->
+ ?TTEST_RUNTIME
+ end.
+
+ttest_tcp(TC,
+ Domain,
+ ServerMod, ServerActive,
+ ClientMod, ClientActive,
+ MsgID, MaxOutstanding) ->
+ ttest_tcp(TC,
+ ?TTEST_RUNTIME,
+ Domain,
+ ServerMod, ServerActive,
+ ClientMod, ClientActive,
+ MsgID, MaxOutstanding).
ttest_tcp(TC,
+ Runtime,
Domain,
ServerMod, ServerActive,
ClientMod, ClientActive,
MsgID, MaxOutstanding) ->
- Runtime = ?TTEST_RUNTIME,
tc_try(TC,
fun() ->
if (Domain =/= inet) -> not_yet_implemented(); true -> ok end,
diff --git a/erts/emulator/test/socket_test_logger.erl b/erts/emulator/test/socket_test_logger.erl
index e42251158f..26610e9ef3 100644
--- a/erts/emulator/test/socket_test_logger.erl
+++ b/erts/emulator/test/socket_test_logger.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2018-2018. All Rights Reserved.
+%% Copyright Ericsson AB 2018-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -21,12 +21,13 @@
-module(socket_test_logger).
-export([
- start/0,
+ start/0, start/1,
stop/0,
format/2
]).
+-define(QUIET, true).
-define(LIB, socket_test_lib).
-define(LOGGER, ?MODULE).
@@ -34,12 +35,15 @@
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
start() ->
+ start(?QUIET).
+
+start(Quiet) ->
case global:whereis_name(?LOGGER) of
Pid when is_pid(Pid) ->
ok;
undefined ->
Self = self(),
- Pid = spawn_link(fun() -> init(Self) end),
+ Pid = spawn_link(fun() -> init(Self, Quiet) end),
yes = global:register_name(?LOGGER, Pid),
ok
end.
@@ -70,12 +74,13 @@ do_format(Msg) ->
ok
end.
-init(Parent) ->
+init(Parent, Quiet) ->
put(sname, "logger"),
print("[~s][logger] starting~n", [?LIB:formated_timestamp()]),
- loop(#{parent => Parent}).
+ loop(#{parent => Parent, quiet => Quiet}).
-loop(#{parent := Parent} = State) ->
+loop(#{parent := Parent,
+ quiet := Quiet} = State) ->
receive
{'EXIT', Parent, _} ->
print("[~s][logger] parent exit~n", [?LIB:formated_timestamp()]),
@@ -86,18 +91,20 @@ loop(#{parent := Parent} = State) ->
exit(normal);
{?MODULE, '$logger', {msg, Msg}} ->
- print(Msg),
+ print_str(Quiet, Msg),
loop(State)
end.
print(F, A) ->
- print(?LIB:f(F, A)).
+ print_str(false, ?LIB:f(F, A)).
-print(Str) ->
+print_str(Quiet, Str) ->
try
begin
- io:format(user, Str ++ "~n", []),
+ if (Quiet =/= true) -> io:format(user, Str ++ "~n", []);
+ true -> ok
+ end,
io:format(Str, [])
end
catch
diff --git a/erts/etc/unix/to_erl.c b/erts/etc/unix/to_erl.c
index afff8f7e54..ed4fe12e8b 100644
--- a/erts/etc/unix/to_erl.c
+++ b/erts/etc/unix/to_erl.c
@@ -245,7 +245,6 @@ int main(int argc, char **argv)
tty_smode.c_iflag =
1*BRKINT |/*Signal interrupt on break.*/
1*IGNPAR |/*Ignore characters with parity errors.*/
- 1*ISTRIP |/*Strip character.*/
0;
#if 0
diff --git a/erts/lib_src/common/erl_printf.c b/erts/lib_src/common/erl_printf.c
index 259ba8c81d..86f5da1c40 100644
--- a/erts/lib_src/common/erl_printf.c
+++ b/erts/lib_src/common/erl_printf.c
@@ -27,6 +27,11 @@
#include "config.h"
#endif
+#if defined(__sun) || defined(__sun__)
+ /* For flockfile(3c), putc_unlocked(3c), etc */
+ #define __EXTENSIONS__
+#endif
+
#include <string.h>
#include "erl_errno.h"
#ifdef __WIN32__
diff --git a/erts/preloaded/ebin/erl_prim_loader.beam b/erts/preloaded/ebin/erl_prim_loader.beam
index bbee904837..661bcd8413 100644
--- a/erts/preloaded/ebin/erl_prim_loader.beam
+++ b/erts/preloaded/ebin/erl_prim_loader.beam
Binary files differ
diff --git a/erts/preloaded/ebin/init.beam b/erts/preloaded/ebin/init.beam
index 3392674e3c..1d89174b25 100644
--- a/erts/preloaded/ebin/init.beam
+++ b/erts/preloaded/ebin/init.beam
Binary files differ
diff --git a/erts/preloaded/ebin/prim_file.beam b/erts/preloaded/ebin/prim_file.beam
index b9f4791ba9..0efd954e50 100644
--- a/erts/preloaded/ebin/prim_file.beam
+++ b/erts/preloaded/ebin/prim_file.beam
Binary files differ
diff --git a/erts/preloaded/src/erl_prim_loader.erl b/erts/preloaded/src/erl_prim_loader.erl
index fefdd34292..1605c20f2c 100644
--- a/erts/preloaded/src/erl_prim_loader.erl
+++ b/erts/preloaded/src/erl_prim_loader.erl
@@ -297,12 +297,13 @@ check_file_result(Func, Target, {error,Reason}) ->
"Target: " ++ TargetStr ++ ". " ++
"Function: " ++ atom_to_list(Func) ++ ". " ++ Process
end,
- %% this is equal to calling error_logger:error_report/1 which
- %% we don't want to do from code_server during system boot
+ %% This is equal to calling logger:error/2 which
+ %% we don't want to do from code_server during system boot.
+ %% We don't want to call logger:timestamp() either.
logger ! {log,error,#{label=>{?MODULE,file_error},report=>Report},
#{pid=>self(),
gl=>group_leader(),
- time=>erlang:system_time(microsecond),
+ time=>os:system_time(microsecond),
error_logger=>#{tag=>error_report,
type=>std_error}}},
error
diff --git a/erts/preloaded/src/init.erl b/erts/preloaded/src/init.erl
index 54cbd96710..5ea67347ec 100644
--- a/erts/preloaded/src/init.erl
+++ b/erts/preloaded/src/init.erl
@@ -477,13 +477,16 @@ do_handle_msg(Msg,State) ->
{From, {ensure_loaded, _}} ->
From ! {init, not_allowed};
X ->
+ %% This is equal to calling logger:info/3 which we don't
+ %% want to do from the init process, at least not during
+ %% system boot. We don't want to call logger:timestamp()
+ %% either.
case whereis(user) of
undefined ->
- Time = erlang:system_time(microsecond),
catch logger ! {log, info, "init got unexpected: ~p", [X],
#{pid=>self(),
gl=>self(),
- time=>Time,
+ time=>os:system_time(microsecond),
error_logger=>#{tag=>info_msg}}};
User ->
User ! X,
diff --git a/erts/preloaded/src/prim_eval.S b/erts/preloaded/src/prim_eval.S
index e4b1560517..900fda5d89 100644
--- a/erts/preloaded/src/prim_eval.S
+++ b/erts/preloaded/src/prim_eval.S
@@ -42,6 +42,10 @@
{label,3}.
{loop_rec,{f,5},{x,0}}.
{move,{y,1},{x,1}}.
+ %% Tell the validator that it's safe to pass the message as an argument,
+ %% as the match fun is "known" not to build a term with it, and the
+ %% loop_rec instruction has disabled the GC.
+ {'%', {remove_fragility, {x,0}}}.
{call_fun,1}.
{test,is_ne_exact,{f,4},[{x,0},{atom,nomatch}]}.
remove_message.
diff --git a/erts/preloaded/src/prim_file.erl b/erts/preloaded/src/prim_file.erl
index 0994e2a9f4..1aa5d85c64 100644
--- a/erts/preloaded/src/prim_file.erl
+++ b/erts/preloaded/src/prim_file.erl
@@ -572,12 +572,13 @@ list_dir_convert([RawName | Rest], SkipInvalid, Result) ->
{error, ignore} ->
list_dir_convert(Rest, SkipInvalid, Result);
{error, warning} ->
- %% this is equal to calling error_logger:warning_msg/2 which
- %% we don't want to do from code_server during system boot
+ %% This is equal to calling logger:warning/3 which
+ %% we don't want to do from code_server during system boot.
+ %% We don't want to call logger:timestamp() either.
logger ! {log,warning,"Non-unicode filename ~p ignored\n", [RawName],
#{pid=>self(),
gl=>group_leader(),
- time=>erlang:system_time(microsecond),
+ time=>os:system_time(microsecond),
error_logger=>#{tag=>warning_msg}}},
list_dir_convert(Rest, SkipInvalid, Result);
{error, _} ->
diff --git a/lib/common_test/doc/src/basics_chapter.xml b/lib/common_test/doc/src/basics_chapter.xml
index 95599ca1f1..899a52fa31 100644
--- a/lib/common_test/doc/src/basics_chapter.xml
+++ b/lib/common_test/doc/src/basics_chapter.xml
@@ -125,7 +125,7 @@
The test case is the smallest unit that the <c>Common Test</c> test server deals with.
</p>
<p>
- Subsets of test cases, called test case groups, can also be defined. A test case
+ Sets of test cases, called test case groups, can also be defined. A test case
group can have execution properties associated with it. Execution properties
specify if the test cases in the group are to be executed in
random order, in parallel, or in sequence, and if the execution of the group
diff --git a/lib/common_test/test_server/ts_install.erl b/lib/common_test/test_server/ts_install.erl
index 09f3da860a..86f16fa072 100644
--- a/lib/common_test/test_server/ts_install.erl
+++ b/lib/common_test/test_server/ts_install.erl
@@ -268,7 +268,7 @@ add_vars(Vars0, Opts0) ->
{Opts, [{longnames, LongNames},
{platform_id, PlatformId},
{platform_filename, PlatformFilename},
- {rsh_name, os:getenv("ERL_RSH", "rsh")},
+ {rsh_name, os:getenv("ERL_RSH", "ssh")},
{platform_label, PlatformLabel},
{ts_net_dir, Mounted},
{erl_flags, []},
diff --git a/lib/compiler/src/beam_jump.erl b/lib/compiler/src/beam_jump.erl
index 6f50bfdb9c..74f80ca70e 100644
--- a/lib/compiler/src/beam_jump.erl
+++ b/lib/compiler/src/beam_jump.erl
@@ -179,8 +179,9 @@ function({function,Name,Arity,CLabel,Asm0}, Lc0) ->
eliminate_moves(Is) ->
eliminate_moves(Is, #{}, []).
-eliminate_moves([{select,select_val,Reg,_,List}=I|Is], D0, Acc) ->
- D = update_value_dict(List, Reg, D0),
+eliminate_moves([{select,select_val,Reg,{f,Fail},List}=I|Is], D0, Acc) ->
+ D1 = add_unsafe_label(Fail, D0),
+ D = update_value_dict(List, Reg, D1),
eliminate_moves(Is, D, [I|Acc]);
eliminate_moves([{test,is_eq_exact,_,[Reg,Val]}=I,
{block,BlkIs0}|Is], D0, Acc) ->
@@ -229,6 +230,9 @@ update_value_dict([Lit,{f,Lbl}|T], Reg, D0) ->
update_value_dict(T, Reg, D);
update_value_dict([], _, D) -> D.
+add_unsafe_label(L, D) ->
+ D#{L=>unsafe}.
+
update_unsafe_labels(I, D) ->
Ls = instr_labels(I),
update_unsafe_labels_1(Ls, D).
diff --git a/lib/compiler/src/beam_kernel_to_ssa.erl b/lib/compiler/src/beam_kernel_to_ssa.erl
index 410bafe0bb..df95749fb3 100644
--- a/lib/compiler/src/beam_kernel_to_ssa.erl
+++ b/lib/compiler/src/beam_kernel_to_ssa.erl
@@ -327,7 +327,7 @@ select_bin_seg(#k_val_clause{val=#k_bin_seg{size=Size,unit=U,type=T,
{Mis,St1} = select_extract_bin(Next, Size, U, T, Fs, Fail,
Ctx, LineAnno, St0),
{Extracted,St2} = new_ssa_var(Seg#k_var.name, St1),
- {Bis,St} = bin_match_cg(Size, B, Fail, St2),
+ {Bis,St} = match_cg(B, Fail, St2),
BsGet = #b_set{op=bs_extract,dst=Extracted,args=[ssa_arg(Next, St)]},
Is = Mis ++ [BsGet] ++ Bis,
{Is,St};
@@ -362,14 +362,6 @@ select_bin_seg(#k_val_clause{val=#k_bin_int{size=Sz,unit=U,flags=Fs,
end,
{Is,St}.
-bin_match_cg(#k_atom{val=all}, B0, Fail, St) ->
- #k_select{types=Types} = B0,
- [#k_type_clause{type=k_bin_end,values=Values}] = Types,
- [#k_val_clause{val=#k_bin_end{},body=B}] = Values,
- match_cg(B, Fail, St);
-bin_match_cg(_, B, Fail, St) ->
- match_cg(B, Fail, St).
-
get_context(#k_var{}=Var, St) ->
ssa_arg(Var, St).
diff --git a/lib/compiler/src/beam_ssa_dead.erl b/lib/compiler/src/beam_ssa_dead.erl
index 2cca9ebadf..bb43a550ae 100644
--- a/lib/compiler/src/beam_ssa_dead.erl
+++ b/lib/compiler/src/beam_ssa_dead.erl
@@ -27,7 +27,8 @@
-export([opt/1]).
-include("beam_ssa.hrl").
--import(lists, [append/1,last/1,member/2,takewhile/2,reverse/1]).
+-import(lists, [append/1,keymember/3,last/1,member/2,
+ takewhile/2,reverse/1]).
-type used_vars() :: #{beam_ssa:label():=ordsets:ordset(beam_ssa:var_name())}.
@@ -58,7 +59,7 @@ opt(Linear) ->
Blocks0 = maps:from_list(Linear),
St0 = #st{bs=Blocks0,us=Used,skippable=Skippable},
St = shortcut_opt(St0),
- #st{bs=Blocks} = combine_eqs(St),
+ #st{bs=Blocks} = combine_eqs(St#st{us=#{}}),
beam_ssa:linearize(Blocks).
%%%
@@ -87,13 +88,22 @@ shortcut_opt(#st{bs=Blocks}=St) ->
%% opportunities for optimizations compared to post order. (Based on
%% running scripts/diffable with both PO and RPO and looking at
%% the diff.)
+ %%
+ %% Unfortunately, processing the blocks in reverse post order
+ %% potentially makes the time complexity quadratic or even cubic if
+ %% the ordset of unset variables grows large, instead of
+ %% linear for post order processing. We try to still get reasonable
+ %% compilation times by optimizations that will keep the constant
+ %% factor as low as possible, and we try to avoid the cubic time
+ %% complexity by trying to keep the set of unset variables as small
+ %% as possible.
+
Ls = beam_ssa:rpo(Blocks),
- shortcut_opt(Ls, #{from=>0}, St).
+ shortcut_opt(Ls, #{}, St).
-shortcut_opt([L|Ls], Bs0, #st{bs=Blocks0}=St) ->
+shortcut_opt([L|Ls], Bs, #st{bs=Blocks0}=St) ->
#b_blk{is=Is,last=Last0} = Blk0 = get_block(L, St),
- Bs = Bs0#{from:=L},
- case shortcut_terminator(Last0, Is, Bs, St) of
+ case shortcut_terminator(Last0, Is, L, Bs, St) of
Last0 ->
%% No change. No need to update the block.
shortcut_opt(Ls, Bs, St);
@@ -107,17 +117,17 @@ shortcut_opt([L|Ls], Bs0, #st{bs=Blocks0}=St) ->
shortcut_opt([], _, St) -> St.
shortcut_terminator(#b_br{bool=#b_literal{val=true},succ=Succ0},
- _Is, Bs, St0) ->
+ _Is, From, Bs, St0) ->
St = St0#st{rel_op=none},
- shortcut(Succ0, Bs, St);
+ shortcut(Succ0, From, Bs, St);
shortcut_terminator(#b_br{bool=#b_var{}=Bool,succ=Succ0,fail=Fail0}=Br,
- Is, Bs, St0) ->
+ Is, From, Bs, St0) ->
St = St0#st{target=one_way},
RelOp = get_rel_op(Bool, Is),
SuccBs = bind_var(Bool, #b_literal{val=true}, Bs),
- BrSucc = shortcut(Succ0, SuccBs, St#st{rel_op=RelOp}),
+ BrSucc = shortcut(Succ0, From, SuccBs, St#st{rel_op=RelOp}),
FailBs = bind_var(Bool, #b_literal{val=false}, Bs),
- BrFail = shortcut(Fail0, FailBs, St#st{rel_op=invert_op(RelOp)}),
+ BrFail = shortcut(Fail0, From, FailBs, St#st{rel_op=invert_op(RelOp)}),
case {BrSucc,BrFail} of
{#b_br{bool=#b_literal{val=true},succ=Succ},
#b_br{bool=#b_literal{val=true},succ=Fail}}
@@ -128,25 +138,25 @@ shortcut_terminator(#b_br{bool=#b_var{}=Bool,succ=Succ0,fail=Fail0}=Br,
%% No change.
Br
end;
-shortcut_terminator(#b_switch{arg=Bool,list=List0}=Sw, _Is, Bs, St) ->
- List = shortcut_switch(List0, Bool, Bs, St),
+shortcut_terminator(#b_switch{arg=Bool,list=List0}=Sw, _Is, From, Bs, St) ->
+ List = shortcut_switch(List0, Bool, From, Bs, St),
beam_ssa:normalize(Sw#b_switch{list=List});
-shortcut_terminator(Last, _Is, _Bs, _St) ->
+shortcut_terminator(Last, _Is, _Bs, _From, _St) ->
Last.
-shortcut_switch([{Lit,L0}|T], Bool, Bs, St0) ->
+shortcut_switch([{Lit,L0}|T], Bool, From, Bs, St0) ->
RelOp = {'=:=',Bool,Lit},
St = St0#st{rel_op=RelOp},
#b_br{bool=#b_literal{val=true},succ=L} =
- shortcut(L0, bind_var(Bool, Lit, Bs), St#st{target=one_way}),
- [{Lit,L}|shortcut_switch(T, Bool, Bs, St0)];
-shortcut_switch([], _, _, _) -> [].
+ shortcut(L0, From, bind_var(Bool, Lit, Bs), St#st{target=one_way}),
+ [{Lit,L}|shortcut_switch(T, Bool, From, Bs, St0)];
+shortcut_switch([], _, _, _, _) -> [].
-shortcut(L, Bs, St) ->
- shortcut_1(L, Bs, ordsets:new(), St).
+shortcut(L, From, Bs, St) ->
+ shortcut_1(L, From, Bs, ordsets:new(), St).
-shortcut_1(L, Bs0, UnsetVars0, St) ->
- case shortcut_2(L, Bs0, UnsetVars0, St) of
+shortcut_1(L, From, Bs0, UnsetVars0, St) ->
+ case shortcut_2(L, From, Bs0, UnsetVars0, St) of
none ->
%% No more shortcuts found. Package up the previous
%% label in an unconditional branch.
@@ -156,13 +166,13 @@ shortcut_1(L, Bs0, UnsetVars0, St) ->
Br;
{#b_br{bool=#b_literal{val=true},succ=Succ},Bs,UnsetVars} ->
%% This is a safe `br`, but try to find a better one.
- shortcut_1(Succ, Bs#{from:=L}, UnsetVars, St)
+ shortcut_1(Succ, L, Bs, UnsetVars, St)
end.
%% Try to shortcut this block, branching to a successor.
-shortcut_2(L, Bs0, UnsetVars0, St) ->
+shortcut_2(L, From, Bs0, UnsetVars0, St) ->
#b_blk{is=Is,last=Last} = get_block(L, St),
- case eval_is(Is, Bs0, St) of
+ case eval_is(Is, From, Bs0, St) of
none ->
%% It is not safe to avoid this block because it
%% has instructions with potential side effects.
@@ -181,139 +191,147 @@ shortcut_2(L, Bs0, UnsetVars0, St) ->
%% We have a potentially suitable br.
%% Now update the set of variables that will never
%% be set if this block will be skipped.
- SetInThisBlock = [V || #b_set{dst=V} <- Is],
- UnsetVars = update_unset_vars(L, Br, SetInThisBlock,
- UnsetVars0, St),
-
- %% Continue checking whether this br is suitable.
- shortcut_3(Br, Bs#{from:=L}, UnsetVars, St)
+ case update_unset_vars(L, Is, Br, UnsetVars0, St) of
+ unsafe ->
+ %% It is unsafe to use this br,
+ %% because it refers to a variable defined
+ %% in this block.
+ shortcut_unsafe_br(Br, L, Bs, UnsetVars0, St);
+ UnsetVars ->
+ %% Continue checking whether this br is
+ %% suitable.
+ shortcut_test_br(Br, L, Bs, UnsetVars, St)
+ end
end
end.
-shortcut_3(Br, Bs, UnsetVars, #st{target=Target}=St) ->
+shortcut_test_br(Br, From, Bs, UnsetVars, St) ->
case is_br_safe(UnsetVars, Br, St) of
false ->
- %% Branching using this `br` is unsafe, either because it
- %% is an unconditional branch to a phi node, or because
- %% one or more of the variables that are not set will be
- %% used. Try to follow branches of this `br`, to find a
- %% safe `br`.
- case Br of
- #b_br{bool=#b_literal{val=true},succ=L} ->
- case Target of
- L ->
- %% We have reached the forced target, and it
- %% is unsafe. Give up.
- none;
- _ ->
- %% Try following this branch to see whether it
- %% leads to a safe `br`.
- shortcut_2(L, Bs, UnsetVars, St)
- end;
- #b_br{bool=#b_var{},succ=Succ,fail=Fail} ->
- case {Succ,Fail} of
- {L,Target} ->
- %% The failure label is the forced target.
- %% Try following the success label to see
- %% whether it also ultimately ends up at the
- %% forced target.
- shortcut_2(L, Bs, UnsetVars, St);
- {Target,L} ->
- %% The success label is the forced target.
- %% Try following the failure label to see
- %% whether it also ultimately ends up at the
- %% forced target.
- shortcut_2(L, Bs, UnsetVars, St);
- {_,_} ->
- case Target of
- any ->
- %% This two-way branch is unsafe. Try reducing
- %% it to a one-way branch.
- shortcut_two_way(Br, Bs, UnsetVars, St);
- one_way ->
- %% This two-way branch is unsafe. Try reducing
- %% it to a one-way branch.
- shortcut_two_way(Br, Bs, UnsetVars, St);
- _ when is_integer(Target) ->
- %% This two-way branch is unsafe, and
- %% there already is a forced target.
- %% Give up.
- none
- end
- end
- end;
+ shortcut_unsafe_br(Br, From, Bs, UnsetVars, St);
true ->
- %% This `br` instruction is safe. It does not
- %% branch to a phi node, and all variables that
- %% will be used are guaranteed to be defined.
- case Br of
- #b_br{bool=#b_literal{val=true},succ=L} ->
- %% This is a one-way branch.
+ shortcut_safe_br(Br, From, Bs, UnsetVars, St)
+ end.
+
+shortcut_unsafe_br(Br, From, Bs, UnsetVars, #st{target=Target}=St) ->
+ %% Branching using this `br` is unsafe, either because it
+ %% is an unconditional branch to a phi node, or because
+ %% one or more of the variables that are not set will be
+ %% used. Try to follow branches of this `br`, to find a
+ %% safe `br`.
+ case Br of
+ #b_br{bool=#b_literal{val=true},succ=L} ->
+ case Target of
+ L ->
+ %% We have reached the forced target, and it
+ %% is unsafe. Give up.
+ none;
+ _ ->
+ %% Try following this branch to see whether it
+ %% leads to a safe `br`.
+ shortcut_2(L, From, Bs, UnsetVars, St)
+ end;
+ #b_br{bool=#b_var{},succ=Succ,fail=Fail} ->
+ case {Succ,Fail} of
+ {L,Target} ->
+ %% The failure label is the forced target.
+ %% Try following the success label to see
+ %% whether it also ultimately ends up at the
+ %% forced target.
+ shortcut_2(L, From, Bs, UnsetVars, St);
+ {Target,L} ->
+ %% The success label is the forced target.
+ %% Try following the failure label to see
+ %% whether it also ultimately ends up at the
+ %% forced target.
+ shortcut_2(L, From, Bs, UnsetVars, St);
+ {_,_} ->
case Target of
any ->
- %% No forced target. Success!
- {Br,Bs,UnsetVars};
+ %% This two-way branch is unsafe. Try
+ %% reducing it to a one-way branch.
+ shortcut_two_way(Br, From, Bs, UnsetVars, St);
one_way ->
- %% The target must be a one-way branch, which this
- %% `br` is. Success!
- {Br,Bs,UnsetVars};
- L when is_integer(Target) ->
- %% The forced target is L. Success!
- {Br,Bs,UnsetVars};
+ %% This two-way branch is unsafe. Try
+ %% reducing it to a one-way branch.
+ shortcut_two_way(Br, From, Bs, UnsetVars, St);
_ when is_integer(Target) ->
- %% Wrong forced target. Try following this branch
- %% to see if it ultimately ends up at the forced
- %% target.
- shortcut_2(L, Bs, UnsetVars, St)
- end;
- #b_br{bool=#b_var{}} ->
- %% This is a two-way branch.
- if
- Target =:= any; Target =:= one_way ->
- %% No specific forced target. Try to reduce the
- %% two-way branch to an one-way branch.
- case shortcut_two_way(Br, Bs, UnsetVars, St) of
- none when Target =:= any ->
- %% This `br` can't be reduced to a one-way
- %% branch. Return the `br` as-is.
- {Br,Bs,UnsetVars};
- none when Target =:= one_way ->
- %% This `br` can't be reduced to a one-way
- %% branch. The caller wants a one-way branch.
- %% Give up.
- none;
- {_,_,_}=Res ->
- %% This `br` was successfully reduced to a
- %% one-way branch.
- Res
- end;
- is_integer(Target) ->
- %% There is a forced target, which can't
- %% be reached because this `br` is a two-way
- %% branch. Give up.
+ %% This two-way branch is unsafe, and
+ %% there already is a forced target.
+ %% Give up.
none
end
end
end.
-update_unset_vars(L, Br, SetInThisBlock, UnsetVars, #st{skippable=Skippable}) ->
+shortcut_safe_br(Br, From, Bs, UnsetVars, #st{target=Target}=St) ->
+ %% This `br` instruction is safe. It does not branch to a phi
+ %% node, and all variables that will be used are guaranteed to be
+ %% defined.
+ case Br of
+ #b_br{bool=#b_literal{val=true},succ=L} ->
+ %% This is a one-way branch.
+ case Target of
+ any ->
+ %% No forced target. Success!
+ {Br,Bs,UnsetVars};
+ one_way ->
+ %% The target must be a one-way branch, which this
+ %% `br` is. Success!
+ {Br,Bs,UnsetVars};
+ L when is_integer(Target) ->
+ %% The forced target is L. Success!
+ {Br,Bs,UnsetVars};
+ _ when is_integer(Target) ->
+ %% Wrong forced target. Try following this branch
+ %% to see if it ultimately ends up at the forced
+ %% target.
+ shortcut_2(L, From, Bs, UnsetVars, St)
+ end;
+ #b_br{bool=#b_var{}} ->
+ %% This is a two-way branch.
+ if
+ Target =:= any; Target =:= one_way ->
+ %% No specific forced target. Try to reduce the
+ %% two-way branch to an one-way branch.
+ case shortcut_two_way(Br, From, Bs, UnsetVars, St) of
+ none when Target =:= any ->
+ %% This `br` can't be reduced to a one-way
+ %% branch. Return the `br` as-is.
+ {Br,Bs,UnsetVars};
+ none when Target =:= one_way ->
+ %% This `br` can't be reduced to a one-way
+ %% branch. The caller wants a one-way
+ %% branch. Give up.
+ none;
+ {_,_,_}=Res ->
+ %% This `br` was successfully reduced to a
+ %% one-way branch.
+ Res
+ end;
+ is_integer(Target) ->
+ %% There is a forced target, which can't
+ %% be reached because this `br` is a two-way
+ %% branch. Give up.
+ none
+ end
+ end.
+
+update_unset_vars(L, Is, Br, UnsetVars, #st{skippable=Skippable}) ->
case is_map_key(L, Skippable) of
true ->
%% None of the variables used in this block are used in
- %% the successors. We can speed up compilation by avoiding
- %% adding variables to the UnsetVars if the presence of
- %% those variable would not change the outcome of the
- %% tests in is_br_safe/2.
+ %% the successors. Thus, there is no need to add the
+ %% variables to the set of unset variables.
case Br of
- #b_br{bool=Bool} ->
- case member(Bool, SetInThisBlock) of
+ #b_br{bool=#b_var{}=Bool} ->
+ case keymember(Bool, #b_set.dst, Is) of
true ->
%% Bool is a variable defined in this
- %% block. It will change the outcome of
- %% the `not member(V, UnsetVars)` check in
- %% is_br_safe/2. The other variables
- %% defined in this block will not.
- ordsets:add_element(Bool, UnsetVars);
+ %% block. Using the br instruction from
+ %% this block (and skipping the body of
+ %% the block) is unsafe.
+ unsafe;
false ->
%% Bool is either a variable not defined
%% in this block or a literal. Adding it
@@ -321,18 +339,24 @@ update_unset_vars(L, Br, SetInThisBlock, UnsetVars, #st{skippable=Skippable}) ->
%% the outcome of the tests in
%% is_br_safe/2.
UnsetVars
- end
+ end;
+ #b_br{} ->
+ UnsetVars
end;
false ->
+ %% Some variables defined in this block are used by
+ %% successors. We must update the set of unset variables.
+ SetInThisBlock = [V || #b_set{dst=V} <- Is],
ordsets:union(UnsetVars, ordsets:from_list(SetInThisBlock))
end.
-shortcut_two_way(#b_br{succ=Succ,fail=Fail}, Bs0, UnsetVars0, St) ->
- case shortcut_2(Succ, Bs0, UnsetVars0, St#st{target=Fail}) of
+shortcut_two_way(#b_br{succ=Succ,fail=Fail}, From, Bs0, UnsetVars0, St0) ->
+ case shortcut_2(Succ, From, Bs0, UnsetVars0, St0#st{target=Fail}) of
{#b_br{bool=#b_literal{},succ=Fail},_,_}=Res ->
Res;
none ->
- case shortcut_2(Fail, Bs0, UnsetVars0, St#st{target=Succ}) of
+ St = St0#st{target=Succ},
+ case shortcut_2(Fail, From, Bs0, UnsetVars0, St) of
{#b_br{bool=#b_literal{},succ=Succ},_,_}=Res ->
Res;
none ->
@@ -374,40 +398,42 @@ is_forbidden(L, St) ->
%% Return the updated bindings, or 'none' if there is
%% any instruction with potential side effects.
-eval_is([#b_set{op=phi,dst=Dst,args=Args}|Is], Bs0, St) ->
- From = map_get(from, Bs0),
- [Val] = [Val || {Val,Pred} <- Args, Pred =:= From],
+eval_is([#b_set{op=phi,dst=Dst,args=Args}|Is], From, Bs0, St) ->
+ Val = get_phi_arg(Args, From),
Bs = bind_var(Dst, Val, Bs0),
- eval_is(Is, Bs, St);
-eval_is([#b_set{op={bif,_},dst=Dst}=I0|Is], Bs, St) ->
+ eval_is(Is, From, Bs, St);
+eval_is([#b_set{op={bif,_},dst=Dst}=I0|Is], From, Bs, St) ->
I = sub(I0, Bs),
case eval_bif(I, St) of
#b_literal{}=Val ->
- eval_is(Is, bind_var(Dst, Val, Bs), St);
+ eval_is(Is, From, bind_var(Dst, Val, Bs), St);
none ->
- eval_is(Is, Bs, St)
+ eval_is(Is, From, Bs, St)
end;
-eval_is([#b_set{op=Op,dst=Dst}=I|Is], Bs, St)
+eval_is([#b_set{op=Op,dst=Dst}=I|Is], From, Bs, St)
when Op =:= is_tagged_tuple; Op =:= is_nonempty_list ->
#b_set{args=Args} = sub(I, Bs),
case eval_rel_op(Op, Args, St) of
#b_literal{}=Val ->
- eval_is(Is, bind_var(Dst, Val, Bs), St);
+ eval_is(Is, From, bind_var(Dst, Val, Bs), St);
none ->
- eval_is(Is, Bs, St)
+ eval_is(Is, From, Bs, St)
end;
-eval_is([#b_set{}=I|Is], Bs, St) ->
+eval_is([#b_set{}=I|Is], From, Bs, St) ->
case beam_ssa:no_side_effect(I) of
true ->
%% This instruction has no side effects. It can
%% safely be omitted.
- eval_is(Is, Bs, St);
+ eval_is(Is, From, Bs, St);
false ->
%% This instruction may have some side effect.
%% It is not safe to avoid this instruction.
none
end;
-eval_is([], Bs, _St) -> Bs.
+eval_is([], _From, Bs, _St) -> Bs.
+
+get_phi_arg([{Val,From}|_], From) -> Val;
+get_phi_arg([_|As], From) -> get_phi_arg(As, From).
eval_terminator(#b_br{bool=#b_var{}=Bool}=Br, Bs, _St) ->
Val = get_value(Bool, Bs),
@@ -477,20 +503,31 @@ eval_bif(#b_set{op={bif,Bif},args=Args}, St) ->
false ->
none;
true ->
- case [Lit || #b_literal{val=Lit} <- Args] of
- LitArgs when length(LitArgs) =:= Arity ->
+ case get_lit_args(Args) of
+ none ->
+ %% Not literal arguments. Try to evaluate
+ %% it based on a previous relational operator.
+ eval_rel_op({bif,Bif}, Args, St);
+ LitArgs ->
try apply(erlang, Bif, LitArgs) of
Val -> #b_literal{val=Val}
catch
error:_ -> none
- end;
- _ ->
- %% Not literal arguments. Try to evaluate
- %% it based on a previous relational operator.
- eval_rel_op({bif,Bif}, Args, St)
+ end
end
end.
+get_lit_args([#b_literal{val=Lit1}]) ->
+ [Lit1];
+get_lit_args([#b_literal{val=Lit1},
+ #b_literal{val=Lit2}]) ->
+ [Lit1,Lit2];
+get_lit_args([#b_literal{val=Lit1},
+ #b_literal{val=Lit2},
+ #b_literal{val=Lit3}]) ->
+ [Lit1,Lit2,Lit3];
+get_lit_args(_) -> none.
+
%%%
%%% Handling of relational operators.
%%%
@@ -1026,11 +1063,12 @@ used_vars_is([], Used) ->
sub(#b_set{args=Args}=I, Sub) ->
I#b_set{args=[sub_arg(A, Sub) || A <- Args]}.
-sub_arg(Old, Sub) ->
+sub_arg(#b_var{}=Old, Sub) ->
case Sub of
#{Old:=New} -> New;
#{} -> Old
- end.
+ end;
+sub_arg(Old, _Sub) -> Old.
rel2fam(S0) ->
S1 = sofs:relation(S0),
diff --git a/lib/compiler/src/beam_ssa_opt.erl b/lib/compiler/src/beam_ssa_opt.erl
index 6e548dd529..bcf55f3fda 100644
--- a/lib/compiler/src/beam_ssa_opt.erl
+++ b/lib/compiler/src/beam_ssa_opt.erl
@@ -175,6 +175,7 @@ epilogue_passes(Opts) ->
?PASS(ssa_opt_blockify),
?PASS(ssa_opt_sink),
?PASS(ssa_opt_merge_blocks),
+ ?PASS(ssa_opt_get_tuple_element),
?PASS(ssa_opt_trim_unreachable)],
passes_1(Ps, Opts).
@@ -682,6 +683,14 @@ record_opt_is([#b_set{op={bif,is_tuple},dst=Bool,args=[Tuple]}=Set],
no ->
[Set]
end;
+record_opt_is([I|Is]=Is0, #b_br{bool=Bool}=Last, Blocks) ->
+ case is_tagged_tuple_1(Is0, Last, Blocks) of
+ {yes,_Fail,Tuple,Arity,Tag} ->
+ Args = [Tuple,Arity,Tag],
+ [I#b_set{op=is_tagged_tuple,dst=Bool,args=Args}];
+ no ->
+ [I|record_opt_is(Is, Last, Blocks)]
+ end;
record_opt_is([I|Is], Last, Blocks) ->
[I|record_opt_is(Is, Last, Blocks)];
record_opt_is([], _Last, _Blocks) -> [].
@@ -689,29 +698,30 @@ record_opt_is([], _Last, _Blocks) -> [].
is_tagged_tuple(#b_var{}=Tuple, Bool,
#b_br{bool=Bool,succ=Succ,fail=Fail},
Blocks) ->
- SuccBlk = map_get(Succ, Blocks),
- is_tagged_tuple_1(SuccBlk, Tuple, Fail, Blocks);
+ #b_blk{is=Is,last=Last} = map_get(Succ, Blocks),
+ case is_tagged_tuple_1(Is, Last, Blocks) of
+ {yes,Fail,Tuple,Arity,Tag} ->
+ {yes,Arity,Tag};
+ _ ->
+ no
+ end;
is_tagged_tuple(_, _, _, _) -> no.
-is_tagged_tuple_1(#b_blk{is=Is,last=Last}, Tuple, Fail, Blocks) ->
- case Is of
- [#b_set{op={bif,tuple_size},dst=ArityVar,
- args=[#b_var{}=Tuple]},
- #b_set{op={bif,'=:='},
- dst=Bool,
- args=[ArityVar, #b_literal{val=ArityVal}=Arity]}]
- when is_integer(ArityVal) ->
- case Last of
- #b_br{bool=Bool,succ=Succ,fail=Fail} ->
- SuccBlk = map_get(Succ, Blocks),
- case is_tagged_tuple_2(SuccBlk, Tuple, Fail) of
- no ->
- no;
- {yes,Tag} ->
- {yes,Arity,Tag}
- end;
- _ ->
- no
+is_tagged_tuple_1(Is, Last, Blocks) ->
+ case {Is,Last} of
+ {[#b_set{op={bif,tuple_size},dst=ArityVar,
+ args=[#b_var{}=Tuple]},
+ #b_set{op={bif,'=:='},
+ dst=Bool,
+ args=[ArityVar, #b_literal{val=ArityVal}=Arity]}],
+ #b_br{bool=Bool,succ=Succ,fail=Fail}}
+ when is_integer(ArityVal) ->
+ SuccBlk = map_get(Succ, Blocks),
+ case is_tagged_tuple_2(SuccBlk, Tuple, Fail) of
+ no ->
+ no;
+ {yes,Tag} ->
+ {yes,Fail,Tuple,Arity,Tag}
end;
_ ->
no
@@ -2174,6 +2184,46 @@ insert_def_is([#b_set{op=Op}=I|Is]=Is0, V, Def) ->
insert_def_is([], _V, Def) ->
[Def].
+%%%
+%%% Order consecutive get_tuple_element instructions in ascending
+%%% position order. This will give the loader more opportunities
+%%% for combining get_tuple_element instructions.
+%%%
+
+ssa_opt_get_tuple_element({#st{ssa=Blocks0}=St, FuncDb}) ->
+ Blocks = opt_get_tuple_element(maps:to_list(Blocks0), Blocks0),
+ {St#st{ssa=Blocks}, FuncDb}.
+
+opt_get_tuple_element([{L,#b_blk{is=Is0}=Blk0}|Bs], Blocks) ->
+ case opt_get_tuple_element_is(Is0, false, []) of
+ {yes,Is} ->
+ Blk = Blk0#b_blk{is=Is},
+ opt_get_tuple_element(Bs, Blocks#{L:=Blk});
+ no ->
+ opt_get_tuple_element(Bs, Blocks)
+ end;
+opt_get_tuple_element([], Blocks) -> Blocks.
+
+opt_get_tuple_element_is([#b_set{op=get_tuple_element,
+ args=[#b_var{}=Src,_]}=I0|Is0],
+ _AnyChange, Acc) ->
+ {GetIs0,Is} = collect_get_tuple_element(Is0, Src, [I0]),
+ GetIs1 = sort([{Pos,I} || #b_set{args=[_,Pos]}=I <- GetIs0]),
+ GetIs = [I || {_,I} <- GetIs1],
+ opt_get_tuple_element_is(Is, true, reverse(GetIs, Acc));
+opt_get_tuple_element_is([I|Is], AnyChange, Acc) ->
+ opt_get_tuple_element_is(Is, AnyChange, [I|Acc]);
+opt_get_tuple_element_is([], AnyChange, Acc) ->
+ case AnyChange of
+ true -> {yes,reverse(Acc)};
+ false -> no
+ end.
+
+collect_get_tuple_element([#b_set{op=get_tuple_element,
+ args=[Src,_]}=I|Is], Src, Acc) ->
+ collect_get_tuple_element(Is, Src, [I|Acc]);
+collect_get_tuple_element(Is, _Src, Acc) ->
+ {Acc,Is}.
%%%
%%% Common utilities.
diff --git a/lib/compiler/src/beam_ssa_type.erl b/lib/compiler/src/beam_ssa_type.erl
index aa4720d222..c01ea4af91 100644
--- a/lib/compiler/src/beam_ssa_type.erl
+++ b/lib/compiler/src/beam_ssa_type.erl
@@ -170,7 +170,8 @@ opt_finish_1([], [], ParamInfo) ->
validator_anno(#t_tuple{size=Size,exact=Exact,elements=Elements0}) ->
Elements = maps:fold(fun(Index, Type, Acc) ->
- Acc#{ Index => validator_anno(Type) }
+ Key = beam_validator:type_anno(integer, Index),
+ Acc#{ Key => validator_anno(Type) }
end, #{}, Elements0),
beam_validator:type_anno(tuple, Size, Exact, Elements);
validator_anno(#t_integer{elements={Same,Same}}) ->
diff --git a/lib/compiler/src/beam_validator.erl b/lib/compiler/src/beam_validator.erl
index 5175be3ad5..296c095be2 100644
--- a/lib/compiler/src/beam_validator.erl
+++ b/lib/compiler/src/beam_validator.erl
@@ -28,8 +28,7 @@
-export([module/2, format_error/1]).
-export([type_anno/1, type_anno/2, type_anno/4]).
--import(lists, [any/2,dropwhile/2,foldl/3,map/2,member/2,reverse/1,
- seq/2,sort/1,zip/2]).
+-import(lists, [dropwhile/2,foldl/3,member/2,reverse/1,sort/1,zip/2]).
%% To be called by the compiler.
@@ -51,7 +50,7 @@ module({Mod,Exp,Attr,Fs,Lc}=Code, _Opts)
-spec type_anno(term()) -> term().
type_anno(atom) -> {atom,[]};
type_anno(bool) -> bool;
-type_anno({binary,_}) -> term;
+type_anno({binary,_}) -> binary;
type_anno(cons) -> cons;
type_anno(float) -> {float,[]};
type_anno(integer) -> {integer,[]};
@@ -62,9 +61,9 @@ type_anno(number) -> number;
type_anno(nil) -> nil.
-spec type_anno(term(), term()) -> term().
-type_anno(atom, Value) -> {atom, Value};
-type_anno(float, Value) -> {float, Value};
-type_anno(integer, Value) -> {integer, Value}.
+type_anno(atom, Value) when is_atom(Value) -> {atom, Value};
+type_anno(float, Value) when is_float(Value) -> {float, Value};
+type_anno(integer, Value) when is_integer(Value) -> {integer, Value}.
-spec type_anno(term(), term(), term(), term()) -> term().
type_anno(tuple, Size, Exact, Elements) when is_integer(Size), Size >= 0,
@@ -137,43 +136,100 @@ validate_0(Module, [{function,Name,Ar,Entry,Code}|Fs], Ft) ->
erlang:raise(Class, Error, Stack)
end.
+-record(value_ref, {id :: index()}).
+-record(value, {op :: term(), args :: [argument()], type :: type()}).
+
+-type argument() :: #value_ref{} | literal().
+
-type index() :: non_neg_integer().
--type reg_tab() :: gb_trees:tree(index(), 'none' | {'value', _}).
-
--record(st, %Emulation state
- {x :: reg_tab(), %x register info.
- y :: reg_tab(), %y register info.
- f=init_fregs(), %
- numy=none, %Number of y registers.
- h=0, %Available heap size.
- hf=0, %Available heap size for floats.
- fls=undefined, %Floating point state.
- ct=[], %List of hot catch/try labels
- setelem=false, %Previous instruction was setelement/3.
- puts_left=none, %put/1 instructions left.
- defs=#{}, %Defining expression for each register.
- aliases=#{}
- }).
+
+-type literal() :: {atom, [] | atom()} |
+ {float, [] | float()} |
+ {integer, [] | integer()} |
+ {literal, term()} |
+ nil.
+
+-type tuple_sz() :: [non_neg_integer()] | %% Inexact
+ non_neg_integer(). %% Exact.
+
+%% Match context type.
+-record(ms,
+ {id=make_ref() :: reference(), %Unique ID.
+ valid=0 :: non_neg_integer(), %Valid slots
+ slots=0 :: non_neg_integer() %Number of slots
+ }).
+
+-type type() :: binary |
+ cons |
+ list |
+ map |
+ nil |
+ #ms{} |
+ ms_position |
+ none |
+ number |
+ term |
+ tuple_in_progress |
+ {tuple, tuple_sz(), #{ literal() => type() }} |
+ literal().
+
+-type tag() :: initialized |
+ uninitialized |
+ {catchtag, [label()]} |
+ {trytag, [label()]}.
+
+-type x_regs() :: #{ {x, index()} => #value_ref{} }.
+-type y_regs() :: #{ {y, index()} => tag() | #value_ref{} }.
+
+%% Emulation state
+-record(st,
+ {%% All known values.
+ vs=#{} :: #{ #value_ref{} => #value{} },
+ %% Register states.
+ xs=#{} :: x_regs(),
+ ys=#{} :: y_regs(),
+ f=init_fregs(),
+ %% A set of all registers containing "fragile" terms. That is, terms
+ %% that don't exist on our process heap and would be destroyed by a
+ %% GC.
+ fragile=cerl_sets:new() :: cerl_sets:set(),
+ %% Number of Y registers.
+ %%
+ %% Note that this may be 0 if there's a frame without saved values,
+ %% such as on a body-recursive call.
+ numy=none :: none | undecided | index(),
+ %% Available heap size.
+ h=0,
+ %Available heap size for floats.
+ hf=0,
+ %% Floating point state.
+ fls=undefined,
+ %% List of hot catch/try labels
+ ct=[],
+ %% Previous instruction was setelement/3.
+ setelem=false,
+ %% put/1 instructions left.
+ puts_left=none
+ }).
-type label() :: integer().
-type label_set() :: gb_sets:set(label()).
-type branched_tab() :: gb_trees:tree(label(), #st{}).
-type ft_tab() :: gb_trees:tree().
--record(vst, %Validator state
- {current=none :: #st{} | 'none', %Current state
- branched=gb_trees:empty() :: branched_tab(), %States at jumps
- labels=gb_sets:empty() :: label_set(), %All defined labels
- ft=gb_trees:empty() :: ft_tab() %Some other functions
- % in the module (those that start with bs_start_match2).
- }).
-
-%% Match context type.
--record(ms,
- {id=make_ref() :: reference(), %Unique ID.
- valid=0 :: non_neg_integer(), %Valid slots
- slots=0 :: non_neg_integer() %Number of slots
- }).
+%% Validator state
+-record(vst,
+ {%% Current state
+ current=none :: #st{} | 'none',
+ %% States at labels
+ branched=gb_trees:empty() :: branched_tab(),
+ %% All defined labels
+ labels=gb_sets:empty() :: label_set(),
+ %% Argument information of other functions in the module
+ ft=gb_trees:empty() :: ft_tab(),
+ %% Counter for #value_ref{} creation
+ ref_ctr=0 :: index()
+ }).
index_parameter_types([{function,_,_,Entry,Code0}|Fs], Acc0) ->
Code = dropwhile(fun({label,L}) when L =:= Entry -> false;
@@ -238,7 +294,7 @@ validate_fun_info_branches_1(X, {Mod,Name,Arity}=MFA, Vst) ->
#vst{current=#st{numy=Size}} ->
error({unexpected_stack_frame,Size})
end,
- get_term_type({x,X}, Vst)
+ assert_term({x,X}, Vst)
catch Error ->
I = {func_info,{atom,Mod},{atom,Name},Arity},
Offset = 2,
@@ -260,24 +316,21 @@ labels_1(Is, R) ->
{reverse(R),Is}.
init_vst(Arity, Ls1, Ls2, Ft) ->
- Xs = init_regs(Arity, term),
- Ys = init_regs(0, initialized),
- St = #st{x=Xs,y=Ys},
- Branches = gb_trees_from_list([{L,St} || L <- Ls1]),
+ Vst0 = init_function_args(Arity - 1, #vst{current=#st{}}),
+ Branches = gb_trees_from_list([{L,Vst0#vst.current} || L <- Ls1]),
Labels = gb_sets:from_list(Ls1++Ls2),
- #vst{branched=Branches,
- current=St,
- labels=Labels,
- ft=Ft}.
+ Vst0#vst{branched=Branches,
+ labels=Labels,
+ ft=Ft}.
+
+init_function_args(-1, Vst) ->
+ Vst;
+init_function_args(X, Vst) ->
+ init_function_args(X - 1, create_term(term, argument, [], {x,X}, Vst)).
kill_heap_allocation(St) ->
St#st{h=0,hf=0}.
-init_regs(0, _) ->
- gb_trees:empty();
-init_regs(N, Type) ->
- gb_trees_from_list([{R,Type} || R <- seq(0, N-1)]).
-
valfun([], MFA, _Offset, #vst{branched=Targets0,labels=Labels0}=Vst) ->
Targets = gb_trees:keys(Targets0),
Labels = gb_sets:to_list(Labels0),
@@ -298,20 +351,25 @@ valfun([I|Is], MFA, Offset, Vst0) ->
%% Instructions that are allowed in dead code or when failing,
%% that is while the state is undecided in some way.
-valfun_1({label,Lbl}, #vst{current=St0,branched=B,labels=Lbls}=Vst) ->
- St = merge_states(Lbl, St0, B),
- Vst#vst{current=St,branched=gb_trees:enter(Lbl, St, B),
- labels=gb_sets:add(Lbl, Lbls)};
+valfun_1({label,Lbl}, #vst{current=St0,
+ ref_ctr=Counter0,
+ branched=B,
+ labels=Lbls}=Vst) ->
+ {St, Counter} = merge_states(Lbl, St0, B, Counter0),
+ Vst#vst{current=St,
+ ref_ctr=Counter,
+ branched=gb_trees:enter(Lbl, St, B),
+ labels=gb_sets:add(Lbl, Lbls)};
valfun_1(_I, #vst{current=none}=Vst) ->
%% Ignore instructions after erlang:error/1,2, which
%% the original R10B compiler thought would return.
Vst;
valfun_1({badmatch,Src}, Vst) ->
- assert_not_fragile(Src, Vst),
+ assert_durable_term(Src, Vst),
verify_y_init(Vst),
kill_state(Vst);
valfun_1({case_end,Src}, Vst) ->
- assert_not_fragile(Src, Vst),
+ assert_durable_term(Src, Vst),
verify_y_init(Vst),
kill_state(Vst);
valfun_1(if_end, Vst) ->
@@ -319,7 +377,7 @@ valfun_1(if_end, Vst) ->
kill_state(Vst);
valfun_1({try_case_end,Src}, Vst) ->
verify_y_init(Vst),
- assert_not_fragile(Src, Vst),
+ assert_durable_term(Src, Vst),
kill_state(Vst);
%% Instructions that cannot cause exceptions
valfun_1({bs_get_tail,Ctx,Dst,Live}, Vst0) ->
@@ -363,17 +421,17 @@ valfun_1({bif,Op,{f,_},Ss,Dst}=I, Vst) ->
end;
%% Put instructions.
valfun_1({put_list,A,B,Dst}, Vst0) ->
- assert_not_fragile(A, Vst0),
- assert_not_fragile(B, Vst0),
+ assert_term(A, Vst0),
+ assert_term(B, Vst0),
Vst = eat_heap(2, Vst0),
create_term(cons, put_list, [A, B], Dst, Vst);
valfun_1({put_tuple2,Dst,{list,Elements}}, Vst0) ->
- _ = [assert_not_fragile(El, Vst0) || El <- Elements],
+ _ = [assert_term(El, Vst0) || El <- Elements],
Size = length(Elements),
Vst = eat_heap(Size+1, Vst0),
{Es,_} = foldl(fun(Val, {Es0, Index}) ->
Type = get_term_type(Val, Vst0),
- Es = set_element_type(Index, Type, Es0),
+ Es = set_element_type({integer,Index}, Type, Es0),
{Es, Index + 1}
end, {#{}, 1}, Elements),
Type = {tuple,Size,Es},
@@ -385,18 +443,19 @@ valfun_1({put_tuple,Sz,Dst}, Vst0) when is_integer(Sz) ->
St = St0#st{puts_left={Sz,{Dst,Sz,#{}}}},
Vst#vst{current=St};
valfun_1({put,Src}, Vst0) ->
- assert_not_fragile(Src, Vst0),
+ assert_term(Src, Vst0),
Vst = eat_heap(1, Vst0),
#vst{current=St0} = Vst,
case St0 of
#st{puts_left=none} ->
error(not_building_a_tuple);
- #st{puts_left={1,{Dst,Sz,Es}}} ->
+ #st{puts_left={1,{Dst,Sz,Es0}}} ->
+ Es = Es0#{ {integer,Sz} => get_term_type(Src, Vst0) },
St = St0#st{puts_left=none},
create_term({tuple,Sz,Es}, put_tuple, [], Dst, Vst#vst{current=St});
#st{puts_left={PutsLeft,{Dst,Sz,Es0}}} when is_integer(PutsLeft) ->
Index = Sz - PutsLeft + 1,
- Es = Es0#{ Index => get_term_type(Src, Vst0) },
+ Es = Es0#{ {integer,Index} => get_term_type(Src, Vst0) },
St = St0#st{puts_left={PutsLeft-1,{Dst,Sz,Es}}},
Vst#vst{current=St}
end;
@@ -417,6 +476,14 @@ valfun_1({'%', {type_info, Reg, Type}}, Vst) ->
%% that Reg has a certain type, so that we can accept cross-function type
%% optimizations.
update_type(fun meet/2, Type, Reg, Vst);
+valfun_1({'%', {remove_fragility, Reg}}, Vst) ->
+ %% This is a hack to make prim_eval:'receive'/2 work.
+ %%
+ %% Normally it's illegal to pass fragile terms as a function argument as we
+ %% have no way of knowing what the callee will do with it, but we know that
+ %% prim_eval:'receive'/2 won't leak the term, nor cause a GC since it's
+ %% disabled while matching messages.
+ remove_fragility(Reg, Vst);
valfun_1({'%',_}, Vst) ->
Vst;
valfun_1({line,_}, Vst) ->
@@ -438,13 +505,13 @@ valfun_1(_I, #vst{current=#st{ct=undecided}}) ->
%%
%% Allocate and deallocate, et.al
valfun_1({allocate,Stk,Live}, Vst) ->
- allocate(false, Stk, 0, Live, Vst);
+ allocate(uninitialized, Stk, 0, Live, Vst);
valfun_1({allocate_heap,Stk,Heap,Live}, Vst) ->
- allocate(false, Stk, Heap, Live, Vst);
+ allocate(uninitialized, Stk, Heap, Live, Vst);
valfun_1({allocate_zero,Stk,Live}, Vst) ->
- allocate(true, Stk, 0, Live, Vst);
+ allocate(initialized, Stk, 0, Live, Vst);
valfun_1({allocate_heap_zero,Stk,Heap,Live}, Vst) ->
- allocate(true, Stk, Heap, Live, Vst);
+ allocate(initialized, Stk, Heap, Live, Vst);
valfun_1({deallocate,StkSize}, #vst{current=#st{numy=StkSize}}=Vst) ->
verify_no_ct(Vst),
deallocate(Vst);
@@ -508,8 +575,9 @@ valfun_1({get_tl,Src,Dst}, Vst) ->
valfun_1({get_tuple_element,Src,N,Dst}, Vst) ->
assert_not_literal(Src),
assert_type({tuple_element,N+1}, Src, Vst),
- Type = get_element_type(N+1, Src, Vst),
- extract_term(Type, get_tuple_element, [Src], Dst, Vst);
+ Index = {integer,N+1},
+ Type = get_element_type(Index, Src, Vst),
+ extract_term(Type, {bif,element}, [Index, Src], Dst, Vst);
valfun_1({jump,{f,Lbl}}, Vst) ->
kill_state(branch_state(Lbl, Vst));
valfun_1(I, Vst) ->
@@ -518,20 +586,26 @@ valfun_1(I, Vst) ->
init_try_catch_branch(Tag, Dst, Fail, Vst0) ->
Vst1 = create_tag({Tag,[Fail]}, 'try_catch', [], Dst, Vst0),
#vst{current=#st{ct=Fails}=St0} = Vst1,
- CurrentSt = St0#st{ct=[[Fail]|Fails]},
+ St = St0#st{ct=[[Fail]|Fails]},
+ Vst = Vst0#vst{current=St},
- %% Set the initial state at the try/catch label.
- %% Assume that Y registers contain terms or try/catch
- %% tags.
- Yregs0 = map(fun({Y,uninitialized}) -> {Y,term};
- ({Y,initialized}) -> {Y,term};
- (E) -> E
- end, gb_trees:to_list(CurrentSt#st.y)),
- Yregs = gb_trees:from_orddict(Yregs0),
- BranchSt = CurrentSt#st{y=Yregs},
+ complex_test(Fail,
+ fun(CatchVst) ->
+ #vst{current=#st{ys=Ys}} = CatchVst,
+ maps:fold(fun init_catch_handler_1/3, CatchVst, Ys)
+ end,
+ fun(SuccVst) ->
+ SuccVst
+ end, Vst).
- Vst = branch_state(Fail, Vst1#vst{current=BranchSt}),
- Vst#vst{current=CurrentSt}.
+%% Set the initial state at the try/catch label. Assume that Y registers
+%% contain terms or try/catch tags.
+init_catch_handler_1(Reg, initialized, Vst) ->
+ create_term(term, 'catch_handler', [], Reg, Vst);
+init_catch_handler_1(Reg, uninitialized, Vst) ->
+ create_term(term, 'catch_handler', [], Reg, Vst);
+init_catch_handler_1(_, _, Vst) ->
+ Vst.
%% Update branched state if necessary and try next set of instructions.
valfun_2(I, #vst{current=#st{ct=[]}}=Vst) ->
@@ -609,15 +683,13 @@ valfun_4({make_fun2,_,_,_,Live}, Vst) ->
call(make_fun, Live, Vst);
%% Other BIFs
valfun_4({bif,element,{f,Fail},[Pos,Tuple],Dst}, Vst0) ->
- PosType = get_durable_term_type(Pos, Vst0),
- ElementType = case PosType of
- {integer,I} -> get_element_type(I, Tuple, Vst0);
- _ -> term
- end,
+ PosType = get_term_type(Pos, Vst0),
+ ElementType = get_element_type(PosType, Tuple, Vst0),
InferredType = {tuple,[get_tuple_size(PosType)],#{}},
Vst1 = branch_state(Fail, Vst0),
- Vst = update_type(fun meet/2, InferredType, Tuple, Vst1),
- extract_term(ElementType, {bif,element}, [Tuple], Dst, Vst);
+ Vst2 = update_type(fun meet/2, InferredType, Tuple, Vst1),
+ Vst = update_type(fun meet/2, {integer,[]}, Pos, Vst2),
+ extract_term(ElementType, {bif,element}, [Pos,Tuple], Dst, Vst);
valfun_4({bif,raise,{f,0},Src,_Dst}, Vst) ->
validate_src(Src, Vst),
kill_state(Vst);
@@ -634,7 +706,7 @@ valfun_4({bif,Op,{f,Fail},Ss,Dst}, Vst0) ->
Vst1 = branch_state(Fail, Vst0),
%% Infer argument types. Note that we can't type_test in the general case
- %% as the BIF could fail for reasons other than bad arguments.
+ %% as the BIF could fail for reasons other than bad argument types.
ArgTypes = bif_arg_types(Op, Ss),
Vst = foldl(fun({Arg, T}, Vsti) ->
update_type(fun meet/2, T, Arg, Vsti)
@@ -659,17 +731,18 @@ valfun_4({gc_bif,Op,{f,Fail},Live,Ss,Dst}, #vst{current=St0}=Vst0) ->
Vst = prune_x_regs(Live, Vst3),
extract_term(Type, {gc_bif,Op}, Ss, Dst, Vst, Vst0);
valfun_4(return, #vst{current=#st{numy=none}}=Vst) ->
- assert_not_fragile({x,0}, Vst),
+ assert_durable_term({x,0}, Vst),
kill_state(Vst);
valfun_4(return, #vst{current=#st{numy=NumY}}) ->
error({stack_frame,NumY});
valfun_4({loop_rec,{f,Fail},Dst}, Vst0) ->
- Vst = branch_state(Fail, Vst0),
%% This term may not be part of the root set until
%% remove_message/0 is executed. If control transfers
%% to the loop_rec_end/1 instruction, no part of
%% this term must be stored in a Y register.
- create_term({fragile,term}, loop_rec, [], Dst, Vst);
+ Vst1 = branch_state(Fail, Vst0),
+ {Ref, Vst} = new_value(term, loop_rec, [], Vst1),
+ mark_fragile(Dst, set_reg_vref(Ref, Dst, Vst));
valfun_4({wait,_}, Vst) ->
verify_y_init(Vst),
kill_state(Vst);
@@ -680,20 +753,20 @@ valfun_4({wait_timeout,_,Src}, Vst) ->
valfun_4({loop_rec_end,_}, Vst) ->
verify_y_init(Vst),
kill_state(Vst);
-valfun_4(timeout, #vst{current=St}=Vst) ->
- Vst#vst{current=St#st{x=init_regs(0, term)}};
+valfun_4(timeout, Vst) ->
+ prune_x_regs(0, Vst);
valfun_4(send, Vst) ->
call(send, 2, Vst);
valfun_4({set_tuple_element,Src,Tuple,N}, Vst) ->
I = N + 1,
- assert_not_fragile(Src, Vst),
+ assert_term(Src, Vst),
assert_type({tuple_element,I}, Tuple, Vst),
%% Manually update the tuple type; we can't rely on the ordinary update
%% helpers as we must support overwriting (rather than just widening or
%% narrowing) known elements, and we can't use extract_term either since
%% the source tuple may be aliased.
{tuple, Sz, Es0} = get_term_type(Tuple, Vst),
- Es = set_element_type(I, get_term_type(Src, Vst), Es0),
+ Es = set_element_type({integer,I}, get_term_type(Src, Vst), Es0),
override_type({tuple, Sz, Es}, Tuple, Vst);
%% Match instructions.
valfun_4({select_val,Src,{f,Fail},{list,Choices}}, Vst0) ->
@@ -750,15 +823,19 @@ valfun_4({bs_get_position, Ctx, Dst, Live}, Vst0) ->
verify_live(Live, Vst0),
verify_y_init(Vst0),
Vst = prune_x_regs(Live, Vst0),
- create_term(bs_position, bs_get_position, [Ctx], Dst, Vst);
+ create_term(ms_position, bs_get_position, [Ctx], Dst, Vst, Vst0);
valfun_4({bs_set_position, Ctx, Pos}, Vst) ->
bsm_validate_context(Ctx, Vst),
- assert_type(bs_position, Pos, Vst),
+ assert_type(ms_position, Pos, Vst),
Vst;
%% Other test instructions.
valfun_4({test,is_atom,{f,Lbl},[Src]}, Vst) ->
type_test(Lbl, {atom,[]}, Src, Vst);
+valfun_4({test,is_binary,{f,Lbl},[Src]}, Vst) ->
+ type_test(Lbl, binary, Src, Vst);
+valfun_4({test,is_bitstr,{f,Lbl},[Src]}, Vst) ->
+ type_test(Lbl, binary, Src, Vst);
valfun_4({test,is_boolean,{f,Lbl},[Src]}, Vst) ->
type_test(Lbl, bool, Src, Vst);
valfun_4({test,is_float,{f,Lbl},[Src]}, Vst) ->
@@ -769,10 +846,21 @@ valfun_4({test,is_integer,{f,Lbl},[Src]}, Vst) ->
type_test(Lbl, {integer,[]}, Src, Vst);
valfun_4({test,is_nonempty_list,{f,Lbl},[Src]}, Vst) ->
type_test(Lbl, cons, Src, Vst);
+valfun_4({test,is_number,{f,Lbl},[Src]}, Vst) ->
+ type_test(Lbl, number, Src, Vst);
valfun_4({test,is_list,{f,Lbl},[Src]}, Vst) ->
type_test(Lbl, list, Src, Vst);
valfun_4({test,is_nil,{f,Lbl},[Src]}, Vst) ->
- type_test(Lbl, nil, Src, Vst);
+ %% is_nil is an exact check against the 'nil' value, and should not be
+ %% treated as a simple type test.
+ assert_term(Src, Vst),
+ complex_test(Lbl,
+ fun(FailVst) ->
+ update_ne_types(Src, nil, FailVst)
+ end,
+ fun(SuccVst) ->
+ update_eq_types(Src, nil, SuccVst)
+ end, Vst);
valfun_4({test,is_map,{f,Lbl},[Src]}, Vst) ->
case Src of
{Tag,_} when Tag =:= x; Tag =:= y ->
@@ -790,7 +878,7 @@ valfun_4({test,test_arity,{f,Lbl},[Tuple,Sz]}, Vst0) when is_integer(Sz) ->
valfun_4({test,is_tagged_tuple,{f,Lbl},[Src,Sz,Atom]}, Vst0) ->
assert_term(Src, Vst0),
Vst = branch_state(Lbl, Vst0),
- update_type(fun meet/2, {tuple,Sz,#{ 1 => Atom }}, Src, Vst);
+ update_type(fun meet/2, {tuple,Sz,#{ {integer,1} => Atom }}, Src, Vst);
valfun_4({test,has_map_fields,{f,Lbl},Src,{list,List}}, Vst) ->
assert_type(map, Src, Vst),
assert_unique_map_keys(List),
@@ -817,8 +905,8 @@ valfun_4({test,_Op,{f,Lbl},Src}, Vst) ->
validate_src(Src, Vst),
branch_state(Lbl, Vst);
valfun_4({bs_add,{f,Fail},[A,B,_],Dst}, Vst) ->
- assert_not_fragile(A, Vst),
- assert_not_fragile(B, Vst),
+ assert_term(A, Vst),
+ assert_term(B, Vst),
create_term({integer,[]}, bs_add, [A, B], Dst, branch_state(Fail, Vst));
valfun_4({bs_utf8_size,{f,Fail},A,Dst}, Vst) ->
assert_term(A, Vst),
@@ -833,12 +921,12 @@ valfun_4({bs_init2,{f,Fail},Sz,Heap,Live,_,Dst}, Vst0) ->
is_integer(Sz) ->
ok;
true ->
- assert_not_fragile(Sz, Vst0)
+ assert_term(Sz, Vst0)
end,
Vst1 = heap_alloc(Heap, Vst0),
Vst2 = branch_state(Fail, Vst1),
Vst = prune_x_regs(Live, Vst2),
- create_term(binary, bs_init2, [], Dst, Vst);
+ create_term(binary, bs_init2, [], Dst, Vst, Vst0);
valfun_4({bs_init_bits,{f,Fail},Sz,Heap,Live,_,Dst}, Vst0) ->
verify_live(Live, Vst0),
verify_y_init(Vst0),
@@ -855,39 +943,39 @@ valfun_4({bs_init_bits,{f,Fail},Sz,Heap,Live,_,Dst}, Vst0) ->
valfun_4({bs_append,{f,Fail},Bits,Heap,Live,_Unit,Bin,_Flags,Dst}, Vst0) ->
verify_live(Live, Vst0),
verify_y_init(Vst0),
- assert_not_fragile(Bits, Vst0),
- assert_not_fragile(Bin, Vst0),
+ assert_term(Bits, Vst0),
+ assert_term(Bin, Vst0),
Vst1 = heap_alloc(Heap, Vst0),
Vst2 = branch_state(Fail, Vst1),
Vst = prune_x_regs(Live, Vst2),
- create_term(binary, bs_append, [Bin], Dst, Vst);
+ create_term(binary, bs_append, [Bin], Dst, Vst, Vst0);
valfun_4({bs_private_append,{f,Fail},Bits,_Unit,Bin,_Flags,Dst}, Vst0) ->
- assert_not_fragile(Bits, Vst0),
- assert_not_fragile(Bin, Vst0),
+ assert_term(Bits, Vst0),
+ assert_term(Bin, Vst0),
Vst = branch_state(Fail, Vst0),
create_term(binary, bs_private_append, [Bin], Dst, Vst);
valfun_4({bs_put_string,Sz,_}, Vst) when is_integer(Sz) ->
Vst;
valfun_4({bs_put_binary,{f,Fail},Sz,_,_,Src}, Vst) ->
- assert_not_fragile(Sz, Vst),
- assert_not_fragile(Src, Vst),
+ assert_term(Sz, Vst),
+ assert_term(Src, Vst),
branch_state(Fail, Vst);
valfun_4({bs_put_float,{f,Fail},Sz,_,_,Src}, Vst) ->
- assert_not_fragile(Sz, Vst),
- assert_not_fragile(Src, Vst),
+ assert_term(Sz, Vst),
+ assert_term(Src, Vst),
branch_state(Fail, Vst);
valfun_4({bs_put_integer,{f,Fail},Sz,_,_,Src}, Vst) ->
- assert_not_fragile(Sz, Vst),
- assert_not_fragile(Src, Vst),
+ assert_term(Sz, Vst),
+ assert_term(Src, Vst),
branch_state(Fail, Vst);
valfun_4({bs_put_utf8,{f,Fail},_,Src}, Vst) ->
- assert_not_fragile(Src, Vst),
+ assert_term(Src, Vst),
branch_state(Fail, Vst);
valfun_4({bs_put_utf16,{f,Fail},_,Src}, Vst) ->
- assert_not_fragile(Src, Vst),
+ assert_term(Src, Vst),
branch_state(Fail, Vst);
valfun_4({bs_put_utf32,{f,Fail},_,Src}, Vst) ->
- assert_not_fragile(Src, Vst),
+ assert_term(Src, Vst),
branch_state(Fail, Vst);
%% Map instructions.
valfun_4({put_map_assoc=Op,{f,Fail},Src,Dst,Live,{list,List}}, Vst) ->
@@ -945,13 +1033,13 @@ verify_put_map(Op, Fail, Src, Dst, Live, List, Vst0) ->
assert_type(map, Src, Vst0),
verify_live(Live, Vst0),
verify_y_init(Vst0),
- [assert_not_fragile(Term, Vst0) || Term <- List],
+ [assert_term(Term, Vst0) || Term <- List],
Vst1 = heap_alloc(0, Vst0),
Vst2 = branch_state(Fail, Vst1),
Vst = prune_x_regs(Live, Vst2),
Keys = extract_map_keys(List),
assert_unique_map_keys(Keys),
- create_term(map, Op, [Src], Dst, Vst).
+ create_term(map, Op, [Src], Dst, Vst, Vst0).
%%
%% Common code for validating bs_start_match* instructions.
@@ -962,18 +1050,20 @@ validate_bs_start_match(Fail, Live, Type, Src, Dst, Vst) ->
verify_y_init(Vst),
%% #ms{} can represent either a match context or a term, so we have to mark
- %% the source as a term if it fails, and retain the incoming type if it
- %% succeeds (match context or not).
- %%
- %% The override_type hack is only needed until we get proper union types.
+ %% the source as a term if it fails with a match context as an input. This
+ %% hack is only needed until we get proper union types.
complex_test(Fail,
fun(FailVst) ->
- override_type(term, Src, FailVst)
+ case get_raw_type(Src, FailVst) of
+ #ms{} -> override_type(term, Src, FailVst);
+ _ -> FailVst
+ end
end,
fun(SuccVst0) ->
- SuccVst = prune_x_regs(Live, SuccVst0),
+ SuccVst1 = update_type(fun meet/2, binary, Src, SuccVst0),
+ SuccVst = prune_x_regs(Live, SuccVst1),
extract_term(Type, bs_start_match, [Src], Dst,
- SuccVst, Vst)
+ SuccVst, SuccVst0)
end, Vst).
%%
@@ -985,7 +1075,7 @@ validate_bs_get(Op, Fail, Ctx, Live, Type, Dst, Vst0) ->
verify_y_init(Vst0),
Vst1 = prune_x_regs(Live, Vst0),
Vst = branch_state(Fail, Vst1),
- extract_term(Type, Op, [Ctx], Dst, Vst).
+ extract_term(Type, Op, [Ctx], Dst, Vst, Vst0).
%%
%% Common code for validating bs_skip_utf* instructions.
@@ -1032,7 +1122,7 @@ call(Name, Live, #vst{current=St0}=Vst0) ->
case call_return_type(Name, Vst0) of
Type when Type =/= exception ->
%% Type is never 'exception' because it has been handled earlier.
- St = St0#st{f=init_fregs(),aliases=#{}},
+ St = St0#st{f=init_fregs()},
Vst = prune_x_regs(0, Vst0#vst{current=St}),
create_term(Type, call, [], {x,0}, Vst)
end.
@@ -1059,13 +1149,15 @@ verify_call_args(_, Live, _) ->
verify_remote_args_1(-1, _) ->
ok;
verify_remote_args_1(X, Vst) ->
- assert_not_fragile({x, X}, Vst),
+ assert_durable_term({x, X}, Vst),
verify_remote_args_1(X - 1, Vst).
verify_local_args(-1, _Lbl, _CtxIds, _Vst) ->
ok;
verify_local_args(X, Lbl, CtxIds, Vst) ->
Reg = {x, X},
+ assert_movable(Reg, Vst),
+ assert_not_fragile(Reg, Vst),
case get_raw_type(Reg, Vst) of
#ms{id=Id}=Type ->
case CtxIds of
@@ -1075,8 +1167,6 @@ verify_local_args(X, Lbl, CtxIds, Vst) ->
verify_arg_type(Lbl, Reg, Type, Vst),
verify_local_args(X - 1, Lbl, CtxIds#{ Id => Reg }, Vst)
end;
- {fragile,_} ->
- error({fragile_message_reference, Reg});
Type ->
verify_arg_type(Lbl, Reg, Type, Vst),
verify_local_args(X - 1, Lbl, CtxIds, Vst)
@@ -1092,56 +1182,89 @@ verify_arg_type(Lbl, Reg, #ms{}, #vst{ft=Ft}) ->
end;
verify_arg_type(Lbl, Reg, GivenType, #vst{ft=Ft}) ->
case gb_trees:lookup({Lbl, Reg}, Ft) of
- {value, bool} when GivenType =:= {atom, true};
- GivenType =:= {atom, false};
- GivenType =:= {atom, []} ->
- %% We don't yet support upgrading true/false to bool, so we
- %% assume unknown atoms can be bools when validating calls.
- ok;
{value, #ms{}} ->
%% Functions that accept match contexts also accept all other
%% terms. This will change once we support union types.
ok;
{value, RequiredType} ->
- case meet(GivenType, RequiredType) of
- none -> error({bad_arg_type, Reg, GivenType, RequiredType});
- _ -> ok
+ case vat_1(GivenType, RequiredType) of
+ true -> ok;
+ false -> error({bad_arg_type, Reg, GivenType, RequiredType})
end;
none ->
ok
end.
-allocate(Zero, Stk, Heap, Live, #vst{current=#st{numy=none}}=Vst0) ->
+%% Checks whether the Given argument is compatible with the Required one. This
+%% is essentially a relaxed version of 'meet(Given, Req) =:= Given', where we
+%% accept that the Given value has the right type but not necessarily the exact
+%% same value; if {atom,gurka} is required, we'll consider {atom,[]} valid.
+%%
+%% This will catch all problems that could crash the emulator, like passing a
+%% 1-tuple when the callee expects a 3-tuple, but some value errors might slip
+%% through.
+vat_1(Same, Same) -> true;
+vat_1({atom,A}, {atom,B}) -> A =:= B orelse is_list(A) orelse is_list(B);
+vat_1({atom,A}, bool) -> is_boolean(A) orelse is_list(A);
+vat_1(bool, {atom,B}) -> is_boolean(B) orelse is_list(B);
+vat_1(cons, list) -> true;
+vat_1({float,A}, {float,B}) -> A =:= B orelse is_list(A) orelse is_list(B);
+vat_1({float,_}, number) -> true;
+vat_1({integer,A}, {integer,B}) -> A =:= B orelse is_list(A) orelse is_list(B);
+vat_1({integer,_}, number) -> true;
+vat_1(_, {literal,_}) -> false;
+vat_1({literal,_}=Lit, Required) -> vat_1(get_literal_type(Lit), Required);
+vat_1(nil, list) -> true;
+vat_1({tuple,SzA,EsA}, {tuple,SzB,EsB}) ->
+ if
+ is_list(SzB) ->
+ tuple_sz(SzA) >= tuple_sz(SzB) andalso vat_elements(EsA, EsB);
+ SzA =:= SzB ->
+ vat_elements(EsA, EsB);
+ SzA =/= SzB ->
+ false
+ end;
+vat_1(_, _) -> false.
+
+vat_elements(EsA, EsB) ->
+ maps:fold(fun(Key, Req, Acc) ->
+ case EsA of
+ #{ Key := Given } -> Acc andalso vat_1(Given, Req);
+ #{} -> false
+ end
+ end, true, EsB).
+
+allocate(Tag, Stk, Heap, Live, #vst{current=#st{numy=none}=St}=Vst0) ->
verify_live(Live, Vst0),
- Vst = #vst{current=St} = prune_x_regs(Live, Vst0),
- Ys = init_regs(Stk, case Zero of
- true -> initialized;
- false -> uninitialized
- end),
- heap_alloc(Heap, Vst#vst{current=St#st{y=Ys,numy=Stk}});
+ Vst1 = Vst0#vst{current=St#st{numy=Stk}},
+ Vst2 = prune_x_regs(Live, Vst1),
+ Vst = init_stack(Tag, Stk - 1, Vst2),
+ heap_alloc(Heap, Vst);
allocate(_, _, _, _, #vst{current=#st{numy=Numy}}) ->
error({existing_stack_frame,{size,Numy}}).
deallocate(#vst{current=St}=Vst) ->
- Vst#vst{current=St#st{y=init_regs(0, initialized),numy=none}}.
-
-trim_stack(From, To, Top, #st{y=Ys0}=St) when From =:= Top ->
- Ys = foldl(fun(Y, Acc) ->
- gb_trees:delete(Y, Acc)
- end, Ys0, seq(To, From - 1)),
- %% Note that all aliases and defs are wiped. This is perhaps a bit too
- %% conservative, but preserving them won't be easy until type management
- %% is refactored.
- St#st{aliases=#{},defs=#{},numy=To,y=Ys};
+ Vst#vst{current=St#st{ys=#{},numy=none}}.
+
+init_stack(_Tag, -1, Vst) ->
+ Vst;
+init_stack(Tag, Y, Vst) ->
+ init_stack(Tag, Y - 1, create_tag(Tag, allocate, [], {y,Y}, Vst)).
+
+trim_stack(From, To, Top, #st{ys=Ys0}=St) when From =:= Top ->
+ Ys = maps:filter(fun({y,Y}, _) -> Y < To end, Ys0),
+ St#st{numy=To,ys=Ys};
trim_stack(From, To, Top, St0) ->
- #st{y=Ys0} = St0,
+ Src = {y, From},
+ Dst = {y, To},
- Ys = case gb_trees:lookup(From, Ys0) of
- none -> error({invalid_shift,{y,From},{y,To}});
- {value,Type} -> gb_trees:enter(To, Type, Ys0)
+ #st{ys=Ys0} = St0,
+ Ys = case Ys0 of
+ #{ Src := Ref } -> Ys0#{ Dst => Ref };
+ #{} -> error({invalid_shift,Src,Dst})
end,
+ St = St0#st{ys=Ys},
- St = St0#st{y=Ys},
trim_stack(From + 1, To + 1, Top, St).
test_heap(Heap, Live, Vst0) ->
@@ -1168,24 +1291,17 @@ heap_alloc_2([{floats,Floats}|T], St0) ->
heap_alloc_2(T, St);
heap_alloc_2([], St) -> St.
-prune_x_regs(Live, #vst{current=St0}=Vst)
- when is_integer(Live) ->
- #st{x=Xs0,defs=Defs0,aliases=Aliases0} = St0,
- Xs1 = gb_trees:to_list(Xs0),
- Xs = [P || {R,_}=P <- Xs1, R < Live],
- Defs = maps:filter(fun({x,X}, _) -> X < Live;
- ({y,_}, _) -> true
- end, Defs0),
- Aliases = maps:filter(fun({x,X1}, {x,X2}) ->
- X1 < Live andalso X2 < Live;
- ({x,X}, _) ->
- X < Live;
- (_, {x,X}) ->
- X < Live;
- (_, _) ->
- true
- end, Aliases0),
- St = St0#st{x=gb_trees:from_orddict(Xs),defs=Defs,aliases=Aliases},
+prune_x_regs(Live, #vst{current=St0}=Vst) when is_integer(Live) ->
+ #st{fragile=Fragile0,xs=Xs0} = St0,
+ Fragile = cerl_sets:filter(fun({x,X}) ->
+ X < Live;
+ ({y,_}) ->
+ true
+ end, Fragile0),
+ Xs = maps:filter(fun({x,X}, _) ->
+ X < Live
+ end, Xs0),
+ St = St0#st{fragile=Fragile,xs=Xs},
Vst#vst{current=St}.
%% All choices in a select_val list must be integers, floats, or atoms.
@@ -1249,8 +1365,7 @@ get_fls(#vst{current=#st{fls=Fls}}) when is_atom(Fls) -> Fls.
init_fregs() -> 0.
-set_freg({fr,Fr}=Freg, #vst{current=#st{f=Fregs0}=St}=Vst)
- when is_integer(Fr), 0 =< Fr ->
+set_freg({fr,Fr}=Freg, #vst{current=#st{f=Fregs0}=St}=Vst) ->
check_limit(Freg),
Bit = 1 bsl Fr,
if
@@ -1308,19 +1423,13 @@ bsm_validate_context(Reg, Vst) ->
_ = bsm_get_context(Reg, Vst),
ok.
-bsm_get_context({x,X}=Reg, #vst{current=#st{x=Xs}}=_Vst) when is_integer(X) ->
- case gb_trees:lookup(X, Xs) of
- {value,#ms{}=Ctx} -> Ctx;
- {value,{fragile,#ms{}=Ctx}} -> Ctx;
- _ -> error({no_bsm_context,Reg})
- end;
-bsm_get_context({y,Y}=Reg, #vst{current=#st{y=Ys}}=_Vst) when is_integer(Y) ->
- case gb_trees:lookup(Y, Ys) of
- {value,#ms{}=Ctx} -> Ctx;
- {value,{fragile,#ms{}=Ctx}} -> Ctx;
- _ -> error({no_bsm_context,Reg})
+bsm_get_context({Kind,_}=Reg, Vst) when Kind =:= x; Kind =:= y->
+ case get_raw_type(Reg, Vst) of
+ #ms{}=Ctx -> Ctx;
+ _ -> error({no_bsm_context,Reg})
end;
-bsm_get_context(Reg, _) -> error({bad_source,Reg}).
+bsm_get_context(Reg, _) ->
+ error({bad_source,Reg}).
bsm_save(Reg, {atom,start}, Vst) ->
%% Save point refering to where the match started.
@@ -1357,17 +1466,17 @@ select_val_branches(Fail, Src, Choices, Vst0) ->
svb_1([Val,{f,L}|T], Src, Vst0) ->
Vst = complex_test(L,
fun(BranchVst) ->
- update_eq_types(Val, Src, BranchVst)
+ update_eq_types(Src, Val, BranchVst)
end,
fun(FailVst) ->
- update_ne_types(Val, Src, FailVst)
+ update_ne_types(Src, Val, FailVst)
end, Vst0),
svb_1(T, Src, Vst);
svb_1([], _, Vst) ->
Vst.
select_arity_branches(Fail, List, Tuple, Vst0) ->
- Type = get_durable_term_type(Tuple, Vst0),
+ Type = get_term_type(Tuple, Vst0),
Vst = sab_1(List, Tuple, Type, Vst0),
kill_state(branch_state(Fail, Vst)).
@@ -1389,42 +1498,54 @@ sab_1([_,{f,_}|T], Tuple, Type, Vst) ->
sab_1([], _, _, #vst{}=Vst) ->
Vst.
-infer_types(Src, Vst) ->
- case get_def(Src, Vst) of
- {{bif,tuple_size}, [Tuple]} ->
- fun({integer,Arity}, S) ->
- update_type(fun meet/2, {tuple,Arity,#{}}, Tuple, S);
- (_, S) -> S
- end;
- {{bif,'=:='},[ArityReg,{integer,_}=Val]} when ArityReg =/= Src ->
- fun({atom,true}, S) ->
- Infer = infer_types(ArityReg, S),
- Infer(Val, S);
- (_, S) -> S
- end;
- {{bif,is_atom},[Src]} ->
- infer_type_test_bif({atom,[]}, Src);
- {{bif,is_boolean},[Src]} ->
- infer_type_test_bif(bool, Src);
- {{bif,is_binary},[Src]} ->
- infer_type_test_bif(binary, Src);
- {{bif,is_bitstring},[Src]} ->
- infer_type_test_bif(binary, Src);
- {{bif,is_float},[Src]} ->
- infer_type_test_bif(float, Src);
- {{bif,is_integer},[Src]} ->
- infer_type_test_bif({integer,{}}, Src);
- {{bif,is_list},[Src]} ->
- infer_type_test_bif(list, Src);
- {{bif,is_map},[Src]} ->
- infer_type_test_bif(map, Src);
- {{bif,is_number},[Src]} ->
- infer_type_test_bif(number, Src);
- {{bif,is_tuple},[Src]} ->
- infer_type_test_bif({tuple,[0],#{}}, Src);
- _ ->
- fun(_, S) -> S end
- end.
+infer_types({Kind,_}=Reg, Vst) when Kind =:= x; Kind =:= y ->
+ infer_types(get_reg_vref(Reg, Vst), Vst);
+infer_types(#value_ref{}=Ref, #vst{current=#st{vs=Vs}}) ->
+ case Vs of
+ #{ Ref := Entry } -> infer_types_1(Entry);
+ #{} -> fun(_, S) -> S end
+ end;
+infer_types(_, #vst{}) ->
+ fun(_, S) -> S end.
+
+infer_types_1(#value{op={bif,'=:='},args=[LHS,RHS]}) ->
+ fun({atom,true}, S) ->
+ Infer = infer_types(RHS, S),
+ Infer(LHS, S);
+ (_, S) -> S
+ end;
+infer_types_1(#value{op={bif,element},args=[{integer,Index}=Key,Tuple]}) ->
+ fun(Val, S) ->
+ Type = get_term_type(Val, S),
+ update_type(fun meet/2,{tuple,[Index],#{ Key => Type }}, Tuple, S)
+ end;
+infer_types_1(#value{op={bif,is_atom},args=[Src]}) ->
+ infer_type_test_bif({atom,[]}, Src);
+infer_types_1(#value{op={bif,is_boolean},args=[Src]}) ->
+ infer_type_test_bif(bool, Src);
+infer_types_1(#value{op={bif,is_binary},args=[Src]}) ->
+ infer_type_test_bif(binary, Src);
+infer_types_1(#value{op={bif,is_bitstring},args=[Src]}) ->
+ infer_type_test_bif(binary, Src);
+infer_types_1(#value{op={bif,is_float},args=[Src]}) ->
+ infer_type_test_bif(float, Src);
+infer_types_1(#value{op={bif,is_integer},args=[Src]}) ->
+ infer_type_test_bif({integer,{}}, Src);
+infer_types_1(#value{op={bif,is_list},args=[Src]}) ->
+ infer_type_test_bif(list, Src);
+infer_types_1(#value{op={bif,is_map},args=[Src]}) ->
+ infer_type_test_bif(map, Src);
+infer_types_1(#value{op={bif,is_number},args=[Src]}) ->
+ infer_type_test_bif(number, Src);
+infer_types_1(#value{op={bif,is_tuple},args=[Src]}) ->
+ infer_type_test_bif({tuple,[0],#{}}, Src);
+infer_types_1(#value{op={bif,tuple_size}, args=[Tuple]}) ->
+ fun({integer,Arity}, S) ->
+ update_type(fun meet/2, {tuple,Arity,#{}}, Tuple, S);
+ (_, S) -> S
+ end;
+infer_types_1(_) ->
+ fun(_, S) -> S end.
infer_type_test_bif(Type, Src) ->
fun({atom,true}, S) ->
@@ -1445,38 +1566,67 @@ assign({y,_}=Src, {y,_}=Dst, Vst) ->
initialized -> create_tag(initialized, init, [], Dst, Vst);
_ -> assign_1(Src, Dst, Vst)
end;
-assign({Kind,_}=Reg, Dst, Vst) when Kind =:= x; Kind =:= y ->
- assign_1(Reg, Dst, Vst);
+assign({Kind,_}=Src, Dst, Vst) when Kind =:= x; Kind =:= y ->
+ assign_1(Src, Dst, Vst);
assign(Literal, Dst, Vst) ->
- Type = get_term_type(Literal, Vst),
+ Type = get_literal_type(Literal),
create_term(Type, move, [Literal], Dst, Vst).
-%% Creates a special tag value that isn't a regular term, such as
-%% 'initialized' or 'catchtag'
-create_tag(Type, Op, Ss, {y,_}=Dst, Vst) ->
- set_type_reg_expr(Type, {Op, Ss}, Dst, Vst);
-create_tag(_Type, _Op, _Ss, Dst, _Vst) ->
+%% Creates a special tag value that isn't a regular term, such as 'initialized'
+%% or 'catchtag'
+create_tag(Tag, _Op, _Ss, {y,_}=Dst, #vst{current=#st{ys=Ys0}=St0}=Vst) ->
+ case maps:get(Dst, Ys0, uninitialized) of
+ {catchtag,_}=Prev ->
+ error(Prev);
+ {trytag,_}=Prev ->
+ error(Prev);
+ _ ->
+ check_try_catch_tags(Tag, Dst, Vst),
+ Ys = Ys0#{ Dst => Tag },
+ St = St0#st{ys=Ys},
+ remove_fragility(Dst, Vst#vst{current=St})
+ end;
+create_tag(_Tag, _Op, _Ss, Dst, _Vst) ->
error({invalid_tag_register, Dst}).
%% Wipes a special tag, leaving the register initialized but empty.
-kill_tag({y,Y}=Reg, #vst{current=#st{y=Ys0}=St0}=Vst) ->
+kill_tag({y,_}=Reg, #vst{current=#st{ys=Ys0}=St0}=Vst) ->
_ = get_tag_type(Reg, Vst), %Assertion.
- Ys = gb_trees:update(Y, initialized, Ys0),
- Vst#vst{current=St0#st{y=Ys}}.
+ Ys = Ys0#{ Reg => initialized },
+ Vst#vst{current=St0#st{ys=Ys}}.
%% Creates a completely new term with the given type.
-create_term(Type, Op, Ss, Dst, Vst) ->
- set_type_reg_expr(Type, {Op, Ss}, Dst, Vst).
+create_term(Type, Op, Ss0, Dst, Vst0) ->
+ create_term(Type, Op, Ss0, Dst, Vst0, Vst0).
-%% Extracts a term from Ss, propagating fragility.
-extract_term(Type, Op, Ss, Dst, Vst) ->
- extract_term(Type, Op, Ss, Dst, Vst, Vst).
+%% As create_term/4, but uses the incoming Vst for argument resolution in
+%% case x-regs have been pruned and the sources can no longer be found.
+create_term(Type, Op, Ss0, Dst, Vst0, OrigVst) ->
+ {Ref, Vst1} = new_value(Type, Op, resolve_args(Ss0, OrigVst), Vst0),
+ Vst = remove_fragility(Dst, Vst1),
+ set_reg_vref(Ref, Dst, Vst).
-%% As extract_term/4, but uses the incoming Vst for fragility in case x-regs
-%% have been pruned and the sources can no longer be found.
-extract_term(Type0, Op, Ss, Dst, Vst, OrigVst) ->
- Type = propagate_fragility(Type0, Ss, OrigVst),
- set_type_reg_expr(Type, {Op, Ss}, Dst, Vst).
+%% Extracts a term from Ss, propagating fragility.
+extract_term(Type, Op, Ss0, Dst, Vst0) ->
+ extract_term(Type, Op, Ss0, Dst, Vst0, Vst0).
+
+%% As extract_term/4, but uses the incoming Vst for argument resolution in
+%% case x-regs have been pruned and the sources can no longer be found.
+extract_term(Type, Op, Ss0, Dst, Vst0, OrigVst) ->
+ {Ref, Vst1} = new_value(Type, Op, resolve_args(Ss0, OrigVst), Vst0),
+ Vst = propagate_fragility(Dst, Ss0, Vst1),
+ set_reg_vref(Ref, Dst, Vst).
+
+%% Translates instruction arguments into the argument() type, decoupling them
+%% from their registers, allowing us to infer their types after they've been
+%% clobbered or moved.
+resolve_args([{Kind,_}=Src | Args], Vst) when Kind =:= x; Kind =:= y ->
+ [get_reg_vref(Src, Vst) | resolve_args(Args, Vst)];
+resolve_args([Lit | Args], Vst) ->
+ assert_literal(Lit),
+ [Lit | resolve_args(Args, Vst)];
+resolve_args([], _Vst) ->
+ [].
%% Helper functions for tests that alter state on both the success and fail
%% branches, keeping the states from tainting each other.
@@ -1501,13 +1651,11 @@ type_test(Fail, Type, Reg, Vst) ->
%% Overrides the type of Reg. This is ugly but a necessity for certain
%% destructive operations.
override_type(Type, Reg, Vst) ->
- %% Once the new type format is in, this should be expressed as:
- %% update_type(fun(_, T) -> T end, Type, Reg, Vst).
- set_aliased_type(Type, Reg, Vst).
+ update_type(fun(_, T) -> T end, Type, Reg, Vst).
%% This is used when linear code finds out more and more information about a
%% type, so that the type gets more specialized.
-update_type(Merge, Type0, Reg, Vst) ->
+update_type(Merge, Type0, #value_ref{}=Ref, Vst) ->
%% If the old type can't be merged with the new one, the type information
%% is inconsistent and we know that some instructions will never be
%% executed at run-time. For example:
@@ -1518,21 +1666,26 @@ update_type(Merge, Type0, Reg, Vst) ->
%%
%% Note that the test_arity instruction can never be reached, so we use the
%% new type instead of 'none'.
- Type = case Merge(get_durable_term_type(Reg, Vst), Type0) of
+ Type = case Merge(get_raw_type(Ref, Vst), Type0) of
none -> Type0;
T -> T
end,
- set_aliased_type(Type, Reg, Vst).
+ set_type(Type, Ref, Vst);
+update_type(Merge, Type, {Kind,_}=Reg, Vst) when Kind =:= x; Kind =:= y ->
+ update_type(Merge, Type, get_reg_vref(Reg, Vst), Vst);
+update_type(_Merge, _Type, Literal, Vst) ->
+ assert_literal(Literal),
+ Vst.
update_ne_types(LHS, RHS, Vst) ->
- update_type(fun subtract/2, get_durable_term_type(RHS, Vst), LHS, Vst).
+ update_type(fun subtract/2, get_term_type(RHS, Vst), LHS, Vst).
update_eq_types(LHS, RHS, Vst0) ->
Infer = infer_types(LHS, Vst0),
Vst1 = Infer(RHS, Vst0),
- T1 = get_durable_term_type(LHS, Vst1),
- T2 = get_durable_term_type(RHS, Vst1),
+ T1 = get_term_type(LHS, Vst1),
+ T2 = get_term_type(RHS, Vst1),
Vst = update_type(fun meet/2, T2, LHS, Vst1),
update_type(fun meet/2, T1, RHS, Vst).
@@ -1540,102 +1693,69 @@ update_eq_types(LHS, RHS, Vst0) ->
%% Helper functions for the above.
assign_1(Src, Dst, Vst0) ->
- Type = get_move_term_type(Src, Vst0),
- Def = get_def(Src, Vst0),
-
- Vst = set_type_reg_expr(Type, Def, Dst, Vst0),
-
- #vst{current=St0} = Vst,
- #st{aliases=Aliases0} = St0,
-
- Aliases = Aliases0#{Src=>Dst,Dst=>Src},
-
- St = St0#st{aliases=Aliases},
- Vst#vst{current=St}.
-
-set_aliased_type(Type, Reg, #vst{current=#st{aliases=Aliases}}=Vst0) ->
- Vst1 = set_type(Type, Reg, Vst0),
- case Aliases of
- #{Reg:=OtherReg} ->
- Vst = set_type_reg(Type, OtherReg, Vst1),
- #vst{current=St} = Vst,
- Vst#vst{current=St#st{aliases=Aliases}};
+ assert_movable(Src, Vst0),
+ Vst = propagate_fragility(Dst, [Src], Vst0),
+ set_reg_vref(get_reg_vref(Src, Vst), Dst, Vst).
+
+set_reg_vref(Ref, {x,_}=Dst, Vst) ->
+ check_limit(Dst),
+ #vst{current=#st{xs=Xs0}=St0} = Vst,
+ St = St0#st{xs=Xs0#{ Dst => Ref }},
+ Vst#vst{current=St};
+set_reg_vref(Ref, {y,_}=Dst, #vst{current=#st{ys=Ys0}=St0} = Vst) ->
+ check_limit(Dst),
+ case Ys0 of
+ #{ Dst := {catchtag,_}=Tag } ->
+ error(Tag);
+ #{ Dst := {trytag,_}=Tag } ->
+ error(Tag);
+ #{ Dst := _ } ->
+ St = St0#st{ys=Ys0#{ Dst => Ref }},
+ Vst#vst{current=St};
#{} ->
- Vst1
+ %% Storing into a non-existent Y register means that we haven't set
+ %% up a (sufficiently large) stack.
+ error({invalid_store, Dst})
end.
-kill_aliases(Reg, #st{aliases=Aliases0}=St) ->
- case Aliases0 of
- #{Reg:=OtherReg} ->
- Aliases = maps:without([Reg,OtherReg], Aliases0),
- St#st{aliases=Aliases};
+get_reg_vref({x,_}=Src, #vst{current=#st{xs=Xs}}) ->
+ check_limit(Src),
+ case Xs of
+ #{ Src := #value_ref{}=Ref } ->
+ Ref;
#{} ->
- St
+ error({uninitialized_reg, Src})
+ end;
+get_reg_vref({y,_}=Src, #vst{current=#st{ys=Ys}}) ->
+ check_limit(Src),
+ case Ys of
+ #{ Src := #value_ref{}=Ref } ->
+ Ref;
+ #{ Src := initialized } ->
+ error({unassigned, Src});
+ #{ Src := Tag } when Tag =/= uninitialized ->
+ error(Tag);
+ #{} ->
+ error({uninitialized_reg, Src})
end.
-set_type(Type, {x,_}=Reg, Vst) ->
- set_type_reg(Type, Reg, Reg, Vst);
-set_type(Type, {y,_}=Reg, Vst) ->
- set_type_reg(Type, Reg, Reg, Vst);
-set_type(_, _, #vst{}=Vst) -> Vst.
-
-set_type_reg(Type, Src, Dst, Vst) ->
- case get_raw_type(Src, Vst) of
- uninitialized ->
- error({uninitialized_reg, Src});
- {fragile,_} ->
- set_type_reg(make_fragile(Type), Dst, Vst);
- _ ->
- set_type_reg(Type, Dst, Vst)
+set_type(Type, #value_ref{}=Ref, #vst{current=#st{vs=Vs0}=St}=Vst) ->
+ case Vs0 of
+ #{ Ref := #value{}=Entry } ->
+ Vs = Vs0#{ Ref => Entry#value{type=Type} },
+ Vst#vst{current=St#st{vs=Vs}};
+ #{} ->
+ %% Dead references may happen during type inference and are not an
+ %% error in and of themselves. If a problem were to arise from this
+ %% it'll explode elsewhere.
+ Vst
end.
-set_type_reg(Type, Reg, Vst) ->
- set_type_reg_expr(Type, none, Reg, Vst).
-
-set_type_reg_expr(Type, Expr, {x,_}=Reg, Vst) ->
- set_type_x(Type, Expr, Reg, Vst);
-set_type_reg_expr(Type, Expr, Reg, Vst) ->
- set_type_y(Type, Expr, Reg, Vst).
-
-set_type_x(Type, Expr, {x,X}=Reg, #vst{current=#st{x=Xs0,defs=Defs0}=St0}=Vst)
- when is_integer(X), 0 =< X ->
- check_limit(Reg),
- Xs = case gb_trees:lookup(X, Xs0) of
- none ->
- gb_trees:insert(X, Type, Xs0);
- {value,{fragile,_}} ->
- gb_trees:update(X, make_fragile(Type), Xs0);
- {value,_} ->
- gb_trees:update(X, Type, Xs0)
- end,
- Defs = Defs0#{Reg=>Expr},
- St = kill_aliases(Reg, St0),
- Vst#vst{current=St#st{x=Xs,defs=Defs}};
-set_type_x(Type, _Expr, Reg, #vst{}) ->
- error({invalid_store,Reg,Type}).
-
-set_type_y(Type, Expr, {y,Y}=Reg, #vst{current=#st{y=Ys0,defs=Defs0}=St0}=Vst)
- when is_integer(Y), 0 =< Y ->
- check_limit(Reg),
- Ys = case gb_trees:lookup(Y, Ys0) of
- none ->
- error({invalid_store,Reg,Type});
- {value,{catchtag,_}=Tag} ->
- error(Tag);
- {value,{trytag,_}=Tag} ->
- error(Tag);
- {value,_} ->
- gb_trees:update(Y, Type, Ys0)
- end,
- check_try_catch_tags(Type, Reg, Vst),
- Defs = Defs0#{Reg=>Expr},
- St = kill_aliases(Reg, St0),
- Vst#vst{current=St#st{y=Ys,defs=Defs}};
-set_type_y(Type, _Expr, Reg, #vst{}) ->
- error({invalid_store,Reg,Type}).
-
-make_fragile({fragile,_}=Type) -> Type;
-make_fragile(Type) -> {fragile,Type}.
+new_value(Type, Op, Ss, #vst{current=#st{vs=Vs0}=St,ref_ctr=Counter}=Vst) ->
+ Ref = #value_ref{id=Counter},
+ Vs = Vs0#{ Ref => #value{op=Op,args=Ss,type=Type} },
+
+ {Ref, Vst#vst{current=St#st{vs=Vs},ref_ctr=Counter+1}}.
kill_catch_tag(Reg, #vst{current=#st{ct=[Fail|Fails]}=St}=Vst0) ->
Vst = Vst0#vst{current=St#st{ct=Fails,fls=undefined}},
@@ -1657,25 +1777,17 @@ check_try_catch_tags(Type, {y,N}=Reg, Vst) ->
ok
end.
-is_reg_defined({x,_}=Reg, Vst) -> is_type_defined_x(Reg, Vst);
-is_reg_defined({y,_}=Reg, Vst) -> is_type_defined_y(Reg, Vst);
+is_reg_defined({x,_}=Reg, #vst{current=#st{xs=Xs}}) -> is_map_key(Reg, Xs);
+is_reg_defined({y,_}=Reg, #vst{current=#st{ys=Ys}}) -> is_map_key(Reg, Ys);
is_reg_defined(V, #vst{}) -> error({not_a_register, V}).
-is_type_defined_x({x,X}, #vst{current=#st{x=Xs}}) ->
- gb_trees:is_defined(X,Xs).
-
-is_type_defined_y({y,Y}, #vst{current=#st{y=Ys}}) ->
- gb_trees:is_defined(Y,Ys).
-
assert_term(Src, Vst) ->
- get_term_type(Src, Vst),
+ _ = get_term_type(Src, Vst),
ok.
-assert_not_fragile(Src, Vst) ->
- case get_term_type(Src, Vst) of
- {fragile, _} -> error({fragile_message_reference, Src});
- _ -> ok
- end.
+assert_movable(Src, Vst) ->
+ _ = get_move_term_type(Src, Vst),
+ ok.
assert_literal(nil) -> ok;
assert_literal({atom,A}) when is_atom(A) -> ok;
@@ -1753,16 +1865,106 @@ assert_not_literal(Literal) -> error({literal_not_allowed,Literal}).
%%
%% none A conflict in types. There will be an exception at runtime.
%%
-%% FRAGILITY
-%% ---------
-%%
-%% The loop_rec/2 instruction may return a reference to a term that is
-%% not part of the root set. That term or any part of it must not be
-%% included in a garbage collection. Therefore, the term (or any part
-%% of it) must not be stored in an Y register.
-%%
-%% Such terms are wrapped in a {fragile,Type} tuple, where Type is one
-%% of the types described above.
+
+%% join(Type1, Type2) -> Type
+%% Return the most specific type possible.
+join(Same, Same) ->
+ Same;
+join(none, Other) ->
+ Other;
+join(Other, none) ->
+ Other;
+join({literal,_}=T1, T2) ->
+ join_literal(T1, T2);
+join(T1, {literal,_}=T2) ->
+ join_literal(T2, T1);
+join({tuple,Size,EsA}, {tuple,Size,EsB}) ->
+ Es = join_tuple_elements(tuple_sz(Size), EsA, EsB),
+ {tuple, Size, Es};
+join({tuple,A,EsA}, {tuple,B,EsB}) ->
+ Size = min(tuple_sz(A), tuple_sz(B)),
+ Es = join_tuple_elements(Size, EsA, EsB),
+ {tuple, [Size], Es};
+join({Type,A}, {Type,B})
+ when Type =:= atom; Type =:= integer; Type =:= float ->
+ if A =:= B -> {Type,A};
+ true -> {Type,[]}
+ end;
+join({Type,_}, number)
+ when Type =:= integer; Type =:= float ->
+ number;
+join(number, {Type,_})
+ when Type =:= integer; Type =:= float ->
+ number;
+join({integer,_}, {float,_}) ->
+ number;
+join({float,_}, {integer,_}) ->
+ number;
+join(bool, {atom,A}) ->
+ join_bool(A);
+join({atom,A}, bool) ->
+ join_bool(A);
+join({atom,A}, {atom,B}) when is_boolean(A), is_boolean(B) ->
+ bool;
+join({atom,_}, {atom,_}) ->
+ {atom,[]};
+join(#ms{id=Id1,valid=B1,slots=Slots1},
+ #ms{id=Id2,valid=B2,slots=Slots2}) ->
+ Id = if
+ Id1 =:= Id2 -> Id1;
+ true -> make_ref()
+ end,
+ #ms{id=Id,valid=B1 band B2,slots=min(Slots1, Slots2)};
+join(T1, T2) when T1 =/= T2 ->
+ %% We've exhaused all other options, so the type must either be a list or
+ %% a 'term'.
+ join_list(T1, T2).
+
+join_tuple_elements(Limit, EsA, EsB) ->
+ Es0 = join_elements(EsA, EsB),
+ maps:filter(fun({integer,Index}, _Type) -> Index =< Limit end, Es0).
+
+join_elements(Es1, Es2) ->
+ Keys = if
+ map_size(Es1) =< map_size(Es2) -> maps:keys(Es1);
+ map_size(Es1) > map_size(Es2) -> maps:keys(Es2)
+ end,
+ join_elements_1(Keys, Es1, Es2, #{}).
+
+join_elements_1([Key | Keys], Es1, Es2, Acc0) ->
+ Type = case {Es1, Es2} of
+ {#{ Key := Same }, #{ Key := Same }} -> Same;
+ {#{ Key := Type1 }, #{ Key := Type2 }} -> join(Type1, Type2);
+ {#{}, #{}} -> term
+ end,
+ Acc = set_element_type(Key, Type, Acc0),
+ join_elements_1(Keys, Es1, Es2, Acc);
+join_elements_1([], _Es1, _Es2, Acc) ->
+ Acc.
+
+%% Joins types of literals; note that the left argument must either be a
+%% literal or exactly equal to the second argument.
+join_literal(Same, Same) ->
+ Same;
+join_literal({literal,_}=Lit, T) ->
+ join_literal(T, get_literal_type(Lit));
+join_literal(T1, T2) ->
+ %% We're done extracting the types, try merging them again.
+ join(T1, T2).
+
+join_list(nil, cons) -> list;
+join_list(nil, list) -> list;
+join_list(cons, list) -> list;
+join_list(T, nil) -> join_list(nil, T);
+join_list(T, cons) -> join_list(cons, T);
+join_list(_, _) ->
+ %% Not a list, so it must be a term.
+ term.
+
+join_bool([]) -> {atom,[]};
+join_bool(true) -> bool;
+join_bool(false) -> bool;
+join_bool(_) -> {atom,[]}.
%% meet(Type1, Type2) -> Type
%% Return the meet of two types. The meet is a more specific type.
@@ -1770,14 +1972,23 @@ assert_not_literal(Literal) -> error({literal_not_allowed,Literal}).
meet(Same, Same) ->
Same;
-meet({literal,_}=T1, T2) ->
- meet_literal(T1, T2);
-meet(T1, {literal,_}=T2) ->
- meet_literal(T2, T1);
meet(term, Other) ->
Other;
meet(Other, term) ->
Other;
+meet(#ms{}, binary) ->
+ #ms{};
+meet(binary, #ms{}) ->
+ #ms{};
+meet({literal,_}, {literal,_}) ->
+ none;
+meet(T1, {literal,_}=T2) ->
+ meet(T2, T1);
+meet({literal,_}=T1, T2) ->
+ case meet(get_literal_type(T1), T2) of
+ none -> none;
+ _ -> T1
+ end;
meet(T1, T2) ->
case {erlang:min(T1, T2),erlang:max(T1, T2)} of
{{atom,_}=A,{atom,[]}} -> A;
@@ -1810,13 +2021,6 @@ meet(T1, T2) ->
{_,_} -> none
end.
-%% Meets types of literals.
-meet_literal({literal,_}=Lit, T) ->
- meet_literal(T, get_literal_type(Lit));
-meet_literal(T1, T2) ->
- %% We're done extracting the types, try merging them again.
- meet(T1, T2).
-
meet_elements(Es1, Es2) ->
Keys = maps:keys(Es1) ++ maps:keys(Es2),
meet_elements_1(Keys, Es1, Es2, #{}).
@@ -1838,7 +2042,7 @@ meet_elements_1([], _Es1, _Es2, Acc) ->
%% No tuple elements may have an index above the known size.
assert_tuple_elements(Limit, Es) ->
- true = maps:fold(fun(Index, _T, true) ->
+ true = maps:fold(fun({integer,Index}, _T, true) ->
Index =< Limit
end, true, Es). %Assertion.
@@ -1855,7 +2059,7 @@ subtract(bool, {atom,true}) -> {atom, false};
subtract(Type, _) -> Type.
assert_type(WantedType, Term, Vst) ->
- Type = get_durable_term_type(Term, Vst),
+ Type = get_term_type(Term, Vst),
assert_type(WantedType, Type).
assert_type(Correct, Correct) -> ok;
@@ -1876,11 +2080,11 @@ assert_type(Needed, Actual) ->
error({bad_type,{needed,Needed},{actual,Actual}}).
get_element_type(Key, Src, Vst) ->
- get_element_type_1(Key, get_durable_term_type(Src, Vst)).
+ get_element_type_1(Key, get_term_type(Src, Vst)).
-get_element_type_1(Index, {tuple,Sz,Es}) ->
+get_element_type_1({integer,Index}=Key, {tuple,Sz,Es}) ->
case Es of
- #{ Index := Type } -> Type;
+ #{ Key := Type } -> Type;
#{} when Index =< Sz -> term;
#{} -> none
end;
@@ -1912,17 +2116,6 @@ get_term_type(Src, Vst) ->
Type -> Type
end.
-%% get_durable_term_type(Src, ValidatorState) -> Type
-%% Get the type of the source Src. The returned type Type will be
-%% a standard Erlang type (no catch/try tags or match contexts).
-%% Fragility will be stripped.
-
-get_durable_term_type(Src, Vst) ->
- case get_term_type(Src, Vst) of
- {fragile,Type} -> Type;
- Type -> Type
- end.
-
%% get_move_term_type(Src, ValidatorState) -> Type
%% Get the type of the source Src. The returned type Type will be
%% a standard Erlang type (no catch/try tags). Match contexts are OK.
@@ -1953,25 +2146,27 @@ get_tag_type(Src, _) ->
%% get_raw_type(Src, ValidatorState) -> Type
%% Return the type of a register without doing any validity checks.
-get_raw_type({x,X}, #vst{current=#st{x=Xs}}) when is_integer(X) ->
- case gb_trees:lookup(X, Xs) of
- {value,Type} -> Type;
- none -> uninitialized
+get_raw_type({x,X}=Src, #vst{current=#st{xs=Xs}}=Vst) when is_integer(X) ->
+ check_limit(Src),
+ case Xs of
+ #{ Src := #value_ref{}=Ref } -> get_raw_type(Ref, Vst);
+ #{} -> uninitialized
end;
-get_raw_type({y,Y}, #vst{current=#st{y=Ys}}) when is_integer(Y) ->
- case gb_trees:lookup(Y, Ys) of
- {value,Type} -> Type;
- none -> uninitialized
+get_raw_type({y,Y}=Src, #vst{current=#st{ys=Ys}}=Vst) when is_integer(Y) ->
+ check_limit(Src),
+ case Ys of
+ #{ Src := #value_ref{}=Ref } -> get_raw_type(Ref, Vst);
+ #{ Src := Tag } -> Tag;
+ #{} -> uninitialized
+ end;
+get_raw_type(#value_ref{}=Ref, #vst{current=#st{vs=Vs}}) ->
+ case Vs of
+ #{ Ref := #value{type=Type} } -> Type;
+ #{} -> none
end;
get_raw_type(Src, #vst{}) ->
get_literal_type(Src).
-get_def(Src, #vst{current=#st{defs=Defs}}) ->
- case Defs of
- #{Src:=Def} -> Def;
- #{} -> none
- end.
-
get_literal_type(nil=T) -> T;
get_literal_type({atom,A}=T) when is_atom(A) -> T;
get_literal_type({float,F}=T) when is_float(F) -> T;
@@ -1979,22 +2174,23 @@ get_literal_type({integer,I}=T) when is_integer(I) -> T;
get_literal_type({literal,[_|_]}) -> cons;
get_literal_type({literal,Bitstring}) when is_bitstring(Bitstring) -> binary;
get_literal_type({literal,Map}) when is_map(Map) -> map;
-get_literal_type({literal,Tuple}) when is_tuple(Tuple) -> value_to_type(Tuple);
+get_literal_type({literal,Tuple}) when is_tuple(Tuple) -> glt_1(Tuple);
get_literal_type({literal,_}) -> term;
get_literal_type(T) -> error({not_literal,T}).
-value_to_type([]) -> nil;
-value_to_type(A) when is_atom(A) -> {atom, A};
-value_to_type(F) when is_float(F) -> {float, F};
-value_to_type(I) when is_integer(I) -> {integer, I};
-value_to_type(T) when is_tuple(T) ->
- {Es,_} = foldl(fun(Val, {Es0, Index}) ->
- Type = value_to_type(Val),
- Es = set_element_type(Index, Type, Es0),
- {Es, Index + 1}
- end, {#{}, 1}, tuple_to_list(T)),
- {tuple, tuple_size(T), Es};
-value_to_type(L) -> {literal, L}.
+glt_1([]) -> nil;
+glt_1(A) when is_atom(A) -> {atom, A};
+glt_1(F) when is_float(F) -> {float, F};
+glt_1(I) when is_integer(I) -> {integer, I};
+glt_1(T) when is_tuple(T) ->
+ {Es,_} = foldl(fun(Val, {Es0, Index}) ->
+ Type = glt_1(Val),
+ Es = set_element_type({integer,Index}, Type, Es0),
+ {Es, Index + 1}
+ end, {#{}, 1}, tuple_to_list(T)),
+ {tuple, tuple_size(T), Es};
+glt_1(L) ->
+ {literal, L}.
branch_state(0, #vst{}=Vst) ->
%% If the instruction fails, the stack may be scanned
@@ -2002,36 +2198,134 @@ branch_state(0, #vst{}=Vst) ->
%% must be initialized at this point.
verify_y_init(Vst),
Vst;
-branch_state(L, #vst{current=St,branched=B}=Vst) ->
- Vst#vst{
- branched=case gb_trees:is_defined(L, B) of
- false ->
- gb_trees:insert(L, St, B);
- true ->
- MergedSt = merge_states(L, St, B),
- gb_trees:update(L, MergedSt, B)
- end}.
-
-%% merge_states/3 is used when there are more than one way to arrive
-%% at this point, and the type states for the different paths has
-%% to be merged. The type states are downgraded to the least common
-%% subset for the subsequent code.
-
-merge_states(L, St, Branched) when L =/= 0 ->
+branch_state(L, #vst{current=St,branched=B,ref_ctr=Counter0}=Vst) ->
+ case gb_trees:is_defined(L, B) of
+ true ->
+ {MergedSt, Counter} = merge_states(L, St, B, Counter0),
+ Branched = gb_trees:update(L, MergedSt, B),
+ Vst#vst{branched=Branched,ref_ctr=Counter};
+ false ->
+ Vst#vst{branched=gb_trees:insert(L, St, B)}
+ end.
+
+%% merge_states/3 is used when there's more than one way to arrive at a
+%% certain point, requiring the states to be merged down to the least
+%% common subset for the subsequent code.
+
+merge_states(L, St, Branched, Counter) when L =/= 0 ->
case gb_trees:lookup(L, Branched) of
- none -> St;
- {value,OtherSt} when St =:= none -> OtherSt;
- {value,OtherSt} -> merge_states_1(St, OtherSt)
+ none ->
+ {St, Counter};
+ {value,OtherSt} when St =:= none ->
+ {OtherSt, Counter};
+ {value,OtherSt} ->
+ merge_states_1(St, OtherSt, Counter)
end.
-merge_states_1(#st{x=Xs0,y=Ys0,numy=NumY0,h=H0,ct=Ct0,aliases=Aliases0},
- #st{x=Xs1,y=Ys1,numy=NumY1,h=H1,ct=Ct1,aliases=Aliases1}) ->
- NumY = merge_stk(NumY0, NumY1),
- Xs = merge_regs(Xs0, Xs1),
- Ys = merge_y_regs(Ys0, Ys1),
- Ct = merge_ct(Ct0, Ct1),
- Aliases = merge_aliases(Aliases0, Aliases1),
- #st{x=Xs,y=Ys,numy=NumY,h=min(H0, H1),ct=Ct,aliases=Aliases}.
+merge_states_1(#st{xs=XsA,ys=YsA,vs=VsA,fragile=FragA,numy=NumYA,h=HA,ct=CtA},
+ #st{xs=XsB,ys=YsB,vs=VsB,fragile=FragB,numy=NumYB,h=HB,ct=CtB},
+ Counter0) ->
+ %% When merging registers we drop all registers that aren't defined in both
+ %% states, and resolve conflicts by creating new values (similar to phi
+ %% nodes in SSA).
+ %%
+ %% While doing this we build a "merge map" detailing which values need to
+ %% be kept and which new values need to be created to resolve conflicts.
+ %% This map is then used to create a new value database where the types of
+ %% all values have been joined.
+ {Xs, Merge0, Counter1} = merge_regs(XsA, XsB, #{}, Counter0),
+ {Ys, Merge, Counter} = merge_regs(YsA, YsB, Merge0, Counter1),
+ Vs = merge_values(Merge, VsA, VsB),
+
+ Fragile = merge_fragility(FragA, FragB),
+ NumY = merge_stk(NumYA, NumYB),
+ Ct = merge_ct(CtA, CtB),
+
+ St = #st{xs=Xs,ys=Ys,vs=Vs,fragile=Fragile,numy=NumY,h=min(HA, HB),ct=Ct},
+ {St, Counter}.
+
+%% Merges the contents of two register maps, returning the updated "merge map"
+%% and the new registers.
+merge_regs(RsA, RsB, Merge, Counter) ->
+ Keys = if
+ map_size(RsA) =< map_size(RsB) -> maps:keys(RsA);
+ map_size(RsA) > map_size(RsB) -> maps:keys(RsB)
+ end,
+ merge_regs_1(Keys, RsA, RsB, #{}, Merge, Counter).
+
+merge_regs_1([Reg | Keys], RsA, RsB, Regs, Merge0, Counter0) ->
+ case {RsA, RsB} of
+ {#{ Reg := #value_ref{}=RefA }, #{ Reg := #value_ref{}=RefB }} ->
+ {Ref, Merge, Counter} = merge_vrefs(RefA, RefB, Merge0, Counter0),
+ merge_regs_1(Keys, RsA, RsB, Regs#{ Reg => Ref }, Merge, Counter);
+ {#{ Reg := TagA }, #{ Reg := TagB }} ->
+ %% Tags describe the state of the register rather than the value it
+ %% contains, so if a register contains a tag in one state we have
+ %% to merge it as a tag regardless of whether the other state says
+ %% it's a value.
+ {y, _} = Reg, %Assertion.
+ merge_regs_1(Keys, RsA, RsB, Regs#{ Reg => merge_tags(TagA,TagB) },
+ Merge0, Counter0);
+ {#{}, #{}} ->
+ merge_regs_1(Keys, RsA, RsB, Regs, Merge0, Counter0)
+ end;
+merge_regs_1([], _, _, Regs, Merge, Counter) ->
+ {Regs, Merge, Counter}.
+
+merge_tags(Same, Same) ->
+ Same;
+merge_tags(uninitialized, _) ->
+ uninitialized;
+merge_tags(_, uninitialized) ->
+ uninitialized;
+merge_tags({catchtag,T0}, {catchtag,T1}) ->
+ {catchtag, ordsets:from_list(T0 ++ T1)};
+merge_tags({trytag,T0}, {trytag,T1}) ->
+ {trytag, ordsets:from_list(T0 ++ T1)};
+merge_tags(_A, _B) ->
+ %% All other combinations leave the register initialized. Errors arising
+ %% from this will be caught later on.
+ initialized.
+
+merge_vrefs(Ref, Ref, Merge, Counter) ->
+ %% We have two (potentially) different versions of the same value, so we
+ %% should join their types into the same value.
+ {Ref, Merge#{ Ref => Ref }, Counter};
+merge_vrefs(RefA, RefB, Merge, Counter) ->
+ %% We have two different values, so we need to create a new value from
+ %% their joined type if we haven't already done so.
+ Key = {RefA, RefB},
+ case Merge of
+ #{ Key := Ref } ->
+ {Ref, Merge, Counter};
+ #{} ->
+ Ref = #value_ref{id=Counter},
+ {Ref, Merge#{ Key => Ref }, Counter + 1}
+ end.
+
+merge_values(Merge, VsA, VsB) ->
+ maps:fold(fun(Spec, New, Acc) ->
+ merge_values_1(Spec, New, VsA, VsB, Acc)
+ end, #{}, Merge).
+
+merge_values_1(Same, Same, VsA, VsB, Acc) ->
+ %% We're merging different versions of the same value, so it's safe to
+ %% reuse old entries if the type's unchanged.
+ #value{type=TypeA}=EntryA = map_get(Same, VsA),
+ #value{type=TypeB}=EntryB = map_get(Same, VsB),
+ Entry = case join(TypeA, TypeB) of
+ TypeA -> EntryA;
+ TypeB -> EntryB;
+ JoinedType -> EntryA#value{type=JoinedType}
+ end,
+ Acc#{ Same => Entry };
+merge_values_1({RefA, RefB}, New, VsA, VsB, Acc) ->
+ #value{type=TypeA} = map_get(RefA, VsA),
+ #value{type=TypeB} = map_get(RefB, VsB),
+ Acc#{ New => #value{op=join,args=[],type=join(TypeA, TypeB)} }.
+
+merge_fragility(FragileA, FragileB) ->
+ cerl_sets:union(FragileA, FragileB).
merge_stk(S, S) -> S;
merge_stk(_, _) -> undecided.
@@ -2044,174 +2338,17 @@ merge_ct_1([C0|Ct0], [C1|Ct1]) ->
merge_ct_1([], []) -> [];
merge_ct_1(_, _) -> undecided.
-merge_regs(Rs0, Rs1) ->
- Rs = merge_regs_1(gb_trees:to_list(Rs0), gb_trees:to_list(Rs1)),
- gb_trees_from_list(Rs).
-
-merge_regs_1([Same|Rs1], [Same|Rs2]) ->
- [Same|merge_regs_1(Rs1, Rs2)];
-merge_regs_1([{R1,_}|Rs1], [{R2,_}|_]=Rs2) when R1 < R2 ->
- merge_regs_1(Rs1, Rs2);
-merge_regs_1([{R1,_}|_]=Rs1, [{R2,_}|Rs2]) when R1 > R2 ->
- merge_regs_1(Rs1, Rs2);
-merge_regs_1([{R,Type1}|Rs1], [{R,Type2}|Rs2]) ->
- [{R,join(Type1, Type2)}|merge_regs_1(Rs1, Rs2)];
-merge_regs_1([], []) -> [];
-merge_regs_1([], [_|_]) -> [];
-merge_regs_1([_|_], []) -> [].
-
-merge_y_regs(Rs0, Rs1) ->
- case {gb_trees:size(Rs0),gb_trees:size(Rs1)} of
- {Sz0,Sz1} when Sz0 < Sz1 ->
- merge_y_regs_1(Sz0-1, Rs1, Rs0);
- {_,Sz1} ->
- merge_y_regs_1(Sz1-1, Rs0, Rs1)
- end.
-
-merge_y_regs_1(Y, S, Regs0) when Y >= 0 ->
- Type0 = gb_trees:get(Y, Regs0),
- case gb_trees:get(Y, S) of
- Type0 ->
- merge_y_regs_1(Y-1, S, Regs0);
- Type1 ->
- Type = join(Type0, Type1),
- Regs = gb_trees:update(Y, Type, Regs0),
- merge_y_regs_1(Y-1, S, Regs)
- end;
-merge_y_regs_1(_, _, Regs) -> Regs.
-
-%% join(Type1, Type2) -> Type
-%% Return the most specific type possible.
-%% Note: Type1 must NOT be the same as Type2.
-join({literal,_}=T1, T2) ->
- join_literal(T1, T2);
-join(T1, {literal,_}=T2) ->
- join_literal(T2, T1);
-join({fragile,Same}=Type, Same) ->
- Type;
-join({fragile,T1}, T2) ->
- make_fragile(join(T1, T2));
-join(Same, {fragile,Same}=Type) ->
- Type;
-join(T1, {fragile,T2}) ->
- make_fragile(join(T1, T2));
-join(uninitialized=I, _) -> I;
-join(_, uninitialized=I) -> I;
-join(initialized=I, _) -> I;
-join(_, initialized=I) -> I;
-join({catchtag,T0},{catchtag,T1}) ->
- {catchtag,ordsets:from_list(T0++T1)};
-join({trytag,T0},{trytag,T1}) ->
- {trytag,ordsets:from_list(T0++T1)};
-join({tuple,Size,EsA}, {tuple,Size,EsB}) ->
- Es = join_tuple_elements(tuple_sz(Size), EsA, EsB),
- {tuple, Size, Es};
-join({tuple,A,EsA}, {tuple,B,EsB}) ->
- Size = min(tuple_sz(A), tuple_sz(B)),
- Es = join_tuple_elements(Size, EsA, EsB),
- {tuple, [Size], Es};
-join({Type,A}, {Type,B})
- when Type =:= atom; Type =:= integer; Type =:= float ->
- if A =:= B -> {Type,A};
- true -> {Type,[]}
- end;
-join({Type,_}, number)
- when Type =:= integer; Type =:= float ->
- number;
-join(number, {Type,_})
- when Type =:= integer; Type =:= float ->
- number;
-join(bool, {atom,A}) ->
- join_bool(A);
-join({atom,A}, bool) ->
- join_bool(A);
-join({atom,_}, {atom,_}) ->
- {atom,[]};
-join(#ms{id=Id1,valid=B1,slots=Slots1},
- #ms{id=Id2,valid=B2,slots=Slots2}) ->
- Id = if
- Id1 =:= Id2 -> Id1;
- true -> make_ref()
- end,
- #ms{id=Id,valid=B1 band B2,slots=min(Slots1, Slots2)};
-join(T1, T2) when T1 =/= T2 ->
- %% We've exhaused all other options, so the type must either be a list or
- %% a 'term'.
- join_list(T1, T2).
-
-join_tuple_elements(Limit, EsA, EsB) ->
- Es0 = join_elements(EsA, EsB),
- maps:filter(fun(Index, _Type) -> Index =< Limit end, Es0).
-
-join_elements(Es1, Es2) ->
- Keys = if
- map_size(Es1) =< map_size(Es2) -> maps:keys(Es1);
- map_size(Es1) > map_size(Es2) -> maps:keys(Es2)
- end,
- join_elements_1(Keys, Es1, Es2, #{}).
-
-join_elements_1([Key | Keys], Es1, Es2, Acc0) ->
- Type = case {Es1, Es2} of
- {#{ Key := Same }, #{ Key := Same }} -> Same;
- {#{ Key := Type1 }, #{ Key := Type2 }} -> join(Type1, Type2);
- {#{}, #{}} -> term
- end,
- Acc = set_element_type(Key, Type, Acc0),
- join_elements_1(Keys, Es1, Es2, Acc);
-join_elements_1([], _Es1, _Es2, Acc) ->
- Acc.
-
-%% Joins types of literals; note that the left argument must either be a
-%% literal or exactly equal to the second argument.
-join_literal(Same, Same) ->
- Same;
-join_literal({literal,_}=Lit, T) ->
- join_literal(T, get_literal_type(Lit));
-join_literal(T1, T2) ->
- %% We're done extracting the types, try merging them again.
- join(T1, T2).
-
-join_list(nil, cons) -> list;
-join_list(nil, list) -> list;
-join_list(cons, list) -> list;
-join_list(T, nil) -> join_list(nil, T);
-join_list(T, cons) -> join_list(cons, T);
-join_list(_, _) ->
- %% Not a list, so it must be a term.
- term.
-
-join_bool([]) -> {atom,[]};
-join_bool(true) -> bool;
-join_bool(false) -> bool;
-join_bool(_) -> {atom,[]}.
-
tuple_sz([Sz]) -> Sz;
tuple_sz(Sz) -> Sz.
-merge_aliases(Al0, Al1) when map_size(Al0) =< map_size(Al1) ->
- maps:filter(fun(K, V) ->
- case Al1 of
- #{K:=V} -> true;
- #{} -> false
- end
- end, Al0);
-merge_aliases(Al0, Al1) ->
- merge_aliases(Al1, Al0).
-
-verify_y_init(#vst{current=#st{numy=NumY,y=Ys}}=Vst)
- when is_integer(NumY), NumY > 0 ->
- {HighestY, _} = gb_trees:largest(Ys),
+verify_y_init(#vst{current=#st{numy=NumY,ys=Ys}}=Vst) when is_integer(NumY) ->
+ HighestY = maps:fold(fun({y,Y}, _, Acc) -> max(Y, Acc) end, -1, Ys),
true = NumY > HighestY, %Assertion.
verify_y_init_1(NumY - 1, Vst),
ok;
-verify_y_init(#vst{current=#st{numy=undecided,y=Ys}}=Vst) ->
- case gb_trees:is_empty(Ys) of
- true ->
- ok;
- false ->
- {HighestY, _} = gb_trees:largest(Ys),
- verify_y_init_1(HighestY, Vst)
- end;
+verify_y_init(#vst{current=#st{numy=undecided,ys=Ys}}=Vst) ->
+ HighestY = maps:fold(fun({y,Y}, _, Acc) -> max(Y, Acc) end, -1, Ys),
+ verify_y_init_1(HighestY, Vst);
verify_y_init(#vst{}) ->
ok.
@@ -2219,15 +2356,10 @@ verify_y_init_1(-1, _Vst) ->
ok;
verify_y_init_1(Y, Vst) ->
Reg = {y, Y},
+ assert_not_fragile(Reg, Vst),
case get_raw_type(Reg, Vst) of
- uninitialized ->
- error({uninitialized_reg,Reg});
- {fragile, _} ->
- %% Unsafe. This term may be outside any heap belonging to the
- %% process and would be corrupted by a GC.
- error({fragile_message_reference,Reg});
- _ ->
- verify_y_init_1(Y - 1, Vst)
+ uninitialized -> error({uninitialized_reg,Reg});
+ _ -> verify_y_init_1(Y - 1, Vst)
end.
verify_live(0, _Vst) ->
@@ -2287,27 +2419,68 @@ eat_heap_float(#vst{current=#st{hf=HeapFloats0}=St}=Vst) ->
Vst#vst{current=St#st{hf=HeapFloats}}
end.
-remove_fragility(#vst{current=#st{x=Xs0,y=Ys0}=St0}=Vst) ->
- F = fun(_, {fragile,Type}) -> Type;
- (_, Type) -> Type
- end,
- Xs = gb_trees:map(F, Xs0),
- Ys = gb_trees:map(F, Ys0),
- St = St0#st{x=Xs,y=Ys},
+%%% FRAGILITY
+%%%
+%%% The loop_rec/2 instruction may return a reference to a term that is not
+%%% part of the root set. That term or any part of it must not be included in a
+%%% garbage collection. Therefore, the term (or any part of it) must not be
+%%% passed to another function, placed in another term, or live in a Y register
+%%% over an instruction that may GC.
+%%%
+%%% Fragility is marked on a per-register (rather than per-value) basis.
+
+%% Marks Reg as fragile.
+mark_fragile(Reg, Vst) ->
+ #vst{current=#st{fragile=Fragile0}=St0} = Vst,
+ Fragile = cerl_sets:add_element(Reg, Fragile0),
+ St = St0#st{fragile=Fragile},
Vst#vst{current=St}.
-propagate_fragility(Type, Ss, Vst) ->
- F = fun(S) ->
- case get_raw_type(S, Vst) of
- {fragile,_} -> true;
- _ -> false
- end
- end,
- case any(F, Ss) of
- true -> make_fragile(Type);
- false -> Type
+propagate_fragility(Reg, Args, #vst{current=St0}=Vst) ->
+ #st{fragile=Fragile0} = St0,
+
+ Sources = cerl_sets:from_list(Args),
+ Fragile = case cerl_sets:is_disjoint(Sources, Fragile0) of
+ true -> cerl_sets:del_element(Reg, Fragile0);
+ false -> cerl_sets:add_element(Reg, Fragile0)
+ end,
+
+ St = St0#st{fragile=Fragile},
+ Vst#vst{current=St}.
+
+%% Marks Reg as durable, must be used when assigning a newly created value to
+%% a register.
+remove_fragility(Reg, Vst) ->
+ #vst{current=#st{fragile=Fragile0}=St0} = Vst,
+ case cerl_sets:is_element(Reg, Fragile0) of
+ true ->
+ Fragile = cerl_sets:del_element(Reg, Fragile0),
+ St = St0#st{fragile=Fragile},
+ Vst#vst{current=St};
+ false ->
+ Vst
end.
+%% Marks all registers as durable.
+remove_fragility(#vst{current=St0}=Vst) ->
+ St = St0#st{fragile=cerl_sets:new()},
+ Vst#vst{current=St}.
+
+assert_durable_term(Src, Vst) ->
+ assert_term(Src, Vst),
+ assert_not_fragile(Src, Vst).
+
+assert_not_fragile({Kind,_}=Src, Vst) when Kind =:= x; Kind =:= y ->
+ check_limit(Src),
+ #vst{current=#st{fragile=Fragile}} = Vst,
+ case cerl_sets:is_element(Src, Fragile) of
+ true -> error({fragile_message_reference, Src});
+ false -> ok
+ end;
+assert_not_fragile(Lit, #vst{}) ->
+ assert_literal(Lit),
+ ok.
+
%%%
%%% Return/argument types of BIFs
%%%
@@ -2319,7 +2492,7 @@ bif_return_type('+', Src, Vst) ->
bif_return_type('*', Src, Vst) ->
arith_return_type(Src, Vst);
bif_return_type(abs, [Num], Vst) ->
- case get_durable_term_type(Num, Vst) of
+ case get_term_type(Num, Vst) of
{float,_}=T -> T;
{integer,_}=T -> T;
_ -> number
@@ -2327,8 +2500,10 @@ bif_return_type(abs, [Num], Vst) ->
bif_return_type(float, _, _) -> {float,[]};
bif_return_type('/', _, _) -> {float,[]};
%% Binary operations
-bif_return_type('byte_size', _, _) -> {integer,[]};
-bif_return_type('bit_size', _, _) -> {integer,[]};
+bif_return_type('binary_part', [_,_], _) -> binary;
+bif_return_type('binary_part', [_,_,_], _) -> binary;
+bif_return_type('bit_size', [_], _) -> {integer,[]};
+bif_return_type('byte_size', [_], _) -> {integer,[]};
%% Integer operations.
bif_return_type(ceil, [_], _) -> {integer,[]};
bif_return_type('div', [_,_], _) -> {integer,[]};
@@ -2362,6 +2537,7 @@ bif_return_type(is_boolean, [_], _) -> bool;
bif_return_type(is_binary, [_], _) -> bool;
bif_return_type(is_float, [_], _) -> bool;
bif_return_type(is_function, [_], _) -> bool;
+bif_return_type(is_function, [_,_], _) -> bool;
bif_return_type(is_integer, [_], _) -> bool;
bif_return_type(is_list, [_], _) -> bool;
bif_return_type(is_map, [_], _) -> bool;
@@ -2372,6 +2548,7 @@ bif_return_type(is_reference, [_], _) -> bool;
bif_return_type(is_tuple, [_], _) -> bool;
%% Misc.
bif_return_type(tuple_size, [_], _) -> {integer,[]};
+bif_return_type(map_size, [_], _) -> {integer,[]};
bif_return_type(node, [], _) -> {atom,[]};
bif_return_type(node, [_], _) -> {atom,[]};
bif_return_type(hd, [_], _) -> term;
@@ -2393,14 +2570,24 @@ bif_arg_types('and', [_,_]) -> [bool, bool];
bif_arg_types('or', [_,_]) -> [bool, bool];
bif_arg_types('xor', [_,_]) -> [bool, bool];
%% Binary
-bif_arg_types('byte_size', [_]) -> [binary];
+bif_arg_types('binary_part', [_,_]) ->
+ PosLen = {tuple, 2, #{ {integer,1} => {integer,[]},
+ {integer,2} => {integer,[]} }},
+ [binary, PosLen];
+bif_arg_types('binary_part', [_,_,_]) ->
+ [binary, {integer,[]}, {integer,[]}];
bif_arg_types('bit_size', [_]) -> [binary];
+bif_arg_types('byte_size', [_]) -> [binary];
%% Numerical
bif_arg_types('-', [_]) -> [number];
+bif_arg_types('-', [_,_]) -> [number,number];
bif_arg_types('+', [_]) -> [number];
+bif_arg_types('+', [_,_]) -> [number,number];
bif_arg_types('*', [_,_]) -> [number, number];
bif_arg_types('/', [_,_]) -> [number, number];
+bif_arg_types(abs, [_]) -> [number];
bif_arg_types(ceil, [_]) -> [number];
+bif_arg_types(float, [_]) -> [number];
bif_arg_types(floor, [_]) -> [number];
bif_arg_types(trunc, [_]) -> [number];
bif_arg_types(round, [_]) -> [number];
@@ -2446,14 +2633,14 @@ is_bif_safe(_, _) -> false.
arith_return_type([A], Vst) ->
%% Unary '+' or '-'.
- case get_durable_term_type(A, Vst) of
+ case get_term_type(A, Vst) of
{integer,_} -> {integer,[]};
{float,_} -> {float,[]};
_ -> number
end;
arith_return_type([A,B], Vst) ->
- TypeA = get_durable_term_type(A, Vst),
- TypeB = get_durable_term_type(B, Vst),
+ TypeA = get_term_type(A, Vst),
+ TypeB = get_term_type(B, Vst),
case {TypeA, TypeB} of
{{integer,_},{integer,_}} -> {integer,[]};
{{float,_},_} -> {float,[]};
@@ -2482,7 +2669,7 @@ call_return_type_1(erlang, setelement, 3, Vst) ->
case meet({tuple,[I],#{}}, TupleType) of
{tuple, Sz, Es0} ->
ValueType = get_term_type({x,2}, Vst),
- Es = set_element_type(I, ValueType, Es0),
+ Es = set_element_type({integer,I}, ValueType, Es0),
{tuple, Sz, Es};
none ->
TupleType
@@ -2542,19 +2729,33 @@ math_mod_return_type(fmod, 2) -> {float,[]};
math_mod_return_type(pi, 0) -> {float,[]};
math_mod_return_type(F, A) when is_atom(F), is_integer(A), A >= 0 -> term.
+lists_mod_return_type(all, 2, _Vst) ->
+ bool;
+lists_mod_return_type(any, 2, _Vst) ->
+ bool;
+lists_mod_return_type(keymember, 3, _Vst) ->
+ bool;
+lists_mod_return_type(member, 2, _Vst) ->
+ bool;
+lists_mod_return_type(prefix, 2, _Vst) ->
+ bool;
+lists_mod_return_type(suffix, 2, _Vst) ->
+ bool;
lists_mod_return_type(dropwhile, 2, _Vst) ->
list;
lists_mod_return_type(duplicate, 2, _Vst) ->
list;
lists_mod_return_type(filter, 2, _Vst) ->
list;
+lists_mod_return_type(flatten, 1, _Vst) ->
+ list;
lists_mod_return_type(flatten, 2, _Vst) ->
list;
lists_mod_return_type(map, 2, Vst) ->
same_length_type({x,1}, Vst);
lists_mod_return_type(MF, 3, Vst) when MF =:= mapfoldl; MF =:= mapfoldr ->
ListType = same_length_type({x,2}, Vst),
- {tuple,2,#{1=>ListType}};
+ {tuple,2,#{ {integer,1} => ListType} };
lists_mod_return_type(partition, 2, _Vst) ->
two_tuple(list, list);
lists_mod_return_type(reverse, 1, Vst) ->
@@ -2590,7 +2791,8 @@ lists_mod_return_type(_, _, _) ->
term.
two_tuple(Type1, Type2) ->
- {tuple,2,#{1=>Type1,2=>Type2}}.
+ {tuple,2,#{ {integer,1} => Type1,
+ {integer,2} => Type2 }}.
same_length_type(Reg, Vst) ->
case get_term_type(Reg, Vst) of
@@ -2600,15 +2802,25 @@ same_length_type(Reg, Vst) ->
_ -> list
end.
-check_limit({x,X}) when is_integer(X), X < 1023 ->
- %% Note: x(1023) is reserved for use by the BEAM loader.
- ok;
-check_limit({y,Y}) when is_integer(Y), Y < 1024 ->
- ok;
-check_limit({fr,Fr}) when is_integer(Fr), Fr < 1024 ->
- ok;
-check_limit(_) ->
- error(limit).
+check_limit({x,X}=Src) when is_integer(X) ->
+ if
+ %% Note: x(1023) is reserved for use by the BEAM loader.
+ 0 =< X, X < 1023 -> ok;
+ 1023 =< X -> error(limit);
+ X < 0 -> error({bad_register, Src})
+ end;
+check_limit({y,Y}=Src) when is_integer(Y) ->
+ if
+ 0 =< Y, Y < 1024 -> ok;
+ 1024 =< Y -> error(limit);
+ Y < 0 -> error({bad_register, Src})
+ end;
+check_limit({fr,Fr}=Src) when is_integer(Fr) ->
+ if
+ 0 =< Fr, Fr < 1023 -> ok;
+ 1023 =< Fr -> error(limit);
+ Fr < 0 -> error({bad_register, Src})
+ end.
min(A, B) when is_integer(A), is_integer(B), A < B -> A;
min(A, B) when is_integer(A), is_integer(B) -> B.
diff --git a/lib/compiler/src/cerl_sets.erl b/lib/compiler/src/cerl_sets.erl
index 0361186713..f489baf238 100644
--- a/lib/compiler/src/cerl_sets.erl
+++ b/lib/compiler/src/cerl_sets.erl
@@ -204,4 +204,4 @@ fold(F, Init, D) ->
Set2 :: set(Element).
filter(F, D) ->
- maps:from_list(lists:filter(fun({K,_}) -> F(K) end, maps:to_list(D))).
+ maps:filter(fun(K,_) -> F(K) end, D).
diff --git a/lib/compiler/src/v3_kernel.erl b/lib/compiler/src/v3_kernel.erl
index 86351bc0c5..e2b8787224 100644
--- a/lib/compiler/src/v3_kernel.erl
+++ b/lib/compiler/src/v3_kernel.erl
@@ -1590,19 +1590,12 @@ match_var([U|Us], Cs0, Def, St) ->
%% constructor/constant as first argument. Group the constructors
%% according to type, the order is really irrelevant but tries to be
%% smart.
-
-match_con(Us, Cs0, Def, St) ->
- %% Expand literals at the top level.
- Cs = [expand_pat_lit_clause(C) || C <- Cs0],
- match_con_1(Us, Cs, Def, St).
-
-match_con_1([U|_Us] = L, Cs, Def, St0) ->
+match_con([U|_Us] = L, Cs, Def, St0) ->
%% Extract clauses for different constructors (types).
%%ok = io:format("match_con ~p~n", [Cs]),
- Ttcs0 = select_types([k_binary], Cs) ++ select_bin_con(Cs) ++
- select_types([k_cons,k_tuple,k_map,k_atom,k_float,
- k_int,k_nil], Cs),
- Ttcs = opt_single_valued(Ttcs0),
+ Ttcs0 = select_types(Cs, [], [], [], [], [], [], [], [], []),
+ Ttcs1 = [{T, Types} || {T, [_ | _] = Types} <- Ttcs0],
+ Ttcs = opt_single_valued(Ttcs1),
%%ok = io:format("ttcs = ~p~n", [Ttcs]),
{Scs,St1} =
mapfoldl(fun ({T,Tcs}, St) ->
@@ -1613,8 +1606,41 @@ match_con_1([U|_Us] = L, Cs, Def, St0) ->
St0, Ttcs),
{build_alt_1st_no_fail(build_select(U, Scs), Def),St1}.
-select_types(Types, Cs) ->
- [{T,Tcs} || T <- Types, begin Tcs = select(T, Cs), Tcs =/= [] end].
+select_types([NoExpC | Cs], Bin, BinCon, Cons, Tuple, Map, Atom, Float, Int, Nil) ->
+ C = expand_pat_lit_clause(NoExpC),
+ case clause_con(C) of
+ k_binary ->
+ select_types(Cs, [C |Bin], BinCon, Cons, Tuple, Map, Atom, Float, Int, Nil);
+ k_bin_seg ->
+ select_types(Cs, Bin, [C | BinCon], Cons, Tuple, Map, Atom, Float, Int, Nil);
+ k_bin_end ->
+ select_types(Cs, Bin, [C | BinCon], Cons, Tuple, Map, Atom, Float, Int, Nil);
+ k_cons ->
+ select_types(Cs, Bin, BinCon, [C | Cons], Tuple, Map, Atom, Float, Int, Nil);
+ k_tuple ->
+ select_types(Cs, Bin, BinCon, Cons, [C | Tuple], Map, Atom, Float, Int, Nil);
+ k_map ->
+ select_types(Cs, Bin, BinCon, Cons, Tuple, [C | Map], Atom, Float, Int, Nil);
+ k_atom ->
+ select_types(Cs, Bin, BinCon, Cons, Tuple, Map, [C | Atom], Float, Int, Nil);
+ k_float ->
+ select_types(Cs, Bin, BinCon, Cons, Tuple, Map, Atom, [C | Float], Int, Nil);
+ k_int ->
+ select_types(Cs, Bin, BinCon, Cons, Tuple, Map, Atom, Float, [C | Int], Nil);
+ k_nil ->
+ select_types(Cs, Bin, BinCon, Cons, Tuple, Map, Atom, Float, Int, [C | Nil])
+ end;
+select_types([], Bin, BinCon, Cons, Tuple, Map, Atom, Float, Int, Nil) ->
+ [{k_binary, reverse(Bin)}] ++ handle_bin_con(reverse(BinCon)) ++
+ [
+ {k_cons, reverse(Cons)},
+ {k_tuple, reverse(Tuple)},
+ {k_map, reverse(Map)},
+ {k_atom, reverse(Atom)},
+ {k_float, reverse(Float)},
+ {k_int, reverse(Int)},
+ {k_nil, reverse(Nil)}
+ ].
expand_pat_lit_clause(#iclause{pats=[#ialias{pat=#k_literal{anno=A,val=Val}}=Alias|Ps]}=C) ->
P = expand_pat_lit(Val, A),
@@ -1743,20 +1769,12 @@ combine_bin_segs(#k_bin_end{}) ->
combine_bin_segs(_) ->
throw(not_possible).
-%% select_bin_con([Clause]) -> [{Type,[Clause]}].
-%% Extract clauses for the k_bin_seg constructor. As k_bin_seg
+%% handle_bin_con([Clause]) -> [{Type,[Clause]}].
+%% Handle clauses for the k_bin_seg constructor. As k_bin_seg
%% matching can overlap, the k_bin_seg constructors cannot be
%% reordered, only grouped.
-select_bin_con(Cs0) ->
- Cs1 = lists:filter(fun (C) ->
- Con = clause_con(C),
- (Con =:= k_bin_seg) or (Con =:= k_bin_end)
- end, Cs0),
- select_bin_con_1(Cs1).
-
-
-select_bin_con_1(Cs) ->
+handle_bin_con(Cs) ->
try
%% The usual way to match literals is to first extract the
%% value to a register, and then compare the register to the
@@ -1795,14 +1813,14 @@ select_bin_con_1(Cs) ->
end
catch
throw:not_possible ->
- select_bin_con_2(Cs)
+ handle_bin_con_not_possible(Cs)
end.
-select_bin_con_2([C1|Cs]) ->
+handle_bin_con_not_possible([C1|Cs]) ->
Con = clause_con(C1),
{More,Rest} = splitwith(fun (C) -> clause_con(C) =:= Con end, Cs),
- [{Con,[C1|More]}|select_bin_con_2(Rest)];
-select_bin_con_2([]) -> [].
+ [{Con,[C1|More]}|handle_bin_con_not_possible(Rest)];
+handle_bin_con_not_possible([]) -> [].
%% select_bin_int([Clause]) -> {k_bin_int,[Clause]}
%% If the first pattern in each clause selects the same integer,
@@ -1902,10 +1920,6 @@ select_utf8(Val0) ->
throw(not_possible)
end.
-%% select(Con, [Clause]) -> [Clause].
-
-select(T, Cs) -> [ C || C <- Cs, clause_con(C) =:= T ].
-
%% match_value([Var], Con, [Clause], Default, State) -> {SelectExpr,State}.
%% At this point all the clauses have the same constructor, we must
%% now separate them according to value.
@@ -2040,6 +2054,10 @@ get_match(#k_cons{}, St0) ->
get_match(#k_binary{}, St0) ->
{[V]=Mes,St1} = new_vars(1, St0),
{#k_binary{segs=V},Mes,St1};
+get_match(#k_bin_seg{size=#k_atom{val=all},next={k_bin_end,[]}}=Seg, St0) ->
+ {[S,N0],St1} = new_vars(2, St0),
+ N = set_kanno(N0, [no_usage]),
+ {Seg#k_bin_seg{seg=S,next=N},[S],St1};
get_match(#k_bin_seg{}=Seg, St0) ->
{[S,N0],St1} = new_vars(2, St0),
N = set_kanno(N0, [no_usage]),
@@ -2067,6 +2085,9 @@ new_clauses(Cs0, U, St) ->
#k_cons{hd=H,tl=T} -> [H,T|As];
#k_tuple{es=Es} -> Es ++ As;
#k_binary{segs=E} -> [E|As];
+ #k_bin_seg{size=#k_atom{val=all},
+ seg=S,next={k_bin_end,[]}} ->
+ [S|As];
#k_bin_seg{seg=S,next=N} ->
[S,N|As];
#k_bin_int{next=N} ->
diff --git a/lib/compiler/test/beam_jump_SUITE.erl b/lib/compiler/test/beam_jump_SUITE.erl
index 759d884dc4..a456f31d79 100644
--- a/lib/compiler/test/beam_jump_SUITE.erl
+++ b/lib/compiler/test/beam_jump_SUITE.erl
@@ -79,12 +79,13 @@ checks(Wanted) ->
{catch case river() of sheet -> begin +Wanted, if "da" -> Wanted end end end, catch case river() of sheet -> begin + Wanted, if "da" -> Wanted end end end}.
unsafe_move_elimination(_Config) ->
- {{left,right,false},false} = unsafe_move_elimination(left, right, false),
- {{false,right,false},false} = unsafe_move_elimination(false, right, true),
- {{true,right,right},right} = unsafe_move_elimination(true, right, true),
+ {{left,right,false},false} = unsafe_move_elimination_1(left, right, false),
+ {{false,right,false},false} = unsafe_move_elimination_1(false, right, true),
+ {{true,right,right},right} = unsafe_move_elimination_1(true, right, true),
+ [ok = unsafe_move_elimination_2(I) || I <- lists:seq(0,16)],
ok.
-unsafe_move_elimination(Left, Right, Simple0) ->
+unsafe_move_elimination_1(Left, Right, Simple0) ->
id(1),
%% The move at label 29 would be removed by beam_jump, which is unsafe because
@@ -115,6 +116,44 @@ unsafe_move_elimination(Left, Right, Simple0) ->
end,
{id({Left,Right,Simple}),Simple}.
+unsafe_move_elimination_2(Int) ->
+ %% The type optimization pass would recognize that TagInt can only be
+ %% [0 .. 7], so the first 'case' would select_val over [0 .. 6] and swap
+ %% out the fail label with the block for 7.
+ %%
+ %% A later optimization would merge this block with 'expects_h' in the
+ %% second case, as the latter is only reachable from the former.
+ %%
+ %% ... but this broke down when the move elimination optimization didn't
+ %% take the fail label of the first select_val into account. This caused it
+ %% to believe that the only way to reach 'expects_h' was through the second
+ %% case when 'Tag' =:= 'h', which made it remove the move instruction
+ %% added in the first case, passing garbage to expects_h/2.
+ TagInt = Int band 2#111,
+ Tag = case TagInt of
+ 0 -> a;
+ 1 -> b;
+ 2 -> c;
+ 3 -> d;
+ 4 -> e;
+ 5 -> f;
+ 6 -> g;
+ 7 -> h
+ end,
+ case Tag of
+ g -> expects_g(TagInt, Tag);
+ h -> expects_h(TagInt, Tag);
+ _ -> Tag = id(Tag), ok
+ end.
+
+expects_g(6, Atom) ->
+ Atom = id(g),
+ ok.
+
+expects_h(7, Atom) ->
+ Atom = id(h),
+ ok.
+
-record(message2, {id, p1}).
-record(message3, {id, p1, p2}).
diff --git a/lib/compiler/test/beam_validator_SUITE.erl b/lib/compiler/test/beam_validator_SUITE.erl
index 2660bf222c..265da43f9d 100644
--- a/lib/compiler/test/beam_validator_SUITE.erl
+++ b/lib/compiler/test/beam_validator_SUITE.erl
@@ -107,13 +107,12 @@ xrange(Config) when is_list(Config) ->
Errors = do_val(xrange, Config),
[{{t,sum_1,2},
{{bif,'+',{f,0},[{x,-1},{x,1}],{x,0}},4,
- {uninitialized_reg,{x,-1}}}},
+ {bad_register,{x,-1}}}},
{{t,sum_2,2},
- {{bif,'+',{f,0},[{x,0},{x,1023}],{x,0}},4,
- {uninitialized_reg,{x,1023}}}},
+ {{bif,'+',{f,0},[{x,0},{x,1023}],{x,0}},4,limit}},
{{t,sum_3,2},
{{bif,'+',{f,0},[{x,0},{x,1}],{x,-1}},4,
- {invalid_store,{x,-1},number}}},
+ {bad_register,{x,-1}}}},
{{t,sum_4,2},
{{bif,'+',{f,0},[{x,0},{x,1}],{x,1023}},4,limit}}] = Errors,
ok.
@@ -122,15 +121,15 @@ yrange(Config) when is_list(Config) ->
Errors = do_val(yrange, Config),
[{{t,sum_1,2},
{{move,{x,1},{y,-1}},5,
- {invalid_store,{y,-1},term}}},
+ {bad_register,{y,-1}}}},
{{t,sum_2,2},
{{bif,'+',{f,0},[{x,0},{y,1024}],{x,0}},7,
- {uninitialized_reg,{y,1024}}}},
+ limit}},
{{t,sum_3,2},
{{move,{x,1},{y,1024}},5,limit}},
{{t,sum_4,2},
{{move,{x,1},{y,-1}},5,
- {invalid_store,{y,-1},term}}}] = Errors,
+ {bad_register,{y,-1}}}}] = Errors,
ok.
stack(Config) when is_list(Config) ->
@@ -178,7 +177,7 @@ unsafe_catch(Config) when is_list(Config) ->
Errors = do_val(unsafe_catch, Config),
[{{t,small,2},
{{bs_put_integer,{f,0},{integer,16},1,
- {field_flags,[unsigned,big]},{y,0}},
+ {field_flags,[unsigned,big]},{y,0}},
20,
{unassigned,{y,0}}}}] = Errors,
ok.
@@ -223,7 +222,7 @@ bad_catch_try(Config) when is_list(Config) ->
{{try_case,{y,1}},12,{invalid_tag,{y,1},term}}},
{{bad_catch_try,bad_6,1},
{{move,{integer,1},{y,1}},7,
- {invalid_store,{y,1},{integer,1}}}}] = Errors,
+ {invalid_store,{y,1}}}}] = Errors,
ok.
cons_guard(Config) when is_list(Config) ->
@@ -247,7 +246,7 @@ freg_range(Config) when is_list(Config) ->
{{t,sum_3,2},
{{bif,fadd,{f,0},[{fr,0},{fr,1}],{fr,-1}},
7,
- {bad_target,{fr,-1}}}},
+ {bad_register,{fr,-1}}}},
{{t,sum_4,2},
{{bif,fadd,{f,0},[{fr,0},{fr,1}],{fr,1024}},
7,
diff --git a/lib/compiler/test/receive_SUITE.erl b/lib/compiler/test/receive_SUITE.erl
index 12108445f0..0038eb1a4b 100644
--- a/lib/compiler/test/receive_SUITE.erl
+++ b/lib/compiler/test/receive_SUITE.erl
@@ -25,7 +25,8 @@
init_per_group/2,end_per_group/2,
init_per_testcase/2,end_per_testcase/2,
export/1,recv/1,coverage/1,otp_7980/1,ref_opt/1,
- wait/1,recv_in_try/1,double_recv/1,receive_var_zero/1]).
+ wait/1,recv_in_try/1,double_recv/1,receive_var_zero/1,
+ match_built_terms/1]).
-include_lib("common_test/include/ct.hrl").
@@ -45,7 +46,8 @@ all() ->
groups() ->
[{p,test_lib:parallel(),
[recv,coverage,otp_7980,ref_opt,export,wait,
- recv_in_try,double_recv,receive_var_zero]}].
+ recv_in_try,double_recv,receive_var_zero,
+ match_built_terms]}].
init_per_suite(Config) ->
@@ -400,5 +402,29 @@ receive_var_zero(Config) when is_list(Config) ->
zero() -> 0.
+%% ERL-862; the validator would explode when a term was constructed in a
+%% receive guard.
+
+-define(MATCH_BUILT_TERM(Ref, Expr),
+ (fun() ->
+ Ref = make_ref(),
+ A = id($a),
+ B = id($b),
+ Built = id(Expr),
+ self() ! {Ref, A, B},
+ receive
+ {Ref, A, B} when Expr =:= Built ->
+ ok
+ after 5000 ->
+ ct:fail("Failed to match message with term built in "
+ "receive guard.")
+ end
+ end)()).
+
+match_built_terms(Config) when is_list(Config) ->
+ ?MATCH_BUILT_TERM(Ref, [A, B]),
+ ?MATCH_BUILT_TERM(Ref, {A, B}),
+ ?MATCH_BUILT_TERM(Ref, <<A, B>>),
+ ?MATCH_BUILT_TERM(Ref, #{ 1 => A, 2 => B}).
id(I) -> I.
diff --git a/lib/crypto/c_src/pkey.c b/lib/crypto/c_src/pkey.c
index 567e8df08a..393358d173 100644
--- a/lib/crypto/c_src/pkey.c
+++ b/lib/crypto/c_src/pkey.c
@@ -70,10 +70,13 @@ static int get_pkey_digest_type(ErlNifEnv *env, ERL_NIF_TERM algorithm, ERL_NIF_
if (type == atom_none && algorithm == atom_rsa)
return PKEY_OK;
+ if (algorithm == atom_eddsa) {
#ifdef HAVE_EDDSA
- if (algorithm == atom_eddsa)
- return PKEY_OK;
+ if (!FIPS_mode()) return PKEY_OK;
+#else
+ return PKEY_NOTSUP;
#endif
+ }
if ((digp = get_digest_type(type)) == NULL)
return PKEY_BADARG;
if (digp->md.p == NULL)
@@ -312,11 +315,16 @@ static int get_pkey_private_key(ErlNifEnv *env, ERL_NIF_TERM algorithm, ERL_NIF_
return PKEY_NOTSUP;
#endif
} else if (algorithm == atom_eddsa) {
-#if defined(HAVE_EDDSA)
- if (!get_eddsa_key(env, 0, key, &result))
- goto err;
+#ifdef HAVE_EDDSA
+ if (!FIPS_mode())
+ {
+ if (!get_eddsa_key(env, 0, key, &result))
+ goto err;
+ else
+ goto done; // Not nice....
+ }
#else
- return PKEY_NOTSUP;
+ return PKEY_NOTSUP;
#endif
} else if (algorithm == atom_dss) {
if ((dsa = DSA_new()) == NULL)
@@ -432,10 +440,11 @@ static int get_pkey_public_key(ErlNifEnv *env, ERL_NIF_TERM algorithm, ERL_NIF_T
return PKEY_NOTSUP;
#endif
} else if (algorithm == atom_eddsa) {
-#if defined(HAVE_EDDSA)
- if (!get_eddsa_key(env, 1, key, &result))
- goto err;
-
+#ifdef HAVE_EDDSA
+ if (!FIPS_mode()) {
+ if (!get_eddsa_key(env, 1, key, &result))
+ goto err;
+ }
#else
return PKEY_NOTSUP;
#endif
@@ -516,7 +525,6 @@ ERL_NIF_TERM pkey_sign_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
/*char buf[1024];
enif_get_atom(env,argv[0],buf,1024,ERL_NIF_LATIN1); printf("algo=%s ",buf);
enif_get_atom(env,argv[1],buf,1024,ERL_NIF_LATIN1); printf("hash=%s ",buf);
-printf("\r\n");
*/
#ifndef HAS_ENGINE_SUPPORT
@@ -583,22 +591,24 @@ printf("\r\n");
if (argv[0] == atom_eddsa) {
#ifdef HAVE_EDDSA
- if ((mdctx = EVP_MD_CTX_new()) == NULL)
- goto err;
+ if (!FIPS_mode()) {
+ if ((mdctx = EVP_MD_CTX_new()) == NULL)
+ goto err;
- if (EVP_DigestSignInit(mdctx, NULL, NULL, NULL, pkey) != 1)
- goto err;
- if (EVP_DigestSign(mdctx, NULL, &siglen, tbs, tbslen) != 1)
- goto err;
- if (!enif_alloc_binary(siglen, &sig_bin))
- goto err;
- sig_bin_alloc = 1;
+ if (EVP_DigestSignInit(mdctx, NULL, NULL, NULL, pkey) != 1)
+ goto err;
+ if (EVP_DigestSign(mdctx, NULL, &siglen, tbs, tbslen) != 1)
+ goto err;
+ if (!enif_alloc_binary(siglen, &sig_bin))
+ goto err;
+ sig_bin_alloc = 1;
- if (EVP_DigestSign(mdctx, sig_bin.data, &siglen, tbs, tbslen) != 1)
- goto bad_key;
-#else
- goto bad_arg;
+ if (EVP_DigestSign(mdctx, sig_bin.data, &siglen, tbs, tbslen) != 1)
+ goto bad_key;
+ }
+ else
#endif
+ goto notsup;
} else {
if (EVP_PKEY_sign(ctx, NULL, &siglen, tbs, tbslen) != 1)
goto err;
@@ -805,16 +815,18 @@ ERL_NIF_TERM pkey_verify_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]
if (argv[0] == atom_eddsa) {
#ifdef HAVE_EDDSA
- if ((mdctx = EVP_MD_CTX_new()) == NULL)
- goto err;
-
- if (EVP_DigestVerifyInit(mdctx, NULL, NULL, NULL, pkey) != 1)
- goto err;
+ if (!FIPS_mode()) {
+ if ((mdctx = EVP_MD_CTX_new()) == NULL)
+ goto err;
- result = EVP_DigestVerify(mdctx, sig_bin.data, sig_bin.size, tbs, tbslen);
-#else
- goto bad_arg;
+ if (EVP_DigestVerifyInit(mdctx, NULL, NULL, NULL, pkey) != 1)
+ goto err;
+
+ result = EVP_DigestVerify(mdctx, sig_bin.data, sig_bin.size, tbs, tbslen);
+ }
+ else
#endif
+ goto notsup;
} else {
if (md != NULL) {
ERL_VALGRIND_ASSERT_MEM_DEFINED(tbs, EVP_MD_size(md));
diff --git a/lib/crypto/test/Makefile b/lib/crypto/test/Makefile
index 8b320e01a9..988d95a8bc 100644
--- a/lib/crypto/test/Makefile
+++ b/lib/crypto/test/Makefile
@@ -7,7 +7,6 @@ include $(ERL_TOP)/make/$(TARGET)/otp.mk
MODULES = \
crypto_bench_SUITE \
- blowfish_SUITE \
crypto_SUITE \
engine_SUITE
diff --git a/lib/crypto/test/blowfish_SUITE.erl b/lib/crypto/test/blowfish_SUITE.erl
deleted file mode 100644
index a931ebb47e..0000000000
--- a/lib/crypto/test/blowfish_SUITE.erl
+++ /dev/null
@@ -1,300 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2009-2018. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-
-%%
--module(blowfish_SUITE).
-
-%% Note: This directive should only be used in test suites.
--compile(export_all).
-
--include_lib("common_test/include/ct.hrl").
-
--define(TIMEOUT, 120000). % 2 min
-
--define(KEY, to_bin("0123456789ABCDEFF0E1D2C3B4A59687")).
--define(IVEC, to_bin("FEDCBA9876543210")).
-%% "7654321 Now is the time for " (includes trailing '\0')
--define(DATA, to_bin("37363534333231204E6F77206973207468652074696D6520666F722000")).
--define(DATA_PADDED, to_bin("37363534333231204E6F77206973207468652074696D6520666F722000000000")).
-
-%% Test server callback functions
-%%--------------------------------------------------------------------
-%% Function: init_per_suite(Config) -> Config
-%% Config - [tuple()]
-%% A list of key/value pairs, holding the test case configuration.
-%% Description: Initialization before the whole suite
-%%
-%% Note: This function is free to add any key/value pairs to the Config
-%% variable, but should NOT alter/remove any existing entries.
-%%--------------------------------------------------------------------
-init_per_suite(Config) ->
- case catch crypto:start() of
- ok ->
- catch ct:comment("~s",[element(3,hd(crypto:info_lib()))]),
- catch ct:log("crypto:info_lib() -> ~p~n"
- "crypto:supports() -> ~p~n"
- "crypto:version() -> ~p~n"
- ,[crypto:info_lib(), crypto:supports(), crypto:version()]),
- Config;
- _Else ->
- {skip,"Could not start crypto!"}
- end.
-
-%%--------------------------------------------------------------------
-%% Function: end_per_suite(Config) -> _
-%% Config - [tuple()]
-%% A list of key/value pairs, holding the test case configuration.
-%% Description: Cleanup after the whole suite
-%%--------------------------------------------------------------------
-end_per_suite(_Config) ->
- crypto:stop().
-
-%%--------------------------------------------------------------------
-%% Function: init_per_testcase(TestCase, Config) -> Config
-%% Case - atom()
-%% Name of the test case that is about to be run.
-%% Config - [tuple()]
-%% A list of key/value pairs, holding the test case configuration.
-%%
-%% Description: Initialization before each test case
-%%
-%% Note: This function is free to add any key/value pairs to the Config
-%% variable, but should NOT alter/remove any existing entries.
-%% Description: Initialization before each test case
-%%--------------------------------------------------------------------
-init_per_testcase(_TestCase, Config0) ->
- Config = lists:keydelete(watchdog, 1, Config0),
- Dog = test_server:timetrap(?TIMEOUT),
- [{watchdog, Dog} | Config].
-
-%%--------------------------------------------------------------------
-%% Function: end_per_testcase(TestCase, Config) -> _
-%% Case - atom()
-%% Name of the test case that is about to be run.
-%% Config - [tuple()]
-%% A list of key/value pairs, holding the test case configuration.
-%% Description: Cleanup after each test case
-%%--------------------------------------------------------------------
-end_per_testcase(_TestCase, Config) ->
- Dog = ?config(watchdog, Config),
- case Dog of
- undefined ->
- ok;
- _ ->
- test_server:timetrap_cancel(Dog)
- end.
-
-%%--------------------------------------------------------------------
-%% Function: all(Clause) -> TestCases
-%% Clause - atom() - suite | doc
-%% TestCases - [Case]
-%% Case - atom()
-%% Name of a test case.
-%% Description: Returns a list of all test cases in this test suite
-%%--------------------------------------------------------------------
-suite() -> [{ct_hooks,[ts_install_cth]}].
-
-all() ->
-[{group, fips},
- {group, non_fips}].
-
-groups() ->
- [{fips, [], [no_ecb, no_cbc, no_cfb64, no_ofb64]},
- {non_fips, [], [ecb, cbc, cfb64, ofb64]}].
-
-init_per_group(fips, Config) ->
- case crypto:info_fips() of
- enabled ->
- Config;
- not_enabled ->
- case crypto:enable_fips_mode(true) of
- true ->
- enabled = crypto:info_fips(),
- Config;
- false ->
- {skip, "Failed to enable FIPS mode"}
- end;
- not_supported ->
- {skip, "FIPS mode not supported"}
- end;
-init_per_group(non_fips, Config) ->
- case crypto:info_fips() of
- enabled ->
- true = crypto:enable_fips_mode(false),
- not_enabled = crypto:info_fips(),
- Config;
- _NotEnabled ->
- Config
- end;
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
-
-%% Test cases start here.
-%%--------------------------------------------------------------------
-
-ecb_test(KeyBytes, ClearBytes, CipherBytes) ->
- {Key, Clear, Cipher} =
- {to_bin(KeyBytes), to_bin(ClearBytes), to_bin(CipherBytes)},
- ?line m(crypto:block_encrypt(blowfish_ecb, Key, Clear), Cipher),
- true.
-
-ecb(doc) ->
- "Test that ECB mode is OK";
-ecb(suite) ->
- [];
-ecb(Config) when is_list(Config) ->
- true = ecb_test("0000000000000000", "0000000000000000", "4EF997456198DD78"),
- true = ecb_test("FFFFFFFFFFFFFFFF", "FFFFFFFFFFFFFFFF", "51866FD5B85ECB8A"),
- true = ecb_test("3000000000000000", "1000000000000001", "7D856F9A613063F2"),
- true = ecb_test("1111111111111111", "1111111111111111", "2466DD878B963C9D"),
- true = ecb_test("0123456789ABCDEF", "1111111111111111", "61F9C3802281B096"),
- true = ecb_test("1111111111111111", "0123456789ABCDEF", "7D0CC630AFDA1EC7"),
- true = ecb_test("0000000000000000", "0000000000000000", "4EF997456198DD78"),
- true = ecb_test("FEDCBA9876543210", "0123456789ABCDEF", "0ACEAB0FC6A0A28D"),
- true = ecb_test("7CA110454A1A6E57", "01A1D6D039776742", "59C68245EB05282B"),
- true = ecb_test("0131D9619DC1376E", "5CD54CA83DEF57DA", "B1B8CC0B250F09A0"),
- true = ecb_test("07A1133E4A0B2686", "0248D43806F67172", "1730E5778BEA1DA4"),
- true = ecb_test("3849674C2602319E", "51454B582DDF440A", "A25E7856CF2651EB"),
- true = ecb_test("04B915BA43FEB5B6", "42FD443059577FA2", "353882B109CE8F1A"),
- true = ecb_test("0113B970FD34F2CE", "059B5E0851CF143A", "48F4D0884C379918"),
- true = ecb_test("0170F175468FB5E6", "0756D8E0774761D2", "432193B78951FC98"),
- true = ecb_test("43297FAD38E373FE", "762514B829BF486A", "13F04154D69D1AE5"),
- true = ecb_test("07A7137045DA2A16", "3BDD119049372802", "2EEDDA93FFD39C79"),
- true = ecb_test("04689104C2FD3B2F", "26955F6835AF609A", "D887E0393C2DA6E3"),
- true = ecb_test("37D06BB516CB7546", "164D5E404F275232", "5F99D04F5B163969"),
- true = ecb_test("1F08260D1AC2465E", "6B056E18759F5CCA", "4A057A3B24D3977B"),
- true = ecb_test("584023641ABA6176", "004BD6EF09176062", "452031C1E4FADA8E"),
- true = ecb_test("025816164629B007", "480D39006EE762F2", "7555AE39F59B87BD"),
- true = ecb_test("49793EBC79B3258F", "437540C8698F3CFA", "53C55F9CB49FC019"),
- true = ecb_test("4FB05E1515AB73A7", "072D43A077075292", "7A8E7BFA937E89A3"),
- true = ecb_test("49E95D6D4CA229BF", "02FE55778117F12A", "CF9C5D7A4986ADB5"),
- true = ecb_test("018310DC409B26D6", "1D9D5C5018F728C2", "D1ABB290658BC778"),
- true = ecb_test("1C587F1C13924FEF", "305532286D6F295A", "55CB3774D13EF201"),
- true = ecb_test("0101010101010101", "0123456789ABCDEF", "FA34EC4847B268B2"),
- true = ecb_test("1F1F1F1F0E0E0E0E", "0123456789ABCDEF", "A790795108EA3CAE"),
- true = ecb_test("E0FEE0FEF1FEF1FE", "0123456789ABCDEF", "C39E072D9FAC631D"),
- true = ecb_test("0000000000000000", "FFFFFFFFFFFFFFFF", "014933E0CDAFF6E4"),
- true = ecb_test("FFFFFFFFFFFFFFFF", "0000000000000000", "F21E9A77B71C49BC"),
- true = ecb_test("0123456789ABCDEF", "0000000000000000", "245946885754369A"),
- true = ecb_test("FEDCBA9876543210", "FFFFFFFFFFFFFFFF", "6B5C5A9C5D9E0A5A"),
- ok.
-
-cbc(doc) ->
- "Test that CBC mode is OK";
-cbc(suite) ->
- [];
-cbc(Config) when is_list(Config) ->
- true = crypto:block_encrypt(blowfish_cbc, ?KEY, ?IVEC, ?DATA_PADDED) =:=
- to_bin("6B77B4D63006DEE605B156E27403979358DEB9E7154616D959F1652BD5FF92CC"),
- ok.
-
-cfb64(doc) ->
- "Test that CFB64 mode is OK";
-cfb64(suite) ->
- [];
-cfb64(Config) when is_list(Config) ->
- true = crypto:block_encrypt(blowfish_cfb64, ?KEY, ?IVEC, ?DATA) =:=
- to_bin("E73214A2822139CAF26ECF6D2EB9E76E3DA3DE04D1517200519D57A6C3"),
- ok.
-
-ofb64(doc) ->
- "Test that OFB64 mode is OK";
-ofb64(suite) ->
- [];
-ofb64(Config) when is_list(Config) ->
- true = crypto:block_encrypt(blowfish_ofb64, ?KEY, ?IVEC, ?DATA) =:=
- to_bin("E73214A2822139CA62B343CC5B65587310DD908D0C241B2263C2CF80DA"),
- ok.
-
-no_ecb(doc) ->
- "Test that ECB mode is disabled";
-no_ecb(suite) ->
- [];
-no_ecb(Config) when is_list(Config) ->
- notsup(fun crypto:block_encrypt/3,
- [blowfish_ecb,
- to_bin("0000000000000000"),
- to_bin("FFFFFFFFFFFFFFFF")]).
-
-no_cbc(doc) ->
- "Test that CBC mode is disabled";
-no_cbc(suite) ->
- [];
-no_cbc(Config) when is_list(Config) ->
- notsup(fun crypto:block_encrypt/4,
- [blowfish_cbc, ?KEY, ?IVEC, ?DATA_PADDED]).
-
-no_cfb64(doc) ->
- "Test that CFB64 mode is disabled";
-no_cfb64(suite) ->
- [];
-no_cfb64(Config) when is_list(Config) ->
- notsup(fun crypto:block_encrypt/4,
- [blowfish_cfb64, ?KEY, ?IVEC, ?DATA]),
- ok.
-
-no_ofb64(doc) ->
- "Test that OFB64 mode is disabled";
-no_ofb64(suite) ->
- [];
-no_ofb64(Config) when is_list(Config) ->
- notsup(fun crypto:block_encrypt/4,
- [blowfish_ofb64, ?KEY, ?IVEC, ?DATA]).
-
-%% Helper functions
-
-%% Assert function fails with notsup error
-notsup(Fun, Args) ->
- ok = try
- {error, {return, apply(Fun, Args)}}
- catch
- error:notsup ->
- ok;
- Class:Error ->
- {error, {Class, Error}}
- end.
-
-
-%% Convert a hexadecimal string to a binary.
--spec(to_bin(L::string()) -> binary()).
-to_bin(L) ->
- to_bin(L, []).
-
-%% @spec dehex(char()) -> integer()
-%% @doc Convert a hex digit to its integer value.
--spec(dehex(char()) -> integer()).
-dehex(C) when C >= $0, C =< $9 ->
- C - $0;
-dehex(C) when C >= $a, C =< $f ->
- C - $a + 10;
-dehex(C) when C >= $A, C =< $F ->
- C - $A + 10.
-
--spec(to_bin(L::string(), list()) -> binary()).
-to_bin([], Acc) ->
- iolist_to_binary(lists:reverse(Acc));
-to_bin([C1, C2 | Rest], Acc) ->
- to_bin(Rest, [(dehex(C1) bsl 4) bor dehex(C2) | Acc]).
-
-m(X,X) -> ok.
diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl
index c4323de83f..ab6d88deb2 100644
--- a/lib/crypto/test/crypto_SUITE.erl
+++ b/lib/crypto/test/crypto_SUITE.erl
@@ -101,6 +101,8 @@ groups() ->
{group, rsa},
{group, dss},
{group, ecdsa},
+ {group, no_ed25519},
+ {group, no_ed448},
{group, dh},
{group, ecdh},
{group, no_srp},
@@ -115,8 +117,8 @@ groups() ->
{group, no_blowfish_cfb64},
{group, no_blowfish_ofb64},
{group, aes_cbc128},
- {group, aes_cfb8},
- {group, aes_cfb128},
+ {group, no_aes_cfb8},
+ {group, no_aes_cfb128},
{group, aes_cbc256},
{group, no_aes_ige256},
{group, no_rc2_cbc},
@@ -187,8 +189,16 @@ groups() ->
{chacha20, [], [stream]},
{poly1305, [], [poly1305]},
{aes_cbc, [], [block]},
+ {no_aes_cfb8,[], [no_support, no_block]},
+ {no_aes_cfb128,[], [no_support, no_block]},
{no_md4, [], [no_support, no_hash]},
{no_md5, [], [no_support, no_hash, no_hmac]},
+ {no_ed25519, [], [no_support, no_sign_verify
+ %% Does not work yet: ,public_encrypt, private_encrypt
+ ]},
+ {no_ed448, [], [no_support, no_sign_verify
+ %% Does not work yet: ,public_encrypt, private_encrypt
+ ]},
{no_ripemd160, [], [no_support, no_hash]},
{no_srp, [], [no_support, no_generate_compute]},
{no_des_cbc, [], [no_support, no_block]},
@@ -255,7 +265,7 @@ init_per_group(fips, Config) ->
enabled = crypto:info_fips(),
FIPSConfig;
false ->
- {skip, "Failed to enable FIPS mode"}
+ {fail, "Failed to enable FIPS mode"}
end;
not_supported ->
{skip, "FIPS mode not supported"}
@@ -405,17 +415,6 @@ block() ->
block(Config) when is_list(Config) ->
Fips = proplists:get_bool(fips, Config),
Type = ?config(type, Config),
- %% See comment about EVP_CIPHER_CTX_set_key_length in
- %% block_crypt_nif in crypto.c.
- case {Fips, Type} of
- {true, aes_cfb8} ->
- throw({skip, "Cannot test aes_cfb8 in FIPS mode because of key length issue"});
- {true, aes_cfb128} ->
- throw({skip, "Cannot test aes_cfb128 in FIPS mode because of key length issue"});
- _ ->
- ok
- end,
-
Blocks = lazy_eval(proplists:get_value(block, Config)),
lists:foreach(fun block_cipher/1, Blocks),
lists:foreach(fun block_cipher/1, block_iolistify(Blocks)),
@@ -504,6 +503,13 @@ sign_verify(Config) when is_list(Config) ->
SignVerify = proplists:get_value(sign_verify, Config),
lists:foreach(fun do_sign_verify/1, SignVerify).
+%%--------------------------------------------------------------------
+no_sign_verify() ->
+ [{doc, "Test disabled sign/verify digital signatures"}].
+no_sign_verify(Config) when is_list(Config) ->
+ [SignVerifyHd|_] = proplists:get_value(sign_verify, Config),
+ notsup(fun do_sign_verify/1, [SignVerifyHd]).
+
%%--------------------------------------------------------------------
public_encrypt() ->
[{doc, "Test public_encrypt/decrypt "}].
diff --git a/lib/edoc/src/edoc.erl b/lib/edoc/src/edoc.erl
index b641118c5d..e9d62d3283 100644
--- a/lib/edoc/src/edoc.erl
+++ b/lib/edoc/src/edoc.erl
@@ -578,7 +578,7 @@ read_source(Name, Opts0) ->
Opts = expand_opts(Opts0),
case read_source_1(Name, Opts) of
{ok, Forms} ->
- check_forms(Forms, Name),
+ check_forms(Forms, Name, Opts),
Forms;
{error, R} ->
edoc_report:error({"error reading file '~ts'.",
@@ -692,13 +692,19 @@ fll([T | L], LastLine, Ts) ->
fll(L, _LastLine, Ts) ->
lists:reverse(L, Ts).
-check_forms(Fs, Name) ->
+check_forms(Fs, Name, Opts) ->
Fun = fun (F) ->
case erl_syntax:type(F) of
error_marker ->
case erl_syntax:error_marker_info(F) of
{L, M, D} ->
- edoc_report:error(L, Name, {format_error, M, D});
+ edoc_report:error(L, Name, {format_error, M, D}),
+ case proplists:get_bool(preprocess, Opts) of
+ true ->
+ ok;
+ false ->
+ helpful_message(Name)
+ end;
Other ->
edoc_report:report(Name, "unknown error in "
"source code: ~w.", [Other])
@@ -710,6 +716,11 @@ check_forms(Fs, Name) ->
end,
lists:foreach(Fun, Fs).
+helpful_message(Name) ->
+ Ms = ["If the error is caused by too exotic macro",
+ "definitions or uses of macros, adding option",
+ "{preprocess, true} can help. See also edoc(3)."],
+ lists:foreach(fun(M) -> edoc_report:report(Name, M, []) end, Ms).
%% @spec get_doc(File::filename()) -> {ModuleName, edoc_module()}
%% @equiv get_doc(File, [])
diff --git a/lib/erl_docgen/priv/css/otp_doc.css b/lib/erl_docgen/priv/css/otp_doc.css
index 89b278215c..17d9f8dd56 100644
--- a/lib/erl_docgen/priv/css/otp_doc.css
+++ b/lib/erl_docgen/priv/css/otp_doc.css
@@ -74,7 +74,7 @@ a:visited { color: #1b6ec2; text-decoration: none }
/* Invisible table for function specs,
* just to get since-version out in right margin */
-.func-table, .func-tr, .func-td, .func-since-td {
+.func-table, .func-tr, .func-td, .cfunc-td, .func-since-td {
width: 200%;
border: 0;
padding: 0;
@@ -86,7 +86,13 @@ a:visited { color: #1b6ec2; text-decoration: none }
}
.func-td {
- width: 50%
+ width: 50%;
+}
+
+.cfunc-td {
+ width: 50%;
+ padding-left: 100px;
+ text-indent: -100px;
}
.func-since-td {
diff --git a/lib/erl_docgen/priv/xsl/db_html.xsl b/lib/erl_docgen/priv/xsl/db_html.xsl
index c5150d447c..c9be926e1e 100644
--- a/lib/erl_docgen/priv/xsl/db_html.xsl
+++ b/lib/erl_docgen/priv/xsl/db_html.xsl
@@ -2119,17 +2119,10 @@
<xsl:when test="ancestor::cref">
<table class="func-table">
<tr class="func-tr">
- <td class="func-td">
+ <td class="cfunc-td">
<span class="bold_code bc-7">
<xsl:call-template name="title_link">
<xsl:with-param name="link" select="substring-before(nametext, '(')"/>
- <xsl:with-param name="title">
- <xsl:value-of select="ret"/>
- <xsl:call-template name="maybe-space-after-ret">
- <xsl:with-param name="s" select="ret"/>
- </xsl:call-template>
- <xsl:value-of select="nametext"/>
- </xsl:with-param>
</xsl:call-template>
</span>
</td>
@@ -2199,18 +2192,6 @@
</xsl:template>
- <xsl:template name="maybe-space-after-ret">
- <xsl:param name="s"/>
- <xsl:variable name="last_char"
- select="substring($s, string-length($s), 1)"/>
- <xsl:choose>
- <xsl:when test="$last_char != '*'">
- <xsl:text> </xsl:text>
- </xsl:when>
- </xsl:choose>
- </xsl:template>
-
-
<!-- Type -->
<xsl:template match="type">
<xsl:param name="partnum"/>
@@ -2264,7 +2245,7 @@
</xsl:template>
<xsl:template name="title_link">
- <xsl:param name="title"/>
+ <xsl:param name="title" select="'APPLY'"/>
<xsl:param name="link" select="erl:to-link(title)"/>
<xsl:param name="ghlink" select="ancestor-or-self::*[@ghlink][position() = 1]/@ghlink"/>
<xsl:variable name="id" select="concat(concat($link,'-'), generate-id(.))"/>
@@ -2274,7 +2255,16 @@
<xsl:with-param name="id" select="$id"/>
<xsl:with-param name="ghlink" select="$ghlink"/>
</xsl:call-template>
- <a class="title_link" name="{$link}" href="#{$link}"><xsl:value-of select="$title"/></a>
+ <a class="title_link" name="{$link}" href="#{$link}">
+ <xsl:choose>
+ <xsl:when test="$title = 'APPLY'">
+ <xsl:apply-templates/> <!-- like <ret> and <nametext> -->
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="$title"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </a>
</span>
</xsl:template>
@@ -2704,4 +2694,46 @@
<xsl:value-of select="normalize-space(.)"/>
</xsl:template>
+ <xsl:template match="ret">
+ <xsl:value-of select="."/>
+ <xsl:variable name="last_char" select="substring(., string-length(.), 1)"/>
+ <xsl:if test="$last_char != '*'">
+ <xsl:text> </xsl:text>
+ </xsl:if>
+ </xsl:template>
+
+ <xsl:template match="nametext">
+ <xsl:value-of select="substring-before(.,'(')"/>
+ <xsl:text>(</xsl:text>
+ <xsl:variable name="arglist" select="substring-after(.,'(')"/>
+ <xsl:choose>
+ <xsl:when test="$arglist = ')' or $arglist = 'void)'">
+ <xsl:value-of select="$arglist"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <br/>
+ <xsl:call-template name="cfunc-arglist">
+ <xsl:with-param name="text" select="$arglist"/>
+ </xsl:call-template>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
+ <!-- Format C function argument list with <br> after comma -->
+ <xsl:template name="cfunc-arglist">
+ <xsl:param name="text"/>
+ <xsl:variable name="line" select="normalize-space($text)"/>
+ <xsl:choose>
+ <xsl:when test="contains($line,',')">
+ <xsl:value-of select="substring-before($line,',')"/>,<br/>
+ <xsl:call-template name="cfunc-arglist">
+ <xsl:with-param name="text" select="substring-after($line,',')"/>
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="$line"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
</xsl:stylesheet>
diff --git a/lib/erl_interface/src/prog/erl_start.c b/lib/erl_interface/src/prog/erl_start.c
index 670a5900c9..ba495ac818 100644
--- a/lib/erl_interface/src/prog/erl_start.c
+++ b/lib/erl_interface/src/prog/erl_start.c
@@ -97,7 +97,7 @@
#endif
#ifndef RSH
-#define RSH "/usr/bin/rsh"
+#define RSH "/usr/bin/ssh"
#endif
#ifndef HAVE_SOCKLEN_T
diff --git a/lib/inets/examples/httpd_load_test/hdlt_slave.erl b/lib/inets/examples/httpd_load_test/hdlt_slave.erl
index 5ee005629d..30ddfd76af 100644
--- a/lib/inets/examples/httpd_load_test/hdlt_slave.erl
+++ b/lib/inets/examples/httpd_load_test/hdlt_slave.erl
@@ -44,18 +44,17 @@
%% this to work is that the 'erl' program can be found in PATH.
%%
%% If the master and slave are on different hosts, start/N uses
-%% the 'rsh' program to spawn an Erlang node on the other host.
+%% the 'ssh' program to spawn an Erlang node on the other host.
%% Alternative, if the master was started as
%% 'erl -sname xxx -rsh my_rsh...', then 'my_rsh' will be used instead
-%% of 'rsh' (this is useful for systems where the rsh program is named
-%% 'remsh').
+%% of 'ssh' (this is useful for systems still using rsh or remsh).
%%
%% For this to work, the following conditions must be fulfilled:
%%
-%% 1. There must be an Rsh program on computer; if not an error
+%% 1. There must be an ssh program on computer; if not an error
%% is returned.
%%
-%% 2. The hosts must be configured to allowed 'rsh' access without
+%% 2. The hosts must be configured to allow 'ssh' access without
%% prompts for password.
%%
%% The slave node will have its filer and user server redirected
@@ -244,7 +243,7 @@ register_unique_name(Number) ->
%% Makes up the command to start the nodes.
%% If the node should run on the local host, there is
-%% no need to use rsh.
+%% no need to use ssh.
mk_cmd(Host, Name, Paths, Args, Waiter, Prog) ->
PaPaths = [[" -pa ", Path] || Path <- Paths],
diff --git a/lib/kernel/doc/src/application.xml b/lib/kernel/doc/src/application.xml
index 4e32c1a3a5..5170502581 100644
--- a/lib/kernel/doc/src/application.xml
+++ b/lib/kernel/doc/src/application.xml
@@ -238,6 +238,41 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code>
</desc>
</func>
<func>
+ <name name="set_env" arity="1" since="OTP @OTP-15642@"/>
+ <name name="set_env" arity="2" since="OTP @OTP-15642@"/>
+ <fsummary>Sets the configuration parameters of multiple applications.</fsummary>
+ <desc>
+ <p>Sets the configuration <c><anno>Config</anno></c> for multiple
+ applications. It is equivalent to calling <c>set_env/4</c> on
+ each application individially, except it is more efficient.
+ The given <c><anno>Config</anno></c> is validated before the
+ configuration is set.</p>
+ <p><c>set_env/2</c> uses the standard <c>gen_server</c> time-out
+ value (5000 ms). Option <c>timeout</c> can be specified
+ if another time-out value is useful, for example, in situations
+ where the application controller is heavily loaded.</p>
+ <p>Option <c>persistent</c> can be set to <c>true</c>
+ to guarantee that parameters set with <c>set_env/2</c>
+ are not overridden by those defined in the application resource
+ file on load. This means that persistent values will stick after the application
+ is loaded and also on application reload.</p>
+ <p>If an application is given more than once or if an application
+ has the same key given more than once, the behaviour is undefined
+ and a warning message will be logged. In future releases, an error
+ will be raised.</p>
+ <p><c>set_env/1</c> is equivalent to <c>set_env(Config, [])</c>.</p>
+ <warning>
+ <p>Use this function only if you know what you are doing,
+ that is, on your own applications. It is very
+ application-dependent and
+ configuration parameter-dependent when and how often
+ the value is read by the application. Careless use
+ of this function can put the application in a
+ weird, inconsistent, and malfunctioning state.</p>
+ </warning>
+ </desc>
+ </func>
+ <func>
<name name="permit" arity="2" since=""/>
<fsummary>Change the permission for an application to run at a node.</fsummary>
<desc>
diff --git a/lib/kernel/doc/src/logger.xml b/lib/kernel/doc/src/logger.xml
index df2d081d76..e6448e144e 100644
--- a/lib/kernel/doc/src/logger.xml
+++ b/lib/kernel/doc/src/logger.xml
@@ -190,7 +190,7 @@ logger:error("error happened because: ~p", [Reason]). % Without macro
<list>
<item><c>pid => self()</c></item>
<item><c>gl => group_leader()</c></item>
- <item><c>time => erlang:system_time(microsecond)</c></item>
+ <item><c>time => logger:timestamp()</c></item>
</list>
<p>When a log macro is used, Logger also inserts location
information:</p>
@@ -288,8 +288,8 @@ logger:error("error happened because: ~p", [Reason]). % Without macro
<name name="timestamp"/>
<desc>
<p>A timestamp produced
- with <seealso marker="erts:erlang#system_time-1">
- <c>erlang:system_time(microsecond)</c></seealso>.</p>
+ with <seealso marker="#timestamp-0">
+ <c>logger:timestamp()</c></seealso>.</p>
</desc>
</datatype>
</datatypes>
@@ -1117,6 +1117,24 @@ logger:set_proxy_config(maps:merge(Old, Config)).
a key-value list before formatting as such.</p>
</desc>
</func>
+
+ <func>
+ <name name="timestamp" arity="0" since="OTP @OTP-15625@"/>
+ <fsummary>Return a timestamp to insert in meta data for a log
+ event.</fsummary>
+ <desc>
+ <p>Return a timestamp that can be inserted as the <c>time</c>
+ field in the meta data for a log event. It is produced with
+ <seealso marker="kernel:os#system_time-1">
+ <c>os:system_time(microsecond)</c></seealso>.</p>
+ <p>Notice that Logger automatically inserts a timestamp in the
+ meta data unless it already exists. This function is
+ exported for the rare case when the timestamp must be taken
+ at a different point in time than when the log event is
+ issued.</p>
+ </desc>
+ </func>
+
</funcs>
<section>
diff --git a/lib/kernel/src/application.erl b/lib/kernel/src/application.erl
index bc6be2f8f5..5c2e981e4b 100644
--- a/lib/kernel/src/application.erl
+++ b/lib/kernel/src/application.erl
@@ -25,7 +25,7 @@
which_applications/0, which_applications/1,
loaded_applications/0, permit/2]).
-export([ensure_started/1, ensure_started/2]).
--export([set_env/3, set_env/4, unset_env/2, unset_env/3]).
+-export([set_env/1, set_env/2, set_env/3, set_env/4, unset_env/2, unset_env/3]).
-export([get_env/1, get_env/2, get_env/3, get_all_env/0, get_all_env/1]).
-export([get_key/1, get_key/2, get_all_key/0, get_all_key/1]).
-export([get_application/0, get_application/1, info/0]).
@@ -279,6 +279,26 @@ loaded_applications() ->
info() ->
application_controller:info().
+-spec set_env(Config) -> 'ok' when
+ Config :: [{Application, Env}],
+ Application :: atom(),
+ Env :: [{Par :: atom(), Val :: term()}].
+
+set_env(Config) when is_list(Config) ->
+ set_env(Config, []).
+
+-spec set_env(Config, Opts) -> 'ok' when
+ Config :: [{Application, Env}],
+ Application :: atom(),
+ Env :: [{Par :: atom(), Val :: term()}],
+ Opts :: [{timeout, timeout()} | {persistent, boolean()}].
+
+set_env(Config, Opts) when is_list(Config), is_list(Opts) ->
+ case application_controller:set_env(Config, Opts) of
+ ok -> ok;
+ {error, Msg} -> erlang:error({badarg, Msg}, [Config, Opts])
+ end.
+
-spec set_env(Application, Par, Val) -> 'ok' when
Application :: atom(),
Par :: atom(),
diff --git a/lib/kernel/src/application_controller.erl b/lib/kernel/src/application_controller.erl
index a074d2e74b..9a8091fb2e 100644
--- a/lib/kernel/src/application_controller.erl
+++ b/lib/kernel/src/application_controller.erl
@@ -26,7 +26,7 @@
control_application/1,
change_application_data/2, prep_config_change/0, config_change/1,
which_applications/0, which_applications/1,
- loaded_applications/0, info/0,
+ loaded_applications/0, info/0, set_env/2,
get_pid_env/2, get_env/2, get_pid_all_env/1, get_all_env/1,
get_pid_key/2, get_key/2, get_pid_all_key/1, get_all_key/1,
get_master/1, get_application/1, get_application_module/1,
@@ -345,9 +345,6 @@ get_all_env(AppName) ->
map(fun([Key, Val]) -> {Key, Val} end,
ets:match(ac_tab, {{env, AppName, '$1'}, '$2'})).
-
-
-
get_pid_key(Master, Key) ->
case ets:match(ac_tab, {{application_master, '$1'}, Master}) of
[[AppName]] -> get_key(AppName, Key);
@@ -461,6 +458,15 @@ permit_application(ApplName, Flag) ->
{permit_application, ApplName, Flag},
infinity).
+set_env(Config, Opts) ->
+ case check_conf_data(Config) of
+ ok ->
+ Timeout = proplists:get_value(timeout, Opts, 5000),
+ gen_server:call(?AC, {set_env, Config, Opts}, Timeout);
+
+ {error, _} = Error ->
+ Error
+ end.
set_env(AppName, Key, Val) ->
gen_server:call(?AC, {set_env, AppName, Key, Val, []}).
@@ -528,19 +534,17 @@ check_conf_data([]) ->
check_conf_data(ConfData) when is_list(ConfData) ->
[Application | ConfDataRem] = ConfData,
case Application of
- {kernel, List} when is_list(List) ->
- case check_para_kernel(List) of
- ok ->
- check_conf_data(ConfDataRem);
- Error1 ->
- Error1
- end;
{AppName, List} when is_atom(AppName), is_list(List) ->
- case check_para(List, atom_to_list(AppName)) of
- ok ->
- check_conf_data(ConfDataRem);
- Error2 ->
- Error2
+ case lists:keymember(AppName, 1, ConfDataRem) of
+ true ->
+ ?LOG_WARNING("duplicate application config: " ++ atom_to_list(AppName));
+ false ->
+ ok
+ end,
+
+ case check_para(List, AppName) of
+ ok -> check_conf_data(ConfDataRem);
+ Error -> Error
end;
{AppName, List} when is_list(List) ->
ErrMsg = "application: "
@@ -553,36 +557,40 @@ check_conf_data(ConfData) when is_list(ConfData) ->
++ "; parameters must be a list",
{error, ErrMsg};
Else ->
- ErrMsg = "invalid application name: " ++
- lists:flatten(io_lib:format(" ~tp",[Else])),
+ ErrMsg = "invalid application config: "
+ ++ lists:flatten(io_lib:format("~tp",[Else])),
{error, ErrMsg}
end;
check_conf_data(_ConfData) ->
- {error, 'configuration must be a list ended by <dot><whitespace>'}.
-
+ {error, "configuration must be a list ended by <dot><whitespace>"}.
-%% Special check of distributed parameter for kernel
-check_para_kernel([]) ->
+
+check_para([], _AppName) ->
ok;
-check_para_kernel([{distributed, Apps} | ParaList]) when is_list(Apps) ->
- case check_distributed(Apps) of
- {error, _ErrorMsg} = Error ->
- Error;
- _ ->
- check_para_kernel(ParaList)
+check_para([{Para, Val} | ParaList], AppName) when is_atom(Para) ->
+ case lists:keymember(Para, 1, ParaList) of
+ true ->
+ ?LOG_WARNING("application: " ++ atom_to_list(AppName) ++
+ "; duplicate parameter: " ++ atom_to_list(Para));
+ false ->
+ ok
+ end,
+
+ case check_para_value(Para, Val, AppName) of
+ ok -> check_para(ParaList, AppName);
+ {error, _} = Error -> Error
end;
-check_para_kernel([{distributed, _Apps} | _ParaList]) ->
- {error, "application: kernel; erroneous parameter: distributed"};
-check_para_kernel([{Para, _Val} | ParaList]) when is_atom(Para) ->
- check_para_kernel(ParaList);
-check_para_kernel([{Para, _Val} | _ParaList]) ->
- {error, "application: kernel; invalid parameter: " ++
+check_para([{Para, _Val} | _ParaList], AppName) ->
+ {error, "application: " ++ atom_to_list(AppName) ++ "; invalid parameter name: " ++
lists:flatten(io_lib:format("~tp",[Para]))};
-check_para_kernel(Else) ->
- {error, "application: kernel; invalid parameter list: " ++
+check_para([Else | _ParaList], AppName) ->
+ {error, "application: " ++ atom_to_list(AppName) ++ "; invalid parameter: " ++
lists:flatten(io_lib:format("~tp",[Else]))}.
-
+check_para_value(distributed, Apps, kernel) -> check_distributed(Apps);
+check_para_value(_Para, _Val, _AppName) -> ok.
+
+%% Special check of distributed parameter for kernel
check_distributed([]) ->
ok;
check_distributed([{App, List} | Apps]) when is_atom(App), is_list(List) ->
@@ -595,18 +603,6 @@ check_distributed(_Else) ->
{error, "application: kernel; erroneous parameter: distributed"}.
-check_para([], _AppName) ->
- ok;
-check_para([{Para, _Val} | ParaList], AppName) when is_atom(Para) ->
- check_para(ParaList, AppName);
-check_para([{Para, _Val} | _ParaList], AppName) ->
- {error, "application: " ++ AppName ++ "; invalid parameter: " ++
- lists:flatten(io_lib:format("~tp",[Para]))};
-check_para([Else | _ParaList], AppName) ->
- {error, "application: " ++ AppName ++ "; invalid parameter: " ++
- lists:flatten(io_lib:format("~tp",[Else]))}.
-
-
-type calls() :: 'info' | 'prep_config_change' | 'which_applications'
| {'config_change' | 'control_application' |
'load_application' | 'start_type' | 'stop_application' |
@@ -863,6 +859,16 @@ handle_call(which_applications, _From, S) ->
end, S#state.running),
{reply, Reply, S};
+handle_call({set_env, Config, Opts}, _From, S) ->
+ _ = [add_env(AppName, Env) || {AppName, Env} <- Config],
+
+ case proplists:get_value(persistent, Opts, false) of
+ true ->
+ {reply, ok, S#state{conf_data = merge_env(S#state.conf_data, Config)}};
+ false ->
+ {reply, ok, S}
+ end;
+
handle_call({set_env, AppName, Key, Val, Opts}, _From, S) ->
ets:insert(ac_tab, {{env, AppName, Key}, Val}),
case proplists:get_value(persistent, Opts, false) of
diff --git a/lib/kernel/src/code_server.erl b/lib/kernel/src/code_server.erl
index 1b4a67ecb7..68e1205301 100644
--- a/lib/kernel/src/code_server.erl
+++ b/lib/kernel/src/code_server.erl
@@ -1434,19 +1434,25 @@ all_loaded(Db) ->
-spec error_msg(io:format(), [term()]) -> 'ok'.
error_msg(Format, Args) ->
+ %% This is equal to calling logger:error/3 which we don't want to
+ %% do from code_server. We don't want to call logger:timestamp()
+ %% either.
logger ! {log,error,Format,Args,
#{pid=>self(),
gl=>group_leader(),
- time=>erlang:system_time(microsecond),
+ time=>os:system_time(microsecond),
error_logger=>#{tag=>error}}},
ok.
-spec info_msg(io:format(), [term()]) -> 'ok'.
info_msg(Format, Args) ->
+ %% This is equal to calling logger:info/3 which we don't want to
+ %% do from code_server. We don't want to call logger:timestamp()
+ %% either.
logger ! {log,info,Format,Args,
#{pid=>self(),
gl=>group_leader(),
- time=>erlang:system_time(microsecond),
+ time=>os:system_time(microsecond),
error_logger=>#{tag=>info_msg}}},
ok.
diff --git a/lib/kernel/src/inet_db.erl b/lib/kernel/src/inet_db.erl
index 6cbb6ac2da..3f5a2ea5ee 100644
--- a/lib/kernel/src/inet_db.erl
+++ b/lib/kernel/src/inet_db.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -1223,7 +1223,10 @@ handle_set_file(Option, Fname, TagTm, TagInfo, ParseFun, From,
{ok, B, _} -> B;
_ -> <<>>
end;
- _ -> <<>>
+ _ ->
+ ets:insert(Db, {TagInfo, undefined}),
+ TimeZero = - (?RES_FILE_UPDATE_TM + 1), % Early enough
+ ets:insert(Db, {TagTm, TimeZero})
end,
handle_set_file(ParseFun, Bin, From, State);
false -> {reply,error,State}
diff --git a/lib/kernel/src/logger.erl b/lib/kernel/src/logger.erl
index 7d36640f52..38bd2f481c 100644
--- a/lib/kernel/src/logger.erl
+++ b/lib/kernel/src/logger.erl
@@ -61,6 +61,7 @@
-export([set_process_metadata/1, update_process_metadata/1,
unset_process_metadata/0, get_process_metadata/0]).
-export([i/0, i/1]).
+-export([timestamp/0]).
%% Basic report formatting
-export([format_report/1, format_otp_report/1]).
@@ -154,7 +155,8 @@
filter_return/0,
config_handler/0,
formatter_config/0,
- olp_config/0]).
+ olp_config/0,
+ timestamp/0]).
%%%-----------------------------------------------------------------
%%% API
@@ -354,6 +356,10 @@ internal_log(Level,Term) when is_atom(Level) ->
erlang:display_string("Logger - "++ atom_to_list(Level) ++ ": "),
erlang:display(Term).
+-spec timestamp() -> timestamp().
+timestamp() ->
+ os:system_time(microsecond).
+
%%%-----------------------------------------------------------------
%%% Configuration
-spec add_primary_filter(FilterId,Filter) -> ok | {error,term()} when
@@ -1129,7 +1135,7 @@ proc_meta() ->
default(pid) -> self();
default(gl) -> group_leader();
-default(time) -> erlang:system_time(microsecond).
+default(time) -> timestamp().
%% Remove everything upto and including this module from the stacktrace
filter_stacktrace(Module,[{Module,_,_,_}|_]) ->
diff --git a/lib/kernel/src/logger_h_common.erl b/lib/kernel/src/logger_h_common.erl
index e69f6de38d..4b5e0a7dd0 100644
--- a/lib/kernel/src/logger_h_common.erl
+++ b/lib/kernel/src/logger_h_common.erl
@@ -351,7 +351,7 @@ log_handler_info(Name, Format, Args, #{module:=Module,
{ok,Conf} -> Conf;
_ -> #{formatter=>{?DEFAULT_FORMATTER,?DEFAULT_FORMAT_CONFIG}}
end,
- Meta = #{time=>erlang:system_time(microsecond)},
+ Meta = #{time=>logger:timestamp()},
Bin = log_to_binary(#{level => notice,
msg => {Format,Args},
meta => Meta}, Config),
diff --git a/lib/kernel/src/logger_simple_h.erl b/lib/kernel/src/logger_simple_h.erl
index fe181722f3..a0d51dba25 100644
--- a/lib/kernel/src/logger_simple_h.erl
+++ b/lib/kernel/src/logger_simple_h.erl
@@ -69,7 +69,7 @@ log(#{msg:=_,meta:=#{time:=_}}=Log,_Config) ->
do_log(
#{level=>error,
msg=>{report,{error,simple_handler_process_dead}},
- meta=>#{time=>erlang:system_time(microsecond)}}),
+ meta=>#{time=>logger:timestamp()}}),
do_log(Log);
_ ->
?MODULE ! {log,Log}
@@ -129,7 +129,7 @@ drop_msg(0) ->
drop_msg(N) ->
[#{level=>info,
msg=>{"Simple handler buffer full, dropped ~w messages",[N]},
- meta=>#{time=>erlang:system_time(microsecond)}}].
+ meta=>#{time=>logger:timestamp()}}].
%%%-----------------------------------------------------------------
%%% Internal
diff --git a/lib/kernel/test/application_SUITE.erl b/lib/kernel/test/application_SUITE.erl
index 5c35b82207..94d7c17712 100644
--- a/lib/kernel/test/application_SUITE.erl
+++ b/lib/kernel/test/application_SUITE.erl
@@ -31,6 +31,7 @@
otp_3002/1, otp_3184/1, otp_4066/1, otp_4227/1, otp_5363/1,
otp_5606/1,
start_phases/1, get_key/1, get_env/1,
+ set_env/1, set_env_persistent/1, set_env_errors/1,
permit_false_start_local/1, permit_false_start_dist/1, script_start/1,
nodedown_start/1, init2973/0, loop2973/0, loop5606/1]).
@@ -55,6 +56,7 @@ all() ->
load_use_cache, ensure_started, {group, reported_bugs}, start_phases,
script_start, nodedown_start, permit_false_start_local,
permit_false_start_dist, get_key, get_env, ensure_all_started,
+ set_env, set_env_persistent, set_env_errors,
{group, distr_changed}, config_change, shutdown_func, shutdown_timeout,
shutdown_deadlock, config_relative_paths,
persistent_env].
@@ -1944,6 +1946,101 @@ get_appls([_ | T], Res) ->
get_appls([], Res) ->
Res.
+%% Test set_env/1.
+set_env(Conf) when is_list(Conf) ->
+ ok = application:set_env([{appinc, [{own2, persist}, {not_in_app, persist}]},
+ {unknown_app, [{key, persist}]}]),
+
+ %% own_env1 and own2 are set in appinc
+ undefined = application:get_env(appinc, own_env1),
+ {ok, persist} = application:get_env(appinc, own2),
+ {ok, persist} = application:get_env(appinc, not_in_app),
+ {ok, persist} = application:get_env(unknown_app, key),
+
+ ok = application:load(appinc()),
+ {ok, value1} = application:get_env(appinc, own_env1),
+ {ok, val2} = application:get_env(appinc, own2),
+ {ok, persist} = application:get_env(appinc, not_in_app),
+ {ok, persist} = application:get_env(unknown_app, key),
+
+ %% On reload, values are lost
+ ok = application:unload(appinc),
+ ok = application:load(appinc()),
+ {ok, value1} = application:get_env(appinc, own_env1),
+ {ok, val2} = application:get_env(appinc, own2),
+ undefined = application:get_env(appinc, not_in_app),
+
+ %% Clean up
+ ok = application:unload(appinc).
+
+%% Test set_env/2 with persistent true.
+set_env_persistent(Conf) when is_list(Conf) ->
+ Opts = [{persistent, true}],
+ ok = application:set_env([{appinc, [{own2, persist}, {not_in_app, persist}]},
+ {unknown_app, [{key, persist}]}], Opts),
+
+ %% own_env1 and own2 are set in appinc
+ undefined = application:get_env(appinc, own_env1),
+ {ok, persist} = application:get_env(appinc, own2),
+ {ok, persist} = application:get_env(appinc, not_in_app),
+ {ok, persist} = application:get_env(unknown_app, key),
+
+ ok = application:load(appinc()),
+ {ok, value1} = application:get_env(appinc, own_env1),
+ {ok, persist} = application:get_env(appinc, own2),
+ {ok, persist} = application:get_env(appinc, not_in_app),
+ {ok, persist} = application:get_env(unknown_app, key),
+
+ %% On reload, values are not lost
+ ok = application:unload(appinc),
+ ok = application:load(appinc()),
+ {ok, value1} = application:get_env(appinc, own_env1),
+ {ok, persist} = application:get_env(appinc, own2),
+ {ok, persist} = application:get_env(appinc, not_in_app),
+
+ %% Clean up
+ ok = application:unload(appinc).
+
+set_env_errors(Conf) when is_list(Conf) ->
+ "application: 1; application name must be an atom" =
+ badarg_msg(fun() -> application:set_env([{1, []}]) end),
+
+ "application: foo; parameters must be a list" =
+ badarg_msg(fun() -> application:set_env([{foo, bar}]) end),
+
+ "invalid application config: foo_bar" =
+ badarg_msg(fun() -> application:set_env([foo_bar]) end),
+
+ "application: foo; invalid parameter name: 1" =
+ badarg_msg(fun() -> application:set_env([{foo, [{1, 2}]}]) end),
+
+ "application: foo; invalid parameter: config" =
+ badarg_msg(fun() -> application:set_env([{foo, [config]}]) end),
+
+ "application: kernel; erroneous parameter: distributed" =
+ badarg_msg(fun() -> application:set_env([{kernel, [{distributed, config}]}]) end),
+
+ %% This will raise in the future
+ ct:capture_start(),
+ _ = application:set_env([{foo, []}, {foo, []}]),
+ timer:sleep(100),
+ ct:capture_stop(),
+ [_ | _] = string:find(ct:capture_get(), "duplicate application config: foo"),
+
+ ct:capture_start(),
+ _ = application:set_env([{foo, [{bar, baz}, {bar, bat}]}]),
+ timer:sleep(100),
+ ct:capture_stop(),
+ [_ | _] = string:find(ct:capture_get(), "application: foo; duplicate parameter: bar"),
+
+ ok.
+
+badarg_msg(Fun) ->
+ try Fun() of
+ _ -> ct:fail(try_succeeded)
+ catch
+ error:{badarg, Msg} -> Msg
+ end.
%% Test set_env/4 and unset_env/3 with persistent true.
persistent_env(Conf) when is_list(Conf) ->
diff --git a/lib/kernel/test/inet_SUITE.erl b/lib/kernel/test/inet_SUITE.erl
index 8b33f4a679..44ec7e7076 100644
--- a/lib/kernel/test/inet_SUITE.erl
+++ b/lib/kernel/test/inet_SUITE.erl
@@ -21,6 +21,7 @@
-include_lib("common_test/include/ct.hrl").
-include_lib("kernel/include/inet.hrl").
+-include_lib("kernel/src/inet_res.hrl").
-include_lib("kernel/src/inet_dns.hrl").
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
@@ -34,7 +35,7 @@
ipv4_to_ipv6/0, ipv4_to_ipv6/1,
host_and_addr/0, host_and_addr/1,
t_gethostnative/1,
- gethostnative_parallell/1, cname_loop/1,
+ gethostnative_parallell/1, cname_loop/1, missing_hosts_reload/1,
gethostnative_soft_restart/0, gethostnative_soft_restart/1,
gethostnative_debug_level/0, gethostnative_debug_level/1,
lookup_bad_search_option/1,
@@ -56,7 +57,7 @@ all() ->
[t_gethostbyaddr, t_gethostbyname, t_getaddr,
t_gethostbyaddr_v6, t_gethostbyname_v6, t_getaddr_v6,
ipv4_to_ipv6, host_and_addr, {group, parse},
- t_gethostnative, gethostnative_parallell, cname_loop,
+ t_gethostnative, gethostnative_parallell, cname_loop, missing_hosts_reload,
gethostnative_debug_level, gethostnative_soft_restart,
lookup_bad_search_option,
getif, getif_ifr_name_overflow, getservbyname_overflow,
@@ -840,6 +841,32 @@ cname_loop(Config) when is_list(Config) ->
ok.
+%% Test that hosts file gets reloaded correctly in case when it
+% was missing during initial startup
+missing_hosts_reload(Config) when is_list(Config) ->
+ RootDir = proplists:get_value(priv_dir,Config),
+ HostsFile = filename:join(RootDir, atom_to_list(?MODULE) ++ ".hosts"),
+ InetRc = filename:join(RootDir, "inetrc"),
+ ok = file:write_file(InetRc, "{hosts_file, \"" ++ HostsFile ++ "\"}.\n"),
+ {error, enoent} = file:read_file_info(HostsFile),
+ % start a node
+ Pa = filename:dirname(code:which(?MODULE)),
+ {ok, TestNode} = test_server:start_node(?MODULE, slave,
+ [{args, "-pa " ++ Pa ++ " -kernel inetrc '\"" ++ InetRc ++ "\"'"}]),
+ % ensure it has our RC
+ Rc = rpc:call(TestNode, inet_db, get_rc, []),
+ {hosts_file, HostsFile} = lists:keyfind(hosts_file, 1, Rc),
+ % ensure it does not resolve
+ {error, nxdomain} = rpc:call(TestNode, inet_hosts, gethostbyname, ["somehost"]),
+ % write hosts file
+ ok = file:write_file(HostsFile, "1.2.3.4 somehost"),
+ % wait for cached timestamp to expire
+ timer:sleep(?RES_FILE_UPDATE_TM * 1000 + 100),
+ % ensure it DOES resolve
+ {ok,{hostent,"somehost",[],inet,4,[{1,2,3,4}]}} =
+ rpc:call(TestNode, inet_hosts, gethostbyname, ["somehost"]),
+ % cleanup
+ true = test_server:stop_node(TestNode).
%% These must be run in the whole suite since they need
%% the host list and require inet_gethost_native to be started.
diff --git a/lib/kernel/test/logger_SUITE.erl b/lib/kernel/test/logger_SUITE.erl
index 2dad651f9c..70bb775db8 100644
--- a/lib/kernel/test/logger_SUITE.erl
+++ b/lib/kernel/test/logger_SUITE.erl
@@ -899,14 +899,14 @@ process_metadata(_Config) ->
undefined = logger:get_process_metadata(),
{error,badarg} = ?TRY(logger:set_process_metadata(bad)),
ok = logger:add_handler(h1,?MODULE,#{level=>notice,filter_default=>log}),
- Time = erlang:system_time(microsecond),
+ Time = logger:timestamp(),
ProcMeta = #{time=>Time,line=>0,custom=>proc},
ok = logger:set_process_metadata(ProcMeta),
S1 = ?str,
?LOG_NOTICE(S1,#{custom=>macro}),
check_logged(notice,S1,#{time=>Time,line=>0,custom=>macro}),
- Time2 = erlang:system_time(microsecond),
+ Time2 = logger:timestamp(),
S2 = ?str,
?LOG_NOTICE(S2,#{time=>Time2,line=>1,custom=>macro}),
check_logged(notice,S2,#{time=>Time2,line=>1,custom=>macro}),
diff --git a/lib/kernel/test/logger_formatter_SUITE.erl b/lib/kernel/test/logger_formatter_SUITE.erl
index 8c13f0f908..83e3e6c40a 100644
--- a/lib/kernel/test/logger_formatter_SUITE.erl
+++ b/lib/kernel/test/logger_formatter_SUITE.erl
@@ -867,7 +867,7 @@ my_try(Fun) ->
try Fun() catch C:R:S -> {C,R,hd(S)} end.
timestamp() ->
- erlang:system_time(microsecond).
+ logger:timestamp().
%% necessary?
add_time(#{time:=_}=Meta) ->
diff --git a/lib/mnesia/examples/bench/README b/lib/mnesia/examples/bench/README
index 3648fb59da..b8209b19b8 100644
--- a/lib/mnesia/examples/bench/README
+++ b/lib/mnesia/examples/bench/README
@@ -46,7 +46,7 @@ you need to:
- put the $ERL_TOP/bin directory in your path on all nodes
- bind IP adresses to hostnames (e.g via DNS or /etc/hosts)
- - enable usage of rsh so it does not prompt for password
+ - enable usage of ssh so it does not prompt for password
If you cannot achieve this, it is possible to run the benchmark
anyway, but it requires more manual work to be done for each
diff --git a/lib/ssl/doc/src/ssl.xml b/lib/ssl/doc/src/ssl.xml
index a2dd1f29b7..b145aac6ab 100644
--- a/lib/ssl/doc/src/ssl.xml
+++ b/lib/ssl/doc/src/ssl.xml
@@ -89,9 +89,12 @@
<datatype>
<name name="active_msgs"/>
<desc>
- <p>When an TLS/DTLS socket is in active mode (the default), data from the
+ <p>When a TLS/DTLS socket is in active mode (the default), data from the
socket is delivered to the owner of the socket in the form of
messages as described above.</p>
+ <p>The <c>ssl_passive</c> message is sent only when the socket is in
+ <c>{active, N}</c> mode and the counter dropped to 0. It indicates
+ that the socket has transitioned to passive (<c>{active, false}</c>) mode.</p>
</desc>
</datatype>
@@ -1204,8 +1207,8 @@ fun(srp, Username :: string(), UserState :: term()) ->
marker="#handshake_cancel-1"><c>handshake_cancel/1</c></seealso>.
</p>
- <p> If the option <c>active</c> is set to <c>once</c> or <c>true</c> the
- process owning the sslsocket will receive messages of type
+ <p> If the option <c>active</c> is set to <c>once</c>, <c>true</c> or an integer value,
+ the process owning the sslsocket will receive messages of type
<seealso marker="#type-active_msgs"> active_msgs() </seealso>
</p>
</desc>
@@ -1252,8 +1255,8 @@ fun(srp, Username :: string(), UserState :: term()) ->
marker="#handshake_cancel-1"><c>handshake_cancel/1</c></seealso>.
</p>
- <p> If the option <c>active</c> is set to <c>once</c> or <c>true</c> the
- process owning the sslsocket will receive messages of type
+ <p> If the option <c>active</c> is set to <c>once</c>, <c>true</c> or an integer value,
+ the process owning the sslsocket will receive messages of type
<seealso marker="#type-active_msgs"> active_msgs() </seealso>
</p>
</desc>
@@ -1414,8 +1417,8 @@ fun(srp, Username :: string(), UserState :: term()) ->
<p>Performs the SSL/TLS/DTLS server-side handshake.</p>
<p>Returns a new TLS/DTLS socket if the handshake is successful.</p>
- <p> If the option <c>active</c> is set to <c>once</c> or <c>true</c> the
- process owning the sslsocket will receive messages of type
+ <p> If the option <c>active</c> is set to <c>once</c>, <c>true</c> or an integer value,
+ the process owning the sslsocket will receive messages of type
<seealso marker="#type-active_msgs"> active_msgs() </seealso>
</p>
</desc>
@@ -1459,8 +1462,8 @@ fun(srp, Username :: string(), UserState :: term()) ->
marker="#handshake_cancel-1"><c>handshake_cancel/1</c></seealso>.
</p>
- <p> If the option <c>active</c> is set to <c>once</c> or <c>true</c> the
- process owning the sslsocket will receive messages of type
+ <p> If the option <c>active</c> is set to <c>once</c>, <c>true</c> or an integer value,
+ the process owning the sslsocket will receive messages of type
<seealso marker="#type-active_msgs"> active_msgs() </seealso>
</p>
diff --git a/lib/ssl/src/dtls_packet_demux.erl b/lib/ssl/src/dtls_packet_demux.erl
index afcd4af000..e0423b07b4 100644
--- a/lib/ssl/src/dtls_packet_demux.erl
+++ b/lib/ssl/src/dtls_packet_demux.erl
@@ -298,6 +298,9 @@ do_set_emulated_opts([], Opts) ->
Opts;
do_set_emulated_opts([{mode, Value} | Rest], Opts) ->
do_set_emulated_opts(Rest, Opts#socket_options{mode = Value});
+do_set_emulated_opts([{active, N0} | Rest], Opts=#socket_options{active = Active}) when is_integer(N0) ->
+ N = tls_socket:update_active_n(N0, Active),
+ do_set_emulated_opts(Rest, Opts#socket_options{active = N});
do_set_emulated_opts([{active, Value} | Rest], Opts) ->
do_set_emulated_opts(Rest, Opts#socket_options{active = Value}).
diff --git a/lib/ssl/src/dtls_socket.erl b/lib/ssl/src/dtls_socket.erl
index 2001afd02f..4d07372e31 100644
--- a/lib/ssl/src/dtls_socket.erl
+++ b/lib/ssl/src/dtls_socket.erl
@@ -38,7 +38,9 @@ listen(Port, #config{transport_info = TransportInfo,
case dtls_listener_sup:start_child([Port, TransportInfo, emulated_socket_options(EmOpts, #socket_options{}),
Options ++ internal_inet_values(), SslOpts]) of
{ok, Pid} ->
- {ok, #sslsocket{pid = {dtls, Config#config{dtls_handler = {Pid, Port}}}}};
+ Socket = #sslsocket{pid = {dtls, Config#config{dtls_handler = {Pid, Port}}}},
+ check_active_n(EmOpts, Socket),
+ {ok, Socket};
Err = {error, _} ->
Err
end.
@@ -81,8 +83,9 @@ socket(Pids, Transport, Socket, ConnectionCb) ->
#sslsocket{pid = Pids,
%% "The name "fd" is keept for backwards compatibility
fd = {Transport, Socket, ConnectionCb}}.
-setopts(_, #sslsocket{pid = {dtls, #config{dtls_handler = {ListenPid, _}}}}, Options) ->
- SplitOpts = tls_socket:split_options(Options),
+setopts(_, Socket = #sslsocket{pid = {dtls, #config{dtls_handler = {ListenPid, _}}}}, Options) ->
+ SplitOpts = {_, EmOpts} = tls_socket:split_options(Options),
+ check_active_n(EmOpts, Socket),
dtls_packet_demux:set_sock_opts(ListenPid, SplitOpts);
%%% Following clauses will not be called for emulated options, they are handled in the connection process
setopts(gen_udp, Socket, Options) ->
@@ -90,6 +93,32 @@ setopts(gen_udp, Socket, Options) ->
setopts(Transport, Socket, Options) ->
Transport:setopts(Socket, Options).
+check_active_n(EmulatedOpts, Socket = #sslsocket{pid = {dtls, #config{dtls_handler = {ListenPid, _}}}}) ->
+ %% We check the resulting options to send an ssl_passive message if necessary.
+ case proplists:lookup(active, EmulatedOpts) of
+ %% The provided value is out of bound.
+ {_, N} when is_integer(N), N < -32768 ->
+ throw(einval);
+ {_, N} when is_integer(N), N > 32767 ->
+ throw(einval);
+ {_, N} when is_integer(N) ->
+ {ok, #socket_options{active = Active}, _} = dtls_packet_demux:get_all_opts(ListenPid),
+ case Active of
+ Atom when is_atom(Atom), N =< 0 ->
+ self() ! {ssl_passive, Socket};
+ %% The result of the addition is out of bound.
+ %% We do not need to check < -32768 because Active can't be below 1.
+ A when is_integer(A), A + N > 32767 ->
+ throw(einval);
+ A when is_integer(A), A + N =< 0 ->
+ self() ! {ssl_passive, Socket};
+ _ ->
+ ok
+ end;
+ _ ->
+ ok
+ end.
+
getopts(_, #sslsocket{pid = {dtls, #config{dtls_handler = {ListenPid, _}}}}, Options) ->
SplitOpts = tls_socket:split_options(Options),
dtls_packet_demux:get_sock_opts(ListenPid, SplitOpts);
@@ -161,9 +190,18 @@ emulated_socket_options(InetValues, #socket_options{
mode = proplists:get_value(mode, InetValues, Mode),
packet = proplists:get_value(packet, InetValues, Packet),
packet_size = proplists:get_value(packet_size, InetValues, PacketSize),
- active = proplists:get_value(active, InetValues, Active)
+ active = emulated_active_option(InetValues, Active)
}.
+emulated_active_option([], Active) ->
+ Active;
+emulated_active_option([{active, Active} | _], _) when Active =< 0 ->
+ false;
+emulated_active_option([{active, Active} | _], _) ->
+ Active;
+emulated_active_option([_|Tail], Active) ->
+ emulated_active_option(Tail, Active).
+
emulated_options([{mode, Value} = Opt |Opts], Inet, Emulated) ->
validate_inet_option(mode, Value),
emulated_options(Opts, Inet, [Opt | proplists:delete(mode, Emulated)]);
@@ -185,6 +223,9 @@ validate_inet_option(mode, Value)
when Value =/= list, Value =/= binary ->
throw({error, {options, {mode,Value}}});
validate_inet_option(active, Value)
+ when Value >= -32768, Value =< 32767 ->
+ ok;
+validate_inet_option(active, Value)
when Value =/= true, Value =/= false, Value =/= once ->
throw({error, {options, {active,Value}}});
validate_inet_option(_, _) ->
diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl
index 3516bd6d49..5a2d31ffc2 100644
--- a/lib/ssl/src/ssl.erl
+++ b/lib/ssl/src/ssl.erl
@@ -94,7 +94,7 @@
-type tls_client_option() :: client_option() | common_option() | socket_option() | transport_option().
-type tls_server_option() :: server_option() | common_option() | socket_option() | transport_option().
-type active_msgs() :: {ssl, sslsocket(), Data::binary() | list()} | {ssl_closed, sslsocket()} |
- {ssl_error, sslsocket(), Reason::term()}.
+ {ssl_error, sslsocket(), Reason::term()} | {ssl_passive, sslsocket()}.
-type transport_option() :: {cb_info, {CallbackModule::atom(), DataTag::atom(),
ClosedTag::atom(), ErrTag::atom()}}.
-type host() :: hostname() | ip_address().
diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl
index f194610d72..422c4c94ae 100644
--- a/lib/ssl/src/ssl_connection.erl
+++ b/lib/ssl/src/ssl_connection.erl
@@ -1383,10 +1383,22 @@ handle_call({get_opts, OptTags}, From, _,
{keep_state_and_data, [{reply, From, OptsReply}]};
handle_call({set_opts, Opts0}, From, StateName,
#state{static_env = #static_env{socket = Socket,
- transport_cb = Transport},
+ transport_cb = Transport,
+ tracker = Tracker},
+ connection_env =
+ #connection_env{user_application = {_Mon, Pid}},
socket_options = Opts1
} = State0, Connection) ->
{Reply, Opts} = set_socket_opts(Connection, Transport, Socket, Opts0, Opts1, []),
+ case {proplists:lookup(active, Opts0), Opts} of
+ {{_, N}, #socket_options{active=false}} when is_integer(N) ->
+ send_user(
+ Pid,
+ format_passive(
+ Connection:pids(State0), Transport, Socket, Tracker, Connection));
+ _ ->
+ ok
+ end,
State = State0#state{socket_options = Opts},
handle_active_option(Opts#socket_options.active, StateName, From, Reply, State);
@@ -2516,6 +2528,30 @@ set_socket_opts(ConnectionCb, Transport, Socket, [{active, Active}| Opts], SockO
Active == false ->
set_socket_opts(ConnectionCb, Transport, Socket, Opts,
SockOpts#socket_options{active = Active}, Other);
+set_socket_opts(ConnectionCb, Transport, Socket, [{active, Active1} = Opt| Opts],
+ SockOpts=#socket_options{active = Active0}, Other)
+ when Active1 >= -32768, Active1 =< 32767 ->
+ Active = if
+ is_integer(Active0), Active0 + Active1 < -32768 ->
+ error;
+ is_integer(Active0), Active0 + Active1 =< 0 ->
+ false;
+ is_integer(Active0), Active0 + Active1 > 32767 ->
+ error;
+ Active1 =< 0 ->
+ false;
+ is_integer(Active0) ->
+ Active0 + Active1;
+ true ->
+ Active1
+ end,
+ case Active of
+ error ->
+ {{error, {options, {socket_options, Opt}} }, SockOpts};
+ _ ->
+ set_socket_opts(ConnectionCb, Transport, Socket, Opts,
+ SockOpts#socket_options{active = Active}, Other)
+ end;
set_socket_opts(_,_, _, [{active, _} = Opt| _], SockOpts, _) ->
{{error, {options, {socket_options, Opt}} }, SockOpts};
set_socket_opts(ConnectionCb, Transport, Socket, [Opt | Opts], SockOpts, Other) ->
@@ -2795,6 +2831,14 @@ deliver_app_data(
case Active of
once ->
SO#socket_options{active=false};
+ 1 ->
+ send_user(
+ Pid,
+ format_passive(
+ CPids, Transport, Socket, Tracker, Connection)),
+ SO#socket_options{active=false};
+ N when is_integer(N) ->
+ SO#socket_options{active=N - 1};
_ ->
SO
end.
@@ -2831,6 +2875,9 @@ do_format_reply(list, Packet, _, Data)
do_format_reply(list, _,_, Data) ->
binary_to_list(Data).
+format_passive(CPids, Transport, Socket, Tracker, Connection) ->
+ {ssl_passive, Connection:socket(CPids, Transport, Socket, Tracker)}.
+
header(0, <<>>) ->
<<>>;
header(_, <<>>) ->
diff --git a/lib/ssl/src/tls_socket.erl b/lib/ssl/src/tls_socket.erl
index a391bc53de..c3c41d3e12 100644
--- a/lib/ssl/src/tls_socket.erl
+++ b/lib/ssl/src/tls_socket.erl
@@ -32,6 +32,7 @@
emulated_socket_options/2, get_emulated_opts/1,
set_emulated_opts/2, get_all_opts/1, handle_call/3, handle_cast/2,
handle_info/2, code_change/3]).
+-export([update_active_n/2]).
-record(state, {
emulated_opts,
@@ -51,7 +52,9 @@ listen(Transport, Port, #config{transport_info = {Transport, _, _, _},
case Transport:listen(Port, Options ++ internal_inet_values()) of
{ok, ListenSocket} ->
{ok, Tracker} = inherit_tracker(ListenSocket, EmOpts, SslOpts),
- {ok, #sslsocket{pid = {ListenSocket, Config#config{emulated = Tracker}}}};
+ Socket = #sslsocket{pid = {ListenSocket, Config#config{emulated = Tracker}}},
+ check_active_n(EmOpts, Socket),
+ {ok, Socket};
Err = {error, _} ->
Err
end.
@@ -117,14 +120,16 @@ socket(Pids, Transport, Socket, ConnectionCb, Tracker) ->
#sslsocket{pid = Pids,
%% "The name "fd" is keept for backwards compatibility
fd = {Transport, Socket, ConnectionCb, Tracker}}.
-setopts(gen_tcp, #sslsocket{pid = {ListenSocket, #config{emulated = Tracker}}}, Options) ->
+setopts(gen_tcp, Socket = #sslsocket{pid = {ListenSocket, #config{emulated = Tracker}}}, Options) ->
{SockOpts, EmulatedOpts} = split_options(Options),
ok = set_emulated_opts(Tracker, EmulatedOpts),
+ check_active_n(EmulatedOpts, Socket),
inet:setopts(ListenSocket, SockOpts);
-setopts(_, #sslsocket{pid = {ListenSocket, #config{transport_info = {Transport,_,_,_},
+setopts(_, Socket = #sslsocket{pid = {ListenSocket, #config{transport_info = {Transport,_,_,_},
emulated = Tracker}}}, Options) ->
{SockOpts, EmulatedOpts} = split_options(Options),
ok = set_emulated_opts(Tracker, EmulatedOpts),
+ check_active_n(EmulatedOpts, Socket),
Transport:setopts(ListenSocket, SockOpts);
%%% Following clauses will not be called for emulated options, they are handled in the connection process
setopts(gen_tcp, Socket, Options) ->
@@ -132,6 +137,31 @@ setopts(gen_tcp, Socket, Options) ->
setopts(Transport, Socket, Options) ->
Transport:setopts(Socket, Options).
+check_active_n(EmulatedOpts, Socket = #sslsocket{pid = {_, #config{emulated = Tracker}}}) ->
+ %% We check the resulting options to send an ssl_passive message if necessary.
+ case proplists:lookup(active, EmulatedOpts) of
+ %% The provided value is out of bound.
+ {_, N} when is_integer(N), N < -32768 ->
+ throw(einval);
+ {_, N} when is_integer(N), N > 32767 ->
+ throw(einval);
+ {_, N} when is_integer(N) ->
+ case get_emulated_opts(Tracker, [active]) of
+ [{_, false}] ->
+ self() ! {ssl_passive, Socket},
+ ok;
+ %% The result of the addition is out of bound.
+ [{_, A}] when is_integer(A), A < -32768 ->
+ throw(einval);
+ [{_, A}] when is_integer(A), A > 32767 ->
+ throw(einval);
+ _ ->
+ ok
+ end;
+ _ ->
+ ok
+ end.
+
getopts(gen_tcp, #sslsocket{pid = {ListenSocket, #config{emulated = Tracker}}}, Options) ->
{SockOptNames, EmulatedOptNames} = split_options(Options),
EmulatedOpts = get_emulated_opts(Tracker, EmulatedOptNames),
@@ -209,7 +239,7 @@ start_link(Port, SockOpts, SslOpts) ->
init([Port, Opts, SslOpts]) ->
process_flag(trap_exit, true),
true = link(Port),
- {ok, #state{emulated_opts = Opts, port = Port, ssl_opts = SslOpts}}.
+ {ok, #state{emulated_opts = do_set_emulated_opts(Opts, []), port = Port, ssl_opts = SslOpts}}.
%%--------------------------------------------------------------------
-spec handle_call(msg(), from(), #state{}) -> {reply, reply(), #state{}}.
@@ -304,9 +334,24 @@ split_options([Name | Opts], Emu, SocketOptNames, EmuOptNames) ->
do_set_emulated_opts([], Opts) ->
Opts;
+do_set_emulated_opts([{active, N0} | Rest], Opts) when is_integer(N0) ->
+ N = update_active_n(N0, proplists:get_value(active, Opts, false)),
+ do_set_emulated_opts(Rest, [{active, N} | proplists:delete(active, Opts)]);
do_set_emulated_opts([{Name,_} = Opt | Rest], Opts) ->
do_set_emulated_opts(Rest, [Opt | proplists:delete(Name, Opts)]).
+update_active_n(New, Current) ->
+ if
+ is_integer(Current), New + Current =< 0 ->
+ false;
+ is_integer(Current) ->
+ New + Current;
+ New =< 0 ->
+ false;
+ true ->
+ New
+ end.
+
get_socket_opts(_, [], _) ->
[];
get_socket_opts(ListenSocket, SockOptNames, Cb) ->
@@ -366,6 +411,9 @@ validate_inet_option(header, Value)
when not is_integer(Value) ->
throw({error, {options, {header,Value}}});
validate_inet_option(active, Value)
+ when Value >= -32768, Value =< 32767 ->
+ ok;
+validate_inet_option(active, Value)
when Value =/= true, Value =/= false, Value =/= once ->
throw({error, {options, {active,Value}}});
validate_inet_option(_, _) ->
diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl
index 353b278f6c..292916692d 100644
--- a/lib/ssl/test/ssl_basic_SUITE.erl
+++ b/lib/ssl/test/ssl_basic_SUITE.erl
@@ -167,6 +167,7 @@ api_tests() ->
accept_pool,
prf,
socket_options,
+ active_n,
cipher_suites,
handshake_continue,
handshake_continue_timeout,
@@ -246,6 +247,7 @@ error_handling_tests()->
[close_transport_accept,
recv_active,
recv_active_once,
+ recv_active_n,
recv_error_handling,
call_in_error_state,
close_in_error_state,
@@ -1993,7 +1995,7 @@ recv_active(Config) when is_list(Config) ->
%%--------------------------------------------------------------------
recv_active_once() ->
- [{doc,"Test recv on active socket"}].
+ [{doc,"Test recv on active (once) socket"}].
recv_active_once(Config) when is_list(Config) ->
ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
@@ -2018,6 +2020,178 @@ recv_active_once(Config) when is_list(Config) ->
ssl_test_lib:close(Client).
%%--------------------------------------------------------------------
+recv_active_n() ->
+ [{doc,"Test recv on active (n) socket"}].
+
+recv_active_n(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Server =
+ ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, try_recv_active_once, []}},
+ {options, [{active, 1} | ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client =
+ ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, try_recv_active_once, []}},
+ {options, [{active, 1} | ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+%%--------------------------------------------------------------------
+%% Test case adapted from gen_tcp_misc_SUITE.
+active_n() ->
+ [{doc,"Test {active,N} option"}].
+
+active_n(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
+ Port = ssl_test_lib:inet_port(node()),
+ N = 3,
+ LS = ok(ssl:listen(Port, [{active,N}|ServerOpts])),
+ [{active,N}] = ok(ssl:getopts(LS, [active])),
+ active_n_common(LS, N),
+ Self = self(),
+ spawn_link(fun() ->
+ S0 = ok(ssl:transport_accept(LS)),
+ {ok, S} = ssl:handshake(S0),
+ ok = ssl:setopts(S, [{active,N}]),
+ [{active,N}] = ok(ssl:getopts(S, [active])),
+ ssl:controlling_process(S, Self),
+ Self ! {server, S}
+ end),
+ C = ok(ssl:connect("localhost", Port, [{active,N}|ClientOpts])),
+ [{active,N}] = ok(ssl:getopts(C, [active])),
+ S = receive
+ {server, S0} -> S0
+ after
+ 1000 ->
+ exit({error, connect})
+ end,
+ active_n_common(C, N),
+ active_n_common(S, N),
+ ok = ssl:setopts(C, [{active,N}]),
+ ok = ssl:setopts(S, [{active,N}]),
+ ReceiveMsg = fun(Socket, Msg) ->
+ receive
+ {ssl,Socket,Msg} ->
+ ok;
+ {ssl,Socket,Begin} ->
+ receive
+ {ssl,Socket,End} ->
+ Msg = Begin ++ End,
+ ok
+ after 1000 ->
+ exit(timeout)
+ end
+ after 1000 ->
+ exit(timeout)
+ end
+ end,
+ repeat(3, fun(I) ->
+ Msg = "message "++integer_to_list(I),
+ ok = ssl:send(C, Msg),
+ ReceiveMsg(S, Msg),
+ ok = ssl:send(S, Msg),
+ ReceiveMsg(C, Msg)
+ end),
+ receive
+ {ssl_passive,S} ->
+ [{active,false}] = ok(ssl:getopts(S, [active]))
+ after
+ 1000 ->
+ exit({error,ssl_passive})
+ end,
+ receive
+ {ssl_passive,C} ->
+ [{active,false}] = ok(ssl:getopts(C, [active]))
+ after
+ 1000 ->
+ exit({error,ssl_passive})
+ end,
+ LS2 = ok(ssl:listen(0, [{active,0}])),
+ receive
+ {ssl_passive,LS2} ->
+ [{active,false}] = ok(ssl:getopts(LS2, [active]))
+ after
+ 1000 ->
+ exit({error,ssl_passive})
+ end,
+ ok = ssl:close(LS2),
+ ok = ssl:close(C),
+ ok = ssl:close(S),
+ ok = ssl:close(LS),
+ ok.
+
+active_n_common(S, N) ->
+ ok = ssl:setopts(S, [{active,-N}]),
+ receive
+ {ssl_passive, S} -> ok
+ after
+ 1000 ->
+ error({error,ssl_passive_failure})
+ end,
+ [{active,false}] = ok(ssl:getopts(S, [active])),
+ ok = ssl:setopts(S, [{active,0}]),
+ receive
+ {ssl_passive, S} -> ok
+ after
+ 1000 ->
+ error({error,ssl_passive_failure})
+ end,
+ ok = ssl:setopts(S, [{active,32767}]),
+ {error,{options,_}} = ssl:setopts(S, [{active,1}]),
+ {error,{options,_}} = ssl:setopts(S, [{active,-32769}]),
+ ok = ssl:setopts(S, [{active,-32768}]),
+ receive
+ {ssl_passive, S} -> ok
+ after
+ 1000 ->
+ error({error,ssl_passive_failure})
+ end,
+ [{active,false}] = ok(ssl:getopts(S, [active])),
+ ok = ssl:setopts(S, [{active,N}]),
+ ok = ssl:setopts(S, [{active,true}]),
+ [{active,true}] = ok(ssl:getopts(S, [active])),
+ receive
+ _ -> error({error,active_n})
+ after
+ 0 ->
+ ok
+ end,
+ ok = ssl:setopts(S, [{active,N}]),
+ ok = ssl:setopts(S, [{active,once}]),
+ [{active,once}] = ok(ssl:getopts(S, [active])),
+ receive
+ _ -> error({error,active_n})
+ after
+ 0 ->
+ ok
+ end,
+ {error,{options,_}} = ssl:setopts(S, [{active,32768}]),
+ ok = ssl:setopts(S, [{active,false}]),
+ [{active,false}] = ok(ssl:getopts(S, [active])),
+ ok.
+
+ok({ok,V}) -> V.
+
+repeat(N, Fun) ->
+ repeat(N, N, Fun).
+
+repeat(N, T, Fun) when is_integer(N), N > 0 ->
+ Fun(T-N),
+ repeat(N-1, T, Fun);
+repeat(_, _, _) ->
+ ok.
+
+%%--------------------------------------------------------------------
dh_params() ->
[{doc,"Test to specify DH-params file in server."}].
diff --git a/lib/stdlib/doc/src/slave.xml b/lib/stdlib/doc/src/slave.xml
index 80fb28b548..778c5f66e5 100644
--- a/lib/stdlib/doc/src/slave.xml
+++ b/lib/stdlib/doc/src/slave.xml
@@ -39,23 +39,30 @@
done through the master.</p>
<p>Slave nodes on other hosts than the current one are started with
- the <c>rsh</c> program. The user must be allowed to <c>rsh</c> to
+ the <c>ssh</c> program. The user must be allowed to <c>ssh</c> to
the remote hosts without being prompted for a password. This can
- be arranged in a number of ways (for details, see the <c>rsh</c>
+ be arranged in a number of ways (for details, see the <c>ssh</c>
documentation). A slave node started on the same host
as the master inherits certain environment values from the master,
such as the current directory and the environment variables. For
what can be assumed about the environment when a slave is started
- on another host, see the documentation for the <c>rsh</c>
+ on another host, see the documentation for the <c>ssh</c>
program.</p>
- <p>An alternative to the <c>rsh</c> program can be specified on
+ <p>An alternative to the <c>ssh</c> program can be specified on
the command line to
<seealso marker="erts:erl#erl"><c>erl(1)</c></seealso> as follows:</p>
<pre>
-rsh Program</pre>
+ <p>Note that the command specified with the <c>-rsh</c> flag is
+ treated as a file name which may contain spaces. It is thus not
+ possible to include any command line options. The remote node will
+ be launched as <c>"$RSH" "$REMOTE_HOSTNAME" erl -detached -noinput
+ ...</c>, so the
+ <c>erl</c> command must be found in the path on the remote host.</p>
+
<p>The slave node is to use the same file system at the master. At
least, Erlang/OTP is to be installed in the same place on both
computers and the same version of Erlang is to be used.</p>
@@ -166,7 +173,9 @@ slave:start(H, Name, Arg).</code>
</item>
<tag><c>no_rsh</c></tag>
<item>
- <p>There is no <c>rsh</c> program on the computer.</p>
+ <p>No remote shell program was found on the computer. Note
+ that <c>ssh</c> is used by default, but this can be overridden
+ with the <c>-rsh</c> flag.</p>
</item>
<tag><c>{already_running, <anno>Node</anno>}</c></tag>
<item>
diff --git a/lib/stdlib/src/calendar.erl b/lib/stdlib/src/calendar.erl
index 3a083d9fda..3a8fe2211b 100644
--- a/lib/stdlib/src/calendar.erl
+++ b/lib/stdlib/src/calendar.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -357,13 +357,17 @@ rfc3339_to_system_time(DateTimeString) ->
rfc3339_to_system_time(DateTimeString, Options) ->
Unit = proplists:get_value(unit, Options, second),
%% _T is the character separating the date and the time:
- {DateStr, [_T|TimeStr]} = lists:split(10, DateTimeString),
- {TimeStr2, TimeStr3} = lists:split(8, TimeStr),
- {ok, [Hour, Min, Sec], []} = io_lib:fread("~d:~d:~d", TimeStr2),
- {ok, [Year, Month, Day], []} = io_lib:fread("~d-~d-~d", DateStr),
+ [Y1, Y2, Y3, Y4, $-, Mon1, Mon2, $-, D1, D2, _T,
+ H1, H2, $:, Min1, Min2, $:, S1, S2 | TimeStr] = DateTimeString,
+ Hour = list_to_integer([H1, H2]),
+ Min = list_to_integer([Min1, Min2]),
+ Sec = list_to_integer([S1, S2]),
+ Year = list_to_integer([Y1, Y2, Y3, Y4]),
+ Month = list_to_integer([Mon1, Mon2]),
+ Day = list_to_integer([D1, D2]),
DateTime = {{Year, Month, Day}, {Hour, Min, Sec}},
IsFractionChar = fun(C) -> C >= $0 andalso C =< $9 orelse C =:= $. end,
- {FractionStr, UtcOffset} = lists:splitwith(IsFractionChar, TimeStr3),
+ {FractionStr, UtcOffset} = lists:splitwith(IsFractionChar, TimeStr),
Time = datetime_to_system_time(DateTime),
Secs = Time - offset_adjustment(Time, second, UtcOffset),
check(DateTimeString, Options, Secs),
@@ -451,8 +455,9 @@ system_time_to_rfc3339(Time, Options) ->
DateTime = system_time_to_datetime(Secs),
{{Year, Month, Day}, {Hour, Min, Sec}} = DateTime,
FractionStr = fraction_str(Factor, AdjustedTime),
- flat_fwrite("~4.10.0B-~2.10.0B-~2.10.0B~c~2.10.0B:~2.10.0B:~2.10.0B~s~s",
- [Year, Month, Day, T, Hour, Min, Sec, FractionStr, Offset]).
+ L = [pad4(Year), "-", pad2(Month), "-", pad2(Day), [T],
+ pad2(Hour), ":", pad2(Min), ":", pad2(Sec), FractionStr, Offset],
+ lists:append(L).
%% time_difference(T1, T2) = Tdiff
%%
@@ -680,7 +685,7 @@ offset(OffsetOption, Secs0) when OffsetOption =:= "";
Secs = abs(Secs0),
Hour = Secs div 3600,
Min = (Secs rem 3600) div 60,
- io_lib:fwrite("~c~2.10.0B:~2.10.0B", [Sign, Hour, Min]);
+ [Sign | lists:append([pad2(Hour), ":", pad2(Min)])];
offset(OffsetOption, _Secs) ->
OffsetOption.
@@ -695,8 +700,10 @@ offset_string_adjustment(_Time, _Unit, "Z") ->
0;
offset_string_adjustment(_Time, _Unit, "z") ->
0;
-offset_string_adjustment(_Time, _Unit, [Sign|Tz]) ->
- {ok, [Hour, Min], []} = io_lib:fread("~d:~d", Tz),
+offset_string_adjustment(_Time, _Unit, Tz) ->
+ [Sign, H1, H2, $:, M1, M2] = Tz,
+ Hour = list_to_integer([H1, H2]),
+ Min = list_to_integer([M1, M2]),
Adjustment = 3600 * Hour + 60 * Min,
case Sign of
$- -> -Adjustment;
@@ -704,8 +711,9 @@ offset_string_adjustment(_Time, _Unit, [Sign|Tz]) ->
end.
local_offset(SystemTime, Unit) ->
- LocalTime = system_time_to_local_time(SystemTime, Unit),
+ %% Not optimized for special cases.
UniversalTime = system_time_to_universal_time(SystemTime, Unit),
+ LocalTime = erlang:universaltime_to_localtime(UniversalTime),
LocalSecs = datetime_to_gregorian_seconds(LocalTime),
UniversalSecs = datetime_to_gregorian_seconds(UniversalTime),
LocalSecs - UniversalSecs.
@@ -714,7 +722,8 @@ fraction_str(1, _Time) ->
"";
fraction_str(Factor, Time) ->
Fraction = Time rem Factor,
- io_lib:fwrite(".~*..0B", [log10(Factor), abs(Fraction)]).
+ S = integer_to_list(abs(Fraction)),
+ [$. | pad(log10(Factor) - length(S), S)].
fraction(second, _) ->
0;
@@ -735,5 +744,21 @@ log10(1000) -> 3;
log10(1000000) -> 6;
log10(1000000000) -> 9.
-flat_fwrite(F, S) ->
- lists:flatten(io_lib:fwrite(F, S)).
+pad(0, S) ->
+ S;
+pad(I, S) ->
+ [$0 | pad(I - 1, S)].
+
+pad2(N) when N < 10 ->
+ [$0 | integer_to_list(N)];
+pad2(N) ->
+ integer_to_list(N).
+
+pad4(N) when N < 10 ->
+ [$0, $0, $0 | integer_to_list(N)];
+pad4(N) when N < 100 ->
+ [$0, $0 | integer_to_list(N)];
+pad4(N) when N < 1000 ->
+ [$0 | integer_to_list(N)];
+pad4(N) ->
+ integer_to_list(N).
diff --git a/lib/stdlib/src/slave.erl b/lib/stdlib/src/slave.erl
index 5e8c1a43ea..4791e3ebda 100644
--- a/lib/stdlib/src/slave.erl
+++ b/lib/stdlib/src/slave.erl
@@ -104,18 +104,17 @@ relay1(Pid) ->
%% this to work is that the 'erl' program can be found in PATH.
%%
%% If the master and slave are on different hosts, start/N uses
-%% the 'rsh' program to spawn an Erlang node on the other host.
+%% the 'ssh' program to spawn an Erlang node on the other host.
%% Alternative, if the master was started as
%% 'erl -sname xxx -rsh my_rsh...', then 'my_rsh' will be used instead
-%% of 'rsh' (this is useful for systems where the rsh program is named
-%% 'remsh').
+%% of 'ssh' (this is useful for systems still using rsh or remsh).
%%
%% For this to work, the following conditions must be fulfilled:
%%
-%% 1. There must be an Rsh program on computer; if not an error
+%% 1. There must be an ssh program on computer; if not an error
%% is returned.
%%
-%% 2. The hosts must be configured to allowed 'rsh' access without
+%% 2. The hosts must be configured to allow 'ssh' access without
%% prompts for password.
%%
%% The slave node will have its filer and user server redirected
@@ -286,7 +285,7 @@ register_unique_name(Number) ->
%% Makes up the command to start the nodes.
%% If the node should run on the local host, there is
-%% no need to use rsh.
+%% no need to use a remote shell.
mk_cmd(Host, Name, Args, Waiter, Prog0) ->
Prog = quote_progname(Prog0),
@@ -342,9 +341,7 @@ do_quote_progname([Prog,Arg|Args]) ->
lists:flatten(lists:map(fun(X) -> [" ",X] end, [Arg|Args]))
end.
-%% Give the user an opportunity to run another program,
-%% than the "rsh". On HP-UX rsh is called remsh; thus HP users
-%% must start erlang as erl -rsh remsh.
+%% Give the user an opportunity to run another program than "ssh".
%%
%% Also checks that the given program exists.
%%
@@ -354,7 +351,7 @@ rsh() ->
Rsh =
case init:get_argument(rsh) of
{ok, [[Prog]]} -> Prog;
- _ -> "rsh"
+ _ -> "ssh"
end,
case os:find_executable(Rsh) of
false -> {error, no_rsh};
diff --git a/lib/stdlib/test/binary_module_SUITE.erl b/lib/stdlib/test/binary_module_SUITE.erl
index e0811f19cf..9b2033ec4a 100644
--- a/lib/stdlib/test/binary_module_SUITE.erl
+++ b/lib/stdlib/test/binary_module_SUITE.erl
@@ -755,8 +755,9 @@ list_to_bin(Config) when is_list(Config) ->
copy(Config) when is_list(Config) ->
<<1,2,3>> = binary:copy(<<1,2,3>>),
RS = random_string({1,10000}),
- RS = RS2 = binary:copy(RS),
- false = erts_debug:same(RS,RS2),
+ RS2 = binary:copy(RS),
+ true = RS =:= RS2,
+ false = erts_debug:same(RS, RS2),
<<>> = ?MASK_ERROR(binary:copy(<<1,2,3>>,0)),
badarg = ?MASK_ERROR(binary:copy(<<1,2,3:3>>,2)),
badarg = ?MASK_ERROR(binary:copy([],0)),
diff --git a/lib/stdlib/test/calendar_SUITE.erl b/lib/stdlib/test/calendar_SUITE.erl
index c6d9dbca4a..224c0d5625 100644
--- a/lib/stdlib/test/calendar_SUITE.erl
+++ b/lib/stdlib/test/calendar_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/stdlib/test/qlc_SUITE.erl b/lib/stdlib/test/qlc_SUITE.erl
index d7354438f9..2354a08f78 100644
--- a/lib/stdlib/test/qlc_SUITE.erl
+++ b/lib/stdlib/test/qlc_SUITE.erl
@@ -3163,19 +3163,13 @@ lookup2(Config) when is_list(Config) ->
[a] = lookup_keys(Q)
end, [{a},{b},{c}])">>,
- {cres,
- <<"etsc(fun(E) ->
+ <<"etsc(fun(E) ->
Q = qlc:q([X || {X}=Y <- ets:table(E),
element(2, Y) == b,
X =:= 1]),
[] = qlc:e(Q),
false = lookup_keys(Q)
- end, [{1,b},{2,3}])">>,
- %% {warnings,[{2,sys_core_fold,nomatch_guard},
- %% {3,qlc,nomatch_filter},
- %% {3,sys_core_fold,{eval_failure,badarg}}]}},
- {warnings,[{2,sys_core_fold,nomatch_guard},
- {3,sys_core_fold,{eval_failure,badarg}}]}},
+ end, [{1,b},{2,3}])">>,
<<"etsc(fun(E) ->
Q = qlc:q([X || {X} <- ets:table(E), element(1,{X}) =:= 1]),