aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CONTRIBUTING.md3
-rw-r--r--HOWTO/INSTALL.md10
-rw-r--r--bootstrap/bin/start.bootbin5055 -> 5121 bytes
-rw-r--r--bootstrap/bin/start_clean.bootbin5055 -> 5121 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_a.beambin2640 -> 2804 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_asm.beambin11616 -> 11780 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_block.beambin8752 -> 8916 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_bs.beambin5624 -> 5788 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_bsm.beambin11956 -> 12120 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_clean.beambin8460 -> 8624 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_dead.beambin12960 -> 13124 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_dict.beambin5092 -> 5256 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_disasm.beambin24808 -> 24972 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_except.beambin3292 -> 3456 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_flatten.beambin2864 -> 3028 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_jump.beambin8636 -> 8800 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_listing.beambin2768 -> 2932 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_opcodes.beambin7112 -> 7276 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_peep.beambin2516 -> 2680 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_receive.beambin6180 -> 6344 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_record.beambin1908 -> 2072 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_reorder.beambin1960 -> 2124 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_split.beambin2156 -> 2320 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_trim.beambin7564 -> 7728 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_type.beambin17640 -> 17804 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_utils.beambin13152 -> 13316 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_validator.beambin28900 -> 29220 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_z.beambin2820 -> 2984 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/cerl.beambin30136 -> 30300 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/cerl_clauses.beambin2940 -> 3104 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/cerl_inline.beambin37736 -> 37908 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/cerl_sets.beambin2868 -> 3032 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/cerl_trees.beambin20884 -> 21048 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/compile.beambin38836 -> 39192 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/core_lib.beambin4296 -> 4460 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/core_lint.beambin12864 -> 13028 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/core_parse.beambin61880 -> 62036 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/core_pp.beambin11756 -> 11920 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/core_scan.beambin6720 -> 6884 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/erl_bifs.beambin2160 -> 2372 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/rec_env.beambin4596 -> 4760 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/sys_core_dsetel.beambin6956 -> 7120 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/sys_core_fold.beambin49420 -> 49584 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/sys_core_fold_lists.beambin4580 -> 4744 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/sys_core_inline.beambin4004 -> 4168 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/sys_pre_attributes.beambin2752 -> 2916 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/v3_codegen.beambin53696 -> 53860 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/v3_core.beambin56500 -> 56556 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/v3_kernel.beambin54572 -> 54844 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/v3_kernel_pp.beambin12536 -> 12700 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/v3_life.beambin17024 -> 17188 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/application.beambin3800 -> 3908 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/application_controller.beambin30848 -> 30956 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/application_master.beambin6412 -> 6520 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/application_starter.beambin1204 -> 1312 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/auth.beambin6356 -> 6464 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/code.beambin13120 -> 13228 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/code_server.beambin24060 -> 24168 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/disk_log.beambin32668 -> 32776 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/disk_log_1.beambin24068 -> 24176 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/disk_log_server.beambin6440 -> 6548 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/disk_log_sup.beambin556 -> 664 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/dist_ac.beambin24980 -> 25088 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/dist_util.beambin10860 -> 10968 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/erl_boot_server.beambin5764 -> 5872 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/erl_ddll.beambin2896 -> 3004 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/erl_distribution.beambin1616 -> 1724 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/erl_epmd.beambin7072 -> 7180 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/erl_reply.beambin908 -> 1016 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/erl_signal_handler.beambin960 -> 1068 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/error_handler.beambin1636 -> 1744 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/error_logger.beambin5936 -> 6044 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/erts_debug.beambin5644 -> 5752 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/file.beambin14100 -> 14208 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/file_io_server.beambin15052 -> 15160 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/file_server.beambin5356 -> 5464 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/gen_sctp.beambin3196 -> 3304 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/gen_tcp.beambin2096 -> 2204 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/gen_udp.beambin1320 -> 1428 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/global.beambin31264 -> 31372 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/global_group.beambin17132 -> 17240 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/global_search.beambin3084 -> 3192 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/group.beambin13876 -> 13984 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/heart.beambin5360 -> 5468 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/hipe_unified_loader.beambin12524 -> 12632 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/inet.beambin23264 -> 23384 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/inet6_sctp.beambin1472 -> 1580 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/inet6_tcp.beambin3012 -> 3120 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/inet6_tcp_dist.beambin872 -> 980 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/inet6_udp.beambin1764 -> 1872 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/inet_config.beambin7532 -> 7640 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/inet_db.beambin26524 -> 26632 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/inet_dns.beambin19320 -> 19428 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/inet_gethost_native.beambin10144 -> 10252 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/inet_hosts.beambin2124 -> 2232 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/inet_parse.beambin12748 -> 12856 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/inet_res.beambin14296 -> 14404 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/inet_sctp.beambin2188 -> 2296 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/inet_tcp.beambin2704 -> 2812 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/inet_tcp_dist.beambin7388 -> 7496 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/inet_udp.beambin1932 -> 2040 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/kernel.beambin3892 -> 4000 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/kernel_config.beambin2760 -> 2868 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/local_tcp.beambin2268 -> 2376 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/local_udp.beambin1416 -> 1524 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/net.beambin612 -> 720 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/net_adm.beambin2948 -> 3056 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/net_kernel.beambin23792 -> 23900 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/os.beambin4260 -> 4368 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/pg2.beambin7860 -> 7968 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/ram_file.beambin6348 -> 6456 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/rpc.beambin7996 -> 8104 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/seq_trace.beambin1608 -> 1716 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/standard_error.beambin3832 -> 3940 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/user.beambin11504 -> 11612 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/user_drv.beambin11152 -> 11260 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/user_sup.beambin1740 -> 1848 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/wrap_log_reader.beambin3136 -> 3244 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/array.beambin11784 -> 11912 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/base64.beambin4628 -> 4756 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/beam_lib.beambin18664 -> 19652 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/binary.beambin2824 -> 2952 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/c.beambin17464 -> 17592 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/calendar.beambin5136 -> 5264 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/dets.beambin49032 -> 49160 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/dets_server.beambin6864 -> 6992 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/dets_sup.beambin544 -> 672 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/dets_utils.beambin27892 -> 28020 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/dets_v9.beambin47968 -> 48096 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/dict.beambin9524 -> 9652 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/digraph.beambin7888 -> 8016 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/digraph_utils.beambin6832 -> 6960 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/edlin.beambin10048 -> 10176 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/edlin_expand.beambin3896 -> 4024 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/epp.beambin28032 -> 28160 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/erl_abstract_code.beambin0 -> 1156 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/erl_anno.beambin3636 -> 3764 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/erl_bits.beambin2476 -> 2604 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/erl_compile.beambin7108 -> 7236 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/erl_eval.beambin29824 -> 29952 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/erl_expand_records.beambin21804 -> 21932 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/erl_internal.beambin7700 -> 7896 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/erl_lint.beambin90988 -> 91116 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/erl_parse.beambin88492 -> 88620 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/erl_posix_msg.beambin5008 -> 5136 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/erl_pp.beambin26956 -> 27084 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/erl_scan.beambin28224 -> 28352 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/erl_tar.beambin32804 -> 32932 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/error_logger_file_h.beambin4332 -> 4460 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/error_logger_tty_h.beambin4664 -> 4792 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/escript.beambin16848 -> 16976 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/ets.beambin22344 -> 22472 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/eval_bits.beambin8112 -> 8240 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/file_sorter.beambin29292 -> 29420 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/filelib.beambin10048 -> 10176 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/filename.beambin14088 -> 14216 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/gb_sets.beambin8392 -> 8520 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/gb_trees.beambin5580 -> 5708 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/gen.beambin5384 -> 5512 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/gen_event.beambin13064 -> 13468 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/gen_fsm.beambin9416 -> 9780 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/gen_server.beambin12788 -> 13212 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/gen_statem.beambin16952 -> 17080 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/io.beambin6204 -> 6332 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/io_lib.beambin10228 -> 10356 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/io_lib_format.beambin13404 -> 13532 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/io_lib_fread.beambin7192 -> 7320 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/io_lib_pretty.beambin17156 -> 17284 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/lib.beambin9500 -> 9628 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/lists.beambin29900 -> 30028 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/log_mf_h.beambin2520 -> 2648 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/maps.beambin2880 -> 3008 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/math.beambin1296 -> 1424 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/ms_transform.beambin19696 -> 19824 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/orddict.beambin2952 -> 3080 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/ordsets.beambin1900 -> 2028 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/otp_internal.beambin9816 -> 9944 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/pool.beambin3828 -> 3956 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/proc_lib.beambin10660 -> 10788 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/proplists.beambin4732 -> 4860 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/qlc.beambin68604 -> 68732 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/qlc_pt.beambin75388 -> 75516 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/queue.beambin6212 -> 6340 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/rand.beambin15520 -> 19296 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/random.beambin1732 -> 1860 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/re.beambin13428 -> 13556 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/sets.beambin6548 -> 6676 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/shell.beambin29840 -> 29872 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/shell_default.beambin4072 -> 4200 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/slave.beambin4760 -> 4888 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/sofs.beambin37604 -> 37732 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/stdlib.app2
-rw-r--r--bootstrap/lib/stdlib/ebin/string.beambin5176 -> 24536 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/supervisor.beambin22392 -> 22520 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/supervisor_bridge.beambin2008 -> 2136 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/sys.beambin8408 -> 8536 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/timer.beambin5412 -> 5540 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/unicode.beambin11408 -> 13176 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/unicode_util.beambin0 -> 193448 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/win32reg.beambin5432 -> 5560 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/zip.beambin26412 -> 26540 bytes
-rw-r--r--configure.in10
-rw-r--r--erts/Makefile (renamed from erts/Makefile.in)14
-rw-r--r--erts/configure.in74
-rw-r--r--erts/doc/src/erl.xml26
-rw-r--r--erts/doc/src/erlang.xml36
-rw-r--r--erts/emulator/Makefile.in35
-rw-r--r--erts/emulator/beam/beam_bif_load.c4
-rw-r--r--erts/emulator/beam/beam_bp.c26
-rw-r--r--erts/emulator/beam/beam_emu.c8
-rw-r--r--erts/emulator/beam/beam_load.c33
-rw-r--r--erts/emulator/beam/bif.c69
-rw-r--r--erts/emulator/beam/bif.tab1
-rw-r--r--erts/emulator/beam/binary.c2
-rw-r--r--erts/emulator/beam/break.c2
-rw-r--r--erts/emulator/beam/code_ix.h8
-rw-r--r--erts/emulator/beam/copy.c16
-rw-r--r--erts/emulator/beam/dist.c4
-rw-r--r--erts/emulator/beam/erl_bif_binary.c1
-rw-r--r--erts/emulator/beam/erl_bif_info.c6
-rw-r--r--erts/emulator/beam/erl_bif_trace.c4
-rw-r--r--erts/emulator/beam/erl_bif_unique.c2
-rw-r--r--erts/emulator/beam/erl_bif_unique.h10
-rw-r--r--erts/emulator/beam/erl_binary.h54
-rw-r--r--erts/emulator/beam/erl_bits.c7
-rw-r--r--erts/emulator/beam/erl_db.c23
-rw-r--r--erts/emulator/beam/erl_db_hash.c4
-rw-r--r--erts/emulator/beam/erl_db_tree.c12
-rw-r--r--erts/emulator/beam/erl_db_util.c7
-rw-r--r--erts/emulator/beam/erl_db_util.h6
-rw-r--r--erts/emulator/beam/erl_gc.c13
-rw-r--r--erts/emulator/beam/erl_init.c72
-rw-r--r--erts/emulator/beam/erl_message.c7
-rw-r--r--erts/emulator/beam/erl_nif.c33
-rw-r--r--erts/emulator/beam/erl_process.c7
-rw-r--r--erts/emulator/beam/erl_process.h6
-rw-r--r--erts/emulator/beam/erl_process_dump.c6
-rw-r--r--erts/emulator/beam/erl_trace.c9
-rw-r--r--erts/emulator/beam/export.c2
-rw-r--r--erts/emulator/beam/external.c27
-rw-r--r--erts/emulator/beam/global.h6
-rw-r--r--erts/emulator/beam/io.c17
-rw-r--r--erts/emulator/beam/time.c12
-rw-r--r--erts/emulator/beam/utils.c2
-rw-r--r--erts/emulator/hipe/hipe_bif0.c74
-rw-r--r--erts/emulator/hipe/hipe_bif0.h2
-rw-r--r--erts/emulator/hipe/hipe_bif0.tab1
-rw-r--r--erts/emulator/hipe/hipe_bif1.c42
-rw-r--r--erts/emulator/hipe/hipe_load.c2
-rw-r--r--erts/emulator/hipe/hipe_mode_switch.c7
-rw-r--r--erts/emulator/hipe/hipe_mode_switch.h2
-rw-r--r--erts/emulator/hipe/hipe_native_bif.c1
-rw-r--r--erts/emulator/sys/common/erl_mseg.c7
-rw-r--r--erts/emulator/test/list_bif_SUITE.erl21
-rw-r--r--erts/emulator/test/scheduler_SUITE.erl16
-rw-r--r--erts/emulator/test/smoke_test_SUITE.erl7
-rw-r--r--erts/emulator/test/statistics_SUITE.erl4
-rw-r--r--erts/etc/common/erlexec.c44
-rw-r--r--erts/preloaded/ebin/erl_prim_loader.beambin54816 -> 54336 bytes
-rw-r--r--erts/preloaded/ebin/erl_tracer.beambin2176 -> 2152 bytes
-rw-r--r--erts/preloaded/ebin/erlang.beambin105848 -> 105016 bytes
-rw-r--r--erts/preloaded/ebin/erts_code_purger.beambin11364 -> 11288 bytes
-rw-r--r--erts/preloaded/ebin/erts_dirty_process_code_checker.beambin2096 -> 2072 bytes
-rw-r--r--erts/preloaded/ebin/erts_internal.beambin11048 -> 10964 bytes
-rw-r--r--erts/preloaded/ebin/erts_literal_area_collector.beambin3280 -> 3244 bytes
-rw-r--r--erts/preloaded/ebin/init.beambin50600 -> 49960 bytes
-rw-r--r--erts/preloaded/ebin/otp_ring0.beambin1420 -> 1400 bytes
-rw-r--r--erts/preloaded/ebin/prim_eval.beambin1424 -> 1368 bytes
-rw-r--r--erts/preloaded/ebin/prim_file.beambin43960 -> 43604 bytes
-rw-r--r--erts/preloaded/ebin/prim_inet.beambin75928 -> 75452 bytes
-rw-r--r--erts/preloaded/ebin/prim_zip.beambin22968 -> 22780 bytes
-rw-r--r--erts/preloaded/ebin/zlib.beambin14256 -> 14160 bytes
-rw-r--r--erts/preloaded/src/add_abstract_code14
-rw-r--r--erts/preloaded/src/erlang.erl14
-rw-r--r--erts/preloaded/src/init.erl8
-rw-r--r--lib/common_test/doc/src/ct.xml3
-rw-r--r--lib/common_test/doc/src/ct_run.xml8
-rw-r--r--lib/common_test/doc/src/run_test_chapter.xml56
-rw-r--r--lib/common_test/src/ct_logs.erl37
-rw-r--r--lib/common_test/src/ct_run.erl18
-rw-r--r--lib/common_test/test/Makefile3
-rw-r--r--lib/common_test/test/ct_keep_logs_SUITE.erl186
-rw-r--r--lib/common_test/test/ct_keep_logs_SUITE_data/keep_logs_SUITE.erl32
-rw-r--r--lib/common_test/test/ct_test_support.erl3
-rw-r--r--lib/compiler/doc/src/compile.xml25
-rw-r--r--lib/compiler/src/compile.erl89
-rw-r--r--lib/compiler/src/erl_bifs.erl3
-rw-r--r--lib/compiler/src/v3_core.erl12
-rw-r--r--lib/compiler/src/v3_kernel.erl2
-rw-r--r--lib/compiler/test/compilation_SUITE.erl2
-rw-r--r--lib/compiler/test/compile_SUITE.erl44
-rw-r--r--lib/debugger/doc/src/debugger_chapter.xml8
-rw-r--r--lib/debugger/src/dbg_icmd.erl44
-rw-r--r--lib/debugger/src/dbg_wx_win.erl5
-rw-r--r--lib/dialyzer/src/dialyzer_analysis_callgraph.erl86
-rw-r--r--lib/dialyzer/src/dialyzer_plt.erl11
-rw-r--r--lib/dialyzer/src/dialyzer_utils.erl298
-rw-r--r--lib/dialyzer/src/typer.erl36
-rw-r--r--lib/edoc/src/edoc_layout.erl19
-rw-r--r--lib/erl_docgen/priv/css/Makefile3
-rw-r--r--lib/erl_docgen/priv/css/highlight.css96
-rw-r--r--lib/erl_docgen/priv/css/otp_doc.css220
-rw-r--r--lib/erl_docgen/priv/images/erlang-logo.gifbin11588 -> 3342 bytes
-rw-r--r--lib/erl_docgen/priv/images/erlang-logo.pngbin14795 -> 5837 bytes
-rw-r--r--lib/erl_docgen/priv/js/flipmenu/Makefile1
-rw-r--r--lib/erl_docgen/priv/js/flipmenu/flip_closed.gifbin82 -> 79 bytes
-rw-r--r--lib/erl_docgen/priv/js/flipmenu/flip_open.gifbin86 -> 85 bytes
-rw-r--r--lib/erl_docgen/priv/js/flipmenu/flip_static.gifbin109 -> 132 bytes
-rw-r--r--lib/erl_docgen/priv/js/highlight.js39
-rw-r--r--lib/erl_docgen/priv/js/highlight.pack.js2
-rw-r--r--lib/erl_docgen/priv/xsl/db_html.xsl287
-rw-r--r--lib/erl_docgen/vsn.mk2
-rw-r--r--lib/hipe/cerl/erl_bif_types.erl5
-rw-r--r--lib/hipe/rtl/Makefile8
-rw-r--r--lib/kernel/test/file_name_SUITE.erl2
-rw-r--r--lib/observer/src/observer_port_wx.erl83
-rw-r--r--lib/reltool/src/reltool.hrl6
-rw-r--r--lib/ssl/src/dtls_connection.erl2
-rw-r--r--lib/ssl/src/dtls_handshake.erl4
-rw-r--r--lib/ssl/src/dtls_record.erl24
-rw-r--r--lib/ssl/src/dtls_v1.erl7
-rw-r--r--lib/ssl/src/ssl.erl6
-rw-r--r--lib/ssl/src/ssl_connection.erl2
-rw-r--r--lib/ssl/src/ssl_handshake.erl26
-rw-r--r--lib/ssl/src/tls_connection.erl2
-rw-r--r--lib/ssl/src/tls_record.erl8
-rw-r--r--lib/ssl/src/tls_v1.erl11
-rw-r--r--lib/stdlib/doc/src/beam_lib.xml46
-rw-r--r--lib/stdlib/doc/src/gen_fsm.xml1109
-rw-r--r--lib/stdlib/doc/src/gen_server.xml1
-rw-r--r--lib/stdlib/doc/src/gen_statem.xml201
-rw-r--r--lib/stdlib/doc/src/io.xml6
-rw-r--r--lib/stdlib/doc/src/io_lib.xml3
-rw-r--r--lib/stdlib/doc/src/proc_lib.xml2
-rw-r--r--lib/stdlib/doc/src/sets.xml2
-rw-r--r--lib/stdlib/doc/src/shell.xml21
-rw-r--r--lib/stdlib/doc/src/supervisor.xml6
-rw-r--r--lib/stdlib/doc/src/sys.xml28
-rw-r--r--lib/stdlib/doc/src/unicode_usage.xml17
-rw-r--r--lib/stdlib/src/Makefile1
-rw-r--r--lib/stdlib/src/beam_lib.erl105
-rw-r--r--lib/stdlib/src/erl_abstract_code.erl28
-rw-r--r--lib/stdlib/src/erl_internal.erl4
-rw-r--r--lib/stdlib/src/erl_lint.erl4
-rw-r--r--lib/stdlib/src/ets.erl2
-rw-r--r--lib/stdlib/src/gen_fsm.erl20
-rw-r--r--lib/stdlib/src/gen_statem.erl207
-rw-r--r--lib/stdlib/src/io_lib.erl87
-rw-r--r--lib/stdlib/src/io_lib_format.erl10
-rw-r--r--lib/stdlib/src/io_lib_fread.erl11
-rw-r--r--lib/stdlib/src/lib.erl223
-rw-r--r--lib/stdlib/src/otp_internal.erl49
-rw-r--r--lib/stdlib/src/qlc.erl45
-rw-r--r--lib/stdlib/src/rand.erl14
-rw-r--r--lib/stdlib/src/shell.erl17
-rw-r--r--lib/stdlib/src/stdlib.app.src1
-rw-r--r--lib/stdlib/test/beam_lib_SUITE.erl40
-rw-r--r--lib/stdlib/test/erl_internal_SUITE.erl11
-rw-r--r--lib/stdlib/test/gen_statem_SUITE.erl139
-rw-r--r--lib/stdlib/test/gen_statem_SUITE_data/oc_statem.erl37
-rw-r--r--lib/stdlib/test/io_SUITE.erl24
-rw-r--r--lib/stdlib/test/qlc_SUITE.erl85
-rw-r--r--lib/stdlib/test/rand_SUITE.erl106
-rw-r--r--lib/stdlib/test/shell_SUITE.erl93
-rw-r--r--lib/stdlib/test/sofs_SUITE.erl4
-rw-r--r--lib/tools/emacs/erlang.el445
-rw-r--r--lib/wx/c_src/wxe_impl.cpp4
-rw-r--r--lib/xmerl/src/xmerl_scan.erl4
-rw-r--r--lib/xmerl/test/xmerl_SUITE.erl9
-rwxr-xr-xmake/emd2exml.in2
-rw-r--r--make/otp.mk.in3
-rwxr-xr-xscripts/build-otp2
-rw-r--r--system/doc/design_principles/fsm.xml338
-rw-r--r--system/doc/design_principles/part.xml1
-rw-r--r--system/doc/design_principles/spec_proc.xml86
-rw-r--r--system/doc/design_principles/statem.xml115
-rw-r--r--system/doc/design_principles/sup_princ.xml7
-rw-r--r--system/doc/design_principles/xmlfiles.mk1
-rw-r--r--system/doc/efficiency_guide/processes.xml4
-rw-r--r--system/doc/reference_manual/character_set.xml3
-rw-r--r--system/doc/reference_manual/modules.xml1
-rw-r--r--system/doc/top/src/erl_html_tools.erl47
-rw-r--r--system/doc/top/src/otp_man_index.erl61
-rw-r--r--system/doc/top/templates/applications.html.src56
-rw-r--r--system/doc/top/templates/index.html.src52
385 files changed, 3755 insertions, 3175 deletions
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 328b9f7859..ca9674d103 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -9,6 +9,9 @@ for more information.
You can contribute to Erlang/OTP by opening a Pull Request.
+Make sure you create a new branch for your pull request with `git checkout -b new-branch-name`.
+Never do your work directly on `maint` or `master`.
+
## Fixing a bug
* In most cases, pull requests for bug fixes should be based on the `maint` branch.
diff --git a/HOWTO/INSTALL.md b/HOWTO/INSTALL.md
index 8587774c12..bec09bdae1 100644
--- a/HOWTO/INSTALL.md
+++ b/HOWTO/INSTALL.md
@@ -343,10 +343,12 @@ use the `--prefix` argument like this: `./configure --prefix=<Dir>`.
Some of the available `configure` options are:
* `--prefix=PATH` - Specify installation prefix.
-
-* `--{enable,disable}-threads` - Thread support. This is enabled by default if possible.
-* `--{enable,disable}-smp-support` - SMP support (enabled by default if
- a usable POSIX thread library or native Windows threads is found)
+* `--enable-plain-emulator` - Build a threaded emulator that only
+ uses one scheduler. This emulator type is deprecated and will be
+ removed in a future release.
+* `--disable-threads` - Build a non-threaded emulator. This emulator type
+ is deprecated and will be
+ removed in a future release.
* `--{enable,disable}-kernel-poll` - Kernel poll support (enabled by
default if possible)
* `--{enable,disable}-hipe` - HiPE support (enabled by default on supported
diff --git a/bootstrap/bin/start.boot b/bootstrap/bin/start.boot
index 8d675873fe..6a42dfe423 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 8d675873fe..6a42dfe423 100644
--- a/bootstrap/bin/start_clean.boot
+++ b/bootstrap/bin/start_clean.boot
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_a.beam b/bootstrap/lib/compiler/ebin/beam_a.beam
index 7cca4b212a..bc936a29f4 100644
--- a/bootstrap/lib/compiler/ebin/beam_a.beam
+++ b/bootstrap/lib/compiler/ebin/beam_a.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_asm.beam b/bootstrap/lib/compiler/ebin/beam_asm.beam
index 72f9982ec8..bdd4b00b3f 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_block.beam b/bootstrap/lib/compiler/ebin/beam_block.beam
index 475cecfa6d..3c286dffbf 100644
--- a/bootstrap/lib/compiler/ebin/beam_block.beam
+++ b/bootstrap/lib/compiler/ebin/beam_block.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_bs.beam b/bootstrap/lib/compiler/ebin/beam_bs.beam
index b19b7efdde..7840bbdf47 100644
--- a/bootstrap/lib/compiler/ebin/beam_bs.beam
+++ b/bootstrap/lib/compiler/ebin/beam_bs.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_bsm.beam b/bootstrap/lib/compiler/ebin/beam_bsm.beam
index aeb44c114c..568c2f3ec4 100644
--- a/bootstrap/lib/compiler/ebin/beam_bsm.beam
+++ b/bootstrap/lib/compiler/ebin/beam_bsm.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_clean.beam b/bootstrap/lib/compiler/ebin/beam_clean.beam
index 469c48dafb..178f660d7a 100644
--- a/bootstrap/lib/compiler/ebin/beam_clean.beam
+++ b/bootstrap/lib/compiler/ebin/beam_clean.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_dead.beam b/bootstrap/lib/compiler/ebin/beam_dead.beam
index 38882d6f77..605607445f 100644
--- a/bootstrap/lib/compiler/ebin/beam_dead.beam
+++ b/bootstrap/lib/compiler/ebin/beam_dead.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_dict.beam b/bootstrap/lib/compiler/ebin/beam_dict.beam
index 7e52f634be..0eafd9c839 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_disasm.beam b/bootstrap/lib/compiler/ebin/beam_disasm.beam
index 9468053997..1028fd7e6c 100644
--- a/bootstrap/lib/compiler/ebin/beam_disasm.beam
+++ b/bootstrap/lib/compiler/ebin/beam_disasm.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_except.beam b/bootstrap/lib/compiler/ebin/beam_except.beam
index 9b7984d027..4cdbb91dd5 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 e0eab64ddf..2db71eafdf 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 8996609dde..d92c009533 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_listing.beam b/bootstrap/lib/compiler/ebin/beam_listing.beam
index 423c171f2b..bd4a5760f3 100644
--- a/bootstrap/lib/compiler/ebin/beam_listing.beam
+++ b/bootstrap/lib/compiler/ebin/beam_listing.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_opcodes.beam b/bootstrap/lib/compiler/ebin/beam_opcodes.beam
index 6b4a8e99fd..9c7029898e 100644
--- a/bootstrap/lib/compiler/ebin/beam_opcodes.beam
+++ b/bootstrap/lib/compiler/ebin/beam_opcodes.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_peep.beam b/bootstrap/lib/compiler/ebin/beam_peep.beam
index 51f28cd1bd..892d8a67c5 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_receive.beam b/bootstrap/lib/compiler/ebin/beam_receive.beam
index 3c8ce31c8b..9b6ee8692e 100644
--- a/bootstrap/lib/compiler/ebin/beam_receive.beam
+++ b/bootstrap/lib/compiler/ebin/beam_receive.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_record.beam b/bootstrap/lib/compiler/ebin/beam_record.beam
index 01c2e5a373..96dbaa4338 100644
--- a/bootstrap/lib/compiler/ebin/beam_record.beam
+++ b/bootstrap/lib/compiler/ebin/beam_record.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_reorder.beam b/bootstrap/lib/compiler/ebin/beam_reorder.beam
index 73f42ff1f6..7500c0f725 100644
--- a/bootstrap/lib/compiler/ebin/beam_reorder.beam
+++ b/bootstrap/lib/compiler/ebin/beam_reorder.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_split.beam b/bootstrap/lib/compiler/ebin/beam_split.beam
index 7ca6a53728..def7cd3314 100644
--- a/bootstrap/lib/compiler/ebin/beam_split.beam
+++ b/bootstrap/lib/compiler/ebin/beam_split.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_trim.beam b/bootstrap/lib/compiler/ebin/beam_trim.beam
index 4c045a6f8b..31e2a2c1c2 100644
--- a/bootstrap/lib/compiler/ebin/beam_trim.beam
+++ b/bootstrap/lib/compiler/ebin/beam_trim.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_type.beam b/bootstrap/lib/compiler/ebin/beam_type.beam
index b60a11b01b..76a2a176f7 100644
--- a/bootstrap/lib/compiler/ebin/beam_type.beam
+++ b/bootstrap/lib/compiler/ebin/beam_type.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_utils.beam b/bootstrap/lib/compiler/ebin/beam_utils.beam
index a72921204f..1d88c6a6e7 100644
--- a/bootstrap/lib/compiler/ebin/beam_utils.beam
+++ b/bootstrap/lib/compiler/ebin/beam_utils.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_validator.beam b/bootstrap/lib/compiler/ebin/beam_validator.beam
index 8d8c9e56cf..97c24118b1 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 15c76094a7..6a95f140f1 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 9e79fd9b07..b9f10145c0 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_clauses.beam b/bootstrap/lib/compiler/ebin/cerl_clauses.beam
index c6d7a3db0a..4c2e4e7f97 100644
--- a/bootstrap/lib/compiler/ebin/cerl_clauses.beam
+++ b/bootstrap/lib/compiler/ebin/cerl_clauses.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/cerl_inline.beam b/bootstrap/lib/compiler/ebin/cerl_inline.beam
index cae60e45b6..605f17f057 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 601d3dbd87..72bcb3527a 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 322e5b7930..6193ea155f 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 26890187b9..65809b44de 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/core_lib.beam b/bootstrap/lib/compiler/ebin/core_lib.beam
index 33b1d00463..eaca62b945 100644
--- a/bootstrap/lib/compiler/ebin/core_lib.beam
+++ b/bootstrap/lib/compiler/ebin/core_lib.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/core_lint.beam b/bootstrap/lib/compiler/ebin/core_lint.beam
index f6dc90b2cc..5ed8c04322 100644
--- a/bootstrap/lib/compiler/ebin/core_lint.beam
+++ b/bootstrap/lib/compiler/ebin/core_lint.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/core_parse.beam b/bootstrap/lib/compiler/ebin/core_parse.beam
index 7865efe421..0555025360 100644
--- a/bootstrap/lib/compiler/ebin/core_parse.beam
+++ b/bootstrap/lib/compiler/ebin/core_parse.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/core_pp.beam b/bootstrap/lib/compiler/ebin/core_pp.beam
index 1672897475..0513126ae0 100644
--- a/bootstrap/lib/compiler/ebin/core_pp.beam
+++ b/bootstrap/lib/compiler/ebin/core_pp.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/core_scan.beam b/bootstrap/lib/compiler/ebin/core_scan.beam
index 556294691e..1f3d88e797 100644
--- a/bootstrap/lib/compiler/ebin/core_scan.beam
+++ b/bootstrap/lib/compiler/ebin/core_scan.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/erl_bifs.beam b/bootstrap/lib/compiler/ebin/erl_bifs.beam
index 8ac0f6ac21..a385352783 100644
--- a/bootstrap/lib/compiler/ebin/erl_bifs.beam
+++ b/bootstrap/lib/compiler/ebin/erl_bifs.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/rec_env.beam b/bootstrap/lib/compiler/ebin/rec_env.beam
index d882555fa2..1830d079b4 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_dsetel.beam b/bootstrap/lib/compiler/ebin/sys_core_dsetel.beam
index 0a74db8040..6e9bd6255c 100644
--- a/bootstrap/lib/compiler/ebin/sys_core_dsetel.beam
+++ b/bootstrap/lib/compiler/ebin/sys_core_dsetel.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 8df7b2374b..90296baf60 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_fold_lists.beam b/bootstrap/lib/compiler/ebin/sys_core_fold_lists.beam
index 7877d17db5..373debfc27 100644
--- a/bootstrap/lib/compiler/ebin/sys_core_fold_lists.beam
+++ b/bootstrap/lib/compiler/ebin/sys_core_fold_lists.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 e5861dd494..92d636005d 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/sys_pre_attributes.beam b/bootstrap/lib/compiler/ebin/sys_pre_attributes.beam
index 3a71c094ed..52391ec2c9 100644
--- a/bootstrap/lib/compiler/ebin/sys_pre_attributes.beam
+++ b/bootstrap/lib/compiler/ebin/sys_pre_attributes.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/v3_codegen.beam b/bootstrap/lib/compiler/ebin/v3_codegen.beam
index dcc9a51a38..df54c8cf70 100644
--- a/bootstrap/lib/compiler/ebin/v3_codegen.beam
+++ b/bootstrap/lib/compiler/ebin/v3_codegen.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/v3_core.beam b/bootstrap/lib/compiler/ebin/v3_core.beam
index d2bccf05ca..73a5a6c48b 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 25f6134fbd..fac8b05528 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 790b8df8bc..54af18ed4c 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/compiler/ebin/v3_life.beam b/bootstrap/lib/compiler/ebin/v3_life.beam
index cd8bc19620..cbfc1f4f82 100644
--- a/bootstrap/lib/compiler/ebin/v3_life.beam
+++ b/bootstrap/lib/compiler/ebin/v3_life.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/application.beam b/bootstrap/lib/kernel/ebin/application.beam
index 4ddd32379b..8746279ae8 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 cc17a3f862..cccab712e7 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_master.beam b/bootstrap/lib/kernel/ebin/application_master.beam
index 1d4e23437d..94b902f08b 100644
--- a/bootstrap/lib/kernel/ebin/application_master.beam
+++ b/bootstrap/lib/kernel/ebin/application_master.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/application_starter.beam b/bootstrap/lib/kernel/ebin/application_starter.beam
index 632fb56fe7..996accedea 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 f315376adc..0daa7ca83a 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 13eeb6a469..f197c8a5b5 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 211c9933b7..b6e8faf492 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 4ae813bdec..1a15e400c5 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 95e6323c34..5efe11b918 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 fa5c5691f4..e212e82d15 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/disk_log_sup.beam b/bootstrap/lib/kernel/ebin/disk_log_sup.beam
index cb802b16ac..939e6f4d3d 100644
--- a/bootstrap/lib/kernel/ebin/disk_log_sup.beam
+++ b/bootstrap/lib/kernel/ebin/disk_log_sup.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/dist_ac.beam b/bootstrap/lib/kernel/ebin/dist_ac.beam
index b1caf1c247..61f988cb71 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 e0870153f6..00d4d5198c 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 ad18c8a1d1..e19853bb22 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 b55c290300..c464b92096 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_distribution.beam b/bootstrap/lib/kernel/ebin/erl_distribution.beam
index 5ce25edd5d..1bd3c7111c 100644
--- a/bootstrap/lib/kernel/ebin/erl_distribution.beam
+++ b/bootstrap/lib/kernel/ebin/erl_distribution.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/erl_epmd.beam b/bootstrap/lib/kernel/ebin/erl_epmd.beam
index d19a07d633..8af37f8bf4 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/erl_reply.beam b/bootstrap/lib/kernel/ebin/erl_reply.beam
index 53298573b4..24ee703ca2 100644
--- a/bootstrap/lib/kernel/ebin/erl_reply.beam
+++ b/bootstrap/lib/kernel/ebin/erl_reply.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/erl_signal_handler.beam b/bootstrap/lib/kernel/ebin/erl_signal_handler.beam
index 063f08877f..c5b85d9b69 100644
--- a/bootstrap/lib/kernel/ebin/erl_signal_handler.beam
+++ b/bootstrap/lib/kernel/ebin/erl_signal_handler.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/error_handler.beam b/bootstrap/lib/kernel/ebin/error_handler.beam
index 568790c444..f2df2a189e 100644
--- a/bootstrap/lib/kernel/ebin/error_handler.beam
+++ b/bootstrap/lib/kernel/ebin/error_handler.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/error_logger.beam b/bootstrap/lib/kernel/ebin/error_logger.beam
index f619c6f6bf..a0a8f8b121 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 e378694072..3c77d5a20f 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 d7bc770e98..4a50f9de78 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 0224c193b4..7245ec2695 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 5037daacfc..ace5489a3c 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/gen_sctp.beam b/bootstrap/lib/kernel/ebin/gen_sctp.beam
index 083f43d892..3fa0409227 100644
--- a/bootstrap/lib/kernel/ebin/gen_sctp.beam
+++ b/bootstrap/lib/kernel/ebin/gen_sctp.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/gen_tcp.beam b/bootstrap/lib/kernel/ebin/gen_tcp.beam
index d57a66dff7..c154687a9b 100644
--- a/bootstrap/lib/kernel/ebin/gen_tcp.beam
+++ b/bootstrap/lib/kernel/ebin/gen_tcp.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/gen_udp.beam b/bootstrap/lib/kernel/ebin/gen_udp.beam
index 32cd268c8a..447d4fdc49 100644
--- a/bootstrap/lib/kernel/ebin/gen_udp.beam
+++ b/bootstrap/lib/kernel/ebin/gen_udp.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/global.beam b/bootstrap/lib/kernel/ebin/global.beam
index de0b853da1..98c21a15f3 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 e6b9c647db..2e1fc5d542 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/global_search.beam b/bootstrap/lib/kernel/ebin/global_search.beam
index 743fb6a89f..ae2a767188 100644
--- a/bootstrap/lib/kernel/ebin/global_search.beam
+++ b/bootstrap/lib/kernel/ebin/global_search.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/group.beam b/bootstrap/lib/kernel/ebin/group.beam
index ce535a9f0b..8bf4af542f 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/heart.beam b/bootstrap/lib/kernel/ebin/heart.beam
index 99b7487044..6eadb43fe4 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/hipe_unified_loader.beam b/bootstrap/lib/kernel/ebin/hipe_unified_loader.beam
index 82fcb51d3f..6e35a4f5cf 100644
--- a/bootstrap/lib/kernel/ebin/hipe_unified_loader.beam
+++ b/bootstrap/lib/kernel/ebin/hipe_unified_loader.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/inet.beam b/bootstrap/lib/kernel/ebin/inet.beam
index ddfe94c1b9..473d6154da 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/inet6_sctp.beam b/bootstrap/lib/kernel/ebin/inet6_sctp.beam
index a5ea524671..2199828859 100644
--- a/bootstrap/lib/kernel/ebin/inet6_sctp.beam
+++ b/bootstrap/lib/kernel/ebin/inet6_sctp.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/inet6_tcp.beam b/bootstrap/lib/kernel/ebin/inet6_tcp.beam
index 5d8af46cea..5a5bbfea43 100644
--- a/bootstrap/lib/kernel/ebin/inet6_tcp.beam
+++ b/bootstrap/lib/kernel/ebin/inet6_tcp.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/inet6_tcp_dist.beam b/bootstrap/lib/kernel/ebin/inet6_tcp_dist.beam
index 23ffe7572a..af6ce5f042 100644
--- a/bootstrap/lib/kernel/ebin/inet6_tcp_dist.beam
+++ b/bootstrap/lib/kernel/ebin/inet6_tcp_dist.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/inet6_udp.beam b/bootstrap/lib/kernel/ebin/inet6_udp.beam
index 70f4997430..0563b5db26 100644
--- a/bootstrap/lib/kernel/ebin/inet6_udp.beam
+++ b/bootstrap/lib/kernel/ebin/inet6_udp.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/inet_config.beam b/bootstrap/lib/kernel/ebin/inet_config.beam
index e803c23433..d9482ebcb0 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 e91883b418..dc505f54da 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 d610a6a662..d3872cebbd 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 3e06a72e80..883cfe6cdf 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_hosts.beam b/bootstrap/lib/kernel/ebin/inet_hosts.beam
index 3882ee4fb5..4d9377b124 100644
--- a/bootstrap/lib/kernel/ebin/inet_hosts.beam
+++ b/bootstrap/lib/kernel/ebin/inet_hosts.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/inet_parse.beam b/bootstrap/lib/kernel/ebin/inet_parse.beam
index e8fc0876d2..f78e30cbb0 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 f21bdf50b5..3147ff5dbc 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_sctp.beam b/bootstrap/lib/kernel/ebin/inet_sctp.beam
index 993752d44a..4eb47f1f50 100644
--- a/bootstrap/lib/kernel/ebin/inet_sctp.beam
+++ b/bootstrap/lib/kernel/ebin/inet_sctp.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/inet_tcp.beam b/bootstrap/lib/kernel/ebin/inet_tcp.beam
index b24dc68ae7..48e3986b0b 100644
--- a/bootstrap/lib/kernel/ebin/inet_tcp.beam
+++ b/bootstrap/lib/kernel/ebin/inet_tcp.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 cee1e8a6c0..666b2b5beb 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/inet_udp.beam b/bootstrap/lib/kernel/ebin/inet_udp.beam
index 21fc35c8b7..804ee860dd 100644
--- a/bootstrap/lib/kernel/ebin/inet_udp.beam
+++ b/bootstrap/lib/kernel/ebin/inet_udp.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/kernel.beam b/bootstrap/lib/kernel/ebin/kernel.beam
index 24e15fc063..6bb295a61a 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 680477f566..90b62dd556 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/local_tcp.beam b/bootstrap/lib/kernel/ebin/local_tcp.beam
index a3097efd74..f3b3291ad1 100644
--- a/bootstrap/lib/kernel/ebin/local_tcp.beam
+++ b/bootstrap/lib/kernel/ebin/local_tcp.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/local_udp.beam b/bootstrap/lib/kernel/ebin/local_udp.beam
index 8a83529d66..0ddae3a57a 100644
--- a/bootstrap/lib/kernel/ebin/local_udp.beam
+++ b/bootstrap/lib/kernel/ebin/local_udp.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/net.beam b/bootstrap/lib/kernel/ebin/net.beam
index 7bb5453cb8..a02b17cae2 100644
--- a/bootstrap/lib/kernel/ebin/net.beam
+++ b/bootstrap/lib/kernel/ebin/net.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/net_adm.beam b/bootstrap/lib/kernel/ebin/net_adm.beam
index cf91942455..6bb14d425d 100644
--- a/bootstrap/lib/kernel/ebin/net_adm.beam
+++ b/bootstrap/lib/kernel/ebin/net_adm.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/net_kernel.beam b/bootstrap/lib/kernel/ebin/net_kernel.beam
index e5813705da..4a15ef6c63 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 d42c3b0f31..fb65ca94e8 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/pg2.beam b/bootstrap/lib/kernel/ebin/pg2.beam
index e3348158b7..1de40824fd 100644
--- a/bootstrap/lib/kernel/ebin/pg2.beam
+++ b/bootstrap/lib/kernel/ebin/pg2.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/ram_file.beam b/bootstrap/lib/kernel/ebin/ram_file.beam
index 893cff2458..0dc6ad73e0 100644
--- a/bootstrap/lib/kernel/ebin/ram_file.beam
+++ b/bootstrap/lib/kernel/ebin/ram_file.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/rpc.beam b/bootstrap/lib/kernel/ebin/rpc.beam
index 6d8d55d312..7578e601ff 100644
--- a/bootstrap/lib/kernel/ebin/rpc.beam
+++ b/bootstrap/lib/kernel/ebin/rpc.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/seq_trace.beam b/bootstrap/lib/kernel/ebin/seq_trace.beam
index d9e9f5200d..5ba162831d 100644
--- a/bootstrap/lib/kernel/ebin/seq_trace.beam
+++ b/bootstrap/lib/kernel/ebin/seq_trace.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/standard_error.beam b/bootstrap/lib/kernel/ebin/standard_error.beam
index 41f5c2ef47..3c4cba4edd 100644
--- a/bootstrap/lib/kernel/ebin/standard_error.beam
+++ b/bootstrap/lib/kernel/ebin/standard_error.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/user.beam b/bootstrap/lib/kernel/ebin/user.beam
index 1523c5f6e8..6d59ec7971 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 cb695170b9..615bd1bb15 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/user_sup.beam b/bootstrap/lib/kernel/ebin/user_sup.beam
index 7de9f27b7c..7277b79a76 100644
--- a/bootstrap/lib/kernel/ebin/user_sup.beam
+++ b/bootstrap/lib/kernel/ebin/user_sup.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 d8db01e52b..f1486678f0 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/array.beam b/bootstrap/lib/stdlib/ebin/array.beam
index 8f5ec723af..6992a24d98 100644
--- a/bootstrap/lib/stdlib/ebin/array.beam
+++ b/bootstrap/lib/stdlib/ebin/array.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/base64.beam b/bootstrap/lib/stdlib/ebin/base64.beam
index eb16f91461..f89e3be956 100644
--- a/bootstrap/lib/stdlib/ebin/base64.beam
+++ b/bootstrap/lib/stdlib/ebin/base64.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/beam_lib.beam b/bootstrap/lib/stdlib/ebin/beam_lib.beam
index b8fcf17609..4c82a8a6c5 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/binary.beam b/bootstrap/lib/stdlib/ebin/binary.beam
index 6dc0df9ebe..0863c4cf8d 100644
--- a/bootstrap/lib/stdlib/ebin/binary.beam
+++ b/bootstrap/lib/stdlib/ebin/binary.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/c.beam b/bootstrap/lib/stdlib/ebin/c.beam
index 5bdce4fc48..5a69b635cb 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/calendar.beam b/bootstrap/lib/stdlib/ebin/calendar.beam
index 6e6c77b3c0..ca9e73c245 100644
--- a/bootstrap/lib/stdlib/ebin/calendar.beam
+++ b/bootstrap/lib/stdlib/ebin/calendar.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/dets.beam b/bootstrap/lib/stdlib/ebin/dets.beam
index b83b604c5e..586b0c35cd 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 07d44a322f..de315c0517 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_sup.beam b/bootstrap/lib/stdlib/ebin/dets_sup.beam
index 29bed64d7c..34732d5a99 100644
--- a/bootstrap/lib/stdlib/ebin/dets_sup.beam
+++ b/bootstrap/lib/stdlib/ebin/dets_sup.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/dets_utils.beam b/bootstrap/lib/stdlib/ebin/dets_utils.beam
index 1700ef5738..576992c128 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 1df7208cf8..55e37c99a4 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/dict.beam b/bootstrap/lib/stdlib/ebin/dict.beam
index e9970e878b..0c38ee1717 100644
--- a/bootstrap/lib/stdlib/ebin/dict.beam
+++ b/bootstrap/lib/stdlib/ebin/dict.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/digraph.beam b/bootstrap/lib/stdlib/ebin/digraph.beam
index 53a2364302..7b1ce6b4ce 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/digraph_utils.beam b/bootstrap/lib/stdlib/ebin/digraph_utils.beam
index 5bb6250241..2b82c5f2d9 100644
--- a/bootstrap/lib/stdlib/ebin/digraph_utils.beam
+++ b/bootstrap/lib/stdlib/ebin/digraph_utils.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/edlin.beam b/bootstrap/lib/stdlib/ebin/edlin.beam
index af842aba99..dbc9a668b0 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 1636da3701..f79a4044e6 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 f53cb974b3..5fc1d337bb 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_abstract_code.beam b/bootstrap/lib/stdlib/ebin/erl_abstract_code.beam
new file mode 100644
index 0000000000..83f5ceac01
--- /dev/null
+++ b/bootstrap/lib/stdlib/ebin/erl_abstract_code.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/erl_anno.beam b/bootstrap/lib/stdlib/ebin/erl_anno.beam
index 20ce3494a5..212fe27e28 100644
--- a/bootstrap/lib/stdlib/ebin/erl_anno.beam
+++ b/bootstrap/lib/stdlib/ebin/erl_anno.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/erl_bits.beam b/bootstrap/lib/stdlib/ebin/erl_bits.beam
index 8c15ac2c30..794162a95e 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 ef2c7548fe..07f78c8599 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_eval.beam b/bootstrap/lib/stdlib/ebin/erl_eval.beam
index 1f2f215397..a15d6d1b39 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 933bce5ada..e38a940352 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_internal.beam b/bootstrap/lib/stdlib/ebin/erl_internal.beam
index dd329206b4..7f4519c7b7 100644
--- a/bootstrap/lib/stdlib/ebin/erl_internal.beam
+++ b/bootstrap/lib/stdlib/ebin/erl_internal.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/erl_lint.beam b/bootstrap/lib/stdlib/ebin/erl_lint.beam
index a41622fe49..641183b959 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_parse.beam b/bootstrap/lib/stdlib/ebin/erl_parse.beam
index ea9534fe0a..ad45f99496 100644
--- a/bootstrap/lib/stdlib/ebin/erl_parse.beam
+++ b/bootstrap/lib/stdlib/ebin/erl_parse.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/erl_posix_msg.beam b/bootstrap/lib/stdlib/ebin/erl_posix_msg.beam
index 65c04825be..d2be4727e1 100644
--- a/bootstrap/lib/stdlib/ebin/erl_posix_msg.beam
+++ b/bootstrap/lib/stdlib/ebin/erl_posix_msg.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/erl_pp.beam b/bootstrap/lib/stdlib/ebin/erl_pp.beam
index e95c141a83..19e5fb932b 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 45d37ec838..608d8c2788 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 ba71ea136b..bcb8a3aa72 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 bb7b78a690..78dfc523b2 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 59accf7f51..9c913ce5fb 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 f14e21ac6e..1411e99456 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 20b89a952a..935a132190 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 bb0df11a28..ecfedab133 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 99e195f664..182eb8d648 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 23487969dd..733b60a71d 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 91eeb2cb90..516ec1fcdd 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/gb_sets.beam b/bootstrap/lib/stdlib/ebin/gb_sets.beam
index 04c8ca9997..2e1a95b10c 100644
--- a/bootstrap/lib/stdlib/ebin/gb_sets.beam
+++ b/bootstrap/lib/stdlib/ebin/gb_sets.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/gb_trees.beam b/bootstrap/lib/stdlib/ebin/gb_trees.beam
index 3240e162bc..ea9d7c7a66 100644
--- a/bootstrap/lib/stdlib/ebin/gb_trees.beam
+++ b/bootstrap/lib/stdlib/ebin/gb_trees.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/gen.beam b/bootstrap/lib/stdlib/ebin/gen.beam
index 7b7a373d7c..8f36971bb5 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 6984704d22..aa01da81eb 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 29ef47b629..bb6263a6db 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 1cebc6084e..f4fd0c415c 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 27be2c302a..46e42828ea 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 6cf3a1f177..5ac3d1f069 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.beam b/bootstrap/lib/stdlib/ebin/io_lib.beam
index f0bde71883..83087d9746 100644
--- a/bootstrap/lib/stdlib/ebin/io_lib.beam
+++ b/bootstrap/lib/stdlib/ebin/io_lib.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/io_lib_format.beam b/bootstrap/lib/stdlib/ebin/io_lib_format.beam
index 55c85df1bd..dacf78ecf3 100644
--- a/bootstrap/lib/stdlib/ebin/io_lib_format.beam
+++ b/bootstrap/lib/stdlib/ebin/io_lib_format.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/io_lib_fread.beam b/bootstrap/lib/stdlib/ebin/io_lib_fread.beam
index 777e3e9b06..8be41c8861 100644
--- a/bootstrap/lib/stdlib/ebin/io_lib_fread.beam
+++ b/bootstrap/lib/stdlib/ebin/io_lib_fread.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 5dd445c5d6..b0756eecdf 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/lib.beam b/bootstrap/lib/stdlib/ebin/lib.beam
index a60c9af6b4..eae6ea3246 100644
--- a/bootstrap/lib/stdlib/ebin/lib.beam
+++ b/bootstrap/lib/stdlib/ebin/lib.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/lists.beam b/bootstrap/lib/stdlib/ebin/lists.beam
index 1278758a58..3331a5808b 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 f25858537b..f305ba99f5 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/maps.beam b/bootstrap/lib/stdlib/ebin/maps.beam
index d405932b1d..3a0fa8ec1d 100644
--- a/bootstrap/lib/stdlib/ebin/maps.beam
+++ b/bootstrap/lib/stdlib/ebin/maps.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/math.beam b/bootstrap/lib/stdlib/ebin/math.beam
index 40ed5460ce..de17278918 100644
--- a/bootstrap/lib/stdlib/ebin/math.beam
+++ b/bootstrap/lib/stdlib/ebin/math.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/ms_transform.beam b/bootstrap/lib/stdlib/ebin/ms_transform.beam
index eff213fcf4..1214b3591b 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/orddict.beam b/bootstrap/lib/stdlib/ebin/orddict.beam
index bcf62fef7b..1fc4685614 100644
--- a/bootstrap/lib/stdlib/ebin/orddict.beam
+++ b/bootstrap/lib/stdlib/ebin/orddict.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/ordsets.beam b/bootstrap/lib/stdlib/ebin/ordsets.beam
index 9e05e9d729..736605b90f 100644
--- a/bootstrap/lib/stdlib/ebin/ordsets.beam
+++ b/bootstrap/lib/stdlib/ebin/ordsets.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/otp_internal.beam b/bootstrap/lib/stdlib/ebin/otp_internal.beam
index 04ede72f53..7302587303 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/pool.beam b/bootstrap/lib/stdlib/ebin/pool.beam
index ca7c91cd1f..da31679d1f 100644
--- a/bootstrap/lib/stdlib/ebin/pool.beam
+++ b/bootstrap/lib/stdlib/ebin/pool.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/proc_lib.beam b/bootstrap/lib/stdlib/ebin/proc_lib.beam
index 781a4f7eb3..25eb3b652d 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/proplists.beam b/bootstrap/lib/stdlib/ebin/proplists.beam
index e566d3a985..d0496eb80f 100644
--- a/bootstrap/lib/stdlib/ebin/proplists.beam
+++ b/bootstrap/lib/stdlib/ebin/proplists.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/qlc.beam b/bootstrap/lib/stdlib/ebin/qlc.beam
index 400837a60f..7015c6fed8 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 9b8be5280a..74f933fb47 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/queue.beam b/bootstrap/lib/stdlib/ebin/queue.beam
index 544b34922c..5a2cd23b83 100644
--- a/bootstrap/lib/stdlib/ebin/queue.beam
+++ b/bootstrap/lib/stdlib/ebin/queue.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/rand.beam b/bootstrap/lib/stdlib/ebin/rand.beam
index 8f09b8c509..c8a6a97976 100644
--- a/bootstrap/lib/stdlib/ebin/rand.beam
+++ b/bootstrap/lib/stdlib/ebin/rand.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/random.beam b/bootstrap/lib/stdlib/ebin/random.beam
index fa572500b4..0073fc5281 100644
--- a/bootstrap/lib/stdlib/ebin/random.beam
+++ b/bootstrap/lib/stdlib/ebin/random.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/re.beam b/bootstrap/lib/stdlib/ebin/re.beam
index b133cbb0f2..7de890492f 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/sets.beam b/bootstrap/lib/stdlib/ebin/sets.beam
index 9d7af9104a..2cc06fb919 100644
--- a/bootstrap/lib/stdlib/ebin/sets.beam
+++ b/bootstrap/lib/stdlib/ebin/sets.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/shell.beam b/bootstrap/lib/stdlib/ebin/shell.beam
index 1a3e3c67b5..8c2451e74f 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/shell_default.beam b/bootstrap/lib/stdlib/ebin/shell_default.beam
index be0490f286..0d4e21e544 100644
--- a/bootstrap/lib/stdlib/ebin/shell_default.beam
+++ b/bootstrap/lib/stdlib/ebin/shell_default.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/slave.beam b/bootstrap/lib/stdlib/ebin/slave.beam
index 0b007135c0..cb606a0736 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 a03c98f7bf..8ef3635454 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/stdlib.app b/bootstrap/lib/stdlib/ebin/stdlib.app
index c5bdcf4eaa..ed73fa6985 100644
--- a/bootstrap/lib/stdlib/ebin/stdlib.app
+++ b/bootstrap/lib/stdlib/ebin/stdlib.app
@@ -39,6 +39,7 @@
edlin_expand,
epp,
eval_bits,
+ erl_abstract_code,
erl_anno,
erl_bits,
erl_compile,
@@ -99,6 +100,7 @@
sys,
timer,
unicode,
+ unicode_util,
win32reg,
zip]},
{registered,[timer_server,rsh_starter,take_over_monitor,pool_master,
diff --git a/bootstrap/lib/stdlib/ebin/string.beam b/bootstrap/lib/stdlib/ebin/string.beam
index f141044d21..65fb114b50 100644
--- a/bootstrap/lib/stdlib/ebin/string.beam
+++ b/bootstrap/lib/stdlib/ebin/string.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/supervisor.beam b/bootstrap/lib/stdlib/ebin/supervisor.beam
index f2f4f3fd68..e11d7c9375 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 69aec60291..a6019f18af 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 6855ce434d..de5443003f 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 d6af12921a..a1803b06b5 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 9d0258c79a..d58ad7564e 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
new file mode 100644
index 0000000000..3251926a9c
--- /dev/null
+++ b/bootstrap/lib/stdlib/ebin/unicode_util.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/win32reg.beam b/bootstrap/lib/stdlib/ebin/win32reg.beam
index 5e90246722..289ca96f59 100644
--- a/bootstrap/lib/stdlib/ebin/win32reg.beam
+++ b/bootstrap/lib/stdlib/ebin/win32reg.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/zip.beam b/bootstrap/lib/stdlib/ebin/zip.beam
index 394b4f9a8a..09f873d8fa 100644
--- a/bootstrap/lib/stdlib/ebin/zip.beam
+++ b/bootstrap/lib/stdlib/ebin/zip.beam
Binary files differ
diff --git a/configure.in b/configure.in
index 229d77863f..559049aca1 100644
--- a/configure.in
+++ b/configure.in
@@ -207,16 +207,12 @@ AC_MSG_CHECKING([OTP version])
AC_MSG_RESULT([$OTP_VSN])
AC_SUBST(OTP_VSN)
-AC_ARG_ENABLE(threads,
-AS_HELP_STRING([--enable-threads], [enable async thread support])
-AS_HELP_STRING([--disable-threads], [disable async thread support]))
-
AC_ARG_ENABLE(dirty-schedulers,
AS_HELP_STRING([--enable-dirty-schedulers], [enable dirty scheduler support]))
-AC_ARG_ENABLE(smp-support,
-AS_HELP_STRING([--enable-smp-support], [enable smp support])
-AS_HELP_STRING([--disable-smp-support], [disable smp support]))
+AC_ARG_ENABLE(plain-emulator,
+AS_HELP_STRING([--enable-plain-emulator], [enable threaded non-smp emulator])
+AS_HELP_STRING([--disable-plain-emulator], [disable threaded non-smp emulator]))
AC_ARG_WITH(termcap,
AS_HELP_STRING([--with-termcap], [use termcap (default)])
diff --git a/erts/Makefile.in b/erts/Makefile
index 3052dc3065..3fe567b7d5 100644
--- a/erts/Makefile.in
+++ b/erts/Makefile
@@ -20,9 +20,9 @@
.NOTPARALLEL:
-include $(ERL_TOP)/make/output.mk
include $(ERL_TOP)/make/target.mk
include vsn.mk
+include $(ERL_TOP)/make/$(TARGET)/otp.mk
# ----------------------------------------------------------------------
@@ -33,10 +33,8 @@ ifeq ($(NO_START_SCRIPTS),)
ERTSDIRS += start_scripts
endif
-EXTRA_FLAVORS=smp
-
.PHONY: all
-all: smp opt
+all: $(FLAVORS)
.PHONY: docs
docs:
@@ -56,9 +54,9 @@ debug opt clean:
# - don't use them in scripts or assume they will always stay like this!
#
-.PHONY: $(EXTRA_FLAVORS)
-$(EXTRA_FLAVORS):
- $(V_at)( cd emulator && $(MAKE) opt FLAVOR=$@ )
+.PHONY: $(FLAVORS)
+$(FLAVORS):
+ $(V_at)( $(MAKE) opt FLAVOR=$@ )
# Make erl script and erlc in $(ERL_TOP)/bin which runs the compiled version
# Note that erlc is not a script and requires extra handling on cygwin.
@@ -129,7 +127,7 @@ makefiles:
.PHONY: release
release:
- $(V_at)for f in plain $(EXTRA_FLAVORS) ; do \
+ $(V_at)for f in $(FLAVORS); do \
( cd emulator && $(MAKE) release FLAVOR=$$f ) \
done
$(V_at)for d in $(ERTSDIRS) $(XINSTDIRS); do \
diff --git a/erts/configure.in b/erts/configure.in
index b488ba9171..9ab5b4cfd2 100644
--- a/erts/configure.in
+++ b/erts/configure.in
@@ -154,6 +154,14 @@ AS_HELP_STRING([--disable-smp-support], [disable smp support]),
*) enable_smp_support=yes ;;
esac ], enable_smp_support=unknown)
+AC_ARG_ENABLE(plain-emulator,
+AS_HELP_STRING([--enable-plain-emulator], [enable plain emulator])
+AS_HELP_STRING([--disable-plain-emulator], [disable plain emulator]),
+[ case "$enableval" in
+ no) enable_plain_emulator=no ;;
+ *) enable_plain_emulator=yes ;;
+ esac ], enable_plain_emulator=unknown)
+
AC_ARG_ENABLE(smp-require-native-atomics,
AS_HELP_STRING([--disable-smp-require-native-atomics],
[disable the SMP requirement of a native atomic implementation]),
@@ -993,7 +1001,7 @@ else
found_threads=yes
fi
-
+FLAVORS=
ERTS_BUILD_SMP_EMU=$enable_smp_support
AC_MSG_CHECKING(whether an emulator with smp support should be built)
case $ERTS_BUILD_SMP_EMU in
@@ -1078,6 +1086,9 @@ EOF
if test $ERTS_BUILD_SMP_EMU = yes; then
+ DEFAULT_FLAVOR=smp
+ FLAVORS="$FLAVORS smp"
+
if test $found_threads = no; then
AC_MSG_ERROR([cannot build smp enabled emulator since no thread library was found])
fi
@@ -1153,6 +1164,66 @@ fi
AC_SUBST(ERTS_BUILD_SMP_EMU)
+ERTS_BUILD_PLAIN_EMU=$enable_plain_emulator
+AC_MSG_CHECKING(whether an emulator without smp support should be built)
+case $ERTS_BUILD_PLAIN_EMU in
+ yes)
+ AC_MSG_RESULT(yes; enabled by user)
+ ;;
+ no)
+ AC_MSG_RESULT(no; disabled by user)
+ ;;
+ unknown)
+ case "$enable_threads-$ERTS_BUILD_SMP_EMU" in
+ no-*)
+ ERTS_BUILD_PLAIN_EMU=yes
+ AC_MSG_RESULT(yes)
+ ;;
+ *-no)
+ ERTS_BUILD_PLAIN_EMU=yes
+ AC_MSG_RESULT(yes; enabled as smp emulator was disabled)
+ ;;
+ *)
+ ERTS_BUILD_PLAIN_EMU=no
+ AC_MSG_RESULT(no)
+ ;;
+ esac
+ ;;
+esac
+
+case $ERTS_BUILD_PLAIN_EMU in
+ yes)
+ AC_DEFINE(ERTS_HAVE_PLAIN_EMU, 1, [Define if the non-smp emulator is built])
+ FLAVORS="$FLAVORS plain"
+ test -f "$ERL_TOP/erts/CONF_INFO" || echo "" > "$ERL_TOP/erts/CONF_INFO"
+ cat >> $ERL_TOP/erts/CONF_INFO <<EOF
+
+ The PLAIN aka NON-SMP emulator has been enabled.
+ This is a DEPRECATED feature scheduled for removal
+ in a future major release.
+
+EOF
+ ;;
+ no)
+ ;;
+esac
+
+AC_SUBST(ERTS_BUILD_PLAIN_EMU)
+AC_SUBST(FLAVORS)
+
+case "$ERTS_BUILD_PLAIN_EMU-$ERTS_BUILD_SMP_EMU" in
+ no-no)
+ AC_MSG_ERROR([both smp and non-smp emulators have been disabled, one of them has to be enabled])
+ ;;
+ *-no)
+ DEFAULT_FLAVOR=plain
+ ;;
+ *)
+ ;;
+esac
+
+AC_SUBST(DEFAULT_FLAVOR)
+
AC_CHECK_FUNCS([posix_fadvise closefrom])
AC_CHECK_HEADERS([linux/falloc.h])
dnl * Old glibcs have broken fallocate64(). Make sure not to use it.
@@ -4953,7 +5024,6 @@ AC_CONFIG_FILES([
include/internal/$host/ethread.mk:include/internal/ethread.mk.in
include/internal/$host/erts_internal.mk:include/internal/erts_internal.mk.in
lib_src/$host/Makefile:lib_src/Makefile.in
- Makefile:Makefile.in
../make/$host/otp.mk:../make/otp.mk.in
../make/$host/otp_ded.mk:../make/otp_ded.mk.in
])
diff --git a/erts/doc/src/erl.xml b/erts/doc/src/erl.xml
index 29fef7348b..ef8126e86f 100644
--- a/erts/doc/src/erl.xml
+++ b/erts/doc/src/erl.xml
@@ -513,11 +513,11 @@
system with SMP support is available. <c>-smp auto</c> starts
the Erlang runtime system with SMP support enabled if it is
available and more than one logical processor is detected.
- <c>-smp disable</c> starts a runtime system without SMP support.</p>
+ <c>-smp disable</c> starts a runtime system without SMP support.
+ The runtime system without SMP support is deprecated and will
+ be removed in a future major release.</p>
<note>
- <p>The runtime system with SMP support is not available on all
- supported platforms. See also flag
- <seealso marker="#+S"><c>+S</c></seealso>.</p>
+ <p>See also flag<seealso marker="#+S"><c>+S</c></seealso>.</p>
</note>
</item>
<tag><c><![CDATA[-version]]></c> (emulator flag)</tag>
@@ -1318,8 +1318,22 @@
<c><![CDATA[+sss size]]></c></tag>
<item>
<p>Suggested stack size, in kilowords, for scheduler threads.
- Valid range is 4-8192 kilowords. The default stack size is
- OS-dependent.</p>
+ Valid range is 20-8192 kilowords. The default suggested
+ stack size is 128 kilowords.</p>
+ </item>
+ <tag><marker id="dcpu_sched_thread_stack_size"/>
+ <c><![CDATA[+sssdcpu size]]></c></tag>
+ <item>
+ <p>Suggested stack size, in kilowords, for dirty CPU scheduler
+ threads. Valid range is 20-8192 kilowords. The default
+ suggested stack size is 40 kilowords.</p>
+ </item>
+ <tag><marker id="dio_sched_thread_stack_size"/>
+ <c><![CDATA[+sssdio size]]></c></tag>
+ <item>
+ <p>Suggested stack size, in kilowords, for dirty IO scheduler
+ threads. Valid range is 20-8192 kilowords. The default
+ suggested stack size is 40 kilowords.</p>
</item>
<tag><marker id="+stbt"/><c>+stbt BindType</c></tag>
<item>
diff --git a/erts/doc/src/erlang.xml b/erts/doc/src/erlang.xml
index cb2cdec606..a26a695f2e 100644
--- a/erts/doc/src/erlang.xml
+++ b/erts/doc/src/erlang.xml
@@ -2499,6 +2499,42 @@ os_prompt%</pre>
</func>
<func>
+ <name name="list_to_port" arity="1"/>
+ <fsummary>Convert from text representation to a port.</fsummary>
+ <desc>
+ <p>Returns a port identifier whose text representation is a
+ <c><anno>String</anno></c>, for example:</p>
+ <pre>
+> <input>list_to_port("#Port&lt;0.4>").</input>
+#Port&lt;0.4></pre>
+ <p>Failure: <c>badarg</c> if <c><anno>String</anno></c> contains a bad
+ representation of a port identifier.</p>
+ <warning>
+ <p>This BIF is intended for debugging and is not to be used
+ in application programs.</p>
+ </warning>
+ </desc>
+ </func>
+
+ <func>
+ <name name="list_to_ref" arity="1"/>
+ <fsummary>Convert from text representation to a ref.</fsummary>
+ <desc>
+ <p>Returns a reference whose text representation is a
+ <c><anno>String</anno></c>, for example:</p>
+ <pre>
+> <input>list_to_ref("#Ref&lt;0.4192537678.4073193475.71181>").</input>
+#Ref&lt;0.4192537678.4073193475.71181></pre>
+ <p>Failure: <c>badarg</c> if <c><anno>String</anno></c> contains a bad
+ representation of a reference.</p>
+ <warning>
+ <p>This BIF is intended for debugging and is not to be used
+ in application programs.</p>
+ </warning>
+ </desc>
+ </func>
+
+ <func>
<name name="list_to_tuple" arity="1"/>
<fsummary>Convert a list to a tuple.</fsummary>
<desc>
diff --git a/erts/emulator/Makefile.in b/erts/emulator/Makefile.in
index 7ea0111e59..227aabcf1e 100644
--- a/erts/emulator/Makefile.in
+++ b/erts/emulator/Makefile.in
@@ -175,7 +175,23 @@ endif
# NOTE: When adding a new type update ERL_BUILD_TYPE_MARKER in sys/unix/sys.c
#
-ifeq ($(FLAVOR),smp)
+FLAVOR=$(DEFAULT_FLAVOR)
+
+ifeq ($(FLAVOR),plain)
+
+DS_SUPPORT=no
+DS_TEST=no
+
+FLAVOR_MARKER=
+FLAVOR_FLAGS=
+ENABLE_ALLOC_TYPE_VARS += nofrag
+M4FLAGS +=
+
+else # FLAVOR
+
+# If flavor isn't one of the above, it *is* smp flavor...
+override FLAVOR=smp
+
FLAVOR_MARKER=.smp
FLAVOR_FLAGS=-DERTS_SMP
ENABLE_ALLOC_TYPE_VARS += smp nofrag
@@ -196,30 +212,15 @@ DS_SUPPORT=no
DS_TEST=no
endif # DIRTY_SCHEDULER_SUPPORT
-else # FLAVOR
-
-DS_SUPPORT=no
-DS_TEST=no
-
-# If flavor isn't one of the above, it *is* plain flavor...
-override FLAVOR=plain
-FLAVOR_MARKER=
-FLAVOR_FLAGS=
-ENABLE_ALLOC_TYPE_VARS += nofrag
-M4FLAGS +=
-endif
+endif # FLAVOR
TF_MARKER=$(TYPEMARKER)$(FLAVOR_MARKER)
-ifeq ($(FLAVOR)-@ERTS_BUILD_SMP_EMU@,smp-no)
-VOID_EMULATOR = '*** SMP emulator disabled by configure'
-else
ifeq ($(TYPE)-@HAVE_VALGRIND@,valgrind-no)
VOID_EMULATOR = '*** valgrind emulator disabled by configure'
else
VOID_EMULATOR =
endif
-endif
OPSYS=@OPSYS@
sol2CFLAGS=
diff --git a/erts/emulator/beam/beam_bif_load.c b/erts/emulator/beam/beam_bif_load.c
index 4ba8c2a669..769fe89219 100644
--- a/erts/emulator/beam/beam_bif_load.c
+++ b/erts/emulator/beam/beam_bif_load.c
@@ -233,7 +233,7 @@ prepare_loading_2(BIF_ALIST_2)
}
hp = HAlloc(BIF_P, ERTS_MAGIC_REF_THING_SIZE);
res = erts_mk_magic_ref(&hp, &MSO(BIF_P), magic);
- erts_refc_dec(&magic->refc, 1);
+ erts_refc_dec(&magic->intern.refc, 1);
BIF_RET(res);
}
@@ -435,7 +435,7 @@ finish_loading_1(BIF_ALIST_1)
Eterm mod;
Eterm retval;
- erts_refc_inc(&p[i].code->refc, 1);
+ erts_refc_inc(&p[i].code->intern.refc, 1);
retval = erts_finish_loading(p[i].code, BIF_P, 0, &mod);
ASSERT(retval == NIL || retval == am_on_load);
if (retval == am_on_load) {
diff --git a/erts/emulator/beam/beam_bp.c b/erts/emulator/beam/beam_bp.c
index b32c74ce7a..1efe7536d6 100644
--- a/erts/emulator/beam/beam_bp.c
+++ b/erts/emulator/beam/beam_bp.c
@@ -327,7 +327,7 @@ erts_consolidate_bif_bp_data(void)
static void
consolidate_bp_data(Module* modp, ErtsCodeInfo *ci, int local)
{
- GenericBp* g = (GenericBp *) ci->native;
+ GenericBp* g = ci->u.gen_bp;
GenericBpData* src;
GenericBpData* dst;
Uint flags;
@@ -376,7 +376,7 @@ consolidate_bp_data(Module* modp, ErtsCodeInfo *ci, int local)
ASSERT(*erts_codeinfo_to_code(ci) !=
(BeamInstr) BeamOp(op_i_generic_breakpoint));
}
- ci->native = 0;
+ ci->u.gen_bp = NULL;
Free(g);
return;
}
@@ -427,7 +427,7 @@ erts_install_breakpoints(BpFunctions* f)
for (i = 0; i < n; i++) {
ErtsCodeInfo* ci = f->matching[i].ci;
BeamInstr *pc = erts_codeinfo_to_code(ci);
- GenericBp* g = (GenericBp *) ci->native;
+ GenericBp* g = ci->u.gen_bp;
if (*pc != br && g) {
Module* modp = f->matching[i].mod;
@@ -468,7 +468,7 @@ uninstall_breakpoint(ErtsCodeInfo *ci)
{
BeamInstr *pc = erts_codeinfo_to_code(ci);
if (*pc == (BeamInstr) BeamOp(op_i_generic_breakpoint)) {
- GenericBp* g = (GenericBp *) ci->native;
+ GenericBp* g = ci->u.gen_bp;
if (g->data[erts_active_bp_ix()].flags == 0) {
/*
* The following write is not protected by any lock. We
@@ -549,7 +549,7 @@ erts_clear_trace_break(BpFunctions* f)
void
erts_clear_call_trace_bif(ErtsCodeInfo *ci, int local)
{
- GenericBp* g = (GenericBp *) ci->native;
+ GenericBp* g = ci->u.gen_bp;
if (g) {
Uint flags = local ? ERTS_BPF_LOCAL_TRACE : ERTS_BPF_GLOBAL_TRACE;
@@ -624,7 +624,7 @@ erts_clear_module_break(Module *modp) {
continue;
uninstall_breakpoint(ci);
consolidate_bp_data(modp, ci, 1);
- ASSERT(ci->native == 0);
+ ASSERT(ci->u.gen_bp == NULL);
}
return n;
}
@@ -638,7 +638,7 @@ erts_clear_export_break(Module* modp, ErtsCodeInfo *ci)
erts_commit_staged_bp();
*erts_codeinfo_to_code(ci) = (BeamInstr) 0;
consolidate_bp_data(modp, ci, 0);
- ASSERT(ci->native == 0);
+ ASSERT(ci->u.gen_bp == NULL);
}
BeamInstr
@@ -651,7 +651,7 @@ erts_generic_breakpoint(Process* c_p, ErtsCodeInfo *info, Eterm* reg)
ASSERT(info->op == (BeamInstr) BeamOp(op_i_func_info_IaaI));
- g = (GenericBp *) info->native;
+ g = info->u.gen_bp;
bp = &g->data[ix];
bp_flags = bp->flags;
ASSERT((bp_flags & ~ERTS_BPF_ALL) == 0);
@@ -754,7 +754,7 @@ erts_bif_trace(int bif_index, Process* p, Eterm* args, BeamInstr* I)
ERTS_SMP_CHK_HAVE_ONLY_MAIN_PROC_LOCK(p);
- g = (GenericBp *) ep->info.native;
+ g = ep->info.u.gen_bp;
if (g) {
bp = &g->data[erts_active_bp_ix()];
bp_flags = bp->flags;
@@ -1511,7 +1511,7 @@ set_function_break(ErtsCodeInfo *ci, Binary *match_spec, Uint break_flags,
ErtsBpIndex ix = erts_staging_bp_ix();
ERTS_SMP_LC_ASSERT(erts_has_code_write_permission());
- g = (GenericBp *) ci->native;
+ g = ci->u.gen_bp;
if (g == 0) {
int i;
if (count_op == ERTS_BREAK_RESTART || count_op == ERTS_BREAK_PAUSE) {
@@ -1523,7 +1523,7 @@ set_function_break(ErtsCodeInfo *ci, Binary *match_spec, Uint break_flags,
for (i = 0; i < ERTS_NUM_BP_IX; i++) {
g->data[i].flags = 0;
}
- ci->native = (BeamInstr) g;
+ ci->u.gen_bp = g;
}
bp = &g->data[ix];
@@ -1633,7 +1633,7 @@ clear_function_break(ErtsCodeInfo *ci, Uint break_flags)
ERTS_SMP_LC_ASSERT(erts_has_code_write_permission());
- if ((g = (GenericBp *) ci->native) == 0) {
+ if ((g = ci->u.gen_bp) == NULL) {
return 1;
}
@@ -1728,7 +1728,7 @@ get_time_break(ErtsCodeInfo *ci)
static GenericBpData*
check_break(ErtsCodeInfo *ci, Uint break_flags)
{
- GenericBp* g = (GenericBp *) ci->native;
+ GenericBp* g = ci->u.gen_bp;
ASSERT(ci->op == (BeamInstr) BeamOp(op_i_func_info_IaaI));
if (erts_is_native_break(ci)) {
diff --git a/erts/emulator/beam/beam_emu.c b/erts/emulator/beam/beam_emu.c
index 6010c17c17..3d36094e07 100644
--- a/erts/emulator/beam/beam_emu.c
+++ b/erts/emulator/beam/beam_emu.c
@@ -3887,7 +3887,6 @@ do { \
* Allocate the binary struct itself.
*/
bptr = erts_bin_nrml_alloc(num_bytes);
- erts_refc_init(&bptr->refc, 1);
erts_current_bin = (byte *) bptr->orig_bytes;
/*
@@ -3982,7 +3981,6 @@ do { \
* Allocate the binary struct itself.
*/
bptr = erts_bin_nrml_alloc(BsOp1);
- erts_refc_init(&bptr->refc, 1);
erts_current_bin = (byte *) bptr->orig_bytes;
/*
@@ -4950,14 +4948,14 @@ do { \
*/
ErtsCodeInfo *ci = erts_code_to_codeinfo(I);
ASSERT(ci->op == (Uint) OpCode(i_func_info_IaaI));
- c_p->hipe.u.ncallee = (void(*)(void)) ci->native;
+ c_p->hipe.u.ncallee = ci->u.ncallee;
++hipe_trap_count;
HIPE_MODE_SWITCH(HIPE_MODE_SWITCH_CMD_CALL | (ci->mfa.arity << 8));
}
OpCase(hipe_trap_call_closure): {
ErtsCodeInfo *ci = erts_code_to_codeinfo(I);
ASSERT(ci->op == (Uint) OpCode(i_func_info_IaaI));
- c_p->hipe.u.ncallee = (void(*)(void)) ci->native;
+ c_p->hipe.u.ncallee = ci->u.ncallee;
++hipe_trap_count;
HIPE_MODE_SWITCH(HIPE_MODE_SWITCH_CMD_CALL_CLOSURE | (ci->mfa.arity << 8));
}
@@ -5029,7 +5027,7 @@ do { \
* ... remainder of original BEAM code
*/
ErtsCodeInfo *ci = erts_code_to_codeinfo(I);
- struct hipe_call_count *hcc = (struct hipe_call_count*)ci->native;
+ struct hipe_call_count *hcc = ci->u.hcc;
ASSERT(ci->op == (Uint) OpCode(i_func_info_IaaI));
ASSERT(hcc != NULL);
ASSERT(VALID_INSTR(hcc->opcode));
diff --git a/erts/emulator/beam/beam_load.c b/erts/emulator/beam/beam_load.c
index 6eea963016..7b79e6303b 100644
--- a/erts/emulator/beam/beam_load.c
+++ b/erts/emulator/beam/beam_load.c
@@ -913,7 +913,7 @@ erts_alloc_loader_state(void)
magic = erts_create_magic_binary(sizeof(LoaderState),
loader_state_dtor);
- erts_refc_inc(&magic->refc, 1);
+ erts_refc_inc(&magic->intern.refc, 1);
stp = ERTS_MAGIC_BIN_DATA(magic);
stp->bin = NULL;
stp->function = THE_NON_VALUE; /* Function not known yet */
@@ -996,9 +996,7 @@ static void
free_loader_state(Binary* magic)
{
loader_state_dtor(magic);
- if (erts_refc_dectest(&magic->refc, 0) == 0) {
- erts_bin_free(magic);
- }
+ erts_bin_release(magic);
}
static ErlHeapFragment* new_literal_fragment(Uint size)
@@ -5672,9 +5670,7 @@ erts_release_literal_area(ErtsLiteralArea* literal_area)
Binary* bptr;
ASSERT(thing_subtag(oh->thing_word) == REFC_BINARY_SUBTAG);
bptr = ((ProcBin*)oh)->val;
- if (erts_refc_dectest(&bptr->refc, 0) == 0) {
- erts_bin_free(bptr);
- }
+ erts_bin_release(bptr);
oh = oh->next;
}
erts_free(ERTS_ALC_T_LITERAL, literal_area);
@@ -5708,12 +5704,13 @@ erts_is_module_native(BeamCodeHeader* code_hdr)
static Eterm
native_addresses(Process* p, BeamCodeHeader* code_hdr)
{
+ Eterm result = NIL;
+#ifdef HIPE
int i;
Eterm* hp;
Uint num_functions;
Uint need;
Eterm* hp_end;
- Eterm result = NIL;
num_functions = code_hdr->num_functions;
need = (6+BIG_UINT_HEAP_SIZE)*num_functions;
@@ -5725,16 +5722,17 @@ native_addresses(Process* p, BeamCodeHeader* code_hdr)
ASSERT(is_atom(ci->mfa.function)
|| is_nil(ci->mfa.function)); /* [] if BIF stub */
- if (ci->native != 0) {
+ if (ci->u.ncallee != NULL) {
Eterm addr;
ASSERT(is_atom(ci->mfa.function));
- addr = erts_bld_uint(&hp, NULL, ci->native);
+ addr = erts_bld_uint(&hp, NULL, (Uint)ci->u.ncallee);
tuple = erts_bld_tuple(&hp, NULL, 3, ci->mfa.function,
make_small(ci->mfa.arity), addr);
result = erts_bld_cons(&hp, NULL, tuple, result);
}
}
HRelease(p, hp_end, hp);
+#endif
return result;
}
@@ -6033,7 +6031,7 @@ make_stub(ErtsCodeInfo* info, Eterm mod, Eterm func, Uint arity, Uint native, Be
DBG_TRACE_MFA(mod,func,arity,"make beam stub at %p", erts_codeinfo_to_code(info));
ASSERT(WORDS_PER_FUNCTION == 6);
info->op = (BeamInstr) BeamOp(op_i_func_info_IaaI);
- info->native = native;
+ info->u.ncallee = (void (*)(void)) native;
info->mfa.module = mod;
info->mfa.function = func;
info->mfa.arity = arity;
@@ -6104,7 +6102,7 @@ stub_final_touch(LoaderState* stp, ErtsCodeInfo* ci)
Lambda* lp;
if (is_bif(ci->mfa.module, ci->mfa.function, ci->mfa.arity)) {
- ci->native = 0;
+ ci->u.ncallee = NULL;
ci->mfa.module = 0;
ci->mfa.function = 0;
ci->mfa.arity = 0;
@@ -6267,16 +6265,7 @@ patch_funentries(Eterm Patchlist)
fe = erts_get_fun_entry(Mod, uniq, index);
fe->native_address = (Uint *)native_address;
- /* Deliberate MEMORY LEAK of native fun entries!!!
- *
- * Uncomment line below when hipe code upgrade and purging works correctly.
- * Today we may get cases when old (leaked) native code of a purged module
- * gets called and tries to create instances of a deleted fun entry.
- *
- * Reproduced on a debug emulator with stdlib_test/qlc_SUITE:join_merge
- *
- * erts_smp_refc_dec(&fe->refc, 1);
- */
+ erts_smp_refc_dec(&fe->refc, 1);
if (!patch(Addresses, (Uint) fe))
return 0;
diff --git a/erts/emulator/beam/bif.c b/erts/emulator/beam/bif.c
index 075909a881..84c9f9d7c4 100644
--- a/erts/emulator/beam/bif.c
+++ b/erts/emulator/beam/bif.c
@@ -4254,6 +4254,75 @@ BIF_RETTYPE list_to_pid_1(BIF_ALIST_1)
BIF_ERROR(BIF_P, BADARG);
}
+BIF_RETTYPE list_to_port_1(BIF_ALIST_1)
+{
+ /*
+ * A valid port identifier is on the format
+ * "#Port<N.P>" where N is node and P is
+ * the port id. Both N and P are of type Uint32.
+ */
+ Uint32 n, p;
+ char* cp;
+ int i;
+ DistEntry *dep = NULL;
+ char buf[6 /* #Port< */
+ + (2)*(10 + 1) /* N.P> */
+ + 1 /* \0 */];
+
+ /* walk down the list and create a C string */
+ if ((i = intlist_to_buf(BIF_ARG_1, buf, sizeof(buf)-1)) < 0)
+ goto bad;
+
+ buf[i] = '\0'; /* null terminal */
+
+ cp = &buf[0];
+ if (strncmp("#Port<", cp, 6) != 0)
+ goto bad;
+
+ cp += 6; /* strlen("#Port<") */
+
+ if (sscanf(cp, "%u.%u>", &n, &p) < 2)
+ goto bad;
+
+ if (p > ERTS_MAX_PORT_NUMBER)
+ goto bad;
+
+ dep = erts_channel_no_to_dist_entry(n);
+
+ if (!dep)
+ goto bad;
+
+ if(dep == erts_this_dist_entry) {
+ erts_deref_dist_entry(dep);
+ BIF_RET(make_internal_port(p));
+ }
+ else {
+ ExternalThing *etp;
+ ErlNode *enp;
+
+ if (is_nil(dep->cid))
+ goto bad;
+
+ enp = erts_find_or_insert_node(dep->sysname, dep->creation);
+ ASSERT(enp != erts_this_node);
+
+ etp = (ExternalThing *) HAlloc(BIF_P, EXTERNAL_THING_HEAD_SIZE + 1);
+ etp->header = make_external_port_header(1);
+ etp->next = MSO(BIF_P).first;
+ etp->node = enp;
+ etp->data.ui[0] = p;
+
+ MSO(BIF_P).first = (struct erl_off_heap_header*) etp;
+ erts_deref_dist_entry(dep);
+ BIF_RET(make_external_port(etp));
+ }
+
+ bad:
+ if (dep)
+ erts_deref_dist_entry(dep);
+ BIF_ERROR(BIF_P, BADARG);
+}
+
BIF_RETTYPE list_to_ref_1(BIF_ALIST_1)
{
/*
diff --git a/erts/emulator/beam/bif.tab b/erts/emulator/beam/bif.tab
index 5aee795088..3f6d82d65c 100644
--- a/erts/emulator/beam/bif.tab
+++ b/erts/emulator/beam/bif.tab
@@ -88,6 +88,7 @@ bif erlang:list_to_binary/1
bif erlang:list_to_float/1
bif erlang:list_to_integer/1
bif erlang:list_to_pid/1
+bif erlang:list_to_port/1
bif erlang:list_to_ref/1
bif erlang:list_to_tuple/1
bif erlang:loaded/0
diff --git a/erts/emulator/beam/binary.c b/erts/emulator/beam/binary.c
index 4dd8316dad..0df6bbb289 100644
--- a/erts/emulator/beam/binary.c
+++ b/erts/emulator/beam/binary.c
@@ -84,7 +84,6 @@ new_binary(Process *p, byte *buf, Uint len)
* Allocate the binary struct itself.
*/
bptr = erts_bin_nrml_alloc(len);
- erts_refc_init(&bptr->refc, 1);
if (buf != NULL) {
sys_memcpy(bptr->orig_bytes, buf, len);
}
@@ -121,7 +120,6 @@ Eterm erts_new_mso_binary(Process *p, byte *buf, Uint len)
* Allocate the binary struct itself.
*/
bptr = erts_bin_nrml_alloc(len);
- erts_refc_init(&bptr->refc, 1);
if (buf != NULL) {
sys_memcpy(bptr->orig_bytes, buf, len);
}
diff --git a/erts/emulator/beam/break.c b/erts/emulator/beam/break.c
index 538ab0d947..e23fdb83d9 100644
--- a/erts/emulator/beam/break.c
+++ b/erts/emulator/beam/break.c
@@ -660,7 +660,7 @@ bin_check(void)
erts_printf("%p orig_size: %bpd, norefs = %bpd\n",
bp->val,
bp->val->orig_size,
- erts_refc_read(&bp->val->refc, 1));
+ erts_refc_read(&bp->val->intern.refc, 1));
}
}
if (printed) {
diff --git a/erts/emulator/beam/code_ix.h b/erts/emulator/beam/code_ix.h
index 1b451bf921..e802ad5dd7 100644
--- a/erts/emulator/beam/code_ix.h
+++ b/erts/emulator/beam/code_ix.h
@@ -80,7 +80,13 @@ typedef struct ErtsCodeMFA_ {
in ops.tab to reflect the new func_info size */
typedef struct ErtsCodeInfo_ {
BeamInstr op; /* OpCode(i_func_info) */
- BeamInstr native; /* Used by hipe and trace to store extra data */
+ union {
+ struct generic_bp* gen_bp; /* Trace breakpoint */
+#ifdef HIPE
+ void (*ncallee)(void);
+ struct hipe_call_count* hcc;
+#endif
+ }u;
ErtsCodeMFA mfa;
} ErtsCodeInfo;
diff --git a/erts/emulator/beam/copy.c b/erts/emulator/beam/copy.c
index 264ba89e8b..62c3f9520d 100644
--- a/erts/emulator/beam/copy.c
+++ b/erts/emulator/beam/copy.c
@@ -761,7 +761,7 @@ Eterm copy_struct_x(Eterm obj, Uint sz, Eterm** hpp, ErlOffHeap* off_heap, Uint
}
*argp = make_binary(hbot);
pb = (ProcBin*) hbot;
- erts_refc_inc(&pb->val->refc, 2);
+ erts_refc_inc(&pb->val->intern.refc, 2);
pb->next = off_heap->first;
pb->flags = 0;
off_heap->first = (struct erl_off_heap_header*) pb;
@@ -809,7 +809,7 @@ Eterm copy_struct_x(Eterm obj, Uint sz, Eterm** hpp, ErlOffHeap* off_heap, Uint
to->thing_word = HEADER_PROC_BIN;
to->size = real_size;
to->val = from->val;
- erts_refc_inc(&to->val->refc, 2);
+ erts_refc_inc(&to->val->intern.refc, 2);
to->bytes = from->bytes + offset;
to->next = off_heap->first;
to->flags = 0;
@@ -901,7 +901,7 @@ Eterm copy_struct_x(Eterm obj, Uint sz, Eterm** hpp, ErlOffHeap* off_heap, Uint
case REF_SUBTAG:
if (is_magic_ref_thing(objp)) {
ErtsMRefThing *mreft = (ErtsMRefThing *) objp;
- erts_refc_inc(&mreft->mb->refc, 2);
+ erts_refc_inc(&mreft->mb->intern.refc, 2);
goto L_off_heap_node_container_common;
}
/* Fall through... */
@@ -1585,7 +1585,7 @@ Uint copy_shared_perform(Eterm obj, Uint size, erts_shcopy_t *info,
while (sz-- > 0) {
*hp++ = *ptr++;
}
- erts_refc_inc(&pb->val->refc, 2);
+ erts_refc_inc(&pb->val->intern.refc, 2);
pb->next = off_heap->first;
pb->flags = 0;
off_heap->first = (struct erl_off_heap_header*) pb;
@@ -1644,7 +1644,7 @@ Uint copy_shared_perform(Eterm obj, Uint size, erts_shcopy_t *info,
to->thing_word = HEADER_PROC_BIN;
to->size = real_size;
to->val = from->val;
- erts_refc_inc(&to->val->refc, 2);
+ erts_refc_inc(&to->val->intern.refc, 2);
to->bytes = from->bytes + offset;
to->next = off_heap->first;
to->flags = 0;
@@ -1678,7 +1678,7 @@ Uint copy_shared_perform(Eterm obj, Uint size, erts_shcopy_t *info,
case REF_SUBTAG:
if (is_magic_ref_thing(ptr)) {
ErtsMRefThing *mreft = (ErtsMRefThing *) ptr;
- erts_refc_inc(&mreft->mb->refc, 2);
+ erts_refc_inc(&mreft->mb->intern.refc, 2);
goto off_heap_node_container_common;
}
/* Fall through... */
@@ -1847,7 +1847,7 @@ Eterm copy_shallow(Eterm* ptr, Uint sz, Eterm** hpp, ErlOffHeap* off_heap)
case REFC_BINARY_SUBTAG:
{
ProcBin* pb = (ProcBin *) (tp-1);
- erts_refc_inc(&pb->val->refc, 2);
+ erts_refc_inc(&pb->val->intern.refc, 2);
OH_OVERHEAD(off_heap, pb->size / sizeof(Eterm));
}
goto off_heap_common;
@@ -1882,7 +1882,7 @@ Eterm copy_shallow(Eterm* ptr, Uint sz, Eterm** hpp, ErlOffHeap* off_heap)
ErtsRefThing *rtp = (ErtsRefThing *) (tp - 1);
if (is_magic_ref_thing(rtp)) {
ErtsMRefThing *mreft = (ErtsMRefThing *) rtp;
- erts_refc_inc(&mreft->mb->refc, 2);
+ erts_refc_inc(&mreft->mb->intern.refc, 2);
goto off_heap_common;
}
/* Fall through... */
diff --git a/erts/emulator/beam/dist.c b/erts/emulator/beam/dist.c
index d1c2da9074..a1581908e5 100644
--- a/erts/emulator/beam/dist.c
+++ b/erts/emulator/beam/dist.c
@@ -629,7 +629,6 @@ alloc_dist_obuf(Uint size)
ErtsDistOutputBuf *obuf;
Uint obuf_size = sizeof(ErtsDistOutputBuf)+sizeof(byte)*(size-1);
Binary *bin = erts_bin_drv_alloc(obuf_size);
- erts_refc_init(&bin->refc, 1);
obuf = (ErtsDistOutputBuf *) &bin->orig_bytes[0];
#ifdef DEBUG
obuf->dbg_pattern = ERTS_DIST_OUTPUT_BUF_DBG_PATTERN;
@@ -643,8 +642,7 @@ free_dist_obuf(ErtsDistOutputBuf *obuf)
{
Binary *bin = ErtsDistOutputBuf2Binary(obuf);
ASSERT(obuf->dbg_pattern == ERTS_DIST_OUTPUT_BUF_DBG_PATTERN);
- if (erts_refc_dectest(&bin->refc, 0) == 0)
- erts_bin_free(bin);
+ erts_bin_release(bin);
}
static ERTS_INLINE Sint
diff --git a/erts/emulator/beam/erl_bif_binary.c b/erts/emulator/beam/erl_bif_binary.c
index 62a752d854..f79b5b6843 100644
--- a/erts/emulator/beam/erl_bif_binary.c
+++ b/erts/emulator/beam/erl_bif_binary.c
@@ -2669,7 +2669,6 @@ static BIF_RETTYPE do_binary_copy(Process *p, Eterm bin, Eterm en)
}
cbs->result = erts_bin_nrml_alloc(target_size); /* Always offheap
if trapping */
- erts_refc_init(&(cbs->result->refc), 1);
t = (byte *) cbs->result->orig_bytes; /* No offset or anything */
pos = 0;
i = 0;
diff --git a/erts/emulator/beam/erl_bif_info.c b/erts/emulator/beam/erl_bif_info.c
index 3a8687dc59..3a70c6036b 100644
--- a/erts/emulator/beam/erl_bif_info.c
+++ b/erts/emulator/beam/erl_bif_info.c
@@ -177,7 +177,7 @@ bld_bin_list(Uint **hpp, Uint *szp, ErlOffHeap* oh)
if (szp)
*szp += 4+2;
if (hpp) {
- Uint refc = (Uint) erts_refc_read(&pb->val->refc, 1);
+ Uint refc = (Uint) erts_refc_read(&pb->val->intern.refc, 1);
tuple = TUPLE3(*hpp, val, orig_size, make_small(refc));
res = CONS(*hpp + 4, tuple, res);
*hpp += 4+2;
@@ -203,7 +203,7 @@ bld_magic_ref_bin_list(Uint **hpp, Uint *szp, ErlOffHeap* oh)
if (szp)
*szp += 4+2;
if (hpp) {
- Uint refc = (Uint) erts_refc_read(&mrtp->mb->refc, 1);
+ Uint refc = (Uint) erts_refc_read(&mrtp->mb->intern.refc, 1);
tuple = TUPLE3(*hpp, val, orig_size, make_small(refc));
res = CONS(*hpp + 4, tuple, res);
*hpp += 4+2;
@@ -3984,7 +3984,7 @@ BIF_RETTYPE erts_debug_get_internal_state_1(BIF_ALIST_1)
BIF_RET(am_false);
}
bin = erts_magic_ref2bin(tp[2]);
- refc = erts_refc_read(&bin->refc, 1);
+ refc = erts_refc_read(&bin->intern.refc, 1);
bin_addr = (UWord) bin;
sz = 4;
erts_bld_uword(NULL, &sz, bin_addr);
diff --git a/erts/emulator/beam/erl_bif_trace.c b/erts/emulator/beam/erl_bif_trace.c
index f471390501..023bfca797 100644
--- a/erts/emulator/beam/erl_bif_trace.c
+++ b/erts/emulator/beam/erl_bif_trace.c
@@ -1737,7 +1737,7 @@ setup_bif_trace(void)
for (i = 0; i < BIF_SIZE; ++i) {
Export *ep = bif_export[i];
- GenericBp* g = (GenericBp *) ep->info.native;
+ GenericBp* g = ep->info.u.gen_bp;
if (g) {
if (ExportIsBuiltIn(ep)) {
ASSERT(ep->beam[1]);
@@ -1755,7 +1755,7 @@ reset_bif_trace(void)
for (i = 0; i < BIF_SIZE; ++i) {
Export *ep = bif_export[i];
- GenericBp* g = (GenericBp *) ep->info.native;
+ GenericBp* g = ep->info.u.gen_bp;
if (g && g->data[active].flags == 0) {
if (ExportIsBuiltIn(ep)) {
ASSERT(ep->beam[1]);
diff --git a/erts/emulator/beam/erl_bif_unique.c b/erts/emulator/beam/erl_bif_unique.c
index 3fd4c87094..7f438daec0 100644
--- a/erts/emulator/beam/erl_bif_unique.c
+++ b/erts/emulator/beam/erl_bif_unique.c
@@ -197,7 +197,7 @@ erts_magic_ref_lookup_bin__(Uint32 refn[ERTS_REF_NUMBERS])
else {
erts_aint_t refc;
mb = tep->mb;
- refc = erts_refc_inc_unless(&mb->refc, 0, 0);
+ refc = erts_refc_inc_unless(&mb->intern.refc, 0, 0);
if (refc == 0)
mb = NULL;
}
diff --git a/erts/emulator/beam/erl_bif_unique.h b/erts/emulator/beam/erl_bif_unique.h
index 27c2a15a5e..0f3f794878 100644
--- a/erts/emulator/beam/erl_bif_unique.h
+++ b/erts/emulator/beam/erl_bif_unique.h
@@ -178,10 +178,10 @@ ERTS_GLB_INLINE Eterm
erts_mk_magic_ref(Eterm **hpp, ErlOffHeap *ohp, Binary *bp)
{
Eterm *hp = *hpp;
- ASSERT(bp->flags & BIN_FLAG_MAGIC);
+ ASSERT(bp->intern.flags & BIN_FLAG_MAGIC);
write_magic_ref_thing(hp, ohp, (ErtsMagicBinary *) bp);
*hpp += ERTS_MAGIC_REF_THING_SIZE;
- erts_refc_inc(&bp->refc, 1);
+ erts_refc_inc(&bp->intern.refc, 1);
OH_OVERHEAD(ohp, bp->orig_size / sizeof(Eterm));
return make_internal_ref(hp);
}
@@ -297,14 +297,14 @@ erts_iref_storage_save(ErtsIRefStorage *iref, Eterm ref)
ASSERT(is_magic_ref_thing(hp));
iref->is_magic = 1;
iref->u.mb = mrtp->mb;
- erts_refc_inc(&mrtp->mb->refc, 1);
+ erts_refc_inc(&mrtp->mb->intern.refc, 1);
}
}
ERTS_GLB_INLINE void
erts_iref_storage_clean(ErtsIRefStorage *iref)
{
- if (iref->is_magic && erts_refc_dectest(&iref->u.mb->refc, 0) == 0)
+ if (iref->is_magic && erts_refc_dectest(&iref->u.mb->intern.refc, 0) == 0)
erts_ref_bin_free(iref->u.mb);
#ifdef DEBUG
memset((void *) iref, 0xf, sizeof(ErtsIRefStorage));
@@ -337,7 +337,7 @@ erts_iref_storage_make_ref(ErtsIRefStorage *iref,
* refc increment of the cleaned storage...
*/
if (!clean_storage)
- erts_refc_inc(&iref->u.mb->refc, 1);
+ erts_refc_inc(&iref->u.mb->intern.refc, 1);
}
#ifdef DEBUG
diff --git a/erts/emulator/beam/erl_binary.h b/erts/emulator/beam/erl_binary.h
index 6ff71ec6d1..de7dbf4e20 100644
--- a/erts/emulator/beam/erl_binary.h
+++ b/erts/emulator/beam/erl_binary.h
@@ -42,14 +42,16 @@
#define ERTS_BINARY_STRUCT_ALIGNMENT
#endif
-/* Add fields in ERTS_INTERNAL_BINARY_FIELDS, otherwise the drivers crash */
-#define ERTS_INTERNAL_BINARY_FIELDS \
- UWord flags; \
- erts_refc_t refc; \
+/* Add fields in binary_internals, otherwise the drivers crash */
+struct binary_internals {
+ UWord flags;
+ erts_refc_t refc;
ERTS_BINARY_STRUCT_ALIGNMENT
+};
+
typedef struct binary {
- ERTS_INTERNAL_BINARY_FIELDS
+ struct binary_internals intern;
SWord orig_size;
char orig_bytes[1]; /* to be continued */
} Binary;
@@ -63,7 +65,7 @@ typedef struct binary {
typedef struct magic_binary ErtsMagicBinary;
struct magic_binary {
- ERTS_INTERNAL_BINARY_FIELDS
+ struct binary_internals intern;
SWord orig_size;
int (*destructor)(Binary *);
Uint32 refn[ERTS_REF_NUMBERS];
@@ -87,7 +89,7 @@ typedef union {
Binary binary;
ErtsMagicBinary magic_binary;
struct {
- ERTS_INTERNAL_BINARY_FIELDS
+ struct binary_internals intern;
ErlDrvBinary binary;
} driver;
} ErtsBinary;
@@ -316,6 +318,7 @@ ERTS_GLB_INLINE Binary *erts_bin_nrml_alloc(Uint size);
ERTS_GLB_INLINE Binary *erts_bin_realloc_fnf(Binary *bp, Uint size);
ERTS_GLB_INLINE Binary *erts_bin_realloc(Binary *bp, Uint size);
ERTS_GLB_INLINE void erts_bin_free(Binary *bp);
+ERTS_GLB_INLINE void erts_bin_release(Binary *bp);
ERTS_GLB_INLINE Binary *erts_create_magic_binary_x(Uint size,
int (*destructor)(Binary *),
ErtsAlcType_t alloc_type,
@@ -374,7 +377,8 @@ erts_bin_drv_alloc_fnf(Uint size)
ERTS_CHK_BIN_ALIGNMENT(res);
if (res) {
res->orig_size = size;
- res->flags = BIN_FLAG_DRV;
+ res->intern.flags = BIN_FLAG_DRV;
+ erts_refc_init(&res->intern.refc, 1);
}
return res;
}
@@ -392,7 +396,8 @@ erts_bin_drv_alloc(Uint size)
res = erts_alloc(ERTS_ALC_T_DRV_BINARY, bsize);
ERTS_CHK_BIN_ALIGNMENT(res);
res->orig_size = size;
- res->flags = BIN_FLAG_DRV;
+ res->intern.flags = BIN_FLAG_DRV;
+ erts_refc_init(&res->intern.refc, 1);
return res;
}
@@ -410,7 +415,8 @@ erts_bin_nrml_alloc(Uint size)
res = erts_alloc(ERTS_ALC_T_BINARY, bsize);
ERTS_CHK_BIN_ALIGNMENT(res);
res->orig_size = size;
- res->flags = 0;
+ res->intern.flags = 0;
+ erts_refc_init(&res->intern.refc, 1);
return res;
}
@@ -419,9 +425,9 @@ erts_bin_realloc_fnf(Binary *bp, Uint size)
{
Binary *nbp;
Uint bsize = ERTS_SIZEOF_Binary(size) + CHICKEN_PAD;
- ErtsAlcType_t type = (bp->flags & BIN_FLAG_DRV) ? ERTS_ALC_T_DRV_BINARY
+ ErtsAlcType_t type = (bp->intern.flags & BIN_FLAG_DRV) ? ERTS_ALC_T_DRV_BINARY
: ERTS_ALC_T_BINARY;
- ASSERT((bp->flags & BIN_FLAG_MAGIC) == 0);
+ ASSERT((bp->intern.flags & BIN_FLAG_MAGIC) == 0);
if (bsize < size) /* overflow */
return NULL;
nbp = erts_realloc_fnf(type, (void *) bp, bsize);
@@ -436,9 +442,9 @@ erts_bin_realloc(Binary *bp, Uint size)
{
Binary *nbp;
Uint bsize = ERTS_SIZEOF_Binary(size) + CHICKEN_PAD;
- ErtsAlcType_t type = (bp->flags & BIN_FLAG_DRV) ? ERTS_ALC_T_DRV_BINARY
+ ErtsAlcType_t type = (bp->intern.flags & BIN_FLAG_DRV) ? ERTS_ALC_T_DRV_BINARY
: ERTS_ALC_T_BINARY;
- ASSERT((bp->flags & BIN_FLAG_MAGIC) == 0);
+ ASSERT((bp->intern.flags & BIN_FLAG_MAGIC) == 0);
if (bsize < size) /* overflow */
erts_realloc_enomem(type, bp, size);
nbp = erts_realloc_fnf(type, (void *) bp, bsize);
@@ -452,7 +458,7 @@ erts_bin_realloc(Binary *bp, Uint size)
ERTS_GLB_INLINE void
erts_bin_free(Binary *bp)
{
- if (bp->flags & BIN_FLAG_MAGIC) {
+ if (bp->intern.flags & BIN_FLAG_MAGIC) {
if (!ERTS_MAGIC_BIN_DESTRUCTOR(bp)(bp)) {
/* Destructor took control of the deallocation */
return;
@@ -460,12 +466,20 @@ erts_bin_free(Binary *bp)
erts_magic_ref_remove_bin(ERTS_MAGIC_BIN_REFN(bp));
erts_free(ERTS_MAGIC_BIN_ATYPE(bp), (void *) bp);
}
- else if (bp->flags & BIN_FLAG_DRV)
+ else if (bp->intern.flags & BIN_FLAG_DRV)
erts_free(ERTS_ALC_T_DRV_BINARY, (void *) bp);
else
erts_free(ERTS_ALC_T_BINARY, (void *) bp);
}
+ERTS_GLB_INLINE void
+erts_bin_release(Binary *bp)
+{
+ if (erts_refc_dectest(&bp->intern.refc, 0) == 0) {
+ erts_bin_free(bp);
+ }
+}
+
ERTS_GLB_INLINE Binary *
erts_create_magic_binary_x(Uint size, int (*destructor)(Binary *),
ErtsAlcType_t alloc_type,
@@ -478,10 +492,10 @@ erts_create_magic_binary_x(Uint size, int (*destructor)(Binary *),
if (!bptr)
erts_alloc_n_enomem(ERTS_ALC_T2N(alloc_type), bsize);
ERTS_CHK_BIN_ALIGNMENT(bptr);
- bptr->flags = BIN_FLAG_MAGIC;
+ bptr->intern.flags = BIN_FLAG_MAGIC;
bptr->orig_size = unaligned ? ERTS_MAGIC_BIN_UNALIGNED_ORIG_SIZE(size)
: ERTS_MAGIC_BIN_ORIG_SIZE(size);
- erts_refc_init(&bptr->refc, 0);
+ erts_refc_init(&bptr->intern.refc, 0);
ERTS_MAGIC_BIN_DESTRUCTOR(bptr) = destructor;
ERTS_MAGIC_BIN_ATYPE(bptr) = alloc_type;
erts_make_magic_ref_in_array(ERTS_MAGIC_BIN_REFN(bptr));
@@ -509,7 +523,7 @@ ERTS_GLB_INLINE erts_smp_atomic_t *
erts_smp_binary_to_magic_indirection(Binary *bp)
{
ErtsMagicIndirectionWord *mip;
- ASSERT(bp->flags & BIN_FLAG_MAGIC);
+ ASSERT(bp->intern.flags & BIN_FLAG_MAGIC);
ASSERT(ERTS_MAGIC_BIN_ATYPE(bp) == ERTS_ALC_T_MINDIRECTION);
mip = ERTS_MAGIC_BIN_UNALIGNED_DATA(bp);
return &mip->smp_atomic_word;
@@ -519,7 +533,7 @@ ERTS_GLB_INLINE erts_atomic_t *
erts_binary_to_magic_indirection(Binary *bp)
{
ErtsMagicIndirectionWord *mip;
- ASSERT(bp->flags & BIN_FLAG_MAGIC);
+ ASSERT(bp->intern.flags & BIN_FLAG_MAGIC);
ASSERT(ERTS_MAGIC_BIN_ATYPE(bp) == ERTS_ALC_T_MINDIRECTION);
mip = ERTS_MAGIC_BIN_UNALIGNED_DATA(bp);
return &mip->atomic_word;
diff --git a/erts/emulator/beam/erl_bits.c b/erts/emulator/beam/erl_bits.c
index 885e955332..df3f6ad557 100644
--- a/erts/emulator/beam/erl_bits.c
+++ b/erts/emulator/beam/erl_bits.c
@@ -1404,7 +1404,6 @@ erts_bs_append(Process* c_p, Eterm* reg, Uint live, Eterm build_size_term,
* Allocate the binary data struct itself.
*/
bptr = erts_bin_nrml_alloc(bin_size);
- erts_refc_init(&bptr->refc, 1);
erts_current_bin = (byte *) bptr->orig_bytes;
/*
@@ -1518,14 +1517,11 @@ erts_bs_private_append(Process* p, Eterm bin, Eterm build_size_term, Uint unit)
* binary and copy the contents of the old binary into it.
*/
Binary* bptr = erts_bin_nrml_alloc(new_size);
- erts_refc_init(&bptr->refc, 1);
sys_memcpy(bptr->orig_bytes, binp->orig_bytes, binp->orig_size);
pb->flags |= PB_IS_WRITABLE | PB_ACTIVE_WRITER;
pb->val = bptr;
pb->bytes = (byte *) bptr->orig_bytes;
- if (erts_refc_dectest(&binp->refc, 0) == 0) {
- erts_bin_free(binp);
- }
+ erts_bin_release(binp);
}
}
erts_current_bin = pb->bytes;
@@ -1565,7 +1561,6 @@ erts_bs_init_writable(Process* p, Eterm sz)
* Allocate the binary data struct itself.
*/
bptr = erts_bin_nrml_alloc(bin_size);
- erts_refc_init(&bptr->refc, 1);
/*
* Now allocate the ProcBin on the heap.
diff --git a/erts/emulator/beam/erl_db.c b/erts/emulator/beam/erl_db.c
index 378328856d..98c689f13f 100644
--- a/erts/emulator/beam/erl_db.c
+++ b/erts/emulator/beam/erl_db.c
@@ -217,7 +217,7 @@ make_btid(DbTable *tb)
* and table is refered once by being alive...
*/
erts_smp_refc_init(&tb->common.refc, 2);
- erts_refc_inc(&btid->refc, 1);
+ erts_refc_inc(&btid->intern.refc, 1);
}
static ERTS_INLINE DbTable* btid2tab(Binary* btid)
@@ -402,8 +402,8 @@ free_dbtable(void *vtb)
#endif
ASSERT(is_immed(tb->common.heir_data));
- if (tb->common.btid && erts_refc_dectest(&tb->common.btid->refc, 0) == 0)
- erts_bin_free(tb->common.btid);
+ if (tb->common.btid)
+ erts_bin_release(tb->common.btid);
erts_db_free(ERTS_ALC_T_DB_TABLE, tb, (void *) tb, sizeof(DbTable));
}
@@ -3616,9 +3616,7 @@ static SWord proc_cleanup_fixed_table(Process* p, DbFixation* fix)
ASSERT(fix->counter == 0);
}
- if (erts_refc_dectest(&fix->tabs.btid->refc, 0) == 0) {
- erts_bin_free(fix->tabs.btid);
- }
+ erts_bin_release(fix->tabs.btid);
erts_free(ERTS_ALC_T_DB_FIXATION, fix);
ERTS_ETS_MISC_MEM_ADD(-sizeof(DbFixation));
++work;
@@ -3783,7 +3781,7 @@ static void fix_table_locked(Process* p, DbTable* tb)
tb, sizeof(DbFixation));
ERTS_ETS_MISC_MEM_ADD(sizeof(DbFixation));
fix->tabs.btid = tb->common.btid;
- erts_refc_inc(&fix->tabs.btid->refc, 2);
+ erts_refc_inc(&fix->tabs.btid->intern.refc, 2);
fix->procs.p = p;
fix->counter = 1;
fixing_procs_rbt_insert(&tb->common.fixing_procs, fix);
@@ -3819,7 +3817,7 @@ static void unfix_table_locked(Process* p, DbTable* tb,
#endif
fixed_tabs_delete(p, fix);
- erts_refc_dec(&fix->tabs.btid->refc, 1);
+ erts_refc_dec(&fix->tabs.btid->intern.refc, 1);
erts_db_free(ERTS_ALC_T_DB_FIXATION,
tb, (void *) fix, sizeof(DbFixation));
@@ -3889,9 +3887,7 @@ static void free_fixations_op(DbFixation* fix, void* vctx)
{
fixed_tabs_delete(fix->procs.p, fix);
- if (erts_refc_dectest(&fix->tabs.btid->refc, 0) == 0) {
- erts_bin_free(fix->tabs.btid);
- }
+ erts_bin_release(fix->tabs.btid);
erts_db_free(ERTS_ALC_T_DB_FIXATION,
ctx->tb, (void *) fix, sizeof(DbFixation));
@@ -3906,9 +3902,8 @@ int erts_db_execute_free_fixation(Process* p, DbFixation* fix)
ASSERT(fix->counter == 0);
fixed_tabs_delete(p, fix);
- if (erts_refc_dectest(&fix->tabs.btid->refc, 0) == 0) {
- erts_bin_free(fix->tabs.btid);
- }
+ erts_bin_release(fix->tabs.btid);
+
erts_free(ERTS_ALC_T_DB_FIXATION, fix);
ERTS_ETS_MISC_MEM_ADD(-sizeof(DbFixation));
return 1;
diff --git a/erts/emulator/beam/erl_db_hash.c b/erts/emulator/beam/erl_db_hash.c
index 7ab27df00c..80c4824eeb 100644
--- a/erts/emulator/beam/erl_db_hash.c
+++ b/erts/emulator/beam/erl_db_hash.c
@@ -1258,7 +1258,7 @@ static int match_traverse(Process* p, DbTableHash* tb,
}
if (mpi.all_objects) {
- mpi.mp->flags |= BIN_FLAG_ALL_OBJECTS;
+ mpi.mp->intern.flags |= BIN_FLAG_ALL_OBJECTS;
}
/*
@@ -1383,7 +1383,7 @@ static int match_traverse_continue(Process* p, DbTableHash* tb,
void* context_ptr, /* For callbacks */
Eterm* ret)
{
- int all_objects = (*mpp)->flags & BIN_FLAG_ALL_OBJECTS;
+ int all_objects = (*mpp)->intern.flags & BIN_FLAG_ALL_OBJECTS;
HashDbTerm** current_ptr; /* Refers to either the bucket pointer or
* the 'next' pointer in the previous term
*/
diff --git a/erts/emulator/beam/erl_db_tree.c b/erts/emulator/beam/erl_db_tree.c
index ab8da6ccf6..f6918b8ec4 100644
--- a/erts/emulator/beam/erl_db_tree.c
+++ b/erts/emulator/beam/erl_db_tree.c
@@ -995,7 +995,7 @@ static int db_select_continue_tree(Process *p,
sc.lastobj = NULL;
sc.max = 1000;
sc.keypos = tb->common.keypos;
- sc.all_objects = mp->flags & BIN_FLAG_ALL_OBJECTS;
+ sc.all_objects = mp->intern.flags & BIN_FLAG_ALL_OBJECTS;
sc.chunk_size = chunk_size;
reverse = unsigned_val(tptr[7]);
sc.got = signed_val(tptr[8]);
@@ -1187,7 +1187,7 @@ static int db_select_tree(Process *p, DbTable *tbl, Eterm tid,
hp = HAlloc(p, 9 + sz + ERTS_MAGIC_REF_THING_SIZE);
key = copy_struct(key, sz, &hp, &MSO(p));
if (mpi.all_objects)
- (mpi.mp)->flags |= BIN_FLAG_ALL_OBJECTS;
+ (mpi.mp)->intern.flags |= BIN_FLAG_ALL_OBJECTS;
mpb= erts_db_make_match_prog_ref(p,mpi.mp,&hp);
continuation = TUPLE8
@@ -1385,7 +1385,7 @@ static int db_select_count_tree(Process *p, DbTable *tbl, Eterm tid,
}
key = copy_struct(key, sz, &hp, &MSO(p));
if (mpi.all_objects)
- (mpi.mp)->flags |= BIN_FLAG_ALL_OBJECTS;
+ (mpi.mp)->intern.flags |= BIN_FLAG_ALL_OBJECTS;
mpb = erts_db_make_match_prog_ref(p,mpi.mp,&hp);
continuation = TUPLE5
@@ -1510,7 +1510,7 @@ static int db_select_chunk_tree(Process *p, DbTable *tbl, Eterm tid,
hp = HAlloc(p, 9 + sz + ERTS_MAGIC_REF_THING_SIZE);
key = copy_struct(key, sz, &hp, &MSO(p));
if (mpi.all_objects)
- (mpi.mp)->flags |= BIN_FLAG_ALL_OBJECTS;
+ (mpi.mp)->intern.flags |= BIN_FLAG_ALL_OBJECTS;
mpb = erts_db_make_match_prog_ref(p,mpi.mp,&hp);
continuation = TUPLE8
@@ -1536,7 +1536,7 @@ static int db_select_chunk_tree(Process *p, DbTable *tbl, Eterm tid,
key = copy_struct(key, sz, &hp, &MSO(p));
if (mpi.all_objects)
- (mpi.mp)->flags |= BIN_FLAG_ALL_OBJECTS;
+ (mpi.mp)->intern.flags |= BIN_FLAG_ALL_OBJECTS;
mpb = erts_db_make_match_prog_ref(p,mpi.mp,&hp);
continuation = TUPLE8
(hp,
@@ -1932,7 +1932,7 @@ static int db_select_replace_tree(Process *p, DbTable *tbl, Eterm tid,
}
key = copy_struct(key, sz, &hp, &MSO(p));
if (mpi.all_objects)
- (mpi.mp)->flags |= BIN_FLAG_ALL_OBJECTS;
+ (mpi.mp)->intern.flags |= BIN_FLAG_ALL_OBJECTS;
mpb = erts_db_make_match_prog_ref(p,mpi.mp,&hp);
continuation = TUPLE5
diff --git a/erts/emulator/beam/erl_db_util.c b/erts/emulator/beam/erl_db_util.c
index 03cc11bdc4..24b22eafb8 100644
--- a/erts/emulator/beam/erl_db_util.c
+++ b/erts/emulator/beam/erl_db_util.c
@@ -3265,9 +3265,7 @@ void db_cleanup_offheap_comp(DbTerm* obj)
}
switch (thing_subtag(u.hdr->thing_word)) {
case REFC_BINARY_SUBTAG:
- if (erts_refc_dectest(&u.pb->val->refc, 0) == 0) {
- erts_bin_free(u.pb->val);
- }
+ erts_bin_release(u.pb->val);
break;
case FUN_SUBTAG:
ASSERT(u.pb != &tmp);
@@ -3277,8 +3275,7 @@ void db_cleanup_offheap_comp(DbTerm* obj)
break;
case REF_SUBTAG:
ASSERT(is_magic_ref_thing(u.hdr));
- if (erts_refc_dectest(&u.mref->mb->refc, 0) == 0)
- erts_bin_free((Binary *)u.mref->mb);
+ erts_bin_release((Binary *)u.mref->mb);
break;
default:
ASSERT(is_external_header(u.hdr->thing_word));
diff --git a/erts/emulator/beam/erl_db_util.h b/erts/emulator/beam/erl_db_util.h
index 9be77fcefa..ed7b9c8618 100644
--- a/erts/emulator/beam/erl_db_util.h
+++ b/erts/emulator/beam/erl_db_util.h
@@ -504,7 +504,7 @@ ERTS_GLB_INLINE Binary *
erts_db_get_match_prog_binary_unchecked(Eterm term)
{
Binary *bp = erts_magic_ref2bin(term);
- ASSERT(bp->flags & BIN_FLAG_MAGIC);
+ ASSERT(bp->intern.flags & BIN_FLAG_MAGIC);
ASSERT((ERTS_MAGIC_BIN_DESTRUCTOR(bp) == erts_db_match_prog_destructor));
return bp;
}
@@ -516,7 +516,7 @@ erts_db_get_match_prog_binary(Eterm term)
if (!is_internal_magic_ref(term))
return NULL;
bp = erts_magic_ref2bin(term);
- ASSERT(bp->flags & BIN_FLAG_MAGIC);
+ ASSERT(bp->intern.flags & BIN_FLAG_MAGIC);
if (ERTS_MAGIC_BIN_DESTRUCTOR(bp) != erts_db_match_prog_destructor)
return NULL;
return bp;
@@ -528,7 +528,7 @@ erts_db_get_match_prog_binary(Eterm term)
** Convenience when compiling into Binary structures
*/
#define IsMatchProgBinary(BP) \
- (((BP)->flags & BIN_FLAG_MAGIC) \
+ (((BP)->intern.flags & BIN_FLAG_MAGIC) \
&& ERTS_MAGIC_BIN_DESTRUCTOR((BP)) == erts_db_match_prog_destructor)
#define Binary2MatchProg(BP) \
diff --git a/erts/emulator/beam/erl_gc.c b/erts/emulator/beam/erl_gc.c
index d51d4fff45..a991c2c164 100644
--- a/erts/emulator/beam/erl_gc.c
+++ b/erts/emulator/beam/erl_gc.c
@@ -1252,7 +1252,7 @@ erts_garbage_collect_literals(Process* p, Eterm* literals,
* link it into the MSO list for the process.
*/
- erts_refc_inc(&bptr->refc, 1);
+ erts_refc_inc(&bptr->intern.refc, 1);
*prev = ptr;
prev = &ptr->next;
}
@@ -2889,9 +2889,7 @@ sweep_off_heap(Process *p, int fullsweep)
case REFC_BINARY_SUBTAG:
{
Binary* bptr = ((ProcBin*)ptr)->val;
- if (erts_refc_dectest(&bptr->refc, 0) == 0) {
- erts_bin_free(bptr);
- }
+ erts_bin_release(bptr);
break;
}
case FUN_SUBTAG:
@@ -2907,8 +2905,7 @@ sweep_off_heap(Process *p, int fullsweep)
ErtsMagicBinary *bptr;
ASSERT(is_magic_ref_thing(ptr));
bptr = ((ErtsMRefThing *) ptr)->mb;
- if (erts_refc_dectest(&bptr->refc, 0) == 0)
- erts_bin_free((Binary *) bptr);
+ erts_bin_release((Binary *) bptr);
break;
}
default:
@@ -3609,7 +3606,7 @@ erts_check_off_heap2(Process *p, Eterm *htop)
erts_aint_t refc;
switch (thing_subtag(u.hdr->thing_word)) {
case REFC_BINARY_SUBTAG:
- refc = erts_refc_read(&u.pb->val->refc, 1);
+ refc = erts_refc_read(&u.pb->val->intern.refc, 1);
break;
case FUN_SUBTAG:
refc = erts_smp_refc_read(&u.fun->fe->refc, 1);
@@ -3621,7 +3618,7 @@ erts_check_off_heap2(Process *p, Eterm *htop)
break;
case REF_SUBTAG:
ASSERT(is_magic_ref_thing(u.hdr));
- refc = erts_refc_read(&u.mref->mb->refc, 1);
+ refc = erts_refc_read(&u.mref->mb->intern.refc, 1);
break;
default:
ASSERT(!"erts_check_off_heap2: Invalid thing_word");
diff --git a/erts/emulator/beam/erl_init.c b/erts/emulator/beam/erl_init.c
index ac0324d846..eaaf5c911a 100644
--- a/erts/emulator/beam/erl_init.c
+++ b/erts/emulator/beam/erl_init.c
@@ -61,8 +61,9 @@
#define ERTS_DEFAULT_NO_ASYNC_THREADS 10
-#define ERTS_DEFAULT_SCHED_STACK_SIZE 256
-#define ERTS_MIN_SCHED_STACK_SIZE 20
+#define ERTS_DEFAULT_SCHED_STACK_SIZE 128
+#define ERTS_DEFAULT_DCPU_SCHED_STACK_SIZE 40
+#define ERTS_DEFAULT_DIO_SCHED_STACK_SIZE 40
/*
* The variables below (prefixed with etp_) are for erts/etc/unix/etp-commands
@@ -641,9 +642,22 @@ void erts_usage(void)
erts_fprintf(stderr, "-swt val set scheduler wakeup threshold, valid values are:\n");
erts_fprintf(stderr, " very_low|low|medium|high|very_high.\n");
erts_fprintf(stderr, "-sss size suggested stack size in kilo words for scheduler threads,\n");
- erts_fprintf(stderr, " valid range is [%d-%d]\n",
+ erts_fprintf(stderr, " valid range is [%d-%d] (default %d)\n",
+ ERTS_SCHED_THREAD_MIN_STACK_SIZE,
+ ERTS_SCHED_THREAD_MAX_STACK_SIZE,
+ ERTS_DEFAULT_SCHED_STACK_SIZE);
+#ifdef ERTS_DIRTY_SCHEDULERS
+ erts_fprintf(stderr, "-sssdcpu size suggested stack size in kilo words for dirty CPU scheduler\n");
+ erts_fprintf(stderr, " threads, valid range is [%d-%d] (default %d)\n",
+ ERTS_SCHED_THREAD_MIN_STACK_SIZE,
+ ERTS_SCHED_THREAD_MAX_STACK_SIZE,
+ ERTS_DEFAULT_DCPU_SCHED_STACK_SIZE);
+ erts_fprintf(stderr, "-sssdio size suggested stack size in kilo words for dirty IO scheduler\n");
+ erts_fprintf(stderr, " threads, valid range is [%d-%d] (default %d)\n",
ERTS_SCHED_THREAD_MIN_STACK_SIZE,
- ERTS_SCHED_THREAD_MAX_STACK_SIZE);
+ ERTS_SCHED_THREAD_MAX_STACK_SIZE,
+ ERTS_DEFAULT_DIO_SCHED_STACK_SIZE);
+#endif
erts_fprintf(stderr, "-spp Bool set port parallelism scheduling hint\n");
erts_fprintf(stderr, "-S n1:n2 set number of schedulers (n1), and number of\n");
erts_fprintf(stderr, " schedulers online (n2), maximum for both\n");
@@ -1327,6 +1341,10 @@ erl_start(int argc, char **argv)
* a lot of stack.
*/
erts_sched_thread_suggested_stack_size = ERTS_DEFAULT_SCHED_STACK_SIZE;
+#ifdef ERTS_DIRTY_SCHEDULERS
+ erts_dcpu_sched_thread_suggested_stack_size = ERTS_DEFAULT_DCPU_SCHED_STACK_SIZE;
+ erts_dio_sched_thread_suggested_stack_size = ERTS_DEFAULT_DIO_SCHED_STACK_SIZE;
+#endif
#ifdef DEBUG
verbose = DEBUG_DEFAULT;
@@ -1945,6 +1963,42 @@ erl_start(int argc, char **argv)
VERBOSE(DEBUG_SYSTEM,
("scheduler wakeup threshold: %s\n", arg));
}
+#ifdef ERTS_DIRTY_SCHEDULERS
+ else if (has_prefix("ssdcpu", sub_param)) {
+ /* suggested stack size (Kilo Words) for dirty CPU scheduler threads */
+ arg = get_arg(sub_param+6, argv[i+1], &i);
+ erts_dcpu_sched_thread_suggested_stack_size = atoi(arg);
+
+ if ((erts_dcpu_sched_thread_suggested_stack_size
+ < ERTS_SCHED_THREAD_MIN_STACK_SIZE)
+ || (erts_dcpu_sched_thread_suggested_stack_size >
+ ERTS_SCHED_THREAD_MAX_STACK_SIZE)) {
+ erts_fprintf(stderr, "bad stack size for dirty CPU scheduler threads %s\n",
+ arg);
+ erts_usage();
+ }
+ VERBOSE(DEBUG_SYSTEM,
+ ("suggested dirty CPU scheduler thread stack size %d kilo words\n",
+ erts_dcpu_sched_thread_suggested_stack_size));
+ }
+ else if (has_prefix("ssdio", sub_param)) {
+ /* suggested stack size (Kilo Words) for dirty IO scheduler threads */
+ arg = get_arg(sub_param+5, argv[i+1], &i);
+ erts_dio_sched_thread_suggested_stack_size = atoi(arg);
+
+ if ((erts_dio_sched_thread_suggested_stack_size
+ < ERTS_SCHED_THREAD_MIN_STACK_SIZE)
+ || (erts_dio_sched_thread_suggested_stack_size >
+ ERTS_SCHED_THREAD_MAX_STACK_SIZE)) {
+ erts_fprintf(stderr, "bad stack size for dirty IO scheduler threads %s\n",
+ arg);
+ erts_usage();
+ }
+ VERBOSE(DEBUG_SYSTEM,
+ ("suggested dirty IO scheduler thread stack size %d kilo words\n",
+ erts_dio_sched_thread_suggested_stack_size));
+ }
+#endif
else if (has_prefix("ss", sub_param)) {
/* suggested stack size (Kilo Words) for scheduler threads */
arg = get_arg(sub_param+2, argv[i+1], &i);
@@ -2259,8 +2313,14 @@ erl_start(int argc, char **argv)
boot_argc = argc - i; /* Number of arguments to init */
boot_argv = &argv[i];
- if (erts_sched_thread_suggested_stack_size < ERTS_MIN_SCHED_STACK_SIZE)
- erts_sched_thread_suggested_stack_size = ERTS_MIN_SCHED_STACK_SIZE;
+ if (erts_sched_thread_suggested_stack_size < ERTS_SCHED_THREAD_MIN_STACK_SIZE)
+ erts_sched_thread_suggested_stack_size = ERTS_SCHED_THREAD_MIN_STACK_SIZE;
+#ifdef ERTS_DIRTY_SCHEDULERS
+ if (erts_dcpu_sched_thread_suggested_stack_size < ERTS_SCHED_THREAD_MIN_STACK_SIZE)
+ erts_dcpu_sched_thread_suggested_stack_size = ERTS_SCHED_THREAD_MIN_STACK_SIZE;
+ if (erts_dio_sched_thread_suggested_stack_size < ERTS_SCHED_THREAD_MIN_STACK_SIZE)
+ erts_dio_sched_thread_suggested_stack_size = ERTS_SCHED_THREAD_MIN_STACK_SIZE;
+#endif
erl_init(ncpu,
proc_tab_sz,
diff --git a/erts/emulator/beam/erl_message.c b/erts/emulator/beam/erl_message.c
index f181c1e3cb..17982a2d14 100644
--- a/erts/emulator/beam/erl_message.c
+++ b/erts/emulator/beam/erl_message.c
@@ -167,9 +167,7 @@ erts_cleanup_offheap(ErlOffHeap *offheap)
for (u.hdr = offheap->first; u.hdr; u.hdr = u.hdr->next) {
switch (thing_subtag(u.hdr->thing_word)) {
case REFC_BINARY_SUBTAG:
- if (erts_refc_dectest(&u.pb->val->refc, 0) == 0) {
- erts_bin_free(u.pb->val);
- }
+ erts_bin_release(u.pb->val);
break;
case FUN_SUBTAG:
if (erts_smp_refc_dectest(&u.fun->fe->refc, 0) == 0) {
@@ -178,8 +176,7 @@ erts_cleanup_offheap(ErlOffHeap *offheap)
break;
case REF_SUBTAG:
ASSERT(is_magic_ref_thing(u.hdr));
- if (erts_refc_dectest(&u.mref->mb->refc, 0) == 0)
- erts_bin_free((Binary *)u.mref->mb);
+ erts_bin_release((Binary *)u.mref->mb);
break;
default:
ASSERT(is_external_header(u.hdr->thing_word));
diff --git a/erts/emulator/beam/erl_nif.c b/erts/emulator/beam/erl_nif.c
index f86b9739fa..872b58d1ef 100644
--- a/erts/emulator/beam/erl_nif.c
+++ b/erts/emulator/beam/erl_nif.c
@@ -1074,7 +1074,6 @@ int enif_alloc_binary(size_t size, ErlNifBinary* bin)
if (refbin == NULL) {
return 0; /* The NIF must take action */
}
- erts_refc_init(&refbin->refc, 1);
bin->size = size;
bin->data = (unsigned char*) refbin->orig_bytes;
@@ -1113,9 +1112,7 @@ void enif_release_binary(ErlNifBinary* bin)
if (bin->ref_bin != NULL) {
Binary* refbin = bin->ref_bin;
ASSERT(bin->bin_term == THE_NON_VALUE);
- if (erts_refc_dectest(&refbin->refc, 0) == 0) {
- erts_bin_free(refbin);
- }
+ erts_bin_release(refbin);
}
#ifdef DEBUG
bin->data = NULL;
@@ -1279,7 +1276,7 @@ Eterm enif_make_binary(ErlNifEnv* env, ErlNifBinary* bin)
OH_OVERHEAD(&(MSO(env->proc)), pb->size / sizeof(Eterm));
bin_term = make_binary(pb);
- if (erts_refc_read(&bptr->refc, 1) == 1) {
+ if (erts_refc_read(&bptr->intern.refc, 1) == 1) {
/* Total ownership transfer */
bin->ref_bin = NULL;
bin->bin_term = bin_term;
@@ -2249,7 +2246,7 @@ static int nif_resource_dtor(Binary* bin)
ASSERT(type->down);
erts_smp_mtx_lock(&rm->lock);
- ASSERT(erts_refc_read(&bin->refc, 0) == 0);
+ ASSERT(erts_refc_read(&bin->intern.refc, 0) == 0);
if (rm->root) {
ASSERT(!rm->is_dying);
destroy_all_monitors(rm->root, resource);
@@ -2323,13 +2320,13 @@ void erts_fire_nif_monitor(ErtsResource* resource, Eterm pid, Eterm ref)
erts_smp_mtx_unlock(&rmp->lock);
if (free_me) {
- ASSERT(erts_refc_read(&bin->binary.refc, 0) == 0);
+ ASSERT(erts_refc_read(&bin->binary.intern.refc, 0) == 0);
erts_bin_free(&bin->binary);
}
return;
}
ASSERT(!rmp->is_dying);
- if (erts_refc_inc_unless(&bin->binary.refc, 0, 0) == 0) {
+ if (erts_refc_inc_unless(&bin->binary.intern.refc, 0, 0) == 0) {
/*
* Racing resource destruction.
* To avoid a more complex refc-dance with destructing thread
@@ -2348,9 +2345,7 @@ void erts_fire_nif_monitor(ErtsResource* resource, Eterm pid, Eterm ref)
resource->type->down(&msg_env.env, resource->data, &nif_pid, &nif_monitor);
post_nif_noproc(&msg_env);
- if (erts_refc_dectest(&bin->binary.refc, 0) == 0) {
- erts_bin_free(&bin->binary);
- }
+ erts_bin_release(&bin->binary);
}
erts_destroy_monitor(rmon);
}
@@ -2379,7 +2374,7 @@ void* enif_alloc_resource(ErlNifResourceType* type, size_t data_sz)
ASSERT(type->owner && type->next && type->prev); /* not allowed in load/upgrade */
resource->type = type;
- erts_refc_inc(&bin->refc, 1);
+ erts_refc_inc(&bin->intern.refc, 1);
#ifdef DEBUG
erts_refc_init(&resource->nif_refc, 1);
#endif
@@ -2408,9 +2403,7 @@ void enif_release_resource(void* obj)
#ifdef DEBUG
erts_refc_dec(&resource->nif_refc, 0);
#endif
- if (erts_refc_dectest(&bin->binary.refc, 0) == 0) {
- erts_bin_free(&bin->binary);
- }
+ erts_bin_release(&bin->binary);
}
void enif_keep_resource(void* obj)
@@ -2423,7 +2416,7 @@ void enif_keep_resource(void* obj)
#ifdef DEBUG
erts_refc_inc(&resource->nif_refc, 1);
#endif
- erts_refc_inc(&bin->binary.refc, 2);
+ erts_refc_inc(&bin->binary.intern.refc, 2);
}
Eterm erts_bld_resource_ref(Eterm** hpp, ErlOffHeap* oh, ErtsResource* resource)
@@ -2460,7 +2453,7 @@ ERL_NIF_TERM enif_make_resource_binary(ErlNifEnv* env, void* obj,
pb->flags = 0;
OH_OVERHEAD(ohp, size / sizeof(Eterm));
- erts_refc_inc(&bin->binary.refc, 1);
+ erts_refc_inc(&bin->binary.intern.refc, 1);
return make_binary(hp);
}
@@ -2485,7 +2478,7 @@ int enif_get_resource(ErlNifEnv* env, ERL_NIF_TERM term, ErlNifResourceType* typ
}
*/
mbin = ((ProcBin *) hp)->val;
- if (!(mbin->flags & BIN_FLAG_MAGIC))
+ if (!(mbin->intern.flags & BIN_FLAG_MAGIC))
return 0;
}
resource = (ErtsResource*) ERTS_MAGIC_BIN_UNALIGNED_DATA(mbin);
@@ -3658,11 +3651,11 @@ BIF_RETTYPE load_nif_2(BIF_ALIST_2)
ci = *get_func_pp(this_mi->code_hdr, f_atom, f->arity);
code_ptr = erts_codeinfo_to_code(ci);
- if (ci->native == 0) {
+ if (ci->u.gen_bp == NULL) {
code_ptr[0] = (BeamInstr) BeamOp(op_call_nif);
}
else { /* Function traced, patch the original instruction word */
- GenericBp* g = (GenericBp *) ci->native;
+ GenericBp* g = ci->u.gen_bp;
ASSERT(code_ptr[0] ==
(BeamInstr) BeamOp(op_i_generic_breakpoint));
g->orig_instr = (BeamInstr) BeamOp(op_call_nif);
diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c
index f35c5e04a2..9947e33f47 100644
--- a/erts/emulator/beam/erl_process.c
+++ b/erts/emulator/beam/erl_process.c
@@ -194,7 +194,10 @@ static UWord thr_prgr_later_cleanup_op_threshold = ERTS_THR_PRGR_LATER_CLEANUP_O
ErtsPTab erts_proc erts_align_attribute(ERTS_CACHE_LINE_SIZE);
int erts_sched_thread_suggested_stack_size = -1;
-
+#ifdef ERTS_DIRTY_SCHEDULERS
+int erts_dcpu_sched_thread_suggested_stack_size = -1;
+int erts_dio_sched_thread_suggested_stack_size = -1;
+#endif
#ifdef ERTS_ENABLE_LOCK_CHECK
ErtsLcPSDLocks erts_psd_required_locks[ERTS_PSD_SIZE];
#endif
@@ -8999,6 +9002,7 @@ erts_start_schedulers(void)
for (ix = 0; ix < erts_no_dirty_cpu_schedulers; ix++) {
ErtsSchedulerData *esdp = ERTS_DIRTY_CPU_SCHEDULER_IX(ix);
erts_snprintf(opts.name, 16, "%d_dirty_cpu_scheduler", ix + 1);
+ opts.suggested_stack_size = erts_dcpu_sched_thread_suggested_stack_size;
res = ethr_thr_create(&esdp->tid,sched_dirty_cpu_thread_func,(void*)esdp,&opts);
if (res != 0)
erts_exit(ERTS_ERROR_EXIT, "Failed to create dirty cpu scheduler thread %d\n", ix);
@@ -9006,6 +9010,7 @@ erts_start_schedulers(void)
for (ix = 0; ix < erts_no_dirty_io_schedulers; ix++) {
ErtsSchedulerData *esdp = ERTS_DIRTY_IO_SCHEDULER_IX(ix);
erts_snprintf(opts.name, 16, "%d_dirty_io_scheduler", ix + 1);
+ opts.suggested_stack_size = erts_dio_sched_thread_suggested_stack_size;
res = ethr_thr_create(&esdp->tid,sched_dirty_io_thread_func,(void*)esdp,&opts);
if (res != 0)
erts_exit(ERTS_ERROR_EXIT, "Failed to create dirty io scheduler thread %d\n", ix);
diff --git a/erts/emulator/beam/erl_process.h b/erts/emulator/beam/erl_process.h
index b21597d63b..5b35dc3c78 100644
--- a/erts/emulator/beam/erl_process.h
+++ b/erts/emulator/beam/erl_process.h
@@ -117,7 +117,11 @@ extern Uint erts_no_dirty_io_schedulers;
#endif
extern Uint erts_no_run_queues;
extern int erts_sched_thread_suggested_stack_size;
-#define ERTS_SCHED_THREAD_MIN_STACK_SIZE 4 /* Kilo words */
+#ifdef ERTS_DIRTY_SCHEDULERS
+extern int erts_dcpu_sched_thread_suggested_stack_size;
+extern int erts_dio_sched_thread_suggested_stack_size;
+#endif
+#define ERTS_SCHED_THREAD_MIN_STACK_SIZE 20 /* Kilo words */
#define ERTS_SCHED_THREAD_MAX_STACK_SIZE 8192 /* Kilo words */
#ifdef ERTS_SMP
diff --git a/erts/emulator/beam/erl_process_dump.c b/erts/emulator/beam/erl_process_dump.c
index 77c7c5e73c..fbf14df92b 100644
--- a/erts/emulator/beam/erl_process_dump.c
+++ b/erts/emulator/beam/erl_process_dump.c
@@ -447,8 +447,8 @@ heap_dump(fmtfn_t to, void *to_arg, Eterm x)
ProcBin* pb = (ProcBin *) binary_val(x);
Binary* val = pb->val;
- if (erts_atomic_xchg_nob(&val->refc, 0) != 0) {
- val->flags = (UWord) all_binaries;
+ if (erts_atomic_xchg_nob(&val->intern.refc, 0) != 0) {
+ val->intern.flags = (UWord) all_binaries;
all_binaries = val;
}
erts_print(to, to_arg,
@@ -529,7 +529,7 @@ dump_binaries(fmtfn_t to, void *to_arg, Binary* current)
erts_print(to, to_arg, "%02X", bytes[i]);
}
erts_putc(to, to_arg, '\n');
- current = (Binary *) current->flags;
+ current = (Binary *) current->intern.flags;
}
}
diff --git a/erts/emulator/beam/erl_trace.c b/erts/emulator/beam/erl_trace.c
index 04f3160d42..870f1f142d 100644
--- a/erts/emulator/beam/erl_trace.c
+++ b/erts/emulator/beam/erl_trace.c
@@ -1875,7 +1875,6 @@ trace_port_tmp_binary(char *bin, Sint sz, Binary **bptrp, Eterm **hp)
} else {
ProcBin* pb = (ProcBin *)*hp;
Binary *bptr = erts_bin_nrml_alloc(sz);
- erts_refc_init(&bptr->refc, 1);
sys_memcpy(bptr->orig_bytes, bin, sz);
pb->thing_word = HEADER_PROC_BIN;
pb->size = sz;
@@ -2000,8 +1999,8 @@ trace_port_receive(Port *t_p, Eterm caller, Eterm what, ...)
TRACE_FUN_T_RECEIVE,
am_receive, data, THE_NON_VALUE, am_true);
- if (bptr && erts_refc_dectest(&bptr->refc, 1) == 0)
- erts_bin_free(bptr);
+ if (bptr)
+ erts_bin_release(bptr);
if (orig_hp)
erts_free(ERTS_ALC_T_TMP, orig_hp);
@@ -2051,8 +2050,8 @@ void trace_port_send_binary(Port *t_p, Eterm to, Eterm what, char *bin, Sint sz)
send_to_tracer_nif(NULL, &t_p->common, t_p->common.id, tnif, TRACE_FUN_T_SEND,
am_send, msg, to, am_true);
- if (bptr && erts_refc_dectest(&bptr->refc, 1) == 0)
- erts_bin_free(bptr);
+ if (bptr)
+ erts_bin_release(bptr);
UnUseTmpHeapNoproc(LOCAL_HEAP_SIZE);
#undef LOCAL_HEAP_SIZE
diff --git a/erts/emulator/beam/export.c b/erts/emulator/beam/export.c
index 33ed6d7ec1..ecfef28c57 100644
--- a/erts/emulator/beam/export.c
+++ b/erts/emulator/beam/export.c
@@ -132,7 +132,7 @@ export_alloc(struct export_entry* tmpl_e)
erts_smp_atomic_add_nob(&total_entries_bytes, sizeof(*blob));
obj = &blob->exp;
obj->info.op = 0;
- obj->info.native = 0;
+ obj->info.u.gen_bp = NULL;
obj->info.mfa.module = tmpl->info.mfa.module;
obj->info.mfa.function = tmpl->info.mfa.function;
obj->info.mfa.arity = tmpl->info.mfa.arity;
diff --git a/erts/emulator/beam/external.c b/erts/emulator/beam/external.c
index 285ae4ac78..f5a5da981c 100644
--- a/erts/emulator/beam/external.c
+++ b/erts/emulator/beam/external.c
@@ -1821,7 +1821,7 @@ static int ttb_context_destructor(Binary *context_bin)
case TTBEncode:
DESTROY_SAVED_WSTACK(&context->s.ec.wstack);
if (context->s.ec.result_bin != NULL) { /* Set to NULL if ever made alive! */
- ASSERT(erts_refc_read(&(context->s.ec.result_bin->refc),0) == 0);
+ ASSERT(erts_refc_read(&(context->s.ec.result_bin->intern.refc),1));
erts_bin_free(context->s.ec.result_bin);
context->s.ec.result_bin = NULL;
}
@@ -1830,13 +1830,13 @@ static int ttb_context_destructor(Binary *context_bin)
erl_zlib_deflate_finish(&(context->s.cc.stream));
if (context->s.cc.destination_bin != NULL) { /* Set to NULL if ever made alive! */
- ASSERT(erts_refc_read(&(context->s.cc.destination_bin->refc),0) == 0);
+ ASSERT(erts_refc_read(&(context->s.cc.destination_bin->intern.refc),1));
erts_bin_free(context->s.cc.destination_bin);
context->s.cc.destination_bin = NULL;
}
if (context->s.cc.result_bin != NULL) { /* Set to NULL if ever made alive! */
- ASSERT(erts_refc_read(&(context->s.cc.result_bin->refc),0) == 0);
+ ASSERT(erts_refc_read(&(context->s.cc.result_bin->intern.refc),1));
erts_bin_free(context->s.cc.result_bin);
context->s.cc.result_bin = NULL;
}
@@ -1920,7 +1920,6 @@ static Eterm erts_term_to_binary_int(Process* p, Eterm Term, int level, Uint fla
}
result_bin = erts_bin_nrml_alloc(size);
- erts_refc_init(&result_bin->refc, 0);
result_bin->orig_bytes[0] = VERSION_MAGIC;
/* Next state immediately, no need to export context */
context->state = TTBEncode;
@@ -1960,8 +1959,7 @@ static Eterm erts_term_to_binary_int(Process* p, Eterm Term, int level, Uint fla
pb->bytes = (byte*) result_bin->orig_bytes;
pb->flags = 0;
OH_OVERHEAD(&(MSO(p)), pb->size / sizeof(Eterm));
- erts_refc_inc(&result_bin->refc, 1);
- if (context_b && erts_refc_read(&context_b->refc,0) == 0) {
+ if (context_b && erts_refc_read(&context_b->intern.refc,0) == 0) {
erts_bin_free(context_b);
}
return make_binary(pb);
@@ -1980,7 +1978,6 @@ static Eterm erts_term_to_binary_int(Process* p, Eterm Term, int level, Uint fla
context->s.cc.result_bin = result_bin;
result_bin = erts_bin_nrml_alloc(real_size);
- erts_refc_init(&result_bin->refc, 0);
result_bin->orig_bytes[0] = VERSION_MAGIC;
context->s.cc.destination_bin = result_bin;
@@ -2028,15 +2025,15 @@ static Eterm erts_term_to_binary_int(Process* p, Eterm Term, int level, Uint fla
pb->next = MSO(p).first;
MSO(p).first = (struct erl_off_heap_header*)pb;
pb->val = result_bin;
+ ASSERT(erts_refc_read(&result_bin->intern.refc, 1));
pb->bytes = (byte*) result_bin->orig_bytes;
pb->flags = 0;
OH_OVERHEAD(&(MSO(p)), pb->size / sizeof(Eterm));
- erts_refc_inc(&result_bin->refc, 1);
erts_bin_free(context->s.cc.result_bin);
context->s.cc.result_bin = NULL;
context->alive = 0;
BUMP_REDS(p, (this_time * CONTEXT_REDS) / TERM_TO_BINARY_COMPRESS_CHUNK);
- if (context_b && erts_refc_read(&context_b->refc,0) == 0) {
+ if (context_b && erts_refc_read(&context_b->intern.refc,0) == 0) {
erts_bin_free(context_b);
}
return make_binary(pb);
@@ -2055,13 +2052,13 @@ static Eterm erts_term_to_binary_int(Process* p, Eterm Term, int level, Uint fla
pb->bytes = (byte*) result_bin->orig_bytes;
pb->flags = 0;
OH_OVERHEAD(&(MSO(p)), pb->size / sizeof(Eterm));
- erts_refc_inc(&result_bin->refc, 1);
+ ASSERT(erts_refc_read(&result_bin->intern.refc, 1));
erl_zlib_deflate_finish(&(context->s.cc.stream));
erts_bin_free(context->s.cc.destination_bin);
context->s.cc.destination_bin = NULL;
context->alive = 0;
BUMP_REDS(p, (this_time * CONTEXT_REDS) / TERM_TO_BINARY_COMPRESS_CHUNK);
- if (context_b && erts_refc_read(&context_b->refc,0) == 0) {
+ if (context_b && erts_refc_read(&context_b->intern.refc,0) == 0) {
erts_bin_free(context_b);
}
return make_binary(pb);
@@ -2749,7 +2746,7 @@ enc_term_int(TTBEncodeContext* ctx, ErtsAtomCacheMap *acmp, Eterm obj, byte* ep,
erts_emasculate_writable_binary(pb);
bytes += (pb->val->orig_bytes - before_realloc);
}
- erts_refc_inc(&pb->val->refc, 2);
+ erts_refc_inc(&pb->val->intern.refc, 2);
sys_memcpy(&tmp, pb, sizeof(ProcBin));
tmp.next = *off_heap;
@@ -3509,7 +3506,6 @@ dec_term_atom_common:
} else {
Binary* dbin = erts_bin_nrml_alloc(n);
ProcBin* pb;
- erts_refc_init(&dbin->refc, 1);
pb = (ProcBin *) hp;
hp += PROC_BIN_SIZE;
pb->thing_word = HEADER_PROC_BIN;
@@ -3562,7 +3558,6 @@ dec_term_atom_common:
Binary* dbin = erts_bin_nrml_alloc(n);
ProcBin* pb;
- erts_refc_init(&dbin->refc, 1);
pb = (ProcBin *) hp;
pb->thing_word = HEADER_PROC_BIN;
pb->size = n;
@@ -3865,7 +3860,7 @@ dec_term_atom_common:
sys_memcpy(pb, ep, sizeof(ProcBin));
ep += sizeof(ProcBin);
- erts_refc_inc(&pb->val->refc, 1);
+ erts_refc_inc(&pb->val->intern.refc, 1);
hp += PROC_BIN_SIZE;
pb->next = factory->off_heap->first;
factory->off_heap->first = (struct erl_off_heap_header*)pb;
@@ -3883,7 +3878,7 @@ dec_term_atom_common:
sys_memcpy(pb, ep, sizeof(ProcBin));
ep += sizeof(ProcBin);
- erts_refc_inc(&pb->val->refc, 1);
+ erts_refc_inc(&pb->val->intern.refc, 1);
hp += PROC_BIN_SIZE;
pb->next = factory->off_heap->first;
factory->off_heap->first = (struct erl_off_heap_header*)pb;
diff --git a/erts/emulator/beam/global.h b/erts/emulator/beam/global.h
index 139394680a..bb4d442240 100644
--- a/erts/emulator/beam/global.h
+++ b/erts/emulator/beam/global.h
@@ -1425,14 +1425,14 @@ Eterm erts_msacc_request(Process *c_p, int action, Eterm *threads);
#define MatchSetRef(MPSP) \
do { \
if ((MPSP) != NULL) { \
- erts_refc_inc(&(MPSP)->refc, 1); \
+ erts_refc_inc(&(MPSP)->intern.refc, 1); \
} \
} while (0)
#define MatchSetUnref(MPSP) \
do { \
- if (((MPSP) != NULL) && erts_refc_dectest(&(MPSP)->refc, 0) <= 0) { \
- erts_bin_free(MPSP); \
+ if (((MPSP) != NULL)) { \
+ erts_bin_release(MPSP); \
} \
} while(0)
diff --git a/erts/emulator/beam/io.c b/erts/emulator/beam/io.c
index ddff862607..2f3117223f 100644
--- a/erts/emulator/beam/io.c
+++ b/erts/emulator/beam/io.c
@@ -3791,7 +3791,6 @@ static void deliver_read_message(Port* prt, erts_aint32_t state, Eterm to,
Binary* bptr;
bptr = erts_bin_nrml_alloc(len);
- erts_refc_init(&bptr->refc, 1);
sys_memcpy(bptr->orig_bytes, buf, len);
pb = (ProcBin *) hp;
@@ -4558,8 +4557,7 @@ static void
cleanup_scheduled_control(Binary *binp, char *bufp)
{
if (binp) {
- if (erts_refc_dectest(&binp->refc, 0) == 0)
- erts_bin_free(binp);
+ erts_bin_release(binp);
}
else {
if (bufp)
@@ -4903,7 +4901,7 @@ erts_port_control(Process* c_p,
ASSERT(bufp <= bufp + size);
ASSERT(binp->orig_bytes <= bufp
&& bufp + size <= binp->orig_bytes + binp->orig_size);
- erts_refc_inc(&binp->refc, 1);
+ erts_refc_inc(&binp->intern.refc, 1);
}
}
@@ -6400,7 +6398,6 @@ driver_deliver_term(Port *prt, Eterm to, ErlDrvTermData* data, int len)
ProcBin* pbp;
Binary* bp = erts_bin_nrml_alloc(size);
ASSERT(bufp);
- erts_refc_init(&bp->refc, 1);
sys_memcpy((void *) bp->orig_bytes, (void *) bufp, size);
pbp = (ProcBin *) erts_produce_heap(&factory,
PROC_BIN_SIZE, HEAP_EXTRA);
@@ -6910,21 +6907,21 @@ ErlDrvSInt
driver_binary_get_refc(ErlDrvBinary *dbp)
{
Binary* bp = ErlDrvBinary2Binary(dbp);
- return (ErlDrvSInt) erts_refc_read(&bp->refc, 1);
+ return (ErlDrvSInt) erts_refc_read(&bp->intern.refc, 1);
}
ErlDrvSInt
driver_binary_inc_refc(ErlDrvBinary *dbp)
{
Binary* bp = ErlDrvBinary2Binary(dbp);
- return (ErlDrvSInt) erts_refc_inctest(&bp->refc, 2);
+ return (ErlDrvSInt) erts_refc_inctest(&bp->intern.refc, 2);
}
ErlDrvSInt
driver_binary_dec_refc(ErlDrvBinary *dbp)
{
Binary* bp = ErlDrvBinary2Binary(dbp);
- return (ErlDrvSInt) erts_refc_dectest(&bp->refc, 1);
+ return (ErlDrvSInt) erts_refc_dectest(&bp->intern.refc, 1);
}
@@ -6940,7 +6937,6 @@ driver_alloc_binary(ErlDrvSizeT size)
bin = erts_bin_drv_alloc_fnf((Uint) size);
if (!bin)
return NULL; /* The driver write must take action */
- erts_refc_init(&bin->refc, 1);
return Binary2ErlDrvBinary(bin);
}
@@ -6970,8 +6966,7 @@ void driver_free_binary(ErlDrvBinary* dbin)
return;
bin = ErlDrvBinary2Binary(dbin);
- if (erts_refc_dectest(&bin->refc, 0) == 0)
- erts_bin_free(bin);
+ erts_bin_release(bin);
}
diff --git a/erts/emulator/beam/time.c b/erts/emulator/beam/time.c
index cee3cb619f..a7e5a64b22 100644
--- a/erts/emulator/beam/time.c
+++ b/erts/emulator/beam/time.c
@@ -1364,21 +1364,29 @@ dbg_verify_empty_later_slots(ErtsTimerWheel *tiw, ErtsMonotonicTime to_pos)
tmp = to_pos;
tmp &= ERTS_TW_LATER_WHEEL_POS_MASK;
if (tmp > tiw->later.pos) {
+ ErtsMonotonicTime pos_min;
int slots;
tmp -= tiw->later.pos;
tmp /= ERTS_TW_LATER_WHEEL_SLOT_SIZE;
ERTS_TW_ASSERT(tmp > 0);
+
+ pos_min = tiw->later.pos;
+
if (tmp < (ErtsMonotonicTime) ERTS_TW_LATER_WHEEL_SIZE)
slots = (int) tmp;
- else
+ else {
+ pos_min += ((tmp / ERTS_TW_LATER_WHEEL_SIZE)
+ * ERTS_TW_LATER_WHEEL_SLOT_SIZE);
slots = ERTS_TW_LATER_WHEEL_SIZE;
+ }
while (slots > 0) {
ErtsTWheelTimer *tmr = tiw->w[ix];
+ pos_min += ERTS_TW_LATER_WHEEL_SLOT_SIZE;
if (tmr) {
ErtsTWheelTimer *end = tmr;
do {
- ERTS_TW_ASSERT(tmr->timeout_pos > to_pos);
+ ERTS_TW_ASSERT(tmr->timeout_pos >= pos_min);
tmr = tmr->next;
} while (tmr != end);
}
diff --git a/erts/emulator/beam/utils.c b/erts/emulator/beam/utils.c
index 8f3f48f38f..9263798a28 100644
--- a/erts/emulator/beam/utils.c
+++ b/erts/emulator/beam/utils.c
@@ -3594,7 +3594,7 @@ store_external_or_ref_(Uint **hpp, ErlOffHeap* oh, Eterm ns)
ErtsMRefThing *mreft = (ErtsMRefThing *) from_hp;
ErtsMagicBinary *mb = mreft->mb;
ASSERT(is_magic_ref_thing(from_hp));
- erts_refc_inc(&mb->refc, 2);
+ erts_refc_inc(&mb->intern.refc, 2);
OH_OVERHEAD(oh, mb->orig_size / sizeof(Eterm));
}
diff --git a/erts/emulator/hipe/hipe_bif0.c b/erts/emulator/hipe/hipe_bif0.c
index 8b420b9e9b..072ca19eae 100644
--- a/erts/emulator/hipe/hipe_bif0.c
+++ b/erts/emulator/hipe/hipe_bif0.c
@@ -603,10 +603,7 @@ static void print_mfa(Eterm mod, Eterm fun, unsigned int ari)
}
#endif
-/*
- * Convert {M,F,A} to pointer to first insn after initial func_info.
- */
-static Uint *hipe_find_emu_address(Eterm mod, Eterm name, unsigned int arity)
+static ErtsCodeInfo* hipe_find_emu_address(Eterm mod, Eterm name, unsigned int arity)
{
Module *modp;
BeamCodeHeader* code_hdr;
@@ -617,15 +614,15 @@ static Uint *hipe_find_emu_address(Eterm mod, Eterm name, unsigned int arity)
return NULL;
n = code_hdr->num_functions;
for (i = 0; i < n; ++i) {
- Uint *code_ptr = (Uint*)code_hdr->functions[i];
- ASSERT(code_ptr[0] == BeamOpCode(op_i_func_info_IaaI));
- if (code_ptr[3] == name && code_ptr[4] == arity)
- return code_ptr+5;
+ ErtsCodeInfo *ci = code_hdr->functions[i];
+ ASSERT(ci->op == BeamOpCode(op_i_func_info_IaaI));
+ if (ci->mfa.function == name && ci->mfa.arity == arity)
+ return ci;
}
return NULL;
}
-Uint *hipe_bifs_find_pc_from_mfa(Eterm term)
+ErtsCodeInfo* hipe_bifs_find_pc_from_mfa(Eterm term)
{
struct hipe_mfa mfa;
@@ -636,10 +633,10 @@ Uint *hipe_bifs_find_pc_from_mfa(Eterm term)
BIF_RETTYPE hipe_bifs_fun_to_address_1(BIF_ALIST_1)
{
- Eterm *pc = hipe_bifs_find_pc_from_mfa(BIF_ARG_1);
- if (!pc)
+ ErtsCodeInfo* ci = hipe_bifs_find_pc_from_mfa(BIF_ARG_1);
+ if (!ci)
BIF_ERROR(BIF_P, BADARG);
- BIF_RET(address_to_term(pc, BIF_P));
+ BIF_RET(address_to_term(erts_codeinfo_to_code(ci), BIF_P));
}
BIF_RETTYPE hipe_bifs_commit_patch_load_1(BIF_ALIST_1)
@@ -652,7 +649,7 @@ BIF_RETTYPE hipe_bifs_commit_patch_load_1(BIF_ALIST_1)
BIF_RETTYPE hipe_bifs_set_native_address_3(BIF_ALIST_3)
{
- Eterm *pc;
+ ErtsCodeInfo *ci;
void *address;
int is_closure;
struct hipe_mfa mfa;
@@ -675,11 +672,12 @@ BIF_RETTYPE hipe_bifs_set_native_address_3(BIF_ALIST_3)
simply have called hipe_bifs_find_pc_from_mfa(). */
if (!term_to_mfa(BIF_ARG_1, &mfa))
BIF_ERROR(BIF_P, BADARG);
- pc = hipe_find_emu_address(mfa.mod, mfa.fun, mfa.ari);
+ ci = hipe_find_emu_address(mfa.mod, mfa.fun, mfa.ari);
- if (pc) {
- DBG_TRACE_MFA(mfa.mod,mfa.fun,mfa.ari, "set beam call trap at %p -> %p", pc, address);
- hipe_set_call_trap(pc, address, is_closure);
+ if (ci) {
+ DBG_TRACE_MFA(mfa.mod,mfa.fun,mfa.ari, "set beam call trap at %p -> %p",
+ erts_codeinfo_to_code(ci), address);
+ hipe_set_call_trap(ci, address, is_closure);
BIF_RET(am_true);
}
DBG_TRACE_MFA(mfa.mod,mfa.fun,mfa.ari, "failed set call trap to %p, no beam code found", address);
@@ -1618,46 +1616,6 @@ static void purge_mfa(struct hipe_mfa_info* p)
erts_free(ERTS_ALC_T_HIPE_LL, p);
}
-/* Called by init:restart after unloading all hipe compiled modules
- * to work around old bug that caused execution of deallocated beam code.
- * Can be removed now when delete/purge of native modules works better.
- * Test: Do init:restart in debug compiled vm with hipe compiled kernel.
- */
-static void hipe_purge_all_refs(void)
-{
- struct hipe_mfa_info **bucket;
- unsigned int i, nrbuckets;
-
- hipe_mfa_info_table_rwlock();
-
- ASSERT(hipe_mfa_info_table.used == 0);
- bucket = hipe_mfa_info_table.bucket;
- nrbuckets = 1 << hipe_mfa_info_table.log2size;
- for (i = 0; i < nrbuckets; ++i) {
- ASSERT(bucket[i] == NULL);
- while (bucket[i] != NULL) {
- struct hipe_mfa_info* mfa = bucket[i];
- bucket[i] = mfa->bucket.next;
-
- hash_erase(&mod2mfa_tab, mfa);
- erts_free(ERTS_ALC_T_HIPE_LL, mfa);
- }
- }
- hipe_mfa_info_table.used = 0;
- hipe_mfa_info_table_rwunlock();
-}
-
-BIF_RETTYPE hipe_bifs_remove_refs_from_1(BIF_ALIST_1)
-{
- if (BIF_ARG_1 == am_all) {
- hipe_purge_all_refs();
- BIF_RET(am_ok);
- }
-
- ASSERT(!"hipe_bifs_remove_refs_from_1() called");
- BIF_ERROR(BIF_P, BADARG);
-}
-
int hipe_purge_need_blocking(Module* modp)
{
/* SVERK: Verify if this is really necessary */
@@ -1978,6 +1936,6 @@ BIF_RETTYPE hipe_bifs_alloc_loader_state_1(BIF_ALIST_1)
hp = HAlloc(BIF_P, ERTS_MAGIC_REF_THING_SIZE);
res = erts_mk_magic_ref(&hp, &MSO(BIF_P), magic);
- erts_refc_dec(&magic->refc, 1);
+ erts_refc_dec(&magic->intern.refc, 1);
BIF_RET(res);
}
diff --git a/erts/emulator/hipe/hipe_bif0.h b/erts/emulator/hipe/hipe_bif0.h
index 811c3801c1..d6be473ff5 100644
--- a/erts/emulator/hipe/hipe_bif0.h
+++ b/erts/emulator/hipe/hipe_bif0.h
@@ -26,7 +26,7 @@
#ifndef HIPE_BIF0_H
#define HIPE_BIF0_H
-extern Uint *hipe_bifs_find_pc_from_mfa(Eterm mfa);
+extern ErtsCodeInfo *hipe_bifs_find_pc_from_mfa(Eterm mfa);
extern void hipe_mfa_info_table_init(void);
extern void *hipe_get_remote_na(Eterm m, Eterm f, unsigned int a);
diff --git a/erts/emulator/hipe/hipe_bif0.tab b/erts/emulator/hipe/hipe_bif0.tab
index 264ea2c34a..078ebc40b7 100644
--- a/erts/emulator/hipe/hipe_bif0.tab
+++ b/erts/emulator/hipe/hipe_bif0.tab
@@ -82,7 +82,6 @@ bif hipe_bifs:patch_insn/3
bif hipe_bifs:patch_call/3
bif hipe_bifs:add_ref/2
-bif hipe_bifs:remove_refs_from/1
bif hipe_bifs:alloc_loader_state/1
diff --git a/erts/emulator/hipe/hipe_bif1.c b/erts/emulator/hipe/hipe_bif1.c
index 0ba0fa5172..0d4c1539b6 100644
--- a/erts/emulator/hipe/hipe_bif1.c
+++ b/erts/emulator/hipe/hipe_bif1.c
@@ -39,13 +39,15 @@
BIF_RETTYPE hipe_bifs_call_count_on_1(BIF_ALIST_1)
{
+ ErtsCodeInfo *ci;
Eterm *pc;
struct hipe_call_count *hcc;
- pc = hipe_bifs_find_pc_from_mfa(BIF_ARG_1);
- if (!pc)
+ ci = hipe_bifs_find_pc_from_mfa(BIF_ARG_1);
+ if (!ci)
BIF_ERROR(BIF_P, BADARG);
- ASSERT(pc[-6] == BeamOpCode(op_i_func_info_IaaI));
+ ASSERT(ci->op == BeamOpCode(op_i_func_info_IaaI));
+ pc = erts_codeinfo_to_code(ci);
if (pc[0] == BeamOpCode(op_hipe_trap_call))
BIF_ERROR(BIF_P, BADARG);
if (pc[0] == BeamOpCode(op_hipe_call_count))
@@ -53,59 +55,65 @@ BIF_RETTYPE hipe_bifs_call_count_on_1(BIF_ALIST_1)
hcc = erts_alloc(ERTS_ALC_T_HIPE_SL, sizeof(*hcc));
hcc->count = 0;
hcc->opcode = pc[0];
- pc[-4] = (Eterm)hcc;
+ ci->u.hcc = hcc;
pc[0] = BeamOpCode(op_hipe_call_count);
BIF_RET(am_true);
}
BIF_RETTYPE hipe_bifs_call_count_off_1(BIF_ALIST_1)
{
+ ErtsCodeInfo* ci;
Eterm *pc;
struct hipe_call_count *hcc;
unsigned count;
- pc = hipe_bifs_find_pc_from_mfa(BIF_ARG_1);
- if (!pc)
+ ci = hipe_bifs_find_pc_from_mfa(BIF_ARG_1);
+ if (!ci)
BIF_ERROR(BIF_P, BADARG);
- ASSERT(pc[-6] == BeamOpCode(op_i_func_info_IaaI));
+ ASSERT(ci->op == BeamOpCode(op_i_func_info_IaaI));
+ pc = erts_codeinfo_to_code(ci);
if (pc[0] != BeamOpCode(op_hipe_call_count))
BIF_RET(am_false);
- hcc = (struct hipe_call_count*)pc[-4];
+ hcc = ci->u.hcc;
count = hcc->count;
pc[0] = hcc->opcode;
- pc[-4] = (Eterm)NULL;
+ ci->u.hcc = NULL;
erts_free(ERTS_ALC_T_HIPE_SL, hcc);
BIF_RET(make_small(count));
}
BIF_RETTYPE hipe_bifs_call_count_get_1(BIF_ALIST_1)
{
+ ErtsCodeInfo* ci;
Eterm *pc;
struct hipe_call_count *hcc;
- pc = hipe_bifs_find_pc_from_mfa(BIF_ARG_1);
- if (!pc)
+ ci = hipe_bifs_find_pc_from_mfa(BIF_ARG_1);
+ if (!ci)
BIF_ERROR(BIF_P, BADARG);
- ASSERT(pc[-6] == BeamOpCode(op_i_func_info_IaaI));
+ ASSERT(ci->op == BeamOpCode(op_i_func_info_IaaI));
+ pc = erts_codeinfo_to_code(ci);
if (pc[0] != BeamOpCode(op_hipe_call_count))
BIF_RET(am_false);
- hcc = (struct hipe_call_count*)pc[-4];
+ hcc = ci->u.hcc;
BIF_RET(make_small(hcc->count));
}
BIF_RETTYPE hipe_bifs_call_count_clear_1(BIF_ALIST_1)
{
+ ErtsCodeInfo* ci;
Eterm *pc;
struct hipe_call_count *hcc;
unsigned count;
- pc = hipe_bifs_find_pc_from_mfa(BIF_ARG_1);
- if (!pc)
+ ci = hipe_bifs_find_pc_from_mfa(BIF_ARG_1);
+ if (!ci)
BIF_ERROR(BIF_P, BADARG);
- ASSERT(pc[-6] == BeamOpCode(op_i_func_info_IaaI));
+ ASSERT(ci->op == BeamOpCode(op_i_func_info_IaaI));
+ pc = erts_codeinfo_to_code(ci);
if (pc[0] != BeamOpCode(op_hipe_call_count))
BIF_RET(am_false);
- hcc = (struct hipe_call_count*)pc[-4];
+ hcc = ci->u.hcc;
count = hcc->count;
hcc->count = 0;
BIF_RET(make_small(count));
diff --git a/erts/emulator/hipe/hipe_load.c b/erts/emulator/hipe/hipe_load.c
index 0b53880628..9a9e3c6b12 100644
--- a/erts/emulator/hipe/hipe_load.c
+++ b/erts/emulator/hipe/hipe_load.c
@@ -81,7 +81,7 @@ Binary *hipe_alloc_loader_state(Eterm module)
magic = erts_create_magic_binary(sizeof(HipeLoaderState),
hipe_loader_state_dtor);
- erts_refc_inc(&magic->refc, 1);
+ erts_refc_inc(&magic->intern.refc, 1);
stp = ERTS_MAGIC_BIN_DATA(magic);
stp->module = module;
diff --git a/erts/emulator/hipe/hipe_mode_switch.c b/erts/emulator/hipe/hipe_mode_switch.c
index 712f65f629..1270a94986 100644
--- a/erts/emulator/hipe/hipe_mode_switch.c
+++ b/erts/emulator/hipe/hipe_mode_switch.c
@@ -176,14 +176,15 @@ void hipe_mode_switch_init(void)
hipe_mfa_info_table_init();
}
-void hipe_set_call_trap(Uint *bfun, void *nfun, int is_closure)
+void hipe_set_call_trap(ErtsCodeInfo* ci, void *nfun, int is_closure)
{
- HIPE_ASSERT(bfun[-5] == BeamOpCode(op_i_func_info_IaaI));
+ BeamInstr* bfun = erts_codeinfo_to_code(ci);
+ HIPE_ASSERT(ci->op == BeamOpCode(op_i_func_info_IaaI));
bfun[0] =
is_closure
? BeamOpCode(op_hipe_trap_call_closure)
: BeamOpCode(op_hipe_trap_call);
- bfun[-4] = (Uint)nfun;
+ ci->u.ncallee = (void (*)(void)) nfun;
}
static __inline__ void
diff --git a/erts/emulator/hipe/hipe_mode_switch.h b/erts/emulator/hipe/hipe_mode_switch.h
index 334e978307..7b896872a6 100644
--- a/erts/emulator/hipe/hipe_mode_switch.h
+++ b/erts/emulator/hipe/hipe_mode_switch.h
@@ -55,7 +55,7 @@
extern int hipe_modeswitch_debug;
void hipe_mode_switch_init(void);
-void hipe_set_call_trap(Uint *bfun, void *nfun, int is_closure);
+void hipe_set_call_trap(ErtsCodeInfo*, void *nfun, int is_closure);
Process *hipe_mode_switch(Process*, unsigned, Eterm*);
void hipe_inc_nstack(Process *p);
void hipe_empty_nstack(Process *p);
diff --git a/erts/emulator/hipe/hipe_native_bif.c b/erts/emulator/hipe/hipe_native_bif.c
index e581f07f56..342407ef62 100644
--- a/erts/emulator/hipe/hipe_native_bif.c
+++ b/erts/emulator/hipe/hipe_native_bif.c
@@ -323,7 +323,6 @@ char *hipe_bs_allocate(int len)
Binary *bptr;
bptr = erts_bin_nrml_alloc(len);
- erts_refc_init(&bptr->refc, 1);
return bptr->orig_bytes;
}
diff --git a/erts/emulator/sys/common/erl_mseg.c b/erts/emulator/sys/common/erl_mseg.c
index 1e05fd3490..d1895f3793 100644
--- a/erts/emulator/sys/common/erl_mseg.c
+++ b/erts/emulator/sys/common/erl_mseg.c
@@ -87,6 +87,7 @@ static const int debruijn[32] = {
#define CACHE_AREAS (32 - MSEG_ALIGN_BITS)
+/* FIXME: segment sizes > 2 GB result in bogus negative indices */
#define SIZE_TO_CACHE_AREA_IDX(S) (LOG2((S)) - MSEG_ALIGN_BITS)
#define MAX_CACHE_SIZE (30)
@@ -396,6 +397,9 @@ static ERTS_INLINE int cache_bless_segment(ErtsMsegAllctr_t *ma, void *seg, UWor
if (MSEG_FLG_IS_2POW(flags)) {
int ix = SIZE_TO_CACHE_AREA_IDX(size);
+ if (ix < 0)
+ return 0;
+
ASSERT(ix < CACHE_AREAS);
ASSERT((1 << (ix + MSEG_ALIGN_BITS)) == size);
@@ -471,6 +475,9 @@ static ERTS_INLINE void *cache_get_segment(ErtsMsegAllctr_t *ma, UWord *size_p,
ASSERT(IS_2POW(size));
+ if (ix < 0)
+ return NULL;
+
for( i = ix; i < CACHE_AREAS; i++) {
if (erts_circleq_is_empty(&(ma->cache_powered_node[i])))
diff --git a/erts/emulator/test/list_bif_SUITE.erl b/erts/emulator/test/list_bif_SUITE.erl
index 9c40929926..08574bff71 100644
--- a/erts/emulator/test/list_bif_SUITE.erl
+++ b/erts/emulator/test/list_bif_SUITE.erl
@@ -23,7 +23,7 @@
-export([all/0, suite/0]).
-export([hd_test/1,tl_test/1,t_length/1,t_list_to_pid/1,
- t_list_to_float/1,t_list_to_integer/1]).
+ t_list_to_port/1,t_list_to_float/1,t_list_to_integer/1]).
suite() ->
@@ -32,7 +32,7 @@ suite() ->
all() ->
- [hd_test, tl_test, t_length, t_list_to_pid,
+ [hd_test, tl_test, t_length, t_list_to_pid, t_list_to_port,
t_list_to_float, t_list_to_integer].
%% Tests list_to_integer and string:to_integer
@@ -106,10 +106,25 @@ t_list_to_pid(Config) when is_list(Config) ->
{'EXIT', {badarg, _}} ->
ok;
Res ->
- ct:fail("list_to_pid/1 with incorrect arg succeeded.~nResult: ~p", [Res])
+ ct:fail("list_to_pid/1 with incorrect arg succeeded.~n"
+ "Result: ~p", [Res])
end,
ok.
+%% Test list_to_port/1 with correct and incorrect arguments.
+
+t_list_to_port(Config) when is_list(Config) ->
+ Me = hd(erlang:ports()),
+ MyListedPid = port_to_list(Me),
+ Me = list_to_port(MyListedPid),
+ case catch list_to_port(id("Incorrect list")) of
+ {'EXIT', {badarg, _}} ->
+ ok;
+ Res ->
+ ct:fail("list_to_port/1 with incorrect arg succeeded.~n"
+ "Result: ~p", [Res])
+ end,
+ ok.
%% Test list_to_float/1 with correct and incorrect arguments.
diff --git a/erts/emulator/test/scheduler_SUITE.erl b/erts/emulator/test/scheduler_SUITE.erl
index 885298ce34..64e51e7d7c 100644
--- a/erts/emulator/test/scheduler_SUITE.erl
+++ b/erts/emulator/test/scheduler_SUITE.erl
@@ -1087,12 +1087,8 @@ scheduler_threads(Config) when is_list(Config) ->
{Sched, SchedOnln, _} = get_sstate(Config, ""),
%% Configure half the number of both the scheduler threads and
%% the scheduler threads online.
- {HalfSched, HalfSchedOnln} = case SmpSupport of
- false -> {1,1};
- true ->
- {Sched div 2,
- SchedOnln div 2}
- end,
+ {HalfSched, HalfSchedOnln} = {lists:max([1,Sched div 2]),
+ lists:max([1,SchedOnln div 2])},
{HalfSched, HalfSchedOnln, _} = get_sstate(Config, "+SP 50:50"),
%% Use +S to configure 4x the number of scheduler threads and
%% 4x the number of scheduler threads online, but alter that
@@ -1149,12 +1145,8 @@ dirty_scheduler_threads(Config) when is_list(Config) ->
dirty_scheduler_threads_test(Config) ->
SmpSupport = erlang:system_info(smp_support),
{Sched, SchedOnln, _} = get_dsstate(Config, ""),
- {HalfSched, HalfSchedOnln} = case SmpSupport of
- false -> {1,1};
- true ->
- {Sched div 2,
- SchedOnln div 2}
- end,
+ {HalfSched, HalfSchedOnln} = {lists:max([1,Sched div 2]),
+ lists:max([1,SchedOnln div 2])},
Cmd1 = "+SDcpu "++integer_to_list(HalfSched)++":"++
integer_to_list(HalfSchedOnln),
{HalfSched, HalfSchedOnln, _} = get_dsstate(Config, Cmd1),
diff --git a/erts/emulator/test/smoke_test_SUITE.erl b/erts/emulator/test/smoke_test_SUITE.erl
index 5eccdc562b..45b28b28a5 100644
--- a/erts/emulator/test/smoke_test_SUITE.erl
+++ b/erts/emulator/test/smoke_test_SUITE.erl
@@ -66,17 +66,10 @@ boot_combo(Config) when is_list(Config) ->
ok
end
end,
- SMPDisable = fun () -> false = erlang:system_info(smp_support) end,
try
chk_boot(Config, "+Ktrue", NOOP),
chk_boot(Config, "+A42", A42),
- chk_boot(Config, "-smp disable", SMPDisable),
chk_boot(Config, "+Ktrue +A42", A42),
- chk_boot(Config, "-smp disable +A42",
- fun () -> SMPDisable(), A42() end),
- chk_boot(Config, "-smp disable +Ktrue", SMPDisable),
- chk_boot(Config, "-smp disable +Ktrue +A42",
- fun () -> SMPDisable(), A42() end),
%% A lot more combos could be implemented...
ok
after
diff --git a/erts/emulator/test/statistics_SUITE.erl b/erts/emulator/test/statistics_SUITE.erl
index f51244485b..729e86cb4f 100644
--- a/erts/emulator/test/statistics_SUITE.erl
+++ b/erts/emulator/test/statistics_SUITE.erl
@@ -329,9 +329,9 @@ scheduler_wall_time_test(Type) ->
%% 50% load
HalfHogs = [StartHog() || _ <- lists:seq(1, (Schedulers-1) div 2)],
HalfDirtyCPUHogs = [StartDirtyHog(dirty_cpu)
- || _ <- lists:seq(1, DirtyCPUSchedulers div 2)],
+ || _ <- lists:seq(1, lists:max([1,DirtyCPUSchedulers div 2]))],
HalfDirtyIOHogs = [StartDirtyHog(dirty_io)
- || _ <- lists:seq(1, DirtyIOSchedulers div 2)],
+ || _ <- lists:seq(1, lists:max([1,DirtyIOSchedulers div 2]))],
HalfLoad = lists:sum(get_load(Type)) div TotLoadSchedulers,
if Schedulers < 2, HalfLoad > 80 -> ok; %% Ok only one scheduler online and one hog
%% We want roughly 50% load
diff --git a/erts/etc/common/erlexec.c b/erts/etc/common/erlexec.c
index a1c6bb223b..f11ec2320a 100644
--- a/erts/etc/common/erlexec.c
+++ b/erts/etc/common/erlexec.c
@@ -141,6 +141,8 @@ static char *pluss_val_switches[] = {
"wt",
"ws",
"ss",
+ "ssdcpu",
+ "ssdio",
"pp",
"ub",
NULL
@@ -203,8 +205,8 @@ void error(char* format, ...);
* Local functions.
*/
-#if !defined(ERTS_HAVE_SMP_EMU)
-static void usage_notsup(const char *switchname);
+#if !defined(ERTS_HAVE_SMP_EMU) || !defined(ERTS_HAVE_PLAIN_EMU)
+static void usage_notsup(const char *switchname, const char *alt);
#endif
static char **build_args_from_env(char *env_var);
static char **build_args_from_string(char *env_var);
@@ -487,8 +489,7 @@ int main(int argc, char **argv)
cpuinfo = erts_cpu_info_create();
/* '-smp auto' is default */
#ifdef ERTS_HAVE_SMP_EMU
- if (erts_get_cpu_configured(cpuinfo) > 1)
- emu_type |= EMU_TYPE_SMP;
+ emu_type |= EMU_TYPE_SMP;
#endif
#if defined(__WIN32__) && defined(WIN32_ALWAYS_DEBUG)
@@ -520,12 +521,11 @@ int main(int argc, char **argv)
i++;
smp_auto:
emu_type_passed |= EMU_TYPE_SMP;
-#ifdef ERTS_HAVE_SMP_EMU
- if (erts_get_cpu_configured(cpuinfo) > 1)
- emu_type |= EMU_TYPE_SMP;
- else
+#if defined(ERTS_HAVE_PLAIN_EMU) && !defined(ERTS_HAVE_SMP_EMU)
+ emu_type &= ~EMU_TYPE_SMP;
+#else
+ emu_type |= EMU_TYPE_SMP;
#endif
- emu_type &= ~EMU_TYPE_SMP;
}
else if (strcmp(argv[i+1], "enable") == 0) {
i++;
@@ -534,14 +534,18 @@ int main(int argc, char **argv)
#ifdef ERTS_HAVE_SMP_EMU
emu_type |= EMU_TYPE_SMP;
#else
- usage_notsup("-smp enable");
+ usage_notsup("-smp enable", "");
#endif
}
else if (strcmp(argv[i+1], "disable") == 0) {
i++;
smp_disable:
- emu_type_passed |= EMU_TYPE_SMP;
+ emu_type_passed &= ~EMU_TYPE_SMP;
+#ifdef ERTS_HAVE_PLAIN_EMU
emu_type &= ~EMU_TYPE_SMP;
+#else
+ usage_notsup("-smp disable", " Use \"+S 1\" instead.");
+#endif
}
else {
smp:
@@ -550,7 +554,7 @@ int main(int argc, char **argv)
#ifdef ERTS_HAVE_SMP_EMU
emu_type |= EMU_TYPE_SMP;
#else
- usage_notsup("-smp");
+ usage_notsup("-smp", "");
#endif
}
} else if (strcmp(argv[i], "-smpenable") == 0) {
@@ -1187,14 +1191,14 @@ usage_aux(void)
#ifdef __WIN32__
"[-start_erl [datafile]] "
#endif
- "[-smp "
+ "[-smp [auto"
#ifdef ERTS_HAVE_SMP_EMU
- "[enable|"
+ "|enable"
#endif
- "auto|disable"
-#ifdef ERTS_HAVE_SMP_EMU
- "]"
+#ifdef ERTS_HAVE_PLAIN_EMU
+ "|disable"
#endif
+ "]"
"] "
"[-make] [-man [manopts] MANPAGE] [-x] [-emu_args] [-start_epmd BOOLEAN] "
"[-args_file FILENAME] [+A THREADS] [+a SIZE] [+B[c|d|i]] [+c [BOOLEAN]] "
@@ -1216,11 +1220,11 @@ usage(const char *switchname)
usage_aux();
}
-#if !defined(ERTS_HAVE_SMP_EMU)
+#if !defined(ERTS_HAVE_SMP_EMU) || !defined(ERTS_HAVE_PLAIN_EMU)
static void
-usage_notsup(const char *switchname)
+usage_notsup(const char *switchname, const char *alt)
{
- fprintf(stderr, "Argument \'%s\' not supported.\n", switchname);
+ fprintf(stderr, "Argument \'%s\' not supported.%s\n", switchname, alt);
usage_aux();
}
#endif
diff --git a/erts/preloaded/ebin/erl_prim_loader.beam b/erts/preloaded/ebin/erl_prim_loader.beam
index 4b2f07f1a4..b17b100261 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/erl_tracer.beam b/erts/preloaded/ebin/erl_tracer.beam
index c4e1e57c40..33f268737a 100644
--- a/erts/preloaded/ebin/erl_tracer.beam
+++ b/erts/preloaded/ebin/erl_tracer.beam
Binary files differ
diff --git a/erts/preloaded/ebin/erlang.beam b/erts/preloaded/ebin/erlang.beam
index c584fe6f97..5980e23fe2 100644
--- a/erts/preloaded/ebin/erlang.beam
+++ b/erts/preloaded/ebin/erlang.beam
Binary files differ
diff --git a/erts/preloaded/ebin/erts_code_purger.beam b/erts/preloaded/ebin/erts_code_purger.beam
index af7028b01c..c109b6c52a 100644
--- a/erts/preloaded/ebin/erts_code_purger.beam
+++ b/erts/preloaded/ebin/erts_code_purger.beam
Binary files differ
diff --git a/erts/preloaded/ebin/erts_dirty_process_code_checker.beam b/erts/preloaded/ebin/erts_dirty_process_code_checker.beam
index a6ecba2a17..63e6d5a656 100644
--- a/erts/preloaded/ebin/erts_dirty_process_code_checker.beam
+++ b/erts/preloaded/ebin/erts_dirty_process_code_checker.beam
Binary files differ
diff --git a/erts/preloaded/ebin/erts_internal.beam b/erts/preloaded/ebin/erts_internal.beam
index c4b281163e..878563c7e2 100644
--- a/erts/preloaded/ebin/erts_internal.beam
+++ b/erts/preloaded/ebin/erts_internal.beam
Binary files differ
diff --git a/erts/preloaded/ebin/erts_literal_area_collector.beam b/erts/preloaded/ebin/erts_literal_area_collector.beam
index 4552a34ae2..5b464e23d1 100644
--- a/erts/preloaded/ebin/erts_literal_area_collector.beam
+++ b/erts/preloaded/ebin/erts_literal_area_collector.beam
Binary files differ
diff --git a/erts/preloaded/ebin/init.beam b/erts/preloaded/ebin/init.beam
index e90a988a07..47a086536a 100644
--- a/erts/preloaded/ebin/init.beam
+++ b/erts/preloaded/ebin/init.beam
Binary files differ
diff --git a/erts/preloaded/ebin/otp_ring0.beam b/erts/preloaded/ebin/otp_ring0.beam
index 77b0b7a537..198a9f0fcd 100644
--- a/erts/preloaded/ebin/otp_ring0.beam
+++ b/erts/preloaded/ebin/otp_ring0.beam
Binary files differ
diff --git a/erts/preloaded/ebin/prim_eval.beam b/erts/preloaded/ebin/prim_eval.beam
index ac9916cc86..eb6409e460 100644
--- a/erts/preloaded/ebin/prim_eval.beam
+++ b/erts/preloaded/ebin/prim_eval.beam
Binary files differ
diff --git a/erts/preloaded/ebin/prim_file.beam b/erts/preloaded/ebin/prim_file.beam
index 2d8a355c82..84a7b734e5 100644
--- a/erts/preloaded/ebin/prim_file.beam
+++ b/erts/preloaded/ebin/prim_file.beam
Binary files differ
diff --git a/erts/preloaded/ebin/prim_inet.beam b/erts/preloaded/ebin/prim_inet.beam
index e2559ac034..066fd0e172 100644
--- a/erts/preloaded/ebin/prim_inet.beam
+++ b/erts/preloaded/ebin/prim_inet.beam
Binary files differ
diff --git a/erts/preloaded/ebin/prim_zip.beam b/erts/preloaded/ebin/prim_zip.beam
index 12cbb5bf7a..327c55ce4d 100644
--- a/erts/preloaded/ebin/prim_zip.beam
+++ b/erts/preloaded/ebin/prim_zip.beam
Binary files differ
diff --git a/erts/preloaded/ebin/zlib.beam b/erts/preloaded/ebin/zlib.beam
index f5217eadf6..687942fbd5 100644
--- a/erts/preloaded/ebin/zlib.beam
+++ b/erts/preloaded/ebin/zlib.beam
Binary files differ
diff --git a/erts/preloaded/src/add_abstract_code b/erts/preloaded/src/add_abstract_code
index 943987872e..f53791cdc2 100644
--- a/erts/preloaded/src/add_abstract_code
+++ b/erts/preloaded/src/add_abstract_code
@@ -28,12 +28,12 @@
main([BeamFile,AbstrFile]) ->
{ok,_,Chunks0} = beam_lib:all_chunks(BeamFile),
{ok,Abstr} = file:consult(AbstrFile),
- Chunks1 = lists:keyreplace("Abst", 1, Chunks0,
- {"Abst",term_to_binary({raw_abstract_v1,Abstr})}),
- {"CInf",CInf0} = lists:keyfind("CInf", 1, Chunks1),
- CInf = fix_options(CInf0),
- Chunks = lists:keyreplace("CInf", 1, Chunks1, {"CInf",CInf}),
- {ok,Module} = beam_lib:build_module(Chunks),
+ {"CInf",CInf0} = lists:keyfind("CInf", 1, Chunks0),
+ {CInf, COpts} = fix_options(CInf0),
+ Chunks1 = lists:keyreplace("CInf", 1, Chunks0, {"CInf",CInf}),
+ Chunks2 = lists:keyreplace("Dbgi", 1, Chunks1,
+ {"Dbgi",term_to_binary({debug_info_v1,erl_abstract_code,{Abstr, COpts}})}),
+ {ok,Module} = beam_lib:build_module(Chunks2),
ok = file:write_file(BeamFile, Module),
init:stop().
@@ -42,4 +42,4 @@ fix_options(CInf0) ->
{options,Opts0} = lists:keyfind(options, 1, CInf1),
Opts = Opts0 -- [from_asm],
CInf = lists:keyreplace(options, 1, CInf1, {options,Opts}),
- term_to_binary(CInf).
+ {term_to_binary(CInf), Opts}.
diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl
index 888d2beee0..8499d40c9a 100644
--- a/erts/preloaded/src/erlang.erl
+++ b/erts/preloaded/src/erlang.erl
@@ -129,7 +129,7 @@
-export([list_to_atom/1, list_to_binary/1]).
-export([list_to_bitstring/1, list_to_existing_atom/1, list_to_float/1]).
-export([list_to_integer/1, list_to_integer/2]).
--export([list_to_pid/1, list_to_ref/1, list_to_tuple/1, loaded/0]).
+-export([list_to_pid/1, list_to_port/1, list_to_ref/1, list_to_tuple/1, loaded/0]).
-export([localtime/0, make_ref/0]).
-export([map_size/1, match_spec_test/3, md5/1, md5_final/1]).
-export([md5_init/0, md5_update/2, module_loaded/1, monitor/2]).
@@ -1159,9 +1159,15 @@ list_to_integer(_String,_Base) ->
String :: string().
list_to_pid(_String) ->
erlang:nif_error(undefined).
+
+%% list_to_port/1
+-spec list_to_port(String) -> port() when
+ String :: string().
+list_to_port(_String) ->
+ erlang:nif_error(undefined).
%% list_to_ref/1
--spec erlang:list_to_ref(String) -> reference() when
+-spec list_to_ref(String) -> reference() when
String :: string().
list_to_ref(_String) ->
erlang:nif_error(undefined).
@@ -1337,7 +1343,7 @@ pid_to_list(_Pid) ->
erlang:nif_error(undefined).
%% port_to_list/1
--spec erlang:port_to_list(Port) -> string() when
+-spec port_to_list(Port) -> string() when
Port :: port().
port_to_list(_Port) ->
erlang:nif_error(undefined).
@@ -1547,7 +1553,7 @@ read_timer(_TimerRef, _Options) ->
erlang:nif_error(undefined).
%% ref_to_list/1
--spec erlang:ref_to_list(Ref) -> string() when
+-spec ref_to_list(Ref) -> string() when
Ref :: reference().
ref_to_list(_Ref) ->
erlang:nif_error(undefined).
diff --git a/erts/preloaded/src/init.erl b/erts/preloaded/src/init.erl
index c12a5b159a..1ccf8d599f 100644
--- a/erts/preloaded/src/init.erl
+++ b/erts/preloaded/src/init.erl
@@ -689,16 +689,8 @@ do_unload([M|Mods]) ->
catch erlang:purge_module(M),
do_unload(Mods);
do_unload([]) ->
- purge_all_hipe_refs(),
ok.
-purge_all_hipe_refs() ->
- case erlang:system_info(hipe_architecture) of
- undefined -> ok;
- _ -> hipe_bifs:remove_refs_from(all)
- end.
-
-
sub([H|T],L) -> sub(T,del(H,L));
sub([],L) -> L.
diff --git a/lib/common_test/doc/src/ct.xml b/lib/common_test/doc/src/ct.xml
index ea9f956271..cd1e51a9a9 100644
--- a/lib/common_test/doc/src/ct.xml
+++ b/lib/common_test/doc/src/ct.xml
@@ -1190,7 +1190,7 @@
Opts.</fsummary>
<type>
<v>Opts = [OptTuples]</v>
- <v>OptTuples = {dir, TestDirs} | {suite, Suites} | {group, Groups} | {testcase, Cases} | {spec, TestSpecs} | {join_specs, Bool} | {label, Label} | {config, CfgFiles} | {userconfig, UserConfig} | {allow_user_terms, Bool} | {logdir, LogDir} | {silent_connections, Conns} | {stylesheet, CSSFile} | {cover, CoverSpecFile} | {cover_stop, Bool} | {step, StepOpts} | {event_handler, EventHandlers} | {include, InclDirs} | {auto_compile, Bool} | {abort_if_missing_suites, Bool} | {create_priv_dir, CreatePrivDir} | {multiply_timetraps, M} | {scale_timetraps, Bool} | {repeat, N} | {duration, DurTime} | {until, StopTime} | {force_stop, ForceStop} | {decrypt, DecryptKeyOrFile} | {refresh_logs, LogDir} | {logopts, LogOpts} | {verbosity, VLevels} | {basic_html, Bool} | {esc_chars, Bool} | {ct_hooks, CTHs} | {enable_builtin_hooks, Bool} | {release_shell, Bool}</v>
+ <v>OptTuples = {dir, TestDirs} | {suite, Suites} | {group, Groups} | {testcase, Cases} | {spec, TestSpecs} | {join_specs, Bool} | {label, Label} | {config, CfgFiles} | {userconfig, UserConfig} | {allow_user_terms, Bool} | {logdir, LogDir} | {silent_connections, Conns} | {stylesheet, CSSFile} | {cover, CoverSpecFile} | {cover_stop, Bool} | {step, StepOpts} | {event_handler, EventHandlers} | {include, InclDirs} | {auto_compile, Bool} | {abort_if_missing_suites, Bool} | {create_priv_dir, CreatePrivDir} | {multiply_timetraps, M} | {scale_timetraps, Bool} | {repeat, N} | {duration, DurTime} | {until, StopTime} | {force_stop, ForceStop} | {decrypt, DecryptKeyOrFile} | {refresh_logs, LogDir} | {logopts, LogOpts} | {verbosity, VLevels} | {basic_html, Bool} | {esc_chars, Bool} | {keep_logs,KeepSpec} | {ct_hooks, CTHs} | {enable_builtin_hooks, Bool} | {release_shell, Bool}</v>
<v>TestDirs = [string()] | string()</v>
<v>Suites = [string()] | [atom()] | string() | atom()</v>
<v>Cases = [atom()] | atom()</v>
@@ -1226,6 +1226,7 @@
<v>VLevels = VLevel | [{Category, VLevel}]</v>
<v>VLevel = integer()</v>
<v>Category = atom()</v>
+ <v>KeepSpec = all | pos_integer()</v>
<v>CTHs = [CTHModule | {CTHModule, CTHInitArgs}]</v>
<v>CTHModule = atom()</v>
<v>CTHInitArgs = term()</v>
diff --git a/lib/common_test/doc/src/ct_run.xml b/lib/common_test/doc/src/ct_run.xml
index 9e6229f1dd..af30550719 100644
--- a/lib/common_test/doc/src/ct_run.xml
+++ b/lib/common_test/doc/src/ct_run.xml
@@ -125,6 +125,7 @@
[-until [YYMoMoDD]HHMMSS [-force_stop [skip_rest]]]
[-basic_html]
[-no_esc_chars]
+ [-keep_logs all | NLogs]
[-ct_hooks CTHModule1 CTHOpts1 and CTHModule2 CTHOpts2 and ..
CTHModuleN CTHOptsN]
[-exit_status ignore_config]
@@ -164,6 +165,7 @@
[-until [YYMoMoDD]HHMMSS [-force_stop [skip_rest]]]
[-basic_html]
[-no_esc_chars]
+ [-keep_logs all | NLogs]
[-ct_hooks CTHModule1 CTHOpts1 and CTHModule2 CTHOpts2 and ..
CTHModuleN CTHOptsN]
[-exit_status ignore_config]</pre>
@@ -189,13 +191,15 @@
[-scale_timetraps]
[-create_priv_dir auto_per_run | auto_per_tc | manual_per_tc]
[-basic_html]
- [-no_esc_chars]</pre>
+ [-no_esc_chars]
+ [-keep_logs all | NLogs]</pre>
</section>
<section>
<title>Refresh HTML Index Files</title>
<pre>
- ct_run -refresh_logs [-logdir LogDir] [-basic_html]</pre>
+ ct_run -refresh_logs [-logdir LogDir] [-basic_html]
+ [-keep_logs all | NLogs]</pre>
</section>
<section>
diff --git a/lib/common_test/doc/src/run_test_chapter.xml b/lib/common_test/doc/src/run_test_chapter.xml
index 76e306c4ed..fa336b7e16 100644
--- a/lib/common_test/doc/src/run_test_chapter.xml
+++ b/lib/common_test/doc/src/run_test_chapter.xml
@@ -1322,8 +1322,8 @@
<title>The Unexpected I/O Log</title>
<p>The test suites overview page includes a link to the Unexpected I/O Log.
In this log, <c>Common Test</c> saves printouts made with
- <seealso marker="ct#log-2"><c>ct:log/2</c></seealso> and
- <seealso marker="ct#pal-2"><c>ct:pal/2</c></seealso>, as well as captured system
+ <seealso marker="ct#log-2"><c>ct:log/1,2,3,4,5</c></seealso> and
+ <seealso marker="ct#pal-2"><c>ct:pal/1,2,3,4,5</c></seealso>, as well as captured system
error- and progress reports, which cannot be associated with particular test cases and
therefore cannot be written to individual test case log files. This occurs,
for example, if a log printout is made from an external process (not a test
@@ -1338,7 +1338,7 @@
<title>The Pre- and Post Test I/O Log</title>
<p>The <c>Common Test</c> Framework Log page includes links to the
Pre- and Post Test I/O Log. In this log, <c>Common Test</c> saves printouts made
- with <c>ct:log/2</c> and <c>ct:pal/2</c>, as well as captured system error-
+ with <c>ct:log/1,2,3,4,5</c> and <c>ct:pal/1,2,3,4,5</c>, as well as captured system error-
and progress reports, which take place before, and after, the test run.
Examples of this are printouts from a CT hook init- or terminate function, or
progress reports generated when an OTP application is started from a CT hook
@@ -1349,10 +1349,22 @@
applications, see section
<seealso marker="ct_hooks_chapter#synchronizing">Synchronizing</seealso>
in section Common Test Hooks.</p>
- <note><p>Logging to file with <c>ct:log/2</c> or <c>ct:pal/2</c>
- only works when <c>Common Test</c> is running. Printouts with <c>ct:pal/2</c>
+ <note><p>Logging to file with <c>ct:log/1,2,3,4,5</c> or <c>ct:pal/1,2,3,4,5</c>
+ only works when <c>Common Test</c> is running. Printouts with <c>ct:pal/1,2,3,4,5</c>
are however always displayed on screen.</p></note>
</section>
+
+ <section>
+ <marker id="delete_old_logs"></marker>
+ <title>Delete Old Logs</title>
+ <p><c>Common Test</c> can automatically delete old log. This
+ is specified with the <c>keep_logs</c> option. The default
+ value for this option is <c>all</c>, which means that no
+ logs are deleted. If the value is set to an
+ integer, <c>N</c>, <c>Common Test</c> deletes
+ all <c>ct_run.&lt;timestamp&gt;</c> directories, except
+ the <c>N</c> newest.</p>
+ </section>
</section>
<section>
@@ -1371,24 +1383,38 @@
<p><c>Common Test</c> includes an <em>optional</em> feature to allow
user HTML style sheets for customizing printouts. The
functions in <c>ct</c> that print to a test case HTML log
- file (<c>log/3</c> and <c>pal/3</c>) accept <c>Category</c>
+ file (<c>log/3,4,5</c> and <c>pal/3,4,5</c>) accept <c>Category</c>
as first argument. With this argument a category can be specified
- that can be mapped to a selector in a CSS
- definition. This is useful, especially for coloring text
+ that can be mapped to a named <c>div</c> selector in a CSS rule-set.
+ This is useful, especially for coloring text
differently depending on the type of (or reason for) the
- printout. Say you want one color for test system
+ printout. Say you want one particular background color for test system
configuration information, a different one for test system
state information, and finally one for errors detected by the
test case functions. The corresponding style sheet can
look as follows:</p>
<pre>
- div.sys_config { background:blue; color:white }
- div.sys_state { background:yellow; color:black }
- div.error { background:red; color:white }</pre>
+ div.sys_config { background:blue }
+ div.sys_state { background:yellow }
+ div.error { background:red }</pre>
+
+ <p>Common Test prints the text from <c>ct:log/3,4,5</c> or
+ <c>ct:pal/3,4,5</c> inside a <c>pre</c> element
+ nested under the named <c>div</c> element. Since the <c>pre</c> selector
+ has a predefined CSS rule (in file <c>ct_default.css</c>) for the attributes
+ <c>color</c>, <c>font-family</c> and <c>font-size</c>, if a user wants to
+ change any of the predefined attribute settings, a new rule for <c>pre</c>
+ must be added to the user stylesheet. Example:</p>
+
+ <pre>
+div.error pre { color:white }</pre>
+
+ <p>Here, white text is used instead of the default black for <c>div.error</c>
+ printouts (and no other attribute settings for <c>pre</c> are affected).</p>
<p>To install the CSS file (<c>Common Test</c> inlines the definition in the
- HTML code), the name can be provided when executing <c>ct_run</c>.</p>
+ HTML code), the file name can be provided when executing <c>ct_run</c>.</p>
<p><em>Example:</em></p>
<pre>
@@ -1436,8 +1462,8 @@
suite.</p>
<p>Argument <c>Category</c> in the previous example can have the
- value (atom) <c>sys_config</c> (white on blue), <c>sys_state</c>
- (black on yellow), or <c>error</c> (white on red).</p>
+ value (atom) <c>sys_config</c> (blue background), <c>sys_state</c>
+ (yellow background), or <c>error</c> (white text on red background).</p>
</section>
<section>
diff --git a/lib/common_test/src/ct_logs.erl b/lib/common_test/src/ct_logs.erl
index 09ad709da5..544b019b64 100644
--- a/lib/common_test/src/ct_logs.erl
+++ b/lib/common_test/src/ct_logs.erl
@@ -41,6 +41,7 @@
-export([xhtml/2, locate_priv_file/1, make_relative/1]).
-export([insert_javascript/1]).
-export([uri/1]).
+-export([parse_keep_logs/1]).
%% Logging stuff directly from testcase
-export([tc_log/3, tc_log/4, tc_log/5, tc_log/6,
@@ -1946,7 +1947,11 @@ make_all_runs_index(When) ->
end,
Dirs = filelib:wildcard(logdir_prefix()++"*.*"),
- DirsSorted = (catch sort_all_runs(Dirs)),
+ DirsSorted0 = (catch sort_all_runs(Dirs)),
+ DirsSorted =
+ if When == start -> DirsSorted0;
+ true -> maybe_delete_old_dirs(DirsSorted0)
+ end,
LogCacheInfo = get_cache_data(UseCache),
@@ -2064,6 +2069,36 @@ sort_ct_runs(Dirs) ->
{DateHH1,MM1,SS1} =< {DateHH2,MM2,SS2}
end, Dirs).
+parse_keep_logs([Str="all"]) ->
+ parse_keep_logs(list_to_atom(Str));
+parse_keep_logs([NStr]) ->
+ parse_keep_logs(list_to_integer(NStr));
+parse_keep_logs(all) ->
+ all;
+parse_keep_logs(N) when is_integer(N), N>0 ->
+ N.
+
+maybe_delete_old_dirs(Sorted) ->
+ {Keep,Delete} =
+ case application:get_env(common_test, keep_logs) of
+ {ok,MaxN} when is_integer(MaxN), length(Sorted)>MaxN ->
+ lists:split(MaxN,Sorted);
+ _ ->
+ {Sorted,[]}
+ end,
+ delete_old_dirs(Delete),
+ Keep.
+
+delete_old_dirs([]) ->
+ ok;
+delete_old_dirs(Dirs) ->
+ io:put_chars("\n Removing old test directories:\n"),
+ [begin
+ io:put_chars(" " ++ Dir ++ "\n"),
+ rm_dir(Dir)
+ end|| Dir <- Dirs],
+ ok.
+
dir_diff_all_runs(Dirs, LogCache) ->
case LogCache#log_cache.all_runs of
[] ->
diff --git a/lib/common_test/src/ct_run.erl b/lib/common_test/src/ct_run.erl
index cac176de3a..ba27303c81 100644
--- a/lib/common_test/src/ct_run.erl
+++ b/lib/common_test/src/ct_run.erl
@@ -363,6 +363,12 @@ script_start1(Parent, Args) ->
_ ->
application:set_env(common_test, disable_log_cache, true)
end,
+ %% log_cleanup - used by ct_logs
+ KeepLogs = get_start_opt(keep_logs,
+ fun ct_logs:parse_keep_logs/1,
+ all,
+ Args),
+ application:set_env(common_test, keep_logs, KeepLogs),
Opts = #opts{label = Label, profile = Profile,
vts = Vts, shell = Shell,
@@ -970,6 +976,12 @@ run_test1(StartOpts) when is_list(StartOpts) ->
stop_trace(Tracing),
exit(Res);
RefreshDir ->
+ %% log_cleanup - used by ct_logs
+ KeepLogs = get_start_opt(keep_logs,
+ fun ct_logs:parse_keep_logs/1,
+ all,
+ StartOpts),
+ application:set_env(common_test, keep_logs, KeepLogs),
ok = refresh_logs(?abs(RefreshDir)),
exit(done)
end.
@@ -1131,6 +1143,12 @@ run_test2(StartOpts) ->
DisableCacheBool ->
application:set_env(common_test, disable_log_cache, DisableCacheBool)
end,
+ %% log_cleanup - used by ct_logs
+ KeepLogs = get_start_opt(keep_logs,
+ fun ct_logs:parse_keep_logs/1,
+ all,
+ StartOpts),
+ application:set_env(common_test, keep_logs, KeepLogs),
%% stepped execution
Step = get_start_opt(step, value, StartOpts),
diff --git a/lib/common_test/test/Makefile b/lib/common_test/test/Makefile
index 2f0fc2e05a..b8fb678dbd 100644
--- a/lib/common_test/test/Makefile
+++ b/lib/common_test/test/Makefile
@@ -71,7 +71,8 @@ MODULES= \
test_server_test_lib \
ct_release_test_SUITE \
ct_log_SUITE \
- ct_SUITE
+ ct_SUITE \
+ ct_keep_logs_SUITE
ERL_FILES= $(MODULES:%=%.erl)
HRL_FILES= test_server_test_lib.hrl
diff --git a/lib/common_test/test/ct_keep_logs_SUITE.erl b/lib/common_test/test/ct_keep_logs_SUITE.erl
new file mode 100644
index 0000000000..34bfaaa97a
--- /dev/null
+++ b/lib/common_test/test/ct_keep_logs_SUITE.erl
@@ -0,0 +1,186 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2009-2016. 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%
+%%
+
+%%%-------------------------------------------------------------------
+%%% File: ct_keep_logs_SUITE
+%%%
+%%% Description:
+%%% Test the 'keep_logs' option
+%%%
+%%%-------------------------------------------------------------------
+-module(ct_keep_logs_SUITE).
+
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+-include_lib("common_test/include/ct_event.hrl").
+
+-define(eh, ct_test_support_eh).
+
+%%--------------------------------------------------------------------
+%% TEST SERVER CALLBACK FUNCTIONS
+%%--------------------------------------------------------------------
+
+init_per_suite(Config0) ->
+ ct_test_support:init_per_suite(Config0).
+
+end_per_suite(Config) ->
+ ct_test_support:end_per_suite(Config).
+
+init_per_testcase(TestCase, Config) ->
+ ct_test_support:init_per_testcase(TestCase, Config).
+
+end_per_testcase(TestCase, Config) ->
+ ct_test_support:end_per_testcase(TestCase, Config).
+
+suite() -> [{ct_hooks,[ts_install_cth]}].
+
+all() ->
+ [
+ keep_logs,
+ refresh_logs
+ ].
+
+%%--------------------------------------------------------------------
+%% TEST CASES
+%%--------------------------------------------------------------------
+
+%% Test the keep_logs option with normal common_test runs
+keep_logs(Config) ->
+ DataDir = ?config(data_dir, Config),
+ Suite = filename:join(DataDir, "keep_logs_SUITE"),
+ Opts0 = ct_test_support:get_opts(Config),
+ Opts = [{suite,Suite},{label,keep_logs} | Opts0],
+
+ LogDir=?config(logdir,Opts),
+ KeepLogsDir = filename:join(LogDir,unique_name("keep_logs-")),
+ ok = file:make_dir(KeepLogsDir),
+ Opts1 = lists:keyreplace(logdir,1,Opts,{logdir,KeepLogsDir}),
+ ct:log("New LogDir = ~s", [KeepLogsDir]),
+
+ %% Create 6 ct_run.* log directories
+ [ok = ct_test_support:run(Opts1, Config) || _ <- lists:seq(1,3)],
+
+ %% Verify the number of directories
+ WC = filename:join(KeepLogsDir,"ct_run.ct@*"),
+ L1 = filelib:wildcard(WC),
+ 6 = length(L1),
+
+ %% Keep all logs
+ {1,0,{0,0}}=ct_test_support:run_ct_run_test([{keep_logs,all}|Opts1], Config),
+ L2 = filelib:wildcard(WC),
+ 7 = length(L2),
+ 0 = ct_test_support:run_ct_script_start([{keep_logs,all}|Opts1], Config),
+ L3 = filelib:wildcard(WC),
+ 8 = length(L3),
+
+ %% N<length of list
+ {1,0,{0,0}}=ct_test_support:run_ct_run_test([{keep_logs,7}|Opts1], Config),
+ L4 = filelib:wildcard(WC),
+ 7 = length(L4),
+ 0 = ct_test_support:run_ct_script_start([{keep_logs,6}|Opts1], Config),
+ L5 = filelib:wildcard(WC),
+ 6 = length(L5),
+
+ %% N>length of list
+ {1,0,{0,0}}=ct_test_support:run_ct_run_test([{keep_logs,10}|Opts1], Config),
+ L6 = filelib:wildcard(WC),
+ 7 = length(L6),
+ 0 = ct_test_support:run_ct_script_start([{keep_logs,10}|Opts1], Config),
+ L7 = filelib:wildcard(WC),
+ 8 = length(L7),
+
+ %% N==length of list
+ {1,0,{0,0}}=ct_test_support:run_ct_run_test([{keep_logs,8}|Opts1], Config),
+ L8 = filelib:wildcard(WC),
+ 8 = length(L8),
+ 0 = ct_test_support:run_ct_script_start([{keep_logs,8}|Opts1], Config),
+ L9 = filelib:wildcard(WC),
+ 8 = length(L9),
+
+ %% N==length of list + current run
+ {1,0,{0,0}}=ct_test_support:run_ct_run_test([{keep_logs,9}|Opts1], Config),
+ L10 = filelib:wildcard(WC),
+ 9 = length(L10),
+ 0 = ct_test_support:run_ct_script_start([{keep_logs,10}|Opts1], Config),
+ L11 = filelib:wildcard(WC),
+ 10 = length(L11).
+
+%% Test the keep_logs option togwther with the refresh_logs option
+refresh_logs(Config) ->
+ DataDir = ?config(data_dir, Config),
+ Suite = filename:join(DataDir, "keep_logs_SUITE"),
+ Opts0 = ct_test_support:get_opts(Config),
+ LogDir=?config(logdir,Opts0),
+ KeepLogsDir = filename:join(LogDir,unique_name("refresh_logs-")),
+ ok = file:make_dir(KeepLogsDir),
+ Opts1 = lists:keyreplace(logdir,1,Opts0,{logdir,KeepLogsDir}),
+ ct:log("New LogDir = ~s", [KeepLogsDir]),
+
+ %% Create 6 ct_run.* log directories
+ SuiteOpts = [{suite,Suite},{label,refresh_logs} | Opts1],
+ [ok = ct_test_support:run(SuiteOpts, Config) || _ <- lists:seq(1,3)],
+
+ %% Verify the number of directories
+ WC = filename:join(KeepLogsDir,"ct_run.ct@*"),
+ L1 = filelib:wildcard(WC),
+ 6 = length(L1),
+
+ RefreshOpts = [{refresh_logs,KeepLogsDir},{label,refresh_logs} | Opts1],
+
+ %% Keep all logs (note that refresh_logs option prevents the
+ %% creation of a new log directory for the current run)
+ done = ct_test_support:run_ct_run_test([{keep_logs,all}|RefreshOpts], Config),
+ L2 = filelib:wildcard(WC),
+ 6 = length(L2),
+ 0 = ct_test_support:run_ct_script_start([{keep_logs,all}|RefreshOpts],Config),
+ L3 = filelib:wildcard(WC),
+ 6 = length(L3),
+
+ %% N<length of list
+ done = ct_test_support:run_ct_run_test([{keep_logs,5}|RefreshOpts], Config),
+ L5 = filelib:wildcard(WC),
+ 5 = length(L5),
+ 0 = ct_test_support:run_ct_script_start([{keep_logs,4}|RefreshOpts], Config),
+ L6 = filelib:wildcard(WC),
+ 4 = length(L6),
+
+ %% N>length of list
+ done = ct_test_support:run_ct_run_test([{keep_logs,5}|RefreshOpts], Config),
+ L7 = filelib:wildcard(WC),
+ 4 = length(L7),
+ 0 = ct_test_support:run_ct_script_start([{keep_logs,5}|RefreshOpts], Config),
+ L8 = filelib:wildcard(WC),
+ 4 = length(L8),
+
+ %% N==length of list
+ done = ct_test_support:run_ct_run_test([{keep_logs,4}|RefreshOpts], Config),
+ L9 = filelib:wildcard(WC),
+ 4 = length(L9),
+ 0 = ct_test_support:run_ct_script_start([{keep_logs,4}|RefreshOpts], Config),
+ L10 = filelib:wildcard(WC),
+ 4 = length(L10),
+
+ ok.
+%%%-----------------------------------------------------------------
+%%% Internal
+unique_name(Prefix) ->
+ I = erlang:unique_integer([positive]),
+ Prefix ++ integer_to_list(I).
diff --git a/lib/common_test/test/ct_keep_logs_SUITE_data/keep_logs_SUITE.erl b/lib/common_test/test/ct_keep_logs_SUITE_data/keep_logs_SUITE.erl
new file mode 100644
index 0000000000..2bccae564b
--- /dev/null
+++ b/lib/common_test/test/ct_keep_logs_SUITE_data/keep_logs_SUITE.erl
@@ -0,0 +1,32 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2009-2016. 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(keep_logs_SUITE).
+
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+
+suite() ->
+ [].
+all() ->
+ [test_case].
+
+test_case(_Config) ->
+ ok.
diff --git a/lib/common_test/test/ct_test_support.erl b/lib/common_test/test/ct_test_support.erl
index 05a452b99d..06d591871f 100644
--- a/lib/common_test/test/ct_test_support.erl
+++ b/lib/common_test/test/ct_test_support.erl
@@ -351,6 +351,9 @@ check_result(CtRunTestResult,ExitStatus,Opts)
catch _:_ ->
{error,{unexpected_return_value,{CtRunTestResult,ExitStatus}}}
end;
+check_result(done,0,_Opts) ->
+ %% refresh_logs return
+ ok;
check_result(CtRunTestResult,ExitStatus,_Opts) ->
{error,{unexpected_return_value,{CtRunTestResult,ExitStatus}}}.
diff --git a/lib/compiler/doc/src/compile.xml b/lib/compiler/doc/src/compile.xml
index ed04dac1c0..94bda0d5e3 100644
--- a/lib/compiler/doc/src/compile.xml
+++ b/lib/compiler/doc/src/compile.xml
@@ -132,12 +132,10 @@
<tag><c>debug_info</c></tag>
<item>
<marker id="debug_info"></marker>
- <p>Includes debug information in the form of abstract code
- (see
- <seealso marker="erts:absform">The Abstract Format</seealso>
- in ERTS User's Guide) in the compiled beam module. Tools
- such as Debugger, Xref, and Cover require
- the debug information to be included.</p>
+ <p>Includes debug information in the form of <seealso marker="erts:absform">
+ Erlang Abstract Format</seealso> in the <c>debug_info</c>
+ chunk of the compiled beam module. Tools such as Debugger,
+ Xref, and Cover require the debug information to be included.</p>
<p><em>Warning</em>: Source code can be reconstructed from
the debug information. Use encrypted debug information
@@ -147,6 +145,21 @@
<seealso marker="stdlib:beam_lib#debug_info">beam_lib(3)</seealso>.</p>
</item>
+ <tag><c>{debug_info, {Backend, Data}}</c></tag>
+ <item>
+ <marker id="debug_info"></marker>
+ <p>Includes custom debug information in the form of a
+ <c>Backend</c> module with custom <c>Data</c> in the compiled beam module.
+ The given module must implement a <c>debug_info/4</c> function
+ and is responsible for generating different code representations,
+ as described in the <c>debug_info</c> under
+ <seealso marker="stdlib:beam_lib#debug_info">beam_lib(3)</seealso>.</p>
+
+ <p><em>Warning</em>: Source code can be reconstructed from
+ the debug information. Use encrypted debug information
+ (<c>encrypt_debug_info</c>) to prevent this.</p>
+ </item>
+
<tag><c>{debug_info_key,KeyString}</c></tag>
<item></item>
<tag><c>{debug_info_key,{Mode,KeyString}}</c></tag>
diff --git a/lib/compiler/src/compile.erl b/lib/compiler/src/compile.erl
index 019d8ba864..be0f45323f 100644
--- a/lib/compiler/src/compile.erl
+++ b/lib/compiler/src/compile.erl
@@ -198,9 +198,9 @@ expand_opts(Opts0) ->
%% {debug_info_key,Key} implies debug_info.
Opts = case {proplists:get_value(debug_info_key, Opts0),
proplists:get_value(encrypt_debug_info, Opts0),
- proplists:get_bool(debug_info, Opts0)} of
+ proplists:get_value(debug_info, Opts0)} of
{undefined,undefined,_} -> Opts0;
- {_,_,false} -> [debug_info|Opts0];
+ {_,_,undefined} -> [debug_info|Opts0];
{_,_,_} -> Opts0
end,
foldr(fun expand_opt/2, [], Opts).
@@ -302,7 +302,7 @@ format_error_reason(Reason) ->
ofile="" :: file:filename(),
module=[] :: module() | [],
core_code=[] :: cerl:c_module() | [],
- abstract_code=[] :: binary() | [], %Abstract code for debugger.
+ abstract_code=[] :: abstract_code(), %Abstract code for debugger.
options=[] :: [option()], %Options for compilation
mod_options=[] :: [option()], %Options for module_info
encoding=none :: none | epp:source_encoding(),
@@ -1315,44 +1315,43 @@ core_inline_module(Code0, #compile{options=Opts}=St) ->
Code = cerl_inline:core_transform(Code0, Opts),
{ok,Code,St}.
-save_abstract_code(Code, #compile{ifile=File}=St) ->
- case abstract_code(Code, St) of
- {ok,Abstr} ->
- {ok,Code,St#compile{abstract_code=Abstr}};
- {error,Es} ->
- {error,St#compile{errors=St#compile.errors ++ [{File,Es}]}}
- end.
+save_abstract_code(Code, St) ->
+ {ok,Code,St#compile{abstract_code=erl_parse:anno_to_term(Code)}}.
+
+debug_info(#compile{module=Module,mod_options=Opts0,ofile=OFile,abstract_code=Abst}) ->
+ AbstOpts = cleanup_compile_options(Opts0),
+ Opts1 = proplists:delete(debug_info, Opts0),
+ {Backend,Metadata,Opts2} =
+ case proplists:get_value(debug_info, Opts0, false) of
+ {OptBackend,OptMetadata} when is_atom(OptBackend) -> {OptBackend,OptMetadata,Opts1};
+ false -> {erl_abstract_code,{none,AbstOpts},Opts1};
+ true -> {erl_abstract_code,{Abst,AbstOpts},[debug_info | Opts1]}
+ end,
+ DebugInfo = erlang:term_to_binary({debug_info_v1,Backend,Metadata}, [compressed]),
-abstract_code(Code0, #compile{options=Opts,ofile=OFile}) ->
- Code = erl_parse:anno_to_term(Code0),
- Abstr = erlang:term_to_binary({raw_abstract_v1,Code}, [compressed]),
- case member(encrypt_debug_info, Opts) of
+ case member(encrypt_debug_info, Opts2) of
true ->
- case keyfind(debug_info_key, 1, Opts) of
- {_,Key} ->
- encrypt_abs_code(Abstr, Key);
+ case lists:keytake(debug_info_key, 1, Opts2) of
+ {value,{_, Key},Opts3} ->
+ encrypt_debug_info(DebugInfo, Key, [{debug_info_key,'********'} | Opts3]);
false ->
- %% Note: #compile.module has not been set yet.
- %% Here is an approximation that should work for
- %% all valid cases.
- Module = list_to_atom(filename:rootname(filename:basename(OFile))),
- Mode = proplists:get_value(crypto_mode, Opts, des3_cbc),
+ Mode = proplists:get_value(crypto_mode, Opts2, des3_cbc),
case beam_lib:get_crypto_key({debug_info, Mode, Module, OFile}) of
error ->
{error, [{none,?MODULE,no_crypto_key}]};
Key ->
- encrypt_abs_code(Abstr, {Mode, Key})
+ encrypt_debug_info(DebugInfo, {Mode, Key}, Opts2)
end
end;
false ->
- {ok,Abstr}
+ {ok,DebugInfo,Opts2}
end.
-encrypt_abs_code(Abstr, Key0) ->
+encrypt_debug_info(DebugInfo, Key, Opts) ->
try
- RealKey = generate_key(Key0),
+ RealKey = generate_key(Key),
case start_crypto() of
- ok -> {ok,encrypt(RealKey, Abstr)};
+ ok -> {ok,encrypt(RealKey, DebugInfo),Opts};
{error,_}=E -> E
end
catch
@@ -1360,6 +1359,18 @@ encrypt_abs_code(Abstr, Key0) ->
{error,[{none,?MODULE,bad_crypto_key}]}
end.
+cleanup_compile_options(Opts) ->
+ lists:filter(fun keep_compile_option/1, Opts).
+
+%% We are storing abstract, not asm or core.
+keep_compile_option(from_asm) -> false;
+keep_compile_option(from_core) -> false;
+%% Parse transform and macros have already been applied.
+keep_compile_option({parse_transform, _}) -> false;
+keep_compile_option({d, _, _}) -> false;
+%% Do not affect compilation result on future calls.
+keep_compile_option(Option) -> effects_code_generation(Option).
+
start_crypto() ->
try crypto:start() of
{error,{already_started,crypto}} -> ok;
@@ -1386,16 +1397,16 @@ encrypt({des3_cbc=Type,Key,IVec,BlockSize}, Bin0) ->
save_core_code(Code, St) ->
{ok,Code,St#compile{core_code=cerl:from_records(Code)}}.
-beam_asm(Code0, #compile{ifile=File,abstract_code=Abst,extra_chunks=ExtraChunks,
- options=CompilerOpts,mod_options=Opts0}=St) ->
- Source = paranoid_absname(File),
- Opts1 = lists:map(fun({debug_info_key,_}) -> {debug_info_key,'********'};
- (Other) -> Other
- end, Opts0),
- Opts2 = [O || O <- Opts1, effects_code_generation(O)],
- Chunks = [{<<"Abst">>, Abst} | ExtraChunks],
- case beam_asm:module(Code0, Chunks, Source, Opts2, CompilerOpts) of
- {ok,Code} -> {ok,Code,St#compile{abstract_code=[]}}
+beam_asm(Code0, #compile{ifile=File,extra_chunks=ExtraChunks,options=CompilerOpts}=St) ->
+ case debug_info(St) of
+ {ok,DebugInfo,Opts0} ->
+ Source = paranoid_absname(File),
+ Opts1 = [O || O <- Opts0, effects_code_generation(O)],
+ Chunks = [{<<"Dbgi">>, DebugInfo} | ExtraChunks],
+ {ok,Code} = beam_asm:module(Code0, Chunks, Source, Opts1, CompilerOpts),
+ {ok,Code,St#compile{abstract_code=[]}};
+ {error,Es} ->
+ {error,St#compile{errors=St#compile.errors ++ [{File,Es}]}}
end.
paranoid_absname(""=File) ->
@@ -1479,15 +1490,17 @@ embed_native_code(Code, {Architecture,NativeCode}) ->
%% errors will be reported).
effects_code_generation(Option) ->
- case Option of
+ case Option of
beam -> false;
report_warnings -> false;
report_errors -> false;
return_errors-> false;
return_warnings-> false;
+ warnings_as_errors -> false;
binary -> false;
verbose -> false;
{cwd,_} -> false;
+ {outdir, _} -> false;
_ -> true
end.
diff --git a/lib/compiler/src/erl_bifs.erl b/lib/compiler/src/erl_bifs.erl
index d60f73d421..b1f1db6fa3 100644
--- a/lib/compiler/src/erl_bifs.erl
+++ b/lib/compiler/src/erl_bifs.erl
@@ -108,11 +108,14 @@ is_pure(erlang, list_to_binary, 1) -> true;
is_pure(erlang, list_to_float, 1) -> true;
is_pure(erlang, list_to_integer, 1) -> true;
is_pure(erlang, list_to_pid, 1) -> true;
+is_pure(erlang, list_to_port, 1) -> true;
+is_pure(erlang, list_to_ref, 1) -> true;
is_pure(erlang, list_to_tuple, 1) -> true;
is_pure(erlang, max, 2) -> true;
is_pure(erlang, min, 2) -> true;
is_pure(erlang, phash, 2) -> false;
is_pure(erlang, pid_to_list, 1) -> true;
+is_pure(erlang, port_to_list, 1) -> true;
is_pure(erlang, round, 1) -> true;
is_pure(erlang, setelement, 3) -> true;
is_pure(erlang, size, 1) -> true;
diff --git a/lib/compiler/src/v3_core.erl b/lib/compiler/src/v3_core.erl
index 8dea7ec03a..fcfc1a4076 100644
--- a/lib/compiler/src/v3_core.erl
+++ b/lib/compiler/src/v3_core.erl
@@ -184,11 +184,8 @@ form({function,_,_,_,_}=F0, Module, Opts) ->
form({attribute,_,module,Mod}, Module, _Opts) ->
true = is_atom(Mod),
Module#imodule{name=Mod};
-form({attribute,_,file,{File,_Line}}, Module, _Opts) ->
- Module#imodule{file=File};
-form({attribute,_,compile,_}, Module, _Opts) ->
- %% Ignore compilation options.
- Module;
+form({attribute,_,file,{File,_Line}}=F, #imodule{attrs=As}=Module, _Opts) ->
+ Module#imodule{file=File, attrs=[attribute(F)|As]};
form({attribute,_,import,_}, Module, _Opts) ->
%% Ignore. We have no futher use for imports.
Module;
@@ -201,9 +198,8 @@ form(_, Module, _Opts) ->
%% Ignore uninteresting forms such as 'eof'.
Module.
-attribute(Attribute) ->
- Fun = fun(A) -> [erl_anno:location(A)] end,
- {attribute,Line,Name,Val0} = erl_parse:map_anno(Fun, Attribute),
+attribute({attribute,A,Name,Val0}) ->
+ Line = [erl_anno:location(A)],
Val = if
is_list(Val0) -> Val0;
true -> [Val0]
diff --git a/lib/compiler/src/v3_kernel.erl b/lib/compiler/src/v3_kernel.erl
index 4b5d7d919c..7a0a63d286 100644
--- a/lib/compiler/src/v3_kernel.erl
+++ b/lib/compiler/src/v3_kernel.erl
@@ -148,6 +148,8 @@ include_attribute(opaque) -> false;
include_attribute(export_type) -> false;
include_attribute(record) -> false;
include_attribute(optional_callbacks) -> false;
+include_attribute(file) -> false;
+include_attribute(compile) -> false;
include_attribute(_) -> true.
function({#c_var{name={F,Arity}=FA},Body}, St0) ->
diff --git a/lib/compiler/test/compilation_SUITE.erl b/lib/compiler/test/compilation_SUITE.erl
index cd1bc099e9..c98aa07a4f 100644
--- a/lib/compiler/test/compilation_SUITE.erl
+++ b/lib/compiler/test/compilation_SUITE.erl
@@ -319,7 +319,7 @@ self_compile_1(Config, Prefix, Opts) ->
%% Compile the compiler. (In this node to get better coverage.)
CompA = make_compiler_dir(Priv, Prefix++"compiler_a"),
VsnA = Version ++ ".0",
- compile_compiler(compiler_src(), CompA, VsnA, [clint0,clint|Opts]),
+ compile_compiler(compiler_src(), CompA, VsnA, Opts),
%% Compile the compiler again using the newly compiled compiler.
%% (In another node because reloading the compiler would disturb cover.)
diff --git a/lib/compiler/test/compile_SUITE.erl b/lib/compiler/test/compile_SUITE.erl
index 474c3e2ca0..11a62ce753 100644
--- a/lib/compiler/test/compile_SUITE.erl
+++ b/lib/compiler/test/compile_SUITE.erl
@@ -27,6 +27,7 @@
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2,
app_test/1,appup_test/1,
+ debug_info/4, custom_debug_info/1,
file_1/1, forms_2/1, module_mismatch/1, big_file/1, outdir/1,
binary/1, makedep/1, cond_and_ifdef/1, listings/1, listings_big/1,
other_output/1, kernel_listing/1, encrypted_abstr/1,
@@ -51,7 +52,7 @@ all() ->
strict_record, utf8_atoms, extra_chunks,
cover, env, core, core_roundtrip, asm, optimized_guards,
sys_pre_attributes, dialyzer, warnings, pre_load_check,
- env_compiler_options].
+ env_compiler_options, custom_debug_info].
groups() ->
[].
@@ -504,17 +505,23 @@ encrypted_abstr_1(Simple, Target) ->
{ok,simple} = compile:file(Simple,
[debug_info,{debug_info_key,Key},
{outdir,TargetDir}]),
- verify_abstract(Target),
+ verify_abstract(Target, erl_abstract_code),
{ok,simple} = compile:file(Simple,
[{debug_info_key,Key},
{outdir,TargetDir}]),
- verify_abstract(Target),
+ verify_abstract(Target, erl_abstract_code),
{ok,simple} = compile:file(Simple,
[debug_info,{debug_info_key,{des3_cbc,Key}},
{outdir,TargetDir}]),
- verify_abstract(Target),
+ verify_abstract(Target, erl_abstract_code),
+
+ {ok,simple} = compile:file(Simple,
+ [{debug_info,{?MODULE,ok}},
+ {debug_info_key,Key},
+ {outdir,TargetDir}]),
+ verify_abstract(Target, ?MODULE),
{ok,{simple,[{compile_info,CInfo}]}} =
beam_lib:chunks(Target, [compile_info]),
@@ -539,7 +546,7 @@ encrypted_abstr_1(Simple, Target) ->
NewKey = "better use another key here",
write_crypt_file(["[{debug_info,des3_cbc,simple,\"",NewKey,"\"}].\n"]),
{ok,simple} = compile:file(Simple, [encrypt_debug_info,report]),
- verify_abstract("simple.beam"),
+ verify_abstract("simple.beam", erl_abstract_code),
ok = file:delete(".erlang.crypt"),
beam_lib:clear_crypto_key_fun(),
{error,beam_lib,{key_missing_or_invalid,"simple.beam",abstract_code}} =
@@ -572,9 +579,10 @@ encrypted_abstr_no_crypto(Simple, Target) ->
{outdir,TargetDir},report]),
ok.
-verify_abstract(Target) ->
- {ok,{simple,[Chunk]}} = beam_lib:chunks(Target, [abstract_code]),
- {abstract_code,{raw_abstract_v1,_}} = Chunk.
+verify_abstract(Beam, Backend) ->
+ {ok,{simple,[Abst, Dbgi]}} = beam_lib:chunks(Beam, [abstract_code, debug_info]),
+ {abstract_code,{raw_abstract_v1,_}} = Abst,
+ {debug_info,{debug_info_v1,Backend,_}} = Dbgi.
has_crypto() ->
try
@@ -593,6 +601,26 @@ install_crypto_key(Key) ->
ok = beam_lib:crypto_key_fun(F).
%% Miscellanous tests, mainly to get better coverage.
+debug_info(erlang_v1, Module, ok, _Opts) ->
+ {ok, [Module]};
+debug_info(erlang_v1, Module, error, _Opts) ->
+ {error, unknown_format}.
+
+custom_debug_info(Config) when is_list(Config) ->
+ {Simple,_} = get_files(Config, simple, "file_1"),
+
+ {ok,simple,OkBin} = compile:file(Simple, [binary, {debug_info,{?MODULE,ok}}]), %Coverage
+ {ok,{simple,[{abstract_code,{raw_abstract_v1,[simple]}}]}} =
+ beam_lib:chunks(OkBin, [abstract_code]),
+ {ok,{simple,[{debug_info,{debug_info_v1,?MODULE,ok}}]}} =
+ beam_lib:chunks(OkBin, [debug_info]),
+
+ {ok,simple,ErrorBin} = compile:file(Simple, [binary, {debug_info,{?MODULE,error}}]), %Coverage
+ {ok,{simple,[{abstract_code,no_abstract_code}]}} =
+ beam_lib:chunks(ErrorBin, [abstract_code]),
+ {ok,{simple,[{debug_info,{debug_info_v1,?MODULE,error}}]}} =
+ beam_lib:chunks(ErrorBin, [debug_info]).
+
cover(Config) when is_list(Config) ->
io:format("~p\n", [compile:options()]),
ok.
diff --git a/lib/debugger/doc/src/debugger_chapter.xml b/lib/debugger/doc/src/debugger_chapter.xml
index 45dfdb3776..3c37d4b924 100644
--- a/lib/debugger/doc/src/debugger_chapter.xml
+++ b/lib/debugger/doc/src/debugger_chapter.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>1997</year><year>2016</year>
+ <year>1997</year><year>2017</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -652,8 +652,10 @@ c_break(Bindings) ->
<item><p>The Bindings area, displaying all variables bindings. If you
click a variable name, the value is displayed in the Evaluator area.
Double-click a variable name to open a window where
- the variable value can be edited. Notice however that pid,
- reference, binary, or port values cannot be edited.</p>
+ the variable value can be edited. Notice however that pid, port,
+ reference, or fun
+ values cannot be edited unless they can be represented in the
+ running system.</p>
</item>
<item><p>The Trace area, which displays a trace output for the
diff --git a/lib/debugger/src/dbg_icmd.erl b/lib/debugger/src/dbg_icmd.erl
index 57a3719a50..4cd3dce670 100644
--- a/lib/debugger/src/dbg_icmd.erl
+++ b/lib/debugger/src/dbg_icmd.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2017. 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.
@@ -382,14 +382,19 @@ eval_restricted({From,_Mod,Cmd,SP}, Bs) ->
case catch parse_cmd(Cmd, 1) of
{'EXIT', _Reason} ->
From ! {self(), {eval_rsp, 'Parse error'}};
- [{var,_,Var}] ->
+ {[{var,_,Var}], XBs} ->
Bs2 = bindings(Bs, SP),
Res = case get_binding(Var, Bs2) of
{value, Value} -> Value;
- unbound -> unbound
+ unbound ->
+ case get_binding(Var, XBs) of
+ {value, _} ->
+ 'Only possible to inspect variables';
+ unbound -> unbound
+ end
end,
From ! {self(), {eval_rsp, Res}};
- _Forms ->
+ {_Forms, _XBs} ->
Rsp = 'Only possible to inspect variables',
From ! {self(), {eval_rsp, Rsp}}
end.
@@ -404,22 +409,22 @@ eval_nonrestricted({From, _Mod, Cmd, _SP}, Bs,
{'EXIT', _Reason} ->
From ! {self(), {eval_rsp, 'Parse error'}},
Bs;
- Forms ->
+ {Forms, XBs} ->
mark_running(Line, Le),
+ Bs1 = merge_bindings(Bs, XBs),
{Res, Bs2} =
lists:foldl(fun(Expr, {_Res, Bs0}) ->
eval_nonrestricted_1(Expr,Bs0,Ieval)
end,
- {null, Bs},
+ {null, Bs1},
Forms),
mark_break(M, Line, Le),
From ! {self(), {eval_rsp, Res}},
- Bs2
+ remove_binding_structs(Bs2, XBs)
end.
eval_nonrestricted_1({match,_,{var,_,Var},Expr}, Bs, Ieval) ->
- {value,Res,Bs2} =
- dbg_ieval:eval_expr(Expr, Bs, Ieval#ieval{top=false}),
+ {Res,Bs2} = eval_expr(Expr, Bs, Ieval),
Bs3 = case lists:keyfind(Var, 1, Bs) of
{Var,_Value} ->
lists:keyreplace(Var, 1, Bs2, {Var,Res});
@@ -433,10 +438,21 @@ eval_nonrestricted_1({var,_,Var}, Bs, _Ieval) ->
end,
{Res,Bs};
eval_nonrestricted_1(Expr, Bs, Ieval) ->
- {value,Res,Bs2} =
- dbg_ieval:eval_expr(Expr, Bs, Ieval#ieval{top=false}),
+ eval_expr(Expr, Bs, Ieval).
+
+eval_expr(Expr, Bs, Ieval) ->
+ {value,Res,Bs2} =
+ dbg_ieval:eval_expr(Expr, Bs, Ieval#ieval{top=false}),
{Res,Bs2}.
+%% XBs have unique keys.
+merge_bindings(Bs1, XBs) ->
+ Bs1 ++ erl_eval:bindings(XBs).
+
+remove_binding_structs(Bs1, XBs) ->
+ lists:foldl(fun({N, _V}, Bs) -> lists:keydelete(N, 1, Bs)
+ end, Bs1, erl_eval:bindings(XBs)).
+
mark_running(LineNo, Le) ->
put(next_break, running),
put(user_eval, [{LineNo, Le} | get(user_eval)]),
@@ -450,9 +466,9 @@ mark_break(Cm, LineNo, Le) ->
dbg_iserver:cast(get(int), {set_status,self(),break,{Cm,LineNo}}).
parse_cmd(Cmd, LineNo) ->
- {ok,Tokens,_} = erl_scan:string(Cmd, LineNo),
- {ok,Forms} = erl_parse:parse_exprs(Tokens),
- Forms.
+ {ok,Tokens,_} = erl_scan:string(Cmd, LineNo, [text]),
+ {ok,Forms,Bs} = lib:extended_parse_exprs(Tokens),
+ {Forms, Bs}.
%%====================================================================
%% Library functions for attached process handling
diff --git a/lib/debugger/src/dbg_wx_win.erl b/lib/debugger/src/dbg_wx_win.erl
index 2c9d83ea74..f1298154ab 100644
--- a/lib/debugger/src/dbg_wx_win.erl
+++ b/lib/debugger/src/dbg_wx_win.erl
@@ -273,10 +273,9 @@ entry(Parent, Title, Prompt, {Type, Value}) ->
verify(Type, Str) ->
- case erl_scan:string(Str) of
+ case erl_scan:string(Str, 1, [text]) of
{ok, Tokens, _EndLine} when Type==term ->
-
- case erl_parse:parse_term(Tokens++[{dot, erl_anno:new(1)}]) of
+ case lib:extended_parse_term(Tokens++[{dot, erl_anno:new(1)}]) of
{ok, Value} -> {edit, Value};
_Error ->
ignore
diff --git a/lib/dialyzer/src/dialyzer_analysis_callgraph.erl b/lib/dialyzer/src/dialyzer_analysis_callgraph.erl
index aeeb895a0c..051b700231 100644
--- a/lib/dialyzer/src/dialyzer_analysis_callgraph.erl
+++ b/lib/dialyzer/src/dialyzer_analysis_callgraph.erl
@@ -385,68 +385,46 @@ compile_src(File, Includes, Defines, Callgraph, CServer, UseContracts,
DefaultIncludes = default_includes(filename:dirname(File)),
SrcCompOpts = dialyzer_utils:src_compiler_opts(),
CompOpts = SrcCompOpts ++ Includes ++ Defines ++ DefaultIncludes,
- case dialyzer_utils:get_abstract_code_from_src(File, CompOpts) of
+ case dialyzer_utils:get_core_from_src(File, CompOpts) of
{error, _Msg} = Error -> Error;
- {ok, AbstrCode} ->
- compile_common(File, AbstrCode, CompOpts, Callgraph, CServer,
- UseContracts, LegalWarnings)
+ {ok, Core} ->
+ compile_common(Core, Callgraph, CServer, UseContracts, LegalWarnings)
end.
compile_byte(File, Callgraph, CServer, UseContracts, LegalWarnings) ->
- case dialyzer_utils:get_abstract_code_from_beam(File) of
- error ->
- {error, " Could not get abstract code for: " ++ File ++ "\n" ++
- " Recompile with +debug_info or analyze starting from source code"};
- {ok, AbstrCode} ->
- compile_byte(File, AbstrCode, Callgraph, CServer, UseContracts,
- LegalWarnings)
- end.
-
-compile_byte(File, AbstrCode, Callgraph, CServer, UseContracts,
- LegalWarnings) ->
- case dialyzer_utils:get_compile_options_from_beam(File) of
- error ->
- {error, " Could not get compile options for: " ++ File ++ "\n" ++
- " Recompile or analyze starting from source code"};
- {ok, CompOpts} ->
- compile_common(File, AbstrCode, CompOpts, Callgraph, CServer,
- UseContracts, LegalWarnings)
+ case dialyzer_utils:get_core_from_beam(File) of
+ {error, _} = Error -> Error;
+ {ok, Core} ->
+ compile_common(Core, Callgraph, CServer, UseContracts, LegalWarnings)
end.
-compile_common(File, AbstrCode, CompOpts, Callgraph, CServer,
- UseContracts, LegalWarnings) ->
- case dialyzer_utils:get_core_from_abstract_code(AbstrCode, CompOpts) of
- error -> {error, " Could not get core Erlang code for: " ++ File};
- {ok, Core} ->
- Mod = cerl:concrete(cerl:module_name(Core)),
- case dialyzer_utils:get_record_and_type_info(AbstrCode) of
+compile_common(Core, Callgraph, CServer, UseContracts, LegalWarnings) ->
+ Mod = cerl:concrete(cerl:module_name(Core)),
+ case dialyzer_utils:get_record_and_type_info(Core) of
+ {error, _} = Error -> Error;
+ {ok, RecInfo} ->
+ CServer1 =
+ dialyzer_codeserver:store_temp_records(Mod, RecInfo, CServer),
+ case dialyzer_utils:get_fun_meta_info(Mod, Core, LegalWarnings) of
{error, _} = Error -> Error;
- {ok, RecInfo} ->
- CServer1 =
- dialyzer_codeserver:store_temp_records(Mod, RecInfo, CServer),
- case
- dialyzer_utils:get_fun_meta_info(Mod, AbstrCode, LegalWarnings)
- of
- {error, _} = Error -> Error;
- MetaFunInfo ->
- CServer2 =
- dialyzer_codeserver:insert_fun_meta_info(MetaFunInfo, CServer1),
- case UseContracts of
- true ->
- case dialyzer_utils:get_spec_info(Mod, AbstrCode, RecInfo) of
- {error, _} = Error -> Error;
- {ok, SpecInfo, CallbackInfo} ->
- CServer3 =
- dialyzer_codeserver:store_temp_contracts(Mod, SpecInfo,
- CallbackInfo,
- CServer2),
- store_core(Mod, Core, Callgraph, CServer3)
- end;
- false ->
- store_core(Mod, Core, Callgraph, CServer2)
- end
- end
+ MetaFunInfo ->
+ CServer2 =
+ dialyzer_codeserver:insert_fun_meta_info(MetaFunInfo, CServer1),
+ case UseContracts of
+ true ->
+ case dialyzer_utils:get_spec_info(Mod, Core, RecInfo) of
+ {error, _} = Error -> Error;
+ {ok, SpecInfo, CallbackInfo} ->
+ CServer3 =
+ dialyzer_codeserver:store_temp_contracts(Mod, SpecInfo,
+ CallbackInfo,
+ CServer2),
+ store_core(Mod, Core, Callgraph, CServer3)
+ end;
+ false ->
+ store_core(Mod, Core, Callgraph, CServer2)
end
+ end
end.
store_core(Mod, Core, Callgraph, CServer) ->
diff --git a/lib/dialyzer/src/dialyzer_plt.erl b/lib/dialyzer/src/dialyzer_plt.erl
index bfd3f84fc5..847faab2f4 100644
--- a/lib/dialyzer/src/dialyzer_plt.erl
+++ b/lib/dialyzer/src/dialyzer_plt.erl
@@ -470,12 +470,11 @@ compute_md5_from_file(File) ->
Msg = io_lib:format("Not a regular file: ~s\n", [File]),
throw({dialyzer_error, Msg});
true ->
- case dialyzer_utils:get_abstract_code_from_beam(File) of
- error ->
- Msg = io_lib:format("Could not get abstract code for file: ~s (please recompile it with +debug_info)\n", [File]),
- throw({dialyzer_error, Msg});
- {ok, Abs} ->
- erlang:md5(term_to_binary(Abs))
+ case dialyzer_utils:get_core_from_beam(File) of
+ {error, Error} ->
+ throw({dialyzer_error, Error});
+ {ok, Core} ->
+ erlang:md5(term_to_binary(Core))
end
end.
diff --git a/lib/dialyzer/src/dialyzer_utils.erl b/lib/dialyzer/src/dialyzer_utils.erl
index 9eaf95c1a2..e0497159b3 100644
--- a/lib/dialyzer/src/dialyzer_utils.erl
+++ b/lib/dialyzer/src/dialyzer_utils.erl
@@ -24,14 +24,10 @@
-export([
format_sig/1,
format_sig/2,
- get_abstract_code_from_beam/1,
- get_compile_options_from_beam/1,
- get_abstract_code_from_src/1,
- get_abstract_code_from_src/2,
- get_core_from_abstract_code/1,
- get_core_from_abstract_code/2,
get_core_from_src/1,
get_core_from_src/2,
+ get_core_from_beam/1,
+ get_core_from_beam/2,
get_record_and_type_info/1,
get_spec_info/3,
get_fun_meta_info/3,
@@ -77,9 +73,7 @@ print_types1([{record, _Name} = Key|T], RecDict) ->
%% ----------------------------------------------------------------------------
--type abstract_code() :: [erl_parse:abstract_form()].
-type comp_options() :: [compile:option()].
--type mod_or_fname() :: module() | file:filename().
-type fa() :: {atom(), arity()}.
-type codeserver() :: dialyzer_codeserver:codeserver().
@@ -89,63 +83,82 @@ print_types1([{record, _Name} = Key|T], RecDict) ->
%%
%% ============================================================================
--spec get_abstract_code_from_src(mod_or_fname()) ->
- {'ok', abstract_code()} | {'error', [string()]}.
+-type get_core_from_src_ret() :: {'ok', cerl:c_module()} | {'error', string()}.
+
+-spec get_core_from_src(file:filename()) -> get_core_from_src_ret().
-get_abstract_code_from_src(File) ->
- get_abstract_code_from_src(File, src_compiler_opts()).
+get_core_from_src(File) ->
+ get_core_from_src(File, []).
--spec get_abstract_code_from_src(mod_or_fname(), comp_options()) ->
- {'ok', abstract_code()} | {'error', [string()]}.
+-spec get_core_from_src(file:filename(), comp_options()) -> get_core_from_src_ret().
-get_abstract_code_from_src(File, Opts) ->
- case compile:noenv_file(File, [to_pp, binary|Opts]) of
+get_core_from_src(File, Opts) ->
+ case compile:noenv_file(File, Opts ++ src_compiler_opts()) of
error -> {error, []};
{error, Errors, _} -> {error, format_errors(Errors)};
- {ok, _, AbstrCode} -> {ok, AbstrCode}
+ {ok, _, Core} -> {ok, Core}
end.
--type get_core_from_src_ret() :: {'ok', cerl:c_module()} | {'error', string()}.
+-type get_core_from_beam_ret() :: {'ok', cerl:c_module()} | {'error', string()}.
--spec get_core_from_src(file:filename()) -> get_core_from_src_ret().
+-spec get_core_from_beam(file:filename()) -> get_core_from_beam_ret().
-get_core_from_src(File) ->
- get_core_from_src(File, []).
+get_core_from_beam(File) ->
+ get_core_from_beam(File, []).
--spec get_core_from_src(file:filename(), comp_options()) -> get_core_from_src_ret().
+-spec get_core_from_beam(file:filename(), comp_options()) -> get_core_from_beam_ret().
-get_core_from_src(File, Opts) ->
- case get_abstract_code_from_src(File, Opts) of
- {error, _} = Error -> Error;
+get_core_from_beam(File, Opts) ->
+ case beam_lib:chunks(File, [debug_info]) of
+ {ok, {Module, [{debug_info, {debug_info_v1, Backend, Metadata}}]}} ->
+ case Backend:debug_info(core_v1, Module, Metadata, Opts ++ src_compiler_opts()) of
+ {ok, Core} ->
+ {ok, Core};
+ {error, _} ->
+ {error, " Could not get Core Erlang code for: " ++ File ++ "\n"}
+ end;
+ _ ->
+ deprecated_get_core_from_beam(File, Opts)
+ end.
+
+deprecated_get_core_from_beam(File, Opts) ->
+ case get_abstract_code_from_beam(File) of
+ error ->
+ {error, " Could not get abstract code for: " ++ File ++ "\n" ++
+ " Recompile with +debug_info or analyze starting from source code"};
{ok, AbstrCode} ->
- case get_core_from_abstract_code(AbstrCode, Opts) of
- error -> {error, " Could not get Core Erlang code from abstract code"};
- {ok, _Core} = C -> C
+ case get_compile_options_from_beam(File) of
+ error ->
+ {error, " Could not get compile options for: " ++ File ++ "\n" ++
+ " Recompile or analyze starting from source code"};
+ {ok, CompOpts} ->
+ case get_core_from_abstract_code(AbstrCode, Opts ++ CompOpts) of
+ error ->
+ {error, " Could not get core Erlang code for: " ++ File};
+ {ok, _} = Core ->
+ Core
+ end
end
end.
--spec get_abstract_code_from_beam(file:filename()) -> 'error' | {'ok', abstract_code()}.
-
get_abstract_code_from_beam(File) ->
case beam_lib:chunks(File, [abstract_code]) of
{ok, {_, List}} ->
case lists:keyfind(abstract_code, 1, List) of
- {abstract_code, {raw_abstract_v1, Abstr}} -> {ok, Abstr};
- _ -> error
+ {abstract_code, {raw_abstract_v1, Abstr}} -> {ok, Abstr};
+ _ -> error
end;
_ ->
%% No or unsuitable abstract code.
error
end.
--spec get_compile_options_from_beam(file:filename()) -> 'error' | {'ok', [compile:option()]}.
-
get_compile_options_from_beam(File) ->
case beam_lib:chunks(File, [compile_info]) of
{ok, {_, List}} ->
case lists:keyfind(compile_info, 1, List) of
- {compile_info, CompInfo} -> compile_info_to_options(CompInfo);
- _ -> error
+ {compile_info, CompInfo} -> compile_info_to_options(CompInfo);
+ _ -> error
end;
_ ->
%% No or unsuitable compile info.
@@ -158,15 +171,6 @@ compile_info_to_options(CompInfo) ->
_ -> error
end.
--type get_core_from_abs_ret() :: {'ok', cerl:c_module()} | 'error'.
-
--spec get_core_from_abstract_code(abstract_code()) -> get_core_from_abs_ret().
-
-get_core_from_abstract_code(AbstrCode) ->
- get_core_from_abstract_code(AbstrCode, []).
-
--spec get_core_from_abstract_code(abstract_code(), comp_options()) -> get_core_from_abs_ret().
-
get_core_from_abstract_code(AbstrCode, Opts) ->
%% We do not want the parse_transforms around since we already
%% performed them. In some cases we end up in trouble when
@@ -175,12 +179,31 @@ get_core_from_abstract_code(AbstrCode, Opts) ->
%% Remove parse_transforms (and other options) from compile options.
Opts2 = cleanup_compile_options(Opts),
try compile:noenv_forms(AbstrCode1, Opts2 ++ src_compiler_opts()) of
- {ok, _, Core} -> {ok, Core};
- _What -> error
+ {ok, _, Core} -> {ok, Core};
+ _What -> error
catch
error:_ -> error
end.
+cleanup_parse_transforms([{attribute, _, compile, {parse_transform, _}}|Left]) ->
+ cleanup_parse_transforms(Left);
+cleanup_parse_transforms([Other|Left]) ->
+ [Other|cleanup_parse_transforms(Left)];
+cleanup_parse_transforms([]) ->
+ [].
+
+cleanup_compile_options(Opts) ->
+ lists:filter(fun keep_compile_option/1, Opts).
+
+%% Using abstract, not asm or core.
+keep_compile_option(from_asm) -> false;
+keep_compile_option(from_core) -> false;
+%% The parse transform will already have been applied, may cause
+%% problems if it is re-applied.
+keep_compile_option({parse_transform, _}) -> false;
+keep_compile_option(warnings_as_errors) -> false;
+keep_compile_option(_) -> true.
+
%% ============================================================================
%%
%% Typed Records
@@ -189,55 +212,50 @@ get_core_from_abstract_code(AbstrCode, Opts) ->
-type type_table() :: erl_types:type_table().
--spec get_record_and_type_info(abstract_code()) ->
- {'ok', type_table()} | {'error', string()}.
+-spec get_record_and_type_info(cerl:module()) ->
+ {'ok', type_table()} | {'error', string()}.
-get_record_and_type_info(AbstractCode) ->
- Module = get_module(AbstractCode),
- get_record_and_type_info(AbstractCode, Module, maps:new()).
+get_record_and_type_info(Core) ->
+ Module = cerl:concrete(cerl:module_name(Core)),
+ Tuples = core_to_attr_tuples(Core),
+ get_record_and_type_info(Tuples, Module, maps:new(), "nofile").
--spec get_record_and_type_info(abstract_code(), module(), type_table()) ->
- {'ok', type_table()} | {'error', string()}.
-
-get_record_and_type_info(AbstractCode, Module, RecDict) ->
- get_record_and_type_info(AbstractCode, Module, RecDict, "nofile").
-
-get_record_and_type_info([{attribute, A, record, {Name, Fields0}}|Left],
+get_record_and_type_info([{record, Line, [{Name, Fields0}]}|Left],
Module, RecDict, File) ->
{ok, Fields} = get_record_fields(Fields0, RecDict),
Arity = length(Fields),
- FN = {File, erl_anno:line(A)},
+ FN = {File, Line},
NewRecDict = maps:put({record, Name}, {FN, [{Arity,Fields}]}, RecDict),
get_record_and_type_info(Left, Module, NewRecDict, File);
-get_record_and_type_info([{attribute, A, type, {{record, Name}, Fields0, []}}
+get_record_and_type_info([{type, Line, [{{record, Name}, Fields0, []}]}
|Left], Module, RecDict, File) ->
%% This overrides the original record declaration.
{ok, Fields} = get_record_fields(Fields0, RecDict),
Arity = length(Fields),
- FN = {File, erl_anno:line(A)},
+ FN = {File, Line},
NewRecDict = maps:put({record, Name}, {FN, [{Arity, Fields}]}, RecDict),
get_record_and_type_info(Left, Module, NewRecDict, File);
-get_record_and_type_info([{attribute, A, Attr, {Name, TypeForm}}|Left],
+get_record_and_type_info([{Attr, Line, [{Name, TypeForm}]}|Left],
Module, RecDict, File)
when Attr =:= 'type'; Attr =:= 'opaque' ->
- FN = {File, erl_anno:line(A)},
+ FN = {File, Line},
try add_new_type(Attr, Name, TypeForm, [], Module, FN, RecDict) of
NewRecDict ->
get_record_and_type_info(Left, Module, NewRecDict, File)
catch
throw:{error, _} = Error -> Error
end;
-get_record_and_type_info([{attribute, A, Attr, {Name, TypeForm, Args}}|Left],
+get_record_and_type_info([{Attr, Line, [{Name, TypeForm, Args}]}|Left],
Module, RecDict, File)
when Attr =:= 'type'; Attr =:= 'opaque' ->
- FN = {File, erl_anno:line(A)},
+ FN = {File, Line},
try add_new_type(Attr, Name, TypeForm, Args, Module, FN, RecDict) of
NewRecDict ->
get_record_and_type_info(Left, Module, NewRecDict, File)
catch
throw:{error, _} = Error -> Error
end;
-get_record_and_type_info([{attribute, _, file, {IncludeFile, _}}|Left],
+get_record_and_type_info([{file, _, [{IncludeFile, _}]}|Left],
Module, RecDict, _File) ->
get_record_and_type_info(Left, Module, RecDict, IncludeFile);
get_record_and_type_info([_Other|Left], Module, RecDict, File) ->
@@ -460,23 +478,18 @@ merge_types(CServer, Plt) ->
-type spec_map() :: dialyzer_codeserver:contracts().
-type callback_map() :: dialyzer_codeserver:contracts().
--spec get_spec_info(module(), abstract_code(), type_table()) ->
+-spec get_spec_info(module(), cerl:module(), type_table()) ->
{'ok', spec_map(), callback_map()} | {'error', string()}.
-get_spec_info(ModName, AbstractCode, RecordsMap) ->
- OptionalCallbacks0 = get_optional_callbacks(AbstractCode, ModName),
+get_spec_info(ModName, Core, RecordsMap) ->
+ Tuples = core_to_attr_tuples(Core),
+ OptionalCallbacks0 = get_optional_callbacks(Tuples, ModName),
OptionalCallbacks = gb_sets:from_list(OptionalCallbacks0),
- get_spec_info(AbstractCode, maps:new(), maps:new(),
+ get_spec_info(Tuples, maps:new(), maps:new(),
RecordsMap, ModName, OptionalCallbacks, "nofile").
-get_optional_callbacks(Abs, ModName) ->
- [{ModName, F, A} || {F, A} <- get_optional_callbacks(Abs)].
-
-get_optional_callbacks(Abs) ->
- L = [O ||
- {attribute, _, optional_callbacks, O} <- Abs,
- is_fa_list(O)],
- lists:append(L).
+get_optional_callbacks(Tuples, ModName) ->
+ [{ModName, F, A} || {optional_callbacks, _, O} <- Tuples, is_fa_list(O), {F, A} <- O].
%% TypeSpec is a list of conditional contracts for a function.
%% Each contract is of the form {[Argument], Range, [Constraint]} where
@@ -484,11 +497,10 @@ get_optional_callbacks(Abs) ->
%% - Constraint is of the form {subtype, T1, T2} where T1 and T2
%% are erl_types:erl_type()
-get_spec_info([{attribute, Anno, Contract, {Id, TypeSpec}}|Left],
+get_spec_info([{Contract, Ln, [{Id, TypeSpec}]}|Left],
SpecMap, CallbackMap, RecordsMap, ModName, OptCb, File)
when ((Contract =:= 'spec') or (Contract =:= 'callback')),
is_list(TypeSpec) ->
- Ln = erl_anno:line(Anno),
MFA = case Id of
{_, _, _} = T -> T;
{F, A} -> {ModName, F, A}
@@ -523,7 +535,7 @@ get_spec_info([{attribute, Anno, Contract, {Id, TypeSpec}}|Left],
{error, flat_format(" Error while parsing contract in line ~w: ~s\n",
[Ln, Error])}
end;
-get_spec_info([{attribute, _, file, {IncludeFile, _}}|Left],
+get_spec_info([{file, _, [{IncludeFile, _}]}|Left],
SpecMap, CallbackMap, RecordsMap, ModName, OptCb, _File) ->
get_spec_info(Left, SpecMap, CallbackMap,
RecordsMap, ModName, OptCb, IncludeFile);
@@ -535,15 +547,25 @@ get_spec_info([], SpecMap, CallbackMap,
_RecordsMap, _ModName, _OptCb, _File) ->
{ok, SpecMap, CallbackMap}.
--spec get_fun_meta_info(module(), abstract_code(), [dial_warn_tag()]) ->
+core_to_attr_tuples(Core) ->
+ [{cerl:concrete(Key), get_core_line(cerl:get_ann(Key)), cerl:concrete(Value)} ||
+ {Key, Value} <- cerl:module_attrs(Core)].
+
+get_core_line([L | _As]) when is_integer(L) -> L;
+get_core_line([_ | As]) -> get_core_line(As);
+get_core_line([]) -> undefined.
+
+-spec get_fun_meta_info(module(), cerl:module(), [dial_warn_tag()]) ->
dialyzer_codeserver:fun_meta_info() | {'error', string()}.
-get_fun_meta_info(M, Abs, LegalWarnings) ->
+get_fun_meta_info(M, Core, LegalWarnings) ->
+ Functions = lists:map(fun cerl:var_name/1, cerl:module_vars(Core)),
try
- {get_nowarn_unused_function(M, Abs), get_func_suppressions(M, Abs)}
+ {get_nowarn_unused_function(M, Core, Functions),
+ get_func_suppressions(M, Core, Functions)}
of
{NoWarn, FuncSupp} ->
- Warnings0 = get_options(Abs, LegalWarnings),
+ Warnings0 = get_options(Core, LegalWarnings),
Warnings = ordsets:to_list(Warnings0),
ModuleWarnings = [{M, W} || W <- Warnings],
RawProps = lists:append([NoWarn, FuncSupp, ModuleWarnings]),
@@ -569,49 +591,45 @@ process_options([{{_M, _F, _A}=MFA, Opts}|Left], Warnings) ->
end;
process_options([], _Warnings) -> [].
--spec get_nowarn_unused_function(module(), abstract_code()) ->
+-spec get_nowarn_unused_function(module(), cerl:module(), [fa()]) ->
[{mfa(), 'no_unused'}].
-get_nowarn_unused_function(M, Abs) ->
- Opts = get_options_with_tag(compile, Abs),
+get_nowarn_unused_function(M, Core, Functions) ->
+ Opts = get_options_with_tag(compile, Core),
Warn = erl_lint:bool_option(warn_unused_function, nowarn_unused_function,
true, Opts),
- Functions = [{F, A} || {function, _, F, A, _} <- Abs],
- AttrFile = collect_attribute(Abs, compile),
+ AttrFile = collect_attribute(Core, compile),
TagsFaList = check_fa_list(AttrFile, nowarn_unused_function, Functions),
FAs = case Warn of
false -> Functions;
true ->
- [FA || {{nowarn_unused_function,_L,_File}, FA} <- TagsFaList]
+ [FA || {{[nowarn_unused_function],_L,_File}, FA} <- TagsFaList]
end,
[{{M, F, A}, no_unused} || {F, A} <- FAs].
--spec get_func_suppressions(module(), abstract_code()) ->
+-spec get_func_suppressions(module(), cerl:module(), [fa()]) ->
[{mfa(), 'nowarn_function' | dial_warn_tag()}].
-get_func_suppressions(M, Abs) ->
- Functions = [{F, A} || {function, _, F, A, _} <- Abs],
- AttrFile = collect_attribute(Abs, dialyzer),
+get_func_suppressions(M, Core, Functions) ->
+ AttrFile = collect_attribute(Core, dialyzer),
TagsFAs = check_fa_list(AttrFile, '*', Functions),
%% Check the options:
- Fun = fun({{nowarn_function, _L, _File}, _FA}) -> ok;
+ Fun = fun({{[nowarn_function], _L, _File}, _FA}) -> ok;
({OptLFile, _FA}) ->
_ = get_options1([OptLFile], ordsets:new())
end,
lists:foreach(Fun, TagsFAs),
- [{{M, F, A}, W} || {{W, _L, _File}, {F, A}} <- TagsFAs].
+ [{{M, F, A}, W} || {{Warnings, _L, _File}, {F, A}} <- TagsFAs, W <- Warnings].
--spec get_options(abstract_code(), [dial_warn_tag()]) ->
+-spec get_options(cerl:module(), [dial_warn_tag()]) ->
ordsets:ordset(dial_warn_tag()).
-get_options(Abs, LegalWarnings) ->
- AttrFile = collect_attribute(Abs, dialyzer),
+get_options(Core, LegalWarnings) ->
+ AttrFile = collect_attribute(Core, dialyzer),
get_options1(AttrFile, LegalWarnings).
get_options1([{Args, L, File}|Left], Warnings) ->
- Opts = [O ||
- O <- lists:flatten([Args]),
- is_atom(O)],
+ Opts = [O || O <- Args, is_atom(O)],
try dialyzer_options:build_warnings(Opts, Warnings) of
NewWarnings ->
get_options1(Left, NewWarnings)
@@ -624,19 +642,24 @@ get_options1([], Warnings) ->
Warnings.
-type collected_attribute() ::
- {Args :: term(), erl_anno:line(), file:filename()}.
-
-collect_attribute(Abs, Tag) ->
- collect_attribute(Abs, Tag, "nofile").
-
-collect_attribute([{attribute, L, Tag, Args}|Left], Tag, File) ->
- CollAttr = {Args, L, File},
- [CollAttr | collect_attribute(Left, Tag, File)];
-collect_attribute([{attribute, _, file, {IncludeFile, _}}|Left], Tag, _) ->
- collect_attribute(Left, Tag, IncludeFile);
-collect_attribute([_Other|Left], Tag, File) ->
- collect_attribute(Left, Tag, File);
-collect_attribute([], _Tag, _File) -> [].
+ {Args :: [term()], erl_anno:line(), file:filename()}.
+
+collect_attribute(Core, Tag) ->
+ collect_attribute(cerl:module_attrs(Core), Tag, "nofile").
+
+collect_attribute([{Key, Value}|T], Tag, File) ->
+ case cerl:concrete(Key) of
+ Tag ->
+ [{cerl:concrete(Value), get_core_line(cerl:get_ann(Key)), File} |
+ collect_attribute(T, Tag, File)];
+ file ->
+ [{IncludeFile, _}] = cerl:concrete(Value),
+ collect_attribute(T, Tag, IncludeFile);
+ _ ->
+ collect_attribute(T, Tag, File)
+ end;
+collect_attribute([], _Tag, _File) ->
+ [].
-spec is_suppressed_fun(mfa(), codeserver()) -> boolean().
@@ -687,35 +710,6 @@ src_compiler_opts() ->
no_inline, strict_record_tests, strict_record_updates,
dialyzer].
--spec get_module(abstract_code()) -> module().
-
-get_module([{attribute, _, module, {M, _As}} | _]) -> M;
-get_module([{attribute, _, module, M} | _]) -> M;
-get_module([_ | Rest]) -> get_module(Rest).
-
--spec cleanup_parse_transforms(abstract_code()) -> abstract_code().
-
-cleanup_parse_transforms([{attribute, _, compile, {parse_transform, _}}|Left]) ->
- cleanup_parse_transforms(Left);
-cleanup_parse_transforms([Other|Left]) ->
- [Other|cleanup_parse_transforms(Left)];
-cleanup_parse_transforms([]) ->
- [].
-
--spec cleanup_compile_options([compile:option()]) -> [compile:option()].
-
-cleanup_compile_options(Opts) ->
- lists:filter(fun keep_compile_option/1, Opts).
-
-%% Using abstract, not asm or core.
-keep_compile_option(from_asm) -> false;
-keep_compile_option(from_core) -> false;
-%% The parse transform will already have been applied, may cause
-%% problems if it is re-applied.
-keep_compile_option({parse_transform, _}) -> false;
-keep_compile_option(warnings_as_errors) -> false;
-keep_compile_option(_) -> true.
-
-spec format_errors([{module(), string()}]) -> [string()].
format_errors([{Mod, Errors}|Left]) ->
@@ -741,10 +735,12 @@ format_sig(Type, RecDict) ->
flat_format(Fmt, Lst) ->
lists:flatten(io_lib:format(Fmt, Lst)).
--spec get_options_with_tag(atom(), abstract_code()) -> [term()].
+-spec get_options_with_tag(atom(), cerl:module()) -> [term()].
-get_options_with_tag(Tag, Abs) ->
- lists:flatten([O || {attribute, _, Tag0, O} <- Abs, Tag =:= Tag0]).
+get_options_with_tag(Tag, Core) ->
+ [O || {Key, Value} <- cerl:module_attrs(Core),
+ cerl:concrete(Key) =:= Tag,
+ O <- cerl:concrete(Value)].
%% Check F/A, and collect (unchecked) warning tags with line and file.
-spec check_fa_list([collected_attribute()], atom(), [fa()]) ->
@@ -755,8 +751,8 @@ check_fa_list(AttrFile, Tag, Functions) ->
check_fa_list1(AttrFile, Tag, FuncTab).
check_fa_list1([{Args, L, File}|Left], Tag, Funcs) ->
- TermsL = [{{Tag0, L, File}, Term} ||
- {Tags, Terms0} <- lists:flatten([Args]),
+ TermsL = [{{[Tag0], L, File}, Term} ||
+ {Tags, Terms0} <- Args,
Tag0 <- lists:flatten([Tags]),
Tag =:= '*' orelse Tag =:= Tag0,
Term <- lists:flatten([Terms0])],
diff --git a/lib/dialyzer/src/typer.erl b/lib/dialyzer/src/typer.erl
index 18c4fe902d..86c7c62f98 100644
--- a/lib/dialyzer/src/typer.erl
+++ b/lib/dialyzer/src/typer.erl
@@ -109,12 +109,12 @@ extract(#analysis{macros = Macros,
AllIncludes = [filename:dirname(filename:dirname(File)) | Includes],
Is = [{i, Dir} || Dir <- AllIncludes],
CompOpts = dialyzer_utils:src_compiler_opts() ++ Is ++ Ds,
- case dialyzer_utils:get_abstract_code_from_src(File, CompOpts) of
- {ok, AbstractCode} ->
- case dialyzer_utils:get_record_and_type_info(AbstractCode) of
+ case dialyzer_utils:get_core_from_src(File, CompOpts) of
+ {ok, Core} ->
+ case dialyzer_utils:get_record_and_type_info(Core) of
{ok, RecDict} ->
Mod = list_to_atom(filename:basename(File, ".erl")),
- case dialyzer_utils:get_spec_info(Mod, AbstractCode, RecDict) of
+ case dialyzer_utils:get_spec_info(Mod, Core, RecDict) of
{ok, SpecDict, CbDict} ->
CS1 = dialyzer_codeserver:store_temp_records(Mod, RecDict, CS),
dialyzer_codeserver:store_temp_contracts(Mod, SpecDict, CbDict, CS1);
@@ -846,26 +846,22 @@ collect_one_file_info(File, Analysis) ->
Includes = [filename:dirname(File)|Analysis#analysis.includes],
Is = [{i,Dir} || Dir <- Includes],
Options = dialyzer_utils:src_compiler_opts() ++ Is ++ Ds,
- case dialyzer_utils:get_abstract_code_from_src(File, Options) of
+ case dialyzer_utils:get_core_from_src(File, Options) of
{error, Reason} ->
%% io:format("File=~p\n,Options=~p\n,Error=~p\n", [File,Options,Reason]),
compile_error(Reason);
- {ok, AbstractCode} ->
- case dialyzer_utils:get_core_from_abstract_code(AbstractCode, Options) of
- error -> compile_error(["Could not get core erlang for "++File]);
- {ok, Core} ->
- case dialyzer_utils:get_record_and_type_info(AbstractCode) of
+ {ok, Core} ->
+ case dialyzer_utils:get_record_and_type_info(Core) of
+ {error, Reason} -> compile_error([Reason]);
+ {ok, Records} ->
+ Mod = cerl:concrete(cerl:module_name(Core)),
+ case dialyzer_utils:get_spec_info(Mod, Core, Records) of
{error, Reason} -> compile_error([Reason]);
- {ok, Records} ->
- Mod = cerl:concrete(cerl:module_name(Core)),
- case dialyzer_utils:get_spec_info(Mod, AbstractCode, Records) of
- {error, Reason} -> compile_error([Reason]);
- {ok, SpecInfo, CbInfo} ->
- ExpTypes = get_exported_types_from_core(Core),
- analyze_core_tree(Core, Records, SpecInfo, CbInfo,
- ExpTypes, Analysis, File)
- end
- end
+ {ok, SpecInfo, CbInfo} ->
+ ExpTypes = get_exported_types_from_core(Core),
+ analyze_core_tree(Core, Records, SpecInfo, CbInfo,
+ ExpTypes, Analysis, File)
+ end
end
end.
diff --git a/lib/edoc/src/edoc_layout.erl b/lib/edoc/src/edoc_layout.erl
index 5b1889ab06..eafab0588e 100644
--- a/lib/edoc/src/edoc_layout.erl
+++ b/lib/edoc/src/edoc_layout.erl
@@ -544,7 +544,7 @@ t_clause(Name, Type, Opts) ->
pp_clause(Pre, Type, Opts) ->
Types = ot_utype([Type]),
- Atom = lists:duplicate(string_length(Pre), $a),
+ Atom = lists:duplicate(string:length(Pre), $a),
Attr = {attribute,0,spec,{{list_to_atom(Atom),0},[Types]}},
L1 = erl_pp:attribute(erl_parse:new_anno(Attr),
[{encoding, Opts#opts.encoding}]),
@@ -566,7 +566,7 @@ format_type(Prefix, _Name, Type, Last, Opts) ->
[{tt, Prefix ++ [" = "] ++ t_utype(Type, Opts) ++ Last}].
pp_type(Prefix, Type, Opts) ->
- Atom = list_to_atom(lists:duplicate(string_length(Prefix), $a)),
+ Atom = list_to_atom(lists:duplicate(string:length(Prefix), $a)),
Attr = {attribute,0,type,{Atom,ot_utype(Type),[]}},
L1 = erl_pp:attribute(erl_parse:new_anno(Attr),
[{encoding, Opts#opts.encoding}]),
@@ -768,21 +768,6 @@ atom(String, #opts{encoding = latin1}) ->
atom(String, #opts{encoding = utf8}) ->
io_lib:write_atom(list_to_atom(String)).
--dialyzer({nowarn_function, string_length/1}).
-string_length(Data) ->
- try iolist_size(Data)
- catch
- _:_ ->
- M = string,
- F = length,
- As = [Data],
- try apply(M, F, As)
- catch
- _:_ ->
- 20
- end
- end.
-
%% <!ATTLIST author
%% name CDATA #REQUIRED
%% email CDATA #IMPLIED
diff --git a/lib/erl_docgen/priv/css/Makefile b/lib/erl_docgen/priv/css/Makefile
index c317411d32..e3d2ee7e3f 100644
--- a/lib/erl_docgen/priv/css/Makefile
+++ b/lib/erl_docgen/priv/css/Makefile
@@ -39,7 +39,8 @@ RELSYSDIR = $(RELEASE_PATH)/lib/erl_docgen-$(VSN)
CSS_FILES = \
- otp_doc.css
+ otp_doc.css \
+ highlight.css
# ----------------------------------------------------
diff --git a/lib/erl_docgen/priv/css/highlight.css b/lib/erl_docgen/priv/css/highlight.css
new file mode 100644
index 0000000000..d5bd1d2a9a
--- /dev/null
+++ b/lib/erl_docgen/priv/css/highlight.css
@@ -0,0 +1,96 @@
+/*
+
+Atom One Light by Daniel Gamage
+Original One Light Syntax theme from https://github.com/atom/one-light-syntax
+
+base: #fafafa
+mono-1: #383a42
+mono-2: #686b77
+mono-3: #a0a1a7
+hue-1: #0184bb
+hue-2: #4078f2
+hue-3: #a626a4
+hue-4: #50a14f
+hue-5: #e45649
+hue-5-2: #c91243
+hue-6: #986801
+hue-6-2: #c18401
+
+*/
+
+.hljs {
+ display: block;
+ overflow-x: auto;
+ padding: 0.5em;
+ color: #383a42;
+ background: #fafafa;
+}
+
+.hljs-comment,
+.hljs-quote {
+ color: #a0a1a7;
+ font-style: italic;
+}
+
+.hljs-doctag,
+.hljs-keyword,
+.hljs-formula {
+ color: #a626a4;
+}
+
+.hljs-section,
+.hljs-name,
+.hljs-selector-tag,
+.hljs-deletion,
+.hljs-subst {
+ color: #e45649;
+}
+
+.hljs-literal {
+ color: #0184bb;
+}
+
+.hljs-string,
+.hljs-regexp,
+.hljs-addition,
+.hljs-attribute,
+.hljs-meta-string {
+ color: #50a14f;
+}
+
+.hljs-built_in,
+.hljs-class .hljs-title {
+ color: #c18401;
+}
+
+.hljs-attr,
+.hljs-variable,
+.hljs-template-variable,
+.hljs-type,
+.hljs-selector-class,
+.hljs-selector-attr,
+.hljs-selector-pseudo,
+.hljs-number {
+ color: #986801;
+}
+
+.hljs-symbol,
+.hljs-bullet,
+.hljs-link,
+.hljs-meta,
+.hljs-selector-id,
+.hljs-title {
+ color: #4078f2;
+}
+
+.hljs-emphasis {
+ font-style: italic;
+}
+
+.hljs-strong {
+ font-weight: bold;
+}
+
+.hljs-link {
+ text-decoration: underline;
+}
diff --git a/lib/erl_docgen/priv/css/otp_doc.css b/lib/erl_docgen/priv/css/otp_doc.css
index 219740a557..844aad2945 100644
--- a/lib/erl_docgen/priv/css/otp_doc.css
+++ b/lib/erl_docgen/priv/css/otp_doc.css
@@ -1,34 +1,39 @@
/* standard OTP style sheet */
body {
- background: white;
- font-family: Verdana, Arial, Helvetica, sans-serif;
+ background: #fefefe;
+ color: #1a1a1a;
+ font-family: sans-serif;
margin: 0;
padding: 0;
border: 0;
overflow: scroll;
height: 100%;
max-height: 100%;
+ line-height: 1.2em;
+ font-size: 16px;
}
-th { font-family: Verdana, Arial, Helvetica, sans-serif }
-td { font-family: Verdana, Arial, Helvetica, sans-serif }
-p { font-family: Verdana, Arial, Helvetica, sans-serif }
+h1, h2, h3, h4, h5, h6{
+ line-height: 1.2em;
+}
+
+p { max-width: 42em }
-.header { background: #222; color: #fff }
+.header { background: #222; color: #fefefe }
.top { background: #efe }
.otp { background: #efe }
.erlang { background: #ffe }
.otp2 { background: #efe }
.app { background: #ffe }
-a:link { color: blue; text-decoration: none }
-a:active { color: blue; text-decoration: none }
-a:visited { color: blue; text-decoration: none }
+a:link { color: #1862ab; text-decoration: none }
+a:active { color: #1c7cd6; text-decoration: none }
+a:visited { color: #1b6ec2; text-decoration: none }
#container {
width: 100%;
margin: 0;
- background-color: #fff;
+ background-color: #fefefe;
}
#leftnav {
@@ -41,11 +46,12 @@ a:visited { color: blue; text-decoration: none }
overflow:auto;
margin: 0;
padding: 1px;
- border-right: 1px solid red;
+ border-right: 1px solid #ccc;
}
#content {
margin-left: 340px; /* set left value to WidthOfFrameDiv */
+ max-width: 42em;
}
.frontpage
@@ -61,66 +67,67 @@ a:visited { color: blue; text-decoration: none }
.footer
{
margin: 15px; /* Magins for inner DIV inside each DIV (to provide padding) */
+ text-align: center;
}
-span.bold_code { font-family: Courier, monospace; font-weight: bold }
-span.code { font-family: Courier, monospace; font-weight: normal }
+.bold_code { font-family: mono, Courier, monospace; font-weight: bold }
+.code {
+ font-family: mono, Courier, monospace;
+ font-weight: normal;
+ background-color: #f3f3f3;
+}
.note, .warning, .do, .dont {
- border: solid black 1px;
- margin: 1em 3em;
+ border: 1px solid #495057;
+ margin: 1em 0;
}
.note .label {
- background: #30d42a;
- color: white;
+ background-color: #2b8a3e;
+ color: #fefefe;
font-weight: bold;
- padding: 5px 10px;
+ padding: 0.5em 1em;
}
.note .content {
- background: #eafeea;
- color: black;
+ background: #f8f9fa;
line-height: 120%;
- font-size: 90%;
- padding: 5px 10px;
+ font-size: 0.9em;
+ padding: 0.5em 1em;
}
.warning .label {
- background: #C00;
- color: white;
+ background: #c92a2a;
+ color: #fefefe;
font-weight: bold;
- padding: 5px 10px;
+ padding: 0.5em 1em;
}
.warning .content {
- background: #FFF0F0;
- color: black;
+ background-color: #f8f9fa;
line-height: 120%;
- font-size: 90%;
- padding: 5px 10px;
+ font-size: 0.9em;
+ padding: 0.5em 1em;
}
.do .label {
- background: #30d42a;
- color: white;
+ background-color: #2b8a3e;
+ color: #fefefe;
font-weight: bold;
- padding: 5px 10px;
+ padding: 0.5em 1em;
}
.do .content {
- background: #eafeea;
- color: black;
+ background: #f8f9fa;
line-height: 120%;
- font-size: 90%;
- padding: 5px 10px;
+ font-size: 0.9em;
+ padding: 0.5em 1em;
}
.dont .label {
- background: #C00;
- color: white;
+ background: #c92a2a;
+ color: #fefefe;
font-weight: bold;
- padding: 5px 10px;
+ padding: 0.5em 1em;
}
.dont .content {
- background: #FFF0F0;
- color: black;
+ background-color: #f8f9fa;
line-height: 120%;
- font-size: 90%;
- padding: 5px 10px;
+ font-size: 0.9em;
+ padding: 0.5em 1em;
}
.quote {
@@ -128,19 +135,134 @@ span.code { font-family: Courier, monospace; font-weight: normal }
}
.example {
- background-color:#eeeeff;
- padding: 0px 10px;
+ background-color:#f1f3f5;
+ border: 1px solid #dee2e6;
+ padding: 0.5em 1em;
+ margin: 1em 0;
+ font-size: 0.7em;
}
.extrafrontpageinfo {
color: #C00;
font-weight: bold;
- font-size: 120%;
+ font-size: 1.2em;
}
-pre { font-family: Courier, monospace; font-weight: normal }
+pre {
+ font-family: mono, Courier, monospace;
+ font-weight: normal;
+ margin: 0;
+}
-.REFBODY { margin-left: 13mm }
-.REFTYPES { margin-left: 8mm }
+.exports-body, .data-types-body, .REFBODY{
+ margin-left: 2em;
+}
+.REFTYPES { margin-left: 1.5em }
footer { }
+
+.erlang-logo-wrapper{
+ text-align: center;
+ margin-bottom: 1em;
+}
+
+.main-title{
+ text-align: center;
+}
+
+.main-description{
+ text-align: center;
+ margin: 2em 0;
+ font-size: 1.5em;
+ line-height: 1.5em;
+}
+
+.doc-table-wrapper, .doc-image-wrapper{
+ width: 100%;
+}
+
+.doc-image-wrapper{
+ text-align: center;
+}
+
+.doc-table, .doc-image{
+ min-width: 50%;
+ margin: 0 auto;
+ font-size: 0.7em;
+}
+
+.doc-table-caption, .doc-image-caption{
+ margin-top: 1em;
+ font-style: italic;
+ text-align: center;
+}
+
+table {
+ border-collapse: collapse;
+ min-width: 50%;
+ margin: 1em;
+}
+
+table, th, td {
+ border: 1px solid #666;
+}
+
+th, td {
+ padding: 0.5em;
+ text-align: left;
+}
+
+tr:hover {
+ background-color: #f5f5f5;
+}
+
+tr:nth-child(even) {
+ background-color: #f2f2f2;
+}
+
+th {
+ background-color: #777;
+ color: #fefefe;
+}
+
+.section-title, .section-subtitle, .section-version{
+ text-align: center;
+ margin: 0;
+}
+
+.section-title{
+ font-weight: bold;
+}
+
+.section-version{
+ font-size: small;
+}
+
+.expand-collapse-items{
+ font-size: small;
+}
+
+h3>a{
+ color: #1a1a1a !important;
+}
+
+hr{
+ border: 0;
+ border-top: 1px solid #aaa;
+}
+
+.section-links, .panel-sections, .expand-collapse-items{
+ padding: 0 1em;
+}
+
+.section-links, .panel-sections{
+ margin-top: 0;
+}
+
+a > .code {
+ color: #1862ab;
+}
+
+.func-types-title{
+ font-size: 1em;
+}
diff --git a/lib/erl_docgen/priv/images/erlang-logo.gif b/lib/erl_docgen/priv/images/erlang-logo.gif
index abf5f225d7..ae13168429 100644
--- a/lib/erl_docgen/priv/images/erlang-logo.gif
+++ b/lib/erl_docgen/priv/images/erlang-logo.gif
Binary files differ
diff --git a/lib/erl_docgen/priv/images/erlang-logo.png b/lib/erl_docgen/priv/images/erlang-logo.png
index 56291aac15..41bba97417 100644
--- a/lib/erl_docgen/priv/images/erlang-logo.png
+++ b/lib/erl_docgen/priv/images/erlang-logo.png
Binary files differ
diff --git a/lib/erl_docgen/priv/js/flipmenu/Makefile b/lib/erl_docgen/priv/js/flipmenu/Makefile
index 06a13defca..ad6d4acb6c 100644
--- a/lib/erl_docgen/priv/js/flipmenu/Makefile
+++ b/lib/erl_docgen/priv/js/flipmenu/Makefile
@@ -76,6 +76,7 @@ release_spec: opt
release_docs_spec:
$(INSTALL_DIR) "$(RELEASE_PATH)/doc/js/flipmenu"
$(INSTALL_DATA) $(JS_FILES) $(GIF_FILES) "$(RELEASE_PATH)/doc/js/flipmenu"
+ $(INSTALL_DATA) ../highlight.js ../highlight.pack.js "$(RELEASE_PATH)/doc/js/"
release_tests_spec:
diff --git a/lib/erl_docgen/priv/js/flipmenu/flip_closed.gif b/lib/erl_docgen/priv/js/flipmenu/flip_closed.gif
index 9a27c7c25d..a75107a782 100644
--- a/lib/erl_docgen/priv/js/flipmenu/flip_closed.gif
+++ b/lib/erl_docgen/priv/js/flipmenu/flip_closed.gif
Binary files differ
diff --git a/lib/erl_docgen/priv/js/flipmenu/flip_open.gif b/lib/erl_docgen/priv/js/flipmenu/flip_open.gif
index 9dda60e73a..1274637fe0 100644
--- a/lib/erl_docgen/priv/js/flipmenu/flip_open.gif
+++ b/lib/erl_docgen/priv/js/flipmenu/flip_open.gif
Binary files differ
diff --git a/lib/erl_docgen/priv/js/flipmenu/flip_static.gif b/lib/erl_docgen/priv/js/flipmenu/flip_static.gif
index 2b3ddb5382..4cc914a50a 100644
--- a/lib/erl_docgen/priv/js/flipmenu/flip_static.gif
+++ b/lib/erl_docgen/priv/js/flipmenu/flip_static.gif
Binary files differ
diff --git a/lib/erl_docgen/priv/js/highlight.js b/lib/erl_docgen/priv/js/highlight.js
new file mode 100644
index 0000000000..0594b42aa3
--- /dev/null
+++ b/lib/erl_docgen/priv/js/highlight.js
@@ -0,0 +1,39 @@
+/*globals document, window*/
+window.addEventListener("load", function () {
+ "use strict";
+ var body = document.body,
+ base = window.__otpTopDocDir || "/doc/js/",
+ cssLink = document.createElement('link'),
+ script = document.createElement('script'),
+ intervalId, attempts = 0;
+
+ cssLink.rel = "stylesheet";
+ cssLink.href = base + "../highlight.css";
+ script.src = base + "highlight.pack.js";
+
+ body.appendChild(cssLink);
+ body.appendChild(script);
+
+ function doHighlight() {
+ attempts += 1;
+
+ if (attempts > 20) {
+ window.clearInterval(intervalId);
+ return;
+ }
+
+ if (!window.hljs) {
+ return;
+ }
+
+ window.clearInterval(intervalId);
+
+ var i, len, nodes = document.querySelectorAll('.example');
+ for (i = 0, len = nodes.length; i < len; i += 1) {
+ window.hljs.highlightBlock(nodes[i]);
+ }
+
+ }
+
+ intervalId = window.setInterval(doHighlight, 50);
+});
diff --git a/lib/erl_docgen/priv/js/highlight.pack.js b/lib/erl_docgen/priv/js/highlight.pack.js
new file mode 100644
index 0000000000..073d39e644
--- /dev/null
+++ b/lib/erl_docgen/priv/js/highlight.pack.js
@@ -0,0 +1,2 @@
+/*! highlight.js v9.7.0 | BSD3 License | git.io/hljslicense */
+!function(e){var n="object"==typeof window&&window||"object"==typeof self&&self;"undefined"!=typeof exports?e(exports):n&&(n.hljs=e({}),"function"==typeof define&&define.amd&&define([],function(){return n.hljs}))}(function(e){function n(e){return e.replace(/[&<>]/gm,function(e){return I[e]})}function t(e){return e.nodeName.toLowerCase()}function r(e,n){var t=e&&e.exec(n);return t&&0===t.index}function a(e){return k.test(e)}function i(e){var n,t,r,i,o=e.className+" ";if(o+=e.parentNode?e.parentNode.className:"",t=B.exec(o))return R(t[1])?t[1]:"no-highlight";for(o=o.split(/\s+/),n=0,r=o.length;r>n;n++)if(i=o[n],a(i)||R(i))return i}function o(e,n){var t,r={};for(t in e)r[t]=e[t];if(n)for(t in n)r[t]=n[t];return r}function u(e){var n=[];return function r(e,a){for(var i=e.firstChild;i;i=i.nextSibling)3===i.nodeType?a+=i.nodeValue.length:1===i.nodeType&&(n.push({event:"start",offset:a,node:i}),a=r(i,a),t(i).match(/br|hr|img|input/)||n.push({event:"stop",offset:a,node:i}));return a}(e,0),n}function c(e,r,a){function i(){return e.length&&r.length?e[0].offset!==r[0].offset?e[0].offset<r[0].offset?e:r:"start"===r[0].event?e:r:e.length?e:r}function o(e){function r(e){return" "+e.nodeName+'="'+n(e.value)+'"'}l+="<"+t(e)+w.map.call(e.attributes,r).join("")+">"}function u(e){l+="</"+t(e)+">"}function c(e){("start"===e.event?o:u)(e.node)}for(var s=0,l="",f=[];e.length||r.length;){var g=i();if(l+=n(a.substr(s,g[0].offset-s)),s=g[0].offset,g===e){f.reverse().forEach(u);do c(g.splice(0,1)[0]),g=i();while(g===e&&g.length&&g[0].offset===s);f.reverse().forEach(o)}else"start"===g[0].event?f.push(g[0].node):f.pop(),c(g.splice(0,1)[0])}return l+n(a.substr(s))}function s(e){function n(e){return e&&e.source||e}function t(t,r){return new RegExp(n(t),"m"+(e.cI?"i":"")+(r?"g":""))}function r(a,i){if(!a.compiled){if(a.compiled=!0,a.k=a.k||a.bK,a.k){var u={},c=function(n,t){e.cI&&(t=t.toLowerCase()),t.split(" ").forEach(function(e){var t=e.split("|");u[t[0]]=[n,t[1]?Number(t[1]):1]})};"string"==typeof a.k?c("keyword",a.k):E(a.k).forEach(function(e){c(e,a.k[e])}),a.k=u}a.lR=t(a.l||/\w+/,!0),i&&(a.bK&&(a.b="\\b("+a.bK.split(" ").join("|")+")\\b"),a.b||(a.b=/\B|\b/),a.bR=t(a.b),a.e||a.eW||(a.e=/\B|\b/),a.e&&(a.eR=t(a.e)),a.tE=n(a.e)||"",a.eW&&i.tE&&(a.tE+=(a.e?"|":"")+i.tE)),a.i&&(a.iR=t(a.i)),null==a.r&&(a.r=1),a.c||(a.c=[]);var s=[];a.c.forEach(function(e){e.v?e.v.forEach(function(n){s.push(o(e,n))}):s.push("self"===e?a:e)}),a.c=s,a.c.forEach(function(e){r(e,a)}),a.starts&&r(a.starts,i);var l=a.c.map(function(e){return e.bK?"\\.?("+e.b+")\\.?":e.b}).concat([a.tE,a.i]).map(n).filter(Boolean);a.t=l.length?t(l.join("|"),!0):{exec:function(){return null}}}}r(e)}function l(e,t,a,i){function o(e,n){var t,a;for(t=0,a=n.c.length;a>t;t++)if(r(n.c[t].bR,e))return n.c[t]}function u(e,n){if(r(e.eR,n)){for(;e.endsParent&&e.parent;)e=e.parent;return e}return e.eW?u(e.parent,n):void 0}function c(e,n){return!a&&r(n.iR,e)}function g(e,n){var t=N.cI?n[0].toLowerCase():n[0];return e.k.hasOwnProperty(t)&&e.k[t]}function h(e,n,t,r){var a=r?"":y.classPrefix,i='<span class="'+a,o=t?"":C;return i+=e+'">',i+n+o}function p(){var e,t,r,a;if(!E.k)return n(B);for(a="",t=0,E.lR.lastIndex=0,r=E.lR.exec(B);r;)a+=n(B.substr(t,r.index-t)),e=g(E,r),e?(M+=e[1],a+=h(e[0],n(r[0]))):a+=n(r[0]),t=E.lR.lastIndex,r=E.lR.exec(B);return a+n(B.substr(t))}function d(){var e="string"==typeof E.sL;if(e&&!x[E.sL])return n(B);var t=e?l(E.sL,B,!0,L[E.sL]):f(B,E.sL.length?E.sL:void 0);return E.r>0&&(M+=t.r),e&&(L[E.sL]=t.top),h(t.language,t.value,!1,!0)}function b(){k+=null!=E.sL?d():p(),B=""}function v(e){k+=e.cN?h(e.cN,"",!0):"",E=Object.create(e,{parent:{value:E}})}function m(e,n){if(B+=e,null==n)return b(),0;var t=o(n,E);if(t)return t.skip?B+=n:(t.eB&&(B+=n),b(),t.rB||t.eB||(B=n)),v(t,n),t.rB?0:n.length;var r=u(E,n);if(r){var a=E;a.skip?B+=n:(a.rE||a.eE||(B+=n),b(),a.eE&&(B=n));do E.cN&&(k+=C),E.skip||(M+=E.r),E=E.parent;while(E!==r.parent);return r.starts&&v(r.starts,""),a.rE?0:n.length}if(c(n,E))throw new Error('Illegal lexeme "'+n+'" for mode "'+(E.cN||"<unnamed>")+'"');return B+=n,n.length||1}var N=R(e);if(!N)throw new Error('Unknown language: "'+e+'"');s(N);var w,E=i||N,L={},k="";for(w=E;w!==N;w=w.parent)w.cN&&(k=h(w.cN,"",!0)+k);var B="",M=0;try{for(var I,j,O=0;;){if(E.t.lastIndex=O,I=E.t.exec(t),!I)break;j=m(t.substr(O,I.index-O),I[0]),O=I.index+j}for(m(t.substr(O)),w=E;w.parent;w=w.parent)w.cN&&(k+=C);return{r:M,value:k,language:e,top:E}}catch(T){if(T.message&&-1!==T.message.indexOf("Illegal"))return{r:0,value:n(t)};throw T}}function f(e,t){t=t||y.languages||E(x);var r={r:0,value:n(e)},a=r;return t.filter(R).forEach(function(n){var t=l(n,e,!1);t.language=n,t.r>a.r&&(a=t),t.r>r.r&&(a=r,r=t)}),a.language&&(r.second_best=a),r}function g(e){return y.tabReplace||y.useBR?e.replace(M,function(e,n){return y.useBR&&"\n"===e?"<br>":y.tabReplace?n.replace(/\t/g,y.tabReplace):void 0}):e}function h(e,n,t){var r=n?L[n]:t,a=[e.trim()];return e.match(/\bhljs\b/)||a.push("hljs"),-1===e.indexOf(r)&&a.push(r),a.join(" ").trim()}function p(e){var n,t,r,o,s,p=i(e);a(p)||(y.useBR?(n=document.createElementNS("http://www.w3.org/1999/xhtml","div"),n.innerHTML=e.innerHTML.replace(/\n/g,"").replace(/<br[ \/]*>/g,"\n")):n=e,s=n.textContent,r=p?l(p,s,!0):f(s),t=u(n),t.length&&(o=document.createElementNS("http://www.w3.org/1999/xhtml","div"),o.innerHTML=r.value,r.value=c(t,u(o),s)),r.value=g(r.value),e.innerHTML=r.value,e.className=h(e.className,p,r.language),e.result={language:r.language,re:r.r},r.second_best&&(e.second_best={language:r.second_best.language,re:r.second_best.r}))}function d(e){y=o(y,e)}function b(){if(!b.called){b.called=!0;var e=document.querySelectorAll("pre code");w.forEach.call(e,p)}}function v(){addEventListener("DOMContentLoaded",b,!1),addEventListener("load",b,!1)}function m(n,t){var r=x[n]=t(e);r.aliases&&r.aliases.forEach(function(e){L[e]=n})}function N(){return E(x)}function R(e){return e=(e||"").toLowerCase(),x[e]||x[L[e]]}var w=[],E=Object.keys,x={},L={},k=/^(no-?highlight|plain|text)$/i,B=/\blang(?:uage)?-([\w-]+)\b/i,M=/((^(<[^>]+>|\t|)+|(?:\n)))/gm,C="</span>",y={classPrefix:"hljs-",tabReplace:null,useBR:!1,languages:void 0},I={"&":"&amp;","<":"&lt;",">":"&gt;"};return e.highlight=l,e.highlightAuto=f,e.fixMarkup=g,e.highlightBlock=p,e.configure=d,e.initHighlighting=b,e.initHighlightingOnLoad=v,e.registerLanguage=m,e.listLanguages=N,e.getLanguage=R,e.inherit=o,e.IR="[a-zA-Z]\\w*",e.UIR="[a-zA-Z_]\\w*",e.NR="\\b\\d+(\\.\\d+)?",e.CNR="(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",e.BNR="\\b(0b[01]+)",e.RSR="!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~",e.BE={b:"\\\\[\\s\\S]",r:0},e.ASM={cN:"string",b:"'",e:"'",i:"\\n",c:[e.BE]},e.QSM={cN:"string",b:'"',e:'"',i:"\\n",c:[e.BE]},e.PWM={b:/\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|like)\b/},e.C=function(n,t,r){var a=e.inherit({cN:"comment",b:n,e:t,c:[]},r||{});return a.c.push(e.PWM),a.c.push({cN:"doctag",b:"(?:TODO|FIXME|NOTE|BUG|XXX):",r:0}),a},e.CLCM=e.C("//","$"),e.CBCM=e.C("/\\*","\\*/"),e.HCM=e.C("#","$"),e.NM={cN:"number",b:e.NR,r:0},e.CNM={cN:"number",b:e.CNR,r:0},e.BNM={cN:"number",b:e.BNR,r:0},e.CSSNM={cN:"number",b:e.NR+"(%|em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|in|pt|pc|px|deg|grad|rad|turn|s|ms|Hz|kHz|dpi|dpcm|dppx)?",r:0},e.RM={cN:"regexp",b:/\//,e:/\/[gimuy]*/,i:/\n/,c:[e.BE,{b:/\[/,e:/\]/,r:0,c:[e.BE]}]},e.TM={cN:"title",b:e.IR,r:0},e.UTM={cN:"title",b:e.UIR,r:0},e.METHOD_GUARD={b:"\\.\\s*"+e.UIR,r:0},e});hljs.registerLanguage("erlang",function(e){var r="[a-z'][a-zA-Z0-9_']*",c="("+r+":"+r+"|"+r+")",b={keyword:"after and andalso|10 band begin bnot bor bsl bzr bxor case catch cond div end fun if let not of orelse|10 query receive rem try when xor",literal:"false true"},i=e.C("%","$"),n={cN:"number",b:"\\b(\\d+#[a-fA-F0-9]+|\\d+(\\.\\d+)?([eE][-+]?\\d+)?)",r:0},a={b:"fun\\s+"+r+"/\\d+"},d={b:c+"\\(",e:"\\)",rB:!0,r:0,c:[{b:c,r:0},{b:"\\(",e:"\\)",eW:!0,rE:!0,r:0}]},o={b:"{",e:"}",r:0},t={b:"\\b_([A-Z][A-Za-z0-9_]*)?",r:0},f={b:"[A-Z][a-zA-Z0-9_]*",r:0},l={b:"#"+e.UIR,r:0,rB:!0,c:[{b:"#"+e.UIR,r:0},{b:"{",e:"}",r:0}]},s={bK:"fun receive if try case",e:"end",k:b};s.c=[i,a,e.inherit(e.ASM,{cN:""}),s,d,e.QSM,n,o,t,f,l];var u=[i,a,s,d,e.QSM,n,o,t,f,l];d.c[1].c=u,o.c=u,l.c[1].c=u;var h={cN:"params",b:"\\(",e:"\\)",c:u};return{aliases:["erl"],k:b,i:"(</|\\*=|\\+=|-=|/\\*|\\*/|\\(\\*|\\*\\))",c:[{cN:"function",b:"^"+r+"\\s*\\(",e:"->",rB:!0,i:"\\(|#|//|/\\*|\\\\|:|;",c:[h,e.inherit(e.TM,{b:r})],starts:{e:";|\\.",k:b,c:u}},i,{b:"^-",e:"\\.",r:0,eE:!0,rB:!0,l:"-"+e.IR,k:"-module -record -undef -export -ifdef -ifndef -author -copyright -doc -vsn -import -include -include_lib -compile -define -else -endif -file -behaviour -behavior -spec",c:[h]},n,e.QSM,l,t,f,o,{b:/\.$/}]}});hljs.registerLanguage("erlang-repl",function(e){return{k:{built_in:"spawn spawn_link self",keyword:"after and andalso|10 band begin bnot bor bsl bsr bxor case catch cond div end fun if let not of or orelse|10 query receive rem try when xor"},c:[{cN:"meta",b:"^[0-9]+> ",r:10},e.C("%","$"),{cN:"number",b:"\\b(\\d+#[a-fA-F0-9]+|\\d+(\\.\\d+)?([eE][-+]?\\d+)?)",r:0},e.ASM,e.QSM,{b:"\\?(::)?([A-Z]\\w*(::)?)+"},{b:"->"},{b:"ok"},{b:"!"},{b:"(\\b[a-z'][a-zA-Z0-9_']*:[a-z'][a-zA-Z0-9_']*)|(\\b[a-z'][a-zA-Z0-9_']*)",r:0},{b:"[A-Z][a-zA-Z0-9_']*",r:0}]}});hljs.registerLanguage("diff",function(e){return{aliases:["patch"],c:[{cN:"meta",r:10,v:[{b:/^@@ +\-\d+,\d+ +\+\d+,\d+ +@@$/},{b:/^\*\*\* +\d+,\d+ +\*\*\*\*$/},{b:/^\-\-\- +\d+,\d+ +\-\-\-\-$/}]},{cN:"comment",v:[{b:/Index: /,e:/$/},{b:/={3,}/,e:/$/},{b:/^\-{3}/,e:/$/},{b:/^\*{3} /,e:/$/},{b:/^\+{3}/,e:/$/},{b:/\*{5}/,e:/\*{5}$/}]},{cN:"addition",b:"^\\+",e:"$"},{cN:"deletion",b:"^\\-",e:"$"},{cN:"addition",b:"^\\!",e:"$"}]}});hljs.registerLanguage("bash",function(e){var t={cN:"variable",v:[{b:/\$[\w\d#@][\w\d_]*/},{b:/\$\{(.*?)}/}]},s={cN:"string",b:/"/,e:/"/,c:[e.BE,t,{cN:"variable",b:/\$\(/,e:/\)/,c:[e.BE]}]},a={cN:"string",b:/'/,e:/'/};return{aliases:["sh","zsh"],l:/-?[a-z\._]+/,k:{keyword:"if then else elif fi for while in do done case esac function",literal:"true false",built_in:"break cd continue eval exec exit export getopts hash pwd readonly return shift test times trap umask unset alias bind builtin caller command declare echo enable help let local logout mapfile printf read readarray source type typeset ulimit unalias set shopt autoload bg bindkey bye cap chdir clone comparguments compcall compctl compdescribe compfiles compgroups compquote comptags comptry compvalues dirs disable disown echotc echoti emulate fc fg float functions getcap getln history integer jobs kill limit log noglob popd print pushd pushln rehash sched setcap setopt stat suspend ttyctl unfunction unhash unlimit unsetopt vared wait whence where which zcompile zformat zftp zle zmodload zparseopts zprof zpty zregexparse zsocket zstyle ztcp",_:"-ne -eq -lt -gt -f -d -e -s -l -a"},c:[{cN:"meta",b:/^#![^\n]+sh\s*$/,r:10},{cN:"function",b:/\w[\w\d_]*\s*\(\s*\)\s*\{/,rB:!0,c:[e.inherit(e.TM,{b:/\w[\w\d_]*/})],r:0},e.HCM,s,a,t]}}); \ No newline at end of file
diff --git a/lib/erl_docgen/priv/xsl/db_html.xsl b/lib/erl_docgen/priv/xsl/db_html.xsl
index edab8e1c7e..6eafa2a165 100644
--- a/lib/erl_docgen/priv/xsl/db_html.xsl
+++ b/lib/erl_docgen/priv/xsl/db_html.xsl
@@ -66,6 +66,10 @@
Additionally, callbacks may be included, as in gen_server.xml:
<name>Module:handle_call(Request, From, State) -> Result</name>
+ For C reference pages the name tag has a substructure where the nametext tag
+ is used in the sort, as in erl_nif.xml
+ <name><ret>void *</ret><nametext>enif_alloc(size_t size)</nametext></name>
+
So first, get the name from either the attribute or the element value.
Then, reverse the case of the first character. This is because xsltproc, used for processing,
orders uppercase before lowercase (even when the 'case-order="lower-first"' option
@@ -82,12 +86,19 @@
<xsl:variable name="base">
<xsl:choose>
- <xsl:when test="string-length($elem/@name) > 0">
- <xsl:value-of select="$elem/@name"/>
- </xsl:when>
- <xsl:otherwise>
- <xsl:value-of select="$elem"/>
- </xsl:otherwise>
+ <xsl:when test="ancestor::cref">
+ <xsl:value-of select="$elem/nametext"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:choose>
+ <xsl:when test="string-length($elem/@name) > 0">
+ <xsl:value-of select="$elem/@name"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="$elem"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:otherwise>
</xsl:choose>
</xsl:variable>
@@ -200,13 +211,12 @@
<xsl:template match="head">
<xsl:param name="local_types"/>
<xsl:param name="global_types"/>
- <span class="bold_code">
+ <div class="bold_code func-head">
<xsl:apply-templates mode="local_type">
<xsl:with-param name="local_types" select="$local_types"/>
<xsl:with-param name="global_types" select="$global_types"/>
</xsl:apply-templates>
- </span>
- <br/>
+ </div>
</xsl:template>
<!-- The *last* <name name="..." arity=".."/> -->
@@ -234,7 +244,8 @@
<!-- It is assumed there is no support for overloaded specs
(there is no spec with more than one clause) -->
<xsl:if test="count($clause/guard) > 0 or count($type) > 0">
- <div class="REFBODY"><p>Types:</p>
+ <div class="REFBODY fun-types">
+ <h3 class="func-types-title">Types</h3>
<xsl:choose>
<xsl:when test="$output_subtypes">
@@ -327,13 +338,13 @@
<xsl:for-each select="$subtype">
<xsl:variable name="tname" select="typename"/>
- <div class="REFTYPES">
- <span class="bold_code">
- <xsl:apply-templates select="string" mode="local_type">
- <xsl:with-param name="local_types" select="$local_types"/>
- <xsl:with-param name="global_types" select="$global_types"/>
- </xsl:apply-templates>
- </span>
+ <div class="REFTYPES rt-1">
+ <span class="bold_code bc-2">
+ <xsl:apply-templates select="string" mode="local_type">
+ <xsl:with-param name="local_types" select="$local_types"/>
+ <xsl:with-param name="global_types" select="$global_types"/>
+ </xsl:apply-templates>
+ </span>
</div>
<xsl:apply-templates select="$type_desc[@variable = $tname]"/>
</xsl:for-each>
@@ -345,7 +356,7 @@
<xsl:param name="global_types"/>
<xsl:for-each select="$local_types">
- <div class="REFTYPES">
+ <div class="REFTYPES rt-2">
<xsl:call-template name="type_name">
<xsl:with-param name="mode" select="'local_type'"/>
<xsl:with-param name="local_types" select="$local_types"/>
@@ -366,7 +377,7 @@
<!-- Similar to <d> -->
<xsl:template match="type_desc">
- <div class="REFBODY">
+ <div class="REFBODY rb-1">
<xsl:apply-templates/>
</div>
</xsl:template>
@@ -375,7 +386,7 @@
<xsl:template match="all_etypes">
<xsl:for-each select= "$i//type">
<pre>
- <span class="bold_code">
+ <span class="bold_code bc-3">
<xsl:apply-templates select="typedecl"/>
</span><xsl:text>
</xsl:text>
@@ -386,15 +397,17 @@
<!-- Datatypes -->
<xsl:template match="datatypes">
<h3>
- <xsl:text>DATA TYPES</xsl:text>
+ <a name="data-types" href="#data-types"><xsl:text>Data Types</xsl:text></a>
</h3>
- <xsl:apply-templates/>
+ <div class="data-types-body">
+ <xsl:apply-templates/>
+ </div>
</xsl:template>
<!-- Datatype -->
<xsl:template match="datatype">
- <p><xsl:apply-templates select="name"/></p>
- <xsl:apply-templates select="desc"/>
+ <div class="data-type-name"><xsl:apply-templates select="name"/></div>
+ <div class="data-type-desc"><xsl:apply-templates select="desc"/></div>
</xsl:template>
<!-- The "mode" attribute of apply has been used to separate the case
@@ -454,7 +467,7 @@
</xsl:template>
<xsl:template match="typehead">
- <span class="bold_code">
+ <span class="bold_code bc-4">
<xsl:apply-templates/>
</span><br/>
</xsl:template>
@@ -462,7 +475,7 @@
<xsl:template match="typehead" mode="local_type">
<xsl:param name="local_types"/>
<xsl:param name="global_types"/>
- <span class="bold_code">
+ <span class="bold_code bc-5">
<xsl:apply-templates mode="local_type">
<xsl:with-param name="local_types" select="$local_types"/>
<xsl:with-param name="global_types" select="$global_types"/>
@@ -473,7 +486,7 @@
<!-- Not used right now -->
<!-- local_defs -->
<xsl:template match="local_defs">
- <div class="REFBODY">
+ <div class="REFBODY rb-2">
<xsl:apply-templates>
</xsl:apply-templates>
</div>
@@ -481,8 +494,8 @@
<!-- Not used right now -->
<xsl:template match="local_def">
- <div class="REFTYPES">
- <span class="bold_code">
+ <div class="REFTYPES rt-3">
+ <span class="bold_code bc-6">
<xsl:apply-templates/>
</span>
</div>
@@ -659,7 +672,7 @@
</xsl:otherwise>
</xsl:choose>
</head>
- <body bgcolor="white" text="#000000" link="#0000ff" vlink="#ff00ff" alink="#ff0000">
+ <body>
<div id="container">
<script id="js" type="text/javascript" language="JavaScript" src="{$topdocdir}/js/flipmenu/flipmenu.js"/>
@@ -734,6 +747,8 @@
</div>
</div>
+ <script type="text/javascript"><xsl:text>window.__otpTopDocDir = '</xsl:text><xsl:value-of select="$topdocdir"/><xsl:text>/js/';</xsl:text></script>
+ <script type="text/javascript" src="{$topdocdir}/js/highlight.js"/>
</body>
</html>
</xsl:template>
@@ -796,36 +811,42 @@
</xsl:template>
- <xsl:template name="menu_top">
+ <xsl:template name="erlang_logo">
<xsl:choose>
<xsl:when test="string-length($logo) > 0">
- <img alt="Erlang logo" src="{$topdocdir}/{$logo}"/>
+ <div class="erlang-logo-wrapper">
+ <a href="{$topdocdir}/index.html"><img alt="Erlang Logo" src="{$topdocdir}/{$logo}" class="erlang-logo"/></a>
+ </div>
</xsl:when>
<xsl:otherwise>
- <img alt="Erlang logo" src="{$topdocdir}/erlang-logo.png"/>
+ <div class="erlang-logo-wrapper">
+ <a href="{$topdocdir}/index.html"><img alt="Erlang Logo" src="{$topdocdir}/erlang-logo.png" class="erlang-logo"/></a>
+ </div>
</xsl:otherwise>
</xsl:choose>
- <br/>
- <small>
+ </xsl:template>
+
+ <xsl:template name="menu_top">
+ <ul class="panel-sections">
<xsl:if test="boolean(/book/parts/part)">
- <a href="users_guide.html">User's Guide</a><br/>
+ <li><a href="users_guide.html">User's Guide</a></li>
</xsl:if>
<xsl:if test="boolean(/book/applications)">
- <a href="index.html">Reference Manual</a><br/>
+ <li><a href="index.html">Reference Manual</a></li>
</xsl:if>
<xsl:if test="boolean(/book/releasenotes)">
- <a href="release_notes.html">Release Notes</a><br/>
+ <li><a href="release_notes.html">Release Notes</a></li>
</xsl:if>
<xsl:choose>
<xsl:when test="string-length($pdfname) > 0">
- <a href="{$pdfdir}/{$pdfname}.pdf">PDF</a><br/>
+ <li><a href="{$pdfdir}/{$pdfname}.pdf">PDF</a></li>
</xsl:when>
<xsl:otherwise>
- <a href="{$pdfdir}/{$appname}-{$appver}.pdf">PDF</a><br/>
+ <li><a href="{$pdfdir}/{$appname}-{$appver}.pdf">PDF</a></li>
</xsl:otherwise>
</xsl:choose>
- <a href="{$topdocdir}/index.html">Top</a>
- </small>
+ <li><a href="{$topdocdir}/index.html">Top</a></li>
+ </ul>
</xsl:template>
<xsl:template name="menu_middle">
@@ -841,10 +862,11 @@
</xsl:when>
</xsl:choose>
</small -->
- <br/>
- <a href="javascript:openAllFlips()">Expand All</a><br/>
- <a href="javascript:closeAllFlips()">Contract All</a>
+ <ul class="expand-collapse-items">
+ <li><a href="javascript:openAllFlips()">Expand All</a></li>
+ <li><a href="javascript:closeAllFlips()">Contract All</a></li>
+ </ul>
</xsl:template>
@@ -934,7 +956,7 @@
<xsl:value-of select="title"/>
</a>
</h3>
- <div class="REFBODY">
+ <div class="REFBODY rb-3">
<xsl:apply-templates>
<xsl:with-param name="chapnum" select="$chapnum"/>
</xsl:apply-templates>
@@ -948,7 +970,7 @@
<h4>
<xsl:value-of select="title"/>
</h4>
- <div class="REFBODY">
+ <div class="REFBODY rb-4">
<xsl:apply-templates>
<xsl:with-param name="chapnum" select="$chapnum"/>
</xsl:apply-templates>
@@ -1129,7 +1151,8 @@
<xsl:variable name="tabnum">
<xsl:number level="any" from="chapter" count="table"/>
</xsl:variable>
- <table border="1" cellpadding="2" cellspacing="0">
+ <div class="doc-table-wrapper">
+ <table class="doc-table">
<!-- tbody-->
<xsl:apply-templates select="row">
<xsl:with-param name="chapnum" select="$chapnum"/>
@@ -1141,6 +1164,7 @@
<xsl:with-param name="chapnum" select="$chapnum"/>
<xsl:with-param name="tabnum" select="$tabnum"/>
</xsl:apply-templates>
+ </div>
</xsl:template>
<xsl:template match="row">
@@ -1160,11 +1184,11 @@
<xsl:param name="chapnum"/>
<xsl:param name="tabnum"/>
- <em>Table
+ <p class="doc-table-caption">Table
<xsl:value-of select="$chapnum"/>.<xsl:value-of select="$tabnum"/>:
&#160;
<xsl:apply-templates/>
- </em>
+ </p>
</xsl:template>
@@ -1175,12 +1199,14 @@
<xsl:number level="any" from="chapter" count="image"/>
</xsl:variable>
- <img alt="IMAGE MISSING" src="{@file}"/><br/>
+ <div class="doc-image-wrapper">
+ <img alt="IMAGE MISSING" src="{@file}" class="doc-image"/>
<xsl:apply-templates>
<xsl:with-param name="chapnum" select="$chapnum"/>
<xsl:with-param name="fignum" select="$fignum"/>
</xsl:apply-templates>
+ </div>
</xsl:template>
@@ -1190,11 +1216,11 @@
<xsl:param name="chapnum"/>
<xsl:param name="fignum"/>
- <p><em>Figure
+ <p class="doc-image-caption">Figure
<xsl:value-of select="$chapnum"/>.<xsl:value-of select="$fignum"/>:
&#160;
<xsl:apply-templates/>
- </em></p>
+ </p>
</xsl:template>
@@ -1244,21 +1270,17 @@
<div id="leftnav">
<div class="innertube">
- <xsl:call-template name="menu_top"/>
+ <xsl:call-template name="erlang_logo"/>
- <p>
- <strong><xsl:value-of select="/book/header/title"/></strong><br/>
- <strong>User's Guide</strong><br/>
- <small>Version <xsl:value-of select="$appver"/></small>
- </p>
+ <p class="section-title"><xsl:value-of select="/book/header/title"/></p>
+ <p class="section-subtitle">User's Guide</p>
+ <p class="section-version">Version <xsl:value-of select="$appver"/></p>
+
+ <xsl:call-template name="menu_top"/>
<xsl:call-template name="menu_middle"/>
- <p>
- <small>
- <strong>Chapters</strong>
- </small>
- </p>
+ <h3>Chapters</h3>
<ul class="flipMenu" imagepath="{$topdocdir}/js/flipmenu">
<xsl:call-template name="menu.chapter">
@@ -1409,21 +1431,17 @@
<div id="leftnav">
<div class="innertube">
- <xsl:call-template name="menu_top"/>
+ <xsl:call-template name="erlang_logo"/>
- <p>
- <strong><xsl:value-of select="/book/header/title"/></strong><br/>
- <strong>Reference Manual</strong><br/>
- <small>Version <xsl:value-of select="$appver"/></small>
- </p>
+ <p class="section-title"><xsl:value-of select="/book/header/title"/></p>
+ <p class="section-subtitle">Reference Manual</p>
+ <p class="section-version">Version <xsl:value-of select="$appver"/></p>
+
+ <xsl:call-template name="menu_top"/>
<xsl:call-template name="menu_middle"/>
- <p>
- <small>
- <strong>Table of Contents</strong>
- </small>
- </p>
+ <h3>Table of Contents</h3>
<ul class="flipMenu">
<xsl:call-template name="menu.ref2">
@@ -1773,8 +1791,8 @@
<!-- Module -->
<xsl:template match="module">
<xsl:param name="partnum"/>
- <h3>MODULE</h3>
- <div class="REFBODY">
+ <h3><a name="module" href="#module">Module</a></h3>
+ <div class="REFBODY module-body">
<xsl:apply-templates>
<xsl:with-param name="partnum" select="$partnum"/>
</xsl:apply-templates>
@@ -1785,8 +1803,8 @@
<!-- Modulesummary -->
<xsl:template match="modulesummary">
<xsl:param name="partnum"/>
- <h3>MODULE SUMMARY</h3>
- <div class="REFBODY">
+ <h3><a name="module-sumary" href="#module-sumary">Module Summary</a></h3>
+ <div class="REFBODY module-summary-body">
<xsl:apply-templates>
<xsl:with-param name="partnum" select="$partnum"/>
</xsl:apply-templates>
@@ -1796,8 +1814,8 @@
<!-- Lib -->
<xsl:template match="lib">
<xsl:param name="partnum"/>
- <h3>C LIBRARY</h3>
- <div class="REFBODY">
+ <h3><a name="c-library" href="#c-library">C Library</a></h3>
+ <div class="REFBODY c-library-body">
<xsl:apply-templates>
<xsl:with-param name="partnum" select="$partnum"/>
</xsl:apply-templates>
@@ -1808,8 +1826,8 @@
<!-- Libsummary -->
<xsl:template match="libsummary">
<xsl:param name="partnum"/>
- <h3>LIBRARY SUMMARY</h3>
- <div class="REFBODY">
+ <h3><a name="library-sumary" href="#library-sumary">Library Summary</a></h3>
+ <div class="REFBODY library-summary-body">
<xsl:apply-templates>
<xsl:with-param name="partnum" select="$partnum"/>
</xsl:apply-templates>
@@ -1819,8 +1837,8 @@
<!-- Com -->
<xsl:template match="com">
<xsl:param name="partnum"/>
- <h3>COMMAND</h3>
- <div class="REFBODY">
+ <h3><a name="command" href="#command">Command</a></h3>
+ <div class="REFBODY command-body">
<xsl:apply-templates>
<xsl:with-param name="partnum" select="$partnum"/>
</xsl:apply-templates>
@@ -1831,8 +1849,8 @@
<!-- Comsummary -->
<xsl:template match="comsummary">
<xsl:param name="partnum"/>
- <h3>COMMAND SUMMARY</h3>
- <div class="REFBODY">
+ <h3><a name="command-summary" href="#command-summary">Command Summary</a></h3>
+ <div class="REFBODY command-summary-body">
<xsl:apply-templates>
<xsl:with-param name="partnum" select="$partnum"/>
</xsl:apply-templates>
@@ -1842,8 +1860,8 @@
<!-- File -->
<xsl:template match="file">
<xsl:param name="partnum"/>
- <h3>FILE</h3>
- <div class="REFBODY">
+ <h3><a name="file" href="#file">File</a></h3>
+ <div class="REFBODY file-body">
<xsl:apply-templates>
<xsl:with-param name="partnum" select="$partnum"/>
</xsl:apply-templates>
@@ -1854,8 +1872,8 @@
<!-- Filesummary -->
<xsl:template match="filesummary">
<xsl:param name="partnum"/>
- <h3>FILE SUMMARY</h3>
- <div class="REFBODY">
+ <h3><a name="file-summary" href="#file-summary">File Summary</a></h3>
+ <div class="REFBODY file-summary-body">
<xsl:apply-templates>
<xsl:with-param name="partnum" select="$partnum"/>
</xsl:apply-templates>
@@ -1866,8 +1884,8 @@
<!-- App -->
<xsl:template match="app">
<xsl:param name="partnum"/>
- <h3>APPLICATION</h3>
- <div class="REFBODY">
+ <h3><a name="application" href="#application">Application</a></h3>
+ <div class="REFBODY application-body">
<xsl:apply-templates>
<xsl:with-param name="partnum" select="$partnum"/>
</xsl:apply-templates>
@@ -1878,8 +1896,8 @@
<!-- Appsummary -->
<xsl:template match="appsummary">
<xsl:param name="partnum"/>
- <h3>APPLICATION SUMMARY</h3>
- <div class="REFBODY">
+ <h3><a name="application-summary" href="#application-summary">Application Summary</a></h3>
+ <div class="REFBODY application-summary-body">
<xsl:apply-templates>
<xsl:with-param name="partnum" select="$partnum"/>
</xsl:apply-templates>
@@ -1889,8 +1907,8 @@
<!-- Description -->
<xsl:template match="description">
<xsl:param name="partnum"/>
- <h3>DESCRIPTION</h3>
- <div class="REFBODY">
+ <h3><a name="description" href="#description">Description</a></h3>
+ <div class="REFBODY description-body">
<p>
<xsl:apply-templates>
<xsl:with-param name="partnum" select="$partnum"/>
@@ -1903,13 +1921,13 @@
<xsl:template match="funcs">
<xsl:param name="partnum"/>
- <h3>
- <xsl:text>EXPORTS</xsl:text>
- </h3>
+ <h3><a name="exports" href="#exports"><xsl:text>Exports</xsl:text></a></h3>
- <xsl:apply-templates>
- <xsl:with-param name="partnum" select="$partnum"/>
- </xsl:apply-templates>
+ <div class="exports-body">
+ <xsl:apply-templates>
+ <xsl:with-param name="partnum" select="$partnum"/>
+ </xsl:apply-templates>
+ </div>
</xsl:template>
@@ -1980,7 +1998,7 @@
<xsl:choose>
<xsl:when test="ancestor::cref">
<a name="{substring-before(nametext, '(')}">
- <span class="bold_code">
+ <span class="bold_code bc-7">
<xsl:value-of select="ret"/>
<xsl:call-template name="maybe-space-after-ret">
<xsl:with-param name="s" select="ret"/>
@@ -2007,15 +2025,15 @@
</xsl:variable>
<xsl:choose>
<xsl:when test="ancestor::datatype">
- <a name="type-{$fname}"></a><span class="bold_code"><xsl:apply-templates/></span><br/>
+ <a name="type-{$fname}"></a><span class="bold_code bc-8"><xsl:apply-templates/></span><br/>
</xsl:when>
<xsl:otherwise>
- <a name="{$fname}-{$arity}"></a><span class="bold_code"><xsl:apply-templates/></span><br/>
+ <a name="{$fname}-{$arity}"></a><span class="bold_code fun-type"><xsl:apply-templates/></span><br/>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:otherwise>
- <span class="bold_code"><xsl:value-of select="."/></span>
+ <span class="bold_code bc-10"><xsl:value-of select="."/></span>
</xsl:otherwise>
</xsl:choose>
@@ -2040,12 +2058,13 @@
<!-- The case where @name != 0 is taken care of in "type_name" -->
<xsl:if test="string-length(@name) = 0 and string-length(@variable) = 0">
- <div class="REFBODY"><p>Types:</p>
+ <div class="REFBODY rb-5">
+ <h3 class="func-types-title">Types</h3>
- <xsl:apply-templates>
- <xsl:with-param name="partnum" select="$partnum"/>
- </xsl:apply-templates>
- </div>
+ <xsl:apply-templates>
+ <xsl:with-param name="partnum" select="$partnum"/>
+ </xsl:apply-templates>
+ </div>
</xsl:if>
@@ -2055,8 +2074,8 @@
<!-- V -->
<xsl:template match="v">
<xsl:param name="partnum"/>
- <div class="REFTYPES">
- <span class="bold_code">
+ <div class="REFTYPES rt-4">
+ <span class="bold_code fun-param-type">
<xsl:apply-templates>
<xsl:with-param name="partnum" select="$partnum"/>
</xsl:apply-templates>
@@ -2067,7 +2086,7 @@
<!-- D -->
<xsl:template match="d">
<xsl:param name="partnum"/>
- <div class="REFBODY">
+ <div class="REFBODY rb-6">
<xsl:apply-templates>
<xsl:with-param name="partnum" select="$partnum"/>
</xsl:apply-templates>
@@ -2077,7 +2096,7 @@
<!-- Desc -->
<xsl:template match="desc">
<xsl:param name="partnum"/>
- <div class="REFBODY">
+ <div class="REFBODY rb-7">
<p>
<xsl:apply-templates>
<xsl:with-param name="partnum" select="$partnum"/>
@@ -2094,7 +2113,7 @@
<xsl:template match="input">
- <span class="bold_code"><xsl:apply-templates/></span>
+ <span class="bold_code bc-12"><xsl:apply-templates/></span>
</xsl:template>
<xsl:template match="seealso">
@@ -2113,7 +2132,7 @@
<xsl:when test="string-length($app_part) > 0">
<!-- "AppPart:ModPart#Linkpart" -->
<xsl:variable name="mod_part"><xsl:value-of select="substring-after($filepart, ':')"/></xsl:variable>
- <span class="bold_code"><a href="javascript:erlhref('{$topdocdir}/../','{$app_part}','{$mod_part}.html#{$linkpart}');"><xsl:apply-templates/></a></span>
+ <span class="bold_code bc-13"><a href="javascript:erlhref('{$topdocdir}/../','{$app_part}','{$mod_part}.html#{$linkpart}');"><xsl:apply-templates/></a></span>
</xsl:when>
<xsl:otherwise>
<!-- "Filepart#Linkpart (there is no ':' in Filepart) -->
@@ -2133,7 +2152,7 @@
<xsl:variable name="app" select="key('mod2app', $filepart)"/>
<xsl:choose>
<xsl:when test="string-length($app) > 0">
- <span class="bold_code"><a href="javascript:erlhref('{$topdocdir}/../','{$app}','{$filepart}.html#{$linkpart}');"><xsl:value-of select="$this"/></a></span>
+ <span class="bold_code bc-14"><a href="javascript:erlhref('{$topdocdir}/../','{$app}','{$filepart}.html#{$linkpart}');"><xsl:value-of select="$this"/></a></span>
</xsl:when>
<xsl:otherwise>
<!-- Unknown application -->
@@ -2146,11 +2165,11 @@
</xsl:when>
<xsl:when test="string-length($linkpart) > 0">
<!-- Still Filepart#Linkpart (there is no ':' in Filepart -->
- <span class="bold_code"><a href="{$filepart}.html#{$linkpart}"><xsl:apply-templates/></a></span>
+ <span class="bold_code bc-15"><a href="{$filepart}.html#{$linkpart}"><xsl:apply-templates/></a></span>
</xsl:when>
<xsl:otherwise>
<!-- "Filepart#" (there is no ':' in Filepart -->
- <span class="bold_code"><a href="{$filepart}.html"><xsl:apply-templates/></a></span>
+ <span class="bold_code bc-16"><a href="{$filepart}.html"><xsl:apply-templates/></a></span>
</xsl:otherwise>
</xsl:choose>
</xsl:otherwise>
@@ -2158,7 +2177,7 @@
</xsl:when> <!-- string-length($filepart) > 0 -->
<xsl:when test="string-length($linkpart) > 0">
<!-- "#Linkpart" -->
- <span class="bold_code"><a href="#{$linkpart}"><xsl:apply-templates/></a></span>
+ <span class="bold_code bc-17"><a href="#{$linkpart}"><xsl:apply-templates/></a></span>
</xsl:when>
<xsl:otherwise>
<!-- "AppPart:Mod" or "Mod" (there is no '#') -->
@@ -2168,11 +2187,11 @@
<xsl:when test="string-length($app_part) > 0">
<!-- "App:Mod" -->
<xsl:variable name="mod_part"><xsl:value-of select="substring-after(@marker, ':')"/></xsl:variable>
- <span class="bold_code"><a href="javascript:erlhref('{$topdocdir}/../','{$app_part}','{$mod_part}.html');"><xsl:apply-templates/></a></span>
+ <span class="bold_code bc-18"><a href="javascript:erlhref('{$topdocdir}/../','{$app_part}','{$mod_part}.html');"><xsl:apply-templates/></a></span>
</xsl:when>
<xsl:otherwise>
<!-- "Mod" -->
- <span class="bold_code"><a href="{@marker}.html"><xsl:apply-templates/></a></span>
+ <span class="bold_code bc-19"><a href="{@marker}.html"><xsl:apply-templates/></a></span>
</xsl:otherwise>
</xsl:choose>
</xsl:otherwise>
@@ -2181,7 +2200,7 @@
</xsl:template>
<xsl:template match="url">
- <span class="bold_code"><a href="{@href}"><xsl:apply-templates/></a></span>
+ <span class="bold_code bc-20"><a href="{@href}"><xsl:apply-templates/></a></span>
</xsl:template>
<xsl:template match="marker">
@@ -2256,21 +2275,17 @@
<div id="leftnav">
<div class="innertube">
- <xsl:call-template name="menu_top"/>
+ <xsl:call-template name="erlang_logo"/>
- <p>
- <strong><xsl:value-of select="/book/header/title"/></strong><br/>
- <strong>Release Notes</strong><br/>
- <small>Version <xsl:value-of select="$appver"/></small>
- </p>
+ <p class="section-title"><xsl:value-of select="/book/header/title"/></p>
+ <p class="section-subtitle">Release Notes</p>
+ <p class="section-version">Version <xsl:value-of select="$appver"/></p>
+
+ <xsl:call-template name="menu_top"/>
<xsl:call-template name="menu_middle"/>
- <p>
- <small>
- <strong>Chapters</strong>
- </small>
- </p>
+ <h3>Chapters</h3>
<ul class="flipMenu" imagepath="{$topdocdir}/js/flipmenu">
<xsl:call-template name="menu.chapter">
diff --git a/lib/erl_docgen/vsn.mk b/lib/erl_docgen/vsn.mk
index d6106a2823..8fad061b26 100644
--- a/lib/erl_docgen/vsn.mk
+++ b/lib/erl_docgen/vsn.mk
@@ -1 +1 @@
-ERL_DOCGEN_VSN = 0.6.1
+ERL_DOCGEN_VSN = 0.7
diff --git a/lib/hipe/cerl/erl_bif_types.erl b/lib/hipe/cerl/erl_bif_types.erl
index 9321750d44..a3a936322a 100644
--- a/lib/hipe/cerl/erl_bif_types.erl
+++ b/lib/hipe/cerl/erl_bif_types.erl
@@ -1080,9 +1080,6 @@ type(hipe_bifs, ref_get, 1, Xs, Opaques) ->
strict(hipe_bifs, ref_get, 1, Xs, fun (_) -> t_immediate() end, Opaques);
type(hipe_bifs, ref_set, 2, Xs, Opaques) ->
strict(hipe_bifs, ref_set, 2, Xs, fun (_) -> t_nil() end, Opaques);
-type(hipe_bifs, remove_refs_from, 1, Xs, Opaques) ->
- strict(hipe_bifs, remove_refs_from, 1, Xs,
- fun (_) -> t_atom('ok') end, Opaques);
type(hipe_bifs, set_funinfo_native_address, 3, Xs, Opaques) ->
strict(hipe_bifs, set_funinfo_native_address, 3, Xs,
fun (_) -> t_nil() end, Opaques);
@@ -2518,8 +2515,6 @@ arg_types(hipe_bifs, ref_get, 1) ->
[t_hiperef()];
arg_types(hipe_bifs, ref_set, 2) ->
[t_hiperef(), t_immediate()];
-arg_types(hipe_bifs, remove_refs_from, 1) ->
- [t_sup([t_mfa(), t_atom('all')])];
arg_types(hipe_bifs, set_funinfo_native_address, 3) ->
arg_types(hipe_bifs, set_native_address, 3);
arg_types(hipe_bifs, commit_patch_load, 1) ->
diff --git a/lib/hipe/rtl/Makefile b/lib/hipe/rtl/Makefile
index b4cdf8b1f2..357f1f6950 100644
--- a/lib/hipe/rtl/Makefile
+++ b/lib/hipe/rtl/Makefile
@@ -118,10 +118,12 @@ else
TYPE_STR=
endif
-ifeq ($(FLAVOR),smp)
-FLAVOR_STR=.smp
-else
+FLAVOR=$(DEFAULT_FLAVOR)
+
+ifeq ($(FLAVOR),plain)
FLAVOR_STR=
+else
+FLAVOR_STR=.smp
endif
ifeq ($(XCOMP),yes)
diff --git a/lib/kernel/test/file_name_SUITE.erl b/lib/kernel/test/file_name_SUITE.erl
index 10b6b105d0..b2051af050 100644
--- a/lib/kernel/test/file_name_SUITE.erl
+++ b/lib/kernel/test/file_name_SUITE.erl
@@ -383,7 +383,7 @@ check_icky(Mod) ->
ok
end,
- _ = make_icky_dir(Mod, treat_icky(<<"åäö_dir">>)),
+ _ = make_icky_dir(Mod, treat_icky(<<"åäö_dir"/utf8>>)),
if
UniMode and (OS =/= win32) ->
{error,enoent} = Mod:set_cwd("åäö_dir");
diff --git a/lib/observer/src/observer_port_wx.erl b/lib/observer/src/observer_port_wx.erl
index db5e6ceb38..1b83ea3fc5 100644
--- a/lib/observer/src/observer_port_wx.erl
+++ b/lib/observer/src/observer_port_wx.erl
@@ -69,7 +69,7 @@
parent,
grid,
panel,
- node=node(),
+ node={node(),true},
opt=#opt{},
right_clicked_port,
ports,
@@ -270,19 +270,39 @@ handle_cast(Event, _State) ->
error({unhandled_cast, Event}).
handle_info({portinfo_open, PortIdStr},
- State = #state{node=Node, grid=Grid, opt=Opt, open_wins=Opened}) ->
- Ports0 = get_ports(Node),
- Ports = update_grid(Grid, sel(State), Opt, Ports0),
- Port = lists:keyfind(PortIdStr, #port.id_str, Ports),
- NewOpened =
- case Port of
- false ->
- self() ! {error,"No such port: " ++ PortIdStr},
- Opened;
+ State = #state{node={ActiveNodeName,ActiveAvailable}, grid=Grid,
+ opt=Opt, open_wins=Opened}) ->
+ NodeName = node(list_to_port(PortIdStr)),
+ Available =
+ case NodeName of
+ ActiveNodeName ->
+ ActiveAvailable;
_ ->
- display_port_info(Grid, Port, Opened)
+ portinfo_available(NodeName)
end,
- {noreply, State#state{ports=Ports, open_wins=NewOpened}};
+ if Available ->
+ Ports0 = get_ports({NodeName,Available}),
+ Port = lists:keyfind(PortIdStr, #port.id_str, Ports0),
+ NewOpened =
+ case Port of
+ false ->
+ self() ! {error,"No such port: " ++ PortIdStr},
+ Opened;
+ _ ->
+ display_port_info(Grid, Port, Opened)
+ end,
+ Ports =
+ case NodeName of
+ ActiveNodeName ->
+ update_grid(Grid, sel(State), Opt, Ports0);
+ _ ->
+ State#state.ports
+ end,
+ {noreply, State#state{ports=Ports, open_wins=NewOpened}};
+ true ->
+ popup_unavailable_info(NodeName),
+ {noreply, State}
+ end;
handle_info(refresh_interval, State = #state{node=Node, grid=Grid, opt=Opt,
ports=OldPorts}) ->
@@ -295,19 +315,28 @@ handle_info(refresh_interval, State = #state{node=Node, grid=Grid, opt=Opt,
{noreply, State#state{ports=Ports}}
end;
-handle_info({active, Node}, State = #state{parent=Parent, grid=Grid, opt=Opt,
- timer=Timer0}) ->
- Ports0 = get_ports(Node),
+handle_info({active, NodeName}, State = #state{parent=Parent, grid=Grid, opt=Opt,
+ timer=Timer0}) ->
+ Available = portinfo_available(NodeName),
+ Available orelse popup_unavailable_info(NodeName),
+ Ports0 = get_ports({NodeName,Available}),
Ports = update_grid(Grid, sel(State), Opt, Ports0),
wxWindow:setFocus(Grid),
create_menus(Parent),
Timer = observer_lib:start_timer(Timer0, 10),
- {noreply, State#state{node=Node, ports=Ports, timer=Timer}};
+ {noreply, State#state{node={NodeName,Available}, ports=Ports, timer=Timer}};
handle_info(not_active, State = #state{timer = Timer0}) ->
Timer = observer_lib:stop_timer(Timer0),
{noreply, State#state{timer=Timer}};
+handle_info({info, {port_info_not_available,NodeName}},
+ State = #state{panel=Panel}) ->
+ Str = io_lib:format("Can not fetch port info from ~p.~n"
+ "Too old OTP version.",[NodeName]),
+ observer_lib:display_info_dialog(Panel, Str),
+ {noreply, State};
+
handle_info({error, Error}, #state{panel=Panel} = State) ->
Str = io_lib:format("ERROR: ~s~n",[Error]),
observer_lib:display_info_dialog(Panel, Str),
@@ -341,16 +370,18 @@ create_menus(Parent) ->
],
observer_wx:create_menus(Parent, MenuEntries).
-get_ports(Node) ->
- case get_ports2(Node) of
+get_ports({_NodeName,false}) ->
+ [];
+get_ports({NodeName,true}) ->
+ case get_ports2(NodeName) of
Error = {error, _} ->
self() ! Error,
[];
Res ->
Res
end.
-get_ports2(Node) ->
- case rpc:call(Node, observer_backend, get_port_list, []) of
+get_ports2(NodeName) ->
+ case rpc:call(NodeName, observer_backend, get_port_list, []) of
{badrpc, Error} ->
{error, Error};
Error = {error, _} ->
@@ -574,3 +605,15 @@ get_indecies(Rest = [_|_], I, [_|T]) ->
get_indecies(Rest, I+1, T);
get_indecies(_, _, _) ->
[].
+
+portinfo_available(NodeName) ->
+ _ = rpc:call(NodeName, code, ensure_loaded, [observer_backend]),
+ case rpc:call(NodeName, erlang, function_exported,
+ [observer_backend, get_port_list, 0]) of
+ true -> true;
+ false -> false
+ end.
+
+popup_unavailable_info(NodeName) ->
+ self() ! {info, {port_info_not_available, NodeName}},
+ ok.
diff --git a/lib/reltool/src/reltool.hrl b/lib/reltool/src/reltool.hrl
index c61c3a0c71..3b1e868757 100644
--- a/lib/reltool/src/reltool.hrl
+++ b/lib/reltool/src/reltool.hrl
@@ -289,8 +289,8 @@
"^lib",
"^releases"]).
-define(EMBEDDED_EXCL_SYS_FILTERS,
- ["^bin/(erlc|dialyzer)(|\\.exe)\$",
- "^erts.*/bin/(erlc|dialyzer)(|\\.exe)\$",
+ ["^bin/(erlc|dialyzer|typer)(|\\.exe)\$",
+ "^erts.*/bin/(erlc|dialyzer|typer)(|\\.exe)\$",
"^erts.*/bin/.*(debug|pdb)"]).
-define(EMBEDDED_INCL_APP_FILTERS, ["^ebin",
"^include",
@@ -303,7 +303,7 @@
"^erts.*/bin",
"^lib\$"]).
-define(STANDALONE_EXCL_SYS_FILTERS,
- ["^erts.*/bin/(erlc|dialyzer)(|\\.exe)\$",
+ ["^erts.*/bin/(erlc|dialyzer|typer)(|\\.exe)\$",
"^erts.*/bin/(start|escript|to_erl|run_erl)(|\\.exe)\$",
"^erts.*/bin/.*(debug|pdb)"]).
-define(STANDALONE_INCL_APP_FILTERS, ["^ebin",
diff --git a/lib/ssl/src/dtls_connection.erl b/lib/ssl/src/dtls_connection.erl
index 440607e99d..14d802085f 100644
--- a/lib/ssl/src/dtls_connection.erl
+++ b/lib/ssl/src/dtls_connection.erl
@@ -250,7 +250,7 @@ init({call, From}, {start, Timeout},
Cache, CacheCb, Renegotiation, Cert),
Version = Hello#client_hello.client_version,
- HelloVersion = dtls_record:lowest_protocol_version(SslOpts#ssl_options.versions),
+ HelloVersion = dtls_record:hello_version(Version, SslOpts#ssl_options.versions),
State1 = prepare_flight(State0#state{negotiated_version = Version}),
{State2, Actions} = send_handshake(Hello, State1#state{negotiated_version = HelloVersion}),
State3 = State2#state{negotiated_version = Version, %% Requested version
diff --git a/lib/ssl/src/dtls_handshake.erl b/lib/ssl/src/dtls_handshake.erl
index d3ba90a226..5fb1b61489 100644
--- a/lib/ssl/src/dtls_handshake.erl
+++ b/lib/ssl/src/dtls_handshake.erl
@@ -66,7 +66,7 @@ client_hello(Host, Port, Cookie, ConnectionStates,
CipherSuites = ssl_handshake:available_suites(UserSuites, TLSVersion),
Extensions = ssl_handshake:client_hello_extensions(Host, TLSVersion, CipherSuites,
- SslOpts, ConnectionStates, Renegotiation),
+ SslOpts, ConnectionStates, Renegotiation),
Id = ssl_session:client_id({Host, Port, SslOpts}, Cache, CacheCb, OwnCert),
@@ -252,7 +252,7 @@ enc_handshake(#server_hello{} = HandshakeMsg, Version) ->
{Type, <<?BYTE(DTLSMajor), ?BYTE(DTLSMinor), Rest/binary>>};
enc_handshake(HandshakeMsg, Version) ->
- ssl_handshake:encode_handshake(HandshakeMsg, Version).
+ ssl_handshake:encode_handshake(HandshakeMsg, dtls_v1:corresponding_tls_version(Version)).
bin_fragments(Bin, Size) ->
bin_fragments(Bin, size(Bin), Size, 0, []).
diff --git a/lib/ssl/src/dtls_record.erl b/lib/ssl/src/dtls_record.erl
index 049f83e49e..bc2097c021 100644
--- a/lib/ssl/src/dtls_record.erl
+++ b/lib/ssl/src/dtls_record.erl
@@ -44,7 +44,7 @@
-export([protocol_version/1, lowest_protocol_version/1, lowest_protocol_version/2,
highest_protocol_version/1, highest_protocol_version/2,
is_higher/2, supported_protocol_versions/0,
- is_acceptable_version/2]).
+ is_acceptable_version/2, hello_version/2]).
-export([save_current_connection_state/2, next_epoch/2]).
@@ -402,6 +402,15 @@ current_connection_state_epoch(#{current_write := #{epoch := Epoch}},
write) ->
Epoch.
+-spec hello_version(dtls_version(), [dtls_version()]) -> dtls_version().
+hello_version(Version, Versions) ->
+ case dtls_v1:corresponding_tls_version(Version) of
+ TLSVersion when TLSVersion >= {3, 3} ->
+ Version;
+ _ ->
+ lowest_protocol_version(Versions)
+ end.
+
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
@@ -525,8 +534,7 @@ calc_mac_hash(Type, Version, #{mac_secret := MacSecret,
security_parameters := #security_parameters{mac_algorithm = MacAlg}},
Epoch, SeqNo, Fragment) ->
Length = erlang:iolist_size(Fragment),
- NewSeq = (Epoch bsl 48) + SeqNo,
- mac_hash(Version, MacAlg, MacSecret, NewSeq, Type,
+ mac_hash(Version, MacAlg, MacSecret, Epoch, SeqNo, Type,
Length, Fragment).
highest_protocol_version() ->
@@ -539,9 +547,11 @@ sufficient_dtlsv1_2_crypto_support() ->
CryptoSupport = crypto:supports(),
proplists:get_bool(sha256, proplists:get_value(hashs, CryptoSupport)).
-mac_hash(Version, MacAlg, MacSecret, SeqNo, Type, Length, Fragment) ->
- dtls_v1:mac_hash(Version, MacAlg, MacSecret, SeqNo, Type,
- Length, Fragment).
-
+mac_hash({Major, Minor}, MacAlg, MacSecret, Epoch, SeqNo, Type, Length, Fragment) ->
+ Value = [<<?UINT16(Epoch), ?UINT48(SeqNo), ?BYTE(Type),
+ ?BYTE(Major), ?BYTE(Minor), ?UINT16(Length)>>,
+ Fragment],
+ dtls_v1:hmac_hash(MacAlg, MacSecret, Value).
+
calc_aad(Type, {MajVer, MinVer}, Epoch, SeqNo) ->
<<?UINT16(Epoch), ?UINT48(SeqNo), ?BYTE(Type), ?BYTE(MajVer), ?BYTE(MinVer)>>.
diff --git a/lib/ssl/src/dtls_v1.erl b/lib/ssl/src/dtls_v1.erl
index 4aaf8baa6c..7f7223cde7 100644
--- a/lib/ssl/src/dtls_v1.erl
+++ b/lib/ssl/src/dtls_v1.erl
@@ -21,7 +21,7 @@
-include("ssl_cipher.hrl").
--export([suites/1, all_suites/1, mac_hash/7, ecc_curves/1,
+-export([suites/1, all_suites/1, hmac_hash/3, ecc_curves/1,
corresponding_tls_version/1, corresponding_dtls_version/1,
cookie_secret/0, cookie_timeout/0]).
@@ -40,9 +40,8 @@ all_suites(Version) ->
end,
ssl_cipher:all_suites(corresponding_tls_version(Version))).
-mac_hash(Version, MacAlg, MacSecret, SeqNo, Type, Length, Fragment) ->
- tls_v1:mac_hash(MacAlg, MacSecret, SeqNo, Type, Version,
- Length, Fragment).
+hmac_hash(MacAlg, MacSecret, Value) ->
+ tls_v1:hmac_hash(MacAlg, MacSecret, Value).
ecc_curves({_Major, Minor}) ->
tls_v1:ecc_curves(corresponding_minor_tls_version(Minor)).
diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl
index b3d08bdfbe..de5ca3dddd 100644
--- a/lib/ssl/src/ssl.erl
+++ b/lib/ssl/src/ssl.erl
@@ -1031,15 +1031,15 @@ validate_option(protocol, Value = dtls) ->
validate_option(Opt, Value) ->
throw({error, {options, {Opt, Value}}}).
-handle_hashsigns_option(Value, {Major, Minor} = Version) when is_list(Value)
- andalso Major >= 3 andalso Minor >= 3->
+handle_hashsigns_option(Value, Version) when is_list(Value)
+ andalso Version >= {3, 3} ->
case tls_v1:signature_algs(Version, Value) of
[] ->
throw({error, {options, no_supported_algorithms, {signature_algs, Value}}});
_ ->
Value
end;
-handle_hashsigns_option(_, {Major, Minor} = Version) when Major >= 3 andalso Minor >= 3->
+handle_hashsigns_option(_, Version) when Version >= {3, 3} ->
handle_hashsigns_option(tls_v1:default_signature_algs(Version), Version);
handle_hashsigns_option(_, _Version) ->
undefined.
diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl
index df9b9e8a63..cc77aa6bf4 100644
--- a/lib/ssl/src/ssl_connection.erl
+++ b/lib/ssl/src/ssl_connection.erl
@@ -1689,7 +1689,7 @@ request_client_cert(#state{ssl_options = #ssl_options{verify = verify_peer,
ssl_record:pending_connection_state(ConnectionStates0, read),
TLSVersion = ssl:tls_version(Version),
HashSigns = ssl_handshake:available_signature_algs(SupportedHashSigns,
- TLSVersion, [TLSVersion]),
+ TLSVersion),
Msg = ssl_handshake:certificate_request(CipherSuite, CertDbHandle, CertDbRef,
HashSigns, TLSVersion),
State = Connection:queue_handshake(Msg, State0),
diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl
index cb61c82334..954b0875ce 100644
--- a/lib/ssl/src/ssl_handshake.erl
+++ b/lib/ssl/src/ssl_handshake.erl
@@ -64,7 +64,7 @@
]).
%% Cipher suites handling
--export([available_suites/2, available_signature_algs/3, cipher_suites/2,
+-export([available_suites/2, available_signature_algs/2, cipher_suites/2,
select_session/11, supported_ecc/1, available_signature_algs/4]).
%% Extensions handling
@@ -121,8 +121,7 @@ server_hello_done() ->
client_hello_extensions(Host, Version, CipherSuites,
#ssl_options{signature_algs = SupportedHashSigns,
- eccs = SupportedECCs,
- versions = AllVersions} = SslOpts, ConnectionStates, Renegotiation) ->
+ eccs = SupportedECCs} = SslOpts, ConnectionStates, Renegotiation) ->
{EcPointFormats, EllipticCurves} =
case advertises_ec_ciphers(lists:map(fun ssl_cipher:suite_definition/1, CipherSuites)) of
true ->
@@ -136,7 +135,7 @@ client_hello_extensions(Host, Version, CipherSuites,
renegotiation_info = renegotiation_info(tls_record, client,
ConnectionStates, Renegotiation),
srp = SRP,
- signature_algs = available_signature_algs(SupportedHashSigns, Version, AllVersions),
+ signature_algs = available_signature_algs(SupportedHashSigns, Version),
ec_point_formats = EcPointFormats,
elliptic_curves = EllipticCurves,
alpn = encode_alpn(SslOpts#ssl_options.alpn_advertised_protocols, Renegotiation),
@@ -2150,16 +2149,11 @@ is_member(Suite, SupportedSuites) ->
select_compression(_CompressionMetodes) ->
?NULL.
-available_signature_algs(undefined, _, _) ->
+available_signature_algs(undefined, _) ->
undefined;
-available_signature_algs(SupportedHashSigns, {Major, Minor}, AllVersions) when Major >= 3 andalso Minor >= 3 ->
- case tls_record:lowest_protocol_version(AllVersions) of
- {3, 3} ->
- #hash_sign_algos{hash_sign_algos = SupportedHashSigns};
- _ ->
- undefined
- end;
-available_signature_algs(_, _, _) ->
+available_signature_algs(SupportedHashSigns, Version) when Version >= {3, 3} ->
+ #hash_sign_algos{hash_sign_algos = SupportedHashSigns};
+available_signature_algs(_, _) ->
undefined.
psk_secret(PSKIdentity, PSKLookup) ->
@@ -2346,11 +2340,11 @@ bad_key(#'RSAPrivateKey'{}) ->
bad_key(#'ECPrivateKey'{}) ->
unacceptable_ecdsa_key.
-available_signature_algs(undefined, SupportedHashSigns, _, {Major, Minor}) when
- (Major >= 3) andalso (Minor >= 3) ->
+available_signature_algs(undefined, SupportedHashSigns, _, Version) when
+ Version >= {3,3} ->
SupportedHashSigns;
available_signature_algs(#hash_sign_algos{hash_sign_algos = ClientHashSigns}, SupportedHashSigns,
- _, {Major, Minor}) when (Major >= 3) andalso (Minor >= 3) ->
+ _, Version) when Version >= {3,3} ->
sets:to_list(sets:intersection(sets:from_list(ClientHashSigns),
sets:from_list(SupportedHashSigns)));
available_signature_algs(_, _, _, _) ->
diff --git a/lib/ssl/src/tls_connection.erl b/lib/ssl/src/tls_connection.erl
index bda6bf0349..ce440d1e71 100644
--- a/lib/ssl/src/tls_connection.erl
+++ b/lib/ssl/src/tls_connection.erl
@@ -220,7 +220,7 @@ init({call, From}, {start, Timeout},
Cache, CacheCb, Renegotiation, Cert),
Version = Hello#client_hello.client_version,
- HelloVersion = tls_record:lowest_protocol_version(SslOpts#ssl_options.versions),
+ HelloVersion = tls_record:hello_version(Version, SslOpts#ssl_options.versions),
Handshake0 = ssl_handshake:init_handshake_history(),
{BinMsg, ConnectionStates, Handshake} =
encode_handshake(Hello, HelloVersion, ConnectionStates0, Handshake0, V2HComp),
diff --git a/lib/ssl/src/tls_record.erl b/lib/ssl/src/tls_record.erl
index 065c6dc8a7..2d6407677f 100644
--- a/lib/ssl/src/tls_record.erl
+++ b/lib/ssl/src/tls_record.erl
@@ -43,7 +43,7 @@
-export([protocol_version/1, lowest_protocol_version/1, lowest_protocol_version/2,
highest_protocol_version/1, highest_protocol_version/2,
is_higher/2, supported_protocol_versions/0,
- is_acceptable_version/1, is_acceptable_version/2]).
+ is_acceptable_version/1, is_acceptable_version/2, hello_version/2]).
%% Decoding
-export([decode_cipher_text/3]).
@@ -277,6 +277,7 @@ supported_protocol_versions([_|_] = Vsns) ->
NewVsns
end
end.
+
%%--------------------------------------------------------------------
%%
%% Description: ssl version 2 is not acceptable security risks are too big.
@@ -296,6 +297,11 @@ is_acceptable_version({N,_} = Version, Versions)
is_acceptable_version(_,_) ->
false.
+-spec hello_version(tls_version(), [tls_version()]) -> tls_version().
+hello_version(Version, _) when Version >= {3, 3} ->
+ Version;
+hello_version(_, Versions) ->
+ lowest_protocol_version(Versions).
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
diff --git a/lib/ssl/src/tls_v1.erl b/lib/ssl/src/tls_v1.erl
index f52ee06e71..bc487fdca4 100644
--- a/lib/ssl/src/tls_v1.erl
+++ b/lib/ssl/src/tls_v1.erl
@@ -29,7 +29,7 @@
-include("ssl_internal.hrl").
-include("ssl_record.hrl").
--export([master_secret/4, finished/5, certificate_verify/3, mac_hash/7,
+-export([master_secret/4, finished/5, certificate_verify/3, mac_hash/7, hmac_hash/3,
setup_keys/8, suites/1, prf/5,
ecc_curves/1, ecc_curves/2, oid_to_enum/1, enum_to_oid/1,
default_signature_algs/1, signature_algs/2]).
@@ -221,11 +221,7 @@ suites(Minor) when Minor == 1; Minor == 2 ->
?TLS_RSA_WITH_3DES_EDE_CBC_SHA
];
suites(3) ->
- [
- ?TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
- ?TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
-
- ?TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+ [?TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
?TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,
?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,
@@ -234,7 +230,10 @@ suites(3) ->
?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384,
?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384,
+ ?TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
+ ?TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
?TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
+
?TLS_DHE_RSA_WITH_AES_256_GCM_SHA384,
?TLS_DHE_DSS_WITH_AES_256_GCM_SHA384,
?TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,
diff --git a/lib/stdlib/doc/src/beam_lib.xml b/lib/stdlib/doc/src/beam_lib.xml
index d5ec90b060..031d79d0e2 100644
--- a/lib/stdlib/doc/src/beam_lib.xml
+++ b/lib/stdlib/doc/src/beam_lib.xml
@@ -42,10 +42,10 @@
and the corresponding identifiers are as follows:</p>
<list type="bulleted">
- <item><c>abstract_code ("Abst")</c></item>
<item><c>atoms ("Atom")</c></item>
<item><c>attributes ("Attr")</c></item>
<item><c>compile_info ("CInf")</c></item>
+ <item><c>debug_info ("Dbgi")</c></item>
<item><c>exports ("ExpT")</c></item>
<item><c>imports ("ImpT")</c></item>
<item><c>indexed_imports ("ImpT")</c></item>
@@ -60,9 +60,8 @@
<title>Debug Information/Abstract Code</title>
<p>Option <c>debug_info</c> can be specified to the Compiler (see
<seealso marker="compiler:compile#debug_info"><c>compile(3)</c></seealso>)
- to have debug information in the form of abstract code (see section
- <seealso marker="erts:absform">The Abstract Format</seealso> in the
- ERTS User's Guide) stored in the <c>abstract_code</c> chunk.
+ to have debug information, such as <seealso marker="erts:absform">Erlang
+ Abstract Format</seealso>, stored in the <c>debug_info</c> chunk.
Tools such as Debugger and Xref require the debug information to
be included.</p>
@@ -79,7 +78,7 @@
<section>
<title>Reconstruct Source Code</title>
- <p>The following example shows how to reconstruct source code from
+ <p>The following example shows how to reconstruct Erlang source code from
the debug information in a BEAM file <c>Beam</c>:</p>
<code type="none">
@@ -117,7 +116,7 @@ io:fwrite("~s~n", [erl_prettypr:format(erl_syntax:form_list(AC))]).</code>
<list type="ordered">
<item>
- <p>Use Compiler option <c>{debug_info,Key}</c>, see
+ <p>Use Compiler option <c>{debug_info_key,Key}</c>, see
<seealso marker="compiler:compile#debug_info_key"><c>compile(3)</c></seealso>
and function
<seealso marker="#crypto_key_fun/1"><c>crypto_key_fun/1</c></seealso>
@@ -198,18 +197,40 @@ io:fwrite("~s~n", [erl_prettypr:format(erl_syntax:form_list(AC))]).</code>
<datatype>
<name name="chunkid"/>
<desc>
- <p>"Abst" | "Attr" | "CInf" | "ExpT" | "ImpT" | "LocT" | "Atom"</p>
+ <p>"Attr" | "CInf" | "Dbgi" | "ExpT" | "ImpT" | "LocT" | "AtU8"</p>
</desc>
</datatype>
<datatype>
<name name="dataB"/>
</datatype>
<datatype>
+ <name name="debug_info"/>
+ <desc>
+ <p>The format stored in the <c>debug_info</c> chunk.
+ To retrieve particular code representation from the backend,
+ <c>Backend:debug_info(Format, Module, Data, Opts)</c> must be
+ invoked. <c>Format</c> is an atom, such as <c>erlang_v1</c> for
+ the Erlang Abstract Format or <c>core_v1</c> for Core Erlang.
+ <c>Module</c> is the module represented by the beam file and
+ <c>Data</c> is the value stored in the debug info chunk.
+ <c>Opts</c> is any list of values supported by the <c>Backend</c>.
+ <c>Backend:debug_info/4</c> must return <c>{ok, Code}</c> or
+ <c>{error, Term}</c>.</p>
+
+ <p>Developers must always invoke the <c>debug_info/4</c> function
+ and never rely on the <c>Data</c> stored in the <c>debug_info</c>
+ chunk, as it is opaque and may change at any moment. <c>no_debug_info</c>
+ means that chunk <c>"Dbgi"</c> is present, but empty.</p>
+ </desc>
+ </datatype>
+ <datatype>
<name name="abst_code"/>
<desc>
<p>It is not checked that the forms conform to the abstract format
indicated by <c><anno>AbstVersion</anno></c>. <c>no_abstract_code</c>
means that chunk <c>"Abst"</c> is present, but empty.</p>
+ <p>For modules compiled with OTP 20 onwards, the <c>abst_code</c> chunk
+ is automatically computed from the <c>debug_info</c> chunk.</p>
</desc>
</datatype>
<datatype>
@@ -346,7 +367,7 @@ io:fwrite("~s~n", [erl_prettypr:format(erl_syntax:form_list(AC))]).</code>
<desc>
<p>Registers an unary fun
that is called if <c>beam_lib</c> must read an
- <c>abstract_code</c> chunk that has been encrypted. The fun
+ <c>debug_info</c> chunk that has been encrypted. The fun
is held in a process that is started by the function.</p>
<p>If a fun is already registered when attempting to
register a fun, <c>{error, exists}</c> is returned.</p>
@@ -443,7 +464,8 @@ CryptoKeyFun(clear) -> term()</code>
<desc>
<p>Removes all chunks from a BEAM
file except those needed by the loader. In particular,
- the debug information (chunk <c>abstract_code</c>) is removed.</p>
+ the debug information (chunk <c>debug_info</c> and <c>abstract_code</c>)
+ is removed.</p>
</desc>
</func>
@@ -454,9 +476,9 @@ CryptoKeyFun(clear) -> term()</code>
<desc>
<p>Removes all chunks except
those needed by the loader from BEAM files. In particular,
- the debug information (chunk <c>abstract_code</c>) is removed.
- The returned list contains one element for each specified filename,
- in the same order as in <c>Files</c>.</p>
+ the debug information (chunk <c>debug_info</c> and <c>abstract_code</c>)
+ is removed. The returned list contains one element for each
+ specified filename, in the same order as in <c>Files</c>.</p>
</desc>
</func>
diff --git a/lib/stdlib/doc/src/gen_fsm.xml b/lib/stdlib/doc/src/gen_fsm.xml
index 691a039e34..7187630b43 100644
--- a/lib/stdlib/doc/src/gen_fsm.xml
+++ b/lib/stdlib/doc/src/gen_fsm.xml
@@ -4,14 +4,14 @@
<erlref>
<header>
<copyright>
- <year>1996</year><year>2016</year>
+ <year>1996-2017</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
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
@@ -29,945 +29,176 @@
<rev></rev>
</header>
<module>gen_fsm</module>
- <modulesummary>Generic finite state machine behavior.</modulesummary>
- <description>
- <note>
- <p>
- There is a new behaviour
- <seealso marker="gen_statem"><c>gen_statem</c></seealso>
- that is intended to replace <c>gen_fsm</c> for new code.
- <c>gen_fsm</c> will not be removed for the foreseeable future
- to keep old state machine implementations running.
- </p>
- </note>
- <p>This behavior module provides a finite state machine.
- A generic finite state machine process (<c>gen_fsm</c>) implemented
- using this module has a standard set of interface functions
- and includes functionality for tracing and error reporting. It
- also fits into an OTP supervision tree. For more information, see
- <seealso marker="doc/design_principles:fsm">OTP Design Principles</seealso>.
- </p>
-
- <p>A <c>gen_fsm</c> process assumes all specific parts to be located in a
- callback module exporting a predefined set of functions. The relationship
- between the behavior functions and the callback functions is as
- follows:</p>
-
- <pre>
-gen_fsm module Callback module
--------------- ---------------
-gen_fsm:start
-gen_fsm:start_link -----> Module:init/1
-
-gen_fsm:stop -----> Module:terminate/3
-
-gen_fsm:send_event -----> Module:StateName/2
-
-gen_fsm:send_all_state_event -----> Module:handle_event/3
-
-gen_fsm:sync_send_event -----> Module:StateName/3
-
-gen_fsm:sync_send_all_state_event -----> Module:handle_sync_event/4
-
-- -----> Module:handle_info/3
-
-- -----> Module:terminate/3
+ <modulesummary>Deprecated and replaced by gen_statem </modulesummary>
-- -----> Module:code_change/4</pre>
-
- <p>If a callback function fails or returns a bad value, the <c>gen_fsm</c>
- process terminates.</p>
-
- <p>A <c>gen_fsm</c> process handles system messages as described in
- <seealso marker="sys"><c>sys(3)</c></seealso>. The <c>sys</c> module
- can be used for debugging a <c>gen_fsm</c> process.</p>
-
- <p>Notice that a <c>gen_fsm</c> process does not trap exit signals
- automatically, this must be explicitly initiated in the callback
- module.</p>
-
- <p>Unless otherwise stated, all functions in this module fail if
- the specified <c>gen_fsm</c> process does not exist or if bad arguments
- are specified.</p>
-
- <p>The <c>gen_fsm</c> process can go into hibernation
- (see <seealso marker="erts:erlang#hibernate/3">
- <c>erlang:hibernate/3</c></seealso>) if a callback function
- specifies <c>'hibernate'</c> instead of a time-out value. This
- can be useful if the server is expected to be idle for a long
- time. However, use this feature with care, as hibernation
- implies at least two garbage collections (when hibernating and
- shortly after waking up) and is not something you want to do
- between each call to a busy state machine.</p>
+ <description>
+ <p> Deprecated and replaced by <seealso marker="gen_statem"><c>gen_statem</c></seealso> </p>
</description>
-
- <funcs>
- <func>
- <name>cancel_timer(Ref) -> RemainingTime | false</name>
- <fsummary>Cancel an internal timer in a generic FSM.</fsummary>
- <type>
- <v>Ref = reference()</v>
- <v>RemainingTime = integer()</v>
- </type>
- <desc>
- <p>Cancels an internal timer referred by <c>Ref</c> in the
- <c>gen_fsm</c> process that calls this function.</p>
- <p><c>Ref</c> is a reference returned from
- <seealso marker="#send_event_after/2">
- <c>send_event_after/2</c></seealso> or
- <seealso marker="#start_timer/2"><c>start_timer/2</c></seealso>.</p>
- <p>If the timer has already timed out, but the event not yet
- been delivered, it is cancelled as if it had <em>not</em>
- timed out, so there is no false timer event after
- returning from this function.</p>
- <p>Returns the remaining time in milliseconds until the timer would
- have expired if <c>Ref</c> referred to an active timer, otherwise
- <c>false</c>.</p>
- </desc>
- </func>
-
- <func>
- <name>enter_loop(Module, Options, StateName, StateData)</name>
- <name>enter_loop(Module, Options, StateName, StateData, FsmName)</name>
- <name>enter_loop(Module, Options, StateName, StateData, Timeout)</name>
- <name>enter_loop(Module, Options, StateName, StateData, FsmName, Timeout)</name>
- <fsummary>Enter the <c>gen_fsm</c> receive loop.</fsummary>
- <type>
- <v>Module = atom()</v>
- <v>Options = [Option]</v>
- <v>&nbsp;Option = {debug,Dbgs}</v>
- <v>&nbsp;&nbsp;Dbgs = [Dbg]</v>
- <v>&nbsp;&nbsp;&nbsp;Dbg = trace | log | statistics</v>
- <v>&nbsp;&nbsp;&nbsp;&nbsp;| {log_to_file,FileName} | {install,{Func,FuncState}}</v>
- <v>StateName = atom()</v>
- <v>StateData = term()</v>
- <v>FsmName = {local,Name} | {global,GlobalName}</v>
- <v>&nbsp;&nbsp;| {via,Module,ViaName}</v>
- <v>&nbsp;Name = atom()</v>
- <v>&nbsp;GlobalName = ViaName = term()</v>
- <v>Timeout = int() | infinity</v>
- </type>
- <desc>
- <p>Makes an existing process into a <c>gen_fsm</c> process.
- Does not return,
- instead the calling process enters the <c>gen_fsm</c> receive
- loop and becomes a <c>gen_fsm</c> process. The process <em>must</em>
- have been started using one of the start functions in
- <seealso marker="proc_lib"><c>proc_lib(3)</c></seealso>. The user is
- responsible for any initialization of the process, including
- registering a name for it.</p>
- <p>This function is useful when a more complex initialization
- procedure is needed than the <c>gen_fsm</c> behavior provides.</p>
- <p><c>Module</c>, <c>Options</c>, and <c>FsmName</c> have
- the same meanings as when calling
- <seealso marker="#start_link/3"><c>start[_link]/3,4</c></seealso>.
- However, if <c>FsmName</c> is specified, the process must have
- been registered accordingly <em>before</em> this function is
- called.</p>
- <p><c>StateName</c>, <c>StateData</c>, and <c>Timeout</c> have
- the same meanings as in the return value of
- <seealso marker="#Moduleinit"><c>Module:init/1</c></seealso>.
- The callback module <c>Module</c> does not need to
- export an <c>init/1</c> function.</p>
- <p>The function fails if the calling process was not started by a
- <c>proc_lib</c> start function, or if it is not registered
- according to <c>FsmName</c>.</p>
- </desc>
- </func>
-
- <func>
- <name>reply(Caller, Reply) -> Result</name>
- <fsummary>Send a reply to a caller.</fsummary>
- <type>
- <v>Caller - see below</v>
- <v>Reply = term()</v>
- <v>Result = term()</v>
- </type>
- <desc>
- <p>This function can be used by a <c>gen_fsm</c> process to
- explicitly send a reply to a client process that called
- <seealso marker="#sync_send_event/2">
- <c>sync_send_event/2,3</c></seealso> or
- <seealso marker="#sync_send_all_state_event/2">
- <c>sync_send_all_state_event/2,3</c></seealso>
- when the reply cannot be defined in the return value of
- <seealso marker="#Module:StateName/3">
- <c>Module:StateName/3</c></seealso> or
- <seealso marker="#Module:handle_sync_event/4">
- <c>Module:handle_sync_event/4</c></seealso>.</p>
- <p><c>Caller</c> must be the <c>From</c> argument provided to
- the callback function. <c>Reply</c> is any term
- given back to the client as the return value of
- <c>sync_send_event/2,3</c> or
- <c>sync_send_all_state_event/2,3</c>.</p>
- <p>Return value <c>Result</c> is not further defined, and
- is always to be ignored.</p>
- </desc>
- </func>
-
- <func>
- <name>send_all_state_event(FsmRef, Event) -> ok</name>
- <fsummary>Send an event asynchronously to a generic FSM.</fsummary>
- <type>
- <v>FsmRef = Name | {Name,Node} | {global,GlobalName}</v>
- <v>&nbsp;&nbsp;| {via,Module,ViaName} | pid()</v>
- <v>&nbsp;Name = Node = atom()</v>
- <v>&nbsp;GlobalName = ViaName = term()</v>
- <v>Event = term()</v>
- </type>
- <desc>
- <p>Sends an event asynchronously to the <c>FsmRef</c> of the
- <c>gen_fsm</c> process and returns <c>ok</c> immediately.
- The <c>gen_fsm</c> process calls
- <seealso marker="#Module:handle_event/3">
- <c>Module:handle_event/3</c></seealso> to handle the event.</p>
- <p>For a description of the arguments, see
- <seealso marker="#send_event/2"><c>send_event/2</c></seealso>.</p>
- <p>The difference between <c>send_event/2</c> and
- <c>send_all_state_event/2</c> is which callback function is
- used to handle the event. This function is useful when
- sending events that are handled the same way in every state,
- as only one <c>handle_event</c> clause is needed to handle
- the event instead of one clause in each state name function.</p>
- </desc>
- </func>
-
- <func>
- <name>send_event(FsmRef, Event) -> ok</name>
- <fsummary>Send an event asynchronously to a generic FSM.</fsummary>
- <type>
- <v>FsmRef = Name | {Name,Node} | {global,GlobalName}</v>
- <v>&nbsp;&nbsp;| {via,Module,ViaName} | pid()</v>
- <v>&nbsp;Name = Node = atom()</v>
- <v>&nbsp;GlobalName = ViaName = term()</v>
- <v>Event = term()</v>
- </type>
- <desc>
- <p>Sends an event asynchronously to the <c>FsmRef</c> of the
- <c>gen_fsm</c> process
- and returns <c>ok</c> immediately. The <c>gen_fsm</c> process calls
- <seealso marker="#Module:StateName/2">
- <c>Module:StateName/2</c></seealso> to handle the event, where
- <c>StateName</c> is the name of the current state of
- the <c>gen_fsm</c> process.</p>
- <p><c>FsmRef</c> can be any of the following:</p>
- <list type="bulleted">
- <item>The pid</item>
- <item><c>Name</c>, if the <c>gen_fsm</c> process is locally
- registered</item>
- <item><c>{Name,Node}</c>, if the <c>gen_fsm</c> process is locally
- registered at another node</item>
- <item><c>{global,GlobalName}</c>, if the <c>gen_fsm</c> process is
- globally registered</item>
- <item><c>{via,Module,ViaName}</c>, if the <c>gen_fsm</c> process is
- registered through an alternative process registry</item>
- </list>
- <p><c>Event</c> is any term that is passed as one of
- the arguments to <c>Module:StateName/2</c>.</p>
- </desc>
- </func>
-
- <func>
- <name>send_event_after(Time, Event) -> Ref</name>
- <fsummary>Send a delayed event internally in a generic FSM.</fsummary>
- <type>
- <v>Time = integer()</v>
- <v>Event = term()</v>
- <v>Ref = reference()</v>
- </type>
- <desc>
- <p>Sends a delayed event internally in the <c>gen_fsm</c> process
- that calls this function after <c>Time</c> milliseconds.
- Returns immediately a
- reference that can be used to cancel the delayed send using
- <seealso marker="#cancel_timer/1"><c>cancel_timer/1</c></seealso>.</p>
- <p>The <c>gen_fsm</c> process calls
- <seealso marker="#Module:StateName/2">
- <c>Module:StateName/2</c></seealso> to handle
- the event, where <c>StateName</c> is the name of the current
- state of the <c>gen_fsm</c> process at the time the delayed event is
- delivered.</p>
- <p><c>Event</c> is any term that is passed as one of
- the arguments to <c>Module:StateName/2</c>.</p>
- </desc>
- </func>
-
- <func>
- <name>start(Module, Args, Options) -> Result</name>
- <name>start(FsmName, Module, Args, Options) -> Result</name>
- <fsummary>Create a standalone <c>gen_fsm</c> process.</fsummary>
- <type>
- <v>FsmName = {local,Name} | {global,GlobalName}</v>
- <v>&nbsp;&nbsp;| {via,Module,ViaName}</v>
- <v>&nbsp;Name = atom()</v>
- <v>&nbsp;GlobalName = ViaName = term()</v>
- <v>Module = atom()</v>
- <v>Args = term()</v>
- <v>Options = [Option]</v>
- <v>&nbsp;Option = {debug,Dbgs} | {timeout,Time} | {spawn_opt,SOpts}</v>
- <v>&nbsp;&nbsp;Dbgs = [Dbg]</v>
- <v>&nbsp;&nbsp;&nbsp;Dbg = trace | log | statistics</v>
- <v>&nbsp;&nbsp;&nbsp;&nbsp;| {log_to_file,FileName} | {install,{Func,FuncState}}</v>
- <v>&nbsp;&nbsp;SOpts = [term()]</v>
- <v>Result = {ok,Pid} | ignore | {error,Error}</v>
- <v>&nbsp;Pid = pid()</v>
- <v>&nbsp;Error = {already_started,Pid} | term()</v>
- </type>
- <desc>
- <p>Creates a standalone <c>gen_fsm</c> process, that is, a process that
- is not part of a supervision tree and thus has no supervisor.</p>
- <p>For a description of arguments and return values, see
- <seealso marker="#start_link/3"><c>start_link/3,4</c></seealso>.</p>
- </desc>
- </func>
-
- <func>
- <name>start_link(Module, Args, Options) -> Result</name>
- <name>start_link(FsmName, Module, Args, Options) -> Result</name>
- <fsummary>Create a <c>gen_fsm</c> process in a supervision tree.
- </fsummary>
- <type>
- <v>FsmName = {local,Name} | {global,GlobalName}</v>
- <v>&nbsp;&nbsp;| {via,Module,ViaName}</v>
- <v>&nbsp;Name = atom()</v>
- <v>&nbsp;GlobalName = ViaName = term()</v>
- <v>Module = atom()</v>
- <v>Args = term()</v>
- <v>Options = [Option]</v>
- <v>&nbsp;Option = {debug,Dbgs} | {timeout,Time} | {spawn_opt,SOpts}</v>
- <v>&nbsp;&nbsp;Dbgs = [Dbg]</v>
- <v>&nbsp;&nbsp;&nbsp;Dbg = trace | log | statistics</v>
- <v>&nbsp;&nbsp;&nbsp;&nbsp;| {log_to_file,FileName} | {install,{Func,FuncState}}</v>
- <v>&nbsp;&nbsp;SOpts = [SOpt]</v>
- <v>&nbsp;&nbsp;&nbsp;SOpt - see erlang:spawn_opt/2,3,4,5</v>
- <v>Result = {ok,Pid} | ignore | {error,Error}</v>
- <v>&nbsp;Pid = pid()</v>
- <v>&nbsp;Error = {already_started,Pid} | term()</v>
- </type>
- <desc>
- <p>Creates a <c>gen_fsm</c> process as part of a supervision tree.
- The function is to be called, directly or indirectly, by
- the supervisor. For example, it ensures that
- the <c>gen_fsm</c> process is linked to the supervisor.</p>
- <p>The <c>gen_fsm</c> process calls
- <seealso marker="#Module:init/1"><c>Module:init/1</c></seealso> to
- initialize. To ensure a synchronized startup procedure,
- <c>start_link/3,4</c> does not return until
- <c>Module:init/1</c> has returned.</p>
- <list type="bulleted">
- <item>
- <p>If <c>FsmName={local,Name}</c>, the <c>gen_fsm</c> process is
- registered locally as <c>Name</c> using <c>register/2</c>.</p>
- </item>
- <item>
- <p>If <c>FsmName={global,GlobalName}</c>, the <c>gen_fsm</c> process
- is registered globally as <c>GlobalName</c> using
- <seealso marker="kernel:global#register_name/2">
- <c>global:register_name/2</c></seealso>.</p>
- </item>
- <item>
- <p>If <c>FsmName={via,Module,ViaName}</c>, the <c>gen_fsm</c>
- process registers with the registry represented by <c>Module</c>.
- The <c>Module</c> callback is to export the functions
- <c>register_name/2</c>, <c>unregister_name/1</c>,
- <c>whereis_name/1</c>, and <c>send/2</c>, which are to behave
- like the corresponding functions in
- <seealso marker="kernel:global"><c>global</c></seealso>.
- Thus, <c>{via,global,GlobalName}</c> is a valid reference.</p>
- </item>
- </list>
- <p>If no name is provided, the <c>gen_fsm</c> process is not
- registered.</p>
- <p><c>Module</c> is the name of the callback module.</p>
- <p><c>Args</c> is any term that is passed as
- the argument to <c>Module:init/1</c>.</p>
- <p>If option <c>{timeout,Time}</c> is present, the <c>gen_fsm</c>
- process is allowed to spend <c>Time</c> milliseconds initializing
- or it terminates and the start function returns
- <c>{error,timeout}</c>.</p>
- <p>If option <c>{debug,Dbgs}</c> is present, the corresponding
- <c>sys</c> function is called for each item in <c>Dbgs</c>; see
- <seealso marker="sys"><c>sys(3)</c></seealso>.</p>
- <p>If option <c>{spawn_opt,SOpts}</c> is present, <c>SOpts</c> is
- passed as option list to the <c>spawn_opt</c> BIF that is used to
- spawn the <c>gen_fsm</c> process; see
- <seealso marker="erts:erlang#spawn_opt/2">
- <c>spawn_opt/2</c></seealso>.</p>
- <note>
- <p>Using spawn option <c>monitor</c> is not
- allowed, it causes the function to fail with reason
- <c>badarg</c>.</p>
- </note>
- <p>If the <c>gen_fsm</c> process is successfully created and
- initialized, the function returns <c>{ok,Pid}</c>, where <c>Pid</c>
- is the pid of the <c>gen_fsm</c> process. If a process with the
- specified <c>FsmName</c> exists already, the function returns
- <c>{error,{already_started,Pid}}</c>, where <c>Pid</c> is
- the pid of that process.</p>
- <p>If <c>Module:init/1</c> fails with <c>Reason</c>,
- the function returns <c>{error,Reason}</c>. If
- <c>Module:init/1</c> returns <c>{stop,Reason}</c> or
- <c>ignore</c>, the process is terminated and the function
- returns <c>{error,Reason}</c> or <c>ignore</c>, respectively.</p>
- </desc>
- </func>
-
- <func>
- <name>start_timer(Time, Msg) -> Ref</name>
- <fsummary>Send a time-out event internally in a generic FSM.</fsummary>
- <type>
- <v>Time = integer()</v>
- <v>Msg = term()</v>
- <v>Ref = reference()</v>
- </type>
- <desc>
- <p>Sends a time-out event internally in the <c>gen_fsm</c>
- process that calls this function after <c>Time</c> milliseconds.
- Returns immediately a
- reference that can be used to cancel the timer using
- <seealso marker="#cancel_timer/1"><c>cancel_timer/1</c></seealso>.</p>
- <p>The <c>gen_fsm</c> process calls
- <seealso marker="#Module:StateName/2">
- <c>Module:StateName/2</c></seealso> to handle
- the event, where <c>StateName</c> is the name of the current
- state of the <c>gen_fsm</c> process at the time the time-out
- message is delivered.</p>
- <p><c>Msg</c> is any term that is passed in the
- time-out message, <c>{timeout, Ref, Msg}</c>, as one of
- the arguments to <c>Module:StateName/2</c>.</p>
- </desc>
- </func>
-
- <func>
- <name>stop(FsmRef) -> ok</name>
- <name>stop(FsmRef, Reason, Timeout) -> ok</name>
- <fsummary>Synchronously stop a generic FSM.</fsummary>
- <type>
- <v>FsmRef = Name | {Name,Node} | {global,GlobalName}</v>
- <v>&nbsp;&nbsp;| {via,Module,ViaName} | pid()</v>
- <v>&nbsp;Node = atom()</v>
- <v>&nbsp;GlobalName = ViaName = term()</v>
- <v>Reason = term()</v>
- <v>Timeout = int()>0 | infinity</v>
- </type>
- <desc>
- <p>Orders a generic finite state machine to exit with the specified
- <c>Reason</c> and waits for it to terminate. The <c>gen_fsm</c>
- process calls <seealso marker="#Module:terminate/3">
- <c>Module:terminate/3</c></seealso> before exiting.</p>
- <p>The function returns <c>ok</c> if the generic finite state machine
- terminates with the expected reason. Any other reason than
- <c>normal</c>, <c>shutdown</c>, or <c>{shutdown,Term}</c> causes an
- error report to be issued using
- <seealso marker="kernel:error_logger#format/2">
- <c>error_logger:format/2</c></seealso>.
- The default <c>Reason</c> is <c>normal</c>.</p>
- <p><c>Timeout</c> is an integer greater than zero that
- specifies how many milliseconds to wait for the generic FSM
- to terminate, or the atom <c>infinity</c> to wait
- indefinitely. The default value is <c>infinity</c>. If the
- generic finite state machine has not terminated within the specified
- time, a <c>timeout</c> exception is raised.</p>
- <p>If the process does not exist, a <c>noproc</c> exception
- is raised.</p>
- </desc>
- </func>
-
- <func>
- <name>sync_send_all_state_event(FsmRef, Event) -> Reply</name>
- <name>sync_send_all_state_event(FsmRef, Event, Timeout) -> Reply</name>
- <fsummary>Send an event synchronously to a generic FSM.</fsummary>
- <type>
- <v>FsmRef = Name | {Name,Node} | {global,GlobalName}</v>
- <v>&nbsp;&nbsp;| {via,Module,ViaName} | pid()</v>
- <v>&nbsp;Name = Node = atom()</v>
- <v>&nbsp;GlobalName = ViaName = term()</v>
- <v>Event = term()</v>
- <v>Timeout = int()>0 | infinity</v>
- <v>Reply = term()</v>
- </type>
- <desc>
- <p>Sends an event to the <c>FsmRef</c> of the <c>gen_fsm</c>
- process and waits until a reply arrives or a time-out occurs.
- The <c>gen_fsm</c> process calls
- <seealso marker="#Module:handle_sync_event/4">
- <c>Module:handle_sync_event/4</c></seealso> to handle the event.</p>
- <p>For a description of <c>FsmRef</c> and <c>Event</c>, see
- <seealso marker="#send_event/2">send_event/2</seealso>.
- For a description of <c>Timeout</c> and <c>Reply</c>, see
- <seealso marker="#sync_send_event/3">
- <c>sync_send_event/3</c></seealso>.</p>
- <p>For a discussion about the difference between
- <c>sync_send_event</c> and <c>sync_send_all_state_event</c>, see
- <seealso marker="#send_all_state_event/2">
- <c>send_all_state_event/2</c></seealso>.</p>
- </desc>
- </func>
-
- <func>
- <name>sync_send_event(FsmRef, Event) -> Reply</name>
- <name>sync_send_event(FsmRef, Event, Timeout) -> Reply</name>
- <fsummary>Send an event synchronously to a generic FSM.</fsummary>
- <type>
- <v>FsmRef = Name | {Name,Node} | {global,GlobalName}</v>
- <v>&nbsp;&nbsp;| {via,Module,ViaName} | pid()</v>
- <v>&nbsp;Name = Node = atom()</v>
- <v>&nbsp;GlobalName = ViaName = term()</v>
- <v>Event = term()</v>
- <v>Timeout = int()>0 | infinity</v>
- <v>Reply = term()</v>
- </type>
- <desc>
- <p>Sends an event to the <c>FsmRef</c> of the <c>gen_fsm</c>
- process and waits until a reply arrives or a time-out occurs.
- <c>The gen_fsm</c> process calls
- <seealso marker="#Module:StateName/3">
- <c>Module:StateName/3</c></seealso> to handle the event, where
- <c>StateName</c> is the name of the current state of
- the <c>gen_fsm</c> process.</p>
- <p>For a description of <c>FsmRef</c> and <c>Event</c>, see
- <seealso marker="#send_event/2"><c>send_event/2</c></seealso>.</p>
- <p><c>Timeout</c> is an integer greater than zero that
- specifies how many milliseconds to wait for a reply, or
- the atom <c>infinity</c> to wait indefinitely. Defaults
- to 5000. If no reply is received within the specified time,
- the function call fails.</p>
- <p>Return value <c>Reply</c> is defined in the return value
- of <c>Module:StateName/3</c>.</p>
- </desc>
- </func>
- </funcs>
-
- <section>
- <title>Callback Functions</title>
- <p>The following functions are to be exported from a <c>gen_fsm</c>
- callback module.</p>
-
- <p><em>state name</em> denotes a state of the state machine.</p>
-
- <p><em>state data</em> denotes the internal state of the Erlang process
- that implements the state machine.</p>
- </section>
-
- <funcs>
- <func>
- <name>Module:code_change(OldVsn, StateName, StateData, Extra) -> {ok, NextStateName, NewStateData}</name>
- <fsummary>Update the internal state data during upgrade/downgrade.
- </fsummary>
- <type>
- <v>OldVsn = Vsn | {down, Vsn}</v>
- <v>&nbsp;&nbsp;Vsn = term()</v>
- <v>StateName = NextStateName = atom()</v>
- <v>StateData = NewStateData = term()</v>
- <v>Extra = term()</v>
- </type>
- <desc>
- <note>
- <p>This callback is optional, so callback modules need not export it.
- If a release upgrade/downgrade with <c>Change={advanced,Extra}</c>
- specified in the <c>appup</c> file is made when <c>code_change/4</c>
- isn't implemented the process will crash with an <c>undef</c> exit
- reason.</p>
- </note>
- <p>This function is called by a <c>gen_fsm</c> process when it is to
- update its internal state data during a release upgrade/downgrade,
- that is, when instruction <c>{update,Module,Change,...}</c>,
- where <c>Change={advanced,Extra}</c>, is given in
- the <c>appup</c> file; see section
- <seealso marker="doc/design_principles:release_handling#instr">
- Release Handling Instructions</seealso> in OTP Design Principles.</p>
- <p>For an upgrade, <c>OldVsn</c> is <c>Vsn</c>, and for a downgrade,
- <c>OldVsn</c> is <c>{down,Vsn}</c>. <c>Vsn</c> is defined by the
- <c>vsn</c> attribute(s) of the old version of the callback module
- <c>Module</c>. If no such attribute is defined, the version is
- the checksum of the Beam file.</p>
- <p><c>StateName</c> is the current state name and <c>StateData</c> the
- internal state data of the <c>gen_fsm</c> process.</p>
- <p><c>Extra</c> is passed "as is" from the <c>{advanced,Extra}</c>
- part of the update instruction.</p>
- <p>The function is to return the new current state name and
- updated internal data.</p>
- </desc>
- </func>
-
- <func>
- <name>Module:format_status(Opt, [PDict, StateData]) -> Status</name>
- <fsummary>Optional function for providing a term describing the
- current <c>gen_fsm</c> process status.</fsummary>
- <type>
- <v>Opt = normal | terminate</v>
- <v>PDict = [{Key, Value}]</v>
- <v>StateData = term()</v>
- <v>Status = term()</v>
- </type>
- <desc>
- <note>
- <p>This callback is optional, so callback modules need not
- export it. The <c>gen_fsm</c> module provides a default
- implementation of this function that returns the callback
- module state data.</p>
- </note>
- <p>This function is called by a <c>gen_fsm</c> process in the
- following situations:</p>
- <list type="bulleted">
- <item>One of <seealso marker="sys#get_status/1">
- <c>sys:get_status/1,2</c></seealso>
- is invoked to get the <c>gen_fsm</c> status. <c>Opt</c> is set to
- the atom <c>normal</c> for this case.</item>
- <item>The <c>gen_fsm</c> process terminates abnormally and logs an
- error. <c>Opt</c> is set to the atom <c>terminate</c> for
- this case.</item>
- </list>
- <p>This function is useful for changing the form and
- appearance of the <c>gen_fsm</c> status for these cases. A callback
- module wishing to change the <c>sys:get_status/1,2</c>
- return value as well as how its status appears in
- termination error logs, exports an instance
- of <c>format_status/2</c> that returns a term describing the
- current status of the <c>gen_fsm</c> process.</p>
- <p><c>PDict</c> is the current value of the process dictionary of the
- <c>gen_fsm</c> process.</p>
- <p><c>StateData</c> is the internal state data of the
- <c>gen_fsm</c> process.</p>
- <p>The function is to return <c>Status</c>, a term that
- change the details of the current state and status of
- the <c>gen_fsm</c> process. There are no restrictions on the
- form <c>Status</c> can take, but for
- the <c>sys:get_status/1,2</c> case (when <c>Opt</c>
- is <c>normal</c>), the recommended form for
- the <c>Status</c> value is <c>[{data, [{"StateData",
- Term}]}]</c>, where <c>Term</c> provides relevant details of
- the <c>gen_fsm</c> state data. Following this recommendation is not
- required, but it makes the callback module status
- consistent with the rest of the <c>sys:get_status/1,2</c>
- return value.</p>
- <p>One use for this function is to return compact alternative
- state data representations to avoid that large state terms
- are printed in log files.</p>
- </desc>
- </func>
-
- <func>
- <name>Module:handle_event(Event, StateName, StateData) -> Result</name>
- <fsummary>Handle an asynchronous event.</fsummary>
- <type>
- <v>Event = term()</v>
- <v>StateName = atom()</v>
- <v>StateData = term()</v>
- <v>Result = {next_state,NextStateName,NewStateData}</v>
- <v>&nbsp;&nbsp;| {next_state,NextStateName,NewStateData,Timeout}</v>
- <v>&nbsp;&nbsp;| {next_state,NextStateName,NewStateData,hibernate}</v>
- <v>&nbsp;&nbsp;| {stop,Reason,NewStateData}</v>
- <v>&nbsp;NextStateName = atom()</v>
- <v>&nbsp;NewStateData = term()</v>
- <v>&nbsp;Timeout = int()>0 | infinity</v>
- <v>&nbsp;Reason = term()</v>
- </type>
- <desc>
- <p>Whenever a <c>gen_fsm</c> process receives an event sent using
- <seealso marker="#send_all_state_event/2">
- <c>send_all_state_event/2</c></seealso>,
- this function is called to handle the event.</p>
- <p><c>StateName</c> is the current state name of the <c>gen_fsm</c>
- process.</p>
- <p>For a description of the other arguments and possible return values,
- see <seealso marker="#Module:StateName/2">
- <c>Module:StateName/2</c></seealso>.</p>
- </desc>
- </func>
-
- <func>
- <name>Module:handle_info(Info, StateName, StateData) -> Result</name>
- <fsummary>Handle an incoming message.</fsummary>
- <type>
- <v>Info = term()</v>
- <v>StateName = atom()</v>
- <v>StateData = term()</v>
- <v>Result = {next_state,NextStateName,NewStateData}</v>
- <v>&nbsp;&nbsp;| {next_state,NextStateName,NewStateData,Timeout}</v>
- <v>&nbsp;&nbsp;| {next_state,NextStateName,NewStateData,hibernate}</v>
- <v>&nbsp;&nbsp;| {stop,Reason,NewStateData}</v>
- <v>&nbsp;NextStateName = atom()</v>
- <v>&nbsp;NewStateData = term()</v>
- <v>&nbsp;Timeout = int()>0 | infinity</v>
- <v>&nbsp;Reason = normal | term()</v>
- </type>
- <desc>
- <note>
- <p>This callback is optional, so callback modules need not
- export it. The <c>gen_fsm</c> module provides a default
- implementation of this function that logs about the unexpected
- <c>Info</c> message, drops it and returns
- <c>{next_state, StateName, StateData}</c>.</p>
- </note>
- <p>This function is called by a <c>gen_fsm</c> process when it receives
- any other message than a synchronous or asynchronous event (or a
- system message).</p>
- <p><c>Info</c> is the received message.</p>
- <p>For a description of the other arguments and possible return values,
- see <seealso marker="#Module:StateName/2">
- <c>Module:StateName/2</c></seealso>.</p>
- </desc>
- </func>
-
- <func>
- <name>Module:handle_sync_event(Event, From, StateName, StateData) -> Result</name>
- <fsummary>Handle a synchronous event.</fsummary>
- <type>
- <v>Event = term()</v>
- <v>From = {pid(),Tag}</v>
- <v>StateName = atom()</v>
- <v>StateData = term()</v>
- <v>Result = {reply,Reply,NextStateName,NewStateData}</v>
- <v>&nbsp;&nbsp;| {reply,Reply,NextStateName,NewStateData,Timeout}</v>
- <v>&nbsp;&nbsp;| {reply,Reply,NextStateName,NewStateData,hibernate}</v>
- <v>&nbsp;&nbsp;| {next_state,NextStateName,NewStateData}</v>
- <v>&nbsp;&nbsp;| {next_state,NextStateName,NewStateData,Timeout}</v>
- <v>&nbsp;&nbsp;| {next_state,NextStateName,NewStateData,hibernate}</v>
- <v>&nbsp;&nbsp;| {stop,Reason,Reply,NewStateData} | {stop,Reason,NewStateData}</v>
- <v>&nbsp;Reply = term()</v>
- <v>&nbsp;NextStateName = atom()</v>
- <v>&nbsp;NewStateData = term()</v>
- <v>&nbsp;Timeout = int()>0 | infinity</v>
- <v>&nbsp;Reason = term()</v>
- </type>
- <desc>
- <p>Whenever a <c>gen_fsm</c> process receives an event sent using
- <seealso marker="#sync_send_all_state_event/2">
- <c>sync_send_all_state_event/2,3</c></seealso>,
- this function is called to handle the event.</p>
- <p><c>StateName</c> is the current state name of the <c>gen_fsm</c>
- process.</p>
- <p>For a description of the other arguments and possible return values,
- see <seealso marker="#Module:StateName/3">
- <c>Module:StateName/3</c></seealso>.</p>
- </desc>
- </func>
-
- <func>
- <name>Module:init(Args) -> Result</name>
- <fsummary>Initialize process and internal state name and state data.
- </fsummary>
- <type>
- <v>Args = term()</v>
- <v>Result = {ok,StateName,StateData} | {ok,StateName,StateData,Timeout}</v>
- <v>&nbsp;&nbsp;| {ok,StateName,StateData,hibernate}</v>
- <v>&nbsp;&nbsp;| {stop,Reason} | ignore</v>
- <v>&nbsp;StateName = atom()</v>
- <v>&nbsp;StateData = term()</v>
- <v>&nbsp;Timeout = int()>0 | infinity</v>
- <v>&nbsp;Reason = term()</v>
- </type>
- <desc>
- <marker id="Moduleinit"></marker>
- <p>Whenever a <c>gen_fsm</c> process is started using
- <seealso marker="#start/3"><c>start/3,4</c></seealso> or
- <seealso marker="#start_link/3"><c>start_link/3,4</c></seealso>,
- this function is called by the new process to initialize.</p>
- <p><c>Args</c> is the <c>Args</c> argument provided to the start
- function.</p>
- <p>If initialization is successful, the function is to return
- <c>{ok,StateName,StateData}</c>,
- <c>{ok,StateName,StateData,Timeout}</c>, or
- <c>{ok,StateName,StateData,hibernate}</c>, where <c>StateName</c>
- is the initial state name and <c>StateData</c> the initial
- state data of the <c>gen_fsm</c> process.</p>
- <p>If an integer time-out value is provided, a time-out occurs
- unless an event or a message is received within <c>Timeout</c>
- milliseconds. A time-out is represented by the atom
- <c>timeout</c> and is to be handled by the
- <seealso marker="#Module:StateName/2">
- <c>Module:StateName/2</c></seealso> callback functions. The atom
- <c>infinity</c> can be used to wait indefinitely, this is
- the default value.</p>
- <p>If <c>hibernate</c> is specified instead of a time-out value, the
- process goes into hibernation when waiting for the next message
- to arrive (by calling <seealso marker="proc_lib#hibernate/3">
- <c>proc_lib:hibernate/3</c></seealso>).</p>
- <p>If the initialization fails, the function returns
- <c>{stop,Reason}</c>, where <c>Reason</c> is any term,
- or <c>ignore</c>.</p>
- </desc>
- </func>
-
- <func>
- <name>Module:StateName(Event, StateData) -> Result</name>
- <fsummary>Handle an asynchronous event.</fsummary>
- <type>
- <v>Event = timeout | term()</v>
- <v>StateData = term()</v>
- <v>Result = {next_state,NextStateName,NewStateData} </v>
- <v>&nbsp;&nbsp;| {next_state,NextStateName,NewStateData,Timeout}</v>
- <v>&nbsp;&nbsp;| {next_state,NextStateName,NewStateData,hibernate}</v>
- <v>&nbsp;&nbsp;| {stop,Reason,NewStateData}</v>
- <v>&nbsp;NextStateName = atom()</v>
- <v>&nbsp;NewStateData = term()</v>
- <v>&nbsp;Timeout = int()>0 | infinity</v>
- <v>&nbsp;Reason = term()</v>
- </type>
- <desc>
- <p>There is to be one instance of this function for each
- possible state name. Whenever a <c>gen_fsm</c> process receives
- an event sent using
- <seealso marker="#send_event/2"><c>send_event/2</c></seealso>,
- the instance of this function with the same name as
- the current state name <c>StateName</c> is called to handle
- the event. It is also called if a time-out occurs.</p>
- <p><c>Event</c> is either the atom <c>timeout</c>, if a time-out
- has occurred, or the <c>Event</c> argument provided to
- <c>send_event/2</c>.</p>
- <p><c>StateData</c> is the state data of the <c>gen_fsm</c> process.</p>
- <p>If the function returns
- <c>{next_state,NextStateName,NewStateData}</c>,
- <c>{next_state,NextStateName,NewStateData,Timeout}</c>, or
- <c>{next_state,NextStateName,NewStateData,hibernate}</c>, the
- <c>gen_fsm</c> process continues executing with the current state
- name set to <c>NextStateName</c> and with the possibly
- updated state data <c>NewStateData</c>. For a description of
- <c>Timeout</c> and <c>hibernate</c>, see
- <seealso marker="#Module:init/1"><c>Module:init/1</c></seealso>.</p>
- <p>If the function returns <c>{stop,Reason,NewStateData}</c>,
- the <c>gen_fsm</c> process calls
- <c>Module:terminate(Reason,StateName,NewStateData)</c> and
- terminates.</p>
- </desc>
- </func>
-
- <func>
- <name>Module:StateName(Event, From, StateData) -> Result</name>
- <fsummary>Handle a synchronous event.</fsummary>
- <type>
- <v>Event = term()</v>
- <v>From = {pid(),Tag}</v>
- <v>StateData = term()</v>
- <v>Result = {reply,Reply,NextStateName,NewStateData}</v>
- <v>&nbsp;&nbsp;| {reply,Reply,NextStateName,NewStateData,Timeout}</v>
- <v>&nbsp;&nbsp;| {reply,Reply,NextStateName,NewStateData,hibernate}</v>
- <v>&nbsp;&nbsp;| {next_state,NextStateName,NewStateData}</v>
- <v>&nbsp;&nbsp;| {next_state,NextStateName,NewStateData,Timeout}</v>
- <v>&nbsp;&nbsp;| {next_state,NextStateName,NewStateData,hibernate}</v>
- <v>&nbsp;&nbsp;| {stop,Reason,Reply,NewStateData} | {stop,Reason,NewStateData}</v>
- <v>&nbsp;Reply = term()</v>
- <v>&nbsp;NextStateName = atom()</v>
- <v>&nbsp;NewStateData = term()</v>
- <v>&nbsp;Timeout = int()>0 | infinity</v>
- <v>&nbsp;Reason = normal | term()</v>
- </type>
- <desc>
- <p>There is to be one instance of this function for each
- possible state name. Whenever a <c>gen_fsm</c> process receives an
- event sent using <seealso marker="#sync_send_event/2">
- <c>sync_send_event/2,3</c></seealso>,
- the instance of this function with the same name as
- the current state name <c>StateName</c> is called to handle
- the event.</p>
- <p><c>Event</c> is the <c>Event</c> argument provided to
- <c>sync_send_event/2,3</c>.</p>
- <p><c>From</c> is a tuple <c>{Pid,Tag}</c> where <c>Pid</c> is
- the pid of the process that called <c>sync_send_event/2,3</c>
- and <c>Tag</c> is a unique tag.</p>
- <p><c>StateData</c> is the state data of the <c>gen_fsm</c> process.</p>
- <list type="bulleted">
- <item>
- <p>If <c>{reply,Reply,NextStateName,NewStateData}</c>,
- <c>{reply,Reply,NextStateName,NewStateData,Timeout}</c>, or
- <c>{reply,Reply,NextStateName,NewStateData,hibernate}</c> is
- returned, <c>Reply</c> is given back to <c>From</c> as the return
- value of <c>sync_send_event/2,3</c>. The <c>gen_fsm</c> process
- then continues executing with the current state name set to
- <c>NextStateName</c> and with the possibly updated state data
- <c>NewStateData</c>. For a description of <c>Timeout</c> and
- <c>hibernate</c>, see
- <seealso marker="#Module:init/1">
- <c>Module:init/1</c></seealso>.</p>
- </item>
- <item>
- <p>If <c>{next_state,NextStateName,NewStateData}</c>,
- <c>{next_state,NextStateName,NewStateData,Timeout}</c>, or
- <c>{next_state,NextStateName,NewStateData,hibernate}</c> is
- returned, the <c>gen_fsm</c> process continues executing in
- <c>NextStateName</c> with <c>NewStateData</c>.
- Any reply to <c>From</c> must be specified explicitly using
- <seealso marker="#reply/2"><c>reply/2</c></seealso>.</p>
- </item>
- <item>
- <p>If the function returns
- <c>{stop,Reason,Reply,NewStateData}</c>, <c>Reply</c> is
- given back to <c>From</c>. If the function returns
- <c>{stop,Reason,NewStateData}</c>, any reply to <c>From</c>
- must be specified explicitly using <c>reply/2</c>.
- The <c>gen_fsm</c> process then calls
- <c>Module:terminate(Reason,StateName,NewStateData)</c> and
- terminates.</p>
- </item>
- </list>
- </desc>
- </func>
-
- <func>
- <name>Module:terminate(Reason, StateName, StateData)</name>
- <fsummary>Clean up before termination.</fsummary>
- <type>
- <v>Reason = normal | shutdown | {shutdown,term()} | term()</v>
- <v>StateName = atom()</v>
- <v>StateData = term()</v>
- </type>
- <desc>
- <note>
- <p>This callback is optional, so callback modules need not
- export it. The <c>gen_fsm</c> module provides a default
- implementation without cleanup.</p>
- </note>
- <p>This function is called by a <c>gen_fsm</c> process when it is about
- to terminate. It is to be the opposite of
- <seealso marker="#Module:init/1"><c>Module:init/1</c></seealso>
- and do any necessary cleaning up. When it returns, the <c>gen_fsm</c>
- process terminates with <c>Reason</c>. The return value is ignored.
- </p>
- <p><c>Reason</c> is a term denoting the stop reason,
- <c>StateName</c> is the current state name, and
- <c>StateData</c> is the state data of the <c>gen_fsm</c> process.</p>
- <p><c>Reason</c> depends on why the <c>gen_fsm</c> process is
- terminating. If
- it is because another callback function has returned a stop
- tuple <c>{stop,..}</c>, <c>Reason</c> has the value
- specified in that tuple. If it is because of a failure,
- <c>Reason</c> is the error reason.</p>
- <p>If the <c>gen_fsm</c> process is part of a supervision tree and is
- ordered by its supervisor to terminate, this function is called
- with <c>Reason=shutdown</c> if the following conditions apply:</p>
- <list type="bulleted">
- <item>
- <p>The <c>gen_fsm</c> process has been set to trap exit signals.</p>
- </item>
- <item>
- <p>The shutdown strategy as defined in the child specification of
- the supervisor is an integer time-out value, not
- <c>brutal_kill</c>.</p>
- </item>
- </list>
- <p>Even if the <c>gen_fsm</c> process is <em>not</em> part of a
- supervision tree,
- this function is called if it receives an <c>'EXIT'</c>
- message from its parent. <c>Reason</c> is the same as in
- the <c>'EXIT'</c> message.</p>
- <p>Otherwise, the <c>gen_fsm</c> process terminates immediately.</p>
- <p>Notice that for any other reason than <c>normal</c>,
- <c>shutdown</c>, or <c>{shutdown,Term}</c> the <c>gen_fsm</c> process
- is assumed to terminate because of an error and an error report is
- issued using <seealso marker="kernel:error_logger#format/2">
- <c>error_logger:format/2</c></seealso>.</p>
- </desc>
- </func>
- </funcs>
-
<section>
- <title>See Also</title>
- <p><seealso marker="gen_event"><c>gen_event(3)</c></seealso>,
- <seealso marker="gen_server"><c>gen_server(3)</c></seealso>,
- <seealso marker="gen_statem"><c>gen_statem(3)</c></seealso>,
- <seealso marker="proc_lib"><c>proc_lib(3)</c></seealso>,
- <seealso marker="supervisor"><c>supervisor(3)</c></seealso>,
- <seealso marker="sys"><c>sys(3)</c></seealso></p>
+ <marker id="Migration to gen_statem"/>
+ <title>Migration to gen_statem</title>
+
+ <p>Here follows a simple example of turning a gen_fsm into
+ a <seealso marker="gen_statem"><c>gen_statem</c></seealso>. The example comes
+ from the previous Users Guide for <c>gen_fsm</c> </p>
+
+ <code type="erl">
+-module(code_lock).
+-define(NAME, code_lock).
+%-define(BEFORE_REWRITE, true).
+
+-ifdef(BEFORE_REWRITE).
+-behaviour(gen_fsm).
+-else.
+-behaviour(gen_statem).
+-endif.
+
+-export([start_link/1, button/1, stop/0]).
+
+-ifdef(BEFORE_REWRITE).
+-export([init/1, locked/2, open/2, handle_sync_event/4, handle_event/3,
+ handle_info/3, terminate/3, code_change/4]).
+-else.
+-export([init/1, callback_mode/0, locked/3, open/3, terminate/3, code_change/4]).
+%% Add callback__mode/0
+%% Change arity of the state functions
+%% Remove handle_info/3
+-endif.
+
+-ifdef(BEFORE_REWRITE).
+start_link(Code) ->
+ gen_fsm:start_link({local, ?NAME}, ?MODULE, Code, []).
+-else.
+start_link(Code) ->
+ gen_statem:start_link({local,?NAME}, ?MODULE, Code, []).
+-endif.
+
+-ifdef(BEFORE_REWRITE).
+button(Digit) ->
+ gen_fsm:send_event(?NAME, {button, Digit}).
+-else.
+button(Digit) ->
+ gen_statem:cast(?NAME, {button,Digit}).
+ %% send_event is asynchronous and becomes a cast
+-endif.
+
+-ifdef(BEFORE_REWRITE).
+stop() ->
+ gen_fsm:sync_send_all_state_event(?NAME, stop).
+-else.
+stop() ->
+ gen_statem:call(?NAME, stop).
+ %% sync_send is synchronous and becomes call
+ %% all_state is handled by callback code in gen_statem
+-endif.
+
+init(Code) ->
+ do_lock(),
+ Data = #{code => Code, remaining => Code},
+ {ok, locked, Data}.
+
+-ifdef(BEFORE_REWRITE).
+-else.
+callback_mode() ->
+ state_functions.
+%% state_functions mode is the mode most similar to
+%% gen_fsm. There is also handle_event mode which is
+%% a fairly different concept.
+-endif.
+
+-ifdef(BEFORE_REWRITE).
+locked({button, Digit}, Data0) ->
+ case analyze_lock(Digit, Data0) of
+ {open = StateName, Data} ->
+ {next_state, StateName, Data, 10000};
+ {StateName, Data} ->
+ {next_state, StateName, Data}
+ end.
+-else.
+locked(cast, {button,Digit}, Data0) ->
+ case analyze_lock(Digit, Data0) of
+ {open = StateName, Data} ->
+ {next_state, StateName, Data, 10000};
+ {StateName, Data} ->
+ {next_state, StateName, Data}
+ end;
+locked({call, From}, Msg, Data) ->
+ handle_call(From, Msg, Data);
+locked({info, Msg}, StateName, Data) ->
+ handle_info(Msg, StateName, Data).
+%% Arity differs
+%% All state events are dispatched to handle_call and handle_info help
+%% functions. If you want to handle a call or cast event specifically
+%% for this state you would add a special clause for it above.
+-endif.
+
+-ifdef(BEFORE_REWRITE).
+open(timeout, State) ->
+ do_lock(),
+ {next_state, locked, State};
+open({button,_}, Data) ->
+ {next_state, locked, Data}.
+-else.
+open(timeout, _, Data) ->
+ do_lock(),
+ {next_state, locked, Data};
+open(cast, {button,_}, Data) ->
+ {next_state, locked, Data};
+open({call, From}, Msg, Data) ->
+ handle_call(From, Msg, Data);
+open(info, Msg, Data) ->
+ handle_info(Msg, open, Data).
+%% Arity differs
+%% All state events are dispatched to handle_call and handle_info help
+%% functions. If you want to handle a call or cast event specifically
+%% for this state you would add a special clause for it above.
+-endif.
+
+-ifdef(BEFORE_REWRITE).
+handle_sync_event(stop, _From, _StateName, Data) ->
+ {stop, normal, ok, Data}.
+
+handle_event(Event, StateName, Data) ->
+ {stop, {shutdown, {unexpected, Event, StateName}}, Data}.
+
+handle_info(Info, StateName, Data) ->
+ {stop, {shutdown, {unexpected, Info, StateName}}, StateName, Data}.
+-else.
+-endif.
+
+terminate(_Reason, State, _Data) ->
+ State =/= locked andalso do_lock(),
+ ok.
+code_change(_Vsn, State, Data, _Extra) ->
+ {ok, State, Data}.
+
+%% Internal functions
+-ifdef(BEFORE_REWRITE).
+-else.
+handle_call(From, stop, Data) ->
+ {stop_and_reply, normal, {reply, From, ok}, Data}.
+
+handle_info(Info, StateName, Data) ->
+ {stop, {shutdown, {unexpected, Info, StateName}}, StateName, Data}.
+%% These are internal functions for handling all state events
+%% and not behaviour callbacks as in gen_fsm
+-endif.
+
+analyze_lock(Digit, #{code := Code, remaining := Remaining} = Data) ->
+ case Remaining of
+ [Digit] ->
+ do_unlock(),
+ {open, Data#{remaining := Code}};
+ [Digit|Rest] -> % Incomplete
+ {locked, Data#{remaining := Rest}};
+ _Wrong ->
+ {locked, Data#{remaining := Code}}
+ end.
+
+do_lock() ->
+ io:format("Lock~n", []).
+do_unlock() ->
+ io:format("Unlock~n", []).
+ </code>
</section>
</erlref>
diff --git a/lib/stdlib/doc/src/gen_server.xml b/lib/stdlib/doc/src/gen_server.xml
index 4540449792..0bcbbc2805 100644
--- a/lib/stdlib/doc/src/gen_server.xml
+++ b/lib/stdlib/doc/src/gen_server.xml
@@ -814,7 +814,6 @@ gen_server:abcast -----> Module:handle_cast/2
<section>
<title>See Also</title>
<p><seealso marker="gen_event"><c>gen_event(3)</c></seealso>,
- <seealso marker="gen_fsm"><c>gen_fsm(3)</c></seealso>,
<seealso marker="gen_statem"><c>gen_statem(3)</c></seealso>,
<seealso marker="proc_lib"><c>proc_lib(3)</c></seealso>,
<seealso marker="supervisor"><c>supervisor(3)</c></seealso>,
diff --git a/lib/stdlib/doc/src/gen_statem.xml b/lib/stdlib/doc/src/gen_statem.xml
index 5eb13db1aa..17a3a3c83c 100644
--- a/lib/stdlib/doc/src/gen_statem.xml
+++ b/lib/stdlib/doc/src/gen_statem.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2016-2017</year>
+ <year>2016</year><year>2017</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -62,24 +62,29 @@
</p>
</note>
<p>
- The <c>gen_statem</c> behavior is intended to replace
- <seealso marker="gen_fsm"><c>gen_fsm</c></seealso> for new code.
+ The <c>gen_statem</c> behavior replaces
+ <seealso marker="gen_fsm"><c>gen_fsm</c> </seealso> in Erlang/OTP 20.0.
It has the same features and adds some really useful:
</p>
<list type="bulleted">
- <item>State code is gathered.</item>
- <item>The state can be any term.</item>
- <item>Events can be postponed.</item>
- <item>Events can be self-generated.</item>
- <item>Automatic state enter code can be called.</item>
- <item>A reply can be sent from a later state.</item>
- <item>There can be multiple <c>sys</c> traceable replies.</item>
+ <item>Gathered state code.</item>
+ <item>Arbitrary term state.</item>
+ <item>Event postponing.</item>
+ <item>Self-generated events.</item>
+ <item>State time-out.</item>
+ <item>Multiple generic named time-outs.</item>
+ <item>Absolute time-out time.</item>
+ <item>Automatic state enter calls.</item>
+ <item>Reply from other state than the request.</item>
+ <item>Multiple <c>sys</c> traceable replies.</item>
</list>
<p>
The callback model(s) for <c>gen_statem</c> differs from
the one for <seealso marker="gen_fsm"><c>gen_fsm</c></seealso>,
- but it is still fairly easy to rewrite
- from <c>gen_fsm</c> to <c>gen_statem</c>.
+ but it is still fairly easy to
+ <seealso marker="gen_fsm#Migration to gen_statem">
+ rewrite from
+ </seealso> <c>gen_fsm</c> to <c>gen_statem</c>.
</p>
<p>
A generic state machine process (<c>gen_statem</c>) implemented
@@ -146,7 +151,7 @@ erlang:'!' -----> Module:StateName/3
This gathers all code for a specific state
in one function as the <c>gen_statem</c> engine
branches depending on state name.
- Notice the fact that there is a mandatory callback function
+ Note the fact that the callback function
<seealso marker="#Module:terminate/3"><c>Module:terminate/3</c></seealso>
makes the state name <c>terminate</c> unusable in this mode.
</p>
@@ -531,10 +536,12 @@ handle_event(_, _, State, Data) ->
originate from the corresponding API functions.
For calls, the event contains whom to reply to.
Type <c>info</c> originates from regular process messages sent
- to the <c>gen_statem</c>. Also, the state machine
- implementation can generate events of types
- <c>timeout</c>, <c>state_timeout</c>,
- and <c>internal</c> to itself.
+ to the <c>gen_statem</c>. The state machine
+ implementation can, in addition to the above,
+ generate
+ <seealso marker="#type-event_type"><c>events of types</c></seealso>
+ <c>timeout</c>, <c>{timeout,<anno>Name</anno>}</c>,
+ <c>state_timeout</c>, and <c>internal</c> to itself.
</p>
</desc>
</datatype>
@@ -701,13 +708,14 @@ handle_event(_, _, State, Data) ->
</item>
<item>
<p>
- Timeout timers
- <seealso marker="#type-state_timeout"><c>state_timeout()</c></seealso>
+ Time-out timers
+ <seealso marker="#type-event_timeout"><c>event_timeout()</c></seealso>,
+ <seealso marker="#type-generic_timeout"><c>generic_timeout()</c></seealso>
and
- <seealso marker="#type-event_timeout"><c>event_timeout()</c></seealso>
+ <seealso marker="#type-state_timeout"><c>state_timeout()</c></seealso>
are handled. Time-outs with zero time are guaranteed to be
delivered to the state machine before any external
- not yet received event so if there is such a timeout requested,
+ not yet received event so if there is such a time-out requested,
the corresponding time-out zero event is enqueued as
the newest event.
</p>
@@ -785,49 +793,102 @@ handle_event(_, _, State, Data) ->
<name name="event_timeout"/>
<desc>
<p>
- Generates an event of
+ Starts a timer set by
+ <seealso marker="#type-enter_action"><c>enter_action()</c></seealso>
+ <c>timeout</c>.
+ When the timer expires an event of
<seealso marker="#type-event_type"><c>event_type()</c></seealso>
- <c>timeout</c>
- after this time (in milliseconds) unless another
- event arrives or has arrived
- in which case this time-out is cancelled.
+ <c>timeout</c> will be generated.
+ See
+ <seealso marker="erts:erlang#start_timer/4"><c>erlang:start_timer/4</c></seealso>
+ for how <c>Time</c> and
+ <seealso marker="#type-timeout_option"><c>Options</c></seealso>
+ are interpreted. Future <c>erlang:start_timer/4</c> <c>Options</c>
+ will not necessarily be supported.
+ </p>
+ <p>
+ Any event that arrives cancels this time-out.
Note that a retried or inserted event counts as arrived.
So does a state time-out zero event, if it was generated
- before this timer is requested.
+ before this time-out is requested.
</p>
<p>
- If the value is <c>infinity</c>, no timer is started, as
- it never would trigger anyway.
+ If <c>Time</c> is <c>infinity</c>,
+ no timer is started, as it never would expire anyway.
</p>
<p>
- If the value is <c>0</c> no timer is actually started,
+ If <c>Time</c> is relative and <c>0</c>
+ no timer is actually started,
instead the the time-out event is enqueued to ensure
that it gets processed before any not yet
received external event.
</p>
<p>
- Note that it is not possible or needed to cancel this time-out,
+ Note that it is not possible nor needed to cancel this time-out,
as it is cancelled automatically by any other event.
</p>
</desc>
</datatype>
<datatype>
+ <name name="generic_timeout"/>
+ <desc>
+ <p>
+ Starts a timer set by
+ <seealso marker="#type-enter_action"><c>enter_action()</c></seealso>
+ <c>{timeout,Name}</c>.
+ When the timer expires an event of
+ <seealso marker="#type-event_type"><c>event_type()</c></seealso>
+ <c>{timeout,Name}</c> will be generated.
+ See
+ <seealso marker="erts:erlang#start_timer/4"><c>erlang:start_timer/4</c></seealso>
+ for how <c>Time</c> and
+ <seealso marker="#type-timeout_option"><c>Options</c></seealso>
+ are interpreted. Future <c>erlang:start_timer/4</c> <c>Options</c>
+ will not necessarily be supported.
+ </p>
+ <p>
+ If <c>Time</c> is <c>infinity</c>,
+ no timer is started, as it never would expire anyway.
+ </p>
+ <p>
+ If <c>Time</c> is relative and <c>0</c>
+ no timer is actually started,
+ instead the the time-out event is enqueued to ensure
+ that it gets processed before any not yet
+ received external event.
+ </p>
+ <p>
+ Setting a timer with the same <c>Name</c> while it is running
+ will restart it with the new time-out value.
+ Therefore it is possible to cancel
+ a specific time-out by setting it to <c>infinity</c>.
+ </p>
+ </desc>
+ </datatype>
+ <datatype>
<name name="state_timeout"/>
<desc>
<p>
- Generates an event of
+ Starts a timer set by
+ <seealso marker="#type-enter_action"><c>enter_action()</c></seealso>
+ <c>state_timeout</c>.
+ When the timer expires an event of
<seealso marker="#type-event_type"><c>event_type()</c></seealso>
- <c>state_timeout</c>
- after this time (in milliseconds) unless the <c>gen_statem</c>
- changes states (<c>NewState =/= OldState</c>)
- which case this time-out is cancelled.
+ <c>state_timeout</c> will be generated.
+ See
+ <seealso marker="erts:erlang#start_timer/4"><c>erlang:start_timer/4</c></seealso>
+ for how <c>Time</c> and
+ <seealso marker="#type-timeout_option"><c>Options</c></seealso>
+ are interpreted. Future <c>erlang:start_timer/4</c> <c>Options</c>
+ will not necessarily be supported.
</p>
<p>
- If the value is <c>infinity</c>, no timer is started, as
- it never would trigger anyway.
+ If <c>Time</c> is <c>infinity</c>,
+ no timer is started, as it never would expire anyway.
</p>
<p>
- If the value is <c>0</c> no timer is actually started,
+ If <c>Time</c> is relative and <c>0</c>
+ no timer is actually started,
instead the the time-out event is enqueued to ensure
that it gets processed before any not yet
received external event.
@@ -840,6 +901,20 @@ handle_event(_, _, State, Data) ->
</desc>
</datatype>
<datatype>
+ <name name="timeout_option"/>
+ <desc>
+ <p>
+ If <c>Abs</c> is <c>true</c> an absolute timer is started,
+ and if it is <c>false</c> a relative, which is the default.
+ See
+ <seealso marker="erts:erlang#start_timer/4"><c>erlang:start_timer/4</c></seealso>
+ for details.
+ </p>
+ <p>
+ </p>
+ </desc>
+ </datatype>
+ <datatype>
<name name="action"/>
<desc>
<p>
@@ -945,7 +1020,6 @@ handle_event(_, _, State, Data) ->
<seealso marker="#state callback">state callback</seealso>
return value <c>{next_state,NextState,NewData,Timeout}</c>
allowed like for <c>gen_fsm</c>'s
- <seealso marker="gen_fsm#Module:StateName/2"><c>Module:StateName/2</c></seealso>.
</p>
</item>
<tag><c>timeout</c></tag>
@@ -954,7 +1028,21 @@ handle_event(_, _, State, Data) ->
Sets the
<seealso marker="#type-transition_option"><c>transition_option()</c></seealso>
<seealso marker="#type-event_timeout"><c>event_timeout()</c></seealso>
- to <c><anno>Time</anno></c> with <c><anno>EventContent</anno></c>.
+ to <c><anno>Time</anno></c> with <c><anno>EventContent</anno></c>
+ and time-out options
+ <seealso marker="#type-timeout_option"><c><anno>Options</anno></c></seealso>.
+ </p>
+ </item>
+ <tag><c>{timeout,<anno>Name</anno>}</c></tag>
+ <item>
+ <p>
+ Sets the
+ <seealso marker="#type-transition_option"><c>transition_option()</c></seealso>
+ <seealso marker="#type-generic_timeout"><c>generic_timeout()</c></seealso>
+ to <c><anno>Time</anno></c> for <c><anno>Name</anno></c>
+ with <c><anno>EventContent</anno></c>
+ and time-out options
+ <seealso marker="#type-timeout_option"><c><anno>Options</anno></c></seealso>.
</p>
</item>
<tag><c>state_timeout</c></tag>
@@ -963,7 +1051,9 @@ handle_event(_, _, State, Data) ->
Sets the
<seealso marker="#type-transition_option"><c>transition_option()</c></seealso>
<seealso marker="#type-state_timeout"><c>state_timeout()</c></seealso>
- to <c><anno>Time</anno></c> with <c><anno>EventContent</anno></c>.
+ to <c><anno>Time</anno></c> with <c><anno>EventContent</anno></c>
+ and time-out options
+ <seealso marker="#type-timeout_option"><c><anno>Options</anno></c></seealso>.
</p>
</item>
</taglist>
@@ -1235,7 +1325,7 @@ handle_event(_, _, State, Data) ->
to avoid that the calling process dies when the call
times out, you will have to be prepared to handle
a late reply.
- So why not just allow the calling process to die?
+ So why not just let the calling process die?
</p>
</note>
<p>
@@ -1644,6 +1734,16 @@ handle_event(_, _, State, Data) ->
<v>Reason = term()</v>
</type>
<desc>
+ <note>
+ <p>
+ This callback is optional, so callback modules need not export it.
+ If a release upgrade/downgrade with
+ <c>Change={advanced,Extra}</c>
+ specified in the <c>.appup</c> file is made
+ when <c>code_change/4</c> is not implemented
+ the process will crash with exit reason <c>undef</c>.
+ </p>
+ </note>
<p>
This function is called by a <c>gen_statem</c> when it is to
update its internal state during a release upgrade/downgrade,
@@ -1704,7 +1804,7 @@ handle_event(_, _, State, Data) ->
<func>
<name>Module:init(Args) -> Result(StateType)</name>
<fsummary>
- Optional function for initializing process and internal state.
+ Initializing process and internal state.
</fsummary>
<type>
<v>Args = term()</v>
@@ -1720,7 +1820,7 @@ handle_event(_, _, State, Data) ->
<seealso marker="#start_link/3"><c>start_link/3,4</c></seealso>
or
<seealso marker="#start/3"><c>start/3,4</c></seealso>,
- this optional function is called by the new process to initialize
+ this function is called by the new process to initialize
the implementation state and server data.
</p>
<p>
@@ -1729,13 +1829,16 @@ handle_event(_, _, State, Data) ->
</p>
<note>
<p>
- This callback is optional, so a callback module does not need
- to export it, but most do. If this function is not exported,
- the <c>gen_statem</c> should be started through
+ Note that if the <c>gen_statem</c> is started trough
<seealso marker="proc_lib"><c>proc_lib</c></seealso>
and
- <seealso marker="#enter_loop/4"><c>enter_loop/4-6</c></seealso>.
+ <seealso marker="#enter_loop/4"><c>enter_loop/4-6</c></seealso>,
+ this callback will never be called.
+ Since this callback is not optional it can
+ in that case be implemented as:
</p>
+ <pre>
+init(Args) -> erlang:error(not_implemented, [Args]).</pre>
</note>
</desc>
</func>
diff --git a/lib/stdlib/doc/src/io.xml b/lib/stdlib/doc/src/io.xml
index 11a64c7f8a..64fcf4379f 100644
--- a/lib/stdlib/doc/src/io.xml
+++ b/lib/stdlib/doc/src/io.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1996</year><year>2016</year>
+ <year>1996</year><year>2017</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -265,6 +265,8 @@ ok
<p>Writes data with the standard syntax. This is used to
output Erlang terms. Atoms are printed within quotes if
they contain embedded non-printable characters.
+ Atom characters &gt; 255 are escaped unless the
+ Unicode translation modifier (<c>t</c>) is used.
Floats are printed accurately as the shortest, correctly
rounded string.</p>
</item>
@@ -567,8 +569,6 @@ Prompt> <input>&lt;Characters beyond latin1 range not printable in this medium&g
<item>
<p>Similar to <c>s</c>, but the resulting string is
converted into an atom.</p>
- <p>The Unicode translation modifier is not allowed (atoms
- cannot contain characters beyond the <c>latin1</c> range).</p>
</item>
<tag><c>c</c></tag>
<item>
diff --git a/lib/stdlib/doc/src/io_lib.xml b/lib/stdlib/doc/src/io_lib.xml
index 5ae400da62..bc1d77ac83 100644
--- a/lib/stdlib/doc/src/io_lib.xml
+++ b/lib/stdlib/doc/src/io_lib.xml
@@ -356,7 +356,8 @@
<func>
<name name="write" arity="1"/>
- <name name="write" arity="2"/>
+ <name name="write" arity="2" clause_i="1"/>
+ <name name="write" arity="2" clause_i="2"/>
<fsummary>Write a term.</fsummary>
<desc>
<p>Returns a character list that represents <c><anno>Term</anno></c>.
diff --git a/lib/stdlib/doc/src/proc_lib.xml b/lib/stdlib/doc/src/proc_lib.xml
index e64b2ce18a..7939a0ef61 100644
--- a/lib/stdlib/doc/src/proc_lib.xml
+++ b/lib/stdlib/doc/src/proc_lib.xml
@@ -36,7 +36,7 @@
the <seealso marker="doc/design_principles:des_princ">
OTP Design Principles</seealso>. Specifically, the functions in this
module are used by the OTP standard behaviors (for example,
- <c>gen_server</c>, <c>gen_fsm</c>, and <c>gen_statem</c>)
+ <c>gen_server</c> and <c>gen_statem</c>)
when starting new processes. The functions
can also be used to start <em>special processes</em>, user-defined
processes that comply to the OTP design principles. For an example,
diff --git a/lib/stdlib/doc/src/sets.xml b/lib/stdlib/doc/src/sets.xml
index 44dc104645..4dc5d68151 100644
--- a/lib/stdlib/doc/src/sets.xml
+++ b/lib/stdlib/doc/src/sets.xml
@@ -40,7 +40,7 @@
<p>This module provides the same interface as the
<seealso marker="ordsets"><c>ordsets(3)</c></seealso> module
- but with a defined representation. One difference is
+ but with an undefined representation. One difference is
that while this module considers two elements as different if they
do not match (<c>=:=</c>), <c>ordsets</c> considers two elements as
different if and only if they do not compare equal (<c>==</c>).</p>
diff --git a/lib/stdlib/doc/src/shell.xml b/lib/stdlib/doc/src/shell.xml
index ab62c2fcdd..2593d3690b 100644
--- a/lib/stdlib/doc/src/shell.xml
+++ b/lib/stdlib/doc/src/shell.xml
@@ -569,7 +569,7 @@ Hello Number: 3378
<pre>
42> <input>E = ets:new(t, []).</input>
-17</pre>
+#Ref&lt;0.1662103692.2407923716.214192></pre>
<p>Command 42 creates an ETS table.</p>
@@ -602,7 +602,7 @@ false</pre>
<pre>
47> <input>E = ets:new(t, []).</input>
-18
+#Ref&lt;0.1662103692.2407923716.214197>
48> <input>ets:insert({d,1,2}).</input>
* exception error: undefined function ets:insert/1</pre>
@@ -617,10 +617,23 @@ true</pre>
<p>Command 49 successfully inserts the tuple into the ETS table.</p>
<pre>
-50> <input>halt().</input>
+50> <input>ets:insert(#Ref&lt;0.1662103692.2407923716.214197>, {e,3,4}).</input>
+true</pre>
+
+ <p>Command 50 inserts another tuple into the ETS table. This time
+ the first argument is the table identifier itself. The shell can
+ parse commands with pids (<c>&lt;0.60.0></c>), ports
+ (<c>#Port&lt;0.536></c>), references
+ (<c>#Ref&lt;0.1662103692.2407792644.214210></c>), and external
+ functions (<c>#Fun&lt;a.b.1></c>), but the command fails unless
+ the corresponding pid, port, reference, or function can be created
+ in the running system.</p>
+
+ <pre>
+51> <input>halt().</input>
strider 2></pre>
- <p>Command 50 exits the Erlang runtime system.</p>
+ <p>Command 51 exits the Erlang runtime system.</p>
</section>
<section>
diff --git a/lib/stdlib/doc/src/supervisor.xml b/lib/stdlib/doc/src/supervisor.xml
index bb06d3645e..a42cfdd567 100644
--- a/lib/stdlib/doc/src/supervisor.xml
+++ b/lib/stdlib/doc/src/supervisor.xml
@@ -36,7 +36,6 @@
process can either be another supervisor or a worker process.
Worker processes are normally implemented using one of the
<seealso marker="gen_event"><c>gen_event</c></seealso>,
- <seealso marker="gen_fsm"><c>gen_fsm</c></seealso>,
<seealso marker="gen_server"><c>gen_server</c></seealso>, or
<seealso marker="gen_statem"><c>gen_statem</c></seealso>
behaviors. A supervisor implemented using this module has
@@ -237,8 +236,8 @@ child_spec() = #{id => child_id(), % mandatory
<p><c>modules</c> is used by the release handler during code
replacement to determine which processes are using a certain
module. As a rule of thumb, if the child process is a
- <c>supervisor</c>, <c>gen_server</c>,
- <c>gen_statem</c>, or <c>gen_fsm</c>,
+ <c>supervisor</c>, <c>gen_server</c> or,
+ <c>gen_statem</c>,
this is to be a list with one element <c>[Module]</c>,
where <c>Module</c> is the callback module. If the child
process is an event manager (<c>gen_event</c>) with a
@@ -706,7 +705,6 @@ child_spec() = #{id => child_id(), % mandatory
<section>
<title>See Also</title>
<p><seealso marker="gen_event"><c>gen_event(3)</c></seealso>,
- <seealso marker="gen_fsm"><c>gen_fsm(3)</c></seealso>,
<seealso marker="gen_statem"><c>gen_statem(3)</c></seealso>,
<seealso marker="gen_server"><c>gen_server(3)</c></seealso>,
<seealso marker="sys"><c>sys(3)</c></seealso></p>
diff --git a/lib/stdlib/doc/src/sys.xml b/lib/stdlib/doc/src/sys.xml
index 45171f814d..78840aaaf3 100644
--- a/lib/stdlib/doc/src/sys.xml
+++ b/lib/stdlib/doc/src/sys.xml
@@ -168,12 +168,6 @@
</item>
<item>
<p>For a
- <seealso marker="gen_fsm"><c>gen_fsm</c></seealso>
- process, <c><anno>State</anno></c> is the tuple
- <c>{CurrentStateName, CurrentStateData}</c>.</p>
- </item>
- <item>
- <p>For a
<seealso marker="gen_statem"><c>gen_statem</c></seealso>
process, <c><anno>State</anno></c> is the tuple
<c>{CurrentState,CurrentData}</c>.</p>
@@ -222,7 +216,7 @@
<p>Function <c>system_get_state/1</c> is primarily useful for
user-defined behaviors and modules that implement OTP
<seealso marker="#special_process">special processes</seealso>.
- The <c>gen_server</c>, <c>gen_fsm</c>,
+ The <c>gen_server</c>,
<c>gen_statem</c>, and <c>gen_event</c> OTP
behavior modules export this function, so callback modules for those
behaviors need not to supply their own.</p>
@@ -246,11 +240,6 @@
process returns the state of the callback module.</p>
</item>
<item>
- <p>A <seealso marker="gen_fsm"><c>gen_fsm</c></seealso>
- process returns information, such as its current
- state name and state data.</p>
- </item>
- <item>
<p>A <seealso marker="gen_statem"><c>gen_statem</c></seealso>
process returns information, such as its current
state name and state data.</p>
@@ -262,14 +251,12 @@
</item>
</list>
<p>Callback modules for <c>gen_server</c>,
- <c>gen_fsm</c>, <c>gen_statem</c>, and <c>gen_event</c>
+ <c>gen_statem</c>, and <c>gen_event</c>
can also change the value of <c><anno>Misc</anno></c>
by exporting a function <c>format_status/2</c>, which contributes
module-specific information. For details, see
<seealso marker="gen_server#Module:format_status/2">
<c>gen_server:format_status/2</c></seealso>,
- <seealso marker="gen_fsm#Module:format_status/2">
- <c>gen_fsm:format_status/2</c></seealso>,
<seealso marker="gen_statem#Module:format_status/2">
<c>gen_statem:format_status/2</c></seealso>, and
<seealso marker="gen_event#Module:format_status/2">
@@ -373,13 +360,6 @@
is a new instance of that state.</p>
</item>
<item>
- <p>For a <seealso marker="gen_fsm"><c>gen_fsm</c></seealso> process,
- <c><anno>State</anno></c> is the tuple <c>{CurrentStateName,
- CurrentStateData}</c>, and <c><anno>NewState</anno></c> is a
- similar tuple, which can contain
- a new state name, new state data, or both.</p>
- </item>
- <item>
<p>For a <seealso marker="gen_statem"><c>gen_statem</c></seealso>
process, <c><anno>State</anno></c> is the
tuple <c>{CurrentState,CurrentData}</c>,
@@ -422,7 +402,7 @@
return its <c><anno>State</anno></c> argument.</p>
<p>If a <c><anno>StateFun</anno></c> function crashes or throws an
exception, the original state of the process is unchanged for
- <c>gen_server</c>, <c>gen_fsm</c>, and <c>gen_statem</c> processes.
+ <c>gen_server</c>, and <c>gen_statem</c> processes.
For <c>gen_event</c> processes, a crashing or
failing <c><anno>StateFun</anno></c> function
means that only the state of the particular event handler it was
@@ -462,7 +442,7 @@
user-defined behaviors and modules that implement OTP
<seealso marker="#special_process">special processes</seealso>. The
OTP behavior modules <c>gen_server</c>,
- <c>gen_fsm</c>, <c>gen_statem</c>, and <c>gen_event</c>
+ <c>gen_statem</c>, and <c>gen_event</c>
export this function, so callback modules for those
behaviors need not to supply their own.</p>
</desc>
diff --git a/lib/stdlib/doc/src/unicode_usage.xml b/lib/stdlib/doc/src/unicode_usage.xml
index 11b84f552a..6af2fa9fa3 100644
--- a/lib/stdlib/doc/src/unicode_usage.xml
+++ b/lib/stdlib/doc/src/unicode_usage.xml
@@ -64,8 +64,8 @@
source files was switched to UTF-8.</p></item>
<item><p>In Erlang/OTP 20.0, atoms and function can contain
- Unicode characters. Module names are still restricted to
- the ISO-Latin-1 range.</p>
+ Unicode characters. Module names, application names, and node
+ names are still restricted to the ISO Latin-1 range.</p>
<p>Support was added for normalizations forms in
<c>unicode</c> and the <c>string</c> module now handles
utf8-encoded binaries.</p></item>
@@ -352,10 +352,11 @@
<p>Having the source code in UTF-8 also allows you to write string
literals, function names, and atoms containing Unicode
characters with code points &gt; 255.
- Module names are still restricted to the ISO Latin-1 range.
- Binary literals, where you use type
+ Module names, application names, and node names are still restricted
+ to the ISO Latin-1 range. Binary literals, where you use type
<c>/utf8</c>, can also be expressed using Unicode characters &gt; 255.
- Having module names using characters other than 7-bit ASCII can cause
+ Having module names or application names using characters other than
+ 7-bit ASCII can cause
trouble on operating systems with inconsistent file naming schemes,
and can hurt portability, so it is not recommended.</p>
<p>EEP 40 suggests that the language is also to allow for Unicode
@@ -451,8 +452,8 @@ external_charlist() = maybe_improper_list(char() | external_unicode_binary() |
marker="stdlib:epp#encoding"><c>epp(3)</c></seealso> module. As
from Erlang/OTP R16, strings and comments can be written using
Unicode. As from Erlang/OTP 20, also atoms and functions can be
- written using Unicode. Modules names must still be named using
- characters from the ISO Latin-1 character set. (These
+ written using Unicode. Modules, applications, and nodes must still be
+ named using characters from the ISO Latin-1 character set. (These
restrictions in the language are independent of the encoding of
the source file.)</p>
@@ -780,7 +781,7 @@ Eshell V5.10.1 (abort with ^G)
filenames or directory names. If the file system content is
listed, you also get Unicode lists as return value. The support
lies in the Kernel and STDLIB modules, which is why
- most applications (that does not explicitly require the filenames
+ most applications (that do not explicitly require the filenames
to be in the ISO Latin-1 range) benefit from the Unicode support
without change.</p>
diff --git a/lib/stdlib/src/Makefile b/lib/stdlib/src/Makefile
index 0864cfeff6..a7d53af7bc 100644
--- a/lib/stdlib/src/Makefile
+++ b/lib/stdlib/src/Makefile
@@ -58,6 +58,7 @@ MODULES= \
edlin \
edlin_expand \
epp \
+ erl_abstract_code \
erl_anno \
erl_bits \
erl_compile \
diff --git a/lib/stdlib/src/beam_lib.erl b/lib/stdlib/src/beam_lib.erl
index 461acf03be..9e5e7b2e7e 100644
--- a/lib/stdlib/src/beam_lib.erl
+++ b/lib/stdlib/src/beam_lib.erl
@@ -54,6 +54,7 @@
%%-------------------------------------------------------------------------
-type beam() :: module() | file:filename() | binary().
+-type debug_info() :: {DbgiVersion :: atom(), Backend :: module(), Data :: term()} | 'no_debug_info'.
-type forms() :: [erl_parse:abstract_form() | erl_parse:form_info()].
@@ -63,8 +64,9 @@
-type label() :: integer().
-type chunkid() :: nonempty_string(). % approximation of the strings below
-%% "Abst" | "Attr" | "CInf" | "ExpT" | "ImpT" | "LocT" | "Atom" | "AtU8".
--type chunkname() :: 'abstract_code' | 'attributes' | 'compile_info'
+%% "Abst" | "Dbgi" | "Attr" | "CInf" | "ExpT" | "ImpT" | "LocT" | "Atom" | "AtU8".
+-type chunkname() :: 'abstract_code' | 'debug_info'
+ | 'attributes' | 'compile_info'
| 'exports' | 'labeled_exports'
| 'imports' | 'indexed_imports'
| 'locals' | 'labeled_locals'
@@ -77,6 +79,7 @@
-type chunkdata() :: {chunkid(), dataB()}
| {'abstract_code', abst_code()}
+ | {'debug_info', debug_info()}
| {'attributes', [attrib_entry()]}
| {'compile_info', [compinfo_entry()]}
| {'exports', [{atom(), arity()}]}
@@ -99,7 +102,7 @@
| {'file_error', file:filename(), file:posix()}.
-type chnk_rsn() :: {'unknown_chunk', file:filename(), atom()}
| {'key_missing_or_invalid', file:filename(),
- 'abstract_code'}
+ 'abstract_code' | 'debug_info'}
| info_rsn().
-type cmp_rsn() :: {'modules_different', module(), module()}
| {'chunks_different', chunkid()}
@@ -267,9 +270,9 @@ format_error({modules_different, Module1, Module2}) ->
[Module1, Module2]);
format_error({not_a_directory, Name}) ->
io_lib:format("~tp: Not a directory~n", [Name]);
-format_error({key_missing_or_invalid, File, abstract_code}) ->
- io_lib:format("~tp: Cannot decrypt abstract code because key is missing or invalid",
- [File]);
+format_error({key_missing_or_invalid, File, ChunkId}) ->
+ io_lib:format("~tp: Cannot decrypt ~ts because key is missing or invalid",
+ [File, ChunkId]);
format_error(badfun) ->
"not a fun or the fun has the wrong arity";
format_error(exists) ->
@@ -510,9 +513,9 @@ read_chunk_data(File0, ChunkNames) ->
read_chunk_data(File0, ChunkNames0, Options)
when is_atom(File0); is_list(File0); is_binary(File0) ->
File = beam_filename(File0),
- {ChunkIds, Names} = check_chunks(ChunkNames0, File, [], []),
+ {ChunkIds, Names, Optional} = check_chunks(ChunkNames0, File, [], [], []),
AllowMissingChunks = member(allow_missing_chunks, Options),
- {ok, Module, Chunks} = scan_beam(File, ChunkIds, AllowMissingChunks),
+ {ok, Module, Chunks} = scan_beam(File, ChunkIds, AllowMissingChunks, Optional),
AT = ets:new(beam_symbols, []),
T = {empty, AT},
try chunks_to_data(Names, Chunks, File, Chunks, Module, T, [])
@@ -520,31 +523,34 @@ read_chunk_data(File0, ChunkNames0, Options)
end.
%% -> {ok, list()} | throw(Error)
-check_chunks([atoms | Ids], File, IL, L) ->
- check_chunks(Ids, File, ["Atom", "AtU8" | IL], [{atom_chunk, atoms} | L]);
-check_chunks([ChunkName | Ids], File, IL, L) when is_atom(ChunkName) ->
+check_chunks([atoms | Ids], File, IL, L, O) ->
+ check_chunks(Ids, File, ["Atom", "AtU8" | IL],
+ [{atom_chunk, atoms} | L], ["Atom", "AtU8" | O]);
+check_chunks([abstract_code | Ids], File, IL, L, O) ->
+ check_chunks(Ids, File, ["Abst", "Dbgi" | IL],
+ [{abst_chunk, abstract_code} | L], ["Abst", "Dbgi" | O]);
+check_chunks([ChunkName | Ids], File, IL, L, O) when is_atom(ChunkName) ->
ChunkId = chunk_name_to_id(ChunkName, File),
- check_chunks(Ids, File, [ChunkId | IL], [{ChunkId, ChunkName} | L]);
-check_chunks([ChunkId | Ids], File, IL, L) -> % when is_list(ChunkId)
- check_chunks(Ids, File, [ChunkId | IL], [{ChunkId, ChunkId} | L]);
-check_chunks([], _File, IL, L) ->
- {lists:usort(IL), reverse(L)}.
+ check_chunks(Ids, File, [ChunkId | IL], [{ChunkId, ChunkName} | L], O);
+check_chunks([ChunkId | Ids], File, IL, L, O) -> % when is_list(ChunkId)
+ check_chunks(Ids, File, [ChunkId | IL], [{ChunkId, ChunkId} | L], O);
+check_chunks([], _File, IL, L, O) ->
+ {lists:usort(IL), reverse(L), O}.
%% -> {ok, Module, Data} | throw(Error)
scan_beam(File, What) ->
- scan_beam(File, What, false).
+ scan_beam(File, What, false, []).
%% -> {ok, Module, Data} | throw(Error)
-scan_beam(File, What0, AllowMissingChunks) ->
+scan_beam(File, What0, AllowMissingChunks, OptionalChunks) ->
case scan_beam1(File, What0) of
{missing, _FD, Mod, Data, What} when AllowMissingChunks ->
{ok, Mod, [{Id, missing_chunk} || Id <- What] ++ Data};
- {missing, _FD, Mod, Data, ["Atom"]} ->
- {ok, Mod, Data};
- {missing, _FD, Mod, Data, ["AtU8"]} ->
- {ok, Mod, Data};
- {missing, FD, _Mod, _Data, What} ->
- error({missing_chunk, filename(FD), hd(What)});
+ {missing, FD, Mod, Data, What} ->
+ case What -- OptionalChunks of
+ [] -> {ok, Mod, Data};
+ [Missing | _] -> error({missing_chunk, filename(FD), Missing})
+ end;
R ->
R
end.
@@ -638,6 +644,22 @@ get_chunk(Id, Pos, Size, FD) ->
chunks_to_data([{atom_chunk, Name} | CNs], Chunks, File, Cs, Module, Atoms, L) ->
{NewAtoms, Ret} = chunk_to_data(Name, <<"">>, File, Cs, Atoms, Module),
chunks_to_data(CNs, Chunks, File, Cs, Module, NewAtoms, [Ret | L]);
+chunks_to_data([{abst_chunk, Name} | CNs], Chunks, File, Cs, Module, Atoms, L) ->
+ DbgiChunk = proplists:get_value("Dbgi", Chunks, <<"">>),
+ {NewAtoms, Ret} =
+ case catch chunk_to_data(debug_info, DbgiChunk, File, Cs, Atoms, Module) of
+ {DbgiAtoms, {debug_info, {debug_info_v1, Backend, Metadata}}} ->
+ case Backend:debug_info(erlang_v1, Module, Metadata, []) of
+ {ok, Code} -> {DbgiAtoms, {abstract_code, {raw_abstract_v1, Code}}};
+ {error, _} -> {DbgiAtoms, {abstract_code, no_abstract_code}}
+ end;
+ {error,beam_lib,{key_missing_or_invalid,Path,debug_info}} ->
+ error({key_missing_or_invalid,Path,abstract_code});
+ _ ->
+ AbstChunk = proplists:get_value("Abst", Chunks, <<"">>),
+ chunk_to_data(Name, AbstChunk, File, Cs, Atoms, Module)
+ end,
+ chunks_to_data(CNs, Chunks, File, Cs, Module, NewAtoms, [Ret | L]);
chunks_to_data([{Id, Name} | CNs], Chunks, File, Cs, Module, Atoms, L) ->
{_Id, Chunk} = lists:keyfind(Id, 1, Chunks),
{NewAtoms, Ret} = chunk_to_data(Name, Chunk, File, Cs, Atoms, Module),
@@ -660,13 +682,30 @@ chunk_to_data(compile_info=Id, Chunk, File, _Cs, AtomTable, _Mod) ->
error:badarg ->
error({invalid_chunk, File, chunk_name_to_id(Id, File)})
end;
+chunk_to_data(debug_info=Id, Chunk, File, _Cs, AtomTable, Mod) ->
+ case Chunk of
+ <<>> ->
+ {AtomTable, {Id, no_debug_info}};
+ <<0:8,N:8,Mode0:N/binary,Rest/binary>> ->
+ Mode = binary_to_atom(Mode0, utf8),
+ Term = decrypt_chunk(Mode, Mod, File, Id, Rest),
+ {AtomTable, {Id, Term}};
+ _ ->
+ case catch binary_to_term(Chunk) of
+ {'EXIT', _} ->
+ error({invalid_chunk, File, chunk_name_to_id(Id, File)});
+ Term ->
+ {AtomTable, {Id, Term}}
+ end
+ end;
chunk_to_data(abstract_code=Id, Chunk, File, _Cs, AtomTable, Mod) ->
case Chunk of
<<>> ->
{AtomTable, {Id, no_abstract_code}};
<<0:8,N:8,Mode0:N/binary,Rest/binary>> ->
Mode = binary_to_atom(Mode0, utf8),
- decrypt_abst(Mode, Mod, File, Id, AtomTable, Rest);
+ Term = decrypt_chunk(Mode, Mod, File, Id, Rest),
+ {AtomTable, {Id, anno_from_term(Term)}};
_ ->
case catch binary_to_term(Chunk) of
{'EXIT', _} ->
@@ -705,6 +744,7 @@ chunk_name_to_id(locals, _) -> "LocT";
chunk_name_to_id(labeled_locals, _) -> "LocT";
chunk_name_to_id(attributes, _) -> "Attr";
chunk_name_to_id(abstract_code, _) -> "Abst";
+chunk_name_to_id(debug_info, _) -> "Dbgi";
chunk_name_to_id(compile_info, _) -> "CInf";
chunk_name_to_id(Other, File) ->
error({unknown_chunk, File, Other}).
@@ -894,23 +934,18 @@ mandatory_chunks() ->
-define(CRYPTO_KEY_SERVER, beam_lib__crypto_key_server).
-decrypt_abst(Type, Module, File, Id, AtomTable, Bin) ->
+decrypt_chunk(Type, Module, File, Id, Bin) ->
try
KeyString = get_crypto_key({debug_info, Type, Module, File}),
- Key = make_crypto_key(Type, KeyString),
- Term = decrypt_abst_1(Key, Bin),
- {AtomTable, {Id, Term}}
+ {Type,Key,IVec,_BlockSize} = make_crypto_key(Type, KeyString),
+ ok = start_crypto(),
+ NewBin = crypto:block_decrypt(Type, Key, IVec, Bin),
+ binary_to_term(NewBin)
catch
_:_ ->
error({key_missing_or_invalid, File, Id})
end.
-decrypt_abst_1({Type,Key,IVec,_BlockSize}, Bin) ->
- ok = start_crypto(),
- NewBin = crypto:block_decrypt(Type, Key, IVec, Bin),
- Term = binary_to_term(NewBin),
- anno_from_term(Term).
-
anno_from_term({raw_abstract_v1, Forms}) ->
{raw_abstract_v1, anno_from_forms(Forms)};
anno_from_term({Tag, Forms}) when Tag =:= abstract_v1; Tag =:= abstract_v2 ->
diff --git a/lib/stdlib/src/erl_abstract_code.erl b/lib/stdlib/src/erl_abstract_code.erl
new file mode 100644
index 0000000000..6e45f11aa3
--- /dev/null
+++ b/lib/stdlib/src/erl_abstract_code.erl
@@ -0,0 +1,28 @@
+-module(erl_abstract_code).
+-export([debug_info/4]).
+
+debug_info(_Format, _Module, {none,_CompilerOpts}, _Opts) ->
+ {error, missing};
+debug_info(erlang_v1, _Module, {AbstrCode,_CompilerOpts}, _Opts) ->
+ {ok, AbstrCode};
+debug_info(core_v1, _Module, {AbstrCode,CompilerOpts}, Opts) ->
+ CoreOpts = add_core_returns(delete_reports(CompilerOpts ++ Opts)),
+ try compile:noenv_forms(AbstrCode, CoreOpts) of
+ {ok, _, Core, _} -> {ok, Core};
+ _What -> {error, failed_conversion}
+ catch
+ error:_ -> {error, failed_conversion}
+ end;
+debug_info(_, _, _, _) ->
+ {error, unknown_format}.
+
+delete_reports(Opts) ->
+ [Opt || Opt <- Opts, not is_report_option(Opt)].
+
+is_report_option(report) -> true;
+is_report_option(report_errors) -> true;
+is_report_option(report_warnings) -> true;
+is_report_option(_) -> false.
+
+add_core_returns(Opts) ->
+ [to_core, return_errors, return_warnings] ++ Opts.
diff --git a/lib/stdlib/src/erl_internal.erl b/lib/stdlib/src/erl_internal.erl
index 006e7946af..9a1b17fdb7 100644
--- a/lib/stdlib/src/erl_internal.erl
+++ b/lib/stdlib/src/erl_internal.erl
@@ -331,6 +331,8 @@ bif(list_to_float, 1) -> true;
bif(list_to_integer, 1) -> true;
bif(list_to_integer, 2) -> true;
bif(list_to_pid, 1) -> true;
+bif(list_to_port, 1) -> true;
+bif(list_to_ref, 1) -> true;
bif(list_to_tuple, 1) -> true;
bif(load_module, 2) -> true;
bif(make_ref, 0) -> true;
@@ -348,6 +350,7 @@ bif(nodes, 1) -> true;
bif(now, 0) -> true;
bif(open_port, 2) -> true;
bif(pid_to_list, 1) -> true;
+bif(port_to_list, 1) -> true;
bif(port_close, 1) -> true;
bif(port_command, 2) -> true;
bif(port_command, 3) -> true;
@@ -361,6 +364,7 @@ bif(process_info, 2) -> true;
bif(processes, 0) -> true;
bif(purge_module, 1) -> true;
bif(put, 2) -> true;
+bif(ref_to_list, 1) -> true;
bif(register, 2) -> true;
bif(registered, 0) -> true;
bif(round, 1) -> true;
diff --git a/lib/stdlib/src/erl_lint.erl b/lib/stdlib/src/erl_lint.erl
index 78b7a0e751..7c40058dd8 100644
--- a/lib/stdlib/src/erl_lint.erl
+++ b/lib/stdlib/src/erl_lint.erl
@@ -3883,6 +3883,10 @@ extract_sequence(4, [$t, $p | Fmt], Need) ->
extract_sequence(5, [$p|Fmt], Need);
extract_sequence(4, [$t, $P | Fmt], Need) ->
extract_sequence(5, [$P|Fmt], Need);
+extract_sequence(4, [$t, $w | Fmt], Need) ->
+ extract_sequence(5, [$w|Fmt], Need);
+extract_sequence(4, [$t, $W | Fmt], Need) ->
+ extract_sequence(5, [$W|Fmt], Need);
extract_sequence(4, [$t, C | _Fmt], _Need) ->
{error,"invalid control ~t" ++ [C]};
extract_sequence(4, [$l, $p | Fmt], Need) ->
diff --git a/lib/stdlib/src/ets.erl b/lib/stdlib/src/ets.erl
index 195a407570..894c15b0cf 100644
--- a/lib/stdlib/src/ets.erl
+++ b/lib/stdlib/src/ets.erl
@@ -54,7 +54,7 @@
| {tab(),integer(),integer(),comp_match_spec(),list(),integer()}
| {tab(),_,_,integer(),comp_match_spec(),list(),integer(),integer()}.
--opaque tid() :: integer().
+-opaque tid() :: reference().
-type match_pattern() :: atom() | tuple().
-type match_spec() :: [{match_pattern(), [_], [_]}].
diff --git a/lib/stdlib/src/gen_fsm.erl b/lib/stdlib/src/gen_fsm.erl
index 39a8fd42fe..d413da3ea1 100644
--- a/lib/stdlib/src/gen_fsm.erl
+++ b/lib/stdlib/src/gen_fsm.erl
@@ -124,6 +124,26 @@
system_replace_state/2,
format_status/2]).
+-deprecated({start, 3, next_major_release}).
+-deprecated({start, 4, next_major_release}).
+-deprecated({start_link, 3, next_major_release}).
+-deprecated({start_link, 4, next_major_release}).
+-deprecated({stop, 1, next_major_release}).
+-deprecated({stop, 3, next_major_release}).
+-deprecated({send_event, 2, next_major_release}).
+-deprecated({sync_send_event, 2, next_major_release}).
+-deprecated({sync_send_event, 3, next_major_release}).
+-deprecated({send_all_state_event, 2, next_major_release}).
+-deprecated({sync_send_all_state_event, 2, next_major_release}).
+-deprecated({sync_send_all_state_event, 3, next_major_release}).
+-deprecated({reply, 2, next_major_release}).
+-deprecated({start_timer, 2, next_major_release}).
+-deprecated({send_event_after, 2, next_major_release}).
+-deprecated({cancel_timer, 1, next_major_release}).
+-deprecated({enter_loop, 4, next_major_release}).
+-deprecated({enter_loop, 5, next_major_release}).
+-deprecated({enter_loop, 6, next_major_release}).
+
-import(error_logger, [format/2]).
%%% ---------------------------------------------------
diff --git a/lib/stdlib/src/gen_statem.erl b/lib/stdlib/src/gen_statem.erl
index cacc932ec4..6f566b8beb 100644
--- a/lib/stdlib/src/gen_statem.erl
+++ b/lib/stdlib/src/gen_statem.erl
@@ -78,8 +78,9 @@
-type data() :: term().
-type event_type() ::
- {'call',From :: from()} | 'cast' |
- 'info' | 'timeout' | 'state_timeout' | 'internal'.
+ {'call',From :: from()} | 'cast' | 'info' |
+ 'timeout' | {'timeout', Name :: term()} | 'state_timeout' |
+ 'internal'.
-type callback_mode_result() ::
callback_mode() | [callback_mode() | state_enter()].
@@ -88,7 +89,7 @@
-type transition_option() ::
postpone() | hibernate() |
- event_timeout() | state_timeout().
+ event_timeout() | generic_timeout() | state_timeout().
-type postpone() ::
%% If 'true' postpone the current event
%% and retry it when the state changes (=/=)
@@ -97,13 +98,17 @@
%% If 'true' hibernate the server instead of going into receive
boolean().
-type event_timeout() ::
- %% Generate a ('timeout', EventContent, ...) event after Time
+ %% Generate a ('timeout', EventContent, ...) event
%% unless some other event is delivered
- Time :: timeout().
+ Time :: timeout() | integer().
+-type generic_timeout() ::
+ %% Generate a ({'timeout',Name}, EventContent, ...) event
+ Time :: timeout() | integer().
-type state_timeout() ::
- %% Generate a ('state_timeout', EventContent, ...) event after Time
+ %% Generate a ('state_timeout', EventContent, ...) event
%% unless the state is changed
- Time :: timeout().
+ Time :: timeout() | integer().
+-type timeout_option() :: {abs,Abs :: boolean()}.
-type action() ::
%% During a state change:
@@ -137,8 +142,24 @@
(Timeout :: event_timeout()) | % {timeout,Timeout}
{'timeout', % Set the event_timeout option
Time :: event_timeout(), EventContent :: term()} |
+ {'timeout', % Set the event_timeout option
+ Time :: event_timeout(),
+ EventContent :: term(),
+ Options :: (timeout_option() | [timeout_option()])} |
+ %%
+ {{'timeout', Name :: term()}, % Set the generic_timeout option
+ Time :: generic_timeout(), EventContent :: term()} |
+ {{'timeout', Name :: term()}, % Set the generic_timeout option
+ Time :: generic_timeout(),
+ EventContent :: term(),
+ Options :: (timeout_option() | [timeout_option()])} |
+ %%
{'state_timeout', % Set the state_timeout option
Time :: state_timeout(), EventContent :: term()} |
+ {'state_timeout', % Set the state_timeout option
+ Time :: state_timeout(),
+ EventContent :: term(),
+ Options :: (timeout_option() | [timeout_option()])} |
%%
reply_action().
-type reply_action() ::
@@ -287,8 +308,7 @@
StatusOption :: 'normal' | 'terminate'.
-optional_callbacks(
- [init/1, % One may use enter_loop/5,6,7 instead
- format_status/2, % Has got a default implementation
+ [format_status/2, % Has got a default implementation
terminate/3, % Has got a default implementation
code_change/4, % Only needed by advanced soft upgrade
%%
@@ -303,37 +323,26 @@
%% Type validation functions
callback_mode(CallbackMode) ->
case CallbackMode of
- state_functions ->
- true;
- handle_event_function ->
- true;
- _ ->
- false
+ state_functions -> true;
+ handle_event_function -> true;
+ _ -> false
end.
%%
-from({Pid,_}) when is_pid(Pid) ->
- true;
-from(_) ->
- false.
+from({Pid,_}) when is_pid(Pid) -> true;
+from(_) -> false.
%%
event_type({call,From}) ->
from(From);
event_type(Type) ->
case Type of
- {call,From} ->
- from(From);
- cast ->
- true;
- info ->
- true;
- timeout ->
- true;
- state_timeout ->
- true;
- internal ->
- true;
- _ ->
- false
+ {call,From} -> from(From);
+ cast -> true;
+ info -> true;
+ timeout -> true;
+ state_timeout -> true;
+ internal -> true;
+ {timeout,_} -> true;
+ _ -> false
end.
@@ -1313,7 +1322,7 @@ parse_enter_actions(Debug, S, State, Actions, Hibernate, TimeoutsR) ->
parse_actions(Debug, S, State, Actions) ->
Hibernate = false,
- TimeoutsR = [{timeout,infinity,infinity}], %% Will cancel event timer
+ TimeoutsR = [infinity], %% Will cancel event timer
Postpone = false,
NextEventsR = [],
parse_actions(
@@ -1379,7 +1388,11 @@ parse_actions(
?STACKTRACE()}
end;
%%
- {state_timeout,_,_} = Timeout ->
+ {{timeout,_},_,_} = Timeout ->
+ parse_actions_timeout(
+ Debug, S, State, Actions,
+ Hibernate, TimeoutsR, Postpone, NextEventsR, Timeout);
+ {{timeout,_},_,_,_} = Timeout ->
parse_actions_timeout(
Debug, S, State, Actions,
Hibernate, TimeoutsR, Postpone, NextEventsR, Timeout);
@@ -1387,6 +1400,18 @@ parse_actions(
parse_actions_timeout(
Debug, S, State, Actions,
Hibernate, TimeoutsR, Postpone, NextEventsR, Timeout);
+ {timeout,_,_,_} = Timeout ->
+ parse_actions_timeout(
+ Debug, S, State, Actions,
+ Hibernate, TimeoutsR, Postpone, NextEventsR, Timeout);
+ {state_timeout,_,_} = Timeout ->
+ parse_actions_timeout(
+ Debug, S, State, Actions,
+ Hibernate, TimeoutsR, Postpone, NextEventsR, Timeout);
+ {state_timeout,_,_,_} = Timeout ->
+ parse_actions_timeout(
+ Debug, S, State, Actions,
+ Hibernate, TimeoutsR, Postpone, NextEventsR, Timeout);
Time ->
parse_actions_timeout(
Debug, S, State, Actions,
@@ -1396,26 +1421,64 @@ parse_actions(
parse_actions_timeout(
Debug, S, State, Actions,
Hibernate, TimeoutsR, Postpone, NextEventsR, Timeout) ->
- Time =
- case Timeout of
- {_,T,_} -> T;
- T -> T
- end,
- case validate_time(Time) of
- true ->
- parse_actions(
- Debug, S, State, Actions,
- Hibernate, [Timeout|TimeoutsR],
- Postpone, NextEventsR);
- false ->
- {error,
- {bad_action_from_state_function,Timeout},
- ?STACKTRACE()}
+ case Timeout of
+ {TimerType,Time,TimerMsg,TimerOpts} ->
+ case validate_timer_args(Time, listify(TimerOpts)) of
+ true ->
+ parse_actions(
+ Debug, S, State, Actions,
+ Hibernate, [Timeout|TimeoutsR],
+ Postpone, NextEventsR);
+ false ->
+ NewTimeout = {TimerType,Time,TimerMsg},
+ parse_actions(
+ Debug, S, State, Actions,
+ Hibernate, [NewTimeout|TimeoutsR],
+ Postpone, NextEventsR);
+ error ->
+ {error,
+ {bad_action_from_state_function,Timeout},
+ ?STACKTRACE()}
+ end;
+ {_,Time,_} ->
+ case validate_timer_args(Time, []) of
+ false ->
+ parse_actions(
+ Debug, S, State, Actions,
+ Hibernate, [Timeout|TimeoutsR],
+ Postpone, NextEventsR);
+ error ->
+ {error,
+ {bad_action_from_state_function,Timeout},
+ ?STACKTRACE()}
+ end;
+ Time ->
+ case validate_timer_args(Time, []) of
+ false ->
+ parse_actions(
+ Debug, S, State, Actions,
+ Hibernate, [Timeout|TimeoutsR],
+ Postpone, NextEventsR);
+ error ->
+ {error,
+ {bad_action_from_state_function,Timeout},
+ ?STACKTRACE()}
+ end
end.
-validate_time(Time) when is_integer(Time), Time >= 0 -> true;
-validate_time(infinity) -> true;
-validate_time(_) -> false.
+validate_timer_args(Time, Opts) ->
+ validate_timer_args(Time, Opts, false).
+%%
+validate_timer_args(Time, [], true) when is_integer(Time) ->
+ true;
+validate_timer_args(Time, [], false) when is_integer(Time), Time >= 0 ->
+ false;
+validate_timer_args(infinity, [], Abs) ->
+ Abs;
+validate_timer_args(Time, [{abs,Abs}|Opts], _) when is_boolean(Abs) ->
+ validate_timer_args(Time, Opts, Abs);
+validate_timer_args(_, [_|_], _) ->
+ error.
%% Stop and start timers as well as create timeout zero events
%% and pending event timer
@@ -1431,22 +1494,39 @@ parse_timers(
TimerRefs, TimerTypes, CancelTimers, [Timeout|TimeoutsR],
Seen, TimeoutEvents) ->
case Timeout of
+ {TimerType,Time,TimerMsg,TimerOpts} ->
+ %% Absolute timer
+ parse_timers(
+ TimerRefs, TimerTypes, CancelTimers, TimeoutsR,
+ Seen, TimeoutEvents,
+ TimerType, Time, TimerMsg, listify(TimerOpts));
+ %% Relative timers below
+ {TimerType,0,TimerMsg} ->
+ parse_timers(
+ TimerRefs, TimerTypes, CancelTimers, TimeoutsR,
+ Seen, TimeoutEvents,
+ TimerType, zero, TimerMsg, []);
{TimerType,Time,TimerMsg} ->
parse_timers(
- TimerRefs, TimerTypes, CancelTimers, TimeoutsR,
- Seen, TimeoutEvents,
- TimerType, Time, TimerMsg);
+ TimerRefs, TimerTypes, CancelTimers, TimeoutsR,
+ Seen, TimeoutEvents,
+ TimerType, Time, TimerMsg, []);
+ 0 ->
+ parse_timers(
+ TimerRefs, TimerTypes, CancelTimers, TimeoutsR,
+ Seen, TimeoutEvents,
+ timeout, zero, 0, []);
Time ->
parse_timers(
- TimerRefs, TimerTypes, CancelTimers, TimeoutsR,
- Seen, TimeoutEvents,
- timeout, Time, Time)
+ TimerRefs, TimerTypes, CancelTimers, TimeoutsR,
+ Seen, TimeoutEvents,
+ timeout, Time, Time, [])
end.
parse_timers(
TimerRefs, TimerTypes, CancelTimers, TimeoutsR,
Seen, TimeoutEvents,
- TimerType, Time, TimerMsg) ->
+ TimerType, Time, TimerMsg, TimerOpts) ->
case Seen of
#{TimerType := _} ->
%% Type seen before - ignore
@@ -1465,7 +1545,7 @@ parse_timers(
parse_timers(
TimerRefs, NewTimerTypes, NewCancelTimers, TimeoutsR,
NewSeen, TimeoutEvents);
- 0 ->
+ zero ->
%% Cancel any running timer
{NewTimerTypes,NewCancelTimers} =
cancel_timer_by_type(
@@ -1478,7 +1558,8 @@ parse_timers(
_ ->
%% (Re)start the timer
TimerRef =
- erlang:start_timer(Time, self(), TimerMsg),
+ erlang:start_timer(
+ Time, self(), TimerMsg, TimerOpts),
case TimerTypes of
#{TimerType := OldTimerRef} ->
%% Cancel the running timer
@@ -1492,6 +1573,8 @@ parse_timers(
NewCancelTimers, TimeoutsR,
NewSeen, TimeoutEvents);
#{} ->
+ %% Insert the new timer into
+ %% both TimerRefs and TimerTypes
parse_timers(
TimerRefs#{TimerRef => TimerType},
TimerTypes#{TimerType => TimerRef},
diff --git a/lib/stdlib/src/io_lib.erl b/lib/stdlib/src/io_lib.erl
index 28e5007e5a..5ed2f4d888 100644
--- a/lib/stdlib/src/io_lib.erl
+++ b/lib/stdlib/src/io_lib.erl
@@ -268,47 +268,61 @@ write(Term, D, false) ->
-spec write(Term, Depth) -> chars() when
Term :: term(),
+ Depth :: depth();
+ (Term, Options) -> chars() when
+ Term :: term(),
+ Options :: [Option],
+ Option :: {'depth', Depth}
+ | {'encoding', 'latin1' | 'utf8' | 'unicode'},
Depth :: depth().
-write(_Term, 0) -> "...";
-write(Term, _D) when is_integer(Term) -> integer_to_list(Term);
-write(Term, _D) when is_float(Term) -> io_lib_format:fwrite_g(Term);
-write(Atom, _D) when is_atom(Atom) -> write_atom(Atom);
-write(Term, _D) when is_port(Term) -> write_port(Term);
-write(Term, _D) when is_pid(Term) -> pid_to_list(Term);
-write(Term, _D) when is_reference(Term) -> write_ref(Term);
-write(<<_/bitstring>>=Term, D) -> write_binary(Term, D);
-write([], _D) -> "[]";
-write({}, _D) -> "{}";
-write([H|T], D) ->
+write(Term, Options) when is_list(Options) ->
+ Depth = get_option(depth, Options, -1),
+ Encoding = get_option(encoding, Options, epp:default_encoding()),
+ write1(Term, Depth, Encoding);
+write(Term, Depth) ->
+ write1(Term, Depth, latin1).
+
+write1(_Term, 0, _E) -> "...";
+write1(Term, _D, _E) when is_integer(Term) -> integer_to_list(Term);
+write1(Term, _D, _E) when is_float(Term) -> io_lib_format:fwrite_g(Term);
+write1(Atom, _D, latin1) when is_atom(Atom) -> write_atom_as_latin1(Atom);
+write1(Atom, _D, _E) when is_atom(Atom) -> write_atom(Atom);
+write1(Term, _D, _E) when is_port(Term) -> write_port(Term);
+write1(Term, _D, _E) when is_pid(Term) -> pid_to_list(Term);
+write1(Term, _D, _E) when is_reference(Term) -> write_ref(Term);
+write1(<<_/bitstring>>=Term, D, _E) -> write_binary(Term, D);
+write1([], _D, _E) -> "[]";
+write1({}, _D, _E) -> "{}";
+write1([H|T], D, E) ->
if
D =:= 1 -> "[...]";
true ->
- [$[,[write(H, D-1)|write_tail(T, D-1, $|)],$]]
+ [$[,[write1(H, D-1, E)|write_tail(T, D-1, E, $|)],$]]
end;
-write(F, _D) when is_function(F) ->
+write1(F, _D, _E) when is_function(F) ->
erlang:fun_to_list(F);
-write(Term, D) when is_map(Term) ->
- write_map(Term, D);
-write(T, D) when is_tuple(T) ->
+write1(Term, D, E) when is_map(Term) ->
+ write_map(Term, D, E);
+write1(T, D, E) when is_tuple(T) ->
if
D =:= 1 -> "{...}";
true ->
[${,
- [write(element(1, T), D-1)|
- write_tail(tl(tuple_to_list(T)), D-1, $,)],
+ [write1(element(1, T), D-1, E)|
+ write_tail(tl(tuple_to_list(T)), D-1, E, $,)],
$}]
end.
%% write_tail(List, Depth, CharacterBeforeDots)
%% Test the terminating case first as this looks better with depth.
-write_tail([], _D, _S) -> "";
-write_tail(_, 1, S) -> [S | "..."];
-write_tail([H|T], D, S) ->
- [$,,write(H, D-1)|write_tail(T, D-1, S)];
-write_tail(Other, D, S) ->
- [S,write(Other, D-1)].
+write_tail([], _D, _E, _S) -> "";
+write_tail(_, 1, _E, S) -> [S | "..."];
+write_tail([H|T], D, E, S) ->
+ [$,,write1(H, D-1, E)|write_tail(T, D-1, E, S)];
+write_tail(Other, D, E, S) ->
+ [S,write1(Other, D-1, E)].
write_port(Port) ->
erlang:port_to_list(Port).
@@ -316,17 +330,17 @@ write_port(Port) ->
write_ref(Ref) ->
erlang:ref_to_list(Ref).
-write_map(Map, D) when is_integer(D) ->
- [$#,${,write_map_body(maps:to_list(Map), D),$}].
+write_map(Map, D, E) when is_integer(D) ->
+ [$#,${,write_map_body(maps:to_list(Map), D, E),$}].
-write_map_body(_, 0) -> "...";
-write_map_body([],_) -> [];
-write_map_body([{K,V}],D) -> write_map_assoc(K,V,D);
-write_map_body([{K,V}|KVs], D) ->
- [write_map_assoc(K,V,D),$, | write_map_body(KVs,D-1)].
+write_map_body(_, 0, _E) -> "...";
+write_map_body([], _, _E) -> [];
+write_map_body([{K,V}], D, E) -> write_map_assoc(K, V, D, E);
+write_map_body([{K,V}|KVs], D, E) ->
+ [write_map_assoc(K, V, D, E),$, | write_map_body(KVs, D-1, E)].
-write_map_assoc(K,V,D) ->
- [write(K,D - 1),"=>",write(V,D-1)].
+write_map_assoc(K, V, D, E) ->
+ [write1(K, D - 1, E),"=>",write1(V, D-1, E)].
write_binary(B, D) when is_integer(D) ->
[$<,$<,write_binary_body(B, D),$>,$>].
@@ -344,6 +358,13 @@ write_binary_body(B, _D) ->
<<X:L>> = B,
[integer_to_list(X),$:,integer_to_list(L)].
+get_option(Key, TupleList, Default) ->
+ case lists:keyfind(Key, 1, TupleList) of
+ false -> Default;
+ {Key, Value} -> Value;
+ _ -> Default
+ end.
+
%%% There are two functions to write Unicode atoms:
%%% - they both escape control characters < 160;
%%% - write_atom() never escapes characters >= 160;
diff --git a/lib/stdlib/src/io_lib_format.erl b/lib/stdlib/src/io_lib_format.erl
index 3113767614..14d925bacf 100644
--- a/lib/stdlib/src/io_lib_format.erl
+++ b/lib/stdlib/src/io_lib_format.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2017. 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.
@@ -257,12 +257,12 @@ indentation([], I) -> I.
%% This is the main dispatch function for the various formatting commands.
%% Field widths and precisions have already been calculated.
-control($w, [A], F, Adj, P, Pad, _Enc, _Str, _I) ->
- term(io_lib:write(A, -1), F, Adj, P, Pad);
+control($w, [A], F, Adj, P, Pad, Enc, _Str, _I) ->
+ term(io_lib:write(A, [{depth,-1}, {encoding, Enc}]), F, Adj, P, Pad);
control($p, [A], F, Adj, P, Pad, Enc, Str, I) ->
print(A, -1, F, Adj, P, Pad, Enc, Str, I);
-control($W, [A,Depth], F, Adj, P, Pad, _Enc, _Str, _I) when is_integer(Depth) ->
- term(io_lib:write(A, Depth), F, Adj, P, Pad);
+control($W, [A,Depth], F, Adj, P, Pad, Enc, _Str, _I) when is_integer(Depth) ->
+ term(io_lib:write(A, [{depth,Depth}, {encoding, Enc}]), F, Adj, P, Pad);
control($P, [A,Depth], F, Adj, P, Pad, Enc, Str, I) when is_integer(Depth) ->
print(A, Depth, F, Adj, P, Pad, Enc, Str, I);
control($s, [A], F, Adj, P, Pad, latin1, _Str, _I) when is_atom(A) ->
diff --git a/lib/stdlib/src/io_lib_fread.erl b/lib/stdlib/src/io_lib_fread.erl
index 6a8f8f728e..983e8d4566 100644
--- a/lib/stdlib/src/io_lib_fread.erl
+++ b/lib/stdlib/src/io_lib_fread.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2017. 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.
@@ -159,8 +159,8 @@ fread_field([$t|Format], F, Sup, _Unic) ->
fread_field(Format, F, Sup, Unic) ->
{Format,F,Sup,Unic}.
-%% fread1(Format, FieldWidth, Suppress, Line, N, Results, AllFormat)
-%% fread1(Format, FieldWidth, Suppress, Line, N, Results)
+%% fread1(Format, FieldWidth, Suppress, Unicode, Line, N, Results, AllFormat)
+%% fread1(Format, FieldWidth, Suppress, Unicode, Line, N, Results)
%% The main dispatch function for the formatting commands. Done in two
%% stages so format commands that need no input can always be processed.
@@ -231,9 +231,8 @@ fread1([$s|Format], none, Sup, U, Line0, N0, Res) ->
fread1([$s|Format], F, Sup, U, Line0, N, Res) ->
{Line,Cs} = fread_chars(Line0, F, U),
fread_string(Cs, Sup, U, Format, Line, N+F, Res);
-%% XXX:PaN Atoms still only latin1...
-fread1([$a|Format], none, Sup, false, Line0, N0, Res) ->
- {Line,N,Cs} = fread_string_cs(Line0, N0, false),
+fread1([$a|Format], none, Sup, U, Line0, N0, Res) ->
+ {Line,N,Cs} = fread_string_cs(Line0, N0, U),
fread_atom(Cs, Sup, Format, Line, N, Res);
fread1([$a|Format], F, Sup, false, Line0, N, Res) ->
{Line,Cs} = fread_chars(Line0, F, false),
diff --git a/lib/stdlib/src/lib.erl b/lib/stdlib/src/lib.erl
index 56654097d9..aa6797bce6 100644
--- a/lib/stdlib/src/lib.erl
+++ b/lib/stdlib/src/lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2017. 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.
@@ -22,6 +22,9 @@
-export([flush_receive/0, error_message/2, progname/0, nonl/1, send/2,
sendw/2, eval_str/1]).
+-export([extended_parse_exprs/1, extended_parse_term/1,
+ subst_values_for_vars/2]).
+
-export([format_exception/6, format_exception/7,
format_stacktrace/4, format_stacktrace/5,
format_call/4, format_call/5, format_fun/1]).
@@ -127,6 +130,224 @@ all_white([$\t|T]) -> all_white(T);
all_white([]) -> true;
all_white(_) -> false.
+%% `Tokens' is assumed to have been scanned with the 'text' option.
+%% The annotations of the returned expressions are locations.
+%%
+%% Can handle pids, ports, references, and external funs ("items").
+%% Known items are represented by variables in the erl_parse tree, and
+%% the items themselves are stored in the returned bindings.
+
+-spec extended_parse_exprs(Tokens) ->
+ {'ok', ExprList, Bindings} | {'error', ErrorInfo} when
+ Tokens :: [erl_scan:token()],
+ ExprList :: [erl_parse:abstract_expr()],
+ Bindings :: erl_eval:binding_struct(),
+ ErrorInfo :: erl_parse:error_info().
+
+extended_parse_exprs(Tokens) ->
+ Ts = tokens_fixup(Tokens),
+ case erl_parse:parse_exprs(Ts) of
+ {ok, Exprs0} ->
+ {Exprs, Bs} = expr_fixup(Exprs0),
+ {ok, reset_expr_anno(Exprs), Bs};
+ _ErrorInfo ->
+ erl_parse:parse_exprs(reset_token_anno(Ts))
+ end.
+
+tokens_fixup([]) -> [];
+tokens_fixup([T|Ts]=Ts0) ->
+ try token_fixup(Ts0) of
+ {NewT, NewTs} ->
+ [NewT|tokens_fixup(NewTs)]
+ catch
+ _:_ ->
+ [T|tokens_fixup(Ts)]
+ end.
+
+token_fixup(Ts) ->
+ {AnnoL, NewTs, FixupTag} = unscannable(Ts),
+ String = lists:append([erl_anno:text(A) || A <- AnnoL]),
+ _ = (fixup_fun(FixupTag))(String),
+ NewAnno = erl_anno:set_text(fixup_text(FixupTag), hd(AnnoL)),
+ {{string, NewAnno, String}, NewTs}.
+
+unscannable([{'#', A1}, {var, A2, 'Fun'}, {'<', A3}, {atom, A4, _},
+ {'.', A5}, {float, A6, _}, {'>', A7}|Ts]) ->
+ {[A1, A2, A3, A4, A5, A6, A7], Ts, function};
+unscannable([{'#', A1}, {var, A2, 'Fun'}, {'<', A3}, {atom, A4, _},
+ {'.', A5}, {atom, A6, _}, {'.', A7}, {integer, A8, _},
+ {'>', A9}|Ts]) ->
+ {[A1, A2, A3, A4, A5, A6, A7, A8, A9], Ts, function};
+unscannable([{'<', A1}, {float, A2, _}, {'.', A3}, {integer, A4, _},
+ {'>', A5}|Ts]) ->
+ {[A1, A2, A3, A4, A5], Ts, pid};
+unscannable([{'#', A1}, {var, A2, 'Port'}, {'<', A3}, {float, A4, _},
+ {'>', A5}|Ts]) ->
+ {[A1, A2, A3, A4, A5], Ts, port};
+unscannable([{'#', A1}, {var, A2, 'Ref'}, {'<', A3}, {float, A4, _},
+ {'.', A5}, {float, A6, _}, {'>', A7}|Ts]) ->
+ {[A1, A2, A3, A4, A5, A6, A7], Ts, reference}.
+
+expr_fixup(Expr0) ->
+ {Expr, Bs, _} = expr_fixup(Expr0, erl_eval:new_bindings(), 1),
+ {Expr, Bs}.
+
+expr_fixup({string,A,S}=T, Bs0, I) ->
+ try string_fixup(A, S) of
+ Value ->
+ Var = new_var(I),
+ Bs = erl_eval:add_binding(Var, Value, Bs0),
+ {{var, A, Var}, Bs, I+1}
+ catch
+ _:_ ->
+ {T, Bs0, I}
+ end;
+expr_fixup(Tuple, Bs0, I0) when is_tuple(Tuple) ->
+ {L, Bs, I} = expr_fixup(tuple_to_list(Tuple), Bs0, I0),
+ {list_to_tuple(L), Bs, I};
+expr_fixup([E0|Es0], Bs0, I0) ->
+ {E, Bs1, I1} = expr_fixup(E0, Bs0, I0),
+ {Es, Bs, I} = expr_fixup(Es0, Bs1, I1),
+ {[E|Es], Bs, I};
+expr_fixup(T, Bs, I) ->
+ {T, Bs, I}.
+
+string_fixup(A, S) ->
+ Text = erl_anno:text(A),
+ FixupTag = fixup_tag(Text, S),
+ (fixup_fun(FixupTag))(S).
+
+new_var(I) ->
+ list_to_atom(lists:concat(['__ExtendedParseExprs_', I, '__'])).
+
+reset_token_anno(Tokens) ->
+ [setelement(2, T, (reset_anno())(element(2, T))) || T <- Tokens].
+
+reset_expr_anno(Exprs) ->
+ [erl_parse:map_anno(reset_anno(), E) || E <- Exprs].
+
+reset_anno() ->
+ fun(A) -> erl_anno:new(erl_anno:location(A)) end.
+
+fixup_fun(function) -> fun function/1;
+fixup_fun(pid) -> fun erlang:list_to_pid/1;
+fixup_fun(port) -> fun erlang:list_to_port/1;
+fixup_fun(reference) -> fun erlang:list_to_ref/1.
+
+function(S) ->
+ %% External function.
+ {ok, [_, _, _,
+ {atom, _, Module}, _,
+ {atom, _, Function}, _,
+ {integer, _, Arity}|_], _} = erl_scan:string(S),
+ erlang:make_fun(Module, Function, Arity).
+
+fixup_text(function) -> "function";
+fixup_text(pid) -> "pid";
+fixup_text(port) -> "port";
+fixup_text(reference) -> "reference".
+
+fixup_tag("function", "#"++_) -> function;
+fixup_tag("pid", "<"++_) -> pid;
+fixup_tag("port", "#"++_) -> port;
+fixup_tag("reference", "#"++_) -> reference.
+
+%%% End of extended_parse_exprs.
+
+%% `Tokens' is assumed to have been scanned with the 'text' option.
+%%
+%% Can handle pids, ports, references, and external funs.
+
+-spec extended_parse_term(Tokens) ->
+ {'ok', Term} | {'error', ErrorInfo} when
+ Tokens :: [erl_scan:token()],
+ Term :: term(),
+ ErrorInfo :: erl_parse:error_info().
+
+extended_parse_term(Tokens) ->
+ case extended_parse_exprs(Tokens) of
+ {ok, [Expr], Bindings} ->
+ try normalise(Expr, Bindings) of
+ Term ->
+ {ok, Term}
+ catch
+ _:_ ->
+ Loc = erl_anno:location(element(2, Expr)),
+ {error,{Loc,?MODULE,"bad term"}}
+ end;
+ {ok, [_,Expr|_], _Bindings} ->
+ Loc = erl_anno:location(element(2, Expr)),
+ {error,{Loc,?MODULE,"bad term"}};
+ {error, _} = Error ->
+ Error
+ end.
+
+%% From erl_parse.
+normalise({var, _, V}, Bs) ->
+ {value, Value} = erl_eval:binding(V, Bs),
+ Value;
+normalise({char,_,C}, _Bs) -> C;
+normalise({integer,_,I}, _Bs) -> I;
+normalise({float,_,F}, _Bs) -> F;
+normalise({atom,_,A}, _Bs) -> A;
+normalise({string,_,S}, _Bs) -> S;
+normalise({nil,_}, _Bs) -> [];
+normalise({bin,_,Fs}, Bs) ->
+ {value, B, _} =
+ eval_bits:expr_grp(Fs, [],
+ fun(E, _) ->
+ {value, normalise(E, Bs), []}
+ end, [], true),
+ B;
+normalise({cons,_,Head,Tail}, Bs) ->
+ [normalise(Head, Bs)|normalise(Tail, Bs)];
+normalise({tuple,_,Args}, Bs) ->
+ list_to_tuple(normalise_list(Args, Bs));
+normalise({map,_,Pairs}, Bs) ->
+ maps:from_list(lists:map(fun
+ %% only allow '=>'
+ ({map_field_assoc,_,K,V}) ->
+ {normalise(K, Bs),normalise(V, Bs)}
+ end, Pairs));
+%% Special case for unary +/-.
+normalise({op,_,'+',{char,_,I}}, _Bs) -> I;
+normalise({op,_,'+',{integer,_,I}}, _Bs) -> I;
+normalise({op,_,'+',{float,_,F}}, _Bs) -> F;
+normalise({op,_,'-',{char,_,I}}, _Bs) -> -I; %Weird, but compatible!
+normalise({op,_,'-',{integer,_,I}}, _Bs) -> -I;
+normalise({op,_,'-',{float,_,F}}, _Bs) -> -F;
+normalise({'fun',_,{function,{atom,_,M},{atom,_,F},{integer,_,A}}}, _Bs) ->
+ %% Since "#Fun<M.F.A>" is recognized, "fun M:F/A" should be too.
+ fun M:F/A.
+
+normalise_list([H|T], Bs) ->
+ [normalise(H, Bs)|normalise_list(T, Bs)];
+normalise_list([], _Bs) ->
+ [].
+
+%% To be used on ExprList and Bindings returned from extended_parse_exprs().
+%% Substitute {value, A, Item} for {var, A, ExtendedParseVar}.
+%% {value, A, Item} is a shell/erl_eval convention, and for example
+%% the linter cannot handle it.
+
+-spec subst_values_for_vars(ExprList, Bindings) -> [term()] when
+ ExprList :: [erl_parse:abstract_expr()],
+ Bindings :: erl_eval:binding_struct().
+
+subst_values_for_vars({var, A, V}=Var, Bs) ->
+ case erl_eval:binding(V, Bs) of
+ {value, Value} ->
+ {value, A, Value};
+ unbound ->
+ Var
+ end;
+subst_values_for_vars(L, Bs) when is_list(L) ->
+ [subst_values_for_vars(E, Bs) || E <- L];
+subst_values_for_vars(T, Bs) when is_tuple(T) ->
+ list_to_tuple(subst_values_for_vars(tuple_to_list(T), Bs));
+subst_values_for_vars(T, _Bs) ->
+ T.
+
%%% Formatting of exceptions, mfa:s and funs.
%% -> iolist() (no \n at end)
diff --git a/lib/stdlib/src/otp_internal.erl b/lib/stdlib/src/otp_internal.erl
index d89ff4a624..42094e3088 100644
--- a/lib/stdlib/src/otp_internal.erl
+++ b/lib/stdlib/src/otp_internal.erl
@@ -55,6 +55,55 @@ obsolete_1(erlang, now, 0) ->
obsolete_1(calendar, local_time_to_universal_time, 1) ->
{deprecated, {calendar, local_time_to_universal_time_dst, 1}};
+%% *** STDLIB added in OTP 20 ***
+
+obsolete_1(gen_fsm, start, 3) ->
+ {deprecated, {gen_statem, start, 3}};
+obsolete_1(gen_fsm, start, 4) ->
+ {deprecated, {gen_statem, start, 4}};
+
+obsolete_1(gen_fsm, start_link, 3) ->
+ {deprecated, {gen_statem, start, 3}};
+obsolete_1(gen_fsm, start_link, 4) ->
+ {deprecated, {gen_statem, start, 4}};
+
+obsolete_1(gen_fsm, stop, 1) ->
+ {deprecated, {gen_statem, stop, 1}};
+obsolete_1(gen_fsm, stop, 3) ->
+ {deprecated, {gen_statem, stop, 3}};
+
+obsolete_1(gen_fsm, enter_loop, 4) ->
+ {deprecated, {gen_statem, enter_loop, 4}};
+obsolete_1(gen_fsm, enter_loop, 5) ->
+ {deprecated, {gen_statem, enter_loop, 5}};
+obsolete_1(gen_fsm, enter_loop, 6) ->
+ {deprecated, {gen_statem, enter_loop, 6}};
+
+obsolete_1(gen_fsm, reply, 2) ->
+ {deprecated, {gen_statem, reply, 2}};
+
+obsolete_1(gen_fsm, send_event, 2) ->
+ {deprecated, {gen_statem, cast, 1}};
+obsolete_1(gen_fsm, send_all_state_event, 2) ->
+ {deprecated, {gen_statem, cast, 1}};
+
+obsolete_1(gen_fsm, sync_send_event, 2) ->
+ {deprecated, {gen_statem, call, 2}};
+obsolete_1(gen_fsm, sync_send_event, 3) ->
+ {deprecated, {gen_statem, call, 3}};
+
+obsolete_1(gen_fsm, sync_send_all_state_event, 2) ->
+ {deprecated, {gen_statem, call, 2}};
+obsolete_1(gen_fsm, sync_send_all_state_event, 3) ->
+ {deprecated, {gen_statem, call, 3}};
+
+obsolete_1(gen_fsm, start_timer, 2) ->
+ {deprecated, {erlang, start_timer, 2}};
+obsolete_1(gen_fsm, cancel_timer, 1) ->
+ {deprecated, {erlang, cancel_timer, 1}};
+obsolete_1(gen_fsm, send_event_after, 2) ->
+ {deprecated, {erlang, send_after, 2}};
+
%% *** CRYPTO added in OTP 20 ***
obsolete_1(crypto, rand_uniform, 2) ->
diff --git a/lib/stdlib/src/qlc.erl b/lib/stdlib/src/qlc.erl
index 8c4d835432..20aaa2638c 100644
--- a/lib/stdlib/src/qlc.erl
+++ b/lib/stdlib/src/qlc.erl
@@ -635,14 +635,25 @@ string_to_handle(Str, Options, Bindings) when is_list(Str) ->
badarg ->
erlang:error(badarg, [Str, Options, Bindings]);
[Unique, Cache, MaxLookup, Join, Lookup] ->
- case erl_scan:string(Str) of
+ case erl_scan:string(Str, 1, [text]) of
{ok, Tokens, _} ->
- case erl_parse:parse_exprs(Tokens) of
- {ok, [Expr]} ->
- case qlc_pt:transform_expression(Expr, Bindings) of
+ ScanRes =
+ case lib:extended_parse_exprs(Tokens) of
+ {ok, [Expr0], SBs} ->
+ {ok, Expr0, SBs};
+ {ok, _ExprList, _SBs} ->
+ erlang:error(badarg,
+ [Str, Options, Bindings]);
+ E ->
+ E
+ end,
+ case ScanRes of
+ {ok, Expr, XBs} ->
+ Bs1 = merge_binding_structs(Bindings, XBs),
+ case qlc_pt:transform_expression(Expr, Bs1) of
{ok, {call, _, _QlcQ, Handle}} ->
{value, QLC_lc, _} =
- erl_eval:exprs(Handle, Bindings),
+ erl_eval:exprs(Handle, Bs1),
O = #qlc_opt{unique = Unique,
cache = Cache,
max_lookup = MaxLookup,
@@ -652,8 +663,6 @@ string_to_handle(Str, Options, Bindings) when is_list(Str) ->
{not_ok, [{error, Error} | _]} ->
error(Error)
end;
- {ok, _ExprList} ->
- erlang:error(badarg, [Str, Options, Bindings]);
{error, ErrorInfo} ->
error(ErrorInfo)
end;
@@ -770,6 +779,10 @@ all_selections([{I,Cs} | ICs]) ->
%%% Local functions
%%%
+merge_binding_structs(Bs1, Bs2) ->
+ lists:foldl(fun({N, V}, Bs) -> erl_eval:add_binding(N, V, Bs)
+ end, Bs1, erl_eval:bindings(Bs2)).
+
aux_name1(Name, N, AllNames) ->
SN = name_suffix(Name, N),
case sets:is_element(SN, AllNames) of
@@ -1180,9 +1193,12 @@ abstract1({table, {M, F, As0}}, _NElements, _Depth, Anno)
abstract1({table, TableDesc}, _NElements, _Depth, _A) ->
case io_lib:deep_char_list(TableDesc) of
true ->
- {ok, Tokens, _} = erl_scan:string(lists:flatten(TableDesc++".")),
- {ok, [Expr]} = erl_parse:parse_exprs(Tokens),
- Expr;
+ {ok, Tokens, _} =
+ erl_scan:string(lists:flatten(TableDesc++"."), 1, [text]),
+ {ok, Es, Bs} =
+ lib:extended_parse_exprs(Tokens),
+ [Expr] = lib:subst_values_for_vars(Es, Bs),
+ special(Expr);
false -> % abstract expression
TableDesc
end;
@@ -1210,6 +1226,15 @@ abstract1({list, L}, NElements, Depth, _A) when NElements =:= infinity;
abstract1({list, L}, NElements, Depth, _A) ->
abstract_term(depth(lists:sublist(L, NElements), Depth) ++ '...', 1).
+special({value, _, Thing}) ->
+ abstract_term(Thing);
+special(Tuple) when is_tuple(Tuple) ->
+ list_to_tuple(special(tuple_to_list(Tuple)));
+special([E|Es]) ->
+ [special(E)|special(Es)];
+special(Expr) ->
+ Expr.
+
depth(List, infinity) ->
List;
depth(List, Depth) ->
diff --git a/lib/stdlib/src/rand.erl b/lib/stdlib/src/rand.erl
index ab9731180f..7a8a5e6d4a 100644
--- a/lib/stdlib/src/rand.erl
+++ b/lib/stdlib/src/rand.erl
@@ -265,7 +265,7 @@ seed_s(Alg0, S0 = {_, _, _}) ->
%%% uniform/0, uniform/1, uniform_s/1, uniform_s/2 are all
%%% uniformly distributed random numbers.
-%% uniform/0: returns a random float X where 0.0 < X < 1.0,
+%% uniform/0: returns a random float X where 0.0 =< X < 1.0,
%% updating the state in the process dictionary.
-spec uniform() -> X :: float().
@@ -285,7 +285,7 @@ uniform(N) ->
X.
%% uniform_s/1: given a state, uniform_s/1
-%% returns a random float X where 0.0 < X < 1.0,
+%% returns a random float X where 0.0 =< X < 1.0,
%% and a new state.
-spec uniform_s(State :: state()) -> {X :: float(), NewState :: state()}.
@@ -742,20 +742,20 @@ exrop_uniform(Range, {Alg, R}) ->
MaxMinusRange = ?BIT(58) - Range,
?uniform_range(Range, Alg, R1, V, MaxMinusRange, I).
-%% Split a 116 bit constant into two '1'++58 bit words,
-%% the top '1' marks the top of the word
+%% Split a 116 bit constant into two 58 bit words,
+%% a top '1' marks the end of the low word.
-define(
JUMP_116(Jump),
- [?BIT(58) bor ?MASK(58, (Jump)),?BIT(58) bor ((Jump) bsr 58)]).
+ [?BIT(58) bor ?MASK(58, (Jump)),(Jump) bsr 58]).
%%
exrop_jump({Alg,S}) ->
[J|Js] = ?JUMP_116(16#9863200f83fcd4a11293241fcb12a),
{Alg, exrop_jump(S, 0, 0, J, Js)}.
%%
-dialyzer({no_improper_lists, exrop_jump/5}).
-exrop_jump(_S, S0, S1, 1, []) -> % End of jump constant
+exrop_jump(_S, S0, S1, 0, []) -> % End of jump constant
[S0|S1];
-exrop_jump(S, S0, S1, 1, [J|Js]) -> % End of the word
+exrop_jump(S, S0, S1, 1, [J|Js]) -> % End of word
exrop_jump(S, S0, S1, J, Js);
exrop_jump([S__0|S__1] = _S, S0, S1, J, Js) ->
case ?MASK(1, J) of
diff --git a/lib/stdlib/src/shell.erl b/lib/stdlib/src/shell.erl
index 394f4f2fa4..76a2789406 100644
--- a/lib/stdlib/src/shell.erl
+++ b/lib/stdlib/src/shell.erl
@@ -229,8 +229,9 @@ server_loop(N0, Eval_0, Bs00, RT, Ds00, History0, Results0) ->
{Eval_1,Bs0,Ds0,Prompt} = prompt(N, Eval_0, Bs00, RT, Ds00),
{Res,Eval0} = get_command(Prompt, Eval_1, Bs0, RT, Ds0),
case Res of
- {ok,Es0} ->
- case expand_hist(Es0, N) of
+ {ok,Es0,XBs} ->
+ Es1 = lib:subst_values_for_vars(Es0, XBs),
+ case expand_hist(Es1, N) of
{ok,Es} ->
{V,Eval,Bs,Ds} = shell_cmd(Es, Eval0, Bs0, RT, Ds0, cmd),
{History,Results} = check_and_get_history_and_results(),
@@ -276,10 +277,10 @@ get_command(Prompt, Eval, Bs, RT, Ds) ->
fun() ->
exit(
case
- io:scan_erl_exprs(group_leader(), Prompt, 1)
+ io:scan_erl_exprs(group_leader(), Prompt, 1, [text])
of
{ok,Toks,_EndPos} ->
- erl_parse:parse_exprs(Toks);
+ lib:extended_parse_exprs(Toks);
{eof,_EndPos} ->
eof;
{error,ErrorInfo,_EndPos} ->
@@ -349,16 +350,10 @@ default_prompt(N) ->
%% Don't bother flattening the list irrespective of what the
%% I/O-protocol states.
case is_alive() of
- true -> io_lib:format(<<"(~ts)~w> ">>, [node_string(), N]);
+ true -> io_lib:format(<<"(~s)~w> ">>, [node(), N]);
false -> io_lib:format(<<"~w> ">>, [N])
end.
-node_string() ->
- case encoding() of
- latin1 -> io_lib:write_atom_as_latin1(node());
- _ -> io_lib:write_atom(node())
- end.
-
%% expand_hist(Expressions, CommandNumber)
%% Preprocess the expression list replacing all history list commands
%% with their expansions.
diff --git a/lib/stdlib/src/stdlib.app.src b/lib/stdlib/src/stdlib.app.src
index c8900d74e8..d56f27953f 100644
--- a/lib/stdlib/src/stdlib.app.src
+++ b/lib/stdlib/src/stdlib.app.src
@@ -39,6 +39,7 @@
edlin_expand,
epp,
eval_bits,
+ erl_abstract_code,
erl_anno,
erl_bits,
erl_compile,
diff --git a/lib/stdlib/test/beam_lib_SUITE.erl b/lib/stdlib/test/beam_lib_SUITE.erl
index 1baf7d0a94..93d51d17b3 100644
--- a/lib/stdlib/test/beam_lib_SUITE.erl
+++ b/lib/stdlib/test/beam_lib_SUITE.erl
@@ -85,6 +85,8 @@ normal(Conf) when is_list(Conf) ->
do_normal(Source, PrivDir, BeamFile, [no_utf8_atoms]),
{ok,_} = compile:file(Source, [{outdir,PrivDir}, no_debug_info]),
+ {ok, {simple, [{debug_info, {debug_info_v1, erl_abstract_code, {none, _}}}]}} =
+ beam_lib:chunks(BeamFile, [debug_info]),
{ok, {simple, [{abstract_code, no_abstract_code}]}} =
beam_lib:chunks(BeamFile, [abstract_code]),
@@ -130,8 +132,10 @@ do_normal(BeamFile, Opts) ->
{ok, {simple, [{labeled_locals, _LLocals}]}} =
beam_lib:chunks(BeamFile, [labeled_locals]),
{ok, {simple, [_Vsn]}} = beam_lib:version(BeamFile),
- {ok, {simple, [{abstract_code, _}]}} =
+ {ok, {simple, [{abstract_code, {_, _}}]}} =
beam_lib:chunks(BeamFile, [abstract_code]),
+ {ok, {simple, [{debug_info, {debug_info_v1, erl_abstract_code, _}}]}} =
+ beam_lib:chunks(BeamFile, [debug_info]),
%% Test reading optional chunks.
All = ["Atom", "Code", "StrT", "ImpT", "ExpT", "FunT", "LitT", "AtU8"],
@@ -197,11 +201,11 @@ error(Conf) when is_list(Conf) ->
LastChunk = last_chunk(Binary),
verify(chunk_too_big, beam_lib:chunks(Binary1, [LastChunk])),
Chunks = chunk_info(Binary),
- {value, {_, AbstractStart, _}} = lists:keysearch("Abst", 1, Chunks),
- {Binary2, _} = split_binary(Binary, AbstractStart),
- verify(chunk_too_big, beam_lib:chunks(Binary2, ["Abst"])),
- {Binary3, _} = split_binary(Binary, AbstractStart-4),
- verify(invalid_beam_file, beam_lib:chunks(Binary3, ["Abst"])),
+ {value, {_, DebugInfoStart, _}} = lists:keysearch("Dbgi", 1, Chunks),
+ {Binary2, _} = split_binary(Binary, DebugInfoStart),
+ verify(chunk_too_big, beam_lib:chunks(Binary2, ["Dbgi"])),
+ {Binary3, _} = split_binary(Binary, DebugInfoStart-4),
+ verify(invalid_beam_file, beam_lib:chunks(Binary3, ["Dbgi"])),
%% Instead of the 5:32 field below, there used to be control characters
%% (including zero bytes) directly in the string. Because inferior programs
@@ -228,7 +232,7 @@ do_error(BeamFile, ACopy) ->
Chunks = chunk_info(BeamFile),
{value, {_, AtomStart, _}} = lists:keysearch("AtU8", 1, Chunks),
{value, {_, ImportStart, _}} = lists:keysearch("ImpT", 1, Chunks),
- {value, {_, AbstractStart, _}} = lists:keysearch("Abst", 1, Chunks),
+ {value, {_, DebugInfoStart, _}} = lists:keysearch("Dbgi", 1, Chunks),
{value, {_, AttributesStart, _}} =
lists:keysearch("Attr", 1, Chunks),
{value, {_, CompileInfoStart, _}} =
@@ -238,8 +242,8 @@ do_error(BeamFile, ACopy) ->
verify(invalid_chunk, beam_lib:chunks(BF2, [imports])),
BF3 = set_byte(ACopy, BeamFile, AtomStart-6, 17),
verify(missing_chunk, beam_lib:chunks(BF3, [imports])),
- BF4 = set_byte(ACopy, BeamFile, AbstractStart+10, 17),
- verify(invalid_chunk, beam_lib:chunks(BF4, [abstract_code])),
+ BF4 = set_byte(ACopy, BeamFile, DebugInfoStart+10, 17),
+ verify(invalid_chunk, beam_lib:chunks(BF4, [debug_info])),
BF5 = set_byte(ACopy, BeamFile, AttributesStart+8, 17),
verify(invalid_chunk, beam_lib:chunks(BF5, [attributes])),
@@ -550,11 +554,11 @@ encrypted_abstr_1(Conf) ->
ok.
do_encrypted_abstr(Beam, Key) ->
- verify(key_missing_or_invalid, beam_lib:chunks(Beam, [abstract_code])),
+ verify(key_missing_or_invalid, beam_lib:chunks(Beam, [debug_info])),
- %% The raw chunk "Abst" can still be read even without a key.
- {ok,{simple,[{"Abst",Abst}]}} = beam_lib:chunks(Beam, ["Abst"]),
- <<0:8,8:8,"des3_cbc",_/binary>> = Abst,
+ %% The raw chunk "Dbgi" can still be read even without a key.
+ {ok,{simple,[{"Dbgi",Dbgi}]}} = beam_lib:chunks(Beam, ["Dbgi"]),
+ <<0:8,8:8,"des3_cbc",_/binary>> = Dbgi,
%% Try som invalid funs.
bad_fun(badfun, fun() -> ok end),
@@ -585,7 +589,7 @@ do_encrypted_abstr(Beam, Key) ->
{ok,_} = beam_lib:clear_crypto_key_fun(),
ok = beam_lib:crypto_key_fun(simple_crypto_fun(Key)),
verify_abstract(Beam),
- {ok,{simple,[{"Abst",Abst}]}} = beam_lib:chunks(Beam, ["Abst"]),
+ {ok,{simple,[{"Dbgi",Dbgi}]}} = beam_lib:chunks(Beam, ["Dbgi"]),
%% Installing a new key fun is not possible without clearing the old.
verify(exists, beam_lib:crypto_key_fun(ets_crypto_fun(Key))),
@@ -594,7 +598,7 @@ do_encrypted_abstr(Beam, Key) ->
{ok,_} = beam_lib:clear_crypto_key_fun(),
ok = beam_lib:crypto_key_fun(ets_crypto_fun(Key)),
verify_abstract(Beam),
- {ok,{simple,[{"Abst",Abst}]}} = beam_lib:chunks(Beam, ["Abst"]),
+ {ok,{simple,[{"Dbgi",Dbgi}]}} = beam_lib:chunks(Beam, ["Dbgi"]),
{ok,cleared} = beam_lib:clear_crypto_key_fun(),
@@ -617,10 +621,10 @@ bad_fun(F) ->
bad_fun(S, F) ->
verify(S, beam_lib:crypto_key_fun(F)).
-
verify_abstract(Beam) ->
- {ok,{simple,[Chunk]}} = beam_lib:chunks(Beam, [abstract_code]),
- {abstract_code,{raw_abstract_v1,_}} = Chunk.
+ {ok,{simple,[Abst, Dbgi]}} = beam_lib:chunks(Beam, [abstract_code, debug_info]),
+ {abstract_code,{raw_abstract_v1,_}} = Abst,
+ {debug_info,{debug_info_v1,erl_abstract_code,_}} = Dbgi.
simple_crypto_fun(Key) ->
fun(init) -> ok;
diff --git a/lib/stdlib/test/erl_internal_SUITE.erl b/lib/stdlib/test/erl_internal_SUITE.erl
index 099f21f905..789a9d4363 100644
--- a/lib/stdlib/test/erl_internal_SUITE.erl
+++ b/lib/stdlib/test/erl_internal_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2017. 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.
@@ -60,7 +60,7 @@ end_per_testcase(_Case, _Config) ->
%% Check that the behaviour callbacks are correctly defined.
behav(_) ->
Modules = [application, gen_server, gen_fsm, gen_event,
- supervisor_bridge, supervisor],
+ gen_statem, supervisor_bridge, supervisor],
lists:foreach(fun check_behav/1, Modules).
check_behav(Module) ->
@@ -89,6 +89,10 @@ callbacks(gen_event) ->
[{init,1}, {handle_event,2}, {handle_call,2},
{handle_info,2}, {terminate,2}, {code_change,3},
{format_status,2}];
+callbacks(gen_statem) ->
+ [{init, 1}, {callback_mode, 0}, {state_name, 3},
+ {handle_event, 4}, {terminate, 3}, {code_change, 4},
+ {format_status, 2}];
callbacks(supervisor_bridge) ->
[{init,1}, {terminate,2}];
callbacks(supervisor) ->
@@ -102,6 +106,9 @@ optional_callbacks(gen_fsm) ->
[{handle_info, 3}, {terminate, 3}, {code_change, 4}, {format_status, 2}];
optional_callbacks(gen_event) ->
[{handle_info, 2}, {terminate, 2}, {code_change, 3}, {format_status, 2}];
+optional_callbacks(gen_statem) ->
+ [{state_name, 3}, {handle_event, 4},
+ {terminate, 3}, {code_change, 4}, {format_status, 2}];
optional_callbacks(supervisor_bridge) ->
[];
optional_callbacks(supervisor) ->
diff --git a/lib/stdlib/test/gen_statem_SUITE.erl b/lib/stdlib/test/gen_statem_SUITE.erl
index ac27c9fc79..05934b3953 100644
--- a/lib/stdlib/test/gen_statem_SUITE.erl
+++ b/lib/stdlib/test/gen_statem_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2016. All Rights Reserved.
+%% Copyright Ericsson AB 2016-2017. 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.
@@ -38,9 +38,10 @@ all() ->
{group, abnormal},
{group, abnormal_handle_event},
shutdown, stop_and_reply, state_enter, event_order,
- state_timeout, event_types, code_change,
+ state_timeout, event_types, generic_timers, code_change,
{group, sys},
- hibernate, enter_loop].
+ hibernate, enter_loop, {group, undef_callbacks},
+ undef_in_terminate].
groups() ->
[{start, [], tcs(start)},
@@ -50,7 +51,8 @@ groups() ->
{abnormal, [], tcs(abnormal)},
{abnormal_handle_event, [], tcs(abnormal)},
{sys, [], tcs(sys)},
- {sys_handle_event, [], tcs(sys)}].
+ {sys_handle_event, [], tcs(sys)},
+ {undef_callbacks, [], tcs(undef_callbacks)}].
tcs(start) ->
[start1, start2, start3, start4, start5, start6, start7,
@@ -62,8 +64,9 @@ tcs(abnormal) ->
tcs(sys) ->
[sys1, call_format_status,
error_format_status, terminate_crash_format,
- get_state, replace_state].
-
+ get_state, replace_state];
+tcs(undef_callbacks) ->
+ [undef_code_change, undef_terminate1, undef_terminate2].
init_per_suite(Config) ->
Config.
@@ -77,6 +80,11 @@ init_per_group(GroupName, Config)
GroupName =:= abnormal_handle_event;
GroupName =:= sys_handle_event ->
[{callback_mode,handle_event_function}|Config];
+init_per_group(undef_callbacks, Config) ->
+ DataDir = ?config(data_dir, Config),
+ StatemPath = filename:join(DataDir, "oc_statem.erl"),
+ {ok, oc_statem} = compile:file(StatemPath),
+ Config;
init_per_group(_GroupName, Config) ->
Config.
@@ -834,6 +842,7 @@ event_types(_Config) ->
{next_event,timeout,3},
{next_event,info,4},
{next_event,cast,5},
+ {next_event,{timeout,6}, 6},
{next_event,Call,Req}]}
end,
state1 =>
@@ -857,6 +866,10 @@ event_types(_Config) ->
{next_state, state6, undefined}
end,
state6 =>
+ fun ({timeout,6}, 6, undefined) ->
+ {next_state, state7, undefined}
+ end,
+ state7 =>
fun ({call,From}, stop, undefined) ->
{stop_and_reply, shutdown,
[{reply,From,stopped}]}
@@ -884,6 +897,69 @@ event_types(_Config) ->
+generic_timers(_Config) ->
+ process_flag(trap_exit, true),
+
+ Machine =
+ %% Abusing the internal format of From...
+ #{init =>
+ fun () ->
+ {ok, start, undefined}
+ end,
+ start =>
+ fun ({call,_} = Call, Req, undefined) ->
+ {next_state, state1, undefined,
+ [{{timeout,a},1500,1},
+ {state_timeout,1500,1},
+ {{timeout,b},1000,1},
+ {next_event,Call,Req}]}
+ end,
+ state1 =>
+ fun ({call,_} = Call, Req, undefined) ->
+ T = erlang:monotonic_time(millisecond) + 500,
+ {next_state, state2, undefined,
+ [{{timeout,c},T,2,{abs,true}},
+ {{timeout,d},0,2,[{abs,false}]},
+ {timeout,0,2},
+ {{timeout,b},infinity,2},
+ {{timeout,a},1000,{Call,Req}}]}
+ end,
+ state2 =>
+ fun ({timeout,d}, 2, undefined) ->
+ {next_state, state3, undefined}
+ end,
+ state3 =>
+ fun ({timeout,c}, 2, undefined) ->
+ {next_state, state4, undefined}
+ end,
+ state4 =>
+ fun ({timeout,a}, {{call,From},stop}, undefined) ->
+ {stop_and_reply, shutdown,
+ [{reply,From,stopped}]}
+ end},
+ {ok,STM} =
+ gen_statem:start_link(
+ ?MODULE, {map_statem,Machine,[]}, [{debug,[trace]}]),
+
+ stopped = gen_statem:call(STM, stop),
+ receive
+ {'EXIT',STM,shutdown} ->
+ ok
+ after 500 ->
+ ct:fail(did_not_stop)
+ end,
+
+ {noproc,_} =
+ ?EXPECT_FAILURE(gen_statem:call(STM, hej), Reason),
+ case flush() of
+ [] ->
+ ok;
+ Other2 ->
+ ct:fail({unexpected,Other2})
+ end.
+
+
+
sys1(Config) ->
{ok,Pid} = gen_statem:start(?MODULE, start_arg(Config, []), []),
{status, Pid, {module,gen_statem}, _} = sys:get_status(Pid),
@@ -1393,6 +1469,51 @@ enter_loop(Reg1, Reg2) ->
gen_statem:enter_loop(?MODULE, [], state0, [])
end.
+undef_code_change(_Config) ->
+ {ok, Statem} = gen_statem:start(oc_statem, [], []),
+ {error, {'EXIT',
+ {undef, [{oc_statem, code_change, [_, _, _, _], _}|_]}}}
+ = fake_upgrade(Statem, oc_statem).
+
+fake_upgrade(Pid, Mod) ->
+ sys:suspend(Pid),
+ sys:replace_state(Pid, fun(State) -> {new, State} end),
+ Ret = sys:change_code(Pid, Mod, old_vsn, []),
+ ok = sys:resume(Pid),
+ Ret.
+
+undef_terminate1(_Config) ->
+ {ok, Statem} = gen_statem:start(oc_statem, [], []),
+ MRef = monitor(process, Statem),
+ ok = gen_statem:stop(Statem),
+ verify_down(Statem, MRef, normal),
+ ok.
+
+undef_terminate2(_Config) ->
+ Reason = {error, test},
+ {ok, Statem} = oc_statem:start(),
+ MRef = monitor(process, Statem),
+ ok = gen_statem:stop(Statem, Reason, infinity),
+ verify_down(Statem, MRef, Reason).
+
+undef_in_terminate(_Config) ->
+ Data = {undef_in_terminate, {?MODULE, terminate}},
+ {ok, Statem} = gen_statem:start(?MODULE, {data, Data}, []),
+ try
+ gen_statem:stop(Statem),
+ ct:fail(should_crash)
+ catch
+ exit:{undef, [{?MODULE, terminate, _, _}|_]} ->
+ ok
+ end.
+
+verify_down(Statem, MRef, Reason) ->
+ receive
+ {'DOWN', MRef, process, Statem, Reason} ->
+ ok
+ after 5000 ->
+ ct:fail(default_terminate_failed)
+ end.
%% Test the order for multiple {next_event,T,C}
next_events(Config) ->
@@ -1571,6 +1692,9 @@ callback_mode() ->
terminate(_, _State, crash_terminate) ->
exit({crash,terminate});
+terminate(_, _State, {undef_in_terminate, {Mod, Fun}}) ->
+ Mod:Fun(),
+ ok;
terminate({From,stopped}, State, _Data) ->
From ! {self(),{stopped,State}},
ok;
@@ -1597,8 +1721,9 @@ idle({call,From}, {delayed_answer,T}, Data) ->
throw({keep_state,Data})
end;
idle({call,From}, {timeout,Time}, _Data) ->
+ AbsTime = erlang:monotonic_time(millisecond) + Time,
{next_state,timeout,{From,Time},
- {timeout,Time,idle}};
+ {timeout,AbsTime,idle,[{abs,true}]}};
idle(cast, next_event, _Data) ->
{next_state,next_events,[a,b,c],
[{next_event,internal,a},
diff --git a/lib/stdlib/test/gen_statem_SUITE_data/oc_statem.erl b/lib/stdlib/test/gen_statem_SUITE_data/oc_statem.erl
new file mode 100644
index 0000000000..27c9e0718d
--- /dev/null
+++ b/lib/stdlib/test/gen_statem_SUITE_data/oc_statem.erl
@@ -0,0 +1,37 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2017. 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(oc_statem).
+
+-behaviour(gen_statem).
+
+%% API
+-export([start/0]).
+
+%% gen_statem callbacks
+-export([init/1, callback_mode/0]).
+
+start() ->
+ gen_statem:start({local, ?MODULE}, ?MODULE, [], []).
+
+init([]) ->
+ {ok, state_name, #{}}.
+
+callback_mode() ->
+ handle_event_function.
diff --git a/lib/stdlib/test/io_SUITE.erl b/lib/stdlib/test/io_SUITE.erl
index b2754e47ba..ef3f0be5d7 100644
--- a/lib/stdlib/test/io_SUITE.erl
+++ b/lib/stdlib/test/io_SUITE.erl
@@ -2348,4 +2348,28 @@ otp_14285(_Config) ->
L1 = [S || C <- Chars, S <- io_lib:write_atom(list_to_atom([C])),
not is_latin1(S)],
L1 = lists:seq(256, 512),
+
+ latin1_fmt("~w", ['кирилли́ческий атом']),
+ latin1_fmt("~w", ['\x{10FFFF}']),
+ "'кирилли́ческий атом'" = fmt("~tw", ['кирилли́ческий атом']),
+ [$',16#10FFFF,$'] = fmt("~tw", ['\x{10FFFF}']),
+
+ latin1_fmt("~W", ['кирилли́ческий атом', 13]),
+ latin1_fmt("~W", ['\x{10FFFF}', 13]),
+ "'кирилли́ческий атом'" = fmt("~tW", ['кирилли́ческий атом', 13]),
+ [$',16#10FFFF,$'] = fmt("~tW", ['\x{10FFFF}', 13]),
+
+ {ok, [an_atom],[]} = io_lib:fread("~a", "an_atom"),
+ {ok, [an_atom],[]} = io_lib:fread("~ta", "an_atom"),
+ Str = "\"ab" ++ [1089] ++ "cd\"",
+ {ok, ["\"ab"], [1089]++"cd\""} = io_lib:fread("~s", Str),
+ {ok, ['\"ab'], [1089]++"cd\""} = io_lib:fread("~a", Str),
+ {ok,[Str], []} = io_lib:fread("~ts", Str),
+ {ok,[Atom],[]} = io_lib:fread("~ta", Str),
+ Str = atom_to_list(Atom),
+
ok.
+
+latin1_fmt(Fmt, Args) ->
+ L = fmt(Fmt, Args),
+ true = lists:all(fun is_latin1/1, L).
diff --git a/lib/stdlib/test/qlc_SUITE.erl b/lib/stdlib/test/qlc_SUITE.erl
index 2b5d52287e..5e9e03e410 100644
--- a/lib/stdlib/test/qlc_SUITE.erl
+++ b/lib/stdlib/test/qlc_SUITE.erl
@@ -1240,6 +1240,17 @@ string_to_handle(Config) when is_list(Config) ->
{'EXIT', {no_lookup_to_carry_out, _}} =
(catch qlc:e(qlc:string_to_handle(Q, {lookup,true}, Bs2))),
ets:delete(Ets),
+
+ %% References can be scanned and parsed.
+ E2 = ets:new(test, [bag]),
+ Ref = make_ref(),
+ true = ets:insert(E2, [{Ref,Ref}]),
+ S2 = "[{Val1} || {Ref1, Val1} <- ets:table("++io_lib:write(E2)++"),"
+ "Ref1 =:= Ref].",
+ Bs = erl_eval:add_binding('Ref', Ref, erl_eval:new_bindings()),
+ [{Ref}] = qlc:e(qlc:string_to_handle(S2, [], Bs)),
+ ets:delete(E2),
+
ok.
%% table
@@ -4321,7 +4332,18 @@ ets(Config) when is_list(Config) ->
R = qlc:e(Q),
ets:delete(E),
[] = R">>]
- end
+ end,
+
+ <<"E2 = ets:new(test, [bag]),
+ Ref = make_ref(),
+ true = ets:insert(E2, [{Ref,Ref}]),
+ Q2 = qlc:q([{Val1} ||
+ {Ref1, Val1} <- ets:table(E2),
+ Ref1 =:= Ref]),
+ S = qlc:info(Q2),
+ true = is_list(S),
+ [{Ref}] = qlc:e(Q2),
+ ets:delete(E2)">>
],
@@ -7071,7 +7093,7 @@ otp_12946(Config) when is_list(Config) ->
%% Examples from qlc(3).
manpage(Config) when is_list(Config) ->
-
+ dets:start(),
ok = compile_gb_table(Config),
Ts = [
@@ -7138,11 +7160,14 @@ manpage(Config) when is_list(Config) ->
\" [{X,Z}|{W,Y}] <- V2\n\"
\" ])\n\"
\"end\",
- Info =
+ Info1 =
re:replace(qlc:info(Q),
- \"table\\\\(-*[0-9]*\",
+ \"table\\\\(#Ref<[\\.0-9]*>\",
\"table(_\", [{return,list},global]),
- L = Info,
+ F = fun(C) -> C =/= $\n andalso C =/= $\s end,
+ Info = lists:filter(F, Info1),
+ L1 = lists:filter(F, L),
+ L1 = Info,
ets:delete(E1),
ets:delete(E2)">>,
@@ -7445,10 +7470,10 @@ etsc(F, Opts, Objs) ->
V.
join_info(H) ->
- {qlc, S, Options} = strip_qlc_call(H),
+ {{qlc, S, Options}, Bs} = strip_qlc_call2(H),
%% "Hide" the call to qlc_pt from the test in run_test().
LoadedPT = code:is_loaded(qlc_pt),
- QH = qlc:string_to_handle(S, Options),
+ QH = qlc:string_to_handle(S, Options, Bs),
_ = [unload_pt() || false <- [LoadedPT]], % doesn't take long...
case {join_info_count(H), join_info_count(QH)} of
{N, N} ->
@@ -7458,30 +7483,34 @@ join_info(H) ->
end.
strip_qlc_call(H) ->
+ {Expr, _Bs} = strip_qlc_call2(H),
+ Expr.
+
+strip_qlc_call2(H) ->
S = qlc:info(H, {flat, false}),
- {ok, Tokens, _EndLine} = erl_scan:string(S++"."),
- {ok, [Expr]} = erl_parse:parse_exprs(Tokens),
- case Expr of
- {call,_,{remote,_,{atom,_,qlc},{atom,_,q}},[LC]} ->
- {qlc, lists:flatten([erl_pp:expr(LC), "."]), []};
- {call,_,{remote,_,{atom,_,qlc},{atom,_,q}},[LC, Opts]} ->
- {qlc, lists:flatten([erl_pp:expr(LC), "."]),
- erl_parse:normalise(Opts)};
- {call,_,{remote,_,{atom,_,ets},{atom,_,match_spec_run}},_} ->
- {match_spec, Expr};
- {call,_,{remote,_,{atom,_,M},{atom,_,table}},_} ->
- {table, M, Expr};
- _ ->
- []
- end.
+ {ok, Tokens, _EndLine} = erl_scan:string(S++".", 1, [text]),
+ {ok, [Expr], Bs} = lib:extended_parse_exprs(Tokens),
+ {case Expr of
+ {call,_,{remote,_,{atom,_,qlc},{atom,_,q}},[LC]} ->
+ {qlc, lists:flatten([erl_pp:expr(LC), "."]), []};
+ {call,_,{remote,_,{atom,_,qlc},{atom,_,q}},[LC, Opts]} ->
+ {qlc, lists:flatten([erl_pp:expr(LC), "."]),
+ erl_parse:normalise(Opts)};
+ {call,_,{remote,_,{atom,_,ets},{atom,_,match_spec_run}},_} ->
+ {match_spec, Expr};
+ {call,_,{remote,_,{atom,_,M},{atom,_,table}},_} ->
+ {table, M, Expr};
+ _ ->
+ []
+ end, Bs}.
-record(ji, {nmerge = 0, nlookup = 0, nnested_loop = 0, nkeysort = 0}).
%% Counts join options and (all) calls to qlc:keysort().
join_info_count(H) ->
S = qlc:info(H, {flat, false}),
- {ok, Tokens, _EndLine} = erl_scan:string(S++"."),
- {ok, [Expr]} = erl_parse:parse_exprs(Tokens),
+ {ok, Tokens, _EndLine} = erl_scan:string(S++".", 1, [text]),
+ {ok, [Expr], _Bs} = lib:extended_parse_exprs(Tokens),
#ji{nmerge = Nmerge, nlookup = Nlookup,
nkeysort = NKeysort, nnested_loop = Nnested_loop} =
ji(Expr, #ji{}),
@@ -7524,8 +7553,8 @@ lookup_keys({list,Q,_}, L) ->
lookup_keys({generate,_,Q}, L) ->
lookup_keys(Q, L);
lookup_keys({table,Chars}, L) when is_list(Chars) ->
- {ok, Tokens, _} = erl_scan:string(lists:flatten(Chars++".")),
- {ok, [Expr]} = erl_parse:parse_exprs(Tokens),
+ {ok, Tokens, _} = erl_scan:string(lists:flatten(Chars++"."), 1, [text]),
+ {ok, [Expr], _Bs} = lib:extended_parse_exprs(Tokens),
case Expr of
{call,_,_,[_fun,AKs]} ->
case erl_parse:normalise(AKs) of
@@ -7842,7 +7871,7 @@ run_test(Config, Extra, {cres, Body, Opts, ExpectedCompileReturn}) ->
{module, _} = code:load_abs(AbsFile, Mod),
Ms0 = erlang:process_info(self(),messages),
- Before = {{get(), ets:all(), Ms0}, pps()},
+ Before = {{get(), lists:sort(ets:all()), Ms0}, pps()},
%% Prepare the check that the qlc module does not call qlc_pt.
_ = [unload_pt() || {file, Name} <- [code:is_loaded(qlc_pt)],
@@ -7874,7 +7903,7 @@ run_test(Config, Extra, Body) ->
wait_for_expected(R, {Strict0,PPS0}=Before, SourceFile, Wait) ->
Ms = erlang:process_info(self(),messages),
- After = {_,PPS1} = {{get(), ets:all(), Ms}, pps()},
+ After = {_,PPS1} = {{get(), lists:sort(ets:all()), Ms}, pps()},
case {R, After} of
{ok, Before} ->
ok;
diff --git a/lib/stdlib/test/rand_SUITE.erl b/lib/stdlib/test/rand_SUITE.erl
index 36bc283aec..2ccd89a59f 100644
--- a/lib/stdlib/test/rand_SUITE.erl
+++ b/lib/stdlib/test/rand_SUITE.erl
@@ -324,8 +324,9 @@ basic_stats_normal(Config) when is_list(Config) ->
ct:timetrap({minutes, 6 * length(IntendedMeanVariancePairs)}), %% valgrind needs a lot of time
lists:foreach(
fun ({IntendedMean, IntendedVariance}) ->
- io:format("Testing normal(~.2f, ~.2f)~n",
- [float(IntendedMean), float(IntendedVariance)]),
+ ct:pal(
+ "Testing normal(~.2f, ~.2f)~n",
+ [float(IntendedMean), float(IntendedVariance)]),
[basic_normal_1(?LOOP, IntendedMean, IntendedVariance,
rand:seed_s(Alg), 0, 0)
|| Alg <- algs()]
@@ -485,12 +486,12 @@ do_measure(_Config) ->
{int, rand:uniform_s(Range, State)}
end) || Algo <- Algos],
%%
- ct:pal("~nRNG uniform integer 2^(N-1) performance~n",[]),
- RangeTwoPowFun = fun (State) -> quart_range(State) bsl 1 end,
+ ct:pal("~nRNG uniform integer half range performance~n",[]),
+ HalfRangeFun = fun (State) -> half_range(State) end,
TMark2 =
measure_1(
random,
- RangeTwoPowFun,
+ HalfRangeFun,
undefined,
fun (Range, State) ->
{int, random:uniform_s(Range, State)}
@@ -498,18 +499,18 @@ do_measure(_Config) ->
_ =
[measure_1(
Algo,
- RangeTwoPowFun,
+ HalfRangeFun,
TMark2,
fun (Range, State) ->
{int, rand:uniform_s(Range, State)}
end) || Algo <- Algos],
%%
- ct:pal("~nRNG uniform integer 3*2^(N-2)+1 performance~n",[]),
- RangeLargeFun = fun (State) -> 3 * quart_range(State) + 1 end,
+ ct:pal("~nRNG uniform integer half range + 1 performance~n",[]),
+ HalfRangePlus1Fun = fun (State) -> half_range(State) + 1 end,
TMark3 =
measure_1(
random,
- RangeLargeFun,
+ HalfRangePlus1Fun,
undefined,
fun (Range, State) ->
{int, random:uniform_s(Range, State)}
@@ -517,17 +518,18 @@ do_measure(_Config) ->
_ =
[measure_1(
Algo,
- RangeLargeFun,
+ HalfRangePlus1Fun,
TMark3,
fun (Range, State) ->
{int, rand:uniform_s(Range, State)}
end) || Algo <- Algos],
%%
- ct:pal("~nRNG uniform integer 2^128 performance~n",[]),
+ ct:pal("~nRNG uniform integer full range - 1 performance~n",[]),
+ FullRangeMinus1Fun = fun (State) -> (half_range(State) bsl 1) - 1 end,
TMark4 =
measure_1(
random,
- fun (_) -> 1 bsl 128 end,
+ FullRangeMinus1Fun,
undefined,
fun (Range, State) ->
{int, random:uniform_s(Range, State)}
@@ -535,17 +537,18 @@ do_measure(_Config) ->
_ =
[measure_1(
Algo,
- fun (_) -> 1 bsl 128 end,
+ FullRangeMinus1Fun,
TMark4,
fun (Range, State) ->
{int, rand:uniform_s(Range, State)}
end) || Algo <- Algos],
%%
- ct:pal("~nRNG uniform integer 2^128 + 1 performance~n",[]),
+ ct:pal("~nRNG uniform integer full range performance~n",[]),
+ FullRangeFun = fun (State) -> half_range(State) bsl 1 end,
TMark5 =
measure_1(
random,
- fun (_) -> (1 bsl 128) + 1 end,
+ FullRangeFun,
undefined,
fun (Range, State) ->
{int, random:uniform_s(Range, State)}
@@ -553,16 +556,73 @@ do_measure(_Config) ->
_ =
[measure_1(
Algo,
- fun (_) -> (1 bsl 128) + 1 end,
+ FullRangeFun,
TMark5,
fun (Range, State) ->
{int, rand:uniform_s(Range, State)}
end) || Algo <- Algos],
%%
- ct:pal("~nRNG uniform float performance~n",[]),
+ ct:pal("~nRNG uniform integer full range + 1 performance~n",[]),
+ FullRangePlus1Fun = fun (State) -> (half_range(State) bsl 1) + 1 end,
TMark6 =
measure_1(
random,
+ FullRangePlus1Fun,
+ undefined,
+ fun (Range, State) ->
+ {int, random:uniform_s(Range, State)}
+ end),
+ _ =
+ [measure_1(
+ Algo,
+ FullRangePlus1Fun,
+ TMark6,
+ fun (Range, State) ->
+ {int, rand:uniform_s(Range, State)}
+ end) || Algo <- Algos],
+ %%
+ ct:pal("~nRNG uniform integer double range performance~n",[]),
+ DoubleRangeFun = fun (State) -> half_range(State) bsl 2 end,
+ TMark7 =
+ measure_1(
+ random,
+ DoubleRangeFun,
+ undefined,
+ fun (Range, State) ->
+ {int, random:uniform_s(Range, State)}
+ end),
+ _ =
+ [measure_1(
+ Algo,
+ DoubleRangeFun,
+ TMark7,
+ fun (Range, State) ->
+ {int, rand:uniform_s(Range, State)}
+ end) || Algo <- Algos],
+ %%
+ ct:pal("~nRNG uniform integer double range + 1 performance~n",[]),
+ DoubleRangePlus1Fun = fun (State) -> (half_range(State) bsl 2) + 1 end,
+ TMark8 =
+ measure_1(
+ random,
+ DoubleRangePlus1Fun,
+ undefined,
+ fun (Range, State) ->
+ {int, random:uniform_s(Range, State)}
+ end),
+ _ =
+ [measure_1(
+ Algo,
+ DoubleRangePlus1Fun,
+ TMark8,
+ fun (Range, State) ->
+ {int, rand:uniform_s(Range, State)}
+ end) || Algo <- Algos],
+ %%
+ ct:pal("~nRNG uniform float performance~n",[]),
+ TMark9 =
+ measure_1(
+ random,
fun (_) -> 0 end,
undefined,
fun (_, State) ->
@@ -572,7 +632,7 @@ do_measure(_Config) ->
[measure_1(
Algo,
fun (_) -> 0 end,
- TMark6,
+ TMark9,
fun (_, State) ->
{uniform, rand:uniform_s(State)}
end) || Algo <- Algos],
@@ -582,7 +642,7 @@ do_measure(_Config) ->
_ = [measure_1(
Algo,
fun (_) -> 0 end,
- TMark6,
+ TMark9,
fun (_, State) ->
{normal, rand:normal_s(State)}
end) || Algo <- Algos],
@@ -1043,7 +1103,7 @@ range({#{max:=Max}, _}) -> Max; %% Old incorrect range
range({_, _, _}) -> 51. % random
-quart_range({#{bits:=Bits}, _}) -> 1 bsl (Bits - 2);
-quart_range({#{max:=Max}, _}) -> (Max bsr 2) + 1;
-quart_range({#{}, _}) -> 1 bsl 62; % crypto
-quart_range({_, _, _}) -> 1 bsl 49. % random
+half_range({#{bits:=Bits}, _}) -> 1 bsl (Bits - 1);
+half_range({#{max:=Max}, _}) -> (Max bsr 1) + 1;
+half_range({#{}, _}) -> 1 bsl 63; % crypto
+half_range({_, _, _}) -> 1 bsl 50. % random
diff --git a/lib/stdlib/test/shell_SUITE.erl b/lib/stdlib/test/shell_SUITE.erl
index 56002dda25..99411bc8fd 100644
--- a/lib/stdlib/test/shell_SUITE.erl
+++ b/lib/stdlib/test/shell_SUITE.erl
@@ -31,7 +31,7 @@
progex_lc/1, progex_funs/1,
otp_5990/1, otp_6166/1, otp_6554/1,
otp_7184/1, otp_7232/1, otp_8393/1, otp_10302/1, otp_13719/1,
- otp_14285/1]).
+ otp_14285/1, otp_14296/1]).
-export([ start_restricted_from_shell/1,
start_restricted_on_command_line/1,restricted_local/1]).
@@ -92,7 +92,7 @@ groups() ->
progex_funs]},
{tickets, [],
[otp_5990, otp_6166, otp_6554, otp_7184,
- otp_7232, otp_8393, otp_10302, otp_13719, otp_14285]}].
+ otp_7232, otp_8393, otp_10302, otp_13719, otp_14285, otp_14296]}].
init_per_suite(Config) ->
Config.
@@ -2841,6 +2841,95 @@ otp_14285(Config) ->
test_server:stop_node(Node),
ok.
+otp_14296(Config) when is_list(Config) ->
+ fun() ->
+ F = fun() -> a end,
+ LocalFun = term_to_string(F),
+ S = LocalFun ++ ".",
+ "1: syntax error before: Fun" = comm_err(S)
+ end(),
+
+ fun() ->
+ F = fun mod:func/1,
+ ExternalFun = term_to_string(F),
+ S = ExternalFun ++ ".",
+ R = ExternalFun ++ ".\n",
+ R = t(S)
+ end(),
+
+ fun() ->
+ UnknownPid = "<100000.0.0>",
+ S = UnknownPid ++ ".",
+ "1: syntax error before: '<'" = comm_err(S)
+ end(),
+
+ fun() ->
+ KnownPid = term_to_string(self()),
+ S = KnownPid ++ ".",
+ R = KnownPid ++ ".\n",
+ R = t(S)
+ end(),
+
+ fun() ->
+ Port = open_port({spawn, "ls"}, [line]),
+ KnownPort = erlang:port_to_list(Port),
+ S = KnownPort ++ ".",
+ R = KnownPort ++ ".\n",
+ R = t(S)
+ end(),
+
+ fun() ->
+ UnknownPort = "#Port<100000.0>",
+ S = UnknownPort ++ ".",
+ "1: syntax error before: Port" = comm_err(S)
+ end(),
+
+ fun() ->
+ UnknownRef = "#Ref<100000.0.0.0>",
+ S = UnknownRef ++ ".",
+ "1: syntax error before: Ref" = comm_err(S)
+ end(),
+
+ fun() ->
+ KnownRef = term_to_string(make_ref()),
+ S = KnownRef ++ ".",
+ R = KnownRef ++ ".\n",
+ R = t(S)
+ end(),
+
+ %% Test lib:extended_parse_term/1
+ TF = fun(S) ->
+ {ok, Ts, _} = erl_scan:string(S++".", 1, [text]),
+ case lib:extended_parse_term(Ts) of
+ {ok, Term} -> Term;
+ {error, _}=Error -> Error
+ end
+ end,
+ Fun = fun m:f/1,
+ Fun = TF(term_to_string(Fun)),
+ Fun = TF("fun m:f/1"),
+ Pid = self(),
+ Pid = TF(term_to_string(Pid)),
+ Ref = make_ref(),
+ Ref = TF(term_to_string(Ref)),
+ Term = {[10, a], {"foo", []}, #{x => <<"bar">>}},
+ Term = TF(lists:flatten(io_lib:format("~p", [Term]))),
+ {$a, F1, "foo"} = TF("{$a, 1.0, \"foo\"}"),
+ true = is_float(F1),
+ 3 = TF("+3"),
+ $a = TF("+$a"),
+ true = is_float(TF("+1.0")),
+ true = -3 =:= TF("-3"),
+ true = -$a =:= TF("-$a"),
+ true = is_float(TF("-1.0")),
+ {error, {_, _, ["syntax error"++_|_]}} = TF("{1"),
+ {error, {_,_,"bad term"}} = TF("fun() -> foo end"),
+ {error, {_,_,"bad term"}} = TF("1, 2"),
+ ok.
+
+term_to_string(T) ->
+ lists:flatten(io_lib:format("~w", [T])).
+
scan(B) ->
F = fun(Ts) ->
case erl_parse:parse_term(Ts) of
diff --git a/lib/stdlib/test/sofs_SUITE.erl b/lib/stdlib/test/sofs_SUITE.erl
index f67bf16f0f..39e56c6df6 100644
--- a/lib/stdlib/test/sofs_SUITE.erl
+++ b/lib/stdlib/test/sofs_SUITE.erl
@@ -1783,7 +1783,7 @@ multiple_relative_product(Conf) when is_list(Conf) ->
ok.
digraph(Conf) when is_list(Conf) ->
- T0 = ets:all(),
+ T0 = lists:sort(ets:all()),
E = empty_set(),
R = relation([{a,b},{b,c},{c,d},{d,a}]),
F = relation_to_family(R),
@@ -1833,7 +1833,7 @@ digraph(Conf) when is_list(Conf) ->
true -> ok
end,
- true = T0 == ets:all(),
+ true = T0 == lists:sort(ets:all()),
ok.
digraph_fail(ExitReason, Fail) ->
diff --git a/lib/tools/emacs/erlang.el b/lib/tools/emacs/erlang.el
index 59b20c552e..4ffc2ca172 100644
--- a/lib/tools/emacs/erlang.el
+++ b/lib/tools/emacs/erlang.el
@@ -97,18 +97,6 @@ Erlang mode menu."
:type '(restricted-sexp :match-alternatives (stringp 'nil))
:safe (lambda (val) (or (eq nil val) (stringp val))))
-(defconst erlang-xemacs-p (string-match "Lucid\\|XEmacs" emacs-version)
- "Non-nil when running under XEmacs or Lucid Emacs.")
-
-(defvar erlang-xemacs-popup-menu '("Erlang Mode Commands" . nil)
- "Common popup menu for all buffers in Erlang mode.
-
-This variable is destructively modified every time the Erlang menu
-is modified. The effect is that all changes take effect in all
-buffers in Erlang mode, just like under GNU Emacs.
-
-Never EVER set this variable!")
-
(defvar erlang-menu-items '(erlang-menu-base-items
erlang-menu-skel-items
erlang-menu-shell-items
@@ -128,17 +116,14 @@ variable.")
(defvar erlang-menu-base-items
'(("Indent"
(("Indent Line" erlang-indent-command)
- ("Indent Region " erlang-indent-region
- (if erlang-xemacs-p (mark) mark-active))
+ ("Indent Region " erlang-indent-region mark-active)
("Indent Clause" erlang-indent-clause)
("Indent Function" erlang-indent-function)
("Indent Buffer" erlang-indent-current-buffer)))
("Edit"
(("Fill Comment" erlang-fill-paragraph)
- ("Comment Region" comment-region
- (if erlang-xemacs-p (mark) mark-active))
- ("Uncomment Region" erlang-uncomment-region
- (if erlang-xemacs-p (mark) mark-active))
+ ("Comment Region" comment-region mark-active)
+ ("Uncomment Region" uncomment-region mark-active)
nil
("Beginning of Function" erlang-beginning-of-function)
("End of Function" erlang-end-of-function)
@@ -576,8 +561,7 @@ This is an elisp list of options. Each option can be either:
- a string")
(eval-and-compile
- (defvar erlang-regexp-modern-p
- (if (> emacs-major-version 21) t nil)
+ (defvar erlang-regexp-modern-p t
"Non-nil when this version of Emacs uses a modern version of regexp.
Supporting \_< and \_> This is determined by checking the version of Emacs used."))
@@ -836,6 +820,8 @@ resulting regexp is surrounded by \\_< and \\_>."
"list_to_float"
"list_to_integer"
"list_to_pid"
+ "list_to_port"
+ "list_to_ref"
"list_to_tuple"
"load_module"
"make_ref"
@@ -854,12 +840,14 @@ resulting regexp is surrounded by \\_< and \\_>."
"port_command"
"port_connect"
"port_control"
+ "port_to_list"
"pre_loaded"
"process_flag"
"process_info"
"processes"
"purge_module"
"put"
+ "ref_to_list"
"register"
"registered"
"round"
@@ -940,7 +928,6 @@ resulting regexp is surrounded by \\_< and \\_>."
"get_cookie"
"get_module_info"
"get_stacktrace"
- "hash"
"has_prepared_code_on_load"
"hibernate"
"insert_element"
@@ -967,14 +954,12 @@ resulting regexp is surrounded by \\_< and \\_>."
"port_get_data"
"port_info"
"port_set_data"
- "port_to_list"
"ports"
"posixtime_to_universaltime"
"prepare_loading"
"process_display"
"raise"
"read_timer"
- "ref_to_list"
"resume_process"
"send"
"send_after"
@@ -1053,8 +1038,7 @@ behaviour.")
(define-key map "\M-q" 'erlang-fill-paragraph)
(unless (boundp 'beginning-of-defun-function)
(define-key map "\M-\C-a" 'erlang-beginning-of-function)
- (define-key map "\M-\C-e" 'erlang-end-of-function)
- (define-key map '(meta control h) 'erlang-mark-function)) ; Xemacs
+ (define-key map "\M-\C-e" 'erlang-end-of-function))
(define-key map "\M-\t" 'erlang-complete-tag)
(define-key map "\C-c\M-\t" 'tempo-complete-tag)
(define-key map "\M-+" 'erlang-find-next-tag)
@@ -1069,7 +1053,7 @@ behaviour.")
(define-key map "\C-c\C-l" 'erlang-compile-display)
(define-key map "\C-c\C-s" 'erlang-show-syntactic-information)
(define-key map "\C-c\C-q" 'erlang-indent-function)
- (define-key map "\C-c\C-u" 'erlang-uncomment-region)
+ (define-key map "\C-c\C-u" 'uncomment-region)
(define-key map "\C-c\C-y" 'erlang-clone-arguments)
(define-key map "\C-c\C-a" 'erlang-align-arrows)
(define-key map "\C-c\C-z" 'erlang-shell-display)
@@ -1112,12 +1096,7 @@ behaviour.")
"Font lock keyword highlighting a function header.")
(defface erlang-font-lock-exported-function-name-face
- (if (featurep 'xemacs)
- (progn
- (require 'font-lock)
- `((t (:foreground ,(face-foreground 'font-lock-function-name-face))
- (:background ,(face-background 'font-lock-function-name-face)))))
- '((default (:inherit font-lock-function-name-face))))
+ '((default (:inherit font-lock-function-name-face)))
"Face used for highlighting exported functions."
:group 'erlang)
@@ -1329,11 +1308,7 @@ Example:
The difference between this and the standard Erlang Mode
syntax table is that `_' is treated as part of words by
-this syntax table.
-
-Unfortunately, XEmacs hasn't got support for a special Font
-Lock syntax table. The effect is that `apply' in the atom
-`foo_apply' will be highlighted as a bif.")
+this syntax table.")
(defvar erlang-replace-etags-tags-completion-table nil
"Internal flag used by advice `erlang-replace-tags-table'.
@@ -1353,18 +1328,9 @@ replaced by `erlang-etags-tags-completion-table'.")
(defvar next-error-last-buffer))
(eval-when-compile
- (if (or (featurep 'bytecomp)
- (featurep 'byte-compile))
- (progn
- (cond ((string-match "Lucid\\|XEmacs" emacs-version)
- (put 'comment-indent-hook 'byte-obsolete-variable nil)
- ;; Do not warn for unused variables
- ;; when compiling under XEmacs.
- (setq byte-compile-warnings
- '(free-vars unresolved callargs redefine))))
- (require 'comint)
- (require 'tempo)
- (require 'compile))))
+ (require 'comint)
+ (require 'tempo)
+ (require 'compile))
(defun erlang-version ()
@@ -1446,8 +1412,7 @@ Other commands:
(erlang-tags-init)
(erlang-font-lock-init)
(erlang-skel-init)
- (when (fboundp 'tempo-use-tag-list)
- (tempo-use-tag-list 'erlang-tempo-tags))
+ (tempo-use-tag-list 'erlang-tempo-tags)
(when (and (fboundp 'add-function) (fboundp 'erldoc-eldoc-function))
(or eldoc-documentation-function
(setq-local eldoc-documentation-function #'ignore))
@@ -1506,8 +1471,7 @@ Other commands:
;; delsel/pending-del mode. Also, set up text properties for bit
;; syntax handling.
(mapc #'(lambda (cmd)
- (put cmd 'delete-selection t) ;for delsel (Emacs)
- (put cmd 'pending-delete t)) ;for pending-del (XEmacs)
+ (put cmd 'delete-selection t)) ;for delsel (Emacs)
'(erlang-electric-semicolon
erlang-electric-comma
erlang-electric-gt))
@@ -1545,8 +1509,6 @@ Other commands:
(make-local-variable 'indent-region-function)
(setq indent-region-function 'erlang-indent-region)
(set (make-local-variable 'comment-indent-function) 'erlang-comment-indent)
- (if (<= emacs-major-version 18)
- (set (make-local-variable 'comment-indent-hook) 'erlang-comment-indent))
(set (make-local-variable 'parse-sexp-ignore-comments) t)
(set (make-local-variable 'dabbrev-case-fold-search) nil)
(set (make-local-variable 'imenu-prev-index-position-function)
@@ -1753,7 +1715,7 @@ menu configuration is changed."
(defun erlang-menu-install (name items keymap &optional popup)
- "Install a menu in Emacs or XEmacs based on an abstract description.
+ "Install a menu in Emacs based on an abstract description.
NAME is the name of the menu.
@@ -1764,32 +1726,15 @@ same same form as ITEMS. The third optional element is an expression
which is evaluated every time the menu is displayed. Should the
expression evaluate to nil the menu item is ghosted.
-KEYMAP is the keymap to add to menu to. (When using XEmacs, the menu
-will only be visible when this menu is the global, the local, or an
-activate minor mode keymap.)
-
-If POPUP is non-nil, the menu is bound to the XEmacs `mode-popup-menu'
-variable, i.e. it will popup when pressing the right mouse button.
+KEYMAP is the keymap to add to menu to.
Please see the variable `erlang-menu-base-items'."
- (cond (erlang-xemacs-p
- (let ((menu (erlang-menu-xemacs name items keymap)))
- ;; We add the menu to the global menubar.
- ;;(funcall (symbol-function 'set-buffer-menubar)
- ;; (symbol-value 'current-menubar))
- (funcall (symbol-function 'add-submenu) nil menu)
- (setcdr erlang-xemacs-popup-menu (cdr menu))
- (if (and popup (boundp 'mode-popup-menu))
- (funcall (symbol-function 'set)
- 'mode-popup-menu erlang-xemacs-popup-menu))))
- ((>= emacs-major-version 19)
- (define-key keymap (vector 'menu-bar (intern name))
- (erlang-menu-make-keymap name items)))
- (t nil)))
+ (define-key keymap (vector 'menu-bar (intern name))
+ (erlang-menu-make-keymap name items)))
(defun erlang-menu-make-keymap (name items)
- "Build a menu for Emacs 19."
+ "Build a menu."
(let ((menumap (funcall (symbol-function 'make-sparse-keymap)
name))
(count 0)
@@ -1827,54 +1772,6 @@ Please see the variable `erlang-menu-base-items'."
(setq items (cdr items)))
(cons name menumap)))
-
-(defun erlang-menu-xemacs (name items &optional keymap)
- "Build a menu for XEmacs."
- (let ((res '())
- first second third entry)
- (while items
- ;; Replace any occurrence of atoms by their value.
- (while (and items (atom (car items)) (not (null (car items))))
- (if (and (boundp (car items))
- (listp (symbol-value (car items))))
- (setq items (append (reverse (symbol-value (car items)))
- (cdr items)))
- (setq items (cdr items))))
- (setq first (car-safe (car items)))
- (setq second (car-safe (cdr-safe (car items))))
- (setq third (car-safe (cdr-safe (cdr-safe (car items)))))
- (cond ((null first)
- (setq res (cons "------" res)))
- ((symbolp second)
- (setq res (cons (vector first second (or third t)) res)))
- ((and (consp second) (eq (car second) 'lambda))
- (setq res (cons (vector first (list 'call-interactively second)
- (or third t)) res)))
- (t
- (setq res (cons (cons first
- (cdr (erlang-menu-xemacs
- first second)))
- res))))
- (setq items (cdr items)))
- (setq res (reverse res))
- ;; When adding a menu to a minor-mode keymap under Emacs,
- ;; it disappears when the mode is disabled. The expression
- ;; generated below imitates this behaviour.
- ;; (This could be expressed much clearer using backquotes,
- ;; but I don't want to pull in every package.)
- (if keymap
- (let ((expr (list 'or
- (list 'eq keymap 'global-map)
- (list 'eq keymap (list 'current-local-map))
- (list 'symbol-value
- (list 'car-safe
- (list 'rassq
- keymap
- 'minor-mode-map-alist))))))
- (setq res (cons ':included (cons expr res)))))
- (cons name res)))
-
-
(defun erlang-menu-substitute (items alist)
"Substitute functions in menu described by ITEMS.
@@ -2278,7 +2175,7 @@ mode with the command `M-x erlang-mode RET'.")))
;; Skeleton code:
;; This code is based on the package `tempo' which is part of modern
-;; Emacsen. (GNU Emacs 19.25 (?) and XEmacs 19.14.)
+;; Emacsen.
(defvar erlang-skel)
(defun erlang-skel-init ()
@@ -2289,36 +2186,33 @@ all skeletons.
The skeleton routines are based on the `tempo' package. Should this
package not be present, this function does nothing."
(interactive)
- (condition-case nil
- (require 'tempo)
- (error t))
- (if (featurep 'tempo)
- (let ((skel erlang-skel)
- (menu '()))
- (while skel
- (cond ((null (car skel))
- (setq menu (cons nil menu)))
- (t
- (funcall (symbol-function 'tempo-define-template)
- (concat "erlang-" (nth 1 (car skel)))
- ;; The tempo template used contains an `include'
- ;; function call only, hence changes to the
- ;; variables describing the templates take effect
- ;; immdiately.
- (list (list 'erlang-skel-include (nth 2 (car skel))))
- (nth 1 (car skel))
- (car (car skel))
- 'erlang-tempo-tags)
- (setq menu (cons (erlang-skel-make-menu-item
- (car skel)) menu))))
- (setq skel (cdr skel)))
- (setq erlang-menu-skel-items
- (list nil (list "Skeletons" (nreverse menu))))
- (setq erlang-menu-items
- (erlang-menu-add-above 'erlang-menu-skel-items
- 'erlang-menu-version-items
- erlang-menu-items))
- (erlang-menu-init))))
+ (require 'tempo)
+ (let ((skel erlang-skel)
+ (menu '()))
+ (while skel
+ (cond ((null (car skel))
+ (setq menu (cons nil menu)))
+ (t
+ (funcall (symbol-function 'tempo-define-template)
+ (concat "erlang-" (nth 1 (car skel)))
+ ;; The tempo template used contains an `include'
+ ;; function call only, hence changes to the
+ ;; variables describing the templates take effect
+ ;; immediately.
+ (list (list 'erlang-skel-include (nth 2 (car skel))))
+ (nth 1 (car skel))
+ (car (car skel))
+ 'erlang-tempo-tags)
+ (setq menu (cons (erlang-skel-make-menu-item
+ (car skel)) menu))))
+ (setq skel (cdr skel)))
+ (setq erlang-menu-skel-items
+ (list nil (list "Skeletons" (nreverse menu))))
+ (setq erlang-menu-items
+ (erlang-menu-add-above 'erlang-menu-skel-items
+ 'erlang-menu-version-items
+ erlang-menu-items))
+ (erlang-menu-init)))
(defun erlang-skel-make-menu-item (skel)
(let ((func (intern (concat "tempo-template-erlang-" (nth 1 skel)))))
@@ -3263,11 +3157,8 @@ With argument, do this that many times."
(interactive)
(push-mark (point))
(erlang-end-of-clause 1)
- ;; Sets the region. In Emacs 19 and XEmacs, we want to activate
- ;; the region.
- (condition-case nil
- (push-mark (point) nil t)
- (error (push-mark (point))))
+ ;; Sets the region.
+ (push-mark (point) nil t)
(erlang-beginning-of-clause 1)
;; The above function deactivates the mark.
(if (boundp 'deactivate-mark)
@@ -3375,11 +3266,8 @@ With negative argument go towards the beginning of the buffer."
(interactive)
(push-mark (point))
(erlang-end-of-function 1)
- ;; Sets the region. In Emacs 19 and XEmacs, we want to activate
- ;; the region.
- (condition-case nil
- (push-mark (point) nil t)
- (error (push-mark (point))))
+ ;; Sets the region.
+ (push-mark (point) nil t)
(erlang-beginning-of-function 1)
;; The above function deactivates the mark.
(if (boundp 'deactivate-mark)
@@ -3462,13 +3350,6 @@ and initial `%':s."
(fill-prefix comment-fill-prefix))
(fill-paragraph justify))))))
-
-(defun erlang-uncomment-region (beg end)
- "Uncomment all commented lines in the region."
- (interactive "r")
- (uncomment-region beg end))
-
-
(defun erlang-generate-new-clause ()
"Create additional Erlang clause header.
@@ -3917,9 +3798,9 @@ of arguments could be found, otherwise nil."
(if (and (stringp str)
(not (string-match (eval-when-compile
(concat "\\`" erlang-atom-regexp "\\'")) str)))
- (progn (if (fboundp 'replace-regexp-in-string)
- (setq str (replace-regexp-in-string "'" "\\'" str t t )))
- (concat "'" str "'"))
+ (progn
+ (setq str (replace-regexp-in-string "'" "\\'" str t t ))
+ (concat "'" str "'"))
str)))
@@ -4314,9 +4195,7 @@ context, nil is returned."
(let* ((lim (or lim (save-excursion
(erlang-beginning-of-clause)
(point))))
- (state (if (fboundp 'syntax-ppss) ; post Emacs 21.3
- (funcall (symbol-function 'syntax-ppss))
- (parse-partial-sexp lim (point)))))
+ (state (funcall (symbol-function 'syntax-ppss))))
(cond
((eq (nth 3 state) ?') 'atom)
((nth 3 state) 'string)
@@ -4426,14 +4305,8 @@ This function is designed to be a member of a criteria list."
;;; Erlang tags support which is aware of erlang modules.
-;; Not yet implemented under XEmacs. (Hint: The Emacs 19 etags
-;; package works under XEmacs.)
-
(eval-when-compile
- (if (or (featurep 'bytecomp)
- (featurep 'byte-compile))
- (progn
- (require 'etags))))
+ (require 'etags))
;; Variables:
@@ -4477,28 +4350,16 @@ After calling this function, the tags functions are aware of
Erlang modules. Tags can be entered on the for `module:tag' as well
as on the old form `tag'.
-In the completion list, `module:tag' and `module:' shows up.
-
-This function only works under Emacs 18 and Emacs 19. Currently, It
-is not implemented under XEmacs. (Hint: The Emacs 19 etags module
-works under XEmacs.)"
+In the completion list, `module:tag' and `module:' shows up."
(interactive)
- (cond ((= emacs-major-version 18)
- (require 'tags)
- (erlang-tags-define-keys (current-local-map))
- (setq erlang-tags-installed t))
- (t
- (require 'etags)
- (set (make-local-variable 'find-tag-default-function)
- 'erlang-find-tag-for-completion)
- (if (>= emacs-major-version 25)
- (add-hook 'xref-backend-functions
- #'erlang-etags--xref-backend nil t)
- ;; Test on a function available in the Emacs 19 version
- ;; of tags but not in the XEmacs version.
- (when (fboundp 'find-tag-noselect)
- (erlang-tags-define-keys (current-local-map))
- (setq erlang-tags-installed t))))))
+ (require 'etags)
+ (set (make-local-variable 'find-tag-default-function)
+ 'erlang-find-tag-for-completion)
+ (if (>= emacs-major-version 25)
+ (add-hook 'xref-backend-functions
+ #'erlang-etags--xref-backend nil t)
+ (erlang-tags-define-keys (current-local-map))
+ (setq erlang-tags-installed t)))
@@ -4635,8 +4496,7 @@ Tags can be given on the forms `tag', `module:', `module:tag'."
(while (null file)
(or erlang-tags-file-list
(save-excursion
- (if (and (featurep 'etags)
- (funcall
+ (if (and (funcall
(symbol-function 'visit-tags-table-buffer) 'same)
(funcall
(symbol-function 'visit-tags-table-buffer) t))
@@ -4655,35 +4515,12 @@ Tags can be given on the forms `tag', `module:', `module:tag'."
(find-file-noselect file)))))
((string-match ":" modtagname)
- (if (boundp 'find-tag-tag-order)
- ;; Method one: Add module-recognising functions to the
- ;; list of order functions. However, the tags system
- ;; from Emacs 18, and derives thereof (read: XEmacs)
- ;; hasn't got this feature.
- (progn
- (erlang-tags-install-module-check)
- (unwind-protect
- (funcall (symbol-function 'find-tag)
- modtagname next-p regexp-p)
- (erlang-tags-remove-module-check)))
- ;; Method two: Call the tags system until a file matching
- ;; the module is found. This could result in that many
- ;; files are read. (e.g. The tag "foo:file" will take a
- ;; while to process.)
- (let* ((modname (substring modtagname 0 (match-beginning 0)))
- (tagname (substring modtagname (match-end 0) nil))
- (last-tag tagname)
- file)
- (while
- (progn
- (funcall (symbol-function 'find-tag) tagname next-p regexp-p)
- (setq next-p t)
- ;; Determine the module form the file name. (The
- ;; alternative, to check `-module', would make this
- ;; code useless for non-Erlang programs.)
- (setq file (erlang-get-module-from-file-name buffer-file-name))
- (not (and (stringp file)
- (string= modname file))))))))
+ (progn
+ (erlang-tags-install-module-check)
+ (unwind-protect
+ (funcall (symbol-function 'find-tag)
+ modtagname next-p regexp-p)
+ (erlang-tags-remove-module-check))))
(t
(funcall (symbol-function 'find-tag) modtagname next-p regexp-p)))
(current-buffer))) ; Return the new buffer.
@@ -4713,9 +4550,7 @@ Tags can be given on the forms `tag', `module:', `module:tag'."
(prompt (if default
(format "%s(default %s) " prompt default)
prompt))
- (spec (if (featurep 'etags)
- (completing-read prompt 'erlang-tags-complete-tag)
- (read-string prompt))))
+ (spec (completing-read prompt 'erlang-tags-complete-tag)))
(list (if (equal spec "")
(or default (error "There is no default tag"))
spec)))))
@@ -4732,23 +4567,12 @@ Tags can be given on the forms `tag', `module:', `module:tag'."
"Install our own tag search functions."
;; Make sure our functions are installed in TAGS files loaded
;; into Emacs while searching.
- (cond
- ((>= emacs-major-version 20)
- (setq erlang-tags-orig-format-functions
- (symbol-value 'tags-table-format-functions))
- (funcall (symbol-function 'set) 'tags-table-format-functions
- (cons 'erlang-tags-recognize-tags-table
- erlang-tags-orig-format-functions))
- (setq erlang-tags-buffer-list '())
- )
- (t
- (setq erlang-tags-orig-format-hooks
- (symbol-value 'tags-table-format-hooks))
- (funcall (symbol-function 'set) 'tags-table-format-hooks
- (cons 'erlang-tags-recognize-tags-table
- erlang-tags-orig-format-hooks))
- (setq erlang-tags-buffer-list '())
- ))
+ (setq erlang-tags-orig-format-functions
+ (symbol-value 'tags-table-format-functions))
+ (funcall (symbol-function 'set) 'tags-table-format-functions
+ (cons 'erlang-tags-recognize-tags-table
+ erlang-tags-orig-format-functions))
+ (setq erlang-tags-buffer-list '())
;; Install our functions in the TAGS files already resident.
(save-excursion
@@ -4810,17 +4634,9 @@ Tags can be given on the forms `tag', `module:', `module:tag'."
(defun erlang-tags-remove-module-check ()
"Remove our own tags search functions."
- (cond
- ((>= emacs-major-version 20)
- (funcall (symbol-function 'set)
- 'tags-table-format-functions
- erlang-tags-orig-format-functions)
- )
- (t
- (funcall (symbol-function 'set)
- 'tags-table-format-hooks
- erlang-tags-orig-format-hooks)
- ))
+ (funcall (symbol-function 'set)
+ 'tags-table-format-functions
+ erlang-tags-orig-format-functions)
;; Remove our functions from the TAGS files. (Note that
;; `tags-table-computed-list' need not be the same list as when
@@ -4888,21 +4704,18 @@ for a tag on the form `module:tag'."
;;; completion-table' containing all normal tags plus tags on the form
;;; `module:tag' and `module:'.
-(when (and (locate-library "etags")
- (require 'etags)
- (fboundp 'etags-tags-completion-table)
- (fboundp 'tags-lazy-completion-table)) ; Emacs 23.1+
- (if (fboundp 'advice-add)
- ;; Emacs 24.4+
- (advice-add 'etags-tags-completion-table :around
- #'erlang-etags-tags-completion-table-advice)
- ;; Emacs 23.1-24.3
- (defadvice etags-tags-completion-table (around
- erlang-replace-tags-table
- activate)
- (if erlang-replace-etags-tags-completion-table
- (setq ad-return-value (erlang-etags-tags-completion-table))
- ad-do-it))))
+(if (fboundp 'advice-add)
+ ;; Emacs 24.4+
+ (require 'etags)
+ (advice-add 'etags-tags-completion-table :around
+ #'erlang-etags-tags-completion-table-advice)
+ ;; Emacs 23.1-24.3
+ (defadvice etags-tags-completion-table (around
+ erlang-replace-tags-table
+ activate)
+ (if erlang-replace-etags-tags-completion-table
+ (setq ad-return-value (erlang-etags-tags-completion-table))
+ ad-do-it)))
(defun erlang-etags-tags-completion-table-advice (oldfun)
(if erlang-replace-etags-tags-completion-table
@@ -4916,28 +4729,9 @@ Completes to the set of names listed in the current tags table.
Should the Erlang tags system be installed this command knows
about Erlang modules."
(interactive)
- (condition-case nil
- (require 'etags)
- (error nil))
- (cond ((and (fboundp 'etags-tags-completion-table)
- (fboundp 'tags-lazy-completion-table)) ; Emacs 23.1+
- (let ((erlang-replace-etags-tags-completion-table t))
- (complete-tag)))
- ((and erlang-tags-installed
- (fboundp 'complete-tag)
- (fboundp 'tags-complete-tag)) ; Emacs 19-22
- (let ((orig-tags-complete-tag (symbol-function 'tags-complete-tag)))
- (fset 'tags-complete-tag
- (symbol-function 'erlang-tags-complete-tag))
- (unwind-protect
- (complete-tag)
- (fset 'tags-complete-tag orig-tags-complete-tag))))
- ((fboundp 'complete-tag) ; Emacs 19
- (complete-tag))
- ((fboundp 'tag-complete-symbol) ; XEmacs
- (funcall (symbol-function 'tag-complete-symbol)))
- (t
- (error "This version of Emacs can't complete tags"))))
+ (require 'etags)
+ (let ((erlang-replace-etags-tags-completion-table t))
+ (complete-tag)))
(defun erlang-find-tag-for-completion ()
@@ -5079,6 +4873,7 @@ considered first when it is time to jump to the definition.")
(and (erlang-soft-require 'xref)
(erlang-soft-require 'cl-generic)
(erlang-soft-require 'eieio)
+ (erlang-soft-require 'etags)
;; The purpose of using eval here is to avoid compilation
;; warnings in emacsen without cl-defmethod etc.
(eval
@@ -5435,13 +5230,11 @@ The following special commands are available:
'inferior-erlang-strip-delete nil t)
(add-hook 'comint-output-filter-functions
'inferior-erlang-strip-ctrl-m nil t)
- ;; Some older versions of comint don't have an input ring.
- (if (fboundp 'comint-read-input-ring)
- (progn
- (setq comint-input-ring-file-name erlang-input-ring-file-name)
- (comint-read-input-ring t)
- (make-local-variable 'kill-buffer-hook)
- (add-hook 'kill-buffer-hook 'comint-write-input-ring)))
+
+ (setq comint-input-ring-file-name erlang-input-ring-file-name)
+ (comint-read-input-ring t)
+ (make-local-variable 'kill-buffer-hook)
+ (add-hook 'kill-buffer-hook 'comint-write-input-ring)
;; At least in Emacs 21, we need to be in `compilation-minor-mode'
;; for `next-error' to work. We can avoid it clobbering the shell
;; keys thus.
@@ -5559,10 +5352,7 @@ editing control characters:
\\{erlang-shell-mode-map}"
(interactive
(when current-prefix-arg
- (list (if (fboundp 'read-shell-command)
- ;; `read-shell-command' is a new function in Emacs 23.
- (read-shell-command "Erlang command: ")
- (read-string "Erlang command: ")))))
+ (list (read-shell-command "Erlang command: "))))
(require 'comint)
(let (cmd opts)
(if command
@@ -5590,10 +5380,8 @@ editing control characters:
(setq inferior-erlang-process
(get-buffer-process inferior-erlang-buffer))
- (if (> 21 emacs-major-version) ; funcalls to avoid compiler warnings
- (funcall (symbol-function 'set-process-query-on-exit-flag)
- inferior-erlang-process nil)
- (funcall (symbol-function 'process-kill-without-query) inferior-erlang-process))
+ (funcall (symbol-function 'set-process-query-on-exit-flag)
+ inferior-erlang-process nil)
(if erlang-inferior-shell-split-window
(switch-to-buffer-other-window inferior-erlang-buffer)
(switch-to-buffer inferior-erlang-buffer))
@@ -5661,7 +5449,7 @@ frame will become deselected before the next command."
(defun inferior-erlang-window (&optional all-frames)
"Return the window containing the inferior Erlang, or nil."
(and (inferior-erlang-running-p)
- (if (and all-frames (>= emacs-major-version 19))
+ (if all-frames
(get-buffer-window inferior-erlang-buffer t)
(get-buffer-window inferior-erlang-buffer))))
@@ -5733,10 +5521,7 @@ Return the position after the newly inserted command."
;; has been sorted out in Emacs 21. -- fx
(let ((comint-eol-on-send nil)
(comint-input-filter (if hist comint-input-filter 'ignore)))
- (if (and (not erlang-xemacs-p)
- (>= emacs-major-version 22))
- (comint-send-input nil t)
- (comint-send-input)))
+ (comint-send-input nil t))
;; Adjust all windows whose points are incorrect.
(if (null comint-process-echoes)
(walk-windows
@@ -6120,8 +5905,7 @@ Tab characters are counted by their visual width."
Simplified version of a combination `defalias' and `make-obsolete',
it assumes that NEWDEF is loaded."
(defalias sym (symbol-function newdef))
- (if (fboundp 'make-obsolete)
- (make-obsolete sym newdef "long ago")))
+ (make-obsolete sym newdef "long ago"))
(erlang-obsolete 'calculate-erlang-indent 'erlang-calculate-indent)
@@ -6141,9 +5925,8 @@ it assumes that NEWDEF is loaded."
(defconst erlang-unload-hook
(list (lambda ()
- (when (featurep 'advice)
- (ad-unadvise 'Man-notify-when-ready)
- (ad-unadvise 'set-visited-file-name)))))
+ (ad-unadvise 'Man-notify-when-ready)
+ (ad-unadvise 'set-visited-file-name))))
;; The end...
diff --git a/lib/wx/c_src/wxe_impl.cpp b/lib/wx/c_src/wxe_impl.cpp
index 05d56667ab..90cd35455a 100644
--- a/lib/wx/c_src/wxe_impl.cpp
+++ b/lib/wx/c_src/wxe_impl.cpp
@@ -672,7 +672,7 @@ void * WxeApp::getPtr(char * bp, wxeMemEnv *memenv) {
throw wxe_badarg(index);
}
void * temp = memenv->ref2ptr[index];
- if((index < memenv->next) && ((index == 0) || (temp > NULL)))
+ if((index < memenv->next) && ((index == 0) || (temp != (void *)NULL)))
return temp;
else {
throw wxe_badarg(index);
@@ -684,7 +684,7 @@ void WxeApp::registerPid(char * bp, ErlDrvTermData pid, wxeMemEnv * memenv) {
if(!memenv)
throw wxe_badarg(index);
void * temp = memenv->ref2ptr[index];
- if((index < memenv->next) && ((index == 0) || (temp > NULL))) {
+ if((index < memenv->next) && ((index == 0) || (temp != (void *) NULL))) {
ptrMap::iterator it;
it = ptr2ref.find(temp);
if(it != ptr2ref.end()) {
diff --git a/lib/xmerl/src/xmerl_scan.erl b/lib/xmerl/src/xmerl_scan.erl
index 95dc82e5c9..18fe7031b9 100644
--- a/lib/xmerl/src/xmerl_scan.erl
+++ b/lib/xmerl/src/xmerl_scan.erl
@@ -474,8 +474,8 @@ event(_X, S) ->
%% into multiple objects (in which case {Acc',Pos',S'} should be returned.)
%% If {Acc',S'} is returned, Pos will be incremented by 1 by default.
%% Below is an example of an acceptable operation
-acc(X = #xmlText{value = Text}, Acc, S) ->
- {[X#xmlText{value = Text}|Acc], S};
+acc(#xmlText{value = Text}, [X = #xmlText{value = AccText}], S) ->
+ {[X#xmlText{value = AccText ++ Text}], S};
acc(X, Acc, S) ->
{[X|Acc], S}.
diff --git a/lib/xmerl/test/xmerl_SUITE.erl b/lib/xmerl/test/xmerl_SUITE.erl
index 58c462483c..2e383f95c5 100644
--- a/lib/xmerl/test/xmerl_SUITE.erl
+++ b/lib/xmerl/test/xmerl_SUITE.erl
@@ -55,7 +55,7 @@ groups() ->
{misc, [],
[latin1_alias, syntax_bug1, syntax_bug2, syntax_bug3,
pe_ref1, copyright, testXSEIF, export_simple1, export,
- default_attrs_bug, xml_ns]},
+ default_attrs_bug, xml_ns, scan_splits_string_bug]},
{eventp_tests, [], [sax_parse_and_export]},
{ticket_tests, [],
[ticket_5998, ticket_7211, ticket_7214, ticket_7430,
@@ -268,6 +268,10 @@ xml_ns(Config) ->
} = xmerl_scan:string(Doc2, [{namespace_conformant, true}]),
ok.
+scan_splits_string_bug(_Config) ->
+ {#xmlElement{ content = [#xmlText{ value = "Jimmy Zöger" }] }, []}
+ = xmerl_scan:string("<name>Jimmy Z&#246;ger</name>").
+
pe_ref1(Config) ->
file:set_cwd(datadir(Config)),
{#xmlElement{},[]} = xmerl_scan:file(datadir_join(Config,[misc,"PE_ref1.xml"]),[{validation,true}]).
@@ -533,8 +537,7 @@ ticket_7430(Config) ->
{xmlElement,a,a,[],
{xmlNamespace,[],[]},
[],1,[],
- [{xmlText,[{a,1}],1,[],"é",text},
- {xmlText,[{a,1}],2,[],"\né",text}],
+ [{xmlText,[{a,1}],1,[],"é\né",text}],
[],_,undeclared} ->
ok;
_ ->
diff --git a/make/emd2exml.in b/make/emd2exml.in
index b4e052fef5..13bd6700d9 100755
--- a/make/emd2exml.in
+++ b/make/emd2exml.in
@@ -1,6 +1,6 @@
#!@ENV@ escript
%% -*- erlang -*-
-%%! -smp disable
+%%!
%%
%% %CopyrightBegin%
diff --git a/make/otp.mk.in b/make/otp.mk.in
index 7e2945b561..cd4572d81b 100644
--- a/make/otp.mk.in
+++ b/make/otp.mk.in
@@ -47,6 +47,9 @@ CROSS_COMPILING = @CROSS_COMPILING@
# ----------------------------------------------------
DEFAULT_TARGETS = opt debug release release_docs clean docs
+DEFAULT_FLAVOR=@DEFAULT_FLAVOR@
+FLAVORS=@FLAVORS@
+
# Slash separated list of return values from $(origin VAR)
# that are untrusted - set default in this file instead.
# The list is not space separated since some return values
diff --git a/scripts/build-otp b/scripts/build-otp
index 92031c79c8..92a866a0a9 100755
--- a/scripts/build-otp
+++ b/scripts/build-otp
@@ -37,7 +37,7 @@ if [ ! -d "logs" ]; then
fi
do_and_log "Autoconfing" autoconf
-do_and_log "Configuring" configure
+do_and_log "Configuring" configure --enable-plain-emulator
do_and_log "Building OTP" boot -a
exit 0
diff --git a/system/doc/design_principles/fsm.xml b/system/doc/design_principles/fsm.xml
deleted file mode 100644
index 4f2b75e6e8..0000000000
--- a/system/doc/design_principles/fsm.xml
+++ /dev/null
@@ -1,338 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE chapter SYSTEM "chapter.dtd">
-
-<chapter>
- <header>
- <copyright>
- <year>1997</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- 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.
-
- </legalnotice>
-
- <title>gen_fsm Behaviour</title>
- <prepared></prepared>
- <docno></docno>
- <date></date>
- <rev></rev>
- <file>fsm.xml</file>
- </header>
- <marker id="gen_fsm behaviour"></marker>
- <note>
- <p>
- There is a new behaviour
- <seealso marker="statem"><c>gen_statem</c></seealso>
- that is intended to replace <c>gen_fsm</c> for new code.
- It has the same features and add some really useful.
- This module will not be removed for the foreseeable future
- to keep old state machine implementations running.
- </p>
- </note>
- <p>This section is to be read with the <c>gen_fsm(3)</c> manual page
- in STDLIB, where all interface functions and callback
- functions are described in detail.</p>
-
- <section>
- <title>Finite-State Machines</title>
- <p>A Finite-State Machine (FSM) can be described as a set of
- relations of the form:</p>
- <pre>
-State(S) x Event(E) -> Actions(A), State(S')</pre>
- <p>These relations are interpreted as meaning:</p>
- <quote>
- <p>If we are in state <c>S</c> and event <c>E</c> occurs, we
- are to perform actions <c>A</c> and make a transition to
- state <c>S'</c>.</p>
- </quote>
- <p>For an FSM implemented using the <c>gen_fsm</c> behaviour,
- the state transition rules are written as a number of Erlang
- functions, which conform to the following convention:</p>
- <pre>
-StateName(Event, StateData) ->
- .. code for actions here ...
- {next_state, StateName', StateData'}</pre>
- </section>
-
- <section>
- <title>Example</title>
- <p>A door with a code lock can be viewed as an FSM. Initially,
- the door is locked. Anytime someone presses a button, this
- generates an event. Depending on what buttons have been pressed
- before, the sequence so far can be correct, incomplete, or wrong.</p>
- <p>If it is correct, the door is unlocked for 30 seconds (30,000 ms).
- If it is incomplete, we wait for another button to be pressed. If
- it is is wrong, we start all over, waiting for a new button
- sequence.</p>
- <p>Implementing the code lock FSM using <c>gen_fsm</c> results in
- the following callback module:</p>
- <marker id="ex"></marker>
- <code type="none"><![CDATA[
--module(code_lock).
--behaviour(gen_fsm).
-
--export([start_link/1]).
--export([button/1]).
--export([init/1, locked/2, open/2]).
-
-start_link(Code) ->
- gen_fsm:start_link({local, code_lock}, code_lock, lists:reverse(Code), []).
-
-button(Digit) ->
- gen_fsm:send_event(code_lock, {button, Digit}).
-
-init(Code) ->
- {ok, locked, {[], Code}}.
-
-locked({button, Digit}, {SoFar, Code}) ->
- case [Digit|SoFar] of
- Code ->
- do_unlock(),
- {next_state, open, {[], Code}, 30000};
- Incomplete when length(Incomplete)<length(Code) ->
- {next_state, locked, {Incomplete, Code}};
- _Wrong ->
- {next_state, locked, {[], Code}}
- end.
-
-open(timeout, State) ->
- do_lock(),
- {next_state, locked, State}.]]></code>
- <p>The code is explained in the next sections.</p>
- </section>
-
- <section>
- <title>Starting gen_fsm</title>
- <p>In the example in the previous section, the <c>gen_fsm</c> is
- started by calling <c>code_lock:start_link(Code)</c>:</p>
- <code type="none">
-start_link(Code) ->
- gen_fsm:start_link({local, code_lock}, code_lock, lists:reverse(Code), []).
- </code>
- <p><c>start_link</c> calls the function <c>gen_fsm:start_link/4</c>,
- which spawns and links to a new process, a <c>gen_fsm</c>.</p>
- <list type="bulleted">
- <item>
- <p>The first argument, <c>{local, code_lock}</c>, specifies
- the name. In this case, the <c>gen_fsm</c> is locally
- registered as <c>code_lock</c>.</p>
- <p>If the name is omitted, the <c>gen_fsm</c> is not registered.
- Instead its pid must be used. The name can also be given
- as <c>{global, Name}</c>, in which case the <c>gen_fsm</c> is
- registered using <c>global:register_name/2</c>.</p>
- </item>
- <item>
- <p>The second argument, <c>code_lock</c>, is the name of
- the callback module, that is, the module where the callback
- functions are located.</p>
- <p>The interface functions (<c>start_link</c> and <c>button</c>)
- are then located in the same module as the callback
- functions (<c>init</c>, <c>locked</c>, and <c>open</c>). This
- is normally good programming practice, to have the code
- corresponding to one process contained in one module.</p>
- </item>
- <item>
- <p>The third argument, <c>Code</c>, is a list of digits that
- which is passed reversed to the callback function <c>init</c>.
- Here, <c>init</c>
- gets the correct code for the lock as indata.</p>
- </item>
- <item>
- <p>The fourth argument, <c>[]</c>, is a list of options. See
- the <c>gen_fsm(3)</c> manual page for available options.</p>
- </item>
- </list>
- <p>If name registration succeeds, the new <c>gen_fsm</c> process calls
- the callback function <c>code_lock:init(Code)</c>. This function
- is expected to return <c>{ok, StateName, StateData}</c>, where
- <c>StateName</c> is the name of the initial state of the
- <c>gen_fsm</c>. In this case <c>locked</c>, assuming the door is
- locked to begin with. <c>StateData</c> is the internal state of
- the <c>gen_fsm</c>. (For <c>gen_fsm</c>, the internal state is
- often referred to 'state data' to
- distinguish it from the state as in states of a state machine.)
- In this case, the state data is the button sequence so far (empty
- to begin with) and the correct code of the lock.</p>
- <code type="none">
-init(Code) ->
- {ok, locked, {[], Code}}.</code>
- <p><c>gen_fsm:start_link</c> is synchronous. It does not return until
- the <c>gen_fsm</c> has been initialized and is ready to
- receive notifications.</p>
- <p><c>gen_fsm:start_link</c> must be used if the <c>gen_fsm</c> is
- part of a supervision tree, that is, started by a supervisor. There
- is another function, <c>gen_fsm:start</c>, to start a standalone
- <c>gen_fsm</c>, that is, a <c>gen_fsm</c> that is not part of a
- supervision tree.</p>
- </section>
-
- <section>
- <title>Notifying about Events</title>
- <p>The function notifying the code lock about a button event is
- implemented using <c>gen_fsm:send_event/2</c>:</p>
- <code type="none">
-button(Digit) ->
- gen_fsm:send_event(code_lock, {button, Digit}).</code>
- <p><c>code_lock</c> is the name of the <c>gen_fsm</c> and must
- agree with the name used to start it.
- <c>{button, Digit}</c> is the actual event.</p>
- <p>The event is made into a message and sent to the <c>gen_fsm</c>.
- When the event is received, the <c>gen_fsm</c> calls
- <c>StateName(Event, StateData)</c>, which is expected to return a
- tuple <c>{next_state,StateName1,StateData1}</c>.
- <c>StateName</c> is the name of the current state and
- <c>StateName1</c> is the name of the next state to go to.
- <c>StateData1</c> is a new value for the state data of
- the <c>gen_fsm</c>.</p>
- <code type="none"><![CDATA[
-locked({button, Digit}, {SoFar, Code}) ->
- case [Digit|SoFar] of
- Code ->
- do_unlock(),
- {next_state, open, {[], Code}, 30000};
- Incomplete when length(Incomplete)<length(Code) ->
- {next_state, locked, {Incomplete, Code}};
- _Wrong ->
- {next_state, locked, {[], Code}};
- end.
-
-open(timeout, State) ->
- do_lock(),
- {next_state, locked, State}.]]></code>
- <p>If the door is locked and a button is pressed, the complete
- button sequence so far is compared with the correct code for
- the lock and, depending on the result, the door is either unlocked
- and the <c>gen_fsm</c> goes to state <c>open</c>, or the door
- remains in state <c>locked</c>.</p>
- </section>
-
- <section>
- <title>Time-Outs</title>
- <p>When a correct code has been given, the door is unlocked and
- the following tuple is returned from <c>locked/2</c>:</p>
- <code type="none">
-{next_state, open, {[], Code}, 30000};</code>
- <p>30,000 is a time-out value in milliseconds. After this time,
- that is, 30 seconds, a time-out occurs. Then,
- <c>StateName(timeout, StateData)</c> is called. The time-out
- then occurs when the door has been in state <c>open</c> for 30
- seconds. After that the door is locked again:</p>
- <code type="none">
-open(timeout, State) ->
- do_lock(),
- {next_state, locked, State}.</code>
- </section>
-
- <section>
- <title>All State Events</title>
- <p>Sometimes an event can arrive at any state of the <c>gen_fsm</c>.
- Instead of sending the message with <c>gen_fsm:send_event/2</c>
- and writing one clause handling the event for each state function,
- the message can be sent with <c>gen_fsm:send_all_state_event/2</c>
- and handled with <c>Module:handle_event/3</c>:</p>
- <code type="none">
--module(code_lock).
-...
--export([stop/0]).
-...
-
-stop() ->
- gen_fsm:send_all_state_event(code_lock, stop).
-
-...
-
-handle_event(stop, _StateName, StateData) ->
- {stop, normal, StateData}.</code>
- </section>
-
- <section>
- <title>Stopping</title>
-
- <section>
- <title>In a Supervision Tree</title>
- <p>If the <c>gen_fsm</c> is part of a supervision tree, no stop
- function is needed. The <c>gen_fsm</c> is automatically
- terminated by its supervisor. Exactly how this is done is
- defined by a
- <seealso marker="sup_princ#shutdown">shutdown strategy</seealso>
- set in the supervisor.</p>
- <p>If it is necessary to clean up before termination, the shutdown
- strategy must be a time-out value and the <c>gen_fsm</c> must be
- set to trap exit signals in the <c>init</c> function. When ordered
- to shutdown, the <c>gen_fsm</c> then calls the callback function
- <c>terminate(shutdown, StateName, StateData)</c>:</p>
- <code type="none">
-init(Args) ->
- ...,
- process_flag(trap_exit, true),
- ...,
- {ok, StateName, StateData}.
-
-...
-
-terminate(shutdown, StateName, StateData) ->
- ..code for cleaning up here..
- ok.</code>
- </section>
-
- <section>
- <title>Standalone gen_fsm</title>
- <p>If the <c>gen_fsm</c> is not part of a supervision tree, a stop
- function can be useful, for example:</p>
- <code type="none">
-...
--export([stop/0]).
-...
-
-stop() ->
- gen_fsm:send_all_state_event(code_lock, stop).
-...
-
-handle_event(stop, _StateName, StateData) ->
- {stop, normal, StateData}.
-
-...
-
-terminate(normal, _StateName, _StateData) ->
- ok.</code>
- <p>The callback function handling the <c>stop</c> event returns a
- tuple, <c>{stop,normal,StateData1}</c>, where <c>normal</c>
- specifies that it is a normal termination and <c>StateData1</c>
- is a new value for the state data of the <c>gen_fsm</c>. This
- causes the <c>gen_fsm</c> to call
- <c>terminate(normal,StateName,StateData1)</c> and then
- it terminates gracefully:</p>
- </section>
- </section>
-
- <section>
- <title>Handling Other Messages</title>
- <p>If the <c>gen_fsm</c> is to be able to receive other messages
- than events, the callback function
- <c>handle_info(Info, StateName, StateData)</c> must be implemented
- to handle them. Examples of
- other messages are exit messages, if the <c>gen_fsm</c> is linked to
- other processes (than the supervisor) and trapping exit signals.</p>
- <code type="none">
-handle_info({'EXIT', Pid, Reason}, StateName, StateData) ->
- ..code to handle exits here..
- {next_state, StateName1, StateData1}.</code>
- <p>The code_change method must also be implemented.</p>
- <code type="none">
-code_change(OldVsn, StateName, StateData, Extra) ->
- ..code to convert state (and more) during code change
- {ok, NextStateName, NewStateData}</code>
- </section>
-</chapter>
-
diff --git a/system/doc/design_principles/part.xml b/system/doc/design_principles/part.xml
index 6495211e04..d52070a674 100644
--- a/system/doc/design_principles/part.xml
+++ b/system/doc/design_principles/part.xml
@@ -30,7 +30,6 @@
</header>
<xi:include href="des_princ.xml"/>
<xi:include href="gen_server_concepts.xml"/>
- <xi:include href="fsm.xml"/>
<xi:include href="statem.xml"/>
<xi:include href="events.xml"/>
<xi:include href="sup_princ.xml"/>
diff --git a/system/doc/design_principles/spec_proc.xml b/system/doc/design_principles/spec_proc.xml
index 5b156ac263..d663c5df79 100644
--- a/system/doc/design_principles/spec_proc.xml
+++ b/system/doc/design_principles/spec_proc.xml
@@ -45,61 +45,63 @@
<p>The <c>sys</c> module has functions for simple debugging of
processes implemented using behaviours. The <c>code_lock</c>
example from
- <seealso marker="fsm#ex">gen_fsm Behaviour</seealso>
+ <seealso marker="statem#Example">gen_statem Behaviour</seealso>
is used to illustrate this:</p>
<pre>
-% <input>erl</input>
-Erlang (BEAM) emulator version 5.2.3.6 [hipe] [threads:0]
+Erlang/OTP 20 [DEVELOPMENT] [erts-9.0] [source-5ace45e] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:10] [hipe] [kernel-poll:false]
-Eshell V5.2.3.6 (abort with ^G)
-1> <input>code_lock:start_link([1,2,3,4]).</input>
-{ok,&lt;0.32.0>}
-2> <input>sys:statistics(code_lock, true).</input>
+Eshell V9.0 (abort with ^G)
+1> code_lock:start_link([1,2,3,4]).
+Lock
+{ok,&lt;0.63.0>}
+2> sys:statistics(code_lock, true).
ok
-3> <input>sys:trace(code_lock, true).</input>
+3> sys:trace(code_lock, true).
ok
-4> <input>code_lock:button(4).</input>
-*DBG* code_lock got event {button,4} in state closed
+4> code_lock:button(1).
+*DBG* code_lock receive cast {button,1} in state locked
ok
-*DBG* code_lock switched to state closed
-5> <input>code_lock:button(3).</input>
-*DBG* code_lock got event {button,3} in state closed
+*DBG* code_lock consume cast {button,1} in state locked
+5> code_lock:button(2).
+*DBG* code_lock receive cast {button,2} in state locked
ok
-*DBG* code_lock switched to state closed
-6> <input>code_lock:button(2).</input>
-*DBG* code_lock got event {button,2} in state closed
+*DBG* code_lock consume cast {button,2} in state locked
+6> code_lock:button(3).
+*DBG* code_lock receive cast {button,3} in state locked
ok
-*DBG* code_lock switched to state closed
-7> <input>code_lock:button(1).</input>
-*DBG* code_lock got event {button,1} in state closed
+*DBG* code_lock consume cast {button,3} in state locked
+7> code_lock:button(4).
+*DBG* code_lock receive cast {button,4} in state locked
ok
-OPEN DOOR
-*DBG* code_lock switched to state open
-*DBG* code_lock got event timeout in state open
-CLOSE DOOR
-*DBG* code_lock switched to state closed
-8> <input>sys:statistics(code_lock, get).</input>
-{ok,[{start_time,{{2003,6,12},{14,11,40}}},
- {current_time,{{2003,6,12},{14,12,14}}},
- {reductions,333},
+Unlock
+*DBG* code_lock consume cast {button,4} in state locked
+*DBG* code_lock receive state_timeout lock in state open
+Lock
+*DBG* code_lock consume state_timeout lock in state open
+8> sys:statistics(code_lock, get).
+{ok,[{start_time,{{2017,4,21},{16,8,7}}},
+ {current_time,{{2017,4,21},{16,9,42}}},
+ {reductions,2973},
{messages_in,5},
{messages_out,0}]}
-9> <input>sys:statistics(code_lock, false).</input>
+9> sys:statistics(code_lock, false).
ok
-10> <input>sys:trace(code_lock, false).</input>
+10> sys:trace(code_lock, false).
ok
-11> <input>sys:get_status(code_lock).</input>
-{status,&lt;0.32.0>,
- {module,gen_fsm},
- [[{'$ancestors',[&lt;0.30.0>]},
- {'$initial_call',{gen,init_it,
- [gen_fsm,&lt;0.30.0>,&lt;0.30.0>,
- {local,code_lock},
- code_lock,
- [1,2,3,4],
- []]}}],
- running,&lt;0.30.0>,[],
- [code_lock,closed,{[],[1,2,3,4]},code_lock,infinity]]}</pre>
+11> sys:get_status(code_lock).
+{status,&lt;0.63.0>,
+ {module,gen_statem},
+ [[{'$initial_call',{code_lock,init,1}},
+ {'$ancestors',[&lt;0.61.0>]}],
+ running,&lt;0.61.0>,[],
+ [{header,"Status for state machine code_lock"},
+ {data,[{"Status",running},
+ {"Parent",&lt;0.61.0>},
+ {"Logged Events",[]},
+ {"Postponed",[]}]},
+ {data,[{"State",
+ {locked,#{code => [1,2,3,4],remaining => [1,2,3,4]}}}]}]]}
+ </pre>
</section>
<section>
diff --git a/system/doc/design_principles/statem.xml b/system/doc/design_principles/statem.xml
index f4d84ab163..0667af7868 100644
--- a/system/doc/design_principles/statem.xml
+++ b/system/doc/design_principles/statem.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2016</year>
+ <year>2016</year><year>2017</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -293,6 +293,13 @@ StateName(EventType, EventContent, Data) ->
<seealso marker="#State Time-Outs">State Time-Outs</seealso>
</item>
<item>
+ Start a
+ <seealso marker="stdlib:gen_statem#type-generic_timeout">
+ generic time-out</seealso>,
+ read more in section
+ <seealso marker="#Generic Time-Outs">Generic Time-Outs</seealso>
+ </item>
+ <item>
Start an
<seealso marker="stdlib:gen_statem#type-event_timeout">event time-out</seealso>,
see more in section
@@ -320,8 +327,9 @@ StateName(EventType, EventContent, Data) ->
<c>gen_statem(3)</c>
</seealso>
manual page.
- You can, for example, reply to many callers
- and generate multiple next events to handle.
+ You can, for example, reply to many callers,
+ generate multiple next events,
+ and set time-outs to relative or absolute times.
</p>
</section>
@@ -369,6 +377,14 @@ StateName(EventType, EventContent, Data) ->
</seealso>
state timer timing out.
</item>
+ <tag><c>{timeout,Name}</c></tag>
+ <item>
+ Generated by state transition action
+ <seealso marker="stdlib:gen_statem#type-generic_timeout">
+ <c>{{timeout,Name},Time,EventContent}</c>
+ </seealso>
+ generic timer timing out.
+ </item>
<tag><c>timeout</c></tag>
<item>
Generated by state transition action
@@ -450,7 +466,7 @@ locked(
[Digit] ->
do_unlock(),
{next_state, open, Data#{remaining := Code},
- [{state_timeout,10000,lock}];
+ [{state_timeout,10000,lock}]};
[Digit|Rest] -> % Incomplete
{next_state, locked, Data#{remaining := Rest}};
_Wrong ->
@@ -779,7 +795,7 @@ handle_event(cast, {button,Digit}, State, #{code := Code} = Data) ->
[Digit] -> % Complete
do_unlock(),
{next_state, open, Data#{remaining := Code},
- [{state_timeout,10000,lock}};
+ [{state_timeout,10000,lock}]};
[Digit|Rest] -> % Incomplete
{keep_state, Data#{remaining := Rest}};
[_|_] -> % Wrong
@@ -873,7 +889,7 @@ stop() ->
<marker id="Event Time-Outs" />
<title>Event Time-Outs</title>
<p>
- A timeout feature inherited from <c>gen_statem</c>'s predecessor
+ A time-out feature inherited from <c>gen_statem</c>'s predecessor
<seealso marker="stdlib:gen_fsm"><c>gen_fsm</c></seealso>,
is an event time-out, that is,
if an event arrives the timer is cancelled.
@@ -906,24 +922,24 @@ locked(
...
]]></code>
<p>
- Whenever we receive a button event we start an event timeout
+ Whenever we receive a button event we start an event time-out
of 30 seconds, and if we get an event type <c>timeout</c>
we reset the remaining code sequence.
</p>
<p>
- An event timeout is cancelled by any other event so you either
- get some other event or the timeout event. It is therefore
- not possible nor needed to cancel or restart an event timeout.
+ An event time-out is cancelled by any other event so you either
+ get some other event or the time-out event. It is therefore
+ not possible nor needed to cancel or restart an event time-out.
Whatever event you act on has already cancelled
- the event timeout...
+ the event time-out...
</p>
</section>
<!-- =================================================================== -->
<section>
- <marker id="Erlang Timers" />
- <title>Erlang Timers</title>
+ <marker id="Generic Time-Outs" />
+ <title>Generic Time-Outs</title>
<p>
The previous example of state time-outs only work if
the state machine stays in the same state during the
@@ -934,13 +950,68 @@ locked(
You may want to start a timer in one state and respond
to the time-out in another, maybe cancel the time-out
without changing states, or perhaps run multiple
- time-outs in parallel. All this can be accomplished
- with Erlang Timers:
+ time-outs in parallel. All this can be accomplished with
+ <seealso marker="stdlib:gen_statem#type-generic_timeout">generic time-outs</seealso>.
+ They may look a little bit like
+ <seealso marker="stdlib:gen_statem#type-event_timeout">event time-outs</seealso>
+ but contain a name to allow for any number of them simultaneously
+ and they are not automatically cancelled.
+ </p>
+ <p>
+ Here is how to accomplish the state time-out
+ in the previous example by instead using a generic time-out
+ named <c>open_tm</c>:
+ </p>
+ <code type="erl"><![CDATA[
+...
+locked(
+ cast, {button,Digit},
+ #{code := Code, remaining := Remaining} = Data) ->
+ case Remaining of
+ [Digit] ->
+ do_unlock(),
+ {next_state, open, Data#{remaining := Code},
+ [{{timeout,open_tm},10000,lock}]};
+...
+
+open({timeout,open_tm}, lock, Data) ->
+ do_lock(),
+ {next_state,locked,Data};
+open(cast, {button,_}, Data) ->
+ {keep_state,Data};
+...
+ ]]></code>
+ <p>
+ Just as
+ <seealso marker="#State Time-Outs">state time-outs</seealso>
+ you can restart or cancel a specific generic time-out
+ by setting it to a new time or <c>infinity</c>.
+ </p>
+ <p>
+ Another way to handle a late time-out can be to not cancel it,
+ but to ignore it if it arrives in a state
+ where it is known to be late.
+ </p>
+ </section>
+
+<!-- =================================================================== -->
+
+ <section>
+ <marker id="Erlang Timers" />
+ <title>Erlang Timers</title>
+ <p>
+ The most versatile way to handle time-outs is to use
+ Erlang Timers; see
<seealso marker="erts:erlang#start_timer/4"><c>erlang:start_timer3,4</c></seealso>.
+ Most time-out tasks can be performed with the
+ time-out features in <c>gen_statem</c>,
+ but an example of one that can not is if you should need
+ the return value from
+ <seealso marker="erts:erlang#cancel_timer/2"><c>erlang:cancel_timer(Tref)</c></seealso>, that is; the remaining time of the timer.
</p>
<p>
Here is how to accomplish the state time-out
- in the previous example by insted using an Erlang Timer:
+ in the previous example by instead using an Erlang Timer:
</p>
<code type="erl"><![CDATA[
...
@@ -1596,7 +1667,7 @@ handle_event(
{call,From}, code_length,
{_StateName,_LockButton}, #{code := Code}) ->
{keep_state_and_data,
- [{reply,From,length(Code)}]};
+ [{reply,From,length(Code)}]};
%%
%% State: locked
handle_event(
@@ -1636,7 +1707,7 @@ handle_event(
if
Digit =:= LockButton ->
{next_state, {locked,LockButton}, Data,
- [{reply,From,locked}]);
+ [{reply,From,locked}]};
true ->
{keep_state_and_data,
[postpone]}
@@ -1710,10 +1781,10 @@ handle_event(
EventType, EventContent,
{open,LockButton}, Data) ->
case {EventType, EventContent} of
- {enter, _OldState} ->
- do_unlock(),
- {keep_state_and_data,
- [{state_timeout,10000,lock},hibernate]};
+ {enter, _OldState} ->
+ do_unlock(),
+ {keep_state_and_data,
+ [{state_timeout,10000,lock},hibernate]};
...
]]></code>
<p>
diff --git a/system/doc/design_principles/sup_princ.xml b/system/doc/design_principles/sup_princ.xml
index 478d1bf714..48b1905e94 100644
--- a/system/doc/design_principles/sup_princ.xml
+++ b/system/doc/design_principles/sup_princ.xml
@@ -206,7 +206,7 @@ SupFlags = #{intensity => MaxR, period => MaxT, ...}</code>
On the other hand, if it is more important that you keep trying
even at a high failure rate, you might want a sustained rate of as
much as 1-2 restarts per second.</p>
- <p>Avoiding common mistakes:
+ <p>Avoiding common mistakes:</p>
<list type="bulleted">
<item>
<p>Do not forget to consider the burst rate. If you set intensity
@@ -236,7 +236,7 @@ SupFlags = #{intensity => MaxR, period => MaxT, ...}</code>
most 3 restarts for the top level supervisor might be a better
choice in this case.</p>
</item>
- </list></p>
+ </list>
</section>
</section>
@@ -276,7 +276,6 @@ child_spec() = #{id => child_id(), % mandatory
<list type="bulleted">
<item><c>supervisor:start_link</c></item>
<item><c>gen_server:start_link</c></item>
- <item><c>gen_fsm:start_link</c></item>
<item><c>gen_statem:start_link</c></item>
<item><c>gen_event:start_link</c></item>
<item>A function compliant with these functions. For details,
@@ -341,7 +340,7 @@ child_spec() = #{id => child_id(), % mandatory
<p><c>modules</c> are to be a list with one element
<c>[Module]</c>, where <c>Module</c> is the name of
the callback module, if the child process is a supervisor,
- gen_server, gen_fsm or gen_statem.
+ gen_server, gen_statem.
If the child process is a gen_event,
the value shall be <c>dynamic</c>.</p>
<p>This information is used by the release handler during
diff --git a/system/doc/design_principles/xmlfiles.mk b/system/doc/design_principles/xmlfiles.mk
index e476255d62..8877e94f39 100644
--- a/system/doc/design_principles/xmlfiles.mk
+++ b/system/doc/design_principles/xmlfiles.mk
@@ -24,7 +24,6 @@ DESIGN_PRINCIPLES_CHAPTER_FILES = \
des_princ.xml \
distributed_applications.xml \
events.xml \
- fsm.xml \
statem.xml \
gen_server_concepts.xml \
included_applications.xml \
diff --git a/system/doc/efficiency_guide/processes.xml b/system/doc/efficiency_guide/processes.xml
index afa4325d8e..3b64c863ff 100644
--- a/system/doc/efficiency_guide/processes.xml
+++ b/system/doc/efficiency_guide/processes.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2001</year><year>2016</year>
+ <year>2001</year><year>2017</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -222,7 +222,7 @@ kilo_byte(N, Acc) ->
<pre>
4> <input>T = ets:new(tab, []).</input>
-17
+#Ref&lt;0.1662103692.2407923716.214181>
5> <input>ets:insert(T, {key,efficiency_guide:kilo_byte()}).</input>
true
6> <input>erts_debug:size(element(2, hd(ets:lookup(T, key)))).</input>
diff --git a/system/doc/reference_manual/character_set.xml b/system/doc/reference_manual/character_set.xml
index 1129ad63d8..8e41142fb4 100644
--- a/system/doc/reference_manual/character_set.xml
+++ b/system/doc/reference_manual/character_set.xml
@@ -110,7 +110,8 @@
Guide</seealso>.</p>
<p>From Erlang/OTP 20, atoms and function names are also allowed
to contain Unicode characters outside the ISO-Latin-1 range.
- Module names are still restricted to the ISO-Latin-1 range.</p>
+ Module names, application names, and node names are still
+ restricted to the ISO-Latin-1 range.</p>
</section>
<section>
<title>Source File Encoding</title>
diff --git a/system/doc/reference_manual/modules.xml b/system/doc/reference_manual/modules.xml
index 96968b547e..6fe6680c84 100644
--- a/system/doc/reference_manual/modules.xml
+++ b/system/doc/reference_manual/modules.xml
@@ -143,7 +143,6 @@ fact(0) -> % |
standard behaviours:</p>
<list type="bulleted">
<item><c>gen_server</c></item>
- <item><c>gen_fsm</c></item>
<item><c>gen_statem</c></item>
<item><c>gen_event</c></item>
<item><c>supervisor</c></item>
diff --git a/system/doc/top/src/erl_html_tools.erl b/system/doc/top/src/erl_html_tools.erl
index d55c2e1164..28a0649658 100644
--- a/system/doc/top/src/erl_html_tools.erl
+++ b/system/doc/top/src/erl_html_tools.erl
@@ -387,9 +387,7 @@ subst("#copyright#", _Info, _Group) ->
"copyright Copyright &copy; 1991-2004";
subst("#groups#", Info, _Group) ->
[
- "<table border=0 width=\"90%\" cellspacing=3 cellpadding=5>\n",
- subst_groups(Info),
- "</table>\n"
+ subst_groups(Info)
];
subst("#applinks#", Info, Group) ->
subst_applinks(Info, Group);
@@ -476,16 +474,10 @@ subst_unknown_groups([{_Group,Heading,Apps} | Groups], Text0, Left) ->
group_table(Heading,Apps) ->
- [
- " <tr>\n",
- " <td colspan=2 class=header>\n",
- " <font size=\"+1\"><b>",Heading,"</b></font>\n",
- " </td>\n",
- " </tr>\n",
+ ["<h2>",Heading,"</h2>",
+ "<table class=\"group-table\">\n",
subst_apps(Apps),
- " <tr>\n",
- " <td colspan=2><font size=1>&nbsp;</font></td>\n",
- " </tr>\n"
+ "</table>\n"
].
% Count and split the applications in half to get the right sort
@@ -500,17 +492,11 @@ subst_apps([]) ->
subst_app(App, [{VSN,_Path,Link,Text}]) ->
[
" <tr class=app>\n",
- " <td align=left valign=top>\n",
- " <table border=0 width=\"100%\" cellspacing=0 cellpadding=0>\n",
- " <tr class=app>\n",
- " <td align=left valign=top>\n",
+ " <td>\n",
" <a href=\"",Link,"\" target=\"_top\">",uc(App),"</a>\n",
" <a href=\"",Link,"\" target=\"_top\">",VSN,"</a>\n",
- " </td>\n",
- " </tr>\n",
- " </table>\n"
" </td>\n",
- " <td align=left valign=top>\n",
+ " <td>\n",
Text,"\n",
" </td>\n",
" </tr>\n"
@@ -518,27 +504,14 @@ subst_app(App, [{VSN,_Path,Link,Text}]) ->
subst_app(App, [{VSN,_Path,Link,Text} | VerInfos]) ->
[
" <tr class=app>\n",
- " <td align=left valign=top>\n",
- " <table border=0 width=\"100%\" cellspacing=0 cellpadding=0>\n",
- " <tr class=app>\n",
- " <td align=left valign=top>\n",
+ " <td>\n",
" <a href=\"",Link,"\" target=\"_top\">",uc(App),
- "</a>&nbsp;&nbsp;<br>\n",
+ "</a>\n",
" <a href=\"",Link,"\" target=\"_top\">",VSN,"</a>\n",
- " </td>\n",
- " <td align=right valign=top width=50>\n",
- " <table border=0 width=40 cellspacing=0 cellpadding=0>\n",
- " <tr class=app>\n",
- " <td align=left valign=top class=appnums>\n",
+ " <td class=appnums>\n",
subst_vsn(VerInfos),
- " </td>\n",
- " </tr>\n",
- " </table>\n"
- " </td>\n",
- " </tr>\n",
- " </table>\n"
" </td>\n",
- " <td align=left valign=top>\n",
+ " <td>\n",
Text,"\n",
" </td>\n",
" </tr>\n"
diff --git a/system/doc/top/src/otp_man_index.erl b/system/doc/top/src/otp_man_index.erl
index 12aaba1423..655d7265f7 100644
--- a/system/doc/top/src/otp_man_index.erl
+++ b/system/doc/top/src/otp_man_index.erl
@@ -154,10 +154,10 @@ gen_html(RefPages, OutFile)->
SortedPages = lists:sort(RefPages),
lists:foreach(fun({_,Module, App, AppDocDir, RefPagePath}) ->
- io:fwrite(Out, " <TR>\n",[]),
- io:fwrite(Out, " <TD><A HREF=\"~s\">~s</A></TD>\n",
+ io:fwrite(Out, " <tr>\n",[]),
+ io:fwrite(Out, " <td><a href=\"~s\">~s</a></td>\n",
[RefPagePath, Module]),
- io:fwrite(Out, " <TD><A HREF=\"~s\">~s</A></TD>\n",
+ io:fwrite(Out, " <td><a HREF=\"~s\">~s</a></td>\n",
[filename:join(AppDocDir, "index.html"),
App]),
io:fwrite(Out, " </TR>\n",[])
@@ -175,41 +175,40 @@ gen_html(RefPages, OutFile)->
html_header() ->
"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n"
"<!-- This file was generated by the otp_man_index -->\n"
- "<HTML>\n"
- "<HEAD>\n"
+ "<html>\n"
+ "<head>\n"
" <link rel=\"stylesheet\" href=\"otp_doc.css\" type=\"text/css\"/>\n"
- " <TITLE>Erlang/OTP Manual Page Index</TITLE>\n"
- "</HEAD>\n"
- "<BODY BGCOLOR=\"#FFFFFF\" TEXT=\"#000000\" LINK=\"#0000FF\" VLINK=\"#FF00FF\" ALINK=\"#FF0000\">\n"
- "<CENTER>\n"
+ " <title>Erlang/OTP Manual Page Index</title>\n"
+ "</head>\n"
+ "<body>\n"
+ "<center>\n"
"<!-- A HREF=\"http://www.erlang.org/\">\n"
"<img alt=\"Erlang logo\" src=\"erlang-logo.png\"/>\n"
- "</A><BR -->\n"
- "<SMALL>\n"
- "[<A HREF=\"index.html\">Up</A> | <A HREF=\"http://www.erlang.org/\">Erlang</A>]\n"
- "</SMALL><BR>\n"
- "<P/><FONT SIZE=\"+4\">OTP Reference Page Index</FONT><BR>\n"
- "</CENTER>\n"
- "<CENTER>\n"
- "<P/>\n"
- "<TABLE BORDER=1>\n"
- "<TR>\n"
- " <TH>Manual Page</TH><TH>Application</TH>\n"
- "</TR>\n".
+ "</a><br -->\n"
+ "<small>\n"
+ "[ <A HREF=\"index.html\">Up</A> | <A HREF=\"http://www.erlang.org/\">Homepage</A> ]\n"
+ "</small><br>\n"
+ "<h1>OTP Reference Page Index</h1>\n"
+ "</center>\n"
+ "<center>\n"
+ "<table class=\"man-index\">\n"
+ "<tr>\n"
+ " <th>Manual Page</th><th>Application</th>\n"
+ "</tr>\n".
html_footer(Year) ->
- "</TABLE>\n"
- "</CENTER>\n"
- "<P/>\n"
- "<CENTER>\n"
- "<HR/>\n"
- "<SMALL>\n"
+ "</table>\n"
+ "</center>\n"
+ "<p/>\n"
+ "<center>\n"
+ "<hr/>\n"
+ "<small>\n"
"Copyright &copy; 1991-" ++ Year ++ "\n"
"<a href=\"http://www.ericsson.com/technology/opensource/erlang/\">\n"
"Ericsson AB</a>\n"
- "</SMALL>\n"
- "</CENTER>\n"
- "</BODY>\n"
- "</HTML>\n".
+ "</small>\n"
+ "</center>\n"
+ "</body>\n"
+ "</html>\n".
diff --git a/system/doc/top/templates/applications.html.src b/system/doc/top/templates/applications.html.src
index 1f73c44d69..7e939ddcd6 100644
--- a/system/doc/top/templates/applications.html.src
+++ b/system/doc/top/templates/applications.html.src
@@ -24,31 +24,53 @@ limitations under the License.
<title>Erlang/OTP #version# Applications</title>
<style type="text/css">
<!--
- BODY { background: white }
+ BODY { background: #fefefe; color: #111; }
- BODY { font-family: Verdana, Arial, Helvetica, sans-serif }
- TH { font-family: Verdana, Arial, Helvetica, sans-serif }
- TD { font-family: Verdana, Arial, Helvetica, sans-serif }
- P { font-family: Verdana, Arial, Helvetica, sans-serif }
+ BODY { font-family: sans-serif }
- .header { background: #222; color: #fff }
- .app { background: #ccc }
+ .header { background: #333; color: #fefefe; }
- a.anum:link { color: green; text-decoration: none }
- a.anum:active { color: green; text-decoration: none }
- a.anum:visited { color: green; text-decoration: none }
+ a:link { color: #303f9f; text-decoration: none }
+ a:active { color: #303f9f; text-decoration: none }
+ a:visited { color: #303f9f; text-decoration: none }
- a:link { text-decoration: none }
- a:active { text-decoration: none }
- a:visited { text-decoration: none }
+ h1,h2{
+ text-align: center;
+ }
+ table {
+ margin: 1em 10%;
+ width: 80%;
+ border-collapse: collapse;
+ min-width: 50%;
+ }
+
+ table, th, td {
+ border: 1px solid #666;
+ }
+
+ th, td {
+ padding: 0.5em;
+ text-align: left;
+ }
+
+ tr:hover {
+ background-color: #f5f5f5;
+ }
+
+ tr:nth-child(even) {
+ background-color: #f2f2f2;
+ }
+
+ th {
+ background-color: #777;
+ color: #fefefe;
+ }
-->
</style>
</head>
-<body bgcolor=white text="#000000" link="#0000ff" vlink="#ff00ff"
- alink="#ff0000">
-<center>
+<body>
+ <h1>Erlang/OTP Applications</h1>
#groups#
-</center>
</body>
</html>
diff --git a/system/doc/top/templates/index.html.src b/system/doc/top/templates/index.html.src
index d2a6736d34..b7fff0993d 100644
--- a/system/doc/top/templates/index.html.src
+++ b/system/doc/top/templates/index.html.src
@@ -29,20 +29,24 @@ limitations under the License.
</script>
</head>
-<body bgcolor=white text="#000000" link="#0000ff" vlink="#ff00ff"
- alink="#ff0000">
+<body>
<div id="container">
<div id="leftnav">
<div class="innertube">
-<img alt="Erlang logo" src="erlang-logo.png"/ >
-<p/>
-<small><a href="applications.html">Applications</a><br>
-<a href="man_index.html">Modules</a></small>
-<p/>
-<a href="javascript:openAllFlips()">Expand All</a><br>
-<a href="javascript:closeAllFlips()">Contract All</a>
-<p/>
+<div class="erlang-logo-wrapper">
+ <img alt="Erlang logo" src="erlang-logo.png" class="erlang-logo"/ >
+</div>
+
+<ul class="section-links">
+ <li><a href="applications.html">Applications</a></li>
+ <li><a href="man_index.html" class="modules">Modules</a></li>
+</ul>
+
+<ul class="expand-collapse-items">
+ <li><a href="javascript:openAllFlips()">Expand All</a></li>
+ <li><a href="javascript:closeAllFlips()">Contract All</a></li>
+</ul>
<ul class="flipMenu">
<li>System Documentation
@@ -60,8 +64,8 @@ limitations under the License.
</ul>
</li>
</ul>
-<b>Application Groups</b>
-<br/>
+
+<h3>Application Groups</h3>
<ul class="flipMenu">
#applinks#
@@ -73,24 +77,12 @@ limitations under the License.
<div id="content">
<div class="innertube">
-<center>
-<font size="+1"><b>Erlang/OTP #otp_base_vsn#</b></font><br>
-</center>
-<center>
-<p>
-<font size="+1">Welcome to Erlang/OTP, a complete<br>
-development environment<br>
-for concurrent programming.</font>
-</p>
-</center>
-<br>
-<br>
-<br>
-<p><b>
-<font size="+1">
-Some hints that may get you started faster
-</font>
-</b></p>
+ <h1 class="main-title">Erlang/OTP #otp_base_vsn#</h1>
+ <p class="main-description">
+ Welcome to Erlang/OTP, a complete development environment for concurrent programming.
+ </p>
+
+ <h2>Some hints that may get you started faster</h2>
<ul>