--- hash_compat.c.orig 2024-02-06 20:29:47 UTC +++ hash_compat.c @@ -0,0 +1,165 @@ +/* The pre-OCaml 4.00 hash implementation */ +/* FIXME: This is included for backwards compatibility only and must be + * REMOVED when a new hash function included in a stable release has been + * available for a few years. The removal of this function will break + * Unison version compatibility. There must be plenty of time given + * for users to upgrade (most users don't compile themselves and are at + * mercy of whatever package repositories they use). */ + +/* Code copied from OCaml sources */ +/**************************************************************************/ +/* */ +/* OCaml */ +/* */ +/* Xavier Leroy, projet Cristal, INRIA Rocquencourt */ +/* */ +/* Copyright 1996 Institut National de Recherche en Informatique et */ +/* en Automatique. */ +/* */ +/* All rights reserved. This file is distributed under the terms of */ +/* the GNU Lesser General Public License version 2.1, with the */ +/* special exception on linking described in the file LICENSE. */ +/* */ +/**************************************************************************/ + +#include +#include +#include + +struct hash_state { + uintnat accu; + intnat univ_limit, univ_count; +}; + +static void hash_aux(struct hash_state*, value obj); + +CAMLprim value unsn_hash_univ_param(value count, value limit, value obj) +{ + struct hash_state h; + h.univ_limit = Long_val(limit); + h.univ_count = Long_val(count); + h.accu = 0; + hash_aux(&h, obj); + return Val_long(h.accu & 0x3FFFFFFF); + /* The & has two purposes: ensure that the return value is positive + and give the same result on 32 bit and 64 bit architectures. */ +} + +#define Alpha 65599 +#define Beta 19 +#define Combine(new) (h->accu = h->accu * Alpha + (new)) +#define Combine_small(new) (h->accu = h->accu * Beta + (new)) + +static void hash_aux(struct hash_state* h, value obj) +{ + unsigned char * p; + mlsize_t i, j; + tag_t tag; + + h->univ_limit--; + if (h->univ_count < 0 || h->univ_limit < 0) return; + + again: + if (Is_long(obj)) { + h->univ_count--; + Combine(Long_val(obj)); + return; + } + if (! Is_in_value_area(obj)) { + /* obj is a pointer outside the heap, to an object with + a priori unknown structure. Use its physical address as hash key. */ + Combine((intnat) obj); + return; + } + /* Pointers into the heap are well-structured blocks. So are atoms. + We can inspect the block contents. */ + /* The code needs reindenting later. Leaving as is to facilitate review. */ + tag = Tag_val(obj); + switch (tag) { + case String_tag: + h->univ_count--; + i = caml_string_length(obj); + for (p = &Byte_u(obj, 0); i > 0; i--, p++) + Combine_small(*p); + break; + case Double_tag: + /* For doubles, we inspect their binary representation, LSB first. + The results are consistent among all platforms with IEEE floats. */ + h->univ_count--; +#ifdef ARCH_BIG_ENDIAN + for (p = &Byte_u(obj, sizeof(double) - 1), i = sizeof(double); + i > 0; + p--, i--) +#else + for (p = &Byte_u(obj, 0), i = sizeof(double); + i > 0; + p++, i--) +#endif + Combine_small(*p); + break; + case Double_array_tag: + h->univ_count--; + for (j = 0; j < Bosize_val(obj); j += sizeof(double)) { +#ifdef ARCH_BIG_ENDIAN + for (p = &Byte_u(obj, j + sizeof(double) - 1), i = sizeof(double); + i > 0; + p--, i--) +#else + for (p = &Byte_u(obj, j), i = sizeof(double); + i > 0; + p++, i--) +#endif + Combine_small(*p); + } + break; + case Abstract_tag: + /* We don't know anything about the contents of the block. + Better do nothing. */ + break; + case Infix_tag: + hash_aux(h, obj - Infix_offset_val(obj)); + break; + case Forward_tag: + obj = Forward_val (obj); + goto again; + case Object_tag: + h->univ_count--; + Combine(Oid_val(obj)); + break; + case Custom_tag: + /* If no hashing function provided, do nothing */ + if (Custom_ops_val(obj)->hash != NULL) { + h->univ_count--; + Combine(Custom_ops_val(obj)->hash(obj)); + } + break; +#ifdef NO_NAKED_POINTERS + case Closure_tag: + h->univ_count--; + Combine_small(tag); + /* Recursively hash the environment fields */ + i = Wosize_val(obj); + j = Start_env_closinfo(Closinfo_val(obj)); + while (i > j) { + i--; + hash_aux(h, Field(obj, i)); + } + /* Combine the code pointers, closure info fields, and infix headers */ + while (i > 0) { + i--; + Combine(Field(obj, i)); + h->univ_count--; + } + break; +#endif + default: + h->univ_count--; + Combine_small(tag); + i = Wosize_val(obj); + while (i != 0) { + i--; + hash_aux(h, Field(obj, i)); + } + break; + } +}