aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator
diff options
context:
space:
mode:
Diffstat (limited to 'erts/emulator')
-rw-r--r--erts/emulator/beam/big.c88
-rw-r--r--erts/emulator/beam/big.h4
-rw-r--r--erts/emulator/beam/erl_nif.c34
-rw-r--r--erts/emulator/beam/erl_nif.h13
-rw-r--r--erts/emulator/beam/erl_nif_api_funcs.h14
-rw-r--r--erts/emulator/test/nif_SUITE_data/nif_SUITE.c63
6 files changed, 210 insertions, 6 deletions
diff --git a/erts/emulator/beam/big.c b/erts/emulator/beam/big.c
index 2d250f32cf..ff15d834ab 100644
--- a/erts/emulator/beam/big.c
+++ b/erts/emulator/beam/big.c
@@ -1881,6 +1881,9 @@ term_to_Uint(Eterm term, Uint *up)
int
term_to_UWord(Eterm term, UWord *up)
{
+#if SIZEOF_VOID_P == ERTS_SIZEOF_ETERM
+ return term_to_Uint(term,up);
+#else
if (is_small(term)) {
Sint i = signed_val(term);
if (i < 0) {
@@ -1903,7 +1906,47 @@ term_to_UWord(Eterm term, UWord *up)
return 0;
}
while (xl-- > 0) {
- uval |= ((Uint)(*xr++)) << n;
+ uval |= ((UWord)(*xr++)) << n;
+ n += D_EXP;
+ }
+ *up = uval;
+ return 1;
+ } else {
+ *up = BADARG;
+ return 0;
+ }
+#endif
+}
+
+int
+term_to_Uint64(Eterm term, Uint64 *up)
+{
+#if SIZEOF_VOID_P == 8
+ return term_to_UWord(term,up);
+#else
+ if (is_small(term)) {
+ Sint i = signed_val(term);
+ if (i < 0) {
+ *up = BADARG;
+ return 0;
+ }
+ *up = (Uint64) i;
+ return 1;
+ } else if (is_big(term)) {
+ ErtsDigit* xr = big_v(term);
+ dsize_t xl = big_size(term);
+ Uint64 uval = 0;
+ int n = 0;
+
+ if (big_sign(term)) {
+ *up = BADARG;
+ return 0;
+ } else if (xl*D_EXP > sizeof(Uint64)*8) {
+ *up = SYSTEM_LIMIT;
+ return 0;
+ }
+ while (xl-- > 0) {
+ uval |= ((Uint64)(*xr++)) << n;
n += D_EXP;
}
*up = uval;
@@ -1912,8 +1955,10 @@ term_to_UWord(Eterm term, UWord *up)
*up = BADARG;
return 0;
}
+#endif
}
+
int term_to_Sint(Eterm term, Sint *sp)
{
if (is_small(term)) {
@@ -1948,6 +1993,47 @@ int term_to_Sint(Eterm term, Sint *sp)
}
}
+#if HAVE_INT64
+int term_to_Sint64(Eterm term, Sint64 *sp)
+{
+#if ERTS_SIZEOF_ETERM == 8
+ return term_to_Sint(term, sp);
+#else
+ if (is_small(term)) {
+ *sp = signed_val(term);
+ return 1;
+ } else if (is_big(term)) {
+ ErtsDigit* xr = big_v(term);
+ dsize_t xl = big_size(term);
+ int sign = big_sign(term);
+ Uint64 uval = 0;
+ int n = 0;
+
+ if (xl*D_EXP > sizeof(Uint64)*8) {
+ return 0;
+ }
+ while (xl-- > 0) {
+ uval |= ((Uint64)(*xr++)) << n;
+ n += D_EXP;
+ }
+ if (sign) {
+ uval = -uval;
+ if ((Sint64)uval > 0)
+ return 0;
+ } else {
+ if ((Sint64)uval < 0)
+ return 0;
+ }
+ *sp = uval;
+ return 1;
+ } else {
+ return 0;
+ }
+#endif
+}
+#endif /* HAVE_INT64 */
+
+
/*
** Add and subtract
*/
diff --git a/erts/emulator/beam/big.h b/erts/emulator/beam/big.h
index 56f3be372a..25466cd3c2 100644
--- a/erts/emulator/beam/big.h
+++ b/erts/emulator/beam/big.h
@@ -152,6 +152,10 @@ byte* big_to_bytes(Eterm, byte*);
int term_to_Uint(Eterm, Uint*);
int term_to_UWord(Eterm, UWord*);
int term_to_Sint(Eterm, Sint*);
+#if HAVE_INT64
+int term_to_Uint64(Eterm, Uint64*);
+int term_to_Sint64(Eterm, Sint64*);
+#endif
Uint32 big_to_uint32(Eterm b);
int term_equals_2pow32(Eterm);
diff --git a/erts/emulator/beam/erl_nif.c b/erts/emulator/beam/erl_nif.c
index e95d9c4f75..255794f030 100644
--- a/erts/emulator/beam/erl_nif.c
+++ b/erts/emulator/beam/erl_nif.c
@@ -750,7 +750,19 @@ int enif_get_ulong(ErlNifEnv* env, Eterm term, unsigned long* ip)
#endif
}
-int enif_get_double(ErlNifEnv* env, Eterm term, double* dp)
+#if HAVE_INT64 && SIZEOF_LONG != 8
+int enif_get_int64(ErlNifEnv* env, ERL_NIF_TERM term, ErlNifSInt64* ip)
+{
+ return term_to_Sint64(term, ip);
+}
+
+int enif_get_uint64(ErlNifEnv* env, ERL_NIF_TERM term, ErlNifUInt64* ip)
+{
+ return term_to_Uint64(term, ip);
+}
+#endif /* HAVE_INT64 && SIZEOF_LONG != 8 */
+
+int enif_get_double(ErlNifEnv* env, ERL_NIF_TERM term, double* dp)
{
FloatDef f;
if (is_not_float(term)) {
@@ -817,6 +829,26 @@ ERL_NIF_TERM enif_make_ulong(ErlNifEnv* env, unsigned long i)
return IS_USMALL(0,i) ? make_small(i) : uint_to_big(i,alloc_heap(env,2));
}
+#if HAVE_INT64 && SIZEOF_LONG != 8
+ERL_NIF_TERM enif_make_int64(ErlNifEnv* env, ErlNifSInt64 i)
+{
+ Uint* hp;
+ Uint need = 0;
+ erts_bld_sint64(NULL, &need, i);
+ hp = alloc_heap(env, need);
+ return erts_bld_sint64(&hp, NULL, i);
+}
+
+ERL_NIF_TERM enif_make_uint64(ErlNifEnv* env, ErlNifUInt64 i)
+{
+ Uint* hp;
+ Uint need = 0;
+ erts_bld_uint64(NULL, &need, i);
+ hp = alloc_heap(env, need);
+ return erts_bld_uint64(&hp, NULL, i);
+}
+#endif /* HAVE_INT64 && SIZEOF_LONG != 8 */
+
ERL_NIF_TERM enif_make_double(ErlNifEnv* env, double d)
{
Eterm* hp = alloc_heap(env,FLOAT_SIZE_OBJECT);
diff --git a/erts/emulator/beam/erl_nif.h b/erts/emulator/beam/erl_nif.h
index 936f03bce1..533c92cb28 100644
--- a/erts/emulator/beam/erl_nif.h
+++ b/erts/emulator/beam/erl_nif.h
@@ -66,6 +66,19 @@
extern "C" {
#endif
+#if defined(__WIN32__)
+typedef unsigned __int64 ErlNifUInt64;
+typedef __int64 ErlNifSInt64;
+#elif SIZEOF_LONG == 8
+typedef unsigned long ErlNifUInt64;
+typedef long ErlNifSInt64;
+#elif SIZEOF_LONG_LONG == 8
+typedef unsigned long long ErlNifUInt64;
+typedef long long ErlNifSInt64;
+#else
+#error No 64-bit integer type
+#endif
+
#ifdef HALFWORD_HEAP_EMULATOR
typedef unsigned int ERL_NIF_TERM;
#else
diff --git a/erts/emulator/beam/erl_nif_api_funcs.h b/erts/emulator/beam/erl_nif_api_funcs.h
index ef4e9580b0..d538200860 100644
--- a/erts/emulator/beam/erl_nif_api_funcs.h
+++ b/erts/emulator/beam/erl_nif_api_funcs.h
@@ -122,6 +122,12 @@ ERL_NIF_API_FUNC_DECL(ErlNifPid*,enif_self,(ErlNifEnv* caller_env, ErlNifPid* pi
ERL_NIF_API_FUNC_DECL(int,enif_get_local_pid,(ErlNifEnv* env, ERL_NIF_TERM, ErlNifPid* pid));
ERL_NIF_API_FUNC_DECL(void,enif_keep_resource,(void* obj));
ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_resource_binary,(ErlNifEnv*,void* obj,const void* data, size_t size));
+#if SIZEOF_LONG != 8
+ERL_NIF_API_FUNC_DECL(int,enif_get_int64,(ErlNifEnv*, ERL_NIF_TERM term, ErlNifSInt64* ip));
+ERL_NIF_API_FUNC_DECL(int,enif_get_uint64,(ErlNifEnv*, ERL_NIF_TERM term, ErlNifUInt64* ip));
+ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_int64,(ErlNifEnv*, ErlNifSInt64));
+ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_uint64,(ErlNifEnv*, ErlNifUInt64));
+#endif
/*
** Add last to keep compatibility on Windows!!!
@@ -253,5 +259,13 @@ ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_resource_binary,(ErlNifEnv*,void* o
# define enif_make_tuple9(ENV,E1,E2,E3,E4,E5,E6,E7,E8,E9) enif_make_tuple(ENV,9,E1,E2,E3,E4,E5,E6,E7,E8,E9)
# define enif_make_pid(ENV, PID) ((const ERL_NIF_TERM)((PID)->pid))
+
+#if SIZEOF_LONG == 8
+# define enif_get_int64 enif_get_long
+# define enif_get_uint64 enif_get_ulong
+# define enif_make_int64 enif_make_long
+# define enif_make_uint64 enif_make_ulong
+#endif
+
#endif
diff --git a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c
index 17f644829f..5384a32f21 100644
--- a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c
+++ b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c
@@ -296,6 +296,30 @@ static int test_ulong(ErlNifEnv* env, unsigned long i1)
return 1;
}
+static int test_int64(ErlNifEnv* env, ErlNifSInt64 i1)
+{
+ ErlNifSInt64 i2 = 0;
+ ERL_NIF_TERM int_term = enif_make_int64(env, i1);
+ if (!enif_get_int64(env,int_term, &i2) || i1 != i2) {
+ fprintf(stderr, "test_int64(%ld) ...FAILED i2=%ld\r\n",
+ (long)i1, (long)i2);
+ return 0;
+ }
+ return 1;
+}
+
+static int test_uint64(ErlNifEnv* env, ErlNifUInt64 i1)
+{
+ ErlNifUInt64 i2 = 0;
+ ERL_NIF_TERM int_term = enif_make_uint64(env, i1);
+ if (!enif_get_uint64(env,int_term, &i2) || i1 != i2) {
+ fprintf(stderr, "test_ulong(%lu) ...FAILED i2=%lu\r\n",
+ (unsigned long)i1, (unsigned long)i2);
+ return 0;
+ }
+ return 1;
+}
+
static int test_double(ErlNifEnv* env, double d1)
{
double d2 = 0;
@@ -319,6 +343,8 @@ static ERL_NIF_TERM type_test(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[
unsigned uint;
long slong;
unsigned long ulong;
+ ErlNifSInt64 sint64;
+ ErlNifUInt64 uint64;
double d;
ERL_NIF_TERM atom, ref1, ref2;
@@ -352,11 +378,25 @@ static ERL_NIF_TERM type_test(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[
slong -= slong / 3 + 1;
} while (slong >= 0);
+ sint64 = ((ErlNifSInt64)1 << 63); /* INT64_MIN */
+ do {
+ if (!test_int64(env,sint64)) {
+ goto error;
+ }
+ sint64 += ~sint64 / 3 + 1;
+ } while (sint64 < 0);
+ sint64 = ((ErlNifUInt64)1 << 63) - 1; /* INT64_MAX */
+ do {
+ if (!test_int64(env,sint64)) {
+ goto error;
+ }
+ sint64 -= sint64 / 3 + 1;
+ } while (sint64 >= 0);
uint = UINT_MAX;
for (;;) {
if (!test_uint(env,uint)) {
-
+ goto error;
}
if (uint == 0) break;
uint -= uint / 3 + 1;
@@ -364,11 +404,19 @@ static ERL_NIF_TERM type_test(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[
ulong = ULONG_MAX;
for (;;) {
if (!test_ulong(env,ulong)) {
-
+ goto error;
}
if (ulong == 0) break;
ulong -= ulong / 3 + 1;
}
+ uint64 = (ErlNifUInt64)-1; /* UINT64_MAX */
+ for (;;) {
+ if (!test_uint64(env,uint64)) {
+ goto error;
+ }
+ if (uint64 == 0) break;
+ uint64 -= uint64 / 3 + 1;
+ }
if (MAX_SMALL < INT_MAX) { /* 32-bit */
for (i=-10 ; i <= 10; i++) {
@@ -391,11 +439,18 @@ static ERL_NIF_TERM type_test(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[
for (i=-10 ; i < 10; i++) {
if (!test_long(env,MAX_SMALL+i) || !test_ulong(env,MAX_SMALL+i) ||
- !test_long(env,MIN_SMALL+i)) {
+ !test_long(env,MIN_SMALL+i) ||
+ !test_int64(env,MAX_SMALL+i) || !test_uint64(env,MAX_SMALL+i) ||
+ !test_int64(env,MIN_SMALL+i)) {
goto error;
}
+ if (MAX_SMALL < INT_MAX) {
+ if (!test_int(env,MAX_SMALL+i) || !test_uint(env,MAX_SMALL+i) ||
+ !test_int(env,MIN_SMALL+i)) {
+ goto error;
+ }
+ }
}
-
for (d=3.141592e-100 ; d < 1e100 ; d *= 9.97) {
if (!test_double(env,d) || !test_double(env,-d)) {
goto error;