diff options
author | Sverker Eriksson <[email protected]> | 2017-02-20 20:06:28 +0100 |
---|---|---|
committer | Sverker Eriksson <[email protected]> | 2017-02-20 20:06:28 +0100 |
commit | 82d3513f95198b0a4295ba866a78ae6c137a34d5 (patch) | |
tree | b45aee60996f1054e15308defddc8e96e8ef91b8 /erts/emulator/beam/utils.c | |
parent | 5adbf961a3c79a6782f8be8336ec26594754e9e8 (diff) | |
parent | 32a74e6c83cd110b8e8ab714be4365c0da558fca (diff) | |
download | otp-82d3513f95198b0a4295ba866a78ae6c137a34d5.tar.gz otp-82d3513f95198b0a4295ba866a78ae6c137a34d5.tar.bz2 otp-82d3513f95198b0a4295ba866a78ae6c137a34d5.zip |
Merge branch 'master' into sverker/enif_select
Conflicts:
erts/emulator/beam/erl_binary.h
erts/emulator/beam/erl_monitors.c
erts/emulator/beam/erl_nif.c
erts/emulator/beam/global.h
erts/emulator/test/nif_SUITE_data/nif_SUITE.c
Diffstat (limited to 'erts/emulator/beam/utils.c')
-rw-r--r-- | erts/emulator/beam/utils.c | 424 |
1 files changed, 113 insertions, 311 deletions
diff --git a/erts/emulator/beam/utils.c b/erts/emulator/beam/utils.c index 3fa48da1ec..092a5320ba 100644 --- a/erts/emulator/beam/utils.c +++ b/erts/emulator/beam/utils.c @@ -700,12 +700,7 @@ erts_bld_atom_2uint_3tup_list(Uint **hpp, Uint *szp, Sint length, /* make a hash index from an erlang term */ /* -** There are three hash functions. -** make_broken_hash: the one used for backward compatibility -** is called from the bif erlang:hash/2. Should never be used -** as it a) hashes only a part of binaries, b) hashes bignums really poorly, -** c) hashes bignums differently on different endian processors and d) hashes -** small integers with different weights on different bytes. +** There are two hash functions. ** ** make_hash: A hash function that will give the same values for the same ** terms regardless of the internal representation. Small integers are @@ -1045,6 +1040,10 @@ tail_recur: DESTROY_WSTACK(stack); return hash; +#undef MAKE_HASH_TUPLE_OP +#undef MAKE_HASH_TERM_ARRAY_OP +#undef MAKE_HASH_CDR_PRE_OP +#undef MAKE_HASH_CDR_POST_OP #undef UINT32_HASH_STEP #undef UINT32_HASH_RET } @@ -1839,7 +1838,7 @@ make_internal_hash(Eterm term) break; case REF_SUBTAG: UINT32_HASH(internal_ref_numbers(term)[0], HCONST_7); - ASSERT(internal_ref_no_of_numbers(term) == 3); + ASSERT(internal_ref_no_numbers(term) == 3); UINT32_HASH_2(internal_ref_numbers(term)[1], internal_ref_numbers(term)[2], HCONST_8); goto pop_next; @@ -1848,7 +1847,7 @@ make_internal_hash(Eterm term) { ExternalThing* thing = external_thing_ptr(term); - ASSERT(external_thing_ref_no_of_numbers(thing) == 3); + ASSERT(external_thing_ref_no_numbers(thing) == 3); /* See limitation #2 */ #ifdef ARCH_64 POINTER_HASH(thing->node, HCONST_7); @@ -1954,259 +1953,6 @@ make_internal_hash(Eterm term) #undef HCONST #undef MIX - -Uint32 make_broken_hash(Eterm term) -{ - Uint32 hash = 0; - DECLARE_WSTACK(stack); - unsigned op; -tail_recur: - op = tag_val_def(term); - for (;;) { - switch (op) { - case NIL_DEF: - hash = hash*FUNNY_NUMBER3 + 1; - break; - case ATOM_DEF: - hash = hash*FUNNY_NUMBER1 + - (atom_tab(atom_val(term))->slot.bucket.hvalue); - break; - case SMALL_DEF: -#if defined(ARCH_64) - { - Sint y1 = signed_val(term); - Uint y2 = y1 < 0 ? -(Uint)y1 : y1; - Uint32 y3 = (Uint32) (y2 >> 32); - int arity = 1; - -#if defined(WORDS_BIGENDIAN) - if (!IS_SSMALL28(y1)) - { /* like a bignum */ - Uint32 y4 = (Uint32) y2; - hash = hash*FUNNY_NUMBER2 + ((y4 << 16) | (y4 >> 16)); - if (y3) { - hash = hash*FUNNY_NUMBER2 + ((y3 << 16) | (y3 >> 16)); - arity++; - } - hash = hash * (y1 < 0 ? FUNNY_NUMBER3 : FUNNY_NUMBER2) + arity; - } else { - hash = hash*FUNNY_NUMBER2 + (((Uint) y1) & 0xfffffff); - } -#else - if (!IS_SSMALL28(y1)) - { /* like a bignum */ - hash = hash*FUNNY_NUMBER2 + ((Uint32) y2); - if (y3) - { - hash = hash*FUNNY_NUMBER2 + y3; - arity++; - } - hash = hash * (y1 < 0 ? FUNNY_NUMBER3 : FUNNY_NUMBER2) + arity; - } else { - hash = hash*FUNNY_NUMBER2 + (((Uint) y1) & 0xfffffff); - } -#endif - } -#else - hash = hash*FUNNY_NUMBER2 + unsigned_val(term); -#endif - break; - - case BINARY_DEF: - { - size_t sz = binary_size(term); - size_t i = (sz < 15) ? sz : 15; - - hash = hash_binary_bytes(term, i, hash); - hash = hash*FUNNY_NUMBER4 + sz; - break; - } - - case EXPORT_DEF: - { - Export* ep = *((Export **) (export_val(term) + 1)); - - hash = hash * FUNNY_NUMBER11 + ep->info.mfa.arity; - hash = hash*FUNNY_NUMBER1 + - (atom_tab(atom_val(ep->info.mfa.module))->slot.bucket.hvalue); - hash = hash*FUNNY_NUMBER1 + - (atom_tab(atom_val(ep->info.mfa.function))->slot.bucket.hvalue); - break; - } - - case FUN_DEF: - { - ErlFunThing* funp = (ErlFunThing *) fun_val(term); - Uint num_free = funp->num_free; - - hash = hash * FUNNY_NUMBER10 + num_free; - hash = hash*FUNNY_NUMBER1 + - (atom_tab(atom_val(funp->fe->module))->slot.bucket.hvalue); - hash = hash*FUNNY_NUMBER2 + funp->fe->old_index; - hash = hash*FUNNY_NUMBER2 + funp->fe->old_uniq; - if (num_free > 0) { - if (num_free > 1) { - WSTACK_PUSH3(stack, (UWord) &funp->env[1], (num_free-1), MAKE_HASH_TERM_ARRAY_OP); - } - term = funp->env[0]; - goto tail_recur; - } - break; - } - - case PID_DEF: - hash = hash*FUNNY_NUMBER5 + internal_pid_number(term); - break; - case EXTERNAL_PID_DEF: - hash = hash*FUNNY_NUMBER5 + external_pid_number(term); - break; - case PORT_DEF: - hash = hash*FUNNY_NUMBER9 + internal_port_number(term); - break; - case EXTERNAL_PORT_DEF: - hash = hash*FUNNY_NUMBER9 + external_port_number(term); - break; - case REF_DEF: - hash = hash*FUNNY_NUMBER9 + internal_ref_numbers(term)[0]; - break; - case EXTERNAL_REF_DEF: - hash = hash*FUNNY_NUMBER9 + external_ref_numbers(term)[0]; - break; - case FLOAT_DEF: - { - FloatDef ff; - GET_DOUBLE(term, ff); - if (ff.fd == 0.0f) { - /* ensure positive 0.0 */ - ff.fd = erts_get_positive_zero_float(); - } - hash = hash*FUNNY_NUMBER6 + (ff.fw[0] ^ ff.fw[1]); - } - break; - case MAKE_HASH_CDR_PRE_OP: - term = (Eterm) WSTACK_POP(stack); - if (is_not_list(term)) { - WSTACK_PUSH(stack, (UWord) MAKE_HASH_CDR_POST_OP); - goto tail_recur; - } - /*fall through*/ - case LIST_DEF: - { - Eterm* list = list_val(term); - WSTACK_PUSH2(stack, (UWord) CDR(list), - (UWord) MAKE_HASH_CDR_PRE_OP); - term = CAR(list); - goto tail_recur; - } - - case MAKE_HASH_CDR_POST_OP: - hash *= FUNNY_NUMBER8; - break; - - case BIG_DEF: - { - Eterm* ptr = big_val(term); - int is_neg = BIG_SIGN(ptr); - Uint arity = BIG_ARITY(ptr); - Uint i = arity; - ptr++; -#if D_EXP == 16 - /* hash over 32 bit LE */ - - while(i--) { - hash = hash*FUNNY_NUMBER2 + *ptr++; - } -#elif D_EXP == 32 - -#if defined(WORDS_BIGENDIAN) - while(i--) { - Uint d = *ptr++; - hash = hash*FUNNY_NUMBER2 + ((d << 16) | (d >> 16)); - } -#else - while(i--) { - hash = hash*FUNNY_NUMBER2 + *ptr++; - } -#endif - -#elif D_EXP == 64 - { - Uint32 h = 0, l; -#if defined(WORDS_BIGENDIAN) - while(i--) { - Uint d = *ptr++; - l = d & 0xffffffff; - h = d >> 32; - hash = hash*FUNNY_NUMBER2 + ((l << 16) | (l >> 16)); - if (h || i) - hash = hash*FUNNY_NUMBER2 + ((h << 16) | (h >> 16)); - } -#else - while(i--) { - Uint d = *ptr++; - l = d & 0xffffffff; - h = d >> 32; - hash = hash*FUNNY_NUMBER2 + l; - if (h || i) - hash = hash*FUNNY_NUMBER2 + h; - } -#endif - /* adjust arity to match 32 bit mode */ - arity = (arity << 1) - (h == 0); - } - -#else -#error "unsupported D_EXP size" -#endif - hash = hash * (is_neg ? FUNNY_NUMBER3 : FUNNY_NUMBER2) + arity; - } - break; - - case MAP_DEF: - hash = hash*FUNNY_NUMBER13 + FUNNY_NUMBER14 + make_hash2(term); - break; - case TUPLE_DEF: - { - Eterm* ptr = tuple_val(term); - Uint arity = arityval(*ptr); - - WSTACK_PUSH3(stack, (UWord) arity, (UWord) (ptr+1), (UWord) arity); - op = MAKE_HASH_TUPLE_OP; - }/*fall through*/ - case MAKE_HASH_TUPLE_OP: - case MAKE_HASH_TERM_ARRAY_OP: - { - Uint i = (Uint) WSTACK_POP(stack); - Eterm* ptr = (Eterm*) WSTACK_POP(stack); - if (i != 0) { - term = *ptr; - WSTACK_PUSH3(stack, (UWord)(ptr+1), (UWord) i-1, (UWord) op); - goto tail_recur; - } - if (op == MAKE_HASH_TUPLE_OP) { - Uint32 arity = (UWord) WSTACK_POP(stack); - hash = hash*FUNNY_NUMBER9 + arity; - } - break; - } - - default: - erts_exit(ERTS_ERROR_EXIT, "Invalid tag in make_broken_hash\n"); - return 0; - } - if (WSTACK_ISEMPTY(stack)) break; - op = (Uint) WSTACK_POP(stack); - } - - DESTROY_WSTACK(stack); - return hash; - -#undef MAKE_HASH_TUPLE_OP -#undef MAKE_HASH_TERM_ARRAY_OP -#undef MAKE_HASH_CDR_PRE_OP -#undef MAKE_HASH_CDR_POST_OP -} - static Eterm do_allocate_logger_message(Eterm gleader, Eterm **hp, ErlOffHeap **ohp, ErlHeapFragment **bp, Process **p, Uint sz) @@ -2740,22 +2486,20 @@ tailrecur_ne: anum = external_thing_ref_numbers(athing); bnum = external_thing_ref_numbers(bthing); - alen = external_thing_ref_no_of_numbers(athing); - blen = external_thing_ref_no_of_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; - { - RefThing* athing = ref_thing_ptr(a); - RefThing* bthing = ref_thing_ptr(b); - alen = internal_thing_ref_no_of_numbers(athing); - blen = internal_thing_ref_no_of_numbers(bthing); - anum = internal_thing_ref_numbers(athing); - bnum = internal_thing_ref_numbers(bthing); - } + 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); @@ -3387,25 +3131,21 @@ tailrecur_ne: */ if (is_internal_ref(b)) { - RefThing* bthing = ref_thing_ptr(b); bnode = erts_this_node; - bnum = internal_thing_ref_numbers(bthing); - blen = internal_thing_ref_no_of_numbers(bthing); + blen = internal_ref_no_numbers(b); + bnum = internal_ref_numbers(b); } else if(is_external_ref(b)) { ExternalThing* bthing = external_thing_ptr(b); bnode = bthing->node; bnum = external_thing_ref_numbers(bthing); - blen = external_thing_ref_no_of_numbers(bthing); + blen = external_thing_ref_no_numbers(bthing); } else { a_tag = REF_DEF; goto mixed_types; } - { - RefThing* athing = ref_thing_ptr(a); - anode = erts_this_node; - anum = internal_thing_ref_numbers(athing); - alen = internal_thing_ref_no_of_numbers(athing); - } + anode = erts_this_node; + alen = internal_ref_no_numbers(a); + anum = internal_ref_numbers(a); ref_common: CMP_NODES(anode, bnode); @@ -3435,15 +3175,14 @@ tailrecur_ne: goto pop_next; case (_TAG_HEADER_EXTERNAL_REF >> _TAG_PRIMARY_SIZE): if (is_internal_ref(b)) { - RefThing* bthing = ref_thing_ptr(b); bnode = erts_this_node; - bnum = internal_thing_ref_numbers(bthing); - blen = internal_thing_ref_no_of_numbers(bthing); + blen = internal_ref_no_numbers(b); + bnum = internal_ref_numbers(b); } else if (is_external_ref(b)) { ExternalThing* bthing = external_thing_ptr(b); bnode = bthing->node; bnum = external_thing_ref_numbers(bthing); - blen = external_thing_ref_no_of_numbers(bthing); + blen = external_thing_ref_no_numbers(bthing); } else { a_tag = EXTERNAL_REF_DEF; goto mixed_types; @@ -3452,7 +3191,7 @@ tailrecur_ne: ExternalThing* athing = external_thing_ptr(a); anode = athing->node; anum = external_thing_ref_numbers(athing); - alen = external_thing_ref_no_of_numbers(athing); + alen = external_thing_ref_no_numbers(athing); } goto ref_common; default: @@ -3829,40 +3568,41 @@ not_equal: Eterm store_external_or_ref_(Uint **hpp, ErlOffHeap* oh, Eterm ns) { + struct erl_off_heap_header *ohhp; Uint i; Uint size; - Uint *from_hp; - Uint *to_hp = *hpp; + Eterm *from_hp; + Eterm *to_hp = *hpp; ASSERT(is_external(ns) || is_internal_ref(ns)); - if(is_external(ns)) { - from_hp = external_val(ns); - size = thing_arityval(*from_hp) + 1; - *hpp += size; - - for(i = 0; i < size; i++) - to_hp[i] = from_hp[i]; - - erts_refc_inc(&((ExternalThing *) to_hp)->node->refc, 2); - - ((struct erl_off_heap_header*) to_hp)->next = oh->first; - oh->first = (struct erl_off_heap_header*) to_hp; - - return make_external(to_hp); - } - - /* Internal ref */ - from_hp = internal_ref_val(ns); - + from_hp = boxed_val(ns); size = thing_arityval(*from_hp) + 1; - *hpp += size; for(i = 0; i < size; i++) to_hp[i] = from_hp[i]; - return make_internal_ref(to_hp); + if (is_external_header(*from_hp)) { + ExternalThing *etp = (ExternalThing *) from_hp; + ASSERT(is_external(ns)); + erts_smp_refc_inc(&etp->node->refc, 2); + } + else if (is_ordinary_ref_thing(from_hp)) + return make_internal_ref(to_hp); + else { + ErtsMRefThing *mreft = (ErtsMRefThing *) from_hp; + ErtsMagicBinary *mb = mreft->mb; + ASSERT(is_magic_ref_thing(from_hp)); + erts_refc_inc(&mb->refc, 2); + OH_OVERHEAD(oh, mb->orig_size / sizeof(Eterm)); + } + + ohhp = (struct erl_off_heap_header*) to_hp; + ohhp->next = oh->first; + oh->first = ohhp; + + return make_boxed(to_hp); } Eterm @@ -3925,6 +3665,68 @@ intlist_to_buf(Eterm list, char *buf, Sint len) return -2; /* not enough space */ } +/* Fill buf with the contents of the unicode list. + * Return the number of bytes in the buffer, + * or -1 for type error, + * or -2 for not enough buffer space (buffer contains truncated result). + */ +Sint +erts_unicode_list_to_buf(Eterm list, byte *buf, Sint len) +{ + Eterm* listptr; + Sint sz = 0; + + if (is_nil(list)) { + return 0; + } + if (is_not_list(list)) { + return -1; + } + listptr = list_val(list); + + while (len-- > 0) { + Sint val; + + if (is_not_small(CAR(listptr))) { + return -1; + } + val = signed_val(CAR(listptr)); + if (0 <= val && val < 0x80) { + buf[sz] = val; + sz++; + } else if (val < 0x800) { + buf[sz+0] = 0xC0 | (val >> 6); + buf[sz+1] = 0x80 | (val & 0x3F); + sz += 2; + } else if (val < 0x10000UL) { + if (0xD800 <= val && val <= 0xDFFF) { + return -1; + } + buf[sz+0] = 0xE0 | (val >> 12); + buf[sz+1] = 0x80 | ((val >> 6) & 0x3F); + buf[sz+2] = 0x80 | (val & 0x3F); + sz += 3; + } else if (val < 0x110000) { + buf[sz+0] = 0xF0 | (val >> 18); + buf[sz+1] = 0x80 | ((val >> 12) & 0x3F); + buf[sz+2] = 0x80 | ((val >> 6) & 0x3F); + buf[sz+3] = 0x80 | (val & 0x3F); + sz += 4; + } else { + return -1; + } + list = CDR(listptr); + if (is_nil(list)) { + return sz; + } + if (is_not_list(list)) { + return -1; + } + listptr = list_val(list); + } + return -2; /* not enough space */ +} + /* ** Convert an integer to a byte list ** return pointer to converted stuff (need not to be at start of buf!) |