in erts/emulator/beam/utils.c [2710:3073]
int eq(Eterm a, Eterm b)
{
DECLARE_WSTACK(stack);
Sint sz;
Eterm* aa;
Eterm* bb;
tailrecur:
if (is_same(a, b)) goto pop_next;
tailrecur_ne:
switch (primary_tag(a)) {
case TAG_PRIMARY_LIST:
if (is_list(b)) {
Eterm* aval = list_val(a);
Eterm* bval = list_val(b);
while (1) {
Eterm atmp = CAR(aval);
Eterm btmp = CAR(bval);
if (!is_same(atmp,btmp)) {
WSTACK_PUSH2(stack,(UWord) CDR(bval),(UWord) CDR(aval));
a = atmp;
b = btmp;
goto tailrecur_ne;
}
atmp = CDR(aval);
btmp = CDR(bval);
if (is_same(atmp,btmp)) {
goto pop_next;
}
if (is_not_list(atmp) || is_not_list(btmp)) {
a = atmp;
b = btmp;
goto tailrecur_ne;
}
aval = list_val(atmp);
bval = list_val(btmp);
}
}
break; /* not equal */
case TAG_PRIMARY_BOXED:
{
Eterm hdr = *boxed_val(a);
switch (hdr & _TAG_HEADER_MASK) {
case ARITYVAL_SUBTAG:
{
aa = tuple_val(a);
if (!is_boxed(b) || *boxed_val(b) != *aa)
goto not_equal;
bb = tuple_val(b);
if ((sz = arityval(*aa)) == 0) goto pop_next;
++aa;
++bb;
goto term_array;
}
case REFC_BINARY_SUBTAG:
case HEAP_BINARY_SUBTAG:
case SUB_BINARY_SUBTAG:
{
byte* a_ptr;
byte* b_ptr;
size_t a_size;
size_t b_size;
Uint a_bitsize;
Uint b_bitsize;
Uint a_bitoffs;
Uint b_bitoffs;
if (!is_binary(b)) {
goto not_equal;
}
a_size = binary_size(a);
b_size = binary_size(b);
if (a_size != b_size) {
goto not_equal;
}
ERTS_GET_BINARY_BYTES(a, a_ptr, a_bitoffs, a_bitsize);
ERTS_GET_BINARY_BYTES(b, b_ptr, b_bitoffs, b_bitsize);
if ((a_bitsize | b_bitsize | a_bitoffs | b_bitoffs) == 0) {
if (sys_memcmp(a_ptr, b_ptr, a_size) == 0) goto pop_next;
} else if (a_bitsize == b_bitsize) {
if (erts_cmp_bits(a_ptr, a_bitoffs, b_ptr, b_bitoffs,
(a_size << 3) + a_bitsize) == 0) goto pop_next;
}
break; /* not equal */
}
case EXPORT_SUBTAG:
{
if (is_export(b)) {
Export* a_exp = *((Export **) (export_val(a) + 1));
Export* b_exp = *((Export **) (export_val(b) + 1));
if (a_exp == b_exp) goto pop_next;
}
break; /* not equal */
}
case FUN_SUBTAG:
{
ErlFunThing* f1;
ErlFunThing* f2;
if (!is_fun(b))
goto not_equal;
f1 = (ErlFunThing *) fun_val(a);
f2 = (ErlFunThing *) fun_val(b);
if (f1->fe->module != f2->fe->module ||
f1->fe->index != f2->fe->index ||
f1->fe->old_uniq != f2->fe->old_uniq ||
f1->num_free != f2->num_free) {
goto not_equal;
}
if ((sz = f1->num_free) == 0) goto pop_next;
aa = f1->env;
bb = f2->env;
goto term_array;
}
case EXTERNAL_PID_SUBTAG: {
ExternalThing *ap;
ExternalThing *bp;
int i;
if(!is_external(b))
goto not_equal;
ap = external_thing_ptr(a);
bp = external_thing_ptr(b);
if(ap->header != bp->header || ap->node != bp->node)
goto not_equal;
ASSERT(external_data_words(a) == EXTERNAL_PID_DATA_WORDS);
ASSERT(external_data_words(b) == EXTERNAL_PID_DATA_WORDS);
for (i = 0; i < EXTERNAL_PID_DATA_WORDS; i++) {
if (ap->data.ui[i] != bp->data.ui[i])
goto not_equal;
}
goto pop_next;
}
case EXTERNAL_PORT_SUBTAG: {
ExternalThing *ap;
ExternalThing *bp;
if(!is_external(b))
goto not_equal;
ap = external_thing_ptr(a);
bp = external_thing_ptr(b);
if(ap->header == bp->header && ap->node == bp->node) {
ASSERT(1 == external_data_words(a));
ASSERT(1 == external_data_words(b));
if (ap->data.ui[0] == bp->data.ui[0]) goto pop_next;
}
break; /* not equal */
}
case EXTERNAL_REF_SUBTAG: {
/*
* Observe!
* When comparing refs we need to compare ref numbers
* (32-bit words) *not* ref data words.
*/
Uint32 *anum;
Uint32 *bnum;
Uint common_len;
Uint alen;
Uint blen;
Uint i;
ExternalThing* athing;
ExternalThing* bthing;
if(!is_external_ref(b))
goto not_equal;
athing = external_thing_ptr(a);
bthing = external_thing_ptr(b);
if(athing->node != bthing->node)
goto not_equal;
anum = external_thing_ref_numbers(athing);
bnum = external_thing_ref_numbers(bthing);
alen = external_thing_ref_no_numbers(athing);
blen = external_thing_ref_no_numbers(bthing);
goto ref_common;
case REF_SUBTAG:
if (!is_internal_ref(b))
goto not_equal;
alen = internal_ref_no_numbers(a);
anum = internal_ref_numbers(a);
blen = internal_ref_no_numbers(b);
bnum = internal_ref_numbers(b);
ref_common:
ASSERT(alen > 0 && blen > 0);
if (anum[0] != bnum[0])
goto not_equal;
if (alen == 3 && blen == 3) {
/* Most refs are of length 3 */
if (anum[1] == bnum[1] && anum[2] == bnum[2]) {
goto pop_next;
} else {
goto not_equal;
}
}
common_len = alen;
if (blen < alen)
common_len = blen;
for (i = 1; i < common_len; i++)
if (anum[i] != bnum[i])
goto not_equal;
if(alen != blen) {
if (alen > blen) {
for (i = common_len; i < alen; i++)
if (anum[i] != 0)
goto not_equal;
}
else {
for (i = common_len; i < blen; i++)
if (bnum[i] != 0)
goto not_equal;
}
}
goto pop_next;
}
case POS_BIG_SUBTAG:
case NEG_BIG_SUBTAG:
{
int i;
if (!is_big(b))
goto not_equal;
aa = big_val(a);
bb = big_val(b);
if (*aa != *bb)
goto not_equal;
i = BIG_ARITY(aa);
while(i--) {
if (*++aa != *++bb)
goto not_equal;
}
goto pop_next;
}
case FLOAT_SUBTAG:
{
FloatDef af;
FloatDef bf;
if (is_float(b)) {
GET_DOUBLE(a, af);
GET_DOUBLE(b, bf);
if (af.fd == bf.fd) goto pop_next;
}
break; /* not equal */
}
case MAP_SUBTAG:
if (is_flatmap(a)) {
aa = flatmap_val(a);
if (!is_boxed(b) || *boxed_val(b) != *aa)
goto not_equal;
bb = flatmap_val(b);
sz = flatmap_get_size((flatmap_t*)aa);
if (sz != flatmap_get_size((flatmap_t*)bb)) goto not_equal;
if (sz == 0) goto pop_next;
aa += 2;
bb += 2;
sz += 1; /* increment for tuple-keys */
goto term_array;
} else {
if (!is_boxed(b) || *boxed_val(b) != hdr)
goto not_equal;
aa = hashmap_val(a) + 1;
bb = hashmap_val(b) + 1;
switch (hdr & _HEADER_MAP_SUBTAG_MASK) {
case HAMT_SUBTAG_HEAD_ARRAY:
if (aa[0] != bb[0])
goto not_equal;
aa++; bb++;
sz = 16;
break;
case HAMT_SUBTAG_HEAD_BITMAP:
if (aa[0] != bb[0])
goto not_equal;
aa++; bb++;
case HAMT_SUBTAG_NODE_BITMAP:
sz = hashmap_bitcount(MAP_HEADER_VAL(hdr));
ASSERT(sz > 0 && sz < 17);
break;
default:
erts_exit(ERTS_ERROR_EXIT, "Unknown hashmap subsubtag\n");
}
goto term_array;
}
default:
ASSERT(!"Unknown boxed subtab in EQ");
}
break;
}
}
goto not_equal;
term_array: /* arrays in 'aa' and 'bb', length in 'sz' */
ASSERT(sz != 0);
{
Eterm* ap = aa;
Eterm* bp = bb;
Sint i = sz;
for (;;) {
if (!is_same(*ap,*bp)) break;
if (--i == 0) goto pop_next;
++ap;
++bp;
}
a = *ap;
b = *bp;
if (is_both_immed(a,b)) {
goto not_equal;
}
if (i > 1) { /* push the rest */
WSTACK_PUSH3(stack, i-1, (UWord)(bp+1),
((UWord)(ap+1)) | TAG_PRIMARY_HEADER);
/* We (ab)use TAG_PRIMARY_HEADER to recognize a term_array */
}
goto tailrecur_ne;
}
pop_next:
if (!WSTACK_ISEMPTY(stack)) {
UWord something = WSTACK_POP(stack);
if (primary_tag((Eterm) something) == TAG_PRIMARY_HEADER) { /* a term_array */
aa = (Eterm*) something;
bb = (Eterm*) WSTACK_POP(stack);
sz = WSTACK_POP(stack);
goto term_array;
}
a = something;
b = WSTACK_POP(stack);
goto tailrecur;
}
DESTROY_WSTACK(stack);
return 1;
not_equal:
DESTROY_WSTACK(stack);
return 0;
}