1 /*
2  * %CopyrightBegin%
3  *
4  * Copyright Ericsson AB 2012-2020. All Rights Reserved.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  * %CopyrightEnd%
19  */
20 
21 #ifndef ERL_UTILS_H__
22 #define ERL_UTILS_H__
23 
24 #include "sys.h"
25 #include "atom.h"
26 #include "erl_printf.h"
27 
28 struct process;
29 
30 typedef struct {
31     union {
32 	Uint64 not_atomic;
33 	erts_atomic64_t atomic;
34     } counter;
35 } erts_interval_t;
36 
37 void erts_interval_init(erts_interval_t *);
38 Uint64 erts_step_interval_nob(erts_interval_t *);
39 Uint64 erts_step_interval_relb(erts_interval_t *);
40 Uint64 erts_ensure_later_interval_nob(erts_interval_t *, Uint64);
41 Uint64 erts_ensure_later_interval_acqb(erts_interval_t *, Uint64);
42 ERTS_GLB_INLINE Uint64 erts_current_interval_nob(erts_interval_t *);
43 ERTS_GLB_INLINE Uint64 erts_current_interval_acqb(erts_interval_t *);
44 
45 #if ERTS_GLB_INLINE_INCL_FUNC_DEF
46 
47 ERTS_GLB_INLINE Uint64
erts_current_interval_nob(erts_interval_t * icp)48 erts_current_interval_nob(erts_interval_t *icp)
49 {
50     return (Uint64) erts_atomic64_read_nob(&icp->counter.atomic);
51 }
52 
53 ERTS_GLB_INLINE Uint64
erts_current_interval_acqb(erts_interval_t * icp)54 erts_current_interval_acqb(erts_interval_t *icp)
55 {
56     return (Uint64) erts_atomic64_read_acqb(&icp->counter.atomic);
57 }
58 
59 #endif /* ERTS_GLB_INLINE_INCL_FUNC_DEF */
60 
61 /*
62  * To be used to silence unused result warnings, but do not abuse it.
63  */
64 void erts_silence_warn_unused_result(long unused);
65 
66 
67 int erts_fit_in_bits_int64(Sint64);
68 int erts_fit_in_bits_int32(Sint32);
69 int erts_fit_in_bits_uint(Uint);
70 Sint erts_list_length(Eterm);
71 int erts_is_builtin(Eterm, Eterm, int);
72 Uint32 make_hash2(Eterm);
73 Uint32 trapping_make_hash2(Eterm, Eterm*, struct process*);
74 Uint32 make_hash(Eterm);
75 Uint32 make_internal_hash(Eterm, Uint32 salt);
76 
77 void erts_save_emu_args(int argc, char **argv);
78 Eterm erts_get_emu_args(struct process *c_p);
79 Eterm erts_get_ethread_info(struct process * c_p);
80 
81 Eterm erts_bld_atom(Uint **hpp, Uint *szp, char *str);
82 Eterm erts_bld_uint(Uint **hpp, Uint *szp, Uint ui);
83 Eterm erts_bld_uword(Uint **hpp, Uint *szp, UWord uw);
84 Eterm erts_bld_uint64(Uint **hpp, Uint *szp, Uint64 ui64);
85 Eterm erts_bld_sint64(Uint **hpp, Uint *szp, Sint64 si64);
86 #define erts_bld_monotonic_time erts_bld_sint64
87 Eterm erts_bld_cons(Uint **hpp, Uint *szp, Eterm car, Eterm cdr);
88 Eterm erts_bld_tuple(Uint **hpp, Uint *szp, Uint arity, ...);
89 #define erts_bld_tuple2(H,S,E1,E2) erts_bld_tuple(H,S,2,E1,E2)
90 #define erts_bld_tuple3(H,S,E1,E2,E3) erts_bld_tuple(H,S,3,E1,E2,E3)
91 #define erts_bld_tuple4(H,S,E1,E2,E3,E4) erts_bld_tuple(H,S,4,E1,E2,E3,E4)
92 #define erts_bld_tuple5(H,S,E1,E2,E3,E4,E5) erts_bld_tuple(H,S,5,E1,E2,E3,E4,E5)
93 Eterm erts_bld_tuplev(Uint **hpp, Uint *szp, Uint arity, Eterm terms[]);
94 Eterm erts_bld_string_n(Uint **hpp, Uint *szp, const char *str, Sint len);
95 #define erts_bld_string(hpp,szp,str) erts_bld_string_n(hpp,szp,str,sys_strlen(str))
96 Eterm erts_bld_list(Uint **hpp, Uint *szp, Sint length, Eterm terms[]);
97 Eterm erts_bld_2tup_list(Uint **hpp, Uint *szp,
98 			 Sint length, Eterm terms1[], Uint terms2[]);
99 Eterm
100 erts_bld_atom_uword_2tup_list(Uint **hpp, Uint *szp,
101 			     Sint length, Eterm atoms[], UWord uints[]);
102 Eterm
103 erts_bld_atom_2uint_3tup_list(Uint **hpp, Uint *szp, Sint length,
104 			      Eterm atoms[], Uint uints1[], Uint uints2[]);
105 
106 void erts_init_utils(void);
107 void erts_init_utils_mem(void);
108 
109 erts_dsprintf_buf_t *erts_create_tmp_dsbuf(Uint);
110 void erts_destroy_tmp_dsbuf(erts_dsprintf_buf_t *);
111 
112 int eq(Eterm, Eterm);
113 
114 #define EQ(x,y) (((x) == (y)) || (is_not_both_immed((x),(y)) && eq((x),(y))))
115 
116 ERTS_GLB_INLINE Sint erts_cmp(Eterm, Eterm, int, int);
117 ERTS_GLB_INLINE int erts_cmp_atoms(Eterm a, Eterm b);
118 
119 Sint cmp(Eterm a, Eterm b);
120 Sint erts_cmp_compound(Eterm, Eterm, int, int);
121 
122 #define CMP(A,B)                         erts_cmp(A,B,0,0)
123 #define CMP_TERM(A,B)                    erts_cmp(A,B,1,0)
124 #define CMP_EQ_ONLY(A,B)                 erts_cmp(A,B,0,1)
125 
126 #define CMP_LT(a,b)          ((a) != (b) && CMP((a),(b)) <  0)
127 #define CMP_LE(a,b)          ((a) == (b) || CMP((a),(b)) <= 0)
128 #define CMP_EQ(a,b)          ((a) == (b) || CMP_EQ_ONLY((a),(b)) == 0)
129 #define CMP_NE(a,b)          ((a) != (b) && CMP_EQ_ONLY((a),(b)) != 0)
130 #define CMP_GE(a,b)          ((a) == (b) || CMP((a),(b)) >= 0)
131 #define CMP_GT(a,b)          ((a) != (b) && CMP((a),(b)) >  0)
132 
133 #define CMP_EQ_ACTION(X,Y,Action)	\
134     if ((X) != (Y)) { EQ_SPEC((X),(Y),!=,Action); }
135 #define CMP_NE_ACTION(X,Y,Action)	\
136     if ((X) == (Y)) { Action; } else { EQ_SPEC((X),(Y),==,Action); }
137 
138 #define EQ_SPEC(X,Y,Op,Action)                                  \
139     if (is_both_immed(X, Y)) {                                  \
140         if (X Op Y) { Action; };                                \
141     } else if (is_float(X) && is_float(Y)) {                    \
142         FloatDef af, bf;                                        \
143         GET_DOUBLE(X, af);                                      \
144         GET_DOUBLE(Y, bf);                                      \
145         if (af.fd Op bf.fd) { Action; };                        \
146     } else {                                                    \
147         if (erts_cmp_compound(X,Y,0,1) Op 0) { Action; };       \
148     }
149 
150 #define CMP_GE_ACTION(X,Y,Action)                       \
151     if ((X) != (Y)) { CMP_SPEC((X),(Y),<,Action); }
152 #define CMP_LT_ACTION(X,Y,Action)	\
153     if ((X) == (Y)) { Action; } else { CMP_SPEC((X),(Y),>=,Action); }
154 
155 #define CMP_SPEC(X,Y,Op,Action)                                 \
156     if (is_atom(X) && is_atom(Y)) {				\
157 	if (erts_cmp_atoms(X, Y) Op 0) { Action; };		\
158     } else if (is_both_small(X, Y)) {				\
159 	if (signed_val(X) Op signed_val(Y)) { Action; };	\
160     } else if (is_float(X) && is_float(Y)) {			\
161         FloatDef af, bf;					\
162         GET_DOUBLE(X, af);					\
163         GET_DOUBLE(Y, bf);					\
164         if (af.fd Op bf.fd) { Action; };			\
165     } else {							\
166 	if (erts_cmp_compound(X,Y,0,0) Op 0) { Action; };	\
167     }
168 
169 /*
170  * When either operand for is_lt or is_ge is a literal, that literal is
171  * almost always an integer and almost never an atom. Therefore, only
172  * special case the comparison of small integers before calling the
173  * general compare function.
174  */
175 
176 #define CMP_GE_LITERAL_ACTION(X,Y,Action)                       \
177     if ((X) != (Y)) { CMP_LITERAL_SPEC((X),(Y),<,Action); }
178 #define CMP_LT_LITERAL_ACTION(X,Y,Action)	\
179     if ((X) == (Y)) { Action; } else { CMP_LITERAL_SPEC((X),(Y),>=,Action); }
180 
181 #define CMP_LITERAL_SPEC(X,Y,Op,Action)                         \
182     if (is_both_small(X, Y)) {                                  \
183         if (signed_val(X) Op signed_val(Y)) { Action; };        \
184     } else {                                                    \
185         if (erts_cmp_compound(X,Y,0,0) Op 0) { Action; };       \
186     }
187 
188 #define erts_float_comp(x,y) (((x)<(y)) ? -1 : (((x)==(y)) ? 0 : 1))
189 
190 #if ERTS_GLB_INLINE_INCL_FUNC_DEF
191 
erts_cmp_atoms(Eterm a,Eterm b)192 ERTS_GLB_INLINE int erts_cmp_atoms(Eterm a, Eterm b) {
193     Atom *aa = atom_tab(atom_val(a));
194     Atom *bb = atom_tab(atom_val(b));
195 
196     byte *name_a, *name_b;
197     int len_a, len_b, diff;
198 
199     diff = aa->ord0 - bb->ord0;
200 
201     if (diff != 0) {
202         return diff;
203     }
204 
205     name_a = &aa->name[3];
206     name_b = &bb->name[3];
207     len_a = aa->len-3;
208     len_b = bb->len-3;
209 
210     if (len_a > 0 && len_b > 0) {
211         diff = sys_memcmp(name_a, name_b, MIN(len_a, len_b));
212 
213         if (diff != 0) {
214             return diff;
215         }
216     }
217 
218     return len_a - len_b;
219 }
220 
erts_cmp(Eterm a,Eterm b,int exact,int eq_only)221 ERTS_GLB_INLINE Sint erts_cmp(Eterm a, Eterm b, int exact, int eq_only) {
222     if (is_atom(a) && is_atom(b)) {
223         return erts_cmp_atoms(a, b);
224     } else if (is_both_small(a, b)) {
225         return (signed_val(a) - signed_val(b));
226     } else if (is_float(a) && is_float(b)) {
227         FloatDef af, bf;
228 
229         GET_DOUBLE(a, af);
230         GET_DOUBLE(b, bf);
231 
232         return erts_float_comp(af.fd, bf.fd);
233     }
234 
235     return erts_cmp_compound(a,b,exact,eq_only);
236 }
237 
238 #endif /* ERTS_GLB_INLINE_INCL_FUNC_DEF */
239 
240 #endif
241