aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--HOWTO/INSTALL.md6
-rw-r--r--erts/aclocal.m493
-rw-r--r--erts/doc/src/notes.xml76
-rw-r--r--erts/emulator/beam/beam_debug.c101
-rw-r--r--erts/emulator/beam/beam_emu.c1650
-rw-r--r--erts/emulator/beam/beam_load.c151
-rw-r--r--erts/emulator/beam/beam_load.h1
-rw-r--r--erts/emulator/beam/erl_arith.c11
-rw-r--r--erts/emulator/beam/erl_bif_info.c9
-rw-r--r--erts/emulator/beam/erl_debug.c25
-rw-r--r--erts/emulator/beam/erl_debug.h6
-rw-r--r--erts/emulator/beam/erl_process.c19
-rw-r--r--erts/emulator/beam/erl_process.h6
-rw-r--r--erts/emulator/beam/erl_term.c6
-rw-r--r--erts/emulator/beam/erl_term.h53
-rw-r--r--erts/emulator/beam/erl_time.h6
-rw-r--r--erts/emulator/beam/erl_time_sup.c85
-rw-r--r--erts/emulator/beam/erl_trace.c24
-rw-r--r--erts/emulator/beam/erl_vm.h9
-rw-r--r--erts/emulator/beam/global.h67
-rw-r--r--erts/emulator/beam/io.c35
-rw-r--r--erts/emulator/beam/ops.tab863
-rw-r--r--erts/emulator/test/erts_debug_SUITE.erl47
-rw-r--r--erts/emulator/test/trace_port_SUITE.erl45
-rw-r--r--erts/emulator/test/trace_port_SUITE_data/echo_drv.c12
-rwxr-xr-xerts/emulator/utils/beam_makeops85
-rw-r--r--lib/.gitignore2
-rw-r--r--lib/public_key/doc/src/public_key.xml11
-rw-r--r--lib/runtime_tools/c_src/trace_file_drv.c24
-rw-r--r--lib/runtime_tools/doc/src/notes.xml17
-rw-r--r--lib/runtime_tools/vsn.mk2
-rw-r--r--lib/ssh/src/ssh_transport.erl33
-rw-r--r--lib/ssh/test/Makefile2
-rw-r--r--lib/ssh/test/ssh_basic_SUITE.erl2
-rw-r--r--lib/ssh/test/ssh_protocol_SUITE.erl404
-rw-r--r--lib/ssh/test/ssh_protocol_SUITE_data/id_dsa13
-rw-r--r--lib/ssh/test/ssh_protocol_SUITE_data/id_rsa15
-rw-r--r--lib/ssh/test/ssh_protocol_SUITE_data/ssh_host_dsa_key13
-rw-r--r--lib/ssh/test/ssh_protocol_SUITE_data/ssh_host_dsa_key.pub11
-rw-r--r--lib/ssh/test/ssh_protocol_SUITE_data/ssh_host_rsa_key16
-rw-r--r--lib/ssh/test/ssh_protocol_SUITE_data/ssh_host_rsa_key.pub5
-rw-r--r--lib/ssh/test/ssh_trpt_test_lib.erl700
-rw-r--r--lib/ssl/test/ssl_ECC_SUITE.erl2
-rw-r--r--lib/ssl/test/ssl_basic_SUITE.erl23
-rw-r--r--lib/ssl/test/ssl_payload_SUITE.erl11
-rw-r--r--lib/ssl/test/ssl_test_lib.erl3
-rw-r--r--lib/tools/doc/src/make.xml2
-rw-r--r--lib/wx/api_gen/gen_util.erl4
-rw-r--r--lib/wx/api_gen/wx_extra/wxEvtHandler.c_src2
-rw-r--r--lib/wx/api_gen/wx_extra/wxEvtHandler.erl2
-rw-r--r--lib/wx/api_gen/wx_gen.erl10
-rw-r--r--lib/wx/api_gen/wx_gen_cpp.erl18
-rw-r--r--lib/wx/api_gen/wxapi.conf38
-rw-r--r--lib/wx/c_src/gen/wxe_events.cpp8
-rw-r--r--lib/wx/c_src/gen/wxe_init.cpp468
-rw-r--r--lib/wx/c_src/wxe_impl.cpp42
-rw-r--r--lib/wx/c_src/wxe_impl.h5
-rw-r--r--lib/wx/include/wx.hrl474
-rw-r--r--lib/wx/src/gen/wxEvtHandler.erl2
-rw-r--r--lib/wx/src/gen/wxMouseCaptureLostEvent.erl65
-rw-r--r--lib/wx/src/wxe_server.erl35
-rw-r--r--lib/wx/test/wx_class_SUITE.erl36
-rw-r--r--lib/wx/test/wx_event_SUITE.erl11
-rw-r--r--otp_versions.table2
64 files changed, 3784 insertions, 2240 deletions
diff --git a/HOWTO/INSTALL.md b/HOWTO/INSTALL.md
index f8900c501b..837e6cbd76 100644
--- a/HOWTO/INSTALL.md
+++ b/HOWTO/INSTALL.md
@@ -400,6 +400,12 @@ Some of the available `configure` options are:
no automatic dependency handling between applications. If you disable
an application that another application depends on, you also have to disable the
dependant application.
+* `--enable-gettimeofday-as-os-system-time` - Force usage of `gettimeofday()` for
+ OS system time.
+* `--enable-prefer-elapsed-monotonic-time-during-suspend` - Prefer an OS monotonic
+ time source with elapsed time during suspend.
+* `--disable-prefer-elapsed-monotonic-time-during-suspend` - Do not prefer an OS
+ monotonic time source with elapsed time during suspend.
* `--enable-dirty-schedulers` - Enable the **experimental** dirty schedulers
functionality. Note that the dirty schedulers functionality is experimental,
and **not supported**. This functionality **will** be subject to backward
diff --git a/erts/aclocal.m4 b/erts/aclocal.m4
index fc2078025e..75f74a14eb 100644
--- a/erts/aclocal.m4
+++ b/erts/aclocal.m4
@@ -707,9 +707,15 @@ esac
AC_DEFUN(ERL_MONOTONIC_CLOCK,
[
- default_resolution_clock_gettime_monotonic="CLOCK_HIGHRES CLOCK_BOOTTIME CLOCK_MONOTONIC"
- low_resolution_clock_gettime_monotonic="CLOCK_MONOTONIC_COARSE CLOCK_MONOTONIC_FAST"
- high_resolution_clock_gettime_monotonic="CLOCK_MONOTONIC_PRECISE"
+ if test "$3" = "yes"; then
+ default_resolution_clock_gettime_monotonic="CLOCK_HIGHRES CLOCK_BOOTTIME CLOCK_MONOTONIC"
+ low_resolution_clock_gettime_monotonic="CLOCK_MONOTONIC_COARSE CLOCK_MONOTONIC_FAST"
+ high_resolution_clock_gettime_monotonic="CLOCK_MONOTONIC_PRECISE"
+ else
+ default_resolution_clock_gettime_monotonic="CLOCK_HIGHRES CLOCK_UPTIME CLOCK_MONOTONIC"
+ low_resolution_clock_gettime_monotonic="CLOCK_MONOTONIC_COARSE CLOCK_UPTIME_FAST"
+ high_resolution_clock_gettime_monotonic="CLOCK_UPTIME_PRECISE"
+ fi
case "$1" in
high_resolution)
@@ -1441,7 +1447,7 @@ AC_ARG_WITH(with_sparc_memory_order,
LM_CHECK_THR_LIB
ERL_INTERNAL_LIBS
-ERL_MONOTONIC_CLOCK(high_resolution)
+ERL_MONOTONIC_CLOCK(high_resolution, undefined, no)
case $erl_monotonic_clock_func in
clock_gettime)
@@ -1860,7 +1866,7 @@ case "$THR_LIB_NAME" in
#define _DARWIN_C_SOURCE
#include <pthread.h>],
[char buff[256]; pthread_getname_np(pthread_self(), buff, 256);],
- pthread_getname=normal)
+ pthread_getname=linux)
AC_TRY_LINK([#define __USE_GNU
#define _DARWIN_C_SOURCE
#include <pthread.h>],
@@ -2160,7 +2166,7 @@ AC_DEFUN(ERL_TIME_CORRECTION,
AC_ARG_WITH(clock-resolution,
AS_HELP_STRING([--with-clock-resolution=high|low|default],
- [specify wanted clock resolution)]))
+ [specify wanted clock resolution]))
AC_ARG_WITH(clock-gettime-realtime-id,
AS_HELP_STRING([--with-clock-gettime-realtime-id=CLOCKID],
@@ -2170,6 +2176,24 @@ AC_ARG_WITH(clock-gettime-monotonic-id,
AS_HELP_STRING([--with-clock-gettime-monotonic-id=CLOCKID],
[specify clock id to use with clock_gettime() for monotonic time)]))
+AC_ARG_ENABLE(prefer-elapsed-monotonic-time-during-suspend,
+ AS_HELP_STRING([--enable-prefer-elapsed-monotonic-time-during-suspend],
+ [Prefer an OS monotonic time source with elapsed time during suspend])
+ AS_HELP_STRING([--disable-prefer-elapsed-monotonic-time-during-suspend],
+ [Do not prefer an OS monotonic time source with elapsed time during suspend]),
+[ case "$enableval" in
+ yes) prefer_elapsed_monotonic_time_during_suspend=yes ;;
+ *) prefer_elapsed_monotonic_time_during_suspend=no ;;
+ esac ], prefer_elapsed_monotonic_time_during_suspend=no)
+
+AC_ARG_ENABLE(gettimeofday-as-os-system-time,
+ AS_HELP_STRING([--enable-gettimeofday-as-os-system-time],
+ [Force usage of gettimeofday() for OS system time]),
+[ case "$enableval" in
+ yes) force_gettimeofday_os_system_time=yes ;;
+ *) force_gettimeofday_os_system_time=no ;;
+ esac ], force_gettimeofday_os_system_time=no)
+
case "$with_clock_resolution" in
""|no|yes)
with_clock_resolution=default;;
@@ -2180,6 +2204,17 @@ case "$with_clock_resolution" in
;;
esac
+if test "$force_gettimeofday_os_system_time" = "yes"; then
+
+ AC_CHECK_FUNCS([gettimeofday])
+ if test "$ac_cv_func_gettimeofday" = "yes"; then
+ AC_DEFINE(OS_SYSTEM_TIME_GETTIMEOFDAY, [1], [Define if you want to implement erts_os_system_time() using gettimeofday()])
+ else
+ AC_MSG_ERROR([No gettimeofday() available])
+ fi
+
+else # $force_gettimeofday_os_system_time != yes
+
case "$with_clock_gettime_realtime_id" in
""|no)
with_clock_gettime_realtime_id=no
@@ -2197,23 +2232,6 @@ case "$with_clock_gettime_realtime_id" in
;;
esac
-case "$with_clock_gettime_monotonic_id" in
- ""|no)
- with_clock_gettime_monotonic_id=no
- ;;
- CLOCK_*CPUTIME*)
- AC_MSG_ERROR([Invalid clock_gettime() monotonic clock id: Refusing to use the cputime clock id $with_clock_gettime_monotonic_id as monotonic clock id])
- ;;
- CLOCK_REALTIME*|CLOCK_TAI*)
- AC_MSG_ERROR([Invalid clock_gettime() monotonic clock id: Refusing to use the realtime clock id $with_clock_gettime_monotonic_id as monotonic clock id])
- ;;
- CLOCK_*)
- ;;
- *)
- AC_MSG_ERROR([Invalid clock_gettime() clock id: $with_clock_gettime_monotonic_id])
- ;;
-esac
-
case "$with_clock_resolution-$with_clock_gettime_realtime_id" in
high-no)
ERL_WALL_CLOCK(high_resolution);;
@@ -2254,15 +2272,34 @@ if test "x$erl_wall_clock_id" != "x"; then
AC_DEFINE_UNQUOTED(WALL_CLOCK_ID, [$erl_wall_clock_id], [Define to wall clock id to use])
fi
+fi # $force_gettimeofday_os_system_time != yes
+
+case "$with_clock_gettime_monotonic_id" in
+ ""|no)
+ with_clock_gettime_monotonic_id=no
+ ;;
+ CLOCK_*CPUTIME*)
+ AC_MSG_ERROR([Invalid clock_gettime() monotonic clock id: Refusing to use the cputime clock id $with_clock_gettime_monotonic_id as monotonic clock id])
+ ;;
+ CLOCK_REALTIME*|CLOCK_TAI*)
+ AC_MSG_ERROR([Invalid clock_gettime() monotonic clock id: Refusing to use the realtime clock id $with_clock_gettime_monotonic_id as monotonic clock id])
+ ;;
+ CLOCK_*)
+ ;;
+ *)
+ AC_MSG_ERROR([Invalid clock_gettime() clock id: $with_clock_gettime_monotonic_id])
+ ;;
+esac
+
case "$with_clock_resolution-$with_clock_gettime_monotonic_id" in
high-no)
- ERL_MONOTONIC_CLOCK(high_resolution);;
+ ERL_MONOTONIC_CLOCK(high_resolution, undefined, $prefer_elapsed_monotonic_time_during_suspend);;
low-no)
- ERL_MONOTONIC_CLOCK(low_resolution);;
+ ERL_MONOTONIC_CLOCK(low_resolution, undefined, $prefer_elapsed_monotonic_time_during_suspend);;
default-no)
- ERL_MONOTONIC_CLOCK(default_resolution);;
+ ERL_MONOTONIC_CLOCK(default_resolution, undefined, $prefer_elapsed_monotonic_time_during_suspend);;
*)
- ERL_MONOTONIC_CLOCK(custom_resolution, $with_clock_gettime_monotonic_id);;
+ ERL_MONOTONIC_CLOCK(custom_resolution, $with_clock_gettime_monotonic_id, $prefer_elapsed_monotonic_time_during_suspend);;
esac
case "$erl_monotonic_clock_func-$erl_monotonic_clock_id-$with_clock_gettime_monotonic_id" in
@@ -2310,7 +2347,7 @@ if test $erl_cv_clock_gettime_monotonic_raw = yes; then
AC_DEFINE(HAVE_CLOCK_GETTIME_MONOTONIC_RAW, [1], [Define if you have clock_gettime(CLOCK_MONOTONIC_RAW, _)])
fi
-ERL_MONOTONIC_CLOCK(high_resolution)
+ERL_MONOTONIC_CLOCK(high_resolution, undefined, no)
case $$erl_monotonic_clock_low_resolution-$erl_monotonic_clock_func in
no-mach_clock_get_time)
diff --git a/erts/doc/src/notes.xml b/erts/doc/src/notes.xml
index 64de3aa622..ab6291614c 100644
--- a/erts/doc/src/notes.xml
+++ b/erts/doc/src/notes.xml
@@ -31,6 +31,82 @@
</header>
<p>This document describes the changes made to the ERTS application.</p>
+<section><title>Erts 7.0.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ A process could end up in an inconsistent half exited
+ state in the runtime system without SMP support. This
+ could occur if the processes was traced by a port that it
+ also was linked to, and the port terminated abnormally
+ while handling a trace message for the process.</p>
+ <p>
+ This bug has always existed in the runtime system without
+ SMP support, but never in the runtime system with SMP
+ support.</p>
+ <p>
+ Own Id: OTP-12889 Aux Id: seq12885 </p>
+ </item>
+ <item>
+ <p>
+ Removed unnecessary copying of data when retrieving
+ corrected Erlang monotonic time.</p>
+ <p>
+ Own Id: OTP-12894</p>
+ </item>
+ <item>
+ <p>
+ Changed default OS monotonic clock source chosen at build
+ time. This in order to improve performance. The behavior
+ will now on most systems be that (both OS and Erlang)
+ monotonic time stops when the system is suspended.</p>
+ <p>
+ If you prefer that monotonic time elapse during suspend
+ of the machine, you can pass the command line argument
+ <c>--enable-prefer-elapsed-monotonic-time-during-suspend</c>
+ to <c>configure</c> when building Erlang/OTP. The
+ configuration stage will try to find such a clock source,
+ but might not be able to find it. Note that there might
+ be a performance penalty associated with such a clock
+ source.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-12895</p>
+ </item>
+ <item>
+ <p>
+ <c>erlang:system_info(end_time)</c> returned a faulty
+ value on 32-bit architectures.</p>
+ <p>
+ Own Id: OTP-12896</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ The <c>configure</c> command line argument
+ <c>--enable-gettimeofday-as-os-system-time</c> has been
+ added which force usage of <c>gettimeofday()</c> for OS
+ system time. This will improve performance of
+ <c>os:system_time()</c> and <c>os:timestamp()</c> on
+ MacOS X, at the expense of worse accuracy, resolution and
+ precision of Erlang monotonic time, Erlang system time,
+ and OS system time.</p>
+ <p>
+ Own Id: OTP-12892</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Erts 7.0.1</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/erts/emulator/beam/beam_debug.c b/erts/emulator/beam/beam_debug.c
index c756de8c8e..ea1f2cd012 100644
--- a/erts/emulator/beam/beam_debug.c
+++ b/erts/emulator/beam/beam_debug.c
@@ -432,39 +432,33 @@ print_op(int to, void *to_arg, int op, int size, BeamInstr* addr)
while (*sign) {
switch (*sign) {
case 'r': /* x(0) */
- erts_print(to, to_arg, "x(0)");
+ erts_print(to, to_arg, "r(0)");
break;
case 'x': /* x(N) */
- if (reg_index(ap[0]) == 0) {
- erts_print(to, to_arg, "x[0]");
- } else {
- erts_print(to, to_arg, "x(%d)", reg_index(ap[0]));
+ {
+ Uint n = ap[0] / sizeof(Eterm);
+ erts_print(to, to_arg, "x(%d)", n);
+ ap++;
}
- ap++;
break;
case 'y': /* y(N) */
- erts_print(to, to_arg, "y(%d)", reg_index(ap[0]) - CP_SIZE);
- ap++;
+ {
+ Uint n = ap[0] / sizeof(Eterm) - CP_SIZE;
+ erts_print(to, to_arg, "y(%d)", n);
+ ap++;
+ }
break;
case 'n': /* Nil */
erts_print(to, to_arg, "[]");
break;
case 's': /* Any source (tagged constant or register) */
- tag = beam_reg_tag(*ap);
- if (tag == X_REG_DEF) {
- if (reg_index(*ap) == 0) {
- erts_print(to, to_arg, "x[0]");
- } else {
- erts_print(to, to_arg, "x(%d)", reg_index(*ap));
- }
- ap++;
- break;
- } else if (tag == Y_REG_DEF) {
- erts_print(to, to_arg, "y(%d)", reg_index(*ap) - CP_SIZE);
+ tag = loader_tag(*ap);
+ if (tag == LOADER_X_REG) {
+ erts_print(to, to_arg, "x(%d)", loader_x_reg_index(*ap));
ap++;
break;
- } else if (tag == R_REG_DEF) {
- erts_print(to, to_arg, "x(0)");
+ } else if (tag == LOADER_Y_REG) {
+ erts_print(to, to_arg, "y(%d)", loader_y_reg_index(*ap) - CP_SIZE);
ap++;
break;
}
@@ -481,20 +475,12 @@ print_op(int to, void *to_arg, int op, int size, BeamInstr* addr)
ap++;
break;
case 'd': /* Destination (x(0), x(N), y(N)) */
- switch (beam_reg_tag(*ap)) {
- case X_REG_DEF:
- if (reg_index(*ap) == 0) {
- erts_print(to, to_arg, "x[0]");
- } else {
- erts_print(to, to_arg, "x(%d)", reg_index(*ap));
- }
- break;
- case Y_REG_DEF:
- erts_print(to, to_arg, "y(%d)", reg_index(*ap) - CP_SIZE);
- break;
- case R_REG_DEF:
- erts_print(to, to_arg, "x(0)");
- break;
+ if (*ap & 1) {
+ erts_print(to, to_arg, "y(%d)",
+ *ap / sizeof(Eterm) - CP_SIZE);
+ } else {
+ erts_print(to, to_arg, "x(%d)",
+ *ap / sizeof(Eterm));
}
ap++;
break;
@@ -561,7 +547,7 @@ print_op(int to, void *to_arg, int op, int size, BeamInstr* addr)
ap++;
break;
case 'l': /* fr(N) */
- erts_print(to, to_arg, "fr(%d)", reg_index(ap[0]));
+ erts_print(to, to_arg, "fr(%d)", loader_reg_index(ap[0]));
ap++;
break;
default:
@@ -580,7 +566,6 @@ print_op(int to, void *to_arg, int op, int size, BeamInstr* addr)
unpacked = ap;
ap = addr + size;
switch (op) {
- case op_i_select_val_lins_rfI:
case op_i_select_val_lins_xfI:
case op_i_select_val_lins_yfI:
{
@@ -600,7 +585,6 @@ print_op(int to, void *to_arg, int op, int size, BeamInstr* addr)
}
}
break;
- case op_i_select_val_bins_rfI:
case op_i_select_val_bins_xfI:
case op_i_select_val_bins_yfI:
{
@@ -614,7 +598,6 @@ print_op(int to, void *to_arg, int op, int size, BeamInstr* addr)
}
}
break;
- case op_i_select_tuple_arity_rfI:
case op_i_select_tuple_arity_xfI:
case op_i_select_tuple_arity_yfI:
{
@@ -639,7 +622,6 @@ print_op(int to, void *to_arg, int op, int size, BeamInstr* addr)
}
}
break;
- case op_i_jump_on_val_rfII:
case op_i_jump_on_val_xfII:
case op_i_jump_on_val_yfII:
{
@@ -651,7 +633,6 @@ print_op(int to, void *to_arg, int op, int size, BeamInstr* addr)
}
}
break;
- case op_i_jump_on_val_zero_rfI:
case op_i_jump_on_val_zero_xfI:
case op_i_jump_on_val_zero_yfI:
{
@@ -663,29 +644,47 @@ print_op(int to, void *to_arg, int op, int size, BeamInstr* addr)
}
}
break;
- case op_i_put_tuple_rI:
case op_i_put_tuple_xI:
case op_i_put_tuple_yI:
case op_new_map_dII:
case op_update_map_assoc_jsdII:
case op_update_map_exact_jsdII:
- case op_i_get_map_elements_fsI:
{
int n = unpacked[-1];
while (n > 0) {
- if (!is_header(ap[0])) {
+ switch (loader_tag(ap[0])) {
+ case LOADER_X_REG:
+ erts_print(to, to_arg, " x(%d)", loader_x_reg_index(ap[0]));
+ break;
+ case LOADER_Y_REG:
+ erts_print(to, to_arg, " x(%d)", loader_y_reg_index(ap[0]));
+ break;
+ default:
erts_print(to, to_arg, " %T", (Eterm) ap[0]);
+ break;
+ }
+ ap++, size++, n--;
+ }
+ }
+ break;
+ case op_i_get_map_elements_fsI:
+ {
+ int n = unpacked[-1];
+
+ while (n > 0) {
+ if (n % 3 == 1) {
+ erts_print(to, to_arg, " %X", ap[0]);
} else {
- switch ((ap[0] >> 2) & 0x03) {
- case R_REG_DEF:
- erts_print(to, to_arg, " x(0)");
+ switch (loader_tag(ap[0])) {
+ case LOADER_X_REG:
+ erts_print(to, to_arg, " x(%d)", loader_x_reg_index(ap[0]));
break;
- case X_REG_DEF:
- erts_print(to, to_arg, " x(%d)", ap[0] >> 4);
+ case LOADER_Y_REG:
+ erts_print(to, to_arg, " y(%d)", loader_y_reg_index(ap[0]));
break;
- case Y_REG_DEF:
- erts_print(to, to_arg, " y(%d)", ap[0] >> 4);
+ default:
+ erts_print(to, to_arg, " %T", (Eterm) ap[0]);
break;
}
}
diff --git a/erts/emulator/beam/beam_emu.c b/erts/emulator/beam/beam_emu.c
index f4111c19f1..a42ce1c9f1 100644
--- a/erts/emulator/beam/beam_emu.c
+++ b/erts/emulator/beam/beam_emu.c
@@ -99,10 +99,7 @@ do { \
do { \
int i_; \
int Arity_ = PC[-1]; \
- if (Arity_ > 0) { \
- CHECK_TERM(r(0)); \
- } \
- for (i_ = 1; i_ < Arity_; i_++) { \
+ for (i_ = 0; i_ < Arity_; i_++) { \
CHECK_TERM(x(i_)); \
} \
} while (0)
@@ -151,25 +148,21 @@ do { \
ASSERT(VALID_INSTR(* (Eterm *)(ip))); \
I = (ip)
-#define FetchArgs(S1, S2) tmp_arg1 = (S1); tmp_arg2 = (S2)
+/*
+ * Register target (X or Y register).
+ */
+#define REG_TARGET(Target) (*(((Target) & 1) ? &yb(Target-1) : &xb(Target)))
/*
* Store a result into a register given a destination descriptor.
*/
-#define StoreResult(Result, DestDesc) \
- do { \
- Eterm stb_reg; \
- stb_reg = (DestDesc); \
- CHECK_TERM(Result); \
- switch (beam_reg_tag(stb_reg)) { \
- case R_REG_DEF: \
- r(0) = (Result); break; \
- case X_REG_DEF: \
- xb(x_reg_offset(stb_reg)) = (Result); break; \
- default: \
- yb(y_reg_offset(stb_reg)) = (Result); break; \
- } \
+#define StoreResult(Result, DestDesc) \
+ do { \
+ Eterm stb_reg; \
+ stb_reg = (DestDesc); \
+ CHECK_TERM(Result); \
+ REG_TARGET(stb_reg) = (Result); \
} while (0)
#define StoreSimpleDest(Src, Dest) Dest = (Src)
@@ -180,22 +173,16 @@ do { \
* be just before the next instruction.
*/
-#define StoreBifResult(Dst, Result) \
- do { \
- BeamInstr* stb_next; \
- Eterm stb_reg; \
- stb_reg = Arg(Dst); \
- I += (Dst) + 2; \
- stb_next = (BeamInstr *) *I; \
- CHECK_TERM(Result); \
- switch (beam_reg_tag(stb_reg)) { \
- case R_REG_DEF: \
- r(0) = (Result); Goto(stb_next); \
- case X_REG_DEF: \
- xb(x_reg_offset(stb_reg)) = (Result); Goto(stb_next); \
- default: \
- yb(y_reg_offset(stb_reg)) = (Result); Goto(stb_next); \
- } \
+#define StoreBifResult(Dst, Result) \
+ do { \
+ BeamInstr* stb_next; \
+ Eterm stb_reg; \
+ stb_reg = Arg(Dst); \
+ I += (Dst) + 2; \
+ stb_next = (BeamInstr *) *I; \
+ CHECK_TERM(Result); \
+ REG_TARGET(stb_reg) = (Result); \
+ Goto(stb_next); \
} while (0)
#define ClauseFail() goto jump_f
@@ -293,7 +280,7 @@ void** beam_ops;
#define Ib(N) (N)
#define x(N) reg[N]
#define y(N) E[N]
-#define r(N) x##N
+#define r(N) x(N)
/*
* Makes sure that there are StackNeed + HeapNeed + 1 words available
@@ -309,12 +296,10 @@ void** beam_ops;
needed = (StackNeed) + 1; \
if (E - HTOP < (needed + (HeapNeed))) { \
SWAPOUT; \
- reg[0] = r(0); \
PROCESS_MAIN_CHK_LOCKS(c_p); \
FCALLS -= erts_garbage_collect(c_p, needed + (HeapNeed), reg, (M)); \
ERTS_VERIFY_UNUSED_TEMP_ALLOC(c_p); \
PROCESS_MAIN_CHK_LOCKS(c_p); \
- r(0) = reg[0]; \
SWAPIN; \
} \
E -= needed; \
@@ -363,12 +348,10 @@ void** beam_ops;
unsigned need = (Nh); \
if ((E - HTOP < need) || (MSO(c_p).overhead + (VNh) >= BIN_VHEAP_SZ(c_p))) {\
SWAPOUT; \
- reg[0] = r(0); \
PROCESS_MAIN_CHK_LOCKS(c_p); \
FCALLS -= erts_garbage_collect(c_p, need, reg, (Live)); \
ERTS_VERIFY_UNUSED_TEMP_ALLOC(c_p); \
PROCESS_MAIN_CHK_LOCKS(c_p); \
- r(0) = reg[0]; \
SWAPIN; \
} \
HEAP_SPACE_VERIFIED(need); \
@@ -386,12 +369,10 @@ void** beam_ops;
unsigned need = (Nh); \
if (E - HTOP < need) { \
SWAPOUT; \
- reg[0] = r(0); \
PROCESS_MAIN_CHK_LOCKS(c_p); \
FCALLS -= erts_garbage_collect(c_p, need, reg, (Live)); \
ERTS_VERIFY_UNUSED_TEMP_ALLOC(c_p); \
PROCESS_MAIN_CHK_LOCKS(c_p); \
- r(0) = reg[0]; \
SWAPIN; \
} \
HEAP_SPACE_VERIFIED(need); \
@@ -408,15 +389,11 @@ void** beam_ops;
unsigned need = (Nh); \
if (E - HTOP < need) { \
SWAPOUT; \
- reg[0] = r(0); \
reg[Live] = Extra; \
PROCESS_MAIN_CHK_LOCKS(c_p); \
FCALLS -= erts_garbage_collect(c_p, need, reg, (Live)+1); \
ERTS_VERIFY_UNUSED_TEMP_ALLOC(c_p); \
PROCESS_MAIN_CHK_LOCKS(c_p); \
- if (Live > 0) { \
- r(0) = reg[0]; \
- } \
Extra = reg[Live]; \
SWAPIN; \
} \
@@ -439,7 +416,6 @@ void** beam_ops;
#define MakeFun(FunP, NumFree) \
do { \
SWAPOUT; \
- reg[0] = r(0); \
r(0) = new_fun(c_p, reg, (ErlFunEntry *) FunP, NumFree); \
SWAPIN; \
} while (0)
@@ -531,15 +507,19 @@ void** beam_ops;
ASSERT(VALID_INSTR(Dst)); \
Goto(Dst)
-#define GetR(pos, tr) \
- do { \
- tr = Arg(pos); \
- switch (beam_reg_tag(tr)) { \
- case R_REG_DEF: tr = r(0); break; \
- case X_REG_DEF: tr = xb(x_reg_offset(tr)); break; \
- case Y_REG_DEF: ASSERT(y_reg_offset(tr) >= 1); tr = yb(y_reg_offset(tr)); break; \
- } \
- CHECK_TERM(tr); \
+#define GetR(pos, tr) \
+ do { \
+ tr = Arg(pos); \
+ switch (loader_tag(tr)) { \
+ case LOADER_X_REG: \
+ tr = x(loader_x_reg_index(tr)); \
+ break; \
+ case LOADER_Y_REG: \
+ ASSERT(loader_y_reg_index(tr) >= 1); \
+ tr = y(loader_y_reg_index(tr)); \
+ break; \
+ } \
+ CHECK_TERM(tr); \
} while (0)
#define GetArg1(N, Dst) GetR((N), Dst)
@@ -557,24 +537,93 @@ void** beam_ops;
HTOP += 2; \
} while (0)
+#define Swap(R1, R2) \
+ do { \
+ Eterm V = R1; \
+ R1 = R2; \
+ R2 = V; \
+ } while (0)
+
+#define SwapTemp(R1, R2, Tmp) \
+ do { \
+ Eterm V = R1; \
+ R1 = R2; \
+ R2 = Tmp = V; \
+ } while (0)
+
#define Move(Src, Dst, Store) \
do { \
Eterm term = (Src); \
Store(term, Dst); \
} while (0)
-#define Move2(S1, D1, S2, D2) D1 = (S1); D2 = (S2)
+#define Move2Par(S1, D1, S2, D2) \
+ do { \
+ Eterm V1, V2; \
+ V1 = (S1); V2 = (S2); D1 = V1; D2 = V2; \
+ } while (0)
+
+#define MoveShift(Src, SD, D) \
+ do { \
+ Eterm V; \
+ V = Src; D = SD; SD = V; \
+ } while (0)
+
+#define MoveDup(Src, D1, D2) \
+ do { \
+ D1 = D2 = (Src); \
+ } while (0)
+
#define Move3(S1, D1, S2, D2, S3, D3) D1 = (S1); D2 = (S2); D3 = (S3)
-#define MoveGenDest(src, dstp) \
- if ((dstp) == NULL) { r(0) = (src); } else { *(dstp) = src; }
+#define MoveWindow3(S1, S2, S3, D) \
+ do { \
+ Eterm xt0, xt1, xt2; \
+ Eterm *y = &D; \
+ xt0 = S1; \
+ xt1 = S2; \
+ xt2 = S3; \
+ y[0] = xt0; \
+ y[1] = xt1; \
+ y[2] = xt2; \
+ } while (0)
+
+#define MoveWindow4(S1, S2, S3, S4, D) \
+ do { \
+ Eterm xt0, xt1, xt2, xt3; \
+ Eterm *y = &D; \
+ xt0 = S1; \
+ xt1 = S2; \
+ xt2 = S3; \
+ xt3 = S4; \
+ y[0] = xt0; \
+ y[1] = xt1; \
+ y[2] = xt2; \
+ y[3] = xt3; \
+ } while (0)
+
+#define MoveWindow5(S1, S2, S3, S4, S5, D) \
+ do { \
+ Eterm xt0, xt1, xt2, xt3, xt4; \
+ Eterm *y = &D; \
+ xt0 = S1; \
+ xt1 = S2; \
+ xt2 = S3; \
+ xt3 = S4; \
+ xt4 = S5; \
+ y[0] = xt0; \
+ y[1] = xt1; \
+ y[2] = xt2; \
+ y[3] = xt3; \
+ y[4] = xt4; \
+ } while (0)
-#define MoveReturn(Src, Dest) \
- (Dest) = (Src); \
- I = c_p->cp; \
- ASSERT(VALID_INSTR(*c_p->cp)); \
- c_p->cp = 0; \
- CHECK_TERM(r(0)); \
+#define MoveReturn(Src) \
+ x(0) = (Src); \
+ I = c_p->cp; \
+ ASSERT(VALID_INSTR(*c_p->cp)); \
+ c_p->cp = 0; \
+ CHECK_TERM(r(0)); \
Goto(*I)
#define DeallocateReturn(Deallocate) \
@@ -586,26 +635,26 @@ void** beam_ops;
Goto(*I); \
} while (0)
-#define MoveDeallocateReturn(Src, Dest, Deallocate) \
- (Dest) = (Src); \
+#define MoveDeallocateReturn(Src, Deallocate) \
+ x(0) = (Src); \
DeallocateReturn(Deallocate)
-#define MoveCall(Src, Dest, CallDest, Size) \
- (Dest) = (Src); \
+#define MoveCall(Src, CallDest, Size) \
+ x(0) = (Src); \
SET_CP(c_p, I+Size+1); \
- SET_I((BeamInstr *) CallDest); \
+ SET_I((BeamInstr *) CallDest); \
Dispatch();
-#define MoveCallLast(Src, Dest, CallDest, Deallocate) \
- (Dest) = (Src); \
- RESTORE_CP(E); \
- E = ADD_BYTE_OFFSET(E, (Deallocate)); \
- SET_I((BeamInstr *) CallDest); \
+#define MoveCallLast(Src, CallDest, Deallocate) \
+ x(0) = (Src); \
+ RESTORE_CP(E); \
+ E = ADD_BYTE_OFFSET(E, (Deallocate)); \
+ SET_I((BeamInstr *) CallDest); \
Dispatch();
-#define MoveCallOnly(Src, Dest, CallDest) \
- (Dest) = (Src); \
- SET_I((BeamInstr *) CallDest); \
+#define MoveCallOnly(Src, CallDest) \
+ x(0) = (Src); \
+ SET_I((BeamInstr *) CallDest); \
Dispatch();
#define MoveJump(Src) \
@@ -613,57 +662,56 @@ void** beam_ops;
SET_I((BeamInstr *) Arg(0)); \
Goto(*I);
-#define GetList(Src, H, T) do { \
- Eterm* tmp_ptr = list_val(Src); \
- H = CAR(tmp_ptr); \
- T = CDR(tmp_ptr); } while (0)
-
-#define GetTupleElement(Src, Element, Dest) \
- do { \
- tmp_arg1 = (Eterm) (((unsigned char *) tuple_val(Src)) + (Element));\
- (Dest) = (*(Eterm *) tmp_arg1); \
- } while (0)
-
-#define ExtractNextElement(Dest) \
- tmp_arg1 += sizeof(Eterm); \
- (Dest) = (* (Eterm *) (((unsigned char *) tmp_arg1)))
-
-#define ExtractNextElement2(Dest) \
- do { \
- Eterm* ene_dstp = &(Dest); \
- ene_dstp[0] = ((Eterm *) tmp_arg1)[1]; \
- ene_dstp[1] = ((Eterm *) tmp_arg1)[2]; \
- tmp_arg1 += sizeof(Eterm) + sizeof(Eterm); \
+#define GetList(Src, H, T) \
+ do { \
+ Eterm* tmp_ptr = list_val(Src); \
+ Eterm hd, tl; \
+ hd = CAR(tmp_ptr); \
+ tl = CDR(tmp_ptr); \
+ H = hd; T = tl; \
} while (0)
-#define ExtractNextElement3(Dest) \
- do { \
- Eterm* ene_dstp = &(Dest); \
- ene_dstp[0] = ((Eterm *) tmp_arg1)[1]; \
- ene_dstp[1] = ((Eterm *) tmp_arg1)[2]; \
- ene_dstp[2] = ((Eterm *) tmp_arg1)[3]; \
- tmp_arg1 += 3*sizeof(Eterm); \
+#define GetTupleElement(Src, Element, Dest) \
+ do { \
+ Eterm* src; \
+ src = ADD_BYTE_OFFSET(tuple_val(Src), (Element)); \
+ (Dest) = *src; \
} while (0)
-#define ExtractNextElement4(Dest) \
- do { \
- Eterm* ene_dstp = &(Dest); \
- ene_dstp[0] = ((Eterm *) tmp_arg1)[1]; \
- ene_dstp[1] = ((Eterm *) tmp_arg1)[2]; \
- ene_dstp[2] = ((Eterm *) tmp_arg1)[3]; \
- ene_dstp[3] = ((Eterm *) tmp_arg1)[4]; \
- tmp_arg1 += 4*sizeof(Eterm); \
+#define GetTupleElement2(Src, Element, Dest) \
+ do { \
+ Eterm* src; \
+ Eterm* dst; \
+ Eterm E1, E2; \
+ src = ADD_BYTE_OFFSET(tuple_val(Src), (Element)); \
+ dst = &(Dest); \
+ E1 = src[0]; \
+ E2 = src[1]; \
+ dst[0] = E1; \
+ dst[1] = E2; \
} while (0)
-#define ExtractElement(Element, Dest) \
- do { \
- tmp_arg1 += (Element); \
- (Dest) = (* (Eterm *) tmp_arg1); \
+#define GetTupleElement3(Src, Element, Dest) \
+ do { \
+ Eterm* src; \
+ Eterm* dst; \
+ Eterm E1, E2, E3; \
+ src = ADD_BYTE_OFFSET(tuple_val(Src), (Element)); \
+ dst = &(Dest); \
+ E1 = src[0]; \
+ E2 = src[1]; \
+ E3 = src[2]; \
+ dst[0] = E1; \
+ dst[1] = E2; \
+ dst[2] = E3; \
} while (0)
#define EqualImmed(X, Y, Action) if (X != Y) { Action; }
#define NotEqualImmed(X, Y, Action) if (X == Y) { Action; }
#define EqualExact(X, Y, Action) if (!EQ(X,Y)) { Action; }
+#define NotEqualExact(X, Y, Action) if (EQ(X,Y)) { Action; }
+#define Equal(X, Y, Action) if (!CMP_EQ(X,Y)) { Action; }
+#define NotEqual(X, Y, Action) if (!CMP_NE(X,Y)) { Action; }
#define IsLessThan(X, Y, Action) if (CMP_GE(X, Y)) { Action; }
#define IsGreaterEqual(X, Y, Action) if (CMP_LT(X, Y)) { Action; }
@@ -689,17 +737,26 @@ void** beam_ops;
if (is_not_list(Src)) { Fail; } \
A(Need, Alive)
-#define IsNonemptyListTestHeap(Src, Need, Alive, Fail) \
- if (is_not_list(Src)) { Fail; } \
+#define IsNonemptyListTestHeap(Need, Alive, Fail) \
+ if (is_not_list(x(0))) { Fail; } \
TestHeap(Need, Alive)
+#define IsNonemptyListGetList(Src, H, T, Fail) \
+ if (is_not_list(Src)) { \
+ Fail; \
+ } else { \
+ Eterm* tmp_ptr = list_val(Src); \
+ Eterm hd, tl; \
+ hd = CAR(tmp_ptr); \
+ tl = CDR(tmp_ptr); \
+ H = hd; T = tl; \
+ }
+
#define IsTuple(X, Action) if (is_not_tuple(X)) Action
-#define IsArity(Pointer, Arity, Fail) \
- if (*(Eterm *) \
- (tmp_arg1 = (Eterm) (tuple_val(Pointer))) != (Arity)) \
- { \
- Fail; \
+#define IsArity(Pointer, Arity, Fail) \
+ if (*tuple_val(Pointer) != (Arity)) { \
+ Fail; \
}
#define IsMap(Src, Fail) if (!is_map(Src)) { Fail; }
@@ -736,14 +793,21 @@ void** beam_ops;
} \
} while (0)
-#define IsTupleOfArity(Src, Arity, Fail) \
- do { \
- if (is_not_tuple(Src) || \
- *(Eterm *) \
- (tmp_arg1 = (Eterm) (tuple_val(Src))) != Arity) { \
- Fail; \
- } \
+#ifdef DEBUG
+#define IsTupleOfArity(Src, Arityval, Fail) \
+ do { \
+ if (!(is_tuple(Src) && *tuple_val(Src) == Arityval)) { \
+ Fail; \
+ } \
+ } while (0)
+#else
+#define IsTupleOfArity(Src, Arityval, Fail) \
+ do { \
+ if (!(is_boxed(Src) && *tuple_val(Src) == Arityval)) { \
+ Fail; \
+ } \
} while (0)
+#endif
#define IsBoolean(X, Fail) if ((X) != am_true && (X) != am_false) { Fail; }
@@ -770,6 +834,7 @@ void** beam_ops;
#define BsGetFieldSize(Bits, Unit, Fail, Target) \
do { \
Sint _signed_size; Uint _uint_size; \
+ Uint temp_bits; \
if (is_small(Bits)) { \
_signed_size = signed_val(Bits); \
if (_signed_size < 0) { Fail; } \
@@ -784,6 +849,7 @@ void** beam_ops;
#define BsGetUncheckedFieldSize(Bits, Unit, Fail, Target) \
do { \
Sint _signed_size; Uint _uint_size; \
+ Uint temp_bits; \
if (is_small(Bits)) { \
_signed_size = signed_val(Bits); \
if (_signed_size < 0) { Fail; } \
@@ -995,23 +1061,17 @@ init_emulator(void)
*/
#if defined(__GNUC__) && defined(sparc) && !defined(DEBUG)
-# define REG_x0 asm("%l0")
# define REG_xregs asm("%l1")
# define REG_htop asm("%l2")
# define REG_stop asm("%l3")
# define REG_I asm("%l4")
# define REG_fcalls asm("%l5")
-# define REG_tmp_arg1 asm("%l6")
-# define REG_tmp_arg2 asm("%l7")
#else
-# define REG_x0
# define REG_xregs
# define REG_htop
# define REG_stop
# define REG_I
# define REG_fcalls
-# define REG_tmp_arg1
-# define REG_tmp_arg2
#endif
#ifdef USE_VM_PROBES
@@ -1129,11 +1189,6 @@ void process_main(void)
ERTS_DECLARE_DUMMY(Eterm pid);
#endif
- /*
- * X register zero; also called r(0)
- */
- register Eterm x0 REG_x0 = NIL;
-
/* Pointer to X registers: x(1)..x(N); reg[0] is used when doing GC,
* in all other cases x0 is used.
*/
@@ -1161,17 +1216,6 @@ void process_main(void)
register Sint FCALLS REG_fcalls = 0;
/*
- * Temporaries used for picking up arguments for instructions.
- */
- register Eterm tmp_arg1 REG_tmp_arg1 = NIL;
- register Eterm tmp_arg2 REG_tmp_arg2 = NIL;
-#if HEAP_ON_C_STACK
- Eterm tmp_big[2]; /* Temporary buffer for small bignums if HEAP_ON_C_STACK. */
-#else
- Eterm *tmp_big; /* Temporary buffer for small bignums if !HEAP_ON_C_STACK. */
-#endif
-
- /*
* X registers and floating point registers are located in
* scheduler specific data.
*/
@@ -1182,8 +1226,6 @@ void process_main(void)
*/
int neg_o_reds = 0;
- Eterm (*arith_func)(Process* p, Eterm* reg, Uint live);
-
#ifdef ERTS_OPCODE_COUNTER_SUPPORT
static void* counting_opcodes[] = { DEFINE_COUNTING_OPCODES };
#else
@@ -1194,8 +1236,6 @@ void process_main(void)
#endif
#endif
- Uint temp_bits; /* Temporary used by BsSkipBits2 & BsGetInteger2 */
-
Eterm pt_arity; /* Used by do_put_tuple */
Uint64 start_time = 0; /* Monitor long schedule */
@@ -1261,9 +1301,6 @@ void process_main(void)
reg = ERTS_PROC_GET_SCHDATA(c_p)->x_reg_array;
freg = ERTS_PROC_GET_SCHDATA(c_p)->f_reg_array;
-#if !HEAP_ON_C_STACK
- tmp_big = ERTS_PROC_GET_SCHDATA(c_p)->beam_emu_tmp_heap;
-#endif
ERL_BITS_RELOAD_STATEP(c_p);
{
int reds;
@@ -1272,7 +1309,7 @@ void process_main(void)
int i;
argp = c_p->arg_reg;
- for (i = c_p->arity - 1; i > 0; i--) {
+ for (i = c_p->arity - 1; i >= 0; i--) {
reg[i] = argp[i];
CHECK_TERM(reg[i]);
}
@@ -1296,12 +1333,6 @@ void process_main(void)
}
next = (BeamInstr *) *I;
- r(0) = c_p->arg_reg[0];
-#ifdef HARDDEBUG
- if (c_p->arity > 0) {
- CHECK_TERM(r(0));
- }
-#endif
SWAPIN;
ASSERT(VALID_INSTR(next));
@@ -1340,26 +1371,24 @@ void process_main(void)
#endif
#include "beam_hot.h"
-#define STORE_ARITH_RESULT(res) StoreBifResult(2, (res));
-#define ARITH_FUNC(name) erts_gc_##name
-
{
Eterm increment_reg_val;
Eterm increment_val;
Uint live;
Eterm result;
- OpCase(i_increment_yIId):
- increment_reg_val = yb(Arg(0));
+ OpCase(i_increment_rIId):
+ increment_reg_val = x(0);
+ I--;
goto do_increment;
OpCase(i_increment_xIId):
increment_reg_val = xb(Arg(0));
goto do_increment;
- OpCase(i_increment_rIId):
- increment_reg_val = r(0);
- I--;
+ OpCase(i_increment_yIId):
+ increment_reg_val = yb(Arg(0));
+ goto do_increment;
do_increment:
increment_val = Arg(1);
@@ -1368,229 +1397,133 @@ void process_main(void)
ASSERT(MY_IS_SSMALL(i) == IS_SSMALL(i));
if (MY_IS_SSMALL(i)) {
result = make_small(i);
- store_result:
StoreBifResult(3, result);
}
}
live = Arg(2);
SWAPOUT;
- reg[0] = r(0);
reg[live] = increment_reg_val;
reg[live+1] = make_small(increment_val);
result = erts_gc_mixed_plus(c_p, reg, live);
- r(0) = reg[0];
SWAPIN;
ERTS_HOLE_CHECK(c_p);
if (is_value(result)) {
- goto store_result;
+ StoreBifResult(3, result);
}
ASSERT(c_p->freason != BADMATCH || is_value(c_p->fvalue));
goto find_func_info;
}
-#define DO_BIG_ARITH(Func,Arg1,Arg2) \
- do { \
- Uint live = Arg(1); \
- SWAPOUT; \
- reg[0] = r(0); \
- reg[live] = (Arg1); \
- reg[live+1] = (Arg2); \
- result = (Func)(c_p, reg, live); \
- r(0) = reg[0]; \
- SWAPIN; \
- ERTS_HOLE_CHECK(c_p); \
- if (is_value(result)) { \
- StoreBifResult(4,result); \
- } \
- goto lb_Cl_error; \
- } while(0)
+#define DO_OUTLINED_ARITH_2(name, Op1, Op2) \
+ do { \
+ Eterm result; \
+ Uint live = Arg(1); \
+ \
+ SWAPOUT; \
+ reg[live] = Op1; \
+ reg[live+1] = Op2; \
+ result = erts_gc_##name(c_p, reg, live); \
+ SWAPIN; \
+ ERTS_HOLE_CHECK(c_p); \
+ if (is_value(result)) { \
+ StoreBifResult(4, result); \
+ } \
+ goto lb_Cl_error; \
+ } while (0)
- OpCase(i_plus_jIxxd):
{
+ Eterm PlusOp1, PlusOp2;
Eterm result;
- if (is_both_small(xb(Arg(2)), xb(Arg(3)))) {
- Sint i = signed_val(xb(Arg(2))) + signed_val(xb(Arg(3)));
+ OpCase(i_plus_jIxxd):
+ PlusOp1 = xb(Arg(2));
+ PlusOp2 = xb(Arg(3));
+ goto do_plus;
+
+ OpCase(i_plus_jIxyd):
+ PlusOp1 = xb(Arg(2));
+ PlusOp2 = yb(Arg(3));
+ goto do_plus;
+
+ OpCase(i_plus_jIssd):
+ GetArg2(2, PlusOp1, PlusOp2);
+ goto do_plus;
+
+ do_plus:
+ if (is_both_small(PlusOp1, PlusOp2)) {
+ Sint i = signed_val(PlusOp1) + signed_val(PlusOp2);
ASSERT(MY_IS_SSMALL(i) == IS_SSMALL(i));
if (MY_IS_SSMALL(i)) {
result = make_small(i);
StoreBifResult(4, result);
}
}
- DO_BIG_ARITH(ARITH_FUNC(mixed_plus), xb(Arg(2)), xb(Arg(3)));
+ DO_OUTLINED_ARITH_2(mixed_plus, PlusOp1, PlusOp2);
}
- OpCase(i_plus_jId):
{
+ Eterm MinusOp1, MinusOp2;
Eterm result;
- if (is_both_small(tmp_arg1, tmp_arg2)) {
- Sint i = signed_val(tmp_arg1) + signed_val(tmp_arg2);
- ASSERT(MY_IS_SSMALL(i) == IS_SSMALL(i));
- if (MY_IS_SSMALL(i)) {
- result = make_small(i);
- STORE_ARITH_RESULT(result);
- }
- }
- arith_func = ARITH_FUNC(mixed_plus);
- goto do_big_arith2;
- }
-
OpCase(i_minus_jIxxd):
- {
- Eterm result;
+ MinusOp1 = xb(Arg(2));
+ MinusOp2 = xb(Arg(3));
+ goto do_minus;
- if (is_both_small(xb(Arg(2)), xb(Arg(3)))) {
- Sint i = signed_val(xb(Arg(2))) - signed_val(xb(Arg(3)));
- ASSERT(MY_IS_SSMALL(i) == IS_SSMALL(i));
- if (MY_IS_SSMALL(i)) {
- result = make_small(i);
- StoreBifResult(4, result);
- }
- }
- DO_BIG_ARITH(ARITH_FUNC(mixed_minus), xb(Arg(2)), xb(Arg(3)));
- }
+ OpCase(i_minus_jIssd):
+ GetArg2(2, MinusOp1, MinusOp2);
+ goto do_minus;
- OpCase(i_minus_jId):
- {
- Eterm result;
-
- if (is_both_small(tmp_arg1, tmp_arg2)) {
- Sint i = signed_val(tmp_arg1) - signed_val(tmp_arg2);
+ do_minus:
+ if (is_both_small(MinusOp1, MinusOp2)) {
+ Sint i = signed_val(MinusOp1) - signed_val(MinusOp2);
ASSERT(MY_IS_SSMALL(i) == IS_SSMALL(i));
if (MY_IS_SSMALL(i)) {
result = make_small(i);
- STORE_ARITH_RESULT(result);
+ StoreBifResult(4, result);
}
}
- arith_func = ARITH_FUNC(mixed_minus);
- goto do_big_arith2;
+ DO_OUTLINED_ARITH_2(mixed_minus, MinusOp1, MinusOp2);
}
- OpCase(i_is_lt_f):
- if (CMP_GE(tmp_arg1, tmp_arg2)) {
- ClauseFail();
- }
- Next(1);
-
- OpCase(i_is_ge_f):
- if (CMP_LT(tmp_arg1, tmp_arg2)) {
- ClauseFail();
- }
- Next(1);
-
- OpCase(i_is_eq_f):
- if (CMP_NE(tmp_arg1, tmp_arg2)) {
- ClauseFail();
- }
- Next(1);
-
- OpCase(i_is_ne_f):
- if (CMP_EQ(tmp_arg1, tmp_arg2)) {
- ClauseFail();
- }
- Next(1);
-
- OpCase(i_is_eq_exact_f):
- if (!EQ(tmp_arg1, tmp_arg2)) {
- ClauseFail();
- }
- Next(1);
-
{
Eterm is_eq_exact_lit_val;
- OpCase(i_is_eq_exact_literal_xfc):
- is_eq_exact_lit_val = xb(Arg(0));
- I++;
+ OpCase(i_is_eq_exact_literal_fxc):
+ is_eq_exact_lit_val = xb(Arg(1));
goto do_is_eq_exact_literal;
- OpCase(i_is_eq_exact_literal_yfc):
- is_eq_exact_lit_val = yb(Arg(0));
- I++;
+ OpCase(i_is_eq_exact_literal_fyc):
+ is_eq_exact_lit_val = yb(Arg(1));
goto do_is_eq_exact_literal;
- OpCase(i_is_eq_exact_literal_rfc):
- is_eq_exact_lit_val = r(0);
-
do_is_eq_exact_literal:
- if (!eq(Arg(1), is_eq_exact_lit_val)) {
+ if (!eq(Arg(2), is_eq_exact_lit_val)) {
ClauseFail();
}
- Next(2);
+ Next(3);
}
{
Eterm is_ne_exact_lit_val;
- OpCase(i_is_ne_exact_literal_xfc):
- is_ne_exact_lit_val = xb(Arg(0));
- I++;
+ OpCase(i_is_ne_exact_literal_fxc):
+ is_ne_exact_lit_val = xb(Arg(1));
goto do_is_ne_exact_literal;
- OpCase(i_is_ne_exact_literal_yfc):
- is_ne_exact_lit_val = yb(Arg(0));
- I++;
+ OpCase(i_is_ne_exact_literal_fyc):
+ is_ne_exact_lit_val = yb(Arg(1));
goto do_is_ne_exact_literal;
- OpCase(i_is_ne_exact_literal_rfc):
- is_ne_exact_lit_val = r(0);
-
do_is_ne_exact_literal:
- if (eq(Arg(1), is_ne_exact_lit_val)) {
+ if (eq(Arg(2), is_ne_exact_lit_val)) {
ClauseFail();
}
- Next(2);
+ Next(3);
}
- OpCase(move_window3_xxxy): {
- BeamInstr *next;
- Eterm xt0, xt1, xt2;
- Eterm *y = (Eterm *)(((unsigned char *)E) + (Arg(3)));
- PreFetch(4, next);
- xt0 = xb(Arg(0));
- xt1 = xb(Arg(1));
- xt2 = xb(Arg(2));
- y[0] = xt0;
- y[1] = xt1;
- y[2] = xt2;
- NextPF(4, next);
- }
- OpCase(move_window4_xxxxy): {
- BeamInstr *next;
- Eterm xt0, xt1, xt2, xt3;
- Eterm *y = (Eterm *)(((unsigned char *)E) + (Arg(4)));
- PreFetch(5, next);
- xt0 = xb(Arg(0));
- xt1 = xb(Arg(1));
- xt2 = xb(Arg(2));
- xt3 = xb(Arg(3));
- y[0] = xt0;
- y[1] = xt1;
- y[2] = xt2;
- y[3] = xt3;
- NextPF(5, next);
- }
- OpCase(move_window5_xxxxxy): {
- BeamInstr *next;
- Eterm xt0, xt1, xt2, xt3, xt4;
- Eterm *y = (Eterm *)(((unsigned char *)E) + (Arg(5)));
- PreFetch(6, next);
- xt0 = xb(Arg(0));
- xt1 = xb(Arg(1));
- xt2 = xb(Arg(2));
- xt3 = xb(Arg(3));
- xt4 = xb(Arg(4));
- y[0] = xt0;
- y[1] = xt1;
- y[2] = xt2;
- y[3] = xt3;
- y[4] = xt4;
- NextPF(6, next);
- }
-
- OpCase(i_move_call_only_fcr): {
+ OpCase(i_move_call_only_fc): {
r(0) = Arg(1);
}
/* FALL THROUGH */
@@ -1600,7 +1533,7 @@ void process_main(void)
Dispatch();
}
- OpCase(i_move_call_last_fPcr): {
+ OpCase(i_move_call_last_fPc): {
r(0) = Arg(2);
}
/* FALL THROUGH */
@@ -1612,7 +1545,7 @@ void process_main(void)
Dispatch();
}
- OpCase(i_move_call_crf): {
+ OpCase(i_move_call_cf): {
r(0) = Arg(0);
I++;
}
@@ -1624,7 +1557,7 @@ void process_main(void)
Dispatch();
}
- OpCase(i_move_call_ext_last_ePcr): {
+ OpCase(i_move_call_ext_last_ePc): {
r(0) = Arg(2);
}
/* FALL THROUGH */
@@ -1640,7 +1573,7 @@ void process_main(void)
DTRACE_GLOBAL_CALL_FROM_EXPORT(c_p, Arg(0));
Dispatchx();
- OpCase(i_move_call_ext_cre): {
+ OpCase(i_move_call_ext_ce): {
r(0) = Arg(0);
I++;
}
@@ -1650,7 +1583,7 @@ void process_main(void)
DTRACE_GLOBAL_CALL_FROM_EXPORT(c_p, Arg(0));
Dispatchx();
- OpCase(i_move_call_ext_only_ecr): {
+ OpCase(i_move_call_ext_only_ec): {
r(0) = Arg(1);
}
/* FALL THROUGH */
@@ -1716,7 +1649,6 @@ void process_main(void)
PRE_BIF_SWAPOUT(c_p);
c_p->fcalls = FCALLS - 1;
- reg[0] = r(0);
result = erl_send(c_p, r(0), x(1));
PreFetch(0, next);
ERTS_VERIFY_UNUSED_TEMP_ALLOC(c_p);
@@ -1724,7 +1656,6 @@ void process_main(void)
PROCESS_MAIN_CHK_LOCKS(c_p);
if (c_p->mbuf || MSO(c_p).overhead >= BIN_VHEAP_SZ(c_p)) {
result = erts_gc_after_bif_call(c_p, result, reg, 2);
- r(0) = reg[0];
E = c_p->stop;
}
HTOP = HEAP_TOP(c_p);
@@ -1737,7 +1668,6 @@ void process_main(void)
SET_CP(c_p, I+1);
SET_I(c_p->i);
SWAPIN;
- r(0) = reg[0];
Dispatch();
}
goto find_func_info;
@@ -1747,29 +1677,23 @@ void process_main(void)
Eterm element_index;
Eterm element_tuple;
- OpCase(i_element_xjsd):
- element_tuple = xb(Arg(0));
- I++;
+ OpCase(i_element_jxsd):
+ element_tuple = xb(Arg(1));
goto do_element;
- OpCase(i_element_yjsd):
- element_tuple = yb(Arg(0));
- I++;
+ OpCase(i_element_jysd):
+ element_tuple = yb(Arg(1));
goto do_element;
- OpCase(i_element_rjsd):
- element_tuple = r(0);
- /* Fall through */
-
do_element:
- GetArg1(1, element_index);
+ GetArg1(2, element_index);
if (is_small(element_index) && is_tuple(element_tuple)) {
Eterm* tp = tuple_val(element_tuple);
if ((signed_val(element_index) >= 1) &&
(signed_val(element_index) <= arityval(*tp))) {
Eterm result = tp[signed_val(element_index)];
- StoreBifResult(2, result);
+ StoreBifResult(3, result);
}
}
}
@@ -1783,29 +1707,24 @@ void process_main(void)
{
Eterm fast_element_tuple;
- OpCase(i_fast_element_rjId):
- fast_element_tuple = r(0);
+ OpCase(i_fast_element_jxId):
+ fast_element_tuple = xb(Arg(1));
+ goto do_fast_element;
+
+ OpCase(i_fast_element_jyId):
+ fast_element_tuple = yb(Arg(1));
+ goto do_fast_element;
do_fast_element:
if (is_tuple(fast_element_tuple)) {
Eterm* tp = tuple_val(fast_element_tuple);
- Eterm pos = Arg(1); /* Untagged integer >= 1 */
+ Eterm pos = Arg(2); /* Untagged integer >= 1 */
if (pos <= arityval(*tp)) {
Eterm result = tp[pos];
- StoreBifResult(2, result);
+ StoreBifResult(3, result);
}
}
goto badarg;
-
- OpCase(i_fast_element_xjId):
- fast_element_tuple = xb(Arg(0));
- I++;
- goto do_fast_element;
-
- OpCase(i_fast_element_yjId):
- fast_element_tuple = yb(Arg(0));
- I++;
- goto do_fast_element;
}
OpCase(catch_yf):
@@ -1911,7 +1830,7 @@ void process_main(void)
* Pick up the next message and place it in x(0).
* If no message, jump to a wait or wait_timeout instruction.
*/
- OpCase(i_loop_rec_fr):
+ OpCase(i_loop_rec_f):
{
BeamInstr *next;
ErlMessage* msgp;
@@ -1945,13 +1864,11 @@ void process_main(void)
ErtsMoveMsgAttachmentIntoProc(msgp, c_p, E, HTOP, FCALLS,
{
SWAPOUT;
- reg[0] = r(0);
PROCESS_MAIN_CHK_LOCKS(c_p);
},
{
ERTS_VERIFY_UNUSED_TEMP_ALLOC(c_p);
PROCESS_MAIN_CHK_LOCKS(c_p);
- r(0) = reg[0];
SWAPIN;
});
if (is_non_value(ERL_MESSAGE_TERM(msgp))) {
@@ -2155,6 +2072,22 @@ void process_main(void)
OpCase(wait_f):
wait2: {
+#ifndef ERTS_SMP
+ if (ERTS_PROC_IS_EXITING(c_p)) {
+ /*
+ * I non smp case:
+ *
+ * Currently executing process might be sent an exit
+ * signal if it is traced by a port that it also is
+ * linked to, and the port terminates during the
+ * trace. In this case we do *not* want to clear
+ * the active flag, which will make the process hang
+ * in limbo forever.
+ */
+ SWAPOUT;
+ goto do_schedule;
+ }
+#endif
c_p->i = (BeamInstr *) Arg(0); /* L1 */
SWAPOUT;
c_p->arity = 0;
@@ -2225,10 +2158,6 @@ void process_main(void)
select_val2 = xb(Arg(0));
goto do_select_tuple_arity2;
- OpCase(i_select_tuple_arity2_rfAAff):
- select_val2 = r(0);
- I--;
-
do_select_tuple_arity2:
if (is_not_tuple(select_val2)) {
goto select_val2_fail;
@@ -2244,10 +2173,6 @@ void process_main(void)
select_val2 = xb(Arg(0));
goto do_select_val2;
- OpCase(i_select_val2_rfccff):
- select_val2 = r(0);
- I--;
-
do_select_val2:
if (select_val2 == Arg(2)) {
I += 3;
@@ -2271,10 +2196,6 @@ void process_main(void)
select_val = yb(Arg(0));
goto do_select_tuple_arity;
- OpCase(i_select_tuple_arity_rfI):
- select_val = r(0);
- I--;
-
do_select_tuple_arity:
if (is_tuple(select_val)) {
select_val = *tuple_val(select_val);
@@ -2291,10 +2212,6 @@ void process_main(void)
select_val = yb(Arg(0));
goto do_linear_search;
- OpCase(i_select_val_lins_rfI):
- select_val = r(0);
- I--;
-
do_linear_search: {
BeamInstr *vs = &Arg(3);
int ix = 0;
@@ -2321,10 +2238,6 @@ void process_main(void)
select_val = yb(Arg(0));
goto do_binary_search;
- OpCase(i_select_val_bins_rfI):
- select_val = r(0);
- I--;
-
do_binary_search:
{
struct Pairs {
@@ -2385,10 +2298,6 @@ void process_main(void)
jump_on_val_zero_index = xb(Arg(0));
goto do_jump_on_val_zero_index;
- OpCase(i_jump_on_val_zero_rfI):
- jump_on_val_zero_index = r(0);
- I--;
-
do_jump_on_val_zero_index:
if (is_small(jump_on_val_zero_index)) {
jump_on_val_zero_index = signed_val(jump_on_val_zero_index);
@@ -2413,10 +2322,6 @@ void process_main(void)
jump_on_val_index = xb(Arg(0));
goto do_jump_on_val_index;
- OpCase(i_jump_on_val_rfII):
- jump_on_val_index = r(0);
- I--;
-
do_jump_on_val_index:
if (is_small(jump_on_val_index)) {
jump_on_val_index = (Uint) (signed_val(jump_on_val_index) - Arg(3));
@@ -2436,15 +2341,12 @@ void process_main(void)
do {
Eterm term = *I++;
- switch (term & _TAG_IMMED1_MASK) {
- case (R_REG_DEF << _TAG_PRIMARY_SIZE) | TAG_PRIMARY_HEADER:
- *hp++ = r(0);
+ switch (loader_tag(term)) {
+ case LOADER_X_REG:
+ *hp++ = x(loader_x_reg_index(term));
break;
- case (X_REG_DEF << _TAG_PRIMARY_SIZE) | TAG_PRIMARY_HEADER:
- *hp++ = x(term >> _TAG_IMMED1_SIZE);
- break;
- case (Y_REG_DEF << _TAG_PRIMARY_SIZE) | TAG_PRIMARY_HEADER:
- *hp++ = y(term >> _TAG_IMMED1_SIZE);
+ case LOADER_Y_REG:
+ *hp++ = y(loader_y_reg_index(term));
break;
default:
*hp++ = term;
@@ -2458,31 +2360,26 @@ void process_main(void)
OpCase(new_map_dII): {
Eterm res;
- x(0) = r(0);
SWAPOUT;
res = new_map(c_p, reg, I-1);
SWAPIN;
- r(0) = x(0);
StoreResult(res, Arg(0));
Next(3+Arg(2));
}
-#define PUT_TERM_REG(term, desc) \
-do { \
- switch ((desc) & _TAG_IMMED1_MASK) { \
- case (R_REG_DEF << _TAG_PRIMARY_SIZE) | TAG_PRIMARY_HEADER: \
- r(0) = (term); \
- break; \
- case (X_REG_DEF << _TAG_PRIMARY_SIZE) | TAG_PRIMARY_HEADER: \
- x((desc) >> _TAG_IMMED1_SIZE) = (term); \
- break; \
- case (Y_REG_DEF << _TAG_PRIMARY_SIZE) | TAG_PRIMARY_HEADER: \
- y((desc) >> _TAG_IMMED1_SIZE) = (term); \
- break; \
- default: \
- ASSERT(0); \
- break; \
- } \
+#define PUT_TERM_REG(term, desc) \
+do { \
+ switch (loader_tag(desc)) { \
+ case LOADER_X_REG: \
+ x(loader_x_reg_index(desc)) = (term); \
+ break; \
+ case LOADER_Y_REG: \
+ y(loader_y_reg_index(desc)) = (term); \
+ break; \
+ default: \
+ ASSERT(0); \
+ break; \
+ } \
} while(0)
OpCase(i_get_map_elements_fsI): {
@@ -2553,12 +2450,10 @@ do { \
Eterm map;
GetArg1(1, map);
- x(0) = r(0);
SWAPOUT;
res = update_map_assoc(c_p, reg, map, I);
SWAPIN;
if (is_value(res)) {
- r(0) = x(0);
StoreResult(res, Arg(2));
Next(5+Arg(4));
} else {
@@ -2577,12 +2472,10 @@ do { \
Eterm map;
GetArg1(1, map);
- x(0) = r(0);
SWAPOUT;
res = update_map_exact(c_p, reg, map, I);
SWAPIN;
if (is_value(res)) {
- r(0) = x(0);
StoreResult(res, Arg(2));
Next(5+Arg(4));
} else {
@@ -2664,13 +2557,10 @@ do { \
{
typedef Eterm (*GcBifFunction)(Process*, Eterm*, Uint);
GcBifFunction bf;
- Eterm arg;
Eterm result;
Uint live = (Uint) Arg(3);
- GetArg1(2, arg);
- reg[0] = r(0);
- reg[live] = arg;
+ GetArg1(2, x(live));
bf = (GcBifFunction) Arg(1);
c_p->fcalls = FCALLS;
SWAPOUT;
@@ -2681,7 +2571,6 @@ do { \
ERTS_SMP_REQ_PROC_MAIN_LOCK(c_p);
PROCESS_MAIN_CHK_LOCKS(c_p);
SWAPIN;
- r(0) = reg[0];
ERTS_HOLE_CHECK(c_p);
FCALLS = c_p->fcalls;
if (is_value(result)) {
@@ -2691,12 +2580,12 @@ do { \
SET_I((BeamInstr *) Arg(0));
Goto(*I);
}
- reg[0] = arg;
+ x(0) = x(live);
I = handle_error(c_p, I, reg, translate_gc_bif((void *) bf));
goto post_error_handling;
}
- OpCase(i_gc_bif2_jIId): /* Note, one less parameter than the i_gc_bif1
+ OpCase(i_gc_bif2_jIIssd): /* Note, one less parameter than the i_gc_bif1
and i_gc_bif3 */
{
typedef Eterm (*GcBifFunction)(Process*, Eterm*, Uint);
@@ -2704,9 +2593,13 @@ do { \
Eterm result;
Uint live = (Uint) Arg(2);
- reg[0] = r(0);
- reg[live++] = tmp_arg1;
- reg[live] = tmp_arg2;
+ GetArg2(3, x(live), x(live+1));
+ /*
+ * XXX This calling convention does not make sense. 'live'
+ * should point out the first argument, not the second
+ * (i.e. 'live' should not be incremented below).
+ */
+ live++;
bf = (GcBifFunction) Arg(1);
c_p->fcalls = FCALLS;
SWAPOUT;
@@ -2717,35 +2610,37 @@ do { \
ERTS_SMP_REQ_PROC_MAIN_LOCK(c_p);
PROCESS_MAIN_CHK_LOCKS(c_p);
SWAPIN;
- r(0) = reg[0];
ERTS_HOLE_CHECK(c_p);
FCALLS = c_p->fcalls;
if (is_value(result)) {
- StoreBifResult(3, result);
+ StoreBifResult(5, result);
}
if (Arg(0) != 0) {
SET_I((BeamInstr *) Arg(0));
Goto(*I);
}
- reg[0] = tmp_arg1;
- reg[1] = tmp_arg2;
+ live--;
+ x(0) = x(live);
+ x(1) = x(live+1);
I = handle_error(c_p, I, reg, translate_gc_bif((void *) bf));
goto post_error_handling;
}
- OpCase(i_gc_bif3_jIsId):
+ OpCase(i_gc_bif3_jIIssd):
{
typedef Eterm (*GcBifFunction)(Process*, Eterm*, Uint);
GcBifFunction bf;
- Eterm arg;
Eterm result;
- Uint live = (Uint) Arg(3);
+ Uint live = (Uint) Arg(2);
- GetArg1(2, arg);
- reg[0] = r(0);
- reg[live++] = arg;
- reg[live++] = tmp_arg1;
- reg[live] = tmp_arg2;
+ x(live) = x(SCRATCH_X_REG);
+ GetArg2(3, x(live+1), x(live+2));
+ /*
+ * XXX This calling convention does not make sense. 'live'
+ * should point out the first argument, not the third
+ * (i.e. 'live' should not be incremented below).
+ */
+ live += 2;
bf = (GcBifFunction) Arg(1);
c_p->fcalls = FCALLS;
SWAPOUT;
@@ -2756,19 +2651,19 @@ do { \
ERTS_SMP_REQ_PROC_MAIN_LOCK(c_p);
PROCESS_MAIN_CHK_LOCKS(c_p);
SWAPIN;
- r(0) = reg[0];
ERTS_HOLE_CHECK(c_p);
FCALLS = c_p->fcalls;
if (is_value(result)) {
- StoreBifResult(4, result);
+ StoreBifResult(5, result);
}
if (Arg(0) != 0) {
SET_I((BeamInstr *) Arg(0));
Goto(*I);
}
- reg[0] = arg;
- reg[1] = tmp_arg1;
- reg[2] = tmp_arg2;
+ live -= 2;
+ x(0) = x(live);
+ x(1) = x(live+1);
+ x(2) = x(live+2);
I = handle_error(c_p, I, reg, translate_gc_bif((void *) bf));
goto post_error_handling;
}
@@ -2776,12 +2671,13 @@ do { \
/*
* Guards bifs and, or, xor in guards.
*/
- OpCase(i_bif2_fbd):
+ OpCase(i_bif2_fbssd):
{
- Eterm tmp_reg[2] = {tmp_arg1, tmp_arg2};
+ Eterm tmp_reg[2];
Eterm (*bf)(Process*, Eterm*);
Eterm result;
+ GetArg2(2, tmp_reg[0], tmp_reg[1]);
bf = (BifFunction) Arg(1);
c_p->fcalls = FCALLS;
PROCESS_MAIN_CHK_LOCKS(c_p);
@@ -2793,7 +2689,7 @@ do { \
ERTS_HOLE_CHECK(c_p);
FCALLS = c_p->fcalls;
if (is_value(result)) {
- StoreBifResult(2, result);
+ StoreBifResult(4, result);
}
SET_I((BeamInstr *) Arg(0));
Goto(*I);
@@ -2802,12 +2698,13 @@ do { \
/*
* Guards bifs and, or, xor, relational operators in body.
*/
- OpCase(i_bif2_body_bd):
+ OpCase(i_bif2_body_bssd):
{
- Eterm tmp_reg[2] = {tmp_arg1, tmp_arg2};
+ Eterm tmp_reg[2];
Eterm (*bf)(Process*, Eterm*);
Eterm result;
+ GetArg2(1, tmp_reg[0], tmp_reg[1]);
bf = (BifFunction) Arg(0);
PROCESS_MAIN_CHK_LOCKS(c_p);
ASSERT(!ERTS_PROC_IS_EXITING(c_p));
@@ -2818,10 +2715,10 @@ do { \
ERTS_HOLE_CHECK(c_p);
if (is_value(result)) {
ASSERT(!is_CP(result));
- StoreBifResult(1, result);
+ StoreBifResult(3, result);
}
- reg[0] = tmp_arg1;
- reg[1] = tmp_arg2;
+ reg[0] = tmp_reg[0];
+ reg[1] = tmp_reg[1];
SWAPOUT;
I = handle_error(c_p, I, reg, bf);
goto post_error_handling;
@@ -2845,7 +2742,6 @@ do { \
PreFetch(1, next);
ASSERT(!ERTS_PROC_IS_EXITING(c_p));
ERTS_VERIFY_UNUSED_TEMP_ALLOC(c_p);
- reg[0] = r(0);
result = (*bf)(c_p, reg, I);
ASSERT(!ERTS_PROC_IS_EXITING(c_p) || is_non_value(result));
ERTS_VERIFY_UNUSED_TEMP_ALLOC(c_p);
@@ -2867,7 +2763,6 @@ do { \
SET_CP(c_p, I+2);
SET_I(c_p->i);
SWAPIN;
- r(0) = reg[0];
Dispatch();
}
@@ -2883,111 +2778,81 @@ do { \
* Arithmetic operations.
*/
- OpCase(i_times_jId):
+ OpCase(i_times_jIssd):
{
- arith_func = ARITH_FUNC(mixed_times);
- goto do_big_arith2;
+ Eterm Op1, Op2;
+ GetArg2(2, Op1, Op2);
+ DO_OUTLINED_ARITH_2(mixed_times, Op1, Op2);
}
- OpCase(i_m_div_jId):
+ OpCase(i_m_div_jIssd):
{
- arith_func = ARITH_FUNC(mixed_div);
- goto do_big_arith2;
+ Eterm Op1, Op2;
+ GetArg2(2, Op1, Op2);
+ DO_OUTLINED_ARITH_2(mixed_div, Op1, Op2);
}
- OpCase(i_int_div_jId):
+ OpCase(i_int_div_jIssd):
{
- Eterm result;
+ Eterm Op1, Op2;
- if (tmp_arg2 == SMALL_ZERO) {
+ GetArg2(2, Op1, Op2);
+ if (Op2 == SMALL_ZERO) {
goto badarith;
- } else if (is_both_small(tmp_arg1, tmp_arg2)) {
- Sint ires = signed_val(tmp_arg1) / signed_val(tmp_arg2);
+ } else if (is_both_small(Op1, Op2)) {
+ Sint ires = signed_val(Op1) / signed_val(Op2);
if (MY_IS_SSMALL(ires)) {
- result = make_small(ires);
- STORE_ARITH_RESULT(result);
+ Eterm result = make_small(ires);
+ StoreBifResult(4, result);
}
}
- arith_func = ARITH_FUNC(int_div);
- goto do_big_arith2;
+ DO_OUTLINED_ARITH_2(int_div, Op1, Op2);
}
- OpCase(i_rem_jIxxd):
{
- Eterm result;
+ Eterm RemOp1, RemOp2;
- if (xb(Arg(3)) == SMALL_ZERO) {
- goto badarith;
- } else if (is_both_small(xb(Arg(2)), xb(Arg(3)))) {
- result = make_small(signed_val(xb(Arg(2))) % signed_val(xb(Arg(3))));
+ OpCase(i_rem_jIxxd):
+ RemOp1 = xb(Arg(2));
+ RemOp2 = xb(Arg(3));
+ goto do_rem;
+
+ OpCase(i_rem_jIssd):
+ GetArg2(2, RemOp1, RemOp2);
+ goto do_rem;
+
+ do_rem:
+ if (RemOp2 == SMALL_ZERO) {
+ goto badarith;
+ } else if (is_both_small(RemOp1, RemOp2)) {
+ Eterm result = make_small(signed_val(RemOp1) % signed_val(RemOp2));
StoreBifResult(4, result);
+ } else {
+ DO_OUTLINED_ARITH_2(int_rem, RemOp1, RemOp2);
}
- DO_BIG_ARITH(ARITH_FUNC(int_rem),xb(Arg(2)),xb(Arg(3)));
}
- OpCase(i_rem_jId):
{
- Eterm result;
-
- if (tmp_arg2 == SMALL_ZERO) {
- goto badarith;
- } else if (is_both_small(tmp_arg1, tmp_arg2)) {
- result = make_small(signed_val(tmp_arg1) % signed_val(tmp_arg2));
- STORE_ARITH_RESULT(result);
- } else {
- arith_func = ARITH_FUNC(int_rem);
- goto do_big_arith2;
- }
- }
+ Eterm BandOp1, BandOp2;
OpCase(i_band_jIxcd):
- {
- Eterm result;
+ BandOp1 = xb(Arg(2));
+ BandOp2 = Arg(3);
+ goto do_band;
- if (is_both_small(xb(Arg(2)), Arg(3))) {
+ OpCase(i_band_jIssd):
+ GetArg2(2, BandOp1, BandOp2);
+ goto do_band;
+
+ do_band:
+ if (is_both_small(BandOp1, BandOp2)) {
/*
* No need to untag -- TAG & TAG == TAG.
*/
- result = xb(Arg(2)) & Arg(3);
+ Eterm result = BandOp1 & BandOp2;
StoreBifResult(4, result);
}
- DO_BIG_ARITH(ARITH_FUNC(band),xb(Arg(2)),Arg(3));
- }
-
- OpCase(i_band_jId):
- {
- Eterm result;
-
- if (is_both_small(tmp_arg1, tmp_arg2)) {
- /*
- * No need to untag -- TAG & TAG == TAG.
- */
- result = tmp_arg1 & tmp_arg2;
- STORE_ARITH_RESULT(result);
- }
- arith_func = ARITH_FUNC(band);
- goto do_big_arith2;
- }
-
-#undef DO_BIG_ARITH
-
- do_big_arith2:
- {
- Eterm result;
- Uint live = Arg(1);
-
- SWAPOUT;
- reg[0] = r(0);
- reg[live] = tmp_arg1;
- reg[live+1] = tmp_arg2;
- result = arith_func(c_p, reg, live);
- r(0) = reg[0];
- SWAPIN;
- ERTS_HOLE_CHECK(c_p);
- if (is_value(result)) {
- STORE_ARITH_RESULT(result);
- }
- goto lb_Cl_error;
+ DO_OUTLINED_ARITH_2(band, BandOp1, BandOp2);
}
/*
@@ -3008,97 +2873,102 @@ do { \
goto find_func_info;
}
- OpCase(i_bor_jId):
+ OpCase(i_bor_jIssd):
{
- Eterm result;
+ Eterm Op1, Op2;
- if (is_both_small(tmp_arg1, tmp_arg2)) {
+ GetArg2(2, Op1, Op2);
+ if (is_both_small(Op1, Op2)) {
/*
* No need to untag -- TAG | TAG == TAG.
*/
- result = tmp_arg1 | tmp_arg2;
- STORE_ARITH_RESULT(result);
+ Eterm result = Op1 | Op2;
+ StoreBifResult(4, result);
}
- arith_func = ARITH_FUNC(bor);
- goto do_big_arith2;
+ DO_OUTLINED_ARITH_2(bor, Op1, Op2);
}
- OpCase(i_bxor_jId):
+ OpCase(i_bxor_jIssd):
{
- Eterm result;
+ Eterm Op1, Op2;
- if (is_both_small(tmp_arg1, tmp_arg2)) {
+ GetArg2(2, Op1, Op2);
+ if (is_both_small(Op1, Op2)) {
/*
* We could extract the tag from one argument, but a tag extraction
* could mean a shift. Therefore, play it safe here.
*/
- result = make_small(signed_val(tmp_arg1) ^ signed_val(tmp_arg2));
- STORE_ARITH_RESULT(result);
+ Eterm result = make_small(signed_val(Op1) ^ signed_val(Op2));
+ StoreBifResult(4, result);
}
- arith_func = ARITH_FUNC(bxor);
- goto do_big_arith2;
+ DO_OUTLINED_ARITH_2(bxor, Op1, Op2);
}
{
+ Eterm Op1, Op2;
Sint i;
Sint ires;
Eterm* bigp;
+ Eterm tmp_big[2];
- OpCase(i_bsr_jId):
- if (is_small(tmp_arg2)) {
- i = -signed_val(tmp_arg2);
- if (is_small(tmp_arg1)) {
+ OpCase(i_bsr_jIssd):
+ GetArg2(2, Op1, Op2);
+ if (is_small(Op2)) {
+ i = -signed_val(Op2);
+ if (is_small(Op1)) {
goto small_shift;
- } else if (is_big(tmp_arg1)) {
+ } else if (is_big(Op1)) {
if (i == 0) {
- StoreBifResult(2, tmp_arg1);
+ StoreBifResult(4, Op1);
}
goto big_shift;
}
- } else if (is_big(tmp_arg2)) {
+ } else if (is_big(Op2)) {
/*
* N bsr NegativeBigNum == N bsl MAX_SMALL
* N bsr PositiveBigNum == N bsl MIN_SMALL
*/
- tmp_arg2 = make_small(bignum_header_is_neg(*big_val(tmp_arg2)) ?
+ Op2 = make_small(bignum_header_is_neg(*big_val(Op2)) ?
MAX_SMALL : MIN_SMALL);
goto do_bsl;
}
goto badarith;
- OpCase(i_bsl_jId):
+ OpCase(i_bsl_jIssd):
+ GetArg2(2, Op1, Op2);
+
do_bsl:
- if (is_small(tmp_arg2)) {
- i = signed_val(tmp_arg2);
+ if (is_small(Op2)) {
+ i = signed_val(Op2);
- if (is_small(tmp_arg1)) {
+ if (is_small(Op1)) {
small_shift:
- ires = signed_val(tmp_arg1);
+ ires = signed_val(Op1);
if (i == 0 || ires == 0) {
- StoreBifResult(2, tmp_arg1);
+ StoreBifResult(4, Op1);
} else if (i < 0) { /* Right shift */
i = -i;
if (i >= SMALL_BITS-1) {
- tmp_arg1 = (ires < 0) ? SMALL_MINUS_ONE : SMALL_ZERO;
+ Op1 = (ires < 0) ? SMALL_MINUS_ONE : SMALL_ZERO;
} else {
- tmp_arg1 = make_small(ires >> i);
+ Op1 = make_small(ires >> i);
}
- StoreBifResult(2, tmp_arg1);
+ StoreBifResult(4, Op1);
} else if (i < SMALL_BITS-1) { /* Left shift */
if ((ires > 0 && ((~(Uint)0 << ((SMALL_BITS-1)-i)) & ires) == 0) ||
((~(Uint)0 << ((SMALL_BITS-1)-i)) & ~ires) == 0) {
- tmp_arg1 = make_small(ires << i);
- StoreBifResult(2, tmp_arg1);
+ Op1 = make_small(ires << i);
+ StoreBifResult(4, Op1);
}
}
- tmp_arg1 = small_to_big(ires, tmp_big);
+ Op1 = small_to_big(ires, tmp_big);
big_shift:
if (i > 0) { /* Left shift. */
- ires = big_size(tmp_arg1) + (i / D_EXP);
+ ires = big_size(Op1) + (i / D_EXP);
} else { /* Right shift. */
- ires = big_size(tmp_arg1);
+ ires = big_size(Op1);
if (ires <= (-i / D_EXP))
ires = 3; /* ??? */
else
@@ -3116,14 +2986,14 @@ do { \
c_p->freason = SYSTEM_LIMIT;
goto lb_Cl_error;
}
- TestHeapPreserve(ires+1, Arg(1), tmp_arg1);
+ TestHeapPreserve(ires+1, Arg(1), Op1);
bigp = HTOP;
- tmp_arg1 = big_lshift(tmp_arg1, i, bigp);
- if (is_big(tmp_arg1)) {
+ Op1 = big_lshift(Op1, i, bigp);
+ if (is_big(Op1)) {
HTOP += bignum_header_arity(*HTOP) + 1;
}
HEAP_SPACE_VERIFIED(0);
- if (is_nil(tmp_arg1)) {
+ if (is_nil(Op1)) {
/*
* This result must have been only slight larger
* than allowed since it wasn't caught by the
@@ -3133,25 +3003,25 @@ do { \
goto lb_Cl_error;
}
ERTS_HOLE_CHECK(c_p);
- StoreBifResult(2, tmp_arg1);
+ StoreBifResult(4, Op1);
}
- } else if (is_big(tmp_arg1)) {
+ } else if (is_big(Op1)) {
if (i == 0) {
- StoreBifResult(2, tmp_arg1);
+ StoreBifResult(4, Op1);
}
goto big_shift;
}
- } else if (is_big(tmp_arg2)) {
- if (bignum_header_is_neg(*big_val(tmp_arg2))) {
+ } else if (is_big(Op2)) {
+ if (bignum_header_is_neg(*big_val(Op2))) {
/*
* N bsl NegativeBigNum is either 0 or -1, depending on
* the sign of N. Since we don't believe this case
* is common, do the calculation with the minimum
* amount of code.
*/
- tmp_arg2 = make_small(MIN_SMALL);
+ Op2 = make_small(MIN_SMALL);
goto do_bsl;
- } else if (is_small(tmp_arg1) || is_big(tmp_arg1)) {
+ } else if (is_small(Op1) || is_big(Op1)) {
/*
* N bsl PositiveBigNum is too large to represent.
*/
@@ -3176,10 +3046,8 @@ do { \
} else {
Uint live = Arg(2);
SWAPOUT;
- reg[0] = r(0);
reg[live] = bnot_val;
bnot_val = erts_gc_bnot(c_p, reg, live);
- r(0) = reg[0];
SWAPIN;
ERTS_HOLE_CHECK(c_p);
if (is_nil(bnot_val)) {
@@ -3199,7 +3067,6 @@ do { \
next = apply(c_p, r(0), x(1), x(2), reg);
SWAPIN;
if (next != NULL) {
- r(0) = reg[0];
SET_CP(c_p, I+1);
SET_I(next);
Dispatch();
@@ -3214,7 +3081,6 @@ do { \
next = apply(c_p, r(0), x(1), x(2), reg);
SWAPIN;
if (next != NULL) {
- r(0) = reg[0];
SET_CP(c_p, (BeamInstr *) E[0]);
E = ADD_BYTE_OFFSET(E, Arg(0));
SET_I(next);
@@ -3230,7 +3096,6 @@ do { \
next = apply(c_p, r(0), x(1), x(2), reg);
SWAPIN;
if (next != NULL) {
- r(0) = reg[0];
SET_I(next);
Dispatch();
}
@@ -3241,12 +3106,10 @@ do { \
OpCase(apply_I): {
BeamInstr *next;
- reg[0] = r(0);
SWAPOUT;
next = fixed_apply(c_p, reg, Arg(0));
SWAPIN;
if (next != NULL) {
- r(0) = reg[0];
SET_CP(c_p, I+2);
SET_I(next);
Dispatch();
@@ -3258,12 +3121,10 @@ do { \
OpCase(apply_last_IP): {
BeamInstr *next;
- reg[0] = r(0);
SWAPOUT;
next = fixed_apply(c_p, reg, Arg(0));
SWAPIN;
if (next != NULL) {
- r(0) = reg[0];
SET_CP(c_p, (BeamInstr *) E[0]);
E = ADD_BYTE_OFFSET(E, Arg(1));
SET_I(next);
@@ -3280,7 +3141,6 @@ do { \
next = apply_fun(c_p, r(0), x(1), reg);
SWAPIN;
if (next != NULL) {
- r(0) = reg[0];
SET_CP(c_p, I+1);
SET_I(next);
Dispatchfun();
@@ -3295,7 +3155,6 @@ do { \
next = apply_fun(c_p, r(0), x(1), reg);
SWAPIN;
if (next != NULL) {
- r(0) = reg[0];
SET_CP(c_p, (BeamInstr *) E[0]);
E = ADD_BYTE_OFFSET(E, Arg(0));
SET_I(next);
@@ -3311,7 +3170,6 @@ do { \
next = apply_fun(c_p, r(0), x(1), reg);
SWAPIN;
if (next != NULL) {
- r(0) = reg[0];
SET_I(next);
Dispatchfun();
}
@@ -3322,12 +3180,9 @@ do { \
BeamInstr *next;
SWAPOUT;
- reg[0] = r(0);
-
next = call_fun(c_p, Arg(0), reg, THE_NON_VALUE);
SWAPIN;
if (next != NULL) {
- r(0) = reg[0];
SET_CP(c_p, I+2);
SET_I(next);
Dispatchfun();
@@ -3339,11 +3194,9 @@ do { \
BeamInstr *next;
SWAPOUT;
- reg[0] = r(0);
next = call_fun(c_p, Arg(0), reg, THE_NON_VALUE);
SWAPIN;
if (next != NULL) {
- r(0) = reg[0];
SET_CP(c_p, (BeamInstr *) E[0]);
E = ADD_BYTE_OFFSET(E, Arg(1));
SET_I(next);
@@ -3428,10 +3281,9 @@ do { \
*/
argp = c_p->arg_reg;
- for (i = c_p->arity - 1; i > 0; i--) {
+ for (i = c_p->arity - 1; i >= 0; i--) {
argp[i] = reg[i];
}
- c_p->arg_reg[0] = r(0);
SWAPOUT;
c_p->i = I;
goto do_schedule1;
@@ -3444,19 +3296,14 @@ do { \
Eterm* p;
PreFetch(3, next);
- GetArg2(0, element, tuple);
+ GetArg1(0, element);
+ tuple = REG_TARGET(Arg(1));
ASSERT(is_tuple(tuple));
p = (Eterm *) ((unsigned char *) tuple_val(tuple) + Arg(2));
*p = element;
NextPF(3, next);
}
- OpCase(i_is_ne_exact_f):
- if (EQ(tmp_arg1, tmp_arg2)) {
- ClauseFail();
- }
- Next(1);
-
OpCase(normal_exit): {
SWAPOUT;
c_p->freason = EXC_NORMAL;
@@ -3523,25 +3370,14 @@ do { \
{
Eterm badmatch_val;
- OpCase(badmatch_y):
- badmatch_val = yb(Arg(0));
- goto do_badmatch;
-
OpCase(badmatch_x):
badmatch_val = xb(Arg(0));
- goto do_badmatch;
-
- OpCase(badmatch_r):
- badmatch_val = r(0);
-
- do_badmatch:
c_p->fvalue = badmatch_val;
c_p->freason = BADMATCH;
}
/* Fall through here */
find_func_info: {
- reg[0] = r(0);
SWAPOUT;
I = handle_error(c_p, I, reg, NULL);
goto post_error_handling;
@@ -3559,9 +3395,7 @@ do { \
* code[4]: Not used
*/
SWAPOUT;
- reg[0] = r(0);
I = call_error_handler(c_p, I-3, reg, am_undefined_function);
- r(0) = reg[0];
SWAPIN;
if (I) {
Goto(*I);
@@ -3570,14 +3404,12 @@ do { \
/* Fall through */
OpCase(error_action_code): {
handle_error:
- reg[0] = r(0);
SWAPOUT;
I = handle_error(c_p, NULL, reg, NULL);
post_error_handling:
if (I == 0) {
goto do_schedule;
} else {
- r(0) = reg[0];
ASSERT(!is_value(r(0)));
if (c_p->mbuf) {
erts_garbage_collect(c_p, 0, reg+1, 3);
@@ -3620,7 +3452,6 @@ do { \
NifF* fp = vbf = (NifF*) I[1];
struct enif_environment_t env;
erts_pre_nif(&env, c_p, (struct erl_module_nif*)I[2]);
- reg[0] = r(0);
nif_bif_result = (*fp)(&env, bif_nif_arity, reg);
if (env.exception_thrown)
nif_bif_result = THE_NON_VALUE;
@@ -3659,7 +3490,7 @@ do { \
bif_nif_arity = I[-1];
ASSERT(bif_nif_arity <= 4);
ERTS_SMP_UNREQ_PROC_MAIN_LOCK(c_p);
- reg[0] = r(0);
+ ERTS_VERIFY_UNUSED_TEMP_ALLOC(c_p);
{
Eterm (*bf)(Process*, Eterm*, BeamInstr*) = vbf;
ASSERT(!ERTS_PROC_IS_EXITING(c_p));
@@ -3689,7 +3520,6 @@ do { \
Goto(*I);
} else if (c_p->freason == TRAP) {
SET_I(c_p->i);
- r(0) = reg[0];
if (c_p->flags & F_HIBERNATE_SCHED) {
c_p->flags &= ~F_HIBERNATE_SCHED;
goto do_schedule;
@@ -3716,16 +3546,6 @@ do { \
OpCase(case_end_x):
case_end_val = xb(Arg(0));
- goto do_case_end;
-
- OpCase(case_end_y):
- case_end_val = yb(Arg(0));
- goto do_case_end;
-
- OpCase(case_end_r):
- case_end_val = r(0);
-
- do_case_end:
c_p->fvalue = case_end_val;
c_p->freason = EXC_CASE_CLAUSE;
goto find_func_info;
@@ -3773,19 +3593,13 @@ do { \
goto do_bs_init_bits_known;
}
- OpCase(i_bs_init_bits_fail_heap_IjId): {
- /* tmp_arg1 was fetched by an i_fetch instruction */
- num_bits_term = tmp_arg1;
- alloc = Arg(0);
- I++;
+ OpCase(i_bs_init_bits_fail_heap_sIjId): {
+ GetArg1(0, num_bits_term);
+ alloc = Arg(1);
+ I += 2;
goto do_bs_init_bits;
}
- OpCase(i_bs_init_bits_fail_rjId): {
- num_bits_term = r(0);
- alloc = 0;
- goto do_bs_init_bits;
- }
OpCase(i_bs_init_bits_fail_yjId): {
num_bits_term = yb(Arg(0));
I++;
@@ -3905,52 +3719,48 @@ do { \
}
{
- OpCase(i_bs_init_fail_heap_IjId): {
- /* tmp_arg1 was fetched by an i_fetch instruction */
- tmp_arg2 = Arg(0);
- I++;
- goto do_bs_init;
- }
+ Eterm BsOp1, BsOp2;
- OpCase(i_bs_init_fail_rjId): {
- tmp_arg1 = r(0);
- tmp_arg2 = 0;
+ OpCase(i_bs_init_fail_heap_sIjId): {
+ GetArg1(0, BsOp1);
+ BsOp2 = Arg(1);
+ I += 2;
goto do_bs_init;
}
OpCase(i_bs_init_fail_yjId): {
- tmp_arg1 = yb(Arg(0));
- tmp_arg2 = 0;
+ BsOp1 = yb(Arg(0));
+ BsOp2 = 0;
I++;
goto do_bs_init;
}
OpCase(i_bs_init_fail_xjId): {
- tmp_arg1 = xb(Arg(0));
- tmp_arg2 = 0;
+ BsOp1 = xb(Arg(0));
+ BsOp2 = 0;
I++;
}
/* FALL THROUGH */
do_bs_init:
- if (is_small(tmp_arg1)) {
- Sint size = signed_val(tmp_arg1);
+ if (is_small(BsOp1)) {
+ Sint size = signed_val(BsOp1);
if (size < 0) {
goto badarg;
}
- tmp_arg1 = (Eterm) size;
+ BsOp1 = (Eterm) size;
} else {
Uint bytes;
- if (!term_to_Uint(tmp_arg1, &bytes)) {
+ if (!term_to_Uint(BsOp1, &bytes)) {
c_p->freason = bytes;
goto lb_Cl_error;
}
if ((bytes >> (8*sizeof(Uint)-3)) != 0) {
goto system_limit;
}
- tmp_arg1 = (Eterm) bytes;
+ BsOp1 = (Eterm) bytes;
}
- if (tmp_arg1 <= ERL_ONHEAP_BIN_LIMIT) {
+ if (BsOp1 <= ERL_ONHEAP_BIN_LIMIT) {
goto do_heap_bin_alloc;
} else {
goto do_proc_bin_alloc;
@@ -3958,15 +3768,15 @@ do { \
OpCase(i_bs_init_heap_IIId): {
- tmp_arg1 = Arg(0);
- tmp_arg2 = Arg(1);
+ BsOp1 = Arg(0);
+ BsOp2 = Arg(1);
I++;
goto do_proc_bin_alloc;
}
OpCase(i_bs_init_IId): {
- tmp_arg1 = Arg(0);
- tmp_arg2 = 0;
+ BsOp1 = Arg(0);
+ BsOp2 = 0;
}
/* FALL THROUGH */
do_proc_bin_alloc: {
@@ -3975,13 +3785,13 @@ do { \
erts_bin_offset = 0;
erts_writable_bin = 0;
- TestBinVHeap(tmp_arg1 / sizeof(Eterm),
- tmp_arg2 + PROC_BIN_SIZE + ERL_SUB_BIN_SIZE, Arg(1));
+ TestBinVHeap(BsOp1 / sizeof(Eterm),
+ BsOp2 + PROC_BIN_SIZE + ERL_SUB_BIN_SIZE, Arg(1));
/*
* Allocate the binary struct itself.
*/
- bptr = erts_bin_nrml_alloc(tmp_arg1);
+ bptr = erts_bin_nrml_alloc(BsOp1);
erts_refc_init(&bptr->refc, 1);
erts_current_bin = (byte *) bptr->orig_bytes;
@@ -3991,28 +3801,28 @@ do { \
pb = (ProcBin *) HTOP;
HTOP += PROC_BIN_SIZE;
pb->thing_word = HEADER_PROC_BIN;
- pb->size = tmp_arg1;
+ pb->size = BsOp1;
pb->next = MSO(c_p).first;
MSO(c_p).first = (struct erl_off_heap_header*) pb;
pb->val = bptr;
pb->bytes = (byte*) bptr->orig_bytes;
pb->flags = 0;
- OH_OVERHEAD(&(MSO(c_p)), tmp_arg1 / sizeof(Eterm));
+ OH_OVERHEAD(&(MSO(c_p)), BsOp1 / sizeof(Eterm));
StoreBifResult(2, make_binary(pb));
}
OpCase(i_bs_init_heap_bin_heap_IIId): {
- tmp_arg1 = Arg(0);
- tmp_arg2 = Arg(1);
+ BsOp1 = Arg(0);
+ BsOp2 = Arg(1);
I++;
goto do_heap_bin_alloc;
}
OpCase(i_bs_init_heap_bin_IId): {
- tmp_arg1 = Arg(0);
- tmp_arg2 = 0;
+ BsOp1 = Arg(0);
+ BsOp2 = 0;
}
/* Fall through */
do_heap_bin_alloc:
@@ -4020,33 +3830,36 @@ do { \
ErlHeapBin* hb;
Uint bin_need;
- bin_need = heap_bin_size(tmp_arg1);
+ bin_need = heap_bin_size(BsOp1);
erts_bin_offset = 0;
erts_writable_bin = 0;
- TestHeap(bin_need+tmp_arg2+ERL_SUB_BIN_SIZE, Arg(1));
+ TestHeap(bin_need+BsOp2+ERL_SUB_BIN_SIZE, Arg(1));
hb = (ErlHeapBin *) HTOP;
HTOP += bin_need;
- hb->thing_word = header_heap_bin(tmp_arg1);
- hb->size = tmp_arg1;
+ hb->thing_word = header_heap_bin(BsOp1);
+ hb->size = BsOp1;
erts_current_bin = (byte *) hb->data;
- tmp_arg1 = make_binary(hb);
- StoreBifResult(2, tmp_arg1);
+ BsOp1 = make_binary(hb);
+ StoreBifResult(2, BsOp1);
}
}
- OpCase(i_bs_add_jId): {
- Uint Unit = Arg(1);
- if (is_both_small(tmp_arg1, tmp_arg2)) {
- Sint Arg1 = signed_val(tmp_arg1);
- Sint Arg2 = signed_val(tmp_arg2);
+ OpCase(bs_add_jssId): {
+ Eterm Op1, Op2;
+ Uint Unit = Arg(3);
+
+ GetArg2(1, Op1, Op2);
+ if (is_both_small(Op1, Op2)) {
+ Sint Arg1 = signed_val(Op1);
+ Sint Arg2 = signed_val(Op2);
if (Arg1 >= 0 && Arg2 >= 0) {
- BsSafeMul(Arg2, Unit, goto system_limit, tmp_arg1);
- tmp_arg1 += Arg1;
+ BsSafeMul(Arg2, Unit, goto system_limit, Op1);
+ Op1 += Arg1;
store_bs_add_result:
- if (MY_IS_SSMALL((Sint) tmp_arg1)) {
- tmp_arg1 = make_small(tmp_arg1);
+ if (MY_IS_SSMALL((Sint) Op1)) {
+ Op1 = make_small(Op1);
} else {
/*
* May generate a heap fragment, but in this
@@ -4058,10 +3871,10 @@ do { \
* references (such as the heap).
*/
SWAPOUT;
- tmp_arg1 = erts_make_integer(tmp_arg1, c_p);
+ Op1 = erts_make_integer(Op1, c_p);
HTOP = HEAP_TOP(c_p);
}
- StoreBifResult(2, tmp_arg1);
+ StoreBifResult(4, Op1);
}
goto badarg;
} else {
@@ -4084,16 +3897,16 @@ do { \
* an Uint, the reason is SYSTEM_LIMIT.
*/
- if (!term_to_Uint(tmp_arg1, &a)) {
+ if (!term_to_Uint(Op1, &a)) {
if (a == BADARG) {
goto badarg;
}
- if (!term_to_Uint(tmp_arg2, &b)) {
+ if (!term_to_Uint(Op2, &b)) {
c_p->freason = b;
goto lb_Cl_error;
}
goto system_limit;
- } else if (!term_to_Uint(tmp_arg2, &b)) {
+ } else if (!term_to_Uint(Op2, &b)) {
c_p->freason = b;
goto lb_Cl_error;
}
@@ -4103,8 +3916,8 @@ do { \
*/
BsSafeMul(b, Unit, goto system_limit, c);
- tmp_arg1 = a + c;
- if (tmp_arg1 < a) {
+ Op1 = a + c;
+ if (Op1 < a) {
/*
* If the result is less than one of the
* arguments, there must have been an overflow.
@@ -4126,48 +3939,43 @@ do { \
}
/*
- * tmp_arg1 = Number of bytes to build
- * tmp_arg2 = Source binary
- * Operands: Fail ExtraHeap Live Unit Dst
+ * x(SCRATCH_X_REG);
+ * Operands: Fail ExtraHeap Live Unit Size Dst
*/
- OpCase(i_bs_append_jIIId): {
+ OpCase(i_bs_append_jIIIsd): {
Uint live = Arg(2);
Uint res;
+ Eterm Size;
+ GetArg1(4, Size);
SWAPOUT;
- reg[0] = r(0);
- reg[live] = tmp_arg2;
- res = erts_bs_append(c_p, reg, live, tmp_arg1, Arg(1), Arg(3));
- r(0) = reg[0];
+ reg[live] = x(SCRATCH_X_REG);
+ res = erts_bs_append(c_p, reg, live, Size, Arg(1), Arg(3));
SWAPIN;
if (is_non_value(res)) {
/* c_p->freason is already set (may be either BADARG or SYSTEM_LIMIT). */
goto lb_Cl_error;
}
- StoreBifResult(4, res);
+ StoreBifResult(5, res);
}
/*
- * tmp_arg1 = Number of bytes to build
- * tmp_arg2 = Source binary
- * Operands: Fail Unit Dst
+ * Operands: Fail Size Src Unit Dst
*/
- OpCase(i_bs_private_append_jId): {
+ OpCase(i_bs_private_append_jIssd): {
Eterm res;
+ Eterm Size, Src;
- res = erts_bs_private_append(c_p, tmp_arg2, tmp_arg1, Arg(1));
+ GetArg2(2, Size, Src);
+ res = erts_bs_private_append(c_p, Src, Size, Arg(1));
if (is_non_value(res)) {
/* c_p->freason is already set (may be either BADARG or SYSTEM_LIMIT). */
goto lb_Cl_error;
}
- StoreBifResult(2, res);
+ StoreBifResult(4, res);
}
- /*
- * tmp_arg1 = Initial size of writable binary
- * Operands: Live Dst
- */
OpCase(bs_init_writable): {
SWAPOUT;
r(0) = erts_bs_init_writable(c_p, r(0));
@@ -4262,26 +4070,29 @@ do { \
/*
* Only used for validating a value matched out.
- *
- * tmp_arg1 = Integer to validate
- * tmp_arg2 = Match context
*/
- OpCase(i_bs_validate_unicode_retract_j): {
- /*
- * There is no need to untag the integer, but it IS necessary
- * to make sure it is small (a bignum pointer could fall in
- * the valid range).
- */
- if (is_not_small(tmp_arg1) || tmp_arg1 > make_small(0x10FFFFUL) ||
- (make_small(0xD800UL) <= tmp_arg1 &&
- tmp_arg1 <= make_small(0xDFFFUL))) {
- ErlBinMatchBuffer *mb = ms_matchbuffer(tmp_arg2);
+ OpCase(i_bs_validate_unicode_retract_jss): {
+ Eterm i; /* Integer to validate */
- mb->offset -= 32;
- goto badarg;
- }
- Next(1);
- }
+ /*
+ * There is no need to untag the integer, but it IS necessary
+ * to make sure it is small (a bignum pointer could fall in
+ * the valid range).
+ */
+
+ GetArg1(1, i);
+ if (is_not_small(i) || i > make_small(0x10FFFFUL) ||
+ (make_small(0xD800UL) <= i && i <= make_small(0xDFFFUL))) {
+ Eterm ms; /* Match context */
+ ErlBinMatchBuffer* mb;
+
+ GetArg1(2, ms);
+ mb = ms_matchbuffer(ms);
+ mb->offset -= 32;
+ goto badarg;
+ }
+ Next(3);
+ }
/*
* Matching of binaries.
@@ -4293,9 +4104,6 @@ do { \
Uint slots;
Eterm context;
- OpCase(i_bs_start_match2_rfIId): {
- context = r(0);
-
do_start_match:
slots = Arg(2);
if (!is_boxed(context)) {
@@ -4342,7 +4150,7 @@ do { \
ClauseFail();
}
NextPF(4, next);
- }
+
OpCase(i_bs_start_match2_xfIId): {
context = xb(Arg(0));
I++;
@@ -4355,18 +4163,6 @@ do { \
}
}
- OpCase(bs_test_zero_tail2_fr): {
- BeamInstr *next;
- ErlBinMatchBuffer *_mb;
-
- PreFetch(1, next);
- _mb = (ErlBinMatchBuffer*) ms_matchbuffer(r(0));
- if (_mb->size != _mb->offset) {
- ClauseFail();
- }
- NextPF(1, next);
- }
-
OpCase(bs_test_zero_tail2_fx): {
BeamInstr *next;
ErlBinMatchBuffer *_mb;
@@ -4379,16 +4175,6 @@ do { \
NextPF(2, next);
}
- OpCase(bs_test_tail_imm2_frI): {
- BeamInstr *next;
- ErlBinMatchBuffer *_mb;
- PreFetch(2, next);
- _mb = ms_matchbuffer(r(0));
- if (_mb->size - _mb->offset != Arg(1)) {
- ClauseFail();
- }
- NextPF(2, next);
- }
OpCase(bs_test_tail_imm2_fxI): {
BeamInstr *next;
ErlBinMatchBuffer *_mb;
@@ -4400,16 +4186,6 @@ do { \
NextPF(3, next);
}
- OpCase(bs_test_unit_frI): {
- BeamInstr *next;
- ErlBinMatchBuffer *_mb;
- PreFetch(2, next);
- _mb = ms_matchbuffer(r(0));
- if ((_mb->size - _mb->offset) % Arg(1)) {
- ClauseFail();
- }
- NextPF(2, next);
- }
OpCase(bs_test_unit_fxI): {
BeamInstr *next;
ErlBinMatchBuffer *_mb;
@@ -4421,16 +4197,6 @@ do { \
NextPF(3, next);
}
- OpCase(bs_test_unit8_fr): {
- BeamInstr *next;
- ErlBinMatchBuffer *_mb;
- PreFetch(1, next);
- _mb = ms_matchbuffer(r(0));
- if ((_mb->size - _mb->offset) & 7) {
- ClauseFail();
- }
- NextPF(1, next);
- }
OpCase(bs_test_unit8_fx): {
BeamInstr *next;
ErlBinMatchBuffer *_mb;
@@ -4445,19 +4211,11 @@ do { \
{
Eterm bs_get_integer8_context;
- OpCase(i_bs_get_integer_8_rfd): {
- bs_get_integer8_context = r(0);
- goto do_bs_get_integer_8;
- }
-
OpCase(i_bs_get_integer_8_xfd): {
- bs_get_integer8_context = xb(Arg(0));
- I++;
- }
-
- do_bs_get_integer_8: {
ErlBinMatchBuffer *_mb;
Eterm _result;
+ bs_get_integer8_context = xb(Arg(0));
+ I++;
_mb = ms_matchbuffer(bs_get_integer8_context);
if (_mb->size - _mb->offset < 8) {
ClauseFail();
@@ -4475,15 +4233,10 @@ do { \
{
Eterm bs_get_integer_16_context;
- OpCase(i_bs_get_integer_16_rfd):
- bs_get_integer_16_context = r(0);
- goto do_bs_get_integer_16;
-
OpCase(i_bs_get_integer_16_xfd):
bs_get_integer_16_context = xb(Arg(0));
I++;
- do_bs_get_integer_16:
{
ErlBinMatchBuffer *_mb;
Eterm _result;
@@ -4504,17 +4257,10 @@ do { \
{
Eterm bs_get_integer_32_context;
- OpCase(i_bs_get_integer_32_rfId):
- bs_get_integer_32_context = r(0);
- goto do_bs_get_integer_32;
-
-
OpCase(i_bs_get_integer_32_xfId):
bs_get_integer_32_context = xb(Arg(0));
I++;
-
- do_bs_get_integer_32:
{
ErlBinMatchBuffer *_mb;
Uint32 _integer;
@@ -4543,103 +4289,82 @@ do { \
}
}
- /* Operands: Size Live Fail Flags Dst */
- OpCase(i_bs_get_integer_imm_rIIfId): {
- tmp_arg1 = r(0);
- /* Operands: Size Live Fail Flags Dst */
- goto do_bs_get_integer_imm_test_heap;
- }
+ {
+ Eterm Ms, Sz;
- /* Operands: x(Reg) Size Live Fail Flags Dst */
+ /* Operands: x(Reg) Size Live Fail Flags Dst */
OpCase(i_bs_get_integer_imm_xIIfId): {
- tmp_arg1 = xb(Arg(0));
- I++;
- /* Operands: Size Live Fail Flags Dst */
- goto do_bs_get_integer_imm_test_heap;
- }
-
- /*
- * tmp_arg1 = match context
- * Operands: Size Live Fail Flags Dst
- */
- do_bs_get_integer_imm_test_heap: {
- Uint wordsneeded;
- tmp_arg2 = Arg(0);
- wordsneeded = 1+WSIZE(NBYTES(tmp_arg2));
- TestHeapPreserve(wordsneeded, Arg(1), tmp_arg1);
- I += 2;
- /* Operands: Fail Flags Dst */
- goto do_bs_get_integer_imm;
- }
-
- /* Operands: Size Fail Flags Dst */
- OpCase(i_bs_get_integer_small_imm_rIfId): {
- tmp_arg1 = r(0);
- tmp_arg2 = Arg(0);
- I++;
- /* Operands: Fail Flags Dst */
- goto do_bs_get_integer_imm;
- }
+ Uint wordsneeded;
+ Ms = xb(Arg(0));
+ Sz = Arg(1);
+ wordsneeded = 1+WSIZE(NBYTES(Sz));
+ TestHeapPreserve(wordsneeded, Arg(2), Ms);
+ I += 3;
+ /* Operands: Fail Flags Dst */
+ goto do_bs_get_integer_imm;
+ }
- /* Operands: x(Reg) Size Fail Flags Dst */
+ /* Operands: x(Reg) Size Fail Flags Dst */
OpCase(i_bs_get_integer_small_imm_xIfId): {
- tmp_arg1 = xb(Arg(0));
- tmp_arg2 = Arg(1);
- I += 2;
- /* Operands: Fail Flags Dst */
- goto do_bs_get_integer_imm;
- }
+ Ms = xb(Arg(0));
+ Sz = Arg(1);
+ I += 2;
+ /* Operands: Fail Flags Dst */
+ goto do_bs_get_integer_imm;
+ }
- /*
- * tmp_arg1 = match context
- * tmp_arg2 = size of field
- * Operands: Fail Flags Dst
- */
+ /*
+ * Ms = match context
+ * Sz = size of field
+ * Operands: Fail Flags Dst
+ */
do_bs_get_integer_imm: {
- ErlBinMatchBuffer* mb;
- Eterm result;
+ ErlBinMatchBuffer* mb;
+ Eterm result;
- mb = ms_matchbuffer(tmp_arg1);
- LIGHT_SWAPOUT;
- result = erts_bs_get_integer_2(c_p, tmp_arg2, Arg(1), mb);
- LIGHT_SWAPIN;
- HEAP_SPACE_VERIFIED(0);
- if (is_non_value(result)) {
- ClauseFail();
+ mb = ms_matchbuffer(Ms);
+ LIGHT_SWAPOUT;
+ result = erts_bs_get_integer_2(c_p, Sz, Arg(1), mb);
+ LIGHT_SWAPIN;
+ HEAP_SPACE_VERIFIED(0);
+ if (is_non_value(result)) {
+ ClauseFail();
+ }
+ StoreBifResult(2, result);
}
- StoreBifResult(2, result);
}
/*
- * tmp_arg1 = Match context
- * tmp_arg2 = Size field
- * Operands: Fail Live FlagsAndUnit Dst
+ * Operands: Fail Live FlagsAndUnit Ms Sz Dst
*/
- OpCase(i_bs_get_integer_fIId): {
+ OpCase(i_bs_get_integer_fIIssd): {
Uint flags;
Uint size;
+ Eterm Ms;
+ Eterm Sz;
ErlBinMatchBuffer* mb;
Eterm result;
flags = Arg(2);
- BsGetFieldSize(tmp_arg2, (flags >> 3), ClauseFail(), size);
+ GetArg2(3, Ms, Sz);
+ BsGetFieldSize(Sz, (flags >> 3), ClauseFail(), size);
if (size >= SMALL_BITS) {
Uint wordsneeded;
- /* check bits size before potential gc.
+ /* Check bits size before potential gc.
* We do not want a gc and then realize we don't need
- * the allocated space (i.e. if the op fails)
+ * the allocated space (i.e. if the op fails).
*
- * remember to reacquire the matchbuffer after gc.
+ * Remember to re-acquire the matchbuffer after gc.
*/
- mb = ms_matchbuffer(tmp_arg1);
+ mb = ms_matchbuffer(Ms);
if (mb->size - mb->offset < size) {
ClauseFail();
}
wordsneeded = 1+WSIZE(NBYTES((Uint) size));
- TestHeapPreserve(wordsneeded, Arg(1), tmp_arg1);
+ TestHeapPreserve(wordsneeded, Arg(1), Ms);
}
- mb = ms_matchbuffer(tmp_arg1);
+ mb = ms_matchbuffer(Ms);
LIGHT_SWAPOUT;
result = erts_bs_get_integer_2(c_p, size, flags, mb);
LIGHT_SWAPIN;
@@ -4647,18 +4372,13 @@ do { \
if (is_non_value(result)) {
ClauseFail();
}
- StoreBifResult(3, result);
+ StoreBifResult(5, result);
}
{
Eterm get_utf8_context;
/* Operands: MatchContext Fail Dst */
- OpCase(i_bs_get_utf8_rfd): {
- get_utf8_context = r(0);
- goto do_bs_get_utf8;
- }
-
OpCase(i_bs_get_utf8_xfd): {
get_utf8_context = xb(Arg(0));
I++;
@@ -4669,7 +4389,7 @@ do { \
* Operands: Fail Dst
*/
- do_bs_get_utf8: {
+ {
Eterm result = erts_bs_get_utf8(ms_matchbuffer(get_utf8_context));
if (is_non_value(result)) {
ClauseFail();
@@ -4682,12 +4402,7 @@ do { \
Eterm get_utf16_context;
/* Operands: MatchContext Fail Flags Dst */
- OpCase(i_bs_get_utf16_rfId): {
- get_utf16_context = r(0);
- goto do_bs_get_utf16;
- }
-
- OpCase(i_bs_get_utf16_xfId): {
+ OpCase(i_bs_get_utf16_xfId): {
get_utf16_context = xb(Arg(0));
I++;
}
@@ -4696,7 +4411,7 @@ do { \
* get_utf16_context = match_context
* Operands: Fail Flags Dst
*/
- do_bs_get_utf16: {
+ {
Eterm result = erts_bs_get_utf16(ms_matchbuffer(get_utf16_context),
Arg(1));
if (is_non_value(result)) {
@@ -4715,26 +4430,10 @@ do { \
Uint orig;
Uint hole_size;
- OpCase(bs_context_to_binary_r): {
- context_to_binary_context = x0;
- I -= 2;
- goto do_context_to_binary;
- }
-
- /* Unfortunately, inlining can generate this instruction. */
- OpCase(bs_context_to_binary_y): {
- context_to_binary_context = yb(Arg(0));
- goto do_context_to_binary0;
- }
-
- OpCase(bs_context_to_binary_x): {
+ OpCase(bs_context_to_binary_x):
context_to_binary_context = xb(Arg(0));
-
- do_context_to_binary0:
I--;
- }
- do_context_to_binary:
if (is_boxed(context_to_binary_context) &&
header_is_bin_matchstate(*boxed_val(context_to_binary_context))) {
ErlBinMatchState* ms;
@@ -4746,17 +4445,11 @@ do { \
}
Next(2);
- OpCase(i_bs_get_binary_all_reuse_rfI): {
- context_to_binary_context = x0;
- goto do_bs_get_binary_all_reuse;
- }
-
OpCase(i_bs_get_binary_all_reuse_xfI): {
context_to_binary_context = xb(Arg(0));
I++;
}
- do_bs_get_binary_all_reuse:
mb = ms_matchbuffer(context_to_binary_context);
size = mb->size - mb->offset;
if (size % Arg(1) != 0) {
@@ -4784,16 +4477,11 @@ do { \
{
Eterm match_string_context;
- OpCase(i_bs_match_string_rfII): {
- match_string_context = r(0);
- goto do_bs_match_string;
- }
OpCase(i_bs_match_string_xfII): {
match_string_context = xb(Arg(0));
I++;
}
- do_bs_match_string:
{
BeamInstr *next;
byte* bytes;
@@ -4821,14 +4509,6 @@ do { \
}
}
- OpCase(i_bs_save2_rI): {
- BeamInstr *next;
- ErlBinMatchState *_ms;
- PreFetch(1, next);
- _ms = (ErlBinMatchState*) boxed_val((Eterm) r(0));
- _ms->save_offset[Arg(0)] = _ms->mb.offset;
- NextPF(1, next);
- }
OpCase(i_bs_save2_xI): {
BeamInstr *next;
ErlBinMatchState *_ms;
@@ -4838,14 +4518,6 @@ do { \
NextPF(2, next);
}
- OpCase(i_bs_restore2_rI): {
- BeamInstr *next;
- ErlBinMatchState *_ms;
- PreFetch(1, next);
- _ms = (ErlBinMatchState*) boxed_val((Eterm) r(0));
- _ms->mb.offset = _ms->save_offset[Arg(0)];
- NextPF(1, next);
- }
OpCase(i_bs_restore2_xI): {
BeamInstr *next;
ErlBinMatchState *_ms;
@@ -4893,9 +4565,7 @@ do { \
BeamInstr real_I;
ASSERT(I[-5] == (BeamInstr) BeamOp(op_i_func_info_IaaI));
SWAPOUT;
- reg[0] = r(0);
real_I = erts_generic_breakpoint(c_p, I, reg);
- r(0) = reg[0];
SWAPIN;
ASSERT(VALID_INSTR(real_I));
Goto(real_I);
@@ -4955,7 +4625,7 @@ do { \
BeamInstr *next;
PreFetch(2, next);
- GetR(0, targ1);
+ targ1 = REG_TARGET(Arg(0));
/* Arg(0) == HEADER_FLONUM */
GET_DOUBLE(targ1, *(FloatDef*)ADD_BYTE_OFFSET(freg, fr));
NextPF(2, next);
@@ -4975,7 +4645,7 @@ do { \
Eterm fr = Arg(1);
BeamInstr *next;
- GetR(0, targ1);
+ targ1 = REG_TARGET(Arg(0));
PreFetch(2, next);
if (is_small(targ1)) {
fb(fr) = (double) signed_val(targ1);
@@ -5071,7 +4741,12 @@ do { \
#ifdef HIPE
{
- unsigned cmd;
+#define HIPE_MODE_SWITCH(Cmd) \
+ SWAPOUT; \
+ c_p->fcalls = FCALLS; \
+ c_p->def_arg_reg[4] = -neg_o_reds; \
+ c_p = hipe_mode_switch(c_p, Cmd, reg); \
+ goto L_post_hipe_mode_switch
OpCase(hipe_trap_call): {
/*
@@ -5085,52 +4760,45 @@ do { \
*/
ASSERT(I[-5] == (Uint) OpCode(i_func_info_IaaI));
c_p->hipe.u.ncallee = (void(*)(void)) I[-4];
- cmd = HIPE_MODE_SWITCH_CMD_CALL | (I[-1] << 8);
++hipe_trap_count;
- goto L_hipe_mode_switch;
+ HIPE_MODE_SWITCH(HIPE_MODE_SWITCH_CMD_CALL | (I[-1] << 8));
}
OpCase(hipe_trap_call_closure): {
ASSERT(I[-5] == (Uint) OpCode(i_func_info_IaaI));
c_p->hipe.u.ncallee = (void(*)(void)) I[-4];
- cmd = HIPE_MODE_SWITCH_CMD_CALL_CLOSURE | (I[-1] << 8);
++hipe_trap_count;
- goto L_hipe_mode_switch;
+ HIPE_MODE_SWITCH(HIPE_MODE_SWITCH_CMD_CALL_CLOSURE | (I[-1] << 8));
}
OpCase(hipe_trap_return): {
- cmd = HIPE_MODE_SWITCH_CMD_RETURN;
- goto L_hipe_mode_switch;
+ HIPE_MODE_SWITCH(HIPE_MODE_SWITCH_CMD_RETURN);
}
OpCase(hipe_trap_throw): {
- cmd = HIPE_MODE_SWITCH_CMD_THROW;
- goto L_hipe_mode_switch;
+ HIPE_MODE_SWITCH(HIPE_MODE_SWITCH_CMD_THROW);
}
OpCase(hipe_trap_resume): {
- cmd = HIPE_MODE_SWITCH_CMD_RESUME;
- goto L_hipe_mode_switch;
+ HIPE_MODE_SWITCH(HIPE_MODE_SWITCH_CMD_RESUME);
}
- L_hipe_mode_switch:
- /* XXX: this abuse of def_arg_reg[] is horrid! */
- SWAPOUT;
- c_p->fcalls = FCALLS;
- c_p->def_arg_reg[4] = -neg_o_reds;
- reg[0] = r(0);
- c_p = hipe_mode_switch(c_p, cmd, reg);
+#undef HIPE_MODE_SWITCH
+
+ L_post_hipe_mode_switch:
reg = ERTS_PROC_GET_SCHDATA(c_p)->x_reg_array;
freg = ERTS_PROC_GET_SCHDATA(c_p)->f_reg_array;
ERL_BITS_RELOAD_STATEP(c_p);
+ /* XXX: this abuse of def_arg_reg[] is horrid! */
neg_o_reds = -c_p->def_arg_reg[4];
FCALLS = c_p->fcalls;
SWAPIN;
switch( c_p->def_arg_reg[3] ) {
case HIPE_MODE_SWITCH_RES_RETURN:
ASSERT(is_value(reg[0]));
- MoveReturn(reg[0], r(0));
+ SET_I(c_p->cp);
+ c_p->cp = 0;
+ Goto(*I);
case HIPE_MODE_SWITCH_RES_CALL_EXPORTED:
c_p->i = c_p->hipe.u.callee_exp->addressv[erts_active_code_ix()];
/*fall through*/
case HIPE_MODE_SWITCH_RES_CALL_BEAM:
SET_I(c_p->i);
- r(0) = reg[0];
Dispatch();
case HIPE_MODE_SWITCH_RES_CALL_CLOSURE:
/* This can be used to call any function value, but currently it's
@@ -5141,7 +4809,6 @@ do { \
next = call_fun(c_p, c_p->arity - 1, reg, THE_NON_VALUE);
SWAPIN;
if (next != NULL) {
- r(0) = reg[0];
SET_I(next);
Dispatchfun();
}
@@ -5201,9 +4868,7 @@ do { \
OpCase(i_debug_breakpoint): {
SWAPOUT;
- reg[0] = r(0);
I = call_error_handler(c_p, I-3, reg, am_breakpoint);
- r(0) = reg[0];
SWAPIN;
if (I) {
Goto(*I);
@@ -6211,6 +5876,23 @@ erts_hibernate(Process* c_p, Eterm module, Eterm function, Eterm args, Eterm* re
int arity;
Eterm tmp;
+#ifndef ERTS_SMP
+ if (ERTS_PROC_IS_EXITING(c_p)) {
+ /*
+ * I non smp case:
+ *
+ * Currently executing process might be sent an exit
+ * signal if it is traced by a port that it also is
+ * linked to, and the port terminates during the
+ * trace. In this case we do *not* want to clear
+ * the active flag, which will make the process hang
+ * in limbo forever. Get out of here and terminate
+ * the process...
+ */
+ return -1;
+ }
+#endif
+
if (is_not_atom(module) || is_not_atom(function)) {
/*
* No need to test args here -- done below.
@@ -6287,7 +5969,16 @@ erts_hibernate(Process* c_p, Eterm module, Eterm function, Eterm args, Eterm* re
ERTS_VERIFY_UNUSED_TEMP_ALLOC(c_p);
PROCESS_MAIN_CHK_LOCKS(c_p);
erts_smp_proc_lock(c_p, ERTS_PROC_LOCK_MSGQ|ERTS_PROC_LOCK_STATUS);
-#ifdef ERTS_SMP
+#ifndef ERTS_SMP
+ if (ERTS_PROC_IS_EXITING(c_p)) {
+ /*
+ * See comment in the begining of the function...
+ *
+ * This second test is needed since gc might be traced.
+ */
+ return -1;
+ }
+#else /* ERTS_SMP */
ERTS_SMP_MSGQ_MV_INQ2PRIVQ(c_p);
if (!c_p->msg.len)
#endif
@@ -6594,23 +6285,20 @@ static Eterm get_map_element_hash(Eterm map, Eterm key, Uint32 hx)
return vs ? *vs : THE_NON_VALUE;
}
-#define GET_TERM(term, dest) \
-do { \
- Eterm src = (Eterm)(term); \
- switch (src & _TAG_IMMED1_MASK) { \
- case (R_REG_DEF << _TAG_PRIMARY_SIZE) | TAG_PRIMARY_HEADER: \
- dest = x(0); \
- break; \
- case (X_REG_DEF << _TAG_PRIMARY_SIZE) | TAG_PRIMARY_HEADER: \
- dest = x(src >> _TAG_IMMED1_SIZE); \
- break; \
- case (Y_REG_DEF << _TAG_PRIMARY_SIZE) | TAG_PRIMARY_HEADER: \
- dest = y(src >> _TAG_IMMED1_SIZE); \
- break; \
- default: \
- dest = src; \
- break; \
- } \
+#define GET_TERM(term, dest) \
+do { \
+ Eterm src = (Eterm)(term); \
+ switch (loader_tag(src)) { \
+ case LOADER_X_REG: \
+ dest = x(loader_x_reg_index(src)); \
+ break; \
+ case LOADER_Y_REG: \
+ dest = y(loader_y_reg_index(src)); \
+ break; \
+ default: \
+ dest = src; \
+ break; \
+ } \
} while(0)
diff --git a/erts/emulator/beam/beam_load.c b/erts/emulator/beam/beam_load.c
index 10baab506a..a9d47eb7b0 100644
--- a/erts/emulator/beam/beam_load.c
+++ b/erts/emulator/beam/beam_load.c
@@ -1847,9 +1847,7 @@ load_code(LoaderState* stp)
case TAG_o:
break;
case TAG_x:
- if (last_op->a[arg].val == 0) {
- last_op->a[arg].type = TAG_r;
- } else if (last_op->a[arg].val >= MAX_REG) {
+ if (last_op->a[arg].val >= MAX_REG) {
LoadError1(stp, "invalid x register number: %u",
last_op->a[arg].val);
}
@@ -2055,7 +2053,42 @@ load_code(LoaderState* stp)
if (((opc[specific].mask[0] & mask[0]) == mask[0]) &&
((opc[specific].mask[1] & mask[1]) == mask[1]) &&
((opc[specific].mask[2] & mask[2]) == mask[2])) {
- break;
+
+ if (!opc[specific].involves_r) {
+ break; /* No complications - match */
+ }
+
+ /*
+ * The specific operation uses the 'r' operand,
+ * which is shorthand for x(0). Now things
+ * get complicated. First we must check whether
+ * all operands that should be of type 'r' use
+ * x(0) (as opposed to some other X register).
+ */
+ for (arg = 0; arg < arity; arg++) {
+ if (opc[specific].involves_r & (1 << arg) &&
+ tmp_op->a[arg].type == TAG_x) {
+ if (tmp_op->a[arg].val != 0) {
+ break; /* Other X register than 0 */
+ }
+ }
+ }
+
+ if (arg == arity) {
+ /*
+ * All 'r' operands use x(0) in the generic
+ * operation. That means a match. Now we
+ * will need to rewrite the generic instruction
+ * to actually use 'r' instead of 'x(0)'.
+ */
+ for (arg = 0; arg < arity; arg++) {
+ if (opc[specific].involves_r & (1 << arg) &&
+ tmp_op->a[arg].type == TAG_x) {
+ tmp_op->a[arg].type = TAG_r;
+ }
+ }
+ break; /* Match */
+ }
}
specific++;
}
@@ -2166,14 +2199,11 @@ load_code(LoaderState* stp)
break;
case 's': /* Any source (tagged constant or register) */
switch (tag) {
- case TAG_r:
- code[ci++] = make_rreg();
- break;
case TAG_x:
- code[ci++] = make_xreg(tmp_op->a[arg].val);
+ code[ci++] = make_loader_x_reg(tmp_op->a[arg].val);
break;
case TAG_y:
- code[ci++] = make_yreg(tmp_op->a[arg].val);
+ code[ci++] = make_loader_y_reg(tmp_op->a[arg].val);
break;
case TAG_i:
code[ci++] = (BeamInstr) make_small((Uint)tmp_op->a[arg].val);
@@ -2184,6 +2214,10 @@ load_code(LoaderState* stp)
case TAG_n:
code[ci++] = NIL;
break;
+ case TAG_q:
+ new_literal_patch(stp, ci);
+ code[ci++] = tmp_op->a[arg].val;
+ break;
default:
LoadError1(stp, "bad tag %d for general source",
tmp_op->a[arg].type);
@@ -2192,14 +2226,11 @@ load_code(LoaderState* stp)
break;
case 'd': /* Destination (x(0), x(N), y(N) */
switch (tag) {
- case TAG_r:
- code[ci++] = make_rreg();
- break;
case TAG_x:
- code[ci++] = make_xreg(tmp_op->a[arg].val);
+ code[ci++] = tmp_op->a[arg].val * sizeof(Eterm);
break;
case TAG_y:
- code[ci++] = make_yreg(tmp_op->a[arg].val);
+ code[ci++] = tmp_op->a[arg].val * sizeof(Eterm) + 1;
break;
default:
LoadError1(stp, "bad tag %d for destination",
@@ -2356,20 +2387,13 @@ load_code(LoaderState* stp)
stp->labels[tmp_op->a[arg].val].patches = ci;
ci++;
break;
- case TAG_r:
- CodeNeed(1);
- code[ci++] = (R_REG_DEF << _TAG_PRIMARY_SIZE) |
- TAG_PRIMARY_HEADER;
- break;
case TAG_x:
CodeNeed(1);
- code[ci++] = (tmp_op->a[arg].val << _TAG_IMMED1_SIZE) |
- (X_REG_DEF << _TAG_PRIMARY_SIZE) | TAG_PRIMARY_HEADER;
+ code[ci++] = make_loader_x_reg(tmp_op->a[arg].val);
break;
case TAG_y:
CodeNeed(1);
- code[ci++] = (tmp_op->a[arg].val << _TAG_IMMED1_SIZE) |
- (Y_REG_DEF << _TAG_PRIMARY_SIZE) | TAG_PRIMARY_HEADER;
+ code[ci++] = make_loader_y_reg(tmp_op->a[arg].val);
break;
case TAG_n:
CodeNeed(1);
@@ -2457,7 +2481,6 @@ load_code(LoaderState* stp)
stp->on_load = ci;
break;
case op_bs_put_string_II:
- case op_i_bs_match_string_rfII:
case op_i_bs_match_string_xfII:
new_string_patch(stp, ci-1);
break;
@@ -2679,6 +2702,12 @@ same_label(LoaderState* stp, GenOpArg Target, GenOpArg Label)
Target.val == Label.val;
}
+static int
+is_killed(LoaderState* stp, GenOpArg Reg, GenOpArg Live)
+{
+ return Reg.type == TAG_x && Live.type == TAG_u &&
+ Live.val <= Reg.val;
+}
/*
* Generate an instruction for element/2.
@@ -2695,17 +2724,17 @@ gen_element(LoaderState* stp, GenOpArg Fail, GenOpArg Index,
op->next = NULL;
if (Index.type == TAG_i && Index.val > 0 &&
- (Tuple.type == TAG_r || Tuple.type == TAG_x || Tuple.type == TAG_y)) {
+ (Tuple.type == TAG_x || Tuple.type == TAG_y)) {
op->op = genop_i_fast_element_4;
- op->a[0] = Tuple;
- op->a[1] = Fail;
+ op->a[0] = Fail;
+ op->a[1] = Tuple;
op->a[2].type = TAG_u;
op->a[2].val = Index.val;
op->a[3] = Dst;
} else {
op->op = genop_i_element_4;
- op->a[0] = Tuple;
- op->a[1] = Fail;
+ op->a[0] = Fail;
+ op->a[1] = Tuple;
op->a[2] = Index;
op->a[3] = Dst;
}
@@ -2831,23 +2860,16 @@ gen_get_integer2(LoaderState* stp, GenOpArg Fail, GenOpArg Ms, GenOpArg Live,
goto generic;
}
} else {
- GenOp* op2;
- NEW_GENOP(stp, op2);
-
- op->op = genop_i_fetch_2;
- op->arity = 2;
- op->a[0] = Ms;
- op->a[1] = Size;
- op->next = op2;
-
- op2->op = genop_i_bs_get_integer_4;
- op2->arity = 4;
- op2->a[0] = Fail;
- op2->a[1] = Live;
- op2->a[2].type = TAG_u;
- op2->a[2].val = (Unit.val << 3) | Flags.val;
- op2->a[3] = Dst;
- op2->next = NULL;
+ op->op = genop_i_bs_get_integer_6;
+ op->arity = 6;
+ op->a[0] = Fail;
+ op->a[1] = Live;
+ op->a[2].type = TAG_u;
+ op->a[2].val = (Unit.val << 3) | Flags.val;
+ op->a[3] = Ms;
+ op->a[4] = Size;
+ op->a[5] = Dst;
+ op->next = NULL;
return op;
}
op->next = NULL;
@@ -3898,9 +3920,7 @@ gen_make_fun2(LoaderState* stp, GenOpArg idx)
/*
* Rewrite gc_bifs with one parameter (the common case). Utilized
* in ops.tab to rewrite instructions calling bif's in guards
- * to use a garbage collecting implementation. The instructions
- * are sometimes once again rewritten to handle literals (putting the
- * parameter in the mostly unused r[0] before the instruction is executed).
+ * to use a garbage collecting implementation.
*/
static GenOp*
gen_guard_bif1(LoaderState* stp, GenOpArg Fail, GenOpArg Live, GenOpArg Bif,
@@ -3955,10 +3975,6 @@ gen_guard_bif1(LoaderState* stp, GenOpArg Fail, GenOpArg Live, GenOpArg Bif,
/*
* This is used by the ops.tab rule that rewrites gc_bifs with two parameters.
- * The instruction returned is then again rewritten to an i_load instruction
- * followed by i_gc_bif2_jIId, to handle literals properly.
- * As opposed to the i_gc_bif1_jIsId, the instruction i_gc_bif2_jIId is
- * always rewritten, regardless of if there actually are any literals.
*/
static GenOp*
gen_guard_bif2(LoaderState* stp, GenOpArg Fail, GenOpArg Live, GenOpArg Bif,
@@ -3985,23 +4001,19 @@ gen_guard_bif2(LoaderState* stp, GenOpArg Fail, GenOpArg Live, GenOpArg Bif,
op->a[2].val = stp->import[Bif.val].arity;
return op;
}
- op->op = genop_ii_gc_bif2_6;
+ op->op = genop_i_gc_bif2_6;
op->arity = 6;
op->a[0] = Fail;
op->a[1].type = TAG_u;
- op->a[2] = S1;
- op->a[3] = S2;
- op->a[4] = Live;
+ op->a[2] = Live;
+ op->a[3] = S1;
+ op->a[4] = S2;
op->a[5] = Dst;
return op;
}
/*
* This is used by the ops.tab rule that rewrites gc_bifs with three parameters.
- * The instruction returned is then again rewritten to a move instruction that
- * uses r[0] for temp storage, followed by an i_load instruction,
- * followed by i_gc_bif3_jIsId, to handle literals properly. Rewriting
- * always occur, as with the gc_bif2 counterpart.
*/
static GenOp*
gen_guard_bif3(LoaderState* stp, GenOpArg Fail, GenOpArg Live, GenOpArg Bif,
@@ -4032,10 +4044,10 @@ gen_guard_bif3(LoaderState* stp, GenOpArg Fail, GenOpArg Live, GenOpArg Bif,
op->arity = 7;
op->a[0] = Fail;
op->a[1].type = TAG_u;
- op->a[2] = S1;
- op->a[3] = S2;
- op->a[4] = S3;
- op->a[5] = Live;
+ op->a[2] = Live;
+ op->a[3] = S1;
+ op->a[4] = S2;
+ op->a[5] = S3;
op->a[6] = Dst;
op->next = NULL;
return op;
@@ -4322,7 +4334,7 @@ gen_has_map_fields(LoaderState* stp, GenOpArg Fail, GenOpArg Src,
for (i = 0; i < n; i++) {
op->a[3+2*i] = Rest[i];
op->a[3+2*i+1].type = TAG_x;
- op->a[3+2*i+1].val = 0; /* x(0); normally not used */
+ op->a[3+2*i+1].val = SCRATCH_X_REG; /* Ignore result */
}
return op;
}
@@ -4800,7 +4812,8 @@ transform_engine(LoaderState* st)
if (var[i].type != instr->a[ap].type)
goto restart;
switch (var[i].type) {
- case TAG_r: case TAG_n: break;
+ case TAG_n:
+ break;
default:
if (var[i].val != instr->a[ap].val)
goto restart;
@@ -5867,7 +5880,7 @@ make_stub(BeamInstr* fp, Eterm mod, Eterm func, Uint arity, Uint native, BeamIns
fp[4] = arity;
#ifdef HIPE
if (native) {
- fp[5] = BeamOpCode(op_move_return_nr);
+ fp[5] = BeamOpCode(op_move_return_n);
hipe_mfa_save_orig_beam_op(mod, func, arity, fp+5);
}
#endif
@@ -6303,7 +6316,7 @@ erts_make_stub_module(Process* p, Eterm Mod, Eterm Beam, Eterm Info)
#ifdef HIPE
op = (Eterm) BeamOpCode(op_hipe_trap_call); /* Might be changed later. */
#else
- op = (Eterm) BeamOpCode(op_move_return_nr);
+ op = (Eterm) BeamOpCode(op_move_return_n);
#endif
fp = make_stub(fp, Mod, func, arity, (Uint)native_address, op);
}
diff --git a/erts/emulator/beam/beam_load.h b/erts/emulator/beam/beam_load.h
index d5af634fad..eedb5ee4cd 100644
--- a/erts/emulator/beam/beam_load.h
+++ b/erts/emulator/beam/beam_load.h
@@ -52,6 +52,7 @@ extern BeamInstr* em_call_error_handler;
extern BeamInstr* em_apply_bif;
extern BeamInstr* em_call_nif;
+
/*
* The following variables keep a sorted list of address ranges for
* each module. It allows us to quickly find a function given an
diff --git a/erts/emulator/beam/erl_arith.c b/erts/emulator/beam/erl_arith.c
index b8c5ef9b09..3671025d22 100644
--- a/erts/emulator/beam/erl_arith.c
+++ b/erts/emulator/beam/erl_arith.c
@@ -42,15 +42,8 @@
# define MAX(x, y) (((x) > (y)) ? (x) : (y))
#endif
-#if !HEAP_ON_C_STACK
-# define DECLARE_TMP(VariableName,N,P) \
- Eterm *VariableName = ((ERTS_PROC_GET_SCHDATA(P)->erl_arith_tmp_heap) + (2 * N))
-#else
-# define DECLARE_TMP(VariableName,N,P) \
- Eterm VariableName[2]
-#endif
-# define ARG_IS_NOT_TMP(Arg,Tmp) ((Arg) != make_big((Tmp)))
-
+#define DECLARE_TMP(VariableName,N,P) Eterm VariableName[2]
+#define ARG_IS_NOT_TMP(Arg,Tmp) ((Arg) != make_big((Tmp)))
static Eterm shift(Process* p, Eterm arg1, Eterm arg2, int right);
diff --git a/erts/emulator/beam/erl_bif_info.c b/erts/emulator/beam/erl_bif_info.c
index a3ff537aa1..9a132ee007 100644
--- a/erts/emulator/beam/erl_bif_info.c
+++ b/erts/emulator/beam/erl_bif_info.c
@@ -73,9 +73,6 @@ static char otp_version[] = ERLANG_OTP_VERSION;
static char erts_system_version[] = ("Erlang/OTP " ERLANG_OTP_RELEASE
"%s"
" [erts-" ERLANG_VERSION "]"
-#if !HEAP_ON_C_STACK
- " [no-c-stack-objects]"
-#endif
#ifndef OTP_RELEASE
#ifdef ERLANG_GIT_VERSION
" [source-" ERLANG_GIT_VERSION "]"
@@ -667,18 +664,12 @@ static Eterm pi_1_keys[] = {
#define ERTS_PI_1_NO_OF_KEYS (sizeof(pi_1_keys)/sizeof(Eterm))
static Eterm pi_1_keys_list;
-#if HEAP_ON_C_STACK
static Eterm pi_1_keys_list_heap[2*ERTS_PI_1_NO_OF_KEYS];
-#endif
static void
process_info_init(void)
{
-#if HEAP_ON_C_STACK
Eterm *hp = &pi_1_keys_list_heap[0];
-#else
- Eterm *hp = erts_alloc(ERTS_ALC_T_LL_TEMP_TERM,sizeof(Eterm)*2*ERTS_PI_1_NO_OF_KEYS);
-#endif
int i;
pi_1_keys_list = NIL;
diff --git a/erts/emulator/beam/erl_debug.c b/erts/emulator/beam/erl_debug.c
index 77a1e3d7cb..434b6c6d7a 100644
--- a/erts/emulator/beam/erl_debug.c
+++ b/erts/emulator/beam/erl_debug.c
@@ -628,29 +628,4 @@ void print_memory_info(Process *p)
}
erts_printf("+-----------------%s-%s-%s-%s-+\n",dashes,dashes,dashes,dashes);
}
-#if !HEAP_ON_C_STACK && defined(DEBUG)
-Eterm *erts_debug_allocate_tmp_heap(int size, Process *p)
-{
- ErtsSchedulerData *sd = ((p == NULL) ? erts_get_scheduler_data() : ERTS_PROC_GET_SCHDATA(p));
- int offset = sd->num_tmp_heap_used;
-
- ASSERT(offset+size <= TMP_HEAP_SIZE);
- return (sd->tmp_heap)+offset;
-}
-void erts_debug_use_tmp_heap(int size, Process *p)
-{
- ErtsSchedulerData *sd = ((p == NULL) ? erts_get_scheduler_data() : ERTS_PROC_GET_SCHDATA(p));
-
- sd->num_tmp_heap_used += size;
- ASSERT(sd->num_tmp_heap_used <= TMP_HEAP_SIZE);
-}
-void erts_debug_unuse_tmp_heap(int size, Process *p)
-{
- ErtsSchedulerData *sd = ((p == NULL) ? erts_get_scheduler_data() : ERTS_PROC_GET_SCHDATA(p));
-
- sd->num_tmp_heap_used -= size;
- ASSERT(sd->num_tmp_heap_used >= 0);
-}
#endif
-#endif
-
diff --git a/erts/emulator/beam/erl_debug.h b/erts/emulator/beam/erl_debug.h
index 4905e64f07..f4259e7dae 100644
--- a/erts/emulator/beam/erl_debug.h
+++ b/erts/emulator/beam/erl_debug.h
@@ -92,10 +92,4 @@ extern void print_tagged_memory(Eterm *start, Eterm *end);
extern void print_untagged_memory(Eterm *start, Eterm *end);
extern void print_memory(Process *p);
extern void print_memory_info(Process *p);
-#if defined(DEBUG) && !HEAP_ON_C_STACK
-extern Eterm *erts_debug_allocate_tmp_heap(int, Process *);
-extern void erts_debug_use_tmp_heap(int, Process *);
-extern void erts_debug_unuse_tmp_heap(int, Process *);
-#endif
-
#endif /* _ERL_DEBUG_H_ */
diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c
index 5b13f74dcb..0b4274f920 100644
--- a/erts/emulator/beam/erl_process.c
+++ b/erts/emulator/beam/erl_process.c
@@ -5452,9 +5452,6 @@ init_scheduler_data(ErtsSchedulerData* esdp, int num,
esdp->f_reg_array =
erts_alloc_permanent_cache_aligned(ERTS_ALC_T_BEAM_REGISTER,
MAX_REG * sizeof(FloatDef));
-#if !HEAP_ON_C_STACK
- esdp->num_tmp_heap_used = 0;
-#endif
#ifdef ERTS_DIRTY_SCHEDULERS
if (ERTS_RUNQ_IX_IS_DIRTY(runq->ix)) {
esdp->no = 0;
@@ -11336,6 +11333,22 @@ set_proc_exiting(Process *p,
KILL_CATCHES(p);
p->i = (BeamInstr *) beam_exit;
+#ifndef ERTS_SMP
+ if (state & (ERTS_PSFLG_RUNNING|ERTS_PSFLG_RUNNING_SYS)) {
+ /*
+ * I non smp case:
+ *
+ * Currently executing process might be sent an exit
+ * signal if it is traced by a port that it also is
+ * linked to, and the port terminates during the
+ * trace. In this case we want schedule out the
+ * process as quickly as possible in order to detect
+ * the event as fast as possible.
+ */
+ ERTS_VBUMP_ALL_REDS(p);
+ }
+#endif
+
if (enqueue)
add2runq(enqueue > 0 ? p : make_proxy_proc(NULL, p, enq_prio),
state,
diff --git a/erts/emulator/beam/erl_process.h b/erts/emulator/beam/erl_process.h
index caac89c087..65422b8c15 100644
--- a/erts/emulator/beam/erl_process.h
+++ b/erts/emulator/beam/erl_process.h
@@ -632,12 +632,6 @@ struct ErtsSchedulerData_ {
Process *free_process;
ErtsThrPrgrData thr_progress_data;
#endif
-#if !HEAP_ON_C_STACK
- Eterm tmp_heap[TMP_HEAP_SIZE];
- int num_tmp_heap_used;
- Eterm beam_emu_tmp_heap[BEAM_EMU_TMP_HEAP_SIZE];
- Eterm erl_arith_tmp_heap[ERL_ARITH_TMP_HEAP_SIZE];
-#endif
ErtsSchedulerSleepInfo *ssi;
Process *current_process;
Uint no; /* Scheduler number for normal schedulers */
diff --git a/erts/emulator/beam/erl_term.c b/erts/emulator/beam/erl_term.c
index 89459fb278..3a5fbcc284 100644
--- a/erts/emulator/beam/erl_term.c
+++ b/erts/emulator/beam/erl_term.c
@@ -173,9 +173,7 @@ ET_DEFINE_CHECKED(Uint,external_thing_data_words,ExternalThing*,is_thing_ptr);
ET_DEFINE_CHECKED(Eterm,make_cp,UWord *,_is_taggable_pointer);
ET_DEFINE_CHECKED(UWord *,cp_val,Eterm,is_CP);
ET_DEFINE_CHECKED(Uint,catch_val,Eterm,is_catch);
-ET_DEFINE_CHECKED(Uint,x_reg_offset,Uint,_is_xreg);
-ET_DEFINE_CHECKED(Uint,y_reg_offset,Uint,_is_yreg);
-ET_DEFINE_CHECKED(Uint,x_reg_index,Uint,_is_xreg);
-ET_DEFINE_CHECKED(Uint,y_reg_index,Uint,_is_yreg);
+ET_DEFINE_CHECKED(Uint,loader_x_reg_index,Uint,_is_loader_x_reg);
+ET_DEFINE_CHECKED(Uint,loader_y_reg_index,Uint,_is_loader_y_reg);
#endif /* ET_DEBUG */
diff --git a/erts/emulator/beam/erl_term.h b/erts/emulator/beam/erl_term.h
index 0d8e981da4..089eecf024 100644
--- a/erts/emulator/beam/erl_term.h
+++ b/erts/emulator/beam/erl_term.h
@@ -23,7 +23,6 @@
typedef UWord Wterm; /* Full word terms */
-#define HEAP_ON_C_STACK 1
struct erl_node_; /* Declared in erl_node_tables.h */
/*
@@ -1028,44 +1027,40 @@ _ET_DECLARE_CHECKED(Uint,catch_val,Eterm)
/*
* Overloaded tags.
*
- * SMALL = 15
- * ATOM/NIL=7
+ * In the loader, we want to tag a term in a way so that it can
+ * be any literal (atom/integer/float/tuple/list/binary) or a
+ * register.
*
- * Note that the two least significant bits in SMALL/ATOM/NIL always are 3;
- * thus, we can distinguish register from literals by looking at only these
- * two bits.
+ * We can achive that by overloading the PID and PORT tags to
+ * mean X and Y registers. That works because there are no
+ * pid or port literals.
*/
-#define X_REG_DEF 0
-#define Y_REG_DEF 1
-#define R_REG_DEF 2
+#define _LOADER_TAG_XREG _TAG_IMMED1_PID
+#define _LOADER_TAG_YREG _TAG_IMMED1_PORT
+#define _LOADER_TAG_SIZE _TAG_IMMED1_SIZE
+#define _LOADER_MASK _TAG_IMMED1_MASK
-#define beam_reg_tag(x) ((x) & 3)
+#define LOADER_X_REG _LOADER_TAG_XREG
+#define LOADER_Y_REG _LOADER_TAG_YREG
-#define make_rreg() R_REG_DEF
-#define make_xreg(ix) (((ix) * sizeof(Eterm)) | X_REG_DEF)
-#define make_yreg(ix) (((ix) * sizeof(Eterm)) | Y_REG_DEF)
+#define make_loader_x_reg(R) (((R) << _LOADER_TAG_SIZE) | _LOADER_TAG_XREG)
+#define make_loader_y_reg(R) (((R) << _LOADER_TAG_SIZE) | _LOADER_TAG_YREG)
-#define _is_xreg(x) (beam_reg_tag(x) == X_REG_DEF)
-#define _is_yreg(x) (beam_reg_tag(x) == Y_REG_DEF)
+#define loader_reg_index(R) ((R) >> _LOADER_TAG_SIZE)
-#define _unchecked_x_reg_offset(R) ((R) - X_REG_DEF)
-_ET_DECLARE_CHECKED(Uint,x_reg_offset,Uint)
-#define x_reg_offset(R) _ET_APPLY(x_reg_offset,(R))
+#define loader_tag(T) ((T) & _LOADER_MASK)
-#define _unchecked_y_reg_offset(R) ((R) - Y_REG_DEF)
-_ET_DECLARE_CHECKED(Uint,y_reg_offset,Uint)
-#define y_reg_offset(R) _ET_APPLY(y_reg_offset,(R))
+#define _is_loader_x_reg(x) (loader_tag(x) == _LOADER_TAG_XREG)
+#define _is_loader_y_reg(x) (loader_tag(x) == _LOADER_TAG_YREG)
-#define reg_index(R) ((R) / sizeof(Eterm))
+#define _unchecked_loader_x_reg_index(R) ((R) >> _LOADER_TAG_SIZE)
+_ET_DECLARE_CHECKED(Uint,loader_x_reg_index,Uint)
+#define loader_x_reg_index(R) _ET_APPLY(loader_x_reg_index,(R))
-#define _unchecked_x_reg_index(R) ((R) >> 2)
-_ET_DECLARE_CHECKED(Uint,x_reg_index,Uint)
-#define x_reg_index(R) _ET_APPLY(x_reg_index,(R))
-
-#define _unchecked_y_reg_index(R) ((R) >> 2)
-_ET_DECLARE_CHECKED(Uint,y_reg_index,Uint)
-#define y_reg_index(R) _ET_APPLY(y_reg_index,(R))
+#define _unchecked_loader_y_reg_index(R) ((R) >> _LOADER_TAG_SIZE)
+_ET_DECLARE_CHECKED(Uint,loader_y_reg_index,Uint)
+#define loader_y_reg_index(R) _ET_APPLY(loader_y_reg_index,(R))
/*
* Backwards compatibility definitions:
diff --git a/erts/emulator/beam/erl_time.h b/erts/emulator/beam/erl_time.h
index 36a3d52264..43e543e035 100644
--- a/erts/emulator/beam/erl_time.h
+++ b/erts/emulator/beam/erl_time.h
@@ -345,8 +345,10 @@ erts_time_unit_conversion(Uint64 value,
#endif /* !ERTS_COMPILE_TIME_MONOTONIC_TIME_UNIT */
#define ERTS_MONOTONIC_TIME_END_EXTERNAL \
- (ERTS_MONOTONIC_TIME_START_EXTERNAL \
- + (ERTS_MONOTONIC_END - ERTS_MONOTONIC_BEGIN))
+ (ERTS_MONOTONIC_TIME_START_EXTERNAL < 0 \
+ ? (ERTS_MONOTONIC_TIME_START_EXTERNAL \
+ + (ERTS_MONOTONIC_END - ERTS_MONOTONIC_BEGIN)) \
+ : (ERTS_MONOTONIC_END - ERTS_MONOTONIC_TIME_START_EXTERNAL))
#define ERTS_MSEC_TO_CLKTCKS__(MON) \
((MON) * (ERTS_CLKTCK_RESOLUTION/1000))
diff --git a/erts/emulator/beam/erl_time_sup.c b/erts/emulator/beam/erl_time_sup.c
index 7f8f560681..7327e0b48c 100644
--- a/erts/emulator/beam/erl_time_sup.c
+++ b/erts/emulator/beam/erl_time_sup.c
@@ -124,7 +124,11 @@ typedef struct {
typedef struct {
ErtsMonotonicCorrectionInstance prev;
- ErtsMonotonicCorrectionInstance curr;
+ ErtsMonotonicCorrectionInstance curr;
+} ErtsMonotonicCorrectionInstances;
+
+typedef struct {
+ ErtsMonotonicCorrectionInstances insts;
ErtsMonotonicDriftData drift;
ErtsMonotonicTime last_check;
int short_check_interval;
@@ -272,27 +276,24 @@ static ERTS_INLINE ErtsMonotonicTime
read_corrected_time(int os_drift_corrected)
{
ErtsMonotonicTime os_mtime;
- ErtsMonotonicCorrectionData cdata;
- ErtsMonotonicCorrectionInstance *cip;
+ ErtsMonotonicCorrectionInstance ci;
erts_smp_rwmtx_rlock(&time_sup.inf.c.parmon.rwmtx);
os_mtime = erts_os_monotonic_time();
- cdata = time_sup.inf.c.parmon.cdata;
-
- erts_smp_rwmtx_runlock(&time_sup.inf.c.parmon.rwmtx);
-
- if (os_mtime >= cdata.curr.os_mtime)
- cip = &cdata.curr;
+ if (os_mtime >= time_sup.inf.c.parmon.cdata.insts.curr.os_mtime)
+ ci = time_sup.inf.c.parmon.cdata.insts.curr;
else {
- if (os_mtime < cdata.prev.os_mtime)
+ if (os_mtime < time_sup.inf.c.parmon.cdata.insts.prev.os_mtime)
erl_exit(ERTS_ABORT_EXIT,
"OS monotonic time stepped backwards\n");
- cip = &cdata.prev;
+ ci = time_sup.inf.c.parmon.cdata.insts.prev;
}
- return calc_corrected_erl_mtime(os_mtime, cip, NULL,
+ erts_smp_rwmtx_runlock(&time_sup.inf.c.parmon.rwmtx);
+
+ return calc_corrected_erl_mtime(os_mtime, &ci, NULL,
os_drift_corrected);
}
@@ -360,9 +361,8 @@ check_time_correction(void *vesdp)
{
int init_drift_adj = !vesdp;
ErtsSchedulerData *esdp = (ErtsSchedulerData *) vesdp;
- ErtsMonotonicCorrectionData cdata;
ErtsMonotonicCorrection new_correction;
- ErtsMonotonicCorrectionInstance *cip;
+ ErtsMonotonicCorrectionInstance ci;
ErtsMonotonicTime mdiff, sdiff, os_mtime, erl_mtime, os_stime,
erl_stime, time_offset, timeout_pos;
Uint timeout;
@@ -373,16 +373,15 @@ check_time_correction(void *vesdp)
erts_os_times(&os_mtime, &os_stime);
- cdata = time_sup.inf.c.parmon.cdata;
+ ci = time_sup.inf.c.parmon.cdata.insts.curr;
erts_smp_rwmtx_runlock(&time_sup.inf.c.parmon.rwmtx);
- if (os_mtime < cdata.curr.os_mtime)
+ if (os_mtime < ci.os_mtime)
erl_exit(ERTS_ABORT_EXIT,
"OS monotonic time stepped backwards\n");
- cip = &cdata.curr;
- erl_mtime = calc_corrected_erl_mtime(os_mtime, cip, &mdiff,
+ erl_mtime = calc_corrected_erl_mtime(os_mtime, &ci, &mdiff,
os_drift_corrected);
time_offset = get_time_offset();
erl_stime = erl_mtime + time_offset;
@@ -397,7 +396,7 @@ check_time_correction(void *vesdp)
time_sup.inf.c.shadow_offset = 0;
}
- new_correction = cip->correction;
+ new_correction = ci.correction;
if (time_sup.r.o.warp_mode == ERTS_MULTI_TIME_WARP_MODE
&& (sdiff < -2*time_sup.r.o.adj.small_diff
@@ -408,7 +407,7 @@ check_time_correction(void *vesdp)
set_time_offset(time_offset);
schedule_send_time_offset_changed_notifications(time_offset);
begin_short_intervals = 1;
- if (cdata.curr.correction.error != 0) {
+ if (ci.correction.error != 0) {
set_new_correction = 1;
new_correction.error = 0;
}
@@ -425,12 +424,12 @@ check_time_correction(void *vesdp)
time_sup.inf.c.shadow_offset -= sdiff;
sdiff = 0;
begin_short_intervals = 1;
- if (cdata.curr.correction.error != 0) {
+ if (ci.correction.error != 0) {
set_new_correction = 1;
new_correction.error = 0;
}
}
- else if (cdata.curr.correction.error == 0) {
+ else if (ci.correction.error == 0) {
if (sdiff < -time_sup.r.o.adj.small_diff) {
set_new_correction = 1;
if (sdiff < -time_sup.r.o.adj.large_diff)
@@ -446,9 +445,9 @@ check_time_correction(void *vesdp)
new_correction.error = -ERTS_TCORR_ERR_SMALL_ADJ;
}
}
- else if (cdata.curr.correction.error > 0) {
+ else if (ci.correction.error > 0) {
if (sdiff < 0) {
- if (cdata.curr.correction.error != ERTS_TCORR_ERR_LARGE_ADJ
+ if (ci.correction.error != ERTS_TCORR_ERR_LARGE_ADJ
&& sdiff < -time_sup.r.o.adj.large_diff) {
new_correction.error = ERTS_TCORR_ERR_LARGE_ADJ;
set_new_correction = 1;
@@ -466,9 +465,9 @@ check_time_correction(void *vesdp)
new_correction.error = 0;
}
}
- else /* if (cdata.curr.correction.error < 0) */ {
+ else /* if (ci.correction.error < 0) */ {
if (0 < sdiff) {
- if (cdata.curr.correction.error != -ERTS_TCORR_ERR_LARGE_ADJ
+ if (ci.correction.error != -ERTS_TCORR_ERR_LARGE_ADJ
&& time_sup.r.o.adj.large_diff < sdiff) {
new_correction.error = -ERTS_TCORR_ERR_LARGE_ADJ;
set_new_correction = 1;
@@ -631,8 +630,8 @@ check_time_correction(void *vesdp)
#ifdef ERTS_TIME_CORRECTION_PRINT
print_correction(set_new_correction,
sdiff,
- cip->correction.error,
- cip->correction.drift,
+ ci.correction.error,
+ ci.correction.drift,
new_correction.error,
new_correction.drift,
timeout);
@@ -644,7 +643,7 @@ check_time_correction(void *vesdp)
os_mtime = erts_os_monotonic_time();
/* Save previous correction instance */
- time_sup.inf.c.parmon.cdata.prev = *cip;
+ time_sup.inf.c.parmon.cdata.insts.prev = ci;
/*
* Current correction instance begin when
@@ -657,15 +656,15 @@ check_time_correction(void *vesdp)
* next OS monotonic time using previous
* correction.
*/
- erl_mtime = calc_corrected_erl_mtime(os_mtime, cip, NULL,
+ erl_mtime = calc_corrected_erl_mtime(os_mtime, &ci, NULL,
os_drift_corrected);
/*
* Save new current correction instance.
*/
- time_sup.inf.c.parmon.cdata.curr.erl_mtime = erl_mtime;
- time_sup.inf.c.parmon.cdata.curr.os_mtime = os_mtime;
- time_sup.inf.c.parmon.cdata.curr.correction = new_correction;
+ time_sup.inf.c.parmon.cdata.insts.curr.erl_mtime = erl_mtime;
+ time_sup.inf.c.parmon.cdata.insts.curr.os_mtime = os_mtime;
+ time_sup.inf.c.parmon.cdata.insts.curr.correction = new_correction;
erts_smp_rwmtx_rwunlock(&time_sup.inf.c.parmon.rwmtx);
}
@@ -784,24 +783,22 @@ static ErtsMonotonicTime
finalize_corrected_time_offset(ErtsSystemTime *stimep)
{
ErtsMonotonicTime os_mtime;
- ErtsMonotonicCorrectionData cdata;
- ErtsMonotonicCorrectionInstance *cip;
+ ErtsMonotonicCorrectionInstance ci;
int os_drift_corrected = time_sup.r.o.os_corrected_monotonic_time;
erts_smp_rwmtx_rlock(&time_sup.inf.c.parmon.rwmtx);
erts_os_times(&os_mtime, stimep);
- cdata = time_sup.inf.c.parmon.cdata;
+ ci = time_sup.inf.c.parmon.cdata.insts.curr;
erts_smp_rwmtx_runlock(&time_sup.inf.c.parmon.rwmtx);
- if (os_mtime < cdata.curr.os_mtime)
+ if (os_mtime < ci.os_mtime)
erl_exit(ERTS_ABORT_EXIT,
"OS monotonic time stepped backwards\n");
- cip = &cdata.curr;
- return calc_corrected_erl_mtime(os_mtime, cip, NULL,
+ return calc_corrected_erl_mtime(os_mtime, &ci, NULL,
os_drift_corrected);
}
@@ -1128,13 +1125,13 @@ erts_init_time_sup(int time_correction, ErtsTimeWarpMode time_warp_mode)
cdatap->drift.intervals[0].time.sys = time_sup.inf.c.sinit;
cdatap->drift.intervals[0].time.mon = time_sup.inf.c.minit;
- cdatap->curr.correction.drift = 0;
- cdatap->curr.correction.error = 0;
- cdatap->curr.erl_mtime = ERTS_MONOTONIC_BEGIN;
- cdatap->curr.os_mtime = time_sup.inf.c.minit;
+ cdatap->insts.curr.correction.drift = 0;
+ cdatap->insts.curr.correction.error = 0;
+ cdatap->insts.curr.erl_mtime = ERTS_MONOTONIC_BEGIN;
+ cdatap->insts.curr.os_mtime = time_sup.inf.c.minit;
cdatap->last_check = time_sup.inf.c.minit;
cdatap->short_check_interval = ERTS_INIT_SHORT_INTERVAL_COUNTER;
- cdatap->prev = cdatap->curr;
+ cdatap->insts.prev = cdatap->insts.curr;
if (!time_sup.r.o.os_corrected_monotonic_time)
time_sup.r.o.get_time = get_corrected_time;
diff --git a/erts/emulator/beam/erl_trace.c b/erts/emulator/beam/erl_trace.c
index 3a74d752fe..e9dd96efc4 100644
--- a/erts/emulator/beam/erl_trace.c
+++ b/erts/emulator/beam/erl_trace.c
@@ -1677,12 +1677,7 @@ erts_call_trace(Process* p, BeamInstr mfa[3], Binary *match_spec,
args = transformed_args;
if (is_internal_port(*tracer_pid)) {
-#if HEAP_ON_C_STACK
Eterm local_heap[64+MAX_ARG];
-#else
- Eterm *local_heap = erts_alloc(ERTS_ALC_T_TEMP_TERM,
- sizeof(Eterm)*(64+MAX_ARG));
-#endif
hp = local_heap;
if (!erts_is_valid_tracer_port(*tracer_pid)) {
@@ -1697,9 +1692,6 @@ erts_call_trace(Process* p, BeamInstr mfa[3], Binary *match_spec,
if (is_not_nil(tracee))
erts_smp_proc_unlock(p, ERTS_PROC_LOCKS_ALL_MINOR);
#endif
-#if !HEAP_ON_C_STACK
- erts_free(ERTS_ALC_T_TEMP_TERM,local_heap);
-#endif
UnUseTmpHeap(ERL_SUB_BIN_SIZE,p);
return 0;
}
@@ -1727,9 +1719,6 @@ erts_call_trace(Process* p, BeamInstr mfa[3], Binary *match_spec,
ERTS_PAM_TMP_RESULT, &return_flags);
if (is_non_value(pam_result)) {
erts_match_set_release_result(p);
-#if !HEAP_ON_C_STACK
- erts_free(ERTS_ALC_T_TEMP_TERM,local_heap);
-#endif
UnUseTmpHeap(ERL_SUB_BIN_SIZE,p);
return 0;
}
@@ -1738,9 +1727,6 @@ erts_call_trace(Process* p, BeamInstr mfa[3], Binary *match_spec,
/* Meta trace */
if (pam_result == am_false) {
erts_match_set_release_result(p);
-#if !HEAP_ON_C_STACK
- erts_free(ERTS_ALC_T_TEMP_TERM,local_heap);
-#endif
UnUseTmpHeap(ERL_SUB_BIN_SIZE,p);
return return_flags;
}
@@ -1748,17 +1734,11 @@ erts_call_trace(Process* p, BeamInstr mfa[3], Binary *match_spec,
/* Non-meta trace */
if (*tracee_flags & F_TRACE_SILENT) {
erts_match_set_release_result(p);
-#if !HEAP_ON_C_STACK
- erts_free(ERTS_ALC_T_TEMP_TERM,local_heap);
-#endif
UnUseTmpHeap(ERL_SUB_BIN_SIZE,p);
return 0;
}
if (pam_result == am_false) {
erts_match_set_release_result(p);
-#if !HEAP_ON_C_STACK
- erts_free(ERTS_ALC_T_TEMP_TERM,local_heap);
-#endif
UnUseTmpHeap(ERL_SUB_BIN_SIZE,p);
return return_flags;
}
@@ -1802,9 +1782,6 @@ erts_call_trace(Process* p, BeamInstr mfa[3], Binary *match_spec,
send_to_port(p, mess, tracer_pid, tracee_flags);
erts_smp_mtx_unlock(&smq_mtx);
erts_match_set_release_result(p);
-#if !HEAP_ON_C_STACK
- erts_free(ERTS_ALC_T_TEMP_TERM,local_heap);
-#endif
UnUseTmpHeap(ERL_SUB_BIN_SIZE,p);
return *tracer_pid == NIL ? 0 : return_flags;
@@ -1823,7 +1800,6 @@ erts_call_trace(Process* p, BeamInstr mfa[3], Binary *match_spec,
#ifdef DEBUG
Eterm* limit;
#endif
-
ASSERT(is_internal_pid(*tracer_pid));
tracer = erts_pid2proc(p, ERTS_PROC_LOCK_MAIN,
diff --git a/erts/emulator/beam/erl_vm.h b/erts/emulator/beam/erl_vm.h
index 2d4141ac8d..98f27a1725 100644
--- a/erts/emulator/beam/erl_vm.h
+++ b/erts/emulator/beam/erl_vm.h
@@ -40,14 +40,6 @@
#define MAX_ARG 255 /* Max number of arguments allowed */
#define MAX_REG 1024 /* Max number of x(N) registers used */
-/* Scheduler stores data for temporary heaps if
- !HEAP_ON_C_STACK. Macros (*TmpHeap*) in global.h selects if we put temporary
- heap data on the C stack or if we use the buffers in the scheduler data. */
-#define TMP_HEAP_SIZE 128 /* Number of Eterm in the schedulers
- small heap for transient heap data */
-#define ERL_ARITH_TMP_HEAP_SIZE 4 /* as does erl_arith... */
-#define BEAM_EMU_TMP_HEAP_SIZE 2 /* and beam_emu... */
-
/*
* The new arithmetic operations need some extra X registers in the register array.
* so does the gc_bif's (i_gc_bif3 need 3 extra).
@@ -149,6 +141,7 @@
typedef struct op_entry {
char* name; /* Name of instruction. */
Uint32 mask[3]; /* Signature mask. */
+ unsigned involves_r; /* Needs special attention when matching. */
int sz; /* Number of loaded words. */
char* pack; /* Instructions for packing engine. */
char* sign; /* Signature string. */
diff --git a/erts/emulator/beam/global.h b/erts/emulator/beam/global.h
index 870afb414f..b4d02dd1dd 100644
--- a/erts/emulator/beam/global.h
+++ b/erts/emulator/beam/global.h
@@ -1444,69 +1444,16 @@ erts_alloc_message_heap(Uint size,
#endif /* #if ERTS_GLB_INLINE_INCL_FUNC_DEF */
-#if !HEAP_ON_C_STACK
-# if defined(DEBUG)
-# define DeclareTmpHeap(VariableName,Size,Process) \
- Eterm *VariableName = erts_debug_allocate_tmp_heap(Size,Process)
-# define DeclareTypedTmpHeap(Type,VariableName,Process) \
- Type *VariableName = (Type *) erts_debug_allocate_tmp_heap(sizeof(Type)/sizeof(Eterm),Process)
-# define DeclareTmpHeapNoproc(VariableName,Size) \
- Eterm *VariableName = erts_debug_allocate_tmp_heap(Size,NULL)
-# define UseTmpHeap(Size,Proc) \
- do { \
- erts_debug_use_tmp_heap((Size),(Proc)); \
- } while (0)
-# define UnUseTmpHeap(Size,Proc) \
- do { \
- erts_debug_unuse_tmp_heap((Size),(Proc)); \
- } while (0)
-# define UseTmpHeapNoproc(Size) \
- do { \
- erts_debug_use_tmp_heap(Size,NULL); \
- } while (0)
-# define UnUseTmpHeapNoproc(Size) \
- do { \
- erts_debug_unuse_tmp_heap(Size,NULL); \
- } while (0)
-# else
-# define DeclareTmpHeap(VariableName,Size,Process) \
- Eterm *VariableName = (ERTS_PROC_GET_SCHDATA(Process)->tmp_heap)+(ERTS_PROC_GET_SCHDATA(Process)->num_tmp_heap_used)
-# define DeclareTypedTmpHeap(Type,VariableName,Process) \
- Type *VariableName = (Type *) (ERTS_PROC_GET_SCHDATA(Process)->tmp_heap)+(ERTS_PROC_GET_SCHDATA(Process)->num_tmp_heap_used)
-# define DeclareTmpHeapNoproc(VariableName,Size) \
- Eterm *VariableName = (erts_get_scheduler_data()->tmp_heap)+(erts_get_scheduler_data()->num_tmp_heap_used)
-# define UseTmpHeap(Size,Proc) \
- do { \
- ERTS_PROC_GET_SCHDATA(Proc)->num_tmp_heap_used += (Size); \
- } while (0)
-# define UnUseTmpHeap(Size,Proc) \
- do { \
- ERTS_PROC_GET_SCHDATA(Proc)->num_tmp_heap_used -= (Size); \
- } while (0)
-# define UseTmpHeapNoproc(Size) \
- do { \
- erts_get_scheduler_data()->num_tmp_heap_used += (Size); \
- } while (0)
-# define UnUseTmpHeapNoproc(Size) \
- do { \
- erts_get_scheduler_data()->num_tmp_heap_used -= (Size); \
- } while (0)
-
-
-# endif
-
-#else
-# define DeclareTmpHeap(VariableName,Size,Process) \
+#define DeclareTmpHeap(VariableName,Size,Process) \
Eterm VariableName[Size]
-# define DeclareTypedTmpHeap(Type,VariableName,Process) \
+#define DeclareTypedTmpHeap(Type,VariableName,Process) \
Type VariableName[1]
-# define DeclareTmpHeapNoproc(VariableName,Size) \
+#define DeclareTmpHeapNoproc(VariableName,Size) \
Eterm VariableName[Size]
-# define UseTmpHeap(Size,Proc) /* Nothing */
-# define UnUseTmpHeap(Size,Proc) /* Nothing */
-# define UseTmpHeapNoproc(Size) /* Nothing */
-# define UnUseTmpHeapNoproc(Size) /* Nothing */
-#endif /* HEAP_ON_C_STACK */
+#define UseTmpHeap(Size,Proc) /* Nothing */
+#define UnUseTmpHeap(Size,Proc) /* Nothing */
+#define UseTmpHeapNoproc(Size) /* Nothing */
+#define UnUseTmpHeapNoproc(Size) /* Nothing */
ERTS_GLB_INLINE void dtrace_pid_str(Eterm pid, char *process_buf);
ERTS_GLB_INLINE void dtrace_proc_str(Process *process, char *process_buf);
diff --git a/erts/emulator/beam/io.c b/erts/emulator/beam/io.c
index d754fc634e..fdd26fcc4b 100644
--- a/erts/emulator/beam/io.c
+++ b/erts/emulator/beam/io.c
@@ -6787,7 +6787,7 @@ int driver_monitor_process(ErlDrvPort drvport,
{
Port *prt;
int ret;
-#if !HEAP_ON_C_STACK || (defined(ERTS_SMP) && defined(ERTS_ENABLE_LOCK_CHECK))
+#if defined(ERTS_SMP) && defined(ERTS_ENABLE_LOCK_CHECK)
ErtsSchedulerData *sched = erts_get_scheduler_data();
#endif
@@ -6798,16 +6798,6 @@ int driver_monitor_process(ErlDrvPort drvport,
/* Now (in SMP) we should have either the port lock (if we have a scheduler) or the port data lock
(if we're a driver thread) */
ERTS_SMP_LC_ASSERT((sched != NULL || prt->port_data_lock));
-
-#if !HEAP_ON_C_STACK
- if (!sched) {
- /* Need a separate allocation for the ref :( */
- Eterm *buf = erts_alloc(ERTS_ALC_T_TEMP_TERM,
- sizeof(Eterm)*REF_THING_SIZE);
- ret = do_driver_monitor_process(prt,buf,process,monitor);
- erts_free(ERTS_ALC_T_TEMP_TERM,buf);
- } else
-#endif
{
DeclareTmpHeapNoproc(buf,REF_THING_SIZE);
UseTmpHeapNoproc(REF_THING_SIZE);
@@ -6860,7 +6850,7 @@ int driver_demonitor_process(ErlDrvPort drvport,
{
Port *prt;
int ret;
-#if !HEAP_ON_C_STACK || (defined(ERTS_SMP) && defined(ERTS_ENABLE_LOCK_CHECK))
+#if defined(ERTS_SMP) && defined(ERTS_ENABLE_LOCK_CHECK)
ErtsSchedulerData *sched = erts_get_scheduler_data();
#endif
@@ -6871,15 +6861,6 @@ int driver_demonitor_process(ErlDrvPort drvport,
/* Now we should have either the port lock (if we have a scheduler) or the port data lock
(if we're a driver thread) */
ERTS_SMP_LC_ASSERT((sched != NULL || prt->port_data_lock));
-#if !HEAP_ON_C_STACK
- if (!sched) {
- /* Need a separate allocation for the ref :( */
- Eterm *buf = erts_alloc(ERTS_ALC_T_TEMP_TERM,
- sizeof(Eterm)*REF_THING_SIZE);
- ret = do_driver_demonitor_process(prt,buf,monitor);
- erts_free(ERTS_ALC_T_TEMP_TERM,buf);
- } else
-#endif
{
DeclareTmpHeapNoproc(buf,REF_THING_SIZE);
UseTmpHeapNoproc(REF_THING_SIZE);
@@ -6915,7 +6896,7 @@ ErlDrvTermData driver_get_monitored_process(ErlDrvPort drvport,
{
Port *prt;
ErlDrvTermData ret;
-#if !HEAP_ON_C_STACK || (defined(ERTS_SMP) && defined(ERTS_ENABLE_LOCK_CHECK))
+#if defined(ERTS_SMP) && defined(ERTS_ENABLE_LOCK_CHECK)
ErtsSchedulerData *sched = erts_get_scheduler_data();
#endif
@@ -6926,16 +6907,6 @@ ErlDrvTermData driver_get_monitored_process(ErlDrvPort drvport,
/* Now we should have either the port lock (if we have a scheduler) or the port data lock
(if we're a driver thread) */
ERTS_SMP_LC_ASSERT((sched != NULL || prt->port_data_lock));
-
-#if !HEAP_ON_C_STACK
- if (!sched) {
- /* Need a separate allocation for the ref :( */
- Eterm *buf = erts_alloc(ERTS_ALC_T_TEMP_TERM,
- sizeof(Eterm)*REF_THING_SIZE);
- ret = do_driver_get_monitored_process(prt,buf,monitor);
- erts_free(ERTS_ALC_T_TEMP_TERM,buf);
- } else
-#endif
{
DeclareTmpHeapNoproc(buf,REF_THING_SIZE);
UseTmpHeapNoproc(REF_THING_SIZE);
diff --git a/erts/emulator/beam/ops.tab b/erts/emulator/beam/ops.tab
index 1d32e72247..46fefb88af 100644
--- a/erts/emulator/beam/ops.tab
+++ b/erts/emulator/beam/ops.tab
@@ -39,8 +39,8 @@ too_old_compiler | never() =>
# necessary.) Since the instructions don't work correctly in R12B, simply
# refuse to load the module.
-func_info M=a a==am_module_info A=u==0 | label L | move n r => too_old_compiler
-func_info M=a a==am_module_info A=u==1 | label L | move n r => too_old_compiler
+func_info M=a a==am_module_info A=u==0 | label L | move n x==0 => too_old_compiler
+func_info M=a a==am_module_info A=u==1 | label L | move n x==0 => too_old_compiler
# The undocumented and unsupported guard BIF is_constant/1 was removed
# in R13. The is_constant/2 operation is marked as obsolete in genop.tab,
@@ -76,17 +76,6 @@ return
# with the following call instruction, we need to make sure that
# there is no line/1 instruction between the move and the call.
#
-
-move S r | line Loc | call_ext Ar Func => \
- line Loc | move S r | call_ext Ar Func
-move S r | line Loc | call_ext_last Ar Func=u$is_bif D => \
- line Loc | move S r | call_ext_last Ar Func D
-move S r | line Loc | call_ext_only Ar Func=u$is_bif => \
- line Loc | move S r | call_ext_only Ar Func
-move S r | line Loc | call Ar Func => \
- line Loc | move S r | call Ar Func
-
-#
# A tail-recursive call to an external function (non-BIF) will
# never be saved on the stack, so there is no reason to keep
# the line instruction. (The compiler did not remove the line
@@ -94,10 +83,14 @@ move S r | line Loc | call Ar Func => \
# BIFs and ordinary Erlang functions.)
#
-line Loc | call_ext_last Ar Func=u$is_not_bif D => \
- call_ext_last Ar Func D
-line Loc | call_ext_only Ar Func=u$is_not_bif => \
- call_ext_only Ar Func
+move S X0=x==0 | line Loc | call_ext Ar Func => \
+ line Loc | move S X0 | call_ext Ar Func
+move S X0=x==0 | line Loc | call_ext_last Ar Func=u$is_not_bif D => \
+ move S X0 | call_ext_last Ar Func D
+move S X0=x==0 | line Loc | call_ext_only Ar Func=u$is_not_bif => \
+ move S X0 | call_ext_only Ar Func
+move S X0=x==0 | line Loc | call Ar Func => \
+ line Loc | move S X0 | call Ar Func
line Loc | func_info M F A => func_info M F A | line Loc
@@ -167,31 +160,24 @@ is_tuple Fail=f S | select_tuple_arity S=d Fail=f Size=u Rest=* => \
select_tuple_arity S=d Fail=f Size=u Rest=* => \
gen_select_tuple_arity(S, Fail, Size, Rest)
-i_select_val_bins r f I
i_select_val_bins x f I
i_select_val_bins y f I
-i_select_val_lins r f I
i_select_val_lins x f I
i_select_val_lins y f I
-i_select_val2 r f c c f f
i_select_val2 x f c c f f
i_select_val2 y f c c f f
-i_select_tuple_arity r f I
i_select_tuple_arity x f I
i_select_tuple_arity y f I
-i_select_tuple_arity2 r f A A f f
i_select_tuple_arity2 x f A A f f
i_select_tuple_arity2 y f A A f f
-i_jump_on_val_zero r f I
i_jump_on_val_zero x f I
i_jump_on_val_zero y f I
-i_jump_on_val r f I I
i_jump_on_val x f I I
i_jump_on_val y f I I
@@ -203,30 +189,21 @@ is_ne_exact L1 S1 S2 | jump Fail | label L2 | same_label(L1, L2) => \
%macro: get_list GetList -pack
get_list x x x
get_list x x y
-get_list x x r
get_list x y x
get_list x y y
-get_list x y r
-get_list x r x
-get_list x r y
get_list y x x
get_list y x y
-get_list y x r
get_list y y x
get_list y y y
-get_list y y r
-get_list y r x
-get_list y r y
+# The following get_list instructions using x(0) are frequently used.
get_list r x x
+get_list r r y
+get_list x r x
get_list r x y
-get_list r x r
-get_list r y x
-get_list r y y
get_list r y r
-get_list r r x
-get_list r r y
+get_list r x r
# Old-style catch.
catch y f
@@ -237,33 +214,31 @@ try Y F => catch Y F
try_case Y => try_end Y
try_end y
-try_case_end Literal=q => move Literal x | try_case_end x
try_case_end s
# Destructive set tuple element
-set_tuple_element Lit=q Tuple Pos => move Lit x | set_tuple_element x Tuple Pos
set_tuple_element s d P
# Get tuple element
%macro: i_get_tuple_element GetTupleElement -pack
i_get_tuple_element x P x
-i_get_tuple_element r P x
i_get_tuple_element y P x
-i_get_tuple_element x P r
-i_get_tuple_element y P r
%cold
-i_get_tuple_element r P r
i_get_tuple_element x P y
-i_get_tuple_element r P y
i_get_tuple_element y P y
%hot
+%macro: i_get_tuple_element2 GetTupleElement2 -pack
+i_get_tuple_element2 x P x
+
+%macro: i_get_tuple_element3 GetTupleElement3 -pack
+i_get_tuple_element3 x P x
+
%macro: is_number IsNumber -fail_action
%cold
-is_number f r
is_number f x
is_number f y
%hot
@@ -273,16 +248,12 @@ is_number Fail Literal=q => move Literal x | is_number Fail x
jump f
-case_end Literal=cq => move Literal x | case_end x
-badmatch Literal=cq => move Literal x | badmatch x
+case_end NotInX=cy => move NotInX x | case_end x
+badmatch NotInX=cy => move NotInX x | badmatch x
-case_end r
case_end x
-case_end y
-badmatch r
badmatch x
-badmatch y
if_end
raise s s
@@ -291,7 +262,7 @@ raise s s
badarg j
system_limit j
-move C=cxy r | jump Lbl => move_jump Lbl C
+move C=cxy x==0 | jump Lbl => move_jump Lbl C
%macro: move_jump MoveJump -nonext
move_jump f n
@@ -309,8 +280,6 @@ move_window/6
# x -> y
-move S1=r S2=y | move X1=x Y1=y => move2 S1 S2 X1 Y1
-
move X1=x Y1=y | move X2=x Y2=y | move X3=x Y3=y | succ(Y1,Y2) | succ(Y2,Y3) => \
move_window X1 X2 X3 Y1 Y3
@@ -323,24 +292,76 @@ move_window X1=x X2=x X3=x X4=x Y1=y Y4=y | move X5=x Y5=y | succ(Y4,Y5) => \
move_window X1=x X2=x X3=x Y1=y Y3=y => move_window3 X1 X2 X3 Y1
move_window X1=x X2=x X3=x X4=x Y1=y Y4=y => move_window4 X1 X2 X3 X4 Y1
+%macro: move_window3 MoveWindow3 -pack
+%macro: move_window4 MoveWindow4 -pack
+%macro: move_window5 MoveWindow5 -pack
+
move_window3 x x x y
move_window4 x x x x y
move_window5 x x x x x y
-move X1=x Y1=y | move X2=x Y2=y => move2 X1 Y1 X2 Y2
-move Y1=y X1=x | move Y2=y X2=x => move2 Y1 X1 Y2 X2
-move X1=x X2=x | move X3=x X4=x => move2 X1 X2 X3 X4
+# Swap registers.
+move R1=x Tmp=x | move R2=xy R1 | move Tmp R2 => swap_temp R1 R2 Tmp
+
+swap_temp R1 R2 Tmp | line Loc | apply Live | is_killed(Tmp, Live) => \
+ swap R1 R2 | line Loc | apply Live
+
+swap_temp R1 R2 Tmp | line Loc | call Live Addr | is_killed(Tmp, Live) => \
+ swap R1 R2 | line Loc | call Live Addr
+swap_temp R1 R2 Tmp | call_only Live Addr | \
+ is_killed(Tmp, Live) => swap R1 R2 | call_only Live Addr
+swap_temp R1 R2 Tmp | call_last Live Addr D | \
+ is_killed(Tmp, Live) => swap R1 R2 | call_last Live Addr D
-move S1=x S2=r | move S3=x S4=x => move2 S1 S2 S3 S4
-move S1=x S2=r | move X1=x Y1=y => move2 S1 S2 X1 Y1
-move S1=y S2=r | move X1=x Y1=y => move2 S1 S2 X1 Y1
+swap_temp R1 R2 Tmp | line Loc | call_ext Live Addr | is_killed(Tmp, Live) => \
+ swap R1 R2 | line Loc | call_ext Live Addr
+swap_temp R1 R2 Tmp | line Loc | call_ext_only Live Addr | \
+ is_killed(Tmp, Live) => swap R1 R2 | line Loc | call_ext_only Live Addr
+swap_temp R1 R2 Tmp | line Loc | call_ext_last Live Addr D | \
+ is_killed(Tmp, Live) => swap R1 R2 | line Loc | call_ext_last Live Addr D
-move Y1=y X1=x | move S1=r D1=x => move2 Y1 X1 S1 D1
-move S1=r D1=x | move Y1=y X1=x => move2 S1 D1 Y1 X1
+%macro: swap_temp SwapTemp -pack
+swap_temp x x x
+swap_temp x y x
-move2 X1=x Y1=y X2=x Y2=y | move X3=x Y3=y => move3 X1 Y1 X2 Y2 X3 Y3
-move2 Y1=y X1=x Y2=y X2=x | move Y3=y X3=x => move3 Y1 X1 Y2 X2 Y3 X3
-move2 X1=x X2=x X3=x X4=x | move X5=x X6=x => move3 X1 X2 X3 X4 X5 X6
+%macro: swap Swap -pack
+swap x x
+swap x y
+
+move Src=x D1=x | move Src=x D2=x => move_dup Src D1 D2
+move Src=x SD=x | move SD=x D=x => move_dup Src SD D
+move Src=x D1=x | move Src=x D2=y => move_dup Src D1 D2
+move Src=y SD=x | move SD=x D=y => move_dup Src SD D
+move Src=x SD=x | move SD=x D=y => move_dup Src SD D
+move Src=y SD=x | move SD=x D=x => move_dup Src SD D
+
+move SD=x D=x | move Src=xy SD=x => move_shift Src SD D
+move SD=y D=x | move Src=x SD=y => move_shift Src SD D
+move SD=x D=y | move Src=x SD=x => move_shift Src SD D
+
+# The transformations above guarantee that the source for
+# the second move is not the same as the destination for
+# the first move. That means that we can do the moves in
+# parallel (fetch both values, then store them) which could
+# be faster.
+
+move X1=x Y1=y | move X2=x Y2=y => move2_par X1 Y1 X2 Y2
+move Y1=y X1=x | move Y2=y X2=x => move2_par Y1 X1 Y2 X2
+
+move X1=x X2=x | move X3=x X4=x => move2_par X1 X2 X3 X4
+
+move X1=x X2=x | move X3=x Y1=y => move2_par X1 X2 X3 Y1
+
+move S1=x S2=x | move X1=x Y1=y => move2_par S1 S2 X1 Y1
+
+move S1=y S2=x | move X1=x Y1=y => move2_par S1 S2 X1 Y1
+
+move Y1=y X1=x | move S1=x D1=x => move2_par Y1 X1 S1 D1
+move S1=x D1=x | move Y1=y X1=x => move2_par S1 D1 Y1 X1
+
+move2_par X1=x Y1=y X2=x Y2=y | move X3=x Y3=y => move3 X1 Y1 X2 Y2 X3 Y3
+move2_par Y1=y X1=x Y2=y X2=x | move Y3=y X3=x => move3 Y1 X1 Y2 X2 Y3 X3
+move2_par X1=x X2=x X3=x X4=x | move X5=x X6=x => move3 X1 X2 X3 X4 X5 X6
move C=aiq X=x==1 => move_x1 C
move C=aiq X=x==2 => move_x2 C
@@ -348,21 +369,32 @@ move C=aiq X=x==2 => move_x2 C
move_x1 c
move_x2 c
-%macro: move2 Move2 -pack
-move2 x y x y
-move2 y x y x
-move2 x x x x
+%macro: move_shift MoveShift -pack
+move_shift x x x
+move_shift y x x
+move_shift x y x
+move_shift x x y
+
+%macro: move_dup MoveDup -pack
+move_dup x x x
+move_dup x x y
+move_dup y x x
+move_dup y x y
-move2 x r x x
+%macro: move2_par Move2Par -pack
-move2 x r x y
-move2 r y x y
-move2 y r x y
+move2_par x y x y
+move2_par y x y x
+move2_par x x x x
-move2 r x y x
-move2 y x r x
+move2_par x x x y
-%macro: move3 Move3
+move2_par y x x y
+
+move2_par x x y x
+move2_par y x x x
+
+%macro: move3 Move3 -pack
move3 x y x y x y
move3 y x y x y x
move3 x x x x x x
@@ -375,20 +407,22 @@ move S=c D=y => move S x | move x D
%macro:move Move -pack -gen_dest
move x x
move x y
-move x r
move y x
-move y r
-move r x
-move r y
-move c r
move c x
move n x
-move n r
move y y
+# The following move instructions using x(0) are frequently used.
+
+move x r
+move r x
+move y r
+move c r
+move r y
+
# Receive operations.
-loop_rec Fail Src | smp_mark_target_label(Fail) => i_loop_rec Fail Src
+loop_rec Fail x==0 | smp_mark_target_label(Fail) => i_loop_rec Fail
label L | wait_timeout Fail Src | smp_already_locked(L) => label L | i_wait_timeout_locked Fail Src
wait_timeout Fail Src => i_wait_timeout Fail Src
@@ -403,7 +437,7 @@ label L | timeout | smp_already_locked(L) => label L | timeout_locked
remove_message
timeout
timeout_locked
-i_loop_rec f r
+i_loop_rec f
loop_rec_end f
wait f
wait_locked f
@@ -421,93 +455,57 @@ send
# Optimized comparisons with one immediate/literal operand.
#
-is_eq_exact Lbl R=rxy C=ian => i_is_eq_exact_immed Lbl R C
-is_eq_exact Lbl R=rxy C=q => i_is_eq_exact_literal R Lbl C
+is_eq_exact Lbl R=xy C=ian => i_is_eq_exact_immed Lbl R C
+is_eq_exact Lbl R=xy C=q => i_is_eq_exact_literal Lbl R C
-is_ne_exact Lbl R=rxy C=ian => i_is_ne_exact_immed Lbl R C
-is_ne_exact Lbl R=rxy C=q => i_is_ne_exact_literal R Lbl C
+is_ne_exact Lbl R=xy C=ian => i_is_ne_exact_immed Lbl R C
+is_ne_exact Lbl R=xy C=q => i_is_ne_exact_literal Lbl R C
%macro: i_is_eq_exact_immed EqualImmed -fail_action
i_is_eq_exact_immed f r c
i_is_eq_exact_immed f x c
i_is_eq_exact_immed f y c
-i_is_eq_exact_literal r f c
-i_is_eq_exact_literal x f c
-i_is_eq_exact_literal y f c
+i_is_eq_exact_literal f x c
+i_is_eq_exact_literal f y c
%macro: i_is_ne_exact_immed NotEqualImmed -fail_action
-i_is_ne_exact_immed f r c
i_is_ne_exact_immed f x c
i_is_ne_exact_immed f y c
-i_is_ne_exact_literal r f c
-i_is_ne_exact_literal x f c
-i_is_ne_exact_literal y f c
-
-#
-# Common Compare Specializations
-# We don't do all of them since we want
-# to keep the instruction set small-ish
-#
-
-is_eq_exact Lbl S1=xy S2=r => is_eq_exact Lbl S2 S1
-is_eq_exact Lbl S1=rx S2=xy => i_is_eq_exact_spec Lbl S1 S2
-%macro: i_is_eq_exact_spec EqualExact -fail_action
-
-i_is_eq_exact_spec f x x
-i_is_eq_exact_spec f x y
-i_is_eq_exact_spec f r x
-i_is_eq_exact_spec f r y
-%cold
-i_is_eq_exact_spec f r r
-%hot
+i_is_ne_exact_literal f x c
+i_is_ne_exact_literal f y c
-is_lt Lbl S1=rxc S2=rxc => i_is_lt_spec Lbl S1 S2
+is_eq_exact Lbl Y=y X=x => is_eq_exact Lbl X Y
+%macro: is_eq_exact EqualExact -fail_action -pack
+is_eq_exact f x x
+is_eq_exact f x y
+is_eq_exact f s s
-%macro: i_is_lt_spec IsLessThan -fail_action
-
-i_is_lt_spec f x x
-i_is_lt_spec f x r
-i_is_lt_spec f x c
-i_is_lt_spec f r x
-i_is_lt_spec f r c
-i_is_lt_spec f c x
-i_is_lt_spec f c r
+%macro: is_lt IsLessThan -fail_action
+is_lt f x x
+is_lt f x c
+is_lt f c x
%cold
-i_is_lt_spec f r r
-i_is_lt_spec f c c
+is_lt f s s
%hot
-is_ge Lbl S1=xc S2=xc => i_is_ge_spec Lbl S1 S2
-
-%macro: i_is_ge_spec IsGreaterEqual -fail_action
-
-i_is_ge_spec f x x
-i_is_ge_spec f x c
-i_is_ge_spec f c x
+%macro: is_ge IsGreaterEqual -fail_action
+is_ge f x x
+is_ge f x c
+is_ge f c x
%cold
-i_is_ge_spec f c c
+is_ge f s s
%hot
-#
-# All other comparisons.
-#
+%macro: is_ne_exact NotEqualExact -fail_action
+is_ne_exact f s s
-is_eq_exact Lbl S1 S2 => i_fetch S1 S2 | i_is_eq_exact Lbl
-is_ne_exact Lbl S1 S2 => i_fetch S1 S2 | i_is_ne_exact Lbl
+%macro: is_eq Equal -fail_action
+is_eq f s s
-is_lt Lbl S1 S2 => i_fetch S1 S2 | i_is_lt Lbl
-is_ge Lbl S1 S2 => i_fetch S1 S2 | i_is_ge Lbl
-is_eq Lbl S1 S2 => i_fetch S1 S2 | i_is_eq Lbl
-is_ne Lbl S1 S2 => i_fetch S1 S2 | i_is_ne Lbl
-
-i_is_eq_exact f
-i_is_ne_exact f
-i_is_lt f
-i_is_ge f
-i_is_eq f
-i_is_ne f
+%macro: is_ne NotEqual -fail_action
+is_ne f s s
#
# Putting things.
@@ -525,7 +523,6 @@ i_put_tuple Dst Arity Puts=* | put S => \
i_put_tuple/2
%macro:i_put_tuple PutTuple -pack -goto:do_put_tuple
-i_put_tuple r I
i_put_tuple x I
i_put_tuple y I
@@ -542,74 +539,36 @@ put_list x n x
put_list y n x
put_list x x x
put_list y x x
-put_list x x r
-put_list y r r
put_list y y x
put_list x y x
-put_list r x x
-put_list r y x
-put_list r x r
-put_list y y r
-put_list y r x
-put_list r n x
-put_list x r x
-put_list x y r
-put_list y x r
put_list y x x
-put_list x r r
-
# put_list SrcReg Constant Dst
-put_list r c r
-put_list r c x
-put_list r c y
-put_list x c r
put_list x c x
put_list x c y
-put_list y c r
put_list y c x
-put_list y c y
# put_list Constant SrcReg Dst
-put_list c r r
-put_list c r x
-put_list c r y
-put_list c x r
put_list c x x
-put_list c x y
-
-put_list c y r
put_list c y x
-put_list c y y
-%cold
-put_list s s d
-%hot
+# The following put_list instructions using x(0) are frequently used.
-%macro: i_fetch FetchArgs -pack
-i_fetch c r
-i_fetch c x
-i_fetch c y
-i_fetch r c
-i_fetch r x
-i_fetch r y
-i_fetch x c
-i_fetch x r
-i_fetch x x
-i_fetch x y
-i_fetch y c
-i_fetch y r
-i_fetch y x
-i_fetch y y
+put_list y r r
+put_list x r r
+put_list r n r
+put_list r n x
+put_list r x x
+put_list r x r
+put_list x x r
%cold
-i_fetch c c
-i_fetch s s
+put_list s s d
%hot
#
@@ -631,27 +590,27 @@ return_trace
# Note: There is no 'move_return y r', since there never are any y registers
# when we do move_return (if we have y registers, we must do move_deallocate_return).
-move S r | return => move_return S r
+move S x==0 | return => move_return S
%macro: move_return MoveReturn -nonext
-move_return x r
-move_return c r
-move_return n r
+move_return x
+move_return c
+move_return n
-move S r | deallocate D | return => move_deallocate_return S r D
+move S x==0 | deallocate D | return => move_deallocate_return S D
%macro: move_deallocate_return MoveDeallocateReturn -pack -nonext
-move_deallocate_return x r Q
-move_deallocate_return y r Q
-move_deallocate_return c r Q
-move_deallocate_return n r Q
+move_deallocate_return x Q
+move_deallocate_return y Q
+move_deallocate_return c Q
+move_deallocate_return n Q
deallocate D | return => deallocate_return D
%macro: deallocate_return DeallocateReturn -nonext
deallocate_return Q
-test_heap Need u==1 | put_list Y=y r r => test_heap_1_put_list Need Y
+test_heap Need u==1 | put_list Y=y x==0 x==0 => test_heap_1_put_list Need Y
%macro: test_heap_1_put_list TestHeapPutList -pack
test_heap_1_put_list I y
@@ -660,18 +619,18 @@ test_heap_1_put_list I y
is_tuple Fail Literal=q => move Literal x | is_tuple Fail x
is_tuple Fail=f c => jump Fail
-is_tuple Fail=f S=rxy | test_arity Fail=f S=rxy Arity => is_tuple_of_arity Fail S Arity
+is_tuple Fail=f S=xy | test_arity Fail=f S=xy Arity => is_tuple_of_arity Fail S Arity
%macro:is_tuple_of_arity IsTupleOfArity -fail_action
+is_tuple_of_arity f r A
is_tuple_of_arity f x A
is_tuple_of_arity f y A
-is_tuple_of_arity f r A
%macro: is_tuple IsTuple -fail_action
+is_tuple f r
is_tuple f x
is_tuple f y
-is_tuple f r
test_arity Fail Literal=q Arity => move Literal x | test_arity Fail x Arity
test_arity Fail=f c Arity => jump Fail
@@ -679,95 +638,63 @@ test_arity Fail=f c Arity => jump Fail
%macro: test_arity IsArity -fail_action
test_arity f x A
test_arity f y A
-test_arity f r A
-
-is_tuple_of_arity Fail=f Reg Arity | get_tuple_element Reg P=u==0 Dst=xy => \
- is_tuple_of_arity Fail Reg Arity | extract_next_element Dst | original_reg Reg P
-
-test_arity Fail Reg Arity | get_tuple_element Reg P=u==0 Dst=xy => \
- test_arity Fail Reg Arity | extract_next_element Dst | original_reg Reg P
-
-original_reg Reg P1 | get_tuple_element Reg P2 Dst=xy | succ(P1, P2) => \
- extract_next_element Dst | original_reg Reg P2
-
-get_tuple_element Reg P Dst => i_get_tuple_element Reg P Dst | original_reg Reg P
-
-original_reg Reg Pos =>
-
-original_reg/2
-
-extract_next_element D1=xy | original_reg Reg P1 | get_tuple_element Reg P2 D2=xy | \
-succ(P1, P2) | succ(D1, D2) => \
- extract_next_element2 D1 | original_reg Reg P2
-
-extract_next_element2 D1=xy | original_reg Reg P1 | get_tuple_element Reg P2 D2=xy | \
-succ(P1, P2) | succ2(D1, D2) => \
- extract_next_element3 D1 | original_reg Reg P2
-
-#extract_next_element3 D1=xy | original_reg Reg P1 | get_tuple_element Reg P2 D2=xy | \
-#succ(P1, P2) | succ3(D1, D2) => \
-# extract_next_element4 D1 | original_reg Reg P2
-
-%macro: extract_next_element ExtractNextElement -pack
-extract_next_element x
-extract_next_element y
-%macro: extract_next_element2 ExtractNextElement2 -pack
-extract_next_element2 x
-extract_next_element2 y
+get_tuple_element Reg=x P1 D1=x | get_tuple_element Reg=x P2 D2=x | \
+ get_tuple_element Reg=x P3 D3=x | \
+ succ(P1, P2) | succ(P2, P3) | \
+ succ(D1, D2) | succ(D2, D3) => i_get_tuple_element3 Reg P1 D1
-%macro: extract_next_element3 ExtractNextElement3 -pack
-extract_next_element3 x
-extract_next_element3 y
+get_tuple_element Reg=x P1 D1=x | get_tuple_element Reg=x P2 D2=x | \
+ succ(P1, P2) | succ(D1, D2) => i_get_tuple_element2 Reg P1 D1
-#%macro: extract_next_element4 ExtractNextElement4 -pack
-#extract_next_element4 x
-#extract_next_element4 y
+get_tuple_element Reg P Dst => i_get_tuple_element Reg P Dst
is_integer Fail=f i =>
is_integer Fail=f an => jump Fail
is_integer Fail Literal=q => move Literal x | is_integer Fail x
-is_integer Fail=f S=rx | allocate Need Regs => is_integer_allocate Fail S Need Regs
+is_integer Fail=f S=x | allocate Need Regs => is_integer_allocate Fail S Need Regs
%macro: is_integer_allocate IsIntegerAllocate -fail_action
is_integer_allocate f x I I
-is_integer_allocate f r I I
%macro: is_integer IsInteger -fail_action
is_integer f x
is_integer f y
-is_integer f r
is_list Fail=f n =>
is_list Fail Literal=q => move Literal x | is_list Fail x
is_list Fail=f c => jump Fail
%macro: is_list IsList -fail_action
-is_list f r
is_list f x
%cold
is_list f y
%hot
-is_nonempty_list Fail=f S=rx | allocate Need Rs => is_nonempty_list_allocate Fail S Need Rs
+is_nonempty_list Fail=f S=x | allocate Need Rs => is_nonempty_list_allocate Fail S Need Rs
%macro:is_nonempty_list_allocate IsNonemptyListAllocate -fail_action -pack
-is_nonempty_list_allocate f x I t
is_nonempty_list_allocate f r I t
+is_nonempty_list_allocate f x I t
-is_nonempty_list F=f r | test_heap I1 I2 => is_non_empty_list_test_heap F r I1 I2
+is_nonempty_list F=f x==0 | test_heap I1 I2 => is_non_empty_list_test_heap F I1 I2
%macro: is_non_empty_list_test_heap IsNonemptyListTestHeap -fail_action -pack
-is_non_empty_list_test_heap f r I t
+is_non_empty_list_test_heap f I t
+
+is_nonempty_list Fail=f S=x | get_list S D1=x D2=x => \
+ is_nonempty_list_get_list Fail S D1 D2
+
+%macro: is_nonempty_list_get_list IsNonemptyListGetList -fail_action -pack
+is_nonempty_list_get_list f r x x
+is_nonempty_list_get_list f x x x
%macro: is_nonempty_list IsNonemptyList -fail_action
is_nonempty_list f x
is_nonempty_list f y
-is_nonempty_list f r
%macro: is_atom IsAtom -fail_action
is_atom f x
-is_atom f r
%cold
is_atom f y
%hot
@@ -775,7 +702,6 @@ is_atom Fail=f a =>
is_atom Fail=f niq => jump Fail
%macro: is_float IsFloat -fail_action
-is_float f r
is_float f x
%cold
is_float f y
@@ -789,12 +715,10 @@ is_nil Fail=f qia => jump Fail
%macro: is_nil IsNil -fail_action
is_nil f x
is_nil f y
-is_nil f r
is_binary Fail Literal=q => move Literal x | is_binary Fail x
is_binary Fail=f c => jump Fail
%macro: is_binary IsBinary -fail_action
-is_binary f r
is_binary f x
%cold
is_binary f y
@@ -806,7 +730,6 @@ is_bitstr Fail Term => is_bitstring Fail Term
is_bitstring Fail Literal=q => move Literal x | is_bitstring Fail x
is_bitstring Fail=f c => jump Fail
%macro: is_bitstring IsBitstring -fail_action
-is_bitstring f r
is_bitstring f x
%cold
is_bitstring f y
@@ -814,7 +737,6 @@ is_bitstring f y
is_reference Fail=f cq => jump Fail
%macro: is_reference IsRef -fail_action
-is_reference f r
is_reference f x
%cold
is_reference f y
@@ -822,7 +744,6 @@ is_reference f y
is_pid Fail=f cq => jump Fail
%macro: is_pid IsPid -fail_action
-is_pid f r
is_pid f x
%cold
is_pid f y
@@ -830,7 +751,6 @@ is_pid f y
is_port Fail=f cq => jump Fail
%macro: is_port IsPort -fail_action
-is_port f r
is_port f x
%cold
is_port f y
@@ -842,14 +762,12 @@ is_boolean Fail=f ac => jump Fail
%cold
%macro: is_boolean IsBoolean -fail_action
-is_boolean f r
is_boolean f x
is_boolean f y
%hot
is_function2 Fail=f acq Arity => jump Fail
is_function2 Fail=f Fun a => jump Fail
-is_function2 Fail Fun Literal=q => move Literal x | is_function2 Fail Fun x
is_function2 f s s
%macro: is_function2 IsFunction2 -fail_action
@@ -989,76 +907,76 @@ call_ext_only u==3 u$func:erlang:hibernate/3 => i_hibernate
%unless USE_VM_PROBES
call_ext Arity u$func:erlang:dt_get_tag/0 => \
- move a=am_undefined r
+ move a=am_undefined x=0
call_ext_last Arity u$func:erlang:dt_get_tag/0 D => \
- move a=am_undefined r | deallocate D | return
+ move a=am_undefined x=0 | deallocate D | return
call_ext_only Arity u$func:erlang:dt_get_tag/0 => \
- move a=am_undefined r | return
-
-move Any r | call_ext Arity u$func:erlang:dt_put_tag/1 => \
- move a=am_undefined r
-move Any r | call_ext_last Arity u$func:erlang:dt_put_tag/1 D => \
- move a=am_undefined r | deallocate D | return
-move Any r | call_ext_only Arity u$func:erlang:dt_put_tag/1 => \
- move a=am_undefined r | return
+ move a=am_undefined x=0 | return
+
+move Any x==0 | call_ext Arity u$func:erlang:dt_put_tag/1 => \
+ move a=am_undefined x=0
+move Any x==0 | call_ext_last Arity u$func:erlang:dt_put_tag/1 D => \
+ move a=am_undefined x=0 | deallocate D | return
+move Any x==0 | call_ext_only Arity u$func:erlang:dt_put_tag/1 => \
+ move a=am_undefined x=0 | return
call_ext Arity u$func:erlang:dt_put_tag/1 => \
- move a=am_undefined r
+ move a=am_undefined x=0
call_ext_last Arity u$func:erlang:dt_put_tag/1 D => \
- move a=am_undefined r | deallocate D | return
+ move a=am_undefined x=0 | deallocate D | return
call_ext_only Arity u$func:erlang:dt_put_tag/1 => \
- move a=am_undefined r | return
+ move a=am_undefined x=0 | return
call_ext Arity u$func:erlang:dt_get_tag_data/0 => \
- move a=am_undefined r
+ move a=am_undefined x=0
call_ext_last Arity u$func:erlang:dt_get_tag_data/0 D => \
- move a=am_undefined r | deallocate D | return
+ move a=am_undefined x=0 | deallocate D | return
call_ext_only Arity u$func:erlang:dt_get_tag_data/0 => \
- move a=am_undefined r | return
-
-move Any r | call_ext Arity u$func:erlang:dt_spread_tag/1 => \
- move a=am_true r
-move Any r | call_ext_last Arity u$func:erlang:dt_spread_tag/1 D => \
- move a=am_true r | deallocate D | return
-move Any r | call_ext_only Arity u$func:erlang:dt_spread_tag/1 => \
- move a=am_true r | return
+ move a=am_undefined x=0 | return
+
+move Any x==0 | call_ext Arity u$func:erlang:dt_spread_tag/1 => \
+ move a=am_true x=0
+move Any x==0 | call_ext_last Arity u$func:erlang:dt_spread_tag/1 D => \
+ move a=am_true x=0 | deallocate D | return
+move Any x==0 | call_ext_only Arity u$func:erlang:dt_spread_tag/1 => \
+ move a=am_true x=0 | return
call_ext Arity u$func:erlang:dt_spread_tag/1 => \
- move a=am_true r
+ move a=am_true x=0
call_ext_last Arity u$func:erlang:dt_spread_tag/1 D => \
- move a=am_true r | deallocate D | return
+ move a=am_true x=0 | deallocate D | return
call_ext_only Arity u$func:erlang:dt_spread_tag/1 => \
- move a=am_true r | return
-
-move Any r | call_ext Arity u$func:erlang:dt_restore_tag/1 => \
- move a=am_true r
-move Any r | call_ext_last Arity u$func:erlang:dt_restore_tag/1 D => \
- move a=am_true r | deallocate D | return
-move Any r | call_ext_only Arity u$func:erlang:dt_restore_tag/1 => \
- move a=am_true r | return
+ move a=am_true x=0 | return
+
+move Any x==0 | call_ext Arity u$func:erlang:dt_restore_tag/1 => \
+ move a=am_true x=0
+move Any x==0 | call_ext_last Arity u$func:erlang:dt_restore_tag/1 D => \
+ move a=am_true x=0 | deallocate D | return
+move Any x==0 | call_ext_only Arity u$func:erlang:dt_restore_tag/1 => \
+ move a=am_true x=0 | return
call_ext Arity u$func:erlang:dt_restore_tag/1 => \
- move a=am_true r
+ move a=am_true x=0
call_ext_last Arity u$func:erlang:dt_restore_tag/1 D => \
- move a=am_true r | deallocate D | return
+ move a=am_true x=0 | deallocate D | return
call_ext_only Arity u$func:erlang:dt_restore_tag/1 => \
- move a=am_true r | return
-
-move Any r | call_ext Arity u$func:erlang:dt_prepend_vm_tag_data/1 => \
- move Any r
-move Any r | call_ext_last Arity u$func:erlang:dt_prepend_vm_tag_data/1 D => \
- move Any r | deallocate D | return
-move Any r | call_ext_only Arity u$func:erlang:dt_prepend_vm_tag_data/1 => \
- move Any r | return
+ move a=am_true x=0 | return
+
+move Any x==0 | call_ext Arity u$func:erlang:dt_prepend_vm_tag_data/1 => \
+ move Any x=0
+move Any x==0 | call_ext_last Arity u$func:erlang:dt_prepend_vm_tag_data/1 D => \
+ move Any x=0 | deallocate D | return
+move Any x==0 | call_ext_only Arity u$func:erlang:dt_prepend_vm_tag_data/1 => \
+ move Any x=0 | return
call_ext Arity u$func:erlang:dt_prepend_vm_tag_data/1 =>
call_ext_last Arity u$func:erlang:dt_prepend_vm_tag_data/1 D => \
deallocate D | return
call_ext_only Arity u$func:erlang:dt_prepend_vm_tag_data/1 => \
return
-move Any r | call_ext Arity u$func:erlang:dt_append_vm_tag_data/1 => \
- move Any r
-move Any r | call_ext_last Arity u$func:erlang:dt_append_vm_tag_data/1 D => \
- move Any r | deallocate D | return
-move Any r | call_ext_only Arity u$func:erlang:dt_append_vm_tag_data/1 => \
- move Any r | return
+move Any x==0 | call_ext Arity u$func:erlang:dt_append_vm_tag_data/1 => \
+ move Any x=0
+move Any x==0 | call_ext_last Arity u$func:erlang:dt_append_vm_tag_data/1 D => \
+ move Any x=0 | deallocate D | return
+move Any x==0 | call_ext_only Arity u$func:erlang:dt_append_vm_tag_data/1 => \
+ move Any x=0 | return
call_ext Arity u$func:erlang:dt_append_vm_tag_data/1 =>
call_ext_last Arity u$func:erlang:dt_append_vm_tag_data/1 D => \
deallocate D | return
@@ -1066,7 +984,7 @@ call_ext_only Arity u$func:erlang:dt_append_vm_tag_data/1 => \
return
# Can happen after one of the transformations above.
-move Discarded r | move Something r => move Something r
+move Discarded x==0 | move Something x==0 => move Something x=0
%endif
@@ -1091,9 +1009,9 @@ call_ext_only Ar=u Bif=u$is_bif => \
# with call instructions.
#
-move S=c r | call_ext Ar=u Func=u$is_not_bif => i_move_call_ext S r Func
-move S=c r | call_ext_last Ar=u Func=u$is_not_bif D => i_move_call_ext_last Func D S r
-move S=c r | call_ext_only Ar=u Func=u$is_not_bif => i_move_call_ext_only Func S r
+move S=c x==0 | call_ext Ar=u Func=u$is_not_bif => i_move_call_ext S Func
+move S=c x==0 | call_ext_last Ar=u Func=u$is_not_bif D => i_move_call_ext_last Func D S
+move S=c x==0 | call_ext_only Ar=u Func=u$is_not_bif => i_move_call_ext_only Func S
call_ext Ar Func => i_call_ext Func
call_ext_last Ar Func D => i_call_ext_last Func D
@@ -1120,78 +1038,71 @@ bif0 u$bif:erlang:node/0 Dst=d => node Dst
bif1 Fail Bif=u$bif:erlang:get/1 Src=s Dst=d => i_get Src Dst
-bif2 Jump=j u$bif:erlang:element/2 S1=s S2=rxy Dst=d => gen_element(Jump, S1, S2, Dst)
+bif2 Jump=j u$bif:erlang:element/2 S1=s S2=xy Dst=d => gen_element(Jump, S1, S2, Dst)
-bif1 Fail Bif Literal=q Dst => move Literal x | bif1 Fail Bif x Dst
bif1 p Bif S1 Dst => bif1_body Bif S1 Dst
-bif1_body Bif Literal=q Dst => move Literal x | bif1_body Bif x Dst
-
-bif2 p Bif S1 S2 Dst => i_fetch S1 S2 | i_bif2_body Bif Dst
-bif2 Fail Bif S1 S2 Dst => i_fetch S1 S2 | i_bif2 Fail Bif Dst
+bif2 p Bif S1 S2 Dst => i_bif2_body Bif S1 S2 Dst
+bif2 Fail Bif S1 S2 Dst => i_bif2 Fail Bif S1 S2 Dst
i_get s d
%macro: self Self
-self r
self x
self y
%macro: node Node
-node r
node x
%cold
node y
%hot
-i_fast_element r j I d
-i_fast_element x j I d
-i_fast_element y j I d
+i_fast_element j x I d
+i_fast_element j y I d
-i_element r j s d
-i_element x j s d
-i_element y j s d
+i_element j x s d
+i_element j y s d
bif1 f b s d
bif1_body b s d
-i_bif2 f b d
-i_bif2_body b d
+i_bif2 f b s s d
+i_bif2_body b s s d
#
# Internal calls.
#
-move S=c r | call Ar P=f => i_move_call S r P
-move S=s r | call Ar P=f => move_call S r P
+move S=c x==0 | call Ar P=f => i_move_call S P
+move S=s x==0 | call Ar P=f => move_call S P
-i_move_call c r f
+i_move_call c f
%macro:move_call MoveCall -arg_f -size -nonext
-move_call/3
+move_call/2
-move_call x r f
-move_call y r f
+move_call x f
+move_call y f
-move S=c r | call_last Ar P=f D => i_move_call_last P D S r
-move S r | call_last Ar P=f D => move_call_last S r P D
+move S=c x==0 | call_last Ar P=f D => i_move_call_last P D S
+move S x==0 | call_last Ar P=f D => move_call_last S P D
-i_move_call_last f P c r
+i_move_call_last f P c
%macro:move_call_last MoveCallLast -arg_f -nonext -pack
-move_call_last/4
-move_call_last x r f Q
-move_call_last y r f Q
+move_call_last/3
+move_call_last x f Q
+move_call_last y f Q
-move S=c r | call_only Ar P=f => i_move_call_only P S r
-move S=x r | call_only Ar P=f => move_call_only S r P
+move S=c x==0 | call_only Ar P=f => i_move_call_only P S
+move S=x x==0 | call_only Ar P=f => move_call_only S P
-i_move_call_only f c r
+i_move_call_only f c
%macro:move_call_only MoveCallOnly -arg_f -nonext
-move_call_only/3
+move_call_only/2
-move_call_only x r f
+move_call_only x f
call Ar Func => i_call Func
call_last Ar Func D => i_call_last Func D
@@ -1205,9 +1116,9 @@ i_call_ext e
i_call_ext_last e P
i_call_ext_only e
-i_move_call_ext c r e
-i_move_call_ext_last e P c r
-i_move_call_ext_only e c r
+i_move_call_ext c e
+i_move_call_ext_last e P c
+i_move_call_ext_only e c
# Fun calls.
@@ -1227,7 +1138,6 @@ i_make_fun I t
%macro: is_function IsFunction -fail_action
is_function f x
is_function f y
-is_function f r
is_function Fail=f c => jump Fail
func_info M F A => i_func_info u M F A
@@ -1239,131 +1149,105 @@ func_info M F A => i_func_info u M F A
%cold
bs_start_match2 Fail=f ica X Y D => jump Fail
bs_start_match2 Fail Bin X Y D => i_bs_start_match2 Bin Fail X Y D
-i_bs_start_match2 r f I I d
i_bs_start_match2 x f I I d
i_bs_start_match2 y f I I d
bs_save2 Reg Index => gen_bs_save(Reg, Index)
-i_bs_save2 r I
i_bs_save2 x I
bs_restore2 Reg Index => gen_bs_restore(Reg, Index)
-i_bs_restore2 r I
i_bs_restore2 x I
# Matching integers
bs_match_string Fail Ms Bits Val => i_bs_match_string Ms Fail Bits Val
-i_bs_match_string r f I I
i_bs_match_string x f I I
# Fetching integers from binaries.
-bs_get_integer2 Fail=f Ms=rx Live=u Sz=sq Unit=u Flags=u Dst=d => \
+bs_get_integer2 Fail=f Ms=x Live=u Sz=sq Unit=u Flags=u Dst=d => \
gen_get_integer2(Fail, Ms, Live, Sz, Unit, Flags, Dst)
-i_bs_get_integer_small_imm r I f I d
i_bs_get_integer_small_imm x I f I d
-i_bs_get_integer_imm r I I f I d
i_bs_get_integer_imm x I I f I d
-i_bs_get_integer f I I d
-i_bs_get_integer_8 r f d
+i_bs_get_integer f I I s s d
i_bs_get_integer_8 x f d
-i_bs_get_integer_16 r f d
i_bs_get_integer_16 x f d
-i_bs_get_integer_32 r f I d
i_bs_get_integer_32 x f I d
# Fetching binaries from binaries.
-bs_get_binary2 Fail=f Ms=rx Live=u Sz=sq Unit=u Flags=u Dst=d => \
+bs_get_binary2 Fail=f Ms=x Live=u Sz=sq Unit=u Flags=u Dst=d => \
gen_get_binary2(Fail, Ms, Live, Sz, Unit, Flags, Dst)
%macro: i_bs_get_binary_imm2 BsGetBinaryImm_2 -fail_action -gen_dest
%macro: i_bs_get_binary2 BsGetBinary_2 -fail_action -gen_dest
%macro: i_bs_get_binary_all2 BsGetBinaryAll_2 -fail_action -gen_dest
-i_bs_get_binary_imm2 f r I I I d
i_bs_get_binary_imm2 f x I I I d
-i_bs_get_binary2 f r I s I d
i_bs_get_binary2 f x I s I d
-i_bs_get_binary_all2 f r I I d
i_bs_get_binary_all2 f x I I d
-i_bs_get_binary_all_reuse r f I
i_bs_get_binary_all_reuse x f I
# Fetching float from binaries.
-bs_get_float2 Fail=f Ms=rx Live=u Sz=s Unit=u Flags=u Dst=d => \
+bs_get_float2 Fail=f Ms=x Live=u Sz=s Unit=u Flags=u Dst=d => \
gen_get_float2(Fail, Ms, Live, Sz, Unit, Flags, Dst)
-bs_get_float2 Fail=f Ms=rx Live=u Sz=q Unit=u Flags=u Dst=d => jump Fail
+bs_get_float2 Fail=f Ms=x Live=u Sz=q Unit=u Flags=u Dst=d => jump Fail
%macro: i_bs_get_float2 BsGetFloat2 -fail_action -gen_dest
-i_bs_get_float2 f r I s I d
i_bs_get_float2 f x I s I d
# Miscellanous
-bs_skip_bits2 Fail=f Ms=rx Sz=s Unit=u Flags=u => \
- gen_skip_bits2(Fail, Ms, Sz, Unit, Flags)
-bs_skip_bits2 Fail=f Ms=rx Sz=q Unit=u Flags=u => \
+bs_skip_bits2 Fail=f Ms=x Sz=sq Unit=u Flags=u => \
gen_skip_bits2(Fail, Ms, Sz, Unit, Flags)
%macro: i_bs_skip_bits_imm2 BsSkipBitsImm2 -fail_action
-i_bs_skip_bits_imm2 f r I
i_bs_skip_bits_imm2 f x I
%macro: i_bs_skip_bits2 BsSkipBits2 -fail_action
-i_bs_skip_bits2 f r x I
-i_bs_skip_bits2 f r y I
i_bs_skip_bits2 f x x I
-i_bs_skip_bits2 f x r I
i_bs_skip_bits2 f x y I
%macro: i_bs_skip_bits_all2 BsSkipBitsAll2 -fail_action
-i_bs_skip_bits_all2 f r I
i_bs_skip_bits_all2 f x I
-bs_test_tail2 Fail=f Ms=rx Bits=u==0 => bs_test_zero_tail2 Fail Ms
-bs_test_tail2 Fail=f Ms=rx Bits=u => bs_test_tail_imm2 Fail Ms Bits
-bs_test_zero_tail2 f r
+bs_test_tail2 Fail=f Ms=x Bits=u==0 => bs_test_zero_tail2 Fail Ms
+bs_test_tail2 Fail=f Ms=x Bits=u => bs_test_tail_imm2 Fail Ms Bits
bs_test_zero_tail2 f x
-bs_test_tail_imm2 f r I
bs_test_tail_imm2 f x I
bs_test_unit F Ms Unit=u==8 => bs_test_unit8 F Ms
-bs_test_unit f r I
bs_test_unit f x I
-bs_test_unit8 f r
bs_test_unit8 f x
-bs_context_to_binary r
+# An y register operand for bs_context_to_binary is rare,
+# but can happen because of inlining.
+
+bs_context_to_binary Y=y => move Y x | bs_context_to_binary x
+
bs_context_to_binary x
-bs_context_to_binary y
#
# Utf8/utf16/utf32 support. (R12B-5)
#
-bs_get_utf8 Fail=f Ms=rx u u Dst=d => i_bs_get_utf8 Ms Fail Dst
-i_bs_get_utf8 r f d
+bs_get_utf8 Fail=f Ms=x u u Dst=d => i_bs_get_utf8 Ms Fail Dst
i_bs_get_utf8 x f d
-bs_skip_utf8 Fail=f Ms=rx u u => i_bs_get_utf8 Ms Fail x
+bs_skip_utf8 Fail=f Ms=x u u => i_bs_get_utf8 Ms Fail x
-bs_get_utf16 Fail=f Ms=rx u Flags=u Dst=d => i_bs_get_utf16 Ms Fail Flags Dst
-bs_skip_utf16 Fail=f Ms=rx u Flags=u => i_bs_get_utf16 Ms Fail Flags x
+bs_get_utf16 Fail=f Ms=x u Flags=u Dst=d => i_bs_get_utf16 Ms Fail Flags Dst
+bs_skip_utf16 Fail=f Ms=x u Flags=u => i_bs_get_utf16 Ms Fail Flags x
-i_bs_get_utf16 r f I d
i_bs_get_utf16 x f I d
-bs_get_utf32 Fail=f Ms=rx Live=u Flags=u Dst=d => \
+bs_get_utf32 Fail=f Ms=x Live=u Flags=u Dst=d => \
bs_get_integer2 Fail Ms Live i=32 u=1 Flags Dst | \
- i_fetch Dst Ms | \
- i_bs_validate_unicode_retract Fail
-bs_skip_utf32 Fail=f Ms=rx Live=u Flags=u => \
+ i_bs_validate_unicode_retract Fail Dst Ms
+bs_skip_utf32 Fail=f Ms=x Live=u Flags=u => \
bs_get_integer2 Fail Ms Live i=32 u=1 Flags x | \
- i_fetch x Ms | \
- i_bs_validate_unicode_retract Fail
+ i_bs_validate_unicode_retract Fail x Ms
-i_bs_validate_unicode_retract j
+i_bs_validate_unicode_retract j s s
%hot
#
@@ -1385,13 +1269,12 @@ bs_init2 Fail Sz=u Words Regs Flags Dst => \
bs_init2 Fail Sz Words=u==0 Regs Flags Dst => \
i_bs_init_fail Sz Fail Regs Dst
bs_init2 Fail Sz Words Regs Flags Dst => \
- i_fetch Sz r | i_bs_init_fail_heap Words Fail Regs Dst
+ i_bs_init_fail_heap Sz Words Fail Regs Dst
-i_bs_init_fail r j I d
i_bs_init_fail x j I d
i_bs_init_fail y j I d
-i_bs_init_fail_heap I j I d
+i_bs_init_fail_heap s I j I d
i_bs_init I I d
i_bs_init_heap_bin I I d
@@ -1408,39 +1291,35 @@ bs_init_bits Fail Sz=u Words Regs Flags Dst => i_bs_init_bits_heap Sz Words Reg
bs_init_bits Fail Sz Words=u==0 Regs Flags Dst => \
i_bs_init_bits_fail Sz Fail Regs Dst
bs_init_bits Fail Sz Words Regs Flags Dst => \
- i_fetch Sz r | i_bs_init_bits_fail_heap Words Fail Regs Dst
+ i_bs_init_bits_fail_heap Sz Words Fail Regs Dst
-i_bs_init_bits_fail r j I d
i_bs_init_bits_fail x j I d
i_bs_init_bits_fail y j I d
-i_bs_init_bits_fail_heap I j I d
+i_bs_init_bits_fail_heap s I j I d
i_bs_init_bits I I d
i_bs_init_bits_heap I I I d
bs_add Fail S1=i==0 S2 Unit=u==1 D => move S2 D
-bs_add Fail S1 S2 Unit D => i_fetch S1 S2 | i_bs_add Fail Unit D
-i_bs_add j I d
+bs_add j s s I d
bs_append Fail Size Extra Live Unit Bin Flags Dst => \
- i_fetch Size Bin | i_bs_append Fail Extra Live Unit Dst
+ move Bin x | i_bs_append Fail Extra Live Unit Size Dst
bs_private_append Fail Size Unit Bin Flags Dst => \
- i_fetch Size Bin | i_bs_private_append Fail Unit Dst
+ i_bs_private_append Fail Unit Size Bin Dst
bs_init_writable
-i_bs_append j I I I d
-i_bs_private_append j I d
+i_bs_append j I I I s d
+i_bs_private_append j I s s d
#
# Storing integers into binaries.
#
-bs_put_integer Fail=j Sz=s Unit=u Flags=u Literal=q => \
- move Literal x | bs_put_integer Fail Sz Unit Flags x
bs_put_integer Fail=j Sz=sq Unit=u Flags=u Src=s => \
gen_put_integer(Fail, Sz, Unit, Flags, Src)
@@ -1454,32 +1333,22 @@ i_new_bs_put_integer_imm j I I s
# Utf8/utf16/utf32 support. (R12B-5)
#
-bs_utf8_size Fail Literal=q Dst=d => \
- move Literal x | bs_utf8_size Fail x Dst
bs_utf8_size j Src=s Dst=d => i_bs_utf8_size Src Dst
i_bs_utf8_size s d
-bs_utf16_size Fail Literal=q Dst=d => \
- move Literal x | bs_utf16_size Fail x Dst
bs_utf16_size j Src=s Dst=d => i_bs_utf16_size Src Dst
i_bs_utf16_size s d
-bs_put_utf8 Fail=j Flags=u Literal=q => \
- move Literal x | bs_put_utf8 Fail Flags x
bs_put_utf8 Fail u Src=s => i_bs_put_utf8 Fail Src
i_bs_put_utf8 j s
-bs_put_utf16 Fail=j Flags=u Literal=q => \
- move Literal x | bs_put_utf16 Fail Flags x
bs_put_utf16 Fail Flags=u Src=s => i_bs_put_utf16 Fail Flags Src
i_bs_put_utf16 j I s
-bs_put_utf32 Fail=j Flags=u Literal=q => \
- move Literal x | bs_put_utf32 Fail Flags x
bs_put_utf32 Fail=j Flags=u Src=s => \
i_bs_validate_unicode Fail Src | bs_put_integer Fail i=32 u=1 Flags Src
@@ -1490,9 +1359,6 @@ i_bs_validate_unicode j s
#
bs_put_float Fail Sz=q Unit Flags Val => badarg Fail
-bs_put_float Fail=j Sz Unit=u Flags=u Literal=q => \
- move Literal x | bs_put_float Fail Sz Unit Flags x
-
bs_put_float Fail=j Sz=s Unit=u Flags=u Src=s => \
gen_put_float(Fail, Sz, Unit, Flags, Src)
@@ -1506,8 +1372,6 @@ i_new_bs_put_float_imm j I I s
# Storing binaries into binaries.
#
-bs_put_binary Fail Sz Unit Flags Literal=q => \
- move Literal x | bs_put_binary Fail Sz Unit Flags x
bs_put_binary Fail=j Sz=s Unit=u Flags=u Src=s => \
gen_put_binary(Fail, Sz, Unit, Flags, Src)
@@ -1600,7 +1464,6 @@ is_map Fail Lit=q | literal_is_map(Lit) =>
is_map Fail cq => jump Fail
%macro: is_map IsMap -fail_action
-is_map f r
is_map f x
is_map f y
@@ -1611,101 +1474,120 @@ has_map_fields Fail Src Size Rest=* => \
## Transform get_map_elements(s) #{ K1 := V1, K2 := V2 }
-get_map_elements Fail Src=rxy Size=u==2 Rest=* => \
+get_map_elements Fail Src=xy Size=u==2 Rest=* => \
gen_get_map_element(Fail, Src, Size, Rest)
get_map_elements Fail Src Size Rest=* | map_key_sort(Size, Rest) => \
gen_get_map_elements(Fail, Src, Size, Rest)
i_get_map_elements f s I
-i_get_map_element Fail Src=rxy Key=ry Dst => \
+i_get_map_element Fail Src=xy Key=y Dst => \
move Key x | i_get_map_element Fail Src x Dst
%macro: i_get_map_element_hash GetMapElementHash -fail_action
-i_get_map_element_hash f r c I r
-i_get_map_element_hash f x c I r
-i_get_map_element_hash f y c I r
-i_get_map_element_hash f r c I x
i_get_map_element_hash f x c I x
i_get_map_element_hash f y c I x
-i_get_map_element_hash f r c I y
i_get_map_element_hash f x c I y
i_get_map_element_hash f y c I y
%macro: i_get_map_element GetMapElement -fail_action
-i_get_map_element f r x r
-i_get_map_element f x x r
-i_get_map_element f y x r
-i_get_map_element f r x x
i_get_map_element f x x x
i_get_map_element f y x x
-i_get_map_element f r x y
i_get_map_element f x x y
i_get_map_element f y x y
#
+# Convert the plus operations to a generic plus instruction.
+#
+gen_plus/5
+gen_minus/5
+
+gc_bif1 Fail Live u$bif:erlang:splus/1 Src Dst => \
+ gen_plus Fail Live Src i Dst
+gc_bif2 Fail Live u$bif:erlang:splus/2 S1 S2 Dst => \
+ gen_plus Fail Live S1 S2 Dst
+
+gc_bif1 Fail Live u$bif:erlang:sminus/1 Src Dst => \
+ gen_minus Fail Live i Src Dst
+gc_bif2 Fail Live u$bif:erlang:sminus/2 S1 S2 Dst => \
+ gen_minus Fail Live S1 S2 Dst
+
+#
# Optimize addition and subtraction of small literals using
# the i_increment/4 instruction (in bodies, not in guards).
#
-gc_bif2 p Live u$bif:erlang:splus/2 Int=i Reg=d Dst => \
+gen_plus p Live Int=i Reg=d Dst => \
gen_increment(Reg, Int, Live, Dst)
-gc_bif2 p Live u$bif:erlang:splus/2 Reg=d Int=i Dst => \
+gen_plus p Live Reg=d Int=i Dst => \
gen_increment(Reg, Int, Live, Dst)
-gc_bif2 p Live u$bif:erlang:sminus/2 Reg=d Int=i Dst | \
- negation_is_small(Int) => \
+gen_minus p Live Reg=d Int=i Dst | negation_is_small(Int) => \
gen_increment_from_minus(Reg, Int, Live, Dst)
#
# GCing arithmetic instructions.
#
-gc_bif2 Fail I u$bif:erlang:splus/2 S1=x S2=x Dst=d => i_plus Fail I S1 S2 Dst
-gc_bif2 Fail I u$bif:erlang:splus/2 S1 S2 Dst=d => i_fetch S1 S2 | i_plus Fail I Dst
-gc_bif2 Fail I u$bif:erlang:sminus/2 S1=x S2=x Dst=d => i_minus Fail I S1 S2 Dst
-gc_bif2 Fail I u$bif:erlang:sminus/2 S1 S2 Dst=d => i_fetch S1 S2 | i_minus Fail I Dst
-gc_bif2 Fail I u$bif:erlang:stimes/2 S1 S2 Dst=d => i_fetch S1 S2 | i_times Fail I Dst
-gc_bif2 Fail I u$bif:erlang:div/2 S1 S2 Dst=d => i_fetch S1 S2 | i_m_div Fail I Dst
+gen_plus Fail Live Y=y X=x Dst => i_plus Fail Live X Y Dst
+gen_plus Fail Live S1 S2 Dst => i_plus Fail Live S1 S2 Dst
-gc_bif2 Fail I u$bif:erlang:intdiv/2 S1 S2 Dst=d => i_fetch S1 S2 | i_int_div Fail I Dst
-gc_bif2 Fail I u$bif:erlang:rem/2 S1=x S2=x Dst=d => i_rem Fail I S1 S2 Dst
-gc_bif2 Fail I u$bif:erlang:rem/2 S1 S2 Dst=d => i_fetch S1 S2 | i_rem Fail I Dst
+gen_minus Fail Live S1 S2 Dst => i_minus Fail Live S1 S2 Dst
-gc_bif2 Fail I u$bif:erlang:bsl/2 S1 S2 Dst=d => i_fetch S1 S2 | i_bsl Fail I Dst
-gc_bif2 Fail I u$bif:erlang:bsr/2 S1 S2 Dst=d => i_fetch S1 S2 | i_bsr Fail I Dst
+gc_bif2 Fail Live u$bif:erlang:stimes/2 S1 S2 Dst => \
+ i_times Fail Live S1 S2 Dst
-gc_bif2 Fail I u$bif:erlang:band/2 S1=x S2=c Dst=d => i_band Fail I S1 S2 Dst
-gc_bif2 Fail I u$bif:erlang:band/2 S1 S2 Dst=d => i_fetch S1 S2 | i_band Fail I Dst
-gc_bif2 Fail I u$bif:erlang:bor/2 S1 S2 Dst=d => i_fetch S1 S2 | i_bor Fail I Dst
-gc_bif2 Fail I u$bif:erlang:bxor/2 S1 S2 Dst=d => i_fetch S1 S2 | i_bxor Fail I Dst
+gc_bif2 Fail Live u$bif:erlang:div/2 S1 S2 Dst => \
+ i_m_div Fail Live S1 S2 Dst
+gc_bif2 Fail Live u$bif:erlang:intdiv/2 S1 S2 Dst => \
+ i_int_div Fail Live S1 S2 Dst
-gc_bif1 Fail I u$bif:erlang:bnot/1 Src Dst=d => i_int_bnot Fail Src I Dst
+gc_bif2 Fail Live u$bif:erlang:rem/2 S1 S2 Dst => \
+ i_rem Fail Live S1 S2 Dst
+
+gc_bif2 Fail Live u$bif:erlang:bsl/2 S1 S2 Dst => \
+ i_bsl Fail Live S1 S2 Dst
+gc_bif2 Fail Live u$bif:erlang:bsr/2 S1 S2 Dst => \
+ i_bsr Fail Live S1 S2 Dst
+
+gc_bif2 Fail Live u$bif:erlang:band/2 S1 S2 Dst => \
+ i_band Fail Live S1 S2 Dst
+
+gc_bif2 Fail Live u$bif:erlang:bor/2 S1 S2 Dst => \
+ i_bor Fail Live S1 S2 Dst
-gc_bif1 Fail I u$bif:erlang:sminus/1 Src Dst=d => i_fetch i Src | i_minus Fail I Dst
-gc_bif1 Fail I u$bif:erlang:splus/1 Src Dst=d => i_fetch i Src | i_plus Fail I Dst
+gc_bif2 Fail Live u$bif:erlang:bxor/2 S1 S2 Dst => \
+ i_bxor Fail Live S1 S2 Dst
+
+gc_bif1 Fail I u$bif:erlang:bnot/1 Src Dst=d => i_int_bnot Fail Src I Dst
i_increment r I I d
i_increment x I I d
i_increment y I I d
i_plus j I x x d
-i_plus j I d
+i_plus j I x y d
+i_plus j I s s d
+
i_minus j I x x d
-i_minus j I d
-i_times j I d
-i_m_div j I d
-i_int_div j I d
+i_minus j I s s d
+
+i_times j I s s d
+
+i_m_div j I s s d
+i_int_div j I s s d
+
i_rem j I x x d
-i_rem j I d
+i_rem j I s s d
-i_bsl j I d
-i_bsr j I d
+i_bsl j I s s d
+i_bsr j I s s d
i_band j I x c d
-i_band j I d
-i_bor j I d
-i_bxor j I d
+i_band j I s s d
+
+i_bor j I s s d
+i_bxor j I s s d
i_int_bnot j s I d
@@ -1731,21 +1613,18 @@ gc_bif2 Fail I Bif S1 S2 Dst => \
gc_bif3 Fail I Bif S1 S2 S3 Dst => \
gen_guard_bif3(Fail, I, Bif, S1, S2, S3, Dst)
-i_gc_bif1 Fail Bif V=q Live D => move V x | i_gc_bif1 Fail Bif x Live D
-
i_gc_bif1 j I s I d
-ii_gc_bif2/6
-
-ii_gc_bif2 Fail Bif S1 S2 Live D => i_fetch S1 S2 | i_gc_bif2 Fail Bif Live D
-
-i_gc_bif2 j I I d
+i_gc_bif2 j I I s s d
ii_gc_bif3/7
-ii_gc_bif3 Fail Bif S1 S2 S3 Live D => move S1 x | i_fetch S2 S3 | i_gc_bif3 Fail Bif x Live D
+# A specific instruction can only have 6 operands, so we must
+# pass one of the arguments in an x register.
+ii_gc_bif3 Fail Bif Live S1 S2 S3 Dst => \
+ move S1 x | i_gc_bif3 Fail Bif Live S2 S3 Dst
-i_gc_bif3 j I s I d
+i_gc_bif3 j I I s s d
#
# The following instruction is specially handled in beam_load.c
diff --git a/erts/emulator/test/erts_debug_SUITE.erl b/erts/emulator/test/erts_debug_SUITE.erl
index 3dd77eb920..35677f9953 100644
--- a/erts/emulator/test/erts_debug_SUITE.erl
+++ b/erts/emulator/test/erts_debug_SUITE.erl
@@ -139,23 +139,48 @@ flat_size_big_1(Term, Size0, Limit) when Size0 < Limit ->
flat_size_big_1(_, _, _) -> ok.
df(Config) when is_list(Config) ->
- ?line P0 = pps(),
- ?line PrivDir = ?config(priv_dir, Config),
- ?line ok = file:set_cwd(PrivDir),
- ?line erts_debug:df(?MODULE),
- ?line Beam = filename:join(PrivDir, ?MODULE_STRING++".dis"),
- ?line {ok,Bin} = file:read_file(Beam),
- ?line ok = io:put_chars(binary_to_list(Bin)),
- ?line ok = file:delete(Beam),
- ?line true = (P0 == pps()),
+ P0 = pps(),
+ PrivDir = ?config(priv_dir, Config),
+ ok = file:set_cwd(PrivDir),
+
+ AllLoaded = [M || {M,_} <- code:all_loaded()],
+ {Pid,Ref} = spawn_monitor(fun() -> df_smoke(AllLoaded) end),
+ receive
+ {'DOWN',Ref,process,Pid,Status} ->
+ normal = Status
+ after 20*1000 ->
+ %% Not finished (i.e. a slow computer). Stop now.
+ Pid ! stop,
+ receive
+ {'DOWN',Ref,process,Pid,Status} ->
+ normal = Status,
+ io:format("...")
+ end
+ end,
+ io:nl(),
+ _ = [_ = file:delete(atom_to_list(M) ++ ".dis") ||
+ M <- AllLoaded],
+
+ true = (P0 == pps()),
ok.
+df_smoke([M|Ms]) ->
+ io:format("~p", [M]),
+ erts_debug:df(M),
+ receive
+ stop ->
+ ok
+ after 0 ->
+ df_smoke(Ms)
+ end;
+df_smoke([]) -> ok.
+
pps() ->
{erlang:ports()}.
instructions(Config) when is_list(Config) ->
- ?line Is = erts_debug:instructions(),
- ?line _ = [list_to_atom(I) || I <- Is],
+ Is = erts_debug:instructions(),
+ _ = [list_to_atom(I) || I <- Is],
ok.
id(I) ->
diff --git a/erts/emulator/test/trace_port_SUITE.erl b/erts/emulator/test/trace_port_SUITE.erl
index d6346f3af0..a77710205e 100644
--- a/erts/emulator/test/trace_port_SUITE.erl
+++ b/erts/emulator/test/trace_port_SUITE.erl
@@ -35,7 +35,8 @@
fake_schedule_after_getting_linked/1,
fake_schedule_after_getting_unlinked/1,
gc/1,
- default_tracer/1]).
+ default_tracer/1,
+ tracer_port_crash/1]).
-include_lib("test_server/include/test_server.hrl").
@@ -45,7 +46,7 @@ test_cases() ->
fake_schedule_after_register,
fake_schedule_after_getting_linked,
fake_schedule_after_getting_unlinked, gc,
- default_tracer].
+ default_tracer, tracer_port_crash].
suite() -> [{ct_hooks,[ts_install_cth]}].
@@ -473,6 +474,42 @@ default_tracer(Config) when is_list(Config) ->
?line M = N,
ok.
+tracer_port_crash(Config) when is_list(Config) ->
+ case test_server:is_native(?MODULE) orelse
+ test_server:is_native(lists) of
+ true ->
+ {skip,"Native code"};
+ false ->
+ Tr = start_tracer(Config),
+ Port = get(tracer_port),
+ Tracee = spawn(fun () ->
+ register(trace_port_linker, self()),
+ link(Port),
+ receive go -> ok end,
+ lists:reverse([1,b,c]),
+ receive die -> ok end
+ end),
+ Tr ! {unlink_tracer_port, self()},
+ receive {unlinked_tracer_port, Tr} -> ok end,
+ port_control(Port, $c, []), %% Make port commands crash tracer port...
+ trace_func({lists,reverse,1}, []),
+ trace_pid(Tracee, true, [call]),
+ trace_info(Tracee, flags),
+ trace_info(self(), tracer),
+ Tracee ! go,
+ receive after 1000 -> ok end,
+ case whereis(trace_port_linker) of
+ undefined ->
+ ok;
+ Id ->
+% erts_debug:set_internal_state(available_internal_state, true),
+% erts_debug:set_internal_state(abort, {trace_port_linker, Id})
+ ?t:fail({trace_port_linker, Id})
+ end,
+ undefined = process_info(Tracee),
+ ok
+ end.
+
%%% Help functions.
huge_data() -> huge_data(16384).
@@ -631,6 +668,10 @@ tracer_loop(RelayTo, Port) ->
{Port,{data,Msg}} ->
RelayTo ! binary_to_term(Msg),
tracer_loop(RelayTo, Port);
+ {unlink_tracer_port, From} ->
+ unlink(Port),
+ From ! {unlinked_tracer_port, self()},
+ tracer_loop(RelayTo, Port);
Other ->
exit({bad_message,Other})
end.
diff --git a/erts/emulator/test/trace_port_SUITE_data/echo_drv.c b/erts/emulator/test/trace_port_SUITE_data/echo_drv.c
index a8d4ede4fe..e40b9193ea 100644
--- a/erts/emulator/test/trace_port_SUITE_data/echo_drv.c
+++ b/erts/emulator/test/trace_port_SUITE_data/echo_drv.c
@@ -1,5 +1,6 @@
#include <stdio.h>
#include "erl_driver.h"
+#include <errno.h>
@@ -14,6 +15,7 @@ enum e_heavy {
typedef struct _erl_drv_data {
ErlDrvPort erlang_port;
enum e_heavy heavy;
+ int crash;
} EchoDrvData;
static EchoDrvData echo_drv_data, *echo_drv_data_p;
@@ -78,6 +80,7 @@ static EchoDrvData *echo_drv_start(ErlDrvPort port, char *command)
echo_drv_data_p = &echo_drv_data;
echo_drv_data_p->erlang_port = port;
echo_drv_data_p->heavy = heavy_off;
+ echo_drv_data_p->crash = 0;
return echo_drv_data_p;
}
@@ -87,6 +90,12 @@ static void echo_drv_stop(EchoDrvData *data_p) {
static void echo_drv_output(ErlDrvData drv_data, char *buf, ErlDrvSizeT len) {
EchoDrvData* data_p = (EchoDrvData *) drv_data;
+
+ if (data_p->crash) {
+ driver_failure_posix(data_p->erlang_port, EINTR);
+ return;
+ }
+
driver_output(data_p->erlang_port, buf, len);
switch (data_p->heavy) {
case heavy_off:
@@ -100,6 +109,7 @@ static void echo_drv_output(ErlDrvData drv_data, char *buf, ErlDrvSizeT len) {
data_p->heavy = heavy_off;
break;
}
+
}
static void echo_drv_finish() {
@@ -115,6 +125,8 @@ static ErlDrvSSizeT echo_drv_control(ErlDrvData drv_data,
case 'h':
data_p->heavy = heavy_set;
break;
+ case 'c':
+ data_p->crash = 1;
}
return 0;
}
diff --git a/erts/emulator/utils/beam_makeops b/erts/emulator/utils/beam_makeops
index e90ed94187..f805e7cc64 100755
--- a/erts/emulator/utils/beam_makeops
+++ b/erts/emulator/utils/beam_makeops
@@ -48,12 +48,17 @@ $pack_shift[4] = ['0', 'BEAM_LOOSE_SHIFT', # Only for 64 bit wordsize
'(3*BEAM_LOOSE_SHIFT)'];
$pack_mask[2] = ['BEAM_LOOSE_MASK', $WHOLE_WORD];
-$pack_mask[3] = ['BEAM_TIGHT_MASK', 'BEAM_TIGHT_MASK', 'BEAM_TIGHT_MASK'];
+$pack_mask[3] = ['BEAM_TIGHT_MASK', 'BEAM_TIGHT_MASK', $WHOLE_WORD];
$pack_mask[4] = ['BEAM_LOOSE_MASK', # Only for 64 bit wordsize
'BEAM_LOOSE_MASK',
'BEAM_LOOSE_MASK',
$WHOLE_WORD];
+# Mapping from packagable arguments to number of packed arguments per
+# word. Initialized after the wordsize is known.
+
+my @args_per_word;
+
# There are two types of instructions: generic and specific.
# The generic instructions are those generated by the Beam compiler.
# Corresponding to each generic instruction, there is generally a
@@ -176,11 +181,12 @@ sub define_type_bit {
}
# Composed types.
- define_type_bit('d', $type_bit{'x'} | $type_bit{'y'} | $type_bit{'r'});
+ define_type_bit('d', $type_bit{'x'} | $type_bit{'y'});
define_type_bit('c', $type_bit{'i'} | $type_bit{'a'} |
$type_bit{'n'} | $type_bit{'q'});
define_type_bit('s', $type_bit{'d'} | $type_bit{'i'} |
- $type_bit{'a'} | $type_bit{'n'});
+ $type_bit{'a'} | $type_bit{'n'} |
+ $type_bit{'q'});
define_type_bit('j', $type_bit{'f'} | $type_bit{'p'});
# Aliases (for matching purposes).
@@ -236,6 +242,20 @@ while (@ARGV && $ARGV[0] =~ /^-(.*)/) {
}
#
+# Initialize number of arguments per packed word.
+#
+
+$args_per_word[2] = 2;
+$args_per_word[3] = 3;
+$args_per_word[4] = 2;
+$args_per_word[5] = 3;
+$args_per_word[6] = 3;
+
+if ($wordsize == 64) {
+ $args_per_word[4] = 4;
+}
+
+#
# Parse the input files.
#
@@ -527,12 +547,16 @@ sub emulator_output {
my(@bits) = (0) x ($max_spec_operands/2);
my($i);
+ my $involves_r = 0;
for ($i = 0; $i < $max_spec_operands && defined $args[$i]; $i++) {
my $t = $args[$i];
- if (defined $type_bit{$t}) {
- my $shift = $max_genop_types * ($i % 2);
- $bits[int($i/2)] |= $type_bit{$t} << $shift;
+ my $bits = $type_bit{$t};
+ if ($t eq 'r') {
+ $bits |= $type_bit{'x'};
+ $involves_r |= 1 << $i;
}
+ my $shift = $max_genop_types * ($i % 2);
+ $bits[int($i/2)] |= $bits << $shift;
}
printf "/* %3d */ ", $spec_opnum;
@@ -544,7 +568,7 @@ sub emulator_output {
$sep = ",";
}
$init .= "}";
- &init_item($print_name, $init, $size, $pack, $sign, 0);
+ init_item($print_name, $init, $involves_r, $size, $pack, $sign, 0);
$op_to_name[$spec_opnum] = $instr;
$spec_opnum++;
}
@@ -601,11 +625,12 @@ sub emulator_output {
print "#define MAX_GENERIC_OPCODE ", $num_file_opcodes-1, "\n";
print "#define NUM_GENERIC_OPS ", scalar(@gen_opname), "\n";
print "#define NUM_SPECIFIC_OPS ", scalar(@op_to_name), "\n";
+ print "#define SCRATCH_X_REG 1023\n";
print "\n";
print "#ifdef ARCH_64\n";
print "# define BEAM_WIDE_MASK 0xFFFFUL\n";
- print "# define BEAM_LOOSE_MASK 0x1FFFUL\n";
- print "# define BEAM_TIGHT_MASK 0x1FF8UL\n";
+ print "# define BEAM_LOOSE_MASK 0xFFFFUL\n";
+ print "# define BEAM_TIGHT_MASK 0xFFFFUL\n";
print "# define BEAM_WIDE_SHIFT 32\n";
print "# define BEAM_LOOSE_SHIFT 16\n";
print "# define BEAM_TIGHT_SHIFT 16\n";
@@ -730,7 +755,7 @@ sub init_item {
print "${sep}NULL";
} elsif (/^\{/) {
print "$sep$_";
- } elsif (/^-?\d/) {
+ } elsif (/^-?\d+$/) {
print "$sep$_";
} else {
print "$sep\"$_\"";
@@ -892,6 +917,7 @@ sub basic_generator {
my($var_decls) = '';
my($gen_dest_arg) = 'StoreSimpleDest';
my($i);
+ my($no_prefetch) = 0;
# The following argument types should be included as macro arguments.
my(%incl_arg) = ('c' => 1,
@@ -990,6 +1016,7 @@ sub basic_generator {
#
$flags =~ /-fail_action/ and do {
+ $no_prefetch = 1;
if (!defined $fail_type) {
my($i);
for ($i = 0; $i < @f_types; $i++) {
@@ -1036,6 +1063,12 @@ sub basic_generator {
"I += $size + 1;",
"goto $goto;",
"}");
+ } elsif ($no_prefetch) {
+ $code = join("\n",
+ "{ $var_decls",
+ $macro_code,
+ "Next($size);",
+ "}", "");
} else {
$code = join("\n",
"{ $var_decls",
@@ -1057,6 +1090,7 @@ sub do_pack {
my($packable_args) = 0;
my @is_packable; # Packability (boolean) for each argument.
my $wide_packing = 0;
+ my(@orig_args) = @args;
#
# Count the number of packable arguments. If we encounter any 's' or 'd'
@@ -1077,6 +1111,18 @@ sub do_pack {
}
} elsif ($arg =~ /^[sd]/) {
return ('', '', @args);
+ } elsif ($arg =~ /^[scq]/ and $packable_args > 0) {
+ # When packing, this operand will be picked up from the
+ # code array, put onto the packing stack, and later put
+ # back into a different location in the code. The problem
+ # is that if this operand is a literal, the original
+ # location in the code would have been remembered in a
+ # literal patch. For packing to work, we would have to
+ # adjust the position in the literal patch. For the
+ # moment, adding additional instructions to the packing
+ # engine to handle this does not seem worth it, so we will
+ # just turn off packing.
+ return ('', '', @args);
} else {
push @is_packable, 0;
}
@@ -1086,7 +1132,6 @@ sub do_pack {
# Get out of here if too few or too many arguments.
#
return ('', '', @args) if $packable_args < 2;
- &error("too many packable arguments") if $packable_args > 4;
my($size) = 0;
my($pack_prefix) = '';
@@ -1094,14 +1139,8 @@ sub do_pack {
# beginning).
my($up) = ''; # Pack commands (storing back while
# moving forward).
- my $args_per_word;
- if ($packable_args < 4 or $wordsize == 64) {
- $args_per_word = $packable_args;
- } else {
- # 4 packable argument, 32 bit wordsize. Need 2 words.
- $args_per_word = 2;
- }
+ my $args_per_word = $args_per_word[$packable_args];
my @shift;
my @mask;
my @instr;
@@ -1295,6 +1334,8 @@ sub tr_parse_op {
foreach (split('', $type)) {
&error("bad type in $op")
unless defined $type_bit{$_} or $type eq '*';
+ $_ eq 'r' and
+ error("$op: 'r' is not allowed in transformations")
}
}
@@ -1328,7 +1369,10 @@ sub tr_parse_op {
}
# Get an optional value. (In destination.)
+ $type_val = $type eq 'x' ? 1023 : 0;
if (/^=(.*)/) {
+ error("value not allowed in source: $op")
+ if $src;
$type_val = $1;
$_ = '';
}
@@ -1347,11 +1391,6 @@ sub tr_parse_op {
if $var && $type;
}
- # Test that source has no values.
- if ($src) {
- error("value not allowed in source: $op")
- if $type_val;
- }
($var,$type,$type_val,$cond,$cond_val);
}
diff --git a/lib/.gitignore b/lib/.gitignore
index 58c49adce0..b1da61706d 100644
--- a/lib/.gitignore
+++ b/lib/.gitignore
@@ -133,10 +133,12 @@
# mnesia
+/mnesia/doc/src/Mnesia_App_A.xml
/mnesia/doc/src/Mnesia_App_B.xml
/mnesia/doc/src/Mnesia_App_C.xml
/mnesia/doc/src/Mnesia_App_D.xml
/mnesia/doc/src/Mnesia_chap2.xml
+/mnesia/doc/src/Mnesia_chap3.xml
/mnesia/doc/src/Mnesia_chap4.xml
/mnesia/doc/src/Mnesia_chap5.xml
/mnesia/doc/src/Mnesia_chap7.xml
diff --git a/lib/public_key/doc/src/public_key.xml b/lib/public_key/doc/src/public_key.xml
index 394fe54428..209de2bdf7 100644
--- a/lib/public_key/doc/src/public_key.xml
+++ b/lib/public_key/doc/src/public_key.xml
@@ -108,8 +108,9 @@
<p><c>| 'SubjectPublicKeyInfo'</c></p>
<p><c>| 'PrivateKeyInfo'</c></p>
<p><c>| 'CertificationRequest'</c></p>
+ <p><c>| 'CertificateList'</c></p>
<p><c>| 'ECPrivateKey'</c></p>
- <p><c>| 'EcpkParameters'</c></p>
+ <p><c>| 'EcpkParameters'</c></p>
</item>
<tag><c>pem_entry () =</c></tag>
@@ -433,7 +434,7 @@
<name>pkix_is_issuer(Cert, IssuerCert) -> boolean()</name>
<fsummary>Checks if <c>IssuerCert</c> issued <c>Cert</c>.</fsummary>
<type>
- <v>Cert = der_encoded() | #'OTPCertificate'{}</v>
+ <v>Cert = der_encoded() | #'OTPCertificate'{} | #'CertificateList'{}</v>
<v>IssuerCert = der_encoded() | #'OTPCertificate'{}</v>
</type>
<desc>
@@ -698,7 +699,7 @@ fun(#'DistributionPoint'{}, #'CertificateList'{},
<name>pkix_sign(#'OTPTBSCertificate'{}, Key) -> der_encoded()</name>
<fsummary>Signs certificate.</fsummary>
<type>
- <v>Key = rsa_public_key() | dsa_public_key()</v>
+ <v>Key = rsa_private_key() | dsa_private_key()</v>
</type>
<desc>
<p>Signs an 'OTPTBSCertificate'. Returns the corresponding
@@ -713,7 +714,7 @@ fun(#'DistributionPoint'{}, #'CertificateList'{},
<v>AlgorithmId = oid()</v>
<d>Signature OID from a certificate or a certificate revocation list.</d>
<v>DigestType = rsa_digest_type() | dss_digest_type()</v>
- <v>SignatureType = rsa | dsa</v>
+ <v>SignatureType = rsa | dsa | ecdsa</v>
</type>
<desc>
<p>Translates signature algorithm OID to Erlang digest and signature types.
@@ -726,7 +727,7 @@ fun(#'DistributionPoint'{}, #'CertificateList'{},
<fsummary>Verifies PKIX x.509 certificate signature.</fsummary>
<type>
<v>Cert = der_encoded()</v>
- <v>Key = rsa_public_key() | dsa_public_key()</v>
+ <v>Key = rsa_public_key() | dsa_public_key() | ec_public_key()</v>
</type>
<desc>
<p>Verifies PKIX x.509 certificate signature.</p>
diff --git a/lib/runtime_tools/c_src/trace_file_drv.c b/lib/runtime_tools/c_src/trace_file_drv.c
index 7549161e05..a63a7d3ad9 100644
--- a/lib/runtime_tools/c_src/trace_file_drv.c
+++ b/lib/runtime_tools/c_src/trace_file_drv.c
@@ -327,9 +327,11 @@ static ErlDrvData trace_file_start(ErlDrvPort port, char *buff)
| O_BINARY
#endif
, 0777)) < 0) {
+ int saved_errno = errno;
if (wrap)
driver_free(wrap);
driver_free(data);
+ errno = saved_errno;
return ERL_DRV_ERROR_ERRNO;
}
@@ -525,14 +527,19 @@ static void *my_alloc(size_t size)
** A write wrapper that regards it as an error if not all data was written.
*/
static int do_write(FILETYPE fd, unsigned char *buff, int siz) {
- int w = write(fd, buff, siz);
- if (w != siz) {
- if (w >= 0) {
- errno = ENOSPC;
+ int w;
+ while (1) {
+ w = write(fd, buff, siz);
+ if (w < 0 && errno == EINTR)
+ continue;
+ else if (w != siz) {
+ if (w >= 0) {
+ errno = ENOSPC;
+ }
+ return -1;
}
- return -1;
+ return siz;
}
- return siz;
}
/*
@@ -627,8 +634,10 @@ static void close_unlink_port(TraceFileData *data)
*/
static int wrap_file(TraceFileData *data) {
if (my_flush(data) < 0) {
+ int saved_errno = errno;
close(data->fd);
data->fd = -1;
+ errno = saved_errno;
return -1;
}
close(data->fd);
@@ -644,12 +653,15 @@ static int wrap_file(TraceFileData *data) {
next_name(&data->wrap->del);
}
next_name(&data->wrap->cur);
+try_open:
data->fd = open(data->wrap->cur.name, O_WRONLY | O_TRUNC | O_CREAT
#ifdef O_BINARY
| O_BINARY
#endif
, 0777);
if (data->fd < 0) {
+ if (errno == EINTR)
+ goto try_open;
data->fd = -1;
return -1;
}
diff --git a/lib/runtime_tools/doc/src/notes.xml b/lib/runtime_tools/doc/src/notes.xml
index 71b244ec6b..5aebea98ce 100644
--- a/lib/runtime_tools/doc/src/notes.xml
+++ b/lib/runtime_tools/doc/src/notes.xml
@@ -32,6 +32,23 @@
<p>This document describes the changes made to the Runtime_Tools
application.</p>
+<section><title>Runtime_Tools 1.9.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ The <c>trace_file_drv</c> did not handle <c>EINTR</c>
+ correct which caused it to fail when the runtime system
+ received a signal.</p>
+ <p>
+ Own Id: OTP-12890 Aux Id: seq12885 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Runtime_Tools 1.9</title>
<section><title>Improvements and New Features</title>
diff --git a/lib/runtime_tools/vsn.mk b/lib/runtime_tools/vsn.mk
index 3aadc46ab6..83e3612561 100644
--- a/lib/runtime_tools/vsn.mk
+++ b/lib/runtime_tools/vsn.mk
@@ -1 +1 @@
-RUNTIME_TOOLS_VSN = 1.9
+RUNTIME_TOOLS_VSN = 1.9.1
diff --git a/lib/ssh/src/ssh_transport.erl b/lib/ssh/src/ssh_transport.erl
index f4e6a23a1e..2e7391e1f8 100644
--- a/lib/ssh/src/ssh_transport.erl
+++ b/lib/ssh/src/ssh_transport.erl
@@ -246,26 +246,41 @@ handle_kexinit_msg(#ssh_msg_kexinit{} = CounterPart, #ssh_msg_kexinit{} = Own,
Ssh0#ssh{algorithms = Algoritms});
_ ->
%% TODO: Correct code?
- throw(#ssh_msg_disconnect{code = ?SSH_DISCONNECT_PROTOCOL_ERROR,
+ throw(#ssh_msg_disconnect{code = ?SSH_DISCONNECT_KEY_EXCHANGE_FAILED,
description = "Selection of key exchange"
" algorithm failed",
- language = "en"})
+ language = ""})
end;
handle_kexinit_msg(#ssh_msg_kexinit{} = CounterPart, #ssh_msg_kexinit{} = Own,
#ssh{role = server} = Ssh) ->
{ok, Algoritms} = select_algorithm(server, CounterPart, Own),
- {ok, Ssh#ssh{algorithms = Algoritms}}.
+ case verify_algorithm(Algoritms) of
+ true ->
+ {ok, Ssh#ssh{algorithms = Algoritms}};
+ _ ->
+ throw(#ssh_msg_disconnect{code = ?SSH_DISCONNECT_KEY_EXCHANGE_FAILED,
+ description = "Selection of key exchange"
+ " algorithm failed",
+ language = ""})
+ end.
%% TODO: diffie-hellman-group14-sha1 should also be supported.
%% Maybe check more things ...
-verify_algorithm(#alg{kex = 'diffie-hellman-group1-sha1'}) ->
- true;
-verify_algorithm(#alg{kex = 'diffie-hellman-group-exchange-sha1'}) ->
- true;
-verify_algorithm(_) ->
- false.
+
+verify_algorithm(#alg{kex = undefined}) -> false;
+verify_algorithm(#alg{hkey = undefined}) -> false;
+verify_algorithm(#alg{send_mac = undefined}) -> false;
+verify_algorithm(#alg{recv_mac = undefined}) -> false;
+verify_algorithm(#alg{encrypt = undefined}) -> false;
+verify_algorithm(#alg{decrypt = undefined}) -> false;
+verify_algorithm(#alg{compress = undefined}) -> false;
+verify_algorithm(#alg{decompress = undefined}) -> false;
+
+verify_algorithm(#alg{kex = 'diffie-hellman-group1-sha1'}) -> true;
+verify_algorithm(#alg{kex = 'diffie-hellman-group-exchange-sha1'}) -> true;
+verify_algorithm(_) -> false.
key_exchange_first_msg('diffie-hellman-group1-sha1', Ssh0) ->
{G, P} = dh_group1(),
diff --git a/lib/ssh/test/Makefile b/lib/ssh/test/Makefile
index 6503d5b643..47c189c162 100644
--- a/lib/ssh/test/Makefile
+++ b/lib/ssh/test/Makefile
@@ -33,8 +33,10 @@ VSN=$(GS_VSN)
MODULES= \
ssh_test_lib \
+ ssh_trpt_test_lib \
ssh_sup_SUITE \
ssh_basic_SUITE \
+ ssh_protocol_SUITE \
ssh_to_openssh_SUITE \
ssh_sftp_SUITE \
ssh_sftpd_SUITE \
diff --git a/lib/ssh/test/ssh_basic_SUITE.erl b/lib/ssh/test/ssh_basic_SUITE.erl
index 9ff3eb8d0b..bf9fe54c57 100644
--- a/lib/ssh/test/ssh_basic_SUITE.erl
+++ b/lib/ssh/test/ssh_basic_SUITE.erl
@@ -1838,6 +1838,8 @@ check_error("Invalid state") ->
ok;
check_error("Connection closed") ->
ok;
+check_error("Selection of key exchange algorithm failed") ->
+ ok;
check_error(Error) ->
ct:fail(Error).
diff --git a/lib/ssh/test/ssh_protocol_SUITE.erl b/lib/ssh/test/ssh_protocol_SUITE.erl
new file mode 100644
index 0000000000..d82cdaf2c7
--- /dev/null
+++ b/lib/ssh/test/ssh_protocol_SUITE.erl
@@ -0,0 +1,404 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2008-2015. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+
+-module(ssh_protocol_SUITE).
+
+-include_lib("common_test/include/ct.hrl").
+-include_lib("kernel/include/inet.hrl").
+-include_lib("ssh/src/ssh.hrl"). % ?UINT32, ?BYTE, #ssh{} ...
+-include_lib("ssh/src/ssh_transport.hrl").
+-include_lib("ssh/src/ssh_auth.hrl").
+
+%% Note: This directive should only be used in test suites.
+-compile(export_all).
+
+-define(NEWLINE, <<"\r\n">>).
+-define(REKEY_DATA_TMO, 65000).
+
+-define(v(Key, Config), proplists:get_value(Key, Config)).
+-define(v(Key, Config, Default), proplists:get_value(Key, Config, Default)).
+
+
+%%--------------------------------------------------------------------
+%% Common Test interface functions -----------------------------------
+%%--------------------------------------------------------------------
+
+suite() ->
+ [{ct_hooks,[ts_install_cth]}].
+
+all() ->
+ [{group,tool_tests},
+ {group,kex}
+ ].
+
+groups() ->
+ [{tool_tests, [], [lib_works_as_client,
+ lib_works_as_server,
+ lib_match,
+ lib_no_match
+ ]},
+ {kex, [], [no_common_alg_server_disconnects,
+ no_common_alg_client_disconnects
+ ]}
+ ].
+
+
+init_per_suite(Config) ->
+ start_std_daemon( setup_dirs( start_apps(Config))).
+
+end_per_suite(Config) ->
+ stop_apps(Config).
+
+
+init_per_testcase(_TestCase, Config) ->
+ check_std_daemon_works(Config, ?LINE).
+
+end_per_testcase(_TestCase, Config) ->
+ check_std_daemon_works(Config, ?LINE).
+
+
+%%%--------------------------------------------------------------------
+%%% Test Cases --------------------------------------------------------
+%%%--------------------------------------------------------------------
+
+%%%--------------------------------------------------------------------
+%%% Connect to an erlang server and check that the testlib acts as a client.
+lib_works_as_client(Config) ->
+ %% Connect and negotiate keys
+ {ok,InitialState} =
+ ssh_trpt_test_lib:exec(
+ [{set_options, [print_ops, print_seqnums, print_messages]},
+ {connect,
+ server_host(Config),server_port(Config),
+ [{silently_accept_hosts, true},
+ {user_dir, user_dir(Config)},
+ {user_interaction, false}]},
+ receive_hello,
+ {send, hello},
+ {send, ssh_msg_kexinit},
+ {match, #ssh_msg_kexinit{_='_'}, receive_msg},
+ {send, ssh_msg_kexdh_init},
+ {match,# ssh_msg_kexdh_reply{_='_'}, receive_msg},
+ {send, #ssh_msg_newkeys{}},
+ {match, #ssh_msg_newkeys{_='_'}, receive_msg}
+ ]
+ ),
+
+ %% Do the authentcation
+ {User,Pwd} = server_user_password(Config),
+ {ok,EndState} =
+ ssh_trpt_test_lib:exec(
+ [{send, #ssh_msg_service_request{name = "ssh-userauth"}},
+ {match, #ssh_msg_service_accept{name = "ssh-userauth"}, receive_msg},
+ {send, #ssh_msg_userauth_request{user = User,
+ service = "ssh-connection",
+ method = "password",
+ data = <<?BOOLEAN(?FALSE),
+ ?STRING(unicode:characters_to_binary(Pwd))>>
+ }},
+ {match, #ssh_msg_userauth_success{_='_'}, receive_msg}
+ ], InitialState),
+
+ %% Disconnect
+ {ok,_} =
+ ssh_trpt_test_lib:exec(
+ [{send, #ssh_msg_disconnect{code = ?SSH_DISCONNECT_BY_APPLICATION,
+ description = "End of the fun",
+ language = ""
+ }},
+ close_socket
+ ], EndState).
+
+
+%%--------------------------------------------------------------------
+%%% Connect an erlang client and check that the testlib can act as a server.
+lib_works_as_server(Config) ->
+ {User,_Pwd} = server_user_password(Config),
+
+ %% Create a listening socket as server socket:
+ {ok,InitialState} = ssh_trpt_test_lib:exec(listen),
+ HostPort = ssh_trpt_test_lib:server_host_port(InitialState),
+
+ %% Start a process handling one connection on the server side:
+ spawn_link(
+ fun() ->
+ {ok,_} =
+ ssh_trpt_test_lib:exec(
+ [{set_options, [print_ops, print_messages]},
+ {accept, [{system_dir, system_dir(Config)},
+ {user_dir, user_dir(Config)}]},
+ receive_hello,
+ {send, hello},
+
+ {send, ssh_msg_kexinit},
+ {match, #ssh_msg_kexinit{_='_'}, receive_msg},
+
+ {match, #ssh_msg_kexdh_init{_='_'}, receive_msg},
+ {send, ssh_msg_kexdh_reply},
+
+ {send, #ssh_msg_newkeys{}},
+ {match, #ssh_msg_newkeys{_='_'}, receive_msg},
+
+ {match, #ssh_msg_service_request{name="ssh-userauth"}, receive_msg},
+ {send, #ssh_msg_service_accept{name="ssh-userauth"}},
+
+ {match, #ssh_msg_userauth_request{service="ssh-connection",
+ method="none",
+ user=User,
+ _='_'}, receive_msg},
+
+ {send, #ssh_msg_userauth_failure{authentications = "password",
+ partial_success = false}},
+
+ {match, #ssh_msg_userauth_request{service="ssh-connection",
+ method="password",
+ user=User,
+ _='_'}, receive_msg},
+ {send, #ssh_msg_userauth_success{}},
+ close_socket,
+ print_state
+ ],
+ InitialState)
+ end),
+
+ %% and finally connect to it with a regular Erlang SSH client:
+ {ok,_} = std_connect(HostPort, Config).
+
+%%--------------------------------------------------------------------
+%%% Matching
+lib_match(_Config) ->
+ {ok,_} =
+ ssh_trpt_test_lib:exec([{set_options, [print_ops]},
+ {match, abc, abc},
+ {match, '$a', {cde,fgh}},
+ {match, {cde,fgh}, '$a'},
+ {match, '_', {cde,fgh}},
+ {match, [a,'$a',b], [a,{cde,fgh},b]},
+ {match, [a,'$a'|'$b'], [a,{cde,fgh},b,c]},
+ {match, '$b', [b,c]}
+ ]).
+
+%%--------------------------------------------------------------------
+%%% Not matching
+lib_no_match(_Config) ->
+ case ssh_trpt_test_lib:exec([{set_options, [print_ops]},
+ {match, '$x', b},
+ {match, a, '$x'}])
+ of
+ {ok,_} -> {fail,"Unexpected match"};
+ {error, {_Op,{expected,a,b},_State}} -> ok
+ end.
+
+%%--------------------------------------------------------------------
+%%% Algo negotiation fail. This should result in a ssh_msg_disconnect
+%%% being sent from the server.
+no_common_alg_server_disconnects(Config) ->
+ {ok,_} =
+ ssh_trpt_test_lib:exec(
+ [{set_options, [print_ops, print_seqnums, print_messages]},
+ {connect,
+ server_host(Config),server_port(Config),
+ [{silently_accept_hosts, true},
+ {user_dir, user_dir(Config)},
+ {user_interaction, false},
+ {preferred_algorithms,[{public_key,['ssh-dss']}]}
+ ]},
+ receive_hello,
+ {send, hello},
+ {match, #ssh_msg_kexinit{_='_'}, receive_msg},
+ {send, ssh_msg_kexinit},
+ {match,
+ {'or',[#ssh_msg_disconnect{code = ?SSH_DISCONNECT_KEY_EXCHANGE_FAILED, _='_'},
+ tcp_closed]},
+ receive_msg}
+ ]
+ ).
+
+%%--------------------------------------------------------------------
+%%% Algo negotiation fail. This should result in a ssh_msg_disconnect
+%%% being sent from the client.
+no_common_alg_client_disconnects(Config) ->
+ %% Create a listening socket as server socket:
+ {ok,InitialState} = ssh_trpt_test_lib:exec(listen),
+ HostPort = ssh_trpt_test_lib:server_host_port(InitialState),
+ Parent = self(),
+
+ %% Start a process handling one connection on the server side:
+ Pid =
+ spawn_link(
+ fun() ->
+ Parent !
+ {result,self(),
+ ssh_trpt_test_lib:exec(
+ [{set_options, [print_ops, print_messages]},
+ {accept, [{system_dir, system_dir(Config)},
+ {user_dir, user_dir(Config)}]},
+ receive_hello,
+ {send, hello},
+
+ {match, #ssh_msg_kexinit{_='_'}, receive_msg},
+ {send, #ssh_msg_kexinit{
+ cookie = 247381486335508958743193106082599558706,
+ kex_algorithms = ["diffie-hellman-group1-sha1"],
+ server_host_key_algorithms = ["some-unknown"],
+ encryption_algorithms_client_to_server = ["aes128-ctr"],
+ encryption_algorithms_server_to_client = ["aes128-ctr"],
+ mac_algorithms_client_to_server = ["hmac-sha2-256"],
+ mac_algorithms_server_to_client = ["hmac-sha2-256"],
+ compression_algorithms_client_to_server = ["none"],
+ compression_algorithms_server_to_client = ["none"],
+ languages_client_to_server = [],
+ languages_server_to_client = [],
+ first_kex_packet_follows = false,
+ reserved = 0
+ }},
+ {match,
+ {'or',[#ssh_msg_disconnect{code = ?SSH_DISCONNECT_KEY_EXCHANGE_FAILED, _='_'},
+ tcp_closed]},
+ receive_msg}
+ ],
+ InitialState)
+ }
+ end),
+
+ %% and finally connect to it with a regular Erlang SSH client:
+ Result = std_connect(HostPort, Config, [{preferred_algorithms,[{public_key,['ssh-dss']}]}]),
+ ct:log("Result of connect is ~p",[Result]),
+
+ receive
+ {result,Pid,{ok,_}} ->
+ ok;
+ {result,Pid,{error,{Op,ExecResult,S}}} ->
+ ct:pal("ERROR!~nOp = ~p~nExecResult = ~p~nState =~n~s",
+ [Op,ExecResult,ssh_trpt_test_lib:format_msg(S)]),
+ {fail, ExecResult};
+ X -> ct:fail(X)
+ end.
+
+%%%================================================================
+%%%==== Internal functions ========================================
+%%%================================================================
+
+%%%---- init_suite and end_suite ---------------------------------------
+start_apps(Config) ->
+ catch crypto:stop(),
+ case catch crypto:start() of
+ ok ->
+ catch ssh:stop(),
+ ok = ssh:start(),
+ [{stop_apps,
+ fun() ->
+ ssh:stop(),
+ crypto:stop()
+ end} | Config];
+ _Else ->
+ {skip, "Crypto could not be started!"}
+ end.
+
+
+stop_apps(Config) ->
+ (?v(stop_apps, Config, fun()-> ok end))(),
+ ssh:stop().
+
+
+setup_dirs(Config) ->
+ DataDir = ?config(data_dir, Config),
+ PrivDir = ?config(priv_dir, Config),
+ ssh_test_lib:setup_rsa(DataDir, PrivDir),
+ Config.
+
+system_dir(Config) -> filename:join(?config(priv_dir, Config), system).
+
+user_dir(Config) -> ?config(priv_dir, Config).
+
+%%%----------------------------------------------------------------
+start_std_daemon(Config) ->
+ start_std_daemon(Config, []).
+
+start_std_daemon(Config, ExtraOpts) ->
+ PrivDir = ?config(priv_dir, Config),
+ UserDir = filename:join(PrivDir, nopubkey), % to make sure we don't use public-key-auth
+ file:make_dir(UserDir),
+ UserPasswords = [{"user1","pwd1"}],
+ Options = [{system_dir, system_dir(Config)},
+ {user_dir, user_dir(Config)},
+ {user_passwords, UserPasswords},
+ {failfun, fun ssh_test_lib:failfun/2}
+ | ExtraOpts],
+ Ref = {Server, Host, Port} = ssh_test_lib:daemon(Options),
+ ct:log("Std server ~p started at ~p:~p~nOptions=~p",[Server, Host, Port, Options]),
+ [{server,Ref}, {user_passwords, UserPasswords} | Config].
+
+
+stop_std_daemon(Config) ->
+ ssh:stop_daemon(server_pid(Config)),
+ ct:log("Std server ~p at ~p:~p stopped", [server_pid(Config), server_host(Config), server_port(Config)]),
+ lists:keydelete(server, 1, Config).
+
+check_std_daemon_works(Config, Line) ->
+ case std_connect(Config) of
+ {ok,C} ->
+ ct:log("Server ~p:~p ~p is ok at line ~p",
+ [server_host(Config), server_port(Config),
+ server_pid(Config), Line]),
+ ok = ssh:close(C),
+ Config;
+ Error = {error,_} ->
+ {fail,
+ lists:flatten(
+ io_lib:format("Standard server ~p:~p ~p is ill at line ~p: ~p",
+ [server_host(Config), server_port(Config),
+ server_pid(Config), Line, Error])
+ )
+ }
+ end.
+
+server_pid(Config) -> element(1,?v(server,Config)).
+server_host(Config) -> element(2,?v(server,Config)).
+server_port(Config) -> element(3,?v(server,Config)).
+
+server_user_password(Config) -> server_user_password(1, Config).
+
+server_user_password(N, Config) -> lists:nth(N, ?v(user_passwords,Config)).
+
+
+std_connect(Config) ->
+ {User,Pwd} = server_user_password(Config),
+ std_connect(server_host(Config), server_port(Config),
+ Config,
+ [{user,User},{password,Pwd}]).
+
+std_connect({Host,Port}, Config) ->
+ {User,Pwd} = server_user_password(Config),
+ std_connect(Host, Port, Config, [{user,User},{password,Pwd}]).
+
+std_connect({Host,Port}, Config, Opts) ->
+ std_connect(Host, Port, Config, Opts).
+
+std_connect(Host, Port, Config, Opts) ->
+ ssh:connect(Host, Port,
+ [{silently_accept_hosts, true},
+ {user_dir, user_dir(Config)},
+ {user_interaction, false} | Opts],
+ 30000).
+
+
+%%%----------------------------------------------------------------
diff --git a/lib/ssh/test/ssh_protocol_SUITE_data/id_dsa b/lib/ssh/test/ssh_protocol_SUITE_data/id_dsa
new file mode 100644
index 0000000000..d306f8b26e
--- /dev/null
+++ b/lib/ssh/test/ssh_protocol_SUITE_data/id_dsa
@@ -0,0 +1,13 @@
+-----BEGIN DSA PRIVATE KEY-----
+MIIBvAIBAAKBgQDfi2flSTZZofwT4yQT0NikX/LGNT7UPeB/XEWe/xovEYCElfaQ
+APFixXvEgXwoojmZ5kiQRKzLM39wBP0jPERLbnZXfOOD0PDnw0haMh7dD7XKVMod
+/EigVgHf/qBdM2M8yz1s/rRF7n1UpLSypziKjkzCm7JoSQ2zbWIPdmBIXwIVAMgP
+kpr7Sq3O7sHdb8D601DRjoExAoGAMOQxDfB2Fd8ouz6G96f/UOzRMI/Kdv8kYYKW
+JIGY+pRYrLPyYzUeJznwZreOJgrczAX+luHnKFWJ2Dnk5CyeXk67Wsr7pJ/4MBMD
+OKeIS0S8qoSBN8+Krp79fgA+yS3IfqbkJLtLu4EBaCX4mKQIX4++k44d4U5lc8pt
++9hlEI8CgYEAznKxx9kyC6bVo7LUYKaGhofRFt0SYFc5PVmT2VUGRs1R6+6DPD+e
+uEO6IhFct7JFSRbP9p0JD4Uk+3zlZF+XX6b2PsZkeV8f/02xlNGUSmEzCSiNg1AX
+Cy/WusYhul0MncWCHMcOZB5rIvU/aP5EJJtn3xrRaz6u0SThF6AnT34CFQC63czE
+ZU8w8Q+H7z0j+a+70x2iAw==
+-----END DSA PRIVATE KEY-----
+
diff --git a/lib/ssh/test/ssh_protocol_SUITE_data/id_rsa b/lib/ssh/test/ssh_protocol_SUITE_data/id_rsa
new file mode 100644
index 0000000000..9d7e0dd5fb
--- /dev/null
+++ b/lib/ssh/test/ssh_protocol_SUITE_data/id_rsa
@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXAIBAAKBgQD1OET+3O/Bvj/dtjxDTXmj1oiJt4sIph5kGy0RfjoPrZfaS+CU
+DhakCmS6t2ivxWFgtpKWaoGMZMJqWj6F6ZsumyFl3FPBtujwY/35cgifrI9Ns4Tl
+zR1uuengNBmV+WRQ5cd9F2qS6Z8aDQihzt0r8JUqLcK+VQbrmNzboCCQQwIDAQAB
+AoGAPQEyqPTt8JUT7mRXuaacjFXiweAXhp9NEDpyi9eLOjtFe9lElZCrsUOkq47V
+TGUeRKEm9qSodfTbKPoqc8YaBJGJPhUaTAcha+7QcDdfHBvIsgxvU7ePVnlpXRp3
+CCUEMPhlnx6xBoTYP+fRU0e3+xJIPVyVCqX1jAdUMkzfRoECQQD6ux7B1QJAIWyK
+SGkbDUbBilNmzCFNgIpOP6PA+bwfi5d16diTpra5AX09keQABAo/KaP1PdV8Vg0p
+z4P3A7G3AkEA+l+AKG6m0kQTTBMJDqOdVPYwe+5GxunMaqmhokpEbuGsrZBl5Dvd
+WpcBjR7jmenrhKZRIuA+Fz5HPo/UQJPl1QJBAKxstDkeED8j/S2XoFhPKAJ+6t39
+sUVICVTIZQeXdmzHJXCcUSkw8+WEhakqw/3SyW0oaK2FSWQJFWJUZ+8eJj8CQEh3
+xeduB5kKnS9CvzdeghZqX6QvVosSdtlUmfUYW/BgH5PpHKTP8wTaeld3XldZTpMJ
+dKiMkUw2+XYROVUrubUCQD+Na1LhULlpn4ISEtIEfqpdlUhxDgO15Wg8USmsng+x
+ICliVOSQtwaZjm8kwaFt0W7XnpnDxbRs37vIEbIMWak=
+-----END RSA PRIVATE KEY-----
diff --git a/lib/ssh/test/ssh_protocol_SUITE_data/ssh_host_dsa_key b/lib/ssh/test/ssh_protocol_SUITE_data/ssh_host_dsa_key
new file mode 100644
index 0000000000..51ab6fbd88
--- /dev/null
+++ b/lib/ssh/test/ssh_protocol_SUITE_data/ssh_host_dsa_key
@@ -0,0 +1,13 @@
+-----BEGIN DSA PRIVATE KEY-----
+MIIBuwIBAAKBgQCClaHzE2ul0gKSUxah5W0W8UiJLy4hXngKEqpaUq9SSdVdY2LK
+wVfKH1gt5iuaf1FfzOhsIC9G/GLnjYttXZc92cv/Gfe3gR+s0ni2++MX+T++mE/Q
+diltXv/Hp27PybS67SmiFW7I+RWnT2OKlMPtw2oUuKeztCe5UWjaj/y5FQIVAPLA
+l9RpiU30Z87NRAHY3NTRaqtrAoGANMRxw8UfdtNVR0CrQj3AgPaXOGE4d+G4Gp4X
+skvnCHycSVAjtYxebUkzUzt5Q6f/IabuLUdge3gXrc8BetvrcKbp+XZgM0/Vj2CF
+Ymmy3in6kzGZq7Fw1sZaku6AOU8vLa5woBT2vAcHLLT1bLAzj7viL048T6MfjrOP
+ef8nHvACgYBhDWFQJ1mf99sg92LalVq1dHLmVXb3PTJDfCO/Gz5NFmj9EZbAtdah
+/XcF3DeRF+eEoz48wQF/ExVxSMIhLdL+o+ElpVhlM7Yii+T7dPhkQfEul6zZXu+U
+ykSTXYUbtsfTNRFQGBW2/GfnEc0mnIxfn9v10NEWMzlq5z9wT9P0CgIVAN4wtL5W
+Lv62jKcdskxNyz2NQoBx
+-----END DSA PRIVATE KEY-----
+
diff --git a/lib/ssh/test/ssh_protocol_SUITE_data/ssh_host_dsa_key.pub b/lib/ssh/test/ssh_protocol_SUITE_data/ssh_host_dsa_key.pub
new file mode 100644
index 0000000000..4dbb1305b0
--- /dev/null
+++ b/lib/ssh/test/ssh_protocol_SUITE_data/ssh_host_dsa_key.pub
@@ -0,0 +1,11 @@
+---- BEGIN SSH2 PUBLIC KEY ----
+AAAAB3NzaC1kc3MAAACBAIKVofMTa6XSApJTFqHlbRbxSIkvLiFeeAoSqlpSr1JJ1V1j
+YsrBV8ofWC3mK5p/UV/M6GwgL0b8YueNi21dlz3Zy/8Z97eBH6zSeLb74xf5P76YT9B2
+KW1e/8enbs/JtLrtKaIVbsj5FadPY4qUw+3DahS4p7O0J7lRaNqP/LkVAAAAFQDywJfU
+aYlN9GfOzUQB2NzU0WqrawAAAIA0xHHDxR9201VHQKtCPcCA9pc4YTh34bganheyS+cI
+fJxJUCO1jF5tSTNTO3lDp/8hpu4tR2B7eBetzwF62+twpun5dmAzT9WPYIViabLeKfqT
+MZmrsXDWxlqS7oA5Ty8trnCgFPa8BwcstPVssDOPu+IvTjxPox+Os495/yce8AAAAIBh
+DWFQJ1mf99sg92LalVq1dHLmVXb3PTJDfCO/Gz5NFmj9EZbAtdah/XcF3DeRF+eEoz48
+wQF/ExVxSMIhLdL+o+ElpVhlM7Yii+T7dPhkQfEul6zZXu+UykSTXYUbtsfTNRFQGBW2
+/GfnEc0mnIxfn9v10NEWMzlq5z9wT9P0Cg==
+---- END SSH2 PUBLIC KEY ----
diff --git a/lib/ssh/test/ssh_protocol_SUITE_data/ssh_host_rsa_key b/lib/ssh/test/ssh_protocol_SUITE_data/ssh_host_rsa_key
new file mode 100644
index 0000000000..79968bdd7d
--- /dev/null
+++ b/lib/ssh/test/ssh_protocol_SUITE_data/ssh_host_rsa_key
@@ -0,0 +1,16 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXQIBAAKBgQDCZX+4FBDwZIh9y/Uxee1VJnEXlowpz2yDKwj8semM4q843337
+zbNfxHmladB1lpz2NqyxI175xMIJuDxogyZdsOxGnFAzAnthR4dqL/RWRWzjaxSB
+6IAO9SPYVVlrpZ+1hsjLW79fwXK/yc8VdhRuWTeQiRgYY2ek8+OKbOqz4QIDAQAB
+AoGANmvJzJO5hkLuvyDZHKfAnGTtpifcR1wtSa9DjdKUyn8vhKF0mIimnbnYQEmW
+NUUb3gXCZLi9PvkpRSVRrASDOZwcjoU/Kvww163vBUVb2cOZfFhyn6o2Sk88Tt++
+udH3hdjpf9i7jTtUkUe+QYPsia+wgvvrmn4QrahLAH86+kECQQDx5gFeXTME3cnW
+WMpFz3PPumduzjqgqMMWEccX4FtQkMX/gyGa5UC7OHFyh0N/gSWvPbRHa8A6YgIt
+n8DO+fh5AkEAzbqX4DOn8NY6xJIi42q7l/2jIA0RkB6P7YugW5NblhqBZ0XDnpA5
+sMt+rz+K07u9XZtxgh1xi7mNfwY6lEAMqQJBAJBEauCKmRj35Z6OyeQku59SPsnY
++SJEREVvSNw2lH9SOKQQ4wPsYlTGbvKtNVZgAcen91L5MmYfeckYE/fdIZECQQCt
+64zxsTnM1I8iFxj/gP/OYlJBikrKt8udWmjaghzvLMEw+T2DExJyb9ZNeT53+UMB
+m6O+B/4xzU/djvp+0hbhAkAemIt+rA5kTmYlFndhpvzkSSM8a2EXsO4XIPgGWCTT
+tQKS/tTly0ADMjN/TVy11+9d6zcqadNVuHXHGtR4W0GR
+-----END RSA PRIVATE KEY-----
+
diff --git a/lib/ssh/test/ssh_protocol_SUITE_data/ssh_host_rsa_key.pub b/lib/ssh/test/ssh_protocol_SUITE_data/ssh_host_rsa_key.pub
new file mode 100644
index 0000000000..75d2025c71
--- /dev/null
+++ b/lib/ssh/test/ssh_protocol_SUITE_data/ssh_host_rsa_key.pub
@@ -0,0 +1,5 @@
+---- BEGIN SSH2 PUBLIC KEY ----
+AAAAB3NzaC1yc2EAAAADAQABAAAAgQDCZX+4FBDwZIh9y/Uxee1VJnEXlowpz2yDKwj8
+semM4q843337zbNfxHmladB1lpz2NqyxI175xMIJuDxogyZdsOxGnFAzAnthR4dqL/RW
+RWzjaxSB6IAO9SPYVVlrpZ+1hsjLW79fwXK/yc8VdhRuWTeQiRgYY2ek8+OKbOqz4Q==
+---- END SSH2 PUBLIC KEY ----
diff --git a/lib/ssh/test/ssh_trpt_test_lib.erl b/lib/ssh/test/ssh_trpt_test_lib.erl
new file mode 100644
index 0000000000..75f495b6d7
--- /dev/null
+++ b/lib/ssh/test/ssh_trpt_test_lib.erl
@@ -0,0 +1,700 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2004-2015. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+%%
+
+-module(ssh_trpt_test_lib).
+
+%%-compile(export_all).
+
+-export([exec/1, exec/2,
+ format_msg/1,
+ server_host_port/1
+ ]
+ ).
+
+-include_lib("common_test/include/ct.hrl").
+-include_lib("ssh/src/ssh.hrl"). % ?UINT32, ?BYTE, #ssh{} ...
+-include_lib("ssh/src/ssh_transport.hrl").
+-include_lib("ssh/src/ssh_auth.hrl").
+
+%%%----------------------------------------------------------------
+-record(s, {
+ socket,
+ listen_socket,
+ opts = [],
+ timeout = 5000, % ms
+ seen_hello = false,
+ enc = <<>>,
+ ssh = #ssh{}, % #ssh{}
+ own_kexinit,
+ peer_kexinit,
+ vars = dict:new(),
+ reply = [], % Some repy msgs are generated hidden in ssh_transport :[
+ prints = [],
+ return_value
+ }).
+
+-define(role(S), ((S#s.ssh)#ssh.role) ).
+
+
+server_host_port(S=#s{}) ->
+ {Host,Port} = ok(inet:sockname(S#s.listen_socket)),
+ {host(Host), Port}.
+
+
+%%% Options: {print_messages, false} true|detail
+%%% {print_seqnums,false} true
+%%% {print_ops,false} true
+
+exec(L) -> exec(L, #s{}).
+
+exec(L, S) when is_list(L) -> lists:foldl(fun exec/2, S, L);
+
+exec(Op, S0=#s{}) ->
+ S1 = init_op_traces(Op, S0),
+ try seqnum_trace(
+ op(Op, S1))
+ of
+ S = #s{} ->
+ print_traces(S),
+ {ok,S}
+ catch
+ {fail,Reason,Se} ->
+ report_trace('', Reason, Se),
+ {error,{Op,Reason,Se}};
+
+ throw:Term ->
+ report_trace(throw, Term, S1),
+ throw(Term);
+
+ error:Error ->
+ report_trace(error, Error, S1),
+ error(Error);
+
+ exit:Exit ->
+ report_trace(exit, Exit, S1),
+ exit(Exit)
+ end;
+exec(Op, {ok,S=#s{}}) -> exec(Op, S);
+exec(_, Error) -> Error.
+
+
+%%%---- Server ops
+op(listen, S) when ?role(S) == undefined -> op({listen,0}, S);
+
+op({listen,Port}, S) when ?role(S) == undefined ->
+ S#s{listen_socket = ok(gen_tcp:listen(Port, mangle_opts([]))),
+ ssh = (S#s.ssh)#ssh{role=server}
+ };
+
+op({accept,Opts}, S) when ?role(S) == server ->
+ {ok,Socket} = gen_tcp:accept(S#s.listen_socket, S#s.timeout),
+ {Host,_Port} = ok(inet:sockname(Socket)),
+ S#s{socket = Socket,
+ ssh = init_ssh(server,Socket,[{host,host(Host)}|Opts]),
+ return_value = ok};
+
+%%%---- Client ops
+op({connect,Host,Port,Opts}, S) when ?role(S) == undefined ->
+ Socket = ok(gen_tcp:connect(host(Host), Port, mangle_opts([]))),
+ S#s{socket = Socket,
+ ssh = init_ssh(client, Socket, [{host,host(Host)}|Opts]),
+ return_value = ok};
+
+%%%---- ops for both client and server
+op(close_socket, S) ->
+ catch tcp_gen:close(S#s.socket),
+ catch tcp_gen:close(S#s.listen_socket),
+ S#s{socket = undefined,
+ listen_socket = undefined,
+ return_value = ok};
+
+op({set_options,Opts}, S) ->
+ S#s{opts = Opts};
+
+op({send,X}, S) ->
+ send(S, instantiate(X,S));
+
+op(receive_hello, S0) when S0#s.seen_hello =/= true ->
+ case recv(S0) of
+ S1=#s{return_value={hello,_}} -> S1;
+ S1=#s{} -> op(receive_hello, receive_wait(S1))
+ end;
+
+op(receive_msg, S) when S#s.seen_hello == true ->
+ try recv(S)
+ catch
+ {tcp,Exc} -> S#s{return_value=Exc}
+ end;
+
+
+op({expect,timeout,E}, S0) ->
+ try op(E, S0)
+ of
+ S=#s{} -> fail({expected,timeout,S#s.return_value}, S)
+ catch
+ {receive_timeout,_} -> S0#s{return_value=timeout}
+ end;
+
+op({match,M,E}, S0) ->
+ {Val,S2} = op_val(E, S0),
+ case match(M, Val, S2) of
+ {true,S3} ->
+ opt(print_ops,S3,
+ fun(true) ->
+ case dict:fold(
+ fun(K,V,Acc) ->
+ case dict:find(K,S0#s.vars) of
+ error -> [{K,V}|Acc];
+ _ -> Acc
+ end
+ end, [], S3#s.vars)
+ of
+ [] -> {"Matches! No new bindings.",[]};
+ New ->
+ Width = lists:max([length(atom_to_list(K)) || {K,_} <- New]),
+ {lists:flatten(
+ ["Matches! New bindings:~n" |
+ [io_lib:format(" ~*s = ~p~n",[Width,K,V]) || {K,V}<-New]]),
+ []}
+ end
+ end);
+ false ->
+ fail({expected,M,Val},
+ opt(print_ops,S2,fun(true) -> {"nomatch!!~n",[]} end)
+ )
+ end;
+
+op({print,E}, S0) ->
+ {Val,S} = op_val(E, S0),
+ io:format("Result of ~p ~p =~n~s~n",[?role(S0),E,format_msg(Val)]),
+ S;
+
+op(print_state, S) ->
+ io:format("State(~p)=~n~s~n",[?role(S), format_msg(S)]),
+ S;
+
+op('$$', S) ->
+ %% For matching etc
+ S.
+
+
+op_val(E, S0) ->
+ case catch op(E, S0) of
+ {'EXIT',{function_clause,[{ssh_trpt_test_lib,op,[E,S0],_}|_]}} ->
+ {instantiate(E,S0), S0};
+ S=#s{} ->
+ {S#s.return_value, S};
+ F={fail,receive_timeout,_St} ->
+ throw(F)
+ end.
+
+
+fail(Reason, S) ->
+ throw({fail, Reason, S}).
+
+%%%----------------------------------------------------------------
+%% No optimizations :)
+
+match('$$', V, S) ->
+ match(S#s.return_value, V, S);
+
+match('_', _, S) ->
+ {true, S};
+
+match({'or',[P]}, V, S) -> match(P,V,S);
+match({'or',[Ph|Pt]}, V, S) ->
+ case match(Ph,V,S) of
+ false -> match({'or',Pt}, V, S);
+ {true,S} -> {true,S}
+ end;
+
+match(P, V, S) when is_atom(P) ->
+ case atom_to_list(P) of
+ "$"++_ ->
+ %% Variable
+ case dict:find(P,S#s.vars) of
+ {ok,Val} -> match(Val, V, S);
+ error -> {true,S#s{vars = dict:store(P,V,S#s.vars)}}
+ end;
+ _ when P==V ->
+ {true,S};
+ _ ->
+ false
+ end;
+
+match(P, V, S) when P==V ->
+ {true, S};
+
+match(P, V, S) when is_tuple(P),
+ is_tuple(V) ->
+ match(tuple_to_list(P), tuple_to_list(V), S);
+
+match([Hp|Tp], [Hv|Tv], S0) ->
+ case match(Hp, Hv, S0) of
+ {true,S} -> match(Tp, Tv, S);
+ false -> false
+ end;
+
+match(_, _, _) ->
+ false.
+
+
+
+instantiate('$$', S) ->
+ S#s.return_value; % FIXME: What if $$ or $... in return_value?
+
+instantiate(A, S) when is_atom(A) ->
+ case atom_to_list(A) of
+ "$"++_ ->
+ %% Variable
+ case dict:find(A,S#s.vars) of
+ {ok,Val} -> Val; % FIXME: What if $$ or $... in Val?
+ error -> throw({unbound,A})
+ end;
+ _ ->
+ A
+ end;
+
+instantiate(T, S) when is_tuple(T) ->
+ list_to_tuple( instantiate(tuple_to_list(T),S) );
+
+instantiate([H|T], S) ->
+ [instantiate(H,S) | instantiate(T,S)];
+
+instantiate(X, _S) ->
+ X.
+
+%%%================================================================
+%%%
+init_ssh(Role, Socket, Options0) ->
+ Options = [{user_interaction,false}
+ | Options0],
+ ssh_connection_handler:init_ssh(Role,
+ {2,0},
+ lists:concat(["SSH-2.0-ErlangTestLib ",Role]),
+ Options, Socket).
+
+mangle_opts(Options) ->
+ SysOpts = [{reuseaddr, true},
+ {active, false},
+ {mode, binary}
+ ],
+ SysOpts ++ lists:foldl(fun({K,_},Opts) ->
+ lists:keydelete(K,1,Opts)
+ end, Options, SysOpts).
+
+host({0,0,0,0}) -> "localhost";
+host(H) -> H.
+
+%%%----------------------------------------------------------------
+send(S=#s{ssh=C}, hello) ->
+ Hello = case ?role(S) of
+ client -> C#ssh.c_version;
+ server -> C#ssh.s_version
+ end ++ "\r\n",
+ send(S, list_to_binary(Hello));
+
+send(S0, ssh_msg_kexinit) ->
+ {Msg, Bytes, C0} = ssh_transport:key_exchange_init_msg(S0#s.ssh),
+ S1 = opt(print_messages, S0,
+ fun(X) when X==true;X==detail -> {"Send~n~s~n",[format_msg(Msg)]} end),
+ S = case ?role(S1) of
+ server when is_record(S1#s.peer_kexinit, ssh_msg_kexinit) ->
+ {ok, C} =
+ ssh_transport:handle_kexinit_msg(S1#s.peer_kexinit, Msg, C0),
+ S1#s{peer_kexinit = used,
+ own_kexinit = used,
+ ssh = C};
+ _ ->
+ S1#s{ssh = C0,
+ own_kexinit = Msg}
+ end,
+ send_bytes(Bytes, S#s{return_value = Msg});
+
+send(S0, ssh_msg_kexdh_init) when ?role(S0) == client,
+ is_record(S0#s.peer_kexinit, ssh_msg_kexinit),
+ is_record(S0#s.own_kexinit, ssh_msg_kexinit) ->
+ {ok, NextKexMsgBin, C} =
+ ssh_transport:handle_kexinit_msg(S0#s.peer_kexinit, S0#s.own_kexinit, S0#s.ssh),
+
+ S = opt(print_messages, S0,
+ fun(X) when X==true;X==detail ->
+ #ssh{keyex_key = {{_Private, Public}, {_G, _P}}} = C,
+ Msg = #ssh_msg_kexdh_init{e = Public},
+ {"Send (reconstructed)~n~s~n",[format_msg(Msg)]}
+ end),
+
+ send_bytes(NextKexMsgBin, S#s{ssh = C,
+ peer_kexinit = used,
+ own_kexinit = used});
+
+send(S0, ssh_msg_kexdh_reply) ->
+ Bytes = proplists:get_value(ssh_msg_kexdh_reply, S0#s.reply),
+ S = opt(print_messages, S0,
+ fun(X) when X==true;X==detail ->
+ {{_Private, Public}, _} = (S0#s.ssh)#ssh.keyex_key,
+ Msg = #ssh_msg_kexdh_reply{public_host_key = 'Key',
+ f = Public,
+ h_sig = 'H_SIG'
+ },
+ {"Send (reconstructed)~n~s~n",[format_msg(Msg)]}
+ end),
+ send_bytes(Bytes, S#s{return_value = Bytes});
+
+send(S0, Line) when is_binary(Line) ->
+ S = opt(print_messages, S0,
+ fun(X) when X==true;X==detail -> {"Send line~n~p~n",[Line]} end),
+ send_bytes(Line, S#s{return_value = Line});
+
+%%% Msg = #ssh_msg_*{}
+send(S0, Msg) when is_tuple(Msg) ->
+ S = opt(print_messages, S0,
+ fun(X) when X==true;X==detail -> {"Send~n~s~n",[format_msg(Msg)]} end),
+ {Packet, C} = ssh_transport:ssh_packet(Msg, S#s.ssh),
+ send_bytes(Packet, S#s{ssh = C, %%inc_send_seq_num(C),
+ return_value = Msg}).
+
+send_bytes(B, S0) ->
+ S = opt(print_messages, S0, fun(detail) -> {"Send bytes~n~p~n",[B]} end),
+ ok(gen_tcp:send(S#s.socket, B)),
+ S.
+
+%%%----------------------------------------------------------------
+recv(S0 = #s{}) ->
+ S1 = receive_poll(S0),
+ case S1#s.seen_hello of
+ {more,Seen} ->
+ %% Has received parts of a line. Has not seen a complete hello.
+ try_find_crlf(Seen, S1);
+ false ->
+ %% Must see hello before binary messages
+ try_find_crlf(<<>>, S1);
+ true ->
+ %% Has seen hello, therefore no more crlf-messages are alowed.
+ S = receive_binary_msg(S1),
+ case M=S#s.return_value of
+ #ssh_msg_kexinit{} when ?role(S) == server,
+ S#s.own_kexinit =/= undefined ->
+ {ok, C} =
+ ssh_transport:handle_kexinit_msg(M, S#s.own_kexinit, S#s.ssh),
+ S#s{peer_kexinit = used,
+ own_kexinit = used,
+ ssh = C};
+ #ssh_msg_kexinit{} ->
+ S#s{peer_kexinit = M};
+ #ssh_msg_kexdh_init{} -> % Always the server
+ {ok, Reply, C} = ssh_transport:handle_kexdh_init(M, S#s.ssh),
+ S#s{ssh = C,
+ reply = [{ssh_msg_kexdh_reply,Reply} | S#s.reply]
+ };
+ #ssh_msg_kexdh_reply{} ->
+ {ok, _NewKeys, C} = ssh_transport:handle_kexdh_reply(M, S#s.ssh),
+ S#s{ssh=C#ssh{send_sequence=S#s.ssh#ssh.send_sequence}}; % Back the number
+ #ssh_msg_newkeys{} ->
+ {ok, C} = ssh_transport:handle_new_keys(M, S#s.ssh),
+ S#s{ssh=C};
+ _ ->
+ S
+ end
+ end.
+
+%%%================================================================
+try_find_crlf(Seen, S0) ->
+ case erlang:decode_packet(line,S0#s.enc,[]) of
+ {more,_} ->
+ Line = <<Seen/binary,(S0#s.enc)/binary>>,
+ S0#s{seen_hello = {more,Line},
+ enc = <<>>, % didn't find a complete line
+ % -> no more characters to test
+ return_value = {more,Line}
+ };
+ {ok,Used,Rest} ->
+ Line = <<Seen/binary,Used/binary>>,
+ case handle_hello(Line, S0) of
+ false ->
+ S = opt(print_messages, S0,
+ fun(X) when X==true;X==detail -> {"Recv info~n~p~n",[Line]} end),
+ S#s{seen_hello = false,
+ enc = Rest,
+ return_value = {info,Line}};
+ S1=#s{} ->
+ S = opt(print_messages, S1,
+ fun(X) when X==true;X==detail -> {"Recv hello~n~p~n",[Line]} end),
+ S#s{seen_hello = true,
+ enc = Rest,
+ return_value = {hello,Line}}
+ end
+ end.
+
+
+handle_hello(Bin, S=#s{ssh=C}) ->
+ case {ssh_transport:handle_hello_version(binary_to_list(Bin)),
+ ?role(S)}
+ of
+ {{undefined,_}, _} -> false;
+ {{Vp,Vs}, client} -> S#s{ssh = C#ssh{s_vsn=Vp, s_version=Vs}};
+ {{Vp,Vs}, server} -> S#s{ssh = C#ssh{c_vsn=Vp, c_version=Vs}}
+ end.
+
+receive_binary_msg(S0=#s{ssh=C0=#ssh{decrypt_block_size = BlockSize,
+ recv_mac_size = MacSize
+ }
+ }) ->
+ case size(S0#s.enc) >= max(8,BlockSize) of
+ false ->
+ %% Need more bytes to decode the packet_length field
+ Remaining = max(8,BlockSize) - size(S0#s.enc),
+ receive_binary_msg( receive_wait(Remaining, S0) );
+ true ->
+ %% Has enough bytes to decode the packet_length field
+ {_, <<?UINT32(PacketLen), _/binary>>, _} =
+ ssh_transport:decrypt_blocks(S0#s.enc, BlockSize, C0), % FIXME: BlockSize should be at least 4
+
+ %% FIXME: Check that ((4+PacketLen) rem BlockSize) == 0 ?
+
+ S1 = if
+ PacketLen > ?SSH_MAX_PACKET_SIZE ->
+ fail({too_large_message,PacketLen},S0); % FIXME: disconnect
+
+ ((4+PacketLen) rem BlockSize) =/= 0 ->
+ fail(bad_packet_length_modulo, S0); % FIXME: disconnect
+
+ size(S0#s.enc) >= (4 + PacketLen + MacSize) ->
+ %% has the whole packet
+ S0;
+
+ true ->
+ %% need more bytes to get have the whole packet
+ Remaining = (4 + PacketLen + MacSize) - size(S0#s.enc),
+ receive_wait(Remaining, S0)
+ end,
+
+ %% Decrypt all, including the packet_length part (re-use the initial #ssh{})
+ {C1, SshPacket = <<?UINT32(_),?BYTE(PadLen),Tail/binary>>, EncRest} =
+ ssh_transport:decrypt_blocks(S1#s.enc, PacketLen+4, C0),
+
+ PayloadLen = PacketLen - 1 - PadLen,
+ <<CompressedPayload:PayloadLen/binary, _Padding:PadLen/binary>> = Tail,
+
+ {C2, Payload} = ssh_transport:decompress(C1, CompressedPayload),
+
+ <<Mac:MacSize/binary, Rest/binary>> = EncRest,
+
+ case {ssh_transport:is_valid_mac(Mac, SshPacket, C2),
+ catch ssh_message:decode(Payload)}
+ of
+ {false, _} -> fail(bad_mac,S1);
+ {_, {'EXIT',_}} -> fail(decode_failed,S1);
+
+ {true, Msg} ->
+ C3 = case Msg of
+ #ssh_msg_kexinit{} ->
+ ssh_transport:key_init(opposite_role(C2), C2, Payload);
+ _ ->
+ C2
+ end,
+ S2 = opt(print_messages, S1,
+ fun(X) when X==true;X==detail -> {"Recv~n~s~n",[format_msg(Msg)]} end),
+ S3 = opt(print_messages, S2,
+ fun(detail) -> {"decrypted bytes ~p~n",[SshPacket]} end),
+ S3#s{ssh = inc_recv_seq_num(C3),
+ enc = Rest,
+ return_value = Msg
+ }
+ end
+ end.
+
+
+receive_poll(S=#s{socket=Sock}) ->
+ inet:setopts(Sock, [{active,once}]),
+ receive
+ {tcp,Sock,Data} ->
+ receive_poll( S#s{enc = <<(S#s.enc)/binary,Data/binary>>} );
+ {tcp_closed,Sock} ->
+ throw({tcp,tcp_closed});
+ {tcp_error, Sock, Reason} ->
+ throw({tcp,{tcp_error,Reason}})
+ after 0 ->
+ S
+ end.
+
+receive_wait(S=#s{socket=Sock,
+ timeout=Timeout}) ->
+ inet:setopts(Sock, [{active,once}]),
+ receive
+ {tcp,Sock,Data} ->
+ S#s{enc = <<(S#s.enc)/binary,Data/binary>>};
+ {tcp_closed,Sock} ->
+ throw({tcp,tcp_closed});
+ {tcp_error, Sock, Reason} ->
+ throw({tcp,{tcp_error,Reason}})
+ after Timeout ->
+ fail(receive_timeout,S)
+ end.
+
+receive_wait(N, S=#s{socket=Sock,
+ timeout=Timeout,
+ enc=Enc0}) when N>0 ->
+ inet:setopts(Sock, [{active,once}]),
+ receive
+ {tcp,Sock,Data} ->
+ receive_wait(N-size(Data), S#s{enc = <<Enc0/binary,Data/binary>>});
+ {tcp_closed,Sock} ->
+ throw({tcp,tcp_closed});
+ {tcp_error, Sock, Reason} ->
+ throw({tcp,{tcp_error,Reason}})
+ after Timeout ->
+ fail(receive_timeout, S)
+ end;
+receive_wait(_N, S) ->
+ S.
+
+%% random_padding_len(PaddingLen1, ChunkSize) ->
+%% MaxAdditionalRandomPaddingLen = % max 255 bytes padding totaö
+%% (255 - PaddingLen1) - ((255 - PaddingLen1) rem ChunkSize),
+%% AddLen0 = crypto:rand_uniform(0,MaxAdditionalRandomPaddingLen),
+%% AddLen0 - (AddLen0 rem ChunkSize). % preserve the blocking
+
+inc_recv_seq_num(C=#ssh{recv_sequence=N}) -> C#ssh{recv_sequence=(N+1) band 16#ffffffff}.
+%%%inc_send_seq_num(C=#ssh{send_sequence=N}) -> C#ssh{send_sequence=(N+1) band 16#ffffffff}.
+
+opposite_role(#ssh{role=R}) -> opposite_role(R);
+opposite_role(client) -> server;
+opposite_role(server) -> client.
+
+ok(ok) -> ok;
+ok({ok,R}) -> R;
+ok({error,E}) -> erlang:error(E).
+
+
+%%%================================================================
+%%%
+%%% Formating of records
+%%%
+
+format_msg(M) -> format_msg(M, 0).
+
+format_msg(M, I0) ->
+ case fields(M) of
+ undefined -> io_lib:format('~p',[M]);
+ Fields ->
+ [Name|Args] = tuple_to_list(M),
+ Head = io_lib:format('#~p{',[Name]),
+ I = lists:flatlength(Head)+I0,
+ NL = io_lib:format('~n~*c',[I,$ ]),
+ Sep = io_lib:format(',~n~*c',[I,$ ]),
+ Tail = [begin
+ S0 = io_lib:format('~p = ',[F]),
+ I1 = I + lists:flatlength(S0),
+ [S0,format_msg(A,I1)]
+ end
+ || {F,A} <- lists:zip(Fields,Args)],
+ [[Head|string:join(Tail,Sep)],NL,"}"]
+ end.
+
+fields(M) ->
+ case M of
+ #ssh_msg_debug{} -> record_info(fields, ssh_msg_debug);
+ #ssh_msg_disconnect{} -> record_info(fields, ssh_msg_disconnect);
+ #ssh_msg_ignore{} -> record_info(fields, ssh_msg_ignore);
+ #ssh_msg_kex_dh_gex_group{} -> record_info(fields, ssh_msg_kex_dh_gex_group);
+ #ssh_msg_kex_dh_gex_init{} -> record_info(fields, ssh_msg_kex_dh_gex_init);
+ #ssh_msg_kex_dh_gex_reply{} -> record_info(fields, ssh_msg_kex_dh_gex_reply);
+ #ssh_msg_kex_dh_gex_request{} -> record_info(fields, ssh_msg_kex_dh_gex_request);
+ #ssh_msg_kex_dh_gex_request_old{} -> record_info(fields, ssh_msg_kex_dh_gex_request_old);
+ #ssh_msg_kexdh_init{} -> record_info(fields, ssh_msg_kexdh_init);
+ #ssh_msg_kexdh_reply{} -> record_info(fields, ssh_msg_kexdh_reply);
+ #ssh_msg_kexinit{} -> record_info(fields, ssh_msg_kexinit);
+ #ssh_msg_newkeys{} -> record_info(fields, ssh_msg_newkeys);
+ #ssh_msg_service_accept{} -> record_info(fields, ssh_msg_service_accept);
+ #ssh_msg_service_request{} -> record_info(fields, ssh_msg_service_request);
+ #ssh_msg_unimplemented{} -> record_info(fields, ssh_msg_unimplemented);
+ #ssh_msg_userauth_request{} -> record_info(fields, ssh_msg_userauth_request);
+ #ssh_msg_userauth_failure{} -> record_info(fields, ssh_msg_userauth_failure);
+ #ssh_msg_userauth_success{} -> record_info(fields, ssh_msg_userauth_success);
+ #ssh_msg_userauth_banner{} -> record_info(fields, ssh_msg_userauth_banner);
+ #ssh_msg_userauth_passwd_changereq{} -> record_info(fields, ssh_msg_userauth_passwd_changereq);
+ #ssh_msg_userauth_pk_ok{} -> record_info(fields, ssh_msg_userauth_pk_ok);
+ #ssh_msg_userauth_info_request{} -> record_info(fields, ssh_msg_userauth_info_request);
+ #ssh_msg_userauth_info_response{} -> record_info(fields, ssh_msg_userauth_info_response);
+ #s{} -> record_info(fields, s);
+ #ssh{} -> record_info(fields, ssh);
+ #alg{} -> record_info(fields, alg);
+ _ -> undefined
+ end.
+
+%%%================================================================
+%%%
+%%% Trace handling
+%%%
+
+init_op_traces(Op, S0) ->
+ opt(print_ops, S0#s{prints=[]},
+ fun(true) ->
+ case ?role(S0) of
+ undefined -> {"-- ~p~n",[Op]};
+ Role -> {"-- ~p ~p~n",[Role,Op]}
+ end
+ end
+ ).
+
+report_trace(Class, Term, S) ->
+ print_traces(
+ opt(print_ops, S,
+ fun(true) -> {"~s ~p",[Class,Term]} end)
+ ).
+
+seqnum_trace(S) ->
+ opt(print_seqnums, S,
+ fun(true) when S#s.ssh#ssh.send_sequence =/= S#s.ssh#ssh.send_sequence,
+ S#s.ssh#ssh.recv_sequence =/= S#s.ssh#ssh.recv_sequence ->
+ {"~p seq num: send ~p->~p, recv ~p->~p~n",
+ [?role(S),
+ S#s.ssh#ssh.send_sequence, S#s.ssh#ssh.send_sequence,
+ S#s.ssh#ssh.recv_sequence, S#s.ssh#ssh.recv_sequence
+ ]};
+ (true) when S#s.ssh#ssh.send_sequence =/= S#s.ssh#ssh.send_sequence ->
+ {"~p seq num: send ~p->~p~n",
+ [?role(S),
+ S#s.ssh#ssh.send_sequence, S#s.ssh#ssh.send_sequence]};
+ (true) when S#s.ssh#ssh.recv_sequence =/= S#s.ssh#ssh.recv_sequence ->
+ {"~p seq num: recv ~p->~p~n",
+ [?role(S),
+ S#s.ssh#ssh.recv_sequence, S#s.ssh#ssh.recv_sequence]}
+ end).
+
+print_traces(S) when S#s.prints == [] -> S;
+print_traces(S) ->
+ ct:log("~s",
+ [lists:foldl(fun({Fmt,Args}, Acc) ->
+ [io_lib:format(Fmt,Args) | Acc]
+ end, "", S#s.prints)]
+ ).
+
+opt(Flag, S, Fun) when is_function(Fun,1) ->
+ try Fun(proplists:get_value(Flag,S#s.opts))
+ of P={Fmt,Args} when is_list(Fmt), is_list(Args) ->
+ save_prints(P, S)
+ catch _:_ ->
+ S
+ end.
+
+save_prints({Fmt,Args}, S) ->
+ S#s{prints = [{Fmt,Args}|S#s.prints]}.
diff --git a/lib/ssl/test/ssl_ECC_SUITE.erl b/lib/ssl/test/ssl_ECC_SUITE.erl
index 6ea0466dde..85152fda22 100644
--- a/lib/ssl/test/ssl_ECC_SUITE.erl
+++ b/lib/ssl/test/ssl_ECC_SUITE.erl
@@ -143,7 +143,7 @@ init_per_testcase(TestCase, Config) ->
ct:log("Ciphers: ~p~n ", [ ssl:cipher_suites()]),
end_per_testcase(TestCase, Config),
ssl:start(),
- ct:timetrap({seconds, 5}),
+ ct:timetrap({seconds, 15}),
Config.
end_per_testcase(_TestCase, Config) ->
diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl
index ecedb89c23..378f42c2ee 100644
--- a/lib/ssl/test/ssl_basic_SUITE.erl
+++ b/lib/ssl/test/ssl_basic_SUITE.erl
@@ -265,12 +265,12 @@ init_per_testcase(protocol_versions, Config) ->
Config;
init_per_testcase(reuse_session_expired, Config) ->
- ct:timetrap({seconds, 30}),
ssl:stop(),
application:load(ssl),
application:set_env(ssl, session_lifetime, ?EXPIRE),
application:set_env(ssl, session_delay_cleanup_time, 500),
ssl:start(),
+ ct:timetrap({seconds, 30}),
Config;
init_per_testcase(empty_protocol_versions, Config) ->
@@ -303,7 +303,24 @@ init_per_testcase(TestCase, Config) when TestCase == client_renegotiate;
ct:log("TLS/SSL version ~p~n ", [tls_record:supported_protocol_versions()]),
ct:timetrap({seconds, 30}),
Config;
-init_per_testcase(ssl_accept_timeout, Config) ->
+
+init_per_testcase(TestCase, Config) when TestCase == psk_cipher_suites;
+ TestCase == psk_with_hint_cipher_suites;
+ TestCase == ciphers_rsa_signed_certs;
+ TestCase == ciphers_rsa_signed_certs_openssl_names;
+ TestCase == versions_option,
+ TestCase == tcp_connect_big ->
+ ct:log("TLS/SSL version ~p~n ", [tls_record:supported_protocol_versions()]),
+
+ ct:timetrap({seconds, 30}),
+ Config;
+init_per_testcase(rizzo, Config) ->
+ ct:log("TLS/SSL version ~p~n ", [tls_record:supported_protocol_versions()]),
+ ct:timetrap({seconds, 40}),
+ Config;
+
+init_per_testcase(TestCase, Config) when TestCase == ssl_accept_timeout;
+ TestCase == client_closes_socket ->
ct:log("TLS/SSL version ~p~n ", [tls_record:supported_protocol_versions()]),
ct:timetrap({seconds, 15}),
Config;
@@ -1428,6 +1445,7 @@ tcp_connect_big(Config) when is_list(Config) ->
{_, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
TcpOpts = [binary, {reuseaddr, true}],
+ Rand = crypto:rand_bytes(?MAX_CIPHER_TEXT_LENGTH+1),
Server = ssl_test_lib:start_upgrade_server_error([{node, ServerNode}, {port, 0},
{from, self()},
{timeout, 5000},
@@ -1439,7 +1457,6 @@ tcp_connect_big(Config) when is_list(Config) ->
{ok, Socket} = gen_tcp:connect(Hostname, Port, [binary, {packet, 0}]),
ct:log("Testcase ~p connected to Server ~p ~n", [self(), Server]),
- Rand = crypto:rand_bytes(?MAX_CIPHER_TEXT_LENGTH+1),
gen_tcp:send(Socket, <<?BYTE(0),
?BYTE(3), ?BYTE(1), ?UINT16(?MAX_CIPHER_TEXT_LENGTH), Rand/binary>>),
diff --git a/lib/ssl/test/ssl_payload_SUITE.erl b/lib/ssl/test/ssl_payload_SUITE.erl
index b05f19d756..fb3890a811 100644
--- a/lib/ssl/test/ssl_payload_SUITE.erl
+++ b/lib/ssl/test/ssl_payload_SUITE.erl
@@ -105,7 +105,16 @@ init_per_testcase(TestCase, Config) when TestCase == server_echos_passive_huge;
TestCase == client_echos_passive_huge;
TestCase == client_echos_active_once_huge;
TestCase == client_echos_active_huge ->
- ct:timetrap({seconds, 30}),
+ ct:timetrap({seconds, 90}),
+ Config;
+
+init_per_testcase(TestCase, Config) when TestCase == server_echos_passive_big;
+ TestCase == server_echos_active_once_big;
+ TestCase == server_echos_active_big;
+ TestCase == client_echos_passive_big;
+ TestCase == client_echos_active_once_big;
+ TestCase == client_echos_active_big ->
+ ct:timetrap({seconds, 60}),
Config;
init_per_testcase(_TestCase, Config) ->
diff --git a/lib/ssl/test/ssl_test_lib.erl b/lib/ssl/test/ssl_test_lib.erl
index da744f7368..8317148aa5 100644
--- a/lib/ssl/test/ssl_test_lib.erl
+++ b/lib/ssl/test/ssl_test_lib.erl
@@ -1076,6 +1076,9 @@ is_sane_ecc(openssl) ->
"OpenSSL 1.0.0" ++ _ -> % Known bug in openssl
%% manifests as SSL_CHECK_SERVERHELLO_TLSEXT:tls invalid ecpointformat list
false;
+ "OpenSSL 1.0.1l" ++ _ ->
+ %% Breaks signature verification
+ false;
"OpenSSL 0.9.8" ++ _ -> % Does not support ECC
false;
"OpenSSL 0.9.7" ++ _ -> % Does not support ECC
diff --git a/lib/tools/doc/src/make.xml b/lib/tools/doc/src/make.xml
index e63163d689..5c2e5e5d62 100644
--- a/lib/tools/doc/src/make.xml
+++ b/lib/tools/doc/src/make.xml
@@ -76,7 +76,7 @@
Load mode. Loads all recompiled modules.</item>
<item><c>netload</c> <br></br>
- Net load mode. Loads all recompiled modules an all known nodes.</item>
+ Net load mode. Loads all recompiled modules on all known nodes.</item>
</list>
<p>All items in <c>Options</c> that are not make options are assumed
to be compiler options and are passed as-is to
diff --git a/lib/wx/api_gen/gen_util.erl b/lib/wx/api_gen/gen_util.erl
index 6bdbb4ca96..ff245a6359 100644
--- a/lib/wx/api_gen/gen_util.erl
+++ b/lib/wx/api_gen/gen_util.erl
@@ -230,7 +230,7 @@ erl_copyright() ->
w("%% Copyright Ericsson AB ~p-~p. All Rights Reserved.~n",
[StartYear, CurrentYear]),
w("%%~n",[]),
- w("%% Licensed under the Apache License, Version 2.0 (the \"License\");,~n",[]),
+ w("%% Licensed under the Apache License, Version 2.0 (the \"License\");~n",[]),
w("%% you may not use this file except in compliance with the License.~n",[]),
w("%% You may obtain a copy of the License at~n",[]),
w("%%~n",[]),
@@ -251,7 +251,7 @@ c_copyright() ->
w(" *~n",[]),
w(" * Copyright Ericsson AB 2008-~p. All Rights Reserved.~n",[CurrentYear]),
w(" *~n",[]),
- w(" * Licensed under the Apache License, Version 2.0 (the \"License\");,~n",[]),
+ w(" * Licensed under the Apache License, Version 2.0 (the \"License\");~n",[]),
w(" * you may not use this file except in compliance with the License.~n",[]),
w(" * You may obtain a copy of the License at~n",[]),
w(" *~n",[]),
diff --git a/lib/wx/api_gen/wx_extra/wxEvtHandler.c_src b/lib/wx/api_gen/wx_extra/wxEvtHandler.c_src
index 5d20019d8f..5e02066309 100644
--- a/lib/wx/api_gen/wx_extra/wxEvtHandler.c_src
+++ b/lib/wx/api_gen/wx_extra/wxEvtHandler.c_src
@@ -11,7 +11,7 @@ case 100: { // wxEvtHandler::Connect
int * class_nameLen = (int *) bp; bp += 4;
if(*haveUserData) {
- userData = new wxeErlTerm(Ecmd.bin[0]);
+ userData = new wxeErlTerm(&Ecmd.bin[0]);
}
int eventType = wxeEventTypeFromAtom(bp); bp += *eventTypeLen;
diff --git a/lib/wx/api_gen/wx_extra/wxEvtHandler.erl b/lib/wx/api_gen/wx_extra/wxEvtHandler.erl
index c9726fd475..85ebc093f5 100644
--- a/lib/wx/api_gen/wx_extra/wxEvtHandler.erl
+++ b/lib/wx/api_gen/wx_extra/wxEvtHandler.erl
@@ -70,6 +70,8 @@ connect(This=#wx_ref{type=ThisT}, EventType, Options) ->
parse_opts([{callback,Fun}|R], Opts) when is_function(Fun) ->
%% Check Fun Arity?
parse_opts(R, Opts#evh{cb=Fun});
+parse_opts([{callback,CB={nospawn, Fun}}|R], Opts) when is_function(Fun) ->
+ parse_opts(R, Opts#evh{cb=CB});
parse_opts([callback|R], Opts) ->
parse_opts(R, Opts#evh{cb=self()});
parse_opts([{userData, UserData}|R],Opts) ->
diff --git a/lib/wx/api_gen/wx_gen.erl b/lib/wx/api_gen/wx_gen.erl
index 212574ede3..114b3e561e 100644
--- a/lib/wx/api_gen/wx_gen.erl
+++ b/lib/wx/api_gen/wx_gen.erl
@@ -1196,7 +1196,7 @@ translate_constants(Enums, NotConsts0, Skip0) ->
create_consts([{{enum, Name},Enum = #enum{vals=Vals}}|R], Skip, NotConsts, Acc0) ->
CC = fun(What, Acc) ->
- create_const(What, Skip, NotConsts, Acc)
+ create_const(What, Name, Skip, NotConsts, Acc)
end,
Acc = case Vals of
undefined ->
@@ -1210,17 +1210,17 @@ create_consts([{{enum, Name},Enum = #enum{vals=Vals}}|R], Skip, NotConsts, Acc0)
create_consts(R, Skip, NotConsts, Acc);
create_consts([],_,_,Acc) -> Acc.
-create_const({Name, Val}, Skip, NotConsts, Acc) ->
+create_const({Name, Val}, EnumName, Skip, NotConsts, Acc) ->
case gb_sets:is_member(Name, Skip) of
true -> Acc;
false ->
- case gb_sets:is_member(Name, NotConsts) of
+ case gb_sets:is_member(Name, NotConsts) orelse
+ gb_sets:is_member(EnumName, NotConsts)
+ of
true ->
[#const{name=Name,val=next_id(const),is_const=false}|Acc];
false ->
[#const{name=Name,val=Val,is_const=true}|Acc]
-%% false ->
-%% [#const{name=Name,val=Val}|Acc]
end
end.
diff --git a/lib/wx/api_gen/wx_gen_cpp.erl b/lib/wx/api_gen/wx_gen_cpp.erl
index 3120d491b1..2ce6295078 100644
--- a/lib/wx/api_gen/wx_gen_cpp.erl
+++ b/lib/wx/api_gen/wx_gen_cpp.erl
@@ -206,8 +206,8 @@ gen_funcs(Defs) ->
" rt.addAtom(\"ok\");~n"
" break;~n"
" }~n"),
- w(" case WXE_BIN_INCR:~n driver_binary_inc_refc(Ecmd.bin[0]->bin);~n break;~n",[]),
- w(" case WXE_BIN_DECR:~n driver_binary_dec_refc(Ecmd.bin[0]->bin);~n break;~n",[]),
+ w(" case WXE_BIN_INCR:~n driver_binary_inc_refc(Ecmd.bin[0].bin);~n break;~n",[]),
+ w(" case WXE_BIN_DECR:~n driver_binary_dec_refc(Ecmd.bin[0].bin);~n break;~n",[]),
w(" case WXE_INIT_OPENGL:~n wxe_initOpenGL(&rt, bp);~n break;~n",[]),
Res = [gen_class(Class) || Class <- Defs],
@@ -631,10 +631,10 @@ decode_arg(N,#type{name=Type,base=binary,mod=Mod0},Arg,A0) ->
Mod = mods([M || M <- Mod0]),
case Arg of
arg ->
- w(" ~s~s * ~s = (~s~s*) Ecmd.bin[~p]->base;~n",
+ w(" ~s~s * ~s = (~s~s*) Ecmd.bin[~p].base;~n",
[Mod,Type,N,Mod,Type, next_id(bin_count)]);
opt ->
- w(" ~s = (~s~s*) Ecmd.bin[~p]->base;~n",
+ w(" ~s = (~s~s*) Ecmd.bin[~p].base;~n",
[N,Mod,Type,next_id(bin_count)])
end,
A0;
@@ -644,10 +644,10 @@ decode_arg(N,#type{base={term,"wxTreeItemData"},mod=Mod0},Arg,A0) ->
BinCnt = next_id(bin_count),
case Arg of
arg ->
- w(" ~s~s * ~s = new ~s(Ecmd.bin[~p]->size, Ecmd.bin[~p]->base);~n",
+ w(" ~s~s * ~s = new ~s(Ecmd.bin[~p].size, Ecmd.bin[~p].base);~n",
[Mod,Type,N,Type,BinCnt,BinCnt]);
opt ->
- w(" ~s = new ~s(Ecmd.bin[~p]->size, Ecmd.bin[~p]->base);~n",
+ w(" ~s = new ~s(Ecmd.bin[~p].size, Ecmd.bin[~p].base);~n",
[N,Type,BinCnt,BinCnt])
end,
A0;
@@ -656,10 +656,10 @@ decode_arg(N,#type{name=Type,base={term,_},mod=Mod0},Arg,A0) ->
BinCnt = next_id(bin_count),
case Arg of
arg ->
- w(" ~s~s * ~s = new ~s(Ecmd.bin[~p]);~n",
+ w(" ~s~s * ~s = new ~s(&Ecmd.bin[~p]);~n",
[Mod,Type,N,Type,BinCnt]);
opt ->
- w(" ~s = new ~s(Ecmd.bin[~p]);~n",
+ w(" ~s = new ~s(&Ecmd.bin[~p]);~n",
[N,Type,BinCnt])
end,
A0;
@@ -832,7 +832,7 @@ call_arg(#param{where=c, alt={length,Alt}}) when is_list(Alt) ->
"*" ++ Alt ++ "Len";
call_arg(#param{where=c, alt={size,Id}}) when is_integer(Id) ->
%% It's a binary
- "Ecmd.bin["++ integer_to_list(Id) ++ "]->size";
+ "Ecmd.bin["++ integer_to_list(Id) ++ "].size";
call_arg(#param{name=N,def=Def,type=#type{by_val=true,single=true,base=Base}})
when Base =:= int; Base =:= long; Base =:= float; Base =:= double; Base =:= bool ->
case Def of
diff --git a/lib/wx/api_gen/wxapi.conf b/lib/wx/api_gen/wxapi.conf
index 09877f0f5a..0d1fef6272 100644
--- a/lib/wx/api_gen/wxapi.conf
+++ b/lib/wx/api_gen/wxapi.conf
@@ -36,7 +36,8 @@
wxSL_LABELS,
wxCURSOR_DEFAULT,
wxCURSOR_ARROWWAIT,
- wxCURSOR_MAX
+ wxCURSOR_MAX,
+ wxLanguage
]}.
{gvars,
@@ -556,14 +557,14 @@
{"alpha",[in,{base,binary}]},
{{4,pre_hook},
[{c, "if(!static_data) {"
- "data = (unsigned char *) malloc(Ecmd.bin[0]->size);"
- "memcpy(data,Ecmd.bin[0]->base,Ecmd.bin[0]->size);}"}]},
+ "data = (unsigned char *) malloc(Ecmd.bin[0].size);"
+ "memcpy(data,Ecmd.bin[0].base,Ecmd.bin[0].size);}"}]},
{{5,pre_hook},
[{c, "if(!static_data) {"
- " data = (unsigned char *) malloc(Ecmd.bin[0]->size);"
- " alpha = (unsigned char *) malloc(Ecmd.bin[1]->size);"
- " memcpy(data,Ecmd.bin[0]->base,Ecmd.bin[0]->size);"
- " memcpy(alpha,Ecmd.bin[1]->base,Ecmd.bin[1]->size);}"}]}
+ " data = (unsigned char *) malloc(Ecmd.bin[0].size);"
+ " alpha = (unsigned char *) malloc(Ecmd.bin[1].size);"
+ " memcpy(data,Ecmd.bin[0].base,Ecmd.bin[0].size);"
+ " memcpy(alpha,Ecmd.bin[1].base,Ecmd.bin[1].size);}"}]}
]},
'~wxImage',%'AddHandler',
'Blur','BlurHorizontal','BlurVertical',
@@ -575,14 +576,14 @@
{"alpha",[in,{base,binary}]},
{{4,pre_hook},
[{c, "if(!static_data) {"
- "data = (unsigned char *) malloc(Ecmd.bin[0]->size);"
- "memcpy(data,Ecmd.bin[0]->base,Ecmd.bin[0]->size);}"}]},
+ "data = (unsigned char *) malloc(Ecmd.bin[0].size);"
+ "memcpy(data,Ecmd.bin[0].base,Ecmd.bin[0].size);}"}]},
{{5,pre_hook},
[{c, "if(!static_data) {"
- " data = (unsigned char *) malloc(Ecmd.bin[0]->size);"
- " alpha = (unsigned char *) malloc(Ecmd.bin[1]->size);"
- " memcpy(data,Ecmd.bin[0]->base,Ecmd.bin[0]->size);"
- " memcpy(alpha,Ecmd.bin[1]->base,Ecmd.bin[1]->size);}"}]}
+ " data = (unsigned char *) malloc(Ecmd.bin[0].size);"
+ " alpha = (unsigned char *) malloc(Ecmd.bin[1].size);"
+ " memcpy(data,Ecmd.bin[0].base,Ecmd.bin[0].size);"
+ " memcpy(alpha,Ecmd.bin[1].base,Ecmd.bin[1].size);}"}]}
]},
'Destroy','FindFirstUnusedColour', % 'FindHandler',
'GetImageExtWildcard',
@@ -608,14 +609,14 @@
{'SetAlpha', [{{2,"alpha"},[in,{base,binary}, {def, none}]},
{{2,pre_hook},
[{c, "if(!static_data) {"
- "alpha = (unsigned char *) malloc(Ecmd.bin[0]->size);"
- "memcpy(alpha,Ecmd.bin[0]->base,Ecmd.bin[0]->size);}"}]}
+ "alpha = (unsigned char *) malloc(Ecmd.bin[0].size);"
+ "memcpy(alpha,Ecmd.bin[0].base,Ecmd.bin[0].size);}"}]}
]},
{'SetData', [{"data",[in,{base,binary}]},
{pre_hook,
[{c, "if(!static_data) {"
- "data = (unsigned char *) malloc(Ecmd.bin[0]->size);"
- "memcpy(data,Ecmd.bin[0]->base,Ecmd.bin[0]->size);}"}]}
+ "data = (unsigned char *) malloc(Ecmd.bin[0].size);"
+ "memcpy(data,Ecmd.bin[0].base,Ecmd.bin[0].size);}"}]}
]},
'SetMask','SetMaskColour','SetMaskFromImage','SetOption',
'SetPalette',
@@ -1925,3 +1926,6 @@
{class, wxPopupTransientWindow, wxPopupWindow, [{ifdef, wxUSE_POPUPWIN}],
['wxPopupTransientWindow', '~wxPopupTransientWindow', 'Popup', 'Dismiss']}.
+
+{class, wxMouseCaptureLostEvent, wxEvent,
+ [{event,[wxEVT_MOUSE_CAPTURE_LOST]}],[]}.
diff --git a/lib/wx/c_src/gen/wxe_events.cpp b/lib/wx/c_src/gen/wxe_events.cpp
index 88a147cf90..f6a5868b48 100644
--- a/lib/wx/c_src/gen/wxe_events.cpp
+++ b/lib/wx/c_src/gen/wxe_events.cpp
@@ -302,6 +302,7 @@ void initEventTable()
{wxEVT_ACTIVATE, 231, "activate"},
{wxEVT_ACTIVATE_APP, 231, "activate_app"},
{wxEVT_HIBERNATE, 231, "hibernate"},
+ {wxEVT_MOUSE_CAPTURE_LOST, 234, "mouse_capture_lost"},
{-1, 0, }
};
for(int i=0; event_types[i].ev_type != -1; i++) {
@@ -870,6 +871,13 @@ case 231: {// wxActivateEvent
rt.addTupleCount(3);
break;
}
+case 234: {// wxMouseCaptureLostEvent
+ evClass = (char*)"wxMouseCaptureLostEvent";
+ rt.addAtom((char*)"wxMouseCaptureLost");
+ rt.addAtom(Etype->eName);
+ rt.addTupleCount(2);
+ break;
+}
}
rt.addTupleCount(5);
diff --git a/lib/wx/c_src/gen/wxe_init.cpp b/lib/wx/c_src/gen/wxe_init.cpp
index fd729accc9..1e432e34ce 100644
--- a/lib/wx/c_src/gen/wxe_init.cpp
+++ b/lib/wx/c_src/gen/wxe_init.cpp
@@ -57,6 +57,472 @@ void WxeApp::init_nonconsts(wxeMemEnv *memenv, ErlDrvTermData caller) {
rt.addTupleCount(2);
rt.addAtom("wxMOD_CMD"); rt.addInt(wxMOD_CMD);
rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_ABKHAZIAN"); rt.addInt(wxLANGUAGE_ABKHAZIAN);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_AFAR"); rt.addInt(wxLANGUAGE_AFAR);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_AFRIKAANS"); rt.addInt(wxLANGUAGE_AFRIKAANS);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_ALBANIAN"); rt.addInt(wxLANGUAGE_ALBANIAN);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_AMHARIC"); rt.addInt(wxLANGUAGE_AMHARIC);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_ARABIC"); rt.addInt(wxLANGUAGE_ARABIC);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_ARABIC_ALGERIA"); rt.addInt(wxLANGUAGE_ARABIC_ALGERIA);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_ARABIC_BAHRAIN"); rt.addInt(wxLANGUAGE_ARABIC_BAHRAIN);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_ARABIC_EGYPT"); rt.addInt(wxLANGUAGE_ARABIC_EGYPT);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_ARABIC_IRAQ"); rt.addInt(wxLANGUAGE_ARABIC_IRAQ);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_ARABIC_JORDAN"); rt.addInt(wxLANGUAGE_ARABIC_JORDAN);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_ARABIC_KUWAIT"); rt.addInt(wxLANGUAGE_ARABIC_KUWAIT);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_ARABIC_LEBANON"); rt.addInt(wxLANGUAGE_ARABIC_LEBANON);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_ARABIC_LIBYA"); rt.addInt(wxLANGUAGE_ARABIC_LIBYA);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_ARABIC_MOROCCO"); rt.addInt(wxLANGUAGE_ARABIC_MOROCCO);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_ARABIC_OMAN"); rt.addInt(wxLANGUAGE_ARABIC_OMAN);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_ARABIC_QATAR"); rt.addInt(wxLANGUAGE_ARABIC_QATAR);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_ARABIC_SAUDI_ARABIA"); rt.addInt(wxLANGUAGE_ARABIC_SAUDI_ARABIA);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_ARABIC_SUDAN"); rt.addInt(wxLANGUAGE_ARABIC_SUDAN);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_ARABIC_SYRIA"); rt.addInt(wxLANGUAGE_ARABIC_SYRIA);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_ARABIC_TUNISIA"); rt.addInt(wxLANGUAGE_ARABIC_TUNISIA);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_ARABIC_UAE"); rt.addInt(wxLANGUAGE_ARABIC_UAE);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_ARABIC_YEMEN"); rt.addInt(wxLANGUAGE_ARABIC_YEMEN);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_ARMENIAN"); rt.addInt(wxLANGUAGE_ARMENIAN);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_ASSAMESE"); rt.addInt(wxLANGUAGE_ASSAMESE);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_AYMARA"); rt.addInt(wxLANGUAGE_AYMARA);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_AZERI"); rt.addInt(wxLANGUAGE_AZERI);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_AZERI_CYRILLIC"); rt.addInt(wxLANGUAGE_AZERI_CYRILLIC);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_AZERI_LATIN"); rt.addInt(wxLANGUAGE_AZERI_LATIN);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_BASHKIR"); rt.addInt(wxLANGUAGE_BASHKIR);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_BASQUE"); rt.addInt(wxLANGUAGE_BASQUE);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_BELARUSIAN"); rt.addInt(wxLANGUAGE_BELARUSIAN);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_BENGALI"); rt.addInt(wxLANGUAGE_BENGALI);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_BHUTANI"); rt.addInt(wxLANGUAGE_BHUTANI);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_BIHARI"); rt.addInt(wxLANGUAGE_BIHARI);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_BISLAMA"); rt.addInt(wxLANGUAGE_BISLAMA);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_BRETON"); rt.addInt(wxLANGUAGE_BRETON);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_BULGARIAN"); rt.addInt(wxLANGUAGE_BULGARIAN);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_BURMESE"); rt.addInt(wxLANGUAGE_BURMESE);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_CAMBODIAN"); rt.addInt(wxLANGUAGE_CAMBODIAN);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_CATALAN"); rt.addInt(wxLANGUAGE_CATALAN);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_CHINESE"); rt.addInt(wxLANGUAGE_CHINESE);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_CHINESE_HONGKONG"); rt.addInt(wxLANGUAGE_CHINESE_HONGKONG);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_CHINESE_MACAU"); rt.addInt(wxLANGUAGE_CHINESE_MACAU);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_CHINESE_SIMPLIFIED"); rt.addInt(wxLANGUAGE_CHINESE_SIMPLIFIED);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_CHINESE_SINGAPORE"); rt.addInt(wxLANGUAGE_CHINESE_SINGAPORE);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_CHINESE_TAIWAN"); rt.addInt(wxLANGUAGE_CHINESE_TAIWAN);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_CHINESE_TRADITIONAL"); rt.addInt(wxLANGUAGE_CHINESE_TRADITIONAL);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_CORSICAN"); rt.addInt(wxLANGUAGE_CORSICAN);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_CROATIAN"); rt.addInt(wxLANGUAGE_CROATIAN);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_CZECH"); rt.addInt(wxLANGUAGE_CZECH);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_DANISH"); rt.addInt(wxLANGUAGE_DANISH);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_DEFAULT"); rt.addInt(wxLANGUAGE_DEFAULT);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_DUTCH"); rt.addInt(wxLANGUAGE_DUTCH);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_DUTCH_BELGIAN"); rt.addInt(wxLANGUAGE_DUTCH_BELGIAN);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_ENGLISH"); rt.addInt(wxLANGUAGE_ENGLISH);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_ENGLISH_AUSTRALIA"); rt.addInt(wxLANGUAGE_ENGLISH_AUSTRALIA);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_ENGLISH_BELIZE"); rt.addInt(wxLANGUAGE_ENGLISH_BELIZE);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_ENGLISH_BOTSWANA"); rt.addInt(wxLANGUAGE_ENGLISH_BOTSWANA);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_ENGLISH_CANADA"); rt.addInt(wxLANGUAGE_ENGLISH_CANADA);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_ENGLISH_CARIBBEAN"); rt.addInt(wxLANGUAGE_ENGLISH_CARIBBEAN);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_ENGLISH_DENMARK"); rt.addInt(wxLANGUAGE_ENGLISH_DENMARK);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_ENGLISH_EIRE"); rt.addInt(wxLANGUAGE_ENGLISH_EIRE);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_ENGLISH_JAMAICA"); rt.addInt(wxLANGUAGE_ENGLISH_JAMAICA);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_ENGLISH_NEW_ZEALAND"); rt.addInt(wxLANGUAGE_ENGLISH_NEW_ZEALAND);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_ENGLISH_PHILIPPINES"); rt.addInt(wxLANGUAGE_ENGLISH_PHILIPPINES);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_ENGLISH_SOUTH_AFRICA"); rt.addInt(wxLANGUAGE_ENGLISH_SOUTH_AFRICA);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_ENGLISH_TRINIDAD"); rt.addInt(wxLANGUAGE_ENGLISH_TRINIDAD);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_ENGLISH_UK"); rt.addInt(wxLANGUAGE_ENGLISH_UK);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_ENGLISH_US"); rt.addInt(wxLANGUAGE_ENGLISH_US);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_ENGLISH_ZIMBABWE"); rt.addInt(wxLANGUAGE_ENGLISH_ZIMBABWE);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_ESPERANTO"); rt.addInt(wxLANGUAGE_ESPERANTO);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_ESTONIAN"); rt.addInt(wxLANGUAGE_ESTONIAN);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_FAEROESE"); rt.addInt(wxLANGUAGE_FAEROESE);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_FARSI"); rt.addInt(wxLANGUAGE_FARSI);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_FIJI"); rt.addInt(wxLANGUAGE_FIJI);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_FINNISH"); rt.addInt(wxLANGUAGE_FINNISH);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_FRENCH"); rt.addInt(wxLANGUAGE_FRENCH);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_FRENCH_BELGIAN"); rt.addInt(wxLANGUAGE_FRENCH_BELGIAN);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_FRENCH_CANADIAN"); rt.addInt(wxLANGUAGE_FRENCH_CANADIAN);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_FRENCH_LUXEMBOURG"); rt.addInt(wxLANGUAGE_FRENCH_LUXEMBOURG);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_FRENCH_MONACO"); rt.addInt(wxLANGUAGE_FRENCH_MONACO);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_FRENCH_SWISS"); rt.addInt(wxLANGUAGE_FRENCH_SWISS);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_FRISIAN"); rt.addInt(wxLANGUAGE_FRISIAN);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_GALICIAN"); rt.addInt(wxLANGUAGE_GALICIAN);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_GEORGIAN"); rt.addInt(wxLANGUAGE_GEORGIAN);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_GERMAN"); rt.addInt(wxLANGUAGE_GERMAN);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_GERMAN_AUSTRIAN"); rt.addInt(wxLANGUAGE_GERMAN_AUSTRIAN);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_GERMAN_BELGIUM"); rt.addInt(wxLANGUAGE_GERMAN_BELGIUM);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_GERMAN_LIECHTENSTEIN"); rt.addInt(wxLANGUAGE_GERMAN_LIECHTENSTEIN);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_GERMAN_LUXEMBOURG"); rt.addInt(wxLANGUAGE_GERMAN_LUXEMBOURG);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_GERMAN_SWISS"); rt.addInt(wxLANGUAGE_GERMAN_SWISS);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_GREEK"); rt.addInt(wxLANGUAGE_GREEK);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_GREENLANDIC"); rt.addInt(wxLANGUAGE_GREENLANDIC);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_GUARANI"); rt.addInt(wxLANGUAGE_GUARANI);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_GUJARATI"); rt.addInt(wxLANGUAGE_GUJARATI);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_HAUSA"); rt.addInt(wxLANGUAGE_HAUSA);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_HEBREW"); rt.addInt(wxLANGUAGE_HEBREW);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_HINDI"); rt.addInt(wxLANGUAGE_HINDI);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_HUNGARIAN"); rt.addInt(wxLANGUAGE_HUNGARIAN);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_ICELANDIC"); rt.addInt(wxLANGUAGE_ICELANDIC);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_INDONESIAN"); rt.addInt(wxLANGUAGE_INDONESIAN);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_INTERLINGUA"); rt.addInt(wxLANGUAGE_INTERLINGUA);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_INTERLINGUE"); rt.addInt(wxLANGUAGE_INTERLINGUE);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_INUKTITUT"); rt.addInt(wxLANGUAGE_INUKTITUT);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_INUPIAK"); rt.addInt(wxLANGUAGE_INUPIAK);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_IRISH"); rt.addInt(wxLANGUAGE_IRISH);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_ITALIAN"); rt.addInt(wxLANGUAGE_ITALIAN);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_ITALIAN_SWISS"); rt.addInt(wxLANGUAGE_ITALIAN_SWISS);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_JAPANESE"); rt.addInt(wxLANGUAGE_JAPANESE);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_JAVANESE"); rt.addInt(wxLANGUAGE_JAVANESE);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_KANNADA"); rt.addInt(wxLANGUAGE_KANNADA);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_KASHMIRI"); rt.addInt(wxLANGUAGE_KASHMIRI);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_KASHMIRI_INDIA"); rt.addInt(wxLANGUAGE_KASHMIRI_INDIA);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_KAZAKH"); rt.addInt(wxLANGUAGE_KAZAKH);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_KERNEWEK"); rt.addInt(wxLANGUAGE_KERNEWEK);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_KINYARWANDA"); rt.addInt(wxLANGUAGE_KINYARWANDA);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_KIRGHIZ"); rt.addInt(wxLANGUAGE_KIRGHIZ);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_KIRUNDI"); rt.addInt(wxLANGUAGE_KIRUNDI);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_KONKANI"); rt.addInt(wxLANGUAGE_KONKANI);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_KOREAN"); rt.addInt(wxLANGUAGE_KOREAN);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_KURDISH"); rt.addInt(wxLANGUAGE_KURDISH);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_LAOTHIAN"); rt.addInt(wxLANGUAGE_LAOTHIAN);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_LATIN"); rt.addInt(wxLANGUAGE_LATIN);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_LATVIAN"); rt.addInt(wxLANGUAGE_LATVIAN);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_LINGALA"); rt.addInt(wxLANGUAGE_LINGALA);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_LITHUANIAN"); rt.addInt(wxLANGUAGE_LITHUANIAN);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_MACEDONIAN"); rt.addInt(wxLANGUAGE_MACEDONIAN);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_MALAGASY"); rt.addInt(wxLANGUAGE_MALAGASY);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_MALAY"); rt.addInt(wxLANGUAGE_MALAY);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_MALAYALAM"); rt.addInt(wxLANGUAGE_MALAYALAM);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_MALAY_BRUNEI_DARUSSALAM"); rt.addInt(wxLANGUAGE_MALAY_BRUNEI_DARUSSALAM);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_MALAY_MALAYSIA"); rt.addInt(wxLANGUAGE_MALAY_MALAYSIA);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_MALTESE"); rt.addInt(wxLANGUAGE_MALTESE);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_MANIPURI"); rt.addInt(wxLANGUAGE_MANIPURI);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_MAORI"); rt.addInt(wxLANGUAGE_MAORI);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_MARATHI"); rt.addInt(wxLANGUAGE_MARATHI);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_MOLDAVIAN"); rt.addInt(wxLANGUAGE_MOLDAVIAN);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_MONGOLIAN"); rt.addInt(wxLANGUAGE_MONGOLIAN);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_NAURU"); rt.addInt(wxLANGUAGE_NAURU);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_NEPALI"); rt.addInt(wxLANGUAGE_NEPALI);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_NEPALI_INDIA"); rt.addInt(wxLANGUAGE_NEPALI_INDIA);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_NORWEGIAN_BOKMAL"); rt.addInt(wxLANGUAGE_NORWEGIAN_BOKMAL);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_NORWEGIAN_NYNORSK"); rt.addInt(wxLANGUAGE_NORWEGIAN_NYNORSK);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_OCCITAN"); rt.addInt(wxLANGUAGE_OCCITAN);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_ORIYA"); rt.addInt(wxLANGUAGE_ORIYA);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_OROMO"); rt.addInt(wxLANGUAGE_OROMO);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_PASHTO"); rt.addInt(wxLANGUAGE_PASHTO);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_POLISH"); rt.addInt(wxLANGUAGE_POLISH);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_PORTUGUESE"); rt.addInt(wxLANGUAGE_PORTUGUESE);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_PORTUGUESE_BRAZILIAN"); rt.addInt(wxLANGUAGE_PORTUGUESE_BRAZILIAN);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_PUNJABI"); rt.addInt(wxLANGUAGE_PUNJABI);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_QUECHUA"); rt.addInt(wxLANGUAGE_QUECHUA);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_RHAETO_ROMANCE"); rt.addInt(wxLANGUAGE_RHAETO_ROMANCE);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_ROMANIAN"); rt.addInt(wxLANGUAGE_ROMANIAN);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_RUSSIAN"); rt.addInt(wxLANGUAGE_RUSSIAN);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_RUSSIAN_UKRAINE"); rt.addInt(wxLANGUAGE_RUSSIAN_UKRAINE);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_SAMI"); rt.addInt(wxLANGUAGE_SAMI);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_SAMOAN"); rt.addInt(wxLANGUAGE_SAMOAN);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_SANGHO"); rt.addInt(wxLANGUAGE_SANGHO);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_SANSKRIT"); rt.addInt(wxLANGUAGE_SANSKRIT);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_SCOTS_GAELIC"); rt.addInt(wxLANGUAGE_SCOTS_GAELIC);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_SERBIAN"); rt.addInt(wxLANGUAGE_SERBIAN);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_SERBIAN_CYRILLIC"); rt.addInt(wxLANGUAGE_SERBIAN_CYRILLIC);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_SERBIAN_LATIN"); rt.addInt(wxLANGUAGE_SERBIAN_LATIN);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_SERBO_CROATIAN"); rt.addInt(wxLANGUAGE_SERBO_CROATIAN);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_SESOTHO"); rt.addInt(wxLANGUAGE_SESOTHO);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_SETSWANA"); rt.addInt(wxLANGUAGE_SETSWANA);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_SHONA"); rt.addInt(wxLANGUAGE_SHONA);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_SINDHI"); rt.addInt(wxLANGUAGE_SINDHI);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_SINHALESE"); rt.addInt(wxLANGUAGE_SINHALESE);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_SISWATI"); rt.addInt(wxLANGUAGE_SISWATI);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_SLOVAK"); rt.addInt(wxLANGUAGE_SLOVAK);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_SLOVENIAN"); rt.addInt(wxLANGUAGE_SLOVENIAN);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_SOMALI"); rt.addInt(wxLANGUAGE_SOMALI);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_SPANISH"); rt.addInt(wxLANGUAGE_SPANISH);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_SPANISH_ARGENTINA"); rt.addInt(wxLANGUAGE_SPANISH_ARGENTINA);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_SPANISH_BOLIVIA"); rt.addInt(wxLANGUAGE_SPANISH_BOLIVIA);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_SPANISH_CHILE"); rt.addInt(wxLANGUAGE_SPANISH_CHILE);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_SPANISH_COLOMBIA"); rt.addInt(wxLANGUAGE_SPANISH_COLOMBIA);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_SPANISH_COSTA_RICA"); rt.addInt(wxLANGUAGE_SPANISH_COSTA_RICA);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_SPANISH_DOMINICAN_REPUBLIC"); rt.addInt(wxLANGUAGE_SPANISH_DOMINICAN_REPUBLIC);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_SPANISH_ECUADOR"); rt.addInt(wxLANGUAGE_SPANISH_ECUADOR);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_SPANISH_EL_SALVADOR"); rt.addInt(wxLANGUAGE_SPANISH_EL_SALVADOR);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_SPANISH_GUATEMALA"); rt.addInt(wxLANGUAGE_SPANISH_GUATEMALA);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_SPANISH_HONDURAS"); rt.addInt(wxLANGUAGE_SPANISH_HONDURAS);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_SPANISH_MEXICAN"); rt.addInt(wxLANGUAGE_SPANISH_MEXICAN);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_SPANISH_MODERN"); rt.addInt(wxLANGUAGE_SPANISH_MODERN);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_SPANISH_NICARAGUA"); rt.addInt(wxLANGUAGE_SPANISH_NICARAGUA);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_SPANISH_PANAMA"); rt.addInt(wxLANGUAGE_SPANISH_PANAMA);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_SPANISH_PARAGUAY"); rt.addInt(wxLANGUAGE_SPANISH_PARAGUAY);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_SPANISH_PERU"); rt.addInt(wxLANGUAGE_SPANISH_PERU);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_SPANISH_PUERTO_RICO"); rt.addInt(wxLANGUAGE_SPANISH_PUERTO_RICO);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_SPANISH_URUGUAY"); rt.addInt(wxLANGUAGE_SPANISH_URUGUAY);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_SPANISH_US"); rt.addInt(wxLANGUAGE_SPANISH_US);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_SPANISH_VENEZUELA"); rt.addInt(wxLANGUAGE_SPANISH_VENEZUELA);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_SUNDANESE"); rt.addInt(wxLANGUAGE_SUNDANESE);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_SWAHILI"); rt.addInt(wxLANGUAGE_SWAHILI);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_SWEDISH"); rt.addInt(wxLANGUAGE_SWEDISH);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_SWEDISH_FINLAND"); rt.addInt(wxLANGUAGE_SWEDISH_FINLAND);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_TAGALOG"); rt.addInt(wxLANGUAGE_TAGALOG);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_TAJIK"); rt.addInt(wxLANGUAGE_TAJIK);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_TAMIL"); rt.addInt(wxLANGUAGE_TAMIL);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_TATAR"); rt.addInt(wxLANGUAGE_TATAR);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_TELUGU"); rt.addInt(wxLANGUAGE_TELUGU);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_THAI"); rt.addInt(wxLANGUAGE_THAI);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_TIBETAN"); rt.addInt(wxLANGUAGE_TIBETAN);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_TIGRINYA"); rt.addInt(wxLANGUAGE_TIGRINYA);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_TONGA"); rt.addInt(wxLANGUAGE_TONGA);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_TSONGA"); rt.addInt(wxLANGUAGE_TSONGA);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_TURKISH"); rt.addInt(wxLANGUAGE_TURKISH);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_TURKMEN"); rt.addInt(wxLANGUAGE_TURKMEN);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_TWI"); rt.addInt(wxLANGUAGE_TWI);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_UIGHUR"); rt.addInt(wxLANGUAGE_UIGHUR);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_UKRAINIAN"); rt.addInt(wxLANGUAGE_UKRAINIAN);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_UNKNOWN"); rt.addInt(wxLANGUAGE_UNKNOWN);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_URDU"); rt.addInt(wxLANGUAGE_URDU);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_URDU_INDIA"); rt.addInt(wxLANGUAGE_URDU_INDIA);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_URDU_PAKISTAN"); rt.addInt(wxLANGUAGE_URDU_PAKISTAN);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_USER_DEFINED"); rt.addInt(wxLANGUAGE_USER_DEFINED);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_UZBEK"); rt.addInt(wxLANGUAGE_UZBEK);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_UZBEK_CYRILLIC"); rt.addInt(wxLANGUAGE_UZBEK_CYRILLIC);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_UZBEK_LATIN"); rt.addInt(wxLANGUAGE_UZBEK_LATIN);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_VALENCIAN"); rt.addInt(wxLANGUAGE_VALENCIAN);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_VIETNAMESE"); rt.addInt(wxLANGUAGE_VIETNAMESE);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_VOLAPUK"); rt.addInt(wxLANGUAGE_VOLAPUK);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_WELSH"); rt.addInt(wxLANGUAGE_WELSH);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_WOLOF"); rt.addInt(wxLANGUAGE_WOLOF);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_XHOSA"); rt.addInt(wxLANGUAGE_XHOSA);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_YIDDISH"); rt.addInt(wxLANGUAGE_YIDDISH);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_YORUBA"); rt.addInt(wxLANGUAGE_YORUBA);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_ZHUANG"); rt.addInt(wxLANGUAGE_ZHUANG);
+ rt.addTupleCount(2);
+ rt.addAtom("wxLANGUAGE_ZULU"); rt.addInt(wxLANGUAGE_ZULU);
+ rt.addTupleCount(2);
rt.addAtom("wxCURSOR_ARROWWAIT"); rt.addInt(wxCURSOR_ARROWWAIT);
rt.addTupleCount(2);
rt.addAtom("wxCURSOR_DEFAULT"); rt.addInt(wxCURSOR_DEFAULT);
@@ -145,7 +611,7 @@ void WxeApp::init_nonconsts(wxeMemEnv *memenv, ErlDrvTermData caller) {
rt.addTupleCount(2);
rt.addAtom("wxWHITE_PEN"); rt.addRef(getRef((void *)wxWHITE_PEN,memenv),"wxPen");
rt.addTupleCount(2);
- rt.endList(60);
+ rt.endList(293);
rt.addTupleCount(2);
rt.send();
}
diff --git a/lib/wx/c_src/wxe_impl.cpp b/lib/wx/c_src/wxe_impl.cpp
index 6236fb708e..5b34f08704 100644
--- a/lib/wx/c_src/wxe_impl.cpp
+++ b/lib/wx/c_src/wxe_impl.cpp
@@ -60,6 +60,7 @@ wxeFifo * wxe_queue = NULL;
wxeFifo * wxe_queue_cb_saved = NULL;
unsigned int wxe_needs_signal = 0; // inside batch if larger than 0
+unsigned int wxe_cb_invoked = 0;
/* ************************************************************
* Commands from erlang
@@ -181,6 +182,25 @@ void WxeApp::dummy_close(wxEvent& Ev) {
// windows open, and this will kill the erlang, override default handling
}
+void WxeApp::OnAssertFailure(const wxChar *file, int line, const wxChar *cfunc,
+ const wxChar *cond, const wxChar *cmsgUser) {
+ wxString msg;
+ wxString func(cfunc);
+ wxString msgUser(cmsgUser);
+
+ msg.Printf(wxT("wxWidgets Assert failure: %s(%d): \"%s\""),
+ file, line, cond);
+ if ( !func.empty() ) {
+ msg << wxT(" in ") << func << wxT("()");
+ }
+ // and the message itself
+ if ( !msgUser.empty() ) {
+ msg << wxT(" : ") << msgUser;
+ }
+
+ send_msg("error", &msg);
+}
+
// Called by wx thread
void WxeApp::idle(wxIdleEvent& event) {
event.Skip(true);
@@ -214,6 +234,7 @@ void handle_event_callback(ErlDrvPort port, ErlDrvTermData process)
app->recurse_level--;
// fprintf(stderr, "CB EV done %lu \r\n", process);fflush(stderr);
driver_demonitor_process(port, &monitor);
+ wxe_cb_invoked = 1;
}
}
@@ -221,10 +242,16 @@ void WxeApp::dispatch_cmds()
{
if(wxe_status != WXE_INITIATED)
return;
- recurse_level++;
- int level = dispatch(wxe_queue_cb_saved, 0, WXE_STORED);
- dispatch(wxe_queue, level, WXE_NORMAL);
- recurse_level--;
+ do {
+ wxe_cb_invoked = 0;
+ recurse_level++;
+ // fprintf(stderr, "\r\ndispatch_saved 0 \r\n");fflush(stderr);
+ int level = dispatch(wxe_queue_cb_saved, 0, WXE_STORED);
+ // fprintf(stderr, "\r\ndispatch_normal %d\r\n", level);fflush(stderr);
+ dispatch(wxe_queue, level, WXE_NORMAL);
+ // fprintf(stderr, "\r\ndispatch_done \r\n");fflush(stderr);
+ recurse_level--;
+ } while(wxe_cb_invoked);
// Cleanup old memenv's and deleted objects
if(recurse_level == 0) {
@@ -294,7 +321,12 @@ int WxeApp::dispatch(wxeFifo * batch, int blevel, int list_type)
break;
}
event->Delete();
- if(list_type == WXE_NORMAL) erl_drv_mutex_lock(wxe_batch_locker_m);
+ if(list_type == WXE_NORMAL) {
+ if(wxe_cb_invoked)
+ return blevel;
+ else
+ erl_drv_mutex_lock(wxe_batch_locker_m);
+ }
}
if(list_type == WXE_STORED)
return blevel;
diff --git a/lib/wx/c_src/wxe_impl.h b/lib/wx/c_src/wxe_impl.h
index d8241d11a4..d6d3095a0f 100644
--- a/lib/wx/c_src/wxe_impl.h
+++ b/lib/wx/c_src/wxe_impl.h
@@ -57,9 +57,14 @@ class WxeApp : public wxApp
{
public:
virtual bool OnInit();
+
+ virtual void OnAssertFailure(const wxChar *file, int line, const wxChar *func,
+ const wxChar *cond, const wxChar *msg);
+
#ifdef _MACOSX
virtual void MacOpenFile(const wxString &filename);
#endif
+
void shutdown(wxeMetaCommand& event);
int dispatch(wxeFifo *, int, int);
diff --git a/lib/wx/include/wx.hrl b/lib/wx/include/wx.hrl
index 6705e34cb9..69ca13aca1 100644
--- a/lib/wx/include/wx.hrl
+++ b/lib/wx/include/wx.hrl
@@ -133,6 +133,10 @@
-type wxSetCursorEventType() :: set_cursor.
-type wxSetCursor() :: #wxSetCursor{}. %% Callback event: {@link wxSetCursorEvent}
+-record(wxMouseCaptureLost, {type :: wxMouseCaptureLostEventType()}). %% Callback event: {@link wxMouseCaptureLostEvent}
+-type wxMouseCaptureLostEventType() :: mouse_capture_lost.
+-type wxMouseCaptureLost() :: #wxMouseCaptureLost{}. %% Callback event: {@link wxMouseCaptureLostEvent}
+
-record(wxFontPicker,{type :: wxFontPickerEventType(), %% Callback event: {@link wxFontPickerEvent}
font :: wxFont:wxFont()}).
-type wxFontPickerEventType() :: command_fontpicker_changed.
@@ -344,8 +348,8 @@
-type wxTreeEventType() :: command_tree_begin_drag | command_tree_begin_rdrag | command_tree_begin_label_edit | command_tree_end_label_edit | command_tree_delete_item | command_tree_get_info | command_tree_set_info | command_tree_item_expanded | command_tree_item_expanding | command_tree_item_collapsed | command_tree_item_collapsing | command_tree_sel_changed | command_tree_sel_changing | command_tree_key_down | command_tree_item_activated | command_tree_item_right_click | command_tree_item_middle_click | command_tree_end_drag | command_tree_state_image_click | command_tree_item_gettooltip | command_tree_item_menu.
-type wxTree() :: #wxTree{}. %% Callback event: {@link wxTreeEvent}
--type event() :: wxActivate() | wxAuiManager() | wxAuiNotebook() | wxCalendar() | wxChildFocus() | wxClipboardText() | wxClose() | wxColourPicker() | wxCommand() | wxContextMenu() | wxDate() | wxDisplayChanged() | wxErase() | wxFileDirPicker() | wxFocus() | wxFontPicker() | wxGrid() | wxHelp() | wxHtmlLink() | wxIconize() | wxIdle() | wxInitDialog() | wxJoystick() | wxKey() | wxList() | wxMaximize() | wxMenu() | wxMouse() | wxMouseCaptureChanged() | wxMove() | wxNavigationKey() | wxNotebook() | wxPaint() | wxPaletteChanged() | wxQueryNewPalette() | wxSash() | wxScroll() | wxScrollWin() | wxSetCursor() | wxShow() | wxSize() | wxSpin() | wxSplitter() | wxStyledText() | wxSysColourChanged() | wxTaskBarIcon() | wxTree() | wxUpdateUI() | wxWindowCreate() | wxWindowDestroy().
--type wxEventType() :: wxActivateEventType() | wxAuiManagerEventType() | wxAuiNotebookEventType() | wxCalendarEventType() | wxChildFocusEventType() | wxClipboardTextEventType() | wxCloseEventType() | wxColourPickerEventType() | wxCommandEventType() | wxContextMenuEventType() | wxDateEventType() | wxDisplayChangedEventType() | wxEraseEventType() | wxFileDirPickerEventType() | wxFocusEventType() | wxFontPickerEventType() | wxGridEventType() | wxHelpEventType() | wxHtmlLinkEventType() | wxIconizeEventType() | wxIdleEventType() | wxInitDialogEventType() | wxJoystickEventType() | wxKeyEventType() | wxListEventType() | wxMaximizeEventType() | wxMenuEventType() | wxMouseCaptureChangedEventType() | wxMouseEventType() | wxMoveEventType() | wxNavigationKeyEventType() | wxNotebookEventType() | wxPaintEventType() | wxPaletteChangedEventType() | wxQueryNewPaletteEventType() | wxSashEventType() | wxScrollEventType() | wxScrollWinEventType() | wxSetCursorEventType() | wxShowEventType() | wxSizeEventType() | wxSpinEventType() | wxSplitterEventType() | wxStyledTextEventType() | wxSysColourChangedEventType() | wxTaskBarIconEventType() | wxTreeEventType() | wxUpdateUIEventType() | wxWindowCreateEventType() | wxWindowDestroyEventType().
+-type event() :: wxActivate() | wxAuiManager() | wxAuiNotebook() | wxCalendar() | wxChildFocus() | wxClipboardText() | wxClose() | wxColourPicker() | wxCommand() | wxContextMenu() | wxDate() | wxDisplayChanged() | wxErase() | wxFileDirPicker() | wxFocus() | wxFontPicker() | wxGrid() | wxHelp() | wxHtmlLink() | wxIconize() | wxIdle() | wxInitDialog() | wxJoystick() | wxKey() | wxList() | wxMaximize() | wxMenu() | wxMouse() | wxMouseCaptureChanged() | wxMouseCaptureLost() | wxMove() | wxNavigationKey() | wxNotebook() | wxPaint() | wxPaletteChanged() | wxQueryNewPalette() | wxSash() | wxScroll() | wxScrollWin() | wxSetCursor() | wxShow() | wxSize() | wxSpin() | wxSplitter() | wxStyledText() | wxSysColourChanged() | wxTaskBarIcon() | wxTree() | wxUpdateUI() | wxWindowCreate() | wxWindowDestroy().
+-type wxEventType() :: wxActivateEventType() | wxAuiManagerEventType() | wxAuiNotebookEventType() | wxCalendarEventType() | wxChildFocusEventType() | wxClipboardTextEventType() | wxCloseEventType() | wxColourPickerEventType() | wxCommandEventType() | wxContextMenuEventType() | wxDateEventType() | wxDisplayChangedEventType() | wxEraseEventType() | wxFileDirPickerEventType() | wxFocusEventType() | wxFontPickerEventType() | wxGridEventType() | wxHelpEventType() | wxHtmlLinkEventType() | wxIconizeEventType() | wxIdleEventType() | wxInitDialogEventType() | wxJoystickEventType() | wxKeyEventType() | wxListEventType() | wxMaximizeEventType() | wxMenuEventType() | wxMouseCaptureChangedEventType() | wxMouseCaptureLostEventType() | wxMouseEventType() | wxMoveEventType() | wxNavigationKeyEventType() | wxNotebookEventType() | wxPaintEventType() | wxPaletteChangedEventType() | wxQueryNewPaletteEventType() | wxSashEventType() | wxScrollEventType() | wxScrollWinEventType() | wxSetCursorEventType() | wxShowEventType() | wxSizeEventType() | wxSpinEventType() | wxSplitterEventType() | wxStyledTextEventType() | wxSysColourChangedEventType() | wxTaskBarIconEventType() | wxTreeEventType() | wxUpdateUIEventType() | wxWindowCreateEventType() | wxWindowDestroyEventType().
%% Hardcoded Records
-record(wxMouseState, {x :: integer(), y :: integer(),
@@ -2009,239 +2013,239 @@
-define(wxIMAGELIST_DRAW_TRANSPARENT, 2).
-define(wxIMAGELIST_DRAW_NORMAL, 1).
% From "intl.h": wxLanguage
--define(wxLANGUAGE_DEFAULT, 0).
--define(wxLANGUAGE_UNKNOWN, 1).
--define(wxLANGUAGE_ABKHAZIAN, 2).
--define(wxLANGUAGE_AFAR, 3).
--define(wxLANGUAGE_AFRIKAANS, 4).
--define(wxLANGUAGE_ALBANIAN, 5).
--define(wxLANGUAGE_AMHARIC, 6).
--define(wxLANGUAGE_ARABIC, 7).
--define(wxLANGUAGE_ARABIC_ALGERIA, 8).
--define(wxLANGUAGE_ARABIC_BAHRAIN, 9).
--define(wxLANGUAGE_ARABIC_EGYPT, 10).
--define(wxLANGUAGE_ARABIC_IRAQ, 11).
--define(wxLANGUAGE_ARABIC_JORDAN, 12).
--define(wxLANGUAGE_ARABIC_KUWAIT, 13).
--define(wxLANGUAGE_ARABIC_LEBANON, 14).
--define(wxLANGUAGE_ARABIC_LIBYA, 15).
--define(wxLANGUAGE_ARABIC_MOROCCO, 16).
--define(wxLANGUAGE_ARABIC_OMAN, 17).
--define(wxLANGUAGE_ARABIC_QATAR, 18).
--define(wxLANGUAGE_ARABIC_SAUDI_ARABIA, 19).
--define(wxLANGUAGE_ARABIC_SUDAN, 20).
--define(wxLANGUAGE_ARABIC_SYRIA, 21).
--define(wxLANGUAGE_ARABIC_TUNISIA, 22).
--define(wxLANGUAGE_ARABIC_UAE, 23).
--define(wxLANGUAGE_ARABIC_YEMEN, 24).
--define(wxLANGUAGE_ARMENIAN, 25).
--define(wxLANGUAGE_ASSAMESE, 26).
--define(wxLANGUAGE_AYMARA, 27).
--define(wxLANGUAGE_AZERI, 28).
--define(wxLANGUAGE_AZERI_CYRILLIC, 29).
--define(wxLANGUAGE_AZERI_LATIN, 30).
--define(wxLANGUAGE_BASHKIR, 31).
--define(wxLANGUAGE_BASQUE, 32).
--define(wxLANGUAGE_BELARUSIAN, 33).
--define(wxLANGUAGE_BENGALI, 34).
--define(wxLANGUAGE_BHUTANI, 35).
--define(wxLANGUAGE_BIHARI, 36).
--define(wxLANGUAGE_BISLAMA, 37).
--define(wxLANGUAGE_BRETON, 38).
--define(wxLANGUAGE_BULGARIAN, 39).
--define(wxLANGUAGE_BURMESE, 40).
--define(wxLANGUAGE_CAMBODIAN, 41).
--define(wxLANGUAGE_CATALAN, 42).
--define(wxLANGUAGE_CHINESE, 43).
--define(wxLANGUAGE_CHINESE_SIMPLIFIED, 44).
--define(wxLANGUAGE_CHINESE_TRADITIONAL, 45).
--define(wxLANGUAGE_CHINESE_HONGKONG, 46).
--define(wxLANGUAGE_CHINESE_MACAU, 47).
--define(wxLANGUAGE_CHINESE_SINGAPORE, 48).
--define(wxLANGUAGE_CHINESE_TAIWAN, 49).
--define(wxLANGUAGE_CORSICAN, 50).
--define(wxLANGUAGE_CROATIAN, 51).
--define(wxLANGUAGE_CZECH, 52).
--define(wxLANGUAGE_DANISH, 53).
--define(wxLANGUAGE_DUTCH, 54).
--define(wxLANGUAGE_DUTCH_BELGIAN, 55).
--define(wxLANGUAGE_ENGLISH, 56).
--define(wxLANGUAGE_ENGLISH_UK, 57).
--define(wxLANGUAGE_ENGLISH_US, 58).
--define(wxLANGUAGE_ENGLISH_AUSTRALIA, 59).
--define(wxLANGUAGE_ENGLISH_BELIZE, 60).
--define(wxLANGUAGE_ENGLISH_BOTSWANA, 61).
--define(wxLANGUAGE_ENGLISH_CANADA, 62).
--define(wxLANGUAGE_ENGLISH_CARIBBEAN, 63).
--define(wxLANGUAGE_ENGLISH_DENMARK, 64).
--define(wxLANGUAGE_ENGLISH_EIRE, 65).
--define(wxLANGUAGE_ENGLISH_JAMAICA, 66).
--define(wxLANGUAGE_ENGLISH_NEW_ZEALAND, 67).
--define(wxLANGUAGE_ENGLISH_PHILIPPINES, 68).
--define(wxLANGUAGE_ENGLISH_SOUTH_AFRICA, 69).
--define(wxLANGUAGE_ENGLISH_TRINIDAD, 70).
--define(wxLANGUAGE_ENGLISH_ZIMBABWE, 71).
--define(wxLANGUAGE_ESPERANTO, 72).
--define(wxLANGUAGE_ESTONIAN, 73).
--define(wxLANGUAGE_FAEROESE, 74).
--define(wxLANGUAGE_FARSI, 75).
--define(wxLANGUAGE_FIJI, 76).
--define(wxLANGUAGE_FINNISH, 77).
--define(wxLANGUAGE_FRENCH, 78).
--define(wxLANGUAGE_FRENCH_BELGIAN, 79).
--define(wxLANGUAGE_FRENCH_CANADIAN, 80).
--define(wxLANGUAGE_FRENCH_LUXEMBOURG, 81).
--define(wxLANGUAGE_FRENCH_MONACO, 82).
--define(wxLANGUAGE_FRENCH_SWISS, 83).
--define(wxLANGUAGE_FRISIAN, 84).
--define(wxLANGUAGE_GALICIAN, 85).
--define(wxLANGUAGE_GEORGIAN, 86).
--define(wxLANGUAGE_GERMAN, 87).
--define(wxLANGUAGE_GERMAN_AUSTRIAN, 88).
--define(wxLANGUAGE_GERMAN_BELGIUM, 89).
--define(wxLANGUAGE_GERMAN_LIECHTENSTEIN, 90).
--define(wxLANGUAGE_GERMAN_LUXEMBOURG, 91).
--define(wxLANGUAGE_GERMAN_SWISS, 92).
--define(wxLANGUAGE_GREEK, 93).
--define(wxLANGUAGE_GREENLANDIC, 94).
--define(wxLANGUAGE_GUARANI, 95).
--define(wxLANGUAGE_GUJARATI, 96).
--define(wxLANGUAGE_HAUSA, 97).
--define(wxLANGUAGE_HEBREW, 98).
--define(wxLANGUAGE_HINDI, 99).
--define(wxLANGUAGE_HUNGARIAN, 100).
--define(wxLANGUAGE_ICELANDIC, 101).
--define(wxLANGUAGE_INDONESIAN, 102).
--define(wxLANGUAGE_INTERLINGUA, 103).
--define(wxLANGUAGE_INTERLINGUE, 104).
--define(wxLANGUAGE_INUKTITUT, 105).
--define(wxLANGUAGE_INUPIAK, 106).
--define(wxLANGUAGE_IRISH, 107).
--define(wxLANGUAGE_ITALIAN, 108).
--define(wxLANGUAGE_ITALIAN_SWISS, 109).
--define(wxLANGUAGE_JAPANESE, 110).
--define(wxLANGUAGE_JAVANESE, 111).
--define(wxLANGUAGE_KANNADA, 112).
--define(wxLANGUAGE_KASHMIRI, 113).
--define(wxLANGUAGE_KASHMIRI_INDIA, 114).
--define(wxLANGUAGE_KAZAKH, 115).
--define(wxLANGUAGE_KERNEWEK, 116).
--define(wxLANGUAGE_KINYARWANDA, 117).
--define(wxLANGUAGE_KIRGHIZ, 118).
--define(wxLANGUAGE_KIRUNDI, 119).
--define(wxLANGUAGE_KONKANI, 120).
--define(wxLANGUAGE_KOREAN, 121).
--define(wxLANGUAGE_KURDISH, 122).
--define(wxLANGUAGE_LAOTHIAN, 123).
--define(wxLANGUAGE_LATIN, 124).
--define(wxLANGUAGE_LATVIAN, 125).
--define(wxLANGUAGE_LINGALA, 126).
--define(wxLANGUAGE_LITHUANIAN, 127).
--define(wxLANGUAGE_MACEDONIAN, 128).
--define(wxLANGUAGE_MALAGASY, 129).
--define(wxLANGUAGE_MALAY, 130).
--define(wxLANGUAGE_MALAYALAM, 131).
--define(wxLANGUAGE_MALAY_BRUNEI_DARUSSALAM, 132).
--define(wxLANGUAGE_MALAY_MALAYSIA, 133).
--define(wxLANGUAGE_MALTESE, 134).
--define(wxLANGUAGE_MANIPURI, 135).
--define(wxLANGUAGE_MAORI, 136).
--define(wxLANGUAGE_MARATHI, 137).
--define(wxLANGUAGE_MOLDAVIAN, 138).
--define(wxLANGUAGE_MONGOLIAN, 139).
--define(wxLANGUAGE_NAURU, 140).
--define(wxLANGUAGE_NEPALI, 141).
--define(wxLANGUAGE_NEPALI_INDIA, 142).
--define(wxLANGUAGE_NORWEGIAN_BOKMAL, 143).
--define(wxLANGUAGE_NORWEGIAN_NYNORSK, 144).
--define(wxLANGUAGE_OCCITAN, 145).
--define(wxLANGUAGE_ORIYA, 146).
--define(wxLANGUAGE_OROMO, 147).
--define(wxLANGUAGE_PASHTO, 148).
--define(wxLANGUAGE_POLISH, 149).
--define(wxLANGUAGE_PORTUGUESE, 150).
--define(wxLANGUAGE_PORTUGUESE_BRAZILIAN, 151).
--define(wxLANGUAGE_PUNJABI, 152).
--define(wxLANGUAGE_QUECHUA, 153).
--define(wxLANGUAGE_RHAETO_ROMANCE, 154).
--define(wxLANGUAGE_ROMANIAN, 155).
--define(wxLANGUAGE_RUSSIAN, 156).
--define(wxLANGUAGE_RUSSIAN_UKRAINE, 157).
--define(wxLANGUAGE_SAMOAN, 158).
--define(wxLANGUAGE_SANGHO, 159).
--define(wxLANGUAGE_SANSKRIT, 160).
--define(wxLANGUAGE_SCOTS_GAELIC, 161).
--define(wxLANGUAGE_SERBIAN, 162).
--define(wxLANGUAGE_SERBIAN_CYRILLIC, 163).
--define(wxLANGUAGE_SERBIAN_LATIN, 164).
--define(wxLANGUAGE_SERBO_CROATIAN, 165).
--define(wxLANGUAGE_SESOTHO, 166).
--define(wxLANGUAGE_SETSWANA, 167).
--define(wxLANGUAGE_SHONA, 168).
--define(wxLANGUAGE_SINDHI, 169).
--define(wxLANGUAGE_SINHALESE, 170).
--define(wxLANGUAGE_SISWATI, 171).
--define(wxLANGUAGE_SLOVAK, 172).
--define(wxLANGUAGE_SLOVENIAN, 173).
--define(wxLANGUAGE_SOMALI, 174).
--define(wxLANGUAGE_SPANISH, 175).
--define(wxLANGUAGE_SPANISH_ARGENTINA, 176).
--define(wxLANGUAGE_SPANISH_BOLIVIA, 177).
--define(wxLANGUAGE_SPANISH_CHILE, 178).
--define(wxLANGUAGE_SPANISH_COLOMBIA, 179).
--define(wxLANGUAGE_SPANISH_COSTA_RICA, 180).
--define(wxLANGUAGE_SPANISH_DOMINICAN_REPUBLIC, 181).
--define(wxLANGUAGE_SPANISH_ECUADOR, 182).
--define(wxLANGUAGE_SPANISH_EL_SALVADOR, 183).
--define(wxLANGUAGE_SPANISH_GUATEMALA, 184).
--define(wxLANGUAGE_SPANISH_HONDURAS, 185).
--define(wxLANGUAGE_SPANISH_MEXICAN, 186).
--define(wxLANGUAGE_SPANISH_MODERN, 187).
--define(wxLANGUAGE_SPANISH_NICARAGUA, 188).
--define(wxLANGUAGE_SPANISH_PANAMA, 189).
--define(wxLANGUAGE_SPANISH_PARAGUAY, 190).
--define(wxLANGUAGE_SPANISH_PERU, 191).
--define(wxLANGUAGE_SPANISH_PUERTO_RICO, 192).
--define(wxLANGUAGE_SPANISH_URUGUAY, 193).
--define(wxLANGUAGE_SPANISH_US, 194).
--define(wxLANGUAGE_SPANISH_VENEZUELA, 195).
--define(wxLANGUAGE_SUNDANESE, 196).
--define(wxLANGUAGE_SWAHILI, 197).
--define(wxLANGUAGE_SWEDISH, 198).
--define(wxLANGUAGE_SWEDISH_FINLAND, 199).
--define(wxLANGUAGE_TAGALOG, 200).
--define(wxLANGUAGE_TAJIK, 201).
--define(wxLANGUAGE_TAMIL, 202).
--define(wxLANGUAGE_TATAR, 203).
--define(wxLANGUAGE_TELUGU, 204).
--define(wxLANGUAGE_THAI, 205).
--define(wxLANGUAGE_TIBETAN, 206).
--define(wxLANGUAGE_TIGRINYA, 207).
--define(wxLANGUAGE_TONGA, 208).
--define(wxLANGUAGE_TSONGA, 209).
--define(wxLANGUAGE_TURKISH, 210).
--define(wxLANGUAGE_TURKMEN, 211).
--define(wxLANGUAGE_TWI, 212).
--define(wxLANGUAGE_UIGHUR, 213).
--define(wxLANGUAGE_UKRAINIAN, 214).
--define(wxLANGUAGE_URDU, 215).
--define(wxLANGUAGE_URDU_INDIA, 216).
--define(wxLANGUAGE_URDU_PAKISTAN, 217).
--define(wxLANGUAGE_UZBEK, 218).
--define(wxLANGUAGE_UZBEK_CYRILLIC, 219).
--define(wxLANGUAGE_UZBEK_LATIN, 220).
--define(wxLANGUAGE_VIETNAMESE, 221).
--define(wxLANGUAGE_VOLAPUK, 222).
--define(wxLANGUAGE_WELSH, 223).
--define(wxLANGUAGE_WOLOF, 224).
--define(wxLANGUAGE_XHOSA, 225).
--define(wxLANGUAGE_YIDDISH, 226).
--define(wxLANGUAGE_YORUBA, 227).
--define(wxLANGUAGE_ZHUANG, 228).
--define(wxLANGUAGE_ZULU, 229).
--define(wxLANGUAGE_USER_DEFINED, 230).
--define(wxLANGUAGE_VALENCIAN, 536870911).
--define(wxLANGUAGE_SAMI, 536870912).
+-define(wxLANGUAGE_DEFAULT, wxe_util:get_const(wxLANGUAGE_DEFAULT)).
+-define(wxLANGUAGE_UNKNOWN, wxe_util:get_const(wxLANGUAGE_UNKNOWN)).
+-define(wxLANGUAGE_ABKHAZIAN, wxe_util:get_const(wxLANGUAGE_ABKHAZIAN)).
+-define(wxLANGUAGE_AFAR, wxe_util:get_const(wxLANGUAGE_AFAR)).
+-define(wxLANGUAGE_AFRIKAANS, wxe_util:get_const(wxLANGUAGE_AFRIKAANS)).
+-define(wxLANGUAGE_ALBANIAN, wxe_util:get_const(wxLANGUAGE_ALBANIAN)).
+-define(wxLANGUAGE_AMHARIC, wxe_util:get_const(wxLANGUAGE_AMHARIC)).
+-define(wxLANGUAGE_ARABIC, wxe_util:get_const(wxLANGUAGE_ARABIC)).
+-define(wxLANGUAGE_ARABIC_ALGERIA, wxe_util:get_const(wxLANGUAGE_ARABIC_ALGERIA)).
+-define(wxLANGUAGE_ARABIC_BAHRAIN, wxe_util:get_const(wxLANGUAGE_ARABIC_BAHRAIN)).
+-define(wxLANGUAGE_ARABIC_EGYPT, wxe_util:get_const(wxLANGUAGE_ARABIC_EGYPT)).
+-define(wxLANGUAGE_ARABIC_IRAQ, wxe_util:get_const(wxLANGUAGE_ARABIC_IRAQ)).
+-define(wxLANGUAGE_ARABIC_JORDAN, wxe_util:get_const(wxLANGUAGE_ARABIC_JORDAN)).
+-define(wxLANGUAGE_ARABIC_KUWAIT, wxe_util:get_const(wxLANGUAGE_ARABIC_KUWAIT)).
+-define(wxLANGUAGE_ARABIC_LEBANON, wxe_util:get_const(wxLANGUAGE_ARABIC_LEBANON)).
+-define(wxLANGUAGE_ARABIC_LIBYA, wxe_util:get_const(wxLANGUAGE_ARABIC_LIBYA)).
+-define(wxLANGUAGE_ARABIC_MOROCCO, wxe_util:get_const(wxLANGUAGE_ARABIC_MOROCCO)).
+-define(wxLANGUAGE_ARABIC_OMAN, wxe_util:get_const(wxLANGUAGE_ARABIC_OMAN)).
+-define(wxLANGUAGE_ARABIC_QATAR, wxe_util:get_const(wxLANGUAGE_ARABIC_QATAR)).
+-define(wxLANGUAGE_ARABIC_SAUDI_ARABIA, wxe_util:get_const(wxLANGUAGE_ARABIC_SAUDI_ARABIA)).
+-define(wxLANGUAGE_ARABIC_SUDAN, wxe_util:get_const(wxLANGUAGE_ARABIC_SUDAN)).
+-define(wxLANGUAGE_ARABIC_SYRIA, wxe_util:get_const(wxLANGUAGE_ARABIC_SYRIA)).
+-define(wxLANGUAGE_ARABIC_TUNISIA, wxe_util:get_const(wxLANGUAGE_ARABIC_TUNISIA)).
+-define(wxLANGUAGE_ARABIC_UAE, wxe_util:get_const(wxLANGUAGE_ARABIC_UAE)).
+-define(wxLANGUAGE_ARABIC_YEMEN, wxe_util:get_const(wxLANGUAGE_ARABIC_YEMEN)).
+-define(wxLANGUAGE_ARMENIAN, wxe_util:get_const(wxLANGUAGE_ARMENIAN)).
+-define(wxLANGUAGE_ASSAMESE, wxe_util:get_const(wxLANGUAGE_ASSAMESE)).
+-define(wxLANGUAGE_AYMARA, wxe_util:get_const(wxLANGUAGE_AYMARA)).
+-define(wxLANGUAGE_AZERI, wxe_util:get_const(wxLANGUAGE_AZERI)).
+-define(wxLANGUAGE_AZERI_CYRILLIC, wxe_util:get_const(wxLANGUAGE_AZERI_CYRILLIC)).
+-define(wxLANGUAGE_AZERI_LATIN, wxe_util:get_const(wxLANGUAGE_AZERI_LATIN)).
+-define(wxLANGUAGE_BASHKIR, wxe_util:get_const(wxLANGUAGE_BASHKIR)).
+-define(wxLANGUAGE_BASQUE, wxe_util:get_const(wxLANGUAGE_BASQUE)).
+-define(wxLANGUAGE_BELARUSIAN, wxe_util:get_const(wxLANGUAGE_BELARUSIAN)).
+-define(wxLANGUAGE_BENGALI, wxe_util:get_const(wxLANGUAGE_BENGALI)).
+-define(wxLANGUAGE_BHUTANI, wxe_util:get_const(wxLANGUAGE_BHUTANI)).
+-define(wxLANGUAGE_BIHARI, wxe_util:get_const(wxLANGUAGE_BIHARI)).
+-define(wxLANGUAGE_BISLAMA, wxe_util:get_const(wxLANGUAGE_BISLAMA)).
+-define(wxLANGUAGE_BRETON, wxe_util:get_const(wxLANGUAGE_BRETON)).
+-define(wxLANGUAGE_BULGARIAN, wxe_util:get_const(wxLANGUAGE_BULGARIAN)).
+-define(wxLANGUAGE_BURMESE, wxe_util:get_const(wxLANGUAGE_BURMESE)).
+-define(wxLANGUAGE_CAMBODIAN, wxe_util:get_const(wxLANGUAGE_CAMBODIAN)).
+-define(wxLANGUAGE_CATALAN, wxe_util:get_const(wxLANGUAGE_CATALAN)).
+-define(wxLANGUAGE_CHINESE, wxe_util:get_const(wxLANGUAGE_CHINESE)).
+-define(wxLANGUAGE_CHINESE_SIMPLIFIED, wxe_util:get_const(wxLANGUAGE_CHINESE_SIMPLIFIED)).
+-define(wxLANGUAGE_CHINESE_TRADITIONAL, wxe_util:get_const(wxLANGUAGE_CHINESE_TRADITIONAL)).
+-define(wxLANGUAGE_CHINESE_HONGKONG, wxe_util:get_const(wxLANGUAGE_CHINESE_HONGKONG)).
+-define(wxLANGUAGE_CHINESE_MACAU, wxe_util:get_const(wxLANGUAGE_CHINESE_MACAU)).
+-define(wxLANGUAGE_CHINESE_SINGAPORE, wxe_util:get_const(wxLANGUAGE_CHINESE_SINGAPORE)).
+-define(wxLANGUAGE_CHINESE_TAIWAN, wxe_util:get_const(wxLANGUAGE_CHINESE_TAIWAN)).
+-define(wxLANGUAGE_CORSICAN, wxe_util:get_const(wxLANGUAGE_CORSICAN)).
+-define(wxLANGUAGE_CROATIAN, wxe_util:get_const(wxLANGUAGE_CROATIAN)).
+-define(wxLANGUAGE_CZECH, wxe_util:get_const(wxLANGUAGE_CZECH)).
+-define(wxLANGUAGE_DANISH, wxe_util:get_const(wxLANGUAGE_DANISH)).
+-define(wxLANGUAGE_DUTCH, wxe_util:get_const(wxLANGUAGE_DUTCH)).
+-define(wxLANGUAGE_DUTCH_BELGIAN, wxe_util:get_const(wxLANGUAGE_DUTCH_BELGIAN)).
+-define(wxLANGUAGE_ENGLISH, wxe_util:get_const(wxLANGUAGE_ENGLISH)).
+-define(wxLANGUAGE_ENGLISH_UK, wxe_util:get_const(wxLANGUAGE_ENGLISH_UK)).
+-define(wxLANGUAGE_ENGLISH_US, wxe_util:get_const(wxLANGUAGE_ENGLISH_US)).
+-define(wxLANGUAGE_ENGLISH_AUSTRALIA, wxe_util:get_const(wxLANGUAGE_ENGLISH_AUSTRALIA)).
+-define(wxLANGUAGE_ENGLISH_BELIZE, wxe_util:get_const(wxLANGUAGE_ENGLISH_BELIZE)).
+-define(wxLANGUAGE_ENGLISH_BOTSWANA, wxe_util:get_const(wxLANGUAGE_ENGLISH_BOTSWANA)).
+-define(wxLANGUAGE_ENGLISH_CANADA, wxe_util:get_const(wxLANGUAGE_ENGLISH_CANADA)).
+-define(wxLANGUAGE_ENGLISH_CARIBBEAN, wxe_util:get_const(wxLANGUAGE_ENGLISH_CARIBBEAN)).
+-define(wxLANGUAGE_ENGLISH_DENMARK, wxe_util:get_const(wxLANGUAGE_ENGLISH_DENMARK)).
+-define(wxLANGUAGE_ENGLISH_EIRE, wxe_util:get_const(wxLANGUAGE_ENGLISH_EIRE)).
+-define(wxLANGUAGE_ENGLISH_JAMAICA, wxe_util:get_const(wxLANGUAGE_ENGLISH_JAMAICA)).
+-define(wxLANGUAGE_ENGLISH_NEW_ZEALAND, wxe_util:get_const(wxLANGUAGE_ENGLISH_NEW_ZEALAND)).
+-define(wxLANGUAGE_ENGLISH_PHILIPPINES, wxe_util:get_const(wxLANGUAGE_ENGLISH_PHILIPPINES)).
+-define(wxLANGUAGE_ENGLISH_SOUTH_AFRICA, wxe_util:get_const(wxLANGUAGE_ENGLISH_SOUTH_AFRICA)).
+-define(wxLANGUAGE_ENGLISH_TRINIDAD, wxe_util:get_const(wxLANGUAGE_ENGLISH_TRINIDAD)).
+-define(wxLANGUAGE_ENGLISH_ZIMBABWE, wxe_util:get_const(wxLANGUAGE_ENGLISH_ZIMBABWE)).
+-define(wxLANGUAGE_ESPERANTO, wxe_util:get_const(wxLANGUAGE_ESPERANTO)).
+-define(wxLANGUAGE_ESTONIAN, wxe_util:get_const(wxLANGUAGE_ESTONIAN)).
+-define(wxLANGUAGE_FAEROESE, wxe_util:get_const(wxLANGUAGE_FAEROESE)).
+-define(wxLANGUAGE_FARSI, wxe_util:get_const(wxLANGUAGE_FARSI)).
+-define(wxLANGUAGE_FIJI, wxe_util:get_const(wxLANGUAGE_FIJI)).
+-define(wxLANGUAGE_FINNISH, wxe_util:get_const(wxLANGUAGE_FINNISH)).
+-define(wxLANGUAGE_FRENCH, wxe_util:get_const(wxLANGUAGE_FRENCH)).
+-define(wxLANGUAGE_FRENCH_BELGIAN, wxe_util:get_const(wxLANGUAGE_FRENCH_BELGIAN)).
+-define(wxLANGUAGE_FRENCH_CANADIAN, wxe_util:get_const(wxLANGUAGE_FRENCH_CANADIAN)).
+-define(wxLANGUAGE_FRENCH_LUXEMBOURG, wxe_util:get_const(wxLANGUAGE_FRENCH_LUXEMBOURG)).
+-define(wxLANGUAGE_FRENCH_MONACO, wxe_util:get_const(wxLANGUAGE_FRENCH_MONACO)).
+-define(wxLANGUAGE_FRENCH_SWISS, wxe_util:get_const(wxLANGUAGE_FRENCH_SWISS)).
+-define(wxLANGUAGE_FRISIAN, wxe_util:get_const(wxLANGUAGE_FRISIAN)).
+-define(wxLANGUAGE_GALICIAN, wxe_util:get_const(wxLANGUAGE_GALICIAN)).
+-define(wxLANGUAGE_GEORGIAN, wxe_util:get_const(wxLANGUAGE_GEORGIAN)).
+-define(wxLANGUAGE_GERMAN, wxe_util:get_const(wxLANGUAGE_GERMAN)).
+-define(wxLANGUAGE_GERMAN_AUSTRIAN, wxe_util:get_const(wxLANGUAGE_GERMAN_AUSTRIAN)).
+-define(wxLANGUAGE_GERMAN_BELGIUM, wxe_util:get_const(wxLANGUAGE_GERMAN_BELGIUM)).
+-define(wxLANGUAGE_GERMAN_LIECHTENSTEIN, wxe_util:get_const(wxLANGUAGE_GERMAN_LIECHTENSTEIN)).
+-define(wxLANGUAGE_GERMAN_LUXEMBOURG, wxe_util:get_const(wxLANGUAGE_GERMAN_LUXEMBOURG)).
+-define(wxLANGUAGE_GERMAN_SWISS, wxe_util:get_const(wxLANGUAGE_GERMAN_SWISS)).
+-define(wxLANGUAGE_GREEK, wxe_util:get_const(wxLANGUAGE_GREEK)).
+-define(wxLANGUAGE_GREENLANDIC, wxe_util:get_const(wxLANGUAGE_GREENLANDIC)).
+-define(wxLANGUAGE_GUARANI, wxe_util:get_const(wxLANGUAGE_GUARANI)).
+-define(wxLANGUAGE_GUJARATI, wxe_util:get_const(wxLANGUAGE_GUJARATI)).
+-define(wxLANGUAGE_HAUSA, wxe_util:get_const(wxLANGUAGE_HAUSA)).
+-define(wxLANGUAGE_HEBREW, wxe_util:get_const(wxLANGUAGE_HEBREW)).
+-define(wxLANGUAGE_HINDI, wxe_util:get_const(wxLANGUAGE_HINDI)).
+-define(wxLANGUAGE_HUNGARIAN, wxe_util:get_const(wxLANGUAGE_HUNGARIAN)).
+-define(wxLANGUAGE_ICELANDIC, wxe_util:get_const(wxLANGUAGE_ICELANDIC)).
+-define(wxLANGUAGE_INDONESIAN, wxe_util:get_const(wxLANGUAGE_INDONESIAN)).
+-define(wxLANGUAGE_INTERLINGUA, wxe_util:get_const(wxLANGUAGE_INTERLINGUA)).
+-define(wxLANGUAGE_INTERLINGUE, wxe_util:get_const(wxLANGUAGE_INTERLINGUE)).
+-define(wxLANGUAGE_INUKTITUT, wxe_util:get_const(wxLANGUAGE_INUKTITUT)).
+-define(wxLANGUAGE_INUPIAK, wxe_util:get_const(wxLANGUAGE_INUPIAK)).
+-define(wxLANGUAGE_IRISH, wxe_util:get_const(wxLANGUAGE_IRISH)).
+-define(wxLANGUAGE_ITALIAN, wxe_util:get_const(wxLANGUAGE_ITALIAN)).
+-define(wxLANGUAGE_ITALIAN_SWISS, wxe_util:get_const(wxLANGUAGE_ITALIAN_SWISS)).
+-define(wxLANGUAGE_JAPANESE, wxe_util:get_const(wxLANGUAGE_JAPANESE)).
+-define(wxLANGUAGE_JAVANESE, wxe_util:get_const(wxLANGUAGE_JAVANESE)).
+-define(wxLANGUAGE_KANNADA, wxe_util:get_const(wxLANGUAGE_KANNADA)).
+-define(wxLANGUAGE_KASHMIRI, wxe_util:get_const(wxLANGUAGE_KASHMIRI)).
+-define(wxLANGUAGE_KASHMIRI_INDIA, wxe_util:get_const(wxLANGUAGE_KASHMIRI_INDIA)).
+-define(wxLANGUAGE_KAZAKH, wxe_util:get_const(wxLANGUAGE_KAZAKH)).
+-define(wxLANGUAGE_KERNEWEK, wxe_util:get_const(wxLANGUAGE_KERNEWEK)).
+-define(wxLANGUAGE_KINYARWANDA, wxe_util:get_const(wxLANGUAGE_KINYARWANDA)).
+-define(wxLANGUAGE_KIRGHIZ, wxe_util:get_const(wxLANGUAGE_KIRGHIZ)).
+-define(wxLANGUAGE_KIRUNDI, wxe_util:get_const(wxLANGUAGE_KIRUNDI)).
+-define(wxLANGUAGE_KONKANI, wxe_util:get_const(wxLANGUAGE_KONKANI)).
+-define(wxLANGUAGE_KOREAN, wxe_util:get_const(wxLANGUAGE_KOREAN)).
+-define(wxLANGUAGE_KURDISH, wxe_util:get_const(wxLANGUAGE_KURDISH)).
+-define(wxLANGUAGE_LAOTHIAN, wxe_util:get_const(wxLANGUAGE_LAOTHIAN)).
+-define(wxLANGUAGE_LATIN, wxe_util:get_const(wxLANGUAGE_LATIN)).
+-define(wxLANGUAGE_LATVIAN, wxe_util:get_const(wxLANGUAGE_LATVIAN)).
+-define(wxLANGUAGE_LINGALA, wxe_util:get_const(wxLANGUAGE_LINGALA)).
+-define(wxLANGUAGE_LITHUANIAN, wxe_util:get_const(wxLANGUAGE_LITHUANIAN)).
+-define(wxLANGUAGE_MACEDONIAN, wxe_util:get_const(wxLANGUAGE_MACEDONIAN)).
+-define(wxLANGUAGE_MALAGASY, wxe_util:get_const(wxLANGUAGE_MALAGASY)).
+-define(wxLANGUAGE_MALAY, wxe_util:get_const(wxLANGUAGE_MALAY)).
+-define(wxLANGUAGE_MALAYALAM, wxe_util:get_const(wxLANGUAGE_MALAYALAM)).
+-define(wxLANGUAGE_MALAY_BRUNEI_DARUSSALAM, wxe_util:get_const(wxLANGUAGE_MALAY_BRUNEI_DARUSSALAM)).
+-define(wxLANGUAGE_MALAY_MALAYSIA, wxe_util:get_const(wxLANGUAGE_MALAY_MALAYSIA)).
+-define(wxLANGUAGE_MALTESE, wxe_util:get_const(wxLANGUAGE_MALTESE)).
+-define(wxLANGUAGE_MANIPURI, wxe_util:get_const(wxLANGUAGE_MANIPURI)).
+-define(wxLANGUAGE_MAORI, wxe_util:get_const(wxLANGUAGE_MAORI)).
+-define(wxLANGUAGE_MARATHI, wxe_util:get_const(wxLANGUAGE_MARATHI)).
+-define(wxLANGUAGE_MOLDAVIAN, wxe_util:get_const(wxLANGUAGE_MOLDAVIAN)).
+-define(wxLANGUAGE_MONGOLIAN, wxe_util:get_const(wxLANGUAGE_MONGOLIAN)).
+-define(wxLANGUAGE_NAURU, wxe_util:get_const(wxLANGUAGE_NAURU)).
+-define(wxLANGUAGE_NEPALI, wxe_util:get_const(wxLANGUAGE_NEPALI)).
+-define(wxLANGUAGE_NEPALI_INDIA, wxe_util:get_const(wxLANGUAGE_NEPALI_INDIA)).
+-define(wxLANGUAGE_NORWEGIAN_BOKMAL, wxe_util:get_const(wxLANGUAGE_NORWEGIAN_BOKMAL)).
+-define(wxLANGUAGE_NORWEGIAN_NYNORSK, wxe_util:get_const(wxLANGUAGE_NORWEGIAN_NYNORSK)).
+-define(wxLANGUAGE_OCCITAN, wxe_util:get_const(wxLANGUAGE_OCCITAN)).
+-define(wxLANGUAGE_ORIYA, wxe_util:get_const(wxLANGUAGE_ORIYA)).
+-define(wxLANGUAGE_OROMO, wxe_util:get_const(wxLANGUAGE_OROMO)).
+-define(wxLANGUAGE_PASHTO, wxe_util:get_const(wxLANGUAGE_PASHTO)).
+-define(wxLANGUAGE_POLISH, wxe_util:get_const(wxLANGUAGE_POLISH)).
+-define(wxLANGUAGE_PORTUGUESE, wxe_util:get_const(wxLANGUAGE_PORTUGUESE)).
+-define(wxLANGUAGE_PORTUGUESE_BRAZILIAN, wxe_util:get_const(wxLANGUAGE_PORTUGUESE_BRAZILIAN)).
+-define(wxLANGUAGE_PUNJABI, wxe_util:get_const(wxLANGUAGE_PUNJABI)).
+-define(wxLANGUAGE_QUECHUA, wxe_util:get_const(wxLANGUAGE_QUECHUA)).
+-define(wxLANGUAGE_RHAETO_ROMANCE, wxe_util:get_const(wxLANGUAGE_RHAETO_ROMANCE)).
+-define(wxLANGUAGE_ROMANIAN, wxe_util:get_const(wxLANGUAGE_ROMANIAN)).
+-define(wxLANGUAGE_RUSSIAN, wxe_util:get_const(wxLANGUAGE_RUSSIAN)).
+-define(wxLANGUAGE_RUSSIAN_UKRAINE, wxe_util:get_const(wxLANGUAGE_RUSSIAN_UKRAINE)).
+-define(wxLANGUAGE_SAMOAN, wxe_util:get_const(wxLANGUAGE_SAMOAN)).
+-define(wxLANGUAGE_SANGHO, wxe_util:get_const(wxLANGUAGE_SANGHO)).
+-define(wxLANGUAGE_SANSKRIT, wxe_util:get_const(wxLANGUAGE_SANSKRIT)).
+-define(wxLANGUAGE_SCOTS_GAELIC, wxe_util:get_const(wxLANGUAGE_SCOTS_GAELIC)).
+-define(wxLANGUAGE_SERBIAN, wxe_util:get_const(wxLANGUAGE_SERBIAN)).
+-define(wxLANGUAGE_SERBIAN_CYRILLIC, wxe_util:get_const(wxLANGUAGE_SERBIAN_CYRILLIC)).
+-define(wxLANGUAGE_SERBIAN_LATIN, wxe_util:get_const(wxLANGUAGE_SERBIAN_LATIN)).
+-define(wxLANGUAGE_SERBO_CROATIAN, wxe_util:get_const(wxLANGUAGE_SERBO_CROATIAN)).
+-define(wxLANGUAGE_SESOTHO, wxe_util:get_const(wxLANGUAGE_SESOTHO)).
+-define(wxLANGUAGE_SETSWANA, wxe_util:get_const(wxLANGUAGE_SETSWANA)).
+-define(wxLANGUAGE_SHONA, wxe_util:get_const(wxLANGUAGE_SHONA)).
+-define(wxLANGUAGE_SINDHI, wxe_util:get_const(wxLANGUAGE_SINDHI)).
+-define(wxLANGUAGE_SINHALESE, wxe_util:get_const(wxLANGUAGE_SINHALESE)).
+-define(wxLANGUAGE_SISWATI, wxe_util:get_const(wxLANGUAGE_SISWATI)).
+-define(wxLANGUAGE_SLOVAK, wxe_util:get_const(wxLANGUAGE_SLOVAK)).
+-define(wxLANGUAGE_SLOVENIAN, wxe_util:get_const(wxLANGUAGE_SLOVENIAN)).
+-define(wxLANGUAGE_SOMALI, wxe_util:get_const(wxLANGUAGE_SOMALI)).
+-define(wxLANGUAGE_SPANISH, wxe_util:get_const(wxLANGUAGE_SPANISH)).
+-define(wxLANGUAGE_SPANISH_ARGENTINA, wxe_util:get_const(wxLANGUAGE_SPANISH_ARGENTINA)).
+-define(wxLANGUAGE_SPANISH_BOLIVIA, wxe_util:get_const(wxLANGUAGE_SPANISH_BOLIVIA)).
+-define(wxLANGUAGE_SPANISH_CHILE, wxe_util:get_const(wxLANGUAGE_SPANISH_CHILE)).
+-define(wxLANGUAGE_SPANISH_COLOMBIA, wxe_util:get_const(wxLANGUAGE_SPANISH_COLOMBIA)).
+-define(wxLANGUAGE_SPANISH_COSTA_RICA, wxe_util:get_const(wxLANGUAGE_SPANISH_COSTA_RICA)).
+-define(wxLANGUAGE_SPANISH_DOMINICAN_REPUBLIC, wxe_util:get_const(wxLANGUAGE_SPANISH_DOMINICAN_REPUBLIC)).
+-define(wxLANGUAGE_SPANISH_ECUADOR, wxe_util:get_const(wxLANGUAGE_SPANISH_ECUADOR)).
+-define(wxLANGUAGE_SPANISH_EL_SALVADOR, wxe_util:get_const(wxLANGUAGE_SPANISH_EL_SALVADOR)).
+-define(wxLANGUAGE_SPANISH_GUATEMALA, wxe_util:get_const(wxLANGUAGE_SPANISH_GUATEMALA)).
+-define(wxLANGUAGE_SPANISH_HONDURAS, wxe_util:get_const(wxLANGUAGE_SPANISH_HONDURAS)).
+-define(wxLANGUAGE_SPANISH_MEXICAN, wxe_util:get_const(wxLANGUAGE_SPANISH_MEXICAN)).
+-define(wxLANGUAGE_SPANISH_MODERN, wxe_util:get_const(wxLANGUAGE_SPANISH_MODERN)).
+-define(wxLANGUAGE_SPANISH_NICARAGUA, wxe_util:get_const(wxLANGUAGE_SPANISH_NICARAGUA)).
+-define(wxLANGUAGE_SPANISH_PANAMA, wxe_util:get_const(wxLANGUAGE_SPANISH_PANAMA)).
+-define(wxLANGUAGE_SPANISH_PARAGUAY, wxe_util:get_const(wxLANGUAGE_SPANISH_PARAGUAY)).
+-define(wxLANGUAGE_SPANISH_PERU, wxe_util:get_const(wxLANGUAGE_SPANISH_PERU)).
+-define(wxLANGUAGE_SPANISH_PUERTO_RICO, wxe_util:get_const(wxLANGUAGE_SPANISH_PUERTO_RICO)).
+-define(wxLANGUAGE_SPANISH_URUGUAY, wxe_util:get_const(wxLANGUAGE_SPANISH_URUGUAY)).
+-define(wxLANGUAGE_SPANISH_US, wxe_util:get_const(wxLANGUAGE_SPANISH_US)).
+-define(wxLANGUAGE_SPANISH_VENEZUELA, wxe_util:get_const(wxLANGUAGE_SPANISH_VENEZUELA)).
+-define(wxLANGUAGE_SUNDANESE, wxe_util:get_const(wxLANGUAGE_SUNDANESE)).
+-define(wxLANGUAGE_SWAHILI, wxe_util:get_const(wxLANGUAGE_SWAHILI)).
+-define(wxLANGUAGE_SWEDISH, wxe_util:get_const(wxLANGUAGE_SWEDISH)).
+-define(wxLANGUAGE_SWEDISH_FINLAND, wxe_util:get_const(wxLANGUAGE_SWEDISH_FINLAND)).
+-define(wxLANGUAGE_TAGALOG, wxe_util:get_const(wxLANGUAGE_TAGALOG)).
+-define(wxLANGUAGE_TAJIK, wxe_util:get_const(wxLANGUAGE_TAJIK)).
+-define(wxLANGUAGE_TAMIL, wxe_util:get_const(wxLANGUAGE_TAMIL)).
+-define(wxLANGUAGE_TATAR, wxe_util:get_const(wxLANGUAGE_TATAR)).
+-define(wxLANGUAGE_TELUGU, wxe_util:get_const(wxLANGUAGE_TELUGU)).
+-define(wxLANGUAGE_THAI, wxe_util:get_const(wxLANGUAGE_THAI)).
+-define(wxLANGUAGE_TIBETAN, wxe_util:get_const(wxLANGUAGE_TIBETAN)).
+-define(wxLANGUAGE_TIGRINYA, wxe_util:get_const(wxLANGUAGE_TIGRINYA)).
+-define(wxLANGUAGE_TONGA, wxe_util:get_const(wxLANGUAGE_TONGA)).
+-define(wxLANGUAGE_TSONGA, wxe_util:get_const(wxLANGUAGE_TSONGA)).
+-define(wxLANGUAGE_TURKISH, wxe_util:get_const(wxLANGUAGE_TURKISH)).
+-define(wxLANGUAGE_TURKMEN, wxe_util:get_const(wxLANGUAGE_TURKMEN)).
+-define(wxLANGUAGE_TWI, wxe_util:get_const(wxLANGUAGE_TWI)).
+-define(wxLANGUAGE_UIGHUR, wxe_util:get_const(wxLANGUAGE_UIGHUR)).
+-define(wxLANGUAGE_UKRAINIAN, wxe_util:get_const(wxLANGUAGE_UKRAINIAN)).
+-define(wxLANGUAGE_URDU, wxe_util:get_const(wxLANGUAGE_URDU)).
+-define(wxLANGUAGE_URDU_INDIA, wxe_util:get_const(wxLANGUAGE_URDU_INDIA)).
+-define(wxLANGUAGE_URDU_PAKISTAN, wxe_util:get_const(wxLANGUAGE_URDU_PAKISTAN)).
+-define(wxLANGUAGE_UZBEK, wxe_util:get_const(wxLANGUAGE_UZBEK)).
+-define(wxLANGUAGE_UZBEK_CYRILLIC, wxe_util:get_const(wxLANGUAGE_UZBEK_CYRILLIC)).
+-define(wxLANGUAGE_UZBEK_LATIN, wxe_util:get_const(wxLANGUAGE_UZBEK_LATIN)).
+-define(wxLANGUAGE_VIETNAMESE, wxe_util:get_const(wxLANGUAGE_VIETNAMESE)).
+-define(wxLANGUAGE_VOLAPUK, wxe_util:get_const(wxLANGUAGE_VOLAPUK)).
+-define(wxLANGUAGE_WELSH, wxe_util:get_const(wxLANGUAGE_WELSH)).
+-define(wxLANGUAGE_WOLOF, wxe_util:get_const(wxLANGUAGE_WOLOF)).
+-define(wxLANGUAGE_XHOSA, wxe_util:get_const(wxLANGUAGE_XHOSA)).
+-define(wxLANGUAGE_YIDDISH, wxe_util:get_const(wxLANGUAGE_YIDDISH)).
+-define(wxLANGUAGE_YORUBA, wxe_util:get_const(wxLANGUAGE_YORUBA)).
+-define(wxLANGUAGE_ZHUANG, wxe_util:get_const(wxLANGUAGE_ZHUANG)).
+-define(wxLANGUAGE_ZULU, wxe_util:get_const(wxLANGUAGE_ZULU)).
+-define(wxLANGUAGE_USER_DEFINED, wxe_util:get_const(wxLANGUAGE_USER_DEFINED)).
+-define(wxLANGUAGE_VALENCIAN, wxe_util:get_const(wxLANGUAGE_VALENCIAN)).
+-define(wxLANGUAGE_SAMI, wxe_util:get_const(wxLANGUAGE_SAMI)).
% From "intl.h": wxLayoutDirection
-define(wxLayout_Default, 0).
-define(wxLayout_LeftToRight, 1).
diff --git a/lib/wx/src/gen/wxEvtHandler.erl b/lib/wx/src/gen/wxEvtHandler.erl
index 6e9770bbb6..2d0a87f4dd 100644
--- a/lib/wx/src/gen/wxEvtHandler.erl
+++ b/lib/wx/src/gen/wxEvtHandler.erl
@@ -90,6 +90,8 @@ connect(This=#wx_ref{type=ThisT}, EventType, Options) ->
parse_opts([{callback,Fun}|R], Opts) when is_function(Fun) ->
%% Check Fun Arity?
parse_opts(R, Opts#evh{cb=Fun});
+parse_opts([{callback,CB={nospawn, Fun}}|R], Opts) when is_function(Fun) ->
+ parse_opts(R, Opts#evh{cb=CB});
parse_opts([callback|R], Opts) ->
parse_opts(R, Opts#evh{cb=self()});
parse_opts([{userData, UserData}|R],Opts) ->
diff --git a/lib/wx/src/gen/wxMouseCaptureLostEvent.erl b/lib/wx/src/gen/wxMouseCaptureLostEvent.erl
new file mode 100644
index 0000000000..a7e68a2d2f
--- /dev/null
+++ b/lib/wx/src/gen/wxMouseCaptureLostEvent.erl
@@ -0,0 +1,65 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2008-2015. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%% This file is generated DO NOT EDIT
+
+%% @doc See external documentation: <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxmousecapturelostevent.html">wxMouseCaptureLostEvent</a>.
+%% <dl><dt>Use {@link wxEvtHandler:connect/3.} with EventType:</dt>
+%% <dd><em>mouse_capture_lost</em></dd></dl>
+%% See also the message variant {@link wxEvtHandler:wxMouseCaptureLost(). #wxMouseCaptureLost{}} event record type.
+%%
+%% <p>This class is derived (and can use functions) from:
+%% <br />{@link wxEvent}
+%% </p>
+%% @type wxMouseCaptureLostEvent(). An object reference, The representation is internal
+%% and can be changed without notice. It can't be used for comparsion
+%% stored on disc or distributed for use on other nodes.
+
+-module(wxMouseCaptureLostEvent).
+-include("wxe.hrl").
+-export([]).
+
+%% inherited exports
+-export([getId/1,getSkipped/1,getTimestamp/1,isCommandEvent/1,parent_class/1,
+ resumePropagation/2,shouldPropagate/1,skip/1,skip/2,stopPropagation/1]).
+
+-export_type([wxMouseCaptureLostEvent/0]).
+%% @hidden
+parent_class(wxEvent) -> true;
+parent_class(_Class) -> erlang:error({badtype, ?MODULE}).
+
+-type wxMouseCaptureLostEvent() :: wx:wx_object().
+ %% From wxEvent
+%% @hidden
+stopPropagation(This) -> wxEvent:stopPropagation(This).
+%% @hidden
+skip(This, Options) -> wxEvent:skip(This, Options).
+%% @hidden
+skip(This) -> wxEvent:skip(This).
+%% @hidden
+shouldPropagate(This) -> wxEvent:shouldPropagate(This).
+%% @hidden
+resumePropagation(This,PropagationLevel) -> wxEvent:resumePropagation(This,PropagationLevel).
+%% @hidden
+isCommandEvent(This) -> wxEvent:isCommandEvent(This).
+%% @hidden
+getTimestamp(This) -> wxEvent:getTimestamp(This).
+%% @hidden
+getSkipped(This) -> wxEvent:getSkipped(This).
+%% @hidden
+getId(This) -> wxEvent:getId(This).
diff --git a/lib/wx/src/wxe_server.erl b/lib/wx/src/wxe_server.erl
index 6679fcfbe1..cc253b1143 100644
--- a/lib/wx/src/wxe_server.erl
+++ b/lib/wx/src/wxe_server.erl
@@ -240,6 +240,8 @@ handle_connect(Object, EvData=#evh{handler=Handler},
invoke_cb({{Ev=#wx{}, Ref=#wx_ref{}}, FunId,_}, _S) ->
%% Event callbacks
case get(FunId) of
+ {{nospawn, Fun}, _} when is_function(Fun) ->
+ invoke_callback_fun(fun() -> Fun(Ev, Ref), <<>> end);
{Fun,_} when is_function(Fun) ->
invoke_callback(fun() -> Fun(Ev, Ref), <<>> end);
{Pid,_} when is_pid(Pid) -> %% wx_object sync event
@@ -258,21 +260,10 @@ invoke_cb({FunId, Args, _}, _S) when is_list(Args), is_integer(FunId) ->
invoke_callback(Fun) ->
Env = get(?WXE_IDENTIFIER),
- CB = fun() ->
- wx:set_env(Env),
- wxe_util:cast(?WXE_CB_START, <<>>),
- Res = try
- Return = Fun(),
- true = is_binary(Return),
- Return
- catch _:Reason ->
- ?log("Callback fun crashed with {'EXIT, ~p, ~p}~n",
- [Reason, erlang:get_stacktrace()]),
- <<>>
- end,
- wxe_util:cast(?WXE_CB_RETURN, Res)
- end,
- spawn(CB),
+ spawn(fun() ->
+ wx:set_env(Env),
+ invoke_callback_fun(Fun)
+ end),
ok.
invoke_callback(Pid, Ev, Ref) ->
@@ -302,6 +293,20 @@ invoke_callback(Pid, Ev, Ref) ->
spawn(CB),
ok.
+invoke_callback_fun(Fun) ->
+ wxe_util:cast(?WXE_CB_START, <<>>),
+ Res = try
+ Return = Fun(),
+ true = is_binary(Return),
+ Return
+ catch _:Reason ->
+ ?log("Callback fun crashed with {'EXIT, ~p, ~p}~n",
+ [Reason, erlang:get_stacktrace()]),
+ <<>>
+ end,
+ wxe_util:cast(?WXE_CB_RETURN, Res).
+
+
get_wx_object_state(Pid) ->
case process_info(Pid, dictionary) of
{dictionary, Dict} ->
diff --git a/lib/wx/test/wx_class_SUITE.erl b/lib/wx/test/wx_class_SUITE.erl
index fd6023a820..465299a649 100644
--- a/lib/wx/test/wx_class_SUITE.erl
+++ b/lib/wx/test/wx_class_SUITE.erl
@@ -386,13 +386,17 @@ listCtrlSort(Config) ->
io:format("Sorted ~p ~n",[Time]),
Item = wxListItem:new(),
+
+ %% Force an assert on (and debug compiled) which 3.0 is by default
+ wxListItem:setId(Item, 200),
+ io:format("Got ~p ~n", [wxListCtrl:getItem(LC, Item)]),
+
wxListItem:setMask(Item, ?wxLIST_MASK_TEXT),
_List = wx:map(fun(Int) ->
wxListItem:setId(Item, Int),
?m(true, wxListCtrl:getItem(LC, Item)),
io:format("~p: ~s~n",[Int, wxListItem:getText(Item)])
end, lists:seq(0,10)),
- wxListItem:destroy(Item),
wx_test_lib:wx_destroy(Frame,Config).
@@ -525,7 +529,6 @@ toolbar(Config) ->
wxFrame:show(Frame),
wx_test_lib:wx_destroy(Frame,Config).
-
popup(TestInfo) when is_atom(TestInfo) -> wx_test_lib:tc_info(TestInfo);
popup(Config) ->
Wx = wx:new(),
@@ -575,3 +578,32 @@ popup(Config) ->
wxPopupTransientWindow:dismiss(Pop)
end,
wx_test_lib:wx_destroy(Frame,Config).
+
+locale(TestInfo) when is_atom(TestInfo) -> wx_test_lib:tc_info(TestInfo);
+locale(_Config) ->
+ wx:new(),
+ io:format("SystemEncoding: ~p~n",[wxLocale:getSystemEncoding()]),
+ io:format("SystemEncodingName: ~ts~n",[wxLocale:getSystemEncodingName()]),
+ io:format("SystemLanguage: ~p~n",[wxLocale:getSystemLanguage()]),
+ io:format("SystemLanguageName: ~p~n",[wxLocale:getLanguageName(wxLocale:getSystemLanguage())]),
+ lang_env(),
+ LC = wxLocale:new(),
+ %% wxLocale:addCatalog(LC, "wxstd"),
+ io:format("Swedish: ~p~n",[wxLocale:getLanguageName(?wxLANGUAGE_SWEDISH)]),
+ R0 = wxLocale:init(LC, [{language, ?wxLANGUAGE_SWEDISH}, {flags, 0}]),
+ io:format("initiated ~p~n",[R0]),
+ lang_env(),
+ ok.
+%% wx_test_lib:wx_destroy(Frame,Config).
+
+lang_env() ->
+ Env0 = os:getenv(),
+ Env = [[R,"\n"]||R <- Env0],
+ %%io:format("~p~n",[lists:sort(Env)]),
+ Opts = [global, multiline, {capture, all, list}],
+ format_env(re:run(Env, "LC_ALL.*", Opts)),
+ format_env(re:run(Env, "^LANG.*=.*$", Opts)),
+ ok.
+format_env({match, List}) ->
+ [io:format(" ~ts~n",[L]) || L <- List];
+format_env(nomatch) -> ok.
diff --git a/lib/wx/test/wx_event_SUITE.erl b/lib/wx/test/wx_event_SUITE.erl
index 2d6f7b6aaa..7e71d6ca69 100644
--- a/lib/wx/test/wx_event_SUITE.erl
+++ b/lib/wx/test/wx_event_SUITE.erl
@@ -78,7 +78,6 @@ connect(Config) ->
Tester ! {got_size, UserD}
end,
- ?m(ok, wxFrame:connect(Frame, size)),
?m(ok, wxEvtHandler:connect(Panel, size,[{skip, true},{userData, panel}])),
?m(ok, wxEvtHandler:connect(Panel, size,[{callback,CB},{userData, panel}])),
@@ -91,12 +90,16 @@ connect(Config) ->
?m(ok, wxWindow:connect(Window, size,[{callback,CB},{userData, window}])),
?m(ok, wxWindow:connect(Window, size,[{skip,true},{userData, window}])),
+ %% For trivial side effect free callbacks, can deadlock easily otherwise
+ CB1 = fun(_,_) -> Tester ! {got_size, nospawn_cb} end,
+ ?m(ok, wxWindow:connect(Frame, size, [{callback,{nospawn, CB1}}])),
+ ?m(ok, wxFrame:connect(Frame, size, [{skip, true}])),
?m(true, wxFrame:show(Frame)),
wxWindow:setSize(Panel, {200,100}),
wxWindow:setSize(Window, {200,100}),
- get_size_messages(Frame, [frame, panel_cb, window_cb, window]),
+ get_size_messages(Frame, [frame, panel_cb, window_cb, window, nospawn_cb]),
wx_test_lib:wx_destroy(Frame, Config).
@@ -115,7 +118,9 @@ get_size_messages(Frame, Msgs) ->
?m(false, lists:member(window, Msgs)),
get_size_messages(Frame, lists:delete(window_cb, Msgs));
{got_size,panel} ->
- get_size_messages(Frame, lists:delete(panel_cb, Msgs));
+ get_size_messages(Frame, lists:delete(panel_cb, Msgs));
+ {got_size,nospawn_cb} ->
+ get_size_messages(Frame, lists:delete(nospawn_cb, Msgs));
Other ->
?error("Got unexpected msg ~p ~p~n", [Other,Msgs])
after 1000 ->
diff --git a/otp_versions.table b/otp_versions.table
index 0c7be6f2c2..ff6c262743 100644
--- a/otp_versions.table
+++ b/otp_versions.table
@@ -1,5 +1,7 @@
+OTP-18.0.2 : erts-7.0.2 runtime_tools-1.9.1 # asn1-4.0 common_test-1.11 compiler-6.0 cosEvent-2.2 cosEventDomain-1.2 cosFileTransfer-1.2 cosNotification-1.2 cosProperty-1.2 cosTime-1.2 cosTransactions-1.3 crypto-3.6 debugger-4.1 dialyzer-2.8 diameter-1.10 edoc-0.7.17 eldap-1.2 erl_docgen-0.4 erl_interface-3.8 et-1.5.1 eunit-2.2.10 gs-1.6 hipe-3.12 ic-4.4 inets-6.0 jinterface-1.6 kernel-4.0 megaco-3.18 mnesia-4.13 observer-2.1 odbc-2.11 orber-3.8 os_mon-2.4 ose-1.1 otp_mibs-1.1 parsetools-2.1 percept-0.8.11 public_key-1.0 reltool-0.7 sasl-2.5 snmp-5.2 ssh-4.0 ssl-7.0 stdlib-2.5 syntax_tools-1.7 test_server-3.9 tools-2.8 typer-0.9.9 webtool-0.9 wx-1.4 xmerl-1.3.8 :
OTP-18.0.1 : erts-7.0.1 # asn1-4.0 common_test-1.11 compiler-6.0 cosEvent-2.2 cosEventDomain-1.2 cosFileTransfer-1.2 cosNotification-1.2 cosProperty-1.2 cosTime-1.2 cosTransactions-1.3 crypto-3.6 debugger-4.1 dialyzer-2.8 diameter-1.10 edoc-0.7.17 eldap-1.2 erl_docgen-0.4 erl_interface-3.8 et-1.5.1 eunit-2.2.10 gs-1.6 hipe-3.12 ic-4.4 inets-6.0 jinterface-1.6 kernel-4.0 megaco-3.18 mnesia-4.13 observer-2.1 odbc-2.11 orber-3.8 os_mon-2.4 ose-1.1 otp_mibs-1.1 parsetools-2.1 percept-0.8.11 public_key-1.0 reltool-0.7 runtime_tools-1.9 sasl-2.5 snmp-5.2 ssh-4.0 ssl-7.0 stdlib-2.5 syntax_tools-1.7 test_server-3.9 tools-2.8 typer-0.9.9 webtool-0.9 wx-1.4 xmerl-1.3.8 :
OTP-18.0 : asn1-4.0 common_test-1.11 compiler-6.0 cosEvent-2.2 cosEventDomain-1.2 cosFileTransfer-1.2 cosNotification-1.2 cosProperty-1.2 cosTime-1.2 cosTransactions-1.3 crypto-3.6 debugger-4.1 dialyzer-2.8 diameter-1.10 edoc-0.7.17 eldap-1.2 erl_docgen-0.4 erl_interface-3.8 erts-7.0 et-1.5.1 eunit-2.2.10 gs-1.6 hipe-3.12 ic-4.4 inets-6.0 jinterface-1.6 kernel-4.0 megaco-3.18 mnesia-4.13 observer-2.1 odbc-2.11 orber-3.8 os_mon-2.4 ose-1.1 otp_mibs-1.1 parsetools-2.1 percept-0.8.11 public_key-1.0 reltool-0.7 runtime_tools-1.9 sasl-2.5 snmp-5.2 ssh-4.0 ssl-7.0 stdlib-2.5 syntax_tools-1.7 test_server-3.9 tools-2.8 typer-0.9.9 webtool-0.9 wx-1.4 xmerl-1.3.8 # :
+OTP-17.5.6.2 : erts-6.4.1.2 runtime_tools-1.8.16.1 # asn1-3.0.4 common_test-1.10.1 compiler-5.0.4 cosEvent-2.1.15 cosEventDomain-1.1.14 cosFileTransfer-1.1.16 cosNotification-1.1.21 cosProperty-1.1.17 cosTime-1.1.14 cosTransactions-1.2.14 crypto-3.5 debugger-4.0.3 dialyzer-2.7.4 diameter-1.9.2 edoc-0.7.16 eldap-1.1.1 erl_docgen-0.3.7 erl_interface-3.7.20 et-1.5 eunit-2.2.9 gs-1.5.16 hipe-3.11.3 ic-4.3.6 inets-5.10.9 jinterface-1.5.12 kernel-3.2 megaco-3.17.3 mnesia-4.12.5 observer-2.0.4 odbc-2.10.22 orber-3.7.1 os_mon-2.3.1 ose-1.0.2 otp_mibs-1.0.10 parsetools-2.0.12 percept-0.8.10 public_key-0.23 reltool-0.6.6 sasl-2.4.1 snmp-5.1.2 ssh-3.2.4 ssl-6.0.1 stdlib-2.4 syntax_tools-1.6.18 test_server-3.8.1 tools-2.7.2 typer-0.9.8 webtool-0.8.10 wx-1.3.3 xmerl-1.3.7 :
OTP-17.5.6.1 : erts-6.4.1.1 # asn1-3.0.4 common_test-1.10.1 compiler-5.0.4 cosEvent-2.1.15 cosEventDomain-1.1.14 cosFileTransfer-1.1.16 cosNotification-1.1.21 cosProperty-1.1.17 cosTime-1.1.14 cosTransactions-1.2.14 crypto-3.5 debugger-4.0.3 dialyzer-2.7.4 diameter-1.9.2 edoc-0.7.16 eldap-1.1.1 erl_docgen-0.3.7 erl_interface-3.7.20 et-1.5 eunit-2.2.9 gs-1.5.16 hipe-3.11.3 ic-4.3.6 inets-5.10.9 jinterface-1.5.12 kernel-3.2 megaco-3.17.3 mnesia-4.12.5 observer-2.0.4 odbc-2.10.22 orber-3.7.1 os_mon-2.3.1 ose-1.0.2 otp_mibs-1.0.10 parsetools-2.0.12 percept-0.8.10 public_key-0.23 reltool-0.6.6 runtime_tools-1.8.16 sasl-2.4.1 snmp-5.1.2 ssh-3.2.4 ssl-6.0.1 stdlib-2.4 syntax_tools-1.6.18 test_server-3.8.1 tools-2.7.2 typer-0.9.8 webtool-0.8.10 wx-1.3.3 xmerl-1.3.7 :
OTP-17.5.6 : inets-5.10.9 ssh-3.2.4 ssl-6.0.1 # asn1-3.0.4 common_test-1.10.1 compiler-5.0.4 cosEvent-2.1.15 cosEventDomain-1.1.14 cosFileTransfer-1.1.16 cosNotification-1.1.21 cosProperty-1.1.17 cosTime-1.1.14 cosTransactions-1.2.14 crypto-3.5 debugger-4.0.3 dialyzer-2.7.4 diameter-1.9.2 edoc-0.7.16 eldap-1.1.1 erl_docgen-0.3.7 erl_interface-3.7.20 erts-6.4.1 et-1.5 eunit-2.2.9 gs-1.5.16 hipe-3.11.3 ic-4.3.6 jinterface-1.5.12 kernel-3.2 megaco-3.17.3 mnesia-4.12.5 observer-2.0.4 odbc-2.10.22 orber-3.7.1 os_mon-2.3.1 ose-1.0.2 otp_mibs-1.0.10 parsetools-2.0.12 percept-0.8.10 public_key-0.23 reltool-0.6.6 runtime_tools-1.8.16 sasl-2.4.1 snmp-5.1.2 stdlib-2.4 syntax_tools-1.6.18 test_server-3.8.1 tools-2.7.2 typer-0.9.8 webtool-0.8.10 wx-1.3.3 xmerl-1.3.7 :
OTP-17.5.5 : diameter-1.9.2 # asn1-3.0.4 common_test-1.10.1 compiler-5.0.4 cosEvent-2.1.15 cosEventDomain-1.1.14 cosFileTransfer-1.1.16 cosNotification-1.1.21 cosProperty-1.1.17 cosTime-1.1.14 cosTransactions-1.2.14 crypto-3.5 debugger-4.0.3 dialyzer-2.7.4 edoc-0.7.16 eldap-1.1.1 erl_docgen-0.3.7 erl_interface-3.7.20 erts-6.4.1 et-1.5 eunit-2.2.9 gs-1.5.16 hipe-3.11.3 ic-4.3.6 inets-5.10.8 jinterface-1.5.12 kernel-3.2 megaco-3.17.3 mnesia-4.12.5 observer-2.0.4 odbc-2.10.22 orber-3.7.1 os_mon-2.3.1 ose-1.0.2 otp_mibs-1.0.10 parsetools-2.0.12 percept-0.8.10 public_key-0.23 reltool-0.6.6 runtime_tools-1.8.16 sasl-2.4.1 snmp-5.1.2 ssh-3.2.3 ssl-6.0 stdlib-2.4 syntax_tools-1.6.18 test_server-3.8.1 tools-2.7.2 typer-0.9.8 webtool-0.8.10 wx-1.3.3 xmerl-1.3.7 :